From 03caca368a2ada8460adecbff0b2d76823373c74 Mon Sep 17 00:00:00 2001 From: "Kenneth D. Merry" Date: Thu, 16 Jul 2020 20:43:28 +0000 Subject: [PATCH 001/287] Hold the mutex when releasing a callout. In xpt_release_device(), callout_stop() was being called without holding the mutex (send_mtx) that is used to protect the callout. So, move the mtx_unlock() call so that it is protected. MFC after: 1 week Sponsored by: Spectra Logic --- sys/cam/cam_xpt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index e8fec4a325f4..9f53761c50cc 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -4959,16 +4959,18 @@ xpt_release_device(struct cam_ed *device) devq = bus->sim->devq; mtx_lock(&devq->send_mtx); cam_devq_resize(devq, devq->send_queue.array_size - 1); - mtx_unlock(&devq->send_mtx); KASSERT(SLIST_EMPTY(&device->periphs), ("destroying device, but periphs list is not empty")); KASSERT(device->devq_entry.index == CAM_UNQUEUED_INDEX, ("destroying device while still queued for ccbs")); + /* The send_mtx must be held when accessing the callout */ if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) callout_stop(&device->callout); + mtx_unlock(&devq->send_mtx); + xpt_release_target(device->target); cam_ccbq_fini(&device->ccbq); From 946b8f6fb02642cc925455132261671398094152 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 16 Jul 2020 21:30:46 +0000 Subject: [PATCH 002/287] Add crypto_initreq() and crypto_destroyreq(). These routines are similar to crypto_getreq() and crypto_freereq() but operate on caller-supplied storage instead of allocating crypto requests from a UMA zone. Reviewed by: markj Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D25691 --- share/man/man9/Makefile | 4 +++- share/man/man9/crypto_request.9 | 35 ++++++++++++++++++++++++++++----- sys/opencrypto/crypto.c | 30 ++++++++++++++++++++++------ sys/opencrypto/cryptodev.h | 2 ++ 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index f5a91afe7ab1..96a7c819eb18 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -927,9 +927,11 @@ MLINKS+=crypto_driver.9 crypto_copyback.9 \ crypto_driver.9 CRYPTODEV_PROCESS.9 \ crypto_driver.9 hmac_init_ipad.9 \ crypto_driver.9 hmac_init_opad.9 -MLINKS+=crypto_request.9 crypto_dispatch.9 \ +MLINKS+=crypto_request.9 crypto_destroyreq.9 \ + crypto_request.9 crypto_dispatch.9 \ crypto_request.9 crypto_freereq.9 \ crypto_request.9 crypto_getreq.9 \ + crypto_request.9 crypto_initreq.9 \ crypto_request.9 crypto_use_buf.9 \ crypto_request.9 crypto_use_mbuf.9 \ crypto_request.9 crypto_use_output_buf.9 \ diff --git a/share/man/man9/crypto_request.9 b/share/man/man9/crypto_request.9 index 1a46a5a9962d..69b2a82d7ab1 100644 --- a/share/man/man9/crypto_request.9 +++ b/share/man/man9/crypto_request.9 @@ -30,7 +30,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 22, 2020 +.Dd July 16, 2020 .Dt CRYPTO_REQUEST 9 .Os .Sh NAME @@ -41,10 +41,14 @@ .Ft int .Fn crypto_dispatch "struct cryptop *crp" .Ft void +.Fn crypto_destroyreq "struct cryptop *crp" +.Ft void .Fn crypto_freereq "struct cryptop *crp" .Ft "struct cryptop *" .Fn crypto_getreq "crypto_session_t cses" "int how" .Ft void +.Fn crypto_initreq "crypto_session_t cses" "int how" +.Ft void .Fn crypto_use_buf "struct cryptop *crp" "void *buf" "int len" .Ft void .Fn crypto_use_mbuf "struct cryptop *crp" "struct mbuf *m" @@ -62,10 +66,27 @@ an instance of .Vt struct cryptop and is associated with an active session. .Pp -New requests are allocated by -.Fn crypto_getreq . +Requests can either be allocated dynamically or use caller-supplied +storage. +Dynamically allocated requests should be allocated by +.Fn crypto_getreq +and freed by +.Fn crypto_freereq +once the request has completed. +Requests using caller-supplied storage should be initialized by +.Fn crypto_initreq +at the start of each operation and destroyed by +.Fn crypto_destroyreq +once the request has completed. +.Pp +For both +.Fn crypto_getreq +and +.Fn crypto_initreq , .Fa cses is a reference to an active session. +For +.Fn crypto_getreq , .Fa how is passed to .Xr malloc 9 @@ -73,7 +94,9 @@ and should be set to either .Dv M_NOWAIT or .Dv M_WAITOK . -The caller should then set fields in the returned structure to describe +.Pp +Once a request has been initialized, +the caller should set fields in the structure to describe request-specific parameters. Unused fields should be left as-is. .Pp @@ -92,7 +115,9 @@ Note that a request's callback function may be invoked before returns. .Pp Once a request has signaled completion by invoking its callback function, -it should be feed via +it should be freed via +.Fn crypto_destroyreq +or .Fn crypto_freereq . .Pp Cryptographic operations include several fields to describe the request. diff --git a/sys/opencrypto/crypto.c b/sys/opencrypto/crypto.c index 3c4ba0ac5a8a..8f0af929da40 100644 --- a/sys/opencrypto/crypto.c +++ b/sys/opencrypto/crypto.c @@ -1734,12 +1734,8 @@ crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint) } void -crypto_freereq(struct cryptop *crp) +crypto_destroyreq(struct cryptop *crp) { - - if (crp == NULL) - return; - #ifdef DIAGNOSTIC { struct cryptop *crp2; @@ -1764,10 +1760,31 @@ crypto_freereq(struct cryptop *crp) } } #endif +} +void +crypto_freereq(struct cryptop *crp) +{ + if (crp == NULL) + return; + + crypto_destroyreq(crp); uma_zfree(cryptop_zone, crp); } +static void +_crypto_initreq(struct cryptop *crp, crypto_session_t cses) +{ + crp->crp_session = cses; +} + +void +crypto_initreq(struct cryptop *crp, crypto_session_t cses) +{ + memset(crp, 0, sizeof(*crp)); + _crypto_initreq(crp, cses); +} + struct cryptop * crypto_getreq(crypto_session_t cses, int how) { @@ -1775,7 +1792,8 @@ crypto_getreq(crypto_session_t cses, int how) MPASS(how == M_WAITOK || how == M_NOWAIT); crp = uma_zalloc(cryptop_zone, how | M_ZERO); - crp->crp_session = cses; + if (crp != NULL) + _crypto_initreq(crp, cses); return (crp); } diff --git a/sys/opencrypto/cryptodev.h b/sys/opencrypto/cryptodev.h index a272aec6cb1b..edde16cf7327 100644 --- a/sys/opencrypto/cryptodev.h +++ b/sys/opencrypto/cryptodev.h @@ -622,6 +622,8 @@ extern void crypto_done(struct cryptop *crp); extern void crypto_kdone(struct cryptkop *); extern int crypto_getfeat(int *); +extern void crypto_destroyreq(struct cryptop *crp); +extern void crypto_initreq(struct cryptop *crp, crypto_session_t cses); extern void crypto_freereq(struct cryptop *crp); extern struct cryptop *crypto_getreq(crypto_session_t cses, int how); From 0bfad4329818423960a75ed0a305005098e237ac Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 16 Jul 2020 21:58:43 +0000 Subject: [PATCH 003/287] Include ABI note tag in shared libraries. Split the ELF feature note into a separate file that is linked into *crt1.o the same as crtbrand.S was before. crtbrand.o is now linked into crti.o on all platforms in addition to *crt1.o. Reviewed by: kib Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25304 --- lib/csu/Makefile.inc | 9 +++++++- lib/csu/common/crtbrand.S | 12 +--------- lib/csu/common/feature_note.S | 42 +++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 lib/csu/common/feature_note.S diff --git a/lib/csu/Makefile.inc b/lib/csu/Makefile.inc index 319f70750938..5681ef65117a 100644 --- a/lib/csu/Makefile.inc +++ b/lib/csu/Makefile.inc @@ -13,7 +13,7 @@ OBJS+= crtbegin.o crtbeginS.o crtbeginT.o OBJS+= crtend.o crtendS.o OBJS+= crti.o crtn.o -CRT1OBJS+= crtbrand.o ignore_init_note.o +CRT1OBJS+= crtbrand.o feature_note.o ignore_init_note.o ACFLAGS+= -DLOCORE @@ -33,6 +33,7 @@ FILESDIR= ${LIBDIR} .undef LIBRARIES_ONLY CLEANFILES+= ${OBJS} ${CRT1OBJS} crt1_c.o gcrt1_c.o Scrt1_c.o +CLEANFILES+= crti_s.o crt1.o: crt1_c.o ${CRT1OBJS} ${LD} ${_LDFLAGS} -o ${.TARGET} -r ${.ALLSRC:M*.o} @@ -68,6 +69,12 @@ crtbeginS.o crtendS.o: ${CC} ${CFLAGS} -I${.CURDIR} ${CFLAGS_CRTS} -c -o ${.TARGET} \ ${.ALLSRC:N*.h:[1]} +crti_s.o: crti.S + ${CC} ${CFLAGS} ${ACFLAGS} -c ${.ALLSRC:M*.S} -o ${.TARGET} + +crti.o: crti_s.o crtbrand.o + ${LD} ${_LDFLAGS} -o ${.TARGET} -r ${.ALLSRC:M*.o} + .endif .include "../Makefile.inc" diff --git a/lib/csu/common/crtbrand.S b/lib/csu/common/crtbrand.S index 8efe7fb6347b..bf223d84bc12 100644 --- a/lib/csu/common/crtbrand.S +++ b/lib/csu/common/crtbrand.S @@ -38,7 +38,7 @@ __FBSDID("$FreeBSD$"); * for more information. */ - .section .note.tag,"a",%note + .section .note.tag,"aG",%note,.freebsd.noteG,comdat .p2align 2 .4byte 2f-1f .4byte 4f-3f @@ -46,14 +46,4 @@ __FBSDID("$FreeBSD$"); 1: .asciz NOTE_FREEBSD_VENDOR 2: .p2align 2 3: .4byte __FreeBSD_version -4: - - .section .note.tag,"a",%note - .p2align 2 - .4byte 2f-1f - .4byte 4f-3f - .4byte NT_FREEBSD_FEATURE_CTL -1: .asciz NOTE_FREEBSD_VENDOR -2: .p2align 2 -3: .4byte 0 4: diff --git a/lib/csu/common/feature_note.S b/lib/csu/common/feature_note.S new file mode 100644 index 000000000000..0274ce61debc --- /dev/null +++ b/lib/csu/common/feature_note.S @@ -0,0 +1,42 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright 2000 David E. O'Brien, John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include "notes.h" + + .section .note.tag,"a",%note + .p2align 2 + .4byte 2f-1f + .4byte 4f-3f + .4byte NT_FREEBSD_FEATURE_CTL +1: .asciz NOTE_FREEBSD_VENDOR +2: .p2align 2 +3: .4byte 0 +4: From e9751a84dd2d177a1ebd6ca58b3b8f7dbc6f6220 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 16 Jul 2020 22:01:01 +0000 Subject: [PATCH 004/287] Include FreeBSD ABI tag note in the ELF runtime loader. Reviewed by: kib Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25306 --- libexec/rtld-elf/Makefile | 4 +++- libexec/rtld-elf/rtld.c | 13 ------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/libexec/rtld-elf/Makefile b/libexec/rtld-elf/Makefile index 23a0f99af2c2..40ad7a7ffc2f 100644 --- a/libexec/rtld-elf/Makefile +++ b/libexec/rtld-elf/Makefile @@ -17,6 +17,7 @@ PROG?= ld-elf.so.1 TAGS+= lib32 .endif SRCS= \ + crtbrand.S \ rtld_start.S \ reloc.c \ rtld.c \ @@ -29,6 +30,7 @@ SRCS= \ libmap.c MAN?= rtld.1 CSTD?= gnu99 +ACFLAGS+= -DLOCORE CFLAGS+= -Wall -DFREEBSD_ELF -DIN_RTLD -ffreestanding CFLAGS+= -I${SRCTOP}/lib/csu/common .if exists(${RTLD_ELF_DIR}/${MACHINE_ARCH}) @@ -75,7 +77,7 @@ beforeinstall: -chflags -h noschg ${DESTDIR}/usr/libexec/${PROG} .endif -.PATH: ${RTLD_ELF_DIR}/${RTLD_ARCH} +.PATH: ${RTLD_ELF_DIR}/${RTLD_ARCH} ${SRCTOP}/lib/csu/common .if ${.CURDIR} == ${RTLD_ELF_DIR} HAS_TESTS= diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index e15aee68ace6..48de9506154c 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -470,19 +470,6 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) } direct_exec = true; - /* - * Set osrel for us, it is later reset to the binary' - * value before first instruction of code from the binary - * is executed. - */ - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_OSREL; - mib[3] = getpid(); - osrel = __FreeBSD_version; - sz = sizeof(old_osrel); - (void)sysctl(mib, 4, &old_osrel, &sz, &osrel, sizeof(osrel)); - dbg("opening main program in direct exec mode"); if (argc >= 2) { rtld_argc = parse_args(argv, argc, &search_in_path, &fd, &argv0); From bbbefa33c9088f2f411479d5b15c671abe0ea38c Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Thu, 16 Jul 2020 23:05:18 +0000 Subject: [PATCH 005/287] add script to help figure out what man pages need MLINKS updated... --- tools/tools/README | 1 + tools/tools/man/README | 23 ++++++++++++++++++++++ tools/tools/man/checkmlinks.sh | 35 ++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 tools/tools/man/README create mode 100755 tools/tools/man/checkmlinks.sh diff --git a/tools/tools/README b/tools/tools/README index e9187d37d029..88658f043d4d 100644 --- a/tools/tools/README +++ b/tools/tools/README @@ -44,6 +44,7 @@ kernelcruft Shellscript to find orphaned *.c files in /sys kerninclude Shellscript to find unused #includes in the kernel. kernxref Shellscript to cross reference symbols in the LINT kernel. kttcp An in-kernel version of the ttcp network performance tool +man Scripts useful for working on man pages. mctest A multicast test program mid Create a Message-ID database for mailing lists. mwl Tools specific to the Marvell 88W8363 support diff --git a/tools/tools/man/README b/tools/tools/man/README new file mode 100644 index 000000000000..b0fd24cf1236 --- /dev/null +++ b/tools/tools/man/README @@ -0,0 +1,23 @@ +man scripts +=========== + +checkmlinks.sh +-------------- + +This is a simple script used to check if a man page's Nm/Fo/Fn macro +names are in the Makefile. + +To run, switch to the directory with the pages in it and run the script: +``` +cd /usr/src/share/man/man9 +sh /usr/src/tools/tools/man/checkmlinks.sh +``` + +The script will output the name that is missing, and the file that it +was sourced from. + +There are a number of exceptions, and those should be added to the +script to skip over, e.g. `SDT_PROBE`. The last one is added because +adding the numbered args is a bit redundant. + +$FreeBSD$ diff --git a/tools/tools/man/checkmlinks.sh b/tools/tools/man/checkmlinks.sh new file mode 100755 index 000000000000..21ebf6ac218a --- /dev/null +++ b/tools/tools/man/checkmlinks.sh @@ -0,0 +1,35 @@ +#!/bin/sh - +# Copyright 2020 John-Mark Gurney. +# 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$ +# + +for i in *.[0-9]*; do + for j in $(awk '($1 == ".Nm" || $1 == ".Fo" || $1 == ".Fn") && $2 != "" && $2 != "." && $2 != "," { print $2 }' "$i" | egrep -v 'SDT_PROBE|_Static_assert|ffs_vget|atomic_'); do + if ! grep "$j" Makefile >/dev/null; then + echo missing "$j" from "$i" + fi + done | sort -u +done From 4ae224c6633de9ab5ab29da11a2cbb42b71ae852 Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Thu, 16 Jul 2020 23:29:26 +0000 Subject: [PATCH 006/287] Revert r240317 to prevent leaking pmap entries Subsequent to r240317, kmem_free() was replaced with kva_free() (r254025). kva_free() releases the KVA allocation for the mapped region, but no longer clears the pmap (pagetable) entries. An affected pmap_unmapdev operation would leave the still-pmap'd VA space free for allocation by other KVA consumers. However, this bug easily avoided notice for ~7 years because most devices (1) never call pmap_unmapdev and (2) on amd64, mostly fit within the DMAP and do not need KVA allocations. Other affected arch are less popular: i386, MIPS, and PowerPC. Arm64, arm32, and riscv are not affected. Reported by: Don Morris Submitted by: Don Morris (amd64 part) Reviewed by: kib, markj, Don (!amd64 parts) MFC after: I don't intend to, but you might want to Sponsored by: Dell Isilon Differential Revision: https://reviews.freebsd.org/D25689 --- sys/amd64/amd64/pmap.c | 4 +++- sys/i386/i386/pmap.c | 4 +++- sys/mips/mips/pmap.c | 1 + sys/powerpc/aim/mmu_oea.c | 1 + sys/powerpc/aim/mmu_oea64.c | 1 + sys/powerpc/aim/mmu_radix.c | 4 +++- sys/powerpc/booke/pmap.c | 1 + 7 files changed, 13 insertions(+), 3 deletions(-) diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index e346d4efd7ac..fdcbff0a3dad 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -8279,8 +8279,10 @@ pmap_unmapdev(vm_offset_t va, vm_size_t size) return; } } - if (pmap_initialized) + if (pmap_initialized) { + pmap_qremove(va, atop(size)); kva_free(va, size); + } } /* diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index 7d564ba48950..5ee0b1c98a5f 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -5538,8 +5538,10 @@ __CONCAT(PMTYPE, unmapdev)(vm_offset_t va, vm_size_t size) return; } } - if (pmap_initialized) + if (pmap_initialized) { + pmap_qremove(va, atop(size)); kva_free(va, size); + } } /* diff --git a/sys/mips/mips/pmap.c b/sys/mips/mips/pmap.c index 06cd5028a640..14cab3a4f37e 100644 --- a/sys/mips/mips/pmap.c +++ b/sys/mips/mips/pmap.c @@ -3264,6 +3264,7 @@ pmap_unmapdev(vm_offset_t va, vm_size_t size) base = trunc_page(va); offset = va & PAGE_MASK; size = roundup(size + offset, PAGE_SIZE); + pmap_qremove(base, atop(size)); kva_free(base, size); #endif } diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c index c5b0b048a418..43b2c7480ddf 100644 --- a/sys/powerpc/aim/mmu_oea.c +++ b/sys/powerpc/aim/mmu_oea.c @@ -2673,6 +2673,7 @@ moea_unmapdev(vm_offset_t va, vm_size_t size) base = trunc_page(va); offset = va & PAGE_MASK; size = roundup(offset + size, PAGE_SIZE); + moea_qremove(base, atop(size)); kva_free(base, size); } } diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c index 1310f4992170..64d6d2f1df84 100644 --- a/sys/powerpc/aim/mmu_oea64.c +++ b/sys/powerpc/aim/mmu_oea64.c @@ -2869,6 +2869,7 @@ moea64_unmapdev(vm_offset_t va, vm_size_t size) offset = va & PAGE_MASK; size = roundup2(offset + size, PAGE_SIZE); + moea64_qremove(base, atop(size)); kva_free(base, size); } diff --git a/sys/powerpc/aim/mmu_radix.c b/sys/powerpc/aim/mmu_radix.c index 9efe0207c108..ee30c3e52b82 100644 --- a/sys/powerpc/aim/mmu_radix.c +++ b/sys/powerpc/aim/mmu_radix.c @@ -5846,8 +5846,10 @@ mmu_radix_unmapdev(vm_offset_t va, vm_size_t size) size = round_page(offset + size); va = trunc_page(va); - if (pmap_initialized) + if (pmap_initialized) { + mmu_radix_qremove(va, atop(size)); kva_free(va, size); + } } static __inline void diff --git a/sys/powerpc/booke/pmap.c b/sys/powerpc/booke/pmap.c index 73c575d61f77..adeaee998fc7 100644 --- a/sys/powerpc/booke/pmap.c +++ b/sys/powerpc/booke/pmap.c @@ -2322,6 +2322,7 @@ mmu_booke_unmapdev(vm_offset_t va, vm_size_t size) base = trunc_page(va); offset = va & PAGE_MASK; size = roundup(offset + size, PAGE_SIZE); + mmu_booke_qremove(base, atop(size)); kva_free(base, size); } #endif From c6a2e9a7ae8a2143564e0deae86b7d76ccb1ee04 Mon Sep 17 00:00:00 2001 From: Piotr Pawel Stefaniak Date: Fri, 17 Jul 2020 06:33:20 +0000 Subject: [PATCH 007/287] Promote use of unprivileged users for building ports by documenting SU_CMD. Phrasing by Daniel O'Connor. Reviewed by: 0mp MFC after: 14 days Differential Revision: https://reviews.freebsd.org/D25433 --- share/man/man7/ports.7 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/share/man/man7/ports.7 b/share/man/man7/ports.7 index 3a382f9e07e3..eb65d117bded 100644 --- a/share/man/man7/ports.7 +++ b/share/man/man7/ports.7 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 4, 2020 +.Dd July 17, 2020 .Dt PORTS 7 .Os .Sh NAME @@ -437,6 +437,14 @@ Where to find/put distfiles, normally .Pa distfiles/ in .Va PORTSDIR . +.It Va SU_CMD +Command used to elevate privilege to configure and install a port. +The unprivileged user must have write access to +.Va WRKDIRPREFIX +and +.Va DISTDIR . +The default is +.Ql /usr/bin/su root -c .It Va PACKAGES Used only for the .Cm package From 256c5d705aa69eb3837436ca0453bd368d51ce31 Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Fri, 17 Jul 2020 14:39:07 +0000 Subject: [PATCH 008/287] Don't overflow the trap frame when accessing lr or xzr. When emulating a load pair or store pair in dtrace on arm64 we need to copy the data between the stack and trap frame. When the registers are either the link register or the zero register we will access memory past the end of the trap frame as these are encoded as registers 30 and 31 respectively while the array they access only has 30 entries. Fix this by creating 2 helper functions to perform the operation with special cases for these registers. Sponsored by: Innovate UK --- sys/cddl/dev/dtrace/aarch64/dtrace_subr.c | 33 ++++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c b/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c index 1921052b0480..000de0094492 100644 --- a/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c +++ b/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c @@ -231,6 +231,31 @@ dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs); } +static void +dtrace_load64(uint64_t *addr, struct trapframe *frame, u_int reg) +{ + + KASSERT(reg <= 31, ("dtrace_load64: Invalid register %u", reg)); + if (reg < nitems(frame->tf_x)) + frame->tf_x[reg] = *addr; + else if (reg == 30) /* lr */ + frame->tf_lr = *addr; + /* Nothing to do for load to xzr */ +} + +static void +dtrace_store64(uint64_t *addr, struct trapframe *frame, u_int reg) +{ + + KASSERT(reg <= 31, ("dtrace_store64: Invalid register %u", reg)); + if (reg < nitems(frame->tf_x)) + *addr = frame->tf_x[reg]; + else if (reg == 30) /* lr */ + *addr = frame->tf_lr; + else if (reg == 31) /* xzr */ + *addr = 0; +} + static int dtrace_invop_start(struct trapframe *frame) { @@ -258,12 +283,12 @@ dtrace_invop_start(struct trapframe *frame) sp -= (~offs & OFFSET_MASK) + 1; else sp += (offs); - *(sp + 0) = frame->tf_x[arg1]; - *(sp + 1) = frame->tf_x[arg2]; + dtrace_store64(sp + 0, frame, arg1); + dtrace_store64(sp + 1, frame, arg2); break; case LDP_64: - frame->tf_x[arg1] = *(sp + 0); - frame->tf_x[arg2] = *(sp + 1); + dtrace_load64(sp + 0, frame, arg1); + dtrace_load64(sp + 1, frame, arg2); if (offs >> (OFFSET_SIZE - 1)) sp -= (~offs & OFFSET_MASK) + 1; else From e5587cbbc22dc7219ff03885127d4da706008b29 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Fri, 17 Jul 2020 14:45:16 +0000 Subject: [PATCH 009/287] Clean up crypto_init(). The function is called from a KLD load handler, so it may sleep. - Stop checking for errors from uma_zcreate(), they don't happen. - Convert M_NOWAIT allocations to M_WAITOK. - Remove error handling for existing M_WAITOK allocations. - Fix style. Reviewed by: cem, delphij, jhb MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25696 --- sys/opencrypto/crypto.c | 40 +++++++++------------------------------- 1 file changed, 9 insertions(+), 31 deletions(-) diff --git a/sys/opencrypto/crypto.c b/sys/opencrypto/crypto.c index 8f0af929da40..c7bf240b0fb7 100644 --- a/sys/opencrypto/crypto.c +++ b/sys/opencrypto/crypto.c @@ -325,41 +325,25 @@ crypto_init(void) TAILQ_INIT(&crp_kq); mtx_init(&crypto_q_mtx, "crypto", "crypto op queues", MTX_DEF); - cryptop_zone = uma_zcreate("cryptop", sizeof (struct cryptop), - 0, 0, 0, 0, - UMA_ALIGN_PTR, UMA_ZONE_ZINIT); + cryptop_zone = uma_zcreate("cryptop", + sizeof(struct cryptop), NULL, NULL, NULL, NULL, + UMA_ALIGN_PTR, UMA_ZONE_ZINIT); cryptoses_zone = uma_zcreate("crypto_session", sizeof(struct crypto_session), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_ZINIT); - if (cryptop_zone == NULL || cryptoses_zone == NULL) { - printf("crypto_init: cannot setup crypto zones\n"); - error = ENOMEM; - goto bad; - } - crypto_drivers_size = CRYPTO_DRIVERS_INITIAL; crypto_drivers = malloc(crypto_drivers_size * - sizeof(struct cryptocap), M_CRYPTO_DATA, M_NOWAIT | M_ZERO); - if (crypto_drivers == NULL) { - printf("crypto_init: cannot setup crypto drivers\n"); - error = ENOMEM; - goto bad; - } + sizeof(struct cryptocap), M_CRYPTO_DATA, M_WAITOK | M_ZERO); if (crypto_workers_num < 1 || crypto_workers_num > mp_ncpus) crypto_workers_num = mp_ncpus; - crypto_tq = taskqueue_create("crypto", M_WAITOK|M_ZERO, - taskqueue_thread_enqueue, &crypto_tq); - if (crypto_tq == NULL) { - printf("crypto init: cannot setup crypto taskqueue\n"); - error = ENOMEM; - goto bad; - } + crypto_tq = taskqueue_create("crypto", M_WAITOK | M_ZERO, + taskqueue_thread_enqueue, &crypto_tq); taskqueue_start_threads(&crypto_tq, crypto_workers_num, PRI_MIN_KERN, - "crypto"); + "crypto"); error = kproc_create((void (*)(void *)) crypto_proc, NULL, &cryptoproc, 0, 0, "crypto"); @@ -369,14 +353,8 @@ crypto_init(void) goto bad; } - crypto_ret_workers = malloc(crypto_workers_num * sizeof(struct crypto_ret_worker), - M_CRYPTO_DATA, M_NOWAIT|M_ZERO); - if (crypto_ret_workers == NULL) { - error = ENOMEM; - printf("crypto_init: cannot allocate ret workers\n"); - goto bad; - } - + crypto_ret_workers = mallocarray(crypto_workers_num, + sizeof(struct crypto_ret_worker), M_CRYPTO_DATA, M_WAITOK | M_ZERO); FOREACH_CRYPTO_RETW(ret_worker) { TAILQ_INIT(&ret_worker->crp_ordered_ret_q); From f3856e68811a32389fbb8f50d334f7409a6dd2e7 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Fri, 17 Jul 2020 14:51:51 +0000 Subject: [PATCH 010/287] Add acpi_iort_map_pci_smmuv3(). This new function allows us to find the SMMU instance assigned for a particular PCI RID. Reviewed by: andrew Sponsored by: DARPA, AFRL Differential Revision: https://reviews.freebsd.org/D25687 --- sys/arm64/acpica/acpi_iort.c | 21 ++++++++++++++++++++- sys/dev/acpica/acpivar.h | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/sys/arm64/acpica/acpi_iort.c b/sys/arm64/acpica/acpi_iort.c index 8ed02bda0438..878441d8b3ba 100644 --- a/sys/arm64/acpica/acpi_iort.c +++ b/sys/arm64/acpica/acpi_iort.c @@ -160,7 +160,7 @@ iort_entry_lookup(struct iort_node *node, u_int id, u_int *outid) if (i == node->nentries) return (NULL); if ((entry->flags & ACPI_IORT_ID_SINGLE_MAPPING) == 0) - *outid = entry->outbase + (id - entry->base); + *outid = entry->outbase + (id - entry->base); else *outid = entry->outbase; return (entry->out_node); @@ -564,3 +564,22 @@ acpi_iort_map_pci_msi(u_int seg, u_int rid, u_int *xref, u_int *devid) *xref = node->entries.its[0].xref; return (0); } + +int +acpi_iort_map_pci_smmuv3(u_int seg, u_int rid, u_int *xref, u_int *sid) +{ + ACPI_IORT_SMMU_V3 *smmu; + struct iort_node *node; + + node = iort_pci_rc_map(seg, rid, ACPI_IORT_NODE_SMMU_V3, sid); + if (node == NULL) + return (ENOENT); + + /* This should be an SMMU node. */ + KASSERT(node->type == ACPI_IORT_NODE_SMMU_V3, ("bad node")); + + smmu = (ACPI_IORT_SMMU_V3 *)&node->data.smmu_v3; + *xref = smmu->BaseAddress; + + return (0); +} diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h index f13a569de8f7..69890f153011 100644 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -556,6 +556,7 @@ int acpi_get_domain(device_t dev, device_t child, int *domain); * ARM specific ACPI interfaces, relating to IORT table. */ int acpi_iort_map_pci_msi(u_int seg, u_int rid, u_int *xref, u_int *devid); +int acpi_iort_map_pci_smmuv3(u_int seg, u_int rid, u_int *xref, u_int *devid); int acpi_iort_its_lookup(u_int its_id, u_int *xref, int *pxm); #endif #endif /* _KERNEL */ From 7f0ad2274be0a7f6050a65bb159dbdf0c5918a58 Mon Sep 17 00:00:00 2001 From: Michael Tuexen Date: Fri, 17 Jul 2020 15:09:49 +0000 Subject: [PATCH 011/287] Improve the locking of address lists by adding some asserts and rearranging the addition of address such that the lock is not given up during checking and adding. MFC after: 1 week --- sys/netinet/sctp_lock_bsd.h | 7 ++++ sys/netinet/sctp_pcb.c | 64 ++++++++++++++++++++++++------------- sys/netinet/sctp_usrreq.c | 8 ++--- sys/netinet/sctputil.c | 7 ++-- 4 files changed, 55 insertions(+), 31 deletions(-) diff --git a/sys/netinet/sctp_lock_bsd.h b/sys/netinet/sctp_lock_bsd.h index 15596f8a7782..96fc335570cc 100644 --- a/sys/netinet/sctp_lock_bsd.h +++ b/sys/netinet/sctp_lock_bsd.h @@ -177,6 +177,13 @@ __FBSDID("$FreeBSD$"); rw_wunlock(&SCTP_BASE_INFO(ipi_addr_mtx)); \ } while (0) +#define SCTP_IPI_ADDR_LOCK_ASSERT() do { \ + rw_assert(&SCTP_BASE_INFO(ipi_addr_mtx), RA_LOCKED); \ +} while (0) + +#define SCTP_IPI_ADDR_WLOCK_ASSERT() do { \ + rw_assert(&SCTP_BASE_INFO(ipi_addr_mtx), RA_WLOCKED); \ +} while (0) #define SCTP_IPI_ITERATOR_WQ_INIT() do { \ mtx_init(&sctp_it_ctl.ipi_iterator_wq_mtx, "sctp-it-wq", \ diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index f20e15e8c84c..690295ca124c 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -200,6 +200,7 @@ sctp_find_ifn(void *ifn, uint32_t ifn_index) * We assume the lock is held for the addresses if that's wrong * problems could occur :-) */ + SCTP_IPI_ADDR_LOCK_ASSERT(); hash_ifn_head = &SCTP_BASE_INFO(vrf_ifn_hash)[(ifn_index & SCTP_BASE_INFO(vrf_ifn_hashmark))]; LIST_FOREACH(sctp_ifnp, hash_ifn_head, next_bucket) { if (sctp_ifnp->ifn_index == ifn_index) { @@ -295,12 +296,16 @@ sctp_delete_ifn(struct sctp_ifn *sctp_ifnp, int hold_addr_lock) /* Not in the list.. sorry */ return; } - if (hold_addr_lock == 0) + if (hold_addr_lock == 0) { SCTP_IPI_ADDR_WLOCK(); + } else { + SCTP_IPI_ADDR_WLOCK_ASSERT(); + } LIST_REMOVE(sctp_ifnp, next_bucket); LIST_REMOVE(sctp_ifnp, next_ifn); - if (hold_addr_lock == 0) + if (hold_addr_lock == 0) { SCTP_IPI_ADDR_WUNLOCK(); + } /* Take away the reference, and possibly free it */ sctp_free_ifn(sctp_ifnp); } @@ -486,8 +491,8 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, int dynamic_add) { struct sctp_vrf *vrf; - struct sctp_ifn *sctp_ifnp = NULL; - struct sctp_ifa *sctp_ifap = NULL; + struct sctp_ifn *sctp_ifnp, *new_sctp_ifnp; + struct sctp_ifa *sctp_ifap, *new_sctp_ifap; struct sctp_ifalist *hash_addr_head; struct sctp_ifnlist *hash_ifn_head; uint32_t hash_of_addr; @@ -497,6 +502,23 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, SCTPDBG(SCTP_DEBUG_PCB4, "vrf_id 0x%x: adding address: ", vrf_id); SCTPDBG_ADDR(SCTP_DEBUG_PCB4, addr); #endif + SCTP_MALLOC(new_sctp_ifnp, struct sctp_ifn *, + sizeof(struct sctp_ifn), SCTP_M_IFN); + if (new_sctp_ifnp == NULL) { +#ifdef INVARIANTS + panic("No memory for IFN"); +#endif + return (NULL); + } + SCTP_MALLOC(new_sctp_ifap, struct sctp_ifa *, sizeof(struct sctp_ifa), SCTP_M_IFA); + if (new_sctp_ifap == NULL) { +#ifdef INVARIANTS + panic("No memory for IFA"); +#endif + SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN); + return (NULL); + } + SCTP_IPI_ADDR_WLOCK(); sctp_ifnp = sctp_find_ifn(ifn, ifn_index); if (sctp_ifnp) { @@ -507,6 +529,8 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, vrf = sctp_allocate_vrf(vrf_id); if (vrf == NULL) { SCTP_IPI_ADDR_WUNLOCK(); + SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN); + SCTP_FREE(new_sctp_ifap, SCTP_M_IFA); return (NULL); } } @@ -516,15 +540,8 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, * build one and add it, can't hold lock until after malloc * done though. */ - SCTP_IPI_ADDR_WUNLOCK(); - SCTP_MALLOC(sctp_ifnp, struct sctp_ifn *, - sizeof(struct sctp_ifn), SCTP_M_IFN); - if (sctp_ifnp == NULL) { -#ifdef INVARIANTS - panic("No memory for IFN"); -#endif - return (NULL); - } + sctp_ifnp = new_sctp_ifnp; + new_sctp_ifnp = NULL; memset(sctp_ifnp, 0, sizeof(struct sctp_ifn)); sctp_ifnp->ifn_index = ifn_index; sctp_ifnp->ifn_p = ifn; @@ -540,7 +557,6 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, } hash_ifn_head = &SCTP_BASE_INFO(vrf_ifn_hash)[(ifn_index & SCTP_BASE_INFO(vrf_ifn_hashmark))]; LIST_INIT(&sctp_ifnp->ifalist); - SCTP_IPI_ADDR_WLOCK(); LIST_INSERT_HEAD(hash_ifn_head, sctp_ifnp, next_bucket); LIST_INSERT_HEAD(&vrf->ifnlist, sctp_ifnp, next_ifn); atomic_add_int(&SCTP_BASE_INFO(ipi_count_ifns), 1); @@ -567,6 +583,10 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, } exit_stage_left: SCTP_IPI_ADDR_WUNLOCK(); + if (new_sctp_ifnp != NULL) { + SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN); + } + SCTP_FREE(new_sctp_ifap, SCTP_M_IFA); return (sctp_ifap); } else { if (sctp_ifap->ifn_p) { @@ -593,14 +613,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, goto exit_stage_left; } } - SCTP_IPI_ADDR_WUNLOCK(); - SCTP_MALLOC(sctp_ifap, struct sctp_ifa *, sizeof(struct sctp_ifa), SCTP_M_IFA); - if (sctp_ifap == NULL) { -#ifdef INVARIANTS - panic("No memory for IFA"); -#endif - return (NULL); - } + sctp_ifap = new_sctp_ifap; memset(sctp_ifap, 0, sizeof(struct sctp_ifa)); sctp_ifap->ifn_p = sctp_ifnp; atomic_add_int(&sctp_ifnp->refcount, 1); @@ -660,7 +673,6 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, (sctp_ifap->src_is_loop == 0)) { sctp_ifap->src_is_glob = 1; } - SCTP_IPI_ADDR_WLOCK(); hash_addr_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)]; LIST_INSERT_HEAD(hash_addr_head, sctp_ifap, next_bucket); sctp_ifap->refcount = 1; @@ -672,6 +684,10 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, sctp_ifnp->registered_af = new_ifn_af; } SCTP_IPI_ADDR_WUNLOCK(); + if (new_sctp_ifnp != NULL) { + SCTP_FREE(new_sctp_ifnp, SCTP_M_IFN); + } + if (dynamic_add) { /* * Bump up the refcount so that when the timer completes it @@ -5906,6 +5922,7 @@ sctp_pcb_finish(void) * free the vrf/ifn/ifa lists and hashes (be sure address monitor is * destroyed first). */ + SCTP_IPI_ADDR_WLOCK(); vrf_bucket = &SCTP_BASE_INFO(sctp_vrfhash)[(SCTP_DEFAULT_VRFID & SCTP_BASE_INFO(hashvrfmark))]; LIST_FOREACH_SAFE(vrf, vrf_bucket, next_vrf, nvrf) { LIST_FOREACH_SAFE(ifn, &vrf->ifnlist, next_ifn, nifn) { @@ -5925,6 +5942,7 @@ sctp_pcb_finish(void) LIST_REMOVE(vrf, next_vrf); SCTP_FREE(vrf, SCTP_M_VRF); } + SCTP_IPI_ADDR_WUNLOCK(); /* free the vrf hashes */ SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_vrfhash), SCTP_BASE_INFO(hashvrfmark)); SCTP_HASH_FREE(SCTP_BASE_INFO(vrf_ifn_hash), SCTP_BASE_INFO(vrf_ifn_hashmark)); diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index f95bb2876c05..9d9320608fb4 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -1004,9 +1004,6 @@ sctp_fill_user_address(struct sockaddr *dst, struct sockaddr *src) -/* - * NOTE: assumes addr lock is held - */ static size_t sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, struct sctp_tcb *stcb, @@ -1026,6 +1023,7 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, #endif struct sctp_vrf *vrf; + SCTP_IPI_ADDR_LOCK_ASSERT(); actual = 0; if (limit == 0) return (actual); @@ -1258,9 +1256,6 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp, return (size); } -/* - * NOTE: assumes addr lock is held - */ static int sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) { @@ -1274,6 +1269,7 @@ sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) * bound-all case a TCB may NOT include the loopback or other * addresses as well. */ + SCTP_IPI_ADDR_LOCK_ASSERT(); vrf = sctp_find_vrf(vrf_id); if (vrf == NULL) { return (0); diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 8c8dcdd78ed2..5ef396cff246 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -5296,8 +5296,11 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock) struct sctp_ifalist *hash_head; uint32_t hash_of_addr; - if (holds_lock == 0) + if (holds_lock == 0) { SCTP_IPI_ADDR_RLOCK(); + } else { + SCTP_IPI_ADDR_LOCK_ASSERT(); + } vrf = sctp_find_vrf(vrf_id); if (vrf == NULL) { @@ -6429,7 +6432,7 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id) struct sctp_ifa *ifa; struct sctp_laddr *wi; - ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0); + ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED); if (ifa == NULL) { SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL); return (EADDRNOTAVAIL); From b8c46d561e33905d00acf44dd350206e0a818d4a Mon Sep 17 00:00:00 2001 From: Takanori Watanabe Date: Fri, 17 Jul 2020 15:50:03 +0000 Subject: [PATCH 012/287] Fix L2CAP ACL packet PB(Packet Boundary) flag for LE PDU. ACL packet boundary flag should be 0 instead of 2 for LE PDU. Some HCI will drop LE packet with PB flag is 2, and if sent, some target may reject the packet. PR: 248024 Reported by: Greg V Reviewed by: Greg V, emax Differential Revision: https://reviews.freebsd.org/D25704 --- sys/netgraph/bluetooth/include/ng_hci.h | 4 ++-- sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sys/netgraph/bluetooth/include/ng_hci.h b/sys/netgraph/bluetooth/include/ng_hci.h index 32a8f6597d00..fedd2d7696b7 100644 --- a/sys/netgraph/bluetooth/include/ng_hci.h +++ b/sys/netgraph/bluetooth/include/ng_hci.h @@ -393,10 +393,10 @@ (((h) & 0x0fff) | (((pb) & 3) << 12) | (((bc) & 3) << 14)) /* PB flag values */ - /* 00 - reserved for future use */ +#define NG_HCI_LE_PACKET_START 0x0 #define NG_HCI_PACKET_FRAGMENT 0x1 #define NG_HCI_PACKET_START 0x2 - /* 11 - reserved for future use */ + /* 11 for AMP packet, not supported */ /* BC flag values */ #define NG_HCI_POINT2POINT 0x0 /* only Host controller to Host */ diff --git a/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.c b/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.c index e77a0031b9ff..cf761af3f7c2 100644 --- a/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.c +++ b/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.c @@ -547,7 +547,7 @@ ng_l2cap_lp_send(ng_l2cap_con_p con, u_int16_t dcid, struct mbuf *m0) ng_l2cap_hdr_t *l2cap_hdr = NULL; ng_hci_acldata_pkt_t *acl_hdr = NULL; struct mbuf *m_last = NULL, *m = NULL; - int len, flag = NG_HCI_PACKET_START; + int len, flag = (con->linktype == NG_HCI_LINK_ACL) ? NG_HCI_PACKET_START : NG_HCI_LE_PACKET_START; KASSERT((con->tx_pkt == NULL), ("%s: %s - another packet pending?!\n", __func__, NG_NODE_NAME(l2cap->node))); @@ -713,7 +713,8 @@ ng_l2cap_lp_receive(ng_l2cap_p l2cap, struct mbuf *m) } /* Process packet */ - if (pb == NG_HCI_PACKET_START) { + if ((pb == NG_HCI_PACKET_START) || (pb == NG_HCI_LE_PACKET_START)) + { if (con->rx_pkt != NULL) { NG_L2CAP_ERR( "%s: %s - dropping incomplete L2CAP packet, got %d bytes, want %d bytes\n", From ce1c2aafce7f78e4f5a2722affc039ef38aa3ab9 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Fri, 17 Jul 2020 19:07:34 +0000 Subject: [PATCH 013/287] Only use the use_inet6 variable when INET6 is a build option. This is a prerequisite to upcoming argument processing cleanups which will resolve consistency as was done with ippool previously. PR: 247952 MFC after: 1 week --- contrib/ipfilter/tools/ipfstat.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/contrib/ipfilter/tools/ipfstat.c b/contrib/ipfilter/tools/ipfstat.c index e18eecaabe28..d37c46dd110a 100644 --- a/contrib/ipfilter/tools/ipfstat.c +++ b/contrib/ipfilter/tools/ipfstat.c @@ -57,7 +57,9 @@ static wordtab_t *state_fields = NULL; int nohdrfields = 0; int opts = 0; +#ifdef USE_INET6 int use_inet6 = 0; +#endif int live_kernel = 1; int state_fd = -1; int ipf_fd = -1; @@ -410,8 +412,13 @@ int main(argc,argv) #ifdef STATETOP else if (opts & OPT_STATETOP) topipstates(saddr, daddr, sport, dport, protocol, - use_inet6 ? 6 : 4, refreshtime, topclosed, filter); +#ifdef USE_INET6 + use_inet6 ? 6 : 4, +#else + 4, #endif +#endif + refreshtime, topclosed, filter); else if (opts & OPT_AUTHSTATS) showauthstates(frauthstp); else if (opts & OPT_GROUPS) @@ -904,10 +911,13 @@ static void printdeadlist(fiop, out, set, fp, group, comment) return; } fp = &fb; +#ifdef USE_INET6 if (use_inet6 != 0) { if (fp->fr_family != 0 && fp->fr_family != 6) continue; - } else { + } else +#endif + { if (fp->fr_family != 0 && fp->fr_family != 4) continue; } From 5317660176971eac99d07f4af30a83537ecdeea6 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Fri, 17 Jul 2020 19:07:37 +0000 Subject: [PATCH 014/287] fr_family (the protocol family) must be AF_INET or AF_INET6, as in the kernel, not an arbitrary 4 or 6. This only affected printing ipfilter stats and rules from a kernel dump. (This is currently undocumented.) PR: 247952 MFC after: 1 week --- contrib/ipfilter/tools/ipfstat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/ipfilter/tools/ipfstat.c b/contrib/ipfilter/tools/ipfstat.c index d37c46dd110a..64de48f11be9 100644 --- a/contrib/ipfilter/tools/ipfstat.c +++ b/contrib/ipfilter/tools/ipfstat.c @@ -913,12 +913,12 @@ static void printdeadlist(fiop, out, set, fp, group, comment) fp = &fb; #ifdef USE_INET6 if (use_inet6 != 0) { - if (fp->fr_family != 0 && fp->fr_family != 6) + if (fp->fr_family != 0 && fp->fr_family != AF_INET6) continue; } else #endif { - if (fp->fr_family != 0 && fp->fr_family != 4) + if (fp->fr_family != 0 && fp->fr_family != AF_INET) continue; } From 88b86bb0f3eb922e893837d83f1423e43e798517 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Fri, 17 Jul 2020 19:07:40 +0000 Subject: [PATCH 015/287] Historically ipfstat listings and stats only listed IPv4 or IPv6 output. ipfstat would list IPv4 outputs by default while -6 would produce IPv6 outputs. This commit combines the ipfstat -i and -o outputs into one listing of IPv4 and IPv6 rules. The -4 option lists only IPv4 rules (as the default before) while -6 continues to list only rules that affect IPv6. PR: 247952 Reported by: joeb1@a1poweruser.com MFC after: 1 week --- contrib/ipfilter/man/ipfstat.8 | 9 ++++-- contrib/ipfilter/tools/ipfstat.c | 51 ++++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/contrib/ipfilter/man/ipfstat.8 b/contrib/ipfilter/man/ipfstat.8 index e93f9d319336..63fb4a9cadb5 100644 --- a/contrib/ipfilter/man/ipfstat.8 +++ b/contrib/ipfilter/man/ipfstat.8 @@ -5,7 +5,7 @@ ipfstat \- reports on packet filter statistics and filter list .SH SYNOPSIS .B ipfstat [ -.B \-6aAdfghIilnoRsv +.B \-46aAdfghIilnoRsv ] .br .B ipfstat -t @@ -35,6 +35,11 @@ is to retrieve and display the accumulated statistics which have been accumulated over time as the kernel has put packets through the filter. .SH OPTIONS .TP +.B \-4 +Display filter lists and states for IPv4, if available. This is the default +when displaying states. \fB-4\fP and \fB-6\fP is the default when +displaying lists. +.TP .B \-6 Display filter lists and states for IPv6, if available. .TP @@ -190,4 +195,4 @@ more entries is to resize the screen. .SH SEE ALSO ipf(8) .SH BUGS -none known. +\fB-4\fP and \fB-6\fP should also be the default when displaying states. diff --git a/contrib/ipfilter/tools/ipfstat.c b/contrib/ipfilter/tools/ipfstat.c index 64de48f11be9..0e9d71fa67a9 100644 --- a/contrib/ipfilter/tools/ipfstat.c +++ b/contrib/ipfilter/tools/ipfstat.c @@ -58,6 +58,7 @@ static wordtab_t *state_fields = NULL; int nohdrfields = 0; int opts = 0; #ifdef USE_INET6 +int use_inet4 = 0; int use_inet6 = 0; #endif int live_kernel = 1; @@ -165,15 +166,15 @@ static void usage(name) char *name; { #ifdef USE_INET6 - fprintf(stderr, "Usage: %s [-6aAdfghIilnoRsv]\n", name); + fprintf(stderr, "Usage: %s [-46aAdfghIilnoRsv]\n", name); #else - fprintf(stderr, "Usage: %s [-aAdfghIilnoRsv]\n", name); + fprintf(stderr, "Usage: %s [-4aAdfghIilnoRsv]\n", name); #endif fprintf(stderr, " %s [-M corefile] [-N symbol-list]\n", name); #ifdef USE_INET6 - fprintf(stderr, " %s -t [-6C] ", name); + fprintf(stderr, " %s -t [-46C] ", name); #else - fprintf(stderr, " %s -t [-C] ", name); + fprintf(stderr, " %s -t [-4C] ", name); #endif fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n"); exit(1); @@ -208,9 +209,9 @@ int main(argc,argv) u_32_t frf; #ifdef USE_INET6 - options = "6aACdfghIilnostvD:m:M:N:O:P:RS:T:"; + options = "46aACdfghIilnostvD:m:M:N:O:P:RS:T:"; #else - options = "aACdfghIilnostvD:m:M:N:O:P:RS:T:"; + options = "4aACdfghIilnostvD:m:M:N:O:P:RS:T:"; #endif saddr.in4.s_addr = INADDR_ANY; /* default any v4 source addr */ @@ -285,6 +286,9 @@ int main(argc,argv) switch (c) { #ifdef USE_INET6 + case '4' : + use_inet4 = 1; + break; case '6' : use_inet6 = 1; break; @@ -387,6 +391,10 @@ int main(argc,argv) break; } } +#ifdef USE_INET6 + if (use_inet4 == 0 && use_inet6 == 0) + use_inet4 = use_inet6 = 1; +#endif if (live_kernel == 1) { bzero((char *)&fio, sizeof(fio)); @@ -413,7 +421,7 @@ int main(argc,argv) else if (opts & OPT_STATETOP) topipstates(saddr, daddr, sport, dport, protocol, #ifdef USE_INET6 - use_inet6 ? 6 : 4, + use_inet6 && !use_inet4 ? 6 : 4, #else 4, #endif @@ -812,15 +820,21 @@ printlivelist(fiop, out, set, fp, group, comment) if (rule.iri_rule == NULL) break; #ifdef USE_INET6 - if (use_inet6 != 0) { + if (use_inet6 != 0 && use_inet4 == 0) { if (fp->fr_family != 0 && fp->fr_family != AF_INET6) continue; - } else + } else if (use_inet4 != 0 && use_inet6 == 0) { #endif - { if (fp->fr_family != 0 && fp->fr_family != AF_INET) continue; +#ifdef USE_INET6 + } else { + if (fp->fr_family != 0 && + fp->fr_family != AF_INET && fp->fr_family != AF_INET6) + continue; } +#endif + if (fp->fr_data != NULL) fp->fr_data = (char *)fp + fp->fr_size; @@ -912,15 +926,20 @@ static void printdeadlist(fiop, out, set, fp, group, comment) } fp = &fb; #ifdef USE_INET6 - if (use_inet6 != 0) { + if (use_inet6 != 0 && use_inet4 == 0) { if (fp->fr_family != 0 && fp->fr_family != AF_INET6) continue; - } else + } else if (use_inet4 != 0 && use_inet6 == 0) { #endif - { if (fp->fr_family != 0 && fp->fr_family != AF_INET) continue; +#ifdef USE_INET6 + } else { + if (fp->fr_family != 0 && + fp->fr_family != AF_INET && fp->fr_family != AF_INET6) + continue; } +#endif data = NULL; type = fb.fr_type & ~FR_T_BUILTIN; @@ -1916,7 +1935,7 @@ static void parse_ipportstr(argument, ip, port) ok = 1; #ifdef USE_INET6 ip->in6 = in6addr_any; - } else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) { + } else if (use_inet6 && !use_inet4 && inet_pton(AF_INET6, s, &ip->in6)) { ok = 1; #endif } else if (inet_aton(s, &ip->in4)) @@ -2057,7 +2076,7 @@ static int sort_srcip(a, b) register const statetop_t *bp = b; #ifdef USE_INET6 - if (use_inet6) { + if (use_inet6 && !use_inet4) { if (IP6_EQ(&ap->st_src, &bp->st_src)) return 0; else if (IP6_GT(&ap->st_src, &bp->st_src)) @@ -2097,7 +2116,7 @@ static int sort_dstip(a, b) register const statetop_t *bp = b; #ifdef USE_INET6 - if (use_inet6) { + if (use_inet6 && !use_inet4) { if (IP6_EQ(&ap->st_dst, &bp->st_dst)) return 0; else if (IP6_GT(&ap->st_dst, &bp->st_dst)) From 08c24e2f886854e8eadb9a522a451fcc6a78480a Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Fri, 17 Jul 2020 19:07:44 +0000 Subject: [PATCH 016/287] ipfstat -t defaults to IPv4 output. Make consistent with ipfstat -i and ipfstat -o where without an argument IPv4 and IPv6 states are shown. Use -4 and -6 to limit the display to IPv4 or IPv6 respectively. PR: 247952 MFC after: 1 week --- contrib/ipfilter/man/ipfstat.8 | 3 ++- contrib/ipfilter/tools/ipfstat.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/contrib/ipfilter/man/ipfstat.8 b/contrib/ipfilter/man/ipfstat.8 index 63fb4a9cadb5..3762bccbdccf 100644 --- a/contrib/ipfilter/man/ipfstat.8 +++ b/contrib/ipfilter/man/ipfstat.8 @@ -195,4 +195,5 @@ more entries is to resize the screen. .SH SEE ALSO ipf(8) .SH BUGS -\fB-4\fP and \fB-6\fP should also be the default when displaying states. +\fB-4\fP and \fB-6\fP are only valid with \fB-i\fP, \fB-o\fP, and \fB-t\fP. +An error should result when used with other arguments. diff --git a/contrib/ipfilter/tools/ipfstat.c b/contrib/ipfilter/tools/ipfstat.c index 0e9d71fa67a9..43878f44d246 100644 --- a/contrib/ipfilter/tools/ipfstat.c +++ b/contrib/ipfilter/tools/ipfstat.c @@ -421,9 +421,9 @@ int main(argc,argv) else if (opts & OPT_STATETOP) topipstates(saddr, daddr, sport, dport, protocol, #ifdef USE_INET6 - use_inet6 && !use_inet4 ? 6 : 4, + use_inet6 && use_inet4 ? 0 : use_inet6 && !use_inet4 ? 6 : 4, #else - 4, + 4, #endif #endif refreshtime, topclosed, filter); @@ -1367,7 +1367,7 @@ static void topipstates(saddr, daddr, sport, dport, protocol, ver, if (ipsstp->iss_list == NULL) break; - if (ips.is_v != ver) + if (ver != 0 && ips.is_v != ver) continue; if ((filter != NULL) && From e082c89385d542a74b7e30a534d83297be1d9426 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Fri, 17 Jul 2020 19:07:47 +0000 Subject: [PATCH 017/287] Make ipfstat -t header generic when IPv4 and IPv6 output are displayed in the same display. PR: 247952 MFC after: 1 week --- contrib/ipfilter/tools/ipfstat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/ipfilter/tools/ipfstat.c b/contrib/ipfilter/tools/ipfstat.c index 43878f44d246..1d40dc67b413 100644 --- a/contrib/ipfilter/tools/ipfstat.c +++ b/contrib/ipfilter/tools/ipfstat.c @@ -1973,6 +1973,9 @@ static char *getip(v, addr) static char hostbuf[MAXHOSTNAMELEN+1]; #endif + if (v == 0) + return ("any"); + if (v == 4) return inet_ntoa(addr->in4); From ebdefe6cb43ce7573d86b13cbaad2d3fdbb9c6ff Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Fri, 17 Jul 2020 19:07:50 +0000 Subject: [PATCH 018/287] The output from usage() need not contain usage for -t when STATETOP is not compiled in. PR: 247952 MFC after: 1 week --- contrib/ipfilter/tools/ipfstat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/ipfilter/tools/ipfstat.c b/contrib/ipfilter/tools/ipfstat.c index 1d40dc67b413..c5bf68ccf90c 100644 --- a/contrib/ipfilter/tools/ipfstat.c +++ b/contrib/ipfilter/tools/ipfstat.c @@ -171,10 +171,12 @@ static void usage(name) fprintf(stderr, "Usage: %s [-4aAdfghIilnoRsv]\n", name); #endif fprintf(stderr, " %s [-M corefile] [-N symbol-list]\n", name); +#ifdef STATETOP #ifdef USE_INET6 fprintf(stderr, " %s -t [-46C] ", name); #else fprintf(stderr, " %s -t [-4C] ", name); +#endif #endif fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n"); exit(1); From 64a1886d5c466022cc4a4795fec6b869a43304d5 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Fri, 17 Jul 2020 19:07:53 +0000 Subject: [PATCH 019/287] -4 and -6 only make sense with -i, -o, and -t. PR: 247952 MFC after: 1 week --- contrib/ipfilter/tools/ipfstat.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/contrib/ipfilter/tools/ipfstat.c b/contrib/ipfilter/tools/ipfstat.c index c5bf68ccf90c..23ffb3832844 100644 --- a/contrib/ipfilter/tools/ipfstat.c +++ b/contrib/ipfilter/tools/ipfstat.c @@ -394,6 +394,15 @@ int main(argc,argv) } } #ifdef USE_INET6 + if ((use_inet4 || use_inet6) && + !(opts & (OPT_INQUE | OPT_OUTQUE | OPT_STATETOP))) { +#ifdef STATETOP + FPRINTF(stderr, "No -i, -o, or -t given with -4 or -6\n"); +#else + FPRINTF(stderr, "No -i or -o given with -4 or -6\n"); +#endif + exit(-2); + } if (use_inet4 == 0 && use_inet6 == 0) use_inet4 = use_inet6 = 1; #endif From 1b5e9f7d1ed62e6f399eb42714caa4b4d734a115 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Fri, 17 Jul 2020 19:07:56 +0000 Subject: [PATCH 020/287] pfil_run_hooks() can be called recursively, so we have to define FASTROUTE_RECURSION in fil.c Submitted by: christos@NetBSD.org Reported by: christos@NetBSD.org Obtained from: NetBSD r1.31 MFC after: 2 weeks --- sys/contrib/ipfilter/netinet/fil.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index add786ed25ca..57b154c069e0 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -115,6 +115,8 @@ extern int opts; extern int blockreason; #endif /* _KERNEL */ +#define FASTROUTE_RECURSION + #define LBUMP(x) softc->x++ #define LBUMPD(x, y) do { softc->x.y++; DT(y); } while (0) From 4fbd491ee3bfa7fcbb14f78768f543c80558548c Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Fri, 17 Jul 2020 19:07:59 +0000 Subject: [PATCH 021/287] Fix incorrect byte order in ipfstat -f output. - make sure frag is initialized to 0 - initialize ipfr_p field NetBSD PR: 55137 Submitted by: christos@NetBSD.org Reported by: christos@NetBSD.org Obtained from: NetBSD fil.c r1.32, ip_frag.c r1.8 MFC after: 2 weeks --- sys/contrib/ipfilter/netinet/fil.c | 2 +- sys/contrib/ipfilter/netinet/ip_frag.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index 57b154c069e0..03d50e0963a1 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -1698,7 +1698,7 @@ ipf_pr_ipv4hdr(fin) fi->fi_p = p; fin->fin_crc = p; fi->fi_tos = ip->ip_tos; - fin->fin_id = ip->ip_id; + fin->fin_id = ntohs(ip->ip_id); off = ntohs(ip->ip_off); /* Get both TTL and protocol */ diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c index f0459da18b03..28d306da2a60 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.c +++ b/sys/contrib/ipfilter/netinet/ip_frag.c @@ -404,6 +404,7 @@ ipfr_frag_new(softc, softf, fin, pass, table } } + memset(&frag, 0, sizeof(frag)); frag.ipfr_v = fin->fin_v; idx = fin->fin_v; frag.ipfr_p = fin->fin_p; @@ -452,6 +453,7 @@ ipfr_frag_new(softc, softf, fin, pass, table FBUMPD(ifs_nomem); return NULL; } + memset(fran, 0, sizeof(*fran)); WRITE_ENTER(lock); @@ -489,6 +491,7 @@ ipfr_frag_new(softc, softf, fin, pass, table table[idx] = fra; bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ); fra->ipfr_v = fin->fin_v; + fra->ipfr_p = fin->fin_p; fra->ipfr_ttl = softc->ipf_ticks + softf->ipfr_ttl; fra->ipfr_firstend = frag.ipfr_firstend; @@ -677,6 +680,7 @@ ipf_frag_lookup(softc, softf, fin, table * * build up a hash value to index the table with. */ + memset(&frag, 0, sizeof(frag)); frag.ipfr_v = fin->fin_v; idx = fin->fin_v; frag.ipfr_p = fin->fin_p; From f4cf731d1aed3c7f58075fb035db24b291a6ee4a Mon Sep 17 00:00:00 2001 From: Allan Jude Date: Fri, 17 Jul 2020 20:43:00 +0000 Subject: [PATCH 022/287] at(1): Fix location of at(1) crontab With r318443, atrun was moved from /etc/crontab to /etc/cron.d/at, but the man-page was unfortunately not updated to reflect this. PR: 248048 Submitted by: debdrup Reported by: yoitsmeremember+fbsd at gmail.com Reviewed by: Pau Amma Sponsored by: Klara Inc. Differential Revision: https://reviews.freebsd.org/D25709 --- usr.bin/at/at.man | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/usr.bin/at/at.man b/usr.bin/at/at.man index fc1d55bababd..88af9d7f1c19 100644 --- a/usr.bin/at/at.man +++ b/usr.bin/at/at.man @@ -213,9 +213,10 @@ every five minutes. This implies that the granularity of .Nm might not be optimal for every deployment. -If a finer granularity is needed, the system crontab at -.Pa /etc/crontab -needs to be changed. +If a finer granularity is desired, the +.Pa /etc/cron.d/at +file can be edited and will be read by the system crontab, from which +the SHELL and PATH environment variables are inherited. .Sh OPTIONS .Bl -tag -width indent .It Fl q Ar queue From 0550be02734047840bcda3a6f02913b5b5629d88 Mon Sep 17 00:00:00 2001 From: Gordon Bergling Date: Fri, 17 Jul 2020 21:47:06 +0000 Subject: [PATCH 023/287] iwm(4): Document limitations of the driver Document that iwm(4) currently doesn't support 802.11n and 802.11ac. PR: 247874 Submitted by: Charles Ross Reviewed by: brueffer, markj Approved by: brueffer MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25666 --- share/man/man4/iwm.4 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/share/man/man4/iwm.4 b/share/man/man4/iwm.4 index 3c75c60ebea9..2eddcbc83e2a 100644 --- a/share/man/man4/iwm.4 +++ b/share/man/man4/iwm.4 @@ -106,6 +106,12 @@ For more information on configuring this device, see This driver requires the firmware built with the .Nm iwmfw module to work. +.Pp +Currently, +.Nm +only supports 802.11b and 802.11g modes. +It will not associate to access points that are configured to operate only +in 802.11n or 802.11ac modes. .Sh EXAMPLES Join an existing BSS network (i.e., connect to an access point): .Bd -literal -offset indent From d511702b8ddc74bcf1255aee7ff426737a055068 Mon Sep 17 00:00:00 2001 From: Gordon Bergling Date: Fri, 17 Jul 2020 21:55:24 +0000 Subject: [PATCH 024/287] mount_nfs(8): document alternate form of the gssname option PR: 238506 Submitted by: Greg Veldman Reviewed by: 0mp, bcr (mentor) Approved by: bcr (mentor) MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25667 --- sbin/mount_nfs/mount_nfs.8 | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sbin/mount_nfs/mount_nfs.8 b/sbin/mount_nfs/mount_nfs.8 index 49ddb5276a50..f0949c5dfe02 100644 --- a/sbin/mount_nfs/mount_nfs.8 +++ b/sbin/mount_nfs/mount_nfs.8 @@ -159,7 +159,16 @@ should be specified without instance or domain and is typically .Dq "host" , .Dq "nfs" or -.Dq "root" . +.Dq "root" , +although the form +.Sm off +.Aq Ar service +@ +.Aq Ar fqdn +.Sm on +can also be used if the local system's +.Xr gethostname 3 +value does not match the host-based principal in the keytab. .It Cm hard Same as not specifying .Cm soft . From d8fd37e1e13483e5494e3bbb93b053134ab3c7b9 Mon Sep 17 00:00:00 2001 From: Gordon Bergling Date: Fri, 17 Jul 2020 22:15:02 +0000 Subject: [PATCH 025/287] devstat(9): Update the man page to reflect the current implementation - Rename devstat_add_entry to devstat_new_entry - Update the description of devstat_trans_flags - Add manpage aliases for devstat_start_transaction_bio and devstat_end_transaction_bio PR: 157316 Submitted by: novel Reviewed by: cem, bcr (mentor) Approved by: bcr (mentor) MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25677 --- ObsoleteFiles.inc | 3 +++ share/man/man9/Makefile | 6 ++++-- share/man/man9/devstat.9 | 41 ++++++++++++++++++++++------------------ 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 13689deea351..9e2baf525f22 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -36,6 +36,9 @@ # xargs -n1 | sort | uniq -d; # done +# 20200715: rework of devstat(9) man page +OLD_FILES+=usr/share/man/man9/devstat_add_entry.9.gz + # 20200714: update byacc to 20200330 OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_calc1.y OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_demo.y diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index 96a7c819eb18..c44805c01c9b 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -968,10 +968,12 @@ MLINKS+=device_set_desc.9 device_get_desc.9 \ device_set_desc.9 device_set_desc_copy.9 MLINKS+=device_set_flags.9 device_get_flags.9 MLINKS+=devstat.9 devicestat.9 \ - devstat.9 devstat_add_entry.9 \ + devstat.9 devstat_new_entry.9 \ devstat.9 devstat_end_transaction.9 \ + devstat.9 devstat_end_transaction_bio.9 \ devstat.9 devstat_remove_entry.9 \ - devstat.9 devstat_start_transaction.9 + devstat.9 devstat_start_transaction.9 \ + devstat.9 devstat_start_transaction_bio.9 MLINKS+=disk.9 disk_add_alias.9 \ disk.9 disk_alloc.9 \ disk.9 disk_create.9 \ diff --git a/share/man/man9/devstat.9 b/share/man/man9/devstat.9 index 51119bc6b62b..5025fba6c3e1 100644 --- a/share/man/man9/devstat.9 +++ b/share/man/man9/devstat.9 @@ -27,25 +27,24 @@ .\" .\" $FreeBSD$ .\" -.Dd August 22, 2018 +.Dd July 15, 2020 .Dt DEVSTAT 9 .Os .Sh NAME .Nm devstat , -.Nm devstat_add_entry , .Nm devstat_end_transaction , .Nm devstat_end_transaction_bio , .Nm devstat_end_transaction_bio_bt , +.Nm devstat_new_entry , .Nm devstat_remove_entry , .Nm devstat_start_transaction , .Nm devstat_start_transaction_bio .Nd kernel interface for keeping device statistics .Sh SYNOPSIS .In sys/devicestat.h -.Ft void -.Fo devstat_add_entry -.Fa "struct devstat *ds" -.Fa "const char *dev_name" +.Ft struct devstat * +.Fo devstat_new_entry +.Fa "const void *dev_name" .Fa "int unit_number" .Fa "uint32_t block_size" .Fa "devstat_support_flags flags" @@ -78,7 +77,6 @@ .Fa "struct devstat *ds" .Fa "const struct bio *bp" .Fc -.Fc .Ft void .Fo devstat_end_transaction_bio_bt .Fa "struct devstat *ds" @@ -103,19 +101,13 @@ for most disk-like drivers in the 2000s and beyond. New consumers of the interface should almost certainly use only the "bio" variants of the start and end transacation routines. .Pp -.Fn devstat_add_entry -registers a device with the -.Nm -subsystem. -The caller is expected to have already allocated \fBand zeroed\fR -the devstat structure before calling this function. -.Fn devstat_add_entry +.Fn devstat_new_entry +allocates and initializes +.Va devstat +structure and returns a pointer to it. +.Fn devstat_new_entry takes several arguments: .Bl -tag -width device_type -.It ds -The -.Va devstat -structure, allocated and zeroed by the client. .It dev_name The device name, e.g., da, cd, sa. .It unit_number @@ -386,6 +378,8 @@ to insert a device in the list. The second parameter is attach order. See below for a list of available priorities. +.It id +Identification for GEOM nodes. .El .Pp Each device is given a device type. @@ -478,8 +472,19 @@ typedef enum { DEVSTAT_WRITE = 0x02, DEVSTAT_FREE = 0x03 } devstat_trans_flags; +#define DEVSTAT_N_TRANS_FLAGS 4 .Ed .Pp +DEVSTAT_NO_DATA is a type of transactions to the device which are neither +reads or writes. +For instance, +.Tn SCSI +drivers often send a test unit ready command to +.Tn SCSI +devices. +The test unit ready command does not read or write any data. +It merely causes the device to return its status. +.Pp There are four possible values for the .Va tag_type argument to From b1dc29fa09052190e87f93cf1888edea9c42df24 Mon Sep 17 00:00:00 2001 From: Jung-uk Kim Date: Fri, 17 Jul 2020 22:53:36 +0000 Subject: [PATCH 026/287] Import ACPICA 20200717. --- changes.txt | 47 ++++++++++++++++++++++++++ source/compiler/aslerror.c | 2 +- source/compiler/aslexternal.c | 8 +++++ source/compiler/aslload.c | 10 +++--- source/compiler/aslmethod.c | 12 +++++++ source/compiler/aslxref.c | 4 ++- source/components/executer/exprep.c | 4 --- source/components/utilities/utdelete.c | 6 +--- source/components/utilities/utids.c | 2 +- source/include/acpixf.h | 2 +- source/include/actypes.h | 2 +- source/include/platform/acmsvc.h | 3 ++ 12 files changed, 83 insertions(+), 19 deletions(-) diff --git a/changes.txt b/changes.txt index 32d7d5648faa..a483f7ec92df 100644 --- a/changes.txt +++ b/changes.txt @@ -1,6 +1,53 @@ ---------------------------------------- +17 July 2020. Summary of changes for version 20200717: + +This release is available at https://acpica.org/downloads + + +1) ACPICA kernel-resident subsystem: + +Do not increment OperationRegion reference counts for field units. Recent +server firmware has revealed that this reference count can overflow on +large servers that declare many field units (thousands) under the same +OperationRegion. This occurs because each field unit declaration will add +a reference count to the source OperationRegion. This release solves the +reference count overflow for OperationRegion objects by preventing +fieldUnits from incrementing their parent OperationRegion's reference +count. + +Replaced one-element arrays with flexible-arrays, which were introduced +in C99. + +Restored the readme file containing the directions for generation of +ACPICA from source on MSVC 2017. Updated the file for MSVC 2017. File is +located at: generate/msvc2017/readme.txt + +2) iASL Compiler/Disassembler and ACPICA tools: + +iASL: Fixed a regression found in version 20200214. Prevent iASL from +emitting an extra byte of garbage data when control methods declared a +single parameter type without using braces. This extra byte is known to +cause a blue screen on the Windows AML interpreter. + +iASL: Made a change to allow external declarations to specify the type of +a named object even when some name segments are not defined. +This change allows the following ASL code to compile (When DEV0 is not +defined or not defined yet): + + External (\_SB.DEV0.OBJ1, IntObj) + External (\_SB.DEV0, DeviceObj) + +iASL: Fixed a problem where method names in "Alias ()" statement could be +misinterpreted. They are now interpreted correctly as method invocations. + +iASL: capture a method parameter count (Within the Method info segment, +as well as the argument node) when using parameter type lists. + +---------------------------------------- + + 28 May 2020. Summary of changes for version 20200528: diff --git a/source/compiler/aslerror.c b/source/compiler/aslerror.c index 8fae779d639e..150983429b3b 100644 --- a/source/compiler/aslerror.c +++ b/source/compiler/aslerror.c @@ -1056,7 +1056,7 @@ GetModifiedLevel ( UINT8 Level, UINT16 MessageId) { - UINT16 i; + UINT32 i; UINT16 ExceptionCode; diff --git a/source/compiler/aslexternal.c b/source/compiler/aslexternal.c index 315247be60f1..a05ba118df0d 100644 --- a/source/compiler/aslexternal.c +++ b/source/compiler/aslexternal.c @@ -200,6 +200,14 @@ ExDoExternal ( ExternType = AnMapObjTypeToBtype (ExternTypeOp); + if (ExternType != ACPI_BTYPE_METHOD) + { + /* + * If this is not a method, it has zero parameters this local variable + * is used only for methods + */ + ParamCount = 0; + } /* * The parser allows optional parameter return types regardless of the diff --git a/source/compiler/aslload.c b/source/compiler/aslload.c index bdc0d805e678..454fa8f5f0db 100644 --- a/source/compiler/aslload.c +++ b/source/compiler/aslload.c @@ -1177,13 +1177,13 @@ LdAnalyzeExternals ( * previously declared External */ Node->Flags &= ~ANOBJ_IS_EXTERNAL; - Node->Type = (UINT8) ExternalOpType; + Node->Type = (UINT8) ActualOpType; /* Just retyped a node, probably will need to open a scope */ - if (AcpiNsOpensScope (ExternalOpType)) + if (AcpiNsOpensScope (ActualOpType)) { - Status = AcpiDsScopeStackPush (Node, ExternalOpType, WalkState); + Status = AcpiDsScopeStackPush (Node, ActualOpType, WalkState); if (ACPI_FAILURE (Status)) { return (Status); @@ -1204,11 +1204,11 @@ LdAnalyzeExternals ( } else if ((Node->Flags & ANOBJ_IS_EXTERNAL) && (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) && - (ExternalOpType == ACPI_TYPE_ANY)) + (ActualOpType == ACPI_TYPE_ANY)) { /* Allow update of externals of unknown type. */ - Node->Type = (UINT8) ExternalOpType; + Node->Type = (UINT8) ActualExternalOpType; Status = AE_OK; } diff --git a/source/compiler/aslmethod.c b/source/compiler/aslmethod.c index ff6fd474193d..32b4b123f02e 100644 --- a/source/compiler/aslmethod.c +++ b/source/compiler/aslmethod.c @@ -306,6 +306,8 @@ MtMethodAnalysisWalkBegin ( { ActualArgs = MtProcessParameterTypeList (NextType, MethodInfo->ValidArgTypes); + MethodInfo->NumArguments = ActualArgs; + ArgNode->Asl.Value.Integer |= ActualArgs; } if ((MethodInfo->NumArguments) && @@ -671,6 +673,16 @@ MtProcessParameterTypeList ( UINT8 ParameterCount = 0; + if (ParamTypeOp && ParamTypeOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) + { + /* Special case for a single parameter without braces */ + + TypeList[ParameterCount] = + MtProcessTypeOp (ParamTypeOp); + + return (1); + } + while (ParamTypeOp) { TypeList[ParameterCount] = diff --git a/source/compiler/aslxref.c b/source/compiler/aslxref.c index 4bbbe2bd91ec..9306af200f50 100644 --- a/source/compiler/aslxref.c +++ b/source/compiler/aslxref.c @@ -994,12 +994,14 @@ XfNamespaceLocateBegin ( * invocation of the method, it is simply a reference to the method. * * September 2016: Removed DeRefOf from this list + * July 2020: Added Alias to this list */ if ((Op->Asl.Parent) && ((Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_REFOF) || (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_PACKAGE) || (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)|| - (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_OBJECTTYPE))) + (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_OBJECTTYPE) || + (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_ALIAS))) { return_ACPI_STATUS (AE_OK); } diff --git a/source/components/executer/exprep.c b/source/components/executer/exprep.c index 6ceac68f549d..3074366d9a67 100644 --- a/source/components/executer/exprep.c +++ b/source/components/executer/exprep.c @@ -651,10 +651,6 @@ AcpiExPrepFieldValue ( } } - /* An additional reference for the container */ - - AcpiUtAddReference (ObjDesc->Field.RegionObj); - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n", ObjDesc->Field.StartFieldBitOffset, diff --git a/source/components/utilities/utdelete.c b/source/components/utilities/utdelete.c index 502ff4132116..aafd52959379 100644 --- a/source/components/utilities/utdelete.c +++ b/source/components/utilities/utdelete.c @@ -749,11 +749,6 @@ AcpiUtUpdateObjectReference ( NextObject = Object->BufferField.BufferObj; break; - case ACPI_TYPE_LOCAL_REGION_FIELD: - - NextObject = Object->Field.RegionObj; - break; - case ACPI_TYPE_LOCAL_BANK_FIELD: NextObject = Object->BankField.BankObj; @@ -789,6 +784,7 @@ AcpiUtUpdateObjectReference ( } break; + case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_REGION: default: diff --git a/source/components/utilities/utids.c b/source/components/utilities/utids.c index e296c00a0bea..34ae697ab3c2 100644 --- a/source/components/utilities/utids.c +++ b/source/components/utilities/utids.c @@ -435,7 +435,7 @@ AcpiUtExecute_CID ( * 3) Size of the actual CID strings */ CidListSize = sizeof (ACPI_PNP_DEVICE_ID_LIST) + - ((Count - 1) * sizeof (ACPI_PNP_DEVICE_ID)) + + (Count * sizeof (ACPI_PNP_DEVICE_ID)) + StringAreaSize; CidList = ACPI_ALLOCATE_ZEROED (CidListSize); diff --git a/source/include/acpixf.h b/source/include/acpixf.h index 2eafdeac6ee1..c1b55401a360 100644 --- a/source/include/acpixf.h +++ b/source/include/acpixf.h @@ -154,7 +154,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20200528 +#define ACPI_CA_VERSION 0x20200717 #include "acconfig.h" #include "actypes.h" diff --git a/source/include/actypes.h b/source/include/actypes.h index 2666ebfbd323..0ec14a36ada9 100644 --- a/source/include/actypes.h +++ b/source/include/actypes.h @@ -1379,7 +1379,7 @@ typedef struct acpi_pnp_device_id_list { UINT32 Count; /* Number of IDs in Ids array */ UINT32 ListSize; /* Size of list, including ID strings */ - ACPI_PNP_DEVICE_ID Ids[1]; /* ID array */ + ACPI_PNP_DEVICE_ID Ids[]; /* ID array */ } ACPI_PNP_DEVICE_ID_LIST; diff --git a/source/include/platform/acmsvc.h b/source/include/platform/acmsvc.h index a003f9fe7ed8..e1a2b51e0731 100644 --- a/source/include/platform/acmsvc.h +++ b/source/include/platform/acmsvc.h @@ -275,6 +275,9 @@ /* warn C4131: uses old-style declarator (iASL compiler only) */ #pragma warning(disable:4459) +/* warn c4200: allow flexible arrays (of zero length) */ +#pragma warning(disable:4200) + #if _MSC_VER > 1200 /* Versions above VC++ 6 */ #pragma warning( disable : 4295 ) /* needed for acpredef.h array */ #endif From c3dbadc1fdab52b37f4b5c840dbfa028295413b3 Mon Sep 17 00:00:00 2001 From: Chuck Silvers Date: Fri, 17 Jul 2020 23:08:01 +0000 Subject: [PATCH 027/287] Revert my change from r361855 in favor of a better fix. Reviewed by: markj, kib Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D25430 --- sys/vm/vnode_pager.c | 46 +++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index 7233b90c1059..0f3ea7300654 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -1150,30 +1150,28 @@ vnode_pager_generic_getpages_done(struct buf *bp) if (mt == bogus_page) continue; - if (error == 0) { - if (nextoff <= object->un_pager.vnp.vnp_size) { - /* - * Read filled up entire page. - */ - vm_page_valid(mt); - KASSERT(mt->dirty == 0, - ("%s: page %p is dirty", __func__, mt)); - KASSERT(!pmap_page_is_mapped(mt), - ("%s: page %p is mapped", __func__, mt)); - } else { - /* - * Read did not fill up entire page. - * - * Currently we do not set the entire page - * valid, we just try to clear the piece that - * we couldn't read. - */ - vm_page_set_valid_range(mt, 0, - object->un_pager.vnp.vnp_size - tfoff); - KASSERT((mt->dirty & vm_page_bits(0, - object->un_pager.vnp.vnp_size - tfoff)) == - 0, ("%s: page %p is dirty", __func__, mt)); - } + if (nextoff <= object->un_pager.vnp.vnp_size) { + /* + * Read filled up entire page. + */ + vm_page_valid(mt); + KASSERT(mt->dirty == 0, + ("%s: page %p is dirty", __func__, mt)); + KASSERT(!pmap_page_is_mapped(mt), + ("%s: page %p is mapped", __func__, mt)); + } else { + /* + * Read did not fill up entire page. + * + * Currently we do not set the entire page valid, + * we just try to clear the piece that we couldn't + * read. + */ + vm_page_set_valid_range(mt, 0, + object->un_pager.vnp.vnp_size - tfoff); + KASSERT((mt->dirty & vm_page_bits(0, + object->un_pager.vnp.vnp_size - tfoff)) == 0, + ("%s: page %p is dirty", __func__, mt)); } if (i < bp->b_pgbefore || i >= bp->b_npages - bp->b_pgafter) From 4dfa06e114ed4332f8ea3b86f9963f475714da1e Mon Sep 17 00:00:00 2001 From: Chuck Silvers Date: Fri, 17 Jul 2020 23:09:36 +0000 Subject: [PATCH 028/287] Add a new function vm_page_free_invalid() for freeing invalid pages that might be wired. If the page is wired then it cannot be freed now, but the thread that eventually unwires it will free it at that point. Reviewed by: markj, kib Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D25430 --- sys/vm/vm_page.c | 25 +++++++++++++++++++++++++ sys/vm/vm_page.h | 1 + 2 files changed, 26 insertions(+) diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index 08420d5da19e..a7d6f3dd9d64 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -1361,6 +1361,31 @@ vm_page_readahead_finish(vm_page_t m) vm_page_xunbusy_unchecked(m); } +/* + * Destroy the identity of an invalid page and free it if possible. + * This is intended to be used when reading a page from backing store fails. + */ +void +vm_page_free_invalid(vm_page_t m) +{ + + KASSERT(vm_page_none_valid(m), ("page %p is valid", m)); + KASSERT(!pmap_page_is_mapped(m), ("page %p is mapped", m)); + vm_page_assert_xbusied(m); + KASSERT(m->object != NULL, ("page %p has no object", m)); + VM_OBJECT_ASSERT_WLOCKED(m->object); + + /* + * If someone has wired this page while the object lock + * was not held, then the thread that unwires is responsible + * for freeing the page. Otherwise just free the page now. + * The wire count of this unmapped page cannot change while + * we have the page xbusy and the page's object wlocked. + */ + if (vm_page_remove(m)) + vm_page_free(m); +} + /* * vm_page_sleep_if_busy: * diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index 2ed6840bfece..4a073cec8e51 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -629,6 +629,7 @@ void vm_page_deactivate_noreuse(vm_page_t); void vm_page_dequeue(vm_page_t m); void vm_page_dequeue_deferred(vm_page_t m); vm_page_t vm_page_find_least(vm_object_t, vm_pindex_t); +void vm_page_free_invalid(vm_page_t); vm_page_t vm_page_getfake(vm_paddr_t paddr, vm_memattr_t memattr); void vm_page_initfake(vm_page_t m, vm_paddr_t paddr, vm_memattr_t memattr); int vm_page_insert (vm_page_t, vm_object_t, vm_pindex_t); From 1bd12a3bb2be72a7d360402f489000dd337f6f3b Mon Sep 17 00:00:00 2001 From: Chuck Silvers Date: Fri, 17 Jul 2020 23:10:35 +0000 Subject: [PATCH 029/287] Fix vnode_pager handling of read ahead/behind pages when a disk read fails. Rather than marking the read ahead/behind pages valid even though they were not initialized, free them using the new function vm_page_free_invalid(). Reviewed by: markj, kib Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D25430 --- sys/vm/vnode_pager.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index 0f3ea7300654..fa9f4cab16f9 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -1139,6 +1139,21 @@ vnode_pager_generic_getpages_done(struct buf *bp) bp->b_data = unmapped_buf; } + /* + * If the read failed, we must free any read ahead/behind pages here. + * The requested pages are freed by the caller (for sync requests) + * or by the bp->b_pgiodone callback (for async requests). + */ + if (error != 0) { + VM_OBJECT_WLOCK(object); + for (i = 0; i < bp->b_pgbefore; i++) + vm_page_free_invalid(bp->b_pages[i]); + for (i = bp->b_npages - bp->b_pgafter; i < bp->b_npages; i++) + vm_page_free_invalid(bp->b_pages[i]); + VM_OBJECT_WUNLOCK(object); + return (error); + } + /* Read lock to protect size. */ VM_OBJECT_RLOCK(object); for (i = 0, tfoff = IDX_TO_OFF(bp->b_pages[0]->pindex); From 7cd4443fb1c7396367c74421289fec7cd60ddfbd Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 18 Jul 2020 00:14:43 +0000 Subject: [PATCH 030/287] Short-circuit tdfind when looking for the calling thread. Common occurence with cpuset and other places. --- sys/kern/kern_thread.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index 46b410a85362..8216c31ef0c0 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -1299,6 +1299,14 @@ tdfind(lwpid_t tid, pid_t pid) struct thread *td; int run = 0; + td = curthread; + if (td->td_tid == tid) { + if (pid != -1 && td->td_proc->p_pid != pid) + return (NULL); + PROC_LOCK(td->td_proc); + return (td); + } + rw_rlock(&tidhash_lock); LIST_FOREACH(td, TIDHASH(tid), td_hash) { if (td->td_tid == tid) { From 8ba7dddd6f30c9fedfcafd54401ecc7637489b23 Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sat, 18 Jul 2020 10:49:17 +0000 Subject: [PATCH 031/287] Fix two typos in flag names in /proc/cpuinfo. MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25695 --- sys/compat/linprocfs/linprocfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index c3d7eafd9492..b9ef6be31586 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -235,10 +235,10 @@ linprocfs_docpuinfo(PFS_FILL_ARGS) }; static char *cpu_feature2_names[] = { - /* 0 */ "pni", "pclmulqdq", "dtes3", "monitor", + /* 0 */ "pni", "pclmulqdq", "dtes64", "monitor", /* 4 */ "ds_cpl", "vmx", "smx", "est", /* 8 */ "tm2", "ssse3", "cid", "sdbg", - /* 12 */ "fma", "cx16", "xptr", "pdcm", + /* 12 */ "fma", "cx16", "xtpr", "pdcm", /* 16 */ "", "pcid", "dca", "sse4_1", /* 20 */ "sse4_2", "x2apic", "movbe", "popcnt", /* 24 */ "tsc_deadline_timer", "aes", "xsave", "", From 7ce051e799154623fe1fce2e5004f3fb0b92acaa Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sat, 18 Jul 2020 10:53:56 +0000 Subject: [PATCH 032/287] Fix bogomips calculation. Previously it was off by half. This was verified under VMWare Fusion, comparing to what's reported under CentOS, and by comparing numbers reported by linuxulator on T420 with a googled up Linux cpuinfo (https://lkml.org/lkml/2011/11/29/116). MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D20693 --- sys/compat/linprocfs/linprocfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index b9ef6be31586..e36914732f8d 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -364,7 +364,7 @@ linprocfs_docpuinfo(PFS_FILL_ARGS) #else "", #endif - fqmhz, fqkhz, + fqmhz * 2, fqkhz, cpu_clflush_line_size, cpu_clflush_line_size, cpu_maxphyaddr, (cpu_maxphyaddr > 32) ? 48 : 0); From 978ffef22f6fe6e56b3705921b6458211cb19a9e Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sat, 18 Jul 2020 10:56:04 +0000 Subject: [PATCH 033/287] Add missing SysV IPC stats to linprocfs(4). Fixes 'ipcs -l', and also helps Oracle. MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25669 --- sys/compat/linprocfs/linprocfs.c | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index e36914732f8d..2dd9b43ac017 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -1404,6 +1405,17 @@ linprocfs_doosbuild(PFS_FILL_ARGS) return (0); } +/* + * Filler function for proc/sys/kernel/msgmax + */ +static int +linprocfs_domsgmax(PFS_FILL_ARGS) +{ + + sbuf_printf(sb, "%d\n", msginfo.msgmax); + return (0); +} + /* * Filler function for proc/sys/kernel/msgmni */ @@ -1415,6 +1427,17 @@ linprocfs_domsgmni(PFS_FILL_ARGS) return (0); } +/* + * Filler function for proc/sys/kernel/msgmnb + */ +static int +linprocfs_domsgmnb(PFS_FILL_ARGS) +{ + + sbuf_printf(sb, "%d\n", msginfo.msgmnb); + return (0); +} + /* * Filler function for proc/sys/kernel/pid_max */ @@ -1438,6 +1461,39 @@ linprocfs_dosem(PFS_FILL_ARGS) return (0); } +/* + * Filler function for proc/sys/kernel/shmall + */ +static int +linprocfs_doshmall(PFS_FILL_ARGS) +{ + + sbuf_printf(sb, "%lu\n", shminfo.shmall); + return (0); +} + +/* + * Filler function for proc/sys/kernel/shmmax + */ +static int +linprocfs_doshmmax(PFS_FILL_ARGS) +{ + + sbuf_printf(sb, "%lu\n", shminfo.shmmax); + return (0); +} + +/* + * Filler function for proc/sys/kernel/shmmni + */ +static int +linprocfs_doshmmni(PFS_FILL_ARGS) +{ + + sbuf_printf(sb, "%lu\n", shminfo.shmmni); + return (0); +} + /* * Filler function for proc/sys/kernel/tainted */ @@ -1837,6 +1893,7 @@ linprocfs_init(PFS_INIT_ARGS) /* /proc/sys/... */ sys = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); + /* /proc/sys/kernel/... */ dir = pfs_create_dir(sys, "kernel", NULL, NULL, NULL, 0); pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, @@ -1845,12 +1902,22 @@ linprocfs_init(PFS_INIT_ARGS) NULL, NULL, NULL, PFS_RD); pfs_create_file(dir, "version", &linprocfs_doosbuild, NULL, NULL, NULL, PFS_RD); + pfs_create_file(dir, "msgmax", &linprocfs_domsgmax, + NULL, NULL, NULL, PFS_RD); pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, NULL, NULL, NULL, PFS_RD); + pfs_create_file(dir, "msgmnb", &linprocfs_domsgmnb, + NULL, NULL, NULL, PFS_RD); pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, NULL, NULL, NULL, PFS_RD); pfs_create_file(dir, "sem", &linprocfs_dosem, NULL, NULL, NULL, PFS_RD); + pfs_create_file(dir, "shmall", &linprocfs_doshmall, + NULL, NULL, NULL, PFS_RD); + pfs_create_file(dir, "shmmax", &linprocfs_doshmmax, + NULL, NULL, NULL, PFS_RD); + pfs_create_file(dir, "shmmni", &linprocfs_doshmmni, + NULL, NULL, NULL, PFS_RD); pfs_create_file(dir, "tainted", &linprocfs_dotainted, NULL, NULL, NULL, PFS_RD); @@ -1887,3 +1954,4 @@ MODULE_DEPEND(linprocfs, linux, 1, 1, 1); MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); +MODULE_DEPEND(linprocfs, sysvshm, 1, 1, 1); From 8d1d01717552c3384e9cf02b7b0daf79ac734bfd Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sat, 18 Jul 2020 11:28:40 +0000 Subject: [PATCH 034/287] Add a trivial linux(4) splice(2) implementation, which simply returns EINVAL. Fixes grep (grep-3.1-2build1). PR: kern/218699 Reported by: avos Reviewed by: emaste MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25636 --- sys/amd64/linux/linux_dummy.c | 1 - sys/amd64/linux/syscalls.master | 9 ++++++++- sys/amd64/linux32/linux32_dummy.c | 1 - sys/amd64/linux32/syscalls.master | 9 ++++++++- sys/arm64/linux/linux_dummy.c | 1 - sys/arm64/linux/syscalls.master | 9 ++++++++- sys/compat/linux/linux_file.c | 14 ++++++++++++++ sys/i386/linux/linux_dummy.c | 1 - sys/i386/linux/syscalls.master | 9 ++++++++- 9 files changed, 46 insertions(+), 8 deletions(-) diff --git a/sys/amd64/linux/linux_dummy.c b/sys/amd64/linux/linux_dummy.c index 0e8c39b993b3..d8bd0d997244 100644 --- a/sys/amd64/linux/linux_dummy.c +++ b/sys/amd64/linux/linux_dummy.c @@ -105,7 +105,6 @@ DUMMY(inotify_rm_watch); DUMMY(migrate_pages); DUMMY(unshare); /* Linux 2.6.17: */ -DUMMY(splice); DUMMY(tee); DUMMY(vmsplice); /* Linux 2.6.18: */ diff --git a/sys/amd64/linux/syscalls.master b/sys/amd64/linux/syscalls.master index 91da10676669..e7dfd77a522b 100644 --- a/sys/amd64/linux/syscalls.master +++ b/sys/amd64/linux/syscalls.master @@ -1612,7 +1612,14 @@ ); } 275 AUE_NULL STD { - int linux_splice(void); + int linux_splice( + int fd_in, + l_loff_t *off_in, + int fd_out, + l_loff_t *off_out, + l_size_t len, + l_uint flags + ); } 276 AUE_NULL STD { int linux_tee(void); diff --git a/sys/amd64/linux32/linux32_dummy.c b/sys/amd64/linux32/linux32_dummy.c index 98037ad09b4a..7cf7cb593b8d 100644 --- a/sys/amd64/linux32/linux32_dummy.c +++ b/sys/amd64/linux32/linux32_dummy.c @@ -102,7 +102,6 @@ DUMMY(inotify_rm_watch); DUMMY(migrate_pages); DUMMY(unshare); /* Linux 2.6.17: */ -DUMMY(splice); DUMMY(tee); DUMMY(vmsplice); /* Linux 2.6.18: */ diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master index fa10fbfb9369..97d448f8d9c3 100644 --- a/sys/amd64/linux32/syscalls.master +++ b/sys/amd64/linux32/syscalls.master @@ -1731,7 +1731,14 @@ ); } 313 AUE_NULL STD { - int linux_splice(void); + int linux_splice( + int fd_in, + l_loff_t *off_in, + int fd_out, + l_loff_t *off_out, + l_size_t len, + l_uint flags + ); } 314 AUE_NULL STD { int linux_sync_file_range( diff --git a/sys/arm64/linux/linux_dummy.c b/sys/arm64/linux/linux_dummy.c index bbae98f919a9..ad56a0eec4e9 100644 --- a/sys/arm64/linux/linux_dummy.c +++ b/sys/arm64/linux/linux_dummy.c @@ -98,7 +98,6 @@ DUMMY(inotify_rm_watch); DUMMY(migrate_pages); DUMMY(unshare); /* Linux 2.6.17: */ -DUMMY(splice); DUMMY(tee); DUMMY(vmsplice); /* Linux 2.6.18: */ diff --git a/sys/arm64/linux/syscalls.master b/sys/arm64/linux/syscalls.master index 9a259c02ad45..81d888e44492 100644 --- a/sys/arm64/linux/syscalls.master +++ b/sys/arm64/linux/syscalls.master @@ -467,7 +467,14 @@ int linux_vmsplice(void); } 76 AUE_NULL STD { - int linux_splice(void); + int linux_splice( + int fd_in, + l_loff_t *off_in, + int fd_out, + l_loff_t *off_out, + l_size_t len, + l_uint flags + ); } 77 AUE_NULL STD { int linux_tee(void); diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 377e0ef4d34a..3267bf2313ef 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -1766,3 +1766,17 @@ linux_memfd_create(struct thread *td, struct linux_memfd_create_args *args) return (kern_shm_open2(td, SHM_ANON, oflags, 0, shmflags, NULL, memfd_name)); } + +int +linux_splice(struct thread *td, struct linux_splice_args *args) +{ + + linux_msg(td, "syscall splice not really implemented"); + + /* + * splice(2) is documented to return EINVAL in various circumstances; + * returning it instead of ENOSYS should hint the caller to use fallback + * instead. + */ + return (EINVAL); +} diff --git a/sys/i386/linux/linux_dummy.c b/sys/i386/linux/linux_dummy.c index b014f9e38561..3ede71769f12 100644 --- a/sys/i386/linux/linux_dummy.c +++ b/sys/i386/linux/linux_dummy.c @@ -98,7 +98,6 @@ DUMMY(inotify_rm_watch); DUMMY(migrate_pages); DUMMY(unshare); /* Linux 2.6.17: */ -DUMMY(splice); DUMMY(tee); DUMMY(vmsplice); /* Linux 2.6.18: */ diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master index 1c7deecd8b58..7f7c124d2d14 100644 --- a/sys/i386/linux/syscalls.master +++ b/sys/i386/linux/syscalls.master @@ -1753,7 +1753,14 @@ ); } 313 AUE_NULL STD { - int linux_splice(void); + int linux_splice( + int fd_in, + l_loff_t *off_in, + int fd_out, + l_loff_t *off_out, + l_size_t len, + l_uint flags + ); } 314 AUE_NULL STD { int linux_sync_file_range( From 3e9a214260493ec4dca3292bb1ac13125b18b2b0 Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sat, 18 Jul 2020 11:31:31 +0000 Subject: [PATCH 035/287] Regen after r363304. MFC after: 2 weeks Sponsored by: The FreeBSD Foundation --- sys/amd64/linux/linux_proto.h | 7 ++++- sys/amd64/linux/linux_sysent.c | 2 +- sys/amd64/linux/linux_systrace_args.c | 34 ++++++++++++++++++++++- sys/amd64/linux32/linux32_proto.h | 7 ++++- sys/amd64/linux32/linux32_sysent.c | 2 +- sys/amd64/linux32/linux32_systrace_args.c | 34 ++++++++++++++++++++++- sys/arm64/linux/linux_proto.h | 7 ++++- sys/arm64/linux/linux_sysent.c | 2 +- sys/arm64/linux/linux_systrace_args.c | 34 ++++++++++++++++++++++- sys/i386/linux/linux_proto.h | 7 ++++- sys/i386/linux/linux_sysent.c | 2 +- sys/i386/linux/linux_systrace_args.c | 34 ++++++++++++++++++++++- 12 files changed, 160 insertions(+), 12 deletions(-) diff --git a/sys/amd64/linux/linux_proto.h b/sys/amd64/linux/linux_proto.h index 24829c6e7a9b..b4cff9bfbcdd 100644 --- a/sys/amd64/linux/linux_proto.h +++ b/sys/amd64/linux/linux_proto.h @@ -1010,7 +1010,12 @@ struct linux_get_robust_list_args { char len_l_[PADL_(l_size_t *)]; l_size_t * len; char len_r_[PADR_(l_size_t *)]; }; struct linux_splice_args { - register_t dummy; + char fd_in_l_[PADL_(int)]; int fd_in; char fd_in_r_[PADR_(int)]; + char off_in_l_[PADL_(l_loff_t *)]; l_loff_t * off_in; char off_in_r_[PADR_(l_loff_t *)]; + char fd_out_l_[PADL_(int)]; int fd_out; char fd_out_r_[PADR_(int)]; + char off_out_l_[PADL_(l_loff_t *)]; l_loff_t * off_out; char off_out_r_[PADR_(l_loff_t *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_tee_args { register_t dummy; diff --git a/sys/amd64/linux/linux_sysent.c b/sys/amd64/linux/linux_sysent.c index 70e778f89176..4ef3158fb9be 100644 --- a/sys/amd64/linux/linux_sysent.c +++ b/sys/amd64/linux/linux_sysent.c @@ -292,7 +292,7 @@ struct sysent linux_sysent[] = { { 0, (sy_call_t *)linux_unshare, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 272 = linux_unshare */ { AS(linux_set_robust_list_args), (sy_call_t *)linux_set_robust_list, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 273 = linux_set_robust_list */ { AS(linux_get_robust_list_args), (sy_call_t *)linux_get_robust_list, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 274 = linux_get_robust_list */ - { 0, (sy_call_t *)linux_splice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 275 = linux_splice */ + { AS(linux_splice_args), (sy_call_t *)linux_splice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 275 = linux_splice */ { 0, (sy_call_t *)linux_tee, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 276 = linux_tee */ { AS(linux_sync_file_range_args), (sy_call_t *)linux_sync_file_range, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 277 = linux_sync_file_range */ { 0, (sy_call_t *)linux_vmsplice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 278 = linux_vmsplice */ diff --git a/sys/amd64/linux/linux_systrace_args.c b/sys/amd64/linux/linux_systrace_args.c index e6d052b034e4..4203723ff99f 100644 --- a/sys/amd64/linux/linux_systrace_args.c +++ b/sys/amd64/linux/linux_systrace_args.c @@ -2092,7 +2092,14 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) } /* linux_splice */ case 275: { - *n_args = 0; + struct linux_splice_args *p = params; + iarg[0] = p->fd_in; /* int */ + uarg[1] = (intptr_t) p->off_in; /* l_loff_t * */ + iarg[2] = p->fd_out; /* int */ + uarg[3] = (intptr_t) p->off_out; /* l_loff_t * */ + iarg[4] = p->len; /* l_size_t */ + iarg[5] = p->flags; /* l_uint */ + *n_args = 6; break; } /* linux_tee */ @@ -5962,6 +5969,28 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; /* linux_splice */ case 275: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland l_loff_t *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "userland l_loff_t *"; + break; + case 4: + p = "l_size_t"; + break; + case 5: + p = "l_uint"; + break; + default: + break; + }; break; /* linux_tee */ case 276: @@ -8008,6 +8037,9 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; /* linux_splice */ case 275: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_tee */ case 276: /* linux_sync_file_range */ diff --git a/sys/amd64/linux32/linux32_proto.h b/sys/amd64/linux32/linux32_proto.h index 57dc8dc6a1f6..948cf582c681 100644 --- a/sys/amd64/linux32/linux32_proto.h +++ b/sys/amd64/linux32/linux32_proto.h @@ -1082,7 +1082,12 @@ struct linux_get_robust_list_args { char len_l_[PADL_(l_size_t *)]; l_size_t * len; char len_r_[PADR_(l_size_t *)]; }; struct linux_splice_args { - register_t dummy; + char fd_in_l_[PADL_(int)]; int fd_in; char fd_in_r_[PADR_(int)]; + char off_in_l_[PADL_(l_loff_t *)]; l_loff_t * off_in; char off_in_r_[PADR_(l_loff_t *)]; + char fd_out_l_[PADL_(int)]; int fd_out; char fd_out_r_[PADR_(int)]; + char off_out_l_[PADL_(l_loff_t *)]; l_loff_t * off_out; char off_out_r_[PADR_(l_loff_t *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_sync_file_range_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; diff --git a/sys/amd64/linux32/linux32_sysent.c b/sys/amd64/linux32/linux32_sysent.c index 00810a657814..dbf9460eae62 100644 --- a/sys/amd64/linux32/linux32_sysent.c +++ b/sys/amd64/linux32/linux32_sysent.c @@ -330,7 +330,7 @@ struct sysent linux32_sysent[] = { { 0, (sy_call_t *)linux_unshare, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 310 = linux_unshare */ { AS(linux_set_robust_list_args), (sy_call_t *)linux_set_robust_list, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 311 = linux_set_robust_list */ { AS(linux_get_robust_list_args), (sy_call_t *)linux_get_robust_list, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 312 = linux_get_robust_list */ - { 0, (sy_call_t *)linux_splice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 313 = linux_splice */ + { AS(linux_splice_args), (sy_call_t *)linux_splice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 313 = linux_splice */ { AS(linux_sync_file_range_args), (sy_call_t *)linux_sync_file_range, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 314 = linux_sync_file_range */ { 0, (sy_call_t *)linux_tee, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 315 = linux_tee */ { 0, (sy_call_t *)linux_vmsplice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 316 = linux_vmsplice */ diff --git a/sys/amd64/linux32/linux32_systrace_args.c b/sys/amd64/linux32/linux32_systrace_args.c index b5efde458733..9913fe8fcc75 100644 --- a/sys/amd64/linux32/linux32_systrace_args.c +++ b/sys/amd64/linux32/linux32_systrace_args.c @@ -2215,7 +2215,14 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) } /* linux_splice */ case 313: { - *n_args = 0; + struct linux_splice_args *p = params; + iarg[0] = p->fd_in; /* int */ + uarg[1] = (intptr_t) p->off_in; /* l_loff_t * */ + iarg[2] = p->fd_out; /* int */ + uarg[3] = (intptr_t) p->off_out; /* l_loff_t * */ + iarg[4] = p->len; /* l_size_t */ + iarg[5] = p->flags; /* l_uint */ + *n_args = 6; break; } /* linux_sync_file_range */ @@ -6590,6 +6597,28 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; /* linux_splice */ case 313: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland l_loff_t *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "userland l_loff_t *"; + break; + case 4: + p = "l_size_t"; + break; + case 5: + p = "l_uint"; + break; + default: + break; + }; break; /* linux_sync_file_range */ case 314: @@ -9184,6 +9213,9 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; /* linux_splice */ case 313: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_sync_file_range */ case 314: if (ndx == 0 || ndx == 1) diff --git a/sys/arm64/linux/linux_proto.h b/sys/arm64/linux/linux_proto.h index feb23d059b6c..c913f9a436eb 100644 --- a/sys/arm64/linux/linux_proto.h +++ b/sys/arm64/linux/linux_proto.h @@ -322,7 +322,12 @@ struct linux_vmsplice_args { register_t dummy; }; struct linux_splice_args { - register_t dummy; + char fd_in_l_[PADL_(int)]; int fd_in; char fd_in_r_[PADR_(int)]; + char off_in_l_[PADL_(l_loff_t *)]; l_loff_t * off_in; char off_in_r_[PADR_(l_loff_t *)]; + char fd_out_l_[PADL_(int)]; int fd_out; char fd_out_r_[PADR_(int)]; + char off_out_l_[PADL_(l_loff_t *)]; l_loff_t * off_out; char off_out_r_[PADR_(l_loff_t *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_tee_args { register_t dummy; diff --git a/sys/arm64/linux/linux_sysent.c b/sys/arm64/linux/linux_sysent.c index b7ca80cfeda9..1e8d5a195919 100644 --- a/sys/arm64/linux/linux_sysent.c +++ b/sys/arm64/linux/linux_sysent.c @@ -93,7 +93,7 @@ struct sysent linux_sysent[] = { { AS(linux_ppoll_args), (sy_call_t *)linux_ppoll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 73 = linux_ppoll */ { 0, (sy_call_t *)linux_signalfd4, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 74 = linux_signalfd4 */ { 0, (sy_call_t *)linux_vmsplice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 75 = linux_vmsplice */ - { 0, (sy_call_t *)linux_splice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 76 = linux_splice */ + { AS(linux_splice_args), (sy_call_t *)linux_splice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 76 = linux_splice */ { 0, (sy_call_t *)linux_tee, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 77 = linux_tee */ { AS(linux_readlinkat_args), (sy_call_t *)linux_readlinkat, AUE_READLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 78 = linux_readlinkat */ { AS(linux_newfstatat_args), (sy_call_t *)linux_newfstatat, AUE_FSTATAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 79 = linux_newfstatat */ diff --git a/sys/arm64/linux/linux_systrace_args.c b/sys/arm64/linux/linux_systrace_args.c index 3bb994e71792..636307c1c1fe 100644 --- a/sys/arm64/linux/linux_systrace_args.c +++ b/sys/arm64/linux/linux_systrace_args.c @@ -599,7 +599,14 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) } /* linux_splice */ case 76: { - *n_args = 0; + struct linux_splice_args *p = params; + iarg[0] = p->fd_in; /* int */ + uarg[1] = (intptr_t) p->off_in; /* l_loff_t * */ + iarg[2] = p->fd_out; /* int */ + uarg[3] = (intptr_t) p->off_out; /* l_loff_t * */ + iarg[4] = p->len; /* l_size_t */ + iarg[5] = p->flags; /* l_uint */ + *n_args = 6; break; } /* linux_tee */ @@ -3207,6 +3214,28 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; /* linux_splice */ case 76: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland l_loff_t *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "userland l_loff_t *"; + break; + case 4: + p = "l_size_t"; + break; + case 5: + p = "l_uint"; + break; + default: + break; + }; break; /* linux_tee */ case 77: @@ -6139,6 +6168,9 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) case 75: /* linux_splice */ case 76: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_tee */ case 77: /* linux_readlinkat */ diff --git a/sys/i386/linux/linux_proto.h b/sys/i386/linux/linux_proto.h index ae69e02b0985..5a546f071a05 100644 --- a/sys/i386/linux/linux_proto.h +++ b/sys/i386/linux/linux_proto.h @@ -1079,7 +1079,12 @@ struct linux_get_robust_list_args { char len_l_[PADL_(l_size_t *)]; l_size_t * len; char len_r_[PADR_(l_size_t *)]; }; struct linux_splice_args { - register_t dummy; + char fd_in_l_[PADL_(int)]; int fd_in; char fd_in_r_[PADR_(int)]; + char off_in_l_[PADL_(l_loff_t *)]; l_loff_t * off_in; char off_in_r_[PADR_(l_loff_t *)]; + char fd_out_l_[PADL_(int)]; int fd_out; char fd_out_r_[PADR_(int)]; + char off_out_l_[PADL_(l_loff_t *)]; l_loff_t * off_out; char off_out_r_[PADR_(l_loff_t *)]; + char len_l_[PADL_(l_size_t)]; l_size_t len; char len_r_[PADR_(l_size_t)]; + char flags_l_[PADL_(l_uint)]; l_uint flags; char flags_r_[PADR_(l_uint)]; }; struct linux_sync_file_range_args { char fd_l_[PADL_(l_int)]; l_int fd; char fd_r_[PADR_(l_int)]; diff --git a/sys/i386/linux/linux_sysent.c b/sys/i386/linux/linux_sysent.c index 54ac4939f3b1..800cd3479b4f 100644 --- a/sys/i386/linux/linux_sysent.c +++ b/sys/i386/linux/linux_sysent.c @@ -330,7 +330,7 @@ struct sysent linux_sysent[] = { { 0, (sy_call_t *)linux_unshare, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 310 = linux_unshare */ { AS(linux_set_robust_list_args), (sy_call_t *)linux_set_robust_list, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 311 = linux_set_robust_list */ { AS(linux_get_robust_list_args), (sy_call_t *)linux_get_robust_list, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 312 = linux_get_robust_list */ - { 0, (sy_call_t *)linux_splice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 313 = linux_splice */ + { AS(linux_splice_args), (sy_call_t *)linux_splice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 313 = linux_splice */ { AS(linux_sync_file_range_args), (sy_call_t *)linux_sync_file_range, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 314 = linux_sync_file_range */ { 0, (sy_call_t *)linux_tee, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 315 = linux_tee */ { 0, (sy_call_t *)linux_vmsplice, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 316 = linux_vmsplice */ diff --git a/sys/i386/linux/linux_systrace_args.c b/sys/i386/linux/linux_systrace_args.c index fb79951eb98d..be5af662345e 100644 --- a/sys/i386/linux/linux_systrace_args.c +++ b/sys/i386/linux/linux_systrace_args.c @@ -2258,7 +2258,14 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) } /* linux_splice */ case 313: { - *n_args = 0; + struct linux_splice_args *p = params; + iarg[0] = p->fd_in; /* int */ + uarg[1] = (intptr_t) p->off_in; /* l_loff_t * */ + iarg[2] = p->fd_out; /* int */ + uarg[3] = (intptr_t) p->off_out; /* l_loff_t * */ + iarg[4] = p->len; /* l_size_t */ + iarg[5] = p->flags; /* l_uint */ + *n_args = 6; break; } /* linux_sync_file_range */ @@ -6679,6 +6686,28 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; /* linux_splice */ case 313: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland l_loff_t *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "userland l_loff_t *"; + break; + case 4: + p = "l_size_t"; + break; + case 5: + p = "l_uint"; + break; + default: + break; + }; break; /* linux_sync_file_range */ case 314: @@ -9290,6 +9319,9 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; /* linux_splice */ case 313: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_sync_file_range */ case 314: if (ndx == 0 || ndx == 1) From eb6ae7576dfda167400715bcdfca3397f8896357 Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sat, 18 Jul 2020 11:37:30 +0000 Subject: [PATCH 036/287] Bump the default linux version from 3.2.0 to 3.10.0, which corresponds to RHEL 7. Required for DB2. Reviewed by: emaste MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25656 --- sys/compat/linux/linux_mib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/compat/linux/linux_mib.h b/sys/compat/linux/linux_mib.h index 385ba2ab390f..8606e995bd76 100644 --- a/sys/compat/linux/linux_mib.h +++ b/sys/compat/linux/linux_mib.h @@ -47,7 +47,7 @@ int linux_get_oss_version(struct thread *td); int linux_kernver(struct thread *td); #define LINUX_KVERSION 3 -#define LINUX_KPATCHLEVEL 2 +#define LINUX_KPATCHLEVEL 10 #define LINUX_KSUBLEVEL 0 #define LINUX_KERNVER(a,b,c) (((a) << 16) + ((b) << 8) + (c)) From d5c5b4b382e3b6e3549287e313a0020162a0e686 Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sat, 18 Jul 2020 12:21:08 +0000 Subject: [PATCH 037/287] Make linux fallocate(2) return EOPNOTSUPP, not ENOSYS, on unsupported mode, as documented in the man page. MFC after: 2 weeks Sponsored by: The FreeBSD Foundation --- sys/compat/linux/linux_file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 3267bf2313ef..ba3a86b8b919 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -1670,7 +1670,7 @@ linux_fallocate(struct thread *td, struct linux_fallocate_args *args) * mode should be 0. */ if (args->mode != 0) - return (ENOSYS); + return (EOPNOTSUPP); #if defined(__amd64__) && defined(COMPAT_LINUX32) len = PAIR32TO64(off_t, args->len); From 93ed6ade6ecf8417b81e30f01e4cff4cbc1b71a1 Mon Sep 17 00:00:00 2001 From: Kristof Provost Date: Sat, 18 Jul 2020 12:43:11 +0000 Subject: [PATCH 038/287] bridge: Don't sleep during epoch While it doesn't trigger INVARIANTS or WITNESS on head it does in stable/12. There's also no reason for it, as we can easily report the out of memory error to the caller (i.e. userspace). All of these can already fail. PR: 248046 MFC after: 3 days --- sys/net/if_bridge.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 19d8d8964d92..51ee9d299067 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1393,9 +1393,9 @@ bridge_ioctl_gifs(struct bridge_softc *sc, void *arg) bifc->ifbic_len = buflen; return (0); } - BRIDGE_UNLOCK(sc); - outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); - BRIDGE_LOCK(sc); + outbuf = malloc(buflen, M_TEMP, M_NOWAIT | M_ZERO); + if (outbuf == NULL) + return (ENOMEM); count = 0; buf = outbuf; @@ -1455,9 +1455,9 @@ bridge_ioctl_rts(struct bridge_softc *sc, void *arg) count++; buflen = sizeof(bareq) * count; - BRIDGE_UNLOCK(sc); - outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); - BRIDGE_LOCK(sc); + outbuf = malloc(buflen, M_TEMP, M_NOWAIT | M_ZERO); + if (outbuf == NULL) + return (ENOMEM); count = 0; buf = outbuf; @@ -1783,9 +1783,9 @@ bridge_ioctl_gifsstp(struct bridge_softc *sc, void *arg) return (0); } - BRIDGE_UNLOCK(sc); - outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); - BRIDGE_LOCK(sc); + outbuf = malloc(buflen, M_TEMP, M_NOWAIT | M_ZERO); + if (outbuf == NULL) + return (ENOMEM); count = 0; buf = outbuf; From 05bceec68e9c7ccb04c17f529bdb63dd3e2db428 Mon Sep 17 00:00:00 2001 From: Michael Tuexen Date: Sat, 18 Jul 2020 13:10:02 +0000 Subject: [PATCH 039/287] Remove code which is not needed. MFC after: 1 week --- sys/netinet/sctp_pcb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 690295ca124c..719e80c171aa 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -3593,9 +3593,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) */ if (from != SCTP_CALLED_FROM_INPKILL_TIMER) { (void)SCTP_OS_TIMER_STOP_DRAIN(&inp->sctp_ep.signature_change.timer); - } else { - /* Probably un-needed */ - (void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.signature_change.timer); } #ifdef SCTP_LOG_CLOSING From 08e99af305e7c3d2f6aa426049a476f8806f2272 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Sat, 18 Jul 2020 13:10:31 +0000 Subject: [PATCH 040/287] o Move iommu_test_boundary() to sys/iommu.h o Rename DMAR -> IOMMU in comments o Add IOMMU_PAGE_SIZE / IOMMU_PAGE_MASK macroses o x86 only: dmar_quirks_pre_use() / dmar_instantiate_rmrr_ctxs() Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25665 --- sys/sys/iommu.h | 13 +++++++++++++ sys/x86/iommu/busdma_dmar.c | 26 ++++++++++++++++---------- sys/x86/iommu/intel_dmar.h | 11 ----------- sys/x86/iommu/intel_drv.c | 2 +- sys/x86/iommu/intel_gas.c | 9 +++++---- sys/x86/iommu/intel_reg.h | 3 +++ 6 files changed, 38 insertions(+), 26 deletions(-) diff --git a/sys/sys/iommu.h b/sys/sys/iommu.h index f2f1828a7d24..8d039c2dee09 100644 --- a/sys/sys/iommu.h +++ b/sys/sys/iommu.h @@ -35,6 +35,7 @@ #define _SYS_IOMMU_H_ #include +#include #include #include @@ -43,6 +44,7 @@ typedef uint64_t iommu_haddr_t; /* Guest or bus address, before translation. */ typedef uint64_t iommu_gaddr_t; +struct bus_dma_tag_common; struct iommu_map_entry; TAILQ_HEAD(iommu_map_entries_tailq, iommu_map_entry); @@ -102,6 +104,7 @@ struct iommu_domain { struct iommu_unit *iommu; /* (c) */ struct mtx lock; /* (c) */ struct task unload_task; /* (c) */ + u_int entries_cnt; /* (d) */ struct iommu_map_entries_tailq unload_entries; /* (d) Entries to unload */ }; @@ -129,6 +132,16 @@ struct iommu_ctx { #define IOMMU_DOMAIN_UNLOCK(dom) mtx_unlock(&(dom)->lock) #define IOMMU_DOMAIN_ASSERT_LOCKED(dom) mtx_assert(&(dom)->lock, MA_OWNED) +static inline bool +iommu_test_boundary(iommu_gaddr_t start, iommu_gaddr_t size, + iommu_gaddr_t boundary) +{ + + if (boundary == 0) + return (true); + return (start + size <= ((start + boundary) & ~(boundary - 1))); +} + void iommu_free_ctx(struct iommu_ctx *ctx); void iommu_free_ctx_locked(struct iommu_unit *iommu, struct iommu_ctx *ctx); struct iommu_ctx *iommu_get_ctx(struct iommu_unit *, device_t dev, diff --git a/sys/x86/iommu/busdma_dmar.c b/sys/x86/iommu/busdma_dmar.c index 1ddac4522611..6b9d3be49b1b 100644 --- a/sys/x86/iommu/busdma_dmar.c +++ b/sys/x86/iommu/busdma_dmar.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -62,11 +63,13 @@ __FBSDID("$FreeBSD$"); #include #include #include +#if defined(__amd64__) || defined(__i386__) #include #include #include #include #include +#endif /* * busdma_dmar.c, the implementation of the busdma(9) interface using @@ -112,11 +115,11 @@ iommu_bus_dma_is_dev_disabled(int domain, int bus, int slot, int func) /* * Given original device, find the requester ID that will be seen by - * the DMAR unit and used for page table lookup. PCI bridges may take + * the IOMMU unit and used for page table lookup. PCI bridges may take * ownership of transactions from downstream devices, so it may not be * the same as the BSF of the target device. In those cases, all * devices downstream of the bridge must share a single mapping - * domain, and must collectively be assigned to use either DMAR or + * domain, and must collectively be assigned to use either IOMMU or * bounce mapping. */ device_t @@ -135,7 +138,7 @@ iommu_get_requester(device_t dev, uint16_t *rid) /* * Walk the bridge hierarchy from the target device to the - * host port to find the translating bridge nearest the DMAR + * host port to find the translating bridge nearest the IOMMU * unit. */ for (;;) { @@ -173,7 +176,7 @@ iommu_get_requester(device_t dev, uint16_t *rid) } else { /* * Device is not PCIe, it cannot be seen as a - * requester by DMAR unit. Check whether the + * requester by IOMMU unit. Check whether the * bridge is PCIe. */ bridge_is_pcie = pci_find_cap(pcib, PCIY_EXPRESS, @@ -243,8 +246,8 @@ iommu_instantiate_ctx(struct iommu_unit *unit, device_t dev, bool rmrr) /* * If the user requested the IOMMU disabled for the device, we - * cannot disable the DMAR, due to possibility of other - * devices on the same DMAR still requiring translation. + * cannot disable the IOMMU unit, due to possibility of other + * devices on the same IOMMU unit still requiring translation. * Instead provide the identity mapping for the device * context. */ @@ -279,13 +282,16 @@ acpi_iommu_get_dma_tag(device_t dev, device_t child) bus_dma_tag_t res; unit = iommu_find(child, bootverbose); - /* Not in scope of any DMAR ? */ + /* Not in scope of any IOMMU ? */ if (unit == NULL) return (NULL); if (!unit->dma_enabled) return (NULL); + +#if defined(__amd64__) || defined(__i386__) dmar_quirks_pre_use(unit); dmar_instantiate_rmrr_ctxs(unit); +#endif ctx = iommu_instantiate_ctx(unit, child, false); res = ctx == NULL ? NULL : (bus_dma_tag_t)ctx->tag; @@ -536,7 +542,7 @@ iommu_bus_dmamap_load_something1(struct bus_dma_tag_iommu *tag, bus_size_t buflen1; int error, idx, gas_flags, seg; - KASSERT(offset < DMAR_PAGE_SIZE, ("offset %d", offset)); + KASSERT(offset < IOMMU_PAGE_SIZE, ("offset %d", offset)); if (segs == NULL) segs = tag->segments; ctx = tag->ctx; @@ -621,7 +627,7 @@ iommu_bus_dmamap_load_something1(struct bus_dma_tag_iommu *tag, idx += OFF_TO_IDX(trunc_page(offset + buflen1)); offset += buflen1; - offset &= DMAR_PAGE_MASK; + offset &= IOMMU_PAGE_MASK; buflen -= buflen1; } if (error == 0) @@ -841,7 +847,7 @@ iommu_bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map1, } /* - * The limitations of busdma KPI forces the dmar to perform the actual + * The limitations of busdma KPI forces the iommu to perform the actual * unload, consisting of the unmapping of the map entries page tables, * from the delayed context on i386, since page table page mapping * might require a sleep to be successfull. The unfortunate diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h index b5e1c6828ae8..cd9639c00b64 100644 --- a/sys/x86/iommu/intel_dmar.h +++ b/sys/x86/iommu/intel_dmar.h @@ -77,7 +77,6 @@ struct dmar_domain { LIST_HEAD(, dmar_ctx) contexts; /* (u) */ vm_object_t pgtbl_obj; /* (c) Page table pages */ u_int flags; /* (u) */ - u_int entries_cnt; /* (d) */ struct dmar_gas_entries_tree rb_root; /* (d) */ struct iommu_map_entry *first_place, *last_place; /* (d) */ u_int batch_no; @@ -460,16 +459,6 @@ dmar_pte_clear(volatile uint64_t *dst) #endif } -static inline bool -iommu_test_boundary(iommu_gaddr_t start, iommu_gaddr_t size, - iommu_gaddr_t boundary) -{ - - if (boundary == 0) - return (true); - return (start + size <= ((start + boundary) & ~(boundary - 1))); -} - extern struct timespec dmar_hw_timeout; #define DMAR_WAIT_UNTIL(cond) \ diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c index 952369794429..6f1771fd9090 100644 --- a/sys/x86/iommu/intel_drv.c +++ b/sys/x86/iommu/intel_drv.c @@ -1160,7 +1160,7 @@ dmar_print_domain(struct dmar_domain *domain, bool show_mappings) " ctx_cnt %d flags %x pgobj %p map_ents %u\n", domain, domain->domain, domain->mgaw, domain->agaw, domain->pglvl, (uintmax_t)domain->end, domain->refs, domain->ctx_cnt, - domain->flags, domain->pgtbl_obj, domain->entries_cnt); + domain->flags, domain->pgtbl_obj, domain->iodom.entries_cnt); if (!LIST_EMPTY(&domain->contexts)) { db_printf(" Contexts:\n"); LIST_FOREACH(ctx, &domain->contexts, link) diff --git a/sys/x86/iommu/intel_gas.c b/sys/x86/iommu/intel_gas.c index fc52885c224c..2ddddf77ad59 100644 --- a/sys/x86/iommu/intel_gas.c +++ b/sys/x86/iommu/intel_gas.c @@ -98,7 +98,7 @@ dmar_gas_alloc_entry(struct dmar_domain *domain, u_int flags) 0 ? M_WAITOK : M_NOWAIT) | M_ZERO); if (res != NULL) { res->domain = (struct iommu_domain *)domain; - atomic_add_int(&domain->entries_cnt, 1); + atomic_add_int(&domain->iodom.entries_cnt, 1); } return (res); } @@ -110,7 +110,7 @@ dmar_gas_free_entry(struct dmar_domain *domain, struct iommu_map_entry *entry) KASSERT(domain == (struct dmar_domain *)entry->domain, ("mismatched free domain %p entry %p entry->domain %p", domain, entry, entry->domain)); - atomic_subtract_int(&domain->entries_cnt, 1); + atomic_subtract_int(&domain->iodom.entries_cnt, 1); uma_zfree(iommu_map_entry_zone, entry); } @@ -214,7 +214,7 @@ dmar_gas_init_domain(struct dmar_domain *domain) end = dmar_gas_alloc_entry(domain, DMAR_PGF_WAITOK); DMAR_DOMAIN_LOCK(domain); - KASSERT(domain->entries_cnt == 2, ("dirty domain %p", domain)); + KASSERT(domain->iodom.entries_cnt == 2, ("dirty domain %p", domain)); KASSERT(RB_EMPTY(&domain->rb_root), ("non-empty entries %p", domain)); begin->start = 0; @@ -239,7 +239,8 @@ dmar_gas_fini_domain(struct dmar_domain *domain) struct iommu_map_entry *entry, *entry1; DMAR_DOMAIN_ASSERT_LOCKED(domain); - KASSERT(domain->entries_cnt == 2, ("domain still in use %p", domain)); + KASSERT(domain->iodom.entries_cnt == 2, + ("domain still in use %p", domain)); entry = RB_MIN(dmar_gas_entries_tree, &domain->rb_root); KASSERT(entry->start == 0, ("start entry start %p", domain)); diff --git a/sys/x86/iommu/intel_reg.h b/sys/x86/iommu/intel_reg.h index bc522ec732dd..e7ab4c7ccd1b 100644 --- a/sys/x86/iommu/intel_reg.h +++ b/sys/x86/iommu/intel_reg.h @@ -41,6 +41,9 @@ #define DMAR_NPTEPGSHIFT 9 #define DMAR_PTEMASK (DMAR_NPTEPG - 1) +#define IOMMU_PAGE_SIZE DMAR_PAGE_SIZE +#define IOMMU_PAGE_MASK DMAR_PAGE_MASK + typedef struct dmar_root_entry { uint64_t r1; uint64_t r2; From 3ec7e1695c7db1a892a57b29dff9d2b12c7baa13 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Sat, 18 Jul 2020 18:19:57 +0000 Subject: [PATCH 041/287] amd64 pmap: microoptimize local shootdowns for PCID PTI configurations When pmap operates in PTI mode, we must reload %cr3 on return to userspace. In non-PCID mode the reload always flushes all non-global TLB entries and we take advantage of it by only invalidating the KPT TLB entries (there is no cached UPT entries at all). In PCID mode, we flush both KPT and UPT TLB explicitly, but we can take advantage of the fact that PCID mode command to reload %cr3 includes a flag to flush/not flush target TLB. In particular, we can avoid the flush for UPT, instead record that load of pc_ucr3 into %cr3 on return to usermode should be flushing. This is done by providing either all-1s or ~CR3_PCID_MASK in pc_ucr3_load_mask. The mask is automatically reset to all-1s on return to usermode. Similarly, we can avoid flushing UPT TLB on context switch, replacing it by setting pc_ucr3_load_mask. This unifies INVPCID and non-INVPCID PTI ifunc, leaving only 4 cases instead of 6. This trick is also applicable both to the TLB shootdown IPI handlers, since handlers interrupt the target thread. But then we need to check pc_curpmap in handlers, and this would reopen the same race for INVPCID machines as was fixed in r306350 for non-INVPCID. To not introduce the same bug, unconditionally do spinlock_enter() in pmap_activate(). Reviewed by: alc, markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 3 weeks Differential revision: https://reviews.freebsd.org/D25483 --- sys/amd64/amd64/exception.S | 5 ++ sys/amd64/amd64/genassym.c | 1 + sys/amd64/amd64/machdep.c | 1 + sys/amd64/amd64/mp_machdep.c | 32 ++++---- sys/amd64/amd64/pmap.c | 151 +++++++++++++---------------------- sys/amd64/include/pcpu.h | 3 +- sys/amd64/include/pmap.h | 1 + 7 files changed, 84 insertions(+), 110 deletions(-) diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S index a005c3b70591..b85471b93169 100644 --- a/sys/amd64/amd64/exception.S +++ b/sys/amd64/amd64/exception.S @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef KDTRACE_HOOKS .bss @@ -607,8 +608,10 @@ fast_syscall_common: cmpq $~0,PCPU(UCR3) je 2f movq PCPU(UCR3),%r9 + andq PCPU(UCR3_LOAD_MASK),%r9 movq %r9,%cr3 2: xorl %r9d,%r9d + movq $PMAP_UCR3_NOMASK,PCPU(UCR3_LOAD_MASK) swapgs sysretq @@ -1262,6 +1265,8 @@ ld_regs: movq TF_SS(%rsp),%rax movq %rax,PTI_SS(%rdx) movq PCPU(UCR3),%rax + andq PCPU(UCR3_LOAD_MASK),%rax + movq $PMAP_UCR3_NOMASK,PCPU(UCR3_LOAD_MASK) swapgs movq %rdx,%rsp movq %rax,%cr3 diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index 78b18001e97b..ec3707ce41f9 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -230,6 +230,7 @@ ASSYM(PC_TSS, offsetof(struct pcpu, pc_tss)); ASSYM(PC_PM_SAVE_CNT, offsetof(struct pcpu, pc_pm_save_cnt)); ASSYM(PC_KCR3, offsetof(struct pcpu, pc_kcr3)); ASSYM(PC_UCR3, offsetof(struct pcpu, pc_ucr3)); +ASSYM(PC_UCR3_LOAD_MASK, offsetof(struct pcpu, pc_ucr3_load_mask)); ASSYM(PC_SAVED_UCR3, offsetof(struct pcpu, pc_saved_ucr3)); ASSYM(PC_PTI_STACK, offsetof(struct pcpu, pc_pti_stack)); ASSYM(PC_PTI_STACK_SZ, PC_PTI_STACK_SZ); diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 1a07080c5daf..294cd8100d3b 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -1562,6 +1562,7 @@ amd64_bsp_pcpu_init1(struct pcpu *pc) PCPU_SET(ldt, (struct system_segment_descriptor *)&gdt[GUSERLDT_SEL]); PCPU_SET(fs32p, &gdt[GUFS32_SEL]); PCPU_SET(gs32p, &gdt[GUGS32_SEL]); + PCPU_SET(ucr3_load_mask, PMAP_UCR3_NOMASK); PCPU_SET(smp_tlb_gen, 1); } diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index 4d2df92664c7..ca95013d9c0b 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -283,6 +283,7 @@ init_secondary(void) pc->pc_fs32p = &gdt[GUFS32_SEL]; pc->pc_gs32p = &gdt[GUGS32_SEL]; pc->pc_ldt = (struct system_segment_descriptor *)&gdt[GUSERLDT_SEL]; + pc->pc_ucr3_load_mask = PMAP_UCR3_NOMASK; /* See comment in pmap_bootstrap(). */ pc->pc_pcid_next = PMAP_PCID_KERN + 2; pc->pc_pcid_gen = 1; @@ -821,15 +822,14 @@ invltlb_invpcid_pti_handler(pmap_t smp_tlb_pmap) invpcid(&d, INVPCID_CTXGLOB); } else { invpcid(&d, INVPCID_CTX); - d.pcid |= PMAP_PCID_USER_PT; - invpcid(&d, INVPCID_CTX); + if (smp_tlb_pmap == PCPU_GET(curpmap)) + PCPU_SET(ucr3_load_mask, ~CR3_PCID_SAVE); } } static void invltlb_pcid_handler(pmap_t smp_tlb_pmap) { - uint64_t kcr3, ucr3; uint32_t pcid; #ifdef COUNT_XINVLTLB_HITS @@ -849,15 +849,11 @@ invltlb_pcid_handler(pmap_t smp_tlb_pmap) * invalidation when switching to the pmap on this * CPU. */ - if (PCPU_GET(curpmap) == smp_tlb_pmap) { + if (smp_tlb_pmap == PCPU_GET(curpmap)) { pcid = smp_tlb_pmap->pm_pcids[PCPU_GET(cpuid)].pm_pcid; - kcr3 = smp_tlb_pmap->pm_cr3 | pcid; - ucr3 = smp_tlb_pmap->pm_ucr3; - if (ucr3 != PMAP_NO_CR3) { - ucr3 |= PMAP_PCID_USER_PT | pcid; - pmap_pti_pcid_invalidate(ucr3, kcr3); - } else - load_cr3(kcr3); + load_cr3(smp_tlb_pmap->pm_cr3 | pcid); + if (smp_tlb_pmap->pm_ucr3 != PMAP_NO_CR3) + PCPU_SET(ucr3_load_mask, ~CR3_PCID_SAVE); } } } @@ -888,7 +884,9 @@ invlpg_invpcid_handler(pmap_t smp_tlb_pmap, vm_offset_t smp_tlb_addr1) #endif /* COUNT_IPIS */ invlpg(smp_tlb_addr1); - if (smp_tlb_pmap->pm_ucr3 != PMAP_NO_CR3) { + if (smp_tlb_pmap == PCPU_GET(curpmap) && + smp_tlb_pmap->pm_ucr3 != PMAP_NO_CR3 && + PCPU_GET(ucr3_load_mask) == PMAP_UCR3_NOMASK) { d.pcid = smp_tlb_pmap->pm_pcids[PCPU_GET(cpuid)].pm_pcid | PMAP_PCID_USER_PT; d.pad = 0; @@ -912,7 +910,8 @@ invlpg_pcid_handler(pmap_t smp_tlb_pmap, vm_offset_t smp_tlb_addr1) invlpg(smp_tlb_addr1); if (smp_tlb_pmap == PCPU_GET(curpmap) && - (ucr3 = smp_tlb_pmap->pm_ucr3) != PMAP_NO_CR3) { + (ucr3 = smp_tlb_pmap->pm_ucr3) != PMAP_NO_CR3 && + PCPU_GET(ucr3_load_mask) == PMAP_UCR3_NOMASK) { pcid = smp_tlb_pmap->pm_pcids[PCPU_GET(cpuid)].pm_pcid; kcr3 = smp_tlb_pmap->pm_cr3 | pcid | CR3_PCID_SAVE; ucr3 |= pcid | PMAP_PCID_USER_PT | CR3_PCID_SAVE; @@ -960,7 +959,9 @@ invlrng_invpcid_handler(pmap_t smp_tlb_pmap, vm_offset_t smp_tlb_addr1, invlpg(addr); addr += PAGE_SIZE; } while (addr < addr2); - if (smp_tlb_pmap->pm_ucr3 != PMAP_NO_CR3) { + if (smp_tlb_pmap == PCPU_GET(curpmap) && + smp_tlb_pmap->pm_ucr3 != PMAP_NO_CR3 && + PCPU_GET(ucr3_load_mask) == PMAP_UCR3_NOMASK) { d.pcid = smp_tlb_pmap->pm_pcids[PCPU_GET(cpuid)].pm_pcid | PMAP_PCID_USER_PT; d.pad = 0; @@ -994,7 +995,8 @@ invlrng_pcid_handler(pmap_t smp_tlb_pmap, vm_offset_t smp_tlb_addr1, addr += PAGE_SIZE; } while (addr < addr2); if (smp_tlb_pmap == PCPU_GET(curpmap) && - (ucr3 = smp_tlb_pmap->pm_ucr3) != PMAP_NO_CR3) { + (ucr3 = smp_tlb_pmap->pm_ucr3) != PMAP_NO_CR3 && + PCPU_GET(ucr3_load_mask) == PMAP_UCR3_NOMASK) { pcid = smp_tlb_pmap->pm_pcids[PCPU_GET(cpuid)].pm_pcid; kcr3 = smp_tlb_pmap->pm_cr3 | pcid | CR3_PCID_SAVE; ucr3 |= pcid | PMAP_PCID_USER_PT | CR3_PCID_SAVE; diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index fdcbff0a3dad..314c8df5b328 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -2520,7 +2520,16 @@ pmap_invalidate_page_pcid(pmap_t pmap, vm_offset_t va, cpuid = PCPU_GET(cpuid); if (pmap == PCPU_GET(curpmap)) { - if (pmap->pm_ucr3 != PMAP_NO_CR3) { + if (pmap->pm_ucr3 != PMAP_NO_CR3 && + /* + * If we context-switched right after + * PCPU_GET(ucr3_load_mask), we could read the + * ~CR3_PCID_SAVE mask, which causes us to skip + * the code below to invalidate user pages. This + * is handled in pmap_activate_sw_pcid_pti() by + * clearing pm_gen if ucr3_load_mask is ~CR3_PCID_SAVE. + */ + PCPU_GET(ucr3_load_mask) == PMAP_UCR3_NOMASK) { /* * Because pm_pcid is recalculated on a * context switch, we must disable switching. @@ -2635,7 +2644,8 @@ pmap_invalidate_range_pcid(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, cpuid = PCPU_GET(cpuid); if (pmap == PCPU_GET(curpmap)) { - if (pmap->pm_ucr3 != PMAP_NO_CR3) { + if (pmap->pm_ucr3 != PMAP_NO_CR3 && + PCPU_GET(ucr3_load_mask) == PMAP_UCR3_NOMASK) { critical_enter(); pcid = pmap->pm_pcids[cpuid].pm_pcid; if (invpcid_works1) { @@ -2736,7 +2746,7 @@ static inline void pmap_invalidate_all_pcid(pmap_t pmap, bool invpcid_works1) { struct invpcid_descr d; - uint64_t kcr3, ucr3; + uint64_t kcr3; uint32_t pcid; u_int cpuid, i; @@ -2757,20 +2767,12 @@ pmap_invalidate_all_pcid(pmap_t pmap, bool invpcid_works1) d.pad = 0; d.addr = 0; invpcid(&d, INVPCID_CTX); - if (pmap->pm_ucr3 != PMAP_NO_CR3) { - d.pcid |= PMAP_PCID_USER_PT; - invpcid(&d, INVPCID_CTX); - } } else { kcr3 = pmap->pm_cr3 | pcid; - ucr3 = pmap->pm_ucr3; - if (ucr3 != PMAP_NO_CR3) { - ucr3 |= pcid | PMAP_PCID_USER_PT; - pmap_pti_pcid_invalidate(ucr3, kcr3); - } else { - load_cr3(kcr3); - } + load_cr3(kcr3); } + if (pmap->pm_ucr3 != PMAP_NO_CR3) + PCPU_SET(ucr3_load_mask, ~CR3_PCID_SAVE); critical_exit(); } else pmap->pm_pcids[cpuid].pm_gen = 0; @@ -8816,12 +8818,23 @@ pmap_activate_sw_pti_post(struct thread *td, pmap_t pmap) PCPU_GET(pti_rsp0) : (uintptr_t)td->td_md.md_stack_base; } -static void inline -pmap_activate_sw_pcid_pti(pmap_t pmap, u_int cpuid, const bool invpcid_works1) +static void +pmap_activate_sw_pcid_pti(struct thread *td, pmap_t pmap, u_int cpuid) { - struct invpcid_descr d; + pmap_t old_pmap; uint64_t cached, cr3, kcr3, ucr3; + KASSERT((read_rflags() & PSL_I) == 0, + ("PCID needs interrupts disabled in pmap_activate_sw()")); + + /* See the comment in pmap_invalidate_page_pcid(). */ + if (PCPU_GET(ucr3_load_mask) != PMAP_UCR3_NOMASK) { + PCPU_SET(ucr3_load_mask, PMAP_UCR3_NOMASK); + old_pmap = PCPU_GET(curpmap); + MPASS(old_pmap->pm_ucr3 != PMAP_NO_CR3); + old_pmap->pm_pcids[cpuid].pm_gen = 0; + } + cached = pmap_pcid_alloc_checked(pmap, cpuid); cr3 = rcr3(); if ((cr3 & ~CR3_PCID_MASK) != pmap->pm_cr3) @@ -8831,68 +8844,14 @@ pmap_activate_sw_pcid_pti(pmap_t pmap, u_int cpuid, const bool invpcid_works1) ucr3 = pmap->pm_ucr3 | pmap->pm_pcids[cpuid].pm_pcid | PMAP_PCID_USER_PT; - if (!cached && pmap->pm_ucr3 != PMAP_NO_CR3) { - /* - * Explicitly invalidate translations cached from the - * user page table. They are not automatically - * flushed by reload of cr3 with the kernel page table - * pointer above. - * - * Note that the if() condition is resolved statically - * by using the function argument instead of - * runtime-evaluated invpcid_works value. - */ - if (invpcid_works1) { - d.pcid = PMAP_PCID_USER_PT | - pmap->pm_pcids[cpuid].pm_pcid; - d.pad = 0; - d.addr = 0; - invpcid(&d, INVPCID_CTX); - } else { - pmap_pti_pcid_invalidate(ucr3, kcr3); - } - } + if (!cached && pmap->pm_ucr3 != PMAP_NO_CR3) + PCPU_SET(ucr3_load_mask, ~CR3_PCID_SAVE); PCPU_SET(kcr3, kcr3 | CR3_PCID_SAVE); PCPU_SET(ucr3, ucr3 | CR3_PCID_SAVE); if (cached) PCPU_INC(pm_save_cnt); -} -static void -pmap_activate_sw_pcid_invpcid_pti(struct thread *td, pmap_t pmap, u_int cpuid) -{ - - pmap_activate_sw_pcid_pti(pmap, cpuid, true); - pmap_activate_sw_pti_post(td, pmap); -} - -static void -pmap_activate_sw_pcid_noinvpcid_pti(struct thread *td, pmap_t pmap, - u_int cpuid) -{ - register_t rflags; - - /* - * If the INVPCID instruction is not available, - * invltlb_pcid_handler() is used to handle an invalidate_all - * IPI, which checks for curpmap == smp_tlb_pmap. The below - * sequence of operations has a window where %CR3 is loaded - * with the new pmap's PML4 address, but the curpmap value has - * not yet been updated. This causes the invltlb IPI handler, - * which is called between the updates, to execute as a NOP, - * which leaves stale TLB entries. - * - * Note that the most typical use of pmap_activate_sw(), from - * the context switch, is immune to this race, because - * interrupts are disabled (while the thread lock is owned), - * and the IPI happens after curpmap is updated. Protect - * other callers in a similar way, by disabling interrupts - * around the %cr3 register reload and curpmap assignment. - */ - rflags = intr_disable(); - pmap_activate_sw_pcid_pti(pmap, cpuid, false); - intr_restore(rflags); pmap_activate_sw_pti_post(td, pmap); } @@ -8902,6 +8861,9 @@ pmap_activate_sw_pcid_nopti(struct thread *td __unused, pmap_t pmap, { uint64_t cached, cr3; + KASSERT((read_rflags() & PSL_I) == 0, + ("PCID needs interrupts disabled in pmap_activate_sw()")); + cached = pmap_pcid_alloc_checked(pmap, cpuid); cr3 = rcr3(); if (!cached || (cr3 & ~CR3_PCID_MASK) != pmap->pm_cr3) @@ -8912,17 +8874,6 @@ pmap_activate_sw_pcid_nopti(struct thread *td __unused, pmap_t pmap, PCPU_INC(pm_save_cnt); } -static void -pmap_activate_sw_pcid_noinvpcid_nopti(struct thread *td __unused, pmap_t pmap, - u_int cpuid) -{ - register_t rflags; - - rflags = intr_disable(); - pmap_activate_sw_pcid_nopti(td, pmap, cpuid); - intr_restore(rflags); -} - static void pmap_activate_sw_nopcid_nopti(struct thread *td __unused, pmap_t pmap, u_int cpuid __unused) @@ -8947,14 +8898,10 @@ DEFINE_IFUNC(static, void, pmap_activate_sw_mode, (struct thread *, pmap_t, u_int)) { - if (pmap_pcid_enabled && pti && invpcid_works) - return (pmap_activate_sw_pcid_invpcid_pti); - else if (pmap_pcid_enabled && pti && !invpcid_works) - return (pmap_activate_sw_pcid_noinvpcid_pti); - else if (pmap_pcid_enabled && !pti && invpcid_works) + if (pmap_pcid_enabled && pti) + return (pmap_activate_sw_pcid_pti); + else if (pmap_pcid_enabled && !pti) return (pmap_activate_sw_pcid_nopti); - else if (pmap_pcid_enabled && !pti && !invpcid_works) - return (pmap_activate_sw_pcid_noinvpcid_nopti); else if (!pmap_pcid_enabled && pti) return (pmap_activate_sw_nopcid_pti); else /* if (!pmap_pcid_enabled && !pti) */ @@ -8991,10 +8938,26 @@ pmap_activate_sw(struct thread *td) void pmap_activate(struct thread *td) { - - critical_enter(); + /* + * invltlb_{invpcid,}_pcid_handler() is used to handle an + * invalidate_all IPI, which checks for curpmap == + * smp_tlb_pmap. The below sequence of operations has a + * window where %CR3 is loaded with the new pmap's PML4 + * address, but the curpmap value has not yet been updated. + * This causes the invltlb IPI handler, which is called + * between the updates, to execute as a NOP, which leaves + * stale TLB entries. + * + * Note that the most common use of pmap_activate_sw(), from + * a context switch, is immune to this race, because + * interrupts are disabled (while the thread lock is owned), + * so the IPI is delayed until after curpmap is updated. Protect + * other callers in a similar way, by disabling interrupts + * around the %cr3 register reload and curpmap assignment. + */ + spinlock_enter(); pmap_activate_sw(td); - critical_exit(); + spinlock_exit(); } void diff --git a/sys/amd64/include/pcpu.h b/sys/amd64/include/pcpu.h index 22c6ed40aa20..4b163636c775 100644 --- a/sys/amd64/include/pcpu.h +++ b/sys/amd64/include/pcpu.h @@ -99,7 +99,8 @@ _Static_assert(sizeof(struct monitorbuf) == 128, "2x cache line"); uint64_t pc_smp_tlb_addr2; \ uint32_t pc_smp_tlb_gen; \ u_int pc_smp_tlb_op; \ - char __pad[2924] /* pad to UMA_PCPU_ALLOC_SIZE */ + uint64_t pc_ucr3_load_mask; \ + char __pad[2916] /* pad to UMA_PCPU_ALLOC_SIZE */ #define PC_DBREG_CMD_NONE 0 #define PC_DBREG_CMD_LOAD 1 diff --git a/sys/amd64/include/pmap.h b/sys/amd64/include/pmap.h index ffa21a674583..e2d7a714511b 100644 --- a/sys/amd64/include/pmap.h +++ b/sys/amd64/include/pmap.h @@ -241,6 +241,7 @@ #define PMAP_PCID_USER_PT 0x800 #define PMAP_NO_CR3 (~0UL) +#define PMAP_UCR3_NOMASK (~0UL) #ifndef LOCORE From 97dd57e66c32a9a74549822a599ca77e50c7ff82 Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Sun, 19 Jul 2020 06:59:09 +0000 Subject: [PATCH 042/287] loader: cstyle cleanup No functional changes intended. Sponsored by: Netflix, Klara Inc. --- stand/i386/loader/main.c | 465 ++++++++++++++++++++------------------- 1 file changed, 243 insertions(+), 222 deletions(-) diff --git a/stand/i386/loader/main.c b/stand/i386/loader/main.c index 0087ec757353..377075f100ee 100644 --- a/stand/i386/loader/main.c +++ b/stand/i386/loader/main.c @@ -95,163 +95,171 @@ ptov(uintptr_t x) int main(void) { - int i; + int i; - /* Pick up arguments */ - kargs = (void *)__args; - initial_howto = kargs->howto; - initial_bootdev = kargs->bootdev; - initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; + /* Pick up arguments */ + kargs = (void *)__args; + initial_howto = kargs->howto; + initial_bootdev = kargs->bootdev; + initial_bootinfo = kargs->bootinfo ? + (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; - /* Initialize the v86 register set to a known-good state. */ - bzero(&v86, sizeof(v86)); - v86.efl = PSL_RESERVED_DEFAULT | PSL_I; + /* Initialize the v86 register set to a known-good state. */ + bzero(&v86, sizeof(v86)); + v86.efl = PSL_RESERVED_DEFAULT | PSL_I; - /* - * Initialise the heap as early as possible. Once this is done, malloc() is usable. - */ - bios_getmem(); + /* + * Initialise the heap as early as possible. + * Once this is done, malloc() is usable. + */ + bios_getmem(); #if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) || \ defined(LOADER_GPT_SUPPORT) || defined(LOADER_ZFS_SUPPORT) - if (high_heap_size > 0) { - heap_top = PTOV(high_heap_base + high_heap_size); - heap_bottom = PTOV(high_heap_base); - if (high_heap_base < memtop_copyin) - memtop_copyin = high_heap_base; - } else + if (high_heap_size > 0) { + heap_top = PTOV(high_heap_base + high_heap_size); + heap_bottom = PTOV(high_heap_base); + if (high_heap_base < memtop_copyin) + memtop_copyin = high_heap_base; + } else #endif - { - heap_top = (void *)PTOV(bios_basemem); - heap_bottom = (void *)end; - } - setheap(heap_bottom, heap_top); + { + heap_top = (void *)PTOV(bios_basemem); + heap_bottom = (void *)end; + } + setheap(heap_bottom, heap_top); - /* - * XXX Chicken-and-egg problem; we want to have console output early, but some - * console attributes may depend on reading from eg. the boot device, which we - * can't do yet. - * - * We can use printf() etc. once this is done. - * If the previous boot stage has requested a serial console, prefer that. - */ - bi_setboothowto(initial_howto); - if (initial_howto & RB_MULTIPLE) { - if (initial_howto & RB_SERIAL) - setenv("console", "comconsole vidconsole", 1); - else - setenv("console", "vidconsole comconsole", 1); - } else if (initial_howto & RB_SERIAL) - setenv("console", "comconsole", 1); - else if (initial_howto & RB_MUTE) - setenv("console", "nullconsole", 1); - cons_probe(); - - /* - * Initialise the block cache. Set the upper limit. - */ - bcache_init(32768, 512); - - /* - * Special handling for PXE and CD booting. - */ - if (kargs->bootinfo == 0) { /* - * We only want the PXE disk to try to init itself in the below - * walk through devsw if we actually booted off of PXE. + * XXX Chicken-and-egg problem; we want to have console output early, + * but some console attributes may depend on reading from eg. the boot + * device, which we can't do yet. + * + * We can use printf() etc. once this is done. + * If the previous boot stage has requested a serial console, + * prefer that. */ - if (kargs->bootflags & KARGS_FLAGS_PXE) - pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); - else if (kargs->bootflags & KARGS_FLAGS_CD) - bc_add(initial_bootdev); - } + bi_setboothowto(initial_howto); + if (initial_howto & RB_MULTIPLE) { + if (initial_howto & RB_SERIAL) + setenv("console", "comconsole vidconsole", 1); + else + setenv("console", "vidconsole comconsole", 1); + } else if (initial_howto & RB_SERIAL) { + setenv("console", "comconsole", 1); + } else if (initial_howto & RB_MUTE) { + setenv("console", "nullconsole", 1); + } + cons_probe(); - archsw.arch_autoload = i386_autoload; - archsw.arch_getdev = i386_getdev; - archsw.arch_copyin = i386_copyin; - archsw.arch_copyout = i386_copyout; - archsw.arch_readin = i386_readin; - archsw.arch_isainb = isa_inb; - archsw.arch_isaoutb = isa_outb; - archsw.arch_hypervisor = x86_hypervisor; + /* + * Initialise the block cache. Set the upper limit. + */ + bcache_init(32768, 512); + + /* + * Special handling for PXE and CD booting. + */ + if (kargs->bootinfo == 0) { + /* + * We only want the PXE disk to try to init itself in the below + * walk through devsw if we actually booted off of PXE. + */ + if (kargs->bootflags & KARGS_FLAGS_PXE) + pxe_enable(kargs->pxeinfo ? + PTOV(kargs->pxeinfo) : NULL); + else if (kargs->bootflags & KARGS_FLAGS_CD) + bc_add(initial_bootdev); + } + + archsw.arch_autoload = i386_autoload; + archsw.arch_getdev = i386_getdev; + archsw.arch_copyin = i386_copyin; + archsw.arch_copyout = i386_copyout; + archsw.arch_readin = i386_readin; + archsw.arch_isainb = isa_inb; + archsw.arch_isaoutb = isa_outb; + archsw.arch_hypervisor = x86_hypervisor; #ifdef LOADER_ZFS_SUPPORT - archsw.arch_zfs_probe = i386_zfs_probe; + archsw.arch_zfs_probe = i386_zfs_probe; - /* - * zfsboot and gptzfsboot have always passed KARGS_FLAGS_ZFS, so if that is - * set along with KARGS_FLAGS_EXTARG we know we can interpret the extarg - * data as a struct zfs_boot_args. - */ + /* + * zfsboot and gptzfsboot have always passed KARGS_FLAGS_ZFS, + * so if that is set along with KARGS_FLAGS_EXTARG we know we + * can interpret the extarg data as a struct zfs_boot_args. + */ #define KARGS_EXTARGS_ZFS (KARGS_FLAGS_EXTARG | KARGS_FLAGS_ZFS) - if ((kargs->bootflags & KARGS_EXTARGS_ZFS) == KARGS_EXTARGS_ZFS) { - zargs = (struct zfs_boot_args *)(kargs + 1); - } + if ((kargs->bootflags & KARGS_EXTARGS_ZFS) == KARGS_EXTARGS_ZFS) { + zargs = (struct zfs_boot_args *)(kargs + 1); + } #endif /* LOADER_ZFS_SUPPORT */ #ifdef LOADER_GELI_SUPPORT - /* - * If we decided earlier that we have zfs_boot_args extarg data, and it is - * big enough to contain the embedded geli data (the early zfs_boot_args - * structs weren't), then init the gbdata pointer accordingly. If there is - * extarg data which isn't zfs_boot_args data, determine whether it is - * geli_boot_args data. Recent versions of gptboot set KARGS_FLAGS_GELI to - * indicate that. Earlier versions didn't, but we presume that's what we - * have if the extarg size exactly matches the size of the geli_boot_args - * struct during that pre-flag era. - */ + /* + * If we decided earlier that we have zfs_boot_args extarg data, + * and it is big enough to contain the embedded geli data + * (the early zfs_boot_args structs weren't), then init the gbdata + * pointer accordingly. If there is extarg data which isn't + * zfs_boot_args data, determine whether it is geli_boot_args data. + * Recent versions of gptboot set KARGS_FLAGS_GELI to indicate that. + * Earlier versions didn't, but we presume that's what we + * have if the extarg size exactly matches the size of the + * geli_boot_args struct during that pre-flag era. + */ #define LEGACY_GELI_ARGS_SIZE 260 /* This can never change */ #ifdef LOADER_ZFS_SUPPORT - if (zargs != NULL) { - if (zargs->size > offsetof(struct zfs_boot_args, gelidata)) { - gbdata = &zargs->gelidata; - } - } else + if (zargs != NULL) { + if (zargs->size > offsetof(struct zfs_boot_args, gelidata)) { + gbdata = &zargs->gelidata; + } + } else #endif /* LOADER_ZFS_SUPPORT */ - if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) { - gargs = (struct geli_boot_args *)(kargs + 1); - if ((kargs->bootflags & KARGS_FLAGS_GELI) || - gargs->size == LEGACY_GELI_ARGS_SIZE) { - gbdata = &gargs->gelidata; + if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) { + gargs = (struct geli_boot_args *)(kargs + 1); + if ((kargs->bootflags & KARGS_FLAGS_GELI) || + gargs->size == LEGACY_GELI_ARGS_SIZE) { + gbdata = &gargs->gelidata; + } } - } - if (gbdata != NULL) - import_geli_boot_data(gbdata); + if (gbdata != NULL) + import_geli_boot_data(gbdata); #endif /* LOADER_GELI_SUPPORT */ - /* - * March through the device switch probing for things. - */ - for (i = 0; devsw[i] != NULL; i++) - if (devsw[i]->dv_init != NULL) - (devsw[i]->dv_init)(); - printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024); - if (initial_bootinfo != NULL) { - initial_bootinfo->bi_basemem = bios_basemem / 1024; - initial_bootinfo->bi_extmem = bios_extmem / 1024; - } + /* + * March through the device switch probing for things. + */ + for (i = 0; devsw[i] != NULL; i++) + if (devsw[i]->dv_init != NULL) + (devsw[i]->dv_init)(); - /* detect ACPI for future reference */ - biosacpi_detect(); + printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, + bios_extmem / 1024); + if (initial_bootinfo != NULL) { + initial_bootinfo->bi_basemem = bios_basemem / 1024; + initial_bootinfo->bi_extmem = bios_extmem / 1024; + } - /* detect SMBIOS for future reference */ - smbios_detect(NULL); + /* detect ACPI for future reference */ + biosacpi_detect(); - /* detect PCI BIOS for future reference */ - biospci_detect(); + /* detect SMBIOS for future reference */ + smbios_detect(NULL); - printf("\n%s", bootprog_info); + /* detect PCI BIOS for future reference */ + biospci_detect(); - extract_currdev(); /* set $currdev and $loaddev */ + printf("\n%s", bootprog_info); + + extract_currdev(); /* set $currdev and $loaddev */ - bios_getsmap(); + bios_getsmap(); - interact(); + interact(); - /* if we ever get here, it is an error */ - return (1); + /* if we ever get here, it is an error */ + return (1); } /* @@ -263,92 +271,105 @@ main(void) static void extract_currdev(void) { - struct i386_devdesc new_currdev; + struct i386_devdesc new_currdev; #ifdef LOADER_ZFS_SUPPORT - char buf[20]; + char buf[20]; #endif - int biosdev = -1; + int biosdev = -1; - /* Assume we are booting from a BIOS disk by default */ - new_currdev.dd.d_dev = &bioshd; + /* Assume we are booting from a BIOS disk by default */ + new_currdev.dd.d_dev = &bioshd; - /* new-style boot loaders such as pxeldr and cdldr */ - if (kargs->bootinfo == 0) { - if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { - /* we are booting from a CD with cdboot */ - new_currdev.dd.d_dev = &bioscd; - new_currdev.dd.d_unit = bd_bios2unit(initial_bootdev); - } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { - /* we are booting from pxeldr */ - new_currdev.dd.d_dev = &pxedisk; - new_currdev.dd.d_unit = 0; - } else { - /* we don't know what our boot device is */ - new_currdev.d_kind.biosdisk.slice = -1; - new_currdev.d_kind.biosdisk.partition = 0; - biosdev = -1; - } + /* new-style boot loaders such as pxeldr and cdldr */ + if (kargs->bootinfo == 0) { + if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { + /* we are booting from a CD with cdboot */ + new_currdev.dd.d_dev = &bioscd; + new_currdev.dd.d_unit = bd_bios2unit(initial_bootdev); + } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { + /* we are booting from pxeldr */ + new_currdev.dd.d_dev = &pxedisk; + new_currdev.dd.d_unit = 0; + } else { + /* we don't know what our boot device is */ + new_currdev.d_kind.biosdisk.slice = -1; + new_currdev.d_kind.biosdisk.partition = 0; + biosdev = -1; + } #ifdef LOADER_ZFS_SUPPORT - } else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) { - /* zargs was set in main() if we have new style extended argument */ - if (zargs != NULL && - zargs->size >= offsetof(struct zfs_boot_args, primary_pool)) { - /* sufficient data is provided */ - new_currdev.d_kind.zfs.pool_guid = zargs->pool; - new_currdev.d_kind.zfs.root_guid = zargs->root; - if (zargs->size >= sizeof(*zargs) && zargs->primary_vdev != 0) { - sprintf(buf, "%llu", zargs->primary_pool); - setenv("vfs.zfs.boot.primary_pool", buf, 1); - sprintf(buf, "%llu", zargs->primary_vdev); - setenv("vfs.zfs.boot.primary_vdev", buf, 1); - } - } else { - /* old style zfsboot block */ - new_currdev.d_kind.zfs.pool_guid = kargs->zfspool; - new_currdev.d_kind.zfs.root_guid = 0; - } - new_currdev.dd.d_dev = &zfs_dev; + } else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) { + /* + * zargs was set in main() if we have new style extended + * argument + */ + if (zargs != NULL && + zargs->size >= + offsetof(struct zfs_boot_args, primary_pool)) { + /* sufficient data is provided */ + new_currdev.d_kind.zfs.pool_guid = zargs->pool; + new_currdev.d_kind.zfs.root_guid = zargs->root; + if (zargs->size >= sizeof(*zargs) && + zargs->primary_vdev != 0) { + sprintf(buf, "%llu", zargs->primary_pool); + setenv("vfs.zfs.boot.primary_pool", buf, 1); + sprintf(buf, "%llu", zargs->primary_vdev); + setenv("vfs.zfs.boot.primary_vdev", buf, 1); + } + } else { + /* old style zfsboot block */ + new_currdev.d_kind.zfs.pool_guid = kargs->zfspool; + new_currdev.d_kind.zfs.root_guid = 0; + } + new_currdev.dd.d_dev = &zfs_dev; #endif - } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { - /* The passed-in boot device is bad */ - new_currdev.d_kind.biosdisk.slice = -1; - new_currdev.d_kind.biosdisk.partition = 0; - biosdev = -1; - } else { - new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1; - new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); - biosdev = initial_bootinfo->bi_bios_dev; + } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { + /* The passed-in boot device is bad */ + new_currdev.d_kind.biosdisk.slice = -1; + new_currdev.d_kind.biosdisk.partition = 0; + biosdev = -1; + } else { + new_currdev.d_kind.biosdisk.slice = + B_SLICE(initial_bootdev) - 1; + new_currdev.d_kind.biosdisk.partition = + B_PARTITION(initial_bootdev); + biosdev = initial_bootinfo->bi_bios_dev; + + /* + * If we are booted by an old bootstrap, we have to guess at + * the BIOS unit number. We will lose if there is more than + * one disk type and we are not booting from the + * lowest-numbered disk type (ie. SCSI when IDE also exists). + */ + if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) { + /* + * biosdev doesn't match major, assume harddisk + */ + biosdev = 0x80 + B_UNIT(initial_bootdev); + } + } /* - * If we are booted by an old bootstrap, we have to guess at the BIOS - * unit number. We will lose if there is more than one disk type - * and we are not booting from the lowest-numbered disk type - * (ie. SCSI when IDE also exists). + * If we are booting off of a BIOS disk and we didn't succeed + * in determining which one we booted off of, just use disk0: + * as a reasonable default. */ - if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */ - biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */ - } - - /* - * If we are booting off of a BIOS disk and we didn't succeed in determining - * which one we booted off of, just use disk0: as a reasonable default. - */ - if ((new_currdev.dd.d_dev->dv_type == bioshd.dv_type) && - ((new_currdev.dd.d_unit = bd_bios2unit(biosdev)) == -1)) { - printf("Can't work out which disk we are booting from.\n" - "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); - new_currdev.dd.d_unit = 0; - } + if ((new_currdev.dd.d_dev->dv_type == bioshd.dv_type) && + ((new_currdev.dd.d_unit = bd_bios2unit(biosdev)) == -1)) { + printf("Can't work out which disk we are booting " + "from.\nGuessed BIOS device 0x%x not found by " + "probes, defaulting to disk0:\n", biosdev); + new_currdev.dd.d_unit = 0; + } #ifdef LOADER_ZFS_SUPPORT - if (new_currdev.dd.d_dev->dv_type == DEVT_ZFS) - init_zfs_bootenv(zfs_fmtdev(&new_currdev)); + if (new_currdev.dd.d_dev->dv_type == DEVT_ZFS) + init_zfs_bootenv(zfs_fmtdev(&new_currdev)); #endif - env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), - i386_setcurrdev, env_nounset); - env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, - env_nounset); + env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), + i386_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), + env_noset, env_nounset); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); @@ -356,22 +377,22 @@ COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { - int i; + int i; - for (i = 0; devsw[i] != NULL; ++i) - if (devsw[i]->dv_cleanup != NULL) - (devsw[i]->dv_cleanup)(); + for (i = 0; devsw[i] != NULL; ++i) + if (devsw[i]->dv_cleanup != NULL) + (devsw[i]->dv_cleanup)(); - printf("Rebooting...\n"); - delay(1000000); - __exit(0); + printf("Rebooting...\n"); + delay(1000000); + __exit(0); } /* provide this for panic, as it's not in the startup code */ void exit(int code) { - __exit(code); + __exit(code); } COMMAND_SET(heap, "heap", "show heap usage", command_heap); @@ -379,10 +400,10 @@ COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { - mallocstats(); - printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, - sbrk(0), heap_top); - return(CMD_OK); + mallocstats(); + printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, + sbrk(0), heap_top); + return (CMD_OK); } /* ISA bus access functions for PnP. */ @@ -390,32 +411,32 @@ static int isa_inb(int port) { - return (inb(port)); + return (inb(port)); } static void isa_outb(int port, int value) { - outb(port, value); + outb(port, value); } #ifdef LOADER_ZFS_SUPPORT static void i386_zfs_probe(void) { - char devname[32]; - struct i386_devdesc dev; + char devname[32]; + struct i386_devdesc dev; - /* - * Open all the disks we can find and see if we can reconstruct - * ZFS pools from them. - */ - dev.dd.d_dev = &bioshd; - for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) { - snprintf(devname, sizeof(devname), "%s%d:", bioshd.dv_name, - dev.dd.d_unit); - zfs_probe_dev(devname, NULL); - } + /* + * Open all the disks we can find and see if we can reconstruct + * ZFS pools from them. + */ + dev.dd.d_dev = &bioshd; + for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) { + snprintf(devname, sizeof(devname), "%s%d:", bioshd.dv_name, + dev.dd.d_unit); + zfs_probe_dev(devname, NULL); + } } #endif From 8cee15d9e4d45fe13b3c8f840350d3e73c96c484 Mon Sep 17 00:00:00 2001 From: "Alexander V. Chernikov" Date: Sun, 19 Jul 2020 09:29:27 +0000 Subject: [PATCH 043/287] Transition from rtrequest1_fib() to rib_action(). Remove all variations of rtrequest and their uses and switch to to rib_action(). This is part of the new routing KPI. Submitted by: Neel Chauhan Differential Revision: https://reviews.freebsd.org/D25546 --- sys/fs/nfsclient/nfs_clvfsops.c | 15 +++-- sys/net/if.c | 4 +- sys/net/route.c | 113 +++----------------------------- sys/net/route.h | 3 - sys/netinet6/in6_rmx.c | 11 ---- sys/netinet6/in6_var.h | 2 - sys/netinet6/nd6.c | 3 +- sys/netinet6/nd6_rtr.c | 69 ++++++++++++------- 8 files changed, 72 insertions(+), 148 deletions(-) diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c index 5490155da68c..7124c10573fa 100644 --- a/sys/fs/nfsclient/nfs_clvfsops.c +++ b/sys/fs/nfsclient/nfs_clvfsops.c @@ -68,6 +68,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -466,6 +467,8 @@ nfs_mountroot(struct mount *mp) nd->mygateway.sin_addr.s_addr != 0) { struct sockaddr_in mask, sin; struct epoch_tracker et; + struct rt_addrinfo info; + struct rib_cmd_info rc; bzero((caddr_t)&mask, sizeof(mask)); sin = mask; @@ -474,10 +477,14 @@ nfs_mountroot(struct mount *mp) /* XXX MRT use table 0 for this sort of thing */ NET_EPOCH_ENTER(et); CURVNET_SET(TD_TO_VNET(td)); - error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin, - (struct sockaddr *)&nd->mygateway, - (struct sockaddr *)&mask, - RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB); + + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = RTF_UP | RTF_GATEWAY; + info.rti_info[RTAX_DST] = (struct sockaddr *)&sin; + info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&nd->mygateway; + info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask; + + error = rib_action(RT_DEFAULT_FIB, RTM_ADD, &info, &rc); CURVNET_RESTORE(); NET_EPOCH_EXIT(et); if (error) diff --git a/sys/net/if.c b/sys/net/if.c index bccbba268b56..59dd38267cfc 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #if defined(INET) || defined(INET6) @@ -1845,6 +1846,7 @@ static int ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa, struct sockaddr *ia) { + struct rib_cmd_info rc; struct epoch_tracker et; int error; struct rt_addrinfo info; @@ -1872,7 +1874,7 @@ ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa, info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl; link_init_sdl(ifp, (struct sockaddr *)&null_sdl, ifp->if_type); - error = rtrequest1_fib(cmd, &info, NULL, ifp->if_fib); + error = rib_action(ifp->if_fib, cmd, &info, &rc); NET_EPOCH_EXIT(et); if (rti_ifa != NULL) diff --git a/sys/net/route.c b/sys/net/route.c index 0b7a0e2d55b6..f24200a88e40 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -470,7 +470,7 @@ int rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, struct sockaddr *author, struct ifnet *ifp, int flags, int lifetime_sec) { - struct rtentry *rt; + struct rib_cmd_info rc; int error; struct rt_addrinfo info; struct rt_metrics rti_rmx; @@ -504,7 +504,7 @@ rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, info.rti_mflags |= RTV_EXPIRE; info.rti_rmx = &rti_rmx; - error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); + error = rib_action(fibnum, RTM_ADD, &info, &rc); ifa_free(ifa); if (error != 0) { @@ -512,9 +512,9 @@ rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, return (error); } - RT_LOCK(rt); - flags = rt->rt_flags; - RT_UNLOCK(rt); + RT_LOCK(rc.rc_rt); + flags = rc.rc_rt->rt_flags; + RT_UNLOCK(rc.rc_rt); RTSTAT_INC(rts_dynamic); @@ -602,32 +602,6 @@ ifa_ifwithroute(int flags, const struct sockaddr *dst, return (ifa); } -/* - * Do appropriate manipulations of a routing tree given - * all the bits of info needed - */ -int -rtrequest_fib(int req, - struct sockaddr *dst, - struct sockaddr *gateway, - struct sockaddr *netmask, - int flags, - struct rtentry **ret_nrt, - u_int fibnum) -{ - struct rt_addrinfo info; - - if (dst->sa_len == 0) - return(EINVAL); - - bzero((caddr_t)&info, sizeof(info)); - info.rti_flags = flags; - info.rti_info[RTAX_DST] = dst; - info.rti_info[RTAX_GATEWAY] = gateway; - info.rti_info[RTAX_NETMASK] = netmask; - return rtrequest1_fib(req, &info, ret_nrt, fibnum); -} - /* * Copy most of @rt data into @info. @@ -1148,73 +1122,6 @@ rt_mpath_unlink(struct rib_head *rnh, struct rt_addrinfo *info, } #endif -int -rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, - u_int fibnum) -{ - const struct sockaddr *dst; - struct rib_head *rnh; - struct rib_cmd_info rc; - int error; - - KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum")); - KASSERT((info->rti_flags & RTF_RNH_LOCKED) == 0, ("rtrequest1_fib: locked")); - NET_EPOCH_ASSERT(); - - dst = info->rti_info[RTAX_DST]; - - switch (dst->sa_family) { - case AF_INET6: - case AF_INET: - /* We support multiple FIBs. */ - break; - default: - fibnum = RT_DEFAULT_FIB; - break; - } - - /* - * Find the correct routing tree to use for this Address Family - */ - rnh = rt_tables_get_rnh(fibnum, dst->sa_family); - if (rnh == NULL) - return (EAFNOSUPPORT); - - /* - * If we are adding a host route then we don't want to put - * a netmask in the tree, nor do we want to clone it. - */ - if (info->rti_flags & RTF_HOST) - info->rti_info[RTAX_NETMASK] = NULL; - - bzero(&rc, sizeof(struct rib_cmd_info)); - error = 0; - switch (req) { - case RTM_DELETE: - error = del_route(rnh, info, &rc); - break; - case RTM_RESOLVE: - /* - * resolve was only used for route cloning - * here for compat - */ - break; - case RTM_ADD: - error = add_route(rnh, info, &rc); - break; - case RTM_CHANGE: - error = change_route(rnh, info, &rc); - break; - default: - error = EOPNOTSUPP; - } - - if (ret_nrt != NULL) - *ret_nrt = rc.rc_rt; - - return (error); -} - void rt_setmetrics(const struct rt_addrinfo *info, struct rtentry *rt) { @@ -1258,7 +1165,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) struct epoch_tracker et; struct sockaddr *dst; struct sockaddr *netmask; - struct rtentry *rt = NULL; + struct rib_cmd_info rc; struct rt_addrinfo info; int error = 0; int startfib, endfib; @@ -1349,7 +1256,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) if (rn == NULL) error = ESRCH; else { - rt = RNTORT(rn); + struct rtentry *rt = RNTORT(rn); /* * for interface route the gateway * gateway is sockaddr_dl, so @@ -1389,14 +1296,14 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; info.rti_info[RTAX_NETMASK] = netmask; NET_EPOCH_ENTER(et); - error = rtrequest1_fib(cmd, &info, &rt, fibnum); - if (error == 0 && rt != NULL) { + error = rib_action(fibnum, cmd, &info, &rc); + if (error == 0 && rc.rc_rt != NULL) { /* * notify any listening routing agents of the change */ /* TODO: interface routes/aliases */ - rt_newaddrmsg_fib(cmd, ifa, rt, fibnum); + rt_newaddrmsg_fib(cmd, ifa, rc.rc_rt, fibnum); didwork = 1; } NET_EPOCH_EXIT(et); diff --git a/sys/net/route.h b/sys/net/route.h index fad32d1a5ee1..1ffabcbc86df 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -411,9 +411,6 @@ int rtinit(struct ifaddr *, int, int); * but this will change.. */ int rtioctl_fib(u_long, caddr_t, u_int); -int rtrequest_fib(int, struct sockaddr *, - struct sockaddr *, struct sockaddr *, int, struct rtentry **, u_int); -int rtrequest1_fib(int, struct rt_addrinfo *, struct rtentry **, u_int); int rib_lookup_info(uint32_t, const struct sockaddr *, uint32_t, uint32_t, struct rt_addrinfo *); void rib_free_info(struct rt_addrinfo *info); diff --git a/sys/netinet6/in6_rmx.c b/sys/netinet6/in6_rmx.c index 5600feee8e6a..357292c5c59d 100644 --- a/sys/netinet6/in6_rmx.c +++ b/sys/netinet6/in6_rmx.c @@ -185,14 +185,3 @@ in6_detachhead(void **head, int off) } #endif -/* - * Extended API for IPv6 FIB support. - */ -int -in6_rtrequest(int req, struct sockaddr *dst, struct sockaddr *gw, - struct sockaddr *mask, int flags, struct rtentry **ret_nrt, u_int fibnum) -{ - - return (rtrequest_fib(req, dst, gw, mask, flags, ret_nrt, fibnum)); -} - diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index 1ca181d83c97..b94e52cac7cd 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -915,8 +915,6 @@ void in6_newaddrmsg(struct in6_ifaddr *, int); * Extended API for IPv6 FIB support. */ struct mbuf *ip6_tryforward(struct mbuf *); -int in6_rtrequest(int, struct sockaddr *, struct sockaddr *, - struct sockaddr *, int, struct rtentry **, u_int); #endif /* _KERNEL */ #endif /* _NETINET6_IN6_VAR_H_ */ diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index e2df8ad2aea3..bb488dbc6ff1 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -1564,6 +1564,7 @@ nd6_free_redirect(const struct llentry *ln) int fibnum; struct sockaddr_in6 sin6; struct rt_addrinfo info; + struct rib_cmd_info rc; struct epoch_tracker et; lltable_fill_sa_entry(ln, (struct sockaddr *)&sin6); @@ -1573,7 +1574,7 @@ nd6_free_redirect(const struct llentry *ln) NET_EPOCH_ENTER(et); for (fibnum = 0; fibnum < rt_numfibs; fibnum++) - rtrequest1_fib(RTM_DELETE, &info, NULL, fibnum); + rib_action(fibnum, RTM_DELETE, &info, &rc); NET_EPOCH_EXIT(et); } diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index 1c5d219035d4..bd54a58c7747 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -674,7 +674,8 @@ static void defrouter_addreq(struct nd_defrouter *new) { struct sockaddr_in6 def, mask, gate; - struct rtentry *newrt = NULL; + struct rt_addrinfo info; + struct rib_cmd_info rc; unsigned int fibnum; int error; @@ -688,11 +689,16 @@ defrouter_addreq(struct nd_defrouter *new) gate.sin6_addr = new->rtaddr; fibnum = new->ifp->if_fib; - error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&def, - (struct sockaddr *)&gate, (struct sockaddr *)&mask, - RTF_GATEWAY, &newrt, fibnum); - if (newrt != NULL) - rt_routemsg(RTM_ADD, newrt, new->ifp, 0, fibnum); + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = RTF_GATEWAY; + info.rti_info[RTAX_DST] = (struct sockaddr *)&def; + info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&gate; + info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask; + + NET_EPOCH_ASSERT(); + error = rib_action(fibnum, RTM_ADD, &info, &rc); + if (rc.rc_rt != NULL) + rt_routemsg(RTM_ADD, rc.rc_rt, new->ifp, 0, fibnum); if (error == 0) new->installed = 1; } @@ -706,7 +712,8 @@ static void defrouter_delreq(struct nd_defrouter *dr) { struct sockaddr_in6 def, mask, gate; - struct rtentry *oldrt = NULL; + struct rt_addrinfo info; + struct rib_cmd_info rc; struct epoch_tracker et; unsigned int fibnum; @@ -720,12 +727,16 @@ defrouter_delreq(struct nd_defrouter *dr) gate.sin6_addr = dr->rtaddr; fibnum = dr->ifp->if_fib; + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = RTF_GATEWAY; + info.rti_info[RTAX_DST] = (struct sockaddr *)&def; + info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&gate; + info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask; + NET_EPOCH_ENTER(et); - in6_rtrequest(RTM_DELETE, (struct sockaddr *)&def, - (struct sockaddr *)&gate, - (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt, fibnum); - if (oldrt != NULL) - rt_routemsg(RTM_DELETE, oldrt, dr->ifp, 0, fibnum); + rib_action(fibnum, RTM_DELETE, &info, &rc); + if (rc.rc_rt != NULL) + rt_routemsg(RTM_DELETE, rc.rc_rt, dr->ifp, 0, fibnum); NET_EPOCH_EXIT(et); dr->installed = 0; @@ -2009,7 +2020,6 @@ static int nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) { struct sockaddr_dl_short sdl; - struct rtentry *rt; struct sockaddr_in6 mask6; u_long rtflags; int error, a_failure, fibnum, maxfib; @@ -2034,11 +2044,17 @@ nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) } a_failure = 0; for (; fibnum < maxfib; fibnum++) { + struct rt_addrinfo info; + struct rib_cmd_info rc; - rt = NULL; - error = in6_rtrequest(RTM_ADD, - (struct sockaddr *)&pr->ndpr_prefix, (struct sockaddr *)&sdl, - (struct sockaddr *)&mask6, rtflags, &rt, fibnum); + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = rtflags; + info.rti_info[RTAX_DST] = (struct sockaddr *)&pr->ndpr_prefix; + info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&sdl; + info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask6; + + NET_EPOCH_ASSERT(); + error = rib_action(fibnum, RTM_ADD, &info, &rc); if (error != 0) { char ip6buf[INET6_ADDRSTRLEN]; char ip6bufg[INET6_ADDRSTRLEN]; @@ -2061,7 +2077,7 @@ nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) } pr->ndpr_stateflags |= NDPRF_ONLINK; - rt_routemsg(RTM_ADD, rt, pr->ndpr_ifp, 0, fibnum); + rt_routemsg(RTM_ADD, rc.rc_rt, pr->ndpr_ifp, 0, fibnum); } /* Return the last error we got. */ @@ -2158,7 +2174,6 @@ nd6_prefix_offlink(struct nd_prefix *pr) struct ifnet *ifp = pr->ndpr_ifp; struct nd_prefix *opr; struct sockaddr_in6 sa6, mask6; - struct rtentry *rt; char ip6buf[INET6_ADDRSTRLEN]; uint64_t genid; int fibnum, maxfib, a_failure; @@ -2191,9 +2206,17 @@ nd6_prefix_offlink(struct nd_prefix *pr) a_failure = 0; NET_EPOCH_ENTER(et); for (; fibnum < maxfib; fibnum++) { - rt = NULL; - error = in6_rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, - (struct sockaddr *)&mask6, 0, &rt, fibnum); + struct rt_addrinfo info; + struct rib_cmd_info rc; + + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = RTF_GATEWAY; + info.rti_info[RTAX_DST] = (struct sockaddr *)&sa6; + info.rti_info[RTAX_GATEWAY] = NULL; + info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask6; + + NET_EPOCH_ASSERT(); + error = rib_action(fibnum, RTM_DELETE, &info, &rc); if (error != 0) { /* Save last error to return, see rtinit(). */ a_failure = error; @@ -2201,7 +2224,7 @@ nd6_prefix_offlink(struct nd_prefix *pr) } /* report route deletion to the routing socket. */ - rt_routemsg(RTM_DELETE, rt, ifp, 0, fibnum); + rt_routemsg(RTM_DELETE, rc.rc_rt, ifp, 0, fibnum); } NET_EPOCH_EXIT(et); error = a_failure; From 725871230d25c652781ccfe0da0de01570fded93 Mon Sep 17 00:00:00 2001 From: "Alexander V. Chernikov" Date: Sun, 19 Jul 2020 10:53:15 +0000 Subject: [PATCH 044/287] Temporarly revert r363319 to unbreak the build. Reported by: CI Pointy hat to: melifaro --- sys/fs/nfsclient/nfs_clvfsops.c | 15 ++--- sys/net/if.c | 4 +- sys/net/route.c | 113 +++++++++++++++++++++++++++++--- sys/net/route.h | 3 + sys/netinet6/in6_rmx.c | 11 ++++ sys/netinet6/in6_var.h | 2 + sys/netinet6/nd6.c | 3 +- sys/netinet6/nd6_rtr.c | 69 +++++++------------ 8 files changed, 148 insertions(+), 72 deletions(-) diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c index 7124c10573fa..5490155da68c 100644 --- a/sys/fs/nfsclient/nfs_clvfsops.c +++ b/sys/fs/nfsclient/nfs_clvfsops.c @@ -68,7 +68,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include @@ -467,8 +466,6 @@ nfs_mountroot(struct mount *mp) nd->mygateway.sin_addr.s_addr != 0) { struct sockaddr_in mask, sin; struct epoch_tracker et; - struct rt_addrinfo info; - struct rib_cmd_info rc; bzero((caddr_t)&mask, sizeof(mask)); sin = mask; @@ -477,14 +474,10 @@ nfs_mountroot(struct mount *mp) /* XXX MRT use table 0 for this sort of thing */ NET_EPOCH_ENTER(et); CURVNET_SET(TD_TO_VNET(td)); - - bzero((caddr_t)&info, sizeof(info)); - info.rti_flags = RTF_UP | RTF_GATEWAY; - info.rti_info[RTAX_DST] = (struct sockaddr *)&sin; - info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&nd->mygateway; - info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask; - - error = rib_action(RT_DEFAULT_FIB, RTM_ADD, &info, &rc); + error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin, + (struct sockaddr *)&nd->mygateway, + (struct sockaddr *)&mask, + RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB); CURVNET_RESTORE(); NET_EPOCH_EXIT(et); if (error) diff --git a/sys/net/if.c b/sys/net/if.c index 59dd38267cfc..bccbba268b56 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -80,7 +80,6 @@ #include #include #include -#include #include #if defined(INET) || defined(INET6) @@ -1846,7 +1845,6 @@ static int ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa, struct sockaddr *ia) { - struct rib_cmd_info rc; struct epoch_tracker et; int error; struct rt_addrinfo info; @@ -1874,7 +1872,7 @@ ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa, info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl; link_init_sdl(ifp, (struct sockaddr *)&null_sdl, ifp->if_type); - error = rib_action(ifp->if_fib, cmd, &info, &rc); + error = rtrequest1_fib(cmd, &info, NULL, ifp->if_fib); NET_EPOCH_EXIT(et); if (rti_ifa != NULL) diff --git a/sys/net/route.c b/sys/net/route.c index f24200a88e40..0b7a0e2d55b6 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -470,7 +470,7 @@ int rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, struct sockaddr *author, struct ifnet *ifp, int flags, int lifetime_sec) { - struct rib_cmd_info rc; + struct rtentry *rt; int error; struct rt_addrinfo info; struct rt_metrics rti_rmx; @@ -504,7 +504,7 @@ rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, info.rti_mflags |= RTV_EXPIRE; info.rti_rmx = &rti_rmx; - error = rib_action(fibnum, RTM_ADD, &info, &rc); + error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); ifa_free(ifa); if (error != 0) { @@ -512,9 +512,9 @@ rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, return (error); } - RT_LOCK(rc.rc_rt); - flags = rc.rc_rt->rt_flags; - RT_UNLOCK(rc.rc_rt); + RT_LOCK(rt); + flags = rt->rt_flags; + RT_UNLOCK(rt); RTSTAT_INC(rts_dynamic); @@ -602,6 +602,32 @@ ifa_ifwithroute(int flags, const struct sockaddr *dst, return (ifa); } +/* + * Do appropriate manipulations of a routing tree given + * all the bits of info needed + */ +int +rtrequest_fib(int req, + struct sockaddr *dst, + struct sockaddr *gateway, + struct sockaddr *netmask, + int flags, + struct rtentry **ret_nrt, + u_int fibnum) +{ + struct rt_addrinfo info; + + if (dst->sa_len == 0) + return(EINVAL); + + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = flags; + info.rti_info[RTAX_DST] = dst; + info.rti_info[RTAX_GATEWAY] = gateway; + info.rti_info[RTAX_NETMASK] = netmask; + return rtrequest1_fib(req, &info, ret_nrt, fibnum); +} + /* * Copy most of @rt data into @info. @@ -1122,6 +1148,73 @@ rt_mpath_unlink(struct rib_head *rnh, struct rt_addrinfo *info, } #endif +int +rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, + u_int fibnum) +{ + const struct sockaddr *dst; + struct rib_head *rnh; + struct rib_cmd_info rc; + int error; + + KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum")); + KASSERT((info->rti_flags & RTF_RNH_LOCKED) == 0, ("rtrequest1_fib: locked")); + NET_EPOCH_ASSERT(); + + dst = info->rti_info[RTAX_DST]; + + switch (dst->sa_family) { + case AF_INET6: + case AF_INET: + /* We support multiple FIBs. */ + break; + default: + fibnum = RT_DEFAULT_FIB; + break; + } + + /* + * Find the correct routing tree to use for this Address Family + */ + rnh = rt_tables_get_rnh(fibnum, dst->sa_family); + if (rnh == NULL) + return (EAFNOSUPPORT); + + /* + * If we are adding a host route then we don't want to put + * a netmask in the tree, nor do we want to clone it. + */ + if (info->rti_flags & RTF_HOST) + info->rti_info[RTAX_NETMASK] = NULL; + + bzero(&rc, sizeof(struct rib_cmd_info)); + error = 0; + switch (req) { + case RTM_DELETE: + error = del_route(rnh, info, &rc); + break; + case RTM_RESOLVE: + /* + * resolve was only used for route cloning + * here for compat + */ + break; + case RTM_ADD: + error = add_route(rnh, info, &rc); + break; + case RTM_CHANGE: + error = change_route(rnh, info, &rc); + break; + default: + error = EOPNOTSUPP; + } + + if (ret_nrt != NULL) + *ret_nrt = rc.rc_rt; + + return (error); +} + void rt_setmetrics(const struct rt_addrinfo *info, struct rtentry *rt) { @@ -1165,7 +1258,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) struct epoch_tracker et; struct sockaddr *dst; struct sockaddr *netmask; - struct rib_cmd_info rc; + struct rtentry *rt = NULL; struct rt_addrinfo info; int error = 0; int startfib, endfib; @@ -1256,7 +1349,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) if (rn == NULL) error = ESRCH; else { - struct rtentry *rt = RNTORT(rn); + rt = RNTORT(rn); /* * for interface route the gateway * gateway is sockaddr_dl, so @@ -1296,14 +1389,14 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; info.rti_info[RTAX_NETMASK] = netmask; NET_EPOCH_ENTER(et); - error = rib_action(fibnum, cmd, &info, &rc); - if (error == 0 && rc.rc_rt != NULL) { + error = rtrequest1_fib(cmd, &info, &rt, fibnum); + if (error == 0 && rt != NULL) { /* * notify any listening routing agents of the change */ /* TODO: interface routes/aliases */ - rt_newaddrmsg_fib(cmd, ifa, rc.rc_rt, fibnum); + rt_newaddrmsg_fib(cmd, ifa, rt, fibnum); didwork = 1; } NET_EPOCH_EXIT(et); diff --git a/sys/net/route.h b/sys/net/route.h index 1ffabcbc86df..fad32d1a5ee1 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -411,6 +411,9 @@ int rtinit(struct ifaddr *, int, int); * but this will change.. */ int rtioctl_fib(u_long, caddr_t, u_int); +int rtrequest_fib(int, struct sockaddr *, + struct sockaddr *, struct sockaddr *, int, struct rtentry **, u_int); +int rtrequest1_fib(int, struct rt_addrinfo *, struct rtentry **, u_int); int rib_lookup_info(uint32_t, const struct sockaddr *, uint32_t, uint32_t, struct rt_addrinfo *); void rib_free_info(struct rt_addrinfo *info); diff --git a/sys/netinet6/in6_rmx.c b/sys/netinet6/in6_rmx.c index 357292c5c59d..5600feee8e6a 100644 --- a/sys/netinet6/in6_rmx.c +++ b/sys/netinet6/in6_rmx.c @@ -185,3 +185,14 @@ in6_detachhead(void **head, int off) } #endif +/* + * Extended API for IPv6 FIB support. + */ +int +in6_rtrequest(int req, struct sockaddr *dst, struct sockaddr *gw, + struct sockaddr *mask, int flags, struct rtentry **ret_nrt, u_int fibnum) +{ + + return (rtrequest_fib(req, dst, gw, mask, flags, ret_nrt, fibnum)); +} + diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index b94e52cac7cd..1ca181d83c97 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -915,6 +915,8 @@ void in6_newaddrmsg(struct in6_ifaddr *, int); * Extended API for IPv6 FIB support. */ struct mbuf *ip6_tryforward(struct mbuf *); +int in6_rtrequest(int, struct sockaddr *, struct sockaddr *, + struct sockaddr *, int, struct rtentry **, u_int); #endif /* _KERNEL */ #endif /* _NETINET6_IN6_VAR_H_ */ diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index bb488dbc6ff1..e2df8ad2aea3 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -1564,7 +1564,6 @@ nd6_free_redirect(const struct llentry *ln) int fibnum; struct sockaddr_in6 sin6; struct rt_addrinfo info; - struct rib_cmd_info rc; struct epoch_tracker et; lltable_fill_sa_entry(ln, (struct sockaddr *)&sin6); @@ -1574,7 +1573,7 @@ nd6_free_redirect(const struct llentry *ln) NET_EPOCH_ENTER(et); for (fibnum = 0; fibnum < rt_numfibs; fibnum++) - rib_action(fibnum, RTM_DELETE, &info, &rc); + rtrequest1_fib(RTM_DELETE, &info, NULL, fibnum); NET_EPOCH_EXIT(et); } diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index bd54a58c7747..1c5d219035d4 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -674,8 +674,7 @@ static void defrouter_addreq(struct nd_defrouter *new) { struct sockaddr_in6 def, mask, gate; - struct rt_addrinfo info; - struct rib_cmd_info rc; + struct rtentry *newrt = NULL; unsigned int fibnum; int error; @@ -689,16 +688,11 @@ defrouter_addreq(struct nd_defrouter *new) gate.sin6_addr = new->rtaddr; fibnum = new->ifp->if_fib; - bzero((caddr_t)&info, sizeof(info)); - info.rti_flags = RTF_GATEWAY; - info.rti_info[RTAX_DST] = (struct sockaddr *)&def; - info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&gate; - info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask; - - NET_EPOCH_ASSERT(); - error = rib_action(fibnum, RTM_ADD, &info, &rc); - if (rc.rc_rt != NULL) - rt_routemsg(RTM_ADD, rc.rc_rt, new->ifp, 0, fibnum); + error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&def, + (struct sockaddr *)&gate, (struct sockaddr *)&mask, + RTF_GATEWAY, &newrt, fibnum); + if (newrt != NULL) + rt_routemsg(RTM_ADD, newrt, new->ifp, 0, fibnum); if (error == 0) new->installed = 1; } @@ -712,8 +706,7 @@ static void defrouter_delreq(struct nd_defrouter *dr) { struct sockaddr_in6 def, mask, gate; - struct rt_addrinfo info; - struct rib_cmd_info rc; + struct rtentry *oldrt = NULL; struct epoch_tracker et; unsigned int fibnum; @@ -727,16 +720,12 @@ defrouter_delreq(struct nd_defrouter *dr) gate.sin6_addr = dr->rtaddr; fibnum = dr->ifp->if_fib; - bzero((caddr_t)&info, sizeof(info)); - info.rti_flags = RTF_GATEWAY; - info.rti_info[RTAX_DST] = (struct sockaddr *)&def; - info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&gate; - info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask; - NET_EPOCH_ENTER(et); - rib_action(fibnum, RTM_DELETE, &info, &rc); - if (rc.rc_rt != NULL) - rt_routemsg(RTM_DELETE, rc.rc_rt, dr->ifp, 0, fibnum); + in6_rtrequest(RTM_DELETE, (struct sockaddr *)&def, + (struct sockaddr *)&gate, + (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt, fibnum); + if (oldrt != NULL) + rt_routemsg(RTM_DELETE, oldrt, dr->ifp, 0, fibnum); NET_EPOCH_EXIT(et); dr->installed = 0; @@ -2020,6 +2009,7 @@ static int nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) { struct sockaddr_dl_short sdl; + struct rtentry *rt; struct sockaddr_in6 mask6; u_long rtflags; int error, a_failure, fibnum, maxfib; @@ -2044,17 +2034,11 @@ nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) } a_failure = 0; for (; fibnum < maxfib; fibnum++) { - struct rt_addrinfo info; - struct rib_cmd_info rc; - bzero((caddr_t)&info, sizeof(info)); - info.rti_flags = rtflags; - info.rti_info[RTAX_DST] = (struct sockaddr *)&pr->ndpr_prefix; - info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&sdl; - info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask6; - - NET_EPOCH_ASSERT(); - error = rib_action(fibnum, RTM_ADD, &info, &rc); + rt = NULL; + error = in6_rtrequest(RTM_ADD, + (struct sockaddr *)&pr->ndpr_prefix, (struct sockaddr *)&sdl, + (struct sockaddr *)&mask6, rtflags, &rt, fibnum); if (error != 0) { char ip6buf[INET6_ADDRSTRLEN]; char ip6bufg[INET6_ADDRSTRLEN]; @@ -2077,7 +2061,7 @@ nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) } pr->ndpr_stateflags |= NDPRF_ONLINK; - rt_routemsg(RTM_ADD, rc.rc_rt, pr->ndpr_ifp, 0, fibnum); + rt_routemsg(RTM_ADD, rt, pr->ndpr_ifp, 0, fibnum); } /* Return the last error we got. */ @@ -2174,6 +2158,7 @@ nd6_prefix_offlink(struct nd_prefix *pr) struct ifnet *ifp = pr->ndpr_ifp; struct nd_prefix *opr; struct sockaddr_in6 sa6, mask6; + struct rtentry *rt; char ip6buf[INET6_ADDRSTRLEN]; uint64_t genid; int fibnum, maxfib, a_failure; @@ -2206,17 +2191,9 @@ nd6_prefix_offlink(struct nd_prefix *pr) a_failure = 0; NET_EPOCH_ENTER(et); for (; fibnum < maxfib; fibnum++) { - struct rt_addrinfo info; - struct rib_cmd_info rc; - - bzero((caddr_t)&info, sizeof(info)); - info.rti_flags = RTF_GATEWAY; - info.rti_info[RTAX_DST] = (struct sockaddr *)&sa6; - info.rti_info[RTAX_GATEWAY] = NULL; - info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask6; - - NET_EPOCH_ASSERT(); - error = rib_action(fibnum, RTM_DELETE, &info, &rc); + rt = NULL; + error = in6_rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, + (struct sockaddr *)&mask6, 0, &rt, fibnum); if (error != 0) { /* Save last error to return, see rtinit(). */ a_failure = error; @@ -2224,7 +2201,7 @@ nd6_prefix_offlink(struct nd_prefix *pr) } /* report route deletion to the routing socket. */ - rt_routemsg(RTM_DELETE, rc.rc_rt, ifp, 0, fibnum); + rt_routemsg(RTM_DELETE, rt, ifp, 0, fibnum); } NET_EPOCH_EXIT(et); error = a_failure; From 55ec696d42d080904411163ebece1a489044fc69 Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sun, 19 Jul 2020 12:22:32 +0000 Subject: [PATCH 045/287] Add missing bitset(9) MLINKS. MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25713 --- share/man/man9/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index c44805c01c9b..ee065b020999 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -607,13 +607,19 @@ MLINKS+=bitset.9 BITSET_DEFINE.9 \ bitset.9 BIT_EMPTY.9 \ bitset.9 BIT_ISFULLSET.9 \ bitset.9 BIT_FFS.9 \ + bitset.9 BIT_FLS.9 \ bitset.9 BIT_COUNT.9 \ bitset.9 BIT_SUBSET.9 \ bitset.9 BIT_OVERLAP.9 \ bitset.9 BIT_CMP.9 \ bitset.9 BIT_OR.9 \ + bitset.9 BIT_OR2.9 \ bitset.9 BIT_AND.9 \ + bitset.9 BIT_AND2.9 \ bitset.9 BIT_ANDNOT.9 \ + bitset.9 BIT_ANDNOT2.9 \ + bitset.9 BIT_XOR.9 \ + bitset.9 BIT_XOR2.9 \ bitset.9 BIT_CLR_ATOMIC.9 \ bitset.9 BIT_SET_ATOMIC.9 \ bitset.9 BIT_SET_ATOMIC_ACQ.9 \ From aa7541214620fb90fdcf5e3a3491c51a2d49c69e Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Sun, 19 Jul 2020 12:25:03 +0000 Subject: [PATCH 046/287] Make linux(4) support the BLKPBSZGET ioctl. Oracle uses it. MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25694 --- sys/compat/linux/linux_ioctl.c | 25 +++++++++++++++++++++++-- sys/compat/linux/linux_ioctl.h | 3 ++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index 5ec47c30b882..15162490ba44 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -285,9 +285,9 @@ linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args) { struct file *fp; int error; - u_int sectorsize; + u_int sectorsize, psectorsize; uint64_t blksize64; - off_t mediasize; + off_t mediasize, stripesize; error = fget(td, args->fd, &cap_ioctl_rights, &fp); if (error != 0) @@ -327,6 +327,27 @@ linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args) return (copyout(§orsize, (void *)args->arg, sizeof(sectorsize))); break; + case LINUX_BLKPBSZGET: + error = fo_ioctl(fp, DIOCGSTRIPESIZE, + (caddr_t)&stripesize, td->td_ucred, td); + if (error != 0) { + fdrop(fp, td); + return (error); + } + if (stripesize > 0 && stripesize <= 4096) { + psectorsize = stripesize; + } else { + error = fo_ioctl(fp, DIOCGSECTORSIZE, + (caddr_t)§orsize, td->td_ucred, td); + if (error != 0) { + fdrop(fp, td); + return (error); + } + psectorsize = sectorsize; + } + fdrop(fp, td); + return (copyout(&psectorsize, (void *)args->arg, + sizeof(psectorsize))); } fdrop(fp, td); return (ENOIOCTL); diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h index 15fd560e116b..c425a6e721eb 100644 --- a/sys/compat/linux/linux_ioctl.h +++ b/sys/compat/linux/linux_ioctl.h @@ -58,9 +58,10 @@ #define LINUX_BLKSECTGET 0x1267 #define LINUX_BLKSSZGET 0x1268 #define LINUX_BLKGETSIZE64 0x1272 +#define LINUX_BLKPBSZGET 0x127b #define LINUX_IOCTL_DISK_MIN LINUX_BLKROSET -#define LINUX_IOCTL_DISK_MAX LINUX_BLKGETSIZE64 +#define LINUX_IOCTL_DISK_MAX LINUX_BLKPBSZGET /* * hdio From 8745f898c47acf40f91cab16d923ce507ed8c15e Mon Sep 17 00:00:00 2001 From: Michael Tuexen Date: Sun, 19 Jul 2020 12:34:19 +0000 Subject: [PATCH 047/287] Add reference counts for inp/stcb/net when timers are running. This avoids a use-after-free reported for the userland stack. Thanks to Taylor Brandstetter for suggesting a patch for the userland stack. MFC after: 1 week --- sys/netinet/sctp_os_bsd.h | 17 +++-- sys/netinet/sctp_pcb.c | 73 ++++++++++++-------- sys/netinet/sctp_var.h | 1 - sys/netinet/sctputil.c | 136 ++++++++++++++++++++++++-------------- sys/netinet/sctputil.h | 8 +++ 5 files changed, 153 insertions(+), 82 deletions(-) diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h index 0b5c23a60b73..932a1efb004d 100644 --- a/sys/netinet/sctp_os_bsd.h +++ b/sys/netinet/sctp_os_bsd.h @@ -269,12 +269,17 @@ typedef struct callout sctp_os_timer_t; #define SCTP_OS_TIMER_INIT(tmr) callout_init(tmr, 1) -#define SCTP_OS_TIMER_START callout_reset -#define SCTP_OS_TIMER_STOP callout_stop -#define SCTP_OS_TIMER_STOP_DRAIN callout_drain -#define SCTP_OS_TIMER_PENDING callout_pending -#define SCTP_OS_TIMER_ACTIVE callout_active -#define SCTP_OS_TIMER_DEACTIVATE callout_deactivate +/* + * NOTE: The next two shouldn't be called directly outside of sctp_timer_start() + * and sctp_timer_stop(), since they don't handle incrementing/decrementing + * relevant reference counts. + */ +#define SCTP_OS_TIMER_START callout_reset +#define SCTP_OS_TIMER_STOP callout_stop +#define SCTP_OS_TIMER_STOP_DRAIN callout_drain +#define SCTP_OS_TIMER_PENDING callout_pending +#define SCTP_OS_TIMER_ACTIVE callout_active +#define SCTP_OS_TIMER_DEACTIVATE callout_deactivate #define sctp_get_tick_count() (ticks) diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 719e80c171aa..fc5e2356ba8a 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -2739,23 +2739,54 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, } } } - /* - * Now any running timers need to be adjusted since we really don't - * care if they are running or not just blast in the new_inp into - * all of them. - */ - - stcb->asoc.dack_timer.ep = (void *)new_inp; - stcb->asoc.asconf_timer.ep = (void *)new_inp; - stcb->asoc.strreset_timer.ep = (void *)new_inp; - stcb->asoc.shut_guard_timer.ep = (void *)new_inp; - stcb->asoc.autoclose_timer.ep = (void *)new_inp; - stcb->asoc.delete_prim_timer.ep = (void *)new_inp; + /* Now any running timers need to be adjusted. */ + if (stcb->asoc.dack_timer.ep == old_inp) { + SCTP_INP_DECR_REF(old_inp); + stcb->asoc.dack_timer.ep = new_inp; + SCTP_INP_INCR_REF(new_inp); + } + if (stcb->asoc.asconf_timer.ep == old_inp) { + SCTP_INP_DECR_REF(old_inp); + stcb->asoc.asconf_timer.ep = new_inp; + SCTP_INP_INCR_REF(new_inp); + } + if (stcb->asoc.strreset_timer.ep == old_inp) { + SCTP_INP_DECR_REF(old_inp); + stcb->asoc.strreset_timer.ep = new_inp; + SCTP_INP_INCR_REF(new_inp); + } + if (stcb->asoc.shut_guard_timer.ep == old_inp) { + SCTP_INP_DECR_REF(old_inp); + stcb->asoc.shut_guard_timer.ep = new_inp; + SCTP_INP_INCR_REF(new_inp); + } + if (stcb->asoc.autoclose_timer.ep == old_inp) { + SCTP_INP_DECR_REF(old_inp); + stcb->asoc.autoclose_timer.ep = new_inp; + SCTP_INP_INCR_REF(new_inp); + } + if (stcb->asoc.delete_prim_timer.ep == old_inp) { + SCTP_INP_DECR_REF(old_inp); + stcb->asoc.delete_prim_timer.ep = new_inp; + SCTP_INP_INCR_REF(new_inp); + } /* now what about the nets? */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - net->pmtu_timer.ep = (void *)new_inp; - net->hb_timer.ep = (void *)new_inp; - net->rxt_timer.ep = (void *)new_inp; + if (net->pmtu_timer.ep == old_inp) { + SCTP_INP_DECR_REF(old_inp); + net->pmtu_timer.ep = new_inp; + SCTP_INP_INCR_REF(new_inp); + } + if (net->hb_timer.ep == old_inp) { + SCTP_INP_DECR_REF(old_inp); + net->hb_timer.ep = new_inp; + SCTP_INP_INCR_REF(new_inp); + } + if (net->rxt_timer.ep == old_inp) { + SCTP_INP_DECR_REF(old_inp); + net->rxt_timer.ep = new_inp; + SCTP_INP_INCR_REF(new_inp); + } } SCTP_INP_WUNLOCK(new_inp); SCTP_INP_WUNLOCK(old_inp); @@ -3562,7 +3593,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) being_refed++; if (SCTP_ASOC_CREATE_LOCK_CONTENDED(inp)) being_refed++; - + /* NOTE: 0 refcount also means no timers are referencing us. */ if ((inp->refcount) || (being_refed) || (inp->sctp_flags & SCTP_PCB_FLAGS_CLOSE_IP)) { @@ -3584,16 +3615,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) SCTP_INP_WUNLOCK(inp); SCTP_ASOC_CREATE_UNLOCK(inp); SCTP_INP_INFO_WUNLOCK(); - /* - * Now we release all locks. Since this INP cannot be found anymore - * except possibly by the kill timer that might be running. We call - * the drain function here. It should hit the case were it sees the - * ACTIVE flag cleared and exit out freeing us to proceed and - * destroy everything. - */ - if (from != SCTP_CALLED_FROM_INPKILL_TIMER) { - (void)SCTP_OS_TIMER_STOP_DRAIN(&inp->sctp_ep.signature_change.timer); - } #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 5); diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h index d9b20f278577..b15721099e5a 100644 --- a/sys/netinet/sctp_var.h +++ b/sys/netinet/sctp_var.h @@ -186,7 +186,6 @@ extern struct pr_usrreqs sctp_usrreqs; #define sctp_free_remote_addr(__net) { \ if ((__net)) { \ if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&(__net)->ref_count)) { \ - (void)SCTP_OS_TIMER_STOP(&(__net)->rxt_timer.timer); \ RO_NHFREE(&(__net)->ro); \ if ((__net)->src_addr_selected) { \ sctp_free_ifa((__net)->ro._s_addr); \ diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 5ef396cff246..41c202c0d62f 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -1713,16 +1713,22 @@ sctp_timeout_handler(void *t) struct sctp_nets *net; struct sctp_timer *tmr; struct mbuf *op_err; - int did_output; int type; int i, secret; + bool did_output, released_asoc_reference; + /* + * If inp, stcb or net are not NULL, then references to these were + * added when the timer was started, and must be released before + * this function returns. + */ tmr = (struct sctp_timer *)t; inp = (struct sctp_inpcb *)tmr->ep; stcb = (struct sctp_tcb *)tmr->tcb; net = (struct sctp_nets *)tmr->net; CURVNET_SET((struct vnet *)tmr->vnet); did_output = 1; + released_asoc_reference = false; #ifdef SCTP_AUDITING_ENABLED sctp_audit_log(0xF0, (uint8_t)tmr->type); @@ -1738,56 +1744,39 @@ sctp_timeout_handler(void *t) KASSERT(stcb == NULL || stcb->sctp_ep == inp, ("sctp_timeout_handler of type %d: inp = %p, stcb->sctp_ep %p", type, stcb, stcb->sctp_ep)); - if (inp) { - SCTP_INP_INCR_REF(inp); - } tmr->stopped_from = 0xa001; - if (stcb) { - atomic_add_int(&stcb->asoc.refcnt, 1); - if (stcb->asoc.state == 0) { - atomic_add_int(&stcb->asoc.refcnt, -1); - if (inp) { - SCTP_INP_DECR_REF(inp); - } - SCTPDBG(SCTP_DEBUG_TIMER2, - "Timer type %d handler exiting due to CLOSED association.\n", - type); - CURVNET_RESTORE(); - return; - } + if ((stcb != NULL) && (stcb->asoc.state == SCTP_STATE_EMPTY)) { + SCTPDBG(SCTP_DEBUG_TIMER2, + "Timer type %d handler exiting due to CLOSED association.\n", + type); + goto out_decr; } tmr->stopped_from = 0xa002; SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d goes off.\n", type); if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { - if (inp) { - SCTP_INP_DECR_REF(inp); - } - if (stcb) { - atomic_add_int(&stcb->asoc.refcnt, -1); - } SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d handler exiting due to not being active.\n", type); - CURVNET_RESTORE(); - return; + goto out_decr; } tmr->stopped_from = 0xa003; if (stcb) { SCTP_TCB_LOCK(stcb); + /* + * Release reference so that association can be freed if + * necessary below. This is safe now that we have acquired + * the lock. + */ atomic_add_int(&stcb->asoc.refcnt, -1); + released_asoc_reference = true; if ((type != SCTP_TIMER_TYPE_ASOCKILL) && - ((stcb->asoc.state == 0) || + ((stcb->asoc.state == SCTP_STATE_EMPTY) || (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED))) { - SCTP_TCB_UNLOCK(stcb); - if (inp) { - SCTP_INP_DECR_REF(inp); - } SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d handler exiting due to CLOSED association.\n", type); - CURVNET_RESTORE(); - return; + goto out; } } else if (inp != NULL) { SCTP_INP_WLOCK(inp); @@ -1803,13 +1792,13 @@ sctp_timeout_handler(void *t) /* * Callout has been rescheduled. */ - goto get_out; + goto out; } if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { /* * Not active, so no action. */ - goto get_out; + goto out; } SCTP_OS_TIMER_DEACTIVATE(&tmr->timer); @@ -1836,6 +1825,7 @@ sctp_timeout_handler(void *t) sctp_auditing(4, inp, stcb, net); #endif sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); + did_output = true; if ((stcb->asoc.num_send_timers_up == 0) && (stcb->asoc.sent_queue_cnt > 0)) { struct sctp_tmit_chunk *chk; @@ -1866,8 +1856,7 @@ sctp_timeout_handler(void *t) /* no need to unlock on tcb its gone */ goto out_decr; } - /* We do output but not here */ - did_output = 0; + did_output = false; break; case SCTP_TIMER_TYPE_RECV: KASSERT(inp != NULL && stcb != NULL && net == NULL, @@ -1880,6 +1869,7 @@ sctp_timeout_handler(void *t) sctp_auditing(4, inp, stcb, NULL); #endif sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED); + did_output = true; break; case SCTP_TIMER_TYPE_SHUTDOWN: KASSERT(inp != NULL && stcb != NULL && net != NULL, @@ -1895,6 +1885,7 @@ sctp_timeout_handler(void *t) sctp_auditing(4, inp, stcb, net); #endif sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED); + did_output = true; break; case SCTP_TIMER_TYPE_HEARTBEAT: KASSERT(inp != NULL && stcb != NULL && net != NULL, @@ -1912,6 +1903,9 @@ sctp_timeout_handler(void *t) if (!(net->dest_state & SCTP_ADDR_NOHB)) { sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED); + did_output = true; + } else { + did_output = false; } break; case SCTP_TIMER_TYPE_COOKIE: @@ -1932,6 +1926,7 @@ sctp_timeout_handler(void *t) * respect to where from in chunk_output. */ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); + did_output = true; break; case SCTP_TIMER_TYPE_NEWCOOKIE: KASSERT(inp != NULL && stcb == NULL && net == NULL, @@ -1953,7 +1948,7 @@ sctp_timeout_handler(void *t) sctp_select_initial_TSN(&inp->sctp_ep); } sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL); - did_output = 0; + did_output = false; break; case SCTP_TIMER_TYPE_PATHMTURAISE: KASSERT(inp != NULL && stcb != NULL && net != NULL, @@ -1961,7 +1956,7 @@ sctp_timeout_handler(void *t) type, inp, stcb, net)); SCTP_STAT_INCR(sctps_timopathmtu); sctp_pathmtu_timer(inp, stcb, net); - did_output = 0; + did_output = false; break; case SCTP_TIMER_TYPE_SHUTDOWNACK: KASSERT(inp != NULL && stcb != NULL && net != NULL, @@ -1977,6 +1972,7 @@ sctp_timeout_handler(void *t) sctp_auditing(4, inp, stcb, net); #endif sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED); + did_output = true; break; case SCTP_TIMER_TYPE_ASCONF: KASSERT(inp != NULL && stcb != NULL && net != NULL, @@ -1991,6 +1987,7 @@ sctp_timeout_handler(void *t) sctp_auditing(4, inp, stcb, net); #endif sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED); + did_output = true; break; case SCTP_TIMER_TYPE_SHUTDOWNGUARD: KASSERT(inp != NULL && stcb != NULL && net == NULL, @@ -2000,6 +1997,7 @@ sctp_timeout_handler(void *t) op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), "Shutdown guard timer expired"); sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); + did_output = true; /* no need to unlock on tcb its gone */ goto out_decr; case SCTP_TIMER_TYPE_AUTOCLOSE: @@ -2009,7 +2007,7 @@ sctp_timeout_handler(void *t) SCTP_STAT_INCR(sctps_timoautoclose); sctp_autoclose_timer(inp, stcb); sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED); - did_output = 0; + did_output = true; break; case SCTP_TIMER_TYPE_STRRESET: KASSERT(inp != NULL && stcb != NULL && net == NULL, @@ -2021,6 +2019,7 @@ sctp_timeout_handler(void *t) goto out_decr; } sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED); + did_output = true; break; case SCTP_TIMER_TYPE_INPKILL: KASSERT(inp != NULL && stcb == NULL && net == NULL, @@ -2061,6 +2060,7 @@ sctp_timeout_handler(void *t) ("timeout of type %d: inp = %p, stcb = %p, net = %p", type, inp, stcb, net)); sctp_handle_addr_wq(); + did_output = true; break; case SCTP_TIMER_TYPE_PRIM_DELETED: KASSERT(inp != NULL && stcb != NULL && net == NULL, @@ -2068,20 +2068,22 @@ sctp_timeout_handler(void *t) type, inp, stcb, net)); SCTP_STAT_INCR(sctps_timodelprim); sctp_delete_prim_timer(inp, stcb); + did_output = false; break; default: #ifdef INVARIANTS panic("Unknown timer type %d", type); #else - goto get_out; + did_output = false; + goto out; #endif } #ifdef SCTP_AUDITING_ENABLED sctp_audit_log(0xF1, (uint8_t)type); - if (inp) + if (inp != NULL) sctp_auditing(5, inp, stcb, net); #endif - if ((did_output) && stcb) { + if (did_output && (stcb != NULL)) { /* * Now we need to clean up the control chunk chain if an * ECNE is on it. It must be marked as UNSENT again so next @@ -2091,8 +2093,8 @@ sctp_timeout_handler(void *t) */ sctp_fix_ecn_echo(&stcb->asoc); } -get_out: - if (stcb) { +out: + if (stcb != NULL) { SCTP_TCB_UNLOCK(stcb); } else if (inp != NULL) { SCTP_INP_WUNLOCK(inp); @@ -2101,10 +2103,16 @@ sctp_timeout_handler(void *t) } out_decr: - if (inp) { + /* These reference counts were incremented in sctp_timer_start(). */ + if (inp != NULL) { SCTP_INP_DECR_REF(inp); } - + if ((stcb != NULL) && !released_asoc_reference) { + atomic_add_int(&stcb->asoc.refcnt, -1); + } + if (net != NULL) { + sctp_free_remote_addr(net); + } out_no_decr: SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d handler finished.\n", type); CURVNET_RESTORE(); @@ -2538,6 +2546,19 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d started: ticks=%u, inp=%p, stcb=%p, net=%p.\n", t_type, to_ticks, inp, stcb, net); + /* + * If this is a newly scheduled callout, as opposed to a + * rescheduled one, increment relevant reference counts. + */ + if (tmr->ep != NULL) { + SCTP_INP_INCR_REF(inp); + } + if (tmr->tcb != NULL) { + atomic_add_int(&stcb->asoc.refcnt, 1); + } + if (tmr->net != NULL) { + atomic_add_int(&net->ref_count, 1); + } } else { /* * This should not happen, since we checked for pending @@ -2830,9 +2851,26 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d stopped: inp=%p, stcb=%p, net=%p.\n", t_type, inp, stcb, net); - tmr->ep = NULL; - tmr->tcb = NULL; - tmr->net = NULL; + /* + * If the timer was actually stopped, decrement reference + * counts that were incremented in sctp_timer_start(). + */ + if (tmr->ep != NULL) { + SCTP_INP_DECR_REF(inp); + tmr->ep = NULL; + } + if (tmr->tcb != NULL) { + atomic_add_int(&stcb->asoc.refcnt, -1); + tmr->tcb = NULL; + } + if (tmr->net != NULL) { + /* + * Can't use net, since it doesn't work for + * SCTP_TIMER_TYPE_ASCONF. + */ + sctp_free_remote_addr((struct sctp_nets *)tmr->net); + tmr->net = NULL; + } } else { SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d not stopped: inp=%p, stcb=%p, net=%p.\n", diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h index 797b2cb19679..b0b1e622f8b2 100644 --- a/sys/netinet/sctputil.h +++ b/sys/netinet/sctputil.h @@ -90,6 +90,14 @@ sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, void sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag); +/* + * NOTE: sctp_timer_start() will increment the reference count of any relevant + * structure the timer is referencing, in order to prevent a race condition + * between the timer executing and the structure being freed. + * + * When the timer fires or sctp_timer_stop() is called, these references are + * removed. + */ void sctp_timer_start(int, struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *); From 4c0fab716a80c362cbeddc317099229379849e86 Mon Sep 17 00:00:00 2001 From: Allan Jude Date: Sun, 19 Jul 2020 14:42:13 +0000 Subject: [PATCH 048/287] at(1): Markup environment variables with proper macros Submitted by: debdrup Reported by: 0mp Reviewed by: imp Sponsored by: Klara Inc. Differential Revision: https://reviews.freebsd.org/D25721 --- usr.bin/at/at.man | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/usr.bin/at/at.man b/usr.bin/at/at.man index 88af9d7f1c19..bcb51ad0055b 100644 --- a/usr.bin/at/at.man +++ b/usr.bin/at/at.man @@ -216,7 +216,11 @@ might not be optimal for every deployment. If a finer granularity is desired, the .Pa /etc/cron.d/at file can be edited and will be read by the system crontab, from which -the SHELL and PATH environment variables are inherited. +the +.Ev SHELL +and +.Ev PATH +environment variables are inherited. .Sh OPTIONS .Bl -tag -width indent .It Fl q Ar queue From f7d38a13a85b74dcedfe3957889edd40ece4cc2f Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sun, 19 Jul 2020 15:16:27 +0000 Subject: [PATCH 049/287] [net80211] Add new privileges; restrict what can be done in a jail. Split the MANAGE privilege into MANAGE, SETMAC and CREATE_VAP. + VAP_MANAGE is everything but setting the MAC and creating a VAP. + VAP_SETMAC is setting the MAC address of the VAP. Typically you wouldn't want the jail to be able to modify this. + CREATE_VAP is to create a new VAP. Again, you don't want to be doing this in a jail, but this DOES stop being able to run some corner cases like Dynamic WDS (DWDS) AP in a jail/vnet. We can figure this bit out later. This allows me to run wpa_supplicant in a jail after transferring a STA VAP into it. I unfortunately can't currently set the wlan debugging inside the jail; that would be super useful! Reviewed by: bz Differential Revision: https://reviews.freebsd.org/D25630 --- sys/kern/kern_jail.c | 6 ++---- sys/net80211/ieee80211_freebsd.c | 5 +++++ sys/net80211/ieee80211_ioctl.c | 15 ++++++++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index e09a2b66c64d..81000783265e 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -3107,10 +3107,8 @@ prison_priv_check(struct ucred *cred, int priv) /* * 802.11-related privileges. */ - case PRIV_NET80211_GETKEY: -#ifdef notyet - case PRIV_NET80211_MANAGE: /* XXX-BZ discuss with sam@ */ -#endif + case PRIV_NET80211_VAP_GETKEY: + case PRIV_NET80211_VAP_MANAGE: #ifdef notyet /* diff --git a/sys/net80211/ieee80211_freebsd.c b/sys/net80211/ieee80211_freebsd.c index 6b55357dd49f..c9afb8b5177a 100644 --- a/sys/net80211/ieee80211_freebsd.c +++ b/sys/net80211/ieee80211_freebsd.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -82,6 +83,10 @@ wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params) struct ieee80211com *ic; int error; + error = priv_check(curthread, PRIV_NET80211_CREATE_VAP); + if (error) + return error; + error = copyin(params, &cp, sizeof(cp)); if (error) return error; diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c index 0eed8667460e..0c3794f62669 100644 --- a/sys/net80211/ieee80211_ioctl.c +++ b/sys/net80211/ieee80211_ioctl.c @@ -106,7 +106,8 @@ ieee80211_ioctl_getkey(struct ieee80211vap *vap, struct ieee80211req *ireq) ik.ik_flags = wk->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV); if (wk->wk_keyix == vap->iv_def_txkey) ik.ik_flags |= IEEE80211_KEY_DEFAULT; - if (priv_check(curthread, PRIV_NET80211_GETKEY) == 0) { + /* XXX TODO: move priv check to ieee80211_freebsd.c */ + if (priv_check(curthread, PRIV_NET80211_VAP_GETKEY) == 0) { /* NB: only root can read key data */ ik.ik_keyrsc = wk->wk_keyrsc[IEEE80211_NONQOS_TID]; ik.ik_keytsc = wk->wk_keytsc; @@ -815,7 +816,8 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd, return EINVAL; len = (u_int) vap->iv_nw_keys[kid].wk_keylen; /* NB: only root can read WEP keys */ - if (priv_check(curthread, PRIV_NET80211_GETKEY) == 0) { + /* XXX TODO: move priv check to ieee80211_freebsd.c */ + if (priv_check(curthread, PRIV_NET80211_VAP_GETKEY) == 0) { bcopy(vap->iv_nw_keys[kid].wk_key, tmpkey, len); } else { bzero(tmpkey, len); @@ -3636,7 +3638,8 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) (struct ieee80211req *) data); break; case SIOCS80211: - error = priv_check(curthread, PRIV_NET80211_MANAGE); + /* XXX TODO: move priv check to ieee80211_freebsd.c */ + error = priv_check(curthread, PRIV_NET80211_VAP_MANAGE); if (error == 0) error = ieee80211_ioctl_set80211(vap, cmd, (struct ieee80211req *) data); @@ -3681,6 +3684,12 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } break; + case SIOCSIFLLADDR: + /* XXX TODO: move priv check to ieee80211_freebsd.c */ + error = priv_check(curthread, PRIV_NET80211_VAP_SETMAC); + if (error == 0) + break; + /* Fallthrough */ default: /* * Pass unknown ioctls first to the driver, and if it From 78957abd9e473ac4bafb3fe3fc4f59c8daa9e99d Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sun, 19 Jul 2020 16:07:51 +0000 Subject: [PATCH 050/287] [net80211] missing from last commit, le whoops Differential Revision:https://reviews.freebsd.org/D25630 --- sys/sys/priv.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/sys/priv.h b/sys/sys/priv.h index 26c4e85f83b8..f5f683f107ee 100644 --- a/sys/sys/priv.h +++ b/sys/sys/priv.h @@ -351,8 +351,10 @@ /* * 802.11-related privileges. */ -#define PRIV_NET80211_GETKEY 440 /* Query 802.11 keys. */ -#define PRIV_NET80211_MANAGE 441 /* Administer 802.11. */ +#define PRIV_NET80211_VAP_GETKEY 440 /* Query VAP 802.11 keys. */ +#define PRIV_NET80211_VAP_MANAGE 441 /* Administer 802.11 VAP */ +#define PRIV_NET80211_VAP_SETMAC 442 /* Set VAP MAC address */ +#define PRIV_NET80211_CREATE_VAP 443 /* Create a new VAP */ /* * Placeholder for AppleTalk privileges, not supported anymore. From 208b9eabb40e717d76852c2d4a6d51023a2b7630 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sun, 19 Jul 2020 17:27:48 +0000 Subject: [PATCH 051/287] [if_an] unbreak! .. I missed this when checking drivers. Differential Revision: https://reviews.freebsd.org/D25723 --- sys/dev/an/if_an.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/dev/an/if_an.c b/sys/dev/an/if_an.c index 9eb9843f444f..d8ec52be8040 100644 --- a/sys/dev/an/if_an.c +++ b/sys/dev/an/if_an.c @@ -2324,7 +2324,7 @@ an_ioctl(struct ifnet *ifp, u_long command, caddr_t data) } break; case SIOCS80211: - if ((error = priv_check(td, PRIV_NET80211_MANAGE))) + if ((error = priv_check(td, PRIV_NET80211_VAP_MANAGE))) goto out; AN_LOCK(sc); sc->areq.an_len = sizeof(sc->areq); From 0675f4e1ca75adb8c00df6bb961d4b3a950c1531 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Sun, 19 Jul 2020 17:47:55 +0000 Subject: [PATCH 052/287] Simplify non-pti syscall entry on amd64. Limit manipulations to use %rax as scratch to the pti portion of the syscall entry code. Submitted by: alc Reviewed by: markj MFC after: 1 week Differential revision: https://reviews.freebsd.org/D25722 --- sys/amd64/amd64/exception.S | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S index b85471b93169..948f6c40e776 100644 --- a/sys/amd64/amd64/exception.S +++ b/sys/amd64/amd64/exception.S @@ -526,17 +526,17 @@ prot_addrf: IDTVEC(fast_syscall_pti) swapgs lfence - movq %rax,PCPU(SCRATCH_RAX) cmpq $~0,PCPU(UCR3) je fast_syscall_common + movq %rax,PCPU(SCRATCH_RAX) movq PCPU(KCR3),%rax movq %rax,%cr3 + movq PCPU(SCRATCH_RAX),%rax jmp fast_syscall_common SUPERALIGN_TEXT IDTVEC(fast_syscall) swapgs lfence - movq %rax,PCPU(SCRATCH_RAX) fast_syscall_common: movq %rsp,PCPU(SCRATCH_RSP) movq PCPU(RSP0),%rsp @@ -547,7 +547,6 @@ fast_syscall_common: movq %rcx,TF_RIP(%rsp) /* %rcx original value is in %r10 */ movq PCPU(SCRATCH_RSP),%r11 /* %r11 already saved */ movq %r11,TF_RSP(%rsp) /* user stack pointer */ - movq PCPU(SCRATCH_RAX),%rax /* * Save a few arg registers early to free them for use in * handle_ibrs_entry(). %r10 is especially tricky. It is not an From d4fb0c0a560dec2834789ef0b32c73fcc67fd584 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Sun, 19 Jul 2020 18:53:19 +0000 Subject: [PATCH 053/287] The ds3231 RTC chip bitmask values for 12- versus 24-hour mode were reversed, flip them so that times in the 20:00:00 to 23:59:59 range read correctly. Reported by: Dr. Rolf Jansen Pointy hat: ian@ --- sys/dev/iicbus/ds3231reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/dev/iicbus/ds3231reg.h b/sys/dev/iicbus/ds3231reg.h index 86f087ce3095..1564d0960dc4 100644 --- a/sys/dev/iicbus/ds3231reg.h +++ b/sys/dev/iicbus/ds3231reg.h @@ -38,8 +38,8 @@ #define DS3231_MINS 0x01 #define DS3231_MINS_MASK 0x7f #define DS3231_HOUR 0x02 -#define DS3231_HOUR_MASK_12HR 0x3f -#define DS3231_HOUR_MASK_24HR 0x1f +#define DS3231_HOUR_MASK_12HR 0x1f +#define DS3231_HOUR_MASK_24HR 0x3f #define DS3231_HOUR_IS_PM 0x20 #define DS3231_HOUR_USE_AMPM 0x40 #define DS3231_WEEKDAY 0x03 From bd8f09eb493af54ab9ca882b2625170f8926966d Mon Sep 17 00:00:00 2001 From: Mitchell Horne Date: Sun, 19 Jul 2020 23:19:09 +0000 Subject: [PATCH 054/287] Make efirt module dependent on MK_EFI MK_EFI was added to kern.opts.mk in r331099, but is currently unused. Take advantage of that fact and gate the build of efirt behind it. Reviewed by: imp Differential Revision: https://reviews.freebsd.org/D24673 --- sys/modules/Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 230d875722e6..dff871fa7338 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -421,6 +421,12 @@ _ktls_ocf= ktls_ocf SUBDIR+= cuse .endif +.if ${MK_EFI} != "no" +.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "amd64" +_efirt= efirt +.endif +.endif + .if (${MK_INET_SUPPORT} != "no" || ${MK_INET6_SUPPORT} != "no") || \ defined(ALL_MODULES) _carp= carp @@ -585,7 +591,6 @@ _cxgb= cxgb .if ${MACHINE_CPUARCH} == "aarch64" _allwinner= allwinner _armv8crypto= armv8crypto -_efirt= efirt _em= em _rockchip= rockchip .endif @@ -707,7 +712,6 @@ _x86bios= x86bios .if ${MACHINE_CPUARCH} == "amd64" _amdgpio= amdgpio _ccp= ccp -_efirt= efirt _iavf= iavf _ioat= ioat _ixl= ixl From cf5cd89c3a93eb41213a0fe83be7ff79c3d9bb63 Mon Sep 17 00:00:00 2001 From: Mitchell Horne Date: Sun, 19 Jul 2020 23:34:52 +0000 Subject: [PATCH 055/287] riscv: look for bootargs in FDT The FDT may contain a short /chosen/bootargs string which we should pass to boot_parse_cmdline. Notably, this allows the use of qemu's -append option to pass things like -s to boot to single user mode. Submitted by: Nathaniel Filardo Reviewed by: mhorne MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25544 --- sys/riscv/riscv/machdep.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sys/riscv/riscv/machdep.c b/sys/riscv/riscv/machdep.c index 2c6bd016ce6d..6b42e9b4b8bc 100644 --- a/sys/riscv/riscv/machdep.c +++ b/sys/riscv/riscv/machdep.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -800,6 +801,19 @@ fake_preload_metadata(struct riscv_bootparams *rvbp) rvbp->kern_phys, rvbp->kern_phys + (lastaddr - KERNBASE)); } +#ifdef FDT +static void +parse_fdt_bootargs(void) +{ + char bootargs[512]; + + bootargs[sizeof(bootargs) - 1] = '\0'; + if (fdt_get_chosen_bootargs(bootargs, sizeof(bootargs) - 1) == 0) { + boothowto |= boot_parse_cmdline(bootargs); + } +} +#endif + static vm_offset_t parse_metadata(void) { @@ -829,6 +843,8 @@ parse_metadata(void) #endif #ifdef FDT try_load_dtb(kmdp); + if (kern_envp == NULL) + parse_fdt_bootargs(); #endif return (lastaddr); } From e17f5b1d307b7b8910d67883e57a9604305906d5 Mon Sep 17 00:00:00 2001 From: "Simon J. Gerraty" Date: Sun, 19 Jul 2020 23:54:00 +0000 Subject: [PATCH 056/287] Oops missed Makefile.config --- lib/libbearssl/Makefile.depend | 1 - lib/libc/Makefile | 2 +- lib/libsecureboot/local.trust.mk | 6 +++++- libexec/dma/dmagent/Makefile.depend | 2 -- libexec/rc/rc.d/tmp | 3 +++ sbin/veriexec/Makefile.depend | 2 +- stand/efi/loader/Makefile | 5 +++++ stand/i386/loader/Makefile | 10 +++++++--- usr.bin/bmake/unit-tests/Makefile.config | 11 +++++++++++ 9 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 usr.bin/bmake/unit-tests/Makefile.config diff --git a/lib/libbearssl/Makefile.depend b/lib/libbearssl/Makefile.depend index 6cfaab1c3644..8d409f5263ac 100644 --- a/lib/libbearssl/Makefile.depend +++ b/lib/libbearssl/Makefile.depend @@ -2,7 +2,6 @@ # Autogenerated - do NOT edit! DIRDEPS = \ - gnu/lib/csu \ include \ include/xlocale \ lib/${CSU_DIR} \ diff --git a/lib/libc/Makefile b/lib/libc/Makefile index d5cfe7e50013..5adc8d71eabb 100644 --- a/lib/libc/Makefile +++ b/lib/libc/Makefile @@ -186,7 +186,7 @@ SUBDIR.${MK_TESTS}+= tests .if (${LIBC_ARCH} == amd64 || ${LIBC_ARCH} == i386) && \ ${.TARGETS:Mall} == all && \ defined(LINKER_FEATURES) && ${LINKER_FEATURES:Mifunc} == "" -.error ${LIBC_ARCH} libc requires linker ifunc support +#.error ${LIBC_ARCH} libc requires linker ifunc support .endif .if !defined(_SKIP_BUILD) diff --git a/lib/libsecureboot/local.trust.mk b/lib/libsecureboot/local.trust.mk index b28e5ee2d1ef..77d45f95facd 100644 --- a/lib/libsecureboot/local.trust.mk +++ b/lib/libsecureboot/local.trust.mk @@ -8,6 +8,9 @@ # force these for Junos #MANIFEST_SKIP_ALWAYS= boot +MANIFEST_SKIP= boot +XCFLAGS.veopen+= -DMANIFEST_SKIP_MAYBE=\"${MANIFEST_SKIP}\" + VE_HASH_LIST= \ SHA1 \ SHA256 \ @@ -37,6 +40,7 @@ VE_SIGNATURE_EXT_LIST+= \ VE_SIGNATURE_LIST+= OPENPGP VE_SIGNATURE_EXT_LIST+= asc +PYTHON ?= /usr/local/bin/python SIGNER ?= ${SB_TOOLS_PATH:U/volume/buildtools/bin}/sign.py .if exists(${SIGNER}) @@ -99,7 +103,7 @@ ta.h: vc_rsa.pem .endif # we take the mtime of this as our baseline time -#BUILD_UTC_FILE= ecerts.pem +BUILD_UTC_FILE= ecerts.pem #VE_DEBUG_LEVEL=3 #VE_VERBOSE_DEFAULT=1 diff --git a/libexec/dma/dmagent/Makefile.depend b/libexec/dma/dmagent/Makefile.depend index c30f467aa7dc..089495a35022 100644 --- a/libexec/dma/dmagent/Makefile.depend +++ b/libexec/dma/dmagent/Makefile.depend @@ -2,7 +2,6 @@ # Autogenerated - do NOT edit! DIRDEPS = \ - gnu/lib/csu \ include \ include/arpa \ include/xlocale \ @@ -11,7 +10,6 @@ DIRDEPS = \ lib/libcompiler_rt \ secure/lib/libcrypto \ secure/lib/libssl \ - usr.bin/yacc.host \ .include diff --git a/libexec/rc/rc.d/tmp b/libexec/rc/rc.d/tmp index 3b75ec0338ef..56da6b498ad5 100755 --- a/libexec/rc/rc.d/tmp +++ b/libexec/rc/rc.d/tmp @@ -41,6 +41,9 @@ load_rc_config $name mount_tmpmfs() { if ! /bin/df /tmp | grep -q "^/dev/md[0-9].* /tmp"; then + if test -w /tmp/. && checkyesno tmpmfs_clear_mnt; then + (cd /tmp/. && rm -rf .* *) + fi mount_md ${tmpsize} /tmp "${tmpmfs_flags}" chmod 01777 /tmp fi diff --git a/sbin/veriexec/Makefile.depend b/sbin/veriexec/Makefile.depend index 480d2d2c255e..d1b5fac9178d 100644 --- a/sbin/veriexec/Makefile.depend +++ b/sbin/veriexec/Makefile.depend @@ -2,7 +2,6 @@ # Autogenerated - do NOT edit! DIRDEPS = \ - gnu/lib/csu \ include \ include/xlocale \ lib/${CSU_DIR} \ @@ -11,6 +10,7 @@ DIRDEPS = \ lib/libcompiler_rt \ lib/libsecureboot \ lib/libveriexec \ + usr.bin/yacc.host \ .include diff --git a/stand/efi/loader/Makefile b/stand/efi/loader/Makefile index 73b1975ad3e3..fe08f5cc4289 100644 --- a/stand/efi/loader/Makefile +++ b/stand/efi/loader/Makefile @@ -102,3 +102,8 @@ DPADD= ${LDR_INTERP} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSA} ${LDSCRIPT} LDADD= ${LDR_INTERP} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSA} .include + +PATH_BOOTABLE_TOKEN=/boot/boot.4th +CFLAGS+= ${XCFLAGS.${.TARGET:T:R}:U} +XCFLAGS.main+= -DPATH_BOOTABLE_TOKEN=\"${PATH_BOOTABLE_TOKEN}\" + diff --git a/stand/i386/loader/Makefile b/stand/i386/loader/Makefile index b74ef9007d97..b46129d5a2dd 100644 --- a/stand/i386/loader/Makefile +++ b/stand/i386/loader/Makefile @@ -1,5 +1,5 @@ # $FreeBSD$ - +.if 0 HAVE_ZFS= ${MK_LOADER_ZFS} LOADER_NET_SUPPORT?= yes @@ -11,6 +11,10 @@ LOADER_MSDOS_SUPPORT?= yes LOADER_UFS_SUPPORT?= yes LOADER_GZIP_SUPPORT?= yes LOADER_BZIP2_SUPPORT?= yes +.else +LOADER_NET_SUPPORT?= yes +LOADER_UFS_SUPPORT?= yes +.endif .include @@ -56,8 +60,8 @@ LIBI386= ${BOOTOBJ}/i386/libi386/libi386.a CFLAGS+= -I${BOOTSRC}/i386 # Debug me! -#CFLAGS+= -g -#LDFLAGS+= -g +CFLAGS+= -g +LDFLAGS+= -g ${LOADER}: ${LOADER}.bin ${BTXLDR} ${BTXKERN} btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \ diff --git a/usr.bin/bmake/unit-tests/Makefile.config b/usr.bin/bmake/unit-tests/Makefile.config new file mode 100644 index 000000000000..895df739d924 --- /dev/null +++ b/usr.bin/bmake/unit-tests/Makefile.config @@ -0,0 +1,11 @@ +# This is a generated file, do NOT edit! +# See contrib/bmake/bsd.after-import.mk +# +# $FreeBSD$ + +SRCTOP?= ${.CURDIR:H:H:H} + +# $Id: Makefile.config.in,v 1.1 2018/12/30 17:14:24 sjg Exp $ + +srcdir= ${SRCTOP}/contrib/bmake/unit-tests +DIFF_FLAGS?= -u From f2be828f97b28345280dec700f02034086dda979 Mon Sep 17 00:00:00 2001 From: "Simon J. Gerraty" Date: Sun, 19 Jul 2020 23:56:19 +0000 Subject: [PATCH 057/287] Revert that! --- lib/libbearssl/Makefile.depend | 1 + lib/libc/Makefile | 2 +- lib/libsecureboot/local.trust.mk | 6 +----- libexec/dma/dmagent/Makefile.depend | 2 ++ libexec/rc/rc.d/tmp | 3 --- sbin/veriexec/Makefile.depend | 2 +- stand/efi/loader/Makefile | 5 ----- stand/i386/loader/Makefile | 10 +++------- 8 files changed, 9 insertions(+), 22 deletions(-) diff --git a/lib/libbearssl/Makefile.depend b/lib/libbearssl/Makefile.depend index 8d409f5263ac..6cfaab1c3644 100644 --- a/lib/libbearssl/Makefile.depend +++ b/lib/libbearssl/Makefile.depend @@ -2,6 +2,7 @@ # Autogenerated - do NOT edit! DIRDEPS = \ + gnu/lib/csu \ include \ include/xlocale \ lib/${CSU_DIR} \ diff --git a/lib/libc/Makefile b/lib/libc/Makefile index 5adc8d71eabb..d5cfe7e50013 100644 --- a/lib/libc/Makefile +++ b/lib/libc/Makefile @@ -186,7 +186,7 @@ SUBDIR.${MK_TESTS}+= tests .if (${LIBC_ARCH} == amd64 || ${LIBC_ARCH} == i386) && \ ${.TARGETS:Mall} == all && \ defined(LINKER_FEATURES) && ${LINKER_FEATURES:Mifunc} == "" -#.error ${LIBC_ARCH} libc requires linker ifunc support +.error ${LIBC_ARCH} libc requires linker ifunc support .endif .if !defined(_SKIP_BUILD) diff --git a/lib/libsecureboot/local.trust.mk b/lib/libsecureboot/local.trust.mk index 77d45f95facd..b28e5ee2d1ef 100644 --- a/lib/libsecureboot/local.trust.mk +++ b/lib/libsecureboot/local.trust.mk @@ -8,9 +8,6 @@ # force these for Junos #MANIFEST_SKIP_ALWAYS= boot -MANIFEST_SKIP= boot -XCFLAGS.veopen+= -DMANIFEST_SKIP_MAYBE=\"${MANIFEST_SKIP}\" - VE_HASH_LIST= \ SHA1 \ SHA256 \ @@ -40,7 +37,6 @@ VE_SIGNATURE_EXT_LIST+= \ VE_SIGNATURE_LIST+= OPENPGP VE_SIGNATURE_EXT_LIST+= asc -PYTHON ?= /usr/local/bin/python SIGNER ?= ${SB_TOOLS_PATH:U/volume/buildtools/bin}/sign.py .if exists(${SIGNER}) @@ -103,7 +99,7 @@ ta.h: vc_rsa.pem .endif # we take the mtime of this as our baseline time -BUILD_UTC_FILE= ecerts.pem +#BUILD_UTC_FILE= ecerts.pem #VE_DEBUG_LEVEL=3 #VE_VERBOSE_DEFAULT=1 diff --git a/libexec/dma/dmagent/Makefile.depend b/libexec/dma/dmagent/Makefile.depend index 089495a35022..c30f467aa7dc 100644 --- a/libexec/dma/dmagent/Makefile.depend +++ b/libexec/dma/dmagent/Makefile.depend @@ -2,6 +2,7 @@ # Autogenerated - do NOT edit! DIRDEPS = \ + gnu/lib/csu \ include \ include/arpa \ include/xlocale \ @@ -10,6 +11,7 @@ DIRDEPS = \ lib/libcompiler_rt \ secure/lib/libcrypto \ secure/lib/libssl \ + usr.bin/yacc.host \ .include diff --git a/libexec/rc/rc.d/tmp b/libexec/rc/rc.d/tmp index 56da6b498ad5..3b75ec0338ef 100755 --- a/libexec/rc/rc.d/tmp +++ b/libexec/rc/rc.d/tmp @@ -41,9 +41,6 @@ load_rc_config $name mount_tmpmfs() { if ! /bin/df /tmp | grep -q "^/dev/md[0-9].* /tmp"; then - if test -w /tmp/. && checkyesno tmpmfs_clear_mnt; then - (cd /tmp/. && rm -rf .* *) - fi mount_md ${tmpsize} /tmp "${tmpmfs_flags}" chmod 01777 /tmp fi diff --git a/sbin/veriexec/Makefile.depend b/sbin/veriexec/Makefile.depend index d1b5fac9178d..480d2d2c255e 100644 --- a/sbin/veriexec/Makefile.depend +++ b/sbin/veriexec/Makefile.depend @@ -2,6 +2,7 @@ # Autogenerated - do NOT edit! DIRDEPS = \ + gnu/lib/csu \ include \ include/xlocale \ lib/${CSU_DIR} \ @@ -10,7 +11,6 @@ DIRDEPS = \ lib/libcompiler_rt \ lib/libsecureboot \ lib/libveriexec \ - usr.bin/yacc.host \ .include diff --git a/stand/efi/loader/Makefile b/stand/efi/loader/Makefile index fe08f5cc4289..73b1975ad3e3 100644 --- a/stand/efi/loader/Makefile +++ b/stand/efi/loader/Makefile @@ -102,8 +102,3 @@ DPADD= ${LDR_INTERP} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSA} ${LDSCRIPT} LDADD= ${LDR_INTERP} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSA} .include - -PATH_BOOTABLE_TOKEN=/boot/boot.4th -CFLAGS+= ${XCFLAGS.${.TARGET:T:R}:U} -XCFLAGS.main+= -DPATH_BOOTABLE_TOKEN=\"${PATH_BOOTABLE_TOKEN}\" - diff --git a/stand/i386/loader/Makefile b/stand/i386/loader/Makefile index b46129d5a2dd..b74ef9007d97 100644 --- a/stand/i386/loader/Makefile +++ b/stand/i386/loader/Makefile @@ -1,5 +1,5 @@ # $FreeBSD$ -.if 0 + HAVE_ZFS= ${MK_LOADER_ZFS} LOADER_NET_SUPPORT?= yes @@ -11,10 +11,6 @@ LOADER_MSDOS_SUPPORT?= yes LOADER_UFS_SUPPORT?= yes LOADER_GZIP_SUPPORT?= yes LOADER_BZIP2_SUPPORT?= yes -.else -LOADER_NET_SUPPORT?= yes -LOADER_UFS_SUPPORT?= yes -.endif .include @@ -60,8 +56,8 @@ LIBI386= ${BOOTOBJ}/i386/libi386/libi386.a CFLAGS+= -I${BOOTSRC}/i386 # Debug me! -CFLAGS+= -g -LDFLAGS+= -g +#CFLAGS+= -g +#LDFLAGS+= -g ${LOADER}: ${LOADER}.bin ${BTXLDR} ${BTXKERN} btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \ From 82b17c8e910b4fcced671146d514f6722fa4f248 Mon Sep 17 00:00:00 2001 From: Xin LI Date: Mon, 20 Jul 2020 01:55:19 +0000 Subject: [PATCH 058/287] Fix indent for if clause. MFC after: 2 weeks --- sys/geom/geom_ccd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/geom/geom_ccd.c b/sys/geom/geom_ccd.c index c113a20f0916..f0a3fad02489 100644 --- a/sys/geom/geom_ccd.c +++ b/sys/geom/geom_ccd.c @@ -917,7 +917,7 @@ g_ccd_config(struct gctl_req *req, struct g_class *mp, char const *verb) } else if (!strcmp(verb, "destroy geom")) { gp = gctl_get_geom(req, mp, "geom"); if (gp != NULL) - g_ccd_destroy_geom(req, mp, gp); + g_ccd_destroy_geom(req, mp, gp); } else if (!strcmp(verb, "list")) { g_ccd_list(req, mp); } else { From 2a7a4b196d1d87189e260e85e7844162d3237b6f Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 20 Jul 2020 12:47:15 +0000 Subject: [PATCH 059/287] tests/sys/opencrypto: use python3 python2 will be EOL soon Reviewed by: lwhsu, jmg MFC after: 2 weeks Sponsored by: Axcient Differential Revision: https://reviews.freebsd.org/D25682 --- tests/sys/opencrypto/Makefile | 2 +- tests/sys/opencrypto/cryptodev.py | 4 ++-- tests/sys/opencrypto/cryptotest.py | 4 ++-- tests/sys/opencrypto/runtests.sh | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/sys/opencrypto/Makefile b/tests/sys/opencrypto/Makefile index fd502fd8bae3..f9685b166afc 100644 --- a/tests/sys/opencrypto/Makefile +++ b/tests/sys/opencrypto/Makefile @@ -14,7 +14,7 @@ ATF_TESTS_C+= blake2_test poly1305_test TAP_TESTS_SH+= runtests -TEST_METADATA.runtests+= required_programs="python2" +TEST_METADATA.runtests+= required_programs="python3" TEST_METADATA.runtests+= required_user="root" PYMODULES= cryptodev.py cryptodevh.py cryptotest.py diff --git a/tests/sys/opencrypto/cryptodev.py b/tests/sys/opencrypto/cryptodev.py index 4a96eb905e06..0fcca6c00244 100644 --- a/tests/sys/opencrypto/cryptodev.py +++ b/tests/sys/opencrypto/cryptodev.py @@ -1,4 +1,4 @@ -#!/usr/local/bin/python2 +#!/usr/local/bin/python3 # # Copyright (c) 2014 The FreeBSD Foundation # Copyright 2014 John-Mark Gurney @@ -31,7 +31,7 @@ # $FreeBSD$ # -from __future__ import print_function + import array import binascii from fcntl import ioctl diff --git a/tests/sys/opencrypto/cryptotest.py b/tests/sys/opencrypto/cryptotest.py index 72543683241b..8868149bdb6f 100644 --- a/tests/sys/opencrypto/cryptotest.py +++ b/tests/sys/opencrypto/cryptotest.py @@ -1,4 +1,4 @@ -#!/usr/local/bin/python2 +#!/usr/local/bin/python3 # # Copyright (c) 2014 The FreeBSD Foundation # All rights reserved. @@ -30,7 +30,7 @@ # $FreeBSD$ # -from __future__ import print_function + import binascii import errno diff --git a/tests/sys/opencrypto/runtests.sh b/tests/sys/opencrypto/runtests.sh index 680173610a00..1bf6149f2857 100644 --- a/tests/sys/opencrypto/runtests.sh +++ b/tests/sys/opencrypto/runtests.sh @@ -30,7 +30,7 @@ # $FreeBSD$ # -: ${PYTHON=python2} +: ${PYTHON=python3} if [ ! -d /usr/local/share/nist-kat ]; then echo "1..0 # SKIP: nist-kat package not installed for test vectors" From cb65eb43ad0a60e97aa6c110c9ddd3354d7f5bcd Mon Sep 17 00:00:00 2001 From: Gordon Bergling Date: Mon, 20 Jul 2020 13:01:19 +0000 Subject: [PATCH 060/287] zpool(8): Fix a few typos regarding 'inverval' -> 'interval' PR: 248068 Submitted by: PauAmma Reviewed by: bcr (mentor) Approved by: bcr (mentor) Differential Revision: https://reviews.freebsd.org/D25719 --- cddl/contrib/opensolaris/cmd/zpool/zpool.8 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool.8 b/cddl/contrib/opensolaris/cmd/zpool/zpool.8 index ea7cbedafc24..f5caffb95d79 100644 --- a/cddl/contrib/opensolaris/cmd/zpool/zpool.8 +++ b/cddl/contrib/opensolaris/cmd/zpool/zpool.8 @@ -134,7 +134,7 @@ .Op Fl gLP .Op Ar pool .Ar ... -.Op Ar inverval Op Ar count +.Op Ar interval Op Ar count .Nm .Cm labelclear .Op Fl f @@ -146,7 +146,7 @@ .Op Fl T Cm d Ns | Ns Cm u .Op Ar pool .Ar ... -.Op Ar inverval Op Ar count +.Op Ar interval Op Ar count .Nm .Cm offline .Op Fl t @@ -1654,7 +1654,7 @@ Treat exported or foreign devices as inactive. .Op Fl T Cm d Ns | Ns Cm u .Op Ar pool .Ar ... -.Op Ar inverval Op Ar count +.Op Ar interval Op Ar count .Xc .Pp Lists the given pools along with a health status and space usage. If no From fcc9702f059c4d3cc75de91247580d5a1d7bdb43 Mon Sep 17 00:00:00 2001 From: Gordon Bergling Date: Mon, 20 Jul 2020 13:24:50 +0000 Subject: [PATCH 061/287] geli(8): Add an example on how to use geli(8) with a file as encrypted storage Reviewed by: bcr (mentor) Approved by: bcr (mentor) MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25741 --- lib/geom/eli/geli.8 | 64 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/lib/geom/eli/geli.8 b/lib/geom/eli/geli.8 index 798c4ce5e2af..0d23c4e09a49 100644 --- a/lib/geom/eli/geli.8 +++ b/lib/geom/eli/geli.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 14, 2020 +.Dd July 20, 2020 .Dt GELI 8 .Os .Sh NAME @@ -1095,6 +1095,64 @@ resuming the laptop: # geli resume gpt/private Enter passphrase: .Ed +.Pp +To create a +.Nm +encrypted filesystem with a file as storage device follow this example. +First a file named private0 is created in +.Pa /usr +and attached as a memory disk like +.Pa /dev/md0 +for example. +.Bd -literal -offset indent +# dd if=/dev/zero of=/usr/private0 bs=1m count=256 +# chmod 0600 /usr/private0 +# mdconfig -t vnode -f /usr/private0 +.Ed +.Pp +It is recommended to place the following line in +.Xr rc.conf 5 +to have the memory disk automatically created during boot. +.Bd -literal -offset indent +mdconfig_md0="-t vnode -f /usr/private0" +.Ed +.Pp +After +.Pa /dev/md0 +is created a random key has to be generated and stored in a secure location, +like +.Pa /root +for example. +This key should be protected by a passphrase, which +is requested when geli init is called. +.Bd -literal -offset indent +# dd if=/dev/random of=/root/private0.key bs=64 count=1 +# geli init -K /root/private0.key -s 4096 /dev/md0 +Enter new passphrase: +Reenter new passphrase: +# dd if=/dev/random of=/dev/md0.eli bs=1m +.Ed +.Pp +Once the initialization of the +.Pa /dev/md0.eli +device is ready create a UFS filesystem and mount it for example in +.Pa /private . +.Bd -literal -offset indent +# newfs /dev/md0.eli +# mount /dev/md0.eli /private +.Ed +.Pp +After a system reboot the +.Nm +device can be mounted again with the following commands. +The call of geli attach will ask for the passphrase. +It is recommended to do this procedure after the boot, because otherwise +the boot process would be waiting for the passphrase input. +.Bd -literal -offset indent +# geli attach -k /root/private0.key /dev/md0 +Enter new passphrase: +# mount /dev/md0.eli /private +.Ed .Sh ENCRYPTION MODES .Nm supports two encryption modes: @@ -1157,7 +1215,9 @@ block cipher was implemented by Yoshisato Yanagisawa in .Pp Highest .Nm GELI -metadata version supported by the given FreeBSD version: +metadata version supported by the given +.Fx +version: .Bl -column -offset indent ".Sy FreeBSD" ".Sy version" .It Sy FreeBSD Ta Sy GELI .It Sy version Ta Sy version From 39bc40e3d2f983764a8d140d65c77c6eca5264b6 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 20 Jul 2020 14:28:26 +0000 Subject: [PATCH 062/287] ext2fs: Stop checking for failures from malloc(M_WAITOK). PR: 240545 Submitted by: Andrew Reiter Reviewed by: fsu MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25707 --- sys/fs/ext2fs/ext2_acl.c | 2 -- sys/fs/ext2fs/ext2_alloc.c | 3 --- sys/fs/ext2fs/ext2_extents.c | 11 ----------- sys/fs/ext2fs/ext2_lookup.c | 4 ---- sys/fs/ext2fs/ext2_vnops.c | 10 ---------- 5 files changed, 30 deletions(-) diff --git a/sys/fs/ext2fs/ext2_acl.c b/sys/fs/ext2fs/ext2_acl.c index a49c98cdb937..30d1c182a0b4 100644 --- a/sys/fs/ext2fs/ext2_acl.c +++ b/sys/fs/ext2fs/ext2_acl.c @@ -234,8 +234,6 @@ ext2_getacl_posix1e(struct vop_getacl_args *ap) len = sizeof(*ap->a_aclp) + sizeof(struct ext2_acl_header); value = malloc(len, M_ACL, M_WAITOK); - if (!value) - return (ENOMEM); error = vn_extattr_get(ap->a_vp, IO_NODELOCKED, attrnamespace, attrname, &len, value, ap->a_td); diff --git a/sys/fs/ext2fs/ext2_alloc.c b/sys/fs/ext2fs/ext2_alloc.c index 1fa4a4c175f0..0cb93b3f0cb9 100644 --- a/sys/fs/ext2fs/ext2_alloc.c +++ b/sys/fs/ext2fs/ext2_alloc.c @@ -425,9 +425,6 @@ ext2_valloc(struct vnode *pvp, int mode, struct ucred *cred, struct vnode **vpp) } ip = malloc(sizeof(struct inode), M_EXT2NODE, M_WAITOK | M_ZERO); - if (ip == NULL) { - return (ENOMEM); - } /* Allocate a new vnode/inode. */ if ((error = getnewvnode("ext2fs", ump->um_mountp, &ext2_vnodeops, &vp)) != 0) { diff --git a/sys/fs/ext2fs/ext2_extents.c b/sys/fs/ext2fs/ext2_extents.c index 2aa9d6e13ac8..ccb7b861da49 100644 --- a/sys/fs/ext2fs/ext2_extents.c +++ b/sys/fs/ext2fs/ext2_extents.c @@ -322,9 +322,6 @@ ext4_ext_fill_path_bdata(struct ext4_extent_path *path, ("ext4_ext_fill_path_bdata: bad ep_data")); path->ep_data = malloc(bp->b_bufsize, M_EXT2EXTENTS, M_WAITOK); - if (!path->ep_data) - return (ENOMEM); - memcpy(path->ep_data, bp->b_data, bp->b_bufsize); path->ep_blk = blk; @@ -397,9 +394,6 @@ ext4_ext_find_extent(struct inode *ip, daddr_t block, path = malloc(EXT4_EXT_DEPTH_MAX * sizeof(struct ext4_extent_path), M_EXT2EXTENTS, M_WAITOK | M_ZERO); - if (!path) - return (ENOMEM); - *ppath = path; alloc = 1; } @@ -762,8 +756,6 @@ ext4_ext_split(struct inode *ip, struct ext4_extent_path *path, /* Allocate new blocks. */ ablks = malloc(sizeof(e4fs_daddr_t) * depth, M_EXT2EXTENTS, M_WAITOK | M_ZERO); - if (!ablks) - return (ENOMEM); for (a = 0; a < depth - at; a++) { newblk = ext4_ext_alloc_meta(ip); if (newblk == 0) @@ -1517,9 +1509,6 @@ ext4_ext_remove_space(struct inode *ip, off_t length, int flags, path = malloc(sizeof(struct ext4_extent_path) * (depth + 1), M_EXT2EXTENTS, M_WAITOK | M_ZERO); - if (!path) - return (ENOMEM); - path[0].ep_header = ehp; path[0].ep_depth = depth; i = 0; diff --git a/sys/fs/ext2fs/ext2_lookup.c b/sys/fs/ext2fs/ext2_lookup.c index 04ec059e85a4..d67a6442d1a5 100644 --- a/sys/fs/ext2fs/ext2_lookup.c +++ b/sys/fs/ext2fs/ext2_lookup.c @@ -894,10 +894,6 @@ ext2_add_first_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry, entry->e2d_reclen = htole16(dirblksize - sizeof(struct ext2fs_direct_tail)); buf = malloc(dirblksize, M_TEMP, M_WAITOK); - if (!buf) { - error = ENOMEM; - goto out; - } memcpy(buf, entry, EXT2_DIR_REC_LEN(entry->e2d_namlen)); ext2_init_dirent_tail(EXT2_DIRENT_TAIL(buf, dirblksize)); ext2_dirent_csum_set(dp, (struct ext2fs_direct_2 *)buf); diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c index 5bea1a376a9b..b98f8289e05c 100644 --- a/sys/fs/ext2fs/ext2_vnops.c +++ b/sys/fs/ext2fs/ext2_vnops.c @@ -1077,10 +1077,6 @@ ext2_rename(struct vop_rename_args *ap) ext2_dec_nlink(dp); dp->i_flag |= IN_CHANGE; dirbuf = malloc(dp->i_e2fs->e2fs_bsize, M_TEMP, M_WAITOK | M_ZERO); - if (!dirbuf) { - error = ENOMEM; - goto bad; - } error = vn_rdwr(UIO_READ, fvp, (caddr_t)dirbuf, ip->i_e2fs->e2fs_bsize, (off_t)0, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, @@ -1390,12 +1386,6 @@ ext2_mkdir(struct vop_mkdir_args *ap) #define DIRBLKSIZ VTOI(dvp)->i_e2fs->e2fs_bsize dirtemplate.dotdot_reclen = htole16(DIRBLKSIZ - 12); buf = malloc(DIRBLKSIZ, M_TEMP, M_WAITOK | M_ZERO); - if (!buf) { - error = ENOMEM; - ext2_dec_nlink(dp); - dp->i_flag |= IN_CHANGE; - goto bad; - } if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { dirtemplate.dotdot_reclen = htole16(le16toh(dirtemplate.dotdot_reclen) - From b4fef8d068705221f3a6adb889ebebb6ec84fccb Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 20 Jul 2020 16:12:14 +0000 Subject: [PATCH 063/287] padlock: fix Via Padlock with 192-bit keys It's been broken since a typo in r359374 Reviewed by: jhb MFC after: 2 weeks Sponsored by: Axcient Differential Revision: https://reviews.freebsd.org/D25710 --- sys/crypto/via/padlock_cipher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/crypto/via/padlock_cipher.c b/sys/crypto/via/padlock_cipher.c index 1f3e8532e65f..0bc831f07c40 100644 --- a/sys/crypto/via/padlock_cipher.c +++ b/sys/crypto/via/padlock_cipher.c @@ -124,7 +124,7 @@ padlock_cipher_setup(struct padlock_session *ses, { union padlock_cw *cw; - if (csp->csp_cipher_klen != 16 && csp->csp_cipher_klen != 25 && + if (csp->csp_cipher_klen != 16 && csp->csp_cipher_klen != 24 && csp->csp_cipher_klen != 32) { return (EINVAL); } From 17eee3b501a2b097c808b048a7003b7940ac82c6 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 20 Jul 2020 17:05:44 +0000 Subject: [PATCH 064/287] Fix a memory leak in dsl_scan_visitbp(). This should be triggered only if arc_read() fails, i.e., quite rarely. The same logic is already present in OpenZFS. PR: 247445 Submitted by: jdolecek@NetBSD.org MFC after: 1 week --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c index 54bd8db1cd30..f87a0539e9bb 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c @@ -1789,7 +1789,7 @@ dsl_scan_visitbp(blkptr_t *bp, const zbookmark_phys_t *zb, *bp_toread = *bp; if (dsl_scan_recurse(scn, ds, ostype, dnp, bp_toread, zb, tx) != 0) - return; + goto out; /* * If dsl_scan_ddt() has already visited this block, it will have From e1a82b35bf70d9d72f54f0549e6b57e34167931e Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 20 Jul 2020 17:44:13 +0000 Subject: [PATCH 065/287] crypto(9): Stop checking for failures from malloc(M_WAITOK). PR: 240545 Submitted by: Andrew Reiter Reviewed by: cem, delphij, jhb MFC after: 1 week Event: July 2020 Bugathon --- sys/opencrypto/cryptodev.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sys/opencrypto/cryptodev.c b/sys/opencrypto/cryptodev.c index ff1c34658315..cab56960e723 100644 --- a/sys/opencrypto/cryptodev.c +++ b/sys/opencrypto/cryptodev.c @@ -1315,11 +1315,7 @@ cryptodev_key(struct crypt_kop *kop) return (EINVAL); } - krp = (struct cryptkop *)malloc(sizeof *krp, M_XDATA, M_WAITOK|M_ZERO); - if (!krp) { - SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); - return (ENOMEM); - } + krp = malloc(sizeof(*krp), M_XDATA, M_WAITOK | M_ZERO); krp->krp_op = kop->crk_op; krp->krp_status = kop->crk_status; krp->krp_iparams = kop->crk_iparams; From f690eff983f926f3f2660f6c205cfdd8cc9bdaf2 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 20 Jul 2020 18:22:38 +0000 Subject: [PATCH 066/287] libdwarf: Hide SHT_NOBITS sections. gnu_debuglink external debug files will contain an .eh_frame section of type SHT_NOBITS. libdwarf does not handle such sections (or rather, it expects all debug sections to not have type SHT_NOBITS). Avoid loading SHT_NOBITS sections, to be consistent with SGI libdwarf's handling of this case. PR: 239516 Diagnosed by: Paco Pascal Reviewed by: emaste (previous version) Event: July 2020 Bugathon MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25626 --- contrib/elftoolchain/libdwarf/libdwarf_elf_init.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contrib/elftoolchain/libdwarf/libdwarf_elf_init.c b/contrib/elftoolchain/libdwarf/libdwarf_elf_init.c index bd68afc09373..e304ef164157 100644 --- a/contrib/elftoolchain/libdwarf/libdwarf_elf_init.c +++ b/contrib/elftoolchain/libdwarf/libdwarf_elf_init.c @@ -260,6 +260,9 @@ _dwarf_elf_init(Dwarf_Debug dbg, Elf *elf, Dwarf_Error *error) goto fail_cleanup; } + if (sh.sh_type == SHT_NOBITS) + continue; + if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) == NULL) { DWARF_SET_ELF_ERROR(dbg, error); @@ -313,6 +316,9 @@ _dwarf_elf_init(Dwarf_Debug dbg, Elf *elf, Dwarf_Error *error) goto fail_cleanup; } + if (sh.sh_type == SHT_NOBITS) + continue; + memcpy(&e->eo_shdr[j], &sh, sizeof(sh)); if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) == From 3b41d99d7639f734cdf5d59bcc464a8fb2f1284a Mon Sep 17 00:00:00 2001 From: Chuck Silvers Date: Mon, 20 Jul 2020 20:36:32 +0000 Subject: [PATCH 067/287] add a few tests for sendfile. Reviewed by: markj Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D25431 --- tests/sys/kern/Makefile | 3 + tests/sys/kern/sendfile_helper.c | 147 +++++++++++++++++++++++++++++ tests/sys/kern/sendfile_test.sh | 155 +++++++++++++++++++++++++++++++ 3 files changed, 305 insertions(+) create mode 100644 tests/sys/kern/sendfile_helper.c create mode 100755 tests/sys/kern/sendfile_test.sh diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile index 5e60f749f846..c73699266178 100644 --- a/tests/sys/kern/Makefile +++ b/tests/sys/kern/Makefile @@ -29,6 +29,7 @@ ATF_TESTS_SH+= coredump_phnum_test ATF_TESTS_SH+= sonewconn_overflow TEST_METADATA.sonewconn_overflow+= required_programs="python" TEST_METADATA.sonewconn_overflow+= required_user="root" +ATF_TESTS_SH+= sendfile_test ${PACKAGE}FILES+= sonewconn_overflow.py ${PACKAGE}FILESMODE_sonewconn_overflow.py=0555 @@ -36,6 +37,7 @@ ${PACKAGE}FILESMODE_sonewconn_overflow.py=0555 BINDIR= ${TESTSDIR} PROGS+= coredump_phnum_helper PROGS+= pdeathsig_helper +PROGS+= sendfile_helper CFLAGS.sys_getrandom+= -I${SRCTOP}/sys/contrib/zstd/lib LIBADD.sys_getrandom+= zstd @@ -44,6 +46,7 @@ LIBADD.sys_getrandom+= pthread LIBADD.ptrace_test+= pthread LIBADD.unix_seqpacket_test+= pthread LIBADD.kcov+= pthread +LIBADD.sendfile_helper+= pthread NETBSD_ATF_TESTS_C+= lockf_test NETBSD_ATF_TESTS_C+= mqueue_test diff --git a/tests/sys/kern/sendfile_helper.c b/tests/sys/kern/sendfile_helper.c new file mode 100644 index 000000000000..d538a510c860 --- /dev/null +++ b/tests/sys/kern/sendfile_helper.c @@ -0,0 +1,147 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020 Netflix, 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$ + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int ls; +static char buf[1024*1024]; +static volatile bool accept_done = false; +static volatile bool read_done = false; + +static void * +server(void *arg) +{ + struct sockaddr_in sin; + ssize_t rv; + socklen_t slen; + int ss; + ssize_t readlen = (uintptr_t)arg; + + slen = sizeof(sin); + ss = accept(ls, (void *)&sin, &slen); + if (ss < 0) + err(1, "accept ls"); + + accept_done = true; + + do { + rv = read(ss, buf, sizeof(buf)); + if (rv == -1) + err(2, "read receiver"); + if (rv == 0) + break; + readlen -= rv; + } while (readlen != 0); + + read_done = true; + + return NULL; +} + +int +main(int argc, char **argv) +{ + pthread_t pt; + struct sockaddr_in sin; + off_t start, len; + socklen_t slen; + int fd, cs, on, flags, error; + + if (argc != 5) + errx(1, "usage: %s ", + getprogname()); + + start = strtoull(argv[2], NULL, 0); + len = strtoull(argv[3], NULL, 0); + flags = strtoul(argv[4], NULL, 0); + + fd = open(argv[1], O_RDONLY); + if (fd < 0) + err(1, "open"); + + ls = socket(PF_INET, SOCK_STREAM, 0); + if (ls < 0) + err(1, "socket ls"); + + on = 1; + if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (void *)&on, + (socklen_t)sizeof(on)) < 0) + err(1, "SO_REUSEADDR"); + + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sin.sin_port = 0; + if (bind(ls, (void *)&sin, sizeof(sin)) < 0) + err(1, "bind ls"); + + slen = sizeof(sin); + if (getsockname(ls, (void *)&sin, &slen) < 0) + err(1, "getsockname"); + + if (listen(ls, 5) < 0) + err(1, "listen ls"); + + error = pthread_create(&pt, NULL, server, (void *)(uintptr_t)len); + if (error) + errc(1, error, "pthread_create"); + + cs = socket(PF_INET, SOCK_STREAM, 0); + if (cs < 0) + err(1, "socket cs"); + + if (connect(cs, (void *)&sin, sizeof(sin)) < 0) + err(1, "connect cs"); + + while (!accept_done) + usleep(1000); + + if (sendfile(fd, cs, start, len, NULL, NULL, flags) < 0) + err(3, "sendfile"); + + while (!read_done) + usleep(1000); + + exit(0); +} diff --git a/tests/sys/kern/sendfile_test.sh b/tests/sys/kern/sendfile_test.sh new file mode 100755 index 000000000000..2efda9310396 --- /dev/null +++ b/tests/sys/kern/sendfile_test.sh @@ -0,0 +1,155 @@ +# SPDX-License-Identifier: BSD-2-Clause-FreeBSD +# +# Copyright (c) 2020 Netflix, 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$ + +# +# These tests exercise a few basic cases for the sendfile() syscall: +# - successful operation. +# - sendfile() starts an async disk read but that async I/O fails. +# - sendfile() fails to read an indirect block and thus cannot +# even start an async I/O. +# +# In all cases we request some read ahead in addition to +# the data to be sent to the socket. +# + +MD_DEVS="md.devs" +MNT=/mnt +FILE=$MNT/file +HELPER="$(atf_get_srcdir)/sendfile_helper" +BSIZE=4096 + +atf_test_case io_success cleanup +io_success_head() +{ + atf_set "descr" "sendfile where all disk I/O succeeds" + atf_set "require.user" "root" + atf_set "timeout" 15 +} +io_success_body() +{ + md=$(alloc_md) + common_body_setup $md + + atf_check $HELPER $FILE 0 0x10000 0x10000 +} +io_success_cleanup() +{ + common_cleanup +} + +atf_test_case io_fail_sync cleanup +io_fail_sync_head() +{ + atf_set "descr" "sendfile where we fail to start async I/O" + atf_set "require.user" "root" + atf_set "timeout" 15 +} +io_fail_sync_body() +{ + md=$(alloc_md) + common_body_setup $md + + atf_check gnop configure -r 100 -e 5 ${md}.nop + atf_check -s exit:3 -e ignore $HELPER $FILE $((12 * $BSIZE)) $BSIZE 0x10000 +} +io_fail_sync_cleanup() +{ + common_cleanup +} + +atf_test_case io_fail_async cleanup +io_fail_async_head() +{ + atf_set "descr" "sendfile where an async I/O fails" + atf_set "require.user" "root" + atf_set "timeout" 15 +} +io_fail_async_body() +{ + md=$(alloc_md) + common_body_setup $md + + atf_check gnop configure -r 100 -e 5 ${md}.nop + atf_check -s exit:2 -e ignore $HELPER $FILE 0 $BSIZE 0x10000 +} +io_fail_async_cleanup() +{ + common_cleanup +} + + +atf_init_test_cases() +{ + atf_add_test_case io_success + atf_add_test_case io_fail_sync + atf_add_test_case io_fail_async +} + +alloc_md() +{ + local md + + md=$(mdconfig -a -t swap -s 256M) || atf_fail "mdconfig -a failed" + echo ${md} >> $MD_DEVS + echo ${md} +} + +common_body_setup() +{ + us=$1 + + atf_check -o ignore -e ignore newfs -b $BSIZE -U -j /dev/${us} + atf_check mount /dev/${us} $MNT + atf_check -e ignore dd if=/dev/zero of=$FILE bs=1m count=1 + atf_check umount /mnt + + load_gnop + atf_check gnop create /dev/${us} + atf_check mount /dev/${us}.nop $MNT + atf_check -o ignore ls -l $MNT/file +} + +common_cleanup() +{ + umount -f $MNT + if [ -f "$MD_DEVS" ]; then + while read test_md; do + gnop destroy -f ${test_md}.nop 2>/dev/null + mdconfig -d -u $test_md 2>/dev/null + done < $MD_DEVS + rm $MD_DEVS + fi + + true +} + +load_gnop() +{ + if ! kldstat -q -m g_nop; then + geom nop load || atf_skip "could not load module for geom nop" + fi +} From ac11d8574093a746fab29c67ce1fbbfb445c449c Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Mon, 20 Jul 2020 21:08:56 +0000 Subject: [PATCH 068/287] iflib: initialize netmap with the correct number of descriptors In case the network device has a RX or TX control queue, the correct number of TX/RX descriptors is contained in the second entry of the isc_ntxd (or isc_nrxd) array, rather than in the first entry. This case is correctly handled by iflib_device_register() and iflib_pseudo_register(), but not by iflib_netmap_attach(). If the first entry is larger than the second, this can result in a panic. This change fixes the bug by introducing two helper functions that also lead to some code simplification. PR: 247647 MFC after: 3 weeks Differential Revision: https://reviews.freebsd.org/D25541 --- sys/net/iflib.c | 60 +++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/sys/net/iflib.c b/sys/net/iflib.c index e614661ca79a..f87b31251ffe 100644 --- a/sys/net/iflib.c +++ b/sys/net/iflib.c @@ -730,6 +730,26 @@ MTX_SYSINIT(iflib_cpu_offset, &cpu_offset_mtx, "iflib_cpu_offset lock", DEBUGNET_DEFINE(iflib); +static int +iflib_num_rx_descs(if_ctx_t ctx) +{ + if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; + if_shared_ctx_t sctx = ctx->ifc_sctx; + uint16_t first_rxq = (sctx->isc_flags & IFLIB_HAS_RXCQ) ? 1 : 0; + + return scctx->isc_nrxd[first_rxq]; +} + +static int +iflib_num_tx_descs(if_ctx_t ctx) +{ + if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; + if_shared_ctx_t sctx = ctx->ifc_sctx; + uint16_t first_txq = (sctx->isc_flags & IFLIB_HAS_TXCQ) ? 1 : 0; + + return scctx->isc_ntxd[first_txq]; +} + #ifdef DEV_NETMAP #include #include @@ -1165,7 +1185,6 @@ static int iflib_netmap_attach(if_ctx_t ctx) { struct netmap_adapter na; - if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; bzero(&na, sizeof(na)); @@ -1174,8 +1193,8 @@ iflib_netmap_attach(if_ctx_t ctx) MPASS(ctx->ifc_softc_ctx.isc_ntxqsets); MPASS(ctx->ifc_softc_ctx.isc_nrxqsets); - na.num_tx_desc = scctx->isc_ntxd[0]; - na.num_rx_desc = scctx->isc_nrxd[0]; + na.num_tx_desc = iflib_num_tx_descs(ctx); + na.num_rx_desc = iflib_num_rx_descs(ctx); na.nm_txsync = iflib_netmap_txsync; na.nm_rxsync = iflib_netmap_rxsync; na.nm_register = iflib_netmap_register; @@ -4590,7 +4609,7 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct kobjop_desc_t kobj_desc; kobj_method_t *kobj_method; int err, msix, rid; - uint16_t main_rxq, main_txq; + int num_txd, num_rxd; ctx = malloc(sizeof(* ctx), M_IFLIB, M_WAITOK|M_ZERO); @@ -4640,21 +4659,20 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct if (scctx->isc_nrxqsets == 0 || (scctx->isc_nrxqsets_max && scctx->isc_nrxqsets_max < scctx->isc_nrxqsets)) scctx->isc_nrxqsets = scctx->isc_nrxqsets_max; - main_txq = (sctx->isc_flags & IFLIB_HAS_TXCQ) ? 1 : 0; - main_rxq = (sctx->isc_flags & IFLIB_HAS_RXCQ) ? 1 : 0; + num_txd = iflib_num_tx_descs(ctx); + num_rxd = iflib_num_rx_descs(ctx); /* XXX change for per-queue sizes */ device_printf(dev, "Using %d TX descriptors and %d RX descriptors\n", - scctx->isc_ntxd[main_txq], scctx->isc_nrxd[main_rxq]); + num_txd, num_rxd); - if (scctx->isc_tx_nsegments > scctx->isc_ntxd[main_txq] / - MAX_SINGLE_PACKET_FRACTION) - scctx->isc_tx_nsegments = max(1, scctx->isc_ntxd[main_txq] / + if (scctx->isc_tx_nsegments > num_txd / MAX_SINGLE_PACKET_FRACTION) + scctx->isc_tx_nsegments = max(1, num_txd / MAX_SINGLE_PACKET_FRACTION); - if (scctx->isc_tx_tso_segments_max > scctx->isc_ntxd[main_txq] / + if (scctx->isc_tx_tso_segments_max > num_txd / MAX_SINGLE_PACKET_FRACTION) scctx->isc_tx_tso_segments_max = max(1, - scctx->isc_ntxd[main_txq] / MAX_SINGLE_PACKET_FRACTION); + num_txd / MAX_SINGLE_PACKET_FRACTION); /* TSO parameters - dig these out of the data sheet - simply correspond to tag setup */ if (if_getcapabilities(ifp) & IFCAP_TSO) { @@ -4831,14 +4849,13 @@ int iflib_pseudo_register(device_t dev, if_shared_ctx_t sctx, if_ctx_t *ctxp, struct iflib_cloneattach_ctx *clctx) { + int num_txd, num_rxd; int err; if_ctx_t ctx; if_t ifp; if_softc_ctx_t scctx; int i; void *sc; - uint16_t main_txq; - uint16_t main_rxq; ctx = malloc(sizeof(*ctx), M_IFLIB, M_WAITOK|M_ZERO); sc = malloc(sctx->isc_driver->size, M_IFLIB, M_WAITOK|M_ZERO); @@ -4924,21 +4941,20 @@ iflib_pseudo_register(device_t dev, if_shared_ctx_t sctx, if_ctx_t *ctxp, if (scctx->isc_nrxqsets == 0 || (scctx->isc_nrxqsets_max && scctx->isc_nrxqsets_max < scctx->isc_nrxqsets)) scctx->isc_nrxqsets = scctx->isc_nrxqsets_max; - main_txq = (sctx->isc_flags & IFLIB_HAS_TXCQ) ? 1 : 0; - main_rxq = (sctx->isc_flags & IFLIB_HAS_RXCQ) ? 1 : 0; + num_txd = iflib_num_tx_descs(ctx); + num_rxd = iflib_num_rx_descs(ctx); /* XXX change for per-queue sizes */ device_printf(dev, "Using %d TX descriptors and %d RX descriptors\n", - scctx->isc_ntxd[main_txq], scctx->isc_nrxd[main_rxq]); + num_txd, num_rxd); - if (scctx->isc_tx_nsegments > scctx->isc_ntxd[main_txq] / - MAX_SINGLE_PACKET_FRACTION) - scctx->isc_tx_nsegments = max(1, scctx->isc_ntxd[main_txq] / + if (scctx->isc_tx_nsegments > num_txd / MAX_SINGLE_PACKET_FRACTION) + scctx->isc_tx_nsegments = max(1, num_txd / MAX_SINGLE_PACKET_FRACTION); - if (scctx->isc_tx_tso_segments_max > scctx->isc_ntxd[main_txq] / + if (scctx->isc_tx_tso_segments_max > num_txd / MAX_SINGLE_PACKET_FRACTION) scctx->isc_tx_tso_segments_max = max(1, - scctx->isc_ntxd[main_txq] / MAX_SINGLE_PACKET_FRACTION); + num_txd / MAX_SINGLE_PACKET_FRACTION); /* TSO parameters - dig these out of the data sheet - simply correspond to tag setup */ if (if_getcapabilities(ifp) & IFCAP_TSO) { From 33a1a488d5c940977dde407404ab766ea9a31092 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 20 Jul 2020 22:32:39 +0000 Subject: [PATCH 069/287] Don't dynamically allocate data structures for KTLS crypto requests. Allocate iovec arrays and struct cryptop and struct ocf_operation objects on the stack to reduce avoid the overhead of malloc(). These structures are all small enough to fit on the stack of the KTLS worker threads. Reviewed by: gallatin Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D25692 --- sys/opencrypto/ktls_ocf.c | 134 ++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 70 deletions(-) diff --git a/sys/opencrypto/ktls_ocf.c b/sys/opencrypto/ktls_ocf.c index 867b68624f67..aab3d98bf5b1 100644 --- a/sys/opencrypto/ktls_ocf.c +++ b/sys/opencrypto/ktls_ocf.c @@ -51,7 +51,6 @@ struct ocf_session { struct ocf_operation { struct ocf_session *os; bool done; - struct iovec iov[0]; }; static MALLOC_DEFINE(M_KTLS_OCF, "ktls_ocf", "OCF KTLS"); @@ -109,18 +108,18 @@ ktls_ocf_tls12_gcm_encrypt(struct ktls_session *tls, { struct uio uio, out_uio, *tag_uio; struct tls_aead_data ad; - struct cryptop *crp; + struct cryptop crp; struct ocf_session *os; - struct ocf_operation *oo; + struct ocf_operation oo; + struct iovec iov[iovcnt + 1]; int i, error; uint16_t tls_comp_len; bool inplace; os = tls->cipher; - oo = malloc(sizeof(*oo) + (iovcnt + 1) * sizeof(struct iovec), - M_KTLS_OCF, M_WAITOK | M_ZERO); - oo->os = os; + oo.os = os; + oo.done = false; uio.uio_iov = iniov; uio.uio_iovcnt = iovcnt; @@ -134,11 +133,11 @@ ktls_ocf_tls12_gcm_encrypt(struct ktls_session *tls, out_uio.uio_segflg = UIO_SYSSPACE; out_uio.uio_td = curthread; - crp = crypto_getreq(os->sid, M_WAITOK); + crypto_initreq(&crp, os->sid); /* Setup the IV. */ - memcpy(crp->crp_iv, tls->params.iv, TLS_AEAD_GCM_LEN); - memcpy(crp->crp_iv + TLS_AEAD_GCM_LEN, hdr + 1, sizeof(uint64_t)); + memcpy(crp.crp_iv, tls->params.iv, TLS_AEAD_GCM_LEN); + memcpy(crp.crp_iv + TLS_AEAD_GCM_LEN, hdr + 1, sizeof(uint64_t)); /* Setup the AAD. */ tls_comp_len = ntohs(hdr->tls_length) - @@ -148,19 +147,19 @@ ktls_ocf_tls12_gcm_encrypt(struct ktls_session *tls, ad.tls_vmajor = hdr->tls_vmajor; ad.tls_vminor = hdr->tls_vminor; ad.tls_length = htons(tls_comp_len); - crp->crp_aad = &ad; - crp->crp_aad_length = sizeof(ad); + crp.crp_aad = &ad; + crp.crp_aad_length = sizeof(ad); /* Compute payload length and determine if encryption is in place. */ inplace = true; - crp->crp_payload_start = 0; + crp.crp_payload_start = 0; for (i = 0; i < iovcnt; i++) { if (iniov[i].iov_base != outiov[i].iov_base) inplace = false; - crp->crp_payload_length += iniov[i].iov_len; + crp.crp_payload_length += iniov[i].iov_len; } - uio.uio_resid = crp->crp_payload_length; - out_uio.uio_resid = crp->crp_payload_length; + uio.uio_resid = crp.crp_payload_length; + out_uio.uio_resid = crp.crp_payload_length; if (inplace) tag_uio = &uio; @@ -168,21 +167,21 @@ ktls_ocf_tls12_gcm_encrypt(struct ktls_session *tls, tag_uio = &out_uio; /* Duplicate iovec and append vector for tag. */ - memcpy(oo->iov, tag_uio->uio_iov, iovcnt * sizeof(struct iovec)); - tag_uio->uio_iov = oo->iov; - tag_uio->uio_iov[iovcnt].iov_base = trailer; - tag_uio->uio_iov[iovcnt].iov_len = AES_GMAC_HASH_LEN; + memcpy(iov, tag_uio->uio_iov, iovcnt * sizeof(struct iovec)); + iov[iovcnt].iov_base = trailer; + iov[iovcnt].iov_len = AES_GMAC_HASH_LEN; + tag_uio->uio_iov = iov; tag_uio->uio_iovcnt++; - crp->crp_digest_start = tag_uio->uio_resid; + crp.crp_digest_start = tag_uio->uio_resid; tag_uio->uio_resid += AES_GMAC_HASH_LEN; - crp->crp_op = CRYPTO_OP_ENCRYPT | CRYPTO_OP_COMPUTE_DIGEST; - crp->crp_flags = CRYPTO_F_CBIMM | CRYPTO_F_IV_SEPARATE; - crypto_use_uio(crp, &uio); + crp.crp_op = CRYPTO_OP_ENCRYPT | CRYPTO_OP_COMPUTE_DIGEST; + crp.crp_flags = CRYPTO_F_CBIMM | CRYPTO_F_IV_SEPARATE; + crypto_use_uio(&crp, &uio); if (!inplace) - crypto_use_output_uio(crp, &out_uio); - crp->crp_opaque = oo; - crp->crp_callback = ktls_ocf_callback; + crypto_use_output_uio(&crp, &out_uio); + crp.crp_opaque = &oo; + crp.crp_callback = ktls_ocf_callback; counter_u64_add(ocf_tls12_gcm_crypts, 1); if (inplace) @@ -190,28 +189,27 @@ ktls_ocf_tls12_gcm_encrypt(struct ktls_session *tls, else counter_u64_add(ocf_separate_output, 1); for (;;) { - error = crypto_dispatch(crp); + error = crypto_dispatch(&crp); if (error) break; mtx_lock(&os->lock); - while (!oo->done) - mtx_sleep(oo, &os->lock, 0, "ocfktls", 0); + while (!oo.done) + mtx_sleep(&oo, &os->lock, 0, "ocfktls", 0); mtx_unlock(&os->lock); - if (crp->crp_etype != EAGAIN) { - error = crp->crp_etype; + if (crp.crp_etype != EAGAIN) { + error = crp.crp_etype; break; } - crp->crp_etype = 0; - crp->crp_flags &= ~CRYPTO_F_DONE; - oo->done = false; + crp.crp_etype = 0; + crp.crp_flags &= ~CRYPTO_F_DONE; + oo.done = false; counter_u64_add(ocf_retries, 1); } - crypto_freereq(crp); - free(oo, M_KTLS_OCF); + crypto_destroyreq(&crp); return (error); } @@ -223,22 +221,19 @@ ktls_ocf_tls13_gcm_encrypt(struct ktls_session *tls, struct uio uio, out_uio; struct tls_aead_data_13 ad; char nonce[12]; - struct cryptop *crp; + struct cryptop crp; struct ocf_session *os; - struct ocf_operation *oo; - struct iovec *iov, *out_iov; + struct ocf_operation oo; + struct iovec iov[iovcnt + 1], out_iov[iovcnt + 1]; int i, error; bool inplace; os = tls->cipher; - oo = malloc(sizeof(*oo) + (iovcnt + 1) * sizeof(*iov) * 2, M_KTLS_OCF, - M_WAITOK | M_ZERO); - oo->os = os; - iov = oo->iov; - out_iov = iov + iovcnt + 2; + oo.os = os; + oo.done = false; - crp = crypto_getreq(os->sid, M_WAITOK); + crypto_initreq(&crp, os->sid); /* Setup the nonce. */ memcpy(nonce, tls->params.iv, tls->params.iv_len); @@ -249,22 +244,22 @@ ktls_ocf_tls13_gcm_encrypt(struct ktls_session *tls, ad.tls_vmajor = hdr->tls_vmajor; ad.tls_vminor = hdr->tls_vminor; ad.tls_length = hdr->tls_length; - crp->crp_aad = &ad; - crp->crp_aad_length = sizeof(ad); + crp.crp_aad = &ad; + crp.crp_aad_length = sizeof(ad); /* Compute payload length and determine if encryption is in place. */ inplace = true; - crp->crp_payload_start = 0; + crp.crp_payload_start = 0; for (i = 0; i < iovcnt; i++) { if (iniov[i].iov_base != outiov[i].iov_base) inplace = false; - crp->crp_payload_length += iniov[i].iov_len; + crp.crp_payload_length += iniov[i].iov_len; } /* Store the record type as the first byte of the trailer. */ trailer[0] = record_type; - crp->crp_payload_length++; - crp->crp_digest_start = crp->crp_payload_length; + crp.crp_payload_length++; + crp.crp_digest_start = crp.crp_payload_length; /* * Duplicate the input iov to append the trailer. Always @@ -277,10 +272,10 @@ ktls_ocf_tls13_gcm_encrypt(struct ktls_session *tls, uio.uio_iov = iov; uio.uio_iovcnt = iovcnt + 1; uio.uio_offset = 0; - uio.uio_resid = crp->crp_payload_length + AES_GMAC_HASH_LEN; + uio.uio_resid = crp.crp_payload_length + AES_GMAC_HASH_LEN; uio.uio_segflg = UIO_SYSSPACE; uio.uio_td = curthread; - crypto_use_uio(crp, &uio); + crypto_use_uio(&crp, &uio); if (!inplace) { /* Duplicate the output iov to append the trailer. */ @@ -290,19 +285,19 @@ ktls_ocf_tls13_gcm_encrypt(struct ktls_session *tls, out_uio.uio_iov = out_iov; out_uio.uio_iovcnt = iovcnt + 1; out_uio.uio_offset = 0; - out_uio.uio_resid = crp->crp_payload_length + + out_uio.uio_resid = crp.crp_payload_length + AES_GMAC_HASH_LEN; out_uio.uio_segflg = UIO_SYSSPACE; out_uio.uio_td = curthread; - crypto_use_output_uio(crp, &out_uio); + crypto_use_output_uio(&crp, &out_uio); } - crp->crp_op = CRYPTO_OP_ENCRYPT | CRYPTO_OP_COMPUTE_DIGEST; - crp->crp_flags = CRYPTO_F_CBIMM | CRYPTO_F_IV_SEPARATE; - crp->crp_opaque = oo; - crp->crp_callback = ktls_ocf_callback; + crp.crp_op = CRYPTO_OP_ENCRYPT | CRYPTO_OP_COMPUTE_DIGEST; + crp.crp_flags = CRYPTO_F_CBIMM | CRYPTO_F_IV_SEPARATE; + crp.crp_opaque = &oo; + crp.crp_callback = ktls_ocf_callback; - memcpy(crp->crp_iv, nonce, sizeof(nonce)); + memcpy(crp.crp_iv, nonce, sizeof(nonce)); counter_u64_add(ocf_tls13_gcm_crypts, 1); if (inplace) @@ -310,28 +305,27 @@ ktls_ocf_tls13_gcm_encrypt(struct ktls_session *tls, else counter_u64_add(ocf_separate_output, 1); for (;;) { - error = crypto_dispatch(crp); + error = crypto_dispatch(&crp); if (error) break; mtx_lock(&os->lock); - while (!oo->done) - mtx_sleep(oo, &os->lock, 0, "ocfktls", 0); + while (!oo.done) + mtx_sleep(&oo, &os->lock, 0, "ocfktls", 0); mtx_unlock(&os->lock); - if (crp->crp_etype != EAGAIN) { - error = crp->crp_etype; + if (crp.crp_etype != EAGAIN) { + error = crp.crp_etype; break; } - crp->crp_etype = 0; - crp->crp_flags &= ~CRYPTO_F_DONE; - oo->done = false; + crp.crp_etype = 0; + crp.crp_flags &= ~CRYPTO_F_DONE; + oo.done = false; counter_u64_add(ocf_retries, 1); } - crypto_freereq(crp); - free(oo, M_KTLS_OCF); + crypto_destroyreq(&crp); return (error); } From 66ba9aafcf88fe900016254e6063969f15d59c7b Mon Sep 17 00:00:00 2001 From: Richard Scheffenegger Date: Mon, 20 Jul 2020 23:47:27 +0000 Subject: [PATCH 070/287] Add MODULE_VERSION to TCP loadable congestion control modules. Without versioning information, using preexisting loader / linker code is not easily possible when another module may have dependencies on pre-loaded modules, and also doesn't allow the automatic loading of dependent modules. No functional change of the actual modules. Reviewed by: tuexen (mentor), rgrimes (mentor) Approved by: tuexen (mentor), rgrimes (mentor) MFC after: 2 weeks Sponsored by: NetApp, Inc. Differential Revision: https://reviews.freebsd.org/D25744 --- sys/netinet/cc/cc_cdg.c | 2 +- sys/netinet/cc/cc_chd.c | 1 + sys/netinet/cc/cc_cubic.c | 1 + sys/netinet/cc/cc_dctcp.c | 1 + sys/netinet/cc/cc_hd.c | 1 + sys/netinet/cc/cc_htcp.c | 1 + sys/netinet/cc/cc_newreno.c | 1 + sys/netinet/cc/cc_vegas.c | 1 + 8 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sys/netinet/cc/cc_cdg.c b/sys/netinet/cc/cc_cdg.c index 6900e4027463..6287583f1f58 100644 --- a/sys/netinet/cc/cc_cdg.c +++ b/sys/netinet/cc/cc_cdg.c @@ -714,5 +714,5 @@ SYSCTL_UINT(_net_inet_tcp_cc_cdg, OID_AUTO, loss_compete_hold_backoff, "the window backoff for loss based CC compatibility"); DECLARE_CC_MODULE(cdg, &cdg_cc_algo); - +MODULE_VERSION(cdg, 1); MODULE_DEPEND(cdg, ertt, 1, 1, 1); diff --git a/sys/netinet/cc/cc_chd.c b/sys/netinet/cc/cc_chd.c index 0be8616c080c..fc995b0ebb02 100644 --- a/sys/netinet/cc/cc_chd.c +++ b/sys/netinet/cc/cc_chd.c @@ -493,4 +493,5 @@ SYSCTL_UINT(_net_inet_tcp_cc_chd, OID_AUTO, use_max, "as the basic delay measurement for the algorithm."); DECLARE_CC_MODULE(chd, &chd_cc_algo); +MODULE_VERSION(chd, 1); MODULE_DEPEND(chd, ertt, 1, 1, 1); diff --git a/sys/netinet/cc/cc_cubic.c b/sys/netinet/cc/cc_cubic.c index a98c1c5c75be..3fb2affaffaf 100644 --- a/sys/netinet/cc/cc_cubic.c +++ b/sys/netinet/cc/cc_cubic.c @@ -473,3 +473,4 @@ cubic_ssthresh_update(struct cc_var *ccv) DECLARE_CC_MODULE(cubic, &cubic_cc_algo); +MODULE_VERSION(cubic, 1); diff --git a/sys/netinet/cc/cc_dctcp.c b/sys/netinet/cc/cc_dctcp.c index f31a9f40be66..215672102512 100644 --- a/sys/netinet/cc/cc_dctcp.c +++ b/sys/netinet/cc/cc_dctcp.c @@ -464,3 +464,4 @@ SYSCTL_PROC(_net_inet_tcp_cc_dctcp, OID_AUTO, slowstart, "half CWND reduction after the first slow start"); DECLARE_CC_MODULE(dctcp, &dctcp_cc_algo); +MODULE_VERSION(dctcp, 1); diff --git a/sys/netinet/cc/cc_hd.c b/sys/netinet/cc/cc_hd.c index f9e944ddfc0f..128a823a6f2b 100644 --- a/sys/netinet/cc/cc_hd.c +++ b/sys/netinet/cc/cc_hd.c @@ -251,4 +251,5 @@ SYSCTL_PROC(_net_inet_tcp_cc_hd, OID_AUTO, queue_min, "minimum queueing delay threshold (qmin) in ticks"); DECLARE_CC_MODULE(hd, &hd_cc_algo); +MODULE_VERSION(hd, 1); MODULE_DEPEND(hd, ertt, 1, 1, 1); diff --git a/sys/netinet/cc/cc_htcp.c b/sys/netinet/cc/cc_htcp.c index 85673e90a521..a528f18d0453 100644 --- a/sys/netinet/cc/cc_htcp.c +++ b/sys/netinet/cc/cc_htcp.c @@ -530,3 +530,4 @@ SYSCTL_UINT(_net_inet_tcp_cc_htcp, OID_AUTO, rtt_scaling, "enable H-TCP RTT scaling"); DECLARE_CC_MODULE(htcp, &htcp_cc_algo); +MODULE_VERSION(htcp, 1); diff --git a/sys/netinet/cc/cc_newreno.c b/sys/netinet/cc/cc_newreno.c index 7ce91ea06943..4a515a474aab 100644 --- a/sys/netinet/cc/cc_newreno.c +++ b/sys/netinet/cc/cc_newreno.c @@ -396,3 +396,4 @@ SYSCTL_PROC(_net_inet_tcp_cc_newreno, OID_AUTO, beta_ecn, "New Reno beta ecn, specified as number between 1 and 100"); DECLARE_CC_MODULE(newreno, &newreno_cc_algo); +MODULE_VERSION(newreno, 1); diff --git a/sys/netinet/cc/cc_vegas.c b/sys/netinet/cc/cc_vegas.c index fa226120d834..cd38ad546140 100644 --- a/sys/netinet/cc/cc_vegas.c +++ b/sys/netinet/cc/cc_vegas.c @@ -301,4 +301,5 @@ SYSCTL_PROC(_net_inet_tcp_cc_vegas, OID_AUTO, beta, "vegas beta, specified as number of \"buffers\" (0 < alpha < beta)"); DECLARE_CC_MODULE(vegas, &vegas_cc_algo); +MODULE_VERSION(vegas, 1); MODULE_DEPEND(vegas, ertt, 1, 1, 1); From c4cbf1fbabcb84d9d0a49c2444ed398ed9907df5 Mon Sep 17 00:00:00 2001 From: Craig Leres Date: Mon, 20 Jul 2020 23:57:53 +0000 Subject: [PATCH 071/287] Fix some regressions with the zgrep(1) wrapper. - Handle whitespace with long flags that take arguments: echo 'foo bar' > test zgrep --regexp='foo bar' test - Do not hang reading from stdin with patterns in a file: echo foobar > test echo foo > pattern zgrep -f pattern test zgrep --file=pattern test - Handle any flags after -e: echo foobar > test zgrep -e foo --ignore-case < test These two are still outstanding problems: - Does not handle flags that take an argument if there is no whitespace: zgrep -enfs /etc/rpc - When more than one -e pattern used matching should occur for all patterns (similar to multiple patterns supplied with -f file). Instead only the last pattern is used for matching: zgrep -e rex -e nfs /etc/rpc (This problem is masked in the unpatched version by the "any flags after -e" problem.) Add tests for the above problems. Update the mange and add references to gzip(1) and zstd(1) and also document the remaining known problems. PR: 247126 Approved by: markj MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D25613 --- contrib/netbsd-tests/usr.bin/grep/t_grep.sh | 89 +++++++++++++++++++++ usr.bin/grep/zgrep.1 | 24 +++++- usr.bin/grep/zgrep.sh | 50 +++++++++--- 3 files changed, 150 insertions(+), 13 deletions(-) diff --git a/contrib/netbsd-tests/usr.bin/grep/t_grep.sh b/contrib/netbsd-tests/usr.bin/grep/t_grep.sh index c5c47e992378..75ee254cc79b 100755 --- a/contrib/netbsd-tests/usr.bin/grep/t_grep.sh +++ b/contrib/netbsd-tests/usr.bin/grep/t_grep.sh @@ -214,6 +214,89 @@ zgrep_body() atf_check -o file:"$(atf_get_srcdir)/d_zgrep.out" zgrep -h line d_input.gz } +atf_test_case zgrep_combined_flags +zgrep_combined_flags_head() +{ + atf_set "descr" "Checks for zgrep wrapper problems with combined flags (PR 247126)" +} +zgrep_combined_flags_body() +{ + atf_expect_fail "known but unsolved zgrep wrapper script regression" + + echo 'foo bar' > test + + atf_check -o inline:"foo bar\n" zgrep -we foo test + # Avoid hang on reading from stdin in the failure case + atf_check -o inline:"foo bar\n" zgrep -wefoo test < /dev/null +} + +atf_test_case zgrep_eflag +zgrep_eflag_head() +{ + atf_set "descr" "Checks for zgrep wrapper problems with -e PATTERN (PR 247126)" +} +zgrep_eflag_body() +{ + echo 'foo bar' > test + + # Avoid hang on reading from stdin in the failure case + atf_check -o inline:"foo bar\n" zgrep -e 'foo bar' test < /dev/null + atf_check -o inline:"foo bar\n" zgrep --regexp='foo bar' test < /dev/null +} + +atf_test_case zgrep_fflag +zgrep_fflag_head() +{ + atf_set "descr" "Checks for zgrep wrapper problems with -f FILE (PR 247126)" +} +zgrep_fflag_body() +{ + echo foo > pattern + echo foobar > test + + # Avoid hang on reading from stdin in the failure case + atf_check -o inline:"foobar\n" zgrep -f pattern test test + + atf_check -o inline:"foobar\n" zgrep -e foo --ignore-case < test +} + +atf_test_case zgrep_multiple_eflags +zgrep_multiple_eflags_head() +{ + atf_set "descr" "Checks for zgrep wrapper problems with multiple -e flags (PR 247126)" +} +zgrep_multiple_eflags_body() +{ + atf_expect_fail "known but unsolved zgrep wrapper script regression" + + echo foobar > test + + atf_check -o inline:"foobar\n" zgrep -e foo -e xxx test +} + +atf_test_case zgrep_empty_eflag +zgrep_empty_eflag_head() +{ + atf_set "descr" "Checks for zgrep wrapper problems with empty -e flags pattern (PR 247126)" +} +zgrep_empty_eflag_body() +{ + echo foobar > test + + atf_check -o inline:"foobar\n" zgrep -e '' test +} + atf_test_case nonexistent nonexistent_head() { @@ -826,6 +909,12 @@ atf_init_test_cases() atf_add_test_case file_exp atf_add_test_case egrep atf_add_test_case zgrep + atf_add_test_case zgrep_combined_flags + atf_add_test_case zgrep_eflag + atf_add_test_case zgrep_empty_eflag + atf_add_test_case zgrep_fflag + atf_add_test_case zgrep_long_eflag + atf_add_test_case zgrep_multiple_eflags atf_add_test_case nonexistent atf_add_test_case context2 # Begin FreeBSD diff --git a/usr.bin/grep/zgrep.1 b/usr.bin/grep/zgrep.1 index 332f980feca7..e300bf54b6d8 100644 --- a/usr.bin/grep/zgrep.1 +++ b/usr.bin/grep/zgrep.1 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 21, 2018 +.Dd July 20, 2020 .Dt ZGREP 1 .Os .Sh NAME @@ -86,9 +86,29 @@ to read compressed files. .Sh SEE ALSO .Xr bzip2 1 , .Xr grep 1 , -.Xr xz 1 +.Xr gzip 1 , +.Xr xz 1 , +.Xr zstd 1 .Sh AUTHORS This version of the .Nm utility was written by .An Thomas Klausner Aq Mt wiz@NetBSD.org . +.Sh BUGS +.Xr zgrep 1 +does not handle flags that take arguments if there is no whitespace +between the flag and the argument, for example: +.Pp +.Dl "zgrep -enfs /etc/rpc" +.Pp +When more than one +.Fl e +flag is used matching +should occur for any of the patterns (similar to multiple patterns +supplied in a file with the +.Fl f +flag). +.Xr zgrep 1 +only matches the last +.Fl e +pattern. diff --git a/usr.bin/grep/zgrep.sh b/usr.bin/grep/zgrep.sh index c645b1ca5907..acbcb48770a7 100755 --- a/usr.bin/grep/zgrep.sh +++ b/usr.bin/grep/zgrep.sh @@ -29,6 +29,7 @@ grep=grep zcat=zstdcat endofopts=0 +pattern_file=0 pattern_found=0 grep_args="" hyphen=0 @@ -75,18 +76,39 @@ while [ $# -gt 0 -a ${endofopts} -eq 0 ] do case $1 in # from GNU grep-2.5.1 -- keep in sync! - -[ABCDXdefm]) + --) + shift + endofopts=1 + ;; + --file=*) + pattern_file=1 + grep_args="${grep_args} ${1}" + shift + ;; + --regexp=*) + pattern="${1#--regexp=}" + pattern_found=1 + shift + ;; + --*) + grep_args="${grep_args} $1" + shift + ;; + -*[ABCDXdefm]) if [ $# -lt 2 ] then echo "${prg}: missing argument for $1 flag" >&2 exit 1 fi case $1 in - -e) + -*e) pattern="$2" pattern_found=1 shift 2 - break + continue + ;; + -*f) + pattern_file=1 ;; *) ;; @@ -94,10 +116,6 @@ do grep_args="${grep_args} $1 $2" shift 2 ;; - --) - shift - endofopts=1 - ;; -) hyphen=1 shift @@ -125,7 +143,7 @@ do done # if no -e option was found, take next argument as grep-pattern -if [ ${pattern_found} -lt 1 ] +if [ ${pattern_file} -eq 0 -a ${pattern_found} -eq 0 ] then if [ $# -ge 1 ]; then pattern="$1" @@ -136,6 +154,7 @@ then echo "${prg}: missing pattern" >&2 exit 1 fi + pattern_found=1 fi ret=0 @@ -143,15 +162,24 @@ ret=0 if [ $# -lt 1 ] then # ... on stdin - ${cattool} ${catargs} - | ${grep} ${grep_args} -- "${pattern}" - || ret=$? + if [ ${pattern_file} -eq 0 ]; then + ${cattool} ${catargs} - | ${grep} ${grep_args} -- "${pattern}" - || ret=$? + else + ${cattool} ${catargs} - | ${grep} ${grep_args} -- - || ret=$? + fi else # ... on all files given on the command line if [ ${silent} -lt 1 -a $# -gt 1 ]; then grep_args="-H ${grep_args}" fi for file; do - ${cattool} ${catargs} -- "${file}" | - ${grep} --label="${file}" ${grep_args} -- "${pattern}" - || ret=$? + if [ ${pattern_file} -eq 0 ]; then + ${cattool} ${catargs} -- "${file}" | + ${grep} --label="${file}" ${grep_args} -- "${pattern}" - || ret=$? + else + ${cattool} ${catargs} -- "${file}" | + ${grep} --label="${file}" ${grep_args} -- - || ret=$? + fi done fi From e57f9c8a9f9b9dc233428d2f86d71d9c2e6b62eb Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Tue, 21 Jul 2020 07:35:03 +0000 Subject: [PATCH 072/287] gpioiic: never drive lines active high I2C communication is done by a combination of driving a line low or letting it float, so that it is either pulled up or driven low by another party. r355276 besides the stated goal of the change -- using the new GPIO API -- also changed the logic, so that active state is signaled by actively driving a line. That worked with iicbb prior to r362042, but stopped working after that commit on at least some hardware. My guess that the breakage was related to getting an ACK bit. A device expected to be able to drive SDA actively low, but controller was actively driving it high for some time. Anyway, this change seems to fix the problem. Tested using gpioiic on Orange Pi PC Plus with HTU21 sensor. Reported by: Nick Kostirya Reviewed by: manu MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25684 --- sys/dev/gpio/gpioiic.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/sys/dev/gpio/gpioiic.c b/sys/dev/gpio/gpioiic.c index 5216f4e8f8a6..6d62a6d04d95 100644 --- a/sys/dev/gpio/gpioiic.c +++ b/sys/dev/gpio/gpioiic.c @@ -191,16 +191,14 @@ static void gpioiic_setsda(device_t dev, int val) { struct gpioiic_softc *sc = device_get_softc(dev); - int err; - /* - * Some controllers cannot set an output value while a pin is in input - * mode; in that case we set the pin again after changing mode. - */ - err = gpio_pin_set_active(sc->sdapin, val); - gpio_pin_setflags(sc->sdapin, GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN); - if (err != 0) - gpio_pin_set_active(sc->sdapin, val); + if (val) { + gpio_pin_setflags(sc->sdapin, GPIO_PIN_INPUT); + } else { + gpio_pin_setflags(sc->sdapin, + GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN); + gpio_pin_set_active(sc->sdapin, 0); + } } static void @@ -208,8 +206,13 @@ gpioiic_setscl(device_t dev, int val) { struct gpioiic_softc *sc = device_get_softc(dev); - gpio_pin_setflags(sc->sclpin, GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN); - gpio_pin_set_active(sc->sclpin, val); + if (val) { + gpio_pin_setflags(sc->sclpin, GPIO_PIN_INPUT); + } else { + gpio_pin_setflags(sc->sclpin, + GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN); + gpio_pin_set_active(sc->sclpin, 0); + } } static int From 2032c532aad7def4246282ff51cc36ac6f2c5db0 Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Tue, 21 Jul 2020 07:41:36 +0000 Subject: [PATCH 073/287] dtrace/fbt: fix return probe arguments on arm arg0 should be an offset of the return point within the function, arg1 should be the return value. Previously the return probe had arguments as if for the entry probe. Tested on armv7. andrew noted that the same problem seems to be present on arm64, mips, and riscv. I am not sure if I will get around to fixing those. So, platform users or anyone looking to make a contribution please be aware of this opportunity. Reviewed by: markj MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25685 --- sys/cddl/dev/dtrace/arm/dtrace_subr.c | 2 +- sys/cddl/dev/fbt/arm/fbt_isa.c | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/sys/cddl/dev/dtrace/arm/dtrace_subr.c b/sys/cddl/dev/dtrace/arm/dtrace_subr.c index be999e3a07a9..8cd9c9c1f204 100644 --- a/sys/cddl/dev/dtrace/arm/dtrace_subr.c +++ b/sys/cddl/dev/dtrace/arm/dtrace_subr.c @@ -248,7 +248,7 @@ dtrace_invop_start(struct trapframe *frame) register_t *r0, *sp; int data, invop, reg, update_sp; - invop = dtrace_invop(frame->tf_pc, frame, frame->tf_pc); + invop = dtrace_invop(frame->tf_pc, frame, frame->tf_r0); switch (invop & DTRACE_INVOP_MASK) { case DTRACE_INVOP_PUSHM: sp = (register_t *)frame->tf_svc_sp; diff --git a/sys/cddl/dev/fbt/arm/fbt_isa.c b/sys/cddl/dev/fbt/arm/fbt_isa.c index dc1abf3cf786..0be28b56aa6a 100644 --- a/sys/cddl/dev/fbt/arm/fbt_isa.c +++ b/sys/cddl/dev/fbt/arm/fbt_isa.c @@ -56,9 +56,12 @@ fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval) register_t fifthparam; for (; fbt != NULL; fbt = fbt->fbtp_hashnext) { - if ((uintptr_t)fbt->fbtp_patchpoint == addr) { - cpu->cpu_dtrace_caller = addr; + if ((uintptr_t)fbt->fbtp_patchpoint != addr) + continue; + cpu->cpu_dtrace_caller = addr; + + if (fbt->fbtp_roffset == 0) { /* Get 5th parameter from stack */ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); fifthparam = *(register_t *)frame->tf_svc_sp; @@ -67,11 +70,13 @@ fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval) dtrace_probe(fbt->fbtp_id, frame->tf_r0, frame->tf_r1, frame->tf_r2, frame->tf_r3, fifthparam); - - cpu->cpu_dtrace_caller = 0; - - return (fbt->fbtp_rval | (fbt->fbtp_savedval << DTRACE_INVOP_SHIFT)); + } else { + dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset, rval, + 0, 0, 0); } + + cpu->cpu_dtrace_caller = 0; + return (fbt->fbtp_rval | (fbt->fbtp_savedval << DTRACE_INVOP_SHIFT)); } return (0); @@ -178,6 +183,7 @@ fbt_provide_module_function(linker_file_t lf, int symindx, fbt->fbtp_rval = DTRACE_INVOP_B; else fbt->fbtp_rval = DTRACE_INVOP_POPM; + fbt->fbtp_roffset = (uintptr_t)instr - (uintptr_t)symval->value; fbt->fbtp_savedval = *instr; fbt->fbtp_patchval = FBT_BREAKPOINT; fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; From f2b2f31707bce25e3fdee9fdfcb75ddbd1ff3338 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Tue, 21 Jul 2020 10:38:51 +0000 Subject: [PATCH 074/287] Move the Intel DMAR busdma backend to a generic place so it can be used on other IOMMU systems. Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25720 --- sys/conf/files.x86 | 2 +- sys/{x86/iommu/busdma_dmar.c => dev/iommu/busdma_iommu.c} | 6 +++--- sys/{x86/iommu/busdma_dmar.h => dev/iommu/busdma_iommu.h} | 0 sys/x86/iommu/intel_ctx.c | 2 +- sys/x86/iommu/intel_drv.c | 2 +- sys/x86/iommu/intel_fault.c | 2 +- sys/x86/iommu/intel_gas.c | 2 +- sys/x86/iommu/intel_idpgtbl.c | 2 +- sys/x86/iommu/intel_intrmap.c | 2 +- sys/x86/iommu/intel_qi.c | 2 +- sys/x86/iommu/intel_quirks.c | 2 +- sys/x86/iommu/intel_utils.c | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) rename sys/{x86/iommu/busdma_dmar.c => dev/iommu/busdma_iommu.c} (99%) rename sys/{x86/iommu/busdma_dmar.h => dev/iommu/busdma_iommu.h} (100%) diff --git a/sys/conf/files.x86 b/sys/conf/files.x86 index 08ab90d0f8f6..b5f68041246d 100644 --- a/sys/conf/files.x86 +++ b/sys/conf/files.x86 @@ -165,6 +165,7 @@ dev/imcsmb/imcsmb.c optional imcsmb dev/imcsmb/imcsmb_pci.c optional imcsmb pci dev/intel/spi.c optional intelspi dev/io/iodev.c optional io +dev/iommu/busdma_iommu.c optional acpi acpi_dmar pci dev/ipmi/ipmi.c optional ipmi dev/ipmi/ipmi_acpi.c optional ipmi acpi dev/ipmi/ipmi_isa.c optional ipmi isa @@ -300,7 +301,6 @@ x86/cpufreq/hwpstate_amd.c optional cpufreq x86/cpufreq/hwpstate_intel.c optional cpufreq x86/cpufreq/p4tcc.c optional cpufreq x86/cpufreq/powernow.c optional cpufreq -x86/iommu/busdma_dmar.c optional acpi acpi_dmar pci x86/iommu/intel_ctx.c optional acpi acpi_dmar pci x86/iommu/intel_drv.c optional acpi acpi_dmar pci x86/iommu/intel_fault.c optional acpi acpi_dmar pci diff --git a/sys/x86/iommu/busdma_dmar.c b/sys/dev/iommu/busdma_iommu.c similarity index 99% rename from sys/x86/iommu/busdma_dmar.c rename to sys/dev/iommu/busdma_iommu.c index 6b9d3be49b1b..02da3acf5e9e 100644 --- a/sys/x86/iommu/busdma_dmar.c +++ b/sys/dev/iommu/busdma_iommu.c @@ -67,13 +67,13 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #endif /* - * busdma_dmar.c, the implementation of the busdma(9) interface using - * DMAR units from Intel VT-d. + * busdma_iommu.c, the implementation of the busdma(9) interface using + * IOMMU units from Intel VT-d. */ static bool diff --git a/sys/x86/iommu/busdma_dmar.h b/sys/dev/iommu/busdma_iommu.h similarity index 100% rename from sys/x86/iommu/busdma_dmar.h rename to sys/dev/iommu/busdma_iommu.h diff --git a/sys/x86/iommu/intel_ctx.c b/sys/x86/iommu/intel_ctx.c index 92ee9676af98..dd551c2f56d3 100644 --- a/sys/x86/iommu/intel_ctx.c +++ b/sys/x86/iommu/intel_ctx.c @@ -66,7 +66,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include #include diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c index 6f1771fd9090..90cc923180fa 100644 --- a/sys/x86/iommu/intel_drv.c +++ b/sys/x86/iommu/intel_drv.c @@ -68,7 +68,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include #include diff --git a/sys/x86/iommu/intel_fault.c b/sys/x86/iommu/intel_fault.c index 281f6d2f5146..628bcf2ee763 100644 --- a/sys/x86/iommu/intel_fault.c +++ b/sys/x86/iommu/intel_fault.c @@ -57,7 +57,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include /* diff --git a/sys/x86/iommu/intel_gas.c b/sys/x86/iommu/intel_gas.c index 2ddddf77ad59..9df0da9242b2 100644 --- a/sys/x86/iommu/intel_gas.c +++ b/sys/x86/iommu/intel_gas.c @@ -66,7 +66,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include diff --git a/sys/x86/iommu/intel_idpgtbl.c b/sys/x86/iommu/intel_idpgtbl.c index fc99f058a1fe..2febb55f9426 100644 --- a/sys/x86/iommu/intel_idpgtbl.c +++ b/sys/x86/iommu/intel_idpgtbl.c @@ -65,7 +65,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include diff --git a/sys/x86/iommu/intel_intrmap.c b/sys/x86/iommu/intel_intrmap.c index 2dbd2d15704d..d2bce59c4c2e 100644 --- a/sys/x86/iommu/intel_intrmap.c +++ b/sys/x86/iommu/intel_intrmap.c @@ -54,7 +54,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include #include diff --git a/sys/x86/iommu/intel_qi.c b/sys/x86/iommu/intel_qi.c index 564a87f21db0..5377ac448df8 100644 --- a/sys/x86/iommu/intel_qi.c +++ b/sys/x86/iommu/intel_qi.c @@ -57,7 +57,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include diff --git a/sys/x86/iommu/intel_quirks.c b/sys/x86/iommu/intel_quirks.c index 4fb17dbcff49..d0eac82e7298 100644 --- a/sys/x86/iommu/intel_quirks.c +++ b/sys/x86/iommu/intel_quirks.c @@ -59,7 +59,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include #include diff --git a/sys/x86/iommu/intel_utils.c b/sys/x86/iommu/intel_utils.c index 419c6100ca1d..739952328b18 100644 --- a/sys/x86/iommu/intel_utils.c +++ b/sys/x86/iommu/intel_utils.c @@ -65,7 +65,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include From 1238a28d152e19b4d0ad0ad98a464e83278c494f Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Tue, 21 Jul 2020 13:50:10 +0000 Subject: [PATCH 075/287] Move sys/iommu.h to dev/iommu/ as a part of generic IOMMU busdma backend. Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25750 --- sys/dev/iommu/busdma_iommu.c | 2 +- sys/dev/iommu/busdma_iommu.h | 2 +- sys/{sys => dev/iommu}/iommu.h | 0 sys/x86/iommu/intel_dmar.h | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename sys/{sys => dev/iommu}/iommu.h (100%) diff --git a/sys/dev/iommu/busdma_iommu.c b/sys/dev/iommu/busdma_iommu.c index 02da3acf5e9e..d543436a8a86 100644 --- a/sys/dev/iommu/busdma_iommu.c +++ b/sys/dev/iommu/busdma_iommu.c @@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -68,6 +67,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #endif diff --git a/sys/dev/iommu/busdma_iommu.h b/sys/dev/iommu/busdma_iommu.h index 22575a6cb35a..77ac9d0a6e2d 100644 --- a/sys/dev/iommu/busdma_iommu.h +++ b/sys/dev/iommu/busdma_iommu.h @@ -34,7 +34,7 @@ #ifndef __X86_IOMMU_BUSDMA_DMAR_H #define __X86_IOMMU_BUSDMA_DMAR_H -#include +#include struct bus_dma_tag_iommu { struct bus_dma_tag_common common; diff --git a/sys/sys/iommu.h b/sys/dev/iommu/iommu.h similarity index 100% rename from sys/sys/iommu.h rename to sys/dev/iommu/iommu.h diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h index cd9639c00b64..e6212255b382 100644 --- a/sys/x86/iommu/intel_dmar.h +++ b/sys/x86/iommu/intel_dmar.h @@ -34,7 +34,7 @@ #ifndef __X86_IOMMU_INTEL_DMAR_H #define __X86_IOMMU_INTEL_DMAR_H -#include +#include struct dmar_unit; From 7377c1df84c21ab95cf19f56c56c8404427421b6 Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Tue, 21 Jul 2020 14:25:36 +0000 Subject: [PATCH 076/287] Only write to VIRTIO_MMIO_GUEST_PAGE_SIZE with virtio mmio version 1 This register is only defined for the legacy v1 interface so only write to it when interacting with a legacy device. Sponsored by: Innovate UK --- sys/dev/virtio/mmio/virtio_mmio.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sys/dev/virtio/mmio/virtio_mmio.c b/sys/dev/virtio/mmio/virtio_mmio.c index 0414706fb990..a9c7b65741cd 100644 --- a/sys/dev/virtio/mmio/virtio_mmio.c +++ b/sys/dev/virtio/mmio/virtio_mmio.c @@ -491,8 +491,10 @@ vtmmio_alloc_virtqueues(device_t dev, int flags, int nvqs, if (sc->vtmmio_vqs == NULL) return (ENOMEM); - vtmmio_write_config_4(sc, VIRTIO_MMIO_GUEST_PAGE_SIZE, - (1 << PAGE_SHIFT)); + if (sc->vtmmio_version == 1) { + vtmmio_write_config_4(sc, VIRTIO_MMIO_GUEST_PAGE_SIZE, + (1 << PAGE_SHIFT)); + } for (idx = 0; idx < nvqs; idx++) { vqx = &sc->vtmmio_vqs[idx]; @@ -564,8 +566,10 @@ vtmmio_reinit(device_t dev, uint64_t features) vtmmio_negotiate_features(dev, features); - vtmmio_write_config_4(sc, VIRTIO_MMIO_GUEST_PAGE_SIZE, - (1 << PAGE_SHIFT)); + if (sc->vtmmio_version == 1) { + vtmmio_write_config_4(sc, VIRTIO_MMIO_GUEST_PAGE_SIZE, + (1 << PAGE_SHIFT)); + } for (idx = 0; idx < sc->vtmmio_nvqs; idx++) { error = vtmmio_reinit_virtqueue(sc, idx); From bdb6d824f4bdf5611f89d62bd70f6251ff64dbcf Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Tue, 21 Jul 2020 14:39:20 +0000 Subject: [PATCH 077/287] lockmgr: add a helper for reading the lock value --- sys/kern/kern_lock.c | 34 +++++++++++++++++----------------- sys/sys/lockmgr.h | 1 + 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index d5cf65c27de6..10b7edb699f4 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -140,7 +140,7 @@ LK_CAN_SHARE(uintptr_t x, int flags, bool fp) #define lockmgr_xlocked_v(v) \ (((v) & ~(LK_FLAGMASK & ~LK_SHARE)) == (uintptr_t)curthread) -#define lockmgr_xlocked(lk) lockmgr_xlocked_v((lk)->lk_lock) +#define lockmgr_xlocked(lk) lockmgr_xlocked_v(lockmgr_read_value(lk)) static void assert_lockmgr(const struct lock_object *lock, int how); #ifdef DDB @@ -233,7 +233,7 @@ static void lockmgr_note_exclusive_release(struct lock *lk, const char *file, int line) { - if (LK_HOLDER(lk->lk_lock) != LK_KERNPROC) { + if (LK_HOLDER(lockmgr_read_value(lk)) != LK_KERNPROC) { WITNESS_UNLOCK(&lk->lock_object, LOP_EXCLUSIVE, file, line); TD_LOCKS_DEC(curthread); } @@ -246,7 +246,7 @@ lockmgr_xholder(const struct lock *lk) { uintptr_t x; - x = lk->lk_lock; + x = lockmgr_read_value(lk); return ((x & LK_SHARE) ? NULL : (struct thread *)LK_HOLDER(x)); } @@ -309,7 +309,7 @@ wakeupshlk(struct lock *lk, const char *file, int line) wakeup_swapper = 0; for (;;) { - x = lk->lk_lock; + x = lockmgr_read_value(lk); if (lockmgr_sunlock_try(lk, &x)) break; @@ -318,7 +318,7 @@ wakeupshlk(struct lock *lk, const char *file, int line) * path in order to handle wakeups correctly. */ sleepq_lock(&lk->lock_object); - orig_x = lk->lk_lock; + orig_x = lockmgr_read_value(lk); retry_sleepq: x = orig_x & (LK_ALL_WAITERS | LK_EXCLUSIVE_SPINNERS); v = LK_UNLOCKED; @@ -515,7 +515,7 @@ lockmgr_slock_try(struct lock *lk, uintptr_t *xp, int flags, bool fp) * waiters, if we fail to acquire the shared lock * loop back and retry. */ - *xp = lk->lk_lock; + *xp = lockmgr_read_value(lk); while (LK_CAN_SHARE(*xp, flags, fp)) { if (atomic_fcmpset_acq_ptr(&lk->lk_lock, xp, *xp + LK_ONE_SHARER)) { @@ -603,7 +603,7 @@ lockmgr_slock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, * probabilly will need to manipulate waiters flags. */ sleepq_lock(&lk->lock_object); - x = lk->lk_lock; + x = lockmgr_read_value(lk); retry_sleepq: /* @@ -772,7 +772,7 @@ lockmgr_xlock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, * probabilly will need to manipulate waiters flags. */ sleepq_lock(&lk->lock_object); - x = lk->lk_lock; + x = lockmgr_read_value(lk); retry_sleepq: /* @@ -889,7 +889,7 @@ lockmgr_upgrade(struct lock *lk, u_int flags, struct lock_object *ilk, tid = (uintptr_t)curthread; _lockmgr_assert(lk, KA_SLOCKED, file, line); - v = lk->lk_lock; + v = lockmgr_read_value(lk); x = v & LK_ALL_WAITERS; v &= LK_EXCLUSIVE_SPINNERS; @@ -970,7 +970,7 @@ lockmgr_lock_flags(struct lock *lk, u_int flags, struct lock_object *ilk, LOP_EXCLUSIVE, file, line, flags & LK_INTERLOCK ? ilk : NULL); tid = (uintptr_t)curthread; - if (lk->lk_lock == LK_UNLOCKED && + if (lockmgr_read_value(lk) == LK_UNLOCKED && atomic_cmpset_acq_ptr(&lk->lk_lock, LK_UNLOCKED, tid)) { lockmgr_note_exclusive_acquire(lk, 0, 0, file, line, flags); @@ -1054,7 +1054,7 @@ lockmgr_xunlock_hard(struct lock *lk, uintptr_t x, u_int flags, struct lock_obje goto out; sleepq_lock(&lk->lock_object); - x = lk->lk_lock; + x = lockmgr_read_value(lk); v = LK_UNLOCKED; /* @@ -1178,7 +1178,7 @@ lockmgr_unlock(struct lock *lk) line = __LINE__; _lockmgr_assert(lk, KA_LOCKED, file, line); - x = lk->lk_lock; + x = lockmgr_read_value(lk); if (__predict_true(x & LK_SHARE) != 0) { lockmgr_note_shared_release(lk, file, line); if (lockmgr_sunlock_try(lk, &x)) { @@ -1292,7 +1292,7 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk, * In order to preserve waiters flags, just spin. */ for (;;) { - x = lk->lk_lock; + x = lockmgr_read_value(lk); MPASS((x & LK_EXCLUSIVE_SPINNERS) == 0); x &= LK_ALL_WAITERS; if (atomic_cmpset_rel_ptr(&lk->lk_lock, tid | x, @@ -1305,7 +1305,7 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk, break; case LK_RELEASE: _lockmgr_assert(lk, KA_LOCKED, file, line); - x = lk->lk_lock; + x = lockmgr_read_value(lk); if (__predict_true(x & LK_SHARE) != 0) { lockmgr_note_shared_release(lk, file, line); @@ -1359,7 +1359,7 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk, * probabilly will need to manipulate waiters flags. */ sleepq_lock(&lk->lock_object); - x = lk->lk_lock; + x = lockmgr_read_value(lk); /* * if the lock has been released while we spun on @@ -1545,7 +1545,7 @@ _lockmgr_disown(struct lock *lk, const char *file, int line) * In order to preserve waiters flags, just spin. */ for (;;) { - x = lk->lk_lock; + x = lockmgr_read_value(lk); MPASS((x & LK_EXCLUSIVE_SPINNERS) == 0); x &= LK_ALL_WAITERS; if (atomic_cmpset_rel_ptr(&lk->lk_lock, tid | x, @@ -1597,7 +1597,7 @@ lockstatus(const struct lock *lk) int ret; ret = LK_SHARED; - x = lk->lk_lock; + x = lockmgr_read_value(lk); v = LK_HOLDER(x); if ((x & LK_SHARE) == 0) { diff --git a/sys/sys/lockmgr.h b/sys/sys/lockmgr.h index 8e5e4d43255f..65a06d7f3ecc 100644 --- a/sys/sys/lockmgr.h +++ b/sys/sys/lockmgr.h @@ -119,6 +119,7 @@ _lockmgr_args_rw(struct lock *lk, u_int flags, struct rwlock *ilk, /* * Define aliases in order to complete lockmgr KPI. */ +#define lockmgr_read_value(lk) ((lk)->lk_lock) #define lockmgr(lk, flags, ilk) \ _lockmgr_args((lk), (flags), (ilk), LK_WMESG_DEFAULT, \ LK_PRIO_DEFAULT, LK_TIMO_DEFAULT, LOCK_FILE, LOCK_LINE) From f6b091fbbd77cbb09728a52f0880dd5632ed7c51 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Tue, 21 Jul 2020 14:41:25 +0000 Subject: [PATCH 078/287] lockmgr: rewrite upgrade to stop always dropping the lock This matches rw and sx locks. --- sys/kern/kern_lock.c | 70 +++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index 10b7edb699f4..28eeb42ad143 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -878,9 +878,8 @@ static __noinline int lockmgr_upgrade(struct lock *lk, u_int flags, struct lock_object *ilk, const char *file, int line, struct lockmgr_wait *lwa) { - uintptr_t tid, x, v; + uintptr_t tid, v, setv; int error = 0; - int wakeup_swapper = 0; int op; if (KERNEL_PANICKED()) @@ -889,48 +888,47 @@ lockmgr_upgrade(struct lock *lk, u_int flags, struct lock_object *ilk, tid = (uintptr_t)curthread; _lockmgr_assert(lk, KA_SLOCKED, file, line); - v = lockmgr_read_value(lk); - x = v & LK_ALL_WAITERS; - v &= LK_EXCLUSIVE_SPINNERS; - - /* - * Try to switch from one shared lock to an exclusive one. - * We need to preserve waiters flags during the operation. - */ - if (atomic_cmpset_ptr(&lk->lk_lock, LK_SHARERS_LOCK(1) | x | v, - tid | x)) { - LOCK_LOG_LOCK("XUPGRADE", &lk->lock_object, 0, 0, file, - line); - WITNESS_UPGRADE(&lk->lock_object, LOP_EXCLUSIVE | - LK_TRYWIT(flags), file, line); - LOCKSTAT_RECORD0(lockmgr__upgrade, lk); - TD_SLOCKS_DEC(curthread); - goto out; - } op = flags & LK_TYPE_MASK; + v = lockmgr_read_value(lk); + for (;;) { + if (LK_SHARERS_LOCK(v) > 1) { + if (op == LK_TRYUPGRADE) { + LOCK_LOG2(lk, "%s: %p failed the nowait upgrade", + __func__, lk); + error = EBUSY; + goto out; + } + if (lockmgr_sunlock_try(lk, &v)) { + lockmgr_note_shared_release(lk, file, line); + goto out_xlock; + } + } + MPASS((v & ~LK_ALL_WAITERS) == LK_SHARERS_LOCK(1)); - /* - * In LK_TRYUPGRADE mode, do not drop the lock, - * returning EBUSY instead. - */ - if (op == LK_TRYUPGRADE) { - LOCK_LOG2(lk, "%s: %p failed the nowait upgrade", - __func__, lk); - error = EBUSY; - goto out; + setv = tid; + setv |= (v & LK_ALL_WAITERS); + + /* + * Try to switch from one shared lock to an exclusive one. + * We need to preserve waiters flags during the operation. + */ + if (atomic_fcmpset_ptr(&lk->lk_lock, &v, setv)) { + LOCK_LOG_LOCK("XUPGRADE", &lk->lock_object, 0, 0, file, + line); + WITNESS_UPGRADE(&lk->lock_object, LOP_EXCLUSIVE | + LK_TRYWIT(flags), file, line); + LOCKSTAT_RECORD0(lockmgr__upgrade, lk); + TD_SLOCKS_DEC(curthread); + goto out; + } } - /* - * We have been unable to succeed in upgrading, so just - * give up the shared lock. - */ - lockmgr_note_shared_release(lk, file, line); - wakeup_swapper |= wakeupshlk(lk, file, line); +out_xlock: error = lockmgr_xlock_hard(lk, flags, ilk, file, line, lwa); flags &= ~LK_INTERLOCK; out: - lockmgr_exit(flags, ilk, wakeup_swapper); + lockmgr_exit(flags, ilk, 0); return (error); } From 4aff9f5d99e0519061217fe07dbd5a1771f8545d Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Tue, 21 Jul 2020 14:42:22 +0000 Subject: [PATCH 079/287] lockmgr: denote recursion with a bit in lock value This reduces excessive reads from the lock. Tested by: pho --- sys/kern/kern_lock.c | 10 ++++++---- sys/sys/lockmgr.h | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index 28eeb42ad143..11396a6e259f 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -736,6 +736,7 @@ lockmgr_xlock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, panic("%s: recursing on non recursive lockmgr %p " "@ %s:%d\n", __func__, lk, file, line); } + atomic_set_ptr(&lk->lk_lock, LK_WRITER_RECURSED); lk->lk_recurse++; LOCK_LOG2(lk, "%s: %p recursing", __func__, lk); LOCK_LOG_LOCK("XLOCK", &lk->lock_object, 0, @@ -1039,9 +1040,11 @@ lockmgr_xunlock_hard(struct lock *lk, uintptr_t x, u_int flags, struct lock_obje * The lock is held in exclusive mode. * If the lock is recursed also, then unrecurse it. */ - if (lockmgr_xlocked_v(x) && lockmgr_recursed(lk)) { + if (lockmgr_recursed_v(x)) { LOCK_LOG2(lk, "%s: %p unrecursing", __func__, lk); lk->lk_recurse--; + if (lk->lk_recurse == 0) + atomic_clear_ptr(&lk->lk_lock, LK_WRITER_RECURSED); goto out; } if (tid != LK_KERNPROC) @@ -1187,9 +1190,8 @@ lockmgr_unlock(struct lock *lk) } else { tid = (uintptr_t)curthread; lockmgr_note_exclusive_release(lk, file, line); - if (!lockmgr_recursed(lk) && - atomic_cmpset_rel_ptr(&lk->lk_lock, tid, LK_UNLOCKED)) { - LOCKSTAT_PROFILE_RELEASE_RWLOCK(lockmgr__release, lk, LOCKSTAT_WRITER); + if (x == tid && atomic_cmpset_rel_ptr(&lk->lk_lock, tid, LK_UNLOCKED)) { + LOCKSTAT_PROFILE_RELEASE_RWLOCK(lockmgr__release, lk,LOCKSTAT_WRITER); } else { return (lockmgr_xunlock_hard(lk, x, LK_RELEASE, NULL, file, line)); } diff --git a/sys/sys/lockmgr.h b/sys/sys/lockmgr.h index 65a06d7f3ecc..336f57007013 100644 --- a/sys/sys/lockmgr.h +++ b/sys/sys/lockmgr.h @@ -42,13 +42,14 @@ #define LK_SHARED_WAITERS 0x02 #define LK_EXCLUSIVE_WAITERS 0x04 #define LK_EXCLUSIVE_SPINNERS 0x08 +#define LK_WRITER_RECURSED 0x10 #define LK_ALL_WAITERS \ (LK_SHARED_WAITERS | LK_EXCLUSIVE_WAITERS) #define LK_FLAGMASK \ - (LK_SHARE | LK_ALL_WAITERS | LK_EXCLUSIVE_SPINNERS) + (LK_SHARE | LK_ALL_WAITERS | LK_EXCLUSIVE_SPINNERS | LK_WRITER_RECURSED) #define LK_HOLDER(x) ((x) & ~LK_FLAGMASK) -#define LK_SHARERS_SHIFT 4 +#define LK_SHARERS_SHIFT 5 #define LK_SHARERS(x) (LK_HOLDER(x) >> LK_SHARERS_SHIFT) #define LK_SHARERS_LOCK(x) ((x) << LK_SHARERS_SHIFT | LK_SHARE) #define LK_ONE_SHARER (1 << LK_SHARERS_SHIFT) @@ -131,8 +132,10 @@ _lockmgr_args_rw(struct lock *lk, u_int flags, struct rwlock *ilk, LOCK_FILE, LOCK_LINE) #define lockmgr_disown(lk) \ _lockmgr_disown((lk), LOCK_FILE, LOCK_LINE) +#define lockmgr_recursed_v(v) \ + (v & LK_WRITER_RECURSED) #define lockmgr_recursed(lk) \ - ((lk)->lk_recurse != 0) + lockmgr_recursed_v((lk)->lk_lock) #define lockmgr_rw(lk, flags, ilk) \ _lockmgr_args_rw((lk), (flags), (ilk), LK_WMESG_DEFAULT, \ LK_PRIO_DEFAULT, LK_TIMO_DEFAULT, LOCK_FILE, LOCK_LINE) From ca19d0d78facb69c0776cff80f59aa3f07db9613 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Tue, 21 Jul 2020 15:03:36 +0000 Subject: [PATCH 080/287] traceroute6: Fix most warnings at the default WARNS level. Fix some style issues as well. Leave -Wno-cast-aligned set for now, as most of the warnings come casts of CMSG_DATA(), which does provide sufficient alignment in practice. Submitted by: Shubh Gupta Sponsored by: Google (GSOC 2020) MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25603 --- usr.sbin/traceroute6/Makefile | 4 +- usr.sbin/traceroute6/traceroute6.c | 105 +++++++++++++---------------- 2 files changed, 50 insertions(+), 59 deletions(-) diff --git a/usr.sbin/traceroute6/Makefile b/usr.sbin/traceroute6/Makefile index a7eaaf5bdaa3..2b79744bf4b5 100644 --- a/usr.sbin/traceroute6/Makefile +++ b/usr.sbin/traceroute6/Makefile @@ -26,8 +26,8 @@ BINMODE= 4555 CFLAGS+= -DIPSEC -DHAVE_POLL CFLAGS+= -I${.CURDIR} -I${TRACEROUTE_DISTDIR} -I. -WARNS?= 3 - LIBADD= ipsec .include + +CWARNFLAGS+= -Wno-cast-align diff --git a/usr.sbin/traceroute6/traceroute6.c b/usr.sbin/traceroute6/traceroute6.c index 4bb268d9b2d1..d377384fac36 100644 --- a/usr.sbin/traceroute6/traceroute6.c +++ b/usr.sbin/traceroute6/traceroute6.c @@ -294,16 +294,14 @@ static const char rcsid[] = #define freehostent(x) #endif -u_char packet[512]; /* last inbound (icmp) packet */ -char *outpacket; /* last output packet */ +static u_char packet[512]; /* last inbound (icmp) packet */ +static char *outpacket; /* last output packet */ int main(int, char *[]); int wait_for_reply(int, struct msghdr *); -#ifdef IPSEC -#ifdef IPSEC_POLICY_IPSEC +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) int setpolicy(int so, char *policy); #endif -#endif void send_probe(int, u_long); void *get_uphdr(struct ip6_hdr *, u_char *); int get_hoplim(struct msghdr *); @@ -318,40 +316,40 @@ u_int16_t tcp_chksum(struct sockaddr_in6 *, struct sockaddr_in6 *, void *, u_int32_t); void usage(void); -int rcvsock; /* receive (icmp) socket file descriptor */ -int sndsock; /* send (raw/udp) socket file descriptor */ +static int rcvsock; /* receive (icmp) socket file descriptor */ +static int sndsock; /* send (raw/udp) socket file descriptor */ -struct msghdr rcvmhdr; -struct iovec rcviov[2]; -int rcvhlim; -struct in6_pktinfo *rcvpktinfo; +static struct msghdr rcvmhdr; +static struct iovec rcviov[2]; +static int rcvhlim; +static struct in6_pktinfo *rcvpktinfo; -struct sockaddr_in6 Src, Dst, Rcv; -u_long datalen = 20; /* How much data */ +static struct sockaddr_in6 Src, Dst, Rcv; +static u_long datalen = 20; /* How much data */ #define ICMP6ECHOLEN 8 /* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */ -char rtbuf[2064]; -struct ip6_rthdr *rth; -struct cmsghdr *cmsg; +static char rtbuf[2064]; +static struct ip6_rthdr *rth; +static struct cmsghdr *cmsg; -char *source = NULL; -char *hostname; +static char *source = NULL; +static char *hostname; -u_long nprobes = 3; -u_long first_hop = 1; -u_long max_hops = 30; -u_int16_t srcport; -u_int16_t port = 32768+666; /* start udp dest port # for probe packets */ -u_int16_t ident; -int options; /* socket options */ -int verbose; -int waittime = 5; /* time to wait for response (in seconds) */ -int nflag; /* print addresses numerically */ -int useproto = IPPROTO_UDP; /* protocol to use to send packet */ -int lflag; /* print both numerical address & hostname */ -int as_path; /* print as numbers for each hop */ -char *as_server = NULL; -void *asn; +static u_long nprobes = 3; +static u_long first_hop = 1; +static u_long max_hops = 30; +static u_int16_t srcport; +static u_int16_t port = 32768+666; /* start udp dest port # for probe packets */ +static u_int16_t ident; +static int options; /* socket options */ +static int verbose; +static int waittime = 5; /* time to wait for response (in seconds) */ +static int nflag; /* print addresses numerically */ +static int useproto = IPPROTO_UDP; /* protocol to use to send packet */ +static int lflag; /* print both numerical address & hostname */ +static int as_path; /* print as numbers for each hop */ +static char *as_server = NULL; +static void *asn; int main(int argc, char *argv[]) @@ -366,6 +364,10 @@ main(int argc, char *argv[]) size_t size, minlen; uid_t uid; u_char type, code; +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) + char ipsec_inpolicy[] = "in bypass"; + char ipsec_outpolicy[] = "out bypass"; +#endif /* * Receive ICMP @@ -628,7 +630,7 @@ main(int argc, char *argv[]) fprintf(stderr, "traceroute6: Warning: %s has multiple " "addresses; using %s\n", hostname, hbuf); } - + freeaddrinfo(res); if (*++argv) { ep = NULL; errno = 0; @@ -705,15 +707,14 @@ main(int argc, char *argv[]) if (options & SO_DONTROUTE) (void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)); -#ifdef IPSEC -#ifdef IPSEC_POLICY_IPSEC +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) /* * do not raise error even if setsockopt fails, kernel may have ipsec * turned off. */ - if (setpolicy(rcvsock, "in bypass") < 0) + if (setpolicy(rcvsock, ipsec_inpolicy) < 0) errx(1, "%s", ipsec_strerror()); - if (setpolicy(rcvsock, "out bypass") < 0) + if (setpolicy(rcvsock, ipsec_outpolicy) < 0) errx(1, "%s", ipsec_strerror()); #else { @@ -735,8 +736,7 @@ main(int argc, char *argv[]) sizeof(level)); #endif } -#endif /*IPSEC_POLICY_IPSEC*/ -#endif /*IPSEC*/ +#endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */ #ifdef SO_SNDBUF i = datalen; @@ -763,15 +763,14 @@ main(int argc, char *argv[]) exit(1); } } -#ifdef IPSEC -#ifdef IPSEC_POLICY_IPSEC +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) /* * do not raise error even if setsockopt fails, kernel may have ipsec * turned off. */ - if (setpolicy(sndsock, "in bypass") < 0) + if (setpolicy(sndsock, ipsec_inpolicy) < 0) errx(1, "%s", ipsec_strerror()); - if (setpolicy(sndsock, "out bypass") < 0) + if (setpolicy(sndsock, ipsec_outpolicy) < 0) errx(1, "%s", ipsec_strerror()); #else { @@ -793,17 +792,13 @@ main(int argc, char *argv[]) sizeof(level)); #endif } -#endif /*IPSEC_POLICY_IPSEC*/ -#endif /*IPSEC*/ +#endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */ /* * Source selection */ bzero(&Src, sizeof(Src)); if (source) { - struct addrinfo hints, *res; - int error; - memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_DGRAM; /*dummy*/ @@ -1018,12 +1013,9 @@ wait_for_reply(int sock, struct msghdr *mhdr) #endif } -#ifdef IPSEC -#ifdef IPSEC_POLICY_IPSEC +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) int -setpolicy(so, policy) - int so; - char *policy; +setpolicy(int so, char *policy) { char *buf; @@ -1040,7 +1032,6 @@ setpolicy(so, policy) return 0; } #endif -#endif void send_probe(int seq, u_long hops) @@ -1627,11 +1618,11 @@ static u_int32_t crc_c[256] = { }; u_int32_t -sctp_crc32c(void *packet, u_int32_t len) +sctp_crc32c(void *pack, u_int32_t len) { u_int32_t i, crc32c; u_int8_t byte0, byte1, byte2, byte3; - u_int8_t *buf = (u_int8_t *)packet; + u_int8_t *buf = (u_int8_t *)pack; crc32c = ~0; for (i = 0; i < len; i++) From f8f51b49d8c51390222350d936988686af568b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Apestegu=C3=ADa?= Date: Tue, 21 Jul 2020 16:17:23 +0000 Subject: [PATCH 081/287] netstat(1): Add EXAMPLES section * Add small EXAMPLES section * Fix warning reported by mandoc (./netstat.1:747:2: WARNING: skipping paragraph macro: Pp before Ss) Approved by: manpages (gbe) Differential Revision: https://reviews.freebsd.org/D25212 --- usr.bin/netstat/netstat.1 | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1 index 6d642c3016ab..688903beb06a 100644 --- a/usr.bin/netstat/netstat.1 +++ b/usr.bin/netstat/netstat.1 @@ -28,7 +28,7 @@ .\" @(#)netstat.1 8.8 (Berkeley) 4/18/94 .\" $FreeBSD$ .\" -.Dd March 22, 2018 +.Dd July 21, 2020 .Dt NETSTAT 1 .Os .Sh NAME @@ -744,7 +744,6 @@ The flags field shows available ISR handlers: .It Li F Ta Dv NETISR_SNP_FLAGS_M2FLOW Ta "Able to map mbuf to flow id" .El .El -.Pp .Ss GENERAL OPTIONS Some options have the general meaning: .Bl -tag -width flag @@ -798,6 +797,28 @@ Normally attempts to resolve addresses and ports, and display them symbolically. .El +.Sh EXAMPLES +Show packet traffic information (packets, bytes, errors, packet drops, etc) for +interface re0 updated every 2 seconds and exit after 5 outputs: +.Bd -literal -offset indent +$ netstat -w 2 -q 5 -I re0 +.Ed +.Pp +Show statistics for ICMP on any interface: +.Bd -literal -offset indent +$ netstat -s -p icmp +.Ed +.Pp +Show routing tables: +.Bd -literal -offset indent +$ netstat -r +.Ed +.Pp +Same as above, but without resolving numeric addresses and port numbers to +names: +.Bd -literal -offset indent +$ netstat -rn +.Ed .Sh SEE ALSO .Xr fstat 1 , .Xr nfsstat 1 , From cce999b38fc5373a6f7751ea2cb6fe4d54504312 Mon Sep 17 00:00:00 2001 From: Richard Scheffenegger Date: Tue, 21 Jul 2020 16:21:52 +0000 Subject: [PATCH 082/287] Fix style and comment around concave/convex regions in TCP cubic. In cubic, the concave region is when snd_cwnd starts growing slower towards max_cwnd (cwnd at the time of the congestion event), and the convex region is when snd_cwnd starts to grow faster and eventually appearing like slow-start like growth. PR: 238478 Reviewed by: tuexen (mentor), rgrimes (mentor) Approved by: tuexen (mentor), rgrimes (mentor) MFC after: 2 weeks Sponsored by: NetApp, Inc. Differential Revision: https://reviews.freebsd.org/D24657 --- sys/netinet/cc/cc_cubic.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sys/netinet/cc/cc_cubic.c b/sys/netinet/cc/cc_cubic.c index 3fb2affaffaf..cbd2e7189326 100644 --- a/sys/netinet/cc/cc_cubic.c +++ b/sys/netinet/cc/cc_cubic.c @@ -185,12 +185,11 @@ cubic_ack_received(struct cc_var *ccv, uint16_t type) */ if (CCV(ccv, snd_cwnd) < w_tf) CCV(ccv, snd_cwnd) = ulmin(w_tf, INT_MAX); - } - - else if (CCV(ccv, snd_cwnd) < w_cubic_next) { + } else if (CCV(ccv, snd_cwnd) < w_cubic_next) { /* * Concave or convex region, follow CUBIC * cwnd growth. + * Only update snd_cwnd, if it doesn't shrink. */ if (V_tcp_do_rfc3465) CCV(ccv, snd_cwnd) = ulmin(w_cubic_next, From e3f1731aec0b3b1ba33229acb6605eff1bb9d0f6 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 21 Jul 2020 16:46:40 +0000 Subject: [PATCH 083/287] [skip ci] document close_range(2) as async-signal-safe Reviewed by: bcr (manpages) MFC after: 2 weeks Sponsored by: Axcient Differential Revision: https://reviews.freebsd.org/D25513 --- lib/libc/sys/sigaction.2 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/libc/sys/sigaction.2 b/lib/libc/sys/sigaction.2 index f7158e23abed..e36ef385c848 100644 --- a/lib/libc/sys/sigaction.2 +++ b/lib/libc/sys/sigaction.2 @@ -28,7 +28,7 @@ .\" From: @(#)sigaction.2 8.2 (Berkeley) 4/3/94 .\" $FreeBSD$ .\" -.Dd June 28, 2018 +.Dd June 29, 2020 .Dt SIGACTION 2 .Os .Sh NAME @@ -569,6 +569,7 @@ Extension Interfaces: .Pp .Fn accept4 , .Fn bindat , +.Fn close_range , .Fn closefrom , .Fn connectat , .Fn eaccess , From f2b6da18dea0a3a4e78cb839defd6f6755b82dc8 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Tue, 21 Jul 2020 17:18:38 +0000 Subject: [PATCH 084/287] Avoid code duplicaiton by using ipi_selected(). MFC after: 2 weeks --- sys/amd64/amd64/mp_machdep.c | 8 +------- sys/i386/i386/mp_machdep.c | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index ca95013d9c0b..b4cc7ab829a4 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -696,13 +696,7 @@ smp_targeted_tlb_shootdown(cpuset_t mask, pmap_t pmap, vm_offset_t addr1, CPU_CLR(PCPU_GET(cpuid), &other_cpus); } else { other_cpus = mask; - while ((cpu = CPU_FFS(&mask)) != 0) { - cpu--; - CPU_CLR(cpu, &mask); - CTR3(KTR_SMP, "%s: cpu: %d invl ipi op: %x", __func__, - cpu, op); - ipi_send_cpu(cpu, IPI_INVLOP); - } + ipi_selected(mask, IPI_INVLOP); } curcpu_cb(pmap, addr1, addr2); while ((cpu = CPU_FFS(&other_cpus)) != 0) { diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c index 8ab16d129537..acdb40197433 100644 --- a/sys/i386/i386/mp_machdep.c +++ b/sys/i386/i386/mp_machdep.c @@ -536,13 +536,7 @@ smp_targeted_tlb_shootdown(cpuset_t mask, u_int vector, pmap_t pmap, CPU_CLR(PCPU_GET(cpuid), &other_cpus); } else { other_cpus = mask; - while ((cpu = CPU_FFS(&mask)) != 0) { - cpu--; - CPU_CLR(cpu, &mask); - CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, - cpu, vector); - ipi_send_cpu(cpu, vector); - } + ipi_selected(mask, vector); } curcpu_cb(pmap, addr1, addr2); while ((cpu = CPU_FFS(&other_cpus)) != 0) { From aafaa8b79491b563c628ebe3a4eadb151683ca45 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 21 Jul 2020 19:18:29 +0000 Subject: [PATCH 085/287] Fix geli's null cipher, and add a test case PR: 247954 Submitted by: jhb (sys), asomers (tests) Reviewed by: jhb (tests), asomers (sys) MFC after: 2 weeks Sponsored by: Axcient --- sys/geom/eli/g_eli_integrity.c | 8 +++-- sys/geom/eli/g_eli_privacy.c | 8 +++-- tests/sys/geom/class/eli/onetime_test.sh | 45 ++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/sys/geom/eli/g_eli_integrity.c b/sys/geom/eli/g_eli_integrity.c index ae3ad52d13ff..e4f31046c45b 100644 --- a/sys/geom/eli/g_eli_integrity.c +++ b/sys/geom/eli/g_eli_integrity.c @@ -536,13 +536,15 @@ g_eli_auth_run(struct g_eli_worker *wr, struct bio *bp) crp->crp_digest_start = 0; crp->crp_payload_start = sc->sc_alen; crp->crp_payload_length = data_secsize; - crp->crp_flags |= CRYPTO_F_IV_SEPARATE; if ((sc->sc_flags & G_ELI_FLAG_FIRST_KEY) == 0) { crp->crp_cipher_key = g_eli_key_hold(sc, dstoff, encr_secsize); } - g_eli_crypto_ivgen(sc, dstoff, crp->crp_iv, - sizeof(crp->crp_iv)); + if (g_eli_ivlen(sc->sc_ealgo) != 0) { + crp->crp_flags |= CRYPTO_F_IV_SEPARATE; + g_eli_crypto_ivgen(sc, dstoff, crp->crp_iv, + sizeof(crp->crp_iv)); + } g_eli_auth_keygen(sc, dstoff, authkey); crp->crp_auth_key = authkey; diff --git a/sys/geom/eli/g_eli_privacy.c b/sys/geom/eli/g_eli_privacy.c index 7ec73968394a..4a3e91948ebb 100644 --- a/sys/geom/eli/g_eli_privacy.c +++ b/sys/geom/eli/g_eli_privacy.c @@ -281,13 +281,15 @@ g_eli_crypto_run(struct g_eli_worker *wr, struct bio *bp) crp->crp_payload_start = 0; crp->crp_payload_length = secsize; - crp->crp_flags |= CRYPTO_F_IV_SEPARATE; if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) == 0) { crp->crp_cipher_key = g_eli_key_hold(sc, dstoff, secsize); } - g_eli_crypto_ivgen(sc, dstoff, crp->crp_iv, - sizeof(crp->crp_iv)); + if (g_eli_ivlen(sc->sc_ealgo) != 0) { + crp->crp_flags |= CRYPTO_F_IV_SEPARATE; + g_eli_crypto_ivgen(sc, dstoff, crp->crp_iv, + sizeof(crp->crp_iv)); + } error = crypto_dispatch(crp); KASSERT(error == 0, ("crypto_dispatch() failed (error=%d)", diff --git a/tests/sys/geom/class/eli/onetime_test.sh b/tests/sys/geom/class/eli/onetime_test.sh index 65939db5761c..479d4d771877 100644 --- a/tests/sys/geom/class/eli/onetime_test.sh +++ b/tests/sys/geom/class/eli/onetime_test.sh @@ -130,9 +130,54 @@ onetime_d_cleanup() geli_test_cleanup } +atf_test_case onetime cleanup +onetime_null_head() +{ + atf_set "descr" "geli onetime can use the null cipher" + atf_set "require.user" "root" +} +onetime_null_body() +{ + geli_test_setup + + sectors=100 + + dd if=/dev/random of=rnd bs=${MAX_SECSIZE} count=${sectors} status=none + + secsize=512 + ealgo=${cipher%%:*} + keylen=${cipher##*:} + + md=$(attach_md -t malloc -s 100k) + + atf_check -s exit:0 -o ignore -e ignore \ + geli onetime -e null -s ${secsize} ${md} + + atf_check dd if=rnd of=/dev/${md}.eli bs=${secsize} count=${sectors} status=none + + md_rnd=`dd if=rnd bs=${secsize} count=${sectors} status=none | md5` + atf_check_equal 0 $? + md_ddev=`dd if=/dev/${md}.eli bs=${secsize} count=${sectors} status=none | md5` + atf_check_equal 0 $? + md_edev=`dd if=/dev/${md} bs=${secsize} count=${sectors} status=none | md5` + atf_check_equal 0 $? + + if [ ${md_rnd} != ${md_ddev} ]; then + atf_fail "geli did not return the original data" + fi + if [ ${md_rnd} != ${md_edev} ]; then + atf_fail "geli encrypted the data even with the null cipher" + fi +} +onetime_null_cleanup() +{ + geli_test_cleanup +} + atf_init_test_cases() { atf_add_test_case onetime atf_add_test_case onetime_a atf_add_test_case onetime_d + atf_add_test_case onetime_null } From e1c05fd290f050f46142f663113e0464e2e89cca Mon Sep 17 00:00:00 2001 From: "Alexander V. Chernikov" Date: Tue, 21 Jul 2020 19:56:13 +0000 Subject: [PATCH 086/287] Transition from rtrequest1_fib() to rib_action(). Remove all variations of rtrequest and their uses and switch to to rib_action(). This is part of the new routing KPI. Submitted by: Neel Chauhan Differential Revision: https://reviews.freebsd.org/D25546 --- sys/fs/nfsclient/nfs_clvfsops.c | 15 +++-- sys/net/if.c | 4 +- sys/net/route.c | 113 +++----------------------------- sys/net/route.h | 3 - sys/netinet6/in6_rmx.c | 11 ---- sys/netinet6/in6_var.h | 2 - sys/netinet6/nd6.c | 3 +- sys/netinet6/nd6_rtr.c | 69 ++++++++++++------- sys/nfs/bootp_subr.c | 26 ++++++-- 9 files changed, 92 insertions(+), 154 deletions(-) diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c index 5490155da68c..7124c10573fa 100644 --- a/sys/fs/nfsclient/nfs_clvfsops.c +++ b/sys/fs/nfsclient/nfs_clvfsops.c @@ -68,6 +68,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -466,6 +467,8 @@ nfs_mountroot(struct mount *mp) nd->mygateway.sin_addr.s_addr != 0) { struct sockaddr_in mask, sin; struct epoch_tracker et; + struct rt_addrinfo info; + struct rib_cmd_info rc; bzero((caddr_t)&mask, sizeof(mask)); sin = mask; @@ -474,10 +477,14 @@ nfs_mountroot(struct mount *mp) /* XXX MRT use table 0 for this sort of thing */ NET_EPOCH_ENTER(et); CURVNET_SET(TD_TO_VNET(td)); - error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin, - (struct sockaddr *)&nd->mygateway, - (struct sockaddr *)&mask, - RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB); + + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = RTF_UP | RTF_GATEWAY; + info.rti_info[RTAX_DST] = (struct sockaddr *)&sin; + info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&nd->mygateway; + info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask; + + error = rib_action(RT_DEFAULT_FIB, RTM_ADD, &info, &rc); CURVNET_RESTORE(); NET_EPOCH_EXIT(et); if (error) diff --git a/sys/net/if.c b/sys/net/if.c index bccbba268b56..59dd38267cfc 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #if defined(INET) || defined(INET6) @@ -1845,6 +1846,7 @@ static int ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa, struct sockaddr *ia) { + struct rib_cmd_info rc; struct epoch_tracker et; int error; struct rt_addrinfo info; @@ -1872,7 +1874,7 @@ ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa, info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl; link_init_sdl(ifp, (struct sockaddr *)&null_sdl, ifp->if_type); - error = rtrequest1_fib(cmd, &info, NULL, ifp->if_fib); + error = rib_action(ifp->if_fib, cmd, &info, &rc); NET_EPOCH_EXIT(et); if (rti_ifa != NULL) diff --git a/sys/net/route.c b/sys/net/route.c index 0b7a0e2d55b6..f24200a88e40 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -470,7 +470,7 @@ int rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, struct sockaddr *author, struct ifnet *ifp, int flags, int lifetime_sec) { - struct rtentry *rt; + struct rib_cmd_info rc; int error; struct rt_addrinfo info; struct rt_metrics rti_rmx; @@ -504,7 +504,7 @@ rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, info.rti_mflags |= RTV_EXPIRE; info.rti_rmx = &rti_rmx; - error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); + error = rib_action(fibnum, RTM_ADD, &info, &rc); ifa_free(ifa); if (error != 0) { @@ -512,9 +512,9 @@ rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, return (error); } - RT_LOCK(rt); - flags = rt->rt_flags; - RT_UNLOCK(rt); + RT_LOCK(rc.rc_rt); + flags = rc.rc_rt->rt_flags; + RT_UNLOCK(rc.rc_rt); RTSTAT_INC(rts_dynamic); @@ -602,32 +602,6 @@ ifa_ifwithroute(int flags, const struct sockaddr *dst, return (ifa); } -/* - * Do appropriate manipulations of a routing tree given - * all the bits of info needed - */ -int -rtrequest_fib(int req, - struct sockaddr *dst, - struct sockaddr *gateway, - struct sockaddr *netmask, - int flags, - struct rtentry **ret_nrt, - u_int fibnum) -{ - struct rt_addrinfo info; - - if (dst->sa_len == 0) - return(EINVAL); - - bzero((caddr_t)&info, sizeof(info)); - info.rti_flags = flags; - info.rti_info[RTAX_DST] = dst; - info.rti_info[RTAX_GATEWAY] = gateway; - info.rti_info[RTAX_NETMASK] = netmask; - return rtrequest1_fib(req, &info, ret_nrt, fibnum); -} - /* * Copy most of @rt data into @info. @@ -1148,73 +1122,6 @@ rt_mpath_unlink(struct rib_head *rnh, struct rt_addrinfo *info, } #endif -int -rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, - u_int fibnum) -{ - const struct sockaddr *dst; - struct rib_head *rnh; - struct rib_cmd_info rc; - int error; - - KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum")); - KASSERT((info->rti_flags & RTF_RNH_LOCKED) == 0, ("rtrequest1_fib: locked")); - NET_EPOCH_ASSERT(); - - dst = info->rti_info[RTAX_DST]; - - switch (dst->sa_family) { - case AF_INET6: - case AF_INET: - /* We support multiple FIBs. */ - break; - default: - fibnum = RT_DEFAULT_FIB; - break; - } - - /* - * Find the correct routing tree to use for this Address Family - */ - rnh = rt_tables_get_rnh(fibnum, dst->sa_family); - if (rnh == NULL) - return (EAFNOSUPPORT); - - /* - * If we are adding a host route then we don't want to put - * a netmask in the tree, nor do we want to clone it. - */ - if (info->rti_flags & RTF_HOST) - info->rti_info[RTAX_NETMASK] = NULL; - - bzero(&rc, sizeof(struct rib_cmd_info)); - error = 0; - switch (req) { - case RTM_DELETE: - error = del_route(rnh, info, &rc); - break; - case RTM_RESOLVE: - /* - * resolve was only used for route cloning - * here for compat - */ - break; - case RTM_ADD: - error = add_route(rnh, info, &rc); - break; - case RTM_CHANGE: - error = change_route(rnh, info, &rc); - break; - default: - error = EOPNOTSUPP; - } - - if (ret_nrt != NULL) - *ret_nrt = rc.rc_rt; - - return (error); -} - void rt_setmetrics(const struct rt_addrinfo *info, struct rtentry *rt) { @@ -1258,7 +1165,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) struct epoch_tracker et; struct sockaddr *dst; struct sockaddr *netmask; - struct rtentry *rt = NULL; + struct rib_cmd_info rc; struct rt_addrinfo info; int error = 0; int startfib, endfib; @@ -1349,7 +1256,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) if (rn == NULL) error = ESRCH; else { - rt = RNTORT(rn); + struct rtentry *rt = RNTORT(rn); /* * for interface route the gateway * gateway is sockaddr_dl, so @@ -1389,14 +1296,14 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; info.rti_info[RTAX_NETMASK] = netmask; NET_EPOCH_ENTER(et); - error = rtrequest1_fib(cmd, &info, &rt, fibnum); - if (error == 0 && rt != NULL) { + error = rib_action(fibnum, cmd, &info, &rc); + if (error == 0 && rc.rc_rt != NULL) { /* * notify any listening routing agents of the change */ /* TODO: interface routes/aliases */ - rt_newaddrmsg_fib(cmd, ifa, rt, fibnum); + rt_newaddrmsg_fib(cmd, ifa, rc.rc_rt, fibnum); didwork = 1; } NET_EPOCH_EXIT(et); diff --git a/sys/net/route.h b/sys/net/route.h index fad32d1a5ee1..1ffabcbc86df 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -411,9 +411,6 @@ int rtinit(struct ifaddr *, int, int); * but this will change.. */ int rtioctl_fib(u_long, caddr_t, u_int); -int rtrequest_fib(int, struct sockaddr *, - struct sockaddr *, struct sockaddr *, int, struct rtentry **, u_int); -int rtrequest1_fib(int, struct rt_addrinfo *, struct rtentry **, u_int); int rib_lookup_info(uint32_t, const struct sockaddr *, uint32_t, uint32_t, struct rt_addrinfo *); void rib_free_info(struct rt_addrinfo *info); diff --git a/sys/netinet6/in6_rmx.c b/sys/netinet6/in6_rmx.c index 5600feee8e6a..357292c5c59d 100644 --- a/sys/netinet6/in6_rmx.c +++ b/sys/netinet6/in6_rmx.c @@ -185,14 +185,3 @@ in6_detachhead(void **head, int off) } #endif -/* - * Extended API for IPv6 FIB support. - */ -int -in6_rtrequest(int req, struct sockaddr *dst, struct sockaddr *gw, - struct sockaddr *mask, int flags, struct rtentry **ret_nrt, u_int fibnum) -{ - - return (rtrequest_fib(req, dst, gw, mask, flags, ret_nrt, fibnum)); -} - diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index 1ca181d83c97..b94e52cac7cd 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -915,8 +915,6 @@ void in6_newaddrmsg(struct in6_ifaddr *, int); * Extended API for IPv6 FIB support. */ struct mbuf *ip6_tryforward(struct mbuf *); -int in6_rtrequest(int, struct sockaddr *, struct sockaddr *, - struct sockaddr *, int, struct rtentry **, u_int); #endif /* _KERNEL */ #endif /* _NETINET6_IN6_VAR_H_ */ diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index e2df8ad2aea3..bb488dbc6ff1 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -1564,6 +1564,7 @@ nd6_free_redirect(const struct llentry *ln) int fibnum; struct sockaddr_in6 sin6; struct rt_addrinfo info; + struct rib_cmd_info rc; struct epoch_tracker et; lltable_fill_sa_entry(ln, (struct sockaddr *)&sin6); @@ -1573,7 +1574,7 @@ nd6_free_redirect(const struct llentry *ln) NET_EPOCH_ENTER(et); for (fibnum = 0; fibnum < rt_numfibs; fibnum++) - rtrequest1_fib(RTM_DELETE, &info, NULL, fibnum); + rib_action(fibnum, RTM_DELETE, &info, &rc); NET_EPOCH_EXIT(et); } diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index 1c5d219035d4..bd54a58c7747 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -674,7 +674,8 @@ static void defrouter_addreq(struct nd_defrouter *new) { struct sockaddr_in6 def, mask, gate; - struct rtentry *newrt = NULL; + struct rt_addrinfo info; + struct rib_cmd_info rc; unsigned int fibnum; int error; @@ -688,11 +689,16 @@ defrouter_addreq(struct nd_defrouter *new) gate.sin6_addr = new->rtaddr; fibnum = new->ifp->if_fib; - error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&def, - (struct sockaddr *)&gate, (struct sockaddr *)&mask, - RTF_GATEWAY, &newrt, fibnum); - if (newrt != NULL) - rt_routemsg(RTM_ADD, newrt, new->ifp, 0, fibnum); + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = RTF_GATEWAY; + info.rti_info[RTAX_DST] = (struct sockaddr *)&def; + info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&gate; + info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask; + + NET_EPOCH_ASSERT(); + error = rib_action(fibnum, RTM_ADD, &info, &rc); + if (rc.rc_rt != NULL) + rt_routemsg(RTM_ADD, rc.rc_rt, new->ifp, 0, fibnum); if (error == 0) new->installed = 1; } @@ -706,7 +712,8 @@ static void defrouter_delreq(struct nd_defrouter *dr) { struct sockaddr_in6 def, mask, gate; - struct rtentry *oldrt = NULL; + struct rt_addrinfo info; + struct rib_cmd_info rc; struct epoch_tracker et; unsigned int fibnum; @@ -720,12 +727,16 @@ defrouter_delreq(struct nd_defrouter *dr) gate.sin6_addr = dr->rtaddr; fibnum = dr->ifp->if_fib; + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = RTF_GATEWAY; + info.rti_info[RTAX_DST] = (struct sockaddr *)&def; + info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&gate; + info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask; + NET_EPOCH_ENTER(et); - in6_rtrequest(RTM_DELETE, (struct sockaddr *)&def, - (struct sockaddr *)&gate, - (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt, fibnum); - if (oldrt != NULL) - rt_routemsg(RTM_DELETE, oldrt, dr->ifp, 0, fibnum); + rib_action(fibnum, RTM_DELETE, &info, &rc); + if (rc.rc_rt != NULL) + rt_routemsg(RTM_DELETE, rc.rc_rt, dr->ifp, 0, fibnum); NET_EPOCH_EXIT(et); dr->installed = 0; @@ -2009,7 +2020,6 @@ static int nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) { struct sockaddr_dl_short sdl; - struct rtentry *rt; struct sockaddr_in6 mask6; u_long rtflags; int error, a_failure, fibnum, maxfib; @@ -2034,11 +2044,17 @@ nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) } a_failure = 0; for (; fibnum < maxfib; fibnum++) { + struct rt_addrinfo info; + struct rib_cmd_info rc; - rt = NULL; - error = in6_rtrequest(RTM_ADD, - (struct sockaddr *)&pr->ndpr_prefix, (struct sockaddr *)&sdl, - (struct sockaddr *)&mask6, rtflags, &rt, fibnum); + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = rtflags; + info.rti_info[RTAX_DST] = (struct sockaddr *)&pr->ndpr_prefix; + info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&sdl; + info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask6; + + NET_EPOCH_ASSERT(); + error = rib_action(fibnum, RTM_ADD, &info, &rc); if (error != 0) { char ip6buf[INET6_ADDRSTRLEN]; char ip6bufg[INET6_ADDRSTRLEN]; @@ -2061,7 +2077,7 @@ nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) } pr->ndpr_stateflags |= NDPRF_ONLINK; - rt_routemsg(RTM_ADD, rt, pr->ndpr_ifp, 0, fibnum); + rt_routemsg(RTM_ADD, rc.rc_rt, pr->ndpr_ifp, 0, fibnum); } /* Return the last error we got. */ @@ -2158,7 +2174,6 @@ nd6_prefix_offlink(struct nd_prefix *pr) struct ifnet *ifp = pr->ndpr_ifp; struct nd_prefix *opr; struct sockaddr_in6 sa6, mask6; - struct rtentry *rt; char ip6buf[INET6_ADDRSTRLEN]; uint64_t genid; int fibnum, maxfib, a_failure; @@ -2191,9 +2206,17 @@ nd6_prefix_offlink(struct nd_prefix *pr) a_failure = 0; NET_EPOCH_ENTER(et); for (; fibnum < maxfib; fibnum++) { - rt = NULL; - error = in6_rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, - (struct sockaddr *)&mask6, 0, &rt, fibnum); + struct rt_addrinfo info; + struct rib_cmd_info rc; + + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = RTF_GATEWAY; + info.rti_info[RTAX_DST] = (struct sockaddr *)&sa6; + info.rti_info[RTAX_GATEWAY] = NULL; + info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask6; + + NET_EPOCH_ASSERT(); + error = rib_action(fibnum, RTM_DELETE, &info, &rc); if (error != 0) { /* Save last error to return, see rtinit(). */ a_failure = error; @@ -2201,7 +2224,7 @@ nd6_prefix_offlink(struct nd_prefix *pr) } /* report route deletion to the routing socket. */ - rt_routemsg(RTM_DELETE, rt, ifp, 0, fibnum); + rt_routemsg(RTM_DELETE, rc.rc_rt, ifp, 0, fibnum); } NET_EPOCH_EXIT(et); error = a_failure; diff --git a/sys/nfs/bootp_subr.c b/sys/nfs/bootp_subr.c index d64026d0cd90..65e81fbade0e 100644 --- a/sys/nfs/bootp_subr.c +++ b/sys/nfs/bootp_subr.c @@ -68,6 +68,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -979,6 +980,8 @@ bootpc_add_default_route(struct bootpc_ifcontext *ifctx) int error; struct sockaddr_in defdst; struct sockaddr_in defmask; + struct rt_addrinfo info; + struct rib_cmd_info rc; if (ifctx->gw.sin_addr.s_addr == htonl(INADDR_ANY)) return; @@ -986,9 +989,14 @@ bootpc_add_default_route(struct bootpc_ifcontext *ifctx) clear_sinaddr(&defdst); clear_sinaddr(&defmask); - error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&defdst, - (struct sockaddr *) &ifctx->gw, (struct sockaddr *)&defmask, - (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, RT_DEFAULT_FIB); + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; + info.rti_info[RTAX_DST] = (struct sockaddr *)&defdst; + info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&defmask; + info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&ifctx->gw; + + error = rib_action(RT_DEFAULT_FIB, RTM_ADD, &info, &rc); + if (error != 0) { printf("%s: RTM_ADD, error=%d\n", __func__, error); } @@ -1000,6 +1008,8 @@ bootpc_remove_default_route(struct bootpc_ifcontext *ifctx) int error; struct sockaddr_in defdst; struct sockaddr_in defmask; + struct rt_addrinfo info; + struct rib_cmd_info rc; if (ifctx->gw.sin_addr.s_addr == htonl(INADDR_ANY)) return; @@ -1007,9 +1017,13 @@ bootpc_remove_default_route(struct bootpc_ifcontext *ifctx) clear_sinaddr(&defdst); clear_sinaddr(&defmask); - error = rtrequest_fib(RTM_DELETE, (struct sockaddr *)&defdst, - (struct sockaddr *) &ifctx->gw, (struct sockaddr *)&defmask, - (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, RT_DEFAULT_FIB); + bzero((caddr_t)&info, sizeof(info)); + info.rti_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; + info.rti_info[RTAX_DST] = (struct sockaddr *)&defdst; + info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&defmask; + info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&ifctx->gw; + + error = rib_action(RT_DEFAULT_FIB, RTM_DELETE, &info, &rc); if (error != 0) { printf("%s: RTM_DELETE, error=%d\n", __func__, error); } From dc4250904956c3e438186dbb78254e0c9bf1b734 Mon Sep 17 00:00:00 2001 From: Mitchell Horne Date: Tue, 21 Jul 2020 22:47:02 +0000 Subject: [PATCH 087/287] INTRNG: only shuffle for !EARLY_AP_STARTUP During device attachment, all interrupt sources will bind to the BSP, as it is the only processor online. This means interrupts must be redistributed ("shuffled") later, during SI_SUB_SMP. For the EARLY_AP_STARTUP case, this is no longer true. SI_SUB_SMP will execute much earlier, meaning APs will be online and available before devices begin attachment, and there will therefore be nothing to shuffle. All PIC-conforming interrupt controllers will handle this early distribution properly, except for RISC-V's PLIC. Make the necessary tweak to the PLIC driver. While here, convert irq_assign_cpu from a boolean_t to a bool. Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D25693 --- sys/kern/subr_intr.c | 12 +++++++++--- sys/riscv/riscv/plic.c | 3 +-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c index eda100164711..791a73957af5 100644 --- a/sys/kern/subr_intr.c +++ b/sys/kern/subr_intr.c @@ -128,7 +128,11 @@ static struct intr_irqsrc *irq_sources[NIRQ]; u_int irq_next_free; #ifdef SMP -static boolean_t irq_assign_cpu = FALSE; +#ifdef EARLY_AP_STARTUP +static bool irq_assign_cpu = true; +#else +static bool irq_assign_cpu = false; +#endif #endif /* @@ -1191,6 +1195,7 @@ intr_irq_next_cpu(u_int last_cpu, cpuset_t *cpumask) return (last_cpu); } +#ifndef EARLY_AP_STARTUP /* * Distribute all the interrupt sources among the available * CPUs once the AP's have been launched. @@ -1205,7 +1210,7 @@ intr_irq_shuffle(void *arg __unused) return; mtx_lock(&isrc_table_lock); - irq_assign_cpu = TRUE; + irq_assign_cpu = true; for (i = 0; i < NIRQ; i++) { isrc = irq_sources[i]; if (isrc == NULL || isrc->isrc_handlers == 0 || @@ -1231,6 +1236,7 @@ intr_irq_shuffle(void *arg __unused) mtx_unlock(&isrc_table_lock); } SYSINIT(intr_irq_shuffle, SI_SUB_SMP, SI_ORDER_SECOND, intr_irq_shuffle, NULL); +#endif /* !EARLY_AP_STARTUP */ #else u_int @@ -1239,7 +1245,7 @@ intr_irq_next_cpu(u_int current_cpu, cpuset_t *cpumask) return (PCPU_GET(cpuid)); } -#endif +#endif /* SMP */ /* * Allocate memory for new intr_map_data structure. diff --git a/sys/riscv/riscv/plic.c b/sys/riscv/riscv/plic.c index 1e99b2d068ab..029525938161 100644 --- a/sys/riscv/riscv/plic.c +++ b/sys/riscv/riscv/plic.c @@ -408,8 +408,7 @@ plic_setup_intr(device_t dev, struct intr_irqsrc *isrc, sc = device_get_softc(dev); src = (struct plic_irqsrc *)isrc; - /* Bind to the boot CPU for now. */ - CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); + CPU_ZERO(&isrc->isrc_cpu); plic_bind_intr(dev, isrc); return (0); From 49d941eee087076eb2b3b901247386119b1f1dd3 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Wed, 22 Jul 2020 00:44:47 +0000 Subject: [PATCH 088/287] getty appears to date from 3rd edition research unix. That's the oldest man page on TUHS and its 'unix 1972' restoration effort has assembler sources that look like simpler version of what's in the 5th edition. --- libexec/getty/getty.8 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libexec/getty/getty.8 b/libexec/getty/getty.8 index 670168926c00..2733388a42af 100644 --- a/libexec/getty/getty.8 +++ b/libexec/getty/getty.8 @@ -28,7 +28,7 @@ .\" from: @(#)getty.8 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" " -.Dd March 2, 2018 +.Dd July 21, 2020 .Dt GETTY 8 .Os .Sh NAME @@ -122,4 +122,4 @@ does not exist. A .Nm utility appeared in -.At v6 . +.At v3 . From 9d6d8bf8c74641895e7545c5adf1440f517377ae Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Wed, 22 Jul 2020 02:09:10 +0000 Subject: [PATCH 089/287] libbe: annotate lbh as __unused in be_is_auto_snapshot_name lbh is included for consistency with other functions and in case future work needs to use it, but it is currently unused. Mark it, and a post-OpenZFS-import world will be able to raise WARNS of libbe to the default (pending some minor changes to openzfs libzfs). MFC after: 3 days --- lib/libbe/be.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libbe/be.c b/lib/libbe/be.c index a5c112c238e5..98304c8bd166 100644 --- a/lib/libbe/be.c +++ b/lib/libbe/be.c @@ -563,7 +563,7 @@ be_setup_snapshot_name(libbe_handle_t *lbh, char *buf, size_t buflen) } bool -be_is_auto_snapshot_name(libbe_handle_t *lbh, const char *name) +be_is_auto_snapshot_name(libbe_handle_t *lbh __unused, const char *name) { const char *snap; int day, hour, minute, month, second, serial, year; From 0ab851aac3a028d0771e6d32054b8b768a2bec3b Mon Sep 17 00:00:00 2001 From: Xin LI Date: Wed, 22 Jul 2020 02:14:27 +0000 Subject: [PATCH 090/287] gctl_get_class, gctl_get_geom and gctl_get_provider: provide feedback when the requested argument is missing. Reviewed by: cem MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D25738 --- sys/geom/geom_ctl.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sys/geom/geom_ctl.c b/sys/geom/geom_ctl.c index cdf0eddd3446..8b9af1aa54ab 100644 --- a/sys/geom/geom_ctl.c +++ b/sys/geom/geom_ctl.c @@ -396,12 +396,15 @@ gctl_get_class(struct gctl_req *req, char const *arg) struct g_class *cp; p = gctl_get_asciiparam(req, arg); - if (p == NULL) + if (p == NULL) { + gctl_error(req, "Missing %s argument", arg); return (NULL); + } LIST_FOREACH(cp, &g_classes, class) { if (!strcmp(p, cp->name)) return (cp); } + gctl_error(req, "Class not found: \"%s\"", p); return (NULL); } @@ -413,8 +416,10 @@ gctl_get_geom(struct gctl_req *req, struct g_class *mpr, char const *arg) struct g_geom *gp; p = gctl_get_asciiparam(req, arg); - if (p == NULL) + if (p == NULL) { + gctl_error(req, "Missing %s argument", arg); return (NULL); + } LIST_FOREACH(mp, &g_classes, class) { if (mpr != NULL && mpr != mp) continue; @@ -434,8 +439,10 @@ gctl_get_provider(struct gctl_req *req, char const *arg) struct g_provider *pp; p = gctl_get_asciiparam(req, arg); - if (p == NULL) + if (p == NULL) { + gctl_error(req, "Missing '%s' argument", arg); return (NULL); + } pp = g_provider_by_name(p); if (pp != NULL) return (pp); @@ -453,10 +460,8 @@ g_ctl_req(void *arg, int flag __unused) g_topology_assert(); req = arg; mp = gctl_get_class(req, "class"); - if (mp == NULL) { - gctl_error(req, "Class not found"); + if (mp == NULL) return; - } if (mp->ctlreq == NULL) { gctl_error(req, "Class takes no requests"); return; From fcf69f3dbce6b3b6187ff584031e690fbe2479d2 Mon Sep 17 00:00:00 2001 From: Xin LI Date: Wed, 22 Jul 2020 02:15:21 +0000 Subject: [PATCH 091/287] Consistently use gctl_get_provider instead of home-grown variants. Reviewed by: cem, imp MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D25739 --- sys/geom/cache/g_cache.c | 14 ++------- sys/geom/concat/g_concat.c | 28 +++++------------ sys/geom/eli/g_eli_ctl.c | 29 +++--------------- sys/geom/label/g_label.c | 14 ++------- sys/geom/mirror/g_mirror_ctl.c | 56 +++++++++++----------------------- sys/geom/mountver/g_mountver.c | 15 ++------- sys/geom/nop/g_nop.c | 48 ++++++++--------------------- sys/geom/raid3/g_raid3_ctl.c | 15 ++------- sys/geom/stripe/g_stripe.c | 26 +++++----------- sys/geom/virstor/g_virstor.c | 19 ++---------- 10 files changed, 62 insertions(+), 202 deletions(-) diff --git a/sys/geom/cache/g_cache.c b/sys/geom/cache/g_cache.c index f20ee9d4368a..337879a3f52c 100644 --- a/sys/geom/cache/g_cache.c +++ b/sys/geom/cache/g_cache.c @@ -757,19 +757,9 @@ g_cache_ctl_create(struct gctl_req *req, struct g_class *mp) /* This field is not important here. */ md.md_provsize = 0; - name = gctl_get_asciiparam(req, "arg1"); - if (name == NULL) { - gctl_error(req, "No 'arg1' argument"); + pp = gctl_get_provider(req, "arg1"); + if (pp == NULL) return; - } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - if (pp == NULL) { - G_CACHE_DEBUG(1, "Provider %s is invalid.", name); - gctl_error(req, "Provider %s is invalid.", name); - return; - } gp = g_cache_create(mp, pp, &md, G_CACHE_TYPE_MANUAL); if (gp == NULL) { gctl_error(req, "Can't create %s.", md.md_name); diff --git a/sys/geom/concat/g_concat.c b/sys/geom/concat/g_concat.c index 63f3cbee82b7..adb92567aba5 100644 --- a/sys/geom/concat/g_concat.c +++ b/sys/geom/concat/g_concat.c @@ -840,19 +840,9 @@ g_concat_ctl_create(struct gctl_req *req, struct g_class *mp) /* Check all providers are valid */ for (no = 1; no < *nargs; no++) { snprintf(param, sizeof(param), "arg%u", no); - name = gctl_get_asciiparam(req, param); - if (name == NULL) { - gctl_error(req, "No 'arg%u' argument.", no); + pp = gctl_get_provider(req, param); + if (pp == NULL) return; - } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - if (pp == NULL) { - G_CONCAT_DEBUG(1, "Disk %s is invalid.", name); - gctl_error(req, "Disk %s is invalid.", name); - return; - } } gp = g_concat_create(mp, &md, G_CONCAT_TYPE_MANUAL); @@ -866,15 +856,13 @@ g_concat_ctl_create(struct gctl_req *req, struct g_class *mp) sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name); for (attached = 0, no = 1; no < *nargs; no++) { snprintf(param, sizeof(param), "arg%u", no); - name = gctl_get_asciiparam(req, param); - if (name == NULL) { - gctl_error(req, "No 'arg%d' argument.", no); - return; + pp = gctl_get_provider(req, param); + if (pp == NULL) { + name = gctl_get_asciiparam(req, param); + MPASS(name != NULL); + sbuf_printf(sb, " %s", name); + continue; } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - KASSERT(pp != NULL, ("Provider %s disappear?!", name)); if (g_concat_add_disk(sc, pp, no - 1) != 0) { G_CONCAT_DEBUG(1, "Disk %u (%s) not attached to %s.", no, pp->name, gp->name); diff --git a/sys/geom/eli/g_eli_ctl.c b/sys/geom/eli/g_eli_ctl.c index ccfdb3aa5119..abff51747709 100644 --- a/sys/geom/eli/g_eli_ctl.c +++ b/sys/geom/eli/g_eli_ctl.c @@ -58,7 +58,6 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp) { struct g_eli_metadata md; struct g_provider *pp; - const char *name; u_char *key, mkey[G_ELI_DATAIVKEYLEN]; int *nargs, *detach, *readonly, *dryrunp; int keysize, error, nkey, dryrun, dummy; @@ -115,22 +114,13 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp) return; } - name = gctl_get_asciiparam(req, "arg0"); - if (name == NULL) { - gctl_error(req, "No 'arg%u' argument.", 0); + pp = gctl_get_provider(req, "arg0"); + if (pp == NULL) return; - } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - if (pp == NULL) { - gctl_error(req, "Provider %s is invalid.", name); - return; - } error = g_eli_read_metadata(mp, pp, &md); if (error != 0) { gctl_error(req, "Cannot read metadata from %s (error=%d).", - name, error); + pp->name, error); return; } if (md.md_keys == 0x00) { @@ -368,18 +358,9 @@ g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp) /* Not important here. */ bzero(md.md_hash, sizeof(md.md_hash)); - name = gctl_get_asciiparam(req, "arg0"); - if (name == NULL) { - gctl_error(req, "No 'arg%u' argument.", 0); + pp = gctl_get_provider(req, "arg0"); + if (pp == NULL) return; - } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - if (pp == NULL) { - gctl_error(req, "Provider %s is invalid.", name); - return; - } sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize)); if (sectorsize == NULL) { diff --git a/sys/geom/label/g_label.c b/sys/geom/label/g_label.c index b418451b82c1..1052865b6a4e 100644 --- a/sys/geom/label/g_label.c +++ b/sys/geom/label/g_label.c @@ -437,19 +437,9 @@ g_label_ctl_create(struct gctl_req *req, struct g_class *mp) /* * arg1 is the name of provider. */ - name = gctl_get_asciiparam(req, "arg1"); - if (name == NULL) { - gctl_error(req, "No 'arg%d' argument", 1); + pp = gctl_get_provider(req, "arg1"); + if (pp == NULL) return; - } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - if (pp == NULL) { - G_LABEL_DEBUG(1, "Provider %s is invalid.", name); - gctl_error(req, "Provider %s is invalid.", name); - return; - } /* * arg0 is the label. */ diff --git a/sys/geom/mirror/g_mirror_ctl.c b/sys/geom/mirror/g_mirror_ctl.c index 60e46d8c903e..a1594dd18177 100644 --- a/sys/geom/mirror/g_mirror_ctl.c +++ b/sys/geom/mirror/g_mirror_ctl.c @@ -441,34 +441,25 @@ g_mirror_ctl_create(struct gctl_req *req, struct g_class *mp) cp = g_new_consumer(gp); for (no = 1; no < *nargs; no++) { snprintf(param, sizeof(param), "arg%u", no); - name = gctl_get_asciiparam(req, param); - if (name == NULL) { - gctl_error(req, "No 'arg%u' argument.", no); + pp = gctl_get_provider(req, param); + if (pp == NULL) { err: g_destroy_consumer(cp); g_destroy_geom(gp); g_topology_unlock(); return; } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - if (pp == NULL) { - G_MIRROR_DEBUG(1, "Disk %s is invalid.", name); - gctl_error(req, "Disk %s is invalid.", name); - goto err; - } g_attach(cp, pp); if (g_access(cp, 1, 0, 0) != 0) { - G_MIRROR_DEBUG(1, "Can't open disk %s.", name); - gctl_error(req, "Can't open disk %s.", name); + G_MIRROR_DEBUG(1, "Can't open disk %s.", pp->name); + gctl_error(req, "Can't open disk %s.", pp->name); err2: g_detach(cp); goto err; } if (pp->mediasize == 0 || pp->sectorsize == 0) { - G_MIRROR_DEBUG(1, "Disk %s has no media.", name); - gctl_error(req, "Disk %s has no media.", name); + G_MIRROR_DEBUG(1, "Disk %s has no media.", pp->name); + gctl_error(req, "Disk %s has no media.", pp->name); g_access(cp, -1, 0, 0); goto err2; } @@ -500,12 +491,10 @@ g_mirror_ctl_create(struct gctl_req *req, struct g_class *mp) sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name); for (attached = 0, no = 1; no < *nargs; no++) { snprintf(param, sizeof(param), "arg%u", no); - name = gctl_get_asciiparam(req, param); - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); + pp = gctl_get_provider(req, param); if (pp == NULL) { - G_MIRROR_DEBUG(1, "Provider %s disappear?!", name); + name = gctl_get_asciiparam(req, param); + MPASS(name != NULL); sbuf_printf(sb, " %s", name); continue; } @@ -677,30 +666,21 @@ g_mirror_ctl_insert(struct gctl_req *req, struct g_class *mp) g_topology_lock(); for (i = 1, n = 0; i < (u_int)*nargs; i++) { snprintf(param, sizeof(param), "arg%u", i); - name = gctl_get_asciiparam(req, param); - if (name == NULL) { - gctl_error(req, "No 'arg%u' argument.", i); + pp = gctl_get_provider(req, param); + if (pp == NULL) continue; - } - if (g_mirror_find_disk(sc, name) != NULL) { - gctl_error(req, "Provider %s already inserted.", name); - continue; - } - if (strncmp(name, _PATH_DEV, 5) == 0) - name += 5; - pp = g_provider_by_name(name); - if (pp == NULL) { - gctl_error(req, "Unknown provider %s.", name); + if (g_mirror_find_disk(sc, pp->name) != NULL) { + gctl_error(req, "Provider %s already inserted.", pp->name); continue; } cp = g_new_consumer(sc->sc_geom); if (g_attach(cp, pp) != 0) { g_destroy_consumer(cp); - gctl_error(req, "Cannot attach to provider %s.", name); + gctl_error(req, "Cannot attach to provider %s.", pp->name); continue; } if (g_access(cp, 0, 1, 1) != 0) { - gctl_error(req, "Cannot access provider %s.", name); + gctl_error(req, "Cannot access provider %s.", pp->name); err: g_detach(cp); g_destroy_consumer(cp); @@ -709,14 +689,14 @@ g_mirror_ctl_insert(struct gctl_req *req, struct g_class *mp) mdsize = (sc->sc_type == G_MIRROR_TYPE_AUTOMATIC) ? pp->sectorsize : 0; if (sc->sc_provider->mediasize > pp->mediasize - mdsize) { - gctl_error(req, "Provider %s too small.", name); + gctl_error(req, "Provider %s too small.", pp->name); err2: g_access(cp, 0, -1, -1); goto err; } if ((sc->sc_provider->sectorsize % pp->sectorsize) != 0) { gctl_error(req, "Invalid sectorsize of provider %s.", - name); + pp->name); goto err2; } if (sc->sc_type != G_MIRROR_TYPE_AUTOMATIC) { @@ -731,7 +711,7 @@ g_mirror_ctl_insert(struct gctl_req *req, struct g_class *mp) md.md_dflags |= G_MIRROR_DISK_FLAG_INACTIVE; if (g_mirror_add_disk(sc, pp, &md) != 0) { sc->sc_ndisks--; - gctl_error(req, "Disk %s not inserted.", name); + gctl_error(req, "Disk %s not inserted.", pp->name); } g_topology_lock(); continue; diff --git a/sys/geom/mountver/g_mountver.c b/sys/geom/mountver/g_mountver.c index c1ca84aa451a..4d48e6bfdb78 100644 --- a/sys/geom/mountver/g_mountver.c +++ b/sys/geom/mountver/g_mountver.c @@ -404,7 +404,6 @@ static void g_mountver_ctl_create(struct gctl_req *req, struct g_class *mp) { struct g_provider *pp; - const char *name; char param[16]; int i, *nargs; @@ -421,19 +420,9 @@ g_mountver_ctl_create(struct gctl_req *req, struct g_class *mp) } for (i = 0; i < *nargs; i++) { snprintf(param, sizeof(param), "arg%d", i); - name = gctl_get_asciiparam(req, param); - if (name == NULL) { - gctl_error(req, "No 'arg%d' argument", i); + pp = gctl_get_provider(req, param); + if (pp == NULL) return; - } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - if (pp == NULL) { - G_MOUNTVER_DEBUG(1, "Provider %s is invalid.", name); - gctl_error(req, "Provider %s is invalid.", name); - return; - } if (g_mountver_create(req, mp, pp) != 0) return; } diff --git a/sys/geom/nop/g_nop.c b/sys/geom/nop/g_nop.c index e0dd92ef20a1..75d4f44f2627 100644 --- a/sys/geom/nop/g_nop.c +++ b/sys/geom/nop/g_nop.c @@ -544,7 +544,7 @@ g_nop_ctl_create(struct gctl_req *req, struct g_class *mp) intmax_t *val, error, rfailprob, wfailprob, count_until_fail, offset, secsize, size, stripesize, stripeoffset, delaymsec, rdelayprob, wdelayprob; - const char *name, *physpath, *gnopname; + const char *physpath, *gnopname; char param[16]; int i, *nargs; @@ -671,19 +671,9 @@ g_nop_ctl_create(struct gctl_req *req, struct g_class *mp) for (i = 0; i < *nargs; i++) { snprintf(param, sizeof(param), "arg%d", i); - name = gctl_get_asciiparam(req, param); - if (name == NULL) { - gctl_error(req, "No 'arg%d' argument", i); + pp = gctl_get_provider(req, param); + if (pp == NULL) return; - } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - if (pp == NULL) { - G_NOP_DEBUG(1, "Provider %s is invalid.", name); - gctl_error(req, "Provider %s is invalid.", name); - return; - } if (g_nop_create(req, mp, pp, gnopname, error == -1 ? EIO : (int)error, @@ -708,7 +698,6 @@ g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp) struct g_provider *pp; intmax_t *val, delaymsec, error, rdelayprob, rfailprob, wdelayprob, wfailprob, count_until_fail; - const char *name; char param[16]; int i, *nargs; @@ -782,17 +771,12 @@ g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp) for (i = 0; i < *nargs; i++) { snprintf(param, sizeof(param), "arg%d", i); - name = gctl_get_asciiparam(req, param); - if (name == NULL) { - gctl_error(req, "No 'arg%d' argument", i); + pp = gctl_get_provider(req, param); + if (pp == NULL) return; - } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - if (pp == NULL || pp->geom->class != mp) { - G_NOP_DEBUG(1, "Provider %s is invalid.", name); - gctl_error(req, "Provider %s is invalid.", name); + if (pp->geom->class != mp) { + G_NOP_DEBUG(1, "Provider %s is invalid.", pp->name); + gctl_error(req, "Provider %s is invalid.", pp->name); return; } sc = pp->geom->softc; @@ -879,7 +863,6 @@ g_nop_ctl_reset(struct gctl_req *req, struct g_class *mp) { struct g_nop_softc *sc; struct g_provider *pp; - const char *name; char param[16]; int i, *nargs; @@ -897,17 +880,12 @@ g_nop_ctl_reset(struct gctl_req *req, struct g_class *mp) for (i = 0; i < *nargs; i++) { snprintf(param, sizeof(param), "arg%d", i); - name = gctl_get_asciiparam(req, param); - if (name == NULL) { - gctl_error(req, "No 'arg%d' argument", i); + pp = gctl_get_provider(req, param); + if (pp == NULL) return; - } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - if (pp == NULL || pp->geom->class != mp) { - G_NOP_DEBUG(1, "Provider %s is invalid.", name); - gctl_error(req, "Provider %s is invalid.", name); + if (pp->geom->class != mp) { + G_NOP_DEBUG(1, "Provider %s is invalid.", pp->name); + gctl_error(req, "Provider %s is invalid.", pp->name); return; } sc = pp->geom->softc; diff --git a/sys/geom/raid3/g_raid3_ctl.c b/sys/geom/raid3/g_raid3_ctl.c index 9794f176470b..1fb81501e87d 100644 --- a/sys/geom/raid3/g_raid3_ctl.c +++ b/sys/geom/raid3/g_raid3_ctl.c @@ -422,24 +422,13 @@ g_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp) gctl_error(req, "No '%s' argument.", "hardcode"); return; } - name = gctl_get_asciiparam(req, "arg1"); - if (name == NULL) { - gctl_error(req, "No 'arg%u' argument.", 1); + pp = gctl_get_provider(req, "arg1"); + if (pp == NULL) return; - } if (gctl_get_param(req, "number", NULL) != NULL) no = gctl_get_paraml(req, "number", sizeof(*no)); else no = NULL; - if (strncmp(name, _PATH_DEV, 5) == 0) - name += 5; - g_topology_lock(); - pp = g_provider_by_name(name); - if (pp == NULL) { - g_topology_unlock(); - gctl_error(req, "Invalid provider."); - return; - } gp = g_new_geomf(mp, "raid3:insert"); gp->orphan = g_raid3_ctl_insert_orphan; cp = g_new_consumer(gp); diff --git a/sys/geom/stripe/g_stripe.c b/sys/geom/stripe/g_stripe.c index af764ee7453a..a1b9835499ee 100644 --- a/sys/geom/stripe/g_stripe.c +++ b/sys/geom/stripe/g_stripe.c @@ -1091,19 +1091,9 @@ g_stripe_ctl_create(struct gctl_req *req, struct g_class *mp) /* Check all providers are valid */ for (no = 1; no < *nargs; no++) { snprintf(param, sizeof(param), "arg%u", no); - name = gctl_get_asciiparam(req, param); - if (name == NULL) { - gctl_error(req, "No 'arg%u' argument.", no); + pp = gctl_get_provider(req, param); + if (pp == NULL) return; - } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - if (pp == NULL) { - G_STRIPE_DEBUG(1, "Disk %s is invalid.", name); - gctl_error(req, "Disk %s is invalid.", name); - return; - } } gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_MANUAL); @@ -1117,15 +1107,13 @@ g_stripe_ctl_create(struct gctl_req *req, struct g_class *mp) sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name); for (attached = 0, no = 1; no < *nargs; no++) { snprintf(param, sizeof(param), "arg%u", no); - name = gctl_get_asciiparam(req, param); - if (name == NULL) { - gctl_error(req, "No 'arg%u' argument.", no); + pp = gctl_get_provider(req, param); + if (pp == NULL) { + name = gctl_get_asciiparam(req, param); + MPASS(name != NULL); + sbuf_printf(sb, " %s", name); continue; } - if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - name += strlen(_PATH_DEV); - pp = g_provider_by_name(name); - KASSERT(pp != NULL, ("Provider %s disappear?!", name)); if (g_stripe_add_disk(sc, pp, no - 1) != 0) { G_STRIPE_DEBUG(1, "Disk %u (%s) not attached to %s.", no, pp->name, gp->name); diff --git a/sys/geom/virstor/g_virstor.c b/sys/geom/virstor/g_virstor.c index be6446e1f8d1..7cc09b32c9c7 100644 --- a/sys/geom/virstor/g_virstor.c +++ b/sys/geom/virstor/g_virstor.c @@ -313,32 +313,19 @@ virstor_ctl_add(struct gctl_req *req, struct g_class *cp) for (i = 1; i < *nargs; i++) { struct g_virstor_metadata md; char aname[8]; - const char *prov_name; struct g_provider *pp; struct g_consumer *cp; u_int nc; u_int j; snprintf(aname, sizeof aname, "arg%d", i); - prov_name = gctl_get_asciiparam(req, aname); - if (prov_name == NULL) { - gctl_error(req, "Error fetching argument '%s'", aname); - g_topology_unlock(); - return; - } - if (strncmp(prov_name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) - prov_name += sizeof(_PATH_DEV) - 1; - - pp = g_provider_by_name(prov_name); + pp = gctl_get_provider(req, aname); if (pp == NULL) { /* This is the most common error so be verbose about it */ if (added != 0) { - gctl_error(req, "Invalid provider: '%s' (added" - " %u components)", prov_name, added); + gctl_error(req, "Invalid provider. (added" + " %u components)", added); update_metadata(sc); - } else { - gctl_error(req, "Invalid provider: '%s'", - prov_name); } g_topology_unlock(); return; From 31ad4050fe8b5ed05a8a4554256c26e3510fcaf2 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Wed, 22 Jul 2020 12:30:31 +0000 Subject: [PATCH 092/287] lockmgr: add adaptive spinning It is very conservative. Only spinning when LK_ADAPTIVE is passed, only on exclusive lock and never when any waiters are present. buffer cache is remains not spinning. This reduces total sleep times during buildworld etc., but it does not shorten total real time (culprits are contention in the vm subsystem along with slock + upgrade which is not covered). For microbenchmarks: open3_processes -t 52 (open/close of the same file for writing) ops/s: before: 258845 after: 801638 Reviewed by: kib Tested by: pho Differential Revision: https://reviews.freebsd.org/D25753 --- sys/kern/kern_lock.c | 129 ++++++++++++++++++++++++++++++++++------ sys/sys/lockmgr.h | 1 + sys/ufs/ffs/ffs_vnops.c | 2 + 3 files changed, 114 insertions(+), 18 deletions(-) diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index 11396a6e259f..36084f3877bd 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -167,6 +167,12 @@ struct lock_class lock_class_lockmgr = { #endif }; +static __read_mostly bool lk_adaptive = true; +static SYSCTL_NODE(_debug, OID_AUTO, lockmgr, CTLFLAG_RD, NULL, "lockmgr debugging"); +SYSCTL_BOOL(_debug_lockmgr, OID_AUTO, adaptive_spinning, CTLFLAG_RW, &lk_adaptive, + 0, ""); +#define lockmgr_delay locks_delay + struct lockmgr_wait { const char *iwmesg; int ipri; @@ -515,7 +521,6 @@ lockmgr_slock_try(struct lock *lk, uintptr_t *xp, int flags, bool fp) * waiters, if we fail to acquire the shared lock * loop back and retry. */ - *xp = lockmgr_read_value(lk); while (LK_CAN_SHARE(*xp, flags, fp)) { if (atomic_fcmpset_acq_ptr(&lk->lk_lock, xp, *xp + LK_ONE_SHARER)) { @@ -541,6 +546,38 @@ lockmgr_sunlock_try(struct lock *lk, uintptr_t *xp) return (false); } +static bool +lockmgr_slock_adaptive(struct lock_delay_arg *lda, struct lock *lk, uintptr_t *xp, + int flags) +{ + struct thread *owner; + uintptr_t x; + + x = *xp; + MPASS(x != LK_UNLOCKED); + owner = (struct thread *)LK_HOLDER(x); + for (;;) { + MPASS(owner != curthread); + if (owner == (struct thread *)LK_KERNPROC) + return (false); + if ((x & LK_SHARE) && LK_SHARERS(x) > 0) + return (false); + if (owner == NULL) + return (false); + if (!TD_IS_RUNNING(owner)) + return (false); + if ((x & LK_ALL_WAITERS) != 0) + return (false); + lock_delay(lda); + x = lockmgr_read_value(lk); + if (LK_CAN_SHARE(x, flags, false)) { + *xp = x; + return (true); + } + owner = (struct thread *)LK_HOLDER(x); + } +} + static __noinline int lockmgr_slock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, const char *file, int line, struct lockmgr_wait *lwa) @@ -557,6 +594,7 @@ lockmgr_slock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, uint64_t waittime = 0; int contested = 0; #endif + struct lock_delay_arg lda; if (KERNEL_PANICKED()) goto out; @@ -566,27 +604,37 @@ lockmgr_slock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, if (LK_CAN_WITNESS(flags)) WITNESS_CHECKORDER(&lk->lock_object, LOP_NEWORDER, file, line, flags & LK_INTERLOCK ? ilk : NULL); + lock_delay_arg_init(&lda, &lockmgr_delay); + if (!lk_adaptive) + flags &= ~LK_ADAPTIVE; + x = lockmgr_read_value(lk); + /* + * The lock may already be locked exclusive by curthread, + * avoid deadlock. + */ + if (LK_HOLDER(x) == tid) { + LOCK_LOG2(lk, + "%s: %p already held in exclusive mode", + __func__, lk); + error = EDEADLK; + goto out; + } + for (;;) { if (lockmgr_slock_try(lk, &x, flags, false)) break; + + if ((flags & (LK_ADAPTIVE | LK_INTERLOCK)) == LK_ADAPTIVE) { + if (lockmgr_slock_adaptive(&lda, lk, &x, flags)) + continue; + } + #ifdef HWPMC_HOOKS PMC_SOFT_CALL( , , lock, failed); #endif lock_profile_obtain_lock_failed(&lk->lock_object, &contested, &waittime); - /* - * If the lock is already held by curthread in - * exclusive way avoid a deadlock. - */ - if (LK_HOLDER(x) == tid) { - LOCK_LOG2(lk, - "%s: %p already held in exclusive mode", - __func__, lk); - error = EDEADLK; - break; - } - /* * If the lock is expected to not sleep just give up * and return. @@ -660,6 +708,7 @@ lockmgr_slock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, } LOCK_LOG2(lk, "%s: %p resuming from the sleep queue", __func__, lk); + x = lockmgr_read_value(lk); } if (error == 0) { #ifdef KDTRACE_HOOKS @@ -682,6 +731,37 @@ lockmgr_slock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, return (error); } +static bool +lockmgr_xlock_adaptive(struct lock_delay_arg *lda, struct lock *lk, uintptr_t *xp) +{ + struct thread *owner; + uintptr_t x; + + x = *xp; + MPASS(x != LK_UNLOCKED); + owner = (struct thread *)LK_HOLDER(x); + for (;;) { + MPASS(owner != curthread); + if (owner == NULL) + return (false); + if ((x & LK_SHARE) && LK_SHARERS(x) > 0) + return (false); + if (owner == (struct thread *)LK_KERNPROC) + return (false); + if (!TD_IS_RUNNING(owner)) + return (false); + if ((x & LK_ALL_WAITERS) != 0) + return (false); + lock_delay(lda); + x = lockmgr_read_value(lk); + if (x == LK_UNLOCKED) { + *xp = x; + return (true); + } + owner = (struct thread *)LK_HOLDER(x); + } +} + static __noinline int lockmgr_xlock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, const char *file, int line, struct lockmgr_wait *lwa) @@ -699,6 +779,7 @@ lockmgr_xlock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, uint64_t waittime = 0; int contested = 0; #endif + struct lock_delay_arg lda; if (KERNEL_PANICKED()) goto out; @@ -747,10 +828,19 @@ lockmgr_xlock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, goto out; } + x = LK_UNLOCKED; + lock_delay_arg_init(&lda, &lockmgr_delay); + if (!lk_adaptive) + flags &= ~LK_ADAPTIVE; for (;;) { - if (lk->lk_lock == LK_UNLOCKED && - atomic_cmpset_acq_ptr(&lk->lk_lock, LK_UNLOCKED, tid)) - break; + if (x == LK_UNLOCKED) { + if (atomic_fcmpset_acq_ptr(&lk->lk_lock, &x, tid)) + break; + } + if ((flags & (LK_ADAPTIVE | LK_INTERLOCK)) == LK_ADAPTIVE) { + if (lockmgr_xlock_adaptive(&lda, lk, &x)) + continue; + } #ifdef HWPMC_HOOKS PMC_SOFT_CALL( , , lock, failed); #endif @@ -853,6 +943,7 @@ lockmgr_xlock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, } LOCK_LOG2(lk, "%s: %p resuming from the sleep queue", __func__, lk); + x = lockmgr_read_value(lk); } if (error == 0) { #ifdef KDTRACE_HOOKS @@ -954,6 +1045,7 @@ lockmgr_lock_flags(struct lock *lk, u_int flags, struct lock_object *ilk, file, line, flags & LK_INTERLOCK ? ilk : NULL); if (__predict_false(lk->lock_object.lo_flags & LK_NOSHARE)) break; + x = lockmgr_read_value(lk); if (lockmgr_slock_try(lk, &x, flags, true)) { lockmgr_note_shared_acquire(lk, 0, 0, file, line, flags); @@ -1139,12 +1231,13 @@ lockmgr_slock(struct lock *lk, u_int flags, const char *file, int line) if (LK_CAN_WITNESS(flags)) WITNESS_CHECKORDER(&lk->lock_object, LOP_NEWORDER, file, line, NULL); + x = lockmgr_read_value(lk); if (__predict_true(lockmgr_slock_try(lk, &x, flags, true))) { lockmgr_note_shared_acquire(lk, 0, 0, file, line, flags); return (0); } - return (lockmgr_slock_hard(lk, flags, NULL, file, line, NULL)); + return (lockmgr_slock_hard(lk, flags | LK_ADAPTIVE, NULL, file, line, NULL)); } int @@ -1165,7 +1258,7 @@ lockmgr_xlock(struct lock *lk, u_int flags, const char *file, int line) return (0); } - return (lockmgr_xlock_hard(lk, flags, NULL, file, line, NULL)); + return (lockmgr_xlock_hard(lk, flags | LK_ADAPTIVE, NULL, file, line, NULL)); } int diff --git a/sys/sys/lockmgr.h b/sys/sys/lockmgr.h index 336f57007013..fc3046f8c85a 100644 --- a/sys/sys/lockmgr.h +++ b/sys/sys/lockmgr.h @@ -170,6 +170,7 @@ _lockmgr_args_rw(struct lock *lk, u_int flags, struct rwlock *ilk, #define LK_SLEEPFAIL 0x000800 #define LK_TIMELOCK 0x001000 #define LK_NODDLKTREAT 0x002000 +#define LK_ADAPTIVE 0x004000 /* * Operations for lockmgr(). diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index f97de5432b67..000ded6cbbaa 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -445,6 +445,7 @@ ffs_lock(ap) struct lock *lkp; int result; + ap->a_flags |= LK_ADAPTIVE; switch (ap->a_flags & LK_TYPE_MASK) { case LK_SHARED: case LK_UPGRADE: @@ -482,6 +483,7 @@ ffs_lock(ap) } return (result); #else + ap->a_flags |= LK_ADAPTIVE; return (VOP_LOCK1_APV(&ufs_vnodeops, ap)); #endif } From 9af25ea3bb5e84846eeb9f39a064bd0a31851cb6 Mon Sep 17 00:00:00 2001 From: Gordon Bergling Date: Wed, 22 Jul 2020 13:00:56 +0000 Subject: [PATCH 093/287] geli(8): Add missing commands in the EXAMPLES section - Add a missing 'geli attach' command - Fix the passphrase prompt for a 'geli attach' command Reported by: Fabian Keil Reviewed by: bcr (mentor) Approved by: bcr (mentor) Differential Revision: https://reviews.freebsd.org/D25761 --- lib/geom/eli/geli.8 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/geom/eli/geli.8 b/lib/geom/eli/geli.8 index 0d23c4e09a49..02bff7bd5380 100644 --- a/lib/geom/eli/geli.8 +++ b/lib/geom/eli/geli.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 20, 2020 +.Dd July 22, 2020 .Dt GELI 8 .Os .Sh NAME @@ -1130,6 +1130,8 @@ is requested when geli init is called. # geli init -K /root/private0.key -s 4096 /dev/md0 Enter new passphrase: Reenter new passphrase: +# geli attach -k /root/private0.key /dev/md0 +Enter passphrase: # dd if=/dev/random of=/dev/md0.eli bs=1m .Ed .Pp @@ -1150,7 +1152,7 @@ It is recommended to do this procedure after the boot, because otherwise the boot process would be waiting for the passphrase input. .Bd -literal -offset indent # geli attach -k /root/private0.key /dev/md0 -Enter new passphrase: +Enter passphrase: # mount /dev/md0.eli /private .Ed .Sh ENCRYPTION MODES From 3b01bf881c848ba0be72fc74ba5eaa58c66c35e1 Mon Sep 17 00:00:00 2001 From: Tom Jones Date: Wed, 22 Jul 2020 13:49:54 +0000 Subject: [PATCH 094/287] Add tests for "add", "change" and "delete" functionality of /sbin/route. Add tests to cover "add", "change" and "delete" functionality of /sbin/route for ipv4 and ipv6. These tests for the existing route tool are the first step towards creating libroute. Submitted by: Ahsan Barkati Sponsored by: Google, Inc. (GSoC 2020) Reviewed by: kp, thj Approved by: bz (mentor) MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D25220 --- etc/mtree/BSD.tests.dist | 2 + sbin/route/Makefile | 3 + sbin/route/tests/Makefile | 11 ++++ sbin/route/tests/basic.sh | 125 ++++++++++++++++++++++++++++++++++++ sbin/route/tests/utils.subr | 47 ++++++++++++++ 5 files changed, 188 insertions(+) create mode 100644 sbin/route/tests/Makefile create mode 100644 sbin/route/tests/basic.sh create mode 100644 sbin/route/tests/utils.subr diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index 9fbf74246f4a..80c4b3e47dc3 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -448,6 +448,8 @@ .. ping6 .. + route + .. .. secure lib diff --git a/sbin/route/Makefile b/sbin/route/Makefile index a1db0b6528dd..e65030f805bb 100644 --- a/sbin/route/Makefile +++ b/sbin/route/Makefile @@ -19,6 +19,9 @@ CFLAGS+= -DINET6 .endif CFLAGS+= -I. +HAS_TESTS= +SUBDIR.${MK_TESTS}+= tests + keywords.h: keywords LC_ALL=C awk '!/^#|^$$/ { \ printf "#define\tK_%s\t%d\n\t{\"%s\", K_%s},\n", \ diff --git a/sbin/route/tests/Makefile b/sbin/route/tests/Makefile new file mode 100644 index 000000000000..eb278981f8cd --- /dev/null +++ b/sbin/route/tests/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +PACKAGE= tests + +ATF_TESTS_SH+= \ + basic + +${PACKAGE}FILES+= \ + utils.subr + +.include diff --git a/sbin/route/tests/basic.sh b/sbin/route/tests/basic.sh new file mode 100644 index 000000000000..6141097a09ec --- /dev/null +++ b/sbin/route/tests/basic.sh @@ -0,0 +1,125 @@ +#- +# SPDX-License-Identifier: BSD-2-Clause-FreeBSD +# +# Copyright (c) 2020 Ahsan Barkati +# +# 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$ +# + +. $(atf_get_srcdir)/utils.subr + +atf_test_case "basic_v4" "cleanup" +basic_v4_head() +{ + atf_set descr 'add/change/delete route test for v4' + atf_set require.user root + atf_set require.progs jq +} + +basic_v4_body() +{ + epair=$(vnet_mkepair) + ifconfig ${epair}a 192.0.2.2/24 up + vnet_mkjail alcatraz ${epair}b + jexec alcatraz ifconfig ${epair}b 192.0.2.1/24 up + + # add a new route in the jail + jexec alcatraz route add 192.0.2.3 192.0.2.2 + gateway=$(check_route "alcatraz" "192.0.2.3") + + if [ "${gateway}" != "192.0.2.2" ]; then + atf_fail "Failed to add new route." + fi + + # change the added route + jexec alcatraz route change 192.0.2.3 192.0.2.4 + gateway=$(check_route "alcatraz" "192.0.2.3") + + if [ "${gateway}" != "192.0.2.4" ]; then + atf_fail "Failed to change route." + fi + + # delete the route + jexec alcatraz route delete 192.0.2.3 + gateway=$(check_route "alcatraz" "192.0.2.3") + + if [ "${gateway}" != "" ]; then + atf_fail "Failed to delete route." + fi +} + +basic_v4_cleanup() +{ + vnet_cleanup +} + +atf_test_case "basic_v6" "cleanup" +basic_v6_head() +{ + atf_set descr 'add/change/delete route test for v6' + atf_set require.user root + atf_set require.progs jq +} + +basic_v6_body() +{ + epair=$(vnet_mkepair) + ifconfig ${epair}a inet6 2001:db8:cc4b::1/64 up no_dad + vnet_mkjail alcatraz ${epair}b + jexec alcatraz ifconfig ${epair}b inet6 2001:db8:cc4b::2/64 up no_dad + + # add a new route in the jail + jexec alcatraz route add -6 2001:db8:cc4b::3 2001:db8:cc4b::1 + gateway=$(check_route "alcatraz" "2001:db8:cc4b::3") + + if [ "${gateway}" != "2001:db8:cc4b::1" ]; then + atf_fail "Failed to add new route." + fi + + # change the added route + jexec alcatraz route change -6 2001:db8:cc4b::3 2001:db8:cc4b::4 + gateway=$(check_route "alcatraz" "2001:db8:cc4b::3") + if [ "${gateway}" != "2001:db8:cc4b::4" ]; then + atf_fail "Failed to change route." + fi + + # delete the route + jexec alcatraz route -6 delete 2001:db8:cc4b::3 + gateway=$(check_route "alcatraz" "2001:db8:cc4b::3") + + if [ "${gateway}" != "" ]; then + atf_fail "Failed to delete route." + fi +} + +basic_v6_cleanup() +{ + vnet_cleanup +} + +atf_init_test_cases() +{ + atf_add_test_case "basic_v4" + atf_add_test_case "basic_v6" +} diff --git a/sbin/route/tests/utils.subr b/sbin/route/tests/utils.subr new file mode 100644 index 000000000000..fda9980eb78d --- /dev/null +++ b/sbin/route/tests/utils.subr @@ -0,0 +1,47 @@ +#- +# SPDX-License-Identifier: BSD-2-Clause-FreeBSD +# +# Copyright (c) 2020 Ahsan Barkati +# +# 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$ +# + +. $(atf_get_srcdir)/../../sys/common/vnet.subr + +check_route() +{ + jname=$1 + dest=$2 + result=$(jexec $jname netstat -r --libxo json) + + # This query selects the JSON item from the array of rt-entry + # for which the destination address is $dest + query=".statistics.\"route-information\".\"route-table\".\"rt-family\"[0].\"rt-entry\"[]|select(.destination==\"${dest}\")" + + # Gateway is then extracted from the JSON item as described above + gateway=$(echo $result | jq -r ${query}.gateway) + + echo ${gateway} +} + From 94140f4781f83c9e98f582439ed69d000ff0323a Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 22 Jul 2020 14:32:47 +0000 Subject: [PATCH 095/287] usb(4): Stop checking for failures from malloc(M_WAITOK). Handle the fact that parts of usb(4) can be compiled into the boot loader, where M_WAITOK does not guarantee a successful allocation. PR: 240545 Submitted by: Andrew Reiter (original version) Reviewed by: hselasky MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25706 --- sys/compat/linuxkpi/common/src/linux_usb.c | 20 +++++++------------- sys/dev/sound/usb/uaudio.c | 4 ---- sys/dev/usb/input/uhid.c | 8 -------- sys/dev/usb/input/uhid_snes.c | 8 -------- sys/dev/usb/storage/ustorage_fs.c | 4 ---- sys/dev/usb/usb_dev.c | 15 +++++---------- sys/dev/usb/usb_device.c | 2 ++ sys/dev/usb/usb_freebsd.h | 1 + sys/dev/usb/usb_freebsd_loader.h | 1 + sys/dev/usb/usb_generic.c | 5 ----- sys/dev/usb/usb_mbuf.c | 6 ------ sys/dev/usb/usb_transfer.c | 5 +++-- 12 files changed, 19 insertions(+), 60 deletions(-) diff --git a/sys/compat/linuxkpi/common/src/linux_usb.c b/sys/compat/linuxkpi/common/src/linux_usb.c index 774cae98f1d7..abef31e20a07 100644 --- a/sys/compat/linuxkpi/common/src/linux_usb.c +++ b/sys/compat/linuxkpi/common/src/linux_usb.c @@ -707,8 +707,6 @@ usb_control_msg(struct usb_device *dev, struct usb_host_endpoint *uhe, * 0xFFFF is a FreeBSD specific magic value. */ urb = usb_alloc_urb(0xFFFF, size); - if (urb == NULL) - return (-ENOMEM); urb->dev = dev; urb->endpoint = uhe; @@ -1008,16 +1006,14 @@ usb_alloc_urb(uint16_t iso_packets, uint16_t mem_flags) } urb = malloc(size, M_USBDEV, M_WAITOK | M_ZERO); - if (urb) { - cv_init(&urb->cv_wait, "URBWAIT"); - if (iso_packets == 0xFFFF) { - urb->setup_packet = (void *)(urb + 1); - urb->transfer_buffer = (void *)(urb->setup_packet + - sizeof(struct usb_device_request)); - } else { - urb->number_of_packets = iso_packets; - } + cv_init(&urb->cv_wait, "URBWAIT"); + if (iso_packets == 0xFFFF) { + urb->setup_packet = (void *)(urb + 1); + urb->transfer_buffer = (void *)(urb->setup_packet + + sizeof(struct usb_device_request)); + } else { + urb->number_of_packets = iso_packets; } return (urb); } @@ -1722,8 +1718,6 @@ usb_bulk_msg(struct usb_device *udev, struct usb_host_endpoint *uhe, return (err); urb = usb_alloc_urb(0, 0); - if (urb == NULL) - return (-ENOMEM); usb_fill_bulk_urb(urb, udev, uhe, data, len, usb_linux_wait_complete, NULL); diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c index 06986b03e8e2..54abd63d9ecb 100644 --- a/sys/dev/sound/usb/uaudio.c +++ b/sys/dev/sound/usb/uaudio.c @@ -4968,10 +4968,6 @@ uaudio_mixer_fill_info(struct uaudio_softc *sc, iot = malloc(sizeof(struct uaudio_terminal_node) * 256, M_TEMP, M_WAITOK | M_ZERO); - if (iot == NULL) { - DPRINTF("no memory!\n"); - goto done; - } while ((desc = usb_desc_foreach(cd, desc))) { dp = desc; diff --git a/sys/dev/usb/input/uhid.c b/sys/dev/usb/input/uhid.c index c3ca63e13f6c..4ef19631b10f 100644 --- a/sys/dev/usb/input/uhid.c +++ b/sys/dev/usb/input/uhid.c @@ -451,10 +451,6 @@ uhid_get_report(struct uhid_softc *sc, uint8_t type, if (kern_data == NULL) { kern_data = malloc(len, M_USBDEV, M_WAITOK); - if (kern_data == NULL) { - err = ENOMEM; - goto done; - } free_data = 1; } err = usbd_req_get_report(sc->sc_udev, NULL, kern_data, @@ -487,10 +483,6 @@ uhid_set_report(struct uhid_softc *sc, uint8_t type, if (kern_data == NULL) { kern_data = malloc(len, M_USBDEV, M_WAITOK); - if (kern_data == NULL) { - err = ENOMEM; - goto done; - } free_data = 1; err = copyin(user_data, kern_data, len); if (err) { diff --git a/sys/dev/usb/input/uhid_snes.c b/sys/dev/usb/input/uhid_snes.c index 5c043acdf6a7..79089782a464 100644 --- a/sys/dev/usb/input/uhid_snes.c +++ b/sys/dev/usb/input/uhid_snes.c @@ -168,10 +168,6 @@ uhid_get_report(struct uhid_snes_softc *sc, uint8_t type, if (kern_data == NULL) { kern_data = malloc(len, M_USBDEV, M_WAITOK); - if (kern_data == NULL) { - err = ENOMEM; - goto done; - } free_data = 1; } err = usbd_req_get_report(sc->sc_udev, NULL, kern_data, @@ -203,10 +199,6 @@ uhid_set_report(struct uhid_snes_softc *sc, uint8_t type, if (kern_data == NULL) { kern_data = malloc(len, M_USBDEV, M_WAITOK); - if (kern_data == NULL) { - err = ENOMEM; - goto done; - } free_data = 1; err = copyin(user_data, kern_data, len); if (err) { diff --git a/sys/dev/usb/storage/ustorage_fs.c b/sys/dev/usb/storage/ustorage_fs.c index ea3f05fb5db9..454dac07d3c0 100644 --- a/sys/dev/usb/storage/ustorage_fs.c +++ b/sys/dev/usb/storage/ustorage_fs.c @@ -381,10 +381,6 @@ ustorage_fs_attach(device_t dev) ustorage_fs_ramdisk = malloc(USTORAGE_FS_RAM_SECT << 9, M_USB, M_ZERO | M_WAITOK); - - if (ustorage_fs_ramdisk == NULL) { - return (ENOMEM); - } } sc->sc_lun[0].memory_image = ustorage_fs_ramdisk; sc->sc_lun[0].num_sectors = USTORAGE_FS_RAM_SECT; diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c index 7860fb67e5fe..9e17dfdc09bf 100644 --- a/sys/dev/usb/usb_dev.c +++ b/sys/dev/usb/usb_dev.c @@ -386,13 +386,11 @@ usb_fifo_alloc(struct mtx *mtx) struct usb_fifo *f; f = malloc(sizeof(*f), M_USBDEV, M_WAITOK | M_ZERO); - if (f != NULL) { - cv_init(&f->cv_io, "FIFO-IO"); - cv_init(&f->cv_drain, "FIFO-DRAIN"); - f->priv_mtx = mtx; - f->refcount = 1; - knlist_init_mtx(&f->selinfo.si_note, mtx); - } + cv_init(&f->cv_io, "FIFO-IO"); + cv_init(&f->cv_drain, "FIFO-DRAIN"); + f->priv_mtx = mtx; + f->refcount = 1; + knlist_init_mtx(&f->selinfo.si_note, mtx); return (f); } @@ -2309,9 +2307,6 @@ usb_alloc_symlink(const char *target) struct usb_symlink *ps; ps = malloc(sizeof(*ps), M_USBDEV, M_WAITOK); - if (ps == NULL) { - return (ps); - } /* XXX no longer needed */ strlcpy(ps->src_path, target, sizeof(ps->src_path)); ps->src_len = strlen(ps->src_path); diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index e4ed447b813d..5560c0ae0acf 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -1785,9 +1785,11 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, return (NULL); } udev = malloc(sizeof(*udev), M_USB, M_WAITOK | M_ZERO); +#if (USB_HAVE_MALLOC_WAITOK == 0) if (udev == NULL) { return (NULL); } +#endif /* initialise our SX-lock */ sx_init_flags(&udev->enum_sx, "USB config SX lock", SX_DUPOK); sx_init_flags(&udev->sr_sx, "USB suspend and resume SX lock", SX_NOWITNESS); diff --git a/sys/dev/usb/usb_freebsd.h b/sys/dev/usb/usb_freebsd.h index 871fc7125ad2..2d2123d4b622 100644 --- a/sys/dev/usb/usb_freebsd.h +++ b/sys/dev/usb/usb_freebsd.h @@ -53,6 +53,7 @@ #define USB_HAVE_FIXED_CONFIG 0 #define USB_HAVE_FIXED_PORT 0 #define USB_HAVE_DISABLE_ENUM 1 +#define USB_HAVE_MALLOC_WAITOK 1 /* define zero ticks callout value */ #define USB_CALLOUT_ZERO_TICKS 1 diff --git a/sys/dev/usb/usb_freebsd_loader.h b/sys/dev/usb/usb_freebsd_loader.h index 52f895b2e557..d3aade89640a 100644 --- a/sys/dev/usb/usb_freebsd_loader.h +++ b/sys/dev/usb/usb_freebsd_loader.h @@ -53,6 +53,7 @@ #define USB_HAVE_FIXED_CONFIG 0 #define USB_HAVE_FIXED_PORT 0 #define USB_HAVE_DISABLE_ENUM 0 +#define USB_HAVE_MALLOC_WAITOK 0 #define USB_CALLOUT_ZERO_TICKS 1 diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c index aee2939ee1f7..940b3dc145b4 100644 --- a/sys/dev/usb/usb_generic.c +++ b/sys/dev/usb/usb_generic.c @@ -2339,11 +2339,6 @@ ugen_ioctl_post(struct usb_fifo *f, u_long cmd, void *addr, int fflags) } f->fs_xfer = malloc(sizeof(f->fs_xfer[0]) * u.pinit->ep_index_max, M_USB, M_WAITOK | M_ZERO); - if (f->fs_xfer == NULL) { - usb_fifo_free_buffer(f); - error = ENOMEM; - break; - } f->fs_ep_max = u.pinit->ep_index_max; f->fs_ep_ptr = u.pinit->pEndpoints; break; diff --git a/sys/dev/usb/usb_mbuf.c b/sys/dev/usb/usb_mbuf.c index eacef78be4cc..4eb27cf6977e 100644 --- a/sys/dev/usb/usb_mbuf.c +++ b/sys/dev/usb/usb_mbuf.c @@ -78,15 +78,10 @@ usb_alloc_mbufs(struct malloc_type *type, struct usb_ifqueue *ifq, alloc_size = (block_size + sizeof(struct usb_mbuf)) * nblocks; free_ptr = malloc(alloc_size, type, M_WAITOK | M_ZERO); - - if (free_ptr == NULL) { - goto done; - } m_ptr = free_ptr; data_ptr = (void *)(m_ptr + nblocks); while (nblocks--) { - m_ptr->cur_data_ptr = m_ptr->min_data_ptr = data_ptr; @@ -99,6 +94,5 @@ usb_alloc_mbufs(struct malloc_type *type, struct usb_ifqueue *ifq, data_ptr += block_size; } } -done: return (free_ptr); } diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c index 15b971bbd0ba..ab70da8afd4c 100644 --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -1342,14 +1342,15 @@ usbd_transfer_setup(struct usb_device *udev, /* allocate zeroed memory */ buf = malloc(parm->size[0], M_USB, M_WAITOK | M_ZERO); - +#if (USB_HAVE_MALLOC_WAITOK == 0) if (buf == NULL) { parm->err = USB_ERR_NOMEM; DPRINTFN(0, "cannot allocate memory block for " "configuration (%d bytes)\n", parm->size[0]); goto done; - } + } +#endif parm->dma_tag_p = USB_ADD_BYTES(buf, parm->size[1]); parm->dma_page_ptr = USB_ADD_BYTES(buf, parm->size[3]); parm->dma_page_cache_ptr = USB_ADD_BYTES(buf, parm->size[4]); From ca7f7593ba7c3e5f930089bc07b20fdd5ab5d6cc Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Wed, 22 Jul 2020 17:33:35 +0000 Subject: [PATCH 096/287] pkg-bootstrap: complain on improper `pkg bootstrap` usage Right now, the bootstrap will gloss over things like pkg bootstrap -x or pkg bootstrap -f pkg. Make it more clear that this is incorrect, and hint at the correct formatting. Reported by: jhb (IIRC via IRC) Approved by: bapt, jhb, manu MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D24750 --- usr.sbin/pkg/pkg.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/usr.sbin/pkg/pkg.c b/usr.sbin/pkg/pkg.c index 7e2359aa97b1..50b196fd9b30 100644 --- a/usr.sbin/pkg/pkg.c +++ b/usr.sbin/pkg/pkg.c @@ -1050,8 +1050,16 @@ main(int argc, char *argv[]) if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) { bootstrap_only = true; - if (argc == 3 && strcmp(argv[2], "-f") == 0) + if (argc > 3) { + fprintf(stderr, "Too many arguments\nUsage: pkg bootstrap [-f]\n"); + exit(EXIT_FAILURE); + } + if (argc == 3 && strcmp(argv[2], "-f") == 0) { force = true; + } else if (argc == 3) { + fprintf(stderr, "Invalid argument specified\nUsage: pkg bootstrap [-f]\n"); + exit(EXIT_FAILURE); + } } if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { From 484489d4f2407a755c6ec9f06ccdbc53b67dd57c Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Wed, 22 Jul 2020 17:36:28 +0000 Subject: [PATCH 097/287] mmc_xpt: Fix debug messages PROBE_RESET was printed for PROBE_IDENTIFY, fix this. While here add one for the PROBE_RESET. Submitted by: kibab --- sys/cam/mmc/mmc_xpt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/cam/mmc/mmc_xpt.c b/sys/cam/mmc/mmc_xpt.c index b4ea0968d135..c1d0abeb0ade 100644 --- a/sys/cam/mmc/mmc_xpt.c +++ b/sys/cam/mmc/mmc_xpt.c @@ -574,10 +574,11 @@ mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb) /* Here is the place where the identify fun begins */ switch (softc->action) { case PROBE_RESET: + CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_RESET\n")); /* FALLTHROUGH */ case PROBE_IDENTIFY: xpt_path_inq(&start_ccb->cpi, periph->path); - CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_RESET\n")); + CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_IDENTIFY\n")); init_standard_ccb(start_ccb, XPT_GET_TRAN_SETTINGS); xpt_action(start_ccb); if (cts->ios.power_mode != power_off) { From 5f2d3b42de185d5d663541122dd2022f4632bd29 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Wed, 22 Jul 2020 17:37:11 +0000 Subject: [PATCH 098/287] Fix sys.geom.class.eli.onetime_test.onetime after r363402 PR: 247954 X-MFC with: r363402 Sponsored by: The FreeBSD Foundation --- tests/sys/geom/class/eli/onetime_test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/sys/geom/class/eli/onetime_test.sh b/tests/sys/geom/class/eli/onetime_test.sh index 479d4d771877..72d4c842e764 100644 --- a/tests/sys/geom/class/eli/onetime_test.sh +++ b/tests/sys/geom/class/eli/onetime_test.sh @@ -130,7 +130,7 @@ onetime_d_cleanup() geli_test_cleanup } -atf_test_case onetime cleanup +atf_test_case onetime_null cleanup onetime_null_head() { atf_set "descr" "geli onetime can use the null cipher" From d5bfd287c29356012607adf6316eb9f7a7a15e16 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Wed, 22 Jul 2020 18:21:37 +0000 Subject: [PATCH 099/287] mmccam: Use a sbuf for the mmc ident function While here fix a typo. --- sys/cam/mmc/mmc_xpt.c | 58 +++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/sys/cam/mmc/mmc_xpt.c b/sys/cam/mmc/mmc_xpt.c index c1d0abeb0ade..56b3c2ff5644 100644 --- a/sys/cam/mmc/mmc_xpt.c +++ b/sys/cam/mmc/mmc_xpt.c @@ -408,27 +408,47 @@ mmc_announce_periph(struct cam_periph *periph) void mmc_print_ident(struct mmc_params *ident_data) { - printf("Relative addr: %08x\n", ident_data->card_rca); - printf("Card features: <"); - if (ident_data->card_features & CARD_FEATURE_MMC) - printf("MMC "); - if (ident_data->card_features & CARD_FEATURE_MEMORY) - printf("Memory "); - if (ident_data->card_features & CARD_FEATURE_SDHC) - printf("High-Capacity "); - if (ident_data->card_features & CARD_FEATURE_SD20) - printf("SD2.0-Conditions "); - if (ident_data->card_features & CARD_FEATURE_SDIO) - printf("SDIO "); - printf(">\n"); + struct sbuf *sb; + bool space = false; - if (ident_data->card_features & CARD_FEATURE_MEMORY) - printf("Card memory OCR: %08x\n", ident_data->card_ocr); + sb = sbuf_new_auto(); + sbuf_printf(sb, "Relative addr: %08x\n", ident_data->card_rca); + sbuf_printf(sb, "Card features: <"); + if (ident_data->card_features & CARD_FEATURE_MMC) { + sbuf_printf(sb, "MMC"); + space = true; + } + if (ident_data->card_features & CARD_FEATURE_MEMORY) { + sbuf_printf(sb, "%sMemory", space ? " " : ""); + space = true; + } + if (ident_data->card_features & CARD_FEATURE_SDHC) { + sbuf_printf(sb, "%sHigh-Capacity", space ? " " : ""); + space = true; + } + if (ident_data->card_features & CARD_FEATURE_SD20) { + sbuf_printf(sb, "%sSD2.0-Conditions", space ? " " : ""); + space = true; + } + if (ident_data->card_features & CARD_FEATURE_SDIO) { + sbuf_printf(sb, "%sSDIO", space ? " " : ""); + space = true; + } + sbuf_printf(sb, ">\n"); - if (ident_data->card_features & CARD_FEATURE_SDIO) { - printf("Card IO OCR: %08x\n", ident_data->io_ocr); - printf("Number of funcitions: %u\n", ident_data->sdio_func_count); - } + if (ident_data->card_features & CARD_FEATURE_MEMORY) + sbuf_printf(sb, "Card memory OCR: %08x\n", + ident_data->card_ocr); + + if (ident_data->card_features & CARD_FEATURE_SDIO) { + sbuf_printf(sb, "Card IO OCR: %08x\n", ident_data->io_ocr); + sbuf_printf(sb, "Number of functions: %u\n", + ident_data->sdio_func_count); + } + + sbuf_finish(sb); + printf("%s", sbuf_data(sb)); + sbuf_clear(sb); } static void From c7a499485320d4e10251cafdb1a296728f2d6a12 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Wed, 22 Jul 2020 18:30:17 +0000 Subject: [PATCH 100/287] mmccam: Add a generic mmccam_start_discovery function This is a generic function start a scan request for the given cam_sim. Other driver can now just use this function to request a new rescan. Submitted by: kibab --- sys/cam/mmc/mmc_all.h | 2 ++ sys/cam/mmc/mmc_xpt.c | 23 ++++++++++++++++++++++ sys/dev/sdhci/sdhci.c | 46 ++----------------------------------------- 3 files changed, 27 insertions(+), 44 deletions(-) diff --git a/sys/cam/mmc/mmc_all.h b/sys/cam/mmc/mmc_all.h index eb7869a05372..dd7cd25453a8 100644 --- a/sys/cam/mmc/mmc_all.h +++ b/sys/cam/mmc/mmc_all.h @@ -64,6 +64,7 @@ #ifndef CAM_MMC_ALL_H #define CAM_MMC_ALL_H +#include #include #include @@ -72,5 +73,6 @@ struct ccb_pathinq; struct cam_sim; void mmc_path_inq(struct ccb_pathinq *cpi, const char *hba, const struct cam_sim *sim, size_t maxio); +void mmccam_start_discovery(struct cam_sim *sim); #endif diff --git a/sys/cam/mmc/mmc_xpt.c b/sys/cam/mmc/mmc_xpt.c index 56b3c2ff5644..6e39cffd13ff 100644 --- a/sys/cam/mmc/mmc_xpt.c +++ b/sys/cam/mmc/mmc_xpt.c @@ -404,6 +404,29 @@ mmc_announce_periph(struct cam_periph *periph) printf("XPT info: CLK %04X, ...\n", cts.proto_specific.mmc.ios.clock); } +void +mmccam_start_discovery(struct cam_sim *sim) { + union ccb *ccb; + uint32_t pathid; + + pathid = cam_sim_path(sim); + ccb = xpt_alloc_ccb_nowait(); + if (ccb == NULL) { + return; + } + + /* + * We create a rescan request for BUS:0:0, since the card + * will be at lun 0. + */ + if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, + /* target */ 0, /* lun */ 0) != CAM_REQ_CMP) { + xpt_free_ccb(ccb); + return; + } + xpt_rescan(ccb); +} + /* This func is called per attached device :-( */ void mmc_print_ident(struct mmc_params *ident_data) diff --git a/sys/dev/sdhci/sdhci.c b/sys/dev/sdhci/sdhci.c index b07d2926a369..16c0653342bc 100644 --- a/sys/dev/sdhci/sdhci.c +++ b/sys/dev/sdhci/sdhci.c @@ -626,29 +626,8 @@ sdhci_card_task(void *arg, int pending __unused) slot_printf(slot, "Card inserted\n"); #ifdef MMCCAM slot->card_present = 1; - union ccb *ccb; - uint32_t pathid; - pathid = cam_sim_path(slot->sim); - ccb = xpt_alloc_ccb_nowait(); - if (ccb == NULL) { - slot_printf(slot, "Unable to alloc CCB for rescan\n"); - SDHCI_UNLOCK(slot); - return; - } - - /* - * We create a rescan request for BUS:0:0, since the card - * will be at lun 0. - */ - if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, - /* target */ 0, /* lun */ 0) != CAM_REQ_CMP) { - slot_printf(slot, "Unable to create path for rescan\n"); - SDHCI_UNLOCK(slot); - xpt_free_ccb(ccb); - return; - } + mmccam_start_discovery(slot->sim); SDHCI_UNLOCK(slot); - xpt_rescan(ccb); #else d = slot->dev = device_add_child(slot->bus, "mmc", -1); SDHCI_UNLOCK(slot); @@ -672,29 +651,8 @@ sdhci_card_task(void *arg, int pending __unused) slot->dev = NULL; #ifdef MMCCAM slot->card_present = 0; - union ccb *ccb; - uint32_t pathid; - pathid = cam_sim_path(slot->sim); - ccb = xpt_alloc_ccb_nowait(); - if (ccb == NULL) { - slot_printf(slot, "Unable to alloc CCB for rescan\n"); - SDHCI_UNLOCK(slot); - return; - } - - /* - * We create a rescan request for BUS:0:0, since the card - * will be at lun 0. - */ - if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, - /* target */ 0, /* lun */ 0) != CAM_REQ_CMP) { - slot_printf(slot, "Unable to create path for rescan\n"); - SDHCI_UNLOCK(slot); - xpt_free_ccb(ccb); - return; - } + mmccam_start_discovery(slot->sim); SDHCI_UNLOCK(slot); - xpt_rescan(ccb); #else slot->intmask &= ~sdhci_tuning_intmask(slot); WR4(slot, SDHCI_INT_ENABLE, slot->intmask); From 9bca4667450d83520b3f68ebd87ee67d6a40792f Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Wed, 22 Jul 2020 18:33:36 +0000 Subject: [PATCH 101/287] aw_mmc: Start a mmccam discovery when the CD handler is called. Submitted by: kibab --- sys/arm/allwinner/aw_mmc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/arm/allwinner/aw_mmc.c b/sys/arm/allwinner/aw_mmc.c index f19ee412cb5c..c8d3c2694d36 100644 --- a/sys/arm/allwinner/aw_mmc.c +++ b/sys/arm/allwinner/aw_mmc.c @@ -371,6 +371,9 @@ aw_mmc_helper_cd_handler(device_t dev, bool present) struct aw_mmc_softc *sc; sc = device_get_softc(dev); +#ifdef MMCCAM + mmccam_start_discovery(sc->sim); +#else AW_MMC_LOCK(sc); if (present) { if (sc->child == NULL) { @@ -397,6 +400,7 @@ aw_mmc_helper_cd_handler(device_t dev, bool present) } else AW_MMC_UNLOCK(sc); } +#endif /* MMCCAM */ } static int From 2657d8e33e4ecf6f17aa17b67fd6bba73eeed942 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Wed, 22 Jul 2020 19:04:45 +0000 Subject: [PATCH 102/287] mmccam: Add support for 1.8V sdcard If the card reports that it support 1.8V signaling switch to this voltage. While here update the list of mode for mmccam. Submitted by: kibab --- sys/cam/cam_ccb.h | 33 ++++++++++++++++++++++++++++++--- sys/cam/mmc/mmc_xpt.c | 19 +++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h index 772de3921122..cf5daf653079 100644 --- a/sys/cam/cam_ccb.h +++ b/sys/cam/cam_ccb.h @@ -1046,14 +1046,41 @@ struct ccb_trans_settings_mmc { #define MMC_PM (1 << 5) #define MMC_BT (1 << 6) #define MMC_BM (1 << 7) +#define MMC_VCCQ (1 << 8) uint32_t ios_valid; /* The folowing is used only for GET_TRAN_SETTINGS */ uint32_t host_ocr; int host_f_min; int host_f_max; -#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can do 4-bit data transfers */ -#define MMC_CAP_8_BIT_DATA (1 << 1) /* Can do 8-bit data transfers */ -#define MMC_CAP_HSPEED (1 << 2) /* Can do High Speed transfers */ +/* Copied from sys/dev/mmc/bridge.h */ +#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can do 4-bit data transfers */ +#define MMC_CAP_8_BIT_DATA (1 << 1) /* Can do 8-bit data transfers */ +#define MMC_CAP_HSPEED (1 << 2) /* Can do High Speed transfers */ +#define MMC_CAP_BOOT_NOACC (1 << 4) /* Cannot access boot partitions */ +#define MMC_CAP_WAIT_WHILE_BUSY (1 << 5) /* Host waits for busy responses */ +#define MMC_CAP_UHS_SDR12 (1 << 6) /* Can do UHS SDR12 */ +#define MMC_CAP_UHS_SDR25 (1 << 7) /* Can do UHS SDR25 */ +#define MMC_CAP_UHS_SDR50 (1 << 8) /* Can do UHS SDR50 */ +#define MMC_CAP_UHS_SDR104 (1 << 9) /* Can do UHS SDR104 */ +#define MMC_CAP_UHS_DDR50 (1 << 10) /* Can do UHS DDR50 */ +#define MMC_CAP_MMC_DDR52_120 (1 << 11) /* Can do eMMC DDR52 at 1.2 V */ +#define MMC_CAP_MMC_DDR52_180 (1 << 12) /* Can do eMMC DDR52 at 1.8 V */ +#define MMC_CAP_MMC_DDR52 (MMC_CAP_MMC_DDR52_120 | MMC_CAP_MMC_DDR52_180) +#define MMC_CAP_MMC_HS200_120 (1 << 13) /* Can do eMMC HS200 at 1.2 V */ +#define MMC_CAP_MMC_HS200_180 (1 << 14) /* Can do eMMC HS200 at 1.8 V */ +#define MMC_CAP_MMC_HS200 (MMC_CAP_MMC_HS200_120| MMC_CAP_MMC_HS200_180) +#define MMC_CAP_MMC_HS400_120 (1 << 15) /* Can do eMMC HS400 at 1.2 V */ +#define MMC_CAP_MMC_HS400_180 (1 << 16) /* Can do eMMC HS400 at 1.8 V */ +#define MMC_CAP_MMC_HS400 (MMC_CAP_MMC_HS400_120 | MMC_CAP_MMC_HS400_180) +#define MMC_CAP_MMC_HSX00_120 (MMC_CAP_MMC_HS200_120 | MMC_CAP_MMC_HS400_120) +#define MMC_CAP_MMC_ENH_STROBE (1 << 17) /* Can do eMMC Enhanced Strobe */ +#define MMC_CAP_SIGNALING_120 (1 << 18) /* Can do signaling at 1.2 V */ +#define MMC_CAP_SIGNALING_180 (1 << 19) /* Can do signaling at 1.8 V */ +#define MMC_CAP_SIGNALING_330 (1 << 20) /* Can do signaling at 3.3 V */ +#define MMC_CAP_DRIVER_TYPE_A (1 << 21) /* Can do Driver Type A */ +#define MMC_CAP_DRIVER_TYPE_C (1 << 22) /* Can do Driver Type C */ +#define MMC_CAP_DRIVER_TYPE_D (1 << 23) /* Can do Driver Type D */ + uint32_t host_caps; uint32_t host_max_data; }; diff --git a/sys/cam/mmc/mmc_xpt.c b/sys/cam/mmc/mmc_xpt.c index 6e39cffd13ff..ad3ea9d8633c 100644 --- a/sys/cam/mmc/mmc_xpt.c +++ b/sys/cam/mmc/mmc_xpt.c @@ -167,6 +167,7 @@ typedef struct { union ccb saved_ccb; uint32_t flags; #define PROBE_FLAG_ACMD_SENT 0x1 /* CMD55 is sent, card expects ACMD */ +#define PROBE_FLAG_HOST_CAN_DO_18V 0x2 /* Host can do 1.8V signaling */ uint8_t acmd41_count; /* how many times ACMD41 has been issued */ struct cam_periph *periph; } mmcprobe_softc; @@ -457,6 +458,9 @@ mmc_print_ident(struct mmc_params *ident_data) sbuf_printf(sb, "%sSDIO", space ? " " : ""); space = true; } + if (ident_data->card_features & CARD_FEATURE_18V) { + sbuf_printf(sb, "%s1.8-Signaling", space ? " " : ""); + } sbuf_printf(sb, ">\n"); if (ident_data->card_features & CARD_FEATURE_MEMORY) @@ -636,6 +640,9 @@ mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb) init_standard_ccb(start_ccb, XPT_GET_TRAN_SETTINGS); xpt_action(start_ccb); + uint32_t host_caps = cts->host_caps; + if (host_caps & MMC_CAP_SIGNALING_180) + softc->flags |= PROBE_FLAG_HOST_CAN_DO_18V; uint32_t hv = mmc_highest_voltage(cts->host_ocr); init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS); cts->ios.vdd = hv; @@ -1008,6 +1015,18 @@ mmcprobe_done(struct cam_periph *periph, union ccb *done_ccb) CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Card supports 1.8V signaling\n")); mmcp->card_features |= CARD_FEATURE_18V; + if (softc->flags & PROBE_FLAG_HOST_CAN_DO_18V) { + CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, + ("Host supports 1.8V signaling. Switch voltage!\n")); + done_ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; + done_ccb->ccb_h.flags = CAM_DIR_NONE; + done_ccb->ccb_h.retry_count = 0; + done_ccb->ccb_h.timeout = 100; + done_ccb->ccb_h.cbfcnp = NULL; + done_ccb->cts.proto_specific.mmc.ios.vccq = vccq_180; + done_ccb->cts.proto_specific.mmc.ios_valid = MMC_VCCQ; + xpt_action(done_ccb); + } } } else { CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, From fd7371f7e20010606e76ebd0fe9e609772ebbcf4 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Wed, 22 Jul 2020 19:08:05 +0000 Subject: [PATCH 103/287] mmccam: Add support for 1.2V and 1.8V eMMC If the card reports that it support 1.2V or 1.8V signaling switch to this voltage. Submitted by: kibab --- sys/cam/mmc/mmc_da.c | 75 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/sys/cam/mmc/mmc_da.c b/sys/cam/mmc/mmc_da.c index 6fd6e7b76e9a..3e407013d5cf 100644 --- a/sys/cam/mmc/mmc_da.c +++ b/sys/cam/mmc/mmc_da.c @@ -136,6 +136,9 @@ struct sdda_softc { /* Generic switch timeout */ uint32_t cmd6_time; + uint32_t timings; /* Mask of bus timings supported */ + uint32_t vccq_120; /* Mask of bus timings at VCCQ of 1.2 V */ + uint32_t vccq_180; /* Mask of bus timings at VCCQ of 1.8 V */ /* MMC partitions support */ struct sdda_part *part[MMC_PART_MAX]; uint8_t part_curr; /* Partition currently switched to */ @@ -1242,6 +1245,7 @@ sdda_start_init(void *context, union ccb *start_ccb) uint32_t sec_count; int err; int host_f_max; + uint8_t card_type; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sdda_start_init\n")); /* periph was held for us when this task was enqueued */ @@ -1370,12 +1374,35 @@ sdda_start_init(void *context, union ccb *start_ccb) } if (mmcp->card_features & CARD_FEATURE_MMC && mmc_get_spec_vers(periph) >= 4) { - if (softc->raw_ext_csd[EXT_CSD_CARD_TYPE] - & EXT_CSD_CARD_TYPE_HS_52) + card_type = softc->raw_ext_csd[EXT_CSD_CARD_TYPE]; + if (card_type & EXT_CSD_CARD_TYPE_HS_52) softc->card_f_max = MMC_TYPE_HS_52_MAX; - else if (softc->raw_ext_csd[EXT_CSD_CARD_TYPE] - & EXT_CSD_CARD_TYPE_HS_26) + else if (card_type & EXT_CSD_CARD_TYPE_HS_26) softc->card_f_max = MMC_TYPE_HS_26_MAX; + if ((card_type & EXT_CSD_CARD_TYPE_DDR_52_1_2V) != 0 && + (host_caps & MMC_CAP_SIGNALING_120) != 0) { + setbit(&softc->timings, bus_timing_mmc_ddr52); + setbit(&softc->vccq_120, bus_timing_mmc_ddr52); + CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Card supports DDR52 at 1.2V\n")); + } + if ((card_type & EXT_CSD_CARD_TYPE_DDR_52_1_8V) != 0 && + (host_caps & MMC_CAP_SIGNALING_180) != 0) { + setbit(&softc->timings, bus_timing_mmc_ddr52); + setbit(&softc->vccq_180, bus_timing_mmc_ddr52); + CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Card supports DDR52 at 1.8V\n")); + } + if ((card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) != 0 && + (host_caps & MMC_CAP_SIGNALING_120) != 0) { + setbit(&softc->timings, bus_timing_mmc_hs200); + setbit(&softc->vccq_120, bus_timing_mmc_hs200); + CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Card supports HS200 at 1.2V\n")); + } + if ((card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) != 0 && + (host_caps & MMC_CAP_SIGNALING_180) != 0) { + setbit(&softc->timings, bus_timing_mmc_hs200); + setbit(&softc->vccq_180, bus_timing_mmc_hs200); + CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Card supports HS200 at 1.8V\n")); + } } } int f_max; @@ -1391,6 +1418,46 @@ sdda_start_init(void *context, union ccb *start_ccb) f_max = 25000000; } } + /* If possible, set lower-level signaling */ + enum mmc_bus_timing timing; + /* FIXME: MMCCAM supports max. bus_timing_mmc_ddr52 at the moment. */ + for (timing = bus_timing_mmc_ddr52; timing > bus_timing_normal; timing--) { + if (isset(&softc->vccq_120, timing)) { + /* Set VCCQ = 1.2V */ + start_ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; + start_ccb->ccb_h.flags = CAM_DIR_NONE; + start_ccb->ccb_h.retry_count = 0; + start_ccb->ccb_h.timeout = 100; + start_ccb->ccb_h.cbfcnp = NULL; + cts->ios.vccq = vccq_120; + cts->ios_valid = MMC_VCCQ; + xpt_action(start_ccb); + break; + } else if (isset(&softc->vccq_180, timing)) { + /* Set VCCQ = 1.8V */ + start_ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; + start_ccb->ccb_h.flags = CAM_DIR_NONE; + start_ccb->ccb_h.retry_count = 0; + start_ccb->ccb_h.timeout = 100; + start_ccb->ccb_h.cbfcnp = NULL; + cts->ios.vccq = vccq_180; + cts->ios_valid = MMC_VCCQ; + xpt_action(start_ccb); + break; + } else { + /* Set VCCQ = 3.3V */ + start_ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; + start_ccb->ccb_h.flags = CAM_DIR_NONE; + start_ccb->ccb_h.retry_count = 0; + start_ccb->ccb_h.timeout = 100; + start_ccb->ccb_h.cbfcnp = NULL; + cts->ios.vccq = vccq_330; + cts->ios_valid = MMC_VCCQ; + xpt_action(start_ccb); + break; + } + } + /* Set frequency on the controller */ start_ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; start_ccb->ccb_h.flags = CAM_DIR_NONE; From ce53f590ca015b38ba58c35f023ae76360082fa6 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Wed, 22 Jul 2020 20:15:21 +0000 Subject: [PATCH 104/287] Untie nmi_handle_intr() from DEV_ISA. The only part of nmi_handle_intr() depending on ISA is isa_nmi(), which is already wrapped. Entering debugger on NMI does not really depend on ISA. MFC after: 2 weeks --- sys/amd64/amd64/trap.c | 4 ---- sys/i386/i386/trap.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 216cf15b0bf9..5ae1e7f3112b 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -350,11 +350,9 @@ trap(struct trapframe *frame) signo = SIGFPE; break; -#ifdef DEV_ISA case T_NMI: nmi_handle_intr(type, frame); return; -#endif case T_OFLOW: /* integer overflow fault */ ucode = FPE_INTOVF; @@ -580,11 +578,9 @@ trap(struct trapframe *frame) #endif break; -#ifdef DEV_ISA case T_NMI: nmi_handle_intr(type, frame); return; -#endif } trap_fatal(frame, 0); diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index ccf16bf009cd..dd1ea0d1907e 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -407,7 +407,6 @@ trap(struct trapframe *frame) signo = SIGFPE; break; -#ifdef DEV_ISA case T_NMI: #ifdef POWERFAIL_NMI #ifndef TIMER_FREQ @@ -423,7 +422,6 @@ trap(struct trapframe *frame) nmi_handle_intr(type, frame); return; #endif /* POWERFAIL_NMI */ -#endif /* DEV_ISA */ case T_OFLOW: /* integer overflow fault */ ucode = FPE_INTOVF; @@ -669,7 +667,6 @@ trap(struct trapframe *frame) #endif break; -#ifdef DEV_ISA case T_NMI: #ifdef POWERFAIL_NMI if (time_second - lastalert > 10) { @@ -682,7 +679,6 @@ trap(struct trapframe *frame) nmi_handle_intr(type, frame); return; #endif /* POWERFAIL_NMI */ -#endif /* DEV_ISA */ } trap_fatal(frame, eva); From d90b364147877f0fff25e98ec76d5042bd283c21 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Wed, 22 Jul 2020 21:44:51 +0000 Subject: [PATCH 105/287] Avoid reading one byte before the path buffer. This happens when there's only one component (e.g. "/foo"). This (mostly-harmless) bug has been present since June 1990 when it was commited to mountd.c SCCS version 5.9. Note: the bug is on the second changed line, the first line is changed for visual consistency. Reviewed by: cem, emaste, mckusick, rmacklem Found with: CHERI Obtained from: CheriBSD MFC after: 1 week Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25759 --- usr.sbin/mountd/mountd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c index ce059ca81f4e..00e554802f55 100644 --- a/usr.sbin/mountd/mountd.c +++ b/usr.sbin/mountd/mountd.c @@ -3155,9 +3155,9 @@ do_mount(struct exportlist *ep, struct grouplist *grp, uint64_t exflags, goto error_exit; } /* back up over the last component */ - while (*cp == '/' && cp > dirp) + while (cp > dirp && *cp == '/') cp--; - while (*(cp - 1) != '/' && cp > dirp) + while (cp > dirp && *(cp - 1) != '/') cp--; if (cp == dirp) { if (debug) From a1119d08b9ba9acbc64864c1ede1424046f1e68c Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Wed, 22 Jul 2020 22:51:14 +0000 Subject: [PATCH 106/287] Add missing space after switch. Reviewed by: br, emaste Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25778 --- sys/arm64/arm64/trap.c | 4 ++-- sys/riscv/riscv/trap.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c index 4e5f9e32b804..f56ce3e81877 100644 --- a/sys/arm64/arm64/trap.c +++ b/sys/arm64/arm64/trap.c @@ -341,7 +341,7 @@ do_el1h_sync(struct thread *td, struct trapframe *frame) break; } - switch(exception) { + switch (exception) { case EXCP_FP_SIMD: case EXCP_TRAP_FP: #ifdef VFP @@ -452,7 +452,7 @@ do_el0_sync(struct thread *td, struct trapframe *frame) "do_el0_sync: curthread: %p, esr %lx, elr: %lx, frame: %p", td, esr, frame->tf_elr, frame); - switch(exception) { + switch (exception) { case EXCP_FP_SIMD: case EXCP_TRAP_FP: #ifdef VFP diff --git a/sys/riscv/riscv/trap.c b/sys/riscv/riscv/trap.c index 6f9fa17f8f17..c9b6a1ea6f47 100644 --- a/sys/riscv/riscv/trap.c +++ b/sys/riscv/riscv/trap.c @@ -269,7 +269,7 @@ do_trap_supervisor(struct trapframe *frame) CTR3(KTR_TRAP, "do_trap_supervisor: curthread: %p, sepc: %lx, frame: %p", curthread, frame->tf_sepc, frame); - switch(exception) { + switch (exception) { case EXCP_FAULT_LOAD: case EXCP_FAULT_STORE: case EXCP_FAULT_FETCH: @@ -326,7 +326,7 @@ do_trap_user(struct trapframe *frame) CTR3(KTR_TRAP, "do_trap_user: curthread: %p, sepc: %lx, frame: %p", curthread, frame->tf_sepc, frame); - switch(exception) { + switch (exception) { case EXCP_FAULT_LOAD: case EXCP_FAULT_STORE: case EXCP_FAULT_FETCH: From 9516bcdfb49003824480d2fa88676c0a422afb67 Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Wed, 22 Jul 2020 23:33:37 +0000 Subject: [PATCH 107/287] Modify writing to mirrored pNFS DSs to prepare for use of ext_pgs mbufs. This patch modifies writing to mirrored pNFS DSs slightly so that there is only one m_copym() call for a mirrored pair instead of two of them. This call replaces the custom nfsm_copym() call, which is no longer needed and deleted by this patch. The patch does introduce a new nfsm_split() function that only calls m_split() for the non-ext_pgs case. The semantics of nfsm_uiombuflist() is changed to include code that nul pads the generated mbuf list. This was done by nfsm_copym() prior to this patch. The main reason for this change is that it allows the data to be a list of ext_pgs mbufs, since the m_copym() is for the entire mbuf list. This support will be added in a future commit. This patch only affects writing to mirrored flexible file layout pNFS servers. --- sys/fs/nfsclient/nfs_clcomsubs.c | 21 +++-- sys/fs/nfsclient/nfs_clrpcops.c | 151 +++++++++++++++++-------------- 2 files changed, 98 insertions(+), 74 deletions(-) diff --git a/sys/fs/nfsclient/nfs_clcomsubs.c b/sys/fs/nfsclient/nfs_clcomsubs.c index f7875ba501f2..440769fe0cc9 100644 --- a/sys/fs/nfsclient/nfs_clcomsubs.c +++ b/sys/fs/nfsclient/nfs_clcomsubs.c @@ -164,9 +164,9 @@ nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp) { char *uiocp; struct mbuf *mp, *mp2, *firstmp; - int xfer, left, mlen; + int i, left, mlen, rem, xfer; int uiosiz, clflg; - char *tcp; + char *mcp, *tcp; KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1")); @@ -179,7 +179,9 @@ nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp) else NFSMGET(mp); mp->m_len = 0; + mcp = mtod(mp, char *); firstmp = mp2 = mp; + rem = NFSM_RNDUP(siz) - siz; while (siz > 0) { left = uiop->uio_iov->iov_len; uiocp = uiop->uio_iov->iov_base; @@ -194,18 +196,18 @@ nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp) else NFSMGET(mp); mp->m_len = 0; + mcp = mtod(mp, char *); mp2->m_next = mp; mp2 = mp; mlen = M_TRAILINGSPACE(mp); } xfer = (left > mlen) ? mlen : left; if (uiop->uio_segflg == UIO_SYSSPACE) - NFSBCOPY(uiocp, mtod(mp, caddr_t) + - mp->m_len, xfer); + NFSBCOPY(uiocp, mcp, xfer); else - copyin(uiocp, mtod(mp, caddr_t) + - mp->m_len, xfer); + copyin(uiocp, mcp, xfer); mp->m_len += xfer; + mcp += xfer; left -= xfer; uiocp += xfer; uiop->uio_offset += xfer; @@ -217,6 +219,13 @@ nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp) uiop->uio_iov->iov_len -= uiosiz; siz -= uiosiz; } + if (rem > 0) { + KASSERT(rem <= M_TRAILINGSPACE(mp), + ("nfsm_uiombuflist: no space for padding")); + for (i = 0; i < rem; i++) + *mcp++ = '\0'; + mp->m_len += rem; + } if (cpp != NULL) *cpp = mtod(mp, caddr_t) + mp->m_len; if (mbp != NULL) diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index e2207696bc3f..35b4a44c2d7f 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -158,7 +158,6 @@ static int nfscl_dofflayoutio(vnode_t, struct uio *, int *, int *, int *, nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *, struct nfsclflayout *, uint64_t, uint64_t, int, int, struct mbuf *, struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *); -static struct mbuf *nfsm_copym(struct mbuf *, int, int); static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *, struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int, struct ucred *, NFSPROC_T *); @@ -220,6 +219,7 @@ static int nfsrpc_copyrpc(vnode_t, off_t, vnode_t, off_t, size_t *, struct nfsvattr *, int *, bool, int *, struct ucred *, NFSPROC_T *); static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *, int, struct nfsvattr *, int *, struct ucred *); +static struct mbuf *nfsm_split(struct mbuf *, uint64_t); int nfs_pnfsio(task_fn_t *, void *); @@ -5756,7 +5756,7 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, struct nfscllayout *layp; struct nfscldevinfo *dip; struct nfsclflayout *rflp; - struct mbuf *m; + struct mbuf *m, *m2; struct nfsclwritedsdorpc *drpc, *tdrpc; nfsv4stateid_t stateid; struct ucred *newcred; @@ -5870,6 +5870,13 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, } } for (i = firstmirror; i < mirrorcnt && error == 0; i++){ + m2 = NULL; + if (m != NULL && i < mirrorcnt - 1) + m2 = m_copym(m, 0, M_COPYALL, M_WAITOK); + else { + m2 = m; + m = NULL; + } if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) { dev = rflp->nfsfl_ffm[i].dev; dip = nfscl_getdevinfo(nmp->nm_clp, dev, @@ -5886,7 +5893,7 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, uiop, iomode, must_commit, &eof, &stateid, rwaccess, dip, layp, rflp, off, xfer, - i, docommit, m, tdrpc, + i, docommit, m2, tdrpc, newcred, p); else error = nfscl_doflayoutio(vp, @@ -5895,8 +5902,11 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, dip, layp, rflp, off, xfer, docommit, newcred, p); nfscl_reldevinfo(dip); - } else + } else { + if (m2 != NULL) + m_freem(m2); error = EIO; + } tdrpc++; } if (m != NULL) @@ -5961,38 +5971,6 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, return (error); } -/* - * Make a copy of the mbuf chain and add an mbuf for null padding, as required. - */ -static struct mbuf * -nfsm_copym(struct mbuf *m, int off, int xfer) -{ - struct mbuf *m2, *m3, *m4; - uint32_t *tl; - int rem; - - m2 = m_copym(m, off, xfer, M_WAITOK); - rem = NFSM_RNDUP(xfer) - xfer; - if (rem > 0) { - /* - * The zero padding to a multiple of 4 bytes is required by - * the XDR. So that the mbufs copied by reference aren't - * modified, add an mbuf with the zero'd bytes to the list. - * rem will be a maximum of 3, so one zero'd uint32_t is - * sufficient. - */ - m3 = m2; - while (m3->m_next != NULL) - m3 = m3->m_next; - NFSMGET(m4); - tl = mtod(m4, uint32_t *); - *tl = 0; - m4->m_len = rem; - m3->m_next = m4; - } - return (m2); -} - /* * Find a file layout that will handle the first bytes of the requested * range and return the information from it needed to the I/O operation. @@ -6148,17 +6126,17 @@ nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, uint64_t len, int mirror, int docommit, struct mbuf *mp, struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) { - uint64_t transfer, xfer; - int error, rel_off; + uint64_t xfer; + int error; struct nfsnode *np; struct nfsfh *fhp; struct nfsclds **dspp; struct ucred *tcred; - struct mbuf *m; + struct mbuf *m, *m2; + uint32_t copylen; np = VTONFS(vp); error = 0; - rel_off = 0; NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off, (uintmax_t)len); /* Loop around, doing I/O for each stripe unit. */ @@ -6176,14 +6154,31 @@ nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, } else tcred = cred; if (rwflag == NFSV4OPEN_ACCESSREAD) - transfer = dp->nfsdi_rsize; - else - transfer = dp->nfsdi_wsize; + copylen = dp->nfsdi_rsize; + else { + copylen = dp->nfsdi_wsize; + if (len > copylen && mp != NULL) { + /* + * When a mirrored configuration needs to do + * multiple writes to each mirror, all writes + * except the last one must be a multiple of + * 4 bytes. This is required so that the XDR + * does not need padding. + * If possible, clip the size to an exact + * multiple of the mbuf length, so that the + * split will be on an mbuf boundary. + */ + copylen &= 0xfffffffc; + if (copylen > mp->m_len) + copylen = copylen / mp->m_len * + mp->m_len; + } + } NFSLOCKNODE(np); np->n_flag |= NDSCOMMIT; NFSUNLOCKNODE(np); - if (len > transfer && docommit == 0) - xfer = transfer; + if (len > copylen && docommit == 0) + xfer = copylen; else xfer = len; if (docommit != 0) { @@ -6244,31 +6239,41 @@ nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, NFSUNLOCKCLSTATE(); } } else { - m = nfsm_copym(mp, rel_off, xfer); - NFSCL_DEBUG(4, "mcopy reloff=%d xfer=%jd\n", - rel_off, (uintmax_t)xfer); + m = mp; + if (xfer < len) { + /* The mbuf list must be split. */ + m2 = nfsm_split(mp, xfer); + if (m2 != NULL) + mp = m2; + else { + m_freem(mp); + error = EIO; + } + } + NFSCL_DEBUG(4, "mcopy len=%jd xfer=%jd\n", + (uintmax_t)len, (uintmax_t)xfer); /* - * Do the writes after the first loop iteration - * and the write for the last mirror via this + * Do last write to a mirrored DS with this * thread. - * This loop only iterates for small values - * of nfsdi_wsize, which may never occur in - * practice. However, the drpc is completely - * used by the first iteration and, as such, - * cannot be used after that. */ - if (mirror < flp->nfsfl_mirrorcnt - 1 && - rel_off == 0) - error = nfsio_writedsmir(vp, iomode, - must_commit, stateidp, *dspp, off, - xfer, fhp, m, dp->nfsdi_vers, - dp->nfsdi_minorvers, drpc, tcred, - p); - else - error = nfsrpc_writedsmir(vp, iomode, - must_commit, stateidp, *dspp, off, - xfer, fhp, m, dp->nfsdi_vers, - dp->nfsdi_minorvers, tcred, p); + if (error == 0) { + if (mirror < flp->nfsfl_mirrorcnt - 1) + error = nfsio_writedsmir(vp, + iomode, must_commit, + stateidp, *dspp, off, + xfer, fhp, m, + dp->nfsdi_vers, + dp->nfsdi_minorvers, drpc, + tcred, p); + else + error = nfsrpc_writedsmir(vp, + iomode, must_commit, + stateidp, *dspp, off, + xfer, fhp, m, + dp->nfsdi_vers, + dp->nfsdi_minorvers, tcred, + p); + } NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error); if (error != 0 && error != EACCES && error != ESTALE) { @@ -6283,7 +6288,6 @@ nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, if (error == 0) { len -= xfer; off += xfer; - rel_off += xfer; } if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) NFSFREECRED(tcred); @@ -8615,3 +8619,14 @@ nfsrpc_listextattr(vnode_t vp, uint64_t *cookiep, struct uio *uiop, return (error); } +/* + * Split an mbuf list. For non-M_EXTPG mbufs, just use m_split(). + */ +static struct mbuf * +nfsm_split(struct mbuf *mp, uint64_t xfer) +{ + struct mbuf *m; + + m = m_split(mp, xfer, M_WAITOK); + return (m); +} From 5a01eca698113fff3e75265e6d59023af47921d7 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Wed, 22 Jul 2020 23:35:41 +0000 Subject: [PATCH 108/287] Use SI_ORDER_(FOURTH|FIFTH) rather than bespoke versions. No functional change. When these SYSINITs were added these macros didn't exist. Reviewed by: imp Obtained from: CheriBSD MFC after: 1 week Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25758 --- sys/kern/init_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 0a6159a123b0..833228c50ed0 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -372,18 +372,18 @@ SYSINIT(version, SI_SUB_COPYRIGHT, SI_ORDER_THIRD, print_version, NULL); #ifdef WITNESS static char wit_warn[] = "WARNING: WITNESS option enabled, expect reduced performance.\n"; -SYSINIT(witwarn, SI_SUB_COPYRIGHT, SI_ORDER_THIRD + 1, +SYSINIT(witwarn, SI_SUB_COPYRIGHT, SI_ORDER_FOURTH, print_caddr_t, wit_warn); -SYSINIT(witwarn2, SI_SUB_LAST, SI_ORDER_THIRD + 1, +SYSINIT(witwarn2, SI_SUB_LAST, SI_ORDER_FOURTH, print_caddr_t, wit_warn); #endif #ifdef DIAGNOSTIC static char diag_warn[] = "WARNING: DIAGNOSTIC option enabled, expect reduced performance.\n"; -SYSINIT(diagwarn, SI_SUB_COPYRIGHT, SI_ORDER_THIRD + 2, +SYSINIT(diagwarn, SI_SUB_COPYRIGHT, SI_ORDER_FIFTH, print_caddr_t, diag_warn); -SYSINIT(diagwarn2, SI_SUB_LAST, SI_ORDER_THIRD + 2, +SYSINIT(diagwarn2, SI_SUB_LAST, SI_ORDER_FIFTH, print_caddr_t, diag_warn); #endif From e9b21d432bac9f7c95bd282cad6849ce28428aee Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Wed, 22 Jul 2020 23:39:58 +0000 Subject: [PATCH 109/287] Correct a type-mismatch between xdr_long and the variable "bad". Way back in r28911 (August 1997, CVS rev 1.22) we imported a NetBSD information leak fix via OpenBSD. Unfortunatly we failed to track the followup commit that fixed the type of the error code. Apply the change from int to long now. Reviewed by: emaste Found by: CHERI Obtained from: CheriBSD MFC after: 3 days Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25779 --- usr.sbin/mountd/mountd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c index 00e554802f55..55ae98d413db 100644 --- a/usr.sbin/mountd/mountd.c +++ b/usr.sbin/mountd/mountd.c @@ -1091,7 +1091,8 @@ mntsrv(struct svc_req *rqstp, SVCXPRT *transp) struct sockaddr *saddr; u_short sport; char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; - int bad = 0, defset, hostset; + int defset, hostset; + long bad = 0; sigset_t sighup_mask; int numsecflavors, *secflavorsp; From 91e04f9e7ab70771497040e53d2ad642a1926311 Mon Sep 17 00:00:00 2001 From: Michael Tuexen Date: Thu, 23 Jul 2020 01:35:24 +0000 Subject: [PATCH 110/287] Detect and handle an invalid reassembly constellation, which results in a memory leak. Thanks to Felix Weinrank for finding this issue using fuzz testing the userland stack. MFC after: 1 week --- sys/netinet/sctp_constants.h | 1 + sys/netinet/sctp_indata.c | 55 +++++++++++++++++++++--------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index f042531a7126..158d49a75a6b 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -795,6 +795,7 @@ __FBSDID("$FreeBSD$"); #define SCTP_LOC_34 0x00000022 #define SCTP_LOC_35 0x00000023 #define SCTP_LOC_36 0x00000024 +#define SCTP_LOC_37 0x00000025 /* Free assoc codes */ #define SCTP_NORMAL_PROC 0 diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index b34bf6e47f89..9f3bbe8a1b75 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -1567,6 +1567,15 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, chk->rec.data.fsn); TAILQ_FOREACH(at, &control->reasm, sctp_next) { if (SCTP_TSN_GT(at->rec.data.fsn, chk->rec.data.fsn)) { + if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { + /* Last not at the end? huh? */ + SCTPDBG(SCTP_DEBUG_XXX, + "Last fragment not last in list: -- abort\n"); + sctp_abort_in_reasm(stcb, control, + chk, abort_flag, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_14); + return; + } /* * This one in queue is bigger than the new * one, insert the new one before at. @@ -1597,7 +1606,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, at->rec.data.fsn); sctp_abort_in_reasm(stcb, control, chk, abort_flag, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_14); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_15); return; } } @@ -1751,7 +1760,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, * Need to send an abort since we had a empty data chunk. */ op_err = sctp_generate_no_user_data_cause(tsn); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_15; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return (0); @@ -1888,7 +1897,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, SCTP_SNPRINTF(msg, sizeof(msg), "Reassembly problem (MID=%8.8x)", mid); err_out: op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return (0); @@ -2023,7 +2032,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, (uint16_t)mid); } op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_18; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return (0); @@ -2597,7 +2606,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap) if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_18); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_19); } sctp_send_shutdown(stcb, ((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination)); @@ -2648,7 +2657,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap) * there are gaps or duplicates. */ sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_19); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); } } else { @@ -2750,7 +2759,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, SCTP_SNPRINTF(msg, sizeof(msg), "%s", "DATA chunk received when I-DATA was negotiated"); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_20; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21; sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); return (2); } @@ -2761,7 +2770,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, SCTP_SNPRINTF(msg, sizeof(msg), "%s", "I-DATA chunk received when DATA was negotiated"); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_22; sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); return (2); } @@ -2786,7 +2795,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, ch->chunk_type == SCTP_DATA ? "DATA" : "I-DATA", chk_length); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_22; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_23; sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); return (2); } @@ -2874,7 +2883,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, SCTP_SNPRINTF(msg, sizeof(msg), "Chunk of length %u", chk_length); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_23; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24; sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); return (2); } @@ -4025,7 +4034,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, "Cum ack %8.8x greater or equal than TSN %8.8x", cumack, send_s); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); return; } @@ -4201,7 +4210,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, net->dest_state &= ~SCTP_ADDR_PF; sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_25); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_26); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net); /* Done with this net */ @@ -4279,7 +4288,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_26); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_27); } } } @@ -4332,7 +4341,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, *abort_now = 1; /* XXX */ op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_27; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_28; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); return; } @@ -4548,7 +4557,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, "Cum ack %8.8x greater or equal than TSN %8.8x", cum_ack, send_s); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_28; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_29; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); return; } @@ -4580,7 +4589,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, /* stop any timers */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_29); + stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30); net->partial_bytes_acked = 0; net->flight_size = 0; } @@ -4780,14 +4789,14 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, if (net->new_pseudo_cumack) sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_30); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_31); } } else { if (accum_moved) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_31); + stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); } } } @@ -4950,7 +4959,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, net->dest_state &= ~SCTP_ADDR_PF; sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_33); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net); /* Done with this net */ @@ -4975,7 +4984,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, /* stop all timers */ sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_33); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_34); net->flight_size = 0; net->partial_bytes_acked = 0; } @@ -5013,7 +5022,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, *abort_now = 1; /* XXX */ op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_34; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_35; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); return; } @@ -5162,7 +5171,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_35); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_36); } } } @@ -5565,7 +5574,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, "New cum ack %8.8x too high, highest TSN %8.8x", new_cum_tsn, asoc->highest_tsn_inside_map); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_36; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_37; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); return; } From 126a2470b9b435d1883359013a5362c8791fca2e Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 23 Jul 2020 08:42:16 +0000 Subject: [PATCH 111/287] vm: annotate swap_reserved with __exclusive_cache_line The counter keeps being updated all the time and variables read afterwards share the cacheline. Note this still fundamentally does not scale and needs to be replaced, in the meantime gets a bandaid. brk1_processes -t 52 ops/s: before: 8598298 after: 9098080 --- sys/vm/swap_pager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c index 74f8ed08d2cd..287122dad34d 100644 --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -152,7 +152,7 @@ static int nswapdev; /* Number of swap devices */ int swap_pager_avail; static struct sx swdev_syscall_lock; /* serialize swap(on|off) */ -static u_long swap_reserved; +static __exclusive_cache_line u_long swap_reserved; static u_long swap_total; static int sysctl_page_shift(SYSCTL_HANDLER_ARGS); From dace381270e6745c6590a9dfca7f238c41aa951d Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 23 Jul 2020 14:03:24 +0000 Subject: [PATCH 112/287] ntb: Stop checking for failures from malloc(M_WAITOK). PR: 240545 Submitted by: Andrew Reiter Reviewed by: cem, mav MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25768 --- sys/dev/ntb/test/ntb_tool.c | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/sys/dev/ntb/test/ntb_tool.c b/sys/dev/ntb/test/ntb_tool.c index c147e9a20385..fc8dd9673108 100644 --- a/sys/dev/ntb/test/ntb_tool.c +++ b/sys/dev/ntb/test/ntb_tool.c @@ -619,10 +619,6 @@ tool_mw_write_fn(struct sysctl_oid *oidp, struct sysctl_req *req, write: data_buf_size = *buf_size; data_buf = malloc(data_buf_size, M_NTB_TOOL, M_WAITOK | M_ZERO); - if (!data_buf) { - rc = ENOMEM; - goto out; - } if (s_pflag) memset(data_buf, pattern, data_buf_size); @@ -677,7 +673,7 @@ sysctl_local_port_number(SYSCTL_HANDLER_ARGS) return (rc); } -static int +static void tool_init_peers(struct tool_ctx *tc) { int pidx; @@ -685,14 +681,10 @@ tool_init_peers(struct tool_ctx *tc) tc->peer_cnt = ntb_peer_port_count(tc->dev); tc->peers = malloc(tc->peer_cnt * sizeof(*tc->peers), M_NTB_TOOL, M_WAITOK | M_ZERO); - if (tc->peers == NULL) - return (ENOMEM); for (pidx = 0; pidx < tc->peer_cnt; pidx++) { tc->peers[pidx].pidx = pidx; tc->peers[pidx].tc = tc; } - - return (0); } static void @@ -1016,8 +1008,6 @@ tool_init_mws(struct tool_ctx *tc) tc->peers[pidx].inmws = malloc(tc->peers[pidx].inmw_cnt * sizeof(*tc->peers[pidx].inmws), M_NTB_TOOL, M_WAITOK | M_ZERO); - if (tc->peers[pidx].inmws == NULL) - return (ENOMEM); for (widx = 0; widx < tc->peers[pidx].inmw_cnt; widx++) { mw = &tc->peers[pidx].inmws[widx]; @@ -1219,7 +1209,7 @@ sysctl_peer_spad_handle(SYSCTL_HANDLER_ARGS) return (rc); } -static int +static void tool_init_spads(struct tool_ctx *tc) { int sidx, pidx; @@ -1228,8 +1218,6 @@ tool_init_spads(struct tool_ctx *tc) tc->inspad_cnt = ntb_spad_count(tc->dev); tc->inspads = malloc(tc->inspad_cnt * sizeof(*tc->inspads), M_NTB_TOOL, M_WAITOK | M_ZERO); - if (tc->inspads == NULL) - return (ENOMEM); for (sidx = 0; sidx < tc->inspad_cnt; sidx++) { tc->inspads[sidx].sidx = sidx; @@ -1243,8 +1231,6 @@ tool_init_spads(struct tool_ctx *tc) tc->peers[pidx].outspads = malloc(tc->peers[pidx].outspad_cnt * sizeof(*tc->peers[pidx].outspads), M_NTB_TOOL, M_WAITOK | M_ZERO); - if (tc->peers[pidx].outspads == NULL) - return (ENOMEM); for (sidx = 0; sidx < tc->peers[pidx].outspad_cnt; sidx++) { tc->peers[pidx].outspads[sidx].sidx = sidx; @@ -1252,8 +1238,6 @@ tool_init_spads(struct tool_ctx *tc) tc->peers[pidx].outspads[sidx].tc = tc; } } - - return (0); } static void @@ -1450,17 +1434,13 @@ ntb_tool_attach(device_t dev) if (rc) goto out; - rc = tool_init_peers(tc); - if (rc) - goto err_clear_data; + tool_init_peers(tc); rc = tool_init_mws(tc); if (rc) goto err_clear_data; - rc = tool_init_spads(tc); - if (rc) - goto err_clear_mws; + tool_init_spads(tc); rc = tool_init_ntb(tc); if (rc) @@ -1472,7 +1452,6 @@ ntb_tool_attach(device_t dev) err_clear_spads: tool_clear_spads(tc); -err_clear_mws: tool_clear_mws(tc); tool_clear_peers(tc); err_clear_data: From cbef26ed161718002e5cb7e0eefd57c5c0c2b08d Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 23 Jul 2020 14:03:37 +0000 Subject: [PATCH 113/287] cuse: Stop checking for failures from malloc(M_WAITOK). PR: 240545 Submitted by: Andrew Reiter Reviewed by: hselasky MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25765 --- sys/fs/cuse/cuse.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/sys/fs/cuse/cuse.c b/sys/fs/cuse/cuse.c index 90c292d17551..0409585d0179 100644 --- a/sys/fs/cuse/cuse.c +++ b/sys/fs/cuse/cuse.c @@ -425,8 +425,6 @@ cuse_server_alloc_memory(struct cuse_server *pcs, uint32_t alloc_nr, int error; mem = malloc(sizeof(*mem), M_CUSE, M_WAITOK | M_ZERO); - if (mem == NULL) - return (ENOMEM); object = vm_pager_allocate(OBJT_SWAP, NULL, PAGE_SIZE * page_count, VM_PROT_DEFAULT, 0, curthread->td_ucred); @@ -748,8 +746,6 @@ cuse_server_open(struct cdev *dev, int fflags, int devtype, struct thread *td) struct cuse_server *pcs; pcs = malloc(sizeof(*pcs), M_CUSE, M_WAITOK | M_ZERO); - if (pcs == NULL) - return (ENOMEM); if (devfs_set_cdevpriv(pcs, &cuse_server_free)) { printf("Cuse: Cannot set cdevpriv.\n"); @@ -1217,10 +1213,6 @@ cuse_server_ioctl(struct cdev *dev, unsigned long cmd, pcsd = malloc(sizeof(*pcsd), M_CUSE, M_WAITOK | M_ZERO); - if (pcsd == NULL) { - error = ENOMEM; - break; - } pcsd->server = pcs; pcsd->user_dev = pcd->dev; @@ -1430,11 +1422,6 @@ cuse_client_open(struct cdev *dev, int fflags, int devtype, struct thread *td) } pcc = malloc(sizeof(*pcc), M_CUSE, M_WAITOK | M_ZERO); - if (pcc == NULL) { - /* drop reference on server */ - cuse_server_unref(pcs); - return (ENOMEM); - } if (devfs_set_cdevpriv(pcc, &cuse_client_free)) { printf("Cuse: Cannot set cdevpriv.\n"); /* drop reference on server */ From 4cbba6ae2464c05639e152c3782bef735b8fbd1f Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 23 Jul 2020 14:21:45 +0000 Subject: [PATCH 114/287] MFOpenZFS: Fix zpool history unbounded memory usage In original implementation, zpool history will read the whole history before printing anything, causing memory usage goes unbounded. We fix this by breaking it into read-print iterations. Reviewed-by: Tom Caputi Reviewed-by: Matt Ahrens Reviewed-by: Igor Kozhukhov Reviewed-by: Brian Behlendorf Signed-off-by: Chunwei Chen Closes #9516 Note, this change changes the libzfs.so ABI by modifying the prototype of zpool_get_history(). Since libzfs is effectively private to the base system it is anticipated that this will not be a problem. PR: 247557 Obtained from: OpenZFS Reported and tested by: Sam Vaughan Discussed with: freqlabs MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D25745 openzfs/zfs@7125a109dcc55628336ff3f58e59e503f4d7694d --- .../opensolaris/cmd/zpool/zpool_main.c | 44 ++++++++++++------- .../opensolaris/lib/libzfs/common/libzfs.h | 3 +- .../lib/libzfs/common/libzfs_pool.c | 20 +++++---- 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c index 414f26756acd..35c3db7893df 100644 --- a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c +++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c @@ -6226,24 +6226,12 @@ typedef struct hist_cbdata { boolean_t internal; } hist_cbdata_t; -/* - * Print out the command history for a specific pool. - */ -static int -get_history_one(zpool_handle_t *zhp, void *data) +static void +print_history_records(nvlist_t *nvhis, hist_cbdata_t *cb) { - nvlist_t *nvhis; nvlist_t **records; uint_t numrecords; - int ret, i; - hist_cbdata_t *cb = (hist_cbdata_t *)data; - - cb->first = B_FALSE; - - (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); - - if ((ret = zpool_get_history(zhp, &nvhis)) != 0) - return (ret); + int i; verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, &records, &numrecords) == 0); @@ -6344,8 +6332,32 @@ get_history_one(zpool_handle_t *zhp, void *data) (void) printf("]"); (void) printf("\n"); } +} + +/* + * Print out the command history for a specific pool. + */ +static int +get_history_one(zpool_handle_t *zhp, void *data) +{ + nvlist_t *nvhis; + int ret; + hist_cbdata_t *cb = (hist_cbdata_t *)data; + uint64_t off = 0; + boolean_t eof = B_FALSE; + + cb->first = B_FALSE; + + (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); + + while (!eof) { + if ((ret = zpool_get_history(zhp, &nvhis, &off, &eof)) != 0) + return (ret); + + print_history_records(nvhis, cb); + nvlist_free(nvhis); + } (void) printf("\n"); - nvlist_free(nvhis); return (ret); } diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h index 7be49cb7e4e0..469d61f5e773 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h @@ -441,7 +441,8 @@ typedef enum { extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *, int name_flags); extern int zpool_upgrade(zpool_handle_t *, uint64_t); -extern int zpool_get_history(zpool_handle_t *, nvlist_t **); +extern int zpool_get_history(zpool_handle_t *, nvlist_t **, uint64_t *, + boolean_t *); extern int zpool_history_unpack(char *, uint64_t, uint64_t *, nvlist_t ***, uint_t *); extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *, diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c index c2dac2362f10..39b6c35f6fbd 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c @@ -4124,33 +4124,37 @@ zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, * Retrieve the command history of a pool. */ int -zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) +zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp, uint64_t *off, + boolean_t *eof) { char *buf; uint64_t buflen = HIS_BUF_LEN_DEF; - uint64_t off = 0; nvlist_t **records = NULL; uint_t numrecords = 0; int err, i; + uint64_t start = *off; buf = malloc(buflen); if (buf == NULL) return (ENOMEM); - do { + /* process about 1MB at a time */ + while (*off - start < 1024 * 1024) { uint64_t bytes_read = buflen; uint64_t leftover; - if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0) + if ((err = get_history(zhp, buf, off, &bytes_read)) != 0) break; /* if nothing else was read in, we're at EOF, just return */ - if (bytes_read == 0) + if (bytes_read == 0) { + *eof = B_TRUE; break; + } if ((err = zpool_history_unpack(buf, bytes_read, &leftover, &records, &numrecords)) != 0) break; - off -= leftover; + *off -= leftover; if (leftover == bytes_read) { /* * no progress made, because buffer is not big enough @@ -4165,9 +4169,7 @@ zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp) break; } } - - /* CONSTCOND */ - } while (1); + } free(buf); From 81614d236f6817d4ceb587c70fa4eb4318588431 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Thu, 23 Jul 2020 14:33:25 +0000 Subject: [PATCH 115/287] Add missing newlines. MFC after: 3 days --- sbin/nvmecontrol/identify.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sbin/nvmecontrol/identify.c b/sbin/nvmecontrol/identify.c index f3c488281fcd..04aff36917ac 100644 --- a/sbin/nvmecontrol/identify.c +++ b/sbin/nvmecontrol/identify.c @@ -151,15 +151,15 @@ print_namespace(struct nvme_namespace_data *nsdata) uint128_to_str(to128(nsdata->nvmcap), cbuf, sizeof(cbuf))); if ((nsdata->nsfeat >> NVME_NS_DATA_NSFEAT_NPVALID_SHIFT) & NVME_NS_DATA_NSFEAT_NPVALID_MASK) { - printf("Preferred Write Granularity: %u blocks", + printf("Preferred Write Granularity: %u blocks\n", nsdata->npwg + 1); - printf("Preferred Write Alignment: %u blocks", + printf("Preferred Write Alignment: %u blocks\n", nsdata->npwa + 1); - printf("Preferred Deallocate Granul: %u blocks", + printf("Preferred Deallocate Granul: %u blocks\n", nsdata->npdg + 1); - printf("Preferred Deallocate Align: %u blocks", + printf("Preferred Deallocate Align: %u blocks\n", nsdata->npda + 1); - printf("Optimal Write Size: %u blocks", + printf("Optimal Write Size: %u blocks\n", nsdata->nows + 1); } printf("Globally Unique Identifier: "); From 7df88b9ddd2e7db27ab71d38db8d0d6b4ad31e51 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 23 Jul 2020 15:03:28 +0000 Subject: [PATCH 116/287] rc.firewall: Merge two identical conditions into one. No functional change intended. PR: 247949 Submitted by: Jose Luis Duran MFC after: 1 week --- libexec/rc/rc.firewall | 3 --- 1 file changed, 3 deletions(-) diff --git a/libexec/rc/rc.firewall b/libexec/rc/rc.firewall index 8389d76c5cc6..ee08a3252566 100644 --- a/libexec/rc/rc.firewall +++ b/libexec/rc/rc.firewall @@ -222,9 +222,6 @@ case ${firewall_type} in if [ -n "$net6" ]; then ${fwcmd} add pass all from me to ${net6} ${fwcmd} add pass all from ${net6} to me - fi - - if [ -n "$net6" ]; then # Allow any link-local multicast traffic ${fwcmd} add pass all from fe80::/10 to ff02::/16 ${fwcmd} add pass all from ${net6} to ff02::/16 From e605dcc939848312a201b4aa53bd7bb67d862b18 Mon Sep 17 00:00:00 2001 From: Doug Moore Date: Thu, 23 Jul 2020 17:16:20 +0000 Subject: [PATCH 117/287] Rank balanced (RB) trees are a class of balanced trees that includes AVL trees, red-black trees, and others. Weak AVL (wavl) trees are a recently discovered member of that class. This change replaces red-black rebalancing with weak AVL rebalancing in the RB tree macros. Wavl trees sit between AVL and red-black trees in terms of how strictly balance is enforced. They have the stricter balance of AVL trees as the tree is built - a wavl tree is an AVL tree until the first deletion. Once removals start, wavl trees are lazier about rebalancing than AVL trees, so that removals can be fast, but the balance of the tree can decay to that of a red-black tree. Subsequent insertions can push balance back toward the stricter AVL conditions. Removing a node from a wavl tree never requires more than two rotations, which is better than either red-black or AVL trees. Inserting a node into a wavl tree never requires more than two rotations, which matches red-black and AVL trees. The only disadvantage of wavl trees to red-black trees is that more insertions are likely to adjust the tree a bit. That's the cost of keeping the tree more balanced. Testing has shown that for the cases where red-black trees do worst, wavl trees better balance leads to faster lookups, so that if lookups outnumber insertions by a nontrivial amount, lookup time saved exceeds the extra cost of balancing. Reviewed by: alc, gbe, markj Tested by: pho Discussed with: emaste Differential Revision: https://reviews.freebsd.org/D25480 --- share/man/man3/tree.3 | 59 +++++---- sys/sys/tree.h | 275 +++++++++++++++++++++--------------------- 2 files changed, 170 insertions(+), 164 deletions(-) diff --git a/share/man/man3/tree.3 b/share/man/man3/tree.3 index 671774aa4b8f..e6ecc6e44237 100644 --- a/share/man/man3/tree.3 +++ b/share/man/man3/tree.3 @@ -99,7 +99,7 @@ .Nm RB_INSERT , .Nm RB_REMOVE , .Nm RB_REINSERT -.Nd "implementations of splay and red-black trees" +.Nd "implementations of splay and rank-balanced (wavl) trees" .Sh SYNOPSIS .In sys/tree.h .Fn SPLAY_PROTOTYPE NAME TYPE FIELD CMP @@ -195,7 +195,7 @@ .Fn RB_REINSERT NAME "RB_HEAD *head" "struct TYPE *elm" .Sh DESCRIPTION These macros define data structures for different types of trees: -splay trees and red-black trees. +splay trees and rank-balanced (wavl) trees. .Pp In the macro definitions, .Fa TYPE @@ -364,26 +364,26 @@ macro: The .Fn SPLAY_EMPTY macro should be used to check whether a splay tree is empty. -.Sh RED-BLACK TREES -A red-black tree is a binary search tree with the node color as an -extra attribute. -It fulfills a set of conditions: -.Bl -enum -offset indent -.It -Every search path from the root to a leaf consists of the same number of -black nodes. -.It -Each red node (except for the root) has a black parent. -.It -Each leaf node is black. -.El +.Sh RANK-BALANCED TREES +Rank-balanced (RB) trees are a framework for defining height-balanced +binary search trees, including AVL and red-black trees. +Each tree node has an associated rank. +Balance conditions are expressed by conditions on the differences in +rank between any node and its children. +Rank differences are stored in each tree node. +.Pp +The balance conditions implemented by the RB macros lead to weak AVL +(wavl) trees, which combine the best aspects of AVL and red-black +trees. +Wavl trees rebalance after an insertion in the same way AVL trees do, +with the same worst-case time as red-black trees offer, and with +better balance in the resulting tree. +Wavl trees rebalance after a removal in a way that requires less +restructuring, in the worst case, than either AVL or red-black trees +do. Removals can lead to a tree almost as unbalanced as a red-black +tree; insertions lead to a tree becoming as balanced as an AVL tree. .Pp -Every operation on a red-black tree is bounded as -.Fn O "lg n" . -The maximum height of a red-black tree is -.Fn 2lg "n + 1" . -.Pp -A red-black tree is headed by a structure defined by the +A rank-balanced tree is headed by a structure defined by the .Fn RB_HEAD macro. A @@ -488,7 +488,7 @@ The macro initializes the tree referenced by .Fa head . .Pp -The red-black tree can also be initialized statically by using the +The rank-balanced tree can also be initialized statically by using the .Fn RB_INITIALIZER macro like this: .Bd -ragged -offset indent @@ -567,7 +567,7 @@ and will be overwritten to provide safe traversal. .Pp The .Fn RB_EMPTY -macro should be used to check whether a red-black tree is empty. +macro should be used to check whether a rank-balanced tree is empty. .Pp The .Fn RB_REINSERT @@ -581,7 +581,7 @@ a node's key. This is a lower overhead alternative to removing the element and reinserting it again. .Sh EXAMPLES -The following example demonstrates how to declare a red-black tree +The following example demonstrates how to declare a rank-balanced tree holding integers. Values are inserted into it and the contents of the tree are printed in order. @@ -697,6 +697,17 @@ to indicate an error. .Sh SEE ALSO .Xr arb 3 , .Xr queue 3 +.Rs +.%A "Bernhard Haeupler" +.%A "Siddhartha Sen" +.%A "Robert E. Tarjan" +.%T "Rank-Balanced Trees" +.%U "http://sidsen.azurewebsites.net/papers/rb-trees-talg.pdf" +.%J "ACM Transactions on Algorithms" +.%V "11" +.%N "4" +.%D "June 2015" +.Re .Sh HISTORY The tree macros first appeared in .Fx 4.6 . diff --git a/sys/sys/tree.h b/sys/sys/tree.h index dae592ad7375..7fa7806c9a91 100644 --- a/sys/sys/tree.h +++ b/sys/sys/tree.h @@ -36,7 +36,7 @@ /* * This file defines data structures for different types of trees: - * splay trees and red-black trees. + * splay trees and rank-balanced trees. * * A splay tree is a self-organizing data structure. Every operation * on the tree causes a splay to happen. The splay moves the requested @@ -50,15 +50,24 @@ * and n inserts on an initially empty tree as O((m + n)lg n). The * amortized cost for a sequence of m accesses to a splay tree is O(lg n); * - * A red-black tree is a binary search tree with the node color as an - * extra attribute. It fulfills a set of conditions: - * - every search path from the root to a leaf consists of the - * same number of black nodes, - * - each red node (except for the root) has a black parent, - * - each leaf node is black. + * A rank-balanced tree is a binary search tree with an integer + * rank-difference as an attribute of each pointer from parent to child. + * The sum of the rank-differences on any path from a node down to null is + * the same, and defines the rank of that node. The rank of the null node + * is -1. * - * Every operation on a red-black tree is bounded as O(lg n). - * The maximum height of a red-black tree is 2lg (n+1). + * Different additional conditions define different sorts of balanced + * trees, including "red-black" and "AVL" trees. The set of conditions + * applied here are the "weak-AVL" conditions of Haeupler, Sen and Tarjan: + * - every rank-difference is 1 or 2. + * - the rank of any leaf is 1. + * + * For historical reasons, rank differences that are even are associated + * with the color red (Rank-Even-Difference), and the child that a red edge + * points to is called a red child. + * + * Every operation on a rank-balanced tree is bounded as O(lg n). + * The maximum height of a rank-balanced tree is 2lg (n+1). */ #define SPLAY_HEAD(name, type) \ @@ -294,7 +303,7 @@ void name##_SPLAY_MINMAX(struct name *head, int __comp) \ (x) != NULL; \ (x) = SPLAY_NEXT(name, head, x)) -/* Macros that define a red-black tree */ +/* Macros that define a rank-balanced tree */ #define RB_HEAD(name, type) \ struct name { \ struct type *rbh_root; /* root of the tree */ \ @@ -325,25 +334,16 @@ struct { \ * that the left or right child of the tree node is "red". */ #define RB_UP(elm, field) (elm)->field.rbe_parent -#define RB_BITS(elm, field) *(__uintptr_t *)&RB_UP(elm, field) -#define RB_RED_L (__uintptr_t)1 -#define RB_RED_R (__uintptr_t)2 -#define RB_RED_MASK (__uintptr_t)3 +#define RB_BITS(elm, field) (*(__uintptr_t *)&RB_UP(elm, field)) +#define RB_RED_L ((__uintptr_t)1) +#define RB_RED_R ((__uintptr_t)2) +#define RB_RED_MASK ((__uintptr_t)3) #define RB_FLIP_LEFT(elm, field) (RB_BITS(elm, field) ^= RB_RED_L) #define RB_FLIP_RIGHT(elm, field) (RB_BITS(elm, field) ^= RB_RED_R) #define RB_RED_LEFT(elm, field) ((RB_BITS(elm, field) & RB_RED_L) != 0) #define RB_RED_RIGHT(elm, field) ((RB_BITS(elm, field) & RB_RED_R) != 0) #define RB_PARENT(elm, field) ((__typeof(RB_UP(elm, field))) \ (RB_BITS(elm, field) & ~RB_RED_MASK)) - -/* - * This header may appear in user code where 'bool' is not defined, - * so it defines its own boolean type to avoid breaking that code. - */ -#define RB_BOOL int -#define RB_TRUE 1 -#define RB_FALSE 0 - #define RB_ROOT(head) (head)->rbh_root #define RB_EMPTY(head) (RB_ROOT(head) == NULL) @@ -357,7 +357,7 @@ struct { \ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ } while (/*CONSTCOND*/ 0) -#define RB_COLOR(elm, field) (RB_PARENT(elm, field) == NULL ? RB_FALSE : \ +#define RB_COLOR(elm, field) (RB_PARENT(elm, field) == NULL ? 0 : \ RB_LEFT(RB_PARENT(elm, field), field) == elm ? \ RB_RED_LEFT(RB_PARENT(elm, field), field) : \ RB_RED_RIGHT(RB_PARENT(elm, field), field)) @@ -422,7 +422,8 @@ struct { \ #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 *) + 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) \ @@ -464,123 +465,132 @@ struct { \ attr void \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ { \ - struct type *gparent, *parent; \ + struct type *child, *parent; \ while ((parent = RB_PARENT(elm, field)) != NULL) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_FLIP_LEFT(parent, field); \ - else \ - RB_FLIP_RIGHT(parent, field); \ - if ((gparent = RB_PARENT(parent, field)) == NULL) \ - break; \ - if (RB_RED_LEFT(gparent, field) && \ - RB_RED_RIGHT(gparent, field)) { \ - RB_FLIP_LEFT(gparent, field); \ - RB_FLIP_RIGHT(gparent, field); \ - elm = gparent; \ - continue; \ - } \ - if (RB_RED_LEFT(gparent, field) && \ - parent == RB_LEFT(gparent, field)) { \ - if (RB_RIGHT(parent, field) == elm) { \ - RB_ROTATE_LEFT(head, parent, elm, field);\ - RB_FLIP_RIGHT(parent, field); \ - RB_FLIP_LEFT(elm, field); \ - parent = elm; \ - } \ - RB_ROTATE_RIGHT(head, gparent, parent, field); \ - RB_FLIP_LEFT(gparent, field); \ - RB_FLIP_RIGHT(parent, field); \ - } else if (RB_RED_RIGHT(gparent, field) && \ - parent == RB_RIGHT(gparent, field)) { \ - if (RB_LEFT(parent, field) == elm) { \ - RB_ROTATE_RIGHT(head, parent, elm, field);\ + if (RB_LEFT(parent, field) == elm) { \ + if (RB_RED_LEFT(parent, field)) { \ RB_FLIP_LEFT(parent, field); \ - RB_FLIP_RIGHT(elm, field); \ - parent = elm; \ + return; \ + } \ + RB_FLIP_RIGHT(parent, field); \ + if (RB_RED_RIGHT(parent, field)) { \ + elm = parent; \ + continue; \ + } \ + if (!RB_RED_RIGHT(elm, field)) { \ + RB_FLIP_LEFT(elm, field); \ + RB_ROTATE_LEFT(head, elm, child, field);\ + if (RB_RED_LEFT(child, field)) \ + RB_FLIP_RIGHT(elm, field); \ + else if (RB_RED_RIGHT(child, field)) \ + RB_FLIP_LEFT(parent, field); \ + elm = child; \ + } \ + RB_ROTATE_RIGHT(head, parent, elm, field); \ + } else { \ + if (RB_RED_RIGHT(parent, field)) { \ + RB_FLIP_RIGHT(parent, field); \ + return; \ } \ - RB_ROTATE_LEFT(head, gparent, parent, field); \ - RB_FLIP_RIGHT(gparent, field); \ RB_FLIP_LEFT(parent, field); \ + if (RB_RED_LEFT(parent, field)) { \ + elm = parent; \ + continue; \ + } \ + if (!RB_RED_LEFT(elm, field)) { \ + RB_FLIP_RIGHT(elm, field); \ + RB_ROTATE_RIGHT(head, elm, child, field);\ + if (RB_RED_RIGHT(child, field)) \ + RB_FLIP_LEFT(elm, field); \ + else if (RB_RED_LEFT(child, field)) \ + RB_FLIP_RIGHT(parent, field); \ + elm = child; \ + } \ + RB_ROTATE_LEFT(head, parent, elm, field); \ } \ + RB_BITS(elm, field) &= ~RB_RED_MASK; \ break; \ } \ } #define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ attr void \ -name##_RB_REMOVE_COLOR(struct name *head, struct type *par) \ +name##_RB_REMOVE_COLOR(struct name *head, \ + struct type *parent, struct type *elm) \ { \ - struct type *gpr, *sib, *nec; \ - RB_BOOL left_elm, left_par, red_gpr; \ - left_par = (RB_LEFT(par, field) == NULL); \ - do { \ - left_elm = left_par; \ - if (left_elm ? \ - !RB_RED_RIGHT(par, field) : \ - !RB_RED_LEFT(par, field)) { \ - gpr = RB_PARENT(par, field); \ - left_par = gpr != NULL && \ - RB_LEFT(gpr, field) == par; \ - red_gpr = gpr == NULL ? \ - RB_TRUE: RB_COLOR(par, field); \ - } \ - if (left_elm) { \ - if (RB_RED_RIGHT(par, field)) { \ - red_gpr = RB_TRUE; \ - RB_ROTATE_LEFT(head, par, gpr, field); \ - RB_FLIP_RIGHT(par, field); \ - RB_FLIP_LEFT(gpr, field); \ + struct type *sib; \ + if (RB_LEFT(parent, field) == elm && \ + RB_RIGHT(parent, field) == elm) { \ + RB_BITS(parent, field) &= ~RB_RED_MASK; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + if (parent == NULL) \ + return; \ + } \ + do { \ + if (RB_LEFT(parent, field) == elm) { \ + if (!RB_RED_LEFT(parent, field)) { \ + RB_FLIP_LEFT(parent, field); \ + return; \ } \ - sib = RB_RIGHT(par, field); \ - if (RB_RED_RIGHT(sib, field)) { \ - if (RB_RED_LEFT(sib, field)) { \ + if (RB_RED_RIGHT(parent, field)) { \ + RB_FLIP_RIGHT(parent, field); \ + elm = parent; \ + continue; \ + } \ + sib = RB_RIGHT(parent, field); \ + if ((~RB_BITS(sib, field) & RB_RED_MASK) == 0) {\ + RB_BITS(sib, field) &= ~RB_RED_MASK; \ + elm = parent; \ + continue; \ + } \ + RB_FLIP_RIGHT(sib, field); \ + if (RB_RED_LEFT(sib, field)) \ + RB_FLIP_LEFT(parent, field); \ + else if (!RB_RED_RIGHT(sib, field)) { \ + RB_FLIP_LEFT(parent, field); \ + RB_ROTATE_RIGHT(head, sib, elm, field); \ + if (RB_RED_RIGHT(elm, field)) \ RB_FLIP_LEFT(sib, field); \ - RB_FLIP_RIGHT(par, field); \ - } \ - RB_FLIP_RIGHT(sib, field); \ - } else if (RB_RED_LEFT(sib, field)) { \ - RB_ROTATE_RIGHT(head, sib, nec, field); \ - RB_FLIP_LEFT(sib, field); \ - sib = nec; \ - } else { \ - RB_FLIP_RIGHT(par, field); \ - par = gpr; \ - continue; \ + if (RB_RED_LEFT(elm, field)) \ + RB_FLIP_RIGHT(parent, field); \ + RB_BITS(elm, field) |= RB_RED_MASK; \ + sib = elm; \ } \ - RB_ROTATE_LEFT(head, par, sib, field); \ - return; \ + RB_ROTATE_LEFT(head, parent, sib, field); \ } else { \ - if (RB_RED_LEFT(par, field)) { \ - red_gpr = RB_TRUE; \ - RB_ROTATE_RIGHT(head, par, gpr, field); \ - RB_FLIP_LEFT(par, field); \ - RB_FLIP_RIGHT(gpr, field); \ + if (!RB_RED_RIGHT(parent, field)) { \ + RB_FLIP_RIGHT(parent, field); \ + return; \ } \ - sib = RB_LEFT(par, field); \ - if (RB_RED_LEFT(sib, field)) { \ - if (RB_RED_RIGHT(sib, field)) { \ - RB_FLIP_RIGHT(sib, field); \ - RB_FLIP_LEFT(par, field); \ - } \ - RB_FLIP_LEFT(sib, field); \ - } else if (RB_RED_RIGHT(sib, field)) { \ - RB_ROTATE_LEFT(head, sib, nec, field); \ - RB_FLIP_RIGHT(sib, field); \ - sib = nec; \ - } else { \ - RB_FLIP_LEFT(par, field); \ - par = gpr; \ + if (RB_RED_LEFT(parent, field)) { \ + RB_FLIP_LEFT(parent, field); \ + elm = parent; \ continue; \ } \ - RB_ROTATE_RIGHT(head, par, sib, field); \ - return; \ + sib = RB_LEFT(parent, field); \ + if ((~RB_BITS(sib, field) & RB_RED_MASK) == 0) {\ + RB_BITS(sib, field) &= ~RB_RED_MASK; \ + elm = parent; \ + continue; \ + } \ + RB_FLIP_LEFT(sib, field); \ + if (RB_RED_RIGHT(sib, field)) \ + RB_FLIP_RIGHT(parent, field); \ + else if (!RB_RED_LEFT(sib, field)) { \ + RB_FLIP_RIGHT(parent, field); \ + RB_ROTATE_LEFT(head, sib, elm, field); \ + if (RB_RED_LEFT(elm, field)) \ + RB_FLIP_RIGHT(sib, field); \ + if (RB_RED_RIGHT(elm, field)) \ + RB_FLIP_LEFT(parent, field); \ + RB_BITS(elm, field) |= RB_RED_MASK; \ + sib = elm; \ + } \ + RB_ROTATE_RIGHT(head, parent, sib, field); \ } \ - } while (!red_gpr); \ - if (gpr == NULL); \ - else if (left_par) \ - RB_FLIP_LEFT(gpr, field); \ - else \ - RB_FLIP_RIGHT(gpr, field); \ + break; \ + } while ((parent = RB_PARENT(elm, field)) != NULL); \ } #define RB_GENERATE_REMOVE(name, type, field, attr) \ @@ -588,7 +598,6 @@ attr struct type * \ name##_RB_REMOVE(struct name *head, struct type *elm) \ { \ struct type *child, *old, *parent, *right; \ - RB_BOOL red; \ \ old = elm; \ parent = RB_PARENT(elm, field); \ @@ -600,9 +609,6 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \ else { \ if ((child = RB_LEFT(right, field)) == NULL) { \ child = RB_RIGHT(right, field); \ - red = RB_RED_RIGHT(old, field); \ - if (red) \ - RB_FLIP_RIGHT(old, field); \ RB_RIGHT(old, field) = child; \ parent = elm = right; \ } else { \ @@ -611,28 +617,17 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \ while ((child = RB_LEFT(elm, field)) != NULL); \ child = RB_RIGHT(elm, field); \ parent = RB_PARENT(elm, field); \ - red = RB_RED_LEFT(parent, field); \ - if (red) \ - RB_FLIP_LEFT(parent, field); \ RB_LEFT(parent, field) = child; \ - RB_SET_PARENT(RB_RIGHT(old, field), elm, field); \ + RB_SET_PARENT(RB_RIGHT(old, field), elm, field);\ } \ RB_SET_PARENT(RB_LEFT(old, field), elm, field); \ elm->field = old->field; \ } \ - if (elm == child) { \ - red = RB_COLOR(old, field); \ - if (!red); \ - else if (RB_LEFT(parent, field) == old) \ - RB_FLIP_LEFT(parent, field); \ - else \ - RB_FLIP_RIGHT(parent, field); \ - } \ RB_SWAP_CHILD(head, old, elm, field); \ if (child != NULL) \ RB_SET_PARENT(child, parent, field); \ - else if (!red && parent != NULL) \ - name##_RB_REMOVE_COLOR(head, parent); \ + if (parent != NULL) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ while (parent != NULL) { \ RB_AUGMENT(parent); \ parent = RB_PARENT(parent, field); \ From c795344ff71ff37ee942ac1ace3705a58a9d9ad8 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 23 Jul 2020 17:26:53 +0000 Subject: [PATCH 118/287] locks: fix a long standing bug for primitives with kdtrace but without spinning In such a case the second argument to lock_delay_arg_init was NULL which was immediately causing a null pointer deref. Since the sructure is only used for spin count, provide a dedicate routine initializing it. Reported by: andrew --- sys/kern/kern_mutex.c | 2 +- sys/kern/kern_rwlock.c | 4 ++-- sys/kern/kern_sx.c | 4 ++-- sys/sys/lock.h | 7 +++++++ 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/sys/kern/kern_mutex.c b/sys/kern/kern_mutex.c index 125ff9397783..13a04a5c8d12 100644 --- a/sys/kern/kern_mutex.c +++ b/sys/kern/kern_mutex.c @@ -538,7 +538,7 @@ __mtx_lock_sleep(volatile uintptr_t *c, uintptr_t v) #if defined(ADAPTIVE_MUTEXES) lock_delay_arg_init(&lda, &mtx_delay); #elif defined(KDTRACE_HOOKS) - lock_delay_arg_init(&lda, NULL); + lock_delay_arg_init_noadapt(&lda); #endif if (__predict_false(v == MTX_UNOWNED)) diff --git a/sys/kern/kern_rwlock.c b/sys/kern/kern_rwlock.c index 4d1f314c09d3..2489d029cbb3 100644 --- a/sys/kern/kern_rwlock.c +++ b/sys/kern/kern_rwlock.c @@ -475,7 +475,7 @@ __rw_rlock_hard(struct rwlock *rw, struct thread *td, uintptr_t v #if defined(ADAPTIVE_RWLOCKS) lock_delay_arg_init(&lda, &rw_delay); #elif defined(KDTRACE_HOOKS) - lock_delay_arg_init(&lda, NULL); + lock_delay_arg_init_noadapt(&lda); #endif #ifdef HWPMC_HOOKS @@ -951,7 +951,7 @@ __rw_wlock_hard(volatile uintptr_t *c, uintptr_t v LOCK_FILE_LINE_ARG_DEF) #if defined(ADAPTIVE_RWLOCKS) lock_delay_arg_init(&lda, &rw_delay); #elif defined(KDTRACE_HOOKS) - lock_delay_arg_init(&lda, NULL); + lock_delay_arg_init_noadapt(&lda); #endif if (__predict_false(v == RW_UNLOCKED)) v = RW_READ_VALUE(rw); diff --git a/sys/kern/kern_sx.c b/sys/kern/kern_sx.c index a016d8c5e964..d1c6cd38886d 100644 --- a/sys/kern/kern_sx.c +++ b/sys/kern/kern_sx.c @@ -623,7 +623,7 @@ _sx_xlock_hard(struct sx *sx, uintptr_t x, int opts LOCK_FILE_LINE_ARG_DEF) #if defined(ADAPTIVE_SX) lock_delay_arg_init(&lda, &sx_delay); #elif defined(KDTRACE_HOOKS) - lock_delay_arg_init(&lda, NULL); + lock_delay_arg_init_noadapt(&lda); #endif if (__predict_false(x == SX_LOCK_UNLOCKED)) @@ -1063,7 +1063,7 @@ _sx_slock_hard(struct sx *sx, int opts, uintptr_t x LOCK_FILE_LINE_ARG_DEF) #if defined(ADAPTIVE_SX) lock_delay_arg_init(&lda, &sx_delay); #elif defined(KDTRACE_HOOKS) - lock_delay_arg_init(&lda, NULL); + lock_delay_arg_init_noadapt(&lda); #endif #ifdef HWPMC_HOOKS diff --git a/sys/sys/lock.h b/sys/sys/lock.h index 9dd4e642f320..e682f590985c 100644 --- a/sys/sys/lock.h +++ b/sys/sys/lock.h @@ -195,6 +195,13 @@ lock_delay_arg_init(struct lock_delay_arg *la, struct lock_delay_config *lc) la->spin_cnt = 0; } +static inline void +lock_delay_arg_init_noadapt(struct lock_delay_arg *la) +{ + la->delay = 0; + la->spin_cnt = 0; +} + #define lock_delay_spin(n) do { \ u_int _i; \ \ From 795be686d8c4cbacd2c78a773b1bf2a98dfa61f3 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Thu, 23 Jul 2020 17:39:45 +0000 Subject: [PATCH 119/287] Load ipfilter, ipnat, and ippool rules, and start ipmon in a vnet jail. PR: 248109 Reported by: joeb1@a1poweruser.com MFC after: 2 weeks --- libexec/rc/rc.d/ipfilter | 2 +- libexec/rc/rc.d/ipmon | 2 +- libexec/rc/rc.d/ipnat | 2 +- libexec/rc/rc.d/ippool | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libexec/rc/rc.d/ipfilter b/libexec/rc/rc.d/ipfilter index 5c1a86876d6c..6a430b55d897 100755 --- a/libexec/rc/rc.d/ipfilter +++ b/libexec/rc/rc.d/ipfilter @@ -5,7 +5,7 @@ # PROVIDE: ipfilter # REQUIRE: FILESYSTEMS -# KEYWORD: nojail +# KEYWORD: nojailvnet . /etc/rc.subr diff --git a/libexec/rc/rc.d/ipmon b/libexec/rc/rc.d/ipmon index 17d46b1a66f2..a742daa363d5 100755 --- a/libexec/rc/rc.d/ipmon +++ b/libexec/rc/rc.d/ipmon @@ -6,7 +6,7 @@ # PROVIDE: ipmon # REQUIRE: FILESYSTEMS hostname sysctl ipfilter # BEFORE: SERVERS -# KEYWORD: nojail +# KEYWORD: nojailvnet . /etc/rc.subr diff --git a/libexec/rc/rc.d/ipnat b/libexec/rc/rc.d/ipnat index 6914bceaf466..bff94154dc65 100755 --- a/libexec/rc/rc.d/ipnat +++ b/libexec/rc/rc.d/ipnat @@ -5,7 +5,7 @@ # PROVIDE: ipnat # REQUIRE: ipfilter -# KEYWORD: nojail +# KEYWORD: nojailvnet . /etc/rc.subr diff --git a/libexec/rc/rc.d/ippool b/libexec/rc/rc.d/ippool index 33c93190db64..5cca6b939c67 100755 --- a/libexec/rc/rc.d/ippool +++ b/libexec/rc/rc.d/ippool @@ -6,7 +6,7 @@ # PROVIDE: ippool # REQUIRE: FILESYSTEMS # BEFORE: ipfilter -# KEYWORD: nojail +# KEYWORD: nojailvnet . /etc/rc.subr From f0276e8c38175617e45fb26a106b75a0680dfa1e Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Thu, 23 Jul 2020 17:39:49 +0000 Subject: [PATCH 120/287] Document the IPFILTER_PREDEFINED environment variable. PR: 248088 Reported by: joeb1@a1poweruser.com MFC after: 1 week --- contrib/ipfilter/man/ipf.8 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/contrib/ipfilter/man/ipf.8 b/contrib/ipfilter/man/ipf.8 index afd3c61fea9d..3a84e7776b47 100644 --- a/contrib/ipfilter/man/ipf.8 +++ b/contrib/ipfilter/man/ipf.8 @@ -158,6 +158,15 @@ display the statistics prior to them being zeroed. Zero global statistics held in the kernel for filtering only (this doesn't affect fragment or state statistics). .DT +.SH ENVIRONMENT +.NM utilizes the following environment variable. +.TP +.B IPF_PREDEFINED +ipfilter variables, see VARIABLES in ipf(5), can be specified in this +environment variable providing shell access to ipfilter and ipnat variables. +For example, +.br +IPF_PREDEFINED='my_server="10.1.1.1"; my_client="10.1.1.2";' .SH FILES /dev/ipauth .br From 0d2c19d05b7c6a96a04b465d759bc0ab49afb7b1 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Thu, 23 Jul 2020 18:55:47 +0000 Subject: [PATCH 121/287] libmd: temporarily disable optimized assembly skein1024 implementation It is apparently broken when assembled by contemporary GNU as as well as Clang IAS (which is used in the default configuration). PR: 248221 Reported by: pizzamig Sponsored by: The FreeBSD Foundation --- lib/libmd/Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/libmd/Makefile b/lib/libmd/Makefile index e001bb428d3c..cc464a1a46bf 100644 --- a/lib/libmd/Makefile +++ b/lib/libmd/Makefile @@ -116,12 +116,12 @@ CFLAGS+= -DSHA1_ASM SRCS+= rmd160.S CFLAGS+= -DRMD160_ASM .endif -.if exists(${MACHINE_ARCH}/skein_block_asm.S) -# Fully unroll all loops in the assembly optimized version -ACFLAGS+= -DSKEIN_LOOP=0 -SRCS+= skein_block_asm.S -CFLAGS+= -DSKEIN_ASM -DSKEIN_USE_ASM=1792 # list of block functions to replace with assembly: 256+512+1024 = 1792 -.endif +#.if exists(${MACHINE_ARCH}/skein_block_asm.S) +## Fully unroll all loops in the assembly optimized version +#ACFLAGS+= -DSKEIN_LOOP=0 +#SRCS+= skein_block_asm.S +#CFLAGS+= -DSKEIN_ASM -DSKEIN_USE_ASM=1792 # list of block functions to replace with assembly: 256+512+1024 = 1792 +#.endif .if exists(${MACHINE_ARCH}/sha.S) || exists(${MACHINE_ARCH}/rmd160.S) || exists(${MACHINE_ARCH}/skein_block_asm.S) ACFLAGS+= -DELF -Wa,--noexecstack .endif From e32e86852841c9b5fd2bcaa740f0f22cfaa3b3e5 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Thu, 23 Jul 2020 19:19:33 +0000 Subject: [PATCH 122/287] modules/crypto: disable optimized assembly skein1024 implementation It is presumably broken in the same way as userland skein1024 (see r363454) PR: 248221 --- sys/modules/crypto/Makefile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sys/modules/crypto/Makefile b/sys/modules/crypto/Makefile index 28243fa9245c..8af02c35ce0e 100644 --- a/sys/modules/crypto/Makefile +++ b/sys/modules/crypto/Makefile @@ -28,14 +28,14 @@ SRCS += sha1.c sha256c.c sha512c.c SRCS += skein.c skein_block.c # unroll the 256 and 512 loops, half unroll the 1024 CFLAGS.skein_block.c += -DSKEIN_LOOP=995 -.if exists(${MACHINE_ARCH}/skein_block_asm.S) -.PATH: ${SRCTOP}/sys/crypto/skein/${MACHINE_ARCH} -SRCS += skein_block_asm.S -CFLAGS += -DSKEIN_ASM -DSKEIN_USE_ASM=1792 # list of block functions to replace with assembly: 256+512+1024 = 1792 -ACFLAGS += -DELF -Wa,--noexecstack -# Fully unroll all loops in the assembly optimized version -ACFLAGS += -DSKEIN_LOOP=0 -.endif +#.if exists(${MACHINE_ARCH}/skein_block_asm.S) +#.PATH: ${SRCTOP}/sys/crypto/skein/${MACHINE_ARCH} +#SRCS += skein_block_asm.S +#CFLAGS += -DSKEIN_ASM -DSKEIN_USE_ASM=1792 # list of block functions to replace with assembly: 256+512+1024 = 1792 +#ACFLAGS += -DELF -Wa,--noexecstack +## Fully unroll all loops in the assembly optimized version +#ACFLAGS += -DSKEIN_LOOP=0 +#.endif SRCS += siphash.c SRCS += gmac.c gfmult.c SRCS += blake2b-ref.c From 205f3e15972cbb40aa0024355ffe1a62e581191a Mon Sep 17 00:00:00 2001 From: Michael Tuexen Date: Thu, 23 Jul 2020 19:43:49 +0000 Subject: [PATCH 123/287] Clear the pointer to the socket when closing it also in case of an ungraceful operation. This fixes a use-after-free bug found and reported by Taylor Brandstetter of Google by testing the userland stack. MFC after: 1 week --- sys/netinet/sctp_pcb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index fc5e2356ba8a..73926f2b4cb7 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -3545,6 +3545,11 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) cnt = 0; LIST_FOREACH_SAFE(asoc, &inp->sctp_asoc_list, sctp_tcblist, nasoc) { SCTP_TCB_LOCK(asoc); + if (immediate != SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE) { + /* Disconnect the socket please */ + asoc->sctp_socket = NULL; + SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_CLOSED_SOCKET); + } if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { if (asoc->asoc.state & SCTP_STATE_IN_ACCEPT_QUEUE) { SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_IN_ACCEPT_QUEUE); From af9de844c469b06654065bc88a6ea147a5b617ac Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Thu, 23 Jul 2020 20:06:24 +0000 Subject: [PATCH 124/287] md5: return non-zero if built-in tests (-x) fail MFC after: 1 week Sponsored by: The FreeBSD Foundation --- sbin/md5/md5.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sbin/md5/md5.c b/sbin/md5/md5.c index d2f2c0ee2911..96dfcede9711 100644 --- a/sbin/md5/md5.c +++ b/sbin/md5/md5.c @@ -498,10 +498,12 @@ MDTestSuite(const Algorithm_t *alg) for (i = 0; i < MDTESTCOUNT; i++) { (*alg->Data)(MDTestInput[i], strlen(MDTestInput[i]), buffer); printf("%s (\"%s\") = %s", alg->name, MDTestInput[i], buffer); - if (strcmp(buffer, (*alg->TestOutput)[i]) == 0) + if (strcmp(buffer, (*alg->TestOutput)[i]) == 0) { printf(" - verified correct\n"); - else + } else { printf(" - INCORRECT RESULT!\n"); + failed++; + } } } From 6273c7420de94ecf8b921816a98ce075f414a1a6 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 23 Jul 2020 20:08:42 +0000 Subject: [PATCH 125/287] Set si_addr to badvaddr for TLB faults. Reviewed by: kib Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25775 --- sys/mips/mips/trap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c index 52e0708740a7..26f7c1515818 100644 --- a/sys/mips/mips/trap.c +++ b/sys/mips/mips/trap.c @@ -740,7 +740,7 @@ trap(struct trapframe *trapframe) } goto err; } - addr = trapframe->pc; + addr = trapframe->badvaddr; msg = "BAD_PAGE_FAULT"; log_bad_page_fault(msg, trapframe, type); From e7aaabe15e697e804bb446b90a54b56857d6f10b Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 23 Jul 2020 21:33:10 +0000 Subject: [PATCH 126/287] Pass the right size to memcpy() when copying the array of FP registers. The size of the containing structure was passed instead of the size of the array. This happened to be harmless as the extra word copied is one we copy in the next line anyway. Reported by: CHERI (bounds check violation) Reviewed by: brooks, imp Obtained from: CheriBSD MFC after: 1 week Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25791 --- sys/riscv/riscv/machdep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/riscv/riscv/machdep.c b/sys/riscv/riscv/machdep.c index 6b42e9b4b8bc..5b49cc9ae3c3 100644 --- a/sys/riscv/riscv/machdep.c +++ b/sys/riscv/riscv/machdep.c @@ -419,7 +419,7 @@ get_fpcontext(struct thread *td, mcontext_t *mcp) KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0, ("Non-userspace FPE flags set in get_fpcontext")); memcpy(mcp->mc_fpregs.fp_x, curpcb->pcb_x, - sizeof(mcp->mc_fpregs)); + sizeof(mcp->mc_fpregs.fp_x)); mcp->mc_fpregs.fp_fcsr = curpcb->pcb_fcsr; mcp->mc_fpregs.fp_flags = curpcb->pcb_fpflags; mcp->mc_flags |= _MC_FP_VALID; @@ -446,7 +446,7 @@ set_fpcontext(struct thread *td, mcontext_t *mcp) curpcb = curthread->td_pcb; /* FPE usage is enabled, override registers. */ memcpy(curpcb->pcb_x, mcp->mc_fpregs.fp_x, - sizeof(mcp->mc_fpregs)); + sizeof(mcp->mc_fpregs.fp_x)); curpcb->pcb_fcsr = mcp->mc_fpregs.fp_fcsr; curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags & PCB_FP_USERMASK; td->td_frame->tf_sstatus |= SSTATUS_FS_CLEAN; From d7d14db9c51e2effbd012c442a540bc84af1b549 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 23 Jul 2020 21:40:03 +0000 Subject: [PATCH 127/287] Set si_trapno to the exception code from esr. Reviewed by: kib Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25771 --- sys/arm64/arm64/trap.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c index f56ce3e81877..9856a35d0010 100644 --- a/sys/arm64/arm64/trap.c +++ b/sys/arm64/arm64/trap.c @@ -104,7 +104,7 @@ static abort_handler *abort_handlers[] = { }; static __inline void -call_trapsignal(struct thread *td, int sig, int code, void *addr) +call_trapsignal(struct thread *td, int sig, int code, void *addr, int trapno) { ksiginfo_t ksi; @@ -112,6 +112,7 @@ call_trapsignal(struct thread *td, int sig, int code, void *addr) ksi.ksi_signo = sig; ksi.ksi_code = code; ksi.ksi_addr = addr; + ksi.ksi_trapno = trapno; trapsignal(td, &ksi); } @@ -161,7 +162,8 @@ svc_handler(struct thread *td, struct trapframe *frame) syscallenter(td); syscallret(td); } else { - call_trapsignal(td, SIGILL, ILL_ILLOPN, (void *)frame->tf_elr); + call_trapsignal(td, SIGILL, ILL_ILLOPN, (void *)frame->tf_elr, + ESR_ELx_EXCEPTION(frame->tf_esr)); userret(td, frame); } } @@ -177,7 +179,8 @@ align_abort(struct thread *td, struct trapframe *frame, uint64_t esr, panic("Misaligned access from kernel space!"); } - call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr); + call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr, + ESR_ELx_EXCEPTION(frame->tf_esr)); userret(td, frame); } @@ -261,7 +264,8 @@ data_abort(struct thread *td, struct trapframe *frame, uint64_t esr, error = vm_fault_trap(map, far, ftype, VM_FAULT_NORMAL, &sig, &ucode); if (error != KERN_SUCCESS) { if (lower) { - call_trapsignal(td, sig, ucode, (void *)far); + call_trapsignal(td, sig, ucode, (void *)far, + ESR_ELx_EXCEPTION(esr)); } else { if (td->td_intr_nesting_level == 0 && pcb->pcb_onfault != 0) { @@ -483,24 +487,29 @@ do_el0_sync(struct thread *td, struct trapframe *frame) break; case EXCP_UNKNOWN: if (!undef_insn(0, frame)) - call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)far); + call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)far, + exception); userret(td, frame); break; case EXCP_SP_ALIGN: - call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_sp); + call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_sp, + exception); userret(td, frame); break; case EXCP_PC_ALIGN: - call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr); + call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr, + exception); userret(td, frame); break; case EXCP_BRKPT_EL0: case EXCP_BRK: - call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr); + call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr, + exception); userret(td, frame); break; case EXCP_MSR: - call_trapsignal(td, SIGILL, ILL_PRVOPC, (void *)frame->tf_elr); + call_trapsignal(td, SIGILL, ILL_PRVOPC, (void *)frame->tf_elr, + exception); userret(td, frame); break; case EXCP_SOFTSTP_EL0: @@ -509,11 +518,12 @@ do_el0_sync(struct thread *td, struct trapframe *frame) WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) & ~DBG_MDSCR_SS); call_trapsignal(td, SIGTRAP, TRAP_TRACE, - (void *)frame->tf_elr); + (void *)frame->tf_elr, exception); userret(td, frame); break; default: - call_trapsignal(td, SIGBUS, BUS_OBJERR, (void *)frame->tf_elr); + call_trapsignal(td, SIGBUS, BUS_OBJERR, (void *)frame->tf_elr, + exception); userret(td, frame); break; } From 70d1a4351aa7475d403d933c0af6029a8113c617 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 23 Jul 2020 21:43:06 +0000 Subject: [PATCH 128/287] Consolidate duplicated code into a ktls_ocf_dispatch function. This function manages the loop around crypto_dispatch and coordination with ktls_ocf_callback. Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D25757 --- sys/opencrypto/ktls_ocf.c | 88 ++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 52 deletions(-) diff --git a/sys/opencrypto/ktls_ocf.c b/sys/opencrypto/ktls_ocf.c index aab3d98bf5b1..c08913d92535 100644 --- a/sys/opencrypto/ktls_ocf.c +++ b/sys/opencrypto/ktls_ocf.c @@ -100,6 +100,40 @@ ktls_ocf_callback(struct cryptop *crp) return (0); } +static int +ktls_ocf_dispatch(struct ocf_session *os, struct cryptop *crp) +{ + struct ocf_operation oo; + int error; + + oo.os = os; + oo.done = false; + + crp->crp_opaque = &oo; + crp->crp_callback = ktls_ocf_callback; + for (;;) { + error = crypto_dispatch(crp); + if (error) + break; + + mtx_lock(&os->lock); + while (!oo.done) + mtx_sleep(&oo, &os->lock, 0, "ocfktls", 0); + mtx_unlock(&os->lock); + + if (crp->crp_etype != EAGAIN) { + error = crp->crp_etype; + break; + } + + crp->crp_etype = 0; + crp->crp_flags &= ~CRYPTO_F_DONE; + oo.done = false; + counter_u64_add(ocf_retries, 1); + } + return (error); +} + static int ktls_ocf_tls12_gcm_encrypt(struct ktls_session *tls, const struct tls_record_layer *hdr, uint8_t *trailer, struct iovec *iniov, @@ -110,7 +144,6 @@ ktls_ocf_tls12_gcm_encrypt(struct ktls_session *tls, struct tls_aead_data ad; struct cryptop crp; struct ocf_session *os; - struct ocf_operation oo; struct iovec iov[iovcnt + 1]; int i, error; uint16_t tls_comp_len; @@ -118,9 +151,6 @@ ktls_ocf_tls12_gcm_encrypt(struct ktls_session *tls, os = tls->cipher; - oo.os = os; - oo.done = false; - uio.uio_iov = iniov; uio.uio_iovcnt = iovcnt; uio.uio_offset = 0; @@ -180,34 +210,13 @@ ktls_ocf_tls12_gcm_encrypt(struct ktls_session *tls, crypto_use_uio(&crp, &uio); if (!inplace) crypto_use_output_uio(&crp, &out_uio); - crp.crp_opaque = &oo; - crp.crp_callback = ktls_ocf_callback; counter_u64_add(ocf_tls12_gcm_crypts, 1); if (inplace) counter_u64_add(ocf_inplace, 1); else counter_u64_add(ocf_separate_output, 1); - for (;;) { - error = crypto_dispatch(&crp); - if (error) - break; - - mtx_lock(&os->lock); - while (!oo.done) - mtx_sleep(&oo, &os->lock, 0, "ocfktls", 0); - mtx_unlock(&os->lock); - - if (crp.crp_etype != EAGAIN) { - error = crp.crp_etype; - break; - } - - crp.crp_etype = 0; - crp.crp_flags &= ~CRYPTO_F_DONE; - oo.done = false; - counter_u64_add(ocf_retries, 1); - } + error = ktls_ocf_dispatch(os, &crp); crypto_destroyreq(&crp); return (error); @@ -223,16 +232,12 @@ ktls_ocf_tls13_gcm_encrypt(struct ktls_session *tls, char nonce[12]; struct cryptop crp; struct ocf_session *os; - struct ocf_operation oo; struct iovec iov[iovcnt + 1], out_iov[iovcnt + 1]; int i, error; bool inplace; os = tls->cipher; - oo.os = os; - oo.done = false; - crypto_initreq(&crp, os->sid); /* Setup the nonce. */ @@ -294,8 +299,6 @@ ktls_ocf_tls13_gcm_encrypt(struct ktls_session *tls, crp.crp_op = CRYPTO_OP_ENCRYPT | CRYPTO_OP_COMPUTE_DIGEST; crp.crp_flags = CRYPTO_F_CBIMM | CRYPTO_F_IV_SEPARATE; - crp.crp_opaque = &oo; - crp.crp_callback = ktls_ocf_callback; memcpy(crp.crp_iv, nonce, sizeof(nonce)); @@ -304,26 +307,7 @@ ktls_ocf_tls13_gcm_encrypt(struct ktls_session *tls, counter_u64_add(ocf_inplace, 1); else counter_u64_add(ocf_separate_output, 1); - for (;;) { - error = crypto_dispatch(&crp); - if (error) - break; - - mtx_lock(&os->lock); - while (!oo.done) - mtx_sleep(&oo, &os->lock, 0, "ocfktls", 0); - mtx_unlock(&os->lock); - - if (crp.crp_etype != EAGAIN) { - error = crp.crp_etype; - break; - } - - crp.crp_etype = 0; - crp.crp_flags &= ~CRYPTO_F_DONE; - oo.done = false; - counter_u64_add(ocf_retries, 1); - } + error = ktls_ocf_dispatch(os, &crp); crypto_destroyreq(&crp); return (error); From 98b765e5c28aa451b82a377bc69283120cd924fa Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Thu, 23 Jul 2020 22:28:35 +0000 Subject: [PATCH 129/287] update example to make it active when creating a new boot method... Clean up some of the sentences and grammar... make igor happy.. --- usr.sbin/efibootmgr/efibootmgr.8 | 70 ++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/usr.sbin/efibootmgr/efibootmgr.8 b/usr.sbin/efibootmgr/efibootmgr.8 index a36d642e85df..3bd476231dbb 100644 --- a/usr.sbin/efibootmgr/efibootmgr.8 +++ b/usr.sbin/efibootmgr/efibootmgr.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 24, 2019 +.Dd July 23, 2020 .Dt EFIBOOTMGR 8 .Os .Sh NAME @@ -66,28 +66,34 @@ .Nm .Fl T .Sh "DESCRIPTION" +The .Nm -manipulates how UEFI Boot Managers boot the system. -Methods of booting can be created and destroyed. -Boot methods can be activated or deactivated. -The order of boot methods tried can be changed. -Temporary boot methods can override the usual booting methods. +program manipulates how UEFI Boot Managers boot the system. +It can create and destroy methods for booting along with activating or +deactivating them. +It can also change the defined order of boot methods. +It can create a temporary boot (BootNext) variable that references a +boot method to be tried once upon the next boot. .Pp The UEFI standard defines how hosts may control what is used to bootstrap the system. Each method is encapsulated within a persistent UEFI variable, stored by the UEFI BIOS of the form -.Cm Boot Ns Em XXXX . -These variables are numbered, describe where to load the bootstrap -program from, and whether or not the method is active. -The boot order of these methods is controlled by another variable +.Cm Boot Ns Em XXXX +(where XXXX are uppercase hexadecimal digits). +These variables are numbered, each describing where to load the bootstrap +program from, and whether or not the method is active (used for booting, +otherwise the method will be skipped). +The order of these methods is controlled by another variable, .Cm BootOrder . -The currently booting method is communicated using +The currently booted method is communicated using .Cm BootCurrent . A global timeout can also be set. .Pp .Nm -requires that the kernel efirt module be loaded to get and set these +requires that the kernel module +.Xr efirt 9 +module be present or loaded to get and set these non-volatile variables. .Pp The following options are available: @@ -113,7 +119,7 @@ boot entry. .It Fl c -create Create a new .Cm Boot -variable. +variable (aka method or entry). .It Fl D -dry-run Process but do not change any variables. .It Fl E -esp @@ -136,7 +142,7 @@ The path to and name of the kernel. .It Fl l -loader Ar loader The path to and name of the loader. .It Fl L -label Ar label -An optional description for the entry. +An optional description for the method. .It Fl n -bootnext Set .Ar bootnum @@ -169,32 +175,36 @@ To display the current .Cm Boot related variables in the system: .Pp -.Dl efibootmgr [-v] +.Dl efibootmgr -v .Pp This will display the optional .Cm BootNext -bootnum, -.Cm BootCurrent , -or currently booted bootnum, followed by the optional +(if present), +.Cm BootCurrent +(currently booted method), followed by the optional .Cm Timeout value, any .Cm BootOrder that may be set, followed finally by all currently defined .Cm Boot variables, active or not. -The verbose flag will augment this output with the disk partition uuids, +The verbose flag, +.Pq Fl v , +augments this output with the disk partition uuids, size/offset and device-path of the variable. +The flag will also include any unreferenced (by BootOrder) variables. .Pp The .Nm program can be used to create new EFI boot variables. -To create a new boot var pointing to an installation with its EFI partition -mounted under +The following command may be used to create a new boot method, using +the EFI partition mounted under .Pa /mnt , -the given loader and a label +mark the method active, using +the given loader and label the method .Qq FreeBSD-11 : .Pp -.Dl efibootmgr -c -l /mnt/EFI/freebsd/loader.efi -L FreeBSD-11 +.Dl efibootmgr -a -c -l /mnt/EFI/freebsd/loader.efi -L FreeBSD-11 .Pp This will result in the next available bootnum being assigned to a new UEFI boot variable, and given the label @@ -203,8 +213,11 @@ such as: .Pp .Dl Boot0009 FreeBSD-11 .Pp -Note newly created boot entries are created inactive. -The active state is denoted by an '*' following the +Note newly created boot entries are, by default, created inactive, hence +the reason +.Fl a +flag is specified above so that it will be considered for booting. +The active state is denoted by a '*' following the .Cm Boot Ns Em XXXX name in the output. They are also inserted into the first position of current @@ -217,7 +230,7 @@ booting from, else they are ignored. .Pp Will delete the given boot entry Boot0009. .Pp -To set a given newly created boot entry active use: +To set the given boot entry active: .Pp .Dl efibootmgr -a -b 0009 .Pp @@ -233,6 +246,11 @@ for the next reboot use: .Pp .Dl efibootmgr -o 0009,0003,... .Sh SEE ALSO +.Xr efirt 9 , .Xr efivar 8 , .Xr gpart 8 , .Xr uefi 8 +.Sh STANDARDS +The Unified Extensible Firmware Interface Specification is available +from +.Pa www.uefi.org . From 3cee7cb26993aea9b089270f098a42ce0f4ba73b Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Thu, 23 Jul 2020 23:29:50 +0000 Subject: [PATCH 130/287] Limit gmirror failpoint tests to the test worker This avoids injecting errors into the test system's mirrors. gnop seems like a good solution here but it injects errors at the wrong place vs where these tests expect and does not support a 'max global count' like the failpoints do with 'n*' syntax. Reviewed by: cem, vangyzen Sponsored by: Dell EMC Isilon --- tests/sys/geom/class/mirror/10_test.sh | 2 +- tests/sys/geom/class/mirror/11_test.sh | 2 +- tests/sys/geom/class/mirror/12_test.sh | 2 +- tests/sys/geom/class/mirror/13_test.sh | 2 +- tests/sys/geom/class/mirror/9_test.sh | 2 +- tests/sys/geom/class/mirror/conf.sh | 5 +++++ tests/sys/geom/class/mirror/sync_error.sh | 4 ++-- 7 files changed, 12 insertions(+), 7 deletions(-) diff --git a/tests/sys/geom/class/mirror/10_test.sh b/tests/sys/geom/class/mirror/10_test.sh index c8187189d60d..9247abddd826 100644 --- a/tests/sys/geom/class/mirror/10_test.sh +++ b/tests/sys/geom/class/mirror/10_test.sh @@ -30,7 +30,7 @@ tmp2=$(mktemp $base.XXXXXX) EIO=5 # gmirror should retry a failed read from the other mirror. -sysctl ${regreadfp}="1*return(${EIO})" +sysctl ${regreadfp}="1*return(${EIO})[pid $(gmirror_worker_pid)]" dd if=/dev/mirror/$name of=$tmp1 iseek=256 bs=$ddbs count=1 >/dev/null 2>&1 dd if=/dev/$us1 of=$tmp2 iseek=256 bs=$ddbs count=1 >/dev/null 2>&1 sysctl ${regreadfp}='off' diff --git a/tests/sys/geom/class/mirror/11_test.sh b/tests/sys/geom/class/mirror/11_test.sh index 284aa19c72fa..8ae65a1f5a04 100644 --- a/tests/sys/geom/class/mirror/11_test.sh +++ b/tests/sys/geom/class/mirror/11_test.sh @@ -31,7 +31,7 @@ tmp2=$(mktemp $base.XXXXXX) ENXIO=6 # gmirror has special handling for ENXIO. It does not mark the failed component # as broken, allowing it to rejoin the mirror automatically when it appears. -sysctl ${regreadfp}="1*return(${ENXIO})" +sysctl ${regreadfp}="1*return(${ENXIO})[pid $(gmirror_worker_pid)]" dd if=/dev/mirror/$name of=$tmp1 iseek=512 bs=$ddbs count=1 >/dev/null 2>&1 dd if=/dev/$us1 of=$tmp2 iseek=512 bs=$ddbs count=1 >/dev/null 2>&1 sysctl ${regreadfp}='off' diff --git a/tests/sys/geom/class/mirror/12_test.sh b/tests/sys/geom/class/mirror/12_test.sh index 07d69b696adf..46a79efe7e05 100644 --- a/tests/sys/geom/class/mirror/12_test.sh +++ b/tests/sys/geom/class/mirror/12_test.sh @@ -29,7 +29,7 @@ dd if=/dev/random of=$tmp1 bs=$ddbs count=1 >/dev/null 2>&1 EIO=5 # gmirror should kick one of the mirrors out after hitting EIO. -sysctl ${regwritefp}="1*return(${EIO})" +sysctl ${regwritefp}="1*return(${EIO})[pid $(gmirror_worker_pid)]" dd if=$tmp1 of=/dev/mirror/$name bs=$ddbs count=1 >/dev/null 2>&1 dd if=/dev/mirror/$name of=$tmp2 bs=$ddbs count=1 >/dev/null 2>&1 sysctl ${regwritefp}='off' diff --git a/tests/sys/geom/class/mirror/13_test.sh b/tests/sys/geom/class/mirror/13_test.sh index 4a66d65321a3..4b0fc6cf7825 100644 --- a/tests/sys/geom/class/mirror/13_test.sh +++ b/tests/sys/geom/class/mirror/13_test.sh @@ -31,7 +31,7 @@ dd if=/dev/random of=$tmp1 bs=$ddbs count=1 >/dev/null 2>&1 ENXIO=6 # gmirror has special handling for ENXIO. It does not mark the failed component # as broken, allowing it to rejoin the mirror automatically when it appears. -sysctl ${regwritefp}="1*return(${ENXIO})" +sysctl ${regwritefp}="1*return(${ENXIO})[pid $(gmirror_worker_pid)]" dd if=$tmp1 of=/dev/mirror/$name bs=$ddbs count=1 >/dev/null 2>&1 dd if=/dev/mirror/$name of=$tmp2 bs=$ddbs count=1 >/dev/null 2>&1 sysctl ${regwritefp}='off' diff --git a/tests/sys/geom/class/mirror/9_test.sh b/tests/sys/geom/class/mirror/9_test.sh index c7af15ba8ed2..0c29cefd4344 100644 --- a/tests/sys/geom/class/mirror/9_test.sh +++ b/tests/sys/geom/class/mirror/9_test.sh @@ -26,7 +26,7 @@ devwait # Break one of the mirrors by forcing a single metadata write error. # When dd closes the mirror provider, gmirror will attempt to mark the mirrors # clean, and will kick one of the mirrors out upon hitting the error. -sysctl debug.fail_point.g_mirror_metadata_write='1*return(5)' || exit 1 +sysctl debug.fail_point.g_mirror_metadata_write="1*return(5)[pid $(gmirror_worker_pid)]" || exit 1 dd if=/dev/random of=/dev/mirror/$name bs=$ddbs count=1 >/dev/null 2>&1 sysctl debug.fail_point.g_mirror_metadata_write='off' || exit 1 diff --git a/tests/sys/geom/class/mirror/conf.sh b/tests/sys/geom/class/mirror/conf.sh index cee2b10e9ff6..f50ff5f6b636 100644 --- a/tests/sys/geom/class/mirror/conf.sh +++ b/tests/sys/geom/class/mirror/conf.sh @@ -12,6 +12,11 @@ gmirror_test_cleanup() } trap gmirror_test_cleanup ABRT EXIT INT TERM +gmirror_worker_pid() +{ + pgrep -S -n "g_mirror mirror\..*" +} + syncwait() { while $(gmirror status -s $name | grep -q SYNCHRONIZING); do diff --git a/tests/sys/geom/class/mirror/sync_error.sh b/tests/sys/geom/class/mirror/sync_error.sh index b5f138aaf8a0..7c736b955a68 100644 --- a/tests/sys/geom/class/mirror/sync_error.sh +++ b/tests/sys/geom/class/mirror/sync_error.sh @@ -28,7 +28,7 @@ sync_read_error_2_disks_body() atf_check gmirror label $name $md1 devwait - atf_check -s ignore -e empty -o not-empty sysctl ${REG_READ_FP}='1*return(5)' + atf_check -s ignore -e empty -o not-empty sysctl ${REG_READ_FP}="1*return(5)[pid $(gmirror_worker_pid)]" # If a read error occurs while synchronizing and the mirror contains # a single active disk, gmirror has no choice but to fail the @@ -75,7 +75,7 @@ sync_read_error_3_disks_body() atf_check gmirror insert $name $md2 syncwait - atf_check -s exit:0 -e empty -o not-empty sysctl ${REG_READ_FP}='1*return(5)' + atf_check -s exit:0 -e empty -o not-empty sysctl ${REG_READ_FP}="1*return(5)[pid $(gmirror_worker_pid)]" # If a read error occurs while synchronizing a new disk, and we have # multiple active disks, we retry the read after an error. The disk From 3c0e5685051142f4125bf93d40a3e0b570e2327c Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 23 Jul 2020 23:48:18 +0000 Subject: [PATCH 131/287] Add support for KTLS RX via software decryption. Allow TLS records to be decrypted in the kernel after being received by a NIC. At a high level this is somewhat similar to software KTLS for the transmit path except in reverse. Protocols enqueue mbufs containing encrypted TLS records (or portions of records) into the tail of a socket buffer and the KTLS layer decrypts those records before returning them to userland applications. However, there is an important difference: - In the transmit case, the socket buffer is always a single "record" holding a chain of mbufs. Not-yet-encrypted mbufs are marked not ready (M_NOTREADY) and released to protocols for transmit by marking mbufs ready once their data is encrypted. - In the receive case, incoming (encrypted) data appended to the socket buffer is still a single stream of data from the protocol, but decrypted TLS records are stored as separate records in the socket buffer and read individually via recvmsg(). Initially I tried to make this work by marking incoming mbufs as M_NOTREADY, but there didn't seemed to be a non-gross way to deal with picking a portion of the mbuf chain and turning it into a new record in the socket buffer after decrypting the TLS record it contained (along with prepending a control message). Also, such mbufs would also need to be "pinned" in some way while they are being decrypted such that a concurrent sbcut() wouldn't free them out from under the thread performing decryption. As such, I settled on the following solution: - Socket buffers now contain an additional chain of mbufs (sb_mtls, sb_mtlstail, and sb_tlscc) containing encrypted mbufs appended by the protocol layer. These mbufs are still marked M_NOTREADY, but soreceive*() generally don't know about them (except that they will block waiting for data to be decrypted for a blocking read). - Each time a new mbuf is appended to this TLS mbuf chain, the socket buffer peeks at the TLS record header at the head of the chain to determine the encrypted record's length. If enough data is queued for the TLS record, the socket is placed on a per-CPU TLS workqueue (reusing the existing KTLS workqueues and worker threads). - The worker thread loops over the TLS mbuf chain decrypting records until it runs out of data. Each record is detached from the TLS mbuf chain while it is being decrypted to keep the mbufs "pinned". However, a new sb_dtlscc field tracks the character count of the detached record and sbcut()/sbdrop() is updated to account for the detached record. After the record is decrypted, the worker thread first checks to see if sbcut() dropped the record. If so, it is freed (can happen when a socket is closed with pending data). Otherwise, the header and trailer are stripped from the original mbufs, a control message is created holding the decrypted TLS header, and the decrypted TLS record is appended to the "normal" socket buffer chain. (Side note: the SBCHECK() infrastucture was very useful as I was able to add assertions there about the TLS chain that caught several bugs during development.) Tested by: rmacklem (various versions) Relnotes: yes Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D24628 --- share/man/man4/tcp.4 | 20 +- sys/kern/uipc_ktls.c | 472 ++++++++++++++++++++++++++++++++++++-- sys/kern/uipc_sockbuf.c | 252 +++++++++++++++++++- sys/kern/uipc_socket.c | 3 +- sys/opencrypto/ktls_ocf.c | 69 +++++- sys/sys/ktls.h | 18 +- sys/sys/sockbuf.h | 11 + sys/sys/socketvar.h | 4 + 8 files changed, 805 insertions(+), 44 deletions(-) diff --git a/share/man/man4/tcp.4 b/share/man/man4/tcp.4 index 915b8d0b6bf5..a62b71a1b4da 100644 --- a/share/man/man4/tcp.4 +++ b/share/man/man4/tcp.4 @@ -34,7 +34,7 @@ .\" From: @(#)tcp.4 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd April 27, 2020 +.Dd July 23, 2020 .Dt TCP 4 .Os .Sh NAME @@ -356,10 +356,22 @@ control message along with the decrypted payload. The control message contains a .Vt struct tls_get_record which includes fields from the TLS record header. -If a corrupted TLS record is received, +If an invalid or corrupted TLS record is received, recvmsg 2 -will fail with -.Dv EBADMSG . +will fail with one of the following errors: +.Bl -tag -width Er +.It Bq Er EINVAL +The version fields in a TLS record's header did not match the version required +by the +.Vt struct tls_so_enable +structure used to enable in-kernel TLS. +.It Bq Er EMSGSIZE +A TLS record's length was either too small or too large. +.It Bq Er EMSGSIZE +The connection was closed after sending a truncated TLS record. +.It Bq Er EBADMSG +The TLS record failed to match the included authentication tag. +.El .Pp At present, only a single receive key may be set on a socket. As such, users of this option must disable rekeying. diff --git a/sys/kern/uipc_ktls.c b/sys/kern/uipc_ktls.c index 4b3053b31494..71bbcc7110fe 100644 --- a/sys/kern/uipc_ktls.c +++ b/sys/kern/uipc_ktls.c @@ -78,7 +78,8 @@ __FBSDID("$FreeBSD$"); struct ktls_wq { struct mtx mtx; - STAILQ_HEAD(, mbuf) head; + STAILQ_HEAD(, mbuf) m_head; + STAILQ_HEAD(, socket) so_head; bool running; } __aligned(CACHE_LINE_SIZE); @@ -130,9 +131,15 @@ static counter_u64_t ktls_tasks_active; SYSCTL_COUNTER_U64(_kern_ipc_tls, OID_AUTO, tasks_active, CTLFLAG_RD, &ktls_tasks_active, "Number of active tasks"); -static counter_u64_t ktls_cnt_on; -SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, so_inqueue, CTLFLAG_RD, - &ktls_cnt_on, "Number of TLS records in queue to tasks for SW crypto"); +static counter_u64_t ktls_cnt_tx_queued; +SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, sw_tx_inqueue, CTLFLAG_RD, + &ktls_cnt_tx_queued, + "Number of TLS records in queue to tasks for SW encryption"); + +static counter_u64_t ktls_cnt_rx_queued; +SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, sw_rx_inqueue, CTLFLAG_RD, + &ktls_cnt_rx_queued, + "Number of TLS sockets in queue to tasks for SW decryption"); static counter_u64_t ktls_offload_total; SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, offload_total, @@ -148,6 +155,10 @@ static counter_u64_t ktls_offload_active; SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, active, CTLFLAG_RD, &ktls_offload_active, "Total Active TLS sessions"); +static counter_u64_t ktls_offload_corrupted_records; +SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, corrupted_records, CTLFLAG_RD, + &ktls_offload_corrupted_records, "Total corrupted TLS records received"); + static counter_u64_t ktls_offload_failed_crypto; SYSCTL_COUNTER_U64(_kern_ipc_tls_stats, OID_AUTO, failed_crypto, CTLFLAG_RD, &ktls_offload_failed_crypto, "Total TLS crypto failures"); @@ -333,10 +344,12 @@ ktls_init(void *dummy __unused) int error, i; ktls_tasks_active = counter_u64_alloc(M_WAITOK); - ktls_cnt_on = counter_u64_alloc(M_WAITOK); + ktls_cnt_tx_queued = counter_u64_alloc(M_WAITOK); + ktls_cnt_rx_queued = counter_u64_alloc(M_WAITOK); ktls_offload_total = counter_u64_alloc(M_WAITOK); ktls_offload_enable_calls = counter_u64_alloc(M_WAITOK); ktls_offload_active = counter_u64_alloc(M_WAITOK); + ktls_offload_corrupted_records = counter_u64_alloc(M_WAITOK); ktls_offload_failed_crypto = counter_u64_alloc(M_WAITOK); ktls_switch_to_ifnet = counter_u64_alloc(M_WAITOK); ktls_switch_to_sw = counter_u64_alloc(M_WAITOK); @@ -369,7 +382,8 @@ ktls_init(void *dummy __unused) * work queue for each CPU. */ CPU_FOREACH(i) { - STAILQ_INIT(&ktls_wq[i].head); + STAILQ_INIT(&ktls_wq[i].m_head); + STAILQ_INIT(&ktls_wq[i].so_head); mtx_init(&ktls_wq[i].mtx, "ktls work queue", NULL, MTX_DEF); error = kproc_kthread_add(ktls_work_thread, &ktls_wq[i], &ktls_proc, &td, 0, 0, "KTLS", "thr_%d", i); @@ -855,7 +869,7 @@ ktls_try_ifnet(struct socket *so, struct ktls_session *tls, bool force) } static int -ktls_try_sw(struct socket *so, struct ktls_session *tls) +ktls_try_sw(struct socket *so, struct ktls_session *tls, int direction) { struct rm_priotracker prio; struct ktls_crypto_backend *be; @@ -870,7 +884,7 @@ ktls_try_sw(struct socket *so, struct ktls_session *tls) if (ktls_allow_unload) rm_rlock(&ktls_backends_lock, &prio); LIST_FOREACH(be, &ktls_backends, next) { - if (be->try(so, tls) == 0) + if (be->try(so, tls, direction) == 0) break; KASSERT(tls->cipher == NULL, ("ktls backend leaked a cipher pointer")); @@ -896,6 +910,61 @@ ktls_try_sw(struct socket *so, struct ktls_session *tls) return (0); } +/* + * KTLS RX stores data in the socket buffer as a list of TLS records, + * where each record is stored as a control message containg the TLS + * header followed by data mbufs containing the decrypted data. This + * is different from KTLS TX which always uses an mb_ext_pgs mbuf for + * both encrypted and decrypted data. TLS records decrypted by a NIC + * should be queued to the socket buffer as records, but encrypted + * data which needs to be decrypted by software arrives as a stream of + * regular mbufs which need to be converted. In addition, there may + * already be pending encrypted data in the socket buffer when KTLS RX + * is enabled. + * + * To manage not-yet-decrypted data for KTLS RX, the following scheme + * is used: + * + * - A single chain of NOTREADY mbufs is hung off of sb_mtls. + * + * - ktls_check_rx checks this chain of mbufs reading the TLS header + * from the first mbuf. Once all of the data for that TLS record is + * queued, the socket is queued to a worker thread. + * + * - The worker thread calls ktls_decrypt to decrypt TLS records in + * the TLS chain. Each TLS record is detached from the TLS chain, + * decrypted, and inserted into the regular socket buffer chain as + * record starting with a control message holding the TLS header and + * a chain of mbufs holding the encrypted data. + */ + +static void +sb_mark_notready(struct sockbuf *sb) +{ + struct mbuf *m; + + m = sb->sb_mb; + sb->sb_mtls = m; + sb->sb_mb = NULL; + sb->sb_mbtail = NULL; + sb->sb_lastrecord = NULL; + for (; m != NULL; m = m->m_next) { + KASSERT(m->m_nextpkt == NULL, ("%s: m_nextpkt != NULL", + __func__)); + KASSERT((m->m_flags & M_NOTAVAIL) == 0, ("%s: mbuf not avail", + __func__)); + KASSERT(sb->sb_acc >= m->m_len, ("%s: sb_acc < m->m_len", + __func__)); + m->m_flags |= M_NOTREADY; + sb->sb_acc -= m->m_len; + sb->sb_tlscc += m->m_len; + sb->sb_mtlstail = m; + } + KASSERT(sb->sb_acc == 0 && sb->sb_tlscc == sb->sb_ccc, + ("%s: acc %u tlscc %u ccc %u", __func__, sb->sb_acc, sb->sb_tlscc, + sb->sb_ccc)); +} + int ktls_enable_rx(struct socket *so, struct tls_enable *en) { @@ -924,16 +993,20 @@ ktls_enable_rx(struct socket *so, struct tls_enable *en) if (en->cipher_algorithm == CRYPTO_AES_CBC && !ktls_cbc_enable) return (ENOTSUP); + /* TLS 1.3 is not yet supported. */ + if (en->tls_vmajor == TLS_MAJOR_VER_ONE && + en->tls_vminor == TLS_MINOR_VER_THREE) + return (ENOTSUP); + error = ktls_create_session(so, en, &tls); if (error) return (error); - /* TLS RX offload is only supported on TOE currently. */ #ifdef TCP_OFFLOAD error = ktls_try_toe(so, tls, KTLS_RX); -#else - error = EOPNOTSUPP; + if (error) #endif + error = ktls_try_sw(so, tls, KTLS_RX); if (error) { ktls_cleanup(tls); @@ -942,7 +1015,13 @@ ktls_enable_rx(struct socket *so, struct tls_enable *en) /* Mark the socket as using TLS offload. */ SOCKBUF_LOCK(&so->so_rcv); + so->so_rcv.sb_tls_seqno = be64dec(en->rec_seq); so->so_rcv.sb_tls_info = tls; + so->so_rcv.sb_flags |= SB_TLS_RX; + + /* Mark existing data as not ready until it can be decrypted. */ + sb_mark_notready(&so->so_rcv); + ktls_check_rx(&so->so_rcv); SOCKBUF_UNLOCK(&so->so_rcv); counter_u64_add(ktls_offload_total, 1); @@ -993,7 +1072,7 @@ ktls_enable_tx(struct socket *so, struct tls_enable *en) #endif error = ktls_try_ifnet(so, tls, false); if (error) - error = ktls_try_sw(so, tls); + error = ktls_try_sw(so, tls, KTLS_TX); if (error) { ktls_cleanup(tls); @@ -1098,7 +1177,7 @@ ktls_set_tx_mode(struct socket *so, int mode) if (mode == TCP_TLS_MODE_IFNET) error = ktls_try_ifnet(so, tls_new, true); else - error = ktls_try_sw(so, tls_new); + error = ktls_try_sw(so, tls_new, KTLS_TX); if (error) { counter_u64_add(ktls_switch_failed, 1); ktls_free(tls_new); @@ -1421,6 +1500,345 @@ ktls_frame(struct mbuf *top, struct ktls_session *tls, int *enq_cnt, } } +void +ktls_check_rx(struct sockbuf *sb) +{ + struct tls_record_layer hdr; + struct ktls_wq *wq; + struct socket *so; + bool running; + + SOCKBUF_LOCK_ASSERT(sb); + KASSERT(sb->sb_flags & SB_TLS_RX, ("%s: sockbuf %p isn't TLS RX", + __func__, sb)); + so = __containerof(sb, struct socket, so_rcv); + + if (sb->sb_flags & SB_TLS_RX_RUNNING) + return; + + /* Is there enough queued for a TLS header? */ + if (sb->sb_tlscc < sizeof(hdr)) { + if ((sb->sb_state & SBS_CANTRCVMORE) != 0 && sb->sb_tlscc != 0) + so->so_error = EMSGSIZE; + return; + } + + m_copydata(sb->sb_mtls, 0, sizeof(hdr), (void *)&hdr); + + /* Is the entire record queued? */ + if (sb->sb_tlscc < sizeof(hdr) + ntohs(hdr.tls_length)) { + if ((sb->sb_state & SBS_CANTRCVMORE) != 0) + so->so_error = EMSGSIZE; + return; + } + + sb->sb_flags |= SB_TLS_RX_RUNNING; + + soref(so); + wq = &ktls_wq[so->so_rcv.sb_tls_info->wq_index]; + mtx_lock(&wq->mtx); + STAILQ_INSERT_TAIL(&wq->so_head, so, so_ktls_rx_list); + running = wq->running; + mtx_unlock(&wq->mtx); + if (!running) + wakeup(wq); + counter_u64_add(ktls_cnt_rx_queued, 1); +} + +static struct mbuf * +ktls_detach_record(struct sockbuf *sb, int len) +{ + struct mbuf *m, *n, *top; + int remain; + + SOCKBUF_LOCK_ASSERT(sb); + MPASS(len <= sb->sb_tlscc); + + /* + * If TLS chain is the exact size of the record, + * just grab the whole record. + */ + top = sb->sb_mtls; + if (sb->sb_tlscc == len) { + sb->sb_mtls = NULL; + sb->sb_mtlstail = NULL; + goto out; + } + + /* + * While it would be nice to use m_split() here, we need + * to know exactly what m_split() allocates to update the + * accounting, so do it inline instead. + */ + remain = len; + for (m = top; remain > m->m_len; m = m->m_next) + remain -= m->m_len; + + /* Easy case: don't have to split 'm'. */ + if (remain == m->m_len) { + sb->sb_mtls = m->m_next; + if (sb->sb_mtls == NULL) + sb->sb_mtlstail = NULL; + m->m_next = NULL; + goto out; + } + + /* + * Need to allocate an mbuf to hold the remainder of 'm'. Try + * with M_NOWAIT first. + */ + n = m_get(M_NOWAIT, MT_DATA); + if (n == NULL) { + /* + * Use M_WAITOK with socket buffer unlocked. If + * 'sb_mtls' changes while the lock is dropped, return + * NULL to force the caller to retry. + */ + SOCKBUF_UNLOCK(sb); + + n = m_get(M_WAITOK, MT_DATA); + + SOCKBUF_LOCK(sb); + if (sb->sb_mtls != top) { + m_free(n); + return (NULL); + } + } + n->m_flags |= M_NOTREADY; + + /* Store remainder in 'n'. */ + n->m_len = m->m_len - remain; + if (m->m_flags & M_EXT) { + n->m_data = m->m_data + remain; + mb_dupcl(n, m); + } else { + bcopy(mtod(m, caddr_t) + remain, mtod(n, caddr_t), n->m_len); + } + + /* Trim 'm' and update accounting. */ + m->m_len -= n->m_len; + sb->sb_tlscc -= n->m_len; + sb->sb_ccc -= n->m_len; + + /* Account for 'n'. */ + sballoc_ktls_rx(sb, n); + + /* Insert 'n' into the TLS chain. */ + sb->sb_mtls = n; + n->m_next = m->m_next; + if (sb->sb_mtlstail == m) + sb->sb_mtlstail = n; + + /* Detach the record from the TLS chain. */ + m->m_next = NULL; + +out: + MPASS(m_length(top, NULL) == len); + for (m = top; m != NULL; m = m->m_next) + sbfree_ktls_rx(sb, m); + sb->sb_tlsdcc = len; + sb->sb_ccc += len; + SBCHECK(sb); + return (top); +} + +static int +m_segments(struct mbuf *m, int skip) +{ + int count; + + while (skip >= m->m_len) { + skip -= m->m_len; + m = m->m_next; + } + + for (count = 0; m != NULL; count++) + m = m->m_next; + return (count); +} + +static void +ktls_decrypt(struct socket *so) +{ + char tls_header[MBUF_PEXT_HDR_LEN]; + struct ktls_session *tls; + struct sockbuf *sb; + struct tls_record_layer *hdr; + struct tls_get_record tgr; + struct mbuf *control, *data, *m; + uint64_t seqno; + int error, remain, tls_len, trail_len; + + hdr = (struct tls_record_layer *)tls_header; + sb = &so->so_rcv; + SOCKBUF_LOCK(sb); + KASSERT(sb->sb_flags & SB_TLS_RX_RUNNING, + ("%s: socket %p not running", __func__, so)); + + tls = sb->sb_tls_info; + MPASS(tls != NULL); + + for (;;) { + /* Is there enough queued for a TLS header? */ + if (sb->sb_tlscc < tls->params.tls_hlen) + break; + + m_copydata(sb->sb_mtls, 0, tls->params.tls_hlen, tls_header); + tls_len = sizeof(*hdr) + ntohs(hdr->tls_length); + + if (hdr->tls_vmajor != tls->params.tls_vmajor || + hdr->tls_vminor != tls->params.tls_vminor) + error = EINVAL; + else if (tls_len < tls->params.tls_hlen || tls_len > + tls->params.tls_hlen + TLS_MAX_MSG_SIZE_V10_2 + + tls->params.tls_tlen) + error = EMSGSIZE; + else + error = 0; + if (__predict_false(error != 0)) { + /* + * We have a corrupted record and are likely + * out of sync. The connection isn't + * recoverable at this point, so abort it. + */ + SOCKBUF_UNLOCK(sb); + counter_u64_add(ktls_offload_corrupted_records, 1); + + CURVNET_SET(so->so_vnet); + so->so_proto->pr_usrreqs->pru_abort(so); + so->so_error = error; + CURVNET_RESTORE(); + goto deref; + } + + /* Is the entire record queued? */ + if (sb->sb_tlscc < tls_len) + break; + + /* + * Split out the portion of the mbuf chain containing + * this TLS record. + */ + data = ktls_detach_record(sb, tls_len); + if (data == NULL) + continue; + MPASS(sb->sb_tlsdcc == tls_len); + + seqno = sb->sb_tls_seqno; + sb->sb_tls_seqno++; + SBCHECK(sb); + SOCKBUF_UNLOCK(sb); + + error = tls->sw_decrypt(tls, hdr, data, seqno, &trail_len); + if (error) { + counter_u64_add(ktls_offload_failed_crypto, 1); + + SOCKBUF_LOCK(sb); + if (sb->sb_tlsdcc == 0) { + /* + * sbcut/drop/flush discarded these + * mbufs. + */ + m_freem(data); + break; + } + + /* + * Drop this TLS record's data, but keep + * decrypting subsequent records. + */ + sb->sb_ccc -= tls_len; + sb->sb_tlsdcc = 0; + + CURVNET_SET(so->so_vnet); + so->so_error = EBADMSG; + sorwakeup_locked(so); + CURVNET_RESTORE(); + + m_freem(data); + + SOCKBUF_LOCK(sb); + continue; + } + + /* Allocate the control mbuf. */ + tgr.tls_type = hdr->tls_type; + tgr.tls_vmajor = hdr->tls_vmajor; + tgr.tls_vminor = hdr->tls_vminor; + tgr.tls_length = htobe16(tls_len - tls->params.tls_hlen - + trail_len); + control = sbcreatecontrol_how(&tgr, sizeof(tgr), + TLS_GET_RECORD, IPPROTO_TCP, M_WAITOK); + + SOCKBUF_LOCK(sb); + if (sb->sb_tlsdcc == 0) { + /* sbcut/drop/flush discarded these mbufs. */ + MPASS(sb->sb_tlscc == 0); + m_freem(data); + m_freem(control); + break; + } + + /* + * Clear the 'dcc' accounting in preparation for + * adding the decrypted record. + */ + sb->sb_ccc -= tls_len; + sb->sb_tlsdcc = 0; + SBCHECK(sb); + + /* If there is no payload, drop all of the data. */ + if (tgr.tls_length == htobe16(0)) { + m_freem(data); + data = NULL; + } else { + /* Trim header. */ + remain = tls->params.tls_hlen; + while (remain > 0) { + if (data->m_len > remain) { + data->m_data += remain; + data->m_len -= remain; + break; + } + remain -= data->m_len; + data = m_free(data); + } + + /* Trim trailer and clear M_NOTREADY. */ + remain = be16toh(tgr.tls_length); + m = data; + for (m = data; remain > m->m_len; m = m->m_next) { + m->m_flags &= ~M_NOTREADY; + remain -= m->m_len; + } + m->m_len = remain; + m_freem(m->m_next); + m->m_next = NULL; + m->m_flags &= ~M_NOTREADY; + + /* Set EOR on the final mbuf. */ + m->m_flags |= M_EOR; + } + + sbappendcontrol_locked(sb, data, control, 0); + } + + sb->sb_flags &= ~SB_TLS_RX_RUNNING; + + if ((sb->sb_state & SBS_CANTRCVMORE) != 0 && sb->sb_tlscc > 0) + so->so_error = EMSGSIZE; + + sorwakeup_locked(so); + +deref: + SOCKBUF_UNLOCK_ASSERT(sb); + + CURVNET_SET(so->so_vnet); + SOCK_LOCK(so); + sorele(so); + CURVNET_RESTORE(); +} + void ktls_enqueue_to_free(struct mbuf *m) { @@ -1431,7 +1849,7 @@ ktls_enqueue_to_free(struct mbuf *m) m->m_epg_flags |= EPG_FLAG_2FREE; wq = &ktls_wq[m->m_epg_tls->wq_index]; mtx_lock(&wq->mtx); - STAILQ_INSERT_TAIL(&wq->head, m, m_epg_stailq); + STAILQ_INSERT_TAIL(&wq->m_head, m, m_epg_stailq); running = wq->running; mtx_unlock(&wq->mtx); if (!running) @@ -1461,12 +1879,12 @@ ktls_enqueue(struct mbuf *m, struct socket *so, int page_count) wq = &ktls_wq[m->m_epg_tls->wq_index]; mtx_lock(&wq->mtx); - STAILQ_INSERT_TAIL(&wq->head, m, m_epg_stailq); + STAILQ_INSERT_TAIL(&wq->m_head, m, m_epg_stailq); running = wq->running; mtx_unlock(&wq->mtx); if (!running) wakeup(wq); - counter_u64_add(ktls_cnt_on, 1); + counter_u64_add(ktls_cnt_tx_queued, 1); } static __noinline void @@ -1618,31 +2036,41 @@ ktls_work_thread(void *ctx) { struct ktls_wq *wq = ctx; struct mbuf *m, *n; - STAILQ_HEAD(, mbuf) local_head; + struct socket *so, *son; + STAILQ_HEAD(, mbuf) local_m_head; + STAILQ_HEAD(, socket) local_so_head; #if defined(__aarch64__) || defined(__amd64__) || defined(__i386__) fpu_kern_thread(0); #endif for (;;) { mtx_lock(&wq->mtx); - while (STAILQ_EMPTY(&wq->head)) { + while (STAILQ_EMPTY(&wq->m_head) && + STAILQ_EMPTY(&wq->so_head)) { wq->running = false; mtx_sleep(wq, &wq->mtx, 0, "-", 0); wq->running = true; } - STAILQ_INIT(&local_head); - STAILQ_CONCAT(&local_head, &wq->head); + STAILQ_INIT(&local_m_head); + STAILQ_CONCAT(&local_m_head, &wq->m_head); + STAILQ_INIT(&local_so_head); + STAILQ_CONCAT(&local_so_head, &wq->so_head); mtx_unlock(&wq->mtx); - STAILQ_FOREACH_SAFE(m, &local_head, m_epg_stailq, n) { + STAILQ_FOREACH_SAFE(m, &local_m_head, m_epg_stailq, n) { if (m->m_epg_flags & EPG_FLAG_2FREE) { ktls_free(m->m_epg_tls); uma_zfree(zone_mbuf, m); } else { ktls_encrypt(m); - counter_u64_add(ktls_cnt_on, -1); + counter_u64_add(ktls_cnt_tx_queued, -1); } } + + STAILQ_FOREACH_SAFE(so, &local_so_head, so_ktls_rx_list, son) { + ktls_decrypt(so); + counter_u64_add(ktls_cnt_rx_queued, -1); + } } } diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c index 1284e0bac4ca..bcdc0970c778 100644 --- a/sys/kern/uipc_sockbuf.c +++ b/sys/kern/uipc_sockbuf.c @@ -70,6 +70,8 @@ u_long sb_max_adj = static u_long sb_efficiency = 8; /* parameter for sbreserve() */ +static void sbcompress_ktls_rx(struct sockbuf *sb, struct mbuf *m, + struct mbuf *n); static struct mbuf *sbcut_internal(struct sockbuf *sb, int len); static void sbflush_internal(struct sockbuf *sb); @@ -334,6 +336,51 @@ sbfree(struct sockbuf *sb, struct mbuf *m) sb->sb_sndptroff -= m->m_len; } +#ifdef KERN_TLS +/* + * Similar to sballoc/sbfree but does not adjust state associated with + * the sb_mb chain such as sb_fnrdy or sb_sndptr*. Also assumes mbufs + * are not ready. + */ +void +sballoc_ktls_rx(struct sockbuf *sb, struct mbuf *m) +{ + + SOCKBUF_LOCK_ASSERT(sb); + + sb->sb_ccc += m->m_len; + sb->sb_tlscc += m->m_len; + + sb->sb_mbcnt += MSIZE; + sb->sb_mcnt += 1; + + if (m->m_flags & M_EXT) { + sb->sb_mbcnt += m->m_ext.ext_size; + sb->sb_ccnt += 1; + } +} + +void +sbfree_ktls_rx(struct sockbuf *sb, struct mbuf *m) +{ + +#if 0 /* XXX: not yet: soclose() call path comes here w/o lock. */ + SOCKBUF_LOCK_ASSERT(sb); +#endif + + sb->sb_ccc -= m->m_len; + sb->sb_tlscc -= m->m_len; + + sb->sb_mbcnt -= MSIZE; + sb->sb_mcnt -= 1; + + if (m->m_flags & M_EXT) { + sb->sb_mbcnt -= m->m_ext.ext_size; + sb->sb_ccnt -= 1; + } +} +#endif + /* * Socantsendmore indicates that no more data will be sent on the socket; it * would normally be applied to a socket when the user informs the system @@ -370,6 +417,10 @@ socantrcvmore_locked(struct socket *so) SOCKBUF_LOCK_ASSERT(&so->so_rcv); so->so_rcv.sb_state |= SBS_CANTRCVMORE; +#ifdef KERN_TLS + if (so->so_rcv.sb_flags & SB_TLS_RX) + ktls_check_rx(&so->so_rcv); +#endif sorwakeup_locked(so); mtx_assert(SOCKBUF_MTX(&so->so_rcv), MA_NOTOWNED); } @@ -770,6 +821,24 @@ sblastmbufchk(struct sockbuf *sb, const char *file, int line) } panic("%s from %s:%u", __func__, file, line); } + +#ifdef KERN_TLS + m = sb->sb_mtls; + while (m && m->m_next) + m = m->m_next; + + if (m != sb->sb_mtlstail) { + printf("%s: sb_mtls %p sb_mtlstail %p last %p\n", + __func__, sb->sb_mtls, sb->sb_mtlstail, m); + printf("TLS packet tree:\n"); + printf("\t"); + for (m = sb->sb_mtls; m != NULL; m = m->m_next) { + printf("%p ", m); + } + printf("\n"); + panic("%s from %s:%u", __func__, file, line); + } +#endif } #endif /* SOCKBUF_DEBUG */ @@ -847,6 +916,29 @@ sbappend(struct sockbuf *sb, struct mbuf *m, int flags) SOCKBUF_UNLOCK(sb); } +#ifdef KERN_TLS +/* + * Append an mbuf containing encrypted TLS data. The data + * is marked M_NOTREADY until it has been decrypted and + * stored as a TLS record. + */ +static void +sbappend_ktls_rx(struct sockbuf *sb, struct mbuf *m) +{ + struct mbuf *n; + + SBLASTMBUFCHK(sb); + + /* Remove all packet headers and mbuf tags to get a pure data chain. */ + m_demote(m, 1, 0); + + for (n = m; n != NULL; n = n->m_next) + n->m_flags |= M_NOTREADY; + sbcompress_ktls_rx(sb, m, sb->sb_mtlstail); + ktls_check_rx(sb); +} +#endif + /* * This version of sbappend() should only be used when the caller absolutely * knows that there will never be more than one record in the socket buffer, @@ -858,6 +950,19 @@ sbappendstream_locked(struct sockbuf *sb, struct mbuf *m, int flags) SOCKBUF_LOCK_ASSERT(sb); KASSERT(m->m_nextpkt == NULL,("sbappendstream 0")); + +#ifdef KERN_TLS + /* + * Decrypted TLS records are appended as records via + * sbappendrecord(). TCP passes encrypted TLS records to this + * function which must be scheduled for decryption. + */ + if (sb->sb_flags & SB_TLS_RX) { + sbappend_ktls_rx(sb, m); + return; + } +#endif + KASSERT(sb->sb_mb == sb->sb_lastrecord,("sbappendstream 1")); SBLASTMBUFCHK(sb); @@ -896,6 +1001,9 @@ sbcheck(struct sockbuf *sb, const char *file, int line) { struct mbuf *m, *n, *fnrdy; u_long acc, ccc, mbcnt; +#ifdef KERN_TLS + u_long tlscc; +#endif SOCKBUF_LOCK_ASSERT(sb); @@ -931,9 +1039,46 @@ sbcheck(struct sockbuf *sb, const char *file, int line) mbcnt += m->m_ext.ext_size; } } +#ifdef KERN_TLS + /* + * Account for mbufs "detached" by ktls_detach_record() while + * they are decrypted by ktls_decrypt(). tlsdcc gives a count + * of the detached bytes that are included in ccc. The mbufs + * and clusters are not included in the socket buffer + * accounting. + */ + ccc += sb->sb_tlsdcc; + + tlscc = 0; + for (m = sb->sb_mtls; m; m = m->m_next) { + if (m->m_nextpkt != NULL) { + printf("sb %p TLS mbuf %p with nextpkt\n", sb, m); + goto fail; + } + if ((m->m_flags & M_NOTREADY) == 0) { + printf("sb %p TLS mbuf %p ready\n", sb, m); + goto fail; + } + tlscc += m->m_len; + ccc += m->m_len; + mbcnt += MSIZE; + if (m->m_flags & M_EXT) /*XXX*/ /* pretty sure this is bogus */ + mbcnt += m->m_ext.ext_size; + } + + if (sb->sb_tlscc != tlscc) { + printf("tlscc %ld/%u dcc %u\n", tlscc, sb->sb_tlscc, + sb->sb_tlsdcc); + goto fail; + } +#endif if (acc != sb->sb_acc || ccc != sb->sb_ccc || mbcnt != sb->sb_mbcnt) { printf("acc %ld/%u ccc %ld/%u mbcnt %ld/%u\n", acc, sb->sb_acc, ccc, sb->sb_ccc, mbcnt, sb->sb_mbcnt); +#ifdef KERN_TLS + printf("tlscc %ld/%u dcc %u\n", tlscc, sb->sb_tlscc, + sb->sb_tlsdcc); +#endif goto fail; } return; @@ -1209,6 +1354,64 @@ sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n) SBLASTMBUFCHK(sb); } +#ifdef KERN_TLS +/* + * A version of sbcompress() for encrypted TLS RX mbufs. These mbufs + * are appended to the 'sb_mtls' chain instead of 'sb_mb' and are also + * a bit simpler (no EOR markers, always MT_DATA, etc.). + */ +static void +sbcompress_ktls_rx(struct sockbuf *sb, struct mbuf *m, struct mbuf *n) +{ + + SOCKBUF_LOCK_ASSERT(sb); + + while (m) { + KASSERT((m->m_flags & M_EOR) == 0, + ("TLS RX mbuf %p with EOR", m)); + KASSERT(m->m_type == MT_DATA, + ("TLS RX mbuf %p is not MT_DATA", m)); + KASSERT((m->m_flags & M_NOTREADY) != 0, + ("TLS RX mbuf %p ready", m)); + KASSERT((m->m_flags & M_EXTPG) == 0, + ("TLS RX mbuf %p unmapped", m)); + + if (m->m_len == 0) { + m = m_free(m); + continue; + } + + /* + * Even though both 'n' and 'm' are NOTREADY, it's ok + * to coalesce the data. + */ + if (n && + M_WRITABLE(n) && + ((sb->sb_flags & SB_NOCOALESCE) == 0) && + !(n->m_flags & (M_EXTPG)) && + m->m_len <= MCLBYTES / 4 && /* XXX: Don't copy too much */ + m->m_len <= M_TRAILINGSPACE(n)) { + m_copydata(m, 0, m->m_len, mtodo(n, n->m_len)); + n->m_len += m->m_len; + sb->sb_ccc += m->m_len; + sb->sb_tlscc += m->m_len; + m = m_free(m); + continue; + } + if (n) + n->m_next = m; + else + sb->sb_mtls = m; + sb->sb_mtlstail = m; + sballoc_ktls_rx(sb, m); + n = m; + m = m->m_next; + n->m_next = NULL; + } + SBLASTMBUFCHK(sb); +} +#endif + /* * Free all mbufs in a sockbuf. Check that all resources are reclaimed. */ @@ -1216,7 +1419,7 @@ static void sbflush_internal(struct sockbuf *sb) { - while (sb->sb_mbcnt) { + while (sb->sb_mbcnt || sb->sb_tlsdcc) { /* * Don't call sbcut(sb, 0) if the leading mbuf is non-empty: * we would loop forever. Panic instead. @@ -1254,6 +1457,7 @@ static struct mbuf * sbcut_internal(struct sockbuf *sb, int len) { struct mbuf *m, *next, *mfree; + bool is_tls; KASSERT(len >= 0, ("%s: len is %d but it is supposed to be >= 0", __func__, len)); @@ -1261,10 +1465,25 @@ sbcut_internal(struct sockbuf *sb, int len) __func__, len, sb->sb_ccc)); next = (m = sb->sb_mb) ? m->m_nextpkt : 0; + is_tls = false; mfree = NULL; while (len > 0) { if (m == NULL) { +#ifdef KERN_TLS + if (next == NULL && !is_tls) { + if (sb->sb_tlsdcc != 0) { + MPASS(len >= sb->sb_tlsdcc); + len -= sb->sb_tlsdcc; + sb->sb_ccc -= sb->sb_tlsdcc; + sb->sb_tlsdcc = 0; + if (len == 0) + break; + } + next = sb->sb_mtls; + is_tls = true; + } +#endif KASSERT(next, ("%s: no next, len %d", __func__, len)); m = next; next = m->m_nextpkt; @@ -1283,12 +1502,17 @@ sbcut_internal(struct sockbuf *sb, int len) break; } len -= m->m_len; - sbfree(sb, m); +#ifdef KERN_TLS + if (is_tls) + sbfree_ktls_rx(sb, m); + else +#endif + sbfree(sb, m); /* * Do not put M_NOTREADY buffers to the free list, they * are referenced from outside. */ - if (m->m_flags & M_NOTREADY) + if (m->m_flags & M_NOTREADY && !is_tls) m = m->m_next; else { struct mbuf *n; @@ -1314,6 +1538,14 @@ sbcut_internal(struct sockbuf *sb, int len) mfree = m; m = n; } +#ifdef KERN_TLS + if (is_tls) { + sb->sb_mb = NULL; + sb->sb_mtls = m; + if (m == NULL) + sb->sb_mtlstail = NULL; + } else +#endif if (m) { sb->sb_mb = m; m->m_nextpkt = next; @@ -1489,17 +1721,18 @@ sbdroprecord(struct sockbuf *sb) * type for presentation on a socket buffer. */ struct mbuf * -sbcreatecontrol(caddr_t p, int size, int type, int level) +sbcreatecontrol_how(void *p, int size, int type, int level, int wait) { struct cmsghdr *cp; struct mbuf *m; + MBUF_CHECKSLEEP(wait); if (CMSG_SPACE((u_int)size) > MCLBYTES) return ((struct mbuf *) NULL); if (CMSG_SPACE((u_int)size) > MLEN) - m = m_getcl(M_NOWAIT, MT_CONTROL, 0); + m = m_getcl(wait, MT_CONTROL, 0); else - m = m_get(M_NOWAIT, MT_CONTROL); + m = m_get(wait, MT_CONTROL); if (m == NULL) return ((struct mbuf *) NULL); cp = mtod(m, struct cmsghdr *); @@ -1520,6 +1753,13 @@ sbcreatecontrol(caddr_t p, int size, int type, int level) return (m); } +struct mbuf * +sbcreatecontrol(caddr_t p, int size, int type, int level) +{ + + return (sbcreatecontrol_how(p, size, type, level, M_NOWAIT)); +} + /* * This does the same for socket buffers that sotoxsocket does for sockets: * generate an user-format data structure describing the socket buffer. Note diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 440a0848f320..15a8b1439463 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1965,7 +1965,8 @@ soreceive_generic(struct socket *so, struct sockaddr **psa, struct uio *uio, } SOCKBUF_LOCK_ASSERT(&so->so_rcv); if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { - if (m == NULL) { + if (m == NULL && so->so_rcv.sb_tlsdcc == 0 && + so->so_rcv.sb_tlscc == 0) { SOCKBUF_UNLOCK(&so->so_rcv); goto release; } else diff --git a/sys/opencrypto/ktls_ocf.c b/sys/opencrypto/ktls_ocf.c index c08913d92535..7dd7861d131e 100644 --- a/sys/opencrypto/ktls_ocf.c +++ b/sys/opencrypto/ktls_ocf.c @@ -222,6 +222,56 @@ ktls_ocf_tls12_gcm_encrypt(struct ktls_session *tls, return (error); } +static int +ktls_ocf_tls12_gcm_decrypt(struct ktls_session *tls, + const struct tls_record_layer *hdr, struct mbuf *m, uint64_t seqno, + int *trailer_len) +{ + struct tls_aead_data ad; + struct cryptop crp; + struct ocf_session *os; + struct ocf_operation oo; + int error; + uint16_t tls_comp_len; + + os = tls->cipher; + + oo.os = os; + oo.done = false; + + crypto_initreq(&crp, os->sid); + + /* Setup the IV. */ + memcpy(crp.crp_iv, tls->params.iv, TLS_AEAD_GCM_LEN); + memcpy(crp.crp_iv + TLS_AEAD_GCM_LEN, hdr + 1, sizeof(uint64_t)); + + /* Setup the AAD. */ + tls_comp_len = ntohs(hdr->tls_length) - + (AES_GMAC_HASH_LEN + sizeof(uint64_t)); + ad.seq = htobe64(seqno); + ad.type = hdr->tls_type; + ad.tls_vmajor = hdr->tls_vmajor; + ad.tls_vminor = hdr->tls_vminor; + ad.tls_length = htons(tls_comp_len); + crp.crp_aad = &ad; + crp.crp_aad_length = sizeof(ad); + + crp.crp_payload_start = tls->params.tls_hlen; + crp.crp_payload_length = tls_comp_len; + crp.crp_digest_start = crp.crp_payload_start + crp.crp_payload_length; + + crp.crp_op = CRYPTO_OP_DECRYPT | CRYPTO_OP_VERIFY_DIGEST; + crp.crp_flags = CRYPTO_F_CBIMM | CRYPTO_F_IV_SEPARATE; + crypto_use_mbuf(&crp, m); + + counter_u64_add(ocf_tls12_gcm_crypts, 1); + error = ktls_ocf_dispatch(os, &crp); + + crypto_destroyreq(&crp); + *trailer_len = AES_GMAC_HASH_LEN; + return (error); +} + static int ktls_ocf_tls13_gcm_encrypt(struct ktls_session *tls, const struct tls_record_layer *hdr, uint8_t *trailer, struct iovec *iniov, @@ -325,7 +375,7 @@ ktls_ocf_free(struct ktls_session *tls) } static int -ktls_ocf_try(struct socket *so, struct ktls_session *tls) +ktls_ocf_try(struct socket *so, struct ktls_session *tls, int direction) { struct crypto_session_params csp; struct ocf_session *os; @@ -359,6 +409,11 @@ ktls_ocf_try(struct socket *so, struct ktls_session *tls) tls->params.tls_vminor > TLS_MINOR_VER_THREE) return (EPROTONOSUPPORT); + /* TLS 1.3 is not yet supported for receive. */ + if (direction == KTLS_RX && + tls->params.tls_vminor == TLS_MINOR_VER_THREE) + return (EPROTONOSUPPORT); + os = malloc(sizeof(*os), M_KTLS_OCF, M_NOWAIT | M_ZERO); if (os == NULL) return (ENOMEM); @@ -372,10 +427,14 @@ ktls_ocf_try(struct socket *so, struct ktls_session *tls) mtx_init(&os->lock, "ktls_ocf", NULL, MTX_DEF); tls->cipher = os; - if (tls->params.tls_vminor == TLS_MINOR_VER_THREE) - tls->sw_encrypt = ktls_ocf_tls13_gcm_encrypt; - else - tls->sw_encrypt = ktls_ocf_tls12_gcm_encrypt; + if (direction == KTLS_TX) { + if (tls->params.tls_vminor == TLS_MINOR_VER_THREE) + tls->sw_encrypt = ktls_ocf_tls13_gcm_encrypt; + else + tls->sw_encrypt = ktls_ocf_tls12_gcm_encrypt; + } else { + tls->sw_decrypt = ktls_ocf_tls12_gcm_decrypt; + } tls->free = ktls_ocf_free; return (0); } diff --git a/sys/sys/ktls.h b/sys/sys/ktls.h index 79ca1117f5fc..edbfe53f51ba 100644 --- a/sys/sys/ktls.h +++ b/sys/sys/ktls.h @@ -163,7 +163,7 @@ struct tls_session_params { #define KTLS_TX 1 #define KTLS_RX 2 -#define KTLS_API_VERSION 6 +#define KTLS_API_VERSION 7 struct iovec; struct ktls_session; @@ -174,7 +174,7 @@ struct socket; struct ktls_crypto_backend { LIST_ENTRY(ktls_crypto_backend) next; - int (*try)(struct socket *so, struct ktls_session *tls); + int (*try)(struct socket *so, struct ktls_session *tls, int direction); int prio; int api_version; int use_count; @@ -182,10 +182,15 @@ struct ktls_crypto_backend { }; struct ktls_session { - int (*sw_encrypt)(struct ktls_session *tls, - const struct tls_record_layer *hdr, uint8_t *trailer, - struct iovec *src, struct iovec *dst, int iovcnt, - uint64_t seqno, uint8_t record_type); + union { + int (*sw_encrypt)(struct ktls_session *tls, + const struct tls_record_layer *hdr, uint8_t *trailer, + struct iovec *src, struct iovec *dst, int iovcnt, + uint64_t seqno, uint8_t record_type); + int (*sw_decrypt)(struct ktls_session *tls, + const struct tls_record_layer *hdr, struct mbuf *m, + uint64_t seqno, int *trailer_len); + }; union { void *cipher; struct m_snd_tag *snd_tag; @@ -202,6 +207,7 @@ struct ktls_session { bool reset_pending; } __aligned(CACHE_LINE_SIZE); +void ktls_check_rx(struct sockbuf *sb); int ktls_crypto_backend_register(struct ktls_crypto_backend *be); int ktls_crypto_backend_deregister(struct ktls_crypto_backend *be); int ktls_enable_rx(struct socket *so, struct tls_enable *en); diff --git a/sys/sys/sockbuf.h b/sys/sys/sockbuf.h index 6e2340eabd50..4c56f4eaf234 100644 --- a/sys/sys/sockbuf.h +++ b/sys/sys/sockbuf.h @@ -38,6 +38,8 @@ /* * Constants for sb_flags field of struct sockbuf/xsockbuf. */ +#define SB_TLS_RX 0x01 /* using KTLS on RX */ +#define SB_TLS_RX_RUNNING 0x02 /* KTLS RX operation running */ #define SB_WAIT 0x04 /* someone is waiting for data/space */ #define SB_SEL 0x08 /* someone is selecting */ #define SB_ASYNC 0x10 /* ASYNC I/O, need signals */ @@ -99,10 +101,14 @@ struct sockbuf { u_int sb_ccnt; /* (a) number of clusters in buffer */ u_int sb_mbmax; /* (a) max chars of mbufs to use */ u_int sb_ctl; /* (a) non-data chars in buffer */ + u_int sb_tlscc; /* (a) TLS chain characters */ + u_int sb_tlsdcc; /* (a) TLS characters being decrypted */ int sb_lowat; /* (a) low water mark */ sbintime_t sb_timeo; /* (a) timeout for read/write */ uint64_t sb_tls_seqno; /* (a) TLS seqno */ struct ktls_session *sb_tls_info; /* (a + b) TLS state */ + struct mbuf *sb_mtls; /* (a) TLS mbuf chain */ + struct mbuf *sb_mtlstail; /* (a) last mbuf in TLS chain */ short sb_flags; /* (a) flags, see above */ int (*sb_upcall)(struct socket *, void *, int); /* (a) */ void *sb_upcallarg; /* (a) */ @@ -153,6 +159,9 @@ void sbappendrecord_locked(struct sockbuf *sb, struct mbuf *m0); void sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n); struct mbuf * sbcreatecontrol(caddr_t p, int size, int type, int level); +struct mbuf * + sbcreatecontrol_how(void *p, int size, int type, int level, + int wait); void sbdestroy(struct sockbuf *sb, struct socket *so); void sbdrop(struct sockbuf *sb, int len); void sbdrop_locked(struct sockbuf *sb, int len); @@ -178,6 +187,8 @@ int sblock(struct sockbuf *sb, int flags); void sbunlock(struct sockbuf *sb); void sballoc(struct sockbuf *, struct mbuf *); void sbfree(struct sockbuf *, struct mbuf *); +void sballoc_ktls_rx(struct sockbuf *sb, struct mbuf *m); +void sbfree_ktls_rx(struct sockbuf *sb, struct mbuf *m); int sbready(struct sockbuf *, struct mbuf *, int); /* diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index 3f1d406472c7..295a1cf3d37f 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -83,6 +83,7 @@ enum socket_qstate { * (f) not locked since integer reads/writes are atomic. * (g) used only as a sleep/wakeup address, no value. * (h) locked by global mutex so_global_mtx. + * (k) locked by KTLS workqueue mutex */ TAILQ_HEAD(accept_queue, socket); struct socket { @@ -132,6 +133,9 @@ struct socket { /* (b) cached MAC label for peer */ struct label *so_peerlabel; u_long so_oobmark; /* chars to oob mark */ + + /* (k) Our place on KTLS RX work queue. */ + STAILQ_ENTRY(socket) so_ktls_rx_list; }; /* * Listening socket, where accepts occur, is so_listen in all From 92b56ebaf720c5c20504378bff287fcb1da138db Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Fri, 24 Jul 2020 00:35:21 +0000 Subject: [PATCH 132/287] document that m_get2 only accepts up to MJUMPAGESIZE.. --- share/man/man9/mbuf.9 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/share/man/man9/mbuf.9 b/share/man/man9/mbuf.9 index 2312d89b32fc..eee040789733 100644 --- a/share/man/man9/mbuf.9 +++ b/share/man/man9/mbuf.9 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 28, 2019 +.Dd July 23, 2020 .Dt MBUF 9 .Os .\" @@ -574,6 +574,9 @@ for non-critical paths. Allocate an .Vt mbuf with enough space to hold specified amount of data. +If the size is is larger than +.Dv MJUMPAGESIZE , NULL +will be returned. .It Fn m_getm orig len how type Allocate .Fa len From b6dd8b71d115bbea97180125ac0aa0bd7d5d5abb Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Fri, 24 Jul 2020 00:47:14 +0000 Subject: [PATCH 133/287] fix up docs for m_getjcl as well.. --- share/man/man9/mbuf.9 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/share/man/man9/mbuf.9 b/share/man/man9/mbuf.9 index eee040789733..47186c16475e 100644 --- a/share/man/man9/mbuf.9 +++ b/share/man/man9/mbuf.9 @@ -635,9 +635,12 @@ on failure. .It Fn m_getjcl how type flags size This is like .Fn m_getcl -but it the size of the cluster allocated will be large enough for +but the specified .Fa size -bytes. +of the cluster to be allocated must be one of +.Dv MCLBYTES , MJUMPAGESIZE , MJUM9BYTES , +or +.Dv MJUM16BYTES. .It Fn m_free mbuf Frees .Vt mbuf . From b798ef649000ced17ed08faaa443da43984deec2 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Fri, 24 Jul 2020 08:40:04 +0000 Subject: [PATCH 134/287] Include TMPFS in all the GENERIC kernel configs Being able to use tmpfs without kernel modules is very useful when building small MFS_ROOT kernels without a real file system. Including TMPFS also matches arm/GENERIC and the MIPS std.MALTA configs. Compiling TMPFS only adds 4 .c files so this should not make much of a difference to NO_MODULES build times (as we do for our minimal RISC-V images). Reviewed By: br (earlier version for riscv), brooks, emaste Differential Revision: https://reviews.freebsd.org/D25317 --- sys/amd64/conf/GENERIC | 1 + sys/arm64/conf/GENERIC | 1 + sys/i386/conf/GENERIC | 1 + sys/powerpc/conf/GENERIC | 1 + sys/powerpc/conf/GENERIC64 | 1 + sys/riscv/conf/GENERIC | 1 + 6 files changed, 6 insertions(+) diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 482507b6eb3c..afa4c4650e5e 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -51,6 +51,7 @@ options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) options PSEUDOFS # Pseudo-filesystem framework +options TMPFS # Efficient memory filesystem options GEOM_RAID # Soft RAID functionality. options GEOM_LABEL # Provides labelization options EFIRT # EFI Runtime Services support diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC index e8fd9fab1961..311a1ae0dbbc 100644 --- a/sys/arm64/conf/GENERIC +++ b/sys/arm64/conf/GENERIC @@ -50,6 +50,7 @@ options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) options PSEUDOFS # Pseudo-filesystem framework +options TMPFS # Efficient memory filesystem options GEOM_RAID # Soft RAID functionality. options GEOM_LABEL # Provides labelization options COMPAT_FREEBSD32 # Compatible with FreeBSD/arm diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index 9adf42a139fa..5cf8fbd018c8 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -50,6 +50,7 @@ options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) options PSEUDOFS # Pseudo-filesystem framework +options TMPFS # Efficient memory filesystem options GEOM_RAID # Soft RAID functionality. options GEOM_LABEL # Provides labelization options COMPAT_FREEBSD4 # Compatible with FreeBSD4 diff --git a/sys/powerpc/conf/GENERIC b/sys/powerpc/conf/GENERIC index f141a113f269..dbc850687ad8 100644 --- a/sys/powerpc/conf/GENERIC +++ b/sys/powerpc/conf/GENERIC @@ -57,6 +57,7 @@ options MSDOSFS #MSDOS Filesystem options CD9660 #ISO 9660 Filesystem options PROCFS #Process filesystem (requires PSEUDOFS) options PSEUDOFS #Pseudo-filesystem framework +options TMPFS #Efficient memory filesystem options GEOM_PART_APM #Apple Partition Maps. options GEOM_PART_GPT #GUID Partition Tables. options GEOM_LABEL #Provides labelization diff --git a/sys/powerpc/conf/GENERIC64 b/sys/powerpc/conf/GENERIC64 index 77fc641dbb4b..a70cd0db605d 100644 --- a/sys/powerpc/conf/GENERIC64 +++ b/sys/powerpc/conf/GENERIC64 @@ -62,6 +62,7 @@ options MSDOSFS #MSDOS Filesystem options CD9660 #ISO 9660 Filesystem options PROCFS #Process filesystem (requires PSEUDOFS) options PSEUDOFS #Pseudo-filesystem framework +options TMPFS #Efficient memory filesystem options GEOM_PART_APM #Apple Partition Maps. options GEOM_PART_GPT #GUID Partition Tables. options GEOM_LABEL #Provides labelization diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC index 4cde17013fa3..6086229b640c 100644 --- a/sys/riscv/conf/GENERIC +++ b/sys/riscv/conf/GENERIC @@ -47,6 +47,7 @@ options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) options PSEUDOFS # Pseudo-filesystem framework +options TMPFS # Efficient memory filesystem options GEOM_PART_GPT # GUID Partition Tables. options GEOM_RAID # Soft RAID functionality. options GEOM_LABEL # Provides labelization From ee74412269ec4d269e288b690359eb97605177ab Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Fri, 24 Jul 2020 13:23:32 +0000 Subject: [PATCH 135/287] vm: fix swap reservation leak and clean up surrounding code The code did not subtract from the global counter if per-uid reservation failed. Cleanup highlights: - load overcommit once - move per-uid manipulation to dedicated routines - don't fetch wire count if requested size is below the limit - convert return type from int to bool - ifdef the routines with _KERNEL to keep vm.h compilable by userspace Reviewed by: kib (previous version) Differential Revision: https://reviews.freebsd.org/D25787 --- sys/vm/swap_pager.c | 145 ++++++++++++++++++++++++++++---------------- sys/vm/vm.h | 6 +- 2 files changed, 97 insertions(+), 54 deletions(-) diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c index 287122dad34d..98aca826e212 100644 --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -202,101 +202,141 @@ sysctl_page_shift(SYSCTL_HANDLER_ARGS) return (sysctl_handle_64(oidp, &newval, 0, req)); } -int +static bool +swap_reserve_by_cred_rlimit(u_long pincr, struct ucred *cred, int oc) +{ + struct uidinfo *uip; + u_long prev; + + uip = cred->cr_ruidinfo; + + prev = atomic_fetchadd_long(&uip->ui_vmsize, pincr); + if ((oc & SWAP_RESERVE_RLIMIT_ON) != 0 && + prev + pincr > lim_cur(curthread, RLIMIT_SWAP) && + priv_check(curthread, PRIV_VM_SWAP_NORLIMIT) != 0) { + prev = atomic_fetchadd_long(&uip->ui_vmsize, -pincr); + KASSERT(prev >= pincr, ("negative vmsize for uid = %d\n", uip->ui_uid)); + return (false); + } + return (true); +} + +static void +swap_release_by_cred_rlimit(u_long pdecr, struct ucred *cred) +{ + struct uidinfo *uip; +#ifdef INVARIANTS + u_long prev; +#endif + + uip = cred->cr_ruidinfo; + +#ifdef INVARIANTS + prev = atomic_fetchadd_long(&uip->ui_vmsize, -pdecr); + KASSERT(prev >= pdecr, ("negative vmsize for uid = %d\n", uip->ui_uid)); +#else + atomic_subtract_long(&uip->ui_vmsize, pdecr); +#endif +} + +static void +swap_reserve_force_rlimit(u_long pincr, struct ucred *cred) +{ + struct uidinfo *uip; + + uip = cred->cr_ruidinfo; + atomic_add_long(&uip->ui_vmsize, pincr); +} + +bool swap_reserve(vm_ooffset_t incr) { return (swap_reserve_by_cred(incr, curthread->td_ucred)); } -int +bool swap_reserve_by_cred(vm_ooffset_t incr, struct ucred *cred) { u_long r, s, prev, pincr; - int res, error; +#ifdef RACCT + int error; +#endif + int oc; static int curfail; static struct timeval lastfail; - struct uidinfo *uip; - - uip = cred->cr_ruidinfo; KASSERT((incr & PAGE_MASK) == 0, ("%s: incr: %ju & PAGE_MASK", __func__, (uintmax_t)incr)); #ifdef RACCT - if (racct_enable) { + if (RACCT_ENABLED()) { PROC_LOCK(curproc); error = racct_add(curproc, RACCT_SWAP, incr); PROC_UNLOCK(curproc); if (error != 0) - return (0); + return (false); } #endif pincr = atop(incr); - res = 0; prev = atomic_fetchadd_long(&swap_reserved, pincr); r = prev + pincr; - if (overcommit & SWAP_RESERVE_ALLOW_NONWIRED) { - s = vm_cnt.v_page_count - vm_cnt.v_free_reserved - + s = swap_total; + oc = atomic_load_int(&overcommit); + if (r > s && (oc & SWAP_RESERVE_ALLOW_NONWIRED) != 0) { + s += vm_cnt.v_page_count - vm_cnt.v_free_reserved - vm_wire_count(); - } else - s = 0; - s += swap_total; - if ((overcommit & SWAP_RESERVE_FORCE_ON) == 0 || r <= s || - (error = priv_check(curthread, PRIV_VM_SWAP_NOQUOTA)) == 0) { - res = 1; - } else { + } + if ((oc & SWAP_RESERVE_FORCE_ON) != 0 && r > s && + priv_check(curthread, PRIV_VM_SWAP_NOQUOTA) != 0) { prev = atomic_fetchadd_long(&swap_reserved, -pincr); - if (prev < pincr) - panic("swap_reserved < incr on overcommit fail"); - } - if (res) { - prev = atomic_fetchadd_long(&uip->ui_vmsize, pincr); - if ((overcommit & SWAP_RESERVE_RLIMIT_ON) != 0 && - prev + pincr > lim_cur(curthread, RLIMIT_SWAP) && - priv_check(curthread, PRIV_VM_SWAP_NORLIMIT)) { - res = 0; - prev = atomic_fetchadd_long(&uip->ui_vmsize, -pincr); - if (prev < pincr) - panic("uip->ui_vmsize < incr on overcommit fail"); - } - } - if (!res && ppsratecheck(&lastfail, &curfail, 1)) { - printf("uid %d, pid %d: swap reservation for %jd bytes failed\n", - uip->ui_uid, curproc->p_pid, incr); + KASSERT(prev >= pincr, ("swap_reserved < incr on overcommit fail")); + goto out_error; } + if (!swap_reserve_by_cred_rlimit(pincr, cred, oc)) { + prev = atomic_fetchadd_long(&swap_reserved, -pincr); + KASSERT(prev >= pincr, ("swap_reserved < incr on overcommit fail")); + goto out_error; + } + + return (true); + +out_error: + if (ppsratecheck(&lastfail, &curfail, 1)) { + printf("uid %d, pid %d: swap reservation for %jd bytes failed\n", + cred->cr_ruidinfo->ui_uid, curproc->p_pid, incr); + } #ifdef RACCT - if (racct_enable && !res) { + if (RACCT_ENABLED()) { PROC_LOCK(curproc); racct_sub(curproc, RACCT_SWAP, incr); PROC_UNLOCK(curproc); } #endif - return (res); + return (false); } void swap_reserve_force(vm_ooffset_t incr) { - struct uidinfo *uip; u_long pincr; KASSERT((incr & PAGE_MASK) == 0, ("%s: incr: %ju & PAGE_MASK", __func__, (uintmax_t)incr)); - PROC_LOCK(curproc); #ifdef RACCT - if (racct_enable) + if (RACCT_ENABLED()) { + PROC_LOCK(curproc); racct_add_force(curproc, RACCT_SWAP, incr); + PROC_UNLOCK(curproc); + } #endif pincr = atop(incr); atomic_add_long(&swap_reserved, pincr); - uip = curproc->p_ucred->cr_ruidinfo; - atomic_add_long(&uip->ui_vmsize, pincr); - PROC_UNLOCK(curproc); + swap_reserve_force_rlimit(pincr, curthread->td_ucred); } void @@ -313,22 +353,23 @@ swap_release(vm_ooffset_t decr) void swap_release_by_cred(vm_ooffset_t decr, struct ucred *cred) { - u_long prev, pdecr; - struct uidinfo *uip; - - uip = cred->cr_ruidinfo; + u_long pdecr; +#ifdef INVARIANTS + u_long prev; +#endif KASSERT((decr & PAGE_MASK) == 0, ("%s: decr: %ju & PAGE_MASK", __func__, (uintmax_t)decr)); pdecr = atop(decr); +#ifdef INVARIANTS prev = atomic_fetchadd_long(&swap_reserved, -pdecr); - if (prev < pdecr) - panic("swap_reserved < decr"); + KASSERT(prev >= pdecr, ("swap_reserved < decr")); +#else + atomic_subtract_long(&swap_reserved, pdecr); +#endif - prev = atomic_fetchadd_long(&uip->ui_vmsize, -pdecr); - if (prev < pdecr) - printf("negative vmsize for uid = %d\n", uip->ui_uid); + swap_release_by_cred_rlimit(pdecr, cred); #ifdef RACCT if (racct_enable) racct_sub_cred(cred, RACCT_SWAP, decr); diff --git a/sys/vm/vm.h b/sys/vm/vm.h index e1d3335183d4..ca114a9aa166 100644 --- a/sys/vm/vm.h +++ b/sys/vm/vm.h @@ -150,13 +150,15 @@ extern int old_mlock; extern int vm_ndomains; +#ifdef _KERNEL struct ucred; -int swap_reserve(vm_ooffset_t incr); -int swap_reserve_by_cred(vm_ooffset_t incr, struct ucred *cred); +bool swap_reserve(vm_ooffset_t incr); +bool swap_reserve_by_cred(vm_ooffset_t incr, struct ucred *cred); void swap_reserve_force(vm_ooffset_t incr); void swap_release(vm_ooffset_t decr); void swap_release_by_cred(vm_ooffset_t decr, struct ucred *cred); void swapper(void); +#endif #endif /* VM_H */ From 5ccb7079f8956d76e3b224c751d797e3a6a93157 Mon Sep 17 00:00:00 2001 From: Mateusz Piotrowski <0mp@FreeBSD.org> Date: Fri, 24 Jul 2020 14:17:37 +0000 Subject: [PATCH 136/287] Document that force_depend() supports only /etc/rc.d scripts Currently, force_depend() from rc.subr(8) does not support depending on scripts outside of /etc/rc.d (like /usr/local/etc/rc.d). The /etc/rc.d path is hard-coded into force_depend(). MFC after: 1 week --- share/man/man8/rc.subr.8 | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/share/man/man8/rc.subr.8 b/share/man/man8/rc.subr.8 index f506c143cade..fa61c27886da 100644 --- a/share/man/man8/rc.subr.8 +++ b/share/man/man8/rc.subr.8 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 5, 2019 +.Dd July 24, 2020 .Dt RC.SUBR 8 .Os .Sh NAME @@ -237,8 +237,13 @@ The .Ar name argument is the .Xr basename 1 -component of the path to the script, usually -.Pa /etc/rc.d/name . +component of the path to the script located at +.Pa /etc/rc.d +(scripts stored in other locations like +.Pa /usr/local/etc/rc.d +cannot be contolled with +.Ic force_depend +currently). If the script fails for any reason it will output a warning and return with a return value of 1. If it was successful From d6dade0002fa6aef64e7f0a9c3c50615a8795171 Mon Sep 17 00:00:00 2001 From: Mateusz Piotrowski <0mp@FreeBSD.org> Date: Fri, 24 Jul 2020 15:04:34 +0000 Subject: [PATCH 137/287] Fix grammar issues and typos Reported by: ian MFC after: 1 week --- share/man/man8/rc.subr.8 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/man/man8/rc.subr.8 b/share/man/man8/rc.subr.8 index fa61c27886da..fd23ca20c36c 100644 --- a/share/man/man8/rc.subr.8 +++ b/share/man/man8/rc.subr.8 @@ -239,9 +239,9 @@ argument is the .Xr basename 1 component of the path to the script located at .Pa /etc/rc.d -(scripts stored in other locations like +(scripts stored in other locations such as .Pa /usr/local/etc/rc.d -cannot be contolled with +cannot be controlled with .Ic force_depend currently). If the script fails for any reason it will output a warning From ce219ecd93a9cc13d8368b73f11647c5417ca53b Mon Sep 17 00:00:00 2001 From: Juli Mallett Date: Fri, 24 Jul 2020 16:58:13 +0000 Subject: [PATCH 138/287] Remove reference to nlist(3) missed in SCCS revision 5.26 by mckusick when converting rwhod(8) to using kern.boottime ather than extracting the boot time from kernel memory directly. Reviewed by: imp --- usr.sbin/rwhod/rwhod.8 | 9 --------- 1 file changed, 9 deletions(-) diff --git a/usr.sbin/rwhod/rwhod.8 b/usr.sbin/rwhod/rwhod.8 index aa9b00e9c158..c4f60a371645 100644 --- a/usr.sbin/rwhod/rwhod.8 +++ b/usr.sbin/rwhod/rwhod.8 @@ -215,15 +215,6 @@ format described above. .Pp Status messages are generated approximately once every 3 minutes. -The -.Nm -utility performs an -.Xr nlist 3 -on -.Pa /boot/kernel/kernel -every 30 minutes to guard against -the possibility that this file is not the system -image currently operating. .Sh SEE ALSO .Xr ruptime 1 , .Xr rwho 1 From bf2868538e719ebbd0e2cdbbced77815b2a71941 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Fri, 24 Jul 2020 17:11:14 +0000 Subject: [PATCH 139/287] mmccam: Add some aliases for non-mmccam to mmccam transition A new tunable is present, kern.cam.sdda.mmcsd_compat to enable this feature or not (default is enabled) --- sys/cam/mmc/mmc_da.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sys/cam/mmc/mmc_da.c b/sys/cam/mmc/mmc_da.c index 3e407013d5cf..6c00283eb2db 100644 --- a/sys/cam/mmc/mmc_da.c +++ b/sys/cam/mmc/mmc_da.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -186,6 +187,13 @@ static void sdda_init_switch_part(struct cam_periph *periph, union ccb *start_cc static int mmc_select_card(struct cam_periph *periph, union ccb *ccb, uint32_t rca); static inline uint32_t mmc_get_sector_size(struct cam_periph *periph) {return MMC_SECTOR_SIZE;} +static SYSCTL_NODE(_kern_cam, OID_AUTO, sdda, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, + "CAM Direct Access Disk driver"); + +static int sdda_mmcsd_compat = 1; +SYSCTL_INT(_kern_cam_sdda, OID_AUTO, mmcsd_compat, CTLFLAG_RDTUN, + &sdda_mmcsd_compat, 1, "Enable creation of mmcsd aliases."); + /* TODO: actually issue GET_TRAN_SETTINGS to get R/O status */ static inline bool sdda_get_read_only(struct cam_periph *periph, union ccb *start_ccb) { @@ -1605,6 +1613,9 @@ sdda_add_part(struct cam_periph *periph, u_int type, const char *name, part->disk->d_fwsectors = 0; part->disk->d_fwheads = 0; + if (sdda_mmcsd_compat) + disk_add_alias(part->disk, "mmcsd"); + /* * Acquire a reference to the periph before we register with GEOM. * We'll release this reference once GEOM calls us back (via From 138698898f19ed92d277783a908433c50f2d6568 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Fri, 24 Jul 2020 17:28:24 +0000 Subject: [PATCH 140/287] lockmgr: add missing 'continue' to account for spuriously failed fcmpset PR: 248245 Reported by: gbe Noted by: markj Fixes by: r363415 ("lockmgr: add adaptive spinning") --- sys/kern/kern_lock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index 36084f3877bd..215d7b71b539 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -836,6 +836,7 @@ lockmgr_xlock_hard(struct lock *lk, u_int flags, struct lock_object *ilk, if (x == LK_UNLOCKED) { if (atomic_fcmpset_acq_ptr(&lk->lk_lock, &x, tid)) break; + continue; } if ((flags & (LK_ADAPTIVE | LK_INTERLOCK)) == LK_ADAPTIVE) { if (lockmgr_xlock_adaptive(&lda, lk, &x)) From 3c30b23519b4273848d08e10ac58ad5ac1882842 Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Fri, 24 Jul 2020 17:32:10 +0000 Subject: [PATCH 141/287] Use SMR to provide safe unlocked lookup for pctries from SMR zones Adapt r358130, for the almost identical vm_radix, to the pctrie subsystem. Like that change, the tree is kept correct for readers with store barriers and careful ordering. Existing locks serialize writers. Add a PCTRIE_DEFINE_SMR() wrapper that takes an additional smr_t parameter and instantiates a FOO_PCTRIE_LOOKUP_UNLOCKED() function, in addition to the usual definitions created by PCTRIE_DEFINE(). Interface consumers will be introduced in later commits. As future work, it might be nice to add vm_radix algorithms missing from generic pctrie to the pctrie interface, and then adapt vm_radix to use pctrie. Reported by: Attilio Reviewed by: markj Sponsored by: Isilon Differential Revision: https://reviews.freebsd.org/D25781 --- sys/kern/subr_pctrie.c | 274 +++++++++++++++++++++++++++++------------ sys/sys/pctrie.h | 14 +++ 2 files changed, 212 insertions(+), 76 deletions(-) diff --git a/sys/kern/subr_pctrie.c b/sys/kern/subr_pctrie.c index 822c5f88084f..e38dc45fa022 100644 --- a/sys/kern/subr_pctrie.c +++ b/sys/kern/subr_pctrie.c @@ -55,6 +55,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include /* smr.h depends on struct thread. */ +#include +#include #ifdef DDB #include @@ -72,18 +75,27 @@ __FBSDID("$FreeBSD$"); #define PCTRIE_UNITLEVEL(lev) \ ((uint64_t)1 << ((lev) * PCTRIE_WIDTH)) +struct pctrie_node; +typedef SMR_POINTER(struct pctrie_node *) smr_pctnode_t; + struct pctrie_node { - uint64_t pn_owner; /* Owner of record. */ - uint16_t pn_count; /* Valid children. */ - uint16_t pn_clev; /* Current level. */ - void *pn_child[PCTRIE_COUNT]; /* Child nodes. */ + uint64_t pn_owner; /* Owner of record. */ + uint16_t pn_count; /* Valid children. */ + uint8_t pn_clev; /* Current level. */ + int8_t pn_last; /* Zero last ptr. */ + smr_pctnode_t pn_child[PCTRIE_COUNT]; /* Child nodes. */ }; +enum pctrie_access { PCTRIE_SMR, PCTRIE_LOCKED, PCTRIE_UNSERIALIZED }; + +static __inline void pctrie_node_store(smr_pctnode_t *p, void *val, + enum pctrie_access access); + /* * Allocate a node. Pre-allocation should ensure that the request * will always be satisfied. */ -static __inline struct pctrie_node * +static struct pctrie_node * pctrie_node_get(struct pctrie *ptree, pctrie_alloc_t allocfn, uint64_t owner, uint16_t count, uint16_t clevel) { @@ -92,10 +104,20 @@ pctrie_node_get(struct pctrie *ptree, pctrie_alloc_t allocfn, uint64_t owner, node = allocfn(ptree); if (node == NULL) return (NULL); + + /* + * We want to clear the last child pointer after the final section + * has exited so lookup can not return false negatives. It is done + * here because it will be cache-cold in the dtor callback. + */ + if (node->pn_last != 0) { + pctrie_node_store(&node->pn_child[node->pn_last - 1], NULL, + PCTRIE_UNSERIALIZED); + node->pn_last = 0; + } node->pn_owner = owner; node->pn_count = count; node->pn_clev = clevel; - return (node); } @@ -104,7 +126,7 @@ pctrie_node_get(struct pctrie *ptree, pctrie_alloc_t allocfn, uint64_t owner, */ static __inline void pctrie_node_put(struct pctrie *ptree, struct pctrie_node *node, - pctrie_free_t freefn) + pctrie_free_t freefn, int8_t last) { #ifdef INVARIANTS int slot; @@ -112,10 +134,14 @@ pctrie_node_put(struct pctrie *ptree, struct pctrie_node *node, KASSERT(node->pn_count == 0, ("pctrie_node_put: node %p has %d children", node, node->pn_count)); - for (slot = 0; slot < PCTRIE_COUNT; slot++) - KASSERT(node->pn_child[slot] == NULL, - ("pctrie_node_put: node %p has a child", node)); + for (slot = 0; slot < PCTRIE_COUNT; slot++) { + if (slot == last) + continue; + KASSERT(smr_unserialized_load(&node->pn_child[slot], true) == + NULL, ("pctrie_node_put: node %p has a child", node)); + } #endif + node->pn_last = last + 1; freefn(ptree, node); } @@ -143,24 +169,59 @@ pctrie_trimkey(uint64_t index, uint16_t level) return (ret); } +/* + * Fetch a node pointer from a slot. + */ +static __inline struct pctrie_node * +pctrie_node_load(smr_pctnode_t *p, smr_t smr, enum pctrie_access access) +{ + switch (access) { + case PCTRIE_UNSERIALIZED: + return (smr_unserialized_load(p, true)); + case PCTRIE_LOCKED: + return (smr_serialized_load(p, true)); + case PCTRIE_SMR: + return (smr_entered_load(p, smr)); + } + __assert_unreachable(); +} + +static __inline void +pctrie_node_store(smr_pctnode_t *p, void *v, enum pctrie_access access) +{ + switch (access) { + case PCTRIE_UNSERIALIZED: + smr_unserialized_store(p, v, true); + break; + case PCTRIE_LOCKED: + smr_serialized_store(p, v, true); + break; + case PCTRIE_SMR: + panic("%s: Not supported in SMR section.", __func__); + break; + default: + __assert_unreachable(); + break; + } +} + /* * Get the root node for a tree. */ static __inline struct pctrie_node * -pctrie_getroot(struct pctrie *ptree) +pctrie_root_load(struct pctrie *ptree, smr_t smr, enum pctrie_access access) { - - return ((struct pctrie_node *)ptree->pt_root); + return (pctrie_node_load((smr_pctnode_t *)&ptree->pt_root, smr, access)); } /* * Set the root node for a tree. */ static __inline void -pctrie_setroot(struct pctrie *ptree, struct pctrie_node *node) +pctrie_root_store(struct pctrie *ptree, struct pctrie_node *node, + enum pctrie_access access) { - - ptree->pt_root = (uintptr_t)node; + pctrie_node_store((smr_pctnode_t *)&ptree->pt_root, node, access); } /* @@ -188,12 +249,13 @@ pctrie_toval(struct pctrie_node *node) */ static __inline void pctrie_addval(struct pctrie_node *node, uint64_t index, uint16_t clev, - uint64_t *val) + uint64_t *val, enum pctrie_access access) { int slot; slot = pctrie_slot(index, clev); - node->pn_child[slot] = (void *)((uintptr_t)val | PCTRIE_ISLEAF); + pctrie_node_store(&node->pn_child[slot], + (void *)((uintptr_t)val | PCTRIE_ISLEAF), access); } /* @@ -237,20 +299,23 @@ static void pctrie_reclaim_allnodes_int(struct pctrie *ptree, struct pctrie_node *node, pctrie_free_t freefn) { + struct pctrie_node *child; int slot; KASSERT(node->pn_count <= PCTRIE_COUNT, ("pctrie_reclaim_allnodes_int: bad count in node %p", node)); for (slot = 0; node->pn_count != 0; slot++) { - if (node->pn_child[slot] == NULL) + child = pctrie_node_load(&node->pn_child[slot], NULL, + PCTRIE_UNSERIALIZED); + if (child == NULL) continue; - if (!pctrie_isleaf(node->pn_child[slot])) - pctrie_reclaim_allnodes_int(ptree, - node->pn_child[slot], freefn); - node->pn_child[slot] = NULL; + if (!pctrie_isleaf(child)) + pctrie_reclaim_allnodes_int(ptree, child, freefn); + pctrie_node_store(&node->pn_child[slot], NULL, + PCTRIE_UNSERIALIZED); node->pn_count--; } - pctrie_node_put(ptree, node, freefn); + pctrie_node_put(ptree, node, freefn, -1); } /* @@ -262,6 +327,7 @@ pctrie_zone_init(void *mem, int size __unused, int flags __unused) struct pctrie_node *node; node = mem; + node->pn_last = 0; memset(node->pn_child, 0, sizeof(node->pn_child)); return (0); } @@ -281,8 +347,8 @@ int pctrie_insert(struct pctrie *ptree, uint64_t *val, pctrie_alloc_t allocfn) { uint64_t index, newind; - void **parentp; struct pctrie_node *node, *tmp; + smr_pctnode_t *parentp; uint64_t *m; int slot; uint16_t clev; @@ -293,12 +359,12 @@ pctrie_insert(struct pctrie *ptree, uint64_t *val, pctrie_alloc_t allocfn) * The owner of record for root is not really important because it * will never be used. */ - node = pctrie_getroot(ptree); + node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); if (node == NULL) { ptree->pt_root = (uintptr_t)val | PCTRIE_ISLEAF; return (0); } - parentp = (void **)&ptree->pt_root; + parentp = (smr_pctnode_t *)&ptree->pt_root; for (;;) { if (pctrie_isleaf(node)) { m = pctrie_toval(node); @@ -310,20 +376,25 @@ pctrie_insert(struct pctrie *ptree, uint64_t *val, pctrie_alloc_t allocfn) pctrie_trimkey(index, clev + 1), 2, clev); if (tmp == NULL) return (ENOMEM); - *parentp = tmp; - pctrie_addval(tmp, index, clev, val); - pctrie_addval(tmp, *m, clev, m); + /* These writes are not yet visible due to ordering. */ + pctrie_addval(tmp, index, clev, val, + PCTRIE_UNSERIALIZED); + pctrie_addval(tmp, *m, clev, m, PCTRIE_UNSERIALIZED); + /* Synchronize to make leaf visible. */ + pctrie_node_store(parentp, tmp, PCTRIE_LOCKED); return (0); } else if (pctrie_keybarr(node, index)) break; slot = pctrie_slot(index, node->pn_clev); - if (node->pn_child[slot] == NULL) { + parentp = &node->pn_child[slot]; + tmp = pctrie_node_load(parentp, NULL, PCTRIE_LOCKED); + if (tmp == NULL) { node->pn_count++; - pctrie_addval(node, index, node->pn_clev, val); + pctrie_addval(node, index, node->pn_clev, val, + PCTRIE_LOCKED); return (0); } - parentp = &node->pn_child[slot]; - node = node->pn_child[slot]; + node = tmp; } /* @@ -337,10 +408,12 @@ pctrie_insert(struct pctrie *ptree, uint64_t *val, pctrie_alloc_t allocfn) pctrie_trimkey(index, clev + 1), 2, clev); if (tmp == NULL) return (ENOMEM); - *parentp = tmp; - pctrie_addval(tmp, index, clev, val); slot = pctrie_slot(newind, clev); - tmp->pn_child[slot] = node; + /* These writes are not yet visible due to ordering. */ + pctrie_addval(tmp, index, clev, val, PCTRIE_UNSERIALIZED); + pctrie_node_store(&tmp->pn_child[slot], node, PCTRIE_UNSERIALIZED); + /* Synchronize to make the above visible. */ + pctrie_node_store(parentp, tmp, PCTRIE_LOCKED); return (0); } @@ -349,31 +422,61 @@ pctrie_insert(struct pctrie *ptree, uint64_t *val, pctrie_alloc_t allocfn) * Returns the value stored at the index. If the index is not present, * NULL is returned. */ -uint64_t * -pctrie_lookup(struct pctrie *ptree, uint64_t index) +static __always_inline uint64_t * +_pctrie_lookup(struct pctrie *ptree, uint64_t index, smr_t smr, + enum pctrie_access access) { struct pctrie_node *node; uint64_t *m; int slot; - node = pctrie_getroot(ptree); + node = pctrie_root_load(ptree, smr, access); while (node != NULL) { if (pctrie_isleaf(node)) { m = pctrie_toval(node); if (*m == index) return (m); - else - break; - } else if (pctrie_keybarr(node, index)) + break; + } + if (pctrie_keybarr(node, index)) break; slot = pctrie_slot(index, node->pn_clev); - node = node->pn_child[slot]; + node = pctrie_node_load(&node->pn_child[slot], smr, access); } return (NULL); } /* - * Look up the nearest entry at a position bigger than or equal to index. + * Returns the value stored at the index, assuming access is externally + * synchronized by a lock. + * + * If the index is not present, NULL is returned. + */ +uint64_t * +pctrie_lookup(struct pctrie *ptree, uint64_t index) +{ + return (_pctrie_lookup(ptree, index, NULL, PCTRIE_LOCKED)); +} + +/* + * Returns the value stored at the index without requiring an external lock. + * + * If the index is not present, NULL is returned. + */ +uint64_t * +pctrie_lookup_unlocked(struct pctrie *ptree, uint64_t index, smr_t smr) +{ + uint64_t *res; + + smr_enter(smr); + res = _pctrie_lookup(ptree, index, smr, PCTRIE_SMR); + smr_exit(smr); + return (res); +} + +/* + * Look up the nearest entry at a position bigger than or equal to index, + * assuming access is externally synchronized by a lock. */ uint64_t * pctrie_lookup_ge(struct pctrie *ptree, uint64_t index) @@ -388,7 +491,7 @@ pctrie_lookup_ge(struct pctrie *ptree, uint64_t index) unsigned tos; int slot; - node = pctrie_getroot(ptree); + node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); if (node == NULL) return (NULL); else if (pctrie_isleaf(node)) { @@ -404,7 +507,7 @@ pctrie_lookup_ge(struct pctrie *ptree, uint64_t index) * If the keys differ before the current bisection node, * then the search key might rollback to the earliest * available bisection node or to the smallest key - * in the current node (if the owner is bigger than the + * in the current node (if the owner is greater than the * search key). */ if (pctrie_keybarr(node, index)) { @@ -439,7 +542,8 @@ pctrie_lookup_ge(struct pctrie *ptree, uint64_t index) ("pctrie_lookup_ge: keybarr failed")); } slot = pctrie_slot(index, node->pn_clev); - child = node->pn_child[slot]; + child = pctrie_node_load(&node->pn_child[slot], NULL, + PCTRIE_LOCKED); if (pctrie_isleaf(child)) { m = pctrie_toval(child); if (*m >= index) @@ -457,7 +561,8 @@ pctrie_lookup_ge(struct pctrie *ptree, uint64_t index) do { index += inc; slot++; - child = node->pn_child[slot]; + child = pctrie_node_load(&node->pn_child[slot], + NULL, PCTRIE_LOCKED); if (pctrie_isleaf(child)) { m = pctrie_toval(child); if (*m >= index) @@ -470,7 +575,7 @@ pctrie_lookup_ge(struct pctrie *ptree, uint64_t index) ("pctrie_lookup_ge: child is radix node")); /* - * If a value or edge bigger than the search slot is not found + * If a value or edge greater than the search slot is not found * in the current node, ascend to the next higher-level node. */ goto ascend; @@ -485,7 +590,8 @@ pctrie_lookup_ge(struct pctrie *ptree, uint64_t index) } /* - * Look up the nearest entry at a position less than or equal to index. + * Look up the nearest entry at a position less than or equal to index, + * assuming access is externally synchronized by a lock. */ uint64_t * pctrie_lookup_le(struct pctrie *ptree, uint64_t index) @@ -500,7 +606,7 @@ pctrie_lookup_le(struct pctrie *ptree, uint64_t index) unsigned tos; int slot; - node = pctrie_getroot(ptree); + node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); if (node == NULL) return (NULL); else if (pctrie_isleaf(node)) { @@ -553,7 +659,8 @@ pctrie_lookup_le(struct pctrie *ptree, uint64_t index) ("pctrie_lookup_le: keybarr failed")); } slot = pctrie_slot(index, node->pn_clev); - child = node->pn_child[slot]; + child = pctrie_node_load(&node->pn_child[slot], NULL, + PCTRIE_LOCKED); if (pctrie_isleaf(child)) { m = pctrie_toval(child); if (*m <= index) @@ -571,7 +678,8 @@ pctrie_lookup_le(struct pctrie *ptree, uint64_t index) do { index -= inc; slot--; - child = node->pn_child[slot]; + child = pctrie_node_load(&node->pn_child[slot], + NULL, PCTRIE_LOCKED); if (pctrie_isleaf(child)) { m = pctrie_toval(child); if (*m <= index) @@ -605,16 +713,16 @@ pctrie_lookup_le(struct pctrie *ptree, uint64_t index) void pctrie_remove(struct pctrie *ptree, uint64_t index, pctrie_free_t freefn) { - struct pctrie_node *node, *parent; + struct pctrie_node *node, *parent, *tmp; uint64_t *m; int i, slot; - node = pctrie_getroot(ptree); + node = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); if (pctrie_isleaf(node)) { m = pctrie_toval(node); if (*m != index) panic("%s: invalid key found", __func__); - pctrie_setroot(ptree, NULL); + pctrie_root_store(ptree, NULL, PCTRIE_LOCKED); return; } parent = NULL; @@ -622,34 +730,46 @@ pctrie_remove(struct pctrie *ptree, uint64_t index, pctrie_free_t freefn) if (node == NULL) panic("pctrie_remove: impossible to locate the key"); slot = pctrie_slot(index, node->pn_clev); - if (pctrie_isleaf(node->pn_child[slot])) { - m = pctrie_toval(node->pn_child[slot]); + tmp = pctrie_node_load(&node->pn_child[slot], NULL, + PCTRIE_LOCKED); + if (pctrie_isleaf(tmp)) { + m = pctrie_toval(tmp); if (*m != index) panic("%s: invalid key found", __func__); - node->pn_child[slot] = NULL; + pctrie_node_store(&node->pn_child[slot], NULL, + PCTRIE_LOCKED); node->pn_count--; if (node->pn_count > 1) break; - for (i = 0; i < PCTRIE_COUNT; i++) - if (node->pn_child[i] != NULL) + for (i = 0; i < PCTRIE_COUNT; i++) { + tmp = pctrie_node_load(&node->pn_child[i], + NULL, PCTRIE_LOCKED); + if (tmp != NULL) break; + } KASSERT(i != PCTRIE_COUNT, ("%s: invalid node configuration", __func__)); if (parent == NULL) - pctrie_setroot(ptree, node->pn_child[i]); + pctrie_root_store(ptree, tmp, PCTRIE_LOCKED); else { slot = pctrie_slot(index, parent->pn_clev); - KASSERT(parent->pn_child[slot] == node, + KASSERT(pctrie_node_load( + &parent->pn_child[slot], NULL, + PCTRIE_LOCKED) == node, ("%s: invalid child value", __func__)); - parent->pn_child[slot] = node->pn_child[i]; + pctrie_node_store(&parent->pn_child[slot], tmp, + PCTRIE_LOCKED); } + /* + * The child is still valid and we can not zero the + * pointer until all SMR references are gone. + */ node->pn_count--; - node->pn_child[i] = NULL; - pctrie_node_put(ptree, node, freefn); + pctrie_node_put(ptree, node, freefn, i); break; } parent = node; - node = node->pn_child[slot]; + node = tmp; } } @@ -663,10 +783,10 @@ pctrie_reclaim_allnodes(struct pctrie *ptree, pctrie_free_t freefn) { struct pctrie_node *root; - root = pctrie_getroot(ptree); + root = pctrie_root_load(ptree, NULL, PCTRIE_LOCKED); if (root == NULL) return; - pctrie_setroot(ptree, NULL); + pctrie_root_store(ptree, NULL, PCTRIE_UNSERIALIZED); if (!pctrie_isleaf(root)) pctrie_reclaim_allnodes_int(ptree, root, freefn); } @@ -677,7 +797,7 @@ pctrie_reclaim_allnodes(struct pctrie *ptree, pctrie_free_t freefn) */ DB_SHOW_COMMAND(pctrienode, db_show_pctrienode) { - struct pctrie_node *node; + struct pctrie_node *node, *tmp; int i; if (!have_addr) @@ -686,12 +806,14 @@ DB_SHOW_COMMAND(pctrienode, db_show_pctrienode) db_printf("node %p, owner %jx, children count %u, level %u:\n", (void *)node, (uintmax_t)node->pn_owner, node->pn_count, node->pn_clev); - for (i = 0; i < PCTRIE_COUNT; i++) - if (node->pn_child[i] != NULL) + for (i = 0; i < PCTRIE_COUNT; i++) { + tmp = pctrie_node_load(&node->pn_child[i], NULL, + PCTRIE_UNSERIALIZED); + if (tmp != NULL) db_printf("slot: %d, val: %p, value: %p, clev: %d\n", - i, (void *)node->pn_child[i], - pctrie_isleaf(node->pn_child[i]) ? - pctrie_toval(node->pn_child[i]) : NULL, + i, (void *)tmp, + pctrie_isleaf(tmp) ? pctrie_toval(tmp) : NULL, node->pn_clev); + } } #endif /* DDB */ diff --git a/sys/sys/pctrie.h b/sys/sys/pctrie.h index 6e9528f24a3d..5cf740b25d7a 100644 --- a/sys/sys/pctrie.h +++ b/sys/sys/pctrie.h @@ -34,9 +34,21 @@ #define _SYS_PCTRIE_H_ #include +#include #ifdef _KERNEL +#define PCTRIE_DEFINE_SMR(name, type, field, allocfn, freefn, smr) \ + PCTRIE_DEFINE(name, type, field, allocfn, freefn) \ + \ +static __inline struct type * \ +name##_PCTRIE_LOOKUP_UNLOCKED(struct pctrie *ptree, uint64_t key) \ +{ \ + \ + return name##_PCTRIE_VAL2PTR(pctrie_lookup_unlocked(ptree, \ + key, (smr))); \ +} \ + #define PCTRIE_DEFINE(name, type, field, allocfn, freefn) \ \ CTASSERT(sizeof(((struct type *)0)->field) == sizeof(uint64_t)); \ @@ -114,6 +126,8 @@ int pctrie_insert(struct pctrie *ptree, uint64_t *val, uint64_t *pctrie_lookup(struct pctrie *ptree, uint64_t key); uint64_t *pctrie_lookup_ge(struct pctrie *ptree, uint64_t key); uint64_t *pctrie_lookup_le(struct pctrie *ptree, uint64_t key); +uint64_t *pctrie_lookup_unlocked(struct pctrie *ptree, uint64_t key, + smr_t smr); void pctrie_reclaim_allnodes(struct pctrie *ptree, pctrie_free_t freefn); void pctrie_remove(struct pctrie *ptree, uint64_t key, From 68ee1dda06464fe490c263be53c9032789d339f8 Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Fri, 24 Jul 2020 17:34:04 +0000 Subject: [PATCH 142/287] Add unlocked/SMR fast path to getblk() Convert the bufobj tries to an SMR zone/PCTRIE and add a gbincore_unlocked() API wrapping this functionality. Use it for a fast path in getblkx(), falling back to locked lookup if we raced a thread changing the buf's identity. Reported by: Attilio Reviewed by: kib, markj Testing: pho (in progress) Sponsored by: Isilon Differential Revision: https://reviews.freebsd.org/D25782 --- sys/kern/vfs_bio.c | 31 ++++++++++++++++++++++++++++--- sys/kern/vfs_subr.c | 33 ++++++++++++++++++++++++++------- sys/sys/buf.h | 4 ++++ 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 9d5d543fbc7e..d74b6dcb2a08 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -3849,7 +3849,7 @@ getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag, struct buf *bp; struct bufobj *bo; daddr_t d_blkno; - int bsize, error, maxsize, vmio; + int bsize, error, maxsize, vmio, lockflags; off_t offset; CTR3(KTR_BUF, "getblk(%p, %ld, %d)", vp, (long)blkno, size); @@ -3864,11 +3864,33 @@ getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag, bo = &vp->v_bufobj; d_blkno = dblkno; + + /* Attempt lockless lookup first. */ + bp = gbincore_unlocked(bo, blkno); + if (bp == NULL) + goto newbuf_unlocked; + + lockflags = LK_EXCLUSIVE | LK_SLEEPFAIL | + ((flags & GB_LOCK_NOWAIT) ? LK_NOWAIT : 0); + + error = BUF_TIMELOCK(bp, lockflags, NULL, "getblku", slpflag, + slptimeo); + if (error == EINTR || error == ERESTART) + return (error); + else if (error != 0) + goto loop; + + /* Verify buf identify has not changed since lookup. */ + if (bp->b_bufobj == bo && bp->b_lblkno == blkno) + goto foundbuf_fastpath; + + /* It changed, fallback to locked lookup. */ + BUF_UNLOCK_RAW(bp); + loop: BO_RLOCK(bo); bp = gbincore(bo, blkno); if (bp != NULL) { - int lockflags; /* * Buffer is in-core. If the buffer is not busy nor managed, * it must be on a queue. @@ -3890,8 +3912,10 @@ getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag, /* We timed out or were interrupted. */ else if (error != 0) return (error); + +foundbuf_fastpath: /* If recursed, assume caller knows the rules. */ - else if (BUF_LOCKRECURSED(bp)) + if (BUF_LOCKRECURSED(bp)) goto end; /* @@ -3989,6 +4013,7 @@ getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag, * buffer is also considered valid (not marked B_INVAL). */ BO_RUNLOCK(bo); +newbuf_unlocked: /* * If the user does not want us to create the buffer, bail out * here. diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 5f964c534dfe..51ec4390da7f 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -234,6 +234,7 @@ static struct mtx __exclusive_cache_line vnode_list_mtx; struct nfs_public nfs_pub; static uma_zone_t buf_trie_zone; +static smr_t buf_trie_smr; /* Zone for allocation of new vnodes - used exclusively by getnewvnode() */ static uma_zone_t vnode_zone; @@ -491,17 +492,16 @@ static int vnsz2log; static void * buf_trie_alloc(struct pctrie *ptree) { - - return uma_zalloc(buf_trie_zone, M_NOWAIT); + return (uma_zalloc_smr(buf_trie_zone, M_NOWAIT)); } static void buf_trie_free(struct pctrie *ptree, void *node) { - - uma_zfree(buf_trie_zone, node); + uma_zfree_smr(buf_trie_zone, node); } -PCTRIE_DEFINE(BUF, buf, b_lblkno, buf_trie_alloc, buf_trie_free); +PCTRIE_DEFINE_SMR(BUF, buf, b_lblkno, buf_trie_alloc, buf_trie_free, + buf_trie_smr); /* * Initialize the vnode management data structures. @@ -675,7 +675,8 @@ vntblinit(void *dummy __unused) */ buf_trie_zone = uma_zcreate("BUF TRIE", pctrie_node_size(), NULL, NULL, pctrie_zone_init, NULL, UMA_ALIGN_PTR, - UMA_ZONE_NOFREE); + UMA_ZONE_NOFREE | UMA_ZONE_SMR); + buf_trie_smr = uma_zone_get_smr(buf_trie_zone); uma_prealloc(buf_trie_zone, nbuf); vnodes_created = counter_u64_alloc(M_WAITOK); @@ -2330,7 +2331,25 @@ gbincore(struct bufobj *bo, daddr_t lblkno) bp = BUF_PCTRIE_LOOKUP(&bo->bo_clean.bv_root, lblkno); if (bp != NULL) return (bp); - return BUF_PCTRIE_LOOKUP(&bo->bo_dirty.bv_root, lblkno); + return (BUF_PCTRIE_LOOKUP(&bo->bo_dirty.bv_root, lblkno)); +} + +/* + * Look up a buf using the buffer tries, without the bufobj lock. This relies + * on SMR for safe lookup, and bufs being in a no-free zone to provide type + * stability of the result. Like other lockless lookups, the found buf may + * already be invalid by the time this function returns. + */ +struct buf * +gbincore_unlocked(struct bufobj *bo, daddr_t lblkno) +{ + struct buf *bp; + + ASSERT_BO_UNLOCKED(bo); + bp = BUF_PCTRIE_LOOKUP_UNLOCKED(&bo->bo_clean.bv_root, lblkno); + if (bp != NULL) + return (bp); + return (BUF_PCTRIE_LOOKUP_UNLOCKED(&bo->bo_dirty.bv_root, lblkno)); } /* diff --git a/sys/sys/buf.h b/sys/sys/buf.h index 2b0aa1c7f688..574a1446ead9 100644 --- a/sys/sys/buf.h +++ b/sys/sys/buf.h @@ -326,6 +326,9 @@ extern const char *buf_wmesg; /* Default buffer lock message */ KASSERT(((bp)->b_flags & B_REMFREE) == 0, \ ("BUF_UNLOCK %p while B_REMFREE is still set.", (bp))); \ \ + BUF_UNLOCK_RAW((bp)); \ +} while (0) +#define BUF_UNLOCK_RAW(bp) do { \ (void)_lockmgr_args(&(bp)->b_lock, LK_RELEASE, NULL, \ LK_WMESG_DEFAULT, LK_PRIO_DEFAULT, LK_TIMO_DEFAULT, \ LOCK_FILE, LOCK_LINE); \ @@ -547,6 +550,7 @@ void vfs_busy_pages_acquire(struct buf *bp); void vfs_busy_pages_release(struct buf *bp); struct buf *incore(struct bufobj *, daddr_t); struct buf *gbincore(struct bufobj *, daddr_t); +struct buf *gbincore_unlocked(struct bufobj *, daddr_t); struct buf *getblk(struct vnode *, daddr_t, int, int, int, int); int getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag, int slptimeo, int flags, struct buf **bpp); From 81dc6c2c61a70c21b61ca296fb64dfd7b215a77e Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Fri, 24 Jul 2020 17:34:44 +0000 Subject: [PATCH 143/287] Use gbincore_unlocked for unprotected incore() Reviewed by: markj Sponsored by: Isilon Differential Revision: https://reviews.freebsd.org/D25790 --- sys/kern/vfs_bio.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index d74b6dcb2a08..0deb5ff785c4 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -3576,12 +3576,7 @@ flushbufqueues(struct vnode *lvp, struct bufdomain *bd, int target, struct buf * incore(struct bufobj *bo, daddr_t blkno) { - struct buf *bp; - - BO_RLOCK(bo); - bp = gbincore(bo, blkno); - BO_RUNLOCK(bo); - return (bp); + return (gbincore_unlocked(bo, blkno)); } /* From f1ed7b6563cc2f24e586bda3a6d0eb7d462a83b0 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Fri, 24 Jul 2020 18:43:46 +0000 Subject: [PATCH 144/287] mmccam: Make non bootverbose more readable Remove some debug printfs. Convert some to CAM_DEBUG Only print some when bootverbose is set. --- sys/cam/mmc/mmc_xpt.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sys/cam/mmc/mmc_xpt.c b/sys/cam/mmc/mmc_xpt.c index ad3ea9d8633c..cf4a96e29d1c 100644 --- a/sys/cam/mmc/mmc_xpt.c +++ b/sys/cam/mmc/mmc_xpt.c @@ -179,7 +179,6 @@ mmc_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) { struct cam_ed *device; - printf("mmc_alloc_device()\n"); device = xpt_alloc_device(bus, target, lun_id); if (device == NULL) return (NULL); @@ -282,7 +281,8 @@ mmc_scan_lun(struct cam_periph *periph, struct cam_path *path, xpt_done(request_ccb); } } else { - xpt_print(path, " Set up the mmcprobe device...\n"); + if (bootverbose) + xpt_print(path, " Set up the mmcprobe device...\n"); status = cam_periph_alloc(mmcprobe_register, NULL, mmcprobe_cleanup, @@ -829,7 +829,6 @@ mmcprobe_done(struct cam_periph *periph, union ccb *done_ccb) /* FALLTHROUGH */ case PROBE_IDENTIFY: { - printf("Starting completion of PROBE_RESET\n"); CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("done with PROBE_RESET\n")); mmcio = &done_ccb->mmcio; err = mmcio->cmd.error; @@ -1149,7 +1148,7 @@ mmcprobe_done(struct cam_periph *periph, union ccb *done_ccb) xpt_schedule(periph, priority); /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */ int frozen = cam_release_devq(path, 0, 0, 0, FALSE); - printf("mmc_probedone: remaining freezecnt %d\n", frozen); + CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("mmc_probedone: remaining freezecnt %d\n", frozen)); if (softc->action == PROBE_DONE) { /* Notify the system that the device is found! */ From a6d9c9257c2816ea280b562de3107825624bdb57 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Fri, 24 Jul 2020 18:44:50 +0000 Subject: [PATCH 145/287] mmccam: aw_mmc: Only print the new ios value under bootverbose --- sys/arm/allwinner/aw_mmc.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/sys/arm/allwinner/aw_mmc.c b/sys/arm/allwinner/aw_mmc.c index c8d3c2694d36..dd3992771375 100644 --- a/sys/arm/allwinner/aw_mmc.c +++ b/sys/arm/allwinner/aw_mmc.c @@ -300,31 +300,38 @@ aw_mmc_cam_settran_settings(struct aw_mmc_softc *sc, union ccb *ccb) /* Update only requested fields */ if (cts->ios_valid & MMC_CLK) { ios->clock = new_ios->clock; - device_printf(sc->aw_dev, "Clock => %d\n", ios->clock); + if (bootverbose) + device_printf(sc->aw_dev, "Clock => %d\n", ios->clock); } if (cts->ios_valid & MMC_VDD) { ios->vdd = new_ios->vdd; - device_printf(sc->aw_dev, "VDD => %d\n", ios->vdd); + if (bootverbose) + device_printf(sc->aw_dev, "VDD => %d\n", ios->vdd); } if (cts->ios_valid & MMC_CS) { ios->chip_select = new_ios->chip_select; - device_printf(sc->aw_dev, "CS => %d\n", ios->chip_select); + if (bootverbose) + device_printf(sc->aw_dev, "CS => %d\n", ios->chip_select); } if (cts->ios_valid & MMC_BW) { ios->bus_width = new_ios->bus_width; - device_printf(sc->aw_dev, "Bus width => %d\n", ios->bus_width); + if (bootverbose) + device_printf(sc->aw_dev, "Bus width => %d\n", ios->bus_width); } if (cts->ios_valid & MMC_PM) { ios->power_mode = new_ios->power_mode; - device_printf(sc->aw_dev, "Power mode => %d\n", ios->power_mode); + if (bootverbose) + device_printf(sc->aw_dev, "Power mode => %d\n", ios->power_mode); } if (cts->ios_valid & MMC_BT) { ios->timing = new_ios->timing; - device_printf(sc->aw_dev, "Timing => %d\n", ios->timing); + if (bootverbose) + device_printf(sc->aw_dev, "Timing => %d\n", ios->timing); } if (cts->ios_valid & MMC_BM) { ios->bus_mode = new_ios->bus_mode; - device_printf(sc->aw_dev, "Bus mode => %d\n", ios->bus_mode); + if (bootverbose) + device_printf(sc->aw_dev, "Bus mode => %d\n", ios->bus_mode); } return (aw_mmc_update_ios(sc->aw_dev, NULL)); From 41c653be9866e5823882027e4c7ab28c6eb96a2e Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Fri, 24 Jul 2020 19:52:52 +0000 Subject: [PATCH 146/287] dwmmc: Add MMCCAM part Add support for MMCCAM for dwmmc Submitted by: kibab Tested On: Rock64, RockPro64 --- sys/dev/mmc/host/dwmmc.c | 323 ++++++++++++++++++++++++++++++++++- sys/dev/mmc/host/dwmmc_var.h | 9 + 2 files changed, 328 insertions(+), 4 deletions(-) diff --git a/sys/dev/mmc/host/dwmmc.c b/sys/dev/mmc/host/dwmmc.c index c3922d08c1dd..682d4db81b2b 100644 --- a/sys/dev/mmc/host/dwmmc.c +++ b/sys/dev/mmc/host/dwmmc.c @@ -68,9 +68,23 @@ __FBSDID("$FreeBSD$"); #include #include +#include "opt_mmccam.h" + +#ifdef MMCCAM +#include +#include +#include +#include +#include +#endif + #include "mmcbr_if.h" +#ifdef DEBUG +#define dprintf(fmt, args...) printf(fmt, ##args) +#else #define dprintf(x, arg...) +#endif #define READ4(_sc, _reg) \ bus_read_4((_sc)->res[0], _reg) @@ -129,6 +143,14 @@ 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 void dwmmc_handle_card_present(struct dwmmc_softc *sc, bool is_present); +static int dwmmc_switch_vccq(device_t, device_t); +#ifdef MMCCAM +static void dwmmc_cam_action(struct cam_sim *, union ccb *); +static void dwmmc_cam_poll(struct cam_sim *); +static int dwmmc_cam_settran_settings(struct dwmmc_softc *, union ccb *); +static int dwmmc_cam_request(struct dwmmc_softc *, union ccb *); +static void dwmmc_cam_handle_mmcio(struct cam_sim *, union ccb *); +#endif static struct resource_spec dwmmc_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, @@ -286,8 +308,18 @@ static void dwmmc_cmd_done(struct dwmmc_softc *sc) { struct mmc_command *cmd; +#ifdef MMCCAM + union ccb *ccb; +#endif +#ifdef MMCCAM + ccb = sc->ccb; + if (ccb == NULL) + return; + cmd = &ccb->mmcio.cmd; +#else cmd = sc->curcmd; +#endif if (cmd == NULL) return; @@ -432,6 +464,9 @@ dwmmc_card_task(void *arg, int pending __unused) { struct dwmmc_softc *sc = arg; +#ifdef MMCCAM + mmccam_start_discovery(sc->sim); +#else DWMMC_LOCK(sc); if (READ4(sc, SDMMC_CDETECT) == 0) { @@ -459,6 +494,7 @@ dwmmc_card_task(void *arg, int pending __unused) } else DWMMC_UNLOCK(sc); } +#endif /* MMCCAM */ } static int @@ -721,12 +757,40 @@ dwmmc_attach(device_t dev) TIMEOUT_TASK_INIT(taskqueue_swi_giant, &sc->card_delayed_task, 0, dwmmc_card_task, sc); +#ifdef MMCCAM + sc->ccb = NULL; + if ((sc->devq = cam_simq_alloc(1)) == NULL) { + goto fail; + } + + mtx_init(&sc->sim_mtx, "dwmmcsim", NULL, MTX_DEF); + sc->sim = cam_sim_alloc_dev(dwmmc_cam_action, dwmmc_cam_poll, + "dw_mmc_sim", sc, dev, + &sc->sim_mtx, 1, 1, sc->devq); + + if (sc->sim == NULL) { + cam_simq_free(sc->devq); + device_printf(dev, "cannot allocate CAM SIM\n"); + goto fail; + } + + mtx_lock(&sc->sim_mtx); + if (xpt_bus_register(sc->sim, sc->dev, 0) != 0) { + device_printf(sc->dev, "cannot register SCSI pass-through bus\n"); + cam_sim_free(sc->sim, FALSE); + cam_simq_free(sc->devq); + mtx_unlock(&sc->sim_mtx); + goto fail; + } + +fail: + mtx_unlock(&sc->sim_mtx); +#endif /* * Schedule a card detection as we won't get an interrupt * if the card is inserted when we attach */ dwmmc_card_task(sc, 0); - return (0); } @@ -1041,15 +1105,17 @@ dwmmc_start_cmd(struct dwmmc_softc *sc, struct mmc_command *cmd) uint32_t blksz; uint32_t cmdr; + dprintf("%s\n", __func__); sc->curcmd = cmd; data = cmd->data; if ((sc->hwtype & HWTYPE_MASK) == HWTYPE_ROCKCHIP) dwmmc_setup_bus(sc, sc->host.ios.clock); +#ifndef MMCCAM /* XXX Upper layers don't always set this */ cmd->mrq = sc->req; - +#endif /* Begin setting up command register. */ cmdr = cmd->opcode; @@ -1119,11 +1185,23 @@ dwmmc_start_cmd(struct dwmmc_softc *sc, struct mmc_command *cmd) static void dwmmc_next_operation(struct dwmmc_softc *sc) { + struct mmc_command *cmd; + dprintf("%s\n", __func__); +#ifdef MMCCAM + union ccb *ccb; + + ccb = sc->ccb; + if (ccb == NULL) + return; + cmd = &ccb->mmcio.cmd; +#else struct mmc_request *req; req = sc->req; if (req == NULL) return; + cmd = req->cmd; +#endif sc->acd_rcvd = 0; sc->dto_rcvd = 0; @@ -1140,17 +1218,26 @@ dwmmc_next_operation(struct dwmmc_softc *sc) if (sc->flags & PENDING_CMD) { sc->flags &= ~PENDING_CMD; - dwmmc_start_cmd(sc, req->cmd); + dwmmc_start_cmd(sc, cmd); return; } else if (sc->flags & PENDING_STOP && !sc->use_auto_stop) { sc->flags &= ~PENDING_STOP; - dwmmc_start_cmd(sc, req->stop); + /// XXX: What to do with this? + //dwmmc_start_cmd(sc, req->stop); return; } +#ifdef MMCCAM + sc->ccb = NULL; + sc->curcmd = NULL; + ccb->ccb_h.status = + (ccb->mmcio.cmd.error == 0 ? CAM_REQ_CMP : CAM_REQ_CMP_ERR); + xpt_done(ccb); +#else sc->req = NULL; sc->curcmd = NULL; req->done(req); +#endif } static int @@ -1164,6 +1251,9 @@ dwmmc_request(device_t brdev, device_t reqdev, struct mmc_request *req) DWMMC_LOCK(sc); +#ifdef MMCCAM + sc->flags |= PENDING_CMD; +#else if (sc->req != NULL) { DWMMC_UNLOCK(sc); return (EBUSY); @@ -1173,6 +1263,7 @@ dwmmc_request(device_t brdev, device_t reqdev, struct mmc_request *req) sc->flags |= PENDING_CMD; if (sc->req->stop) sc->flags |= PENDING_STOP; +#endif dwmmc_next_operation(sc); DWMMC_UNLOCK(sc); @@ -1327,6 +1418,230 @@ dwmmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value) return (0); } +/* Note: this function likely belongs to the specific driver impl */ +static int +dwmmc_switch_vccq(device_t dev, device_t child) +{ + device_printf(dev, "This is a default impl of switch_vccq() that always fails\n"); + return EINVAL; +} + +#ifdef MMCCAM +static void +dwmmc_cam_handle_mmcio(struct cam_sim *sim, union ccb *ccb) +{ + struct dwmmc_softc *sc; + + sc = cam_sim_softc(sim); + + dwmmc_cam_request(sc, ccb); +} + +static void +dwmmc_cam_action(struct cam_sim *sim, union ccb *ccb) +{ + struct dwmmc_softc *sc; + + sc = cam_sim_softc(sim); + if (sc == NULL) { + ccb->ccb_h.status = CAM_SEL_TIMEOUT; + xpt_done(ccb); + return; + } + + mtx_assert(&sc->sim_mtx, MA_OWNED); + + switch (ccb->ccb_h.func_code) { + case XPT_PATH_INQ: + /* XXX: correctly calculate maxio here */ + mmc_path_inq(&ccb->cpi, "Deglitch Networks", sim, MMC_SECTOR_SIZE); + break; + + case XPT_GET_TRAN_SETTINGS: + { + struct ccb_trans_settings *cts = &ccb->cts; + + if (bootverbose) + device_printf(sc->dev, "Got XPT_GET_TRAN_SETTINGS\n"); + + cts->protocol = PROTO_MMCSD; + cts->protocol_version = 1; + cts->transport = XPORT_MMCSD; + cts->transport_version = 1; + cts->xport_specific.valid = 0; + cts->proto_specific.mmc.host_ocr = sc->host.host_ocr; + cts->proto_specific.mmc.host_f_min = sc->host.f_min; + cts->proto_specific.mmc.host_f_max = sc->host.f_max; + cts->proto_specific.mmc.host_caps = sc->host.caps; + /* XXX: correctly calculate host_max_data */ + cts->proto_specific.mmc.host_max_data = 1; + memcpy(&cts->proto_specific.mmc.ios, &sc->host.ios, sizeof(struct mmc_ios)); + ccb->ccb_h.status = CAM_REQ_CMP; + break; + } + case XPT_SET_TRAN_SETTINGS: + { + if (bootverbose) + device_printf(sc->dev, "Got XPT_SET_TRAN_SETTINGS\n"); + dwmmc_cam_settran_settings(sc, ccb); + ccb->ccb_h.status = CAM_REQ_CMP; + break; + } + case XPT_RESET_BUS: { + struct ccb_trans_settings_mmc *cts; + + cts = &ccb->cts.proto_specific.mmc; + cts->ios_valid = MMC_PM; + cts->ios.power_mode = power_off; + /* Power off the MMC bus */ + if (dwmmc_cam_settran_settings(sc, ccb) != 0) { + device_printf(sc->dev,"cannot power down the MMC bus\n"); + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + break; + } + + /* Soft Reset controller and run initialization again */ + if (dwmmc_ctrl_reset(sc, (SDMMC_CTRL_RESET | + SDMMC_CTRL_FIFO_RESET | + SDMMC_CTRL_DMA_RESET)) != 0) { + device_printf(sc->dev, "cannot reset the controller\n"); + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + break; + } + + cts->ios_valid = MMC_PM; + cts->ios.power_mode = power_on; + /* Power off the MMC bus */ + if (dwmmc_cam_settran_settings(sc, ccb) != 0) { + device_printf(sc->dev, "cannot power on the MMC bus\n"); + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + break; + } + + ccb->ccb_h.status = CAM_REQ_CMP; + break; + } + case XPT_MMC_IO: + /* + * Here is the HW-dependent part of + * sending the command to the underlying h/w + * At some point in the future an interrupt comes. + * Then the request will be marked as completed. + */ + ccb->ccb_h.status = CAM_REQ_INPROG; + + dwmmc_cam_handle_mmcio(sim, ccb); + return; + /* NOTREACHED */ + break; + default: + ccb->ccb_h.status = CAM_REQ_INVALID; + break; + } + xpt_done(ccb); + return; +} + +static void +dwmmc_cam_poll(struct cam_sim *sim) +{ + return; +} + +static int +dwmmc_cam_settran_settings(struct dwmmc_softc *sc, union ccb *ccb) +{ + struct mmc_ios *ios; + struct mmc_ios *new_ios; + struct ccb_trans_settings_mmc *cts; + int res; + + ios = &sc->host.ios; + + cts = &ccb->cts.proto_specific.mmc; + new_ios = &cts->ios; + + /* Update only requested fields */ + if (cts->ios_valid & MMC_CLK) { + ios->clock = new_ios->clock; + if (bootverbose) + device_printf(sc->dev, "Clock => %d\n", ios->clock); + } + if (cts->ios_valid & MMC_VDD) { + ios->vdd = new_ios->vdd; + if (bootverbose) + device_printf(sc->dev, "VDD => %d\n", ios->vdd); + } + if (cts->ios_valid & MMC_CS) { + ios->chip_select = new_ios->chip_select; + if (bootverbose) + device_printf(sc->dev, "CS => %d\n", ios->chip_select); + } + if (cts->ios_valid & MMC_BW) { + ios->bus_width = new_ios->bus_width; + if (bootverbose) + device_printf(sc->dev, "Bus width => %d\n", ios->bus_width); + } + if (cts->ios_valid & MMC_PM) { + ios->power_mode = new_ios->power_mode; + if (bootverbose) + device_printf(sc->dev, "Power mode => %d\n", ios->power_mode); + } + if (cts->ios_valid & MMC_BT) { + ios->timing = new_ios->timing; + if (bootverbose) + device_printf(sc->dev, "Timing => %d\n", ios->timing); + } + if (cts->ios_valid & MMC_BM) { + ios->bus_mode = new_ios->bus_mode; + if (bootverbose) + device_printf(sc->dev, "Bus mode => %d\n", ios->bus_mode); + } + if (cts->ios_valid & MMC_VCCQ) { + ios->vccq = new_ios->vccq; + if (bootverbose) + device_printf(sc->dev, "VCCQ => %d\n", ios->vccq); + res = dwmmc_switch_vccq(sc->dev, NULL); + device_printf(sc->dev, "VCCQ switch result: %d\n", res); + } + + return (dwmmc_update_ios(sc->dev, NULL)); +} + +static int +dwmmc_cam_request(struct dwmmc_softc *sc, union ccb *ccb) +{ + struct ccb_mmcio *mmcio; + + mmcio = &ccb->mmcio; + + DWMMC_LOCK(sc); + +#ifdef DEBUG + if (__predict_false(bootverbose)) { + device_printf(sc->dev, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n", + mmcio->cmd.opcode, mmcio->cmd.arg, mmcio->cmd.flags, + mmcio->cmd.data != NULL ? (unsigned int) mmcio->cmd.data->len : 0, + mmcio->cmd.data != NULL ? mmcio->cmd.data->flags: 0); + } +#endif + if (mmcio->cmd.data != NULL) { + if (mmcio->cmd.data->len == 0 || mmcio->cmd.data->flags == 0) + panic("data->len = %d, data->flags = %d -- something is b0rked", + (int)mmcio->cmd.data->len, mmcio->cmd.data->flags); + } + if (sc->ccb != NULL) { + device_printf(sc->dev, "Controller still has an active command\n"); + return (EBUSY); + } + sc->ccb = ccb; + DWMMC_UNLOCK(sc); + dwmmc_request(sc->dev, NULL, NULL); + + return (0); +} +#endif + static device_method_t dwmmc_methods[] = { /* Bus interface */ DEVMETHOD(bus_read_ivar, dwmmc_read_ivar), diff --git a/sys/dev/mmc/host/dwmmc_var.h b/sys/dev/mmc/host/dwmmc_var.h index a9a77223f9e1..6c7aae79640d 100644 --- a/sys/dev/mmc/host/dwmmc_var.h +++ b/sys/dev/mmc/host/dwmmc_var.h @@ -39,6 +39,8 @@ #include #endif +#include "opt_mmccam.h" + enum { HWTYPE_NONE, HWTYPE_ALTERA, @@ -54,7 +56,14 @@ struct dwmmc_softc { struct mmc_host host; struct mmc_fdt_helper mmc_helper; struct mtx sc_mtx; +#ifdef MMCCAM + union ccb * ccb; + struct cam_devq * devq; + struct cam_sim * sim; + struct mtx sim_mtx; +#else struct mmc_request *req; +#endif struct mmc_command *curcmd; uint32_t flags; uint32_t hwtype; From 23ce4620920b0b1d306a2d8cc8e784c124d5cc47 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Fri, 24 Jul 2020 19:54:15 +0000 Subject: [PATCH 147/287] Make lapic_ipi_vectored(APIC_IPI_DEST_SELF) NMI safe. Sending IPI to self or all CPUs does not require write into upper part of the ICR, prone to races. Previously the code disabled interrupts, but it was not enough for NMIs. Instead of that when possible write only lower part of the register, or use special SELF IPI register in x2APIC mode. This also removes ICR reads used to preserve reserved bits on write. It was there from the beginning, but I failed to find explanation why, neither I see Linux doing it. Specification even tells that ICR content may be lost in deep C-states, so if hardware does not bother to preserve it, why should we? MFC after: 2 weeks Sponsored by: iXsystems, Inc. --- sys/x86/x86/local_apic.c | 116 ++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 63 deletions(-) diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c index ba64d1724524..878b0a0fa969 100644 --- a/sys/x86/x86/local_apic.c +++ b/sys/x86/x86/local_apic.c @@ -253,22 +253,6 @@ lapic_write32_nofence(enum LAPIC_REGISTERS reg, uint32_t val) } #ifdef SMP -static uint64_t -lapic_read_icr(void) -{ - uint64_t v; - uint32_t vhi, vlo; - - if (x2apic_mode) { - v = rdmsr(MSR_APIC_000 + LAPIC_ICR_LO); - } else { - vhi = lapic_read32(LAPIC_ICR_HI); - vlo = lapic_read32(LAPIC_ICR_LO); - v = ((uint64_t)vhi << 32) | vlo; - } - return (v); -} - static uint64_t lapic_read_icr_lo(void) { @@ -279,6 +263,7 @@ lapic_read_icr_lo(void) static void lapic_write_icr(uint32_t vhi, uint32_t vlo) { + register_t saveintr; uint64_t v; if (x2apic_mode) { @@ -286,10 +271,32 @@ lapic_write_icr(uint32_t vhi, uint32_t vlo) mfence(); wrmsr(MSR_APIC_000 + LAPIC_ICR_LO, v); } else { + saveintr = intr_disable(); lapic_write32(LAPIC_ICR_HI, vhi); lapic_write32(LAPIC_ICR_LO, vlo); + intr_restore(saveintr); } } + +static void +lapic_write_icr_lo(uint32_t vlo) +{ + + if (x2apic_mode) { + mfence(); + wrmsr(MSR_APIC_000 + LAPIC_ICR_LO, vlo); + } else { + lapic_write32(LAPIC_ICR_LO, vlo); + } +} + +static void +lapic_write_self_ipi(uint32_t vector) +{ + + KASSERT(x2apic_mode, ("SELF IPI write in xAPIC mode")); + wrmsr(MSR_APIC_000 + LAPIC_SELF_IPI, vector); +} #endif /* SMP */ static void @@ -1991,9 +1998,7 @@ native_lapic_ipi_wait(int delay) static void native_lapic_ipi_raw(register_t icrlo, u_int dest) { - uint64_t icr; - uint32_t vhi, vlo; - register_t saveintr; + uint32_t icrhi; /* XXX: Need more sanity checking of icrlo? */ KASSERT(x2apic_mode || lapic_map != NULL, @@ -2004,35 +2009,15 @@ native_lapic_ipi_raw(register_t icrlo, u_int dest) KASSERT((icrlo & APIC_ICRLO_RESV_MASK) == 0, ("%s: reserved bits set in ICR LO register", __func__)); - /* Set destination in ICR HI register if it is being used. */ - if (!x2apic_mode) { - saveintr = intr_disable(); - icr = lapic_read_icr(); - } - if ((icrlo & APIC_DEST_MASK) == APIC_DEST_DESTFLD) { - if (x2apic_mode) { - vhi = dest; - } else { - vhi = icr >> 32; - vhi &= ~APIC_ID_MASK; - vhi |= dest << APIC_ID_SHIFT; - } + if (x2apic_mode) + icrhi = dest; + else + icrhi = dest << APIC_ID_SHIFT; + lapic_write_icr(icrhi, icrlo); } else { - vhi = 0; + lapic_write_icr_lo(icrlo); } - - /* Program the contents of the IPI and dispatch it. */ - if (x2apic_mode) { - vlo = icrlo; - } else { - vlo = icr; - vlo &= APIC_ICRLO_RESV_MASK; - vlo |= icrlo; - } - lapic_write_icr(vhi, vlo); - if (!x2apic_mode) - intr_restore(saveintr); } #define BEFORE_SPIN 50000 @@ -2048,7 +2033,28 @@ native_lapic_ipi_vectored(u_int vector, int dest) KASSERT((vector & ~APIC_VECTOR_MASK) == 0, ("%s: invalid vector %d", __func__, vector)); - icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE | APIC_LEVEL_ASSERT; + destfield = 0; + switch (dest) { + case APIC_IPI_DEST_SELF: + if (x2apic_mode && vector < IPI_NMI_FIRST) { + lapic_write_self_ipi(vector); + return; + } + icrlo = APIC_DEST_SELF; + break; + case APIC_IPI_DEST_ALL: + icrlo = APIC_DEST_ALLISELF; + break; + case APIC_IPI_DEST_OTHERS: + icrlo = APIC_DEST_ALLESELF; + break; + default: + icrlo = 0; + KASSERT(x2apic_mode || + (dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0, + ("%s: invalid destination 0x%x", __func__, dest)); + destfield = dest; + } /* * NMI IPIs are just fake vectors used to send a NMI. Use special rules @@ -2058,23 +2064,7 @@ native_lapic_ipi_vectored(u_int vector, int dest) icrlo |= APIC_DELMODE_NMI; else icrlo |= vector | APIC_DELMODE_FIXED; - destfield = 0; - switch (dest) { - case APIC_IPI_DEST_SELF: - icrlo |= APIC_DEST_SELF; - break; - case APIC_IPI_DEST_ALL: - icrlo |= APIC_DEST_ALLISELF; - break; - case APIC_IPI_DEST_OTHERS: - icrlo |= APIC_DEST_ALLESELF; - break; - default: - KASSERT(x2apic_mode || - (dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0, - ("%s: invalid destination 0x%x", __func__, dest)); - destfield = dest; - } + icrlo |= APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE | APIC_LEVEL_ASSERT; /* Wait for an earlier IPI to finish. */ if (!lapic_ipi_wait(BEFORE_SPIN)) { From 279cd05b7e4d91f2740d02422697e75657a4c20f Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Fri, 24 Jul 2020 20:44:50 +0000 Subject: [PATCH 148/287] Use APIC_IPI_DEST_OTHERS for bitmapped IPIs too. It should save bunch of LAPIC register accesses. MFC after: 2 weeks --- sys/x86/include/x86_smp.h | 1 - sys/x86/x86/mp_x86.c | 62 +++++++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/sys/x86/include/x86_smp.h b/sys/x86/include/x86_smp.h index d5535a602bcb..60cc9df26401 100644 --- a/sys/x86/include/x86_smp.h +++ b/sys/x86/include/x86_smp.h @@ -107,6 +107,5 @@ void smp_masked_invltlb(cpuset_t mask, struct pmap *pmap, smp_invl_cb_t curcpu_cb); void mem_range_AP_init(void); void topo_probe(void); -void ipi_send_cpu(int cpu, u_int ipi); #endif diff --git a/sys/x86/x86/mp_x86.c b/sys/x86/x86/mp_x86.c index bc1d211a27fd..121a2d1ed901 100644 --- a/sys/x86/x86/mp_x86.c +++ b/sys/x86/x86/mp_x86.c @@ -1233,32 +1233,39 @@ ipi_startup(int apic_id, int vector) DELAY(200); /* wait ~200uS */ } -/* - * Send an IPI to specified CPU handling the bitmap logic. - */ -void -ipi_send_cpu(int cpu, u_int ipi) +static bool +ipi_bitmap_set(int cpu, u_int ipi) { u_int bitmap, old, new; u_int *cpu_bitmap; + bitmap = 1 << ipi; + cpu_bitmap = &cpuid_to_pcpu[cpu]->pc_ipi_bitmap; + old = *cpu_bitmap; + for (;;) { + if ((old & bitmap) != 0) + break; + new = old | bitmap; + if (atomic_fcmpset_int(cpu_bitmap, &old, new)) + break; + } + return (old != 0); +} + +/* + * Send an IPI to specified CPU handling the bitmap logic. + */ +static void +ipi_send_cpu(int cpu, u_int ipi) +{ + KASSERT((u_int)cpu < MAXCPU && cpu_apic_ids[cpu] != -1, ("IPI to non-existent CPU %d", cpu)); if (IPI_IS_BITMAPED(ipi)) { - bitmap = 1 << ipi; - ipi = IPI_BITMAP_VECTOR; - cpu_bitmap = &cpuid_to_pcpu[cpu]->pc_ipi_bitmap; - old = *cpu_bitmap; - for (;;) { - if ((old & bitmap) == bitmap) - break; - new = old | bitmap; - if (atomic_fcmpset_int(cpu_bitmap, &old, new)) - break; - } - if (old) + if (ipi_bitmap_set(cpu, ipi)) return; + ipi = IPI_BITMAP_VECTOR; } lapic_ipi_vectored(ipi, cpu_apic_ids[cpu]); } @@ -1366,23 +1373,28 @@ void ipi_all_but_self(u_int ipi) { cpuset_t other_cpus; - - other_cpus = all_cpus; - CPU_CLR(PCPU_GET(cpuid), &other_cpus); - if (IPI_IS_BITMAPED(ipi)) { - ipi_selected(other_cpus, ipi); - return; - } + int cpu, c; /* * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit * of help in order to understand what is the source. * Set the mask of receiving CPUs for this purpose. */ - if (ipi == IPI_STOP_HARD) + if (ipi == IPI_STOP_HARD) { + other_cpus = all_cpus; + CPU_CLR(PCPU_GET(cpuid), &other_cpus); CPU_OR_ATOMIC(&ipi_stop_nmi_pending, &other_cpus); + } CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi); + if (IPI_IS_BITMAPED(ipi)) { + cpu = PCPU_GET(cpuid); + CPU_FOREACH(c) { + if (c != cpu) + ipi_bitmap_set(c, ipi); + } + ipi = IPI_BITMAP_VECTOR; + } lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS); } From 9977c593a7a93ed22e37e7b473a654fd629f6fec Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Fri, 24 Jul 2020 20:52:09 +0000 Subject: [PATCH 149/287] Introduce ipi_self_from_nmi(). It allows safe IPI sending to current CPU from NMI context. Unlike other ipi_*() functions this waits for delivery to leave LAPIC in a state safe for interrupted code. MFC after: 2 weeks Sponsored by: iXsystems, Inc. --- sys/x86/include/x86_smp.h | 1 + sys/x86/x86/mp_x86.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/sys/x86/include/x86_smp.h b/sys/x86/include/x86_smp.h index 60cc9df26401..e2b59a2b4703 100644 --- a/sys/x86/include/x86_smp.h +++ b/sys/x86/include/x86_smp.h @@ -97,6 +97,7 @@ void ipi_bitmap_handler(struct trapframe frame); void ipi_cpu(int cpu, u_int ipi); int ipi_nmi_handler(void); void ipi_selected(cpuset_t cpus, u_int ipi); +void ipi_self_from_nmi(u_int vector); void set_interrupt_apic_ids(void); void smp_cache_flush(smp_invl_cb_t curcpu_cb); void smp_masked_invlpg(cpuset_t mask, vm_offset_t addr, struct pmap *pmap, diff --git a/sys/x86/x86/mp_x86.c b/sys/x86/x86/mp_x86.c index 121a2d1ed901..cfcbca53a1c9 100644 --- a/sys/x86/x86/mp_x86.c +++ b/sys/x86/x86/mp_x86.c @@ -1398,6 +1398,21 @@ ipi_all_but_self(u_int ipi) lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS); } +void +ipi_self_from_nmi(u_int vector) +{ + + lapic_ipi_vectored(vector, APIC_IPI_DEST_SELF); + + /* Wait for IPI to finish. */ + if (!lapic_ipi_wait(50000)) { + if (KERNEL_PANICKED()) + return; + else + panic("APIC: IPI is stuck"); + } +} + int ipi_nmi_handler(void) { From badc50c2707ce2569ccdd55135982a5d293ce201 Mon Sep 17 00:00:00 2001 From: Ilya Bakulin Date: Fri, 24 Jul 2020 21:14:59 +0000 Subject: [PATCH 150/287] Make it possible to get/set MMC frequency from camcontrol Enhance camcontrol(8) so that it's possible to manually set frequency for SD/MMC cards. While here, display more information about the current controller, such as supported operating modes and VCCQ voltages, as well as current VCCQ voltage. Reviewed by: manu Approved by: imp (mentor) Differential Revision: https://reviews.freebsd.org/D25795 --- sbin/camcontrol/camcontrol.c | 83 +++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 6 deletions(-) diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c index 79ab12e196bb..0d53b18912f6 100644 --- a/sbin/camcontrol/camcontrol.c +++ b/sbin/camcontrol/camcontrol.c @@ -190,7 +190,7 @@ static struct camcontrol_opts option_table[] = { {"rescan", CAM_CMD_RESCAN, CAM_ARG_NONE, NULL}, {"reset", CAM_CMD_RESET, CAM_ARG_NONE, NULL}, {"cmd", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts}, - {"mmcsdcmd", CAM_CMD_MMCSD_CMD, CAM_ARG_NONE, "c:a:f:Wb:l:41S:I"}, + {"mmcsdcmd", CAM_CMD_MMCSD_CMD, CAM_ARG_NONE, "c:a:F:f:Wb:l:41S:I"}, {"command", CAM_CMD_SCSI_CMD, CAM_ARG_NONE, scsicmd_opts}, {"smpcmd", CAM_CMD_SMP_CMD, CAM_ARG_NONE, "r:R:"}, {"smprg", CAM_CMD_SMP_RG, CAM_ARG_NONE, smprg_opts}, @@ -7833,10 +7833,12 @@ mmcsdcmd(struct cam_device *device, int argc, char **argv, char *combinedopt, int retval; int is_write = 0; int is_bw_4 = 0, is_bw_1 = 0; + int is_frequency = 0; int is_highspeed = 0, is_stdspeed = 0; int is_info_request = 0; int flags = 0; uint8_t mmc_data_byte = 0; + uint32_t mmc_frequency = 0; /* For IO_RW_EXTENDED command */ uint8_t *mmc_data = NULL; @@ -7873,6 +7875,10 @@ mmcsdcmd(struct cam_device *device, int argc, char **argv, char *combinedopt, case 'I': is_info_request = 1; break; + case 'F': + is_frequency = 1; + mmc_frequency = strtol(optarg, NULL, 0); + break; case 'c': mmc_opcode = strtol(optarg, NULL, 0); if (mmc_opcode < 0) { @@ -7978,6 +7984,23 @@ mmcsdcmd(struct cam_device *device, int argc, char **argv, char *combinedopt, return (retval); } + if (is_frequency) { + struct ccb_trans_settings_mmc *cts; + ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; + ccb->ccb_h.flags = 0; + cts = &ccb->cts.proto_specific.mmc; + cts->ios.clock = mmc_frequency; + cts->ios_valid = MMC_CLK; + if (((retval = cam_send_ccb(device, ccb)) < 0) + || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { + warn("Error sending command"); + } else { + printf("Parameters set OK\n"); + } + cam_freeccb(ccb); + return (retval); + } + // Switch bus speed instead of sending IO command if (is_stdspeed || is_highspeed) { struct ccb_trans_settings_mmc *cts; @@ -8011,13 +8034,48 @@ mmcsdcmd(struct cam_device *device, int argc, char **argv, char *combinedopt, printf("Host OCR: 0x%x\n", cts->host_ocr); printf("Min frequency: %u KHz\n", cts->host_f_min / 1000); printf("Max frequency: %u MHz\n", cts->host_f_max / 1000000); - printf("Supported bus width: "); + printf("Supported bus width:\n"); if (cts->host_caps & MMC_CAP_4_BIT_DATA) printf(" 4 bit\n"); if (cts->host_caps & MMC_CAP_8_BIT_DATA) printf(" 8 bit\n"); - printf("\nCurrent settings:\n"); - printf("Bus width: "); + + printf("Supported operating modes:\n"); + if (cts->host_caps & MMC_CAP_HSPEED) + printf(" Can do High Speed transfers\n"); + if (cts->host_caps & MMC_CAP_UHS_SDR12) + printf(" Can do UHS SDR12\n"); + if (cts->host_caps & MMC_CAP_UHS_SDR25) + printf(" Can do UHS SDR25\n"); + if (cts->host_caps & MMC_CAP_UHS_SDR50) + printf(" Can do UHS SDR50\n"); + if (cts->host_caps & MMC_CAP_UHS_SDR104) + printf(" Can do UHS SDR104\n"); + if (cts->host_caps & MMC_CAP_UHS_DDR50) + printf(" Can do UHS DDR50\n"); + if (cts->host_caps & MMC_CAP_MMC_DDR52_120) + printf(" Can do eMMC DDR52 at 1.2V\n"); + if (cts->host_caps & MMC_CAP_MMC_DDR52_180) + printf(" Can do eMMC DDR52 at 1.8V\n"); + if (cts->host_caps & MMC_CAP_MMC_HS200_120) + printf(" Can do eMMC HS200 at 1.2V\n"); + if (cts->host_caps & MMC_CAP_MMC_HS200_180) + printf(" Can do eMMC HS200 at 1.8V\n"); + if (cts->host_caps & MMC_CAP_MMC_HS400_120) + printf(" Can do eMMC HS400 at 1.2V\n"); + if (cts->host_caps & MMC_CAP_MMC_HS400_180) + printf(" Can do eMMC HS400 at 1.8V\n"); + + printf("Supported VCCQ voltages:\n"); + if (cts->host_caps & MMC_CAP_SIGNALING_120) + printf(" 1.2V\n"); + if (cts->host_caps & MMC_CAP_SIGNALING_180) + printf(" 1.8V\n"); + if (cts->host_caps & MMC_CAP_SIGNALING_330) + printf(" 3.3V\n"); + + printf("Current settings:\n"); + printf(" Bus width: "); switch (cts->ios.bus_width) { case bus_width_1: printf("1 bit\n"); @@ -8029,10 +8087,23 @@ mmcsdcmd(struct cam_device *device, int argc, char **argv, char *combinedopt, printf("8 bit\n"); break; } - printf("Freq: %d.%03d MHz%s\n", + printf(" Freq: %d.%03d MHz%s\n", cts->ios.clock / 1000000, (cts->ios.clock / 1000) % 1000, - cts->ios.timing == bus_timing_hs ? "(high-speed timing)" : ""); + cts->ios.timing == bus_timing_hs ? " (high-speed timing)" : ""); + + printf(" VCCQ: "); + switch (cts->ios.vccq) { + case vccq_330: + printf("3.3V\n"); + break; + case vccq_180: + printf("1.8V\n"); + break; + case vccq_120: + printf("1.2V\n"); + break; + } return (0); } From a2e160c5afdacc6fa219364b8d59e3673c5bdbc1 Mon Sep 17 00:00:00 2001 From: Navdeep Parhar Date: Fri, 24 Jul 2020 23:15:42 +0000 Subject: [PATCH 151/287] cxgbe(4): Some updates to the common code. Obtained from: Chelsio Communications MFC after: 1 week Sponsored by: Chelsio Communications --- sys/dev/cxgbe/common/common.h | 31 +- sys/dev/cxgbe/common/t4_hw.c | 663 +++++++++++++++++++++++++++----- sys/dev/cxgbe/common/t4_hw.h | 12 + sys/dev/cxgbe/cudbg/cudbg_lib.c | 2 +- 4 files changed, 612 insertions(+), 96 deletions(-) diff --git a/sys/dev/cxgbe/common/common.h b/sys/dev/cxgbe/common/common.h index 984fedfeccae..27271ad87020 100644 --- a/sys/dev/cxgbe/common/common.h +++ b/sys/dev/cxgbe/common/common.h @@ -299,6 +299,7 @@ struct chip_params { u16 vfcount; u32 sge_fl_db; u16 mps_tcam_size; + u16 rss_nentries; }; /* VF-only parameters. */ @@ -377,6 +378,7 @@ struct adapter_params { unsigned int hash_filter:1; unsigned int filter2_wr_support:1; unsigned int port_caps32:1; + unsigned int smac_add_support:1; unsigned int ofldq_wr_cred; unsigned int eo_wr_cred; @@ -783,8 +785,27 @@ int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid, int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, unsigned int viid, bool free, unsigned int naddr, const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok); +int t4_free_mac_filt(struct adapter *adap, unsigned int mbox, + unsigned int viid, unsigned int naddr, + const u8 **addr, bool sleep_ok); +int t4_free_encap_mac_filt(struct adapter *adap, unsigned int viid, + int idx, bool sleep_ok); +int t4_free_raw_mac_filt(struct adapter *adap, unsigned int viid, + const u8 *addr, const u8 *mask, unsigned int idx, + u8 lookup_type, u8 port_id, bool sleep_ok); +int t4_alloc_raw_mac_filt(struct adapter *adap, unsigned int viid, + const u8 *addr, const u8 *mask, unsigned int idx, + u8 lookup_type, u8 port_id, bool sleep_ok); +int t4_alloc_encap_mac_filt(struct adapter *adap, unsigned int viid, + const u8 *addr, const u8 *mask, unsigned int vni, + unsigned int vni_mask, u8 dip_hit, u8 lookup_type, + bool sleep_ok); int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, int idx, const u8 *addr, bool persist, uint16_t *smt_idx); +int t4_del_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, + const u8 *addr, bool smac); +int t4_add_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, + int idx, const u8 *addr, bool persist, u8 *smt_idx, bool smac); int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, bool ucast, u64 vec, bool sleep_ok); int t4_enable_vi_params(struct adapter *adap, unsigned int mbox, @@ -797,6 +818,10 @@ int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, unsigned int mmd, unsigned int reg, unsigned int *valp); int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, unsigned int mmd, unsigned int reg, unsigned int val); +int t4_i2c_io(struct adapter *adap, unsigned int mbox, + int port, unsigned int devid, + unsigned int offset, unsigned int len, + u8 *buf, bool write); int t4_i2c_rd(struct adapter *adap, unsigned int mbox, int port, unsigned int devid, unsigned int offset, unsigned int len, @@ -821,7 +846,7 @@ int t4_sge_ctxt_rd(struct adapter *adap, unsigned int mbox, unsigned int cid, enum ctxt_type ctype, u32 *data); int t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid, enum ctxt_type ctype, u32 *data); -int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox); +int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox, int ctxt_type); const char *t4_link_down_rc_str(unsigned char link_down_rc); int t4_update_port_info(struct port_info *pi); int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl); @@ -854,6 +879,10 @@ void t4_tp_tm_pio_read(struct adapter *adap, u32 *buff, u32 nregs, u32 start_index, bool sleep_ok); void t4_tp_mib_read(struct adapter *adap, u32 *buff, u32 nregs, u32 start_index, bool sleep_ok); +int t4_configure_ringbb(struct adapter *adap); +int t4_configure_add_smac(struct adapter *adap); +int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf, + u16 vlan); static inline int t4vf_query_params(struct adapter *adapter, unsigned int nparams, const u32 *params, diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c index b7750f619710..84c42053477c 100644 --- a/sys/dev/cxgbe/common/t4_hw.c +++ b/sys/dev/cxgbe/common/t4_hw.c @@ -1359,8 +1359,7 @@ void t4_get_regs(struct adapter *adap, u8 *buf, size_t buf_size) 0x9608, 0x9638, 0x9640, 0x96f4, 0x9800, 0x9808, - 0x9820, 0x983c, - 0x9850, 0x9864, + 0x9810, 0x9864, 0x9c00, 0x9c6c, 0x9c80, 0x9cec, 0x9d00, 0x9d6c, @@ -1369,7 +1368,7 @@ void t4_get_regs(struct adapter *adap, u8 *buf, size_t buf_size) 0x9e80, 0x9eec, 0x9f00, 0x9f6c, 0x9f80, 0xa020, - 0xd004, 0xd004, + 0xd000, 0xd004, 0xd010, 0xd03c, 0xdfc0, 0xdfe0, 0xe000, 0x1106c, @@ -1410,10 +1409,8 @@ void t4_get_regs(struct adapter *adap, u8 *buf, size_t buf_size) 0x1a0b0, 0x1a0e4, 0x1a0ec, 0x1a0f8, 0x1a100, 0x1a108, - 0x1a114, 0x1a120, - 0x1a128, 0x1a130, - 0x1a138, 0x1a138, - 0x1a190, 0x1a1c4, + 0x1a114, 0x1a130, + 0x1a138, 0x1a1c4, 0x1a1fc, 0x1a1fc, 0x1e008, 0x1e00c, 0x1e040, 0x1e044, @@ -2084,7 +2081,7 @@ void t4_get_regs(struct adapter *adap, u8 *buf, size_t buf_size) 0x1180, 0x1184, 0x1190, 0x1194, 0x11a0, 0x11a4, - 0x11b0, 0x11b4, + 0x11b0, 0x11c4, 0x11fc, 0x1274, 0x1280, 0x133c, 0x1800, 0x18fc, @@ -2140,7 +2137,7 @@ void t4_get_regs(struct adapter *adap, u8 *buf, size_t buf_size) 0x7e4c, 0x7e78, 0x7e80, 0x7edc, 0x7ee8, 0x7efc, - 0x8dc0, 0x8de4, + 0x8dc0, 0x8de0, 0x8df8, 0x8e04, 0x8e10, 0x8e84, 0x8ea0, 0x8f88, @@ -2154,8 +2151,7 @@ void t4_get_regs(struct adapter *adap, u8 *buf, size_t buf_size) 0x9640, 0x9704, 0x9710, 0x971c, 0x9800, 0x9808, - 0x9820, 0x983c, - 0x9850, 0x9864, + 0x9810, 0x9864, 0x9c00, 0x9c6c, 0x9c80, 0x9cec, 0x9d00, 0x9d6c, @@ -2164,7 +2160,7 @@ void t4_get_regs(struct adapter *adap, u8 *buf, size_t buf_size) 0x9e80, 0x9eec, 0x9f00, 0x9f6c, 0x9f80, 0xa020, - 0xd004, 0xd03c, + 0xd000, 0xd03c, 0xd100, 0xd118, 0xd200, 0xd214, 0xd220, 0xd234, @@ -2198,7 +2194,6 @@ void t4_get_regs(struct adapter *adap, u8 *buf, size_t buf_size) 0x191d0, 0x191e8, 0x19238, 0x19290, 0x192a4, 0x192b0, - 0x192bc, 0x192bc, 0x19348, 0x1934c, 0x193f8, 0x19418, 0x19420, 0x19428, @@ -2216,7 +2211,7 @@ void t4_get_regs(struct adapter *adap, u8 *buf, size_t buf_size) 0x19d00, 0x19d28, 0x19d50, 0x19d78, 0x19d94, 0x19d98, - 0x19da0, 0x19dc8, + 0x19da0, 0x19de0, 0x19df0, 0x19e10, 0x19e50, 0x19e6c, 0x19ea0, 0x19ebc, @@ -2232,10 +2227,8 @@ void t4_get_regs(struct adapter *adap, u8 *buf, size_t buf_size) 0x1a0b0, 0x1a0e4, 0x1a0ec, 0x1a0f8, 0x1a100, 0x1a108, - 0x1a114, 0x1a120, - 0x1a128, 0x1a130, - 0x1a138, 0x1a138, - 0x1a190, 0x1a1c4, + 0x1a114, 0x1a130, + 0x1a138, 0x1a1c4, 0x1a1fc, 0x1a1fc, 0x1e008, 0x1e00c, 0x1e040, 0x1e044, @@ -3357,7 +3350,7 @@ int t4_get_tp_version(struct adapter *adapter, u32 *vers) * this in the Firmware Version Format since it's convenient. Return * 0 on success, -ENOENT if no Expansion ROM is present. */ -int t4_get_exprom_version(struct adapter *adap, u32 *vers) +int t4_get_exprom_version(struct adapter *adapter, u32 *vers) { struct exprom_header { unsigned char hdr_arr[16]; /* must start with 0x55aa */ @@ -3367,7 +3360,7 @@ int t4_get_exprom_version(struct adapter *adap, u32 *vers) sizeof(u32))]; int ret; - ret = t4_read_flash(adap, FLASH_EXP_ROM_START, + ret = t4_read_flash(adapter, FLASH_EXP_ROM_START, ARRAY_SIZE(exprom_header_buf), exprom_header_buf, 0); if (ret) @@ -5703,8 +5696,9 @@ int t4_read_rss(struct adapter *adapter, u16 *map) { u32 val; int i, ret; + int rss_nentries = adapter->chip_params->rss_nentries; - for (i = 0; i < RSS_NENTRIES / 2; ++i) { + for (i = 0; i < rss_nentries / 2; ++i) { ret = rd_rss_row(adapter, i, &val); if (ret) return ret; @@ -7374,14 +7368,16 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state) * Issues a FW command through the given mailbox to flush the * SGE context cache. */ -int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox) +int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox, int ctxt_type) { int ret; u32 ldst_addrspace; struct fw_ldst_cmd c; memset(&c, 0, sizeof(c)); - ldst_addrspace = V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_SGE_EGRC); + ldst_addrspace = V_FW_LDST_CMD_ADDRSPACE(ctxt_type == CTXT_EGRESS ? + FW_LDST_ADDRSPC_SGE_EGRC : + FW_LDST_ADDRSPC_SGE_INGC); c.op_to_addrspace = cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST | F_FW_CMD_READ | ldst_addrspace); @@ -8034,6 +8030,111 @@ int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid, return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); } +/** + * t4_alloc_encap_mac_filt - Adds a mac entry in mps tcam with VNI support + * @adap: the adapter + * @viid: the VI id + * @mac: the MAC address + * @mask: the mask + * @vni: the VNI id for the tunnel protocol + * @vni_mask: mask for the VNI id + * @dip_hit: to enable DIP match for the MPS entry + * @lookup_type: MAC address for inner (1) or outer (0) header + * @sleep_ok: call is allowed to sleep + * + * Allocates an MPS entry with specified MAC address and VNI value. + * + * Returns a negative error number or the allocated index for this mac. + */ +int t4_alloc_encap_mac_filt(struct adapter *adap, unsigned int viid, + const u8 *addr, const u8 *mask, unsigned int vni, + unsigned int vni_mask, u8 dip_hit, u8 lookup_type, + bool sleep_ok) +{ + struct fw_vi_mac_cmd c; + struct fw_vi_mac_vni *p = c.u.exact_vni; + int ret = 0; + u32 val; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_VI_MAC_CMD_VIID(viid)); + val = V_FW_CMD_LEN16(1) | + V_FW_VI_MAC_CMD_ENTRY_TYPE(FW_VI_MAC_TYPE_EXACTMAC_VNI); + c.freemacs_to_len16 = cpu_to_be32(val); + p->valid_to_idx = cpu_to_be16(F_FW_VI_MAC_CMD_VALID | + V_FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); + memcpy(p->macaddr, addr, sizeof(p->macaddr)); + memcpy(p->macaddr_mask, mask, sizeof(p->macaddr_mask)); + + p->lookup_type_to_vni = cpu_to_be32(V_FW_VI_MAC_CMD_VNI(vni) | + V_FW_VI_MAC_CMD_DIP_HIT(dip_hit) | + V_FW_VI_MAC_CMD_LOOKUP_TYPE(lookup_type)); + p->vni_mask_pkd = cpu_to_be32(V_FW_VI_MAC_CMD_VNI_MASK(vni_mask)); + + ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); + if (ret == 0) + ret = G_FW_VI_MAC_CMD_IDX(be16_to_cpu(p->valid_to_idx)); + return ret; +} + +/** + * t4_alloc_raw_mac_filt - Adds a mac entry in mps tcam + * @adap: the adapter + * @viid: the VI id + * @mac: the MAC address + * @mask: the mask + * @idx: index at which to add this entry + * @port_id: the port index + * @lookup_type: MAC address for inner (1) or outer (0) header + * @sleep_ok: call is allowed to sleep + * + * Adds the mac entry at the specified index using raw mac interface. + * + * Returns a negative error number or the allocated index for this mac. + */ +int t4_alloc_raw_mac_filt(struct adapter *adap, unsigned int viid, + const u8 *addr, const u8 *mask, unsigned int idx, + u8 lookup_type, u8 port_id, bool sleep_ok) +{ + int ret = 0; + struct fw_vi_mac_cmd c; + struct fw_vi_mac_raw *p = &c.u.raw; + u32 val; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_VI_MAC_CMD_VIID(viid)); + val = V_FW_CMD_LEN16(1) | + V_FW_VI_MAC_CMD_ENTRY_TYPE(FW_VI_MAC_TYPE_RAW); + c.freemacs_to_len16 = cpu_to_be32(val); + + /* Specify that this is an inner mac address */ + p->raw_idx_pkd = cpu_to_be32(V_FW_VI_MAC_CMD_RAW_IDX(idx)); + + /* Lookup Type. Outer header: 0, Inner header: 1 */ + p->data0_pkd = cpu_to_be32(V_DATALKPTYPE(lookup_type) | + V_DATAPORTNUM(port_id)); + /* Lookup mask and port mask */ + p->data0m_pkd = cpu_to_be64(V_DATALKPTYPE(M_DATALKPTYPE) | + V_DATAPORTNUM(M_DATAPORTNUM)); + + /* Copy the address and the mask */ + memcpy((u8 *)&p->data1[0] + 2, addr, ETHER_ADDR_LEN); + memcpy((u8 *)&p->data1m[0] + 2, mask, ETHER_ADDR_LEN); + + ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); + if (ret == 0) { + ret = G_FW_VI_MAC_CMD_RAW_IDX(be32_to_cpu(p->raw_idx_pkd)); + if (ret != idx) + ret = -ENOMEM; + } + + return ret; +} + /** * t4_alloc_mac_filt - allocates exact-match filters for MAC addresses * @adap: the adapter @@ -8127,6 +8228,168 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, return ret; } +/** + * t4_free_encap_mac_filt - frees MPS entry at given index + * @adap: the adapter + * @viid: the VI id + * @idx: index of MPS entry to be freed + * @sleep_ok: call is allowed to sleep + * + * Frees the MPS entry at supplied index + * + * Returns a negative error number or zero on success + */ +int t4_free_encap_mac_filt(struct adapter *adap, unsigned int viid, + int idx, bool sleep_ok) +{ + struct fw_vi_mac_exact *p; + struct fw_vi_mac_cmd c; + u8 addr[] = {0,0,0,0,0,0}; + int ret = 0; + u32 exact; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_WRITE | + V_FW_CMD_EXEC(0) | + V_FW_VI_MAC_CMD_VIID(viid)); + exact = V_FW_VI_MAC_CMD_ENTRY_TYPE(FW_VI_MAC_TYPE_EXACTMAC); + c.freemacs_to_len16 = cpu_to_be32(V_FW_VI_MAC_CMD_FREEMACS(0) | + exact | + V_FW_CMD_LEN16(1)); + p = c.u.exact; + p->valid_to_idx = cpu_to_be16(F_FW_VI_MAC_CMD_VALID | + V_FW_VI_MAC_CMD_IDX(idx)); + memcpy(p->macaddr, addr, sizeof(p->macaddr)); + + ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); + return ret; +} + +/** + * t4_free_raw_mac_filt - Frees a raw mac entry in mps tcam + * @adap: the adapter + * @viid: the VI id + * @addr: the MAC address + * @mask: the mask + * @idx: index of the entry in mps tcam + * @lookup_type: MAC address for inner (1) or outer (0) header + * @port_id: the port index + * @sleep_ok: call is allowed to sleep + * + * Removes the mac entry at the specified index using raw mac interface. + * + * Returns a negative error number on failure. + */ +int t4_free_raw_mac_filt(struct adapter *adap, unsigned int viid, + const u8 *addr, const u8 *mask, unsigned int idx, + u8 lookup_type, u8 port_id, bool sleep_ok) +{ + struct fw_vi_mac_cmd c; + struct fw_vi_mac_raw *p = &c.u.raw; + u32 raw; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_CMD_EXEC(0) | + V_FW_VI_MAC_CMD_VIID(viid)); + raw = V_FW_VI_MAC_CMD_ENTRY_TYPE(FW_VI_MAC_TYPE_RAW); + c.freemacs_to_len16 = cpu_to_be32(V_FW_VI_MAC_CMD_FREEMACS(0) | + raw | + V_FW_CMD_LEN16(1)); + + p->raw_idx_pkd = cpu_to_be32(V_FW_VI_MAC_CMD_RAW_IDX(idx) | + FW_VI_MAC_ID_BASED_FREE); + + /* Lookup Type. Outer header: 0, Inner header: 1 */ + p->data0_pkd = cpu_to_be32(V_DATALKPTYPE(lookup_type) | + V_DATAPORTNUM(port_id)); + /* Lookup mask and port mask */ + p->data0m_pkd = cpu_to_be64(V_DATALKPTYPE(M_DATALKPTYPE) | + V_DATAPORTNUM(M_DATAPORTNUM)); + + /* Copy the address and the mask */ + memcpy((u8 *)&p->data1[0] + 2, addr, ETHER_ADDR_LEN); + memcpy((u8 *)&p->data1m[0] + 2, mask, ETHER_ADDR_LEN); + + return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); +} + +/** + * t4_free_mac_filt - frees exact-match filters of given MAC addresses + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @viid: the VI id + * @naddr: the number of MAC addresses to allocate filters for (up to 7) + * @addr: the MAC address(es) + * @sleep_ok: call is allowed to sleep + * + * Frees the exact-match filter for each of the supplied addresses + * + * Returns a negative error number or the number of filters freed. + */ +int t4_free_mac_filt(struct adapter *adap, unsigned int mbox, + unsigned int viid, unsigned int naddr, + const u8 **addr, bool sleep_ok) +{ + int offset, ret = 0; + struct fw_vi_mac_cmd c; + unsigned int nfilters = 0; + unsigned int max_naddr = adap->chip_params->mps_tcam_size; + unsigned int rem = naddr; + + if (naddr > max_naddr) + return -EINVAL; + + for (offset = 0; offset < (int)naddr ; /**/) { + unsigned int fw_naddr = (rem < ARRAY_SIZE(c.u.exact) + ? rem + : ARRAY_SIZE(c.u.exact)); + size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, + u.exact[fw_naddr]), 16); + struct fw_vi_mac_exact *p; + int i; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_WRITE | + V_FW_CMD_EXEC(0) | + V_FW_VI_MAC_CMD_VIID(viid)); + c.freemacs_to_len16 = + cpu_to_be32(V_FW_VI_MAC_CMD_FREEMACS(0) | + V_FW_CMD_LEN16(len16)); + + for (i = 0, p = c.u.exact; i < (int)fw_naddr; i++, p++) { + p->valid_to_idx = cpu_to_be16( + F_FW_VI_MAC_CMD_VALID | + V_FW_VI_MAC_CMD_IDX(FW_VI_MAC_MAC_BASED_FREE)); + memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr)); + } + + ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); + if (ret) + break; + + for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) { + u16 index = G_FW_VI_MAC_CMD_IDX( + be16_to_cpu(p->valid_to_idx)); + + if (index < max_naddr) + nfilters++; + } + + offset += fw_naddr; + rem -= fw_naddr; + } + + if (ret == 0) + ret = nfilters; + return ret; +} + /** * t4_change_mac - modifies the exact-match filter for a MAC address * @adap: the adapter @@ -8916,6 +9179,7 @@ const struct chip_params *t4_get_chip_params(int chipid) .vfcount = 128, .sge_fl_db = F_DBPRIO, .mps_tcam_size = NUM_MPS_CLS_SRAM_L_INSTANCES, + .rss_nentries = RSS_NENTRIES, }, { /* T5 */ @@ -8928,6 +9192,7 @@ const struct chip_params *t4_get_chip_params(int chipid) .vfcount = 128, .sge_fl_db = F_DBPRIO | F_DBTYPE, .mps_tcam_size = NUM_MPS_T5_CLS_SRAM_L_INSTANCES, + .rss_nentries = RSS_NENTRIES, }, { /* T6 */ @@ -8940,6 +9205,7 @@ const struct chip_params *t4_get_chip_params(int chipid) .vfcount = 256, .sge_fl_db = 0, .mps_tcam_size = NUM_MPS_T5_CLS_SRAM_L_INSTANCES, + .rss_nentries = T6_RSS_NENTRIES, }, }; @@ -9728,15 +9994,15 @@ int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr) if (ret) break; - /* address can't exceed 0xfff (UpDbgLaRdPtr is of 12-bits) */ - idx = (idx + 1) & M_UPDBGLARDPTR; - /* - * Bits 0-3 of UpDbgLaRdPtr can be between 0000 to 1001 to + /* Bits 0-3 of UpDbgLaRdPtr can be between 0000 to 1001 to * identify the 32-bit portion of the full 312-bit data */ - if (is_t6(adap)) - while ((idx & 0xf) > 9) - idx = (idx + 1) % M_UPDBGLARDPTR; + if (is_t6(adap) && (idx & 0xf) >= 9) + idx = (idx & 0xff0) + 0x10; + else + idx++; + /* address can't exceed 0xfff */ + idx &= M_UPDBGLARDPTR; } restart: if (cfg & F_UPDBGLAEN) { @@ -10479,88 +10745,81 @@ void t4_clr_port_stats(struct adapter *adap, int idx) } /** - * t4_i2c_rd - read I2C data from adapter + * t4_i2c_io - read/write I2C data from adapter * @adap: the adapter * @port: Port number if per-port device; <0 if not * @devid: per-port device ID or absolute device ID * @offset: byte offset into device I2C space * @len: byte length of I2C space data - * @buf: buffer in which to return I2C data - * - * Reads the I2C data from the indicated device and location. + * @buf: buffer in which to return I2C data for read + * buffer which holds the I2C data for write + * @write: if true, do a write; else do a read + * Reads/Writes the I2C data from/to the indicated device and location. */ +int t4_i2c_io(struct adapter *adap, unsigned int mbox, + int port, unsigned int devid, + unsigned int offset, unsigned int len, + u8 *buf, bool write) +{ + struct fw_ldst_cmd ldst_cmd, ldst_rpl; + unsigned int i2c_max = sizeof(ldst_cmd.u.i2c.data); + int ret = 0; + + if (len > I2C_PAGE_SIZE) + return -EINVAL; + + /* Dont allow reads that spans multiple pages */ + if (offset < I2C_PAGE_SIZE && offset + len > I2C_PAGE_SIZE) + return -EINVAL; + + memset(&ldst_cmd, 0, sizeof(ldst_cmd)); + ldst_cmd.op_to_addrspace = + cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | + F_FW_CMD_REQUEST | + (write ? F_FW_CMD_WRITE : F_FW_CMD_READ) | + V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C)); + ldst_cmd.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst_cmd)); + ldst_cmd.u.i2c.pid = (port < 0 ? 0xff : port); + ldst_cmd.u.i2c.did = devid; + + while (len > 0) { + unsigned int i2c_len = (len < i2c_max) ? len : i2c_max; + + ldst_cmd.u.i2c.boffset = offset; + ldst_cmd.u.i2c.blen = i2c_len; + + if (write) + memcpy(ldst_cmd.u.i2c.data, buf, i2c_len); + + ret = t4_wr_mbox(adap, mbox, &ldst_cmd, sizeof(ldst_cmd), + write ? NULL : &ldst_rpl); + if (ret) + break; + + if (!write) + memcpy(buf, ldst_rpl.u.i2c.data, i2c_len); + offset += i2c_len; + buf += i2c_len; + len -= i2c_len; + } + + return ret; +} + int t4_i2c_rd(struct adapter *adap, unsigned int mbox, int port, unsigned int devid, unsigned int offset, unsigned int len, u8 *buf) { - u32 ldst_addrspace; - struct fw_ldst_cmd ldst; - int ret; - - if (port >= 4 || - devid >= 256 || - offset >= 256 || - len > sizeof ldst.u.i2c.data) - return -EINVAL; - - memset(&ldst, 0, sizeof ldst); - ldst_addrspace = V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C); - ldst.op_to_addrspace = - cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | - F_FW_CMD_REQUEST | - F_FW_CMD_READ | - ldst_addrspace); - ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst)); - ldst.u.i2c.pid = (port < 0 ? 0xff : port); - ldst.u.i2c.did = devid; - ldst.u.i2c.boffset = offset; - ldst.u.i2c.blen = len; - ret = t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst); - if (!ret) - memcpy(buf, ldst.u.i2c.data, len); - return ret; + return t4_i2c_io(adap, mbox, port, devid, offset, len, buf, false); } -/** - * t4_i2c_wr - write I2C data to adapter - * @adap: the adapter - * @port: Port number if per-port device; <0 if not - * @devid: per-port device ID or absolute device ID - * @offset: byte offset into device I2C space - * @len: byte length of I2C space data - * @buf: buffer containing new I2C data - * - * Write the I2C data to the indicated device and location. - */ int t4_i2c_wr(struct adapter *adap, unsigned int mbox, int port, unsigned int devid, unsigned int offset, unsigned int len, u8 *buf) { - u32 ldst_addrspace; - struct fw_ldst_cmd ldst; - - if (port >= 4 || - devid >= 256 || - offset >= 256 || - len > sizeof ldst.u.i2c.data) - return -EINVAL; - - memset(&ldst, 0, sizeof ldst); - ldst_addrspace = V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C); - ldst.op_to_addrspace = - cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) | - F_FW_CMD_REQUEST | - F_FW_CMD_WRITE | - ldst_addrspace); - ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst)); - ldst.u.i2c.pid = (port < 0 ? 0xff : port); - ldst.u.i2c.did = devid; - ldst.u.i2c.boffset = offset; - ldst.u.i2c.blen = len; - memcpy(ldst.u.i2c.data, buf, len); - return t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst); + return t4_i2c_io(adap, mbox, port, devid, offset, len, buf, true); } /** @@ -10827,3 +11086,219 @@ int t4_set_devlog_level(struct adapter *adapter, unsigned int level) return t4_wr_mbox(adapter, adapter->mbox, &devlog_cmd, sizeof(devlog_cmd), &devlog_cmd); } + +int t4_configure_add_smac(struct adapter *adap) +{ + unsigned int param, val; + int ret = 0; + + adap->params.smac_add_support = 0; + param = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | + V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_ADD_SMAC)); + /* Query FW to check if FW supports adding source mac address + * to TCAM feature or not. + * If FW returns 1, driver can use this feature and driver need to send + * FW_PARAMS_PARAM_DEV_ADD_SMAC write command with value 1 to + * enable adding smac to TCAM. + */ + ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); + if (ret) + return ret; + + if (val == 1) { + ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, + ¶m, &val); + if (!ret) + /* Firmware allows adding explicit TCAM entries. + * Save this internally. + */ + adap->params.smac_add_support = 1; + } + + return ret; +} + +int t4_configure_ringbb(struct adapter *adap) +{ + unsigned int param, val; + int ret = 0; + + param = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | + V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_RING_BACKBONE)); + /* Query FW to check if FW supports ring switch feature or not. + * If FW returns 1, driver can use this feature and driver need to send + * FW_PARAMS_PARAM_DEV_RING_BACKBONE write command with value 1 to + * enable the ring backbone configuration. + */ + ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); + if (ret < 0) { + CH_ERR(adap, "Querying FW using Ring backbone params command failed, err=%d\n", + ret); + goto out; + } + + if (val != 1) { + CH_ERR(adap, "FW doesnot support ringbackbone features\n"); + goto out; + } + + ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); + if (ret < 0) { + CH_ERR(adap, "Could not set Ringbackbone, err= %d\n", + ret); + goto out; + } + +out: + return ret; +} + +/* + * t4_set_vlan_acl - Set a VLAN id for the specified VF + * @adapter: the adapter + * @mbox: mailbox to use for the FW command + * @vf: one of the VFs instantiated by the specified PF + * @vlan: The vlanid to be set + * + */ +int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf, + u16 vlan) +{ + struct fw_acl_vlan_cmd vlan_cmd; + unsigned int enable; + + enable = (vlan ? F_FW_ACL_VLAN_CMD_EN : 0); + memset(&vlan_cmd, 0, sizeof(vlan_cmd)); + vlan_cmd.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_ACL_VLAN_CMD) | + F_FW_CMD_REQUEST | + F_FW_CMD_WRITE | + F_FW_CMD_EXEC | + V_FW_ACL_VLAN_CMD_PFN(adap->pf) | + V_FW_ACL_VLAN_CMD_VFN(vf)); + vlan_cmd.en_to_len16 = cpu_to_be32(enable | FW_LEN16(vlan_cmd)); + /* Drop all packets that donot match vlan id */ + vlan_cmd.dropnovlan_fm = (enable + ? (F_FW_ACL_VLAN_CMD_DROPNOVLAN | + F_FW_ACL_VLAN_CMD_FM) + : 0); + if (enable != 0) { + vlan_cmd.nvlan = 1; + vlan_cmd.vlanid[0] = cpu_to_be16(vlan); + } + + return t4_wr_mbox(adap, adap->mbox, &vlan_cmd, sizeof(vlan_cmd), NULL); +} + +/** + * t4_del_mac - Removes the exact-match filter for a MAC address + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @viid: the VI id + * @addr: the MAC address value + * @smac: if true, delete from only the smac region of MPS + * + * Modifies an exact-match filter and sets it to the new MAC address if + * @idx >= 0, or adds the MAC address to a new filter if @idx < 0. In the + * latter case the address is added persistently if @persist is %true. + * + * Returns a negative error number or the index of the filter with the new + * MAC value. Note that this index may differ from @idx. + */ +int t4_del_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, + const u8 *addr, bool smac) +{ + int ret; + struct fw_vi_mac_cmd c; + struct fw_vi_mac_exact *p = c.u.exact; + unsigned int max_mac_addr = adap->chip_params->mps_tcam_size; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_VI_MAC_CMD_VIID(viid)); + c.freemacs_to_len16 = cpu_to_be32( + V_FW_CMD_LEN16(1) | + (smac ? F_FW_VI_MAC_CMD_IS_SMAC : 0)); + + memcpy(p->macaddr, addr, sizeof(p->macaddr)); + p->valid_to_idx = cpu_to_be16( + F_FW_VI_MAC_CMD_VALID | + V_FW_VI_MAC_CMD_IDX(FW_VI_MAC_MAC_BASED_FREE)); + + ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); + if (ret == 0) { + ret = G_FW_VI_MAC_CMD_IDX(be16_to_cpu(p->valid_to_idx)); + if (ret < max_mac_addr) + return -ENOMEM; + } + + return ret; +} + +/** + * t4_add_mac - Adds an exact-match filter for a MAC address + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @viid: the VI id + * @idx: index of existing filter for old value of MAC address, or -1 + * @addr: the new MAC address value + * @persist: whether a new MAC allocation should be persistent + * @add_smt: if true also add the address to the HW SMT + * @smac: if true, update only the smac region of MPS + * + * Modifies an exact-match filter and sets it to the new MAC address if + * @idx >= 0, or adds the MAC address to a new filter if @idx < 0. In the + * latter case the address is added persistently if @persist is %true. + * + * Returns a negative error number or the index of the filter with the new + * MAC value. Note that this index may differ from @idx. + */ +int t4_add_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, + int idx, const u8 *addr, bool persist, u8 *smt_idx, bool smac) +{ + int ret, mode; + struct fw_vi_mac_cmd c; + struct fw_vi_mac_exact *p = c.u.exact; + unsigned int max_mac_addr = adap->chip_params->mps_tcam_size; + + if (idx < 0) /* new allocation */ + idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC; + mode = smt_idx ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) | + F_FW_CMD_REQUEST | F_FW_CMD_WRITE | + V_FW_VI_MAC_CMD_VIID(viid)); + c.freemacs_to_len16 = cpu_to_be32( + V_FW_CMD_LEN16(1) | + (smac ? F_FW_VI_MAC_CMD_IS_SMAC : 0)); + p->valid_to_idx = cpu_to_be16(F_FW_VI_MAC_CMD_VALID | + V_FW_VI_MAC_CMD_SMAC_RESULT(mode) | + V_FW_VI_MAC_CMD_IDX(idx)); + memcpy(p->macaddr, addr, sizeof(p->macaddr)); + + ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); + if (ret == 0) { + ret = G_FW_VI_MAC_CMD_IDX(be16_to_cpu(p->valid_to_idx)); + if (ret >= max_mac_addr) + return -ENOMEM; + if (smt_idx) { + /* Does fw supports returning smt_idx? */ + if (adap->params.viid_smt_extn_support) + *smt_idx = G_FW_VI_MAC_CMD_SMTID(be32_to_cpu(c.op_to_viid)); + else { + /* In T4/T5, SMT contains 256 SMAC entries + * organized in 128 rows of 2 entries each. + * In T6, SMT contains 256 SMAC entries in + * 256 rows. + */ + if (chip_id(adap) <= CHELSIO_T5) + *smt_idx = ((viid & M_FW_VIID_VIN) << 1); + else + *smt_idx = (viid & M_FW_VIID_VIN); + } + } + } + + return ret; +} diff --git a/sys/dev/cxgbe/common/t4_hw.h b/sys/dev/cxgbe/common/t4_hw.h index 4458840cdd56..36ce6271dad6 100644 --- a/sys/dev/cxgbe/common/t4_hw.h +++ b/sys/dev/cxgbe/common/t4_hw.h @@ -43,6 +43,7 @@ enum { EEPROMVSIZE = 32768, /* Serial EEPROM virtual address space size */ EEPROMPFSIZE = 1024, /* EEPROM writable area size for PFn, n>0 */ RSS_NENTRIES = 2048, /* # of entries in RSS mapping table */ + T6_RSS_NENTRIES = 4096, TCB_SIZE = 128, /* TCB size */ NMTUS = 16, /* size of MTU table */ NCCTRL_WIN = 32, /* # of congestion control windows */ @@ -92,6 +93,7 @@ enum { SGE_CTXT_SIZE = 24, /* size of SGE context */ SGE_NTIMERS = 6, /* # of interrupt holdoff timer values */ SGE_NCOUNTERS = 4, /* # of interrupt packet counter values */ + SGE_NDBQTIMERS = 8, /* # of Doorbell Queue Timer values */ SGE_MAX_IQ_SIZE = 65520, SGE_FLBUF_SIZES = 16, }; @@ -299,4 +301,14 @@ enum { #define V_SGE_TIMESTAMP(x) ((__u64)(x) << S_SGE_TIMESTAMP) #define G_SGE_TIMESTAMP(x) (((__u64)(x) >> S_SGE_TIMESTAMP) & M_SGE_TIMESTAMP) +#define I2C_DEV_ADDR_A0 0xa0 +#define I2C_DEV_ADDR_A2 0xa2 +#define I2C_PAGE_SIZE 0x100 +#define SFP_DIAG_TYPE_ADDR 0x5c +#define SFP_DIAG_TYPE_LEN 0x1 +#define SFF_8472_COMP_ADDR 0x5e +#define SFF_8472_COMP_LEN 0x1 +#define SFF_REV_ADDR 0x1 +#define SFF_REV_LEN 0x1 + #endif /* __T4_HW_H */ diff --git a/sys/dev/cxgbe/cudbg/cudbg_lib.c b/sys/dev/cxgbe/cudbg/cudbg_lib.c index 5123ea72fa75..abd34b09dde2 100644 --- a/sys/dev/cxgbe/cudbg/cudbg_lib.c +++ b/sys/dev/cxgbe/cudbg/cudbg_lib.c @@ -576,7 +576,7 @@ static int collect_rss(struct cudbg_init *pdbg_init, u32 size; int rc = 0; - size = RSS_NENTRIES * sizeof(u16); + size = padap->chip_params->rss_nentries * sizeof(u16); rc = get_scratch_buff(dbg_buff, size, &scratch_buff); if (rc) goto err; From cfaafa790855a20004cedf0ea519d80db88c4d1d Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Fri, 24 Jul 2020 23:17:09 +0000 Subject: [PATCH 152/287] Add support for ext_pgs mbufs to nfsm_uiombuflist() and nfsm_split(). This patch uses a slightly different algorithm for nfsm_uiombuflist() for the non-ext_pgs case, where a variable called "mcp" is maintained, pointing to the current location that mbuf data can be filled into. This avoids use of mtod(mp, char *) + mp->m_len to calculate the location, since this does not work for ext_pgs mbufs and I think it makes the algorithm more readable. This change should not result in semantic changes for the non-ext_pgs case. The patch also deletes come unneeded code. It also adds support for anonymous page ext_pgs mbufs to nfsm_split(). This is another in the series of commits that add support to the NFS client and server for building RPC messages in ext_pgs mbufs with anonymous pages. This is useful so that the entire mbuf list does not need to be copied before calling sosend() when NFS over TLS is enabled. At this time for this case, use of ext_pgs mbufs cannot be enabled, since ktls_encrypt() replaces the unencrypted data with encrypted data in place. Until such time as this can be enabled, there should be no semantic change. Also, note that this code is only used by the NFS client for a mirrored pNFS server. --- sys/fs/nfs/nfs_var.h | 2 +- sys/fs/nfsclient/nfs_clcomsubs.c | 73 ++++++++++++++-------- sys/fs/nfsclient/nfs_clrpcops.c | 103 ++++++++++++++++++++++++++++--- 3 files changed, 141 insertions(+), 37 deletions(-) diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index e92a6859d0de..0e826a2b6524 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -365,7 +365,7 @@ struct mbuf *nfsm_add_ext_pgs(struct mbuf *, int, int *); /* nfs_clcomsubs.c */ void nfsm_uiombuf(struct nfsrv_descript *, struct uio *, int); -struct mbuf *nfsm_uiombuflist(struct uio *, int, struct mbuf **, char **); +struct mbuf *nfsm_uiombuflist(struct uio *, int, u_int); nfsuint64 *nfscl_getcookie(struct nfsnode *, off_t off, int); u_int8_t *nfscl_getmyip(struct nfsmount *, struct in6_addr *, int *); int nfsm_getfh(struct nfsrv_descript *, struct nfsfh **); diff --git a/sys/fs/nfsclient/nfs_clcomsubs.c b/sys/fs/nfsclient/nfs_clcomsubs.c index 440769fe0cc9..f4a6b8dfa90b 100644 --- a/sys/fs/nfsclient/nfs_clcomsubs.c +++ b/sys/fs/nfsclient/nfs_clcomsubs.c @@ -160,26 +160,33 @@ nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz) * NOTE: can ony handle iovcnt == 1 */ struct mbuf * -nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp) +nfsm_uiombuflist(struct uio *uiop, int siz, u_int maxext) { char *uiocp; struct mbuf *mp, *mp2, *firstmp; - int i, left, mlen, rem, xfer; + int extpg, extpgsiz = 0, i, left, mlen, rem, xfer; int uiosiz, clflg; char *mcp, *tcp; KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1")); - if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */ - clflg = 1; - else - clflg = 0; - if (clflg != 0) - NFSMCLGET(mp, M_WAITOK); - else - NFSMGET(mp); + if (maxext > 0) { + mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK); + mcp = (char *)(void *)PHYS_TO_DMAP(mp->m_epg_pa[0]); + extpg = 0; + extpgsiz = PAGE_SIZE; + } else { + if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */ + clflg = 1; + else + clflg = 0; + if (clflg != 0) + NFSMCLGET(mp, M_WAITOK); + else + NFSMGET(mp); + mcp = mtod(mp, char *); + } mp->m_len = 0; - mcp = mtod(mp, char *); firstmp = mp2 = mp; rem = NFSM_RNDUP(siz) - siz; while (siz > 0) { @@ -189,17 +196,28 @@ nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp) left = siz; uiosiz = left; while (left > 0) { - mlen = M_TRAILINGSPACE(mp); - if (mlen == 0) { - if (clflg) - NFSMCLGET(mp, M_WAITOK); - else - NFSMGET(mp); - mp->m_len = 0; - mcp = mtod(mp, char *); - mp2->m_next = mp; - mp2 = mp; + if (maxext > 0) + mlen = extpgsiz; + else mlen = M_TRAILINGSPACE(mp); + if (mlen == 0) { + if (maxext > 0) { + mp = nfsm_add_ext_pgs(mp, maxext, + &extpg); + mlen = extpgsiz = PAGE_SIZE; + mcp = (char *)(void *)PHYS_TO_DMAP( + mp->m_epg_pa[extpg]); + } else { + if (clflg) + NFSMCLGET(mp, M_WAITOK); + else + NFSMGET(mp); + mcp = mtod(mp, char *); + mlen = M_TRAILINGSPACE(mp); + mp->m_len = 0; + mp2->m_next = mp; + mp2 = mp; + } } xfer = (left > mlen) ? mlen : left; if (uiop->uio_segflg == UIO_SYSSPACE) @@ -208,6 +226,10 @@ nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp) copyin(uiocp, mcp, xfer); mp->m_len += xfer; mcp += xfer; + if (maxext > 0) { + extpgsiz -= xfer; + mp->m_epg_last_len += xfer; + } left -= xfer; uiocp += xfer; uiop->uio_offset += xfer; @@ -220,16 +242,15 @@ nfsm_uiombuflist(struct uio *uiop, int siz, struct mbuf **mbp, char **cpp) siz -= uiosiz; } if (rem > 0) { - KASSERT(rem <= M_TRAILINGSPACE(mp), + KASSERT((mp->m_flags & M_EXTPG) != 0 || + rem <= M_TRAILINGSPACE(mp), ("nfsm_uiombuflist: no space for padding")); for (i = 0; i < rem; i++) *mcp++ = '\0'; mp->m_len += rem; + if (maxext > 0) + mp->m_epg_last_len += rem; } - if (cpp != NULL) - *cpp = mtod(mp, caddr_t) + mp->m_len; - if (mbp != NULL) - *mbp = mp; return (firstmp); } diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 35b4a44c2d7f..33065249315f 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -5862,7 +5862,7 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, uiop->uio_iov->iov_base; iovlen = uiop->uio_iov->iov_len; m = nfsm_uiombuflist(uiop, len, - NULL, NULL); + 0); } tdrpc = drpc = malloc(sizeof(*drpc) * (mirrorcnt - 1), M_TEMP, M_WAITOK | @@ -6545,12 +6545,6 @@ nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit, if (len > 0) { /* Put data in mbuf chain. */ nd->nd_mb->m_next = m; - /* Set nd_mb and nd_bpos to end of data. */ - while (m->m_next != NULL) - m = m->m_next; - nd->nd_mb = m; - nd->nd_bpos = mtod(m, char *) + m->m_len; - NFSCL_DEBUG(4, "nfsrpc_writedsmir: lastmb len=%d\n", m->m_len); } nrp = dsp->nfsclds_sockp; if (nrp == NULL) @@ -8625,8 +8619,97 @@ nfsrpc_listextattr(vnode_t vp, uint64_t *cookiep, struct uio *uiop, static struct mbuf * nfsm_split(struct mbuf *mp, uint64_t xfer) { - struct mbuf *m; + struct mbuf *m, *m2; + vm_page_t pg; + int i, j, left, pgno, plen, trim; + char *cp, *cp2; - m = m_split(mp, xfer, M_WAITOK); - return (m); + if ((mp->m_flags & M_EXTPG) == 0) { + m = m_split(mp, xfer, M_WAITOK); + return (m); + } + + /* Find the correct mbuf to split at. */ + for (m = mp; m != NULL && xfer > m->m_len; m = m->m_next) + xfer -= m->m_len; + if (m == NULL) + return (NULL); + + /* If xfer == m->m_len, we can just split the mbuf list. */ + if (xfer == m->m_len) { + m2 = m->m_next; + m->m_next = NULL; + return (m2); + } + + /* Find the page to split at. */ + pgno = 0; + left = xfer; + do { + if (pgno == 0) + plen = m_epg_pagelen(m, 0, m->m_epg_1st_off); + else + plen = m_epg_pagelen(m, pgno, 0); + if (left <= plen) + break; + left -= plen; + pgno++; + } while (pgno < m->m_epg_npgs); + if (pgno == m->m_epg_npgs) + panic("nfsm_split: eroneous ext_pgs mbuf"); + + m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs); + m2->m_epg_flags |= EPG_FLAG_ANON; + + /* + * If left < plen, allocate a new page for the new mbuf + * and copy the data after left in the page to this new + * page. + */ + if (left < plen) { + do { + pg = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | + VM_ALLOC_NOOBJ | VM_ALLOC_NODUMP | + VM_ALLOC_WIRED); + if (pg == NULL) + vm_wait(NULL); + } while (pg == NULL); + m2->m_epg_pa[0] = VM_PAGE_TO_PHYS(pg); + m2->m_epg_npgs = 1; + + /* Copy the data after left to the new page. */ + trim = plen - left; + cp = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]); + if (pgno == 0) + cp += m->m_epg_1st_off; + cp += left; + cp2 = (char *)(void *)PHYS_TO_DMAP(m2->m_epg_pa[0]); + if (pgno == m->m_epg_npgs - 1) + m2->m_epg_last_len = trim; + else { + cp2 += PAGE_SIZE - trim; + m2->m_epg_1st_off = PAGE_SIZE - trim; + m2->m_epg_last_len = m->m_epg_last_len; + } + memcpy(cp2, cp, trim); + m2->m_len = trim; + } else { + m2->m_len = 0; + m2->m_epg_last_len = m->m_epg_last_len; + } + + /* Move the pages beyond pgno to the new mbuf. */ + for (i = pgno + 1, j = m2->m_epg_npgs; i < m->m_epg_npgs; i++, j++) { + m2->m_epg_pa[j] = m->m_epg_pa[i]; + /* Never moves page 0. */ + m2->m_len += m_epg_pagelen(m, i, 0); + } + m2->m_epg_npgs = j; + m->m_epg_npgs = pgno + 1; + m->m_epg_last_len = left; + m->m_len = xfer; + + m2->m_next = m->m_next; + m->m_next = NULL; + return (m2); } From d873a521cad3dfa744d069c9a682c6ac0d21d837 Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Sat, 25 Jul 2020 06:32:23 +0000 Subject: [PATCH 153/287] Revert r363123. As Emanuel poited me the Linux processes these clock assignments in forward order, not in reversed. I misread the original code. Tha problem with wrong order for assigned clocks found in tegra (and some imx) DT should be reanalyzed and solved by different way. MFC with: r363123 Reported by; manu --- sys/dev/extres/clk/clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/dev/extres/clk/clk.c b/sys/dev/extres/clk/clk.c index 5715315d309b..acb4a2cfecb0 100644 --- a/sys/dev/extres/clk/clk.c +++ b/sys/dev/extres/clk/clk.c @@ -1407,7 +1407,7 @@ clk_set_assigned(device_t dev, phandle_t node) if (ofw_bus_parse_xref_list_get_length(node, "assigned-clock-parents", "#clock-cells", &nparents) != 0) nparents = -1; - for (i = nclocks - 1; i >= 0; i--) { + for (i = 0; i < nclocks; i++) { /* First get the clock we are supposed to modify */ rv = clk_get_by_ofw_index_prop(dev, 0, "assigned-clocks", i, &clk); From bf71b96c69b07a177c34a5dfe6d021e9a8d1c2e8 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 07:14:33 +0000 Subject: [PATCH 154/287] Do a lockless check in kthread_suspend_check Otherwise an idle system running lockstat sleep 10 reports contention on process lock comming from bufdaemon. While here fix a style nit. --- sys/kern/kern_kthread.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c index 939bd689269b..092d0b9a0e0f 100644 --- a/sys/kern/kern_kthread.c +++ b/sys/kern/kern_kthread.c @@ -441,12 +441,15 @@ kthread_suspend_check(void) panic("%s: curthread is not a valid kthread", __func__); /* - * As long as the double-lock protection is used when accessing the - * TDF_KTH_SUSP flag, synchronizing the read operation via proc mutex - * is fine. + * Setting the TDF_KTH_SUSP flag is protected by process lock. + * + * Do an unlocked read first to avoid serializing with all other threads + * in the common case of not suspending. */ + if ((td->td_flags & TDF_KTH_SUSP) == 0) + return; PROC_LOCK(p); - while (td->td_flags & TDF_KTH_SUSP) { + while ((td->td_flags & TDF_KTH_SUSP) != 0) { wakeup(&td->td_flags); msleep(&td->td_flags, &p->p_mtx, PPAUSE, "ktsusp", 0); } From d1385ab26e090d3c442327378ae9b03d587c6a18 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 07:15:23 +0000 Subject: [PATCH 155/287] Guard sbcompress_ktls_rx with KERN_TLS Fixes a compilation warning after r363464 --- sys/kern/uipc_sockbuf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c index bcdc0970c778..7a364ba3d5d2 100644 --- a/sys/kern/uipc_sockbuf.c +++ b/sys/kern/uipc_sockbuf.c @@ -70,8 +70,10 @@ u_long sb_max_adj = static u_long sb_efficiency = 8; /* parameter for sbreserve() */ +#ifdef KERN_TLS static void sbcompress_ktls_rx(struct sockbuf *sb, struct mbuf *m, struct mbuf *n); +#endif static struct mbuf *sbcut_internal(struct sockbuf *sb, int len); static void sbflush_internal(struct sockbuf *sb); From 109b537cd7bd65b0ed03362ecabb1d8634d2ed21 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 07:45:44 +0000 Subject: [PATCH 156/287] Remove leftover macros for long gone vmsize mtx --- sys/sys/resourcevar.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/sys/sys/resourcevar.h b/sys/sys/resourcevar.h index cba2667555c9..c33511f94434 100644 --- a/sys/sys/resourcevar.h +++ b/sys/sys/resourcevar.h @@ -109,9 +109,6 @@ struct uidinfo { #endif }; -#define UIDINFO_VMSIZE_LOCK(ui) mtx_lock(&((ui)->ui_vmsize_mtx)) -#define UIDINFO_VMSIZE_UNLOCK(ui) mtx_unlock(&((ui)->ui_vmsize_mtx)) - struct proc; struct rusage_ext; struct thread; From d53582388b2f58142df8021efa0765f4fb879b84 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 07:48:20 +0000 Subject: [PATCH 157/287] Remove duplicated content from _eventhandler.h --- sys/sys/_eventhandler.h | 72 ----------------------------------------- 1 file changed, 72 deletions(-) diff --git a/sys/sys/_eventhandler.h b/sys/sys/_eventhandler.h index f8f24d2b1533..ce8ab253a445 100644 --- a/sys/sys/_eventhandler.h +++ b/sys/sys/_eventhandler.h @@ -70,75 +70,3 @@ struct eventhandler_entry_ ## name \ struct __hack #endif -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 1999 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _SYS__EVENTHANDLER_H_ -#define _SYS__EVENTHANDLER_H_ - -#include - -struct eventhandler_entry { - TAILQ_ENTRY(eventhandler_entry) ee_link; - int ee_priority; -#define EHE_DEAD_PRIORITY (-1) - void *ee_arg; -}; - -typedef struct eventhandler_entry *eventhandler_tag; - -/* - * You can optionally use the EVENTHANDLER_LIST and EVENTHANDLER_DIRECT macros - * to pre-define a symbol for the eventhandler list. This symbol can be used by - * EVENTHANDLER_DIRECT_INVOKE, which has the advantage of not needing to do a - * locked search of the global list of eventhandler lists. At least - * EVENTHANDLER_LIST_DEFINE must be be used for EVENTHANDLER_DIRECT_INVOKE to - * work. EVENTHANDLER_LIST_DECLARE is only needed if the call to - * EVENTHANDLER_DIRECT_INVOKE is in a different compilation unit from - * EVENTHANDLER_LIST_DEFINE. If the events are even relatively high frequency - * it is suggested that you directly define a list for them. - */ -struct eventhandler_list; -#define EVENTHANDLER_LIST_DECLARE(name) \ -extern struct eventhandler_list *_eventhandler_list_ ## name \ - -/* - * Event handlers need to be declared, but do not need to be defined. The - * declaration must be in scope wherever the handler is to be invoked. - */ -#define EVENTHANDLER_DECLARE(name, type) \ -struct eventhandler_entry_ ## name \ -{ \ - struct eventhandler_entry ee; \ - type eh_func; \ -}; \ -struct __hack - -#endif From 62ad310c93831fef195e4c0fbecaeb998e1064cb Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Sat, 25 Jul 2020 09:28:38 +0000 Subject: [PATCH 158/287] Split-out the Intel GAS (Guest Address Space) management component from Intel DMAR support, so it can be used on other IOMMU systems. Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25743 --- sys/dev/iommu/iommu.h | 9 ++ sys/x86/iommu/intel_ctx.c | 56 ++++--- sys/x86/iommu/intel_dmar.h | 31 ++-- sys/x86/iommu/intel_drv.c | 14 +- sys/x86/iommu/intel_gas.c | 297 ++++++++++++++++------------------ sys/x86/iommu/intel_idpgtbl.c | 24 ++- sys/x86/iommu/intel_utils.c | 4 +- 7 files changed, 219 insertions(+), 216 deletions(-) diff --git a/sys/dev/iommu/iommu.h b/sys/dev/iommu/iommu.h index 8d039c2dee09..d0ac3052a313 100644 --- a/sys/dev/iommu/iommu.h +++ b/sys/dev/iommu/iommu.h @@ -48,6 +48,10 @@ struct bus_dma_tag_common; struct iommu_map_entry; TAILQ_HEAD(iommu_map_entries_tailq, iommu_map_entry); +RB_HEAD(iommu_gas_entries_tree, iommu_map_entry); +RB_PROTOTYPE(iommu_gas_entries_tree, iommu_map_entry, rb_entry, + iommu_gas_cmp_entries); + struct iommu_qi_genseq { u_int gen; uint32_t seq; @@ -107,6 +111,11 @@ struct iommu_domain { u_int entries_cnt; /* (d) */ struct iommu_map_entries_tailq unload_entries; /* (d) Entries to unload */ + struct iommu_gas_entries_tree rb_root; /* (d) */ + iommu_gaddr_t end; /* (c) Highest address + 1 in + the guest AS */ + struct iommu_map_entry *first_place, *last_place; /* (d) */ + u_int flags; /* (u) */ }; struct iommu_ctx { diff --git a/sys/x86/iommu/intel_ctx.c b/sys/x86/iommu/intel_ctx.c index dd551c2f56d3..9d67a5cf20f4 100644 --- a/sys/x86/iommu/intel_ctx.c +++ b/sys/x86/iommu/intel_ctx.c @@ -132,7 +132,7 @@ device_tag_init(struct dmar_ctx *ctx, device_t dev) bus_addr_t maxaddr; domain = (struct dmar_domain *)ctx->context.domain; - maxaddr = MIN(domain->end, BUS_SPACE_MAXADDR); + maxaddr = MIN(domain->iodom.end, BUS_SPACE_MAXADDR); ctx->context.tag->common.ref_count = 1; /* Prevent free */ ctx->context.tag->common.impl = &bus_dma_iommu_impl; ctx->context.tag->common.boundary = 0; @@ -186,7 +186,7 @@ ctx_id_entry_init(struct dmar_ctx *ctx, dmar_ctx_entry_t *ctxp, bool move, pci_get_function(ctx->context.tag->owner), ctxp->ctx1, ctxp->ctx2)); - if ((domain->flags & DMAR_DOMAIN_IDMAP) != 0 && + if ((domain->iodom.flags & DMAR_DOMAIN_IDMAP) != 0 && (unit->hw_ecap & DMAR_ECAP_PT) != 0) { KASSERT(domain->pgtbl_obj == NULL, ("ctx %p non-null pgtbl_obj", ctx)); @@ -254,7 +254,7 @@ domain_init_rmrr(struct dmar_domain *domain, device_t dev, int bus, * and round as neccesary. * * We also allow the overlapping RMRR entries, see - * dmar_gas_alloc_region(). + * iommu_gas_alloc_region(). */ start = entry->start; end = entry->end; @@ -282,7 +282,8 @@ domain_init_rmrr(struct dmar_domain *domain, device_t dev, int bus, ma[i] = vm_page_getfake(entry->start + PAGE_SIZE * i, VM_MEMATTR_DEFAULT); } - error1 = dmar_gas_map_region(domain, entry, + error1 = iommu_gas_map_region((struct iommu_domain *)domain, + entry, IOMMU_MAP_ENTRY_READ | IOMMU_MAP_ENTRY_WRITE, IOMMU_MF_CANWAIT | IOMMU_MF_RMRR, ma); /* @@ -294,7 +295,7 @@ domain_init_rmrr(struct dmar_domain *domain, device_t dev, int bus, if (error1 == 0 && entry->end != entry->start) { IOMMU_LOCK(domain->iodom.iommu); domain->refs++; /* XXXKIB prevent free */ - domain->flags |= DMAR_DOMAIN_RMRR; + domain->iodom.flags |= DMAR_DOMAIN_RMRR; IOMMU_UNLOCK(domain->iodom.iommu); } else { if (error1 != 0) { @@ -308,7 +309,8 @@ domain_init_rmrr(struct dmar_domain *domain, device_t dev, int bus, error = error1; } TAILQ_REMOVE(&rmrr_entries, entry, unroll_link); - dmar_gas_free_entry(domain, entry); + iommu_gas_free_entry((struct iommu_domain *)domain, + entry); } for (i = 0; i < size; i++) vm_page_putfake(ma[i]); @@ -320,6 +322,7 @@ domain_init_rmrr(struct dmar_domain *domain, device_t dev, int bus, static struct dmar_domain * dmar_domain_alloc(struct dmar_unit *dmar, bool id_mapped) { + struct iommu_domain *iodom; struct dmar_domain *domain; int error, id, mgaw; @@ -327,9 +330,10 @@ dmar_domain_alloc(struct dmar_unit *dmar, bool id_mapped) if (id == -1) return (NULL); domain = malloc(sizeof(*domain), M_DMAR_DOMAIN, M_WAITOK | M_ZERO); + iodom = (struct iommu_domain *)domain; domain->domain = id; LIST_INIT(&domain->contexts); - RB_INIT(&domain->rb_root); + RB_INIT(&domain->iodom.rb_root); TAILQ_INIT(&domain->iodom.unload_entries); TASK_INIT(&domain->iodom.unload_task, 0, dmar_domain_unload_task, domain); @@ -343,29 +347,29 @@ dmar_domain_alloc(struct dmar_unit *dmar, bool id_mapped) * It is useful for the identity mapping, and less so for the * virtualized bus address space. */ - domain->end = id_mapped ? ptoa(Maxmem) : BUS_SPACE_MAXADDR; - mgaw = dmar_maxaddr2mgaw(dmar, domain->end, !id_mapped); + domain->iodom.end = id_mapped ? ptoa(Maxmem) : BUS_SPACE_MAXADDR; + mgaw = dmar_maxaddr2mgaw(dmar, domain->iodom.end, !id_mapped); error = domain_set_agaw(domain, mgaw); if (error != 0) goto fail; if (!id_mapped) /* Use all supported address space for remapping. */ - domain->end = 1ULL << (domain->agaw - 1); + domain->iodom.end = 1ULL << (domain->agaw - 1); - dmar_gas_init_domain(domain); + iommu_gas_init_domain((struct iommu_domain *)domain); if (id_mapped) { if ((dmar->hw_ecap & DMAR_ECAP_PT) == 0) { domain->pgtbl_obj = domain_get_idmap_pgtbl(domain, - domain->end); + domain->iodom.end); } - domain->flags |= DMAR_DOMAIN_IDMAP; + domain->iodom.flags |= DMAR_DOMAIN_IDMAP; } else { error = domain_alloc_pgtbl(domain); if (error != 0) goto fail; /* Disable local apic region access */ - error = dmar_gas_reserve_region(domain, 0xfee00000, + error = iommu_gas_reserve_region(iodom, 0xfee00000, 0xfeefffff + 1); if (error != 0) goto fail; @@ -436,12 +440,12 @@ dmar_domain_destroy(struct dmar_domain *domain) ("destroying dom %p with ctx_cnt %d", domain, domain->ctx_cnt)); KASSERT(domain->refs == 0, ("destroying dom %p with refs %d", domain, domain->refs)); - if ((domain->flags & DMAR_DOMAIN_GAS_INITED) != 0) { + if ((domain->iodom.flags & DMAR_DOMAIN_GAS_INITED) != 0) { DMAR_DOMAIN_LOCK(domain); - dmar_gas_fini_domain(domain); + iommu_gas_fini_domain((struct iommu_domain *)domain); DMAR_DOMAIN_UNLOCK(domain); } - if ((domain->flags & DMAR_DOMAIN_PGTBL_INITED) != 0) { + if ((domain->iodom.flags & DMAR_DOMAIN_PGTBL_INITED) != 0) { if (domain->pgtbl_obj != NULL) DMAR_DOMAIN_PGLOCK(domain); domain_free_pgtbl(domain); @@ -639,7 +643,7 @@ dmar_move_ctx_to_domain(struct dmar_domain *domain, struct dmar_ctx *ctx) /* If flush failed, rolling back would not work as well. */ printf("dmar%d rid %x domain %d->%d %s-mapped\n", dmar->iommu.unit, ctx->rid, old_domain->domain, domain->domain, - (domain->flags & DMAR_DOMAIN_IDMAP) != 0 ? "id" : "re"); + (domain->iodom.flags & DMAR_DOMAIN_IDMAP) != 0 ? "id" : "re"); dmar_unref_domain_locked(dmar, old_domain); TD_PINNED_ASSERT; return (error); @@ -663,7 +667,7 @@ dmar_unref_domain_locked(struct dmar_unit *dmar, struct dmar_domain *domain) return; } - KASSERT((domain->flags & DMAR_DOMAIN_RMRR) == 0, + KASSERT((domain->iodom.flags & DMAR_DOMAIN_RMRR) == 0, ("lost ref on RMRR domain %p", domain)); LIST_REMOVE(domain, link); @@ -781,17 +785,17 @@ dmar_find_ctx_locked(struct dmar_unit *dmar, uint16_t rid) void dmar_domain_free_entry(struct iommu_map_entry *entry, bool free) { - struct dmar_domain *domain; + struct iommu_domain *domain; - domain = (struct dmar_domain *)entry->domain; - DMAR_DOMAIN_LOCK(domain); + domain = entry->domain; + IOMMU_DOMAIN_LOCK(domain); if ((entry->flags & IOMMU_MAP_ENTRY_RMRR) != 0) - dmar_gas_free_region(domain, entry); + iommu_gas_free_region(domain, entry); else - dmar_gas_free_space(domain, entry); - DMAR_DOMAIN_UNLOCK(domain); + iommu_gas_free_space(domain, entry); + IOMMU_DOMAIN_UNLOCK(domain); if (free) - dmar_gas_free_entry(domain, entry); + iommu_gas_free_entry(domain, entry); else entry->flags = 0; } diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h index e6212255b382..ef2bdd3c9bf7 100644 --- a/sys/x86/iommu/intel_dmar.h +++ b/sys/x86/iommu/intel_dmar.h @@ -38,10 +38,6 @@ struct dmar_unit; -RB_HEAD(dmar_gas_entries_tree, iommu_map_entry); -RB_PROTOTYPE(dmar_gas_entries_tree, iommu_map_entry, rb_entry, - dmar_gas_cmp_entries); - /* * Locking annotations: * (u) - Protected by iommu unit lock @@ -68,17 +64,12 @@ struct dmar_domain { int pglvl; /* (c) The pagelevel */ int awlvl; /* (c) The pagelevel as the bitmask, to set in context entry */ - iommu_gaddr_t end; /* (c) Highest address + 1 in - the guest AS */ u_int ctx_cnt; /* (u) Number of contexts owned */ u_int refs; /* (u) Refs, including ctx */ struct dmar_unit *dmar; /* (c) */ LIST_ENTRY(dmar_domain) link; /* (u) Member in the dmar list */ LIST_HEAD(, dmar_ctx) contexts; /* (u) */ vm_object_t pgtbl_obj; /* (c) Page table pages */ - u_int flags; /* (u) */ - struct dmar_gas_entries_tree rb_root; /* (d) */ - struct iommu_map_entry *first_place, *last_place; /* (d) */ u_int batch_no; }; @@ -269,7 +260,7 @@ void dmar_qi_invalidate_iec(struct dmar_unit *unit, u_int start, u_int cnt); vm_object_t domain_get_idmap_pgtbl(struct dmar_domain *domain, iommu_gaddr_t maxaddr); void put_idmap_pgtbl(vm_object_t obj); -int domain_map_buf(struct dmar_domain *domain, iommu_gaddr_t base, +int domain_map_buf(struct iommu_domain *domain, iommu_gaddr_t base, iommu_gaddr_t size, vm_page_t *ma, uint64_t pflags, int flags); int domain_unmap_buf(struct dmar_domain *domain, iommu_gaddr_t base, iommu_gaddr_t size, int flags); @@ -295,22 +286,22 @@ void dmar_domain_unload(struct dmar_domain *domain, struct iommu_map_entries_tailq *entries, bool cansleep); void dmar_domain_free_entry(struct iommu_map_entry *entry, bool free); -void dmar_gas_init_domain(struct dmar_domain *domain); -void dmar_gas_fini_domain(struct dmar_domain *domain); -struct iommu_map_entry *dmar_gas_alloc_entry(struct dmar_domain *domain, +void iommu_gas_init_domain(struct iommu_domain *domain); +void iommu_gas_fini_domain(struct iommu_domain *domain); +struct iommu_map_entry *iommu_gas_alloc_entry(struct iommu_domain *domain, u_int flags); -void dmar_gas_free_entry(struct dmar_domain *domain, +void iommu_gas_free_entry(struct iommu_domain *domain, struct iommu_map_entry *entry); -void dmar_gas_free_space(struct dmar_domain *domain, +void iommu_gas_free_space(struct iommu_domain *domain, struct iommu_map_entry *entry); -int dmar_gas_map(struct dmar_domain *domain, +int iommu_gas_map(struct iommu_domain *domain, const struct bus_dma_tag_common *common, iommu_gaddr_t size, int offset, u_int eflags, u_int flags, vm_page_t *ma, struct iommu_map_entry **res); -void dmar_gas_free_region(struct dmar_domain *domain, +void iommu_gas_free_region(struct iommu_domain *domain, struct iommu_map_entry *entry); -int dmar_gas_map_region(struct dmar_domain *domain, +int iommu_gas_map_region(struct iommu_domain *domain, struct iommu_map_entry *entry, u_int eflags, u_int flags, vm_page_t *ma); -int dmar_gas_reserve_region(struct dmar_domain *domain, iommu_gaddr_t start, +int iommu_gas_reserve_region(struct iommu_domain *domain, iommu_gaddr_t start, iommu_gaddr_t end); void dmar_dev_parse_rmrr(struct dmar_domain *domain, int dev_domain, @@ -342,7 +333,7 @@ extern iommu_haddr_t dmar_high; extern int haw; extern int dmar_tbl_pagecnt; extern int dmar_batch_coalesce; -extern int dmar_check_free; +extern int iommu_check_free; static inline uint32_t dmar_read4(const struct dmar_unit *unit, int reg) diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c index 90cc923180fa..1d3b1abc914d 100644 --- a/sys/x86/iommu/intel_drv.c +++ b/sys/x86/iommu/intel_drv.c @@ -176,7 +176,7 @@ dmar_identify(driver_t *driver, device_t parent) if (!dmar_enable) return; #ifdef INVARIANTS - TUNABLE_INT_FETCH("hw.dmar.check_free", &dmar_check_free); + TUNABLE_INT_FETCH("hw.iommu.check_free", &iommu_check_free); #endif status = AcpiGetTable(ACPI_SIG_DMAR, 1, (ACPI_TABLE_HEADER **)&dmartbl); if (ACPI_FAILURE(status)) @@ -945,7 +945,8 @@ dmar_rmrr_iter(ACPI_DMAR_HEADER *dmarh, void *arg) match = dmar_match_devscope(devscope, ria->dev_busno, ria->dev_path, ria->dev_path_len); if (match == 1) { - entry = dmar_gas_alloc_entry(ria->domain, + entry = iommu_gas_alloc_entry( + (struct iommu_domain *)ria->domain, DMAR_PGF_WAITOK); entry->start = resmem->BaseAddress; /* The RMRR entry end address is inclusive. */ @@ -1152,15 +1153,18 @@ dmar_print_ctx(struct dmar_ctx *ctx) static void dmar_print_domain(struct dmar_domain *domain, bool show_mappings) { + struct iommu_domain *iodom; struct iommu_map_entry *entry; struct dmar_ctx *ctx; + iodom = (struct iommu_domain *)domain; + db_printf( " @%p dom %d mgaw %d agaw %d pglvl %d end %jx refs %d\n" " ctx_cnt %d flags %x pgobj %p map_ents %u\n", domain, domain->domain, domain->mgaw, domain->agaw, domain->pglvl, - (uintmax_t)domain->end, domain->refs, domain->ctx_cnt, - domain->flags, domain->pgtbl_obj, domain->iodom.entries_cnt); + (uintmax_t)domain->iodom.end, domain->refs, domain->ctx_cnt, + domain->iodom.flags, domain->pgtbl_obj, domain->iodom.entries_cnt); if (!LIST_EMPTY(&domain->contexts)) { db_printf(" Contexts:\n"); LIST_FOREACH(ctx, &domain->contexts, link) @@ -1169,7 +1173,7 @@ dmar_print_domain(struct dmar_domain *domain, bool show_mappings) if (!show_mappings) return; db_printf(" mapped:\n"); - RB_FOREACH(entry, dmar_gas_entries_tree, &domain->rb_root) { + RB_FOREACH(entry, iommu_gas_entries_tree, &iodom->rb_root) { dmar_print_domain_entry(entry); if (db_pager_quit) break; diff --git a/sys/x86/iommu/intel_gas.c b/sys/x86/iommu/intel_gas.c index 9df0da9242b2..83302bb19db4 100644 --- a/sys/x86/iommu/intel_gas.c +++ b/sys/x86/iommu/intel_gas.c @@ -32,7 +32,7 @@ #include __FBSDID("$FreeBSD$"); -#define RB_AUGMENT(entry) dmar_gas_augment_entry(entry) +#define RB_AUGMENT(entry) iommu_gas_augment_entry(entry) #include #include @@ -63,12 +63,15 @@ __FBSDID("$FreeBSD$"); #include #include #include +#if defined(__amd64__) || defined(__i386__) #include #include #include #include +#include #include #include +#endif /* * Guest Address Space management. @@ -87,7 +90,7 @@ intel_gas_init(void) SYSINIT(intel_gas, SI_SUB_DRIVERS, SI_ORDER_FIRST, intel_gas_init, NULL); struct iommu_map_entry * -dmar_gas_alloc_entry(struct dmar_domain *domain, u_int flags) +iommu_gas_alloc_entry(struct iommu_domain *domain, u_int flags) { struct iommu_map_entry *res; @@ -97,25 +100,25 @@ dmar_gas_alloc_entry(struct dmar_domain *domain, u_int flags) res = uma_zalloc(iommu_map_entry_zone, ((flags & DMAR_PGF_WAITOK) != 0 ? M_WAITOK : M_NOWAIT) | M_ZERO); if (res != NULL) { - res->domain = (struct iommu_domain *)domain; - atomic_add_int(&domain->iodom.entries_cnt, 1); + res->domain = domain; + atomic_add_int(&domain->entries_cnt, 1); } return (res); } void -dmar_gas_free_entry(struct dmar_domain *domain, struct iommu_map_entry *entry) +iommu_gas_free_entry(struct iommu_domain *domain, struct iommu_map_entry *entry) { - KASSERT(domain == (struct dmar_domain *)entry->domain, + KASSERT(domain == (struct iommu_domain *)entry->domain, ("mismatched free domain %p entry %p entry->domain %p", domain, entry, entry->domain)); - atomic_subtract_int(&domain->iodom.entries_cnt, 1); + atomic_subtract_int(&domain->entries_cnt, 1); uma_zfree(iommu_map_entry_zone, entry); } static int -dmar_gas_cmp_entries(struct iommu_map_entry *a, struct iommu_map_entry *b) +iommu_gas_cmp_entries(struct iommu_map_entry *a, struct iommu_map_entry *b) { /* Last entry have zero size, so <= */ @@ -137,7 +140,7 @@ dmar_gas_cmp_entries(struct iommu_map_entry *a, struct iommu_map_entry *b) } static void -dmar_gas_augment_entry(struct iommu_map_entry *entry) +iommu_gas_augment_entry(struct iommu_map_entry *entry) { struct iommu_map_entry *child; iommu_gaddr_t free_down; @@ -159,18 +162,18 @@ dmar_gas_augment_entry(struct iommu_map_entry *entry) entry->free_down = free_down; } -RB_GENERATE(dmar_gas_entries_tree, iommu_map_entry, rb_entry, - dmar_gas_cmp_entries); +RB_GENERATE(iommu_gas_entries_tree, iommu_map_entry, rb_entry, + iommu_gas_cmp_entries); #ifdef INVARIANTS static void -dmar_gas_check_free(struct dmar_domain *domain) +iommu_gas_check_free(struct iommu_domain *domain) { struct iommu_map_entry *entry, *l, *r; iommu_gaddr_t v; - RB_FOREACH(entry, dmar_gas_entries_tree, &domain->rb_root) { - KASSERT(domain == (struct dmar_domain *)entry->domain, + RB_FOREACH(entry, iommu_gas_entries_tree, &domain->rb_root) { + KASSERT(domain == (struct iommu_domain *)entry->domain, ("mismatched free domain %p entry %p entry->domain %p", domain, entry, entry->domain)); l = RB_LEFT(entry, rb_entry); @@ -190,85 +193,88 @@ dmar_gas_check_free(struct dmar_domain *domain) #endif static bool -dmar_gas_rb_insert(struct dmar_domain *domain, struct iommu_map_entry *entry) +iommu_gas_rb_insert(struct iommu_domain *domain, struct iommu_map_entry *entry) { struct iommu_map_entry *found; - found = RB_INSERT(dmar_gas_entries_tree, &domain->rb_root, entry); + found = RB_INSERT(iommu_gas_entries_tree, + &domain->rb_root, entry); return (found == NULL); } static void -dmar_gas_rb_remove(struct dmar_domain *domain, struct iommu_map_entry *entry) +iommu_gas_rb_remove(struct iommu_domain *domain, struct iommu_map_entry *entry) { - RB_REMOVE(dmar_gas_entries_tree, &domain->rb_root, entry); + RB_REMOVE(iommu_gas_entries_tree, &domain->rb_root, entry); } void -dmar_gas_init_domain(struct dmar_domain *domain) +iommu_gas_init_domain(struct iommu_domain *domain) { struct iommu_map_entry *begin, *end; - begin = dmar_gas_alloc_entry(domain, DMAR_PGF_WAITOK); - end = dmar_gas_alloc_entry(domain, DMAR_PGF_WAITOK); + begin = iommu_gas_alloc_entry(domain, DMAR_PGF_WAITOK); + end = iommu_gas_alloc_entry(domain, DMAR_PGF_WAITOK); - DMAR_DOMAIN_LOCK(domain); - KASSERT(domain->iodom.entries_cnt == 2, ("dirty domain %p", domain)); - KASSERT(RB_EMPTY(&domain->rb_root), ("non-empty entries %p", domain)); + IOMMU_DOMAIN_LOCK(domain); + KASSERT(domain->entries_cnt == 2, ("dirty domain %p", domain)); + KASSERT(RB_EMPTY(&domain->rb_root), + ("non-empty entries %p", domain)); begin->start = 0; - begin->end = DMAR_PAGE_SIZE; + begin->end = IOMMU_PAGE_SIZE; begin->flags = IOMMU_MAP_ENTRY_PLACE | IOMMU_MAP_ENTRY_UNMAPPED; - dmar_gas_rb_insert(domain, begin); + iommu_gas_rb_insert(domain, begin); end->start = domain->end; end->end = domain->end; end->flags = IOMMU_MAP_ENTRY_PLACE | IOMMU_MAP_ENTRY_UNMAPPED; - dmar_gas_rb_insert(domain, end); + iommu_gas_rb_insert(domain, end); domain->first_place = begin; domain->last_place = end; domain->flags |= DMAR_DOMAIN_GAS_INITED; - DMAR_DOMAIN_UNLOCK(domain); + IOMMU_DOMAIN_UNLOCK(domain); } void -dmar_gas_fini_domain(struct dmar_domain *domain) +iommu_gas_fini_domain(struct iommu_domain *domain) { struct iommu_map_entry *entry, *entry1; - DMAR_DOMAIN_ASSERT_LOCKED(domain); - KASSERT(domain->iodom.entries_cnt == 2, + IOMMU_DOMAIN_ASSERT_LOCKED(domain); + KASSERT(domain->entries_cnt == 2, ("domain still in use %p", domain)); - entry = RB_MIN(dmar_gas_entries_tree, &domain->rb_root); + entry = RB_MIN(iommu_gas_entries_tree, &domain->rb_root); KASSERT(entry->start == 0, ("start entry start %p", domain)); - KASSERT(entry->end == DMAR_PAGE_SIZE, ("start entry end %p", domain)); + KASSERT(entry->end == IOMMU_PAGE_SIZE, ("start entry end %p", domain)); KASSERT(entry->flags == IOMMU_MAP_ENTRY_PLACE, ("start entry flags %p", domain)); - RB_REMOVE(dmar_gas_entries_tree, &domain->rb_root, entry); - dmar_gas_free_entry(domain, entry); + RB_REMOVE(iommu_gas_entries_tree, &domain->rb_root, entry); + iommu_gas_free_entry(domain, entry); - entry = RB_MAX(dmar_gas_entries_tree, &domain->rb_root); + entry = RB_MAX(iommu_gas_entries_tree, &domain->rb_root); KASSERT(entry->start == domain->end, ("end entry start %p", domain)); KASSERT(entry->end == domain->end, ("end entry end %p", domain)); KASSERT(entry->flags == IOMMU_MAP_ENTRY_PLACE, ("end entry flags %p", domain)); - RB_REMOVE(dmar_gas_entries_tree, &domain->rb_root, entry); - dmar_gas_free_entry(domain, entry); + RB_REMOVE(iommu_gas_entries_tree, &domain->rb_root, entry); + iommu_gas_free_entry(domain, entry); - RB_FOREACH_SAFE(entry, dmar_gas_entries_tree, &domain->rb_root, + RB_FOREACH_SAFE(entry, iommu_gas_entries_tree, &domain->rb_root, entry1) { KASSERT((entry->flags & IOMMU_MAP_ENTRY_RMRR) != 0, ("non-RMRR entry left %p", domain)); - RB_REMOVE(dmar_gas_entries_tree, &domain->rb_root, entry); - dmar_gas_free_entry(domain, entry); + RB_REMOVE(iommu_gas_entries_tree, &domain->rb_root, + entry); + iommu_gas_free_entry(domain, entry); } } -struct dmar_gas_match_args { - struct dmar_domain *domain; +struct iommu_gas_match_args { + struct iommu_domain *domain; iommu_gaddr_t size; int offset; const struct bus_dma_tag_common *common; @@ -277,25 +283,25 @@ struct dmar_gas_match_args { }; /* - * The interval [beg, end) is a free interval between two dmar_map_entries. + * The interval [beg, end) is a free interval between two iommu_map_entries. * maxaddr is an upper bound on addresses that can be allocated. Try to * allocate space in the free interval, subject to the conditions expressed * by a, and return 'true' if and only if the allocation attempt succeeds. */ static bool -dmar_gas_match_one(struct dmar_gas_match_args *a, iommu_gaddr_t beg, +iommu_gas_match_one(struct iommu_gas_match_args *a, iommu_gaddr_t beg, iommu_gaddr_t end, iommu_gaddr_t maxaddr) { iommu_gaddr_t bs, start; - a->entry->start = roundup2(beg + DMAR_PAGE_SIZE, + a->entry->start = roundup2(beg + IOMMU_PAGE_SIZE, a->common->alignment); if (a->entry->start + a->size > maxaddr) return (false); - /* DMAR_PAGE_SIZE to create gap after new entry. */ - if (a->entry->start < beg + DMAR_PAGE_SIZE || - a->entry->start + a->size + a->offset + DMAR_PAGE_SIZE > end) + /* IOMMU_PAGE_SIZE to create gap after new entry. */ + if (a->entry->start < beg + IOMMU_PAGE_SIZE || + a->entry->start + a->size + a->offset + IOMMU_PAGE_SIZE > end) return (false); /* No boundary crossing. */ @@ -311,8 +317,8 @@ dmar_gas_match_one(struct dmar_gas_match_args *a, iommu_gaddr_t beg, bs = rounddown2(a->entry->start + a->offset + a->common->boundary, a->common->boundary); start = roundup2(bs, a->common->alignment); - /* DMAR_PAGE_SIZE to create gap after new entry. */ - if (start + a->offset + a->size + DMAR_PAGE_SIZE <= end && + /* IOMMU_PAGE_SIZE to create gap after new entry. */ + if (start + a->offset + a->size + IOMMU_PAGE_SIZE <= end && start + a->offset + a->size <= maxaddr && iommu_test_boundary(start + a->offset, a->size, a->common->boundary)) { @@ -337,7 +343,7 @@ dmar_gas_match_one(struct dmar_gas_match_args *a, iommu_gaddr_t beg, } static void -dmar_gas_match_insert(struct dmar_gas_match_args *a) +iommu_gas_match_insert(struct iommu_gas_match_args *a) { bool found; @@ -351,84 +357,84 @@ dmar_gas_match_insert(struct dmar_gas_match_args *a) */ a->entry->end = a->entry->start + a->size; - found = dmar_gas_rb_insert(a->domain, a->entry); + found = iommu_gas_rb_insert(a->domain, a->entry); KASSERT(found, ("found dup %p start %jx size %jx", a->domain, (uintmax_t)a->entry->start, (uintmax_t)a->size)); a->entry->flags = IOMMU_MAP_ENTRY_MAP; } static int -dmar_gas_lowermatch(struct dmar_gas_match_args *a, struct iommu_map_entry *entry) +iommu_gas_lowermatch(struct iommu_gas_match_args *a, struct iommu_map_entry *entry) { struct iommu_map_entry *child; child = RB_RIGHT(entry, rb_entry); if (child != NULL && entry->end < a->common->lowaddr && - dmar_gas_match_one(a, entry->end, child->first, + iommu_gas_match_one(a, entry->end, child->first, a->common->lowaddr)) { - dmar_gas_match_insert(a); + iommu_gas_match_insert(a); return (0); } - if (entry->free_down < a->size + a->offset + DMAR_PAGE_SIZE) + if (entry->free_down < a->size + a->offset + IOMMU_PAGE_SIZE) return (ENOMEM); if (entry->first >= a->common->lowaddr) return (ENOMEM); child = RB_LEFT(entry, rb_entry); - if (child != NULL && 0 == dmar_gas_lowermatch(a, child)) + if (child != NULL && 0 == iommu_gas_lowermatch(a, child)) return (0); if (child != NULL && child->last < a->common->lowaddr && - dmar_gas_match_one(a, child->last, entry->start, + iommu_gas_match_one(a, child->last, entry->start, a->common->lowaddr)) { - dmar_gas_match_insert(a); + iommu_gas_match_insert(a); return (0); } child = RB_RIGHT(entry, rb_entry); - if (child != NULL && 0 == dmar_gas_lowermatch(a, child)) + if (child != NULL && 0 == iommu_gas_lowermatch(a, child)) return (0); return (ENOMEM); } static int -dmar_gas_uppermatch(struct dmar_gas_match_args *a, struct iommu_map_entry *entry) +iommu_gas_uppermatch(struct iommu_gas_match_args *a, struct iommu_map_entry *entry) { struct iommu_map_entry *child; - if (entry->free_down < a->size + a->offset + DMAR_PAGE_SIZE) + if (entry->free_down < a->size + a->offset + IOMMU_PAGE_SIZE) return (ENOMEM); if (entry->last < a->common->highaddr) return (ENOMEM); child = RB_LEFT(entry, rb_entry); - if (child != NULL && 0 == dmar_gas_uppermatch(a, child)) + if (child != NULL && 0 == iommu_gas_uppermatch(a, child)) return (0); if (child != NULL && child->last >= a->common->highaddr && - dmar_gas_match_one(a, child->last, entry->start, + iommu_gas_match_one(a, child->last, entry->start, a->domain->end)) { - dmar_gas_match_insert(a); + iommu_gas_match_insert(a); return (0); } child = RB_RIGHT(entry, rb_entry); if (child != NULL && entry->end >= a->common->highaddr && - dmar_gas_match_one(a, entry->end, child->first, + iommu_gas_match_one(a, entry->end, child->first, a->domain->end)) { - dmar_gas_match_insert(a); + iommu_gas_match_insert(a); return (0); } - if (child != NULL && 0 == dmar_gas_uppermatch(a, child)) + if (child != NULL && 0 == iommu_gas_uppermatch(a, child)) return (0); return (ENOMEM); } static int -dmar_gas_find_space(struct dmar_domain *domain, +iommu_gas_find_space(struct iommu_domain *domain, const struct bus_dma_tag_common *common, iommu_gaddr_t size, int offset, u_int flags, struct iommu_map_entry *entry) { - struct dmar_gas_match_args a; + struct iommu_gas_match_args a; int error; - DMAR_DOMAIN_ASSERT_LOCKED(domain); + IOMMU_DOMAIN_ASSERT_LOCKED(domain); KASSERT(entry->flags == 0, ("dirty entry %p %p", domain, entry)); - KASSERT((size & DMAR_PAGE_MASK) == 0, ("size %jx", (uintmax_t)size)); + KASSERT((size & IOMMU_PAGE_MASK) == 0, ("size %jx", (uintmax_t)size)); a.domain = domain; a.size = size; @@ -439,42 +445,43 @@ dmar_gas_find_space(struct dmar_domain *domain, /* Handle lower region. */ if (common->lowaddr > 0) { - error = dmar_gas_lowermatch(&a, RB_ROOT(&domain->rb_root)); + error = iommu_gas_lowermatch(&a, + RB_ROOT(&domain->rb_root)); if (error == 0) return (0); KASSERT(error == ENOMEM, - ("error %d from dmar_gas_lowermatch", error)); + ("error %d from iommu_gas_lowermatch", error)); } /* Handle upper region. */ if (common->highaddr >= domain->end) return (ENOMEM); - error = dmar_gas_uppermatch(&a, RB_ROOT(&domain->rb_root)); + error = iommu_gas_uppermatch(&a, RB_ROOT(&domain->rb_root)); KASSERT(error == ENOMEM, - ("error %d from dmar_gas_uppermatch", error)); + ("error %d from iommu_gas_uppermatch", error)); return (error); } static int -dmar_gas_alloc_region(struct dmar_domain *domain, struct iommu_map_entry *entry, +iommu_gas_alloc_region(struct iommu_domain *domain, struct iommu_map_entry *entry, u_int flags) { struct iommu_map_entry *next, *prev; bool found; - DMAR_DOMAIN_ASSERT_LOCKED(domain); + IOMMU_DOMAIN_ASSERT_LOCKED(domain); - if ((entry->start & DMAR_PAGE_MASK) != 0 || - (entry->end & DMAR_PAGE_MASK) != 0) + if ((entry->start & IOMMU_PAGE_MASK) != 0 || + (entry->end & IOMMU_PAGE_MASK) != 0) return (EINVAL); if (entry->start >= entry->end) return (EINVAL); if (entry->end >= domain->end) return (EINVAL); - next = RB_NFIND(dmar_gas_entries_tree, &domain->rb_root, entry); + next = RB_NFIND(iommu_gas_entries_tree, &domain->rb_root, entry); KASSERT(next != NULL, ("next must be non-null %p %jx", domain, (uintmax_t)entry->start)); - prev = RB_PREV(dmar_gas_entries_tree, &domain->rb_root, next); + prev = RB_PREV(iommu_gas_entries_tree, &domain->rb_root, next); /* prev could be NULL */ /* @@ -504,15 +511,15 @@ dmar_gas_alloc_region(struct dmar_domain *domain, struct iommu_map_entry *entry, if (prev != NULL && prev->end > entry->start) { /* This assumes that prev is the placeholder entry. */ - dmar_gas_rb_remove(domain, prev); + iommu_gas_rb_remove(domain, prev); prev = NULL; } if (next->start < entry->end) { - dmar_gas_rb_remove(domain, next); + iommu_gas_rb_remove(domain, next); next = NULL; } - found = dmar_gas_rb_insert(domain, entry); + found = iommu_gas_rb_insert(domain, entry); KASSERT(found, ("found RMRR dup %p start %jx end %jx", domain, (uintmax_t)entry->start, (uintmax_t)entry->end)); if ((flags & IOMMU_MF_RMRR) != 0) @@ -520,8 +527,8 @@ dmar_gas_alloc_region(struct dmar_domain *domain, struct iommu_map_entry *entry, #ifdef INVARIANTS struct iommu_map_entry *ip, *in; - ip = RB_PREV(dmar_gas_entries_tree, &domain->rb_root, entry); - in = RB_NEXT(dmar_gas_entries_tree, &domain->rb_root, entry); + ip = RB_PREV(iommu_gas_entries_tree, &domain->rb_root, entry); + in = RB_NEXT(iommu_gas_entries_tree, &domain->rb_root, entry); KASSERT(prev == NULL || ip == prev, ("RMRR %p (%jx %jx) prev %p (%jx %jx) ins prev %p (%jx %jx)", entry, entry->start, entry->end, prev, @@ -538,45 +545,45 @@ dmar_gas_alloc_region(struct dmar_domain *domain, struct iommu_map_entry *entry, } void -dmar_gas_free_space(struct dmar_domain *domain, struct iommu_map_entry *entry) +iommu_gas_free_space(struct iommu_domain *domain, struct iommu_map_entry *entry) { - DMAR_DOMAIN_ASSERT_LOCKED(domain); + IOMMU_DOMAIN_ASSERT_LOCKED(domain); KASSERT((entry->flags & (IOMMU_MAP_ENTRY_PLACE | IOMMU_MAP_ENTRY_RMRR | IOMMU_MAP_ENTRY_MAP)) == IOMMU_MAP_ENTRY_MAP, ("permanent entry %p %p", domain, entry)); - dmar_gas_rb_remove(domain, entry); + iommu_gas_rb_remove(domain, entry); entry->flags &= ~IOMMU_MAP_ENTRY_MAP; #ifdef INVARIANTS - if (dmar_check_free) - dmar_gas_check_free(domain); + if (iommu_check_free) + iommu_gas_check_free(domain); #endif } void -dmar_gas_free_region(struct dmar_domain *domain, struct iommu_map_entry *entry) +iommu_gas_free_region(struct iommu_domain *domain, struct iommu_map_entry *entry) { struct iommu_map_entry *next, *prev; - DMAR_DOMAIN_ASSERT_LOCKED(domain); + IOMMU_DOMAIN_ASSERT_LOCKED(domain); KASSERT((entry->flags & (IOMMU_MAP_ENTRY_PLACE | IOMMU_MAP_ENTRY_RMRR | IOMMU_MAP_ENTRY_MAP)) == IOMMU_MAP_ENTRY_RMRR, ("non-RMRR entry %p %p", domain, entry)); - prev = RB_PREV(dmar_gas_entries_tree, &domain->rb_root, entry); - next = RB_NEXT(dmar_gas_entries_tree, &domain->rb_root, entry); - dmar_gas_rb_remove(domain, entry); + prev = RB_PREV(iommu_gas_entries_tree, &domain->rb_root, entry); + next = RB_NEXT(iommu_gas_entries_tree, &domain->rb_root, entry); + iommu_gas_rb_remove(domain, entry); entry->flags &= ~IOMMU_MAP_ENTRY_RMRR; if (prev == NULL) - dmar_gas_rb_insert(domain, domain->first_place); + iommu_gas_rb_insert(domain, domain->first_place); if (next == NULL) - dmar_gas_rb_insert(domain, domain->last_place); + iommu_gas_rb_insert(domain, domain->last_place); } int -dmar_gas_map(struct dmar_domain *domain, +iommu_gas_map(struct iommu_domain *domain, const struct bus_dma_tag_common *common, iommu_gaddr_t size, int offset, u_int eflags, u_int flags, vm_page_t *ma, struct iommu_map_entry **res) { @@ -586,38 +593,34 @@ dmar_gas_map(struct dmar_domain *domain, KASSERT((flags & ~(IOMMU_MF_CANWAIT | IOMMU_MF_CANSPLIT)) == 0, ("invalid flags 0x%x", flags)); - entry = dmar_gas_alloc_entry(domain, + entry = iommu_gas_alloc_entry(domain, (flags & IOMMU_MF_CANWAIT) != 0 ? DMAR_PGF_WAITOK : 0); if (entry == NULL) return (ENOMEM); - DMAR_DOMAIN_LOCK(domain); - error = dmar_gas_find_space(domain, common, size, offset, flags, + IOMMU_DOMAIN_LOCK(domain); + error = iommu_gas_find_space(domain, common, size, offset, flags, entry); if (error == ENOMEM) { - DMAR_DOMAIN_UNLOCK(domain); - dmar_gas_free_entry(domain, entry); + IOMMU_DOMAIN_UNLOCK(domain); + iommu_gas_free_entry(domain, entry); return (error); } #ifdef INVARIANTS - if (dmar_check_free) - dmar_gas_check_free(domain); + if (iommu_check_free) + iommu_gas_check_free(domain); #endif KASSERT(error == 0, - ("unexpected error %d from dmar_gas_find_entry", error)); + ("unexpected error %d from iommu_gas_find_entry", error)); KASSERT(entry->end < domain->end, ("allocated GPA %jx, max GPA %jx", (uintmax_t)entry->end, (uintmax_t)domain->end)); entry->flags |= eflags; - DMAR_DOMAIN_UNLOCK(domain); + IOMMU_DOMAIN_UNLOCK(domain); error = domain_map_buf(domain, entry->start, entry->end - entry->start, - ma, - ((eflags & IOMMU_MAP_ENTRY_READ) != 0 ? DMAR_PTE_R : 0) | - ((eflags & IOMMU_MAP_ENTRY_WRITE) != 0 ? DMAR_PTE_W : 0) | - ((eflags & IOMMU_MAP_ENTRY_SNOOP) != 0 ? DMAR_PTE_SNP : 0) | - ((eflags & IOMMU_MAP_ENTRY_TM) != 0 ? DMAR_PTE_TM : 0), - (flags & IOMMU_MF_CANWAIT) != 0 ? DMAR_PGF_WAITOK : 0); + ma, eflags, + ((flags & IOMMU_MF_CANWAIT) != 0 ? DMAR_PGF_WAITOK : 0)); if (error == ENOMEM) { - dmar_domain_unload_entry(entry, true); + iommu_domain_unload_entry(entry, true); return (error); } KASSERT(error == 0, @@ -628,7 +631,7 @@ dmar_gas_map(struct dmar_domain *domain, } int -dmar_gas_map_region(struct dmar_domain *domain, struct iommu_map_entry *entry, +iommu_gas_map_region(struct iommu_domain *domain, struct iommu_map_entry *entry, u_int eflags, u_int flags, vm_page_t *ma) { iommu_gaddr_t start; @@ -640,26 +643,22 @@ dmar_gas_map_region(struct dmar_domain *domain, struct iommu_map_entry *entry, ("invalid flags 0x%x", flags)); start = entry->start; - DMAR_DOMAIN_LOCK(domain); - error = dmar_gas_alloc_region(domain, entry, flags); + IOMMU_DOMAIN_LOCK(domain); + error = iommu_gas_alloc_region(domain, entry, flags); if (error != 0) { - DMAR_DOMAIN_UNLOCK(domain); + IOMMU_DOMAIN_UNLOCK(domain); return (error); } entry->flags |= eflags; - DMAR_DOMAIN_UNLOCK(domain); + IOMMU_DOMAIN_UNLOCK(domain); if (entry->end == entry->start) return (0); error = domain_map_buf(domain, entry->start, entry->end - entry->start, - ma + OFF_TO_IDX(start - entry->start), - ((eflags & IOMMU_MAP_ENTRY_READ) != 0 ? DMAR_PTE_R : 0) | - ((eflags & IOMMU_MAP_ENTRY_WRITE) != 0 ? DMAR_PTE_W : 0) | - ((eflags & IOMMU_MAP_ENTRY_SNOOP) != 0 ? DMAR_PTE_SNP : 0) | - ((eflags & IOMMU_MAP_ENTRY_TM) != 0 ? DMAR_PTE_TM : 0), - (flags & IOMMU_MF_CANWAIT) != 0 ? DMAR_PGF_WAITOK : 0); + ma + OFF_TO_IDX(start - entry->start), eflags, + ((flags & IOMMU_MF_CANWAIT) != 0 ? DMAR_PGF_WAITOK : 0)); if (error == ENOMEM) { - dmar_domain_unload_entry(entry, false); + iommu_domain_unload_entry(entry, false); return (error); } KASSERT(error == 0, @@ -669,74 +668,62 @@ dmar_gas_map_region(struct dmar_domain *domain, struct iommu_map_entry *entry, } int -dmar_gas_reserve_region(struct dmar_domain *domain, iommu_gaddr_t start, +iommu_gas_reserve_region(struct iommu_domain *domain, iommu_gaddr_t start, iommu_gaddr_t end) { struct iommu_map_entry *entry; int error; - entry = dmar_gas_alloc_entry(domain, DMAR_PGF_WAITOK); + entry = iommu_gas_alloc_entry(domain, DMAR_PGF_WAITOK); entry->start = start; entry->end = end; - DMAR_DOMAIN_LOCK(domain); - error = dmar_gas_alloc_region(domain, entry, IOMMU_MF_CANWAIT); + IOMMU_DOMAIN_LOCK(domain); + error = iommu_gas_alloc_region(domain, entry, IOMMU_MF_CANWAIT); if (error == 0) entry->flags |= IOMMU_MAP_ENTRY_UNMAPPED; - DMAR_DOMAIN_UNLOCK(domain); + IOMMU_DOMAIN_UNLOCK(domain); if (error != 0) - dmar_gas_free_entry(domain, entry); + iommu_gas_free_entry(domain, entry); return (error); } struct iommu_map_entry * -iommu_map_alloc_entry(struct iommu_domain *iodom, u_int flags) +iommu_map_alloc_entry(struct iommu_domain *domain, u_int flags) { - struct dmar_domain *domain; struct iommu_map_entry *res; - domain = (struct dmar_domain *)iodom; - - res = dmar_gas_alloc_entry(domain, flags); + res = iommu_gas_alloc_entry(domain, flags); return (res); } void -iommu_map_free_entry(struct iommu_domain *iodom, struct iommu_map_entry *entry) +iommu_map_free_entry(struct iommu_domain *domain, struct iommu_map_entry *entry) { - struct dmar_domain *domain; - domain = (struct dmar_domain *)iodom; - - dmar_gas_free_entry(domain, entry); + iommu_gas_free_entry(domain, entry); } int -iommu_map(struct iommu_domain *iodom, +iommu_map(struct iommu_domain *domain, const struct bus_dma_tag_common *common, iommu_gaddr_t size, int offset, u_int eflags, u_int flags, vm_page_t *ma, struct iommu_map_entry **res) { - struct dmar_domain *domain; int error; - domain = (struct dmar_domain *)iodom; - - error = dmar_gas_map(domain, common, size, offset, eflags, flags, + error = iommu_gas_map(domain, common, size, offset, eflags, flags, ma, res); return (error); } int -iommu_map_region(struct iommu_domain *iodom, struct iommu_map_entry *entry, +iommu_map_region(struct iommu_domain *domain, struct iommu_map_entry *entry, u_int eflags, u_int flags, vm_page_t *ma) { - struct dmar_domain *domain; int error; - domain = (struct dmar_domain *)iodom; - - error = dmar_gas_map_region(domain, entry, eflags, flags, ma); + error = iommu_gas_map_region(domain, entry, eflags, flags, ma); return (error); } diff --git a/sys/x86/iommu/intel_idpgtbl.c b/sys/x86/iommu/intel_idpgtbl.c index 2febb55f9426..89b3bf5d96d2 100644 --- a/sys/x86/iommu/intel_idpgtbl.c +++ b/sys/x86/iommu/intel_idpgtbl.c @@ -499,15 +499,23 @@ domain_map_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base, } int -domain_map_buf(struct dmar_domain *domain, iommu_gaddr_t base, iommu_gaddr_t size, - vm_page_t *ma, uint64_t pflags, int flags) +domain_map_buf(struct iommu_domain *iodom, iommu_gaddr_t base, + iommu_gaddr_t size, vm_page_t *ma, uint64_t eflags, int flags) { + struct dmar_domain *domain; struct dmar_unit *unit; + uint64_t pflags; int error; + pflags = ((eflags & IOMMU_MAP_ENTRY_READ) != 0 ? DMAR_PTE_R : 0) | + ((eflags & IOMMU_MAP_ENTRY_WRITE) != 0 ? DMAR_PTE_W : 0) | + ((eflags & IOMMU_MAP_ENTRY_SNOOP) != 0 ? DMAR_PTE_SNP : 0) | + ((eflags & IOMMU_MAP_ENTRY_TM) != 0 ? DMAR_PTE_TM : 0); + + domain = (struct dmar_domain *)iodom; unit = domain->dmar; - KASSERT((domain->flags & DMAR_DOMAIN_IDMAP) == 0, + KASSERT((domain->iodom.flags & DMAR_DOMAIN_IDMAP) == 0, ("modifying idmap pagetable domain %p", domain)); KASSERT((base & DMAR_PAGE_MASK) == 0, ("non-aligned base %p %jx %jx", domain, (uintmax_t)base, @@ -618,7 +626,7 @@ domain_unmap_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base, if (size == 0) return (0); - KASSERT((domain->flags & DMAR_DOMAIN_IDMAP) == 0, + KASSERT((domain->iodom.flags & DMAR_DOMAIN_IDMAP) == 0, ("modifying idmap pagetable domain %p", domain)); KASSERT((base & DMAR_PAGE_MASK) == 0, ("non-aligned base %p %jx %jx", domain, (uintmax_t)base, @@ -705,7 +713,7 @@ domain_alloc_pgtbl(struct dmar_domain *domain) m->ref_count = 1; DMAR_DOMAIN_PGUNLOCK(domain); DMAR_LOCK(domain->dmar); - domain->flags |= DMAR_DOMAIN_PGTBL_INITED; + domain->iodom.flags |= DMAR_DOMAIN_PGTBL_INITED; DMAR_UNLOCK(domain->dmar); return (0); } @@ -719,16 +727,16 @@ domain_free_pgtbl(struct dmar_domain *domain) obj = domain->pgtbl_obj; if (obj == NULL) { KASSERT((domain->dmar->hw_ecap & DMAR_ECAP_PT) != 0 && - (domain->flags & DMAR_DOMAIN_IDMAP) != 0, + (domain->iodom.flags & DMAR_DOMAIN_IDMAP) != 0, ("lost pagetable object domain %p", domain)); return; } DMAR_DOMAIN_ASSERT_PGLOCKED(domain); domain->pgtbl_obj = NULL; - if ((domain->flags & DMAR_DOMAIN_IDMAP) != 0) { + if ((domain->iodom.flags & DMAR_DOMAIN_IDMAP) != 0) { put_idmap_pgtbl(obj); - domain->flags &= ~DMAR_DOMAIN_IDMAP; + domain->iodom.flags &= ~DMAR_DOMAIN_IDMAP; return; } diff --git a/sys/x86/iommu/intel_utils.c b/sys/x86/iommu/intel_utils.c index 739952328b18..72a1c2a3a0d3 100644 --- a/sys/x86/iommu/intel_utils.c +++ b/sys/x86/iommu/intel_utils.c @@ -668,9 +668,9 @@ SYSCTL_PROC(_hw_dmar, OID_AUTO, timeout, dmar_timeout_sysctl, "QU", "Timeout for command wait, in nanoseconds"); #ifdef INVARIANTS -int dmar_check_free; +int iommu_check_free; SYSCTL_INT(_hw_dmar, OID_AUTO, check_free, CTLFLAG_RWTUN, - &dmar_check_free, 0, + &iommu_check_free, 0, "Check the GPA RBtree for free_down and free_after validity"); #endif From 82dc812235dd054da8744f8b029bf1f46fe75a65 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 10:29:48 +0000 Subject: [PATCH 159/287] seqc: add a sleepable variant and convert some routines to macros This temporarily duplicates some code. Macro conversion convinces clang to carry predicts into consumers. --- sys/sys/_seqc.h | 11 +++++++++++ sys/sys/seqc.h | 51 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 sys/sys/_seqc.h diff --git a/sys/sys/_seqc.h b/sys/sys/_seqc.h new file mode 100644 index 000000000000..718559e8b893 --- /dev/null +++ b/sys/sys/_seqc.h @@ -0,0 +1,11 @@ +/*- + * This file is in the public domain. + */ +/* $FreeBSD$ */ + +#ifndef _SYS__SEQC_H_ +#define _SYS__SEQC_H_ + +typedef uint32_t seqc_t; + +#endif /* _SYS__SEQC_H */ diff --git a/sys/sys/seqc.h b/sys/sys/seqc.h index 82a0ae9c30ba..a04e342ad7d3 100644 --- a/sys/sys/seqc.h +++ b/sys/sys/seqc.h @@ -36,7 +36,7 @@ /* * seqc_t may be included in structs visible to userspace */ -typedef uint32_t seqc_t; +#include #ifdef _KERNEL @@ -45,12 +45,14 @@ typedef uint32_t seqc_t; #include -static __inline bool -seqc_in_modify(seqc_t seqcp) -{ - - return (seqcp & 1); -} +/* + * Predicts from inline functions are not honored by clang. + */ +#define seqc_in_modify(seqc) ({ \ + seqc_t __seqc = (seqc); \ + \ + __predict_false(__seqc & 1); \ +}) static __inline void seqc_write_begin(seqc_t *seqcp) @@ -86,7 +88,7 @@ seqc_read(const seqc_t *seqcp) for (;;) { ret = seqc_read_any(seqcp); - if (__predict_false(seqc_in_modify(ret))) { + if (seqc_in_modify(ret)) { cpu_spinwait(); continue; } @@ -96,19 +98,38 @@ seqc_read(const seqc_t *seqcp) return (ret); } -static __inline bool -seqc_consistent_nomb(const seqc_t *seqcp, seqc_t oldseqc) +#define seqc_consistent_nomb(seqcp, oldseqc) ({ \ + const seqc_t *__seqcp = (seqcp); \ + seqc_t __oldseqc = (oldseqc); \ + \ + MPASS(!(seqc_in_modify(__oldseqc))); \ + __predict_true(*__seqcp == __oldseqc); \ +}) + +#define seqc_consistent(seqcp, oldseqc) ({ \ + atomic_thread_fence_acq(); \ + seqc_consistent_nomb(seqcp, oldseqc); \ +}) + +/* + * Variant which does not critical enter/exit. + */ +static __inline void +seqc_sleepable_write_begin(seqc_t *seqcp) { - return (*seqcp == oldseqc); + MPASS(!seqc_in_modify(*seqcp)); + *seqcp += 1; + atomic_thread_fence_rel(); } -static __inline bool -seqc_consistent(const seqc_t *seqcp, seqc_t oldseqc) +static __inline void +seqc_sleepable_write_end(seqc_t *seqcp) { - atomic_thread_fence_acq(); - return (seqc_consistent_nomb(seqcp, oldseqc)); + atomic_thread_fence_rel(); + *seqcp += 1; + MPASS(!seqc_in_modify(*seqcp)); } #endif /* _KERNEL */ From 0379ff6ae30878fcb2fb5de34e8dfe2ba49d0d9d Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 10:31:52 +0000 Subject: [PATCH 160/287] vfs: introduce vnode sequence counters Modified on each permission change and link/unlink. Reviewed by: kib Tested by: pho (in a patchset) Differential Revision: https://reviews.freebsd.org/D25573 --- .../compat/opensolaris/kern/opensolaris_vfs.c | 3 + sys/kern/vfs_mount.c | 55 ++- sys/kern/vfs_subr.c | 324 ++++++++++++++++-- sys/kern/vnode_if.src | 14 + sys/sys/vnode.h | 40 +++ 5 files changed, 395 insertions(+), 41 deletions(-) diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c b/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c index 15b1ecafb1f2..0ba0338a9848 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c @@ -154,6 +154,7 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath, vput(vp); return (error); } + vn_seqc_write_begin(vp); VOP_UNLOCK(vp); /* @@ -206,6 +207,7 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath, VI_LOCK(vp); vp->v_iflag &= ~VI_MOUNT; VI_UNLOCK(vp); + vn_seqc_write_end(vp); vput(vp); vfs_unbusy(mp); vfs_freeopts(mp->mnt_optnew); @@ -241,6 +243,7 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath, vfs_event_signal(NULL, VQ_MOUNT, 0); if (VFS_ROOT(mp, LK_EXCLUSIVE, &mvp)) panic("mount: lost mount"); + vn_seqc_write_end(vp); VOP_UNLOCK(vp); vfs_op_exit(mp); vfs_unbusy(mp); diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 61b76f82ebc7..7e8106abcc56 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -947,6 +947,7 @@ vfs_domount_first( vput(vp); return (error); } + vn_seqc_write_begin(vp); VOP_UNLOCK(vp); /* Allocate and initialize the filesystem. */ @@ -979,9 +980,11 @@ vfs_domount_first( VI_LOCK(vp); vp->v_iflag &= ~VI_MOUNT; VI_UNLOCK(vp); + vn_seqc_write_end(vp); vrele(vp); return (error); } + vn_seqc_write_begin(newdp); VOP_UNLOCK(newdp); if (mp->mnt_opt != NULL) @@ -1018,6 +1021,8 @@ vfs_domount_first( EVENTHANDLER_DIRECT_INVOKE(vfs_mounted, mp, newdp, td); VOP_UNLOCK(newdp); mountcheckdirs(vp, newdp); + vn_seqc_write_end(vp); + vn_seqc_write_end(newdp); vrele(newdp); if ((mp->mnt_flag & MNT_RDONLY) == 0) vfs_allocate_syncvnode(mp); @@ -1094,7 +1099,9 @@ vfs_domount_update( VOP_UNLOCK(vp); vfs_op_enter(mp); + vn_seqc_write_begin(vp); + rootvp = NULL; MNT_ILOCK(mp); if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0) { MNT_IUNLOCK(mp); @@ -1108,8 +1115,6 @@ vfs_domount_update( mp->mnt_kern_flag &= ~MNTK_ASYNC; rootvp = vfs_cache_root_clear(mp); MNT_IUNLOCK(mp); - if (rootvp != NULL) - vrele(rootvp); mp->mnt_optnew = *optlist; vfs_mergeopts(mp->mnt_optnew, mp->mnt_opt); @@ -1233,6 +1238,11 @@ vfs_domount_update( vfs_deallocate_syncvnode(mp); end: vfs_op_exit(mp); + if (rootvp != NULL) { + vn_seqc_write_end(rootvp); + vrele(rootvp); + } + vn_seqc_write_end(vp); vfs_unbusy(mp); VI_LOCK(vp); vp->v_iflag &= ~VI_MOUNT; @@ -1723,14 +1733,19 @@ dounmount(struct mount *mp, int flags, struct thread *td) } mp->mnt_kern_flag |= MNTK_UNMOUNT; rootvp = vfs_cache_root_clear(mp); + if (coveredvp != NULL) + vn_seqc_write_begin(coveredvp); if (flags & MNT_NONBUSY) { MNT_IUNLOCK(mp); error = vfs_check_usecounts(mp); MNT_ILOCK(mp); if (error != 0) { + vn_seqc_write_end(coveredvp); dounmount_cleanup(mp, coveredvp, MNTK_UNMOUNT); - if (rootvp != NULL) + if (rootvp != NULL) { + vn_seqc_write_end(rootvp); vrele(rootvp); + } return (error); } } @@ -1759,22 +1774,19 @@ dounmount(struct mount *mp, int flags, struct thread *td) ("%s: invalid return value for msleep in the drain path @ %s:%d", __func__, __FILE__, __LINE__)); - if (rootvp != NULL) + /* + * We want to keep the vnode around so that we can vn_seqc_write_end + * after we are done with unmount. Downgrade our reference to a mere + * hold count so that we don't interefere with anything. + */ + if (rootvp != NULL) { + vhold(rootvp); vrele(rootvp); + } if (mp->mnt_flag & MNT_EXPUBLIC) vfs_setpublicfs(NULL, NULL, NULL); - /* - * From now, we can claim that the use reference on the - * coveredvp is ours, and the ref can be released only by - * successfull unmount by us, or left for later unmount - * attempt. The previously acquired hold reference is no - * longer needed to protect the vnode from reuse. - */ - if (coveredvp != NULL) - vdrop(coveredvp); - vfs_periodic(mp, MNT_WAIT); MNT_ILOCK(mp); async_flag = mp->mnt_flag & MNT_ASYNC; @@ -1809,8 +1821,15 @@ dounmount(struct mount *mp, int flags, struct thread *td) } vfs_op_exit_locked(mp); MNT_IUNLOCK(mp); - if (coveredvp) + if (coveredvp) { + vn_seqc_write_end(coveredvp); VOP_UNLOCK(coveredvp); + vdrop(coveredvp); + } + if (rootvp != NULL) { + vn_seqc_write_end(rootvp); + vdrop(rootvp); + } return (error); } mtx_lock(&mountlist_mtx); @@ -1819,7 +1838,13 @@ dounmount(struct mount *mp, int flags, struct thread *td) EVENTHANDLER_DIRECT_INVOKE(vfs_unmounted, mp, td); if (coveredvp != NULL) { coveredvp->v_mountedhere = NULL; + vn_seqc_write_end(coveredvp); VOP_UNLOCK(coveredvp); + vdrop(coveredvp); + } + if (rootvp != NULL) { + vn_seqc_write_end(rootvp); + vdrop(rootvp); } vfs_event_signal(NULL, VQ_UNMOUNT, 0); if (rootvnode != NULL && mp == rootvnode->v_mount) { diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 51ec4390da7f..c5604c422fd6 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1761,6 +1761,12 @@ freevnode(struct vnode *vp) * so as not to contaminate the freshly allocated vnode. */ CTR2(KTR_VFS, "%s: destroying the vnode %p", __func__, vp); + /* + * Paired with vgone. + */ + vn_seqc_write_end_locked(vp); + VNPASS(vp->v_seqc_users == 0, vp); + bo = &vp->v_bufobj; VNASSERT(vp->v_data == NULL, vp, ("cleaned vnode isn't")); VNPASS(vp->v_holdcnt == VHOLD_NO_SMR, vp); @@ -4018,6 +4024,10 @@ vgonel(struct vnode *vp) */ if (vp->v_irflag & VIRF_DOOMED) return; + /* + * Paired with freevnode. + */ + vn_seqc_write_begin_locked(vp); vunlazy_gone(vp); vp->v_irflag |= VIRF_DOOMED; @@ -4160,8 +4170,9 @@ vn_printf(struct vnode *vp, const char *fmt, ...) printf("%p: ", (void *)vp); printf("type %s\n", typename[vp->v_type]); holdcnt = atomic_load_int(&vp->v_holdcnt); - printf(" usecount %d, writecount %d, refcount %d", - vp->v_usecount, vp->v_writecount, holdcnt & ~VHOLD_ALL_FLAGS); + printf(" usecount %d, writecount %d, refcount %d seqc users %d", + vp->v_usecount, vp->v_writecount, holdcnt & ~VHOLD_ALL_FLAGS, + vp->v_seqc_users); switch (vp->v_type) { case VDIR: printf(" mountedhere %p\n", vp->v_mountedhere); @@ -5508,6 +5519,14 @@ vop_rename_pre(void *ap) ASSERT_VOP_LOCKED(a->a_tvp, "vop_rename: tvp not locked"); ASSERT_VOP_LOCKED(a->a_tdvp, "vop_rename: tdvp not locked"); #endif + /* + * It may be tempting to add vn_seqc_write_begin/end calls here and + * in vop_rename_post but that's not going to work out since some + * filesystems relookup vnodes mid-rename. This is probably a bug. + * + * For now filesystems are expected to do the relevant calls after they + * decide what vnodes to operate on. + */ if (a->a_tdvp != a->a_fdvp) vhold(a->a_fdvp); if (a->a_tvp != a->a_fvp) @@ -5588,70 +5607,194 @@ vop_need_inactive_post(void *ap, int rc) } #endif +void +vop_create_pre(void *ap) +{ + struct vop_create_args *a; + struct vnode *dvp; + + a = ap; + dvp = a->a_dvp; + vn_seqc_write_begin(dvp); +} + void vop_create_post(void *ap, int rc) { - struct vop_create_args *a = ap; + struct vop_create_args *a; + struct vnode *dvp; + a = ap; + dvp = a->a_dvp; + vn_seqc_write_end(dvp); if (!rc) - VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE); + VFS_KNOTE_LOCKED(dvp, NOTE_WRITE); +} + +void +vop_whiteout_pre(void *ap) +{ + struct vop_whiteout_args *a; + struct vnode *dvp; + + a = ap; + dvp = a->a_dvp; + vn_seqc_write_begin(dvp); +} + +void +vop_whiteout_post(void *ap, int rc) +{ + struct vop_whiteout_args *a; + struct vnode *dvp; + + a = ap; + dvp = a->a_dvp; + vn_seqc_write_end(dvp); +} + +void +vop_deleteextattr_pre(void *ap) +{ + struct vop_deleteextattr_args *a; + struct vnode *vp; + + a = ap; + vp = a->a_vp; + vn_seqc_write_begin(vp); } void vop_deleteextattr_post(void *ap, int rc) { - struct vop_deleteextattr_args *a = ap; + struct vop_deleteextattr_args *a; + struct vnode *vp; + a = ap; + vp = a->a_vp; + vn_seqc_write_end(vp); if (!rc) VFS_KNOTE_LOCKED(a->a_vp, NOTE_ATTRIB); } +void +vop_link_pre(void *ap) +{ + struct vop_link_args *a; + struct vnode *vp, *tdvp; + + a = ap; + vp = a->a_vp; + tdvp = a->a_tdvp; + vn_seqc_write_begin(vp); + vn_seqc_write_begin(tdvp); +} + void vop_link_post(void *ap, int rc) { - struct vop_link_args *a = ap; + struct vop_link_args *a; + struct vnode *vp, *tdvp; + a = ap; + vp = a->a_vp; + tdvp = a->a_tdvp; + vn_seqc_write_end(vp); + vn_seqc_write_end(tdvp); if (!rc) { - VFS_KNOTE_LOCKED(a->a_vp, NOTE_LINK); - VFS_KNOTE_LOCKED(a->a_tdvp, NOTE_WRITE); + VFS_KNOTE_LOCKED(vp, NOTE_LINK); + VFS_KNOTE_LOCKED(tdvp, NOTE_WRITE); } } +void +vop_mkdir_pre(void *ap) +{ + struct vop_mkdir_args *a; + struct vnode *dvp; + + a = ap; + dvp = a->a_dvp; + vn_seqc_write_begin(dvp); +} + void vop_mkdir_post(void *ap, int rc) { - struct vop_mkdir_args *a = ap; + struct vop_mkdir_args *a; + struct vnode *dvp; + a = ap; + dvp = a->a_dvp; + vn_seqc_write_end(dvp); if (!rc) - VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE | NOTE_LINK); + VFS_KNOTE_LOCKED(dvp, NOTE_WRITE | NOTE_LINK); +} + +void +vop_mknod_pre(void *ap) +{ + struct vop_mknod_args *a; + struct vnode *dvp; + + a = ap; + dvp = a->a_dvp; + vn_seqc_write_begin(dvp); } void vop_mknod_post(void *ap, int rc) { - struct vop_mknod_args *a = ap; + struct vop_mknod_args *a; + struct vnode *dvp; + a = ap; + dvp = a->a_dvp; + vn_seqc_write_end(dvp); if (!rc) - VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE); + VFS_KNOTE_LOCKED(dvp, NOTE_WRITE); } void vop_reclaim_post(void *ap, int rc) { - struct vop_reclaim_args *a = ap; + struct vop_reclaim_args *a; + struct vnode *vp; + a = ap; + vp = a->a_vp; + ASSERT_VOP_IN_SEQC(vp); if (!rc) - VFS_KNOTE_LOCKED(a->a_vp, NOTE_REVOKE); + VFS_KNOTE_LOCKED(vp, NOTE_REVOKE); +} + +void +vop_remove_pre(void *ap) +{ + struct vop_remove_args *a; + struct vnode *dvp, *vp; + + a = ap; + dvp = a->a_dvp; + vp = a->a_vp; + vn_seqc_write_begin(dvp); + vn_seqc_write_begin(vp); } void vop_remove_post(void *ap, int rc) { - struct vop_remove_args *a = ap; + struct vop_remove_args *a; + struct vnode *dvp, *vp; + a = ap; + dvp = a->a_dvp; + vp = a->a_vp; + vn_seqc_write_end(dvp); + vn_seqc_write_end(vp); if (!rc) { - VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE); - VFS_KNOTE_LOCKED(a->a_vp, NOTE_DELETE); + VFS_KNOTE_LOCKED(dvp, NOTE_WRITE); + VFS_KNOTE_LOCKED(vp, NOTE_DELETE); } } @@ -5693,42 +5836,128 @@ vop_rename_post(void *ap, int rc) vdrop(a->a_tvp); } +void +vop_rmdir_pre(void *ap) +{ + struct vop_rmdir_args *a; + struct vnode *dvp, *vp; + + a = ap; + dvp = a->a_dvp; + vp = a->a_vp; + vn_seqc_write_begin(dvp); + vn_seqc_write_begin(vp); +} + void vop_rmdir_post(void *ap, int rc) { - struct vop_rmdir_args *a = ap; + struct vop_rmdir_args *a; + struct vnode *dvp, *vp; + a = ap; + dvp = a->a_dvp; + vp = a->a_vp; + vn_seqc_write_end(dvp); + vn_seqc_write_end(vp); if (!rc) { - VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE | NOTE_LINK); - VFS_KNOTE_LOCKED(a->a_vp, NOTE_DELETE); + VFS_KNOTE_LOCKED(dvp, NOTE_WRITE | NOTE_LINK); + VFS_KNOTE_LOCKED(vp, NOTE_DELETE); } } +void +vop_setattr_pre(void *ap) +{ + struct vop_setattr_args *a; + struct vnode *vp; + + a = ap; + vp = a->a_vp; + vn_seqc_write_begin(vp); +} + void vop_setattr_post(void *ap, int rc) { - struct vop_setattr_args *a = ap; + struct vop_setattr_args *a; + struct vnode *vp; + a = ap; + vp = a->a_vp; + vn_seqc_write_end(vp); if (!rc) - VFS_KNOTE_LOCKED(a->a_vp, NOTE_ATTRIB); + VFS_KNOTE_LOCKED(vp, NOTE_ATTRIB); +} + +void +vop_setacl_pre(void *ap) +{ + struct vop_setacl_args *a; + struct vnode *vp; + + a = ap; + vp = a->a_vp; + vn_seqc_write_begin(vp); +} + +void +vop_setacl_post(void *ap, int rc __unused) +{ + struct vop_setacl_args *a; + struct vnode *vp; + + a = ap; + vp = a->a_vp; + vn_seqc_write_end(vp); +} + +void +vop_setextattr_pre(void *ap) +{ + struct vop_setextattr_args *a; + struct vnode *vp; + + a = ap; + vp = a->a_vp; + vn_seqc_write_begin(vp); } void vop_setextattr_post(void *ap, int rc) { - struct vop_setextattr_args *a = ap; + struct vop_setextattr_args *a; + struct vnode *vp; + a = ap; + vp = a->a_vp; + vn_seqc_write_end(vp); if (!rc) - VFS_KNOTE_LOCKED(a->a_vp, NOTE_ATTRIB); + VFS_KNOTE_LOCKED(vp, NOTE_ATTRIB); +} + +void +vop_symlink_pre(void *ap) +{ + struct vop_symlink_args *a; + struct vnode *dvp; + + a = ap; + dvp = a->a_dvp; + vn_seqc_write_begin(dvp); } void vop_symlink_post(void *ap, int rc) { - struct vop_symlink_args *a = ap; + struct vop_symlink_args *a; + struct vnode *dvp; + a = ap; + dvp = a->a_dvp; + vn_seqc_write_end(dvp); if (!rc) - VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE); + VFS_KNOTE_LOCKED(dvp, NOTE_WRITE); } void @@ -6281,6 +6510,8 @@ vfs_cache_root_clear(struct mount *mp) */ MPASS(mp->mnt_vfs_ops > 0); vp = mp->mnt_rootvnode; + if (vp != NULL) + vn_seqc_write_begin(vp); mp->mnt_rootvnode = NULL; return (vp); } @@ -6577,3 +6808,44 @@ vn_dir_check_exec(struct vnode *vp, struct componentname *cnp) return (VOP_ACCESS(vp, VEXEC, cnp->cn_cred, cnp->cn_thread)); } + +void +vn_seqc_write_begin_locked(struct vnode *vp) +{ + + ASSERT_VI_LOCKED(vp, __func__); + VNPASS(vp->v_holdcnt > 0, vp); + VNPASS(vp->v_seqc_users >= 0, vp); + vp->v_seqc_users++; + if (vp->v_seqc_users == 1) + seqc_sleepable_write_begin(&vp->v_seqc); +} + +void +vn_seqc_write_begin(struct vnode *vp) +{ + + VI_LOCK(vp); + vn_seqc_write_begin_locked(vp); + VI_UNLOCK(vp); +} + +void +vn_seqc_write_end_locked(struct vnode *vp) +{ + + ASSERT_VI_LOCKED(vp, __func__); + VNPASS(vp->v_seqc_users > 0, vp); + vp->v_seqc_users--; + if (vp->v_seqc_users == 0) + seqc_sleepable_write_end(&vp->v_seqc); +} + +void +vn_seqc_write_end(struct vnode *vp) +{ + + VI_LOCK(vp); + vn_seqc_write_end_locked(vp); + VI_UNLOCK(vp); +} diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src index bfa810169464..beac2eef4e21 100644 --- a/sys/kern/vnode_if.src +++ b/sys/kern/vnode_if.src @@ -88,6 +88,7 @@ vop_cachedlookup { %% create dvp E E E %% create vpp - L - +%! create pre vop_create_pre %! create post vop_create_post vop_create { @@ -99,6 +100,8 @@ vop_create { %% whiteout dvp E E E +%! whiteout pre vop_whiteout_pre +%! whiteout post vop_whiteout_post vop_whiteout { IN struct vnode *dvp; @@ -109,6 +112,7 @@ vop_whiteout { %% mknod dvp E E E %% mknod vpp - L - +%! mknod pre vop_mknod_pre %! mknod post vop_mknod_post vop_mknod { @@ -172,6 +176,7 @@ vop_getattr { %% setattr vp E E E +%! setattr pre vop_setattr_pre %! setattr post vop_setattr_post vop_setattr { @@ -260,6 +265,7 @@ vop_fsync { %% remove dvp E E E %% remove vp E E E +%! remove pre vop_remove_pre %! remove post vop_remove_post vop_remove { @@ -271,6 +277,7 @@ vop_remove { %% link tdvp E E E %% link vp E E E +%! link pre vop_link_pre %! link post vop_link_post vop_link { @@ -295,6 +302,7 @@ vop_rename { %% mkdir dvp E E E %% mkdir vpp - E - +%! mkdir pre vop_mkdir_pre %! mkdir post vop_mkdir_post vop_mkdir { @@ -307,6 +315,7 @@ vop_mkdir { %% rmdir dvp E E E %% rmdir vp E E E +%! rmdir pre vop_rmdir_pre %! rmdir post vop_rmdir_post vop_rmdir { @@ -318,6 +327,7 @@ vop_rmdir { %% symlink dvp E E E %% symlink vpp - E - +%! symlink pre vop_symlink_pre %! symlink post vop_symlink_post vop_symlink { @@ -523,6 +533,8 @@ vop_getacl { %% setacl vp E E E +%! setacl pre vop_setacl_pre +%! setacl post vop_setacl_post vop_setacl { IN struct vnode *vp; @@ -589,6 +601,7 @@ vop_openextattr { %% deleteextattr vp E E E +%! deleteextattr pre vop_deleteextattr_pre %! deleteextattr post vop_deleteextattr_post vop_deleteextattr { @@ -601,6 +614,7 @@ vop_deleteextattr { %% setextattr vp E E E +%! setextattr pre vop_setextattr_pre %! setextattr post vop_setextattr_post vop_setextattr { diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 19f07d05d7c9..7c0a4f568451 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -45,6 +45,7 @@ #include #include #include +#include /* * The vnode is the focus of all file activity in UNIX. There is a @@ -105,6 +106,7 @@ struct vnode { */ enum vtype v_type:8; /* u vnode type */ short v_irflag; /* i frequently read flags */ + seqc_t v_seqc; /* i modification count */ struct vop_vector *v_op; /* u vnode operations vector */ void *v_data; /* u private data for fs */ @@ -175,6 +177,7 @@ struct vnode { short v_dbatchcpu; /* i LRU requeue deferral batch */ int v_writecount; /* I ref count of writers or (negative) text users */ + int v_seqc_users; /* i modifications pending */ u_int v_hash; }; @@ -539,6 +542,18 @@ void assert_vop_unlocked(struct vnode *vp, const char *str); #define ASSERT_VOP_LOCKED(vp, str) assert_vop_locked((vp), (str)) #define ASSERT_VOP_UNLOCKED(vp, str) assert_vop_unlocked((vp), (str)) +#define ASSERT_VOP_IN_SEQC(vp) do { \ + struct vnode *_vp = (vp); \ + \ + VNPASS(seqc_in_modify(_vp->v_seqc), _vp); \ +} while (0) + +#define ASSERT_VOP_NOT_IN_SEQC(vp) do { \ + struct vnode *_vp = (vp); \ + \ + VNPASS(!seqc_in_modify(_vp->v_seqc), _vp); \ +} while (0) + #else /* !DEBUG_VFS_LOCKS */ #define ASSERT_VI_LOCKED(vp, str) ((void)0) @@ -546,6 +561,10 @@ void assert_vop_unlocked(struct vnode *vp, const char *str); #define ASSERT_VOP_ELOCKED(vp, str) ((void)0) #define ASSERT_VOP_LOCKED(vp, str) ((void)0) #define ASSERT_VOP_UNLOCKED(vp, str) ((void)0) + +#define ASSERT_VOP_IN_SEQC(vp) ((void)0) +#define ASSERT_VOP_NOT_IN_SEQC(vp) ((void)0) + #endif /* DEBUG_VFS_LOCKS */ @@ -738,6 +757,13 @@ int vn_io_fault_uiomove(char *data, int xfersize, struct uio *uio); int vn_io_fault_pgmove(vm_page_t ma[], vm_offset_t offset, int xfersize, struct uio *uio); +void vn_seqc_write_begin_locked(struct vnode *vp); +void vn_seqc_write_begin(struct vnode *vp); +void vn_seqc_write_end_locked(struct vnode *vp); +void vn_seqc_write_end(struct vnode *vp); +#define vn_seqc_read_any(vp) seqc_read_any(&(vp)->v_seqc) +#define vn_seqc_consistent(vp, seq) seqc_consistent(&(vp)->v_seqc, seq) + #define vn_rangelock_unlock(vp, cookie) \ rangelock_unlock(&(vp)->v_rl, (cookie), VI_MTX(vp)) #define vn_rangelock_unlock_range(vp, cookie, start, end) \ @@ -804,23 +830,37 @@ int dead_write(struct vop_write_args *ap); /* These are called from within the actual VOPS. */ void vop_close_post(void *a, int rc); +void vop_create_pre(void *a); void vop_create_post(void *a, int rc); +void vop_whiteout_pre(void *a); +void vop_whiteout_post(void *a, int rc); +void vop_deleteextattr_pre(void *a); void vop_deleteextattr_post(void *a, int rc); +void vop_link_pre(void *a); void vop_link_post(void *a, int rc); void vop_lookup_post(void *a, int rc); void vop_lookup_pre(void *a); +void vop_mkdir_pre(void *a); void vop_mkdir_post(void *a, int rc); +void vop_mknod_pre(void *a); void vop_mknod_post(void *a, int rc); void vop_open_post(void *a, int rc); void vop_read_post(void *a, int rc); void vop_readdir_post(void *a, int rc); void vop_reclaim_post(void *a, int rc); +void vop_remove_pre(void *a); void vop_remove_post(void *a, int rc); void vop_rename_post(void *a, int rc); void vop_rename_pre(void *a); +void vop_rmdir_pre(void *a); void vop_rmdir_post(void *a, int rc); +void vop_setattr_pre(void *a); void vop_setattr_post(void *a, int rc); +void vop_setacl_pre(void *a); +void vop_setacl_post(void *a, int rc); +void vop_setextattr_pre(void *a); void vop_setextattr_post(void *a, int rc); +void vop_symlink_pre(void *a); void vop_symlink_post(void *a, int rc); int vop_sigdefer(struct vop_vector *vop, struct vop_generic_args *a); From 07d2145a17178e9df663c90cc45d249502f7f768 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 10:32:45 +0000 Subject: [PATCH 161/287] vfs: add the infrastructure for lockless lookup Reviewed by: kib Tested by: pho (in a patchset) Differential Revision: https://reviews.freebsd.org/D25577 --- sys/kern/kern_descrip.c | 29 ++++++--- sys/kern/vfs_subr.c | 105 ++++++++++++++++++++++++++----- sys/kern/vnode_if.src | 11 ++++ sys/security/mac/mac_framework.h | 3 +- sys/sys/filedesc.h | 1 + sys/sys/mount.h | 1 + sys/sys/vnode.h | 16 +++++ 7 files changed, 141 insertions(+), 25 deletions(-) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index e2b57609c9f1..1f422bbf57c0 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -102,8 +102,8 @@ MALLOC_DECLARE(M_FADVISE); static __read_mostly uma_zone_t file_zone; static __read_mostly uma_zone_t filedesc0_zone; -static __read_mostly uma_zone_t pwd_zone; -static __read_mostly smr_t pwd_smr; +__read_mostly uma_zone_t pwd_zone; +VFS_SMR_DECLARE; static int closefp(struct filedesc *fdp, int fd, struct file *fp, struct thread *td, int holdleaders); @@ -3343,18 +3343,27 @@ pwd_hold(struct thread *td) fdp = td->td_proc->p_fd; - smr_enter(pwd_smr); - pwd = smr_entered_load(&fdp->fd_pwd, pwd_smr); + vfs_smr_enter(); + pwd = vfs_smr_entered_load(&fdp->fd_pwd); MPASS(pwd != NULL); if (__predict_true(refcount_acquire_if_not_zero(&pwd->pwd_refcount))) { - smr_exit(pwd_smr); + vfs_smr_exit(); return (pwd); } - smr_exit(pwd_smr); + vfs_smr_exit(); FILEDESC_SLOCK(fdp); pwd = pwd_hold_filedesc(fdp); MPASS(pwd != NULL); - FILEDESC_SUNLOCK(fdp); + return (pwd); +} + +struct pwd * +pwd_get_smr(void) +{ + struct pwd *pwd; + + pwd = vfs_smr_entered_load(&curproc->p_fd->fd_pwd); + MPASS(pwd != NULL); return (pwd); } @@ -4368,7 +4377,11 @@ filelistinit(void *dummy) NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); pwd_zone = uma_zcreate("PWD", sizeof(struct pwd), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_SMR); - pwd_smr = uma_zone_get_smr(pwd_zone); + /* + * XXXMJG this is a temporary hack due to boot ordering issues against + * the vnode zone. + */ + vfs_smr = uma_zone_get_smr(pwd_zone); mtx_init(&sigio_lock, "sigio lock", NULL, MTX_DEF); } SYSINIT(select, SI_SUB_LOCK, SI_ORDER_FIRST, filelistinit, NULL); diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index c5604c422fd6..2eec46774327 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -664,8 +664,8 @@ vntblinit(void *dummy __unused) vnode_list_reclaim_marker = vn_alloc_marker(NULL); TAILQ_INSERT_HEAD(&vnode_list, vnode_list_reclaim_marker, v_vnodelist); vnode_zone = uma_zcreate("VNODE", sizeof (struct vnode), NULL, NULL, - vnode_init, vnode_fini, UMA_ALIGN_PTR, UMA_ZONE_SMR); - vfs_smr = uma_zone_get_smr(vnode_zone); + vnode_init, vnode_fini, UMA_ALIGN_PTR, 0); + uma_zone_set_smr(vnode_zone, vfs_smr); vnodepoll_zone = uma_zcreate("VNODEPOLL", sizeof (struct vpollinfo), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); /* @@ -2914,6 +2914,22 @@ vget_prep(struct vnode *vp) return (vs); } +void +vget_abort(struct vnode *vp, enum vgetstate vs) +{ + + switch (vs) { + case VGET_USECOUNT: + vrele(vp); + break; + case VGET_HOLDCNT: + vdrop(vp); + break; + default: + __assert_unreachable(); + } +} + int vget(struct vnode *vp, int flags, struct thread *td) { @@ -2925,7 +2941,7 @@ vget(struct vnode *vp, int flags, struct thread *td) return (vget_finish(vp, flags, vs)); } -static int __noinline +static void __noinline vget_finish_vchr(struct vnode *vp) { @@ -2941,7 +2957,7 @@ vget_finish_vchr(struct vnode *vp) #else refcount_release(&vp->v_holdcnt); #endif - return (0); + return; } VI_LOCK(vp); @@ -2953,18 +2969,17 @@ vget_finish_vchr(struct vnode *vp) refcount_release(&vp->v_holdcnt); #endif VI_UNLOCK(vp); - return (0); + return; } v_incr_devcount(vp); refcount_acquire(&vp->v_usecount); VI_UNLOCK(vp); - return (0); } int vget_finish(struct vnode *vp, int flags, enum vgetstate vs) { - int error, old; + int error; if ((flags & LK_INTERLOCK) != 0) ASSERT_VI_LOCKED(vp, __func__); @@ -2976,20 +2991,32 @@ vget_finish(struct vnode *vp, int flags, enum vgetstate vs) error = vn_lock(vp, flags); if (__predict_false(error != 0)) { - if (vs == VGET_USECOUNT) - vrele(vp); - else - vdrop(vp); + vget_abort(vp, vs); CTR2(KTR_VFS, "%s: impossible to lock vnode %p", __func__, vp); return (error); } - if (vs == VGET_USECOUNT) - return (0); + vget_finish_ref(vp, vs); + return (0); +} - if (__predict_false(vp->v_type == VCHR)) - return (vget_finish_vchr(vp)); +void +vget_finish_ref(struct vnode *vp, enum vgetstate vs) +{ + int old; + + VNPASS(vs == VGET_HOLDCNT || vs == VGET_USECOUNT, vp); + VNPASS(vp->v_holdcnt > 0, vp); + VNPASS(vs == VGET_HOLDCNT || vp->v_usecount > 0, vp); + + if (vs == VGET_USECOUNT) + return; + + if (__predict_false(vp->v_type == VCHR)) { + vget_finish_vchr(vp); + return; + } /* * We hold the vnode. If the usecount is 0 it will be utilized to keep @@ -3006,7 +3033,6 @@ vget_finish(struct vnode *vp, int flags, enum vgetstate vs) refcount_release(&vp->v_holdcnt); #endif } - return (0); } /* @@ -4424,6 +4450,7 @@ DB_SHOW_COMMAND(mount, db_show_mount) MNT_KERN_FLAG(MNTK_LOOKUP_EXCL_DOTDOT); MNT_KERN_FLAG(MNTK_MARKER); MNT_KERN_FLAG(MNTK_USES_BCACHE); + MNT_KERN_FLAG(MNTK_FPLOOKUP); MNT_KERN_FLAG(MNTK_NOASYNC); MNT_KERN_FLAG(MNTK_UNMOUNT); MNT_KERN_FLAG(MNTK_MWAIT); @@ -5239,6 +5266,38 @@ vn_isdisk(struct vnode *vp, int *errp) return (error == 0); } +/* + * VOP_FPLOOKUP_VEXEC routines are subject to special circumstances, see + * the comment above cache_fplookup for details. + * + * We never deny as priv_check_cred calls are not yet supported, see vaccess. + */ +int +vaccess_vexec_smr(mode_t file_mode, uid_t file_uid, gid_t file_gid, struct ucred *cred) +{ + + VFS_SMR_ASSERT_ENTERED(); + + /* Check the owner. */ + if (cred->cr_uid == file_uid) { + if (file_mode & S_IXUSR) + return (0); + return (EAGAIN); + } + + /* Otherwise, check the groups (first match) */ + if (groupmember(file_gid, cred)) { + if (file_mode & S_IXGRP) + return (0); + return (EAGAIN); + } + + /* Otherwise, check everyone else. */ + if (file_mode & S_IXOTH) + return (0); + return (EAGAIN); +} + /* * Common filesystem object access control check routine. Accepts a * vnode's type, "mode", uid and gid, requested access mode, credentials, @@ -5537,6 +5596,20 @@ vop_rename_pre(void *ap) } #ifdef DEBUG_VFS_LOCKS +void +vop_fplookup_vexec_pre(void *ap __unused) +{ + + VFS_SMR_ASSERT_ENTERED(); +} + +void +vop_fplookup_vexec_post(void *ap __unused, int rc __unused) +{ + + VFS_SMR_ASSERT_ENTERED(); +} + void vop_strategy_pre(void *ap) { diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src index beac2eef4e21..5c0649fdadaf 100644 --- a/sys/kern/vnode_if.src +++ b/sys/kern/vnode_if.src @@ -146,6 +146,17 @@ vop_close { }; +%% fplookup_vexec vp - - - +%! fplookup_vexec pre vop_fplookup_vexec_pre +%! fplookup_vexec post vop_fplookup_vexec_post + +vop_fplookup_vexec { + IN struct vnode *vp; + IN struct ucred *cred; + IN struct thread *td; +}; + + %% access vp L L L vop_access { diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h index 1ab82dd709d4..e917eeb3c893 100644 --- a/sys/security/mac/mac_framework.h +++ b/sys/security/mac/mac_framework.h @@ -422,13 +422,14 @@ int mac_vnode_check_listextattr(struct ucred *cred, struct vnode *vp, int mac_vnode_check_lookup_impl(struct ucred *cred, struct vnode *dvp, struct componentname *cnp); extern bool mac_vnode_check_lookup_fp_flag; +#define mac_vnode_check_lookup_enabled() __predict_false(mac_vnode_check_lookup_fp_flag) static inline int mac_vnode_check_lookup(struct ucred *cred, struct vnode *dvp, struct componentname *cnp) { mac_vnode_assert_locked(dvp, "mac_vnode_check_lookup"); - if (__predict_false(mac_vnode_check_lookup_fp_flag)) + if (mac_vnode_check_lookup_enabled()) return (mac_vnode_check_lookup_impl(cred, dvp, cnp)); return (0); } diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index 6954b1d23f45..a99b3b0cb047 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -311,6 +311,7 @@ pwd_set(struct filedesc *fdp, struct pwd *newpwd) smr_serialized_store(&fdp->fd_pwd, newpwd, (FILEDESC_XLOCK_ASSERT(fdp), true)); } +struct pwd *pwd_get_smr(void); #endif /* _KERNEL */ diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 6e1517aac4c6..a3bc0518a7ea 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -420,6 +420,7 @@ void __mnt_vnode_markerfree_lazy(struct vnode **mvp, struct mount *mp); #define MNTK_TEXT_REFS 0x00008000 /* Keep use ref for text */ #define MNTK_VMSETSIZE_BUG 0x00010000 #define MNTK_UNIONFS 0x00020000 /* A hack for F_ISUNIONSTACK */ +#define MNTK_FPLOOKUP 0x00040000 /* fast path lookup is supported */ #define MNTK_NOASYNC 0x00800000 /* disable async */ #define MNTK_UNMOUNT 0x01000000 /* unmount in progress */ #define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */ diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 7c0a4f568451..8273842a91f5 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -666,6 +666,8 @@ int vn_path_to_global_path(struct thread *td, struct vnode *vp, int vaccess(enum vtype type, mode_t file_mode, uid_t file_uid, gid_t file_gid, accmode_t accmode, struct ucred *cred, int *privused); +int vaccess_vexec_smr(mode_t file_mode, uid_t file_uid, gid_t file_gid, + struct ucred *cred); int vaccess_acl_nfs4(enum vtype type, uid_t file_uid, gid_t file_gid, struct acl *aclp, accmode_t accmode, struct ucred *cred, int *privused); @@ -682,6 +684,8 @@ int vget(struct vnode *vp, int flags, struct thread *td); enum vgetstate vget_prep_smr(struct vnode *vp); enum vgetstate vget_prep(struct vnode *vp); int vget_finish(struct vnode *vp, int flags, enum vgetstate vs); +void vget_finish_ref(struct vnode *vp, enum vgetstate vs); +void vget_abort(struct vnode *vp, enum vgetstate vs); void vgone(struct vnode *vp); void vhold(struct vnode *); void vholdl(struct vnode *); @@ -865,6 +869,8 @@ void vop_symlink_post(void *a, int rc); int vop_sigdefer(struct vop_vector *vop, struct vop_generic_args *a); #ifdef DEBUG_VFS_LOCKS +void vop_fplookup_vexec_pre(void *a); +void vop_fplookup_vexec_post(void *a, int rc); void vop_strategy_pre(void *a); void vop_lock_pre(void *a); void vop_lock_post(void *a, int rc); @@ -872,6 +878,8 @@ void vop_unlock_pre(void *a); void vop_need_inactive_pre(void *a); void vop_need_inactive_post(void *a, int rc); #else +#define vop_fplookup_vexec_pre(x) do { } while (0) +#define vop_fplookup_vexec_post(x, y) do { } while (0) #define vop_strategy_pre(x) do { } while (0) #define vop_lock_pre(x) do { } while (0) #define vop_lock_post(x, y) do { } while (0) @@ -1025,10 +1033,18 @@ int vn_dir_check_exec(struct vnode *vp, struct componentname *cnp); #define VFS_SMR() vfs_smr #define vfs_smr_enter() smr_enter(VFS_SMR()) #define vfs_smr_exit() smr_exit(VFS_SMR()) +#define vfs_smr_entered_load(ptr) smr_entered_load((ptr), VFS_SMR()) #define VFS_SMR_ASSERT_ENTERED() SMR_ASSERT_ENTERED(VFS_SMR()) #define VFS_SMR_ASSERT_NOT_ENTERED() SMR_ASSERT_NOT_ENTERED(VFS_SMR()) #define VFS_SMR_ZONE_SET(zone) uma_zone_set_smr((zone), VFS_SMR()) +#define vn_load_v_data_smr(vp) ({ \ + struct vnode *_vp = (vp); \ + \ + VFS_SMR_ASSERT_ENTERED(); \ + atomic_load_ptr(&(_vp)->v_data); \ +}) + #endif /* _KERNEL */ #endif /* !_SYS_VNODE_H_ */ From c42b77e6941903af76b58f96a1ecb86c6ffac36d Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 10:37:15 +0000 Subject: [PATCH 162/287] vfs: lockless lookup Provides full scalability as long as all visited filesystems support the lookup and terminal vnodes are different. Inner workings are explained in the comment above cache_fplookup. Capabilities and fd-relative lookups are not supported and will result in immediate fallback to regular code. Symlinks, ".." in the path, mount points without support for lockless lookup and mismatched counters will result in an attempt to get a reference to the directory vnode and continue in regular lookup. If this fails, the entire operation is aborted and regular lookup starts from scratch. However, care is taken that data is not copied again from userspace. Sample benchmark: incremental -j 104 bzImage on tmpfs: before: 142.96s user 1025.63s system 4924% cpu 23.731 total after: 147.36s user 313.40s system 3216% cpu 14.326 total Sample microbenchmark: access calls to separate files in /tmpfs, 104 workers, ops/s: before: 2165816 after: 151216530 Reviewed by: kib Tested by: pho (in a patchset) Differential Revision: https://reviews.freebsd.org/D25578 --- sys/kern/vfs_cache.c | 866 ++++++++++++++++++++++++++++++++++++++++++ sys/kern/vfs_lookup.c | 357 +++++++++-------- sys/sys/namei.h | 6 + 3 files changed, 1076 insertions(+), 153 deletions(-) diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index c4945200ec4f..8984ee411fa6 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -67,6 +68,11 @@ __FBSDID("$FreeBSD$"); #include #endif +#include + +#include +#include + #ifdef DDB #include #endif @@ -100,6 +106,10 @@ SDT_PROBE_DEFINE2(vfs, namecache, zap_negative, done, "struct vnode *", SDT_PROBE_DEFINE2(vfs, namecache, shrink_negative, done, "struct vnode *", "char *"); +SDT_PROBE_DEFINE3(vfs, fplookup, lookup, done, "struct nameidata", "int", "bool"); +SDT_PROBE_DECLARE(vfs, namei, lookup, entry); +SDT_PROBE_DECLARE(vfs, namei, lookup, return); + /* * This structure describes the elements in the cache of recent * names looked up by namei. @@ -2835,3 +2845,859 @@ DB_SHOW_COMMAND(vpath, db_show_vpath) } #endif + +extern uma_zone_t namei_zone; + +static bool __read_frequently cache_fast_lookup = true; +SYSCTL_BOOL(_vfs, OID_AUTO, cache_fast_lookup, CTLFLAG_RW, + &cache_fast_lookup, 0, ""); + +#define CACHE_FPL_FAILED -2020 + +static void +cache_fpl_cleanup_cnp(struct componentname *cnp) +{ + + uma_zfree(namei_zone, cnp->cn_pnbuf); +#ifdef DIAGNOSTIC + cnp->cn_pnbuf = NULL; + cnp->cn_nameptr = NULL; +#endif +} + +static void +cache_fpl_handle_root(struct nameidata *ndp, struct vnode **dpp) +{ + struct componentname *cnp; + + cnp = &ndp->ni_cnd; + while (*(cnp->cn_nameptr) == '/') { + cnp->cn_nameptr++; + ndp->ni_pathlen--; + } + + *dpp = ndp->ni_rootdir; +} + +/* + * Components of nameidata (or objects it can point to) which may + * need restoring in case fast path lookup fails. + */ +struct nameidata_saved { + int cn_flags; + long cn_namelen; + char *cn_nameptr; + size_t ni_pathlen; +}; + +struct cache_fpl { + int line; + enum cache_fpl_status status; + bool in_smr; + struct nameidata *ndp; + struct nameidata_saved snd; + struct componentname *cnp; + struct vnode *dvp; + seqc_t dvp_seqc; + struct vnode *tvp; + seqc_t tvp_seqc; + struct pwd *pwd; +}; + +static void +cache_fpl_checkpoint(struct cache_fpl *fpl, struct nameidata_saved *snd) +{ + + snd->cn_flags = fpl->ndp->ni_cnd.cn_flags; + snd->cn_namelen = fpl->ndp->ni_cnd.cn_namelen; + snd->cn_nameptr = fpl->ndp->ni_cnd.cn_nameptr; + snd->ni_pathlen = fpl->ndp->ni_pathlen; +} + +static void +cache_fpl_restore(struct cache_fpl *fpl, struct nameidata_saved *snd) +{ + + fpl->ndp->ni_cnd.cn_flags = snd->cn_flags; + fpl->ndp->ni_cnd.cn_namelen = snd->cn_namelen; + fpl->ndp->ni_cnd.cn_nameptr = snd->cn_nameptr; + fpl->ndp->ni_pathlen = snd->ni_pathlen; +} + +#ifdef INVARIANTS +#define cache_fpl_smr_assert_entered(fpl) ({ \ + struct cache_fpl *_fpl = (fpl); \ + MPASS(_fpl->in_smr == true); \ + VFS_SMR_ASSERT_ENTERED(); \ +}) +#define cache_fpl_smr_assert_not_entered(fpl) ({ \ + struct cache_fpl *_fpl = (fpl); \ + MPASS(_fpl->in_smr == false); \ + VFS_SMR_ASSERT_NOT_ENTERED(); \ +}) +#else +#define cache_fpl_smr_assert_entered(fpl) do { } while (0) +#define cache_fpl_smr_assert_not_entered(fpl) do { } while (0) +#endif + +#define cache_fpl_smr_enter(fpl) ({ \ + struct cache_fpl *_fpl = (fpl); \ + MPASS(_fpl->in_smr == false); \ + vfs_smr_enter(); \ + _fpl->in_smr = true; \ +}) + +#define cache_fpl_smr_exit(fpl) ({ \ + struct cache_fpl *_fpl = (fpl); \ + MPASS(_fpl->in_smr == true); \ + vfs_smr_exit(); \ + _fpl->in_smr = false; \ +}) + +static int +cache_fpl_aborted_impl(struct cache_fpl *fpl, int line) +{ + + if (fpl->status != CACHE_FPL_STATUS_UNSET) { + KASSERT(fpl->status == CACHE_FPL_STATUS_PARTIAL, + ("%s: converting to abort from %d at %d, set at %d\n", + __func__, fpl->status, line, fpl->line)); + } + fpl->status = CACHE_FPL_STATUS_ABORTED; + fpl->line = line; + return (CACHE_FPL_FAILED); +} + +#define cache_fpl_aborted(x) cache_fpl_aborted_impl((x), __LINE__) + +static int +cache_fpl_partial_impl(struct cache_fpl *fpl, int line) +{ + + KASSERT(fpl->status == CACHE_FPL_STATUS_UNSET, + ("%s: setting to partial at %d, but already set to %d at %d\n", + __func__, line, fpl->status, fpl->line)); + cache_fpl_smr_assert_entered(fpl); + fpl->status = CACHE_FPL_STATUS_PARTIAL; + fpl->line = line; + return (CACHE_FPL_FAILED); +} + +#define cache_fpl_partial(x) cache_fpl_partial_impl((x), __LINE__) + +static int +cache_fpl_handled_impl(struct cache_fpl *fpl, int error, int line) +{ + + KASSERT(fpl->status == CACHE_FPL_STATUS_UNSET, + ("%s: setting to handled at %d, but already set to %d at %d\n", + __func__, line, fpl->status, fpl->line)); + cache_fpl_smr_assert_not_entered(fpl); + MPASS(error != CACHE_FPL_FAILED); + fpl->status = CACHE_FPL_STATUS_HANDLED; + fpl->line = line; + return (error); +} + +#define cache_fpl_handled(x, e) cache_fpl_handled_impl((x), (e), __LINE__) + +#define CACHE_FPL_SUPPORTED_CN_FLAGS \ + (LOCKLEAF | FOLLOW | LOCKSHARED | SAVENAME | ISOPEN | AUDITVNODE1) + +static bool +cache_can_fplookup(struct cache_fpl *fpl) +{ + struct nameidata *ndp; + struct componentname *cnp; + struct thread *td; + + ndp = fpl->ndp; + cnp = fpl->cnp; + td = cnp->cn_thread; + + if (!cache_fast_lookup) { + cache_fpl_aborted(fpl); + return (false); + } +#ifdef MAC + if (mac_vnode_check_lookup_enabled()) { + cache_fpl_aborted(fpl); + return (false); + } +#endif + if ((cnp->cn_flags & ~CACHE_FPL_SUPPORTED_CN_FLAGS) != 0) { + cache_fpl_aborted(fpl); + return (false); + } + if ((cnp->cn_flags & LOCKLEAF) == 0) { + cache_fpl_aborted(fpl); + return (false); + } + if (cnp->cn_nameiop != LOOKUP) { + cache_fpl_aborted(fpl); + return (false); + } + if (ndp->ni_dirfd != AT_FDCWD) { + cache_fpl_aborted(fpl); + return (false); + } + if (IN_CAPABILITY_MODE(td)) { + cache_fpl_aborted(fpl); + return (false); + } + if (AUDITING_TD(td)) { + cache_fpl_aborted(fpl); + return (false); + } + if (ndp->ni_startdir != NULL) { + cache_fpl_aborted(fpl); + return (false); + } + return (true); +} + +static bool +cache_fplookup_vnode_supported(struct vnode *vp) +{ + + return (vp->v_type != VLNK); +} + +/* + * The target vnode is not supported, prepare for the slow path to take over. + */ +static int +cache_fplookup_partial_setup(struct cache_fpl *fpl) +{ + struct componentname *cnp; + enum vgetstate dvs; + struct vnode *dvp; + struct pwd *pwd; + seqc_t dvp_seqc; + + cnp = fpl->cnp; + dvp = fpl->dvp; + dvp_seqc = fpl->dvp_seqc; + + dvs = vget_prep_smr(dvp); + if (dvs == VGET_NONE) { + cache_fpl_smr_exit(fpl); + return (cache_fpl_aborted(fpl)); + } + + cache_fpl_smr_exit(fpl); + + vget_finish_ref(dvp, dvs); + if (!vn_seqc_consistent(dvp, dvp_seqc)) { + vrele(dvp); + return (cache_fpl_aborted(fpl)); + } + + pwd = pwd_hold(curthread); + if (fpl->pwd != pwd) { + vrele(dvp); + pwd_drop(pwd); + return (cache_fpl_aborted(fpl)); + } + + fpl->ndp->ni_startdir = dvp; + return (0); +} + +static int +cache_fplookup_final(struct cache_fpl *fpl) +{ + struct componentname *cnp; + enum vgetstate tvs; + struct vnode *dvp, *tvp; + seqc_t dvp_seqc, tvp_seqc; + int error; + + cnp = fpl->cnp; + dvp = fpl->dvp; + dvp_seqc = fpl->dvp_seqc; + tvp = fpl->tvp; + tvp_seqc = fpl->tvp_seqc; + + VNPASS(cache_fplookup_vnode_supported(dvp), dvp); + MPASS((cnp->cn_flags & LOCKLEAF) != 0); + + tvs = vget_prep_smr(tvp); + if (tvs == VGET_NONE) { + return (cache_fpl_partial(fpl)); + } + + if (!vn_seqc_consistent(dvp, dvp_seqc)) { + cache_fpl_smr_exit(fpl); + vget_abort(tvp, tvs); + return (cache_fpl_aborted(fpl)); + } + + cache_fpl_smr_exit(fpl); + + error = vget_finish(tvp, cnp->cn_lkflags, tvs); + if (error != 0) { + return (cache_fpl_aborted(fpl)); + } + + if (!vn_seqc_consistent(tvp, tvp_seqc)) { + vput(tvp); + return (cache_fpl_aborted(fpl)); + } + + return (cache_fpl_handled(fpl, 0)); +} + +static int +cache_fplookup_next(struct cache_fpl *fpl) +{ + struct componentname *cnp; + struct namecache *ncp; + struct negstate *negstate; + struct vnode *dvp, *tvp; + u_char nc_flag; + uint32_t hash; + bool neg_hot; + + cnp = fpl->cnp; + dvp = fpl->dvp; + + if (__predict_false(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')) { + fpl->tvp = dvp; + fpl->tvp_seqc = vn_seqc_read_any(dvp); + if (seqc_in_modify(fpl->tvp_seqc)) { + return (cache_fpl_aborted(fpl)); + } + return (0); + } + + hash = cache_get_hash(cnp->cn_nameptr, cnp->cn_namelen, dvp); + + CK_LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) { + counter_u64_add(numchecks, 1); + if (ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen && + !bcmp(ncp->nc_name, cnp->cn_nameptr, ncp->nc_nlen)) + break; + } + + /* + * If there is no entry we have to punt to the slow path to perform + * actual lookup. Should there be nothing with this name a negative + * entry will be created. + */ + if (__predict_false(ncp == NULL)) { + return (cache_fpl_partial(fpl)); + } + + tvp = atomic_load_ptr(&ncp->nc_vp); + nc_flag = atomic_load_char(&ncp->nc_flag); + if ((nc_flag & NCF_NEGATIVE) != 0) { + negstate = NCP2NEGSTATE(ncp); + neg_hot = ((negstate->neg_flag & NEG_HOT) != 0); + if (__predict_false(cache_ncp_invalid(ncp))) { + return (cache_fpl_partial(fpl)); + } + if (__predict_false((nc_flag & NCF_WHITE) != 0)) { + return (cache_fpl_partial(fpl)); + } + if (!neg_hot) { + /* + * TODO + * Promoting to hot negative requires locks, thus is + * left not yet supported for simplicity. + */ + return (cache_fpl_partial(fpl)); + } + SDT_PROBE2(vfs, namecache, lookup, hit__negative, dvp, + ncp->nc_name); + counter_u64_add(numneghits, 1); + cache_fpl_smr_exit(fpl); + return (cache_fpl_handled(fpl, ENOENT)); + } + + if (__predict_false(cache_ncp_invalid(ncp))) { + return (cache_fpl_partial(fpl)); + } + + fpl->tvp = tvp; + fpl->tvp_seqc = vn_seqc_read_any(tvp); + if (seqc_in_modify(fpl->tvp_seqc)) { + return (cache_fpl_partial(fpl)); + } + + if (!cache_fplookup_vnode_supported(tvp)) { + return (cache_fpl_partial(fpl)); + } + + counter_u64_add(numposhits, 1); + SDT_PROBE3(vfs, namecache, lookup, hit, dvp, ncp->nc_name, tvp); + return (0); +} + +static bool +cache_fplookup_mp_supported(struct mount *mp) +{ + + if (mp == NULL) + return (false); + if ((mp->mnt_kern_flag & MNTK_FPLOOKUP) == 0) + return (false); + if ((mp->mnt_flag & MNT_UNION) != 0) + return (false); + return (true); +} + +/* + * Walk up the mount stack (if any). + * + * Correctness is provided in the following ways: + * - all vnodes are protected from freeing with SMR + * - struct mount objects are type stable making them always safe to access + * - stability of the particular mount is provided by busying it + * - relationship between the vnode which is mounted on and the mount is + * verified with the vnode sequence counter after busying + * - association between root vnode of the mount and the mount is protected + * by busy + * + * From that point on we can read the sequence counter of the root vnode + * and get the next mount on the stack (if any) using the same protection. + * + * By the end of successful walk we are guaranteed the reached state was + * indeed present at least at some point which matches the regular lookup. + */ +static int +cache_fplookup_climb_mount(struct cache_fpl *fpl) +{ + struct mount *mp, *prev_mp; + struct vnode *vp; + seqc_t vp_seqc; + + vp = fpl->tvp; + vp_seqc = fpl->tvp_seqc; + if (vp->v_type != VDIR) + return (0); + + mp = atomic_load_ptr(&vp->v_mountedhere); + if (mp == NULL) + return (0); + + prev_mp = NULL; + for (;;) { + if (!vfs_op_thread_enter(mp)) { + if (prev_mp != NULL) + vfs_op_thread_exit(prev_mp); + return (cache_fpl_partial(fpl)); + } + if (prev_mp != NULL) + vfs_op_thread_exit(prev_mp); + if (!vn_seqc_consistent(vp, vp_seqc)) { + vfs_op_thread_exit(mp); + return (cache_fpl_partial(fpl)); + } + if (!cache_fplookup_mp_supported(mp)) { + vfs_op_thread_exit(mp); + return (cache_fpl_partial(fpl)); + } + vp = atomic_load_ptr(&mp->mnt_rootvnode); + if (vp == NULL || VN_IS_DOOMED(vp)) { + vfs_op_thread_exit(mp); + return (cache_fpl_partial(fpl)); + } + vp_seqc = vn_seqc_read_any(vp); + if (seqc_in_modify(vp_seqc)) { + vfs_op_thread_exit(mp); + return (cache_fpl_partial(fpl)); + } + prev_mp = mp; + mp = atomic_load_ptr(&vp->v_mountedhere); + if (mp == NULL) + break; + } + + vfs_op_thread_exit(prev_mp); + fpl->tvp = vp; + fpl->tvp_seqc = vp_seqc; + return (0); +} + +/* + * Parse the path. + * + * The code is mostly copy-pasted from regular lookup, see lookup(). + * The structure is maintained along with comments for easier maintenance. + * Deduplicating the code will become feasible after fast path lookup + * becomes more feature-complete. + */ +static int +cache_fplookup_parse(struct cache_fpl *fpl) +{ + struct nameidata *ndp; + struct componentname *cnp; + char *cp; + char *prev_ni_next; /* saved ndp->ni_next */ + size_t prev_ni_pathlen; /* saved ndp->ni_pathlen */ + + ndp = fpl->ndp; + cnp = fpl->cnp; + + /* + * Search a new directory. + * + * The last component of the filename is left accessible via + * cnp->cn_nameptr for callers that need the name. Callers needing + * the name set the SAVENAME flag. When done, they assume + * responsibility for freeing the pathname buffer. + */ + for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) + continue; + cnp->cn_namelen = cp - cnp->cn_nameptr; + if (cnp->cn_namelen > NAME_MAX) { + cache_fpl_smr_exit(fpl); + return (cache_fpl_handled(fpl, ENAMETOOLONG)); + } + prev_ni_pathlen = ndp->ni_pathlen; + ndp->ni_pathlen -= cnp->cn_namelen; + KASSERT(ndp->ni_pathlen <= PATH_MAX, + ("%s: ni_pathlen underflow to %zd\n", __func__, ndp->ni_pathlen)); + prev_ni_next = ndp->ni_next; + ndp->ni_next = cp; + + /* + * Replace multiple slashes by a single slash and trailing slashes + * by a null. This must be done before VOP_LOOKUP() because some + * fs's don't know about trailing slashes. Remember if there were + * trailing slashes to handle symlinks, existing non-directories + * and non-existing files that won't be directories specially later. + */ + while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { + cp++; + ndp->ni_pathlen--; + if (*cp == '\0') { + /* + * TODO + * Regular lookup performs the following: + * *ndp->ni_next = '\0'; + * cnp->cn_flags |= TRAILINGSLASH; + * + * Which is problematic since it modifies data read + * from userspace. Then if fast path lookup was to + * abort we would have to either restore it or convey + * the flag. Since this is a corner case just ignore + * it for simplicity. + */ + return (cache_fpl_partial(fpl)); + } + } + ndp->ni_next = cp; + + cnp->cn_flags |= MAKEENTRY; + + if (cnp->cn_namelen == 2 && + cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') + cnp->cn_flags |= ISDOTDOT; + else + cnp->cn_flags &= ~ISDOTDOT; + if (*ndp->ni_next == 0) + cnp->cn_flags |= ISLASTCN; + else + cnp->cn_flags &= ~ISLASTCN; + + /* + * Check for degenerate name (e.g. / or "") + * which is a way of talking about a directory, + * e.g. like "/." or ".". + * + * TODO + * Another corner case handled by the regular lookup + */ + if (__predict_false(cnp->cn_nameptr[0] == '\0')) { + return (cache_fpl_partial(fpl)); + } + return (0); +} + +static void +cache_fplookup_parse_advance(struct cache_fpl *fpl) +{ + struct nameidata *ndp; + struct componentname *cnp; + + ndp = fpl->ndp; + cnp = fpl->cnp; + + cnp->cn_nameptr = ndp->ni_next; + while (*cnp->cn_nameptr == '/') { + cnp->cn_nameptr++; + ndp->ni_pathlen--; + } +} + +static int +cache_fplookup_impl(struct vnode *dvp, struct cache_fpl *fpl) +{ + struct nameidata *ndp; + struct componentname *cnp; + struct mount *mp; + int error; + + error = CACHE_FPL_FAILED; + ndp = fpl->ndp; + ndp->ni_lcf = 0; + cnp = fpl->cnp; + cnp->cn_lkflags = LK_SHARED; + if ((cnp->cn_flags & LOCKSHARED) == 0) + cnp->cn_lkflags = LK_EXCLUSIVE; + + cache_fpl_checkpoint(fpl, &fpl->snd); + + fpl->dvp = dvp; + fpl->dvp_seqc = vn_seqc_read_any(fpl->dvp); + if (seqc_in_modify(fpl->dvp_seqc)) { + cache_fpl_aborted(fpl); + goto out; + } + mp = atomic_load_ptr(&fpl->dvp->v_mount); + if (!cache_fplookup_mp_supported(mp)) { + cache_fpl_aborted(fpl); + goto out; + } + + VNPASS(cache_fplookup_vnode_supported(fpl->dvp), fpl->dvp); + + for (;;) { + error = cache_fplookup_parse(fpl); + if (__predict_false(error != 0)) { + break; + } + + if (cnp->cn_flags & ISDOTDOT) { + error = cache_fpl_partial(fpl); + break; + } + + VNPASS(cache_fplookup_vnode_supported(fpl->dvp), fpl->dvp); + + error = VOP_FPLOOKUP_VEXEC(fpl->dvp, cnp->cn_cred, cnp->cn_thread); + if (__predict_false(error != 0)) { + switch (error) { + case EAGAIN: + case EOPNOTSUPP: /* can happen when racing against vgone */ + cache_fpl_partial(fpl); + break; + default: + /* + * See the API contract for VOP_FPLOOKUP_VEXEC. + */ + if (!vn_seqc_consistent(fpl->dvp, fpl->dvp_seqc)) { + error = cache_fpl_aborted(fpl); + } else { + cache_fpl_smr_exit(fpl); + cache_fpl_handled(fpl, error); + } + break; + } + break; + } + + error = cache_fplookup_next(fpl); + if (__predict_false(error != 0)) { + break; + } + + VNPASS(!seqc_in_modify(fpl->tvp_seqc), fpl->tvp); + + error = cache_fplookup_climb_mount(fpl); + if (__predict_false(error != 0)) { + break; + } + + VNPASS(!seqc_in_modify(fpl->tvp_seqc), fpl->tvp); + + if (cnp->cn_flags & ISLASTCN) { + error = cache_fplookup_final(fpl); + break; + } + + if (!vn_seqc_consistent(fpl->dvp, fpl->dvp_seqc)) { + error = cache_fpl_aborted(fpl); + break; + } + + fpl->dvp = fpl->tvp; + fpl->dvp_seqc = fpl->tvp_seqc; + + cache_fplookup_parse_advance(fpl); + cache_fpl_checkpoint(fpl, &fpl->snd); + } +out: + switch (fpl->status) { + case CACHE_FPL_STATUS_UNSET: + __assert_unreachable(); + break; + case CACHE_FPL_STATUS_PARTIAL: + cache_fpl_smr_assert_entered(fpl); + return (cache_fplookup_partial_setup(fpl)); + case CACHE_FPL_STATUS_ABORTED: + if (fpl->in_smr) + cache_fpl_smr_exit(fpl); + return (CACHE_FPL_FAILED); + case CACHE_FPL_STATUS_HANDLED: + cache_fpl_smr_assert_not_entered(fpl); + if (__predict_false(error != 0)) { + ndp->ni_dvp = NULL; + ndp->ni_vp = NULL; + cache_fpl_cleanup_cnp(cnp); + return (error); + } + ndp->ni_dvp = fpl->dvp; + ndp->ni_vp = fpl->tvp; + if (cnp->cn_flags & SAVENAME) + cnp->cn_flags |= HASBUF; + else + cache_fpl_cleanup_cnp(cnp); + return (error); + } +} + +/* + * Fast path lookup protected with SMR and sequence counters. + * + * Note: all VOP_FPLOOKUP_VEXEC routines have a comment referencing this one. + * + * Filesystems can opt in by setting the MNTK_FPLOOKUP flag and meeting criteria + * outlined below. + * + * Traditional vnode lookup conceptually looks like this: + * + * vn_lock(current); + * for (;;) { + * next = find(); + * vn_lock(next); + * vn_unlock(current); + * current = next; + * if (last) + * break; + * } + * return (current); + * + * Each jump to the next vnode is safe memory-wise and atomic with respect to + * any modifications thanks to holding respective locks. + * + * The same guarantee can be provided with a combination of safe memory + * reclamation and sequence counters instead. If all operations which affect + * the relationship between the current vnode and the one we are looking for + * also modify the counter, we can verify whether all the conditions held as + * we made the jump. This includes things like permissions, mount points etc. + * Counter modification is provided by enclosing relevant places in + * vn_seqc_write_begin()/end() calls. + * + * Thus this translates to: + * + * vfs_smr_enter(); + * dvp_seqc = seqc_read_any(dvp); + * if (seqc_in_modify(dvp_seqc)) // someone is altering the vnode + * abort(); + * for (;;) { + * tvp = find(); + * tvp_seqc = seqc_read_any(tvp); + * if (seqc_in_modify(tvp_seqc)) // someone is altering the target vnode + * abort(); + * if (!seqc_consistent(dvp, dvp_seqc) // someone is altering the vnode + * abort(); + * dvp = tvp; // we know nothing of importance has changed + * dvp_seqc = tvp_seqc; // store the counter for the tvp iteration + * if (last) + * break; + * } + * vget(); // secure the vnode + * if (!seqc_consistent(tvp, tvp_seqc) // final check + * abort(); + * // at this point we know nothing has changed for any parent<->child pair + * // as they were crossed during the lookup, meaning we matched the guarantee + * // of the locked variant + * return (tvp); + * + * The API contract for VOP_FPLOOKUP_VEXEC routines is as follows: + * - they are called while within vfs_smr protection which they must never exit + * - EAGAIN can be returned to denote checking could not be performed, it is + * always valid to return it + * - if the sequence counter has not changed the result must be valid + * - if the sequence counter has changed both false positives and false negatives + * are permitted (since the result will be rejected later) + * - for simple cases of unix permission checks vaccess_vexec_smr can be used + * + * Caveats to watch out for: + * - vnodes are passed unlocked and unreferenced with nothing stopping + * VOP_RECLAIM, in turn meaning that ->v_data can become NULL. It is advised + * to use atomic_load_ptr to fetch it. + * - the aforementioned object can also get freed, meaning absent other means it + * should be protected with vfs_smr + * - either safely checking permissions as they are modified or guaranteeing + * their stability is left to the routine + */ +int +cache_fplookup(struct nameidata *ndp, enum cache_fpl_status *status, + struct pwd **pwdp) +{ + struct cache_fpl fpl; + struct pwd *pwd; + struct vnode *dvp; + struct componentname *cnp; + struct nameidata_saved orig; + int error; + + *status = CACHE_FPL_STATUS_UNSET; + bzero(&fpl, sizeof(fpl)); + fpl.status = CACHE_FPL_STATUS_UNSET; + fpl.ndp = ndp; + fpl.cnp = &ndp->ni_cnd; + MPASS(curthread == fpl.cnp->cn_thread); + + if (!cache_can_fplookup(&fpl)) { + SDT_PROBE3(vfs, fplookup, lookup, done, ndp, fpl.line, fpl.status); + *status = fpl.status; + return (EOPNOTSUPP); + } + + cache_fpl_checkpoint(&fpl, &orig); + + cache_fpl_smr_enter(&fpl); + pwd = pwd_get_smr(); + fpl.pwd = pwd; + ndp->ni_rootdir = pwd->pwd_rdir; + ndp->ni_topdir = pwd->pwd_jdir; + + cnp = fpl.cnp; + cnp->cn_nameptr = cnp->cn_pnbuf; + if (cnp->cn_pnbuf[0] == '/') { + cache_fpl_handle_root(ndp, &dvp); + } else { + MPASS(ndp->ni_dirfd == AT_FDCWD); + dvp = pwd->pwd_cdir; + } + + SDT_PROBE4(vfs, namei, lookup, entry, dvp, cnp->cn_pnbuf, cnp->cn_flags, true); + + error = cache_fplookup_impl(dvp, &fpl); + cache_fpl_smr_assert_not_entered(&fpl); + SDT_PROBE3(vfs, fplookup, lookup, done, ndp, fpl.line, fpl.status); + + *status = fpl.status; + switch (fpl.status) { + case CACHE_FPL_STATUS_UNSET: + __assert_unreachable(); + break; + case CACHE_FPL_STATUS_HANDLED: + SDT_PROBE3(vfs, namei, lookup, return, error, + (error == 0 ? ndp->ni_vp : NULL), true); + break; + case CACHE_FPL_STATUS_PARTIAL: + *pwdp = fpl.pwd; + cache_fpl_restore(&fpl, &fpl.snd); + break; + case CACHE_FPL_STATUS_ABORTED: + cache_fpl_restore(&fpl, &orig); + break; + } + return (error); +} diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index fa58f7576cea..13e1d6ddce99 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -71,9 +71,9 @@ __FBSDID("$FreeBSD$"); #undef NAMEI_DIAGNOSTIC SDT_PROVIDER_DECLARE(vfs); -SDT_PROBE_DEFINE3(vfs, namei, lookup, entry, "struct vnode *", "char *", - "unsigned long"); -SDT_PROBE_DEFINE2(vfs, namei, lookup, return, "int", "struct vnode *"); +SDT_PROBE_DEFINE4(vfs, namei, lookup, entry, "struct vnode *", "char *", + "unsigned long", "bool"); +SDT_PROBE_DEFINE3(vfs, namei, lookup, return, "int", "struct vnode *", "bool"); /* Allocation zone for namei. */ uma_zone_t namei_zone; @@ -280,6 +280,166 @@ namei_handle_root(struct nameidata *ndp, struct vnode **dpp) return (0); } +static int +namei_setup(struct nameidata *ndp, struct vnode **dpp, struct pwd **pwdp) +{ + struct componentname *cnp; + struct file *dfp; + struct thread *td; + struct pwd *pwd; + cap_rights_t rights; + struct filecaps dirfd_caps; + int error, startdir_used; + + cnp = &ndp->ni_cnd; + td = cnp->cn_thread; + + *pwdp = NULL; + +#ifdef CAPABILITY_MODE + /* + * In capability mode, lookups must be restricted to happen in + * the subtree with the root specified by the file descriptor: + * - The root must be real file descriptor, not the pseudo-descriptor + * AT_FDCWD. + * - The passed path must be relative and not absolute. + * - If lookup_cap_dotdot is disabled, path must not contain the + * '..' components. + * - If lookup_cap_dotdot is enabled, we verify that all '..' + * components lookups result in the directories which were + * previously walked by us, which prevents an escape from + * the relative root. + */ + if (IN_CAPABILITY_MODE(td) && (cnp->cn_flags & NOCAPCHECK) == 0) { + ndp->ni_lcf |= NI_LCF_STRICTRELATIVE; + if (ndp->ni_dirfd == AT_FDCWD) { +#ifdef KTRACE + if (KTRPOINT(td, KTR_CAPFAIL)) + ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL); +#endif + return (ECAPMODE); + } + } +#endif + error = 0; + + /* + * Get starting point for the translation. + */ + pwd = pwd_hold(td); + /* + * The reference on ni_rootdir is acquired in the block below to avoid + * back-to-back atomics for absolute lookups. + */ + ndp->ni_rootdir = pwd->pwd_rdir; + ndp->ni_topdir = pwd->pwd_jdir; + + if (cnp->cn_pnbuf[0] == '/') { + ndp->ni_resflags |= NIRES_ABS; + error = namei_handle_root(ndp, dpp); + } else { + if (ndp->ni_startdir != NULL) { + *dpp = ndp->ni_startdir; + startdir_used = 1; + } else if (ndp->ni_dirfd == AT_FDCWD) { + *dpp = pwd->pwd_cdir; + vrefact(*dpp); + } else { + rights = ndp->ni_rightsneeded; + cap_rights_set_one(&rights, CAP_LOOKUP); + + if (cnp->cn_flags & AUDITVNODE1) + AUDIT_ARG_ATFD1(ndp->ni_dirfd); + if (cnp->cn_flags & AUDITVNODE2) + AUDIT_ARG_ATFD2(ndp->ni_dirfd); + /* + * Effectively inlined fgetvp_rights, because we need to + * inspect the file as well as grabbing the vnode. + */ + error = fget_cap(td, ndp->ni_dirfd, &rights, + &dfp, &ndp->ni_filecaps); + if (error != 0) { + /* + * Preserve the error; it should either be EBADF + * or capability-related, both of which can be + * safely returned to the caller. + */ + } else { + if (dfp->f_ops == &badfileops) { + error = EBADF; + } else if (dfp->f_vnode == NULL) { + error = ENOTDIR; + } else { + *dpp = dfp->f_vnode; + vrefact(*dpp); + + if ((dfp->f_flag & FSEARCH) != 0) + cnp->cn_flags |= NOEXECCHECK; + } + fdrop(dfp, td); + } +#ifdef CAPABILITIES + /* + * If file descriptor doesn't have all rights, + * all lookups relative to it must also be + * strictly relative. + */ + CAP_ALL(&rights); + if (!cap_rights_contains(&ndp->ni_filecaps.fc_rights, + &rights) || + ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL || + ndp->ni_filecaps.fc_nioctls != -1) { + ndp->ni_lcf |= NI_LCF_STRICTRELATIVE; + } +#endif + } + if (error == 0 && (*dpp)->v_type != VDIR) + error = ENOTDIR; + } + if (error == 0 && (cnp->cn_flags & BENEATH) != 0) { + if (ndp->ni_dirfd == AT_FDCWD) { + ndp->ni_beneath_latch = pwd->pwd_cdir; + vrefact(ndp->ni_beneath_latch); + } else { + rights = ndp->ni_rightsneeded; + cap_rights_set_one(&rights, CAP_LOOKUP); + error = fgetvp_rights(td, ndp->ni_dirfd, &rights, + &dirfd_caps, &ndp->ni_beneath_latch); + if (error == 0 && (*dpp)->v_type != VDIR) { + vrele(ndp->ni_beneath_latch); + error = ENOTDIR; + } + } + if (error == 0) + ndp->ni_lcf |= NI_LCF_LATCH; + } + /* + * If we are auditing the kernel pathname, save the user pathname. + */ + if (cnp->cn_flags & AUDITVNODE1) + AUDIT_ARG_UPATH1_VP(td, ndp->ni_rootdir, *dpp, cnp->cn_pnbuf); + if (cnp->cn_flags & AUDITVNODE2) + AUDIT_ARG_UPATH2_VP(td, ndp->ni_rootdir, *dpp, cnp->cn_pnbuf); + if (ndp->ni_startdir != NULL && !startdir_used) + vrele(ndp->ni_startdir); + if (error != 0) { + if (*dpp != NULL) + vrele(*dpp); + return (error); + } + MPASS((ndp->ni_lcf & (NI_LCF_BENEATH_ABS | NI_LCF_LATCH)) != + NI_LCF_BENEATH_ABS); + if (((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0 && + lookup_cap_dotdot != 0) || + ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) == 0 && + (cnp->cn_flags & BENEATH) != 0)) + ndp->ni_lcf |= NI_LCF_CAP_DOTDOT; + SDT_PROBE4(vfs, namei, lookup, entry, *dpp, cnp->cn_pnbuf, + cnp->cn_flags, false); + *pwdp = pwd; + return (0); +} + /* * Convert a pathname into a pointer to a locked vnode. * @@ -307,14 +467,12 @@ namei(struct nameidata *ndp) struct vnode *dp; /* the directory we are searching */ struct iovec aiov; /* uio for reading symbolic links */ struct componentname *cnp; - struct file *dfp; struct thread *td; struct proc *p; struct pwd *pwd; - cap_rights_t rights; - struct filecaps dirfd_caps; struct uio auio; - int error, linklen, startdir_used; + int error, linklen; + enum cache_fpl_status status; cnp = &ndp->ni_cnd; td = cnp->cn_thread; @@ -329,10 +487,14 @@ namei(struct nameidata *ndp) ndp->ni_startdir->v_type == VBAD); TAILQ_INIT(&ndp->ni_cap_tracker); ndp->ni_lcf = 0; + ndp->ni_loopcnt = 0; + dp = NULL; /* We will set this ourselves if we need it. */ cnp->cn_flags &= ~TRAILINGSLASH; + ndp->ni_vp = NULL; + /* * Get a buffer for the name to be translated, and copy the * name into the buffer. @@ -346,44 +508,21 @@ namei(struct nameidata *ndp) error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, MAXPATHLEN, &ndp->ni_pathlen); + if (error != 0) { + namei_cleanup_cnp(cnp); + return (error); + } + + cnp->cn_nameptr = cnp->cn_pnbuf; + /* * Don't allow empty pathnames. */ - if (error == 0 && *cnp->cn_pnbuf == '\0') - error = ENOENT; - -#ifdef CAPABILITY_MODE - /* - * In capability mode, lookups must be restricted to happen in - * the subtree with the root specified by the file descriptor: - * - The root must be real file descriptor, not the pseudo-descriptor - * AT_FDCWD. - * - The passed path must be relative and not absolute. - * - If lookup_cap_dotdot is disabled, path must not contain the - * '..' components. - * - If lookup_cap_dotdot is enabled, we verify that all '..' - * components lookups result in the directories which were - * previously walked by us, which prevents an escape from - * the relative root. - */ - if (error == 0 && IN_CAPABILITY_MODE(td) && - (cnp->cn_flags & NOCAPCHECK) == 0) { - ndp->ni_lcf |= NI_LCF_STRICTRELATIVE; - if (ndp->ni_dirfd == AT_FDCWD) { -#ifdef KTRACE - if (KTRPOINT(td, KTR_CAPFAIL)) - ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL); -#endif - error = ECAPMODE; - } - } -#endif - if (error != 0) { + if (*cnp->cn_pnbuf == '\0') { namei_cleanup_cnp(cnp); - ndp->ni_vp = NULL; - return (error); + return (ENOENT); } - ndp->ni_loopcnt = 0; + #ifdef KTRACE if (KTRPOINT(td, KTR_NAMEI)) { KASSERT(cnp->cn_thread == curthread, @@ -391,122 +530,34 @@ namei(struct nameidata *ndp) ktrnamei(cnp->cn_pnbuf); } #endif + /* - * Get starting point for the translation. + * First try looking up the target without locking any vnodes. + * + * We may need to start from scratch or pick up where it left off. */ - pwd = pwd_hold(td); - /* - * The reference on ni_rootdir is acquired in the block below to avoid - * back-to-back atomics for absolute lookups. - */ - ndp->ni_rootdir = pwd->pwd_rdir; - ndp->ni_topdir = pwd->pwd_jdir; - - startdir_used = 0; - dp = NULL; - cnp->cn_nameptr = cnp->cn_pnbuf; - if (cnp->cn_pnbuf[0] == '/') { - ndp->ni_resflags |= NIRES_ABS; - error = namei_handle_root(ndp, &dp); - } else { - if (ndp->ni_startdir != NULL) { - dp = ndp->ni_startdir; - startdir_used = 1; - } else if (ndp->ni_dirfd == AT_FDCWD) { - dp = pwd->pwd_cdir; - vrefact(dp); - } else { - rights = ndp->ni_rightsneeded; - cap_rights_set_one(&rights, CAP_LOOKUP); - - if (cnp->cn_flags & AUDITVNODE1) - AUDIT_ARG_ATFD1(ndp->ni_dirfd); - if (cnp->cn_flags & AUDITVNODE2) - AUDIT_ARG_ATFD2(ndp->ni_dirfd); - /* - * Effectively inlined fgetvp_rights, because we need to - * inspect the file as well as grabbing the vnode. - */ - error = fget_cap(td, ndp->ni_dirfd, &rights, - &dfp, &ndp->ni_filecaps); - if (error != 0) { - /* - * Preserve the error; it should either be EBADF - * or capability-related, both of which can be - * safely returned to the caller. - */ - } else { - if (dfp->f_ops == &badfileops) { - error = EBADF; - } else if (dfp->f_vnode == NULL) { - error = ENOTDIR; - } else { - dp = dfp->f_vnode; - vrefact(dp); - - if ((dfp->f_flag & FSEARCH) != 0) - cnp->cn_flags |= NOEXECCHECK; - } - fdrop(dfp, td); - } -#ifdef CAPABILITIES - /* - * If file descriptor doesn't have all rights, - * all lookups relative to it must also be - * strictly relative. - */ - CAP_ALL(&rights); - if (!cap_rights_contains(&ndp->ni_filecaps.fc_rights, - &rights) || - ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL || - ndp->ni_filecaps.fc_nioctls != -1) { - ndp->ni_lcf |= NI_LCF_STRICTRELATIVE; - } -#endif + error = cache_fplookup(ndp, &status, &pwd); + switch (status) { + case CACHE_FPL_STATUS_UNSET: + __assert_unreachable(); + break; + case CACHE_FPL_STATUS_HANDLED: + return (error); + case CACHE_FPL_STATUS_PARTIAL: + dp = ndp->ni_startdir; + break; + case CACHE_FPL_STATUS_ABORTED: + error = namei_setup(ndp, &dp, &pwd); + if (error != 0) { + namei_cleanup_cnp(cnp); + return (error); } - if (error == 0 && dp->v_type != VDIR) - error = ENOTDIR; - } - if (error == 0 && (cnp->cn_flags & BENEATH) != 0) { - if (ndp->ni_dirfd == AT_FDCWD) { - ndp->ni_beneath_latch = pwd->pwd_cdir; - vrefact(ndp->ni_beneath_latch); - } else { - rights = ndp->ni_rightsneeded; - cap_rights_set_one(&rights, CAP_LOOKUP); - error = fgetvp_rights(td, ndp->ni_dirfd, &rights, - &dirfd_caps, &ndp->ni_beneath_latch); - if (error == 0 && dp->v_type != VDIR) { - vrele(ndp->ni_beneath_latch); - error = ENOTDIR; - } - } - if (error == 0) - ndp->ni_lcf |= NI_LCF_LATCH; + break; } + /* - * If we are auditing the kernel pathname, save the user pathname. + * Locked lookup. */ - if (cnp->cn_flags & AUDITVNODE1) - AUDIT_ARG_UPATH1_VP(td, ndp->ni_rootdir, dp, cnp->cn_pnbuf); - if (cnp->cn_flags & AUDITVNODE2) - AUDIT_ARG_UPATH2_VP(td, ndp->ni_rootdir, dp, cnp->cn_pnbuf); - if (ndp->ni_startdir != NULL && !startdir_used) - vrele(ndp->ni_startdir); - if (error != 0) { - if (dp != NULL) - vrele(dp); - goto out; - } - MPASS((ndp->ni_lcf & (NI_LCF_BENEATH_ABS | NI_LCF_LATCH)) != - NI_LCF_BENEATH_ABS); - if (((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) != 0 && - lookup_cap_dotdot != 0) || - ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) == 0 && - (cnp->cn_flags & BENEATH) != 0)) - ndp->ni_lcf |= NI_LCF_CAP_DOTDOT; - SDT_PROBE3(vfs, namei, lookup, entry, dp, cnp->cn_pnbuf, - cnp->cn_flags); for (;;) { ndp->ni_startdir = dp; error = lookup(ndp); @@ -526,8 +577,8 @@ namei(struct nameidata *ndp) error = ENOTCAPABLE; } nameicap_cleanup(ndp, true); - SDT_PROBE2(vfs, namei, lookup, return, error, - (error == 0 ? ndp->ni_vp : NULL)); + SDT_PROBE3(vfs, namei, lookup, return, error, + (error == 0 ? ndp->ni_vp : NULL), false); pwd_drop(pwd); return (error); } @@ -602,7 +653,7 @@ namei(struct nameidata *ndp) MPASS(error != 0); namei_cleanup_cnp(cnp); nameicap_cleanup(ndp, true); - SDT_PROBE2(vfs, namei, lookup, return, error, NULL); + SDT_PROBE3(vfs, namei, lookup, return, error, NULL, false); pwd_drop(pwd); return (error); } diff --git a/sys/sys/namei.h b/sys/sys/namei.h index 602d7eff28b2..1fa20081a552 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -108,6 +108,12 @@ struct nameidata { }; #ifdef _KERNEL + +enum cache_fpl_status { CACHE_FPL_STATUS_ABORTED, CACHE_FPL_STATUS_PARTIAL, + CACHE_FPL_STATUS_HANDLED, CACHE_FPL_STATUS_UNSET }; +int cache_fplookup(struct nameidata *ndp, enum cache_fpl_status *status, + struct pwd **pwdp); + /* * namei operations */ From 9d5a594f0b7f5939834be10a8652837c6933344c Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 10:38:05 +0000 Subject: [PATCH 163/287] ufs: add support for lockless lookup ACLs are not supported, meaning their presence will force the use of the old lookup. Reviewed by: kib Tested by: pho (in a patchset) Differential Revision: https://reviews.freebsd.org/D25579 --- sys/ufs/ffs/ffs_vfsops.c | 22 +++++++-- sys/ufs/ffs/ffs_vnops.c | 8 +++- sys/ufs/ufs/inode.h | 10 ++++ sys/ufs/ufs/ufs_acl.c | 13 +++-- sys/ufs/ufs/ufs_vnops.c | 101 ++++++++++++++++++++++++++++++++++----- 5 files changed, 132 insertions(+), 22 deletions(-) diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 696be51ae6a0..8c69212d82e6 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -84,6 +84,7 @@ __FBSDID("$FreeBSD$"); #include static uma_zone_t uma_inode, uma_ufs1, uma_ufs2; +VFS_SMR_DECLARE; static int ffs_mountfs(struct vnode *, struct mount *, struct thread *); static void ffs_oldfscompat_read(struct fs *, struct ufsmount *, @@ -393,6 +394,7 @@ ffs_mount(struct mount *mp) uma_ufs2 = uma_zcreate("FFS2 dinode", sizeof(struct ufs2_dinode), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + VFS_SMR_ZONE_SET(uma_inode); } vfs_deleteopt(mp->mnt_optnew, "groupquota"); @@ -455,6 +457,7 @@ ffs_mount(struct mount *mp) } MNT_ILOCK(mp); + mp->mnt_kern_flag &= ~MNTK_FPLOOKUP; mp->mnt_flag |= mntorflags; MNT_IUNLOCK(mp); /* @@ -795,6 +798,17 @@ ffs_mount(struct mount *mp) } } } + + MNT_ILOCK(mp); + /* + * This is racy versus lookup, see ufs_fplookup_vexec for details. + */ + if ((mp->mnt_kern_flag & MNTK_FPLOOKUP) != 0) + panic("MNTK_FPLOOKUP set on mount %p when it should not be", mp); + if ((mp->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) + mp->mnt_kern_flag |= MNTK_FPLOOKUP; + MNT_IUNLOCK(mp); + vfs_mountedfrom(mp, fspec); return (0); } @@ -1968,14 +1982,14 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags) ump = VFSTOUFS(mp); fs = ump->um_fs; - ip = uma_zalloc(uma_inode, M_WAITOK | M_ZERO); + ip = uma_zalloc_smr(uma_inode, M_WAITOK | M_ZERO); /* Allocate a new vnode/inode. */ error = getnewvnode("ufs", mp, fs->fs_magic == FS_UFS1_MAGIC ? &ffs_vnodeops1 : &ffs_vnodeops2, &vp); if (error) { *vpp = NULL; - uma_zfree(uma_inode, ip); + uma_zfree_smr(uma_inode, ip); return (error); } /* @@ -2004,7 +2018,7 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags) vp->v_vflag |= VV_FORCEINSMQ; error = insmntque(vp, mp); if (error != 0) { - uma_zfree(uma_inode, ip); + uma_zfree_smr(uma_inode, ip); *vpp = NULL; return (error); } @@ -2327,7 +2341,7 @@ ffs_ifree(struct ufsmount *ump, struct inode *ip) uma_zfree(uma_ufs1, ip->i_din1); else if (ip->i_din2 != NULL) uma_zfree(uma_ufs2, ip->i_din2); - uma_zfree(uma_inode, ip); + uma_zfree_smr(uma_inode, ip); } static int dobkgrdwrite = 1; diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 000ded6cbbaa..c363f4bbb094 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -905,8 +905,10 @@ ffs_write(ap) if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid && ap->a_cred) { if (priv_check_cred(ap->a_cred, PRIV_VFS_RETAINSUGID)) { - ip->i_mode &= ~(ISUID | ISGID); + vn_seqc_write_begin(vp); + UFS_INODE_SET_MODE(ip, ip->i_mode & ~(ISUID | ISGID)); DIP_SET(ip, i_mode, ip->i_mode); + vn_seqc_write_end(vp); } } if (error) { @@ -1152,8 +1154,10 @@ ffs_extwrite(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *ucred) */ if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid && ucred) { if (priv_check_cred(ucred, PRIV_VFS_RETAINSUGID)) { - ip->i_mode &= ~(ISUID | ISGID); + vn_seqc_write_begin(vp); + UFS_INODE_SET_MODE(ip, ip->i_mode & ~(ISUID | ISGID)); dp->di_mode = ip->i_mode; + vn_seqc_write_end(vp); } } if (error) { diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h index defa888b17fe..15f60caae1f7 100644 --- a/sys/ufs/ufs/inode.h +++ b/sys/ufs/ufs/inode.h @@ -43,6 +43,7 @@ #include #include #include +#include /* * This must agree with the definition in . @@ -149,6 +150,14 @@ struct inode { #define UFS_INODE_FLAG_LAZY_MASK_ASSERTABLE \ (UFS_INODE_FLAG_LAZY_MASK & ~(IN_LAZYMOD | IN_LAZYACCESS)) +#define UFS_INODE_SET_MODE(ip, mode) do { \ + struct inode *_ip = (ip); \ + int _mode = (mode); \ + \ + ASSERT_VOP_IN_SEQC(ITOV(_ip)); \ + atomic_store_short(&(_ip)->i_mode, _mode); \ +} while (0) + #define UFS_INODE_SET_FLAG(ip, flags) do { \ struct inode *_ip = (ip); \ struct vnode *_vp = ITOV(_ip); \ @@ -229,6 +238,7 @@ struct indir { /* Convert between inode pointers and vnode pointers. */ #define VTOI(vp) ((struct inode *)(vp)->v_data) +#define VTOI_SMR(vp) ((struct inode *)vn_load_v_data_smr(vp)) #define ITOV(ip) ((ip)->i_vnode) /* Determine if soft dependencies are being done */ diff --git a/sys/ufs/ufs/ufs_acl.c b/sys/ufs/ufs/ufs_acl.c index cb077387ae9c..68e8ef91534e 100644 --- a/sys/ufs/ufs/ufs_acl.c +++ b/sys/ufs/ufs/ufs_acl.c @@ -139,9 +139,11 @@ ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl) void ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip) { + int newmode; - ip->i_mode &= ACL_PRESERVE_MASK; - ip->i_mode |= acl_posix1e_acl_to_mode(acl); + newmode = ip->i_mode & ACL_PRESERVE_MASK; + newmode |= acl_posix1e_acl_to_mode(acl); + UFS_INODE_SET_MODE(ip, newmode); DIP_SET(ip, i_mode, ip->i_mode); } @@ -381,7 +383,7 @@ int ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td) { int error; - mode_t mode; + mode_t mode, newmode; struct inode *ip = VTOI(vp); KASSERT(acl_nfs4_check(aclp, vp->v_type == VDIR) == 0, @@ -418,8 +420,9 @@ ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td) acl_nfs4_sync_mode_from_acl(&mode, aclp); - ip->i_mode &= ACL_PRESERVE_MASK; - ip->i_mode |= mode; + newmode = ip->i_mode & ACL_PRESERVE_MASK; + newmode |= mode; + UFS_INODE_SET_MODE(ip, newmode); DIP_SET(ip, i_mode, ip->i_mode); UFS_INODE_SET_FLAG(ip, IN_CHANGE); diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index 2e6aa283fc80..70dd7dbe86c1 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include @@ -96,10 +97,12 @@ FEATURE(suiddir, "Give all new files in directory the same ownership as the directory"); #endif +VFS_SMR_DECLARE; #include static vop_accessx_t ufs_accessx; +static vop_fplookup_vexec_t ufs_fplookup_vexec; static int ufs_chmod(struct vnode *, int, struct ucred *, struct thread *); static int ufs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct thread *); static vop_close_t ufs_close; @@ -422,6 +425,46 @@ ufs_accessx(ap) return (error); } +/* + * VOP_FPLOOKUP_VEXEC routines are subject to special circumstances, see + * the comment above cache_fplookup for details. + */ +static int +ufs_fplookup_vexec(ap) + struct vop_fplookup_vexec_args /* { + struct vnode *a_vp; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp; + struct inode *ip; + struct ucred *cred; + mode_t all_x, mode; + + vp = ap->a_vp; + ip = VTOI_SMR(vp); + if (__predict_false(ip == NULL)) + return (EAGAIN); + + /* + * XXX ACL race + * + * ACLs are not supported and UFS clears/sets this flag on mount and + * remount. However, we may still be racing with seeing them and there + * is no provision to make sure they were accounted for. This matches + * the behavior of the locked case, since the lookup there is also + * racy: mount takes no measures to block anyone from progressing. + */ + all_x = S_IXUSR | S_IXGRP | S_IXOTH; + mode = atomic_load_short(&ip->i_mode); + if (__predict_true((mode & all_x) == all_x)) + return (0); + + cred = ap->a_cred; + return (vaccess_vexec_smr(mode, ip->i_uid, ip->i_gid, cred)); +} + /* ARGSUSED */ static int ufs_getattr(ap) @@ -711,7 +754,7 @@ ufs_chmod(vp, mode, cred, td) struct thread *td; { struct inode *ip = VTOI(vp); - int error; + int newmode, error; /* * To modify the permissions on a file, must possess VADMIN @@ -744,8 +787,9 @@ ufs_chmod(vp, mode, cred, td) return (error); } - ip->i_mode &= ~ALLPERMS; - ip->i_mode |= (mode & ALLPERMS); + newmode = ip->i_mode & ~ALLPERMS; + newmode |= (mode & ALLPERMS); + UFS_INODE_SET_MODE(ip, newmode); DIP_SET(ip, i_mode, ip->i_mode); UFS_INODE_SET_FLAG(ip, IN_CHANGE); #ifdef UFS_ACL @@ -869,7 +913,7 @@ ufs_chown(vp, uid, gid, cred, td) UFS_INODE_SET_FLAG(ip, IN_CHANGE); if ((ip->i_mode & (ISUID | ISGID)) && (ouid != uid || ogid != gid)) { if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) { - ip->i_mode &= ~(ISUID | ISGID); + UFS_INODE_SET_MODE(ip, ip->i_mode & ~(ISUID | ISGID)); DIP_SET(ip, i_mode, ip->i_mode); } } @@ -1111,6 +1155,9 @@ ufs_rename(ap) int error = 0; struct mount *mp; ino_t ino; + bool want_seqc_end; + + want_seqc_end = false; #ifdef INVARIANTS if ((tcnp->cn_flags & HASBUF) == 0 || @@ -1315,6 +1362,13 @@ ufs_rename(ap) tdp->i_effnlink == 0) panic("Bad effnlink fip %p, fdp %p, tdp %p", fip, fdp, tdp); + if (tvp != NULL) + vn_seqc_write_begin(tvp); + vn_seqc_write_begin(tdvp); + vn_seqc_write_begin(fvp); + vn_seqc_write_begin(fdvp); + want_seqc_end = true; + /* * 1) Bump link count while we're moving stuff * around. If we crash somewhere before @@ -1513,6 +1567,14 @@ ufs_rename(ap) cache_purge_negative(tdvp); unlockout: + if (want_seqc_end) { + if (tvp != NULL) + vn_seqc_write_end(tvp); + vn_seqc_write_end(tdvp); + vn_seqc_write_end(fvp); + vn_seqc_write_end(fdvp); + } + vput(fdvp); vput(fvp); if (tvp) @@ -1556,6 +1618,14 @@ ufs_rename(ap) goto unlockout; releout: + if (want_seqc_end) { + if (tvp != NULL) + vn_seqc_write_end(tvp); + vn_seqc_write_end(tdvp); + vn_seqc_write_end(fvp); + vn_seqc_write_end(fdvp); + } + vrele(fdvp); vrele(fvp); vrele(tdvp); @@ -1590,7 +1660,7 @@ ufs_do_posix1e_acl_inheritance_dir(struct vnode *dvp, struct vnode *tvp, */ if (acl->acl_cnt != 0) { dmode = acl_posix1e_newfilemode(dmode, acl); - ip->i_mode = dmode; + UFS_INODE_SET_MODE(ip, dmode); DIP_SET(ip, i_mode, dmode); *dacl = *acl; ufs_sync_acl_from_inode(ip, acl); @@ -1602,7 +1672,7 @@ ufs_do_posix1e_acl_inheritance_dir(struct vnode *dvp, struct vnode *tvp, /* * Just use the mode as-is. */ - ip->i_mode = dmode; + UFS_INODE_SET_MODE(ip, dmode); DIP_SET(ip, i_mode, dmode); error = 0; goto out; @@ -1673,7 +1743,7 @@ ufs_do_posix1e_acl_inheritance_file(struct vnode *dvp, struct vnode *tvp, * the it's not defined case. */ mode = acl_posix1e_newfilemode(mode, acl); - ip->i_mode = mode; + UFS_INODE_SET_MODE(ip, mode); DIP_SET(ip, i_mode, mode); ufs_sync_acl_from_inode(ip, acl); break; @@ -1684,7 +1754,7 @@ ufs_do_posix1e_acl_inheritance_file(struct vnode *dvp, struct vnode *tvp, /* * Just use the mode as-is. */ - ip->i_mode = mode; + UFS_INODE_SET_MODE(ip, mode); DIP_SET(ip, i_mode, mode); error = 0; goto out; @@ -1796,6 +1866,7 @@ ufs_mkdir(ap) error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp); if (error) goto out; + vn_seqc_write_begin(tvp); ip = VTOI(tvp); ip->i_gid = dp->i_gid; DIP_SET(ip, i_gid, dp->i_gid); @@ -1846,6 +1917,7 @@ ufs_mkdir(ap) if (DOINGSOFTDEP(tvp)) softdep_revert_link(dp, ip); UFS_VFREE(tvp, ip->i_number, dmode); + vn_seqc_write_end(tvp); vgone(tvp); vput(tvp); return (error); @@ -1861,6 +1933,7 @@ ufs_mkdir(ap) if (DOINGSOFTDEP(tvp)) softdep_revert_link(dp, ip); UFS_VFREE(tvp, ip->i_number, dmode); + vn_seqc_write_end(tvp); vgone(tvp); vput(tvp); return (error); @@ -1868,7 +1941,7 @@ ufs_mkdir(ap) #endif #endif /* !SUIDDIR */ UFS_INODE_SET_FLAG(ip, IN_ACCESS | IN_CHANGE | IN_UPDATE); - ip->i_mode = dmode; + UFS_INODE_SET_MODE(ip, dmode); DIP_SET(ip, i_mode, dmode); tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ ip->i_effnlink = 2; @@ -1974,6 +2047,7 @@ ufs_mkdir(ap) bad: if (error == 0) { *ap->a_vpp = tvp; + vn_seqc_write_end(tvp); } else { dp->i_effnlink--; dp->i_nlink--; @@ -1989,6 +2063,7 @@ ufs_mkdir(ap) UFS_INODE_SET_FLAG(ip, IN_CHANGE); if (DOINGSOFTDEP(tvp)) softdep_revert_mkdir(dp, ip); + vn_seqc_write_end(tvp); vgone(tvp); vput(tvp); } @@ -2637,8 +2712,9 @@ ufs_makeinode(mode, dvp, vpp, cnp, callfunc) } #endif #endif /* !SUIDDIR */ + vn_seqc_write_begin(tvp); /* Mostly to cover asserts */ UFS_INODE_SET_FLAG(ip, IN_ACCESS | IN_CHANGE | IN_UPDATE); - ip->i_mode = mode; + UFS_INODE_SET_MODE(ip, mode); DIP_SET(ip, i_mode, mode); tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ ip->i_effnlink = 1; @@ -2648,7 +2724,7 @@ ufs_makeinode(mode, dvp, vpp, cnp, callfunc) softdep_setup_create(VTOI(dvp), ip); if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) && priv_check_cred(cnp->cn_cred, PRIV_VFS_SETGID)) { - ip->i_mode &= ~ISGID; + UFS_INODE_SET_MODE(ip, ip->i_mode & ~ISGID); DIP_SET(ip, i_mode, ip->i_mode); } @@ -2688,6 +2764,7 @@ ufs_makeinode(mode, dvp, vpp, cnp, callfunc) error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL, 0); if (error) goto bad; + vn_seqc_write_end(tvp); *vpp = tvp; return (0); @@ -2702,6 +2779,7 @@ ufs_makeinode(mode, dvp, vpp, cnp, callfunc) UFS_INODE_SET_FLAG(ip, IN_CHANGE); if (DOINGSOFTDEP(tvp)) softdep_revert_create(VTOI(dvp), ip); + vn_seqc_write_end(tvp); vgone(tvp); vput(tvp); return (error); @@ -2740,6 +2818,7 @@ struct vop_vector ufs_vnodeops = { .vop_write = VOP_PANIC, .vop_accessx = ufs_accessx, .vop_bmap = ufs_bmap, + .vop_fplookup_vexec = ufs_fplookup_vexec, .vop_cachedlookup = ufs_lookup, .vop_close = ufs_close, .vop_create = ufs_create, From 172ffe702cc682ee396fcc619274fd714c3d7d29 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 10:38:44 +0000 Subject: [PATCH 164/287] tmpfs: add support for lockless lookup Reviewed by: kib Tested by: pho (in a patchset) Differential Revision: https://reviews.freebsd.org/D25580 --- sys/fs/tmpfs/tmpfs.h | 3 ++ sys/fs/tmpfs/tmpfs_subr.c | 22 +++++++++----- sys/fs/tmpfs/tmpfs_vfsops.c | 2 ++ sys/fs/tmpfs/tmpfs_vnops.c | 57 +++++++++++++++++++++++++++++++++++-- sys/fs/tmpfs/tmpfs_vnops.h | 1 + 5 files changed, 76 insertions(+), 9 deletions(-) diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h index f94992dfc813..b15a83af7eba 100644 --- a/sys/fs/tmpfs/tmpfs.h +++ b/sys/fs/tmpfs/tmpfs.h @@ -526,6 +526,9 @@ VP_TO_TMPFS_NODE(struct vnode *vp) return (node); } +#define VP_TO_TMPFS_NODE_SMR(vp) \ + ((struct tmpfs_node *)vn_load_v_data_smr(vp)) + static inline struct tmpfs_node * VP_TO_TMPFS_DIR(struct vnode *vp) { diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index 06f5f9890749..55a6390f6833 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -75,6 +75,7 @@ static long tmpfs_pages_reserved = TMPFS_PAGES_MINRESERVED; static uma_zone_t tmpfs_dirent_pool; static uma_zone_t tmpfs_node_pool; +VFS_SMR_DECLARE; static int tmpfs_node_ctor(void *mem, int size, void *arg, int flags) @@ -131,6 +132,7 @@ tmpfs_subr_init(void) tmpfs_node_pool = uma_zcreate("TMPFS node", sizeof(struct tmpfs_node), tmpfs_node_ctor, tmpfs_node_dtor, tmpfs_node_init, tmpfs_node_fini, UMA_ALIGN_PTR, 0); + VFS_SMR_ZONE_SET(tmpfs_node_pool); } void @@ -288,7 +290,7 @@ tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount *tmp, enum vtype type, if ((mp->mnt_kern_flag & MNT_RDONLY) != 0) return (EROFS); - nnode = uma_zalloc_arg(tmpfs_node_pool, tmp, M_WAITOK); + nnode = uma_zalloc_smr(tmpfs_node_pool, M_WAITOK); /* Generic initialization. */ nnode->tn_type = type; @@ -435,7 +437,7 @@ tmpfs_free_node_locked(struct tmpfs_mount *tmp, struct tmpfs_node *node, panic("tmpfs_free_node: type %p %d", node, (int)node->tn_type); } - uma_zfree(tmpfs_node_pool, node); + uma_zfree_smr(tmpfs_node_pool, node); TMPFS_LOCK(tmp); tmpfs_free_tmp(tmp); return (true); @@ -1621,8 +1623,10 @@ tmpfs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred, struct thread *p) { int error; struct tmpfs_node *node; + mode_t newmode; ASSERT_VOP_ELOCKED(vp, "chmod"); + ASSERT_VOP_IN_SEQC(vp); node = VP_TO_TMPFS_NODE(vp); @@ -1656,9 +1660,9 @@ tmpfs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred, struct thread *p) return (error); } - - node->tn_mode &= ~ALLPERMS; - node->tn_mode |= mode & ALLPERMS; + newmode = node->tn_mode & ~ALLPERMS; + newmode |= mode & ALLPERMS; + atomic_store_short(&node->tn_mode, newmode); node->tn_status |= TMPFS_NODE_CHANGED; @@ -1682,8 +1686,10 @@ tmpfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, struct tmpfs_node *node; uid_t ouid; gid_t ogid; + mode_t newmode; ASSERT_VOP_ELOCKED(vp, "chown"); + ASSERT_VOP_IN_SEQC(vp); node = VP_TO_TMPFS_NODE(vp); @@ -1729,8 +1735,10 @@ tmpfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, node->tn_status |= TMPFS_NODE_CHANGED; if ((node->tn_mode & (S_ISUID | S_ISGID)) && (ouid != uid || ogid != gid)) { - if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) - node->tn_mode &= ~(S_ISUID | S_ISGID); + if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) { + newmode = node->tn_mode & ~(S_ISUID | S_ISGID); + atomic_store_short(&node->tn_mode, newmode); + } } ASSERT_VOP_ELOCKED(vp, "chown2"); diff --git a/sys/fs/tmpfs/tmpfs_vfsops.c b/sys/fs/tmpfs/tmpfs_vfsops.c index c36ec68f928d..fee923e61328 100644 --- a/sys/fs/tmpfs/tmpfs_vfsops.c +++ b/sys/fs/tmpfs/tmpfs_vfsops.c @@ -462,6 +462,8 @@ tmpfs_mount(struct mount *mp) mp->mnt_flag |= MNT_LOCAL; mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED | MNTK_TEXT_REFS | MNTK_NOMSYNC; + if (!nonc) + mp->mnt_kern_flag |= MNTK_FPLOOKUP; MNT_IUNLOCK(mp); mp->mnt_data = tmp; diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index a5e21bd1d882..c0d970edeb94 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -64,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include SYSCTL_DECL(_vfs_tmpfs); +VFS_SMR_DECLARE; static volatile int tmpfs_rename_restarts; SYSCTL_INT(_vfs_tmpfs, OID_AUTO, rename_restarts, CTLFLAG_RD, @@ -317,6 +319,32 @@ tmpfs_close(struct vop_close_args *v) return (0); } +/* + * VOP_FPLOOKUP_VEXEC routines are subject to special circumstances, see + * the comment above cache_fplookup for details. + */ +int +tmpfs_fplookup_vexec(struct vop_fplookup_vexec_args *v) +{ + struct vnode *vp; + struct tmpfs_node *node; + struct ucred *cred; + mode_t all_x, mode; + + vp = v->a_vp; + node = VP_TO_TMPFS_NODE_SMR(vp); + if (__predict_false(node == NULL)) + return (EAGAIN); + + all_x = S_IXUSR | S_IXGRP | S_IXOTH; + mode = atomic_load_short(&node->tn_mode); + if (__predict_true((mode & all_x) == all_x)) + return (0); + + cred = v->a_cred; + return (vaccess_vexec_smr(mode, node->tn_uid, node->tn_gid, cred)); +} + int tmpfs_access(struct vop_access_args *v) { @@ -427,6 +455,7 @@ tmpfs_setattr(struct vop_setattr_args *v) int error; MPASS(VOP_ISLOCKED(vp)); + ASSERT_VOP_IN_SEQC(vp); error = 0; @@ -497,6 +526,7 @@ tmpfs_write(struct vop_write_args *v) struct tmpfs_node *node; off_t oldsize; int error, ioflag; + mode_t newmode; vp = v->a_vp; uio = v->a_uio; @@ -527,8 +557,12 @@ tmpfs_write(struct vop_write_args *v) node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED; if (node->tn_mode & (S_ISUID | S_ISGID)) { - if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID)) - node->tn_mode &= ~(S_ISUID | S_ISGID); + if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID)) { + newmode = node->tn_mode & ~(S_ISUID | S_ISGID); + vn_seqc_write_begin(vp); + atomic_store_short(&node->tn_mode, newmode); + vn_seqc_write_end(vp); + } } if (error != 0) (void)tmpfs_reg_resize(vp, oldsize, TRUE); @@ -806,12 +840,15 @@ tmpfs_rename(struct vop_rename_args *v) struct tmpfs_node *tnode; struct tmpfs_node *tdnode; int error; + bool want_seqc_end; MPASS(VOP_ISLOCKED(tdvp)); MPASS(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp))); MPASS(fcnp->cn_flags & HASBUF); MPASS(tcnp->cn_flags & HASBUF); + want_seqc_end = false; + /* * Disallow cross-device renames. * XXX Why isn't this done by the caller? @@ -852,6 +889,13 @@ tmpfs_rename(struct vop_rename_args *v) } } + if (tvp != NULL) + vn_seqc_write_begin(tvp); + vn_seqc_write_begin(tdvp); + vn_seqc_write_begin(fvp); + vn_seqc_write_begin(fdvp); + want_seqc_end = true; + tmp = VFS_TO_TMPFS(tdvp->v_mount); tdnode = VP_TO_TMPFS_DIR(tdvp); tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp); @@ -1065,6 +1109,14 @@ tmpfs_rename(struct vop_rename_args *v) VOP_UNLOCK(fdvp); out: + if (want_seqc_end) { + if (tvp != NULL) + vn_seqc_write_end(tvp); + vn_seqc_write_end(tdvp); + vn_seqc_write_end(fvp); + vn_seqc_write_end(fdvp); + } + /* * Release target nodes. * XXX: I don't understand when tdvp can be the same as tvp, but @@ -1621,6 +1673,7 @@ struct vop_vector tmpfs_vnodeop_entries = { .vop_mknod = tmpfs_mknod, .vop_open = tmpfs_open, .vop_close = tmpfs_close, + .vop_fplookup_vexec = tmpfs_fplookup_vexec, .vop_access = tmpfs_access, .vop_getattr = tmpfs_getattr, .vop_setattr = tmpfs_setattr, diff --git a/sys/fs/tmpfs/tmpfs_vnops.h b/sys/fs/tmpfs/tmpfs_vnops.h index 2f89e15629dd..0fa9739c0bc6 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.h +++ b/sys/fs/tmpfs/tmpfs_vnops.h @@ -49,6 +49,7 @@ extern struct vop_vector tmpfs_vnodeop_entries; extern struct vop_vector tmpfs_vnodeop_nonc_entries; vop_access_t tmpfs_access; +vop_fplookup_vexec_t tmpfs_fplookup_vexec; vop_getattr_t tmpfs_getattr; vop_setattr_t tmpfs_setattr; vop_pathconf_t tmpfs_pathconf; From e4cdb74faf764f4cc9c668679858f6976ba5048b Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 10:39:41 +0000 Subject: [PATCH 165/287] zfs: add support for lockless lookup Tested by: pho (in a patchset, previous version) Differential Revision: https://reviews.freebsd.org/D25581 --- .../uts/common/fs/zfs/sys/zfs_znode.h | 2 + .../opensolaris/uts/common/fs/zfs/zfs_acl.c | 3 + .../uts/common/fs/zfs/zfs_vfsops.c | 3 + .../opensolaris/uts/common/fs/zfs/zfs_vnops.c | 49 +++++++++ .../opensolaris/uts/common/fs/zfs/zfs_znode.c | 100 ++++++++++++++++-- 5 files changed, 147 insertions(+), 10 deletions(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h index 19e8b34690b9..a95545bda4e1 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h @@ -246,6 +246,8 @@ VTOZ(vnode_t *vp) #define VTOZ(VP) ((znode_t *)(VP)->v_data) #endif +#define VTOZ_SMR(VP) ((znode_t *)vn_load_v_data_smr(VP)) + /* Called on entry to each ZFS vnode and vfs operation */ #define ZFS_ENTER(zfsvfs) \ { \ diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c index 6527b5878e60..a588c59b491c 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c @@ -1146,6 +1146,7 @@ zfs_acl_chown_setattr(znode_t *zp) ASSERT_VOP_ELOCKED(ZTOV(zp), __func__); ASSERT(MUTEX_HELD(&zp->z_acl_lock)); + ASSERT_VOP_IN_SEQC(ZTOV(zp)); if ((error = zfs_acl_node_read(zp, &aclp, B_FALSE)) == 0) zp->z_mode = zfs_mode_compute(zp->z_mode, aclp, @@ -1173,6 +1174,8 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) int count = 0; zfs_acl_phys_t acl_phys; + ASSERT_VOP_IN_SEQC(ZTOV(zp)); + mode = zp->z_mode; mode = zfs_mode_compute(mode, aclp, &zp->z_pflags, 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 17504e5118a9..fb6a40ac49b4 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 @@ -1391,6 +1391,9 @@ zfs_domount(vfs_t *vfsp, char *osname) vfsp->vfs_data = zfsvfs; vfsp->mnt_flag |= MNT_LOCAL; +#if defined(_KERNEL) && !defined(KMEM_DEBUG) + vfsp->mnt_kern_flag |= MNTK_FPLOOKUP; +#endif vfsp->mnt_kern_flag |= MNTK_LOOKUP_SHARED; vfsp->mnt_kern_flag |= MNTK_SHARED_WRITES; vfsp->mnt_kern_flag |= MNTK_EXTENDED_SHARED; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c index 3610cdaa323a..13f3412e96f5 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,8 @@ #include #include +VFS_SMR_DECLARE; + /* * Programming rules. * @@ -3698,6 +3701,7 @@ zfs_rename(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, char *snm = scnp->cn_nameptr; char *tnm = tcnp->cn_nameptr; int error = 0; + bool want_seqc_end = false; /* Reject renames across filesystems. */ if ((*svpp)->v_mount != tdvp->v_mount || @@ -3828,6 +3832,14 @@ zfs_rename(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, } } + vn_seqc_write_begin(*svpp); + vn_seqc_write_begin(sdvp); + if (*tvpp != NULL) + vn_seqc_write_begin(*tvpp); + if (tdvp != *tvpp) + vn_seqc_write_begin(tdvp); + want_seqc_end = true; + vnevent_rename_src(*svpp, sdvp, scnp->cn_nameptr, ct); if (tzp) vnevent_rename_dest(*tvpp, tdvp, tnm, ct); @@ -3914,10 +3926,20 @@ zfs_rename(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, unlockout: /* all 4 vnodes are locked, ZFS_ENTER called */ ZFS_EXIT(zfsvfs); + if (want_seqc_end) { + vn_seqc_write_end(*svpp); + vn_seqc_write_end(sdvp); + if (*tvpp != NULL) + vn_seqc_write_end(*tvpp); + if (tdvp != *tvpp) + vn_seqc_write_end(tdvp); + want_seqc_end = false; + } VOP_UNLOCK(*svpp); VOP_UNLOCK(sdvp); out: /* original two vnodes are locked */ + MPASS(!want_seqc_end); if (error == 0 && zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) zil_commit(zilog, 0); @@ -4861,6 +4883,31 @@ zfs_freebsd_write(ap) ap->a_cred, NULL)); } +/* + * VOP_FPLOOKUP_VEXEC routines are subject to special circumstances, see + * the comment above cache_fplookup for details. + */ +static int +zfs_freebsd_fplookup_vexec(struct vop_fplookup_vexec_args *v) +{ + vnode_t *vp; + znode_t *zp; + uint64_t pflags; + + vp = v->a_vp; + zp = VTOZ_SMR(vp); + if (__predict_false(zp == NULL)) + return (EAGAIN); + pflags = atomic_load_64(&zp->z_pflags); + if (pflags & ZFS_AV_QUARANTINED) + return (EAGAIN); + if (pflags & ZFS_XATTR) + return (EAGAIN); + if ((pflags & ZFS_NO_EXECS_DENIED) == 0) + return (EAGAIN); + return (0); +} + static int zfs_freebsd_access(ap) struct vop_access_args /* { @@ -5998,6 +6045,7 @@ struct vop_vector zfs_vnodeops = { .vop_inactive = zfs_freebsd_inactive, .vop_need_inactive = zfs_freebsd_need_inactive, .vop_reclaim = zfs_freebsd_reclaim, + .vop_fplookup_vexec = zfs_freebsd_fplookup_vexec, .vop_access = zfs_freebsd_access, .vop_allocate = VOP_EINVAL, .vop_lookup = zfs_cache_lookup, @@ -6066,6 +6114,7 @@ VFS_VOP_VECTOR_REGISTER(zfs_fifoops); */ struct vop_vector zfs_shareops = { .vop_default = &default_vnodeops, + .vop_fplookup_vexec = zfs_freebsd_fplookup_vexec, .vop_access = zfs_freebsd_access, .vop_inactive = zfs_freebsd_inactive, .vop_reclaim = zfs_freebsd_reclaim, 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 2c8a8b45d420..ecc11d16f42a 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 @@ -99,7 +99,12 @@ SYSCTL_INT(_debug_sizeof, OID_AUTO, znode, CTLFLAG_RD, */ krwlock_t zfsvfs_lock; +#if defined(_KERNEL) && !defined(KMEM_DEBUG) +#define _ZFS_USE_SMR +static uma_zone_t znode_uma_zone; +#else static kmem_cache_t *znode_cache = NULL; +#endif /*ARGSUSED*/ static void @@ -366,6 +371,51 @@ zfs_znode_move(void *buf, void *newbuf, size_t size, void *arg) } #endif /* illumos */ +#ifdef _ZFS_USE_SMR +VFS_SMR_DECLARE; + +static int +zfs_znode_cache_constructor_smr(void *mem, int size __unused, void *private, int flags) +{ + + return (zfs_znode_cache_constructor(mem, private, flags)); +} + +static void +zfs_znode_cache_destructor_smr(void *mem, int size __unused, void *private) +{ + + zfs_znode_cache_destructor(mem, private); +} + +void +zfs_znode_init(void) +{ + /* + * Initialize zcache + */ + rw_init(&zfsvfs_lock, NULL, RW_DEFAULT, NULL); + ASSERT(znode_uma_zone == NULL); + znode_uma_zone = uma_zcreate("zfs_znode_cache", + sizeof (znode_t), zfs_znode_cache_constructor_smr, + zfs_znode_cache_destructor_smr, NULL, NULL, 0, 0); + VFS_SMR_ZONE_SET(znode_uma_zone); +} + +static znode_t * +zfs_znode_alloc_kmem(int flags) +{ + + return (uma_zalloc_smr(znode_uma_zone, flags)); +} + +static void +zfs_znode_free_kmem(znode_t *zp) +{ + + uma_zfree_smr(znode_uma_zone, zp); +} +#else void zfs_znode_init(void) { @@ -380,6 +430,21 @@ zfs_znode_init(void) kmem_cache_set_move(znode_cache, zfs_znode_move); } +static znode_t * +zfs_znode_alloc_kmem(int flags) +{ + + return (kmem_cache_alloc(znode_cache, flags)); +} + +static void +zfs_znode_free_kmem(znode_t *zp) +{ + + kmem_cache_free(znode_cache, zp); +} +#endif + void zfs_znode_fini(void) { @@ -393,9 +458,17 @@ zfs_znode_fini(void) /* * Cleanup zcache */ - if (znode_cache) +#ifdef _ZFS_USE_SMR + if (znode_uma_zone) { + uma_zdestroy(znode_uma_zone); + znode_uma_zone = NULL; + } +#else + if (znode_cache) { kmem_cache_destroy(znode_cache); - znode_cache = NULL; + znode_cache = NULL; + } +#endif rw_destroy(&zfsvfs_lock); } @@ -508,7 +581,7 @@ zfs_create_share_dir(zfsvfs_t *zfsvfs, dmu_tx_t *tx) vattr.va_uid = crgetuid(kcred); vattr.va_gid = crgetgid(kcred); - sharezp = kmem_cache_alloc(znode_cache, KM_SLEEP); + sharezp = zfs_znode_alloc_kmem(KM_SLEEP); ASSERT(!POINTER_IS_VALID(sharezp->z_zfsvfs)); sharezp->z_moved = 0; sharezp->z_unlinked = 0; @@ -527,7 +600,7 @@ zfs_create_share_dir(zfsvfs_t *zfsvfs, dmu_tx_t *tx) zfs_acl_ids_free(&acl_ids); sa_handle_destroy(sharezp->z_sa_hdl); - kmem_cache_free(znode_cache, sharezp); + zfs_znode_free_kmem(sharezp); return (error); } @@ -642,13 +715,18 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, int count = 0; int error; - zp = kmem_cache_alloc(znode_cache, KM_SLEEP); + zp = zfs_znode_alloc_kmem(KM_SLEEP); + +#ifndef _ZFS_USE_SMR + KASSERT((zfsvfs->z_parent->z_vfs->mnt_kern_flag & MNTK_FPLOOKUP) == 0, + ("%s: fast path lookup enabled without smr", __func__)); +#endif KASSERT(curthread->td_vp_reserved != NULL, ("zfs_znode_alloc: getnewvnode without preallocated vnode")); error = getnewvnode("zfs", zfsvfs->z_parent->z_vfs, &zfs_vnodeops, &vp); if (error != 0) { - kmem_cache_free(znode_cache, zp); + zfs_znode_free_kmem(zp); return (NULL); } zp->z_vnode = vp; @@ -695,7 +773,7 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, sa_handle_destroy(zp->z_sa_hdl); zfs_vnode_forget(vp); zp->z_vnode = NULL; - kmem_cache_free(znode_cache, zp); + zfs_znode_free_kmem(zp); return (NULL); } @@ -1061,6 +1139,8 @@ zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx) xoap = xva_getxoptattr(xvap); ASSERT(xoap); + ASSERT_VOP_IN_SEQC(ZTOV(zp)); + if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) { uint64_t times[2]; ZFS_TIME_ENCODE(&xoap->xoa_createtime, times); @@ -1490,7 +1570,7 @@ zfs_znode_free(znode_t *zp) zp->z_acl_cached = NULL; } - kmem_cache_free(znode_cache, zp); + zfs_znode_free_kmem(zp); #ifdef illumos VFS_RELE(zfsvfs->z_vfs); @@ -1950,7 +2030,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx) zfsvfs = kmem_zalloc(sizeof (zfsvfs_t), KM_SLEEP); - rootzp = kmem_cache_alloc(znode_cache, KM_SLEEP); + rootzp = zfs_znode_alloc_kmem(KM_SLEEP); ASSERT(!POINTER_IS_VALID(rootzp->z_zfsvfs)); rootzp->z_moved = 0; rootzp->z_unlinked = 0; @@ -1994,7 +2074,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx) POINTER_INVALIDATE(&rootzp->z_zfsvfs); sa_handle_destroy(rootzp->z_sa_hdl); - kmem_cache_free(znode_cache, rootzp); + zfs_znode_free_kmem(rootzp); /* * Create shares directory From 9dbd12fb52668ee5730153cc9dffc4edfbf267d8 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 10:40:38 +0000 Subject: [PATCH 166/287] vfs: add support for !LOCKLEAF to lockless lookup Tested by: pho (in a patchset) Differential Revision: https://reviews.freebsd.org/D23916 --- sys/kern/vfs_cache.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 8984ee411fa6..16c493a1e39a 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -3029,10 +3029,6 @@ cache_can_fplookup(struct cache_fpl *fpl) cache_fpl_aborted(fpl); return (false); } - if ((cnp->cn_flags & LOCKLEAF) == 0) { - cache_fpl_aborted(fpl); - return (false); - } if (cnp->cn_nameiop != LOOKUP) { cache_fpl_aborted(fpl); return (false); @@ -3120,7 +3116,6 @@ cache_fplookup_final(struct cache_fpl *fpl) tvp_seqc = fpl->tvp_seqc; VNPASS(cache_fplookup_vnode_supported(dvp), dvp); - MPASS((cnp->cn_flags & LOCKLEAF) != 0); tvs = vget_prep_smr(tvp); if (tvs == VGET_NONE) { @@ -3135,13 +3130,20 @@ cache_fplookup_final(struct cache_fpl *fpl) cache_fpl_smr_exit(fpl); - error = vget_finish(tvp, cnp->cn_lkflags, tvs); - if (error != 0) { - return (cache_fpl_aborted(fpl)); + if ((cnp->cn_flags & LOCKLEAF) != 0) { + error = vget_finish(tvp, cnp->cn_lkflags, tvs); + if (error != 0) { + return (cache_fpl_aborted(fpl)); + } + } else { + vget_finish_ref(tvp, tvs); } if (!vn_seqc_consistent(tvp, tvp_seqc)) { - vput(tvp); + if ((cnp->cn_flags & LOCKLEAF) != 0) + vput(tvp); + else + vrele(tvp); return (cache_fpl_aborted(fpl)); } From 3024e8af1eba0abfac452ceb71d15d002a15520f Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Sat, 25 Jul 2020 11:34:50 +0000 Subject: [PATCH 167/287] Move Intel GAS to dev/iommu/ as now a part of generic iommu framework. Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25799 --- sys/conf/files.x86 | 2 +- sys/{x86/iommu/intel_gas.c => dev/iommu/iommu_gas.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename sys/{x86/iommu/intel_gas.c => dev/iommu/iommu_gas.c} (100%) diff --git a/sys/conf/files.x86 b/sys/conf/files.x86 index b5f68041246d..348ef57f8750 100644 --- a/sys/conf/files.x86 +++ b/sys/conf/files.x86 @@ -166,6 +166,7 @@ dev/imcsmb/imcsmb_pci.c optional imcsmb pci dev/intel/spi.c optional intelspi dev/io/iodev.c optional io dev/iommu/busdma_iommu.c optional acpi acpi_dmar pci +dev/iommu/iommu_gas.c optional acpi acpi_dmar pci dev/ipmi/ipmi.c optional ipmi dev/ipmi/ipmi_acpi.c optional ipmi acpi dev/ipmi/ipmi_isa.c optional ipmi isa @@ -304,7 +305,6 @@ x86/cpufreq/powernow.c optional cpufreq x86/iommu/intel_ctx.c optional acpi acpi_dmar pci x86/iommu/intel_drv.c optional acpi acpi_dmar pci x86/iommu/intel_fault.c optional acpi acpi_dmar pci -x86/iommu/intel_gas.c optional acpi acpi_dmar pci x86/iommu/intel_idpgtbl.c optional acpi acpi_dmar pci x86/iommu/intel_intrmap.c optional acpi acpi_dmar pci x86/iommu/intel_qi.c optional acpi acpi_dmar pci diff --git a/sys/x86/iommu/intel_gas.c b/sys/dev/iommu/iommu_gas.c similarity index 100% rename from sys/x86/iommu/intel_gas.c rename to sys/dev/iommu/iommu_gas.c From aba10e131fe7a9ea168af9ff9002e95559a2f80b Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sat, 25 Jul 2020 15:19:38 +0000 Subject: [PATCH 168/287] Allow swi_sched() to be called from NMI context. For purposes of handling hardware error reported via NMIs I need a way to escape NMI context, being too restrictive to do something significant. To do it this change introduces new swi_sched() flag SWI_FROMNMI, making it careful about used KPIs. On platforms allowing IPI sending from NMI context (x86 for now) it immediately wakes clk_intr_event via new IPI_SWI, otherwise it works just like SWI_DELAY. To handle the delayed SWIs this patch calls clk_intr_event on every hardclock() tick. MFC after: 2 weeks Sponsored by: iXsystems, Inc. Differential Revision: https://reviews.freebsd.org/D25754 --- share/man/man9/swi.9 | 11 +++++++++-- sys/amd64/amd64/apic_vector.S | 10 ++++++++++ sys/amd64/amd64/mp_machdep.c | 4 ++++ sys/amd64/include/smp.h | 1 + sys/i386/i386/apic_vector.s | 17 +++++++++++++++++ sys/i386/i386/mp_machdep.c | 4 ++++ sys/kern/kern_clock.c | 1 + sys/kern/kern_intr.c | 34 +++++++++++++++++++++++++++------- sys/sys/interrupt.h | 4 +++- sys/x86/include/apicvar.h | 3 ++- sys/x86/include/x86_smp.h | 2 ++ sys/x86/x86/mp_x86.c | 11 +++++++++++ sys/x86/xen/xen_apic.c | 11 +++++++++++ 13 files changed, 102 insertions(+), 11 deletions(-) diff --git a/share/man/man9/swi.9 b/share/man/man9/swi.9 index b9ac0ca47b8b..52a39fe61c86 100644 --- a/share/man/man9/swi.9 +++ b/share/man/man9/swi.9 @@ -23,7 +23,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 19, 2012 +.Dd July 25, 2020 .Dt SWI 9 .Os .Sh NAME @@ -132,7 +132,7 @@ The .Fa flags argument specifies how and when the handler should be run and is a mask of one or more of the following flags: -.Bl -tag -width SWI_DELAY +.Bl -tag -width SWI_FROMNMI .It Dv SWI_DELAY Specifies that the kernel should mark the specified handler as needing to run, but the kernel should not schedule the software interrupt thread to run. @@ -146,6 +146,13 @@ functionality performed by .Fn setdelayed in earlier versions of .Fx . +.It Dv SWI_FROMNMI +Specifies that +.Fn swi_sched +is called from NMI context and should be careful about used KPIs. +On platforms allowing IPI sending from NMI context it immediately wakes +.Va clk_intr_event +via the IPI, otherwise it works just like SWI_DELAY. .El .Pp The diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S index 8d73717b03b3..4de39283f92f 100644 --- a/sys/amd64/amd64/apic_vector.S +++ b/sys/amd64/amd64/apic_vector.S @@ -205,6 +205,16 @@ IDTVEC(spuriousint) call as_lapic_eoi jmp doreti +/* + * Executed by a CPU when it receives an IPI_SWI. + */ + INTR_HANDLER ipi_swi + call as_lapic_eoi + FAKE_MCOUNT(TF_RIP(%rsp)) + call ipi_swi_handler + MEXITCOUNT + jmp doreti + /* * Executed by a CPU when it receives a RENDEZVOUS IPI from another CPU. * diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index b4cc7ab829a4..d46362ba9f9c 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -223,6 +223,10 @@ cpu_mp_start(void) setidt(IPI_SUSPEND, pti ? IDTVEC(cpususpend_pti) : IDTVEC(cpususpend), SDT_SYSIGT, SEL_KPL, 0); + /* Install an IPI for calling delayed SWI */ + setidt(IPI_SWI, pti ? IDTVEC(ipi_swi_pti) : IDTVEC(ipi_swi), + SDT_SYSIGT, SEL_KPL, 0); + /* Set boot_cpu_id if needed. */ if (boot_cpu_id == -1) { boot_cpu_id = PCPU_GET(apic_id); diff --git a/sys/amd64/include/smp.h b/sys/amd64/include/smp.h index d5b5fa9c5b81..8fbd89da0e57 100644 --- a/sys/amd64/include/smp.h +++ b/sys/amd64/include/smp.h @@ -32,6 +32,7 @@ inthand_t IDTVEC(invlop_pti), IDTVEC(invlop), IDTVEC(ipi_intr_bitmap_handler_pti), + IDTVEC(ipi_swi_pti), IDTVEC(cpustop_pti), IDTVEC(cpususpend_pti), IDTVEC(rendezvous_pti); diff --git a/sys/i386/i386/apic_vector.s b/sys/i386/i386/apic_vector.s index 7587f6bb5f88..6c5f3667de71 100644 --- a/sys/i386/i386/apic_vector.s +++ b/sys/i386/i386/apic_vector.s @@ -308,6 +308,23 @@ IDTVEC(cpususpend) call *%eax jmp doreti +/* + * Executed by a CPU when it receives an IPI_SWI. + */ + .text + SUPERALIGN_TEXT +IDTVEC(ipi_swi) + PUSH_FRAME + SET_KERNEL_SREGS + cld + KENTER + call as_lapic_eoi + FAKE_MCOUNT(TF_EIP(%esp)) + movl $ipi_swi_handler, %eax + call *%eax + MEXITCOUNT + jmp doreti + /* * Executed by a CPU when it receives a RENDEZVOUS IPI from another CPU. * diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c index acdb40197433..8631d56f4854 100644 --- a/sys/i386/i386/mp_machdep.c +++ b/sys/i386/i386/mp_machdep.c @@ -188,6 +188,10 @@ cpu_mp_start(void) setidt(IPI_SUSPEND, IDTVEC(cpususpend), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* Install an IPI for calling delayed SWI */ + setidt(IPI_SWI, IDTVEC(ipi_swi), + SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + /* Set boot_cpu_id if needed. */ if (boot_cpu_id == -1) { boot_cpu_id = PCPU_GET(apic_id); diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index 1009ee1cd4b6..e91eac05a2dc 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -508,6 +508,7 @@ hardclock(int cnt, int usermode) if (i > 0 && i <= newticks) watchdog_fire(); } + intr_event_handle(clk_intr_event, NULL); } if (curcpu == CPU_FIRST()) cpu_tick_calibration(); diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c index 5c96f41eda8b..0e11af2123e2 100644 --- a/sys/kern/kern_intr.c +++ b/sys/kern/kern_intr.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #ifdef DDB #include @@ -85,6 +86,7 @@ struct intr_entropy { uintptr_t event; }; +struct intr_event *clk_intr_event; struct intr_event *tty_intr_event; void *vm_ih; struct proc *intrproc; @@ -1018,7 +1020,7 @@ swi_add(struct intr_event **eventp, const char *name, driver_intr_t handler, void *arg, int pri, enum intr_type flags, void **cookiep) { struct intr_event *ie; - int error; + int error = 0; if (flags & INTR_ENTROPY) return (EINVAL); @@ -1036,8 +1038,10 @@ swi_add(struct intr_event **eventp, const char *name, driver_intr_t handler, if (eventp != NULL) *eventp = ie; } - error = intr_event_add_handler(ie, name, NULL, handler, arg, - PI_SWI(pri), flags, cookiep); + if (handler != NULL) { + error = intr_event_add_handler(ie, name, NULL, handler, arg, + PI_SWI(pri), flags, cookiep); + } return (error); } @@ -1055,9 +1059,11 @@ swi_sched(void *cookie, int flags) CTR3(KTR_INTR, "swi_sched: %s %s need=%d", ie->ie_name, ih->ih_name, ih->ih_need); - entropy.event = (uintptr_t)ih; - entropy.td = curthread; - random_harvest_queue(&entropy, sizeof(entropy), RANDOM_SWI); + if ((flags & SWI_FROMNMI) == 0) { + entropy.event = (uintptr_t)ih; + entropy.td = curthread; + random_harvest_queue(&entropy, sizeof(entropy), RANDOM_SWI); + } /* * Set ih_need for this handler so that if the ithread is already @@ -1066,7 +1072,16 @@ swi_sched(void *cookie, int flags) */ ih->ih_need = 1; - if (!(flags & SWI_DELAY)) { + if (flags & SWI_DELAY) + return; + + if (flags & SWI_FROMNMI) { +#if defined(SMP) && (defined(__i386__) || defined(__amd64__)) + KASSERT(ie == clk_intr_event, + ("SWI_FROMNMI used not with clk_intr_event")); + ipi_self_from_nmi(IPI_SWI); +#endif + } else { VM_CNT_INC(v_soft); error = intr_event_schedule_thread(ie); KASSERT(error == 0, ("stray software interrupt")); @@ -1346,6 +1361,8 @@ intr_event_handle(struct intr_event *ie, struct trapframe *frame) CK_SLIST_FOREACH(ih, &ie->ie_handlers, ih_next) { if ((ih->ih_flags & IH_SUSP) != 0) continue; + if ((ie->ie_flags & IE_SOFT) != 0 && ih->ih_need == 0) + continue; if (ih->ih_filter == NULL) { thread = true; continue; @@ -1570,6 +1587,9 @@ static void start_softintr(void *dummy) { + if (swi_add(&clk_intr_event, "clk", NULL, NULL, SWI_CLOCK, + INTR_MPSAFE, NULL)) + panic("died while creating clk swi ithread"); if (swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, INTR_MPSAFE, &vm_ih)) panic("died while creating vm swi ithread"); } diff --git a/sys/sys/interrupt.h b/sys/sys/interrupt.h index 3492b17bf8d4..138e99495af2 100644 --- a/sys/sys/interrupt.h +++ b/sys/sys/interrupt.h @@ -133,7 +133,8 @@ struct intr_event { #define IE_SOFT 0x000001 /* Software interrupt. */ #define IE_ADDING_THREAD 0x000004 /* Currently building an ithread. */ -/* Flags to pass to sched_swi. */ +/* Flags to pass to swi_sched. */ +#define SWI_FROMNMI 0x1 #define SWI_DELAY 0x2 /* @@ -151,6 +152,7 @@ struct intr_event { struct proc; +extern struct intr_event *clk_intr_event; extern struct intr_event *tty_intr_event; extern void *vm_ih; diff --git a/sys/x86/include/apicvar.h b/sys/x86/include/apicvar.h index 866dafe6dca4..0f4961c1d631 100644 --- a/sys/x86/include/apicvar.h +++ b/sys/x86/include/apicvar.h @@ -130,7 +130,8 @@ #define IPI_STOP (APIC_IPI_INTS + 6) /* Stop CPU until restarted. */ #define IPI_SUSPEND (APIC_IPI_INTS + 7) /* Suspend CPU until restarted. */ -#define IPI_DYN_FIRST (APIC_IPI_INTS + 8) +#define IPI_SWI (APIC_IPI_INTS + 8) /* Run clk_intr_event. */ +#define IPI_DYN_FIRST (APIC_IPI_INTS + 9) #define IPI_DYN_LAST (254) /* IPIs allocated at runtime */ /* diff --git a/sys/x86/include/x86_smp.h b/sys/x86/include/x86_smp.h index e2b59a2b4703..e01f869a58f6 100644 --- a/sys/x86/include/x86_smp.h +++ b/sys/x86/include/x86_smp.h @@ -76,6 +76,7 @@ extern u_long *ipi_rendezvous_counts[MAXCPU]; /* IPI handlers */ inthand_t IDTVEC(ipi_intr_bitmap_handler), /* Bitmap based IPIs */ + IDTVEC(ipi_swi), /* Runs delayed SWI */ IDTVEC(cpustop), /* CPU stops & waits to be restarted */ IDTVEC(cpususpend), /* CPU suspends & waits to be resumed */ IDTVEC(rendezvous); /* handle CPU rendezvous */ @@ -96,6 +97,7 @@ void ipi_all_but_self(u_int ipi); void ipi_bitmap_handler(struct trapframe frame); void ipi_cpu(int cpu, u_int ipi); int ipi_nmi_handler(void); +void ipi_swi_handler(struct trapframe frame); void ipi_selected(cpuset_t cpus, u_int ipi); void ipi_self_from_nmi(u_int vector); void set_interrupt_apic_ids(void); diff --git a/sys/x86/x86/mp_x86.c b/sys/x86/x86/mp_x86.c index cfcbca53a1c9..df17cfd6b137 100644 --- a/sys/x86/x86/mp_x86.c +++ b/sys/x86/x86/mp_x86.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #ifdef GPROF #include #endif +#include #include #include #include @@ -1620,6 +1621,16 @@ cpususpend_handler(void) CPU_CLR_ATOMIC(cpu, &toresume_cpus); } +/* + * Handle an IPI_SWI by waking delayed SWI thread. + */ +void +ipi_swi_handler(struct trapframe frame) +{ + + intr_event_handle(clk_intr_event, &frame); +} + /* * This is called once the rest of the system is up and running and we're * ready to let the AP's out of the pen. diff --git a/sys/x86/xen/xen_apic.c b/sys/x86/xen/xen_apic.c index 7d23f0a50417..78471eb1d997 100644 --- a/sys/x86/xen/xen_apic.c +++ b/sys/x86/xen/xen_apic.c @@ -76,6 +76,7 @@ static driver_filter_t xen_invlcache; static driver_filter_t xen_ipi_bitmap_handler; static driver_filter_t xen_cpustop_handler; static driver_filter_t xen_cpususpend_handler; +static driver_filter_t xen_ipi_swi_handler; #endif /*---------------------------------- Macros ----------------------------------*/ @@ -103,6 +104,7 @@ static struct xen_ipi_handler xen_ipis[] = [IPI_TO_IDX(IPI_BITMAP_VECTOR)] = { xen_ipi_bitmap_handler, "b" }, [IPI_TO_IDX(IPI_STOP)] = { xen_cpustop_handler, "st" }, [IPI_TO_IDX(IPI_SUSPEND)] = { xen_cpususpend_handler, "sp" }, + [IPI_TO_IDX(IPI_SWI)] = { xen_ipi_swi_handler, "sw" }, }; #endif @@ -522,6 +524,15 @@ xen_cpususpend_handler(void *arg) return (FILTER_HANDLED); } +static int +xen_ipi_swi_handler(void *arg) +{ + struct trapframe *frame = arg; + + ipi_swi_handler(*frame); + return (FILTER_HANDLED); +} + /*----------------------------- XEN PV IPI setup -----------------------------*/ /* * Those functions are provided outside of the Xen PV APIC implementation From e914224af127f7c0520f2bc20b9970cf17dcbf67 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sat, 25 Jul 2020 15:34:29 +0000 Subject: [PATCH 169/287] fd: put back FILEDESC_SUNLOCK to pwd_hold lost during rebase Reported by: pho --- sys/kern/kern_descrip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 1f422bbf57c0..7533802d7168 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -3354,6 +3354,7 @@ pwd_hold(struct thread *td) FILEDESC_SLOCK(fdp); pwd = pwd_hold_filedesc(fdp); MPASS(pwd != NULL); + FILEDESC_SUNLOCK(fdp); return (pwd); } From 46da523a2bd4c34d5943aec122a9820945063859 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Sat, 25 Jul 2020 18:09:04 +0000 Subject: [PATCH 170/287] clean up whitespace... --- sys/dev/usb/net/if_ure.c | 24 ++++++++++++------------ sys/dev/usb/net/if_urereg.h | 24 ++++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/sys/dev/usb/net/if_ure.c b/sys/dev/usb/net/if_ure.c index bc30f6de87a7..c640b5ca26eb 100644 --- a/sys/dev/usb/net/if_ure.c +++ b/sys/dev/usb/net/if_ure.c @@ -239,7 +239,7 @@ ure_read_1(struct ure_softc *sc, uint16_t reg, uint16_t index) shift = (reg & 3) << 3; reg &= ~3; - + ure_read_mem(sc, reg, index, &temp, 4); val = UGETDW(temp); val >>= shift; @@ -385,7 +385,7 @@ ure_miibus_writereg(device_t dev, int phy, int reg, int val) locked = mtx_owned(&sc->sc_mtx); if (!locked) URE_LOCK(sc); - + ure_ocp_reg_write(sc, URE_OCP_BASE_MII + reg * 2, val); if (!locked) @@ -751,7 +751,7 @@ ure_init(struct usb_ether *ue) ure_write_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA, ure_read_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA) | URE_FMC_FCR_MCU_EN); - + /* Enable transmit and receive. */ ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, ure_read_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA) | URE_CR_RE | @@ -975,7 +975,7 @@ ure_rtl8152_init(struct ure_softc *sc) ure_read_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) | URE_RX_AGG_DISABLE); - /* Disable ALDPS. */ + /* Disable ALDPS. */ ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | URE_DIS_SDSAVE); uether_pause(&sc->sc_ue, hz / 50); @@ -1005,7 +1005,7 @@ ure_rtl8153_init(struct ure_softc *sc) ure_write_mem(sc, URE_USB_TOLERANCE, URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); - for (i = 0; i < URE_TIMEOUT; i++) { + for (i = 0; i < URE_TIMEOUT; i++) { if (ure_read_2(sc, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & URE_AUTOLOAD_DONE) break; @@ -1015,7 +1015,7 @@ ure_rtl8153_init(struct ure_softc *sc) device_printf(sc->sc_ue.ue_dev, "timeout waiting for chip autoload\n"); - for (i = 0; i < URE_TIMEOUT; i++) { + for (i = 0; i < URE_TIMEOUT; i++) { val = ure_ocp_reg_read(sc, URE_OCP_PHY_STATUS) & URE_PHY_STAT_MASK; if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) @@ -1025,7 +1025,7 @@ ure_rtl8153_init(struct ure_softc *sc) if (i == URE_TIMEOUT) device_printf(sc->sc_ue.ue_dev, "timeout waiting for phy to stabilize\n"); - + ure_write_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, ure_read_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB) & ~URE_U2P3_ENABLE); @@ -1057,7 +1057,7 @@ ure_rtl8153_init(struct ure_softc *sc) ure_write_1(sc, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, ure_read_1(sc, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB) | URE_EP4_FULL_FC); - + ure_write_2(sc, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, ure_read_2(sc, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB) & ~URE_TIMER11_EN); @@ -1065,7 +1065,7 @@ ure_rtl8153_init(struct ure_softc *sc) ure_write_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, ure_read_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & ~URE_LED_MODE_MASK); - + if ((sc->sc_chip & URE_CHIP_VER_5C10) && usbd_get_speed(sc->sc_ue.ue_udev) != USB_SPEED_SUPER) val = URE_LPM_TIMER_500MS; @@ -1112,7 +1112,7 @@ ure_rtl8153_init(struct ure_softc *sc) ure_write_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); memset(u1u2, 0x00, sizeof(u1u2)); - ure_write_mem(sc, URE_USB_TOLERANCE, + ure_write_mem(sc, URE_USB_TOLERANCE, URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); /* Disable ALDPS. */ @@ -1162,7 +1162,7 @@ ure_disable_teredo(struct ure_softc *sc) { ure_write_4(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, - ure_read_4(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & + ure_read_4(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN)); ure_write_2(sc, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, URE_WDT6_SET_MODE); @@ -1194,7 +1194,7 @@ ure_init_fifo(struct ure_softc *sc) } if (sc->sc_chip & URE_CHIP_VER_5C00) { ure_ocp_reg_write(sc, URE_OCP_EEE_CFG, - ure_ocp_reg_read(sc, URE_OCP_EEE_CFG) & + ure_ocp_reg_read(sc, URE_OCP_EEE_CFG) & ~URE_CTAP_SHORT_EN); } ure_ocp_reg_write(sc, URE_OCP_POWER_CFG, diff --git a/sys/dev/usb/net/if_urereg.h b/sys/dev/usb/net/if_urereg.h index cc70093f3117..d7c024c1acc4 100644 --- a/sys/dev/usb/net/if_urereg.h +++ b/sys/dev/usb/net/if_urereg.h @@ -195,19 +195,19 @@ #define URE_CRWECR_CONFIG 0xc0 /* PLA_OOB_CTRL */ -#define URE_NOW_IS_OOB 0x80 -#define URE_TXFIFO_EMPTY 0x20 -#define URE_RXFIFO_EMPTY 0x10 -#define URE_LINK_LIST_READY 0x02 -#define URE_DIS_MCU_CLROOB 0x01 +#define URE_NOW_IS_OOB 0x80 +#define URE_TXFIFO_EMPTY 0x20 +#define URE_RXFIFO_EMPTY 0x10 +#define URE_LINK_LIST_READY 0x02 +#define URE_DIS_MCU_CLROOB 0x01 #define URE_FIFO_EMPTY (URE_TXFIFO_EMPTY | URE_RXFIFO_EMPTY) /* PLA_MISC_1 */ -#define URE_RXDY_GATED_EN 0x0008 +#define URE_RXDY_GATED_EN 0x0008 /* PLA_SFF_STS_7 */ -#define URE_RE_INIT_LL 0x8000 -#define URE_MCU_BORW_EN 0x4000 +#define URE_RE_INIT_LL 0x8000 +#define URE_MCU_BORW_EN 0x4000 /* PLA_CPCR */ #define URE_CPCR_RX_VLAN 0x0040 @@ -344,14 +344,14 @@ #define URE_SEL_RXIDLE 0x0100 /* OCP_ALDPS_CONFIG */ -#define URE_ENPWRSAVE 0x8000 -#define URE_ENPDNPS 0x0200 -#define URE_LINKENA 0x0100 +#define URE_ENPWRSAVE 0x8000 +#define URE_ENPDNPS 0x0200 +#define URE_LINKENA 0x0100 #define URE_DIS_SDSAVE 0x0010 /* OCP_PHY_STATUS */ #define URE_PHY_STAT_MASK 0x0007 -#define URE_PHY_STAT_LAN_ON 3 +#define URE_PHY_STAT_LAN_ON 3 #define URE_PHY_STAT_PWRDN 5 /* OCP_POWER_CFG */ From 00fd73d2dabdee2638203dd1145f007787f05be9 Mon Sep 17 00:00:00 2001 From: Doug Moore Date: Sat, 25 Jul 2020 18:29:10 +0000 Subject: [PATCH 171/287] Fix an overflow bug in the blist allocator that needlessly capped max swap size by dividing a value, which was always a multiple of 64, by 64. Remove the code that reduced max swap size down to that cap. Eliminate the distinction between BLIST_BMAP_RADIX and BLIST_META_RADIX. Call them both BLIST_RADIX. Make improvments to the blist self-test code to silence compiler warnings and to test larger blists. Reported by: jmallett Reviewed by: alc Discussed with: kib Tested by: pho Differential Revision: https://reviews.freebsd.org/D25736 --- sys/kern/subr_blist.c | 221 +++++++++++++++++++++--------------------- sys/sys/blist.h | 5 +- sys/vm/swap_pager.c | 15 +-- 3 files changed, 115 insertions(+), 126 deletions(-) diff --git a/sys/kern/subr_blist.c b/sys/kern/subr_blist.c index c98744615ec9..0479ebc99e5d 100644 --- a/sys/kern/subr_blist.c +++ b/sys/kern/subr_blist.c @@ -36,15 +36,14 @@ * * A radix tree controls access to pieces of the bitmap, and includes * auxiliary information at each interior node about the availabilty of - * contiguous free blocks in the subtree rooted at that node. Two radix - * constants are involved: one for the size of the bitmaps contained in the - * leaf nodes (BLIST_BMAP_RADIX), and one for the number of descendents of - * each of the meta (interior) nodes (BLIST_META_RADIX). Each subtree is - * associated with a range of blocks. The root of any subtree stores a - * hint field that defines an upper bound on the size of the largest - * allocation that can begin in the associated block range. A hint is an - * upper bound on a potential allocation, but not necessarily a tight upper - * bound. + * contiguous free blocks in the subtree rooted at that node. A radix + * constant defines the size of the bitmaps contained in a leaf node + * and the number of descendents of each of the meta (interior) nodes. + * Each subtree is associated with a range of blocks. The root of any + * subtree stores a hint field that defines an upper bound on the size + * of the largest allocation that can begin in the associated block + * range. A hint is an upper bound on a potential allocation, but not + * necessarily a tight upper bound. * * The bitmap field in each node directs the search for available blocks. * For a leaf node, a bit is set if the corresponding block is free. For a @@ -64,17 +63,16 @@ * * LAYOUT: The radix tree is laid out recursively using a linear array. * Each meta node is immediately followed (laid out sequentially in - * memory) by BLIST_META_RADIX lower level nodes. This is a recursive + * memory) by BLIST_RADIX lower-level nodes. This is a recursive * structure but one that can be easily scanned through a very simple * 'skip' calculation. The memory allocation is only large enough to * cover the number of blocks requested at creation time. Nodes that * represent blocks beyond that limit, nodes that would never be read * or written, are not allocated, so that the last of the - * BLIST_META_RADIX lower level nodes of a some nodes may not be - * allocated. + * BLIST_RADIX lower-level nodes of a some nodes may not be allocated. * * NOTE: the allocator cannot currently allocate more than - * BLIST_BMAP_RADIX blocks per call. It will panic with 'allocation too + * BLIST_RADIX blocks per call. It will panic with 'allocation too * large' if you try. This is an area that could use improvement. The * radix is large enough that this restriction does not effect the swap * system, though. Currently only the allocation code is affected by @@ -152,24 +150,19 @@ static void blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, static MALLOC_DEFINE(M_SWAP, "SWAP", "Swap space"); #endif -_Static_assert(BLIST_BMAP_RADIX % BLIST_META_RADIX == 0, - "radix divisibility error"); -#define BLIST_BMAP_MASK (BLIST_BMAP_RADIX - 1) -#define BLIST_META_MASK (BLIST_META_RADIX - 1) +#define BLIST_MASK (BLIST_RADIX - 1) /* * For a subtree that can represent the state of up to 'radix' blocks, the - * number of leaf nodes of the subtree is L=radix/BLIST_BMAP_RADIX. If 'm' - * is short for BLIST_META_RADIX, then for a tree of height h with L=m**h + * number of leaf nodes of the subtree is L=radix/BLIST_RADIX. If 'm' + * is short for BLIST_RADIX, then for a tree of height h with L=m**h * leaf nodes, the total number of tree nodes is 1 + m + m**2 + ... + m**h, * or, equivalently, (m**(h+1)-1)/(m-1). This quantity is called 'skip' * in the 'meta' functions that process subtrees. Since integer division * discards remainders, we can express this computation as * skip = (m * m**h) / (m - 1) - * skip = (m * (radix / BLIST_BMAP_RADIX)) / (m - 1) - * and since m divides BLIST_BMAP_RADIX, we can simplify further to - * skip = (radix / (BLIST_BMAP_RADIX / m)) / (m - 1) - * skip = radix / ((BLIST_BMAP_RADIX / m) * (m - 1)) + * skip = (m * (radix / m)) / (m - 1) + * skip = radix / (m - 1) * so that simple integer division by a constant can safely be used for the * calculation. */ @@ -177,8 +170,7 @@ static inline daddr_t radix_to_skip(daddr_t radix) { - return (radix / - ((BLIST_BMAP_RADIX / BLIST_META_RADIX) * BLIST_META_MASK)); + return (radix / BLIST_MASK); } /* @@ -189,7 +181,7 @@ bitrange(int n, int count) { return (((u_daddr_t)-1 << n) & - ((u_daddr_t)-1 >> (BLIST_BMAP_RADIX - (n + count)))); + ((u_daddr_t)-1 >> (BLIST_RADIX - (n + count)))); } /* @@ -201,7 +193,7 @@ generic_bitpos(u_daddr_t mask) int hi, lo, mid; lo = 0; - hi = BLIST_BMAP_RADIX; + hi = BLIST_RADIX; while (lo + 1 < hi) { mid = (lo + hi) >> 1; if (mask & bitrange(0, mid)) @@ -238,7 +230,7 @@ bitpos(u_daddr_t mask) * flags - malloc flags * * The smallest blist consists of a single leaf node capable of - * managing BLIST_BMAP_RADIX blocks. + * managing BLIST_RADIX blocks. */ blist_t blist_create(daddr_t blocks, int flags) @@ -252,11 +244,8 @@ blist_create(daddr_t blocks, int flags) * Calculate the radix and node count used for scanning. */ nodes = 1; - radix = BLIST_BMAP_RADIX; - while (radix <= blocks) { - nodes += 1 + (blocks - 1) / radix; - radix *= BLIST_META_RADIX; - } + for (radix = 1; radix <= blocks / BLIST_RADIX; radix *= BLIST_RADIX) + nodes += 1 + (blocks - 1) / radix / BLIST_RADIX; bl = malloc(offsetof(struct blist, bl_root[nodes]), M_SWAP, flags | M_ZERO); @@ -549,19 +538,12 @@ blist_stats(blist_t bl, struct sbuf *s) init_gap_stats(stats); nodes = 0; - i = bl->bl_radix; - while (i < bl->bl_radix + bl->bl_blocks) { - /* - * Find max size subtree starting at i. - */ - radix = BLIST_BMAP_RADIX; - while (((i / radix) & BLIST_META_MASK) == 0) - radix *= BLIST_META_RADIX; - + radix = bl->bl_radix; + for (i = 0; i < bl->bl_blocks; ) { /* * Check for skippable subtrees starting at i. */ - while (radix > BLIST_BMAP_RADIX) { + while (radix != 1) { if (bl->bl_root[nodes].bm_bitmap == 0) { if (gap_stats_counting(stats)) update_gap_stats(stats, i); @@ -572,9 +554,9 @@ blist_stats(blist_t bl, struct sbuf *s) * Skip subtree root. */ nodes++; - radix /= BLIST_META_RADIX; + radix /= BLIST_RADIX; } - if (radix == BLIST_BMAP_RADIX) { + if (radix == 1) { /* * Scan leaf. */ @@ -588,8 +570,16 @@ blist_stats(blist_t bl, struct sbuf *s) diff ^= bitrange(digit, 1); } } - nodes += radix_to_skip(radix); - i += radix; + nodes += radix_to_skip(radix * BLIST_RADIX); + i += radix * BLIST_RADIX; + + /* + * Find max size subtree starting at i. + */ + for (radix = 1; + ((i / BLIST_RADIX / radix) & BLIST_MASK) == 0; + radix *= BLIST_RADIX) + ; } update_gap_stats(stats, i); dump_gap_stats(stats, s); @@ -623,13 +613,13 @@ blst_next_leaf_alloc(blmeta_t *scan, daddr_t start, int count, int maxcount) daddr_t blk; int avail, digit; - start += BLIST_BMAP_RADIX; - for (blk = start; blk - start < maxcount; blk += BLIST_BMAP_RADIX) { + start += BLIST_RADIX; + for (blk = start; blk - start < maxcount; blk += BLIST_RADIX) { /* Skip meta-nodes, as long as they promise more free blocks. */ - radix = BLIST_BMAP_RADIX; + radix = BLIST_RADIX; while (((++scan)->bm_bitmap & 1) == 1 && - ((blk / radix) & BLIST_META_MASK) == 0) - radix *= BLIST_META_RADIX; + ((blk / radix) & BLIST_MASK) == 0) + radix *= BLIST_RADIX; if (~scan->bm_bitmap != 0) { /* * Either there is no next leaf with any free blocks, @@ -647,39 +637,37 @@ blst_next_leaf_alloc(blmeta_t *scan, daddr_t start, int count, int maxcount) return (avail); } maxcount = imin(avail, maxcount); - if (maxcount % BLIST_BMAP_RADIX == 0) { + if (maxcount % BLIST_RADIX == 0) { /* * There was no next leaf. Back scan up to * last leaf. */ - --scan; - while (radix != BLIST_BMAP_RADIX) { - radix /= BLIST_META_RADIX; + do { + radix /= BLIST_RADIX; --scan; - } - blk -= BLIST_BMAP_RADIX; + } while (radix != 1); + blk -= BLIST_RADIX; } } } /* * 'scan' is the last leaf that provides blocks. Clear from 1 to - * BLIST_BMAP_RADIX bits to represent the allocation of those last - * blocks. + * BLIST_RADIX bits to represent the allocation of those last blocks. */ - if (maxcount % BLIST_BMAP_RADIX != 0) - scan->bm_bitmap &= ~bitrange(0, maxcount % BLIST_BMAP_RADIX); + if (maxcount % BLIST_RADIX != 0) + scan->bm_bitmap &= ~bitrange(0, maxcount % BLIST_RADIX); else scan->bm_bitmap = 0; for (;;) { /* Back up over meta-nodes, clearing bits if necessary. */ - blk -= BLIST_BMAP_RADIX; - radix = BLIST_BMAP_RADIX; - while ((digit = ((blk / radix) & BLIST_META_MASK)) == 0) { + blk -= BLIST_RADIX; + for (radix = BLIST_RADIX; + (digit = ((blk / radix) & BLIST_MASK)) == 0; + radix *= BLIST_RADIX) { if ((scan--)->bm_bitmap == 0) scan->bm_bitmap ^= 1; - radix *= BLIST_META_RADIX; } if ((scan--)->bm_bitmap == 0) scan[-digit * radix_to_skip(radix)].bm_bitmap ^= @@ -734,17 +722,17 @@ blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int *count, int maxcount) } /* Discard any candidates that appear before blk. */ - if ((blk & BLIST_BMAP_MASK) != 0) { - if ((~mask & bitrange(0, blk & BLIST_BMAP_MASK)) != 0) { + if ((blk & BLIST_MASK) != 0) { + if ((~mask & bitrange(0, blk & BLIST_MASK)) != 0) { /* Grow bighint in case all discarded bits are set. */ - bighint += blk & BLIST_BMAP_MASK; - mask |= bitrange(0, blk & BLIST_BMAP_MASK); + bighint += blk & BLIST_MASK; + mask |= bitrange(0, blk & BLIST_MASK); if (~mask == 0) { scan->bm_bighint = bighint; return (SWAPBLK_NONE); } } - blk -= blk & BLIST_BMAP_MASK; + blk -= blk & BLIST_MASK; } /* @@ -763,17 +751,17 @@ blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int *count, int maxcount) hi = lo + maxcount; *count = hi - lo; mask = ~bitrange(lo, *count); - } else if (maxcount <= BLIST_BMAP_RADIX - lo) { + } else if (maxcount <= BLIST_RADIX - lo) { /* All the blocks we can use are available here. */ hi = lo + maxcount; *count = maxcount; mask = ~bitrange(lo, *count); - if (hi == BLIST_BMAP_RADIX) + if (hi == BLIST_RADIX) scan->bm_bighint = bighint; } else { /* Check next leaf for some of the blocks we want or need. */ - count1 = *count - (BLIST_BMAP_RADIX - lo); - maxcount -= BLIST_BMAP_RADIX - lo; + count1 = *count - (BLIST_RADIX - lo); + maxcount -= BLIST_RADIX - lo; hi = blst_next_leaf_alloc(scan, blk, count1, maxcount); if (hi < count1) /* @@ -785,7 +773,7 @@ blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int *count, int maxcount) * this leaf. */ return (SWAPBLK_NONE); - *count = BLIST_BMAP_RADIX - lo + hi; + *count = BLIST_RADIX - lo + hi; scan->bm_bighint = bighint; } @@ -811,16 +799,15 @@ blst_meta_alloc(blmeta_t *scan, daddr_t cursor, int *count, bool scan_from_start; int digit; - if (radix == BLIST_BMAP_RADIX) + if (radix == 1) return (blst_leaf_alloc(scan, cursor, count, maxcount)); - blk = cursor & -radix; + blk = cursor & -(radix * BLIST_RADIX); scan_from_start = (cursor == blk); - radix /= BLIST_META_RADIX; skip = radix_to_skip(radix); mask = scan->bm_bitmap; /* Discard any candidates that appear before cursor. */ - digit = (cursor / radix) & BLIST_META_MASK; + digit = (cursor / radix) & BLIST_MASK; mask &= (u_daddr_t)-1 << digit; if (mask == 0) return (SWAPBLK_NONE); @@ -846,7 +833,7 @@ blst_meta_alloc(blmeta_t *scan, daddr_t cursor, int *count, * The allocation might fit beginning in the i'th subtree. */ r = blst_meta_alloc(&scan[i], cursor + digit * radix, - count, maxcount, radix); + count, maxcount, radix / BLIST_RADIX); if (r != SWAPBLK_NONE) { if (scan[i].bm_bitmap == 0) scan->bm_bitmap ^= bitrange(digit, 1); @@ -860,7 +847,7 @@ blst_meta_alloc(blmeta_t *scan, daddr_t cursor, int *count, * We couldn't allocate count in this subtree. If the whole tree was * scanned, and the last tree node is allocated, update bighint. */ - if (scan_from_start && !(digit == BLIST_META_RADIX - 1 && + if (scan_from_start && !(digit == BLIST_RADIX - 1 && scan[i].bm_bighint == BLIST_MAX_ALLOC)) scan->bm_bighint = *count - 1; @@ -882,7 +869,7 @@ blst_leaf_free(blmeta_t *scan, daddr_t blk, int count) * \_________/\__/ * count n */ - mask = bitrange(blk & BLIST_BMAP_MASK, count); + mask = bitrange(blk & BLIST_MASK, count); KASSERT((scan->bm_bitmap & mask) == 0, ("freeing free block: %jx, size %d, mask %jx", (uintmax_t)blk, count, (uintmax_t)scan->bm_bitmap & mask)); @@ -913,20 +900,26 @@ blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, u_daddr_t radix) */ scan->bm_bighint = BLIST_MAX_ALLOC; - if (radix == BLIST_BMAP_RADIX) + if (radix == 1) return (blst_leaf_free(scan, freeBlk, count)); - endBlk = ummin(freeBlk + count, (freeBlk + radix) & -radix); - radix /= BLIST_META_RADIX; + endBlk = freeBlk + count; + blk = (freeBlk + radix * BLIST_RADIX) & -(radix * BLIST_RADIX); + /* + * blk is first block past the end of the range of this meta node, + * or 0 in case of overflow. + */ + if (blk != 0) + endBlk = ummin(endBlk, blk); skip = radix_to_skip(radix); blk = freeBlk & -radix; - digit = (blk / radix) & BLIST_META_MASK; - endDigit = 1 + (((endBlk - 1) / radix) & BLIST_META_MASK); + digit = (blk / radix) & BLIST_MASK; + endDigit = 1 + (((endBlk - 1) / radix) & BLIST_MASK); scan->bm_bitmap |= bitrange(digit, endDigit - digit); for (i = 1 + digit * skip; blk < endBlk; i += skip) { blk += radix; count = ummin(blk, endBlk) - freeBlk; - blst_meta_free(&scan[i], freeBlk, count, radix); + blst_meta_free(&scan[i], freeBlk, count, radix / BLIST_RADIX); freeBlk = blk; } } @@ -947,7 +940,7 @@ blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, blist_t dest, * Leaf node */ - if (radix == BLIST_BMAP_RADIX) { + if (radix == 1) { u_daddr_t v = scan->bm_bitmap; if (v == (u_daddr_t)-1) { @@ -975,14 +968,14 @@ blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, blist_t dest, } endBlk = blk + count; - radix /= BLIST_META_RADIX; skip = radix_to_skip(radix); for (i = 1; blk < endBlk; i += skip) { blk += radix; count = radix; if (blk >= endBlk) count -= blk - endBlk; - blst_copy(&scan[i], blk - radix, radix, dest, count); + blst_copy(&scan[i], blk - radix, + radix / BLIST_RADIX, dest, count); } } @@ -999,7 +992,7 @@ blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count) daddr_t nblks; u_daddr_t mask; - mask = bitrange(blk & BLIST_BMAP_MASK, count); + mask = bitrange(blk & BLIST_MASK, count); /* Count the number of blocks that we are allocating. */ nblks = bitcount64(scan->bm_bitmap & mask); @@ -1022,20 +1015,27 @@ blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, u_daddr_t radix) daddr_t blk, endBlk, i, nblks, skip; int digit; - if (radix == BLIST_BMAP_RADIX) + if (radix == 1) return (blst_leaf_fill(scan, allocBlk, count)); - endBlk = ummin(allocBlk + count, (allocBlk + radix) & -radix); - radix /= BLIST_META_RADIX; + endBlk = allocBlk + count; + blk = (allocBlk + radix * BLIST_RADIX) & -(radix * BLIST_RADIX); + /* + * blk is first block past the end of the range of this meta node, + * or 0 in case of overflow. + */ + if (blk != 0) + endBlk = ummin(endBlk, blk); skip = radix_to_skip(radix); blk = allocBlk & -radix; nblks = 0; while (blk < endBlk) { - digit = (blk / radix) & BLIST_META_MASK; + digit = (blk / radix) & BLIST_MASK; i = 1 + digit * skip; blk += radix; count = ummin(blk, endBlk) - allocBlk; - nblks += blst_meta_fill(&scan[i], allocBlk, count, radix); + nblks += blst_meta_fill(&scan[i], allocBlk, count, + radix / BLIST_RADIX); if (scan[i].bm_bitmap == 0) scan->bm_bitmap &= ~((u_daddr_t)1 << digit); allocBlk = blk; @@ -1052,12 +1052,12 @@ blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int tab) u_daddr_t mask; int digit; - if (radix == BLIST_BMAP_RADIX) { + if (radix == 1) { printf( "%*.*s(%08llx,%lld): bitmap %0*llx big=%lld\n", tab, tab, "", - (long long)blk, (long long)radix, - 1 + (BLIST_BMAP_RADIX - 1) / 4, + (long long)blk, (long long)BLIST_RADIX, + (int)(1 + (BLIST_RADIX - 1) / 4), (long long)scan->bm_bitmap, (long long)scan->bm_bighint ); @@ -1067,14 +1067,13 @@ blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int tab) printf( "%*.*s(%08llx): subtree (%lld/%lld) bitmap %0*llx big=%lld {\n", tab, tab, "", - (long long)blk, (long long)radix, - (long long)radix, - 1 + (BLIST_META_RADIX - 1) / 4, + (long long)blk, (long long)radix * BLIST_RADIX, + (long long)radix * BLIST_RADIX, + (int)(1 + (BLIST_RADIX - 1) / 4), (long long)scan->bm_bitmap, (long long)scan->bm_bighint ); - radix /= BLIST_META_RADIX; skip = radix_to_skip(radix); tab += 4; @@ -1083,7 +1082,7 @@ blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int tab) do { digit = bitpos(mask); blst_radix_print(&scan[1 + digit * skip], blk + digit * radix, - radix, tab); + radix / BLIST_RADIX, tab); } while ((mask ^= bitrange(digit, 1)) != 0); tab -= 4; @@ -1100,7 +1099,7 @@ blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int tab) int main(int ac, char **av) { - int size = BLIST_META_RADIX * BLIST_BMAP_RADIX; + daddr_t size = BLIST_RADIX * BLIST_RADIX; int i; blist_t bl; struct sbuf *s; @@ -1108,7 +1107,7 @@ main(int ac, char **av) for (i = 1; i < ac; ++i) { const char *ptr = av[i]; if (*ptr != '-') { - size = strtol(ptr, NULL, 0); + size = strtoll(ptr, NULL, 0); continue; } ptr += 2; @@ -1116,6 +1115,10 @@ main(int ac, char **av) exit(1); } bl = blist_create(size, M_WAITOK); + if (bl == NULL) { + fprintf(stderr, "blist_create failed\n"); + exit(1); + } blist_free(bl, 0, size); for (;;) { @@ -1124,7 +1127,7 @@ main(int ac, char **av) int count = 0, maxcount = 0; printf("%lld/%lld/%lld> ", (long long)blist_avail(bl), - (long long)size, (long long)bl->bl_radix); + (long long)size, (long long)bl->bl_radix * BLIST_RADIX); fflush(stdout); if (fgets(buf, sizeof(buf), stdin) == NULL) break; diff --git a/sys/sys/blist.h b/sys/sys/blist.h index 3ad72e80cecc..e37d82fc8b4d 100644 --- a/sys/sys/blist.h +++ b/sys/sys/blist.h @@ -85,10 +85,9 @@ typedef struct blist { blmeta_t bl_root[1]; /* root of radix tree */ } *blist_t; -#define BLIST_BMAP_RADIX (sizeof(u_daddr_t)*8) -#define BLIST_META_RADIX BLIST_BMAP_RADIX +#define BLIST_RADIX (sizeof(u_daddr_t) * 8) -#define BLIST_MAX_ALLOC BLIST_BMAP_RADIX +#define BLIST_MAX_ALLOC BLIST_RADIX struct sbuf; diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c index 98aca826e212..fee8d1474c45 100644 --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -2369,7 +2369,6 @@ swaponsomething(struct vnode *vp, void *id, u_long nblks, { struct swdevt *sp, *tsp; daddr_t dvbase; - u_long mblocks; /* * nblks is in DEV_BSIZE'd chunks, convert to PAGE_SIZE'd chunks. @@ -2380,19 +2379,8 @@ swaponsomething(struct vnode *vp, void *id, u_long nblks, nblks &= ~(ctodb(1) - 1); nblks = dbtoc(nblks); - /* - * If we go beyond this, we get overflows in the radix - * tree bitmap code. - */ - mblocks = 0x40000000 / BLIST_META_RADIX; - if (nblks > mblocks) { - printf( - "WARNING: reducing swap size to maximum of %luMB per unit\n", - mblocks / 1024 / 1024 * PAGE_SIZE); - nblks = mblocks; - } - sp = malloc(sizeof *sp, M_VMPGDATA, M_WAITOK | M_ZERO); + sp->sw_blist = blist_create(nblks, M_WAITOK); sp->sw_vp = vp; sp->sw_id = id; sp->sw_dev = dev; @@ -2402,7 +2390,6 @@ swaponsomething(struct vnode *vp, void *id, u_long nblks, sp->sw_close = close; sp->sw_flags = flags; - sp->sw_blist = blist_create(nblks, M_WAITOK); /* * Do not free the first blocks in order to avoid overwriting * any bsd label at the front of the partition From 9c843a409bde9e16200d1c0bd790a997528d90e6 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Sat, 25 Jul 2020 19:07:12 +0000 Subject: [PATCH 172/287] o Move iommu gas prototypes, DMAR flags to iommu.h; o Move hw.dmar sysctl node to iommu_gas.c. Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25802 --- sys/dev/iommu/iommu.h | 36 ++++++++++++++++++++++++++++++++++++ sys/dev/iommu/iommu_gas.c | 12 ++++++++++++ sys/x86/iommu/intel_dmar.h | 37 ------------------------------------- sys/x86/iommu/intel_drv.c | 3 --- sys/x86/iommu/intel_utils.c | 7 ------- 5 files changed, 48 insertions(+), 47 deletions(-) diff --git a/sys/dev/iommu/iommu.h b/sys/dev/iommu/iommu.h index d0ac3052a313..781ba00219b5 100644 --- a/sys/dev/iommu/iommu.h +++ b/sys/dev/iommu/iommu.h @@ -133,6 +133,24 @@ struct iommu_ctx { ephemeral reference is kept to prevent context destruction */ +#define DMAR_DOMAIN_GAS_INITED 0x0001 +#define DMAR_DOMAIN_PGTBL_INITED 0x0002 +#define DMAR_DOMAIN_IDMAP 0x0010 /* Domain uses identity + page table */ +#define DMAR_DOMAIN_RMRR 0x0020 /* Domain contains RMRR entry, + cannot be turned off */ + +/* Map flags */ +#define IOMMU_MF_CANWAIT 0x0001 +#define IOMMU_MF_CANSPLIT 0x0002 +#define IOMMU_MF_RMRR 0x0004 + +#define DMAR_PGF_WAITOK 0x0001 +#define DMAR_PGF_ZERO 0x0002 +#define DMAR_PGF_ALLOC 0x0004 +#define DMAR_PGF_NOALLOC 0x0008 +#define DMAR_PGF_OBJL 0x0010 + #define IOMMU_LOCK(unit) mtx_lock(&(unit)->lock) #define IOMMU_UNLOCK(unit) mtx_unlock(&(unit)->lock) #define IOMMU_ASSERT_LOCKED(unit) mtx_assert(&(unit)->lock, MA_OWNED) @@ -174,4 +192,22 @@ int iommu_map(struct iommu_domain *iodom, int iommu_map_region(struct iommu_domain *domain, struct iommu_map_entry *entry, u_int eflags, u_int flags, vm_page_t *ma); +void iommu_gas_init_domain(struct iommu_domain *domain); +void iommu_gas_fini_domain(struct iommu_domain *domain); +struct iommu_map_entry *iommu_gas_alloc_entry(struct iommu_domain *domain, + u_int flags); +void iommu_gas_free_entry(struct iommu_domain *domain, + struct iommu_map_entry *entry); +void iommu_gas_free_space(struct iommu_domain *domain, + struct iommu_map_entry *entry); +int iommu_gas_map(struct iommu_domain *domain, + const struct bus_dma_tag_common *common, iommu_gaddr_t size, int offset, + u_int eflags, u_int flags, vm_page_t *ma, struct iommu_map_entry **res); +void iommu_gas_free_region(struct iommu_domain *domain, + struct iommu_map_entry *entry); +int iommu_gas_map_region(struct iommu_domain *domain, + struct iommu_map_entry *entry, u_int eflags, u_int flags, vm_page_t *ma); +int iommu_gas_reserve_region(struct iommu_domain *domain, iommu_gaddr_t start, + iommu_gaddr_t end); + #endif /* !_SYS_IOMMU_H_ */ diff --git a/sys/dev/iommu/iommu_gas.c b/sys/dev/iommu/iommu_gas.c index 83302bb19db4..a080a617656c 100644 --- a/sys/dev/iommu/iommu_gas.c +++ b/sys/dev/iommu/iommu_gas.c @@ -79,6 +79,10 @@ __FBSDID("$FreeBSD$"); static uma_zone_t iommu_map_entry_zone; +#ifdef INVARIANTS +static int iommu_check_free; +#endif + static void intel_gas_init(void) { @@ -727,3 +731,11 @@ iommu_map_region(struct iommu_domain *domain, struct iommu_map_entry *entry, return (error); } + +#ifdef INVARIANTS +static SYSCTL_NODE(_hw, OID_AUTO, iommu, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, + ""); +SYSCTL_INT(_hw_iommu, OID_AUTO, check_free, CTLFLAG_RWTUN, + &iommu_check_free, 0, + "Check the GPA RBtree for free_down and free_after validity"); +#endif diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h index ef2bdd3c9bf7..fba5e36f95cd 100644 --- a/sys/x86/iommu/intel_dmar.h +++ b/sys/x86/iommu/intel_dmar.h @@ -81,13 +81,6 @@ struct dmar_ctx { u_int refs; /* (u) References from tags */ }; -#define DMAR_DOMAIN_GAS_INITED 0x0001 -#define DMAR_DOMAIN_PGTBL_INITED 0x0002 -#define DMAR_DOMAIN_IDMAP 0x0010 /* Domain uses identity - page table */ -#define DMAR_DOMAIN_RMRR 0x0020 /* Domain contains RMRR entry, - cannot be turned off */ - #define DMAR_DOMAIN_PGLOCK(dom) VM_OBJECT_WLOCK((dom)->pgtbl_obj) #define DMAR_DOMAIN_PGTRYLOCK(dom) VM_OBJECT_TRYWLOCK((dom)->pgtbl_obj) #define DMAR_DOMAIN_PGUNLOCK(dom) VM_OBJECT_WUNLOCK((dom)->pgtbl_obj) @@ -286,24 +279,6 @@ void dmar_domain_unload(struct dmar_domain *domain, struct iommu_map_entries_tailq *entries, bool cansleep); void dmar_domain_free_entry(struct iommu_map_entry *entry, bool free); -void iommu_gas_init_domain(struct iommu_domain *domain); -void iommu_gas_fini_domain(struct iommu_domain *domain); -struct iommu_map_entry *iommu_gas_alloc_entry(struct iommu_domain *domain, - u_int flags); -void iommu_gas_free_entry(struct iommu_domain *domain, - struct iommu_map_entry *entry); -void iommu_gas_free_space(struct iommu_domain *domain, - struct iommu_map_entry *entry); -int iommu_gas_map(struct iommu_domain *domain, - const struct bus_dma_tag_common *common, iommu_gaddr_t size, int offset, - u_int eflags, u_int flags, vm_page_t *ma, struct iommu_map_entry **res); -void iommu_gas_free_region(struct iommu_domain *domain, - struct iommu_map_entry *entry); -int iommu_gas_map_region(struct iommu_domain *domain, - struct iommu_map_entry *entry, u_int eflags, u_int flags, vm_page_t *ma); -int iommu_gas_reserve_region(struct iommu_domain *domain, iommu_gaddr_t start, - iommu_gaddr_t end); - void dmar_dev_parse_rmrr(struct dmar_domain *domain, int dev_domain, int dev_busno, const void *dev_path, int dev_path_len, struct iommu_map_entries_tailq *rmrr_entries); @@ -318,22 +293,10 @@ void dmar_fini_irt(struct dmar_unit *unit); void dmar_set_buswide_ctx(struct iommu_unit *unit, u_int busno); bool dmar_is_buswide_ctx(struct dmar_unit *unit, u_int busno); -/* Map flags */ -#define IOMMU_MF_CANWAIT 0x0001 -#define IOMMU_MF_CANSPLIT 0x0002 -#define IOMMU_MF_RMRR 0x0004 - -#define DMAR_PGF_WAITOK 0x0001 -#define DMAR_PGF_ZERO 0x0002 -#define DMAR_PGF_ALLOC 0x0004 -#define DMAR_PGF_NOALLOC 0x0008 -#define DMAR_PGF_OBJL 0x0010 - extern iommu_haddr_t dmar_high; extern int haw; extern int dmar_tbl_pagecnt; extern int dmar_batch_coalesce; -extern int iommu_check_free; static inline uint32_t dmar_read4(const struct dmar_unit *unit, int reg) diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c index 1d3b1abc914d..492846f9dfb1 100644 --- a/sys/x86/iommu/intel_drv.c +++ b/sys/x86/iommu/intel_drv.c @@ -175,9 +175,6 @@ dmar_identify(driver_t *driver, device_t parent) TUNABLE_INT_FETCH("hw.dmar.enable", &dmar_enable); if (!dmar_enable) return; -#ifdef INVARIANTS - TUNABLE_INT_FETCH("hw.iommu.check_free", &iommu_check_free); -#endif status = AcpiGetTable(ACPI_SIG_DMAR, 1, (ACPI_TABLE_HEADER **)&dmartbl); if (ACPI_FAILURE(status)) return; diff --git a/sys/x86/iommu/intel_utils.c b/sys/x86/iommu/intel_utils.c index 72a1c2a3a0d3..1a14d2292c65 100644 --- a/sys/x86/iommu/intel_utils.c +++ b/sys/x86/iommu/intel_utils.c @@ -667,10 +667,3 @@ SYSCTL_PROC(_hw_dmar, OID_AUTO, timeout, CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 0, dmar_timeout_sysctl, "QU", "Timeout for command wait, in nanoseconds"); -#ifdef INVARIANTS -int iommu_check_free; -SYSCTL_INT(_hw_dmar, OID_AUTO, check_free, CTLFLAG_RWTUN, - &iommu_check_free, 0, - "Check the GPA RBtree for free_down and free_after validity"); -#endif - From 357149f037beef26ff80e4a7e716e7d07a8a312f Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Sat, 25 Jul 2020 21:37:07 +0000 Subject: [PATCH 173/287] o Make the _hw_iommu sysctl node non-static; o Move the dmar sysctl knobs to _hw_iommu_dmar. Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25807 --- sys/dev/iommu/iommu.h | 3 +++ sys/dev/iommu/iommu_gas.c | 4 ++-- sys/x86/iommu/intel_utils.c | 10 +++++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/sys/dev/iommu/iommu.h b/sys/dev/iommu/iommu.h index 781ba00219b5..10d6bb65a564 100644 --- a/sys/dev/iommu/iommu.h +++ b/sys/dev/iommu/iommu.h @@ -35,6 +35,7 @@ #define _SYS_IOMMU_H_ #include +#include #include #include #include @@ -210,4 +211,6 @@ int iommu_gas_map_region(struct iommu_domain *domain, int iommu_gas_reserve_region(struct iommu_domain *domain, iommu_gaddr_t start, iommu_gaddr_t end); +SYSCTL_DECL(_hw_iommu); + #endif /* !_SYS_IOMMU_H_ */ diff --git a/sys/dev/iommu/iommu_gas.c b/sys/dev/iommu/iommu_gas.c index a080a617656c..21b22238829c 100644 --- a/sys/dev/iommu/iommu_gas.c +++ b/sys/dev/iommu/iommu_gas.c @@ -732,9 +732,9 @@ iommu_map_region(struct iommu_domain *domain, struct iommu_map_entry *entry, return (error); } +SYSCTL_NODE(_hw, OID_AUTO, iommu, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, ""); + #ifdef INVARIANTS -static SYSCTL_NODE(_hw, OID_AUTO, iommu, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, - ""); SYSCTL_INT(_hw_iommu, OID_AUTO, check_free, CTLFLAG_RWTUN, &iommu_check_free, 0, "Check the GPA RBtree for free_down and free_after validity"); diff --git a/sys/x86/iommu/intel_utils.c b/sys/x86/iommu/intel_utils.c index 1a14d2292c65..39ade22ac945 100644 --- a/sys/x86/iommu/intel_utils.c +++ b/sys/x86/iommu/intel_utils.c @@ -655,15 +655,15 @@ dmar_timeout_sysctl(SYSCTL_HANDLER_ARGS) return (error); } -static SYSCTL_NODE(_hw, OID_AUTO, dmar, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, - ""); -SYSCTL_INT(_hw_dmar, OID_AUTO, tbl_pagecnt, CTLFLAG_RD, +static SYSCTL_NODE(_hw_iommu, OID_AUTO, dmar, CTLFLAG_RD | CTLFLAG_MPSAFE, + NULL, ""); +SYSCTL_INT(_hw_iommu_dmar, OID_AUTO, tbl_pagecnt, CTLFLAG_RD, &dmar_tbl_pagecnt, 0, "Count of pages used for DMAR pagetables"); -SYSCTL_INT(_hw_dmar, OID_AUTO, batch_coalesce, CTLFLAG_RWTUN, +SYSCTL_INT(_hw_iommu_dmar, OID_AUTO, batch_coalesce, CTLFLAG_RWTUN, &dmar_batch_coalesce, 0, "Number of qi batches between interrupt"); -SYSCTL_PROC(_hw_dmar, OID_AUTO, timeout, +SYSCTL_PROC(_hw_iommu_dmar, OID_AUTO, timeout, CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 0, dmar_timeout_sysctl, "QU", "Timeout for command wait, in nanoseconds"); From 795c5f365e38fe109e6611461dcc032a4a1134b8 Mon Sep 17 00:00:00 2001 From: Xin LI Date: Sun, 26 Jul 2020 00:44:59 +0000 Subject: [PATCH 174/287] geom_label: Make glabel labels more trivial by separating the tasting routines out. While there, also simplify the creation of label paths a little bit by requiring the / suffix for label directory prefixes (ld_dir renamed to ld_dirprefix to indicate the change) and stop defining macros for these when they are only used once. Reviewed by: cem MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D25597 --- sys/geom/label/g_label.c | 98 ++++++++++++++++------------- sys/geom/label/g_label.h | 3 +- sys/geom/label/g_label_disk_ident.c | 4 +- sys/geom/label/g_label_ext2fs.c | 2 +- sys/geom/label/g_label_flashmap.c | 4 +- sys/geom/label/g_label_gpt.c | 7 +-- sys/geom/label/g_label_iso9660.c | 4 +- sys/geom/label/g_label_msdosfs.c | 3 +- sys/geom/label/g_label_ntfs.c | 4 +- sys/geom/label/g_label_reiserfs.c | 2 +- sys/geom/label/g_label_ufs.c | 7 +-- 11 files changed, 67 insertions(+), 71 deletions(-) diff --git a/sys/geom/label/g_label.c b/sys/geom/label/g_label.c index 1052865b6a4e..ceb9d9d83d83 100644 --- a/sys/geom/label/g_label.c +++ b/sys/geom/label/g_label.c @@ -63,9 +63,12 @@ static int g_label_destroy_geom(struct gctl_req *req, struct g_class *mp, static int g_label_destroy(struct g_geom *gp, boolean_t force); static struct g_geom *g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused); +static void g_label_generic_taste(struct g_consumer *, char *, size_t); static void g_label_config(struct gctl_req *req, struct g_class *mp, const char *verb); +#define G_LABEL_DIRPREFIX "label/" + struct g_class g_label_class = { .name = G_LABEL_CLASS_NAME, .version = G_VERSION, @@ -74,6 +77,12 @@ struct g_class g_label_class = { .destroy_geom = g_label_destroy_geom }; +static struct g_label_desc g_label_generic = { + .ld_taste = g_label_generic_taste, + .ld_dirprefix = G_LABEL_DIRPREFIX, + .ld_enabled = 1 +}; + /* * To add a new file system where you want to look for volume labels, * you have to: @@ -99,6 +108,7 @@ const struct g_label_desc *g_labels[] = { &g_label_disk_ident, &g_label_flashmap, #endif + &g_label_generic, NULL }; @@ -213,7 +223,7 @@ g_label_mangle_name(char *label, size_t size) static struct g_geom * g_label_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp, - const char *label, const char *dir, off_t mediasize) + const char *label, const char *dirprefix, off_t mediasize) { struct g_geom *gp; struct g_provider *pp2; @@ -232,7 +242,7 @@ g_label_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp, } gp = NULL; cp = NULL; - if (snprintf(name, sizeof(name), "%s/%s", dir, label) >= sizeof(name)) { + if (snprintf(name, sizeof(name), "%s%s", dirprefix, label) >= sizeof(name)) { if (req != NULL) gctl_error(req, "Label name %s is too long.", label); return (NULL); @@ -300,13 +310,9 @@ g_label_read_metadata(struct g_consumer *cp, struct g_label_metadata *md) u_char *buf; int error; - g_topology_assert(); - pp = cp->provider; - g_topology_unlock(); buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, &error); - g_topology_lock(); if (buf == NULL) return (error); /* Decode metadata. */ @@ -339,12 +345,43 @@ g_label_access_taste(struct g_provider *pp __unused, int dr __unused, return (EOPNOTSUPP); } +static void +g_label_generic_taste(struct g_consumer *cp, char *label, size_t size) +{ + struct g_provider *pp; + struct g_label_metadata md; + + g_topology_assert_not(); + label[0] = '\0'; + pp = cp->provider; + + if (g_label_read_metadata(cp, &md) != 0) + return; + + if (strcmp(md.md_magic, G_LABEL_MAGIC) != 0) + return; + + if (md.md_version > G_LABEL_VERSION) { + printf("geom_label.ko module is too old to handle %s.\n", + pp->name); + return; + } + /* + * Backward compatibility: there was no md_provsize field in + * earlier versions of metadata, so only check if we have it. + */ + if (md.md_version >= 2 && md.md_provsize != pp->mediasize) + return; + + strlcpy(label, md.md_label, size); +} + static struct g_geom * g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) { - struct g_label_metadata md; struct g_consumer *cp; struct g_geom *gp; + off_t mediasize; int i; g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); @@ -367,33 +404,6 @@ g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) g_attach(cp, pp); if (g_access(cp, 1, 0, 0) != 0) goto end; - do { - if (g_label_read_metadata(cp, &md) != 0) - break; - if (strcmp(md.md_magic, G_LABEL_MAGIC) != 0) - break; - if (md.md_version > G_LABEL_VERSION) { - printf("geom_label.ko module is too old to handle %s.\n", - pp->name); - break; - } - - /* - * Backward compatibility: - */ - /* - * There was no md_provsize field in earlier versions of - * metadata. - */ - if (md.md_version < 2) - md.md_provsize = pp->mediasize; - - if (md.md_provsize != pp->mediasize) - break; - - g_label_create(NULL, mp, pp, md.md_label, G_LABEL_DIR, - pp->mediasize - pp->sectorsize); - } while (0); for (i = 0; g_labels[i] != NULL; i++) { char label[128]; @@ -405,8 +415,13 @@ g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) g_topology_lock(); if (label[0] == '\0') continue; - g_label_create(NULL, mp, pp, label, g_labels[i]->ld_dir, - pp->mediasize); + if (g_labels[i] != &g_label_generic) { + mediasize = pp->mediasize; + } else { + mediasize = pp->mediasize - pp->sectorsize; + } + g_label_create(NULL, mp, pp, label, + g_labels[i]->ld_dirprefix, mediasize); } g_access(cp, -1, 0, 0); end: @@ -448,23 +463,20 @@ g_label_ctl_create(struct gctl_req *req, struct g_class *mp) gctl_error(req, "No 'arg%d' argument", 0); return; } - g_label_create(req, mp, pp, name, G_LABEL_DIR, pp->mediasize); + g_label_create(req, mp, pp, name, G_LABEL_DIRPREFIX, pp->mediasize); } static const char * g_label_skip_dir(const char *name) { - char path[64]; u_int i; if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) name += strlen(_PATH_DEV); - if (strncmp(name, G_LABEL_DIR "/", strlen(G_LABEL_DIR "/")) == 0) - name += strlen(G_LABEL_DIR "/"); for (i = 0; g_labels[i] != NULL; i++) { - snprintf(path, sizeof(path), "%s/", g_labels[i]->ld_dir); - if (strncmp(name, path, strlen(path)) == 0) { - name += strlen(path); + if (strncmp(name, g_labels[i]->ld_dirprefix, + strlen(g_labels[i]->ld_dirprefix)) == 0) { + name += strlen(g_labels[i]->ld_dirprefix); break; } } diff --git a/sys/geom/label/g_label.h b/sys/geom/label/g_label.h index 4f71915d5b06..60df7e68a12b 100644 --- a/sys/geom/label/g_label.h +++ b/sys/geom/label/g_label.h @@ -45,7 +45,6 @@ * 2 - Added md_provsize field to metadata. */ #define G_LABEL_VERSION 2 -#define G_LABEL_DIR "label" #ifdef _KERNEL extern u_int g_label_debug; @@ -66,7 +65,7 @@ typedef void g_label_taste_t (struct g_consumer *cp, char *label, size_t size); struct g_label_desc { g_label_taste_t *ld_taste; - char *ld_dir; + char *ld_dirprefix; int ld_enabled; }; diff --git a/sys/geom/label/g_label_disk_ident.c b/sys/geom/label/g_label_disk_ident.c index 030dba5e37d2..39789f91dc9a 100644 --- a/sys/geom/label/g_label_disk_ident.c +++ b/sys/geom/label/g_label_disk_ident.c @@ -40,8 +40,6 @@ __FBSDID("$FreeBSD$"); #include -#define G_LABEL_DISK_IDENT_DIR "diskid" - static char* classes_pass[] = { G_DISK_CLASS_NAME, G_MULTIPATH_CLASS_NAME, NULL }; @@ -82,7 +80,7 @@ g_label_disk_ident_taste(struct g_consumer *cp, char *label, size_t size) struct g_label_desc g_label_disk_ident = { .ld_taste = g_label_disk_ident_taste, - .ld_dir = G_LABEL_DISK_IDENT_DIR, + .ld_dirprefix = "diskid/", .ld_enabled = 1 }; diff --git a/sys/geom/label/g_label_ext2fs.c b/sys/geom/label/g_label_ext2fs.c index 783ea0c4e61e..2003d9b631f6 100644 --- a/sys/geom/label/g_label_ext2fs.c +++ b/sys/geom/label/g_label_ext2fs.c @@ -97,7 +97,7 @@ g_label_ext2fs_taste(struct g_consumer *cp, char *label, size_t size) struct g_label_desc g_label_ext2fs = { .ld_taste = g_label_ext2fs_taste, - .ld_dir = "ext2fs", + .ld_dirprefix = "ext2fs/", .ld_enabled = 1 }; diff --git a/sys/geom/label/g_label_flashmap.c b/sys/geom/label/g_label_flashmap.c index 23b018fb5b5a..c19f5fe3ee97 100644 --- a/sys/geom/label/g_label_flashmap.c +++ b/sys/geom/label/g_label_flashmap.c @@ -39,8 +39,6 @@ __FBSDID("$FreeBSD$"); #include #include -#define G_LABEL_FLASHMAP_SLICE_DIR "flash" - static void g_label_flashmap_taste(struct g_consumer *cp, char *label, size_t size) { @@ -70,7 +68,7 @@ g_label_flashmap_taste(struct g_consumer *cp, char *label, size_t size) struct g_label_desc g_label_flashmap = { .ld_taste = g_label_flashmap_taste, - .ld_dir = G_LABEL_FLASHMAP_SLICE_DIR, + .ld_dirprefix = "flash/", .ld_enabled = 1 }; diff --git a/sys/geom/label/g_label_gpt.c b/sys/geom/label/g_label_gpt.c index 3ed8afeed2fd..13f161735aca 100644 --- a/sys/geom/label/g_label_gpt.c +++ b/sys/geom/label/g_label_gpt.c @@ -44,9 +44,6 @@ __FBSDID("$FreeBSD$"); #define PART_CLASS_NAME "PART" #define SCHEME_NAME "GPT" -#define G_LABEL_GPT_VOLUME_DIR "gpt" -#define G_LABEL_GPT_ID_DIR "gptid" - /* XXX: Also defined in geom/part/g_part_gpt.c */ struct g_part_gpt_entry { struct g_part_entry base; @@ -158,13 +155,13 @@ g_label_gpt_uuid_taste(struct g_consumer *cp, char *label, size_t size) struct g_label_desc g_label_gpt = { .ld_taste = g_label_gpt_taste, - .ld_dir = G_LABEL_GPT_VOLUME_DIR, + .ld_dirprefix = "gpt/", .ld_enabled = 1 }; struct g_label_desc g_label_gpt_uuid = { .ld_taste = g_label_gpt_uuid_taste, - .ld_dir = G_LABEL_GPT_ID_DIR, + .ld_dirprefix = "gptid/", .ld_enabled = 1 }; diff --git a/sys/geom/label/g_label_iso9660.c b/sys/geom/label/g_label_iso9660.c index 3b1926696a6f..d35f090cd616 100644 --- a/sys/geom/label/g_label_iso9660.c +++ b/sys/geom/label/g_label_iso9660.c @@ -38,8 +38,6 @@ __FBSDID("$FreeBSD$"); #include #include -#define G_LABEL_ISO9660_DIR "iso9660" - #define ISO9660_MAGIC "\x01" "CD001" "\x01\x00" #define ISO9660_OFFSET 0x8000 #define VOLUME_LEN 32 @@ -75,7 +73,7 @@ g_label_iso9660_taste(struct g_consumer *cp, char *label, size_t size) struct g_label_desc g_label_iso9660 = { .ld_taste = g_label_iso9660_taste, - .ld_dir = G_LABEL_ISO9660_DIR, + .ld_dirprefix = "iso9660/", .ld_enabled = 1 }; diff --git a/sys/geom/label/g_label_msdosfs.c b/sys/geom/label/g_label_msdosfs.c index d78f728f4c4a..e02d95c0180c 100644 --- a/sys/geom/label/g_label_msdosfs.c +++ b/sys/geom/label/g_label_msdosfs.c @@ -40,7 +40,6 @@ __FBSDID("$FreeBSD$"); #include #include -#define G_LABEL_MSDOSFS_DIR "msdosfs" #define LABEL_NO_NAME "NO NAME " static void @@ -213,7 +212,7 @@ g_label_msdosfs_taste(struct g_consumer *cp, char *label, size_t size) struct g_label_desc g_label_msdosfs = { .ld_taste = g_label_msdosfs_taste, - .ld_dir = G_LABEL_MSDOSFS_DIR, + .ld_dirprefix = "msdosfs/", .ld_enabled = 1 }; diff --git a/sys/geom/label/g_label_ntfs.c b/sys/geom/label/g_label_ntfs.c index 653524ab654c..dee105bcc833 100644 --- a/sys/geom/label/g_label_ntfs.c +++ b/sys/geom/label/g_label_ntfs.c @@ -41,8 +41,6 @@ __FBSDID("$FreeBSD$"); #define NTFS_FILEMAGIC ((uint32_t)(0x454C4946)) #define NTFS_VOLUMEINO 3 -#define G_LABEL_NTFS_DIR "ntfs" - struct ntfs_attr { uint32_t a_type; uint32_t reclen; @@ -170,7 +168,7 @@ g_label_ntfs_taste(struct g_consumer *cp, char *label, size_t size) struct g_label_desc g_label_ntfs = { .ld_taste = g_label_ntfs_taste, - .ld_dir = G_LABEL_NTFS_DIR, + .ld_dirprefix = "ntfs/", .ld_enabled = 1 }; diff --git a/sys/geom/label/g_label_reiserfs.c b/sys/geom/label/g_label_reiserfs.c index 385f906035b8..4ed04f632324 100644 --- a/sys/geom/label/g_label_reiserfs.c +++ b/sys/geom/label/g_label_reiserfs.c @@ -116,7 +116,7 @@ g_label_reiserfs_taste(struct g_consumer *cp, char *label, size_t size) struct g_label_desc g_label_reiserfs = { .ld_taste = g_label_reiserfs_taste, - .ld_dir = "reiserfs", + .ld_dirprefix = "reiserfs/", .ld_enabled = 1 }; diff --git a/sys/geom/label/g_label_ufs.c b/sys/geom/label/g_label_ufs.c index 1d2614b52747..ababbaa4b43a 100644 --- a/sys/geom/label/g_label_ufs.c +++ b/sys/geom/label/g_label_ufs.c @@ -45,9 +45,6 @@ __FBSDID("$FreeBSD$"); #include #include -#define G_LABEL_UFS_VOLUME_DIR "ufs" -#define G_LABEL_UFS_ID_DIR "ufsid" - #define G_LABEL_UFS_VOLUME 0 #define G_LABEL_UFS_ID 1 @@ -142,13 +139,13 @@ g_label_ufs_id_taste(struct g_consumer *cp, char *label, size_t size) struct g_label_desc g_label_ufs_volume = { .ld_taste = g_label_ufs_volume_taste, - .ld_dir = G_LABEL_UFS_VOLUME_DIR, + .ld_dirprefix = "ufs/", .ld_enabled = 1 }; struct g_label_desc g_label_ufs_id = { .ld_taste = g_label_ufs_id_taste, - .ld_dir = G_LABEL_UFS_ID_DIR, + .ld_dirprefix = "ufsid/", .ld_enabled = 1 }; From 7201590bbf94e0abe5550a203021bfc802612401 Mon Sep 17 00:00:00 2001 From: Xin LI Date: Sun, 26 Jul 2020 01:45:26 +0000 Subject: [PATCH 175/287] Use snprintf instead of sprintf. MFC after: 2 weeks --- sys/geom/geom_ccd.c | 4 ++-- sys/geom/part/g_part_vtoc8.c | 6 ++++-- sys/geom/virstor/g_virstor.c | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sys/geom/geom_ccd.c b/sys/geom/geom_ccd.c index f0a3fad02489..f7b580fa65f3 100644 --- a/sys/geom/geom_ccd.c +++ b/sys/geom/geom_ccd.c @@ -771,7 +771,7 @@ g_ccd_create(struct gctl_req *req, struct g_class *mp) /* Check all providers are valid */ for (i = 0; i < *nprovider; i++) { - sprintf(buf, "provider%d", i); + snprintf(buf, sizeof(buf), "provider%d", i); pp = gctl_get_provider(req, buf); if (pp == NULL) return; @@ -788,7 +788,7 @@ g_ccd_create(struct gctl_req *req, struct g_class *mp) /* Create consumers and attach to all providers */ for (i = 0; i < *nprovider; i++) { - sprintf(buf, "provider%d", i); + snprintf(buf, sizeof(buf), "provider%d", i); pp = gctl_get_provider(req, buf); cp = g_new_consumer(gp); error = g_attach(cp, pp); diff --git a/sys/geom/part/g_part_vtoc8.c b/sys/geom/part/g_part_vtoc8.c index 7b595cb14598..c32d8e32eeaf 100644 --- a/sys/geom/part/g_part_vtoc8.c +++ b/sys/geom/part/g_part_vtoc8.c @@ -224,7 +224,8 @@ g_part_vtoc8_create(struct g_part_table *basetable, struct g_part_parms *gpp) ncyls = pcyls - acyls; msize = ncyls * table->secpercyl; - sprintf(table->vtoc.ascii, "FreeBSD%lldM cyl %u alt %u hd %u sec %u", + snprintf(table->vtoc.ascii, sizeof(table->vtoc.ascii), + "FreeBSD%lldM cyl %u alt %u hd %u sec %u", (long long)(msize / 2048), ncyls, acyls, basetable->gpt_heads, basetable->gpt_sectors); be32enc(&table->vtoc.version, VTOC_VERSION); @@ -338,7 +339,8 @@ vtoc8_set_rawsize(struct g_part_table *basetable, struct g_provider *pp) basetable->gpt_last = msize - 1; bzero(table->vtoc.ascii, sizeof(table->vtoc.ascii)); - sprintf(table->vtoc.ascii, "FreeBSD%lldM cyl %u alt %u hd %u sec %u", + snprintf(table->vtoc.ascii, sizeof(table->vtoc.ascii), + "FreeBSD%lldM cyl %u alt %u hd %u sec %u", (long long)(msize / 2048), ncyls, acyls, basetable->gpt_heads, basetable->gpt_sectors); be16enc(&table->vtoc.physcyls, pcyls); diff --git a/sys/geom/virstor/g_virstor.c b/sys/geom/virstor/g_virstor.c index 7cc09b32c9c7..69fff73df945 100644 --- a/sys/geom/virstor/g_virstor.c +++ b/sys/geom/virstor/g_virstor.c @@ -227,7 +227,7 @@ virstor_ctl_stop(struct gctl_req *req, struct g_class *cp) struct g_virstor_softc *sc; int error; - sprintf(param, "arg%d", i); + snprintf(param, sizeof(param), "arg%d", i); name = gctl_get_asciiparam(req, param); if (name == NULL) { gctl_error(req, "No 'arg%d' argument", i); @@ -565,7 +565,7 @@ virstor_ctl_remove(struct gctl_req *req, struct g_class *cp) int j, found; struct g_virstor_component *newcomp, *compbak; - sprintf(param, "arg%d", i); + snprintf(param, sizeof(param), "arg%d", i); prov_name = gctl_get_asciiparam(req, param); if (prov_name == NULL) { gctl_error(req, "Error fetching argument '%s'", param); From 18a48314bae9d51ba2a18f20df3d8ed6cd2fd33d Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Sun, 26 Jul 2020 02:42:09 +0000 Subject: [PATCH 176/287] Add support for ext_pgs mbufs to nfsrv_adj(). This patch uses a slightly different algorithm for nfsrv_adj() since ext_pgs mbuf lists are not permitted to have m_len == 0 mbufs. As such, the code now frees mbufs after the adjustment in the list instead of setting their m_len field to 0. Since mbuf(s) may be trimmed off the tail of the list, the function now returns a pointer to the last mbuf in the list. This saves the caller from needing to use m_last() to find the last mbuf. It also implies that it might return a nul list, which required a check for that in nfsrvd_readlink(). This is another in the series of commits that add support to the NFS client and server for building RPC messages in ext_pgs mbufs with anonymous pages. This is useful so that the entire mbuf list does not need to be copied before calling sosend() when NFS over TLS is enabled. Use of ext_pgs mbufs will not be enabled until the kernel RPC is updated to handle TLS. --- sys/fs/nfs/nfs_var.h | 2 +- sys/fs/nfsserver/nfs_nfsdport.c | 17 +++-- sys/fs/nfsserver/nfs_nfsdserv.c | 8 ++- sys/fs/nfsserver/nfs_nfsdsubs.c | 112 +++++++++++++++++++++----------- 4 files changed, 94 insertions(+), 45 deletions(-) diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 0e826a2b6524..1cf792edeced 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -391,7 +391,7 @@ int nfsv4_fillattr(struct nfsrv_descript *, struct mount *, vnode_t, NFSACL_T *, struct vattr *, fhandle_t *, int, nfsattrbit_t *, struct ucred *, NFSPROC_T *, int, int, int, int, uint64_t, struct statfs *); void nfsrv_fillattr(struct nfsrv_descript *, struct nfsvattr *); -void nfsrv_adj(struct mbuf *, int, int); +struct mbuf *nfsrv_adj(struct mbuf *, int, int); void nfsrv_postopattr(struct nfsrv_descript *, int, struct nfsvattr *); int nfsd_errmap(struct nfsrv_descript *); void nfsv4_uidtostr(uid_t, u_char **, int *); diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 050ca6df7aa8..fbe77fcaf9b6 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -757,7 +757,12 @@ nfsvno_readlink(struct vnode *vp, struct ucred *cred, struct thread *p, if (uiop->uio_resid > 0) { len -= uiop->uio_resid; tlen = NFSM_RNDUP(len); - nfsrv_adj(mp3, NFS_MAXPATHLEN - tlen, tlen - len); + if (tlen == 0) { + m_freem(mp3); + mp3 = mp = NULL; + } else if (tlen != NFS_MAXPATHLEN || tlen != len) + mp = nfsrv_adj(mp3, NFS_MAXPATHLEN - tlen, + tlen - len); } *lenp = len; *mpp = mp3; @@ -872,9 +877,9 @@ nfsvno_read(struct vnode *vp, off_t off, int cnt, struct ucred *cred, tlen = NFSM_RNDUP(cnt); if (tlen == 0) { m_freem(m3); - m3 = NULL; + m3 = m = NULL; } else if (len != tlen || tlen != cnt) - nfsrv_adj(m3, len - tlen, tlen - cnt); + m = nfsrv_adj(m3, len - tlen, tlen - cnt); *mpp = m3; *mpendp = m; @@ -6247,7 +6252,11 @@ nfsvno_getxattr(struct vnode *vp, char *name, uint32_t maxresp, tlen = NFSM_RNDUP(len); if (alen != tlen) printf("nfsvno_getxattr: weird size read\n"); - nfsrv_adj(m, alen - tlen, tlen - len); + if (tlen == 0) { + m_freem(m); + m = m2 = NULL; + } else if (alen != tlen || tlen != len) + m2 = nfsrv_adj(m, alen - tlen, tlen - len); } *lenp = len; *mpp = m; diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c index 09aa87ae2e2c..1b34cb27dd01 100644 --- a/sys/fs/nfsserver/nfs_nfsdserv.c +++ b/sys/fs/nfsserver/nfs_nfsdserv.c @@ -690,9 +690,11 @@ nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram, goto out; NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(len); - nd->nd_mb->m_next = mp; - nd->nd_mb = mpend; - nd->nd_bpos = mtod(mpend, caddr_t) + mpend->m_len; + if (mp != NULL) { + nd->nd_mb->m_next = mp; + nd->nd_mb = mpend; + nd->nd_bpos = mtod(mpend, caddr_t) + mpend->m_len; + } out: NFSEXITCODE2(0, nd); diff --git a/sys/fs/nfsserver/nfs_nfsdsubs.c b/sys/fs/nfsserver/nfs_nfsdsubs.c index 17349343d5e0..428751372121 100644 --- a/sys/fs/nfsserver/nfs_nfsdsubs.c +++ b/sys/fs/nfsserver/nfs_nfsdsubs.c @@ -1268,62 +1268,100 @@ static short *nfsrv_v4errmap[] = { }; /* - * A fiddled version of m_adj() that ensures null fill to a long - * boundary and only trims off the back end + * Trim tlen bytes off the end of the mbuf list and then ensure + * the end of the last mbuf is nul filled to a long boundary, + * as indicated by the value of "nul". + * Return the last mbuf in the updated list and free and mbufs + * that follow it in the original list. + * This is somewhat different than the old nfsrv_adj() with + * support for ext_pgs mbufs. It frees the remaining mbufs + * instead of setting them 0 length, since lists of ext_pgs + * mbufs are all expected to be non-empty. */ -void +struct mbuf * nfsrv_adj(struct mbuf *mp, int len, int nul) { - struct mbuf *m; - int count, i; + struct mbuf *m, *m2; + vm_page_t pg; + int i, lastlen, pgno, plen, tlen, trim; + uint16_t off; char *cp; /* - * Trim from tail. Scan the mbuf chain, - * calculating its length and finding the last mbuf. - * If the adjustment only affects this mbuf, then just - * adjust and return. Otherwise, rescan and truncate - * after the remaining size. + * Find the last mbuf after adjustment and + * how much it needs to be adjusted by. */ - count = 0; + tlen = 0; m = mp; for (;;) { - count += m->m_len; + tlen += m->m_len; if (m->m_next == NULL) break; m = m->m_next; } - if (m->m_len > len) { - m->m_len -= len; - if (nul > 0) { - cp = mtod(m, caddr_t) + m->m_len - nul; - for (i = 0; i < nul; i++) - *cp++ = '\0'; + /* m is now the last mbuf and tlen the total length. */ + + if (len >= m->m_len) { + /* Need to trim away the last mbuf(s). */ + i = tlen - len; + m = mp; + for (;;) { + if (m->m_len >= i) + break; + i -= m->m_len; + m = m->m_next; } - return; - } - count -= len; - if (count < 0) - count = 0; + lastlen = i; + } else + lastlen = m->m_len - len; + /* - * Correct length for chain is "count". - * Find the mbuf with last data, adjust its length, - * and toss data from remaining mbufs on chain. + * m is now the last mbuf after trimming and its length needs to + * be lastlen. + * Adjust the last mbuf and set cp to point to where nuls must be + * written. */ - for (m = mp; m; m = m->m_next) { - if (m->m_len >= count) { - m->m_len = count; - if (nul > 0) { - cp = mtod(m, caddr_t) + m->m_len - nul; - for (i = 0; i < nul; i++) - *cp++ = '\0'; + if ((m->m_flags & M_EXTPG) != 0) { + pgno = m->m_epg_npgs - 1; + off = (pgno == 0) ? m->m_epg_1st_off : 0; + plen = m_epg_pagelen(m, pgno, off); + if (m->m_len > lastlen) { + /* Trim this mbuf. */ + trim = m->m_len - lastlen; + while (trim >= plen) { + KASSERT(pgno > 0, + ("nfsrv_adj: freeing page 0")); + /* Free page. */ + pg = PHYS_TO_VM_PAGE(m->m_epg_pa[pgno]); + vm_page_unwire_noq(pg); + vm_page_free(pg); + trim -= plen; + m->m_epg_npgs--; + pgno--; + off = (pgno == 0) ? m->m_epg_1st_off : 0; + plen = m_epg_pagelen(m, pgno, off); } - break; + plen -= trim; + m->m_epg_last_len = plen; + m->m_len = lastlen; } - count -= m->m_len; + cp = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]); + cp += off + plen - nul; + } else { + m->m_len = lastlen; + cp = mtod(m, char *) + m->m_len - nul; } - for (m = m->m_next; m; m = m->m_next) - m->m_len = 0; + + /* Write the nul bytes. */ + for (i = 0; i < nul; i++) + *cp++ = '\0'; + + /* Free up any mbufs past "m". */ + m2 = m->m_next; + m->m_next = NULL; + if (m2 != NULL) + m_freem(m2); + return (m); } /* From 14fdf163717efe7730104832b7a4b09c963c42ea Mon Sep 17 00:00:00 2001 From: Yuri Pankov Date: Sun, 26 Jul 2020 09:15:05 +0000 Subject: [PATCH 177/287] sed: treat '[' as ordinary character in 'y' command 'y' does not handle bracket expressions, treat '[' as ordinary character and do not apply bracket expression checks (GNU sed agrees). PR: 247931 Reviewed by: pfg, kevans Tested by: antoine (exp-run), Quentin L'Hours Differential Revision: https://reviews.freebsd.org/D25640 --- usr.bin/sed/compile.c | 16 ++++++++++++---- usr.bin/sed/tests/sed2_test.sh | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/usr.bin/sed/compile.c b/usr.bin/sed/compile.c index 99fa2b17a92f..a7cb3cbd6a73 100644 --- a/usr.bin/sed/compile.c +++ b/usr.bin/sed/compile.c @@ -437,11 +437,19 @@ compile_delimited(char *p, char *d, int is_tr) linenum, fname); while (*p) { if (*p == '[' && *p != c) { - if ((d = compile_ccl(&p, d)) == NULL) - errx(1, "%lu: %s: unbalanced brackets ([])", linenum, fname); - continue; + if (!is_tr) { + if ((d = compile_ccl(&p, d)) == NULL) { + errx(1, + "%lu: %s: unbalanced brackets ([])", + linenum, fname); + } + continue; + } } else if (*p == '\\' && p[1] == '[') { - *d++ = *p++; + if (is_tr) + p++; + else + *d++ = *p++; } else if (*p == '\\' && p[1] == c) { p++; } else if (*p == '\\' && diff --git a/usr.bin/sed/tests/sed2_test.sh b/usr.bin/sed/tests/sed2_test.sh index efa04f212ad4..9f831e0ed673 100755 --- a/usr.bin/sed/tests/sed2_test.sh +++ b/usr.bin/sed/tests/sed2_test.sh @@ -134,6 +134,22 @@ commands_on_stdin_body() atf_check -o 'empty' sed -f - < insert_x } +atf_test_case bracket_y +bracket_y_head() +{ + atf_set "descr" "Verify '[' is ordinary character for 'y' command" +} +bracket_y_body() +{ + atf_check -e empty -o ignore echo | sed 'y/[/x/' + atf_check -e empty -o ignore echo | sed 'y/[]/xy/' + atf_check -e empty -o ignore echo | sed 'y/[a]/xyz/' + atf_check -e empty -o "inline:zyx" echo '][a' | sed 'y/[a]/xyz/' + atf_check -e empty -o "inline:bracket\n" echo 'bra[ke]' | sed 'y/[]/ct/' + atf_check -e empty -o "inline:bracket\n" \ + echo 'bra[ke]' | sed 'y[\[][ct[' +} + atf_init_test_cases() { atf_add_test_case inplace_command_q @@ -142,4 +158,5 @@ atf_init_test_cases() atf_add_test_case escape_subst atf_add_test_case commands_on_stdin atf_add_test_case hex_subst + atf_add_test_case bracket_y } From 4111838d375485d3ae638683b61840383217c8c0 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Sun, 26 Jul 2020 10:07:05 +0000 Subject: [PATCH 178/287] arm64: Only compile imx8 files if soc_freescale_imx8 is selected No Objection from: gonzo --- sys/conf/files.arm64 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index a538da81f1c4..44155655a7ba 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -408,8 +408,8 @@ arm64/freescale/imx/clk/imx_clk_sscg_pll.c optional fdt soc_freescale_imx8 arm64/freescale/imx/clk/imx_clk_frac_pll.c optional fdt soc_freescale_imx8 # iMX drivers -arm/freescale/imx/imx_gpio.c optional gpio +arm/freescale/imx/imx_gpio.c optional gpio soc_freescale_imx8 arm/freescale/imx/imx_i2c.c optional fsliic -arm/freescale/imx/imx_machdep.c standard +arm/freescale/imx/imx_machdep.c optional fdt soc_freescale_imx8 arm64/freescale/imx/imx7gpc.c optional fdt soc_freescale_imx8 dev/ffec/if_ffec.c optional ffec From 15f6baf44534d45086b5e3423363ff0b2f6e6c36 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Sun, 26 Jul 2020 12:29:22 +0000 Subject: [PATCH 179/287] Rename DMAR flags: o DMAR_DOMAIN_* -> IOMMU_DOMAIN_* o DMAR_PGF_* -> IOMMU_PGF_* Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25812 --- sys/dev/iommu/busdma_iommu.c | 2 +- sys/dev/iommu/iommu.h | 18 ++++++++-------- sys/dev/iommu/iommu_gas.c | 18 ++++++++-------- sys/x86/iommu/intel_ctx.c | 29 +++++++++++++------------ sys/x86/iommu/intel_drv.c | 4 ++-- sys/x86/iommu/intel_idpgtbl.c | 38 ++++++++++++++++----------------- sys/x86/iommu/intel_utils.c | 40 +++++++++++++++++------------------ 7 files changed, 75 insertions(+), 74 deletions(-) diff --git a/sys/dev/iommu/busdma_iommu.c b/sys/dev/iommu/busdma_iommu.c index d543436a8a86..a4fe8ee9d063 100644 --- a/sys/dev/iommu/busdma_iommu.c +++ b/sys/dev/iommu/busdma_iommu.c @@ -1017,7 +1017,7 @@ bus_dma_dmar_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map1, map = (struct bus_dmamap_iommu *)map1; waitok = (flags & BUS_DMA_NOWAIT) != 0; - entry = iommu_map_alloc_entry(domain, waitok ? 0 : DMAR_PGF_WAITOK); + entry = iommu_map_alloc_entry(domain, waitok ? 0 : IOMMU_PGF_WAITOK); if (entry == NULL) return (ENOMEM); entry->start = start; diff --git a/sys/dev/iommu/iommu.h b/sys/dev/iommu/iommu.h index 10d6bb65a564..c3bc3d26b765 100644 --- a/sys/dev/iommu/iommu.h +++ b/sys/dev/iommu/iommu.h @@ -134,11 +134,11 @@ struct iommu_ctx { ephemeral reference is kept to prevent context destruction */ -#define DMAR_DOMAIN_GAS_INITED 0x0001 -#define DMAR_DOMAIN_PGTBL_INITED 0x0002 -#define DMAR_DOMAIN_IDMAP 0x0010 /* Domain uses identity +#define IOMMU_DOMAIN_GAS_INITED 0x0001 +#define IOMMU_DOMAIN_PGTBL_INITED 0x0002 +#define IOMMU_DOMAIN_IDMAP 0x0010 /* Domain uses identity page table */ -#define DMAR_DOMAIN_RMRR 0x0020 /* Domain contains RMRR entry, +#define IOMMU_DOMAIN_RMRR 0x0020 /* Domain contains RMRR entry, cannot be turned off */ /* Map flags */ @@ -146,11 +146,11 @@ struct iommu_ctx { #define IOMMU_MF_CANSPLIT 0x0002 #define IOMMU_MF_RMRR 0x0004 -#define DMAR_PGF_WAITOK 0x0001 -#define DMAR_PGF_ZERO 0x0002 -#define DMAR_PGF_ALLOC 0x0004 -#define DMAR_PGF_NOALLOC 0x0008 -#define DMAR_PGF_OBJL 0x0010 +#define IOMMU_PGF_WAITOK 0x0001 +#define IOMMU_PGF_ZERO 0x0002 +#define IOMMU_PGF_ALLOC 0x0004 +#define IOMMU_PGF_NOALLOC 0x0008 +#define IOMMU_PGF_OBJL 0x0010 #define IOMMU_LOCK(unit) mtx_lock(&(unit)->lock) #define IOMMU_UNLOCK(unit) mtx_unlock(&(unit)->lock) diff --git a/sys/dev/iommu/iommu_gas.c b/sys/dev/iommu/iommu_gas.c index 21b22238829c..5a6e48850b5b 100644 --- a/sys/dev/iommu/iommu_gas.c +++ b/sys/dev/iommu/iommu_gas.c @@ -98,10 +98,10 @@ iommu_gas_alloc_entry(struct iommu_domain *domain, u_int flags) { struct iommu_map_entry *res; - KASSERT((flags & ~(DMAR_PGF_WAITOK)) == 0, + KASSERT((flags & ~(IOMMU_PGF_WAITOK)) == 0, ("unsupported flags %x", flags)); - res = uma_zalloc(iommu_map_entry_zone, ((flags & DMAR_PGF_WAITOK) != + res = uma_zalloc(iommu_map_entry_zone, ((flags & IOMMU_PGF_WAITOK) != 0 ? M_WAITOK : M_NOWAIT) | M_ZERO); if (res != NULL) { res->domain = domain; @@ -218,8 +218,8 @@ iommu_gas_init_domain(struct iommu_domain *domain) { struct iommu_map_entry *begin, *end; - begin = iommu_gas_alloc_entry(domain, DMAR_PGF_WAITOK); - end = iommu_gas_alloc_entry(domain, DMAR_PGF_WAITOK); + begin = iommu_gas_alloc_entry(domain, IOMMU_PGF_WAITOK); + end = iommu_gas_alloc_entry(domain, IOMMU_PGF_WAITOK); IOMMU_DOMAIN_LOCK(domain); KASSERT(domain->entries_cnt == 2, ("dirty domain %p", domain)); @@ -238,7 +238,7 @@ iommu_gas_init_domain(struct iommu_domain *domain) domain->first_place = begin; domain->last_place = end; - domain->flags |= DMAR_DOMAIN_GAS_INITED; + domain->flags |= IOMMU_DOMAIN_GAS_INITED; IOMMU_DOMAIN_UNLOCK(domain); } @@ -598,7 +598,7 @@ iommu_gas_map(struct iommu_domain *domain, ("invalid flags 0x%x", flags)); entry = iommu_gas_alloc_entry(domain, - (flags & IOMMU_MF_CANWAIT) != 0 ? DMAR_PGF_WAITOK : 0); + (flags & IOMMU_MF_CANWAIT) != 0 ? IOMMU_PGF_WAITOK : 0); if (entry == NULL) return (ENOMEM); IOMMU_DOMAIN_LOCK(domain); @@ -622,7 +622,7 @@ iommu_gas_map(struct iommu_domain *domain, error = domain_map_buf(domain, entry->start, entry->end - entry->start, ma, eflags, - ((flags & IOMMU_MF_CANWAIT) != 0 ? DMAR_PGF_WAITOK : 0)); + ((flags & IOMMU_MF_CANWAIT) != 0 ? IOMMU_PGF_WAITOK : 0)); if (error == ENOMEM) { iommu_domain_unload_entry(entry, true); return (error); @@ -660,7 +660,7 @@ iommu_gas_map_region(struct iommu_domain *domain, struct iommu_map_entry *entry, error = domain_map_buf(domain, entry->start, entry->end - entry->start, ma + OFF_TO_IDX(start - entry->start), eflags, - ((flags & IOMMU_MF_CANWAIT) != 0 ? DMAR_PGF_WAITOK : 0)); + ((flags & IOMMU_MF_CANWAIT) != 0 ? IOMMU_PGF_WAITOK : 0)); if (error == ENOMEM) { iommu_domain_unload_entry(entry, false); return (error); @@ -678,7 +678,7 @@ iommu_gas_reserve_region(struct iommu_domain *domain, iommu_gaddr_t start, struct iommu_map_entry *entry; int error; - entry = iommu_gas_alloc_entry(domain, DMAR_PGF_WAITOK); + entry = iommu_gas_alloc_entry(domain, IOMMU_PGF_WAITOK); entry->start = start; entry->end = end; IOMMU_DOMAIN_LOCK(domain); diff --git a/sys/x86/iommu/intel_ctx.c b/sys/x86/iommu/intel_ctx.c index 9d67a5cf20f4..45151c8dd355 100644 --- a/sys/x86/iommu/intel_ctx.c +++ b/sys/x86/iommu/intel_ctx.c @@ -89,7 +89,7 @@ dmar_ensure_ctx_page(struct dmar_unit *dmar, int bus) /* * Allocated context page must be linked. */ - ctxm = dmar_pgalloc(dmar->ctx_obj, 1 + bus, DMAR_PGF_NOALLOC); + ctxm = dmar_pgalloc(dmar->ctx_obj, 1 + bus, IOMMU_PGF_NOALLOC); if (ctxm != NULL) return; @@ -100,9 +100,9 @@ dmar_ensure_ctx_page(struct dmar_unit *dmar, int bus) * threads are equal. */ TD_PREP_PINNED_ASSERT; - ctxm = dmar_pgalloc(dmar->ctx_obj, 1 + bus, DMAR_PGF_ZERO | - DMAR_PGF_WAITOK); - re = dmar_map_pgtbl(dmar->ctx_obj, 0, DMAR_PGF_NOALLOC, &sf); + ctxm = dmar_pgalloc(dmar->ctx_obj, 1 + bus, IOMMU_PGF_ZERO | + IOMMU_PGF_WAITOK); + re = dmar_map_pgtbl(dmar->ctx_obj, 0, IOMMU_PGF_NOALLOC, &sf); re += bus; dmar_pte_store(&re->r1, DMAR_ROOT_R1_P | (DMAR_ROOT_R1_CTP_MASK & VM_PAGE_TO_PHYS(ctxm))); @@ -120,7 +120,7 @@ dmar_map_ctx_entry(struct dmar_ctx *ctx, struct sf_buf **sfp) dmar = (struct dmar_unit *)ctx->context.domain->iommu; ctxp = dmar_map_pgtbl(dmar->ctx_obj, 1 + - PCI_RID2BUS(ctx->rid), DMAR_PGF_NOALLOC | DMAR_PGF_WAITOK, sfp); + PCI_RID2BUS(ctx->rid), IOMMU_PGF_NOALLOC | IOMMU_PGF_WAITOK, sfp); ctxp += ctx->rid & 0xff; return (ctxp); } @@ -186,13 +186,14 @@ ctx_id_entry_init(struct dmar_ctx *ctx, dmar_ctx_entry_t *ctxp, bool move, pci_get_function(ctx->context.tag->owner), ctxp->ctx1, ctxp->ctx2)); - if ((domain->iodom.flags & DMAR_DOMAIN_IDMAP) != 0 && + if ((domain->iodom.flags & IOMMU_DOMAIN_IDMAP) != 0 && (unit->hw_ecap & DMAR_ECAP_PT) != 0) { KASSERT(domain->pgtbl_obj == NULL, ("ctx %p non-null pgtbl_obj", ctx)); ctx_root = NULL; } else { - ctx_root = dmar_pgalloc(domain->pgtbl_obj, 0, DMAR_PGF_NOALLOC); + ctx_root = dmar_pgalloc(domain->pgtbl_obj, 0, + IOMMU_PGF_NOALLOC); } if (dmar_is_buswide_ctx(unit, busno)) { @@ -295,7 +296,7 @@ domain_init_rmrr(struct dmar_domain *domain, device_t dev, int bus, if (error1 == 0 && entry->end != entry->start) { IOMMU_LOCK(domain->iodom.iommu); domain->refs++; /* XXXKIB prevent free */ - domain->iodom.flags |= DMAR_DOMAIN_RMRR; + domain->iodom.flags |= IOMMU_DOMAIN_RMRR; IOMMU_UNLOCK(domain->iodom.iommu); } else { if (error1 != 0) { @@ -363,7 +364,7 @@ dmar_domain_alloc(struct dmar_unit *dmar, bool id_mapped) domain->pgtbl_obj = domain_get_idmap_pgtbl(domain, domain->iodom.end); } - domain->iodom.flags |= DMAR_DOMAIN_IDMAP; + domain->iodom.flags |= IOMMU_DOMAIN_IDMAP; } else { error = domain_alloc_pgtbl(domain); if (error != 0) @@ -440,12 +441,12 @@ dmar_domain_destroy(struct dmar_domain *domain) ("destroying dom %p with ctx_cnt %d", domain, domain->ctx_cnt)); KASSERT(domain->refs == 0, ("destroying dom %p with refs %d", domain, domain->refs)); - if ((domain->iodom.flags & DMAR_DOMAIN_GAS_INITED) != 0) { + if ((domain->iodom.flags & IOMMU_DOMAIN_GAS_INITED) != 0) { DMAR_DOMAIN_LOCK(domain); iommu_gas_fini_domain((struct iommu_domain *)domain); DMAR_DOMAIN_UNLOCK(domain); } - if ((domain->iodom.flags & DMAR_DOMAIN_PGTBL_INITED) != 0) { + if ((domain->iodom.flags & IOMMU_DOMAIN_PGTBL_INITED) != 0) { if (domain->pgtbl_obj != NULL) DMAR_DOMAIN_PGLOCK(domain); domain_free_pgtbl(domain); @@ -643,7 +644,7 @@ dmar_move_ctx_to_domain(struct dmar_domain *domain, struct dmar_ctx *ctx) /* If flush failed, rolling back would not work as well. */ printf("dmar%d rid %x domain %d->%d %s-mapped\n", dmar->iommu.unit, ctx->rid, old_domain->domain, domain->domain, - (domain->iodom.flags & DMAR_DOMAIN_IDMAP) != 0 ? "id" : "re"); + (domain->iodom.flags & IOMMU_DOMAIN_IDMAP) != 0 ? "id" : "re"); dmar_unref_domain_locked(dmar, old_domain); TD_PINNED_ASSERT; return (error); @@ -667,7 +668,7 @@ dmar_unref_domain_locked(struct dmar_unit *dmar, struct dmar_domain *domain) return; } - KASSERT((domain->iodom.flags & DMAR_DOMAIN_RMRR) == 0, + KASSERT((domain->iodom.flags & IOMMU_DOMAIN_RMRR) == 0, ("lost ref on RMRR domain %p", domain)); LIST_REMOVE(domain, link); @@ -848,7 +849,7 @@ dmar_domain_unload(struct dmar_domain *domain, KASSERT((entry->flags & IOMMU_MAP_ENTRY_MAP) != 0, ("not mapped entry %p %p", domain, entry)); error = domain_unmap_buf(domain, entry->start, entry->end - - entry->start, cansleep ? DMAR_PGF_WAITOK : 0); + entry->start, cansleep ? IOMMU_PGF_WAITOK : 0); KASSERT(error == 0, ("unmap %p error %d", domain, error)); if (!unit->qi_enabled) { domain_flush_iotlb_sync(domain, entry->start, diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c index 492846f9dfb1..a8a2bc7cf770 100644 --- a/sys/x86/iommu/intel_drv.c +++ b/sys/x86/iommu/intel_drv.c @@ -489,7 +489,7 @@ dmar_attach(device_t dev) * address translation after the required invalidations are * done. */ - dmar_pgalloc(unit->ctx_obj, 0, DMAR_PGF_WAITOK | DMAR_PGF_ZERO); + dmar_pgalloc(unit->ctx_obj, 0, IOMMU_PGF_WAITOK | IOMMU_PGF_ZERO); DMAR_LOCK(unit); error = dmar_load_root_entry_ptr(unit); if (error != 0) { @@ -944,7 +944,7 @@ dmar_rmrr_iter(ACPI_DMAR_HEADER *dmarh, void *arg) if (match == 1) { entry = iommu_gas_alloc_entry( (struct iommu_domain *)ria->domain, - DMAR_PGF_WAITOK); + IOMMU_PGF_WAITOK); entry->start = resmem->BaseAddress; /* The RMRR entry end address is inclusive. */ entry->end = resmem->EndAddress; diff --git a/sys/x86/iommu/intel_idpgtbl.c b/sys/x86/iommu/intel_idpgtbl.c index 89b3bf5d96d2..d85abefc54c4 100644 --- a/sys/x86/iommu/intel_idpgtbl.c +++ b/sys/x86/iommu/intel_idpgtbl.c @@ -121,8 +121,8 @@ domain_idmap_nextlvl(struct idpgtbl *tbl, int lvl, vm_pindex_t idx, VM_OBJECT_ASSERT_LOCKED(tbl->pgtbl_obj); if (addr >= tbl->maxaddr) return; - (void)dmar_pgalloc(tbl->pgtbl_obj, idx, DMAR_PGF_OBJL | DMAR_PGF_WAITOK | - DMAR_PGF_ZERO); + (void)dmar_pgalloc(tbl->pgtbl_obj, idx, IOMMU_PGF_OBJL | + IOMMU_PGF_WAITOK | IOMMU_PGF_ZERO); base = idx * DMAR_NPTEPG + 1; /* Index of the first child page of idx */ pg_sz = pglvl_page_size(tbl->pglvl, lvl); if (lvl != tbl->leaf) { @@ -130,7 +130,7 @@ domain_idmap_nextlvl(struct idpgtbl *tbl, int lvl, vm_pindex_t idx, domain_idmap_nextlvl(tbl, lvl + 1, base + i, f); } VM_OBJECT_WUNLOCK(tbl->pgtbl_obj); - pte = dmar_map_pgtbl(tbl->pgtbl_obj, idx, DMAR_PGF_WAITOK, &sf); + pte = dmar_map_pgtbl(tbl->pgtbl_obj, idx, IOMMU_PGF_WAITOK, &sf); if (lvl == tbl->leaf) { for (i = 0, f = addr; i < DMAR_NPTEPG; i++, f += pg_sz) { if (f >= tbl->maxaddr) @@ -143,7 +143,7 @@ domain_idmap_nextlvl(struct idpgtbl *tbl, int lvl, vm_pindex_t idx, if (f >= tbl->maxaddr) break; m1 = dmar_pgalloc(tbl->pgtbl_obj, base + i, - DMAR_PGF_NOALLOC); + IOMMU_PGF_NOALLOC); KASSERT(m1 != NULL, ("lost page table page")); pte[i].pte = (DMAR_PTE_ADDR_MASK & VM_PAGE_TO_PHYS(m1)) | DMAR_PTE_R | DMAR_PTE_W; @@ -362,7 +362,7 @@ domain_pgtbl_map_pte(struct dmar_domain *domain, iommu_gaddr_t base, int lvl, vm_pindex_t idx, idx1; DMAR_DOMAIN_ASSERT_PGLOCKED(domain); - KASSERT((flags & DMAR_PGF_OBJL) != 0, ("lost PGF_OBJL")); + KASSERT((flags & IOMMU_PGF_OBJL) != 0, ("lost PGF_OBJL")); idx = domain_pgtbl_get_pindex(domain, base, lvl); if (*sf != NULL && idx == *idxp) { @@ -382,7 +382,7 @@ domain_pgtbl_map_pte(struct dmar_domain *domain, iommu_gaddr_t base, int lvl, * to reference the allocated page table page. */ m = dmar_pgalloc(domain->pgtbl_obj, idx, flags | - DMAR_PGF_ZERO); + IOMMU_PGF_ZERO); if (m == NULL) return (NULL); @@ -435,7 +435,7 @@ domain_map_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base, base1 = base; size1 = size; - flags |= DMAR_PGF_OBJL; + flags |= IOMMU_PGF_OBJL; TD_PREP_PINNED_ASSERT; for (sf = NULL, pi = 0; size > 0; base += pg_sz, size -= pg_sz, @@ -478,7 +478,7 @@ domain_map_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base, KASSERT(pg_sz > 0, ("pg_sz 0 lvl %d", lvl)); pte = domain_pgtbl_map_pte(domain, base, lvl, flags, &idx, &sf); if (pte == NULL) { - KASSERT((flags & DMAR_PGF_WAITOK) == 0, + KASSERT((flags & IOMMU_PGF_WAITOK) == 0, ("failed waitable pte alloc %p", domain)); if (sf != NULL) dmar_unmap_pgtbl(sf); @@ -515,7 +515,7 @@ domain_map_buf(struct iommu_domain *iodom, iommu_gaddr_t base, domain = (struct dmar_domain *)iodom; unit = domain->dmar; - KASSERT((domain->iodom.flags & DMAR_DOMAIN_IDMAP) == 0, + KASSERT((domain->iodom.flags & IOMMU_DOMAIN_IDMAP) == 0, ("modifying idmap pagetable domain %p", domain)); KASSERT((base & DMAR_PAGE_MASK) == 0, ("non-aligned base %p %jx %jx", domain, (uintmax_t)base, @@ -547,7 +547,7 @@ domain_map_buf(struct iommu_domain *iodom, iommu_gaddr_t base, (unit->hw_ecap & DMAR_ECAP_DI) != 0, ("PTE_TM for dmar without DIOTLB %p %jx", domain, (uintmax_t)pflags)); - KASSERT((flags & ~DMAR_PGF_WAITOK) == 0, ("invalid flags %x", flags)); + KASSERT((flags & ~IOMMU_PGF_WAITOK) == 0, ("invalid flags %x", flags)); DMAR_DOMAIN_PGLOCK(domain); error = domain_map_buf_locked(domain, base, size, ma, pflags, flags); @@ -626,7 +626,7 @@ domain_unmap_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base, if (size == 0) return (0); - KASSERT((domain->iodom.flags & DMAR_DOMAIN_IDMAP) == 0, + KASSERT((domain->iodom.flags & IOMMU_DOMAIN_IDMAP) == 0, ("modifying idmap pagetable domain %p", domain)); KASSERT((base & DMAR_PAGE_MASK) == 0, ("non-aligned base %p %jx %jx", domain, (uintmax_t)base, @@ -643,10 +643,10 @@ domain_unmap_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base, KASSERT(base + size > base, ("size overflow %p %jx %jx", domain, (uintmax_t)base, (uintmax_t)size)); - KASSERT((flags & ~DMAR_PGF_WAITOK) == 0, ("invalid flags %x", flags)); + KASSERT((flags & ~IOMMU_PGF_WAITOK) == 0, ("invalid flags %x", flags)); pg_sz = 0; /* silence gcc */ - flags |= DMAR_PGF_OBJL; + flags |= IOMMU_PGF_OBJL; TD_PREP_PINNED_ASSERT; for (sf = NULL; size > 0; base += pg_sz, size -= pg_sz) { @@ -707,13 +707,13 @@ domain_alloc_pgtbl(struct dmar_domain *domain) domain->pgtbl_obj = vm_pager_allocate(OBJT_PHYS, NULL, IDX_TO_OFF(pglvl_max_pages(domain->pglvl)), 0, 0, NULL); DMAR_DOMAIN_PGLOCK(domain); - m = dmar_pgalloc(domain->pgtbl_obj, 0, DMAR_PGF_WAITOK | - DMAR_PGF_ZERO | DMAR_PGF_OBJL); + m = dmar_pgalloc(domain->pgtbl_obj, 0, IOMMU_PGF_WAITOK | + IOMMU_PGF_ZERO | IOMMU_PGF_OBJL); /* No implicit free of the top level page table page. */ m->ref_count = 1; DMAR_DOMAIN_PGUNLOCK(domain); DMAR_LOCK(domain->dmar); - domain->iodom.flags |= DMAR_DOMAIN_PGTBL_INITED; + domain->iodom.flags |= IOMMU_DOMAIN_PGTBL_INITED; DMAR_UNLOCK(domain->dmar); return (0); } @@ -727,16 +727,16 @@ domain_free_pgtbl(struct dmar_domain *domain) obj = domain->pgtbl_obj; if (obj == NULL) { KASSERT((domain->dmar->hw_ecap & DMAR_ECAP_PT) != 0 && - (domain->iodom.flags & DMAR_DOMAIN_IDMAP) != 0, + (domain->iodom.flags & IOMMU_DOMAIN_IDMAP) != 0, ("lost pagetable object domain %p", domain)); return; } DMAR_DOMAIN_ASSERT_PGLOCKED(domain); domain->pgtbl_obj = NULL; - if ((domain->iodom.flags & DMAR_DOMAIN_IDMAP) != 0) { + if ((domain->iodom.flags & IOMMU_DOMAIN_IDMAP) != 0) { put_idmap_pgtbl(obj); - domain->iodom.flags &= ~DMAR_DOMAIN_IDMAP; + domain->iodom.flags &= ~IOMMU_DOMAIN_IDMAP; return; } diff --git a/sys/x86/iommu/intel_utils.c b/sys/x86/iommu/intel_utils.c index 39ade22ac945..7e89465240af 100644 --- a/sys/x86/iommu/intel_utils.c +++ b/sys/x86/iommu/intel_utils.c @@ -262,22 +262,22 @@ dmar_pgalloc(vm_object_t obj, vm_pindex_t idx, int flags) vm_page_t m; int zeroed, aflags; - zeroed = (flags & DMAR_PGF_ZERO) != 0 ? VM_ALLOC_ZERO : 0; + zeroed = (flags & IOMMU_PGF_ZERO) != 0 ? VM_ALLOC_ZERO : 0; aflags = zeroed | VM_ALLOC_NOBUSY | VM_ALLOC_SYSTEM | VM_ALLOC_NODUMP | - ((flags & DMAR_PGF_WAITOK) != 0 ? VM_ALLOC_WAITFAIL : + ((flags & IOMMU_PGF_WAITOK) != 0 ? VM_ALLOC_WAITFAIL : VM_ALLOC_NOWAIT); for (;;) { - if ((flags & DMAR_PGF_OBJL) == 0) + if ((flags & IOMMU_PGF_OBJL) == 0) VM_OBJECT_WLOCK(obj); m = vm_page_lookup(obj, idx); - if ((flags & DMAR_PGF_NOALLOC) != 0 || m != NULL) { - if ((flags & DMAR_PGF_OBJL) == 0) + if ((flags & IOMMU_PGF_NOALLOC) != 0 || m != NULL) { + if ((flags & IOMMU_PGF_OBJL) == 0) VM_OBJECT_WUNLOCK(obj); break; } m = vm_page_alloc_contig(obj, idx, aflags, 1, 0, dmar_high, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT); - if ((flags & DMAR_PGF_OBJL) == 0) + if ((flags & IOMMU_PGF_OBJL) == 0) VM_OBJECT_WUNLOCK(obj); if (m != NULL) { if (zeroed && (m->flags & PG_ZERO) == 0) @@ -285,7 +285,7 @@ dmar_pgalloc(vm_object_t obj, vm_pindex_t idx, int flags) atomic_add_int(&dmar_tbl_pagecnt, 1); break; } - if ((flags & DMAR_PGF_WAITOK) == 0) + if ((flags & IOMMU_PGF_WAITOK) == 0) break; } return (m); @@ -296,14 +296,14 @@ dmar_pgfree(vm_object_t obj, vm_pindex_t idx, int flags) { vm_page_t m; - if ((flags & DMAR_PGF_OBJL) == 0) + if ((flags & IOMMU_PGF_OBJL) == 0) VM_OBJECT_WLOCK(obj); m = vm_page_grab(obj, idx, VM_ALLOC_NOCREAT); if (m != NULL) { vm_page_free(m); atomic_subtract_int(&dmar_tbl_pagecnt, 1); } - if ((flags & DMAR_PGF_OBJL) == 0) + if ((flags & IOMMU_PGF_OBJL) == 0) VM_OBJECT_WUNLOCK(obj); } @@ -314,39 +314,39 @@ dmar_map_pgtbl(vm_object_t obj, vm_pindex_t idx, int flags, vm_page_t m; bool allocated; - if ((flags & DMAR_PGF_OBJL) == 0) + if ((flags & IOMMU_PGF_OBJL) == 0) VM_OBJECT_WLOCK(obj); m = vm_page_lookup(obj, idx); - if (m == NULL && (flags & DMAR_PGF_ALLOC) != 0) { - m = dmar_pgalloc(obj, idx, flags | DMAR_PGF_OBJL); + if (m == NULL && (flags & IOMMU_PGF_ALLOC) != 0) { + m = dmar_pgalloc(obj, idx, flags | IOMMU_PGF_OBJL); allocated = true; } else allocated = false; if (m == NULL) { - if ((flags & DMAR_PGF_OBJL) == 0) + if ((flags & IOMMU_PGF_OBJL) == 0) VM_OBJECT_WUNLOCK(obj); return (NULL); } /* Sleepable allocations cannot fail. */ - if ((flags & DMAR_PGF_WAITOK) != 0) + if ((flags & IOMMU_PGF_WAITOK) != 0) VM_OBJECT_WUNLOCK(obj); sched_pin(); - *sf = sf_buf_alloc(m, SFB_CPUPRIVATE | ((flags & DMAR_PGF_WAITOK) + *sf = sf_buf_alloc(m, SFB_CPUPRIVATE | ((flags & IOMMU_PGF_WAITOK) == 0 ? SFB_NOWAIT : 0)); if (*sf == NULL) { sched_unpin(); if (allocated) { VM_OBJECT_ASSERT_WLOCKED(obj); - dmar_pgfree(obj, m->pindex, flags | DMAR_PGF_OBJL); + dmar_pgfree(obj, m->pindex, flags | IOMMU_PGF_OBJL); } - if ((flags & DMAR_PGF_OBJL) == 0) + if ((flags & IOMMU_PGF_OBJL) == 0) VM_OBJECT_WUNLOCK(obj); return (NULL); } - if ((flags & (DMAR_PGF_WAITOK | DMAR_PGF_OBJL)) == - (DMAR_PGF_WAITOK | DMAR_PGF_OBJL)) + if ((flags & (IOMMU_PGF_WAITOK | IOMMU_PGF_OBJL)) == + (IOMMU_PGF_WAITOK | IOMMU_PGF_OBJL)) VM_OBJECT_WLOCK(obj); - else if ((flags & (DMAR_PGF_WAITOK | DMAR_PGF_OBJL)) == 0) + else if ((flags & (IOMMU_PGF_WAITOK | IOMMU_PGF_OBJL)) == 0) VM_OBJECT_WUNLOCK(obj); return ((void *)sf_buf_kva(*sf)); } From 29f25856a4ad06b104019cd3e490e52f701518da Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sun, 26 Jul 2020 13:30:33 +0000 Subject: [PATCH 180/287] Bump __FreeBSD_version after introduction of lockless lookup to the VFS layer --- sys/sys/param.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/sys/param.h b/sys/sys/param.h index 25b9aedaa81c..e196d4038feb 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -60,7 +60,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1300101 /* Master, propagated to newvers */ +#define __FreeBSD_version 1300102 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, From 8550ddb2eac9677d27ea215880a5495e6e6e59ac Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Sun, 26 Jul 2020 15:10:33 +0000 Subject: [PATCH 181/287] chio: avoid out of bounds read ch_ces is alloacated with space for total_elem entries. CID: 1418536 Reported by: Coverity Scan Sponsored by: The FreeBSD Foundation --- bin/chio/chio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/chio/chio.c b/bin/chio/chio.c index 5a2a7ba215c3..3264db8bb18d 100644 --- a/bin/chio/chio.c +++ b/bin/chio/chio.c @@ -1144,7 +1144,7 @@ find_element(char *voltag, uint16_t *et, uint16_t *eu) /* * Now search the list the specified */ - for (elem = 0; elem <= total_elem; ++elem) { + for (elem = 0; elem < total_elem; ++elem) { ces = &ch_ces[elem]; From 820272c40891be7440dcdbec20acfa69ad1c1720 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Sun, 26 Jul 2020 16:30:01 +0000 Subject: [PATCH 182/287] linuxkpi: Include linux/sizes.h in dma-mapping.h Linux does the same, this avoids ifdef or extra includes in ported drivers. Reviewed by: emaste, hselasky Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25701 --- sys/compat/linuxkpi/common/include/linux/dma-mapping.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h index 2662923eb905..291bd4a8e7ce 100644 --- a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h +++ b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include From f12af2b387dfa1c7429e6a18959c32674cda3f79 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Sun, 26 Jul 2020 16:30:59 +0000 Subject: [PATCH 183/287] linuxkpi: Include hardirq.h in preempt.h and lockdep.h in hardirq.h Linux does the same, this avoids ifdef or extra includes in ported drivers. Reviewed by: emaste, hselasky Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25702 --- sys/compat/linuxkpi/common/include/linux/hardirq.h | 1 + sys/compat/linuxkpi/common/include/linux/preempt.h | 1 + 2 files changed, 2 insertions(+) diff --git a/sys/compat/linuxkpi/common/include/linux/hardirq.h b/sys/compat/linuxkpi/common/include/linux/hardirq.h index b8e4c95360f8..d338e11c5a6f 100644 --- a/sys/compat/linuxkpi/common/include/linux/hardirq.h +++ b/sys/compat/linuxkpi/common/include/linux/hardirq.h @@ -32,6 +32,7 @@ #define _LINUX_HARDIRQ_H_ #include +#include #include #include diff --git a/sys/compat/linuxkpi/common/include/linux/preempt.h b/sys/compat/linuxkpi/common/include/linux/preempt.h index bff8860c92e7..e19e7ee09a48 100644 --- a/sys/compat/linuxkpi/common/include/linux/preempt.h +++ b/sys/compat/linuxkpi/common/include/linux/preempt.h @@ -29,6 +29,7 @@ #ifndef _LINUX_PREEMPT_H_ #define _LINUX_PREEMPT_H_ +#include #include #define in_interrupt() \ From 0e4e9e8f3431b431297cd518875f7e530ec26de4 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Sun, 26 Jul 2020 16:31:49 +0000 Subject: [PATCH 184/287] linuxkpi: Add taint* defines This isn't used for us but allow us to port drivers more easily. Reviewed by: hselasky Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25703 --- sys/compat/linuxkpi/common/include/linux/kernel.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/compat/linuxkpi/common/include/linux/kernel.h b/sys/compat/linuxkpi/common/include/linux/kernel.h index 92c7da110dac..098f0493f659 100644 --- a/sys/compat/linuxkpi/common/include/linux/kernel.h +++ b/sys/compat/linuxkpi/common/include/linux/kernel.h @@ -593,4 +593,7 @@ linux_ratelimited(linux_ratelimit_t *rl) (is_signed(datatype) ? INT8_MIN : 0) \ ) +#define TAINT_WARN 0 +#define test_taint(x) (0) + #endif /* _LINUX_KERNEL_H_ */ From cdb6eebe089bfb6599f83b1643de5de309bfcf62 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Sun, 26 Jul 2020 17:21:24 +0000 Subject: [PATCH 185/287] Revert r363564 linux/sizes.h doesn't exists in base ... sorry. --- sys/compat/linuxkpi/common/include/linux/dma-mapping.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h index 291bd4a8e7ce..2662923eb905 100644 --- a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h +++ b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h @@ -38,7 +38,6 @@ #include #include #include -#include #include #include From e9c003e51a4747176dfc3dd4d5f3ce2b10871e10 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Sun, 26 Jul 2020 17:50:39 +0000 Subject: [PATCH 186/287] Remove commented-out lines describing the old never-implemented -t option. In 2018, r338094 removed the commented-out code for supporting the -t command line option which had been present since the BSD 4.4 Lite import, but was never implemented for freebsd. This does the same for the man page. --- usr.bin/vmstat/vmstat.8 | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/usr.bin/vmstat/vmstat.8 b/usr.bin/vmstat/vmstat.8 index 36ebac41eb6a..1d7e5956a2fa 100644 --- a/usr.bin/vmstat/vmstat.8 +++ b/usr.bin/vmstat/vmstat.8 @@ -28,7 +28,7 @@ .\" @(#)vmstat.8 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ .\" -.Dd May 26, 2020 +.Dd July 26, 2020 .Dt VMSTAT 8 .Os .Sh NAME @@ -209,9 +209,6 @@ Display the contents of the .Em sum structure, giving the total number of several kinds of paging related events which have occurred since system startup. -.\" .It Fl t -.\" Report on the number of page in and page reclaims since system startup, -.\" and the amount of time required by each. .It Fl w Pause .Ar wait From d63a631e72441687910b8ec4a9396ac5d05029fb Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Sun, 26 Jul 2020 18:15:16 +0000 Subject: [PATCH 187/287] Add Goldfish RTC device driver for RISC-V This device was originally used as part of the goldfish virtual hardware platform used for emulating Android on QEMU, but is now also used as the RTC for the RISC-V virt machine in QEMU. It provides a simple 64-bit nanosecond timer exposed via a pair of memory-mapped 32-bit registers, although only with 1s granularity. Reviewed by: brooks (mentor), jhb (mentor), kp Approved by: brooks (mentor), jhb (mentor), kp Obtained from: CheriBSD Differential Revision: https://reviews.freebsd.org/D25717 --- sys/conf/files | 1 + sys/dev/goldfish/goldfish_rtc.c | 182 ++++++++++++++++++++++++++++++++ sys/riscv/conf/GENERIC | 2 + 3 files changed, 185 insertions(+) create mode 100644 sys/dev/goldfish/goldfish_rtc.c diff --git a/sys/conf/files b/sys/conf/files index da06f0250d3e..63f3eecaf0ad 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1736,6 +1736,7 @@ dev/fxp/if_fxp.c optional fxp dev/fxp/inphy.c optional fxp dev/gem/if_gem.c optional gem dev/gem/if_gem_pci.c optional gem pci +dev/goldfish/goldfish_rtc.c optional goldfish_rtc fdt dev/gpio/dwgpio/dwgpio.c optional gpio dwgpio fdt dev/gpio/dwgpio/dwgpio_bus.c optional gpio dwgpio fdt dev/gpio/dwgpio/dwgpio_if.m optional gpio dwgpio fdt diff --git a/sys/dev/goldfish/goldfish_rtc.c b/sys/dev/goldfish/goldfish_rtc.c new file mode 100644 index 000000000000..d1c2b6627ae2 --- /dev/null +++ b/sys/dev/goldfish/goldfish_rtc.c @@ -0,0 +1,182 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Jessica Clarke + * + * 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. + */ + +/* + * RTC for the goldfish virtual hardware platform implemented in QEMU, + * initially for Android but now also used for RISC-V's virt machine. + * + * https://android.googlesource.com/platform/external/qemu/+/master/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "clock_if.h" + +#define GOLDFISH_RTC_TIME_LOW 0x00 +#define GOLDFISH_RTC_TIME_HIGH 0x04 + +struct goldfish_rtc_softc { + struct resource *res; + int rid; + struct mtx mtx; +}; + +static int +goldfish_rtc_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_is_compatible(dev, "google,goldfish-rtc")) { + device_set_desc(dev, "Goldfish RTC"); + return (BUS_PROBE_DEFAULT); + } + + return (ENXIO); +} + +static int +goldfish_rtc_attach(device_t dev) +{ + struct goldfish_rtc_softc *sc; + + sc = device_get_softc(dev); + + sc->rid = 0; + sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, + RF_ACTIVE); + if (sc->res == NULL) { + device_printf(dev, "could not allocate resource\n"); + return (ENXIO); + } + + mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); + + /* + * Register as a system realtime clock with 1 second resolution. + */ + clock_register_flags(dev, 1000000, CLOCKF_SETTIME_NO_ADJ); + clock_schedule(dev, 1); + + return (0); +} + +static int +goldfish_rtc_detach(device_t dev) +{ + struct goldfish_rtc_softc *sc; + + sc = device_get_softc(dev); + + clock_unregister(dev); + mtx_destroy(&sc->mtx); + bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); + + return (0); +} + +static int +goldfish_rtc_gettime(device_t dev, struct timespec *ts) +{ + struct goldfish_rtc_softc *sc; + uint64_t low, high, nsec; + + sc = device_get_softc(dev); + + /* + * Reading TIME_HIGH is defined in the documentation to give the high + * 32 bits corresponding to the last TIME_LOW read, so must be done in + * that order, but means we have atomicity guaranteed. + */ + mtx_lock(&sc->mtx); + low = bus_read_4(sc->res, GOLDFISH_RTC_TIME_LOW); + high = bus_read_4(sc->res, GOLDFISH_RTC_TIME_HIGH); + mtx_unlock(&sc->mtx); + + nsec = (high << 32) | low; + ts->tv_sec = nsec / 1000000000; + ts->tv_nsec = nsec % 1000000000; + + return (0); +} + +static int +goldfish_rtc_settime(device_t dev, struct timespec *ts) +{ + struct goldfish_rtc_softc *sc; + uint64_t nsec; + + sc = device_get_softc(dev); + + nsec = (uint64_t)ts->tv_sec * 1000000000 + ts->tv_nsec; + + mtx_lock(&sc->mtx); + bus_write_4(sc->res, GOLDFISH_RTC_TIME_HIGH, nsec >> 32); + bus_write_4(sc->res, GOLDFISH_RTC_TIME_LOW, nsec); + mtx_unlock(&sc->mtx); + + return (0); +} + +static device_method_t goldfish_rtc_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, goldfish_rtc_probe), + DEVMETHOD(device_attach, goldfish_rtc_attach), + DEVMETHOD(device_detach, goldfish_rtc_detach), + + /* Clock interface */ + DEVMETHOD(clock_gettime, goldfish_rtc_gettime), + DEVMETHOD(clock_settime, goldfish_rtc_settime), + + DEVMETHOD_END, +}; + +DEFINE_CLASS_0(goldfish_rtc, goldfish_rtc_driver, goldfish_rtc_methods, + sizeof(struct goldfish_rtc_softc)); +static devclass_t goldfish_rtc_devclass; + +DRIVER_MODULE(goldfish_rtc, simplebus, goldfish_rtc_driver, + goldfish_rtc_devclass, NULL, NULL); diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC index 6086229b640c..2d26d28f8539 100644 --- a/sys/riscv/conf/GENERIC +++ b/sys/riscv/conf/GENERIC @@ -101,6 +101,8 @@ device uart # Generic UART driver device uart_lowrisc # lowRISC UART driver device uart_ns8250 # ns8250-type UART driver +# RTC +device goldfish_rtc # QEMU RTC # Ethernet drivers device miibus # MII bus support From 4f8212c8b28fe5d87e9109cfc0e19c9396c97e8f Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Sun, 26 Jul 2020 18:17:36 +0000 Subject: [PATCH 188/287] loader: Avoid -Wpointer-to-int cast warnings for Arm and RISC-V On RISC-V, Clang warns with: cast to smaller integer type 'unsigned int' from 'void (*)(void *)' Instead, use %p as the standard format specifier for printing pointers. Whilst Arm's pointer size is the same as unsigned, it's still cleaner to use the right thing there too. Reviewed by: brooks (mentor), emaste Approved by: brooks (mentor), emaste Differential Revision: https://reviews.freebsd.org/D25718 --- stand/efi/loader/arch/arm/exec.c | 2 +- stand/efi/loader/arch/riscv/exec.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stand/efi/loader/arch/arm/exec.c b/stand/efi/loader/arch/arm/exec.c index 5fdf8e3daa39..86c931bcbbe8 100644 --- a/stand/efi/loader/arch/arm/exec.c +++ b/stand/efi/loader/arch/arm/exec.c @@ -77,7 +77,7 @@ __elfN(arm_exec)(struct preloaded_file *fp) entry = efi_translate(e->e_entry); - printf("Kernel entry at 0x%x...\n", (unsigned)entry); + printf("Kernel entry at %p...\n", entry); printf("Kernel args: %s\n", fp->f_args); if ((error = bi_load(fp->f_args, &modulep, &kernend)) != 0) { diff --git a/stand/efi/loader/arch/riscv/exec.c b/stand/efi/loader/arch/riscv/exec.c index 7803932184cd..fe40003a475b 100644 --- a/stand/efi/loader/arch/riscv/exec.c +++ b/stand/efi/loader/arch/riscv/exec.c @@ -63,7 +63,7 @@ __elfN(exec)(struct preloaded_file *fp) entry = efi_translate(e->e_entry); - printf("Kernel entry at 0x%x...\n", (unsigned)entry); + printf("Kernel entry at %p...\n", entry); printf("Kernel args: %s\n", fp->f_args); if ((error = bi_load(fp->f_args, &modulep, &kernend)) != 0) { From 28da7c9ed0f28f79a819b4003b32e81a3fdf55b5 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Sun, 26 Jul 2020 18:19:50 +0000 Subject: [PATCH 189/287] Add syscon power and reset control device driver This device driver supports both syscon-power and syscon-reset devices, as specified in [1] and [2]. These provide a very simple interface for power and reset control, and among other things are used by QEMU's virt machine on RISC-V. A separate commit will enable this on RISC-V, as that requires adding a RISC-V-specific riscv_syscon akin to r327936's aw_syscon. [1] https://www.kernel.org/doc/Documentation/devicetree/bindings/power/reset/syscon-poweroff.txt [2] https://www.kernel.org/doc/Documentation/devicetree/bindings/power/reset/syscon-reboot.txt Reviewed by: brooks (mentor), jhb (mentor) Approved by: brooks (mentor), jhb (mentor) Obtained from: CheriBSD Differential Revision: https://reviews.freebsd.org/D25724 --- sys/conf/files | 1 + sys/dev/extres/syscon/syscon_power.c | 198 +++++++++++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 sys/dev/extres/syscon/syscon_power.c diff --git a/sys/conf/files b/sys/conf/files index 63f3eecaf0ad..8ed21c37d214 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1702,6 +1702,7 @@ dev/extres/regulator/regulator_fixed.c optional ext_resources regulator fdt dev/extres/syscon/syscon.c optional ext_resources syscon dev/extres/syscon/syscon_generic.c optional ext_resources syscon fdt dev/extres/syscon/syscon_if.m optional ext_resources syscon +dev/extres/syscon/syscon_power.c optional ext_resources syscon syscon_power fdt dev/fb/fbd.c optional fbd | vt dev/fb/fb_if.m standard dev/fb/splash.c optional sc splash diff --git a/sys/dev/extres/syscon/syscon_power.c b/sys/dev/extres/syscon/syscon_power.c new file mode 100644 index 000000000000..586af0102713 --- /dev/null +++ b/sys/dev/extres/syscon/syscon_power.c @@ -0,0 +1,198 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Jessica Clarke + * + * 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. + */ + +/* + * Driver for simple syscon poweroff and reset devices. The device tree + * specifications are fully described at: + * + * https://www.kernel.org/doc/Documentation/devicetree/bindings/power/reset/syscon-poweroff.txt + * https://www.kernel.org/doc/Documentation/devicetree/bindings/power/reset/syscon-reboot.txt + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "syscon_if.h" +#include "syscon.h" + +struct syscon_power_softc { + struct syscon *regmap; + uint32_t offset; + uint32_t value; + uint32_t mask; + bool reboot; + eventhandler_tag shutdown_tag; +}; + +static void +syscon_power_shutdown_final(device_t dev, int howto) +{ + struct syscon_power_softc *sc; + bool write; + + sc = device_get_softc(dev); + if (sc->reboot) + write = (howto & RB_HALT) == 0; + else + write = (howto & RB_POWEROFF) != 0; + + if (write) + SYSCON_MODIFY_4(sc->regmap, sc->offset, sc->mask, + sc->value & sc->mask); +} + +static int +syscon_power_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_is_compatible(dev, "syscon-poweroff")) { + device_set_desc(dev, "Syscon poweroff"); + return (BUS_PROBE_DEFAULT); + } else if (ofw_bus_is_compatible(dev, "syscon-reboot")) { + device_set_desc(dev, "Syscon reboot"); + return (BUS_PROBE_DEFAULT); + } + + return (ENXIO); +} + +static int +syscon_power_attach(device_t dev) +{ + struct syscon_power_softc *sc; + phandle_t node; + int error, len; + bool has_mask; + + sc = device_get_softc(dev); + node = ofw_bus_get_node(dev); + + if (!OF_hasprop(node, "regmap")) { + device_printf(dev, "could not find regmap\n"); + return (ENXIO); + } + + error = syscon_get_by_ofw_property(dev, node, "regmap", &sc->regmap); + if (error != 0) { + device_printf(dev, "could not get syscon\n"); + return (ENXIO); + } + + len = OF_getproplen(node, "offset"); + if (len != 4) { + device_printf(dev, "could not get offset\n"); + return (ENXIO); + } + + OF_getencprop(node, "offset", &sc->offset, sizeof(sc->offset)); + + /* Optional mask */ + has_mask = OF_hasprop(node, "mask"); + if (has_mask) { + len = OF_getproplen(node, "mask"); + if (len != 4) { + device_printf(dev, "cannot handle mask\n"); + return (ENXIO); + } + + OF_getencprop(node, "mask", &sc->mask, sizeof(sc->mask)); + } else { + sc->mask = 0xffffffff; + } + + /* + * From the device tree specification: + * + * Legacy usage: If a node doesn't contain a value property but + * contains a mask property, the mask property is used as the value. + */ + if (!OF_hasprop(node, "value")) { + if (!has_mask) { + device_printf(dev, "must have a value or a mask\n"); + return (ENXIO); + } + + sc->value = sc->mask; + } else { + len = OF_getproplen(node, "value"); + if (len != 4) { + device_printf(dev, "cannot handle value\n"); + return (ENXIO); + } + + OF_getencprop(node, "value", &sc->value, sizeof(sc->value)); + } + + sc->reboot = ofw_bus_is_compatible(dev, "syscon-reboot"); + sc->shutdown_tag = EVENTHANDLER_REGISTER(shutdown_final, + syscon_power_shutdown_final, dev, SHUTDOWN_PRI_LAST); + + return (0); +} + +static int +syscon_power_detach(device_t dev) +{ + struct syscon_power_softc *sc; + + sc = device_get_softc(dev); + EVENTHANDLER_DEREGISTER(shutdown_final, sc->shutdown_tag); + + return (0); +} + +static device_method_t syscon_power_methods[] = { + DEVMETHOD(device_probe, syscon_power_probe), + DEVMETHOD(device_attach, syscon_power_attach), + DEVMETHOD(device_detach, syscon_power_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(syscon_power, syscon_power_driver, syscon_power_methods, + sizeof(struct syscon_power_softc)); +static devclass_t syscon_power_devclass; + +DRIVER_MODULE(syscon_power, simplebus, syscon_power_driver, + syscon_power_devclass, NULL, NULL); From 825240034e019236c352f48d7651bd060e296400 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Sun, 26 Jul 2020 18:21:02 +0000 Subject: [PATCH 190/287] riscv: Include syscon_power device driver in GENERIC kernel config QEMU's RISC-V virt machine provides syscon-power and syscon-reset devices as the means by which to shutdown and reboot. We also need to ensure that we have attached the syscon_generic device before attaching any syscon_power devices, and so we introduce a new riscv_syscon device akin to aw_syscon added in r327936. Currently the SiFive test finisher is used as the specific implementation of such a syscon device. Reviewed by: br, brooks (mentor), jhb (mentor) Approved by: br, brooks (mentor), jhb (mentor) Obtained from: CheriBSD Differential Revision: https://reviews.freebsd.org/D25725 --- sys/conf/files.riscv | 1 + sys/riscv/conf/GENERIC | 7 +++ sys/riscv/riscv/riscv_syscon.c | 84 ++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 sys/riscv/riscv/riscv_syscon.c diff --git a/sys/conf/files.riscv b/sys/conf/files.riscv index aad690e59105..06593cc5aa7e 100644 --- a/sys/conf/files.riscv +++ b/sys/conf/files.riscv @@ -57,6 +57,7 @@ riscv/riscv/ofw_machdep.c optional fdt riscv/riscv/plic.c standard riscv/riscv/pmap.c standard riscv/riscv/riscv_console.c optional rcons +riscv/riscv/riscv_syscon.c optional ext_resources syscon riscv_syscon fdt riscv/riscv/sbi.c standard riscv/riscv/soc.c standard riscv/riscv/stack_machdep.c optional ddb | stack diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC index 2d26d28f8539..7caee97e7912 100644 --- a/sys/riscv/conf/GENERIC +++ b/sys/riscv/conf/GENERIC @@ -77,6 +77,13 @@ options INTRNG # RISC-V SBI console device rcons +# EXT_RESOURCES pseudo devices +options EXT_RESOURCES +device clk +device syscon +device syscon_power +device riscv_syscon + # Bus drivers device pci diff --git a/sys/riscv/riscv/riscv_syscon.c b/sys/riscv/riscv/riscv_syscon.c new file mode 100644 index 000000000000..8613b298b797 --- /dev/null +++ b/sys/riscv/riscv/riscv_syscon.c @@ -0,0 +1,84 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 Kyle Evans + * Copyright (c) 2020 Jessica Clarke + * + * 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. + */ + +/* + * RISC-V syscon driver. Used as a generic interface by QEMU's virt machine for + * describing the SiFive test finisher as a power and reset controller. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +static struct ofw_compat_data compat_data[] = { + {"sifive,test0", 1}, + {"sifive,test1", 1}, + {NULL, 0} +}; + +static int +riscv_syscon_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "RISC-V syscon"); + return (BUS_PROBE_DEFAULT); +} + +static device_method_t riscv_syscon_methods[] = { + DEVMETHOD(device_probe, riscv_syscon_probe), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(riscv_syscon, riscv_syscon_driver, riscv_syscon_methods, + sizeof(struct syscon_generic_softc), syscon_generic_driver); + +static devclass_t riscv_syscon_devclass; +/* riscv_syscon needs to attach prior to syscon_power */ +EARLY_DRIVER_MODULE(riscv_syscon, simplebus, riscv_syscon_driver, + riscv_syscon_devclass, 0, 0, BUS_PASS_SCHEDULER + BUS_PASS_ORDER_LAST); +MODULE_VERSION(riscv_syscon, 1); From 85d787b2fefc1a53280009680523ccbb09211b9d Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Sun, 26 Jul 2020 18:33:29 +0000 Subject: [PATCH 191/287] Fix r363565 lockdep.h needs sys/lock.h for LOCK_CLASS --- sys/compat/linuxkpi/common/include/linux/lockdep.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/compat/linuxkpi/common/include/linux/lockdep.h b/sys/compat/linuxkpi/common/include/linux/lockdep.h index d3e3d04db9ee..d2b3d4485dde 100644 --- a/sys/compat/linuxkpi/common/include/linux/lockdep.h +++ b/sys/compat/linuxkpi/common/include/linux/lockdep.h @@ -32,6 +32,8 @@ #ifndef _LINUX_LOCKDEP_H_ #define _LINUX_LOCKDEP_H_ +#include + struct lock_class_key { }; From 336ab722d2745aa4dab6510d038c36954ffb2a5c Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Sun, 26 Jul 2020 18:33:29 +0000 Subject: [PATCH 192/287] Describe the value in the 're' column of vmstat(8) in terms of freebsd's vm implementation. The old description was left over from the 4.4 BSD Lite import in 1994, and was a bit misleading (not all arches use simulated reference bits, some implement reference tracking in hardware). --- usr.bin/vmstat/vmstat.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr.bin/vmstat/vmstat.8 b/usr.bin/vmstat/vmstat.8 index 1d7e5956a2fa..b9c23dee50cf 100644 --- a/usr.bin/vmstat/vmstat.8 +++ b/usr.bin/vmstat/vmstat.8 @@ -283,7 +283,7 @@ These are given in units per second. .It flt total number of page faults .It re -page reclaims (simulating reference bits) +pages reactivated (found in laundry or inactive queues) .\" .It at .\" pages attached (found in free list) .It pi From 178d88fa397919d7627325a8911bb724968b232e Mon Sep 17 00:00:00 2001 From: Xin LI Date: Sun, 26 Jul 2020 22:30:01 +0000 Subject: [PATCH 193/287] geom_map and geom_redboot: Remove unused ctlreq handler. The two classes do not take any verbs and always gctl_error for all requests, so don't bother to provide a ctlreq handler. Reviewed by: mav MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D25810 --- sys/geom/geom_map.c | 13 ------------- sys/geom/geom_redboot.c | 13 ------------- 2 files changed, 26 deletions(-) diff --git a/sys/geom/geom_map.c b/sys/geom/geom_map.c index fcdba38c8055..e5f1cb649421 100644 --- a/sys/geom/geom_map.c +++ b/sys/geom/geom_map.c @@ -387,24 +387,11 @@ g_map_taste(struct g_class *mp, struct g_provider *pp, int insist __unused) return (gp); } -static void -g_map_config(struct gctl_req *req, struct g_class *mp, const char *verb) -{ - struct g_geom *gp; - - g_topology_assert(); - gp = gctl_get_geom(req, mp, "geom"); - if (gp == NULL) - return; - gctl_error(req, "Unknown verb"); -} - static struct g_class g_map_class = { .name = MAP_CLASS_NAME, .version = G_VERSION, .taste = g_map_taste, .dumpconf = g_map_dumpconf, - .ctlreq = g_map_config, }; DECLARE_GEOM_CLASS(g_map_class, g_map); MODULE_VERSION(geom_map, 0); diff --git a/sys/geom/geom_redboot.c b/sys/geom/geom_redboot.c index febee5bd8377..ffdb64d16274 100644 --- a/sys/geom/geom_redboot.c +++ b/sys/geom/geom_redboot.c @@ -336,24 +336,11 @@ g_redboot_taste(struct g_class *mp, struct g_provider *pp, int insist) return (gp); } -static void -g_redboot_config(struct gctl_req *req, struct g_class *mp, const char *verb) -{ - struct g_geom *gp; - - g_topology_assert(); - gp = gctl_get_geom(req, mp, "geom"); - if (gp == NULL) - return; - gctl_error(req, "Unknown verb"); -} - static struct g_class g_redboot_class = { .name = REDBOOT_CLASS_NAME, .version = G_VERSION, .taste = g_redboot_taste, .dumpconf = g_redboot_dumpconf, - .ctlreq = g_redboot_config, .ioctl = g_redboot_ioctl, }; DECLARE_GEOM_CLASS(g_redboot_class, g_redboot); From a450ecfdbd954f5b10a3b6eb74b1cd863b2b5c1c Mon Sep 17 00:00:00 2001 From: Xin LI Date: Sun, 26 Jul 2020 22:30:55 +0000 Subject: [PATCH 194/287] gctl_get_geom: Skip validation of g_class. The caller from kernel is expected to provide an valid g_class pointer, instead of traversing the global g_class list, just use that pointer directly instead. Reviewed by: mav MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D25811 --- sys/geom/geom.h | 2 +- sys/geom/geom_ctl.c | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/sys/geom/geom.h b/sys/geom/geom.h index 46ec01e6c94a..25cf0131355d 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -434,7 +434,7 @@ void *gctl_get_paraml(struct gctl_req *req, const char *param, int len); void *gctl_get_paraml_opt(struct gctl_req *req, const char *param, int len); int gctl_error(struct gctl_req *req, const char *fmt, ...) __printflike(2, 3); struct g_class *gctl_get_class(struct gctl_req *req, char const *arg); -struct g_geom *gctl_get_geom(struct gctl_req *req, struct g_class *mpr, char const *arg); +struct g_geom *gctl_get_geom(struct gctl_req *req, struct g_class *mp, char const *arg); struct g_provider *gctl_get_provider(struct gctl_req *req, char const *arg); #endif /* _GEOM_GEOM_H_ */ diff --git a/sys/geom/geom_ctl.c b/sys/geom/geom_ctl.c index 8b9af1aa54ab..7dbe012a3320 100644 --- a/sys/geom/geom_ctl.c +++ b/sys/geom/geom_ctl.c @@ -409,25 +409,20 @@ gctl_get_class(struct gctl_req *req, char const *arg) } struct g_geom * -gctl_get_geom(struct gctl_req *req, struct g_class *mpr, char const *arg) +gctl_get_geom(struct gctl_req *req, struct g_class *mp, char const *arg) { char const *p; - struct g_class *mp; struct g_geom *gp; + MPASS(mp != NULL); p = gctl_get_asciiparam(req, arg); if (p == NULL) { gctl_error(req, "Missing %s argument", arg); return (NULL); } - LIST_FOREACH(mp, &g_classes, class) { - if (mpr != NULL && mpr != mp) - continue; - LIST_FOREACH(gp, &mp->geom, geom) { - if (!strcmp(p, gp->name)) - return (gp); - } - } + LIST_FOREACH(gp, &mp->geom, geom) + if (!strcmp(p, gp->name)) + return (gp); gctl_error(req, "Geom not found: \"%s\"", p); return (NULL); } From 2de592f6e14d3a4c1803146fd4c2252a1827a957 Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Sun, 26 Jul 2020 23:03:41 +0000 Subject: [PATCH 195/287] Fix the NFS server so that it sets va_birthtime. r362490 marked that the NFSv4 attribute TimeCreate (va_birthtime) is supported, but it did not change the NFS server code to actually do it. As such, errors could occur when unrolling a tarball onto an NFSv4 mounted volume, since setting TimeCreate would fail with a NFSERR_ATTRNOTSUPP reply. This patch fixes the server so that it does TimeCreate and also makes sure that TimeCreate will not be set for a DS file for a pNFS server. A separate commit will add a check to the NFSv4 client for support of the TimeCreate attribute before attempting to set it, to avoid a problem when mounting a server that does not support the attribute. The failures will still occur for r362490 or later kernels that do not have this patch, since they indicate support for the attribute, but do not actually support the attribute. --- sys/fs/nfsserver/nfs_nfsdport.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index fbe77fcaf9b6..34066585c3a3 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -459,6 +459,7 @@ nfsvno_setattr(struct vnode *vp, struct nfsvattr *nvap, struct ucred *cred, { u_quad_t savsize = 0; int error, savedit; + time_t savbtime; /* * If this is an exported file system and a pNFS service is running, @@ -490,9 +491,13 @@ nfsvno_setattr(struct vnode *vp, struct nfsvattr *nvap, struct ucred *cred, nvap->na_vattr.va_mode != (mode_t)VNOVAL || nvap->na_vattr.va_atime.tv_sec != VNOVAL || nvap->na_vattr.va_mtime.tv_sec != VNOVAL)) { + /* Never modify birthtime on a DS file. */ + savbtime = nvap->na_vattr.va_birthtime.tv_sec; + nvap->na_vattr.va_birthtime.tv_sec = VNOVAL; /* For a pNFS server, set the attributes on the DS file. */ error = nfsrv_proxyds(vp, 0, 0, cred, p, NFSPROC_SETATTR, NULL, NULL, NULL, nvap, NULL, NULL, 0, NULL); + nvap->na_vattr.va_birthtime.tv_sec = savbtime; if (error == ENOENT) error = 0; } @@ -2914,8 +2919,7 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap, break; case NFSATTRBIT_TIMECREATE: NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); - if (!nd->nd_repstat) - nd->nd_repstat = NFSERR_ATTRNOTSUPP; + fxdr_nfsv4time(tl, &nvap->na_btime); attrsum += NFSX_V4TIME; break; case NFSATTRBIT_TIMEMODIFYSET: From 194d870481f8cb2d25d7125b2e1609d5c5d202f7 Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Sun, 26 Jul 2020 23:13:10 +0000 Subject: [PATCH 196/287] Fix the NFSv4 client so that it checks for support of TimeCreate before trying to set it. r362490 added support for setting of the TimeCreate (va_birthtime) attribute, but it does so without checking to see if the server supports the attribute. This could result in NFSERR_ATTRNOTSUPP error replies to the Setattr operation. This patch adds code to check that the server supports TimeCreate before attempting to do a Setattr of it to avoid these error returns. --- sys/fs/nfs/nfs_commonsubs.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index 51baee32616e..d9e03cf7b791 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -504,6 +504,7 @@ nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap, u_int32_t *tl; struct nfsv2_sattr *sp; nfsattrbit_t attrbits; + struct nfsnode *np; switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) { case ND_NFSV2: @@ -605,8 +606,18 @@ nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap, NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET); if (vap->va_mtime.tv_sec != VNOVAL) NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET); - if (vap->va_birthtime.tv_sec != VNOVAL) - NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE); + if (vap->va_birthtime.tv_sec != VNOVAL && + strcmp(vp->v_mount->mnt_vfc->vfc_name, "nfs") == 0) { + /* + * We can only test for support of TimeCreate if + * the "vp" argument is for an NFS vnode. + */ + np = VTONFS(vp); + if (NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, + NFSATTRBIT_TIMECREATE)) + NFSSETBIT_ATTRBIT(&attrbits, + NFSATTRBIT_TIMECREATE); + } (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0, &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL); break; From 0ae0e8d2bdb90405f3b67adbe80d90fd769cba00 Mon Sep 17 00:00:00 2001 From: Matt Macy Date: Mon, 27 Jul 2020 01:17:59 +0000 Subject: [PATCH 197/287] iflib: fix LOR with bpf detach Reported by: grehan@ Approved by: grehan@ MFC after: 1 week Sponsored by: Netgate Differential Revision: https://reviews.freebsd.org/D25530 --- sys/net/iflib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/net/iflib.c b/sys/net/iflib.c index f87b31251ffe..9a37f30b43f6 100644 --- a/sys/net/iflib.c +++ b/sys/net/iflib.c @@ -4192,7 +4192,9 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { if ((if_getflags(ifp) ^ ctx->ifc_if_flags) & (IFF_PROMISC | IFF_ALLMULTI)) { + CTX_UNLOCK(ctx); err = IFDI_PROMISC_SET(ctx, if_getflags(ifp)); + CTX_LOCK(ctx); } } else reinit = 1; From bb97350f2838ef4272ada92cc73182a3ea925498 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Mon, 27 Jul 2020 03:13:23 +0000 Subject: [PATCH 198/287] makesyscalls.sh: spit out a deprecation notice to stderr This has for a while been replaced by makesyscalls.lua in the stock FreeBSD build. Ensure downstreams get some notice that it'a going away if they're reliant on it, maybe. --- sys/kern/makesyscalls.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/kern/makesyscalls.sh b/sys/kern/makesyscalls.sh index 5a0fcfedfb1a..8ee34837ccfb 100644 --- a/sys/kern/makesyscalls.sh +++ b/sys/kern/makesyscalls.sh @@ -60,6 +60,8 @@ case $# in ;; esac +1>&2 echo "$0: This script is deprecated and will be removed before FreeBSD 13." + if [ -n "$2" ]; then . "$2" fi From 9af3bcd7c977f2132135cfd609f1c727dcfb8d20 Mon Sep 17 00:00:00 2001 From: Peter Grehan Date: Mon, 27 Jul 2020 07:56:55 +0000 Subject: [PATCH 199/287] Support the setting of additional AHCI controller parameters. Allow the serial number, firmware revision, model number and nominal media rotation rate (nmrr) parameters to be set from the command line. Note that setting the nmrr value can be used to indicate the AHCI device is an SSD. Submitted by: Wanpeng Qian Reviewed by: jhb, grehan (#bhyve) Approved by: jhb, grehan MFC after: 3 weeks Relnotes: yes Differential Revision: https://reviews.freebsd.org/D24174 --- usr.sbin/bhyve/bhyve.8 | 12 ++ usr.sbin/bhyve/pci_ahci.c | 308 +++++++++++++++++++++++--------------- 2 files changed, 201 insertions(+), 119 deletions(-) diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index e92b39cc6825..2e91ed86d3a1 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -540,6 +540,18 @@ Sector size (defaults to blockif sector size). Serial number with maximum 20 characters. .El .Pp +AHCI devices: +.Bl -tag -width 10n +.It Li nmrr +Nominal Media Rotation Rate, known as RPM. value 1 will indicate device as Solid State Disk. default value is 0, not report. +.It Li ser +Serial Number with maximum 20 characters. +.It Li rev +Revision Number with maximum 8 characters. +.It Li model +Model Number with maximum 40 characters. +.El +.Pp HD Audio devices: .Bl -tag -width 10n .It Li play diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c index 49e6452a355d..6cc0b3b65ef2 100644 --- a/usr.sbin/bhyve/pci_ahci.c +++ b/usr.sbin/bhyve/pci_ahci.c @@ -139,9 +139,9 @@ struct ahci_ioreq { struct ahci_port { struct blockif_ctxt *bctx; struct pci_ahci_softc *pr_sc; + struct ata_params ata_ident; uint8_t *cmd_lst; uint8_t *rfis; - char ident[AHCI_PORT_IDENT]; int port; int atapi; int reset; @@ -987,7 +987,49 @@ handle_identify(struct ahci_port *p, int slot, uint8_t *cfis) ahci_write_fis_d2h(p, slot, cfis, (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); } else { - uint16_t buf[256]; + ahci_write_fis_piosetup(p); + write_prdt(p, slot, cfis, (void*)&p->ata_ident, sizeof(struct ata_params)); + ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY); + } +} + +static void +ata_identify_init(struct ahci_port* p, int atapi) +{ + struct ata_params* ata_ident = &p->ata_ident; + + if (atapi) { + ata_ident->config = (2 << 14 | 5 << 8 | 1 << 7 | 2 << 5); + ata_ident->capabilities1 = ATA_SUPPORT_LBA | + ATA_SUPPORT_DMA; + ata_ident->capabilities2 = (1 << 14 | 1); + ata_ident->atavalid = ATA_FLAG_54_58 | ATA_FLAG_64_70; + ata_ident->obsolete62 = 0x3f; + ata_ident->mwdmamodes = 7; + if (p->xfermode & ATA_WDMA0) + ata_ident->mwdmamodes |= (1 << ((p->xfermode & 7) + 8)); + ata_ident->apiomodes = 3; + ata_ident->mwdmamin = 0x0078; + ata_ident->mwdmarec = 0x0078; + ata_ident->pioblind = 0x0078; + ata_ident->pioiordy = 0x0078; + ata_ident->satacapabilities = (ATA_SATA_GEN1 | ATA_SATA_GEN2 | ATA_SATA_GEN3); + ata_ident->satacapabilities2 = ((p->ssts & ATA_SS_SPD_MASK) >> 3); + ata_ident->satasupport = ATA_SUPPORT_NCQ_STREAM; + ata_ident->version_major = 0x3f0; + ata_ident->support.command1 = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_PACKET | + ATA_SUPPORT_RESET | ATA_SUPPORT_NOP); + ata_ident->support.command2 = (1 << 14); + ata_ident->support.extension = (1 << 14); + ata_ident->enabled.command1 = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_PACKET | + ATA_SUPPORT_RESET | ATA_SUPPORT_NOP); + ata_ident->enabled.extension = (1 << 14); + ata_ident->udmamodes = 0x7f; + if (p->xfermode & ATA_UDMA0) + ata_ident->udmamodes |= (1 << ((p->xfermode & 7) + 8)); + ata_ident->transport_major = 0x1020; + ata_ident->integrity = 0x00a5; + } else { uint64_t sectors; int sectsz, psectsz, psectoff, candelete, ro; uint16_t cyl; @@ -999,87 +1041,85 @@ handle_identify(struct ahci_port *p, int slot, uint8_t *cfis) sectors = blockif_size(p->bctx) / sectsz; blockif_chs(p->bctx, &cyl, &heads, &sech); blockif_psectsz(p->bctx, &psectsz, &psectoff); - memset(buf, 0, sizeof(buf)); - buf[0] = 0x0040; - buf[1] = cyl; - buf[3] = heads; - buf[6] = sech; - ata_string((uint8_t *)(buf+10), p->ident, 20); - ata_string((uint8_t *)(buf+23), "001", 8); - ata_string((uint8_t *)(buf+27), "BHYVE SATA DISK", 40); - buf[47] = (0x8000 | 128); - buf[48] = 0; - buf[49] = (1 << 8 | 1 << 9 | 1 << 11); - buf[50] = (1 << 14); - buf[53] = (1 << 1 | 1 << 2); + ata_ident->config = ATA_DRQ_FAST; + ata_ident->cylinders = cyl; + ata_ident->heads = heads; + ata_ident->sectors = sech; + + ata_ident->sectors_intr = (0x8000 | 128); + ata_ident->tcg = 0; + + ata_ident->capabilities1 = ATA_SUPPORT_DMA | + ATA_SUPPORT_LBA | ATA_SUPPORT_IORDY; + ata_ident->capabilities2 = (1 << 14); + ata_ident->atavalid = ATA_FLAG_54_58 | + ATA_FLAG_64_70; if (p->mult_sectors) - buf[59] = (0x100 | p->mult_sectors); + ata_ident->multi = (ATA_MULTI_VALID | p->mult_sectors); if (sectors <= 0x0fffffff) { - buf[60] = sectors; - buf[61] = (sectors >> 16); + ata_ident->lba_size_1 = sectors; + ata_ident->lba_size_2 = (sectors >> 16); } else { - buf[60] = 0xffff; - buf[61] = 0x0fff; + ata_ident->lba_size_1 = 0xffff; + ata_ident->lba_size_2 = 0x0fff; } - buf[63] = 0x7; + ata_ident->mwdmamodes = 0x7; if (p->xfermode & ATA_WDMA0) - buf[63] |= (1 << ((p->xfermode & 7) + 8)); - buf[64] = 0x3; - buf[65] = 120; - buf[66] = 120; - buf[67] = 120; - buf[68] = 120; - buf[69] = 0; - buf[75] = 31; - buf[76] = (ATA_SATA_GEN1 | ATA_SATA_GEN2 | ATA_SATA_GEN3 | - ATA_SUPPORT_NCQ); - buf[77] = (ATA_SUPPORT_RCVSND_FPDMA_QUEUED | - (p->ssts & ATA_SS_SPD_MASK) >> 3); - buf[80] = 0x3f0; - buf[81] = 0x28; - buf[82] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE| - ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP); - buf[83] = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE | - ATA_SUPPORT_FLUSHCACHE48 | 1 << 14); - buf[84] = (1 << 14); - buf[85] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE| - ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP); - buf[86] = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE | - ATA_SUPPORT_FLUSHCACHE48 | 1 << 15); - buf[87] = (1 << 14); - buf[88] = 0x7f; + ata_ident->mwdmamodes |= (1 << ((p->xfermode & 7) + 8)); + ata_ident->apiomodes = 0x3; + ata_ident->mwdmamin = 0x0078; + ata_ident->mwdmarec = 0x0078; + ata_ident->pioblind = 0x0078; + ata_ident->pioiordy = 0x0078; + ata_ident->support3 = 0; + ata_ident->queue = 31; + ata_ident->satacapabilities = (ATA_SATA_GEN1 | ATA_SATA_GEN2 | ATA_SATA_GEN3 | + ATA_SUPPORT_NCQ); + ata_ident->satacapabilities2 = (ATA_SUPPORT_RCVSND_FPDMA_QUEUED | + (p->ssts & ATA_SS_SPD_MASK) >> 3); + ata_ident->version_major = 0x3f0; + ata_ident->version_minor = 0x28; + ata_ident->support.command1 = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE | + ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP); + ata_ident->support.command2 = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE | + ATA_SUPPORT_FLUSHCACHE48 | 1 << 14); + ata_ident->support.extension = (1 << 14); + ata_ident->enabled.command1 = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE | + ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP); + ata_ident->enabled.command2 = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE | + ATA_SUPPORT_FLUSHCACHE48 | 1 << 15); + ata_ident->enabled.extension = (1 << 14); + ata_ident->udmamodes = 0x7f; if (p->xfermode & ATA_UDMA0) - buf[88] |= (1 << ((p->xfermode & 7) + 8)); - buf[100] = sectors; - buf[101] = (sectors >> 16); - buf[102] = (sectors >> 32); - buf[103] = (sectors >> 48); + ata_ident->udmamodes |= (1 << ((p->xfermode & 7) + 8)); + ata_ident->lba_size48_1 = sectors; + ata_ident->lba_size48_2 = (sectors >> 16); + ata_ident->lba_size48_3 = (sectors >> 32); + ata_ident->lba_size48_4 = (sectors >> 48); + if (candelete && !ro) { - buf[69] |= ATA_SUPPORT_RZAT | ATA_SUPPORT_DRAT; - buf[105] = 1; - buf[169] = ATA_SUPPORT_DSM_TRIM; + ata_ident->support3 |= ATA_SUPPORT_RZAT | ATA_SUPPORT_DRAT; + ata_ident->max_dsm_blocks = 1; + ata_ident->support_dsm = ATA_SUPPORT_DSM_TRIM; } - buf[106] = 0x4000; - buf[209] = 0x4000; + ata_ident->pss = ATA_PSS_VALID_VALUE; + ata_ident->lsalign = 0x4000; if (psectsz > sectsz) { - buf[106] |= 0x2000; - buf[106] |= ffsl(psectsz / sectsz) - 1; - buf[209] |= (psectoff / sectsz); + ata_ident->pss |= ATA_PSS_MULTLS; + ata_ident->pss |= ffsl(psectsz / sectsz) - 1; + ata_ident->lsalign |= (psectoff / sectsz); } if (sectsz > 512) { - buf[106] |= 0x1000; - buf[117] = sectsz / 2; - buf[118] = ((sectsz / 2) >> 16); + ata_ident->pss |= ATA_PSS_LSSABOVE512; + ata_ident->lss_1 = sectsz / 2; + ata_ident->lss_2 = ((sectsz / 2) >> 16); } - buf[119] = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14); - buf[120] = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14); - buf[222] = 0x1020; - buf[255] = 0x00a5; - ahci_checksum((uint8_t *)buf, sizeof(buf)); - ahci_write_fis_piosetup(p); - write_prdt(p, slot, cfis, (void *)buf, sizeof(buf)); - ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY); + ata_ident->support2 = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14); + ata_ident->enabled2 = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14); + ata_ident->transport_major = 0x1020; + ata_ident->integrity = 0x00a5; } + ahci_checksum((uint8_t*)ata_ident, sizeof(struct ata_params)); } static void @@ -1089,44 +1129,8 @@ handle_atapi_identify(struct ahci_port *p, int slot, uint8_t *cfis) ahci_write_fis_d2h(p, slot, cfis, (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR); } else { - uint16_t buf[256]; - - memset(buf, 0, sizeof(buf)); - buf[0] = (2 << 14 | 5 << 8 | 1 << 7 | 2 << 5); - ata_string((uint8_t *)(buf+10), p->ident, 20); - ata_string((uint8_t *)(buf+23), "001", 8); - ata_string((uint8_t *)(buf+27), "BHYVE SATA DVD ROM", 40); - buf[49] = (1 << 9 | 1 << 8); - buf[50] = (1 << 14 | 1); - buf[53] = (1 << 2 | 1 << 1); - buf[62] = 0x3f; - buf[63] = 7; - if (p->xfermode & ATA_WDMA0) - buf[63] |= (1 << ((p->xfermode & 7) + 8)); - buf[64] = 3; - buf[65] = 120; - buf[66] = 120; - buf[67] = 120; - buf[68] = 120; - buf[76] = (ATA_SATA_GEN1 | ATA_SATA_GEN2 | ATA_SATA_GEN3); - buf[77] = ((p->ssts & ATA_SS_SPD_MASK) >> 3); - buf[78] = (1 << 5); - buf[80] = 0x3f0; - buf[82] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_PACKET | - ATA_SUPPORT_RESET | ATA_SUPPORT_NOP); - buf[83] = (1 << 14); - buf[84] = (1 << 14); - buf[85] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_PACKET | - ATA_SUPPORT_RESET | ATA_SUPPORT_NOP); - buf[87] = (1 << 14); - buf[88] = 0x7f; - if (p->xfermode & ATA_UDMA0) - buf[88] |= (1 << ((p->xfermode & 7) + 8)); - buf[222] = 0x1020; - buf[255] = 0x00a5; - ahci_checksum((uint8_t *)buf, sizeof(buf)); ahci_write_fis_piosetup(p); - write_prdt(p, slot, cfis, (void *)buf, sizeof(buf)); + write_prdt(p, slot, cfis, (void *)&p->ata_ident, sizeof(struct ata_params)); ahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY); } } @@ -2319,6 +2323,10 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) MD5_CTX mdctx; u_char digest[16]; char *next, *next2; + char *bopt, *uopt, *xopts, *config; + FILE* fp; + size_t block_len; + int comma, optpos; ret = 0; @@ -2335,6 +2343,9 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) slots = 32; for (p = 0; p < MAX_PORTS && opts != NULL; p++, opts = next) { + struct ata_params *ata_ident = &sc->port[p].ata_ident; + memset(ata_ident, 0, sizeof(struct ata_params)); + /* Identify and cut off type of present port. */ if (strncmp(opts, "hd:", 3) == 0) { atapi = 0; @@ -2357,13 +2368,82 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) if (opts[0] == 0) continue; + uopt = strdup(opts); + bopt = NULL; + fp = open_memstream(&bopt, &block_len); + comma = 0; + optpos = 0; + + for (xopts = strtok(uopt, ","); + xopts != NULL; + xopts = strtok(NULL, ",")) { + + /* First option assume as block filename. */ + if (optpos == 0) { + /* + * Create an identifier for the backing file. + * Use parts of the md5 sum of the filename + */ + char ident[AHCI_PORT_IDENT]; + MD5Init(&mdctx); + MD5Update(&mdctx, opts, strlen(opts)); + MD5Final(digest, &mdctx); + snprintf(ident, AHCI_PORT_IDENT, + "BHYVE-%02X%02X-%02X%02X-%02X%02X", + digest[0], digest[1], digest[2], digest[3], digest[4], + digest[5]); + ata_string((uint8_t*)&ata_ident->serial, ident, 20); + ata_string((uint8_t*)&ata_ident->revision, "001", 8); + if (atapi) { + ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DVD ROM", 40); + } + else { + ata_string((uint8_t*)&ata_ident->model, "BHYVE SATA DISK", 40); + } + } + + if ((config = strchr(xopts, '=')) != NULL) { + *config++ = '\0'; + if (!strcmp("nmrr", xopts)) { + ata_ident->media_rotation_rate = atoi(config); + } + else if (!strcmp("ser", xopts)) { + ata_string((uint8_t*)(&ata_ident->serial), config, 20); + } + else if (!strcmp("rev", xopts)) { + ata_string((uint8_t*)(&ata_ident->revision), config, 8); + } + else if (!strcmp("model", xopts)) { + ata_string((uint8_t*)(&ata_ident->model), config, 40); + } + else { + /* Pass all other options to blockif_open. */ + *--config = '='; + fprintf(fp, "%s%s", comma ? "," : "", xopts); + comma = 1; + } + } + else { + /* Pass all other options to blockif_open. */ + fprintf(fp, "%s%s", comma ? "," : "", xopts); + comma = 1; + } + optpos++; + } + free(uopt); + fclose(fp); + + DPRINTF("%s\n", bopt); + /* * Attempt to open the backing image. Use the PCI slot/func * and the port number for the identifier string. */ snprintf(bident, sizeof(bident), "%d:%d:%d", pi->pi_slot, pi->pi_func, p); - bctxt = blockif_open(opts, bident); + bctxt = blockif_open(bopt, bident); + free(bopt); + if (bctxt == NULL) { sc->ports = p; ret = 1; @@ -2374,17 +2454,7 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) sc->port[p].port = p; sc->port[p].atapi = atapi; - /* - * Create an identifier for the backing file. - * Use parts of the md5 sum of the filename - */ - MD5Init(&mdctx); - MD5Update(&mdctx, opts, strlen(opts)); - MD5Final(digest, &mdctx); - snprintf(sc->port[p].ident, AHCI_PORT_IDENT, - "BHYVE-%02X%02X-%02X%02X-%02X%02X", - digest[0], digest[1], digest[2], digest[3], digest[4], - digest[5]); + ata_identify_init(&sc->port[p], atapi); /* * Allocate blockif request structures and add them From 062528c5f216f702be2c63145ca1c453415badfb Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Mon, 27 Jul 2020 09:10:02 +0000 Subject: [PATCH 200/287] actually enable gate control for allwinner's r-ccu ir clock The gate control bit offset was correctly specified, but AW_CLK_HAS_GATE flag was not set. Tested with (C)IR receiver on Orange Pi PC Plus. Reviewed by: manu MFC after: 1 week --- sys/arm/allwinner/clkng/ccu_sun8i_r.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/arm/allwinner/clkng/ccu_sun8i_r.c b/sys/arm/allwinner/clkng/ccu_sun8i_r.c index 74f822ca761d..a0b7093ea8fd 100644 --- a/sys/arm/allwinner/clkng/ccu_sun8i_r.c +++ b/sys/arm/allwinner/clkng/ccu_sun8i_r.c @@ -122,7 +122,7 @@ NM_CLK(r_ccu_ir_clk, 16, 2, 0, 0, /* M flags */ 24, 2, /* mux */ 31, /* gate */ - AW_CLK_HAS_MUX | AW_CLK_REPARENT); /* flags */ + AW_CLK_HAS_MUX | AW_CLK_REPARENT | AW_CLK_HAS_GATE);/* flags */ static const char *a83t_ir_parents[] = {"osc16M", "osc24M"}; static struct aw_clk_nm_def a83t_ir_clk = { From d421b01028513e4e25230445a4d6f9206a77dbd3 Mon Sep 17 00:00:00 2001 From: Mateusz Piotrowski <0mp@FreeBSD.org> Date: Mon, 27 Jul 2020 10:45:47 +0000 Subject: [PATCH 201/287] nologin.8: Improve wording Reported by: yuripv Reviewed by: bcr, yuripv MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D25814 --- usr.sbin/nologin/nologin.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr.sbin/nologin/nologin.8 b/usr.sbin/nologin/nologin.8 index a6be6ac249fd..90b1d10f28f0 100644 --- a/usr.sbin/nologin/nologin.8 +++ b/usr.sbin/nologin/nologin.8 @@ -44,7 +44,7 @@ have been disabled. .Pp When executed, .Nm -first writes about the login attempt to +first logs about the login attempt using .Xr syslog 3 and then displays a message that an account is not available. .Pp From 58f5de0d8afaf8423b87a613a4a0772e56f8f72a Mon Sep 17 00:00:00 2001 From: Mateusz Piotrowski <0mp@FreeBSD.org> Date: Mon, 27 Jul 2020 11:42:22 +0000 Subject: [PATCH 202/287] tree.3: Bump date after 363450 (WAVL) While here: - Address whitespace warnings. - Start sentences on a new line. --- share/man/man3/tree.3 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/share/man/man3/tree.3 b/share/man/man3/tree.3 index e6ecc6e44237..a29f06d3c21e 100644 --- a/share/man/man3/tree.3 +++ b/share/man/man3/tree.3 @@ -30,7 +30,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 25, 2020 +.Dd July 27, 2020 .Dt TREE 3 .Os .Sh NAME @@ -371,7 +371,7 @@ Each tree node has an associated rank. Balance conditions are expressed by conditions on the differences in rank between any node and its children. Rank differences are stored in each tree node. -.Pp +.Pp The balance conditions implemented by the RB macros lead to weak AVL (wavl) trees, which combine the best aspects of AVL and red-black trees. @@ -380,7 +380,8 @@ with the same worst-case time as red-black trees offer, and with better balance in the resulting tree. Wavl trees rebalance after a removal in a way that requires less restructuring, in the worst case, than either AVL or red-black trees -do. Removals can lead to a tree almost as unbalanced as a red-black +do. +Removals can lead to a tree almost as unbalanced as a red-black tree; insertions lead to a tree becoming as balanced as an AVL tree. .Pp A rank-balanced tree is headed by a structure defined by the From 782ebde52ef5e51fe8fb5161e65c18c351537a20 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 27 Jul 2020 14:25:10 +0000 Subject: [PATCH 203/287] vm_page_free_invalid(): Relax the xbusy assertion. vm_page_assert_xbusied() asserts that the busying thread is the current thread. For some uses of vm_page_free_invalid() (e.g., error handling in vnode_pager_generic_getpages_done()), this condition might not hold. Reported by: Jenkins via trasz Reviewed by: chs, kib Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25828 --- sys/vm/vm_page.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index a7d6f3dd9d64..8c2df3e78e17 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -1371,10 +1371,15 @@ vm_page_free_invalid(vm_page_t m) KASSERT(vm_page_none_valid(m), ("page %p is valid", m)); KASSERT(!pmap_page_is_mapped(m), ("page %p is mapped", m)); - vm_page_assert_xbusied(m); KASSERT(m->object != NULL, ("page %p has no object", m)); VM_OBJECT_ASSERT_WLOCKED(m->object); + /* + * We may be attempting to free the page as part of the handling for an + * I/O error, in which case the page was xbusied by a different thread. + */ + vm_page_xbusy_claim(m); + /* * If someone has wired this page while the object lock * was not held, then the thread that unwires is responsible From d2a5f0812bb96b6011b0f1cd7e820a0f2f63a15c Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 27 Jul 2020 14:28:55 +0000 Subject: [PATCH 204/287] mpr(4), mps(4): Stop checking for failures from malloc(M_WAITOK). PR: 240545 Submitted by: Andrew Reiter Reviewed by: imp MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25766 --- sys/dev/mpr/mpr.c | 9 --------- sys/dev/mpr/mpr_sas.c | 15 --------------- sys/dev/mpr/mpr_user.c | 7 ------- sys/dev/mps/mps.c | 8 -------- sys/dev/mps/mps_sas.c | 15 --------------- sys/dev/mps/mps_user.c | 7 ------- 6 files changed, 61 deletions(-) diff --git a/sys/dev/mpr/mpr.c b/sys/dev/mpr/mpr.c index 863c9a59c27d..b202ea40db45 100644 --- a/sys/dev/mpr/mpr.c +++ b/sys/dev/mpr/mpr.c @@ -1529,10 +1529,6 @@ mpr_alloc_requests(struct mpr_softc *sc) */ sc->commands = malloc(sizeof(struct mpr_command) * sc->num_reqs, M_MPR, M_WAITOK | M_ZERO); - if (!sc->commands) { - mpr_dprint(sc, MPR_ERROR, "Cannot allocate command memory\n"); - return (ENOMEM); - } for (i = 1; i < sc->num_reqs; i++) { cm = &sc->commands[i]; cm->cm_req = sc->req_frames + i * sc->reqframesz; @@ -2684,11 +2680,6 @@ mpr_register_events(struct mpr_softc *sc, uint8_t *mask, int error = 0; eh = malloc(sizeof(struct mpr_event_handle), M_MPR, M_WAITOK|M_ZERO); - if (!eh) { - mpr_dprint(sc, MPR_EVENT|MPR_ERROR, - "Cannot allocate event memory\n"); - return (ENOMEM); - } eh->callback = cb; eh->data = data; TAILQ_INSERT_TAIL(&sc->event_list, eh, eh_list); diff --git a/sys/dev/mpr/mpr_sas.c b/sys/dev/mpr/mpr_sas.c index 64eed15ea5a6..0e31f0c4d21e 100644 --- a/sys/dev/mpr/mpr_sas.c +++ b/sys/dev/mpr/mpr_sas.c @@ -736,11 +736,6 @@ mpr_attach_sas(struct mpr_softc *sc) mpr_dprint(sc, MPR_INIT, "%s entered\n", __func__); sassc = malloc(sizeof(struct mprsas_softc), M_MPR, M_WAITOK|M_ZERO); - if (!sassc) { - mpr_dprint(sc, MPR_INIT|MPR_ERROR, - "Cannot allocate SAS subsystem memory\n"); - return (ENOMEM); - } /* * XXX MaxTargets could change during a reinit. Since we don't @@ -751,12 +746,6 @@ mpr_attach_sas(struct mpr_softc *sc) sassc->maxtargets = sc->facts->MaxTargets + sc->facts->MaxVolumes; sassc->targets = malloc(sizeof(struct mprsas_target) * sassc->maxtargets, M_MPR, M_WAITOK|M_ZERO); - if (!sassc->targets) { - mpr_dprint(sc, MPR_INIT|MPR_ERROR, - "Cannot allocate SAS target memory\n"); - free(sassc, M_MPR); - return (ENOMEM); - } sc->sassc = sassc; sassc->sc = sc; @@ -3556,8 +3545,4 @@ mprsas_realloc_targets(struct mpr_softc *sc, int maxtargets) sassc->targets = malloc(sizeof(struct mprsas_target) * maxtargets, M_MPR, M_WAITOK|M_ZERO); - if (!sassc->targets) { - panic("%s failed to alloc targets with error %d\n", - __func__, ENOMEM); - } } diff --git a/sys/dev/mpr/mpr_user.c b/sys/dev/mpr/mpr_user.c index 308b559c7172..751741bcc4f6 100644 --- a/sys/dev/mpr/mpr_user.c +++ b/sys/dev/mpr/mpr_user.c @@ -1528,13 +1528,6 @@ mpr_diag_register(struct mpr_softc *sc, mpr_fw_diag_register_t *diag_register, bzero(sc->fw_diag_buffer, buffer_size); ctx = malloc(sizeof(*ctx), M_MPR, M_WAITOK | M_ZERO); - if (ctx == NULL) { - device_printf(sc->mpr_dev, "%s: context malloc failed\n", - __func__); - *return_code = MPR_FW_DIAG_ERROR_NO_BUFFER; - status = MPR_DIAG_FAILURE; - goto bailout; - } ctx->addr = &sc->fw_diag_busaddr; ctx->buffer_dmat = sc->fw_diag_dmat; ctx->buffer_dmamap = sc->fw_diag_map; diff --git a/sys/dev/mps/mps.c b/sys/dev/mps/mps.c index 9802296f06f8..1adbf58c9e17 100644 --- a/sys/dev/mps/mps.c +++ b/sys/dev/mps/mps.c @@ -1520,10 +1520,6 @@ mps_alloc_requests(struct mps_softc *sc) */ sc->commands = malloc(sizeof(struct mps_command) * sc->num_reqs, M_MPT2, M_WAITOK | M_ZERO); - if(!sc->commands) { - mps_dprint(sc, MPS_ERROR, "Cannot allocate command memory\n"); - return (ENOMEM); - } for (i = 1; i < sc->num_reqs; i++) { cm = &sc->commands[i]; cm->cm_req = sc->req_frames + i * sc->reqframesz; @@ -2598,10 +2594,6 @@ mps_register_events(struct mps_softc *sc, u32 *mask, int error = 0; eh = malloc(sizeof(struct mps_event_handle), M_MPT2, M_WAITOK|M_ZERO); - if(!eh) { - mps_dprint(sc, MPS_ERROR, "Cannot allocate event memory\n"); - return (ENOMEM); - } eh->callback = cb; eh->data = data; TAILQ_INSERT_TAIL(&sc->event_list, eh, eh_list); diff --git a/sys/dev/mps/mps_sas.c b/sys/dev/mps/mps_sas.c index fd3f47c63697..74fced8abfab 100644 --- a/sys/dev/mps/mps_sas.c +++ b/sys/dev/mps/mps_sas.c @@ -722,11 +722,6 @@ mps_attach_sas(struct mps_softc *sc) mps_dprint(sc, MPS_INIT, "%s entered\n", __func__); sassc = malloc(sizeof(struct mpssas_softc), M_MPT2, M_WAITOK|M_ZERO); - if(!sassc) { - mps_dprint(sc, MPS_INIT|MPS_ERROR, - "Cannot allocate SAS controller memory\n"); - return (ENOMEM); - } /* * XXX MaxTargets could change during a reinit. Since we don't @@ -737,12 +732,6 @@ mps_attach_sas(struct mps_softc *sc) sassc->maxtargets = sc->facts->MaxTargets + sc->facts->MaxVolumes; sassc->targets = malloc(sizeof(struct mpssas_target) * sassc->maxtargets, M_MPT2, M_WAITOK|M_ZERO); - if(!sassc->targets) { - mps_dprint(sc, MPS_INIT|MPS_ERROR, - "Cannot allocate SAS target memory\n"); - free(sassc, M_MPT2); - return (ENOMEM); - } sc->sassc = sassc; sassc->sc = sc; @@ -3421,8 +3410,4 @@ mpssas_realloc_targets(struct mps_softc *sc, int maxtargets) sassc->targets = malloc(sizeof(struct mpssas_target) * maxtargets, M_MPT2, M_WAITOK|M_ZERO); - if (!sassc->targets) { - panic("%s failed to alloc targets with error %d\n", - __func__, ENOMEM); - } } diff --git a/sys/dev/mps/mps_user.c b/sys/dev/mps/mps_user.c index 0a2506070849..15ae463a1ad1 100644 --- a/sys/dev/mps/mps_user.c +++ b/sys/dev/mps/mps_user.c @@ -1436,13 +1436,6 @@ mps_diag_register(struct mps_softc *sc, mps_fw_diag_register_t *diag_register, bzero(sc->fw_diag_buffer, buffer_size); ctx = malloc(sizeof(*ctx), M_MPSUSER, M_WAITOK | M_ZERO); - if (ctx == NULL) { - device_printf(sc->mps_dev, "%s: context malloc failed\n", - __func__); - *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER; - status = MPS_DIAG_FAILURE; - goto bailout; - } ctx->addr = &sc->fw_diag_busaddr; ctx->buffer_dmat = sc->fw_diag_dmat; ctx->buffer_dmamap = sc->fw_diag_map; From c2895f19347c21f3ebb853d417581603cb4fbba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Apestegu=C3=ADa?= Date: Mon, 27 Jul 2020 15:25:04 +0000 Subject: [PATCH 205/287] truncate(1): Add EXAMPLES section Add four simple examples showing the use of -c, -r and -s Approved by: manpages (bcr@) Differential Revision: https://reviews.freebsd.org/D25774 --- usr.bin/truncate/truncate.1 | 39 ++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/usr.bin/truncate/truncate.1 b/usr.bin/truncate/truncate.1 index a6065b1de9f1..2058530162c5 100644 --- a/usr.bin/truncate/truncate.1 +++ b/usr.bin/truncate/truncate.1 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 19, 2006 +.Dd July 27, 2020 .Dt TRUNCATE 1 .Os .Sh NAME @@ -143,6 +143,43 @@ If the operation fails for an argument, .Nm will issue a diagnostic and continue processing the remaining arguments. +.Sh EXAMPLES +Adjust the size of the file +.Pa test_file +to 10 Megabytes but do not create it if it does not exist: +.Bd -literal -offset indent +truncate -c -s +10M test_file +.Ed +.Pp +Same as above but create the file if it does not exist: +.Bd -literal -offset indent +truncate -s +10M test_file +ls -l test_file +-rw-r--r-- 1 root wheel 10485760 Jul 22 18:48 test_file +.Ed +.Pp +Adjust the size of +.Pa test_file +to the size of the kernel and create another file +.Pa test_file2 +with the same size: +.Bd -literal -offset indent +truncate -r /boot/kernel/kernel test_file test_file2 +ls -l /boot/kernel/kernel test_file* +-r-xr-xr-x 1 root wheel 31352552 May 15 14:18 /boot/kernel/kernel* +-rw-r--r-- 1 root wheel 31352552 Jul 22 19:15 test_file +-rw-r--r-- 1 root wheel 31352552 Jul 22 19:15 test_file2 +.Ed +.Pp +Downsize +.Pa test_file +in 5 Megabytes: +.Bd -literal -offset indent +# truncate -s -5M test_file +ls -l test_file* +-rw-r--r-- 1 root wheel 26109672 Jul 22 19:17 test_file +-rw-r--r-- 1 root wheel 31352552 Jul 22 19:15 test_file2 +.Ed .Sh SEE ALSO .Xr dd 1 , .Xr touch 1 , From e21c0b0753092a6299544a001c34b19d5a324972 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 27 Jul 2020 16:25:18 +0000 Subject: [PATCH 206/287] Don't include T_USER in si_trapno reported to userland. Signals are only reported for user traps, so T_USER is redundant. It is also a software convention and not included in the value reported by the hardware. Reviewed by: kib Obtained from: CheriBSD Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25769 --- sys/mips/mips/trap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c index 26f7c1515818..a2cd7e0e8d6e 100644 --- a/sys/mips/mips/trap.c +++ b/sys/mips/mips/trap.c @@ -1107,7 +1107,7 @@ trap(struct trapframe *trapframe) ksi.ksi_signo = i; ksi.ksi_code = ucode; ksi.ksi_addr = (void *)addr; - ksi.ksi_trapno = type; + ksi.ksi_trapno = type & ~T_USER; trapsignal(td, &ksi); out: From c294dddb0334feb6d8690ee63f3367d78458ac8e Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 27 Jul 2020 16:28:44 +0000 Subject: [PATCH 207/287] Set si_trapno to the exception code from scause. Reviewed by: kib Obtained from: CheriBSD Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25770 --- sys/riscv/riscv/trap.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sys/riscv/riscv/trap.c b/sys/riscv/riscv/trap.c index c9b6a1ea6f47..00b66822cbac 100644 --- a/sys/riscv/riscv/trap.c +++ b/sys/riscv/riscv/trap.c @@ -80,7 +80,7 @@ void do_trap_supervisor(struct trapframe *); void do_trap_user(struct trapframe *); static __inline void -call_trapsignal(struct thread *td, int sig, int code, void *addr) +call_trapsignal(struct thread *td, int sig, int code, void *addr, int trapno) { ksiginfo_t ksi; @@ -88,6 +88,7 @@ call_trapsignal(struct thread *td, int sig, int code, void *addr) ksi.ksi_signo = sig; ksi.ksi_code = code; ksi.ksi_addr = addr; + ksi.ksi_trapno = trapno; trapsignal(td, &ksi); } @@ -224,7 +225,8 @@ data_abort(struct trapframe *frame, int usermode) error = vm_fault_trap(map, va, ftype, VM_FAULT_NORMAL, &sig, &ucode); if (error != KERN_SUCCESS) { if (usermode) { - call_trapsignal(td, sig, ucode, (void *)stval); + call_trapsignal(td, sig, ucode, (void *)stval, + frame->tf_scause & EXCP_MASK); } else { if (pcb->pcb_onfault != 0) { frame->tf_a[0] = error; @@ -353,11 +355,13 @@ do_trap_user(struct trapframe *frame) break; } #endif - call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_sepc); + call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_sepc, + exception); userret(td, frame); break; case EXCP_BREAKPOINT: - call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_sepc); + call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_sepc, + exception); userret(td, frame); break; default: From 91371fbcf6c75d004d883ebf079b80feef1fa230 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 27 Jul 2020 16:29:21 +0000 Subject: [PATCH 208/287] Set si_trapno to the fault index from fsr. Reviewed by: kib Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25772 --- sys/arm/arm/trap-v6.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sys/arm/arm/trap-v6.c b/sys/arm/arm/trap-v6.c index 84acf479bfe1..7ade224f949e 100644 --- a/sys/arm/arm/trap-v6.c +++ b/sys/arm/arm/trap-v6.c @@ -169,7 +169,8 @@ static const struct abort aborts[] = { }; static __inline void -call_trapsignal(struct thread *td, int sig, int code, vm_offset_t addr) +call_trapsignal(struct thread *td, int sig, int code, vm_offset_t addr, + int trapno) { ksiginfo_t ksi; @@ -185,6 +186,7 @@ call_trapsignal(struct thread *td, int sig, int code, vm_offset_t addr) ksi.ksi_signo = sig; ksi.ksi_code = code; ksi.ksi_addr = (void *)addr; + ksi.ksi_trapno = trapno; trapsignal(td, &ksi); } @@ -252,7 +254,7 @@ abort_debug(struct trapframe *tf, u_int fsr, u_int prefetch, bool usermode, struct thread *td; td = curthread; - call_trapsignal(td, SIGTRAP, TRAP_BRKPT, far); + call_trapsignal(td, SIGTRAP, TRAP_BRKPT, far, FAULT_DEBUG); userret(td, tf); } else { #ifdef KDB @@ -523,7 +525,7 @@ abort_handler(struct trapframe *tf, int prefetch) ksig.addr = far; do_trapsignal: - call_trapsignal(td, ksig.sig, ksig.code, ksig.addr); + call_trapsignal(td, ksig.sig, ksig.code, ksig.addr, idx); out: if (usermode) userret(td, tf); From e2bbd168adecb8c1a53ee30263db0fda622497da Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 27 Jul 2020 16:31:21 +0000 Subject: [PATCH 209/287] Fix indentation. --- sys/geom/eli/g_eli_integrity.c | 2 +- sys/geom/eli/g_eli_privacy.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/geom/eli/g_eli_integrity.c b/sys/geom/eli/g_eli_integrity.c index e4f31046c45b..d20b753256dd 100644 --- a/sys/geom/eli/g_eli_integrity.c +++ b/sys/geom/eli/g_eli_integrity.c @@ -543,7 +543,7 @@ g_eli_auth_run(struct g_eli_worker *wr, struct bio *bp) if (g_eli_ivlen(sc->sc_ealgo) != 0) { crp->crp_flags |= CRYPTO_F_IV_SEPARATE; g_eli_crypto_ivgen(sc, dstoff, crp->crp_iv, - sizeof(crp->crp_iv)); + sizeof(crp->crp_iv)); } g_eli_auth_keygen(sc, dstoff, authkey); diff --git a/sys/geom/eli/g_eli_privacy.c b/sys/geom/eli/g_eli_privacy.c index 4a3e91948ebb..7bd8eb29cc28 100644 --- a/sys/geom/eli/g_eli_privacy.c +++ b/sys/geom/eli/g_eli_privacy.c @@ -288,7 +288,7 @@ g_eli_crypto_run(struct g_eli_worker *wr, struct bio *bp) if (g_eli_ivlen(sc->sc_ealgo) != 0) { crp->crp_flags |= CRYPTO_F_IV_SEPARATE; g_eli_crypto_ivgen(sc, dstoff, crp->crp_iv, - sizeof(crp->crp_iv)); + sizeof(crp->crp_iv)); } error = crypto_dispatch(crp); From d11a7b16cdc5871ba5b99b64b67b42091b0e1483 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 27 Jul 2020 16:32:21 +0000 Subject: [PATCH 210/287] Fix si_addr value for breakpoints in a delay slot. Reviewed by: kib Obtained from: CheriBSD Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25773 --- sys/mips/mips/trap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c index a2cd7e0e8d6e..6ada543577c9 100644 --- a/sys/mips/mips/trap.c +++ b/sys/mips/mips/trap.c @@ -824,12 +824,12 @@ trap(struct trapframe *trapframe) i = SIGTRAP; ucode = TRAP_BRKPT; - addr = trapframe->pc; /* compute address of break instruction */ va = trapframe->pc; if (DELAYBRANCH(trapframe->cause)) va += sizeof(int); + addr = va; if (td->td_md.md_ss_addr != va) break; From 7d351d60fa935a2af59e30e6d4059cc16cae289e Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 27 Jul 2020 16:34:31 +0000 Subject: [PATCH 211/287] Set si_addr to dar for MMU and alignment faults. Reviewed by: kib Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25776 --- sys/powerpc/powerpc/trap.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sys/powerpc/powerpc/trap.c b/sys/powerpc/powerpc/trap.c index d6579ecfc9cf..743299c09fdb 100644 --- a/sys/powerpc/powerpc/trap.c +++ b/sys/powerpc/powerpc/trap.c @@ -207,7 +207,7 @@ trap(struct trapframe *frame) int sig, type, user; u_int ucode; ksiginfo_t ksi; - register_t fscr; + register_t addr, fscr; VM_CNT_INC(v_trap); @@ -224,6 +224,7 @@ trap(struct trapframe *frame) type = ucode = frame->exc; sig = 0; user = frame->srr1 & PSL_PR; + addr = 0; CTR3(KTR_TRAP, "trap: %s type=%s (%s)", td->td_name, trapname(type), user ? "user" : "kernel"); @@ -248,6 +249,7 @@ trap(struct trapframe *frame) if (user) { td->td_pticks = 0; td->td_frame = frame; + addr = frame->srr0; if (td->td_cowgen != p->p_cowgen) thread_cow_update(td); @@ -261,18 +263,22 @@ trap(struct trapframe *frame) break; #if defined(__powerpc64__) && defined(AIM) - case EXC_ISE: case EXC_DSE: + addr = frame->dar; + /* FALLTHROUGH */ + case EXC_ISE: /* DSE/ISE are automatically fatal with radix pmap. */ if (radix_mmu || handle_user_slb_spill(&p->p_vmspace->vm_pmap, - (type == EXC_ISE) ? frame->srr0 : frame->dar) != 0){ + addr) != 0){ sig = SIGSEGV; ucode = SEGV_MAPERR; } break; #endif case EXC_DSI: + addr = frame->dar; + /* FALLTHROUGH */ case EXC_ISI: if (trap_pfault(frame, true, &sig, &ucode)) sig = 0; @@ -368,6 +374,7 @@ trap(struct trapframe *frame) if (fix_unaligned(td, frame) != 0) { sig = SIGBUS; ucode = BUS_ADRALN; + addr = frame->dar; } else frame->srr0 += 4; @@ -481,7 +488,7 @@ trap(struct trapframe *frame) ksiginfo_init_trap(&ksi); ksi.ksi_signo = sig; ksi.ksi_code = (int) ucode; /* XXX, not POSIX */ - ksi.ksi_addr = (void *)frame->srr0; + ksi.ksi_addr = (void *)addr; ksi.ksi_trapno = type; trapsignal(td, &ksi); } From 9886554a027a35eb37beff6f744f2b677f7ee550 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 27 Jul 2020 16:37:18 +0000 Subject: [PATCH 212/287] Trim some extraneous parentheses. Reported by: kib (do_trap_user) Sponsored by: DARPA --- sys/riscv/riscv/intr_machdep.c | 2 +- sys/riscv/riscv/trap.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/riscv/riscv/intr_machdep.c b/sys/riscv/riscv/intr_machdep.c index 2a45e0905261..3e4afe11989e 100644 --- a/sys/riscv/riscv/intr_machdep.c +++ b/sys/riscv/riscv/intr_machdep.c @@ -163,7 +163,7 @@ riscv_cpu_intr(struct trapframe *frame) KASSERT(frame->tf_scause & EXCP_INTR, ("riscv_cpu_intr: wrong frame passed")); - active_irq = (frame->tf_scause & EXCP_MASK); + active_irq = frame->tf_scause & EXCP_MASK; switch (active_irq) { case IRQ_SOFTWARE_USER: diff --git a/sys/riscv/riscv/trap.c b/sys/riscv/riscv/trap.c index 00b66822cbac..aa9ec534669d 100644 --- a/sys/riscv/riscv/trap.c +++ b/sys/riscv/riscv/trap.c @@ -256,7 +256,7 @@ do_trap_supervisor(struct trapframe *frame) KASSERT((csr_read(sstatus) & (SSTATUS_SPP | SSTATUS_SIE)) == SSTATUS_SPP, ("Came from S mode with interrupts enabled")); - exception = (frame->tf_scause & EXCP_MASK); + exception = frame->tf_scause & EXCP_MASK; if (frame->tf_scause & EXCP_INTR) { /* Interrupt */ riscv_cpu_intr(frame); @@ -318,7 +318,7 @@ do_trap_user(struct trapframe *frame) KASSERT((csr_read(sstatus) & (SSTATUS_SPP | SSTATUS_SIE)) == 0, ("Came from U mode with interrupts enabled")); - exception = (frame->tf_scause & EXCP_MASK); + exception = frame->tf_scause & EXCP_MASK; if (frame->tf_scause & EXCP_INTR) { /* Interrupt */ riscv_cpu_intr(frame); From bdfea496cf9f32b9fcfa8be83ee37931138e6ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Apestegu=C3=ADa?= Date: Mon, 27 Jul 2020 16:51:23 +0000 Subject: [PATCH 213/287] comm(1): Add EXAMPLES section Add two very simple examples. Approved by: manpages (gbe@) Differential Revision: https://reviews.freebsd.org/D25344 --- usr.bin/comm/comm.1 | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/usr.bin/comm/comm.1 b/usr.bin/comm/comm.1 index 6e258806287e..b70e08692bd6 100644 --- a/usr.bin/comm/comm.1 +++ b/usr.bin/comm/comm.1 @@ -31,7 +31,7 @@ .\" From: @(#)comm.1 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ .\" -.Dd December 12, 2009 +.Dd July 27, 2020 .Dt COMM 1 .Os .Sh NAME @@ -95,6 +95,35 @@ as described in .Xr environ 7 . .Sh EXIT STATUS .Ex -std +.Sh EXAMPLES +Assuming a file named +.Pa example.txt +with the following contents: +.Bd -literal -offset indent +a +b +c +d +.Ed +.Pp +Show lines only in +.Pa example.txt , +lines only in stdin and common lines: +.Bd -literal -offset indent +$ echo -e "B\enc" | comm example.txt - + B +a +b + c +d +.Ed +.Pp +Show only common lines doing case insensitive comparisons: +.Bd -literal -offset indent +$ echo -e "B\enc" | comm -1 -2 -i example.txt - +b +c +.Ed .Sh SEE ALSO .Xr cmp 1 , .Xr diff 1 , @@ -108,9 +137,7 @@ utility conforms to .Pp The .Fl i -option is an extension to the -.Tn POSIX -standard. +option is an extension to the POSIX standard. .Sh HISTORY A .Nm From 9b2a97806ffff94c9568be2f1ecebdf1f61bd50b Mon Sep 17 00:00:00 2001 From: Piotr Pawel Stefaniak Date: Mon, 27 Jul 2020 18:46:20 +0000 Subject: [PATCH 214/287] sh(1): print a newline when ^D quits sh I've always found this a little bit confusing: > sh $ ^D> sh $ ^D> Reviewed by: 0mp, jilles MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25813 --- bin/sh/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/sh/main.c b/bin/sh/main.c index 4d0aae96215f..8df24dba312e 100644 --- a/bin/sh/main.c +++ b/bin/sh/main.c @@ -228,6 +228,10 @@ cmdloop(int top) } } popstackmark(&smark); + if (top && iflag) { + out2c('\n'); + flushout(out2); + } } From 153f46edf4eb10428a6b06770a57480a27318264 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 27 Jul 2020 18:57:28 +0000 Subject: [PATCH 215/287] Restrict definition of CTL_P1003_1B_MAXID to the kernel This constant is only used to size an array within the kernel. There are probably no legitimate uses in userland. Worse, since the kernel's array could theoretically change size over time, any use of that symbol in userland wouldn't be forwards compatible to new kernel versions. Reviewed by: jhb MFC after: Never Differential Revision: https://reviews.freebsd.org/D25816 --- sys/sys/sysctl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index 08fa64bed407..d0390ac42f4d 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -1096,10 +1096,10 @@ TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry); #define CTL_P1003_1B_SIGQUEUE_MAX 24 /* int */ #define CTL_P1003_1B_TIMER_MAX 25 /* int */ -#define CTL_P1003_1B_MAXID 26 - #ifdef _KERNEL +#define CTL_P1003_1B_MAXID 26 + /* * Declare some common oids. */ From 5822a14c4318d3b80aa1d5816ef89339449d0b8b Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 27 Jul 2020 19:05:53 +0000 Subject: [PATCH 216/287] cxgbe(4): Stop checking for failures from malloc(M_WAITOK). PR: 240545 Submitted by: Andrew Reiter Reviewed by: np MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25767 --- sys/dev/cxgbe/t4_main.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index 938d042c66b4..b088b5899dc0 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -10003,10 +10003,6 @@ load_fw(struct adapter *sc, struct t4_data *fw) } fw_data = malloc(fw->len, M_CXGBE, M_WAITOK); - if (fw_data == NULL) { - rc = ENOMEM; - goto done; - } rc = copyin(fw->data, fw_data, fw->len); if (rc == 0) @@ -10035,10 +10031,6 @@ load_cfg(struct adapter *sc, struct t4_data *cfg) } cfg_data = malloc(cfg->len, M_CXGBE, M_WAITOK); - if (cfg_data == NULL) { - rc = ENOMEM; - goto done; - } rc = copyin(cfg->data, cfg_data, cfg->len); if (rc == 0) @@ -10084,10 +10076,6 @@ load_boot(struct adapter *sc, struct t4_bootrom *br) } br_data = malloc(br->len, M_CXGBE, M_WAITOK); - if (br_data == NULL) { - rc = ENOMEM; - goto done; - } rc = copyin(br->data, br_data, br->len); if (rc == 0) @@ -10116,10 +10104,6 @@ load_bootcfg(struct adapter *sc, struct t4_data *bc) } bc_data = malloc(bc->len, M_CXGBE, M_WAITOK); - if (bc_data == NULL) { - rc = ENOMEM; - goto done; - } rc = copyin(bc->data, bc_data, bc->len); if (rc == 0) From 855e49f3b0adf4f47d2fa2a9cf92c83d9e700705 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Mon, 27 Jul 2020 21:19:41 +0000 Subject: [PATCH 217/287] Add initial driver for ACPI Platform Error Interfaces. APEI allows platform to report different kinds of errors to OS in several ways. We've found that Supermicro X10/X11 motherboards report PCIe errors appearing on hot-unplug via this interface using NMI. Without respective driver it ended up in kernel panic without any additional information. This driver introduces support for the APEI Generic Hardware Error Source reporting via NMI, SCI or polling. It decodes the reported errors and either pass them to pci(4) for processing or just logs otherwise. Errors marked as fatal still end up in kernel panic, but some more informative. When somebody get to native PCIe AER support implementation both of the reporting mechanisms should get common error recovery code. Since in our case errors happen when the device is already gone, there is nothing to recover, so the code just clears the error statuses, practically ignoring the otherwise destructive NMIs in nicer way. MFC after: 2 weeks Relnotes: yes Sponsored by: iXsystems, Inc. --- sys/arm64/arm64/machdep.c | 2 + sys/arm64/include/acpica_machdep.h | 2 + sys/conf/files | 1 + sys/dev/acpica/acpi.c | 31 ++ sys/dev/acpica/acpi_apei.c | 684 +++++++++++++++++++++++++++++ sys/dev/pci/pci.c | 61 +++ sys/dev/pci/pcivar.h | 1 + sys/x86/include/acpica_machdep.h | 1 + sys/x86/x86/cpu_machdep.c | 5 + 9 files changed, 788 insertions(+) create mode 100644 sys/dev/acpica/acpi_apei.c diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c index 1667d5993998..423adac08208 100644 --- a/sys/arm64/arm64/machdep.c +++ b/sys/arm64/arm64/machdep.c @@ -132,6 +132,8 @@ void pagezero_cache(void *); /* pagezero_simple is default pagezero */ void (*pagezero)(void *p) = pagezero_simple; +int (*apei_nmi)(void); + static void pan_setup(void) { diff --git a/sys/arm64/include/acpica_machdep.h b/sys/arm64/include/acpica_machdep.h index 282c79f5eaec..7f8139f9134b 100644 --- a/sys/arm64/include/acpica_machdep.h +++ b/sys/arm64/include/acpica_machdep.h @@ -57,6 +57,8 @@ struct acpi_generic_address; int acpi_map_addr(struct acpi_generic_address *, bus_space_tag_t *, bus_space_handle_t *, bus_size_t); +extern int (*apei_nmi)(void); + #endif /* _KERNEL */ #endif /* __ACPICA_MACHDEP_H__ */ diff --git a/sys/conf/files b/sys/conf/files index 8ed21c37d214..dd9b4bfa8581 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -754,6 +754,7 @@ dev/acpica/Osd/OsdSynch.c optional acpi dev/acpica/Osd/OsdTable.c optional acpi dev/acpica/acpi.c optional acpi dev/acpica/acpi_acad.c optional acpi +dev/acpica/acpi_apei.c optional acpi dev/acpica/acpi_battery.c optional acpi dev/acpica/acpi_button.c optional acpi dev/acpica/acpi_cmbat.c optional acpi diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index c3da5eb4cbbe..abe517263706 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -152,6 +152,7 @@ static ACPI_STATUS acpi_device_scan_children(device_t bus, device_t dev, int max_depth, acpi_scan_cb_t user_fn, void *arg); static int acpi_isa_pnp_probe(device_t bus, device_t child, struct isa_pnp_id *ids); +static void acpi_platform_osc(device_t dev); static void acpi_probe_children(device_t bus); static void acpi_probe_order(ACPI_HANDLE handle, int *order); static ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level, @@ -683,6 +684,8 @@ acpi_attach(device_t dev) /* Register ACPI again to pass the correct argument of pm_func. */ power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, sc); + acpi_platform_osc(dev); + if (!acpi_disabled("bus")) { EVENTHANDLER_REGISTER(dev_lookup, acpi_lookup, NULL, 1000); acpi_probe_children(dev); @@ -1943,6 +1946,34 @@ acpi_enable_pcie(void) #endif } +static void +acpi_platform_osc(device_t dev) +{ + ACPI_HANDLE sb_handle; + ACPI_STATUS status; + uint32_t cap_set[2]; + + /* 0811B06E-4A27-44F9-8D60-3CBBC22E7B48 */ + static uint8_t acpi_platform_uuid[ACPI_UUID_LENGTH] = { + 0x6e, 0xb0, 0x11, 0x08, 0x27, 0x4a, 0xf9, 0x44, + 0x8d, 0x60, 0x3c, 0xbb, 0xc2, 0x2e, 0x7b, 0x48 + }; + + if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle))) + return; + + cap_set[1] = 0x10; /* APEI Support */ + status = acpi_EvaluateOSC(sb_handle, acpi_platform_uuid, 1, + nitems(cap_set), cap_set, cap_set, false); + if (ACPI_FAILURE(status)) { + if (status == AE_NOT_FOUND) + return; + device_printf(dev, "_OSC failed: %s\n", + AcpiFormatException(status)); + return; + } +} + /* * Scan all of the ACPI namespace and attach child devices. * diff --git a/sys/dev/acpica/acpi_apei.c b/sys/dev/acpica/acpi_apei.c new file mode 100644 index 000000000000..8cdf09ee150c --- /dev/null +++ b/sys/dev/acpica/acpi_apei.c @@ -0,0 +1,684 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Alexander Motin + * + * 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_acpi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +struct apei_ge { + union { + ACPI_HEST_GENERIC v1; + ACPI_HEST_GENERIC_V2 v2; + }; + int res_type; + int res_rid; + struct resource *res; + int res2_type; + int res2_rid; + struct resource *res2; + uint8_t *buf, *copybuf; + TAILQ_ENTRY(apei_ge) link; + struct callout poll; + void *swi_ih; +} *apei_nmi_ge; + +struct apei_softc { + ACPI_TABLE_HEST *hest; + TAILQ_HEAD(, apei_ge) ges; +}; + +struct apei_mem_error { + uint64_t ValidationBits; + uint64_t ErrorStatus; + uint64_t PhysicalAddress; + uint64_t PhysicalAddressMask; + uint16_t Node; + uint16_t Card; + uint16_t Module; + uint16_t Bank; + uint16_t Device; + uint16_t Row; + uint16_t Column; + uint16_t BitPosition; + uint64_t RequesterID; + uint64_t ResponderID; + uint64_t TargetID; + uint8_t MemoryErrorType; + uint8_t Extended; + uint16_t RankNumber; + uint16_t CardHandle; + uint16_t ModuleHandle; +}; + +struct apei_pcie_error { + uint64_t ValidationBits; + uint32_t PortType; + uint32_t Version; + uint32_t CommandStatus; + uint32_t Reserved; + uint8_t DeviceID[16]; + uint8_t DeviceSerialNumber[8]; + uint8_t BridgeControlStatus[4]; + uint8_t CapabilityStructure[60]; + uint8_t AERInfo[96]; +}; + +#ifdef __i386__ +static __inline uint64_t +apei_bus_read_8(struct resource *res, bus_size_t offset) +{ + return (bus_read_4(res, offset) | + ((uint64_t)bus_read_4(res, offset + 4)) << 32); +} +static __inline void +apei_bus_write_8(struct resource *res, bus_size_t offset, uint64_t val) +{ + bus_write_4(res, offset, val); + bus_write_4(res, offset + 4, val >> 32); +} +#define READ8(r, o) apei_bus_read_8((r), (o)) +#define WRITE8(r, o, v) apei_bus_write_8((r), (o), (v)) +#else +#define READ8(r, o) bus_read_8((r), (o)) +#define WRITE8(r, o, v) bus_write_8((r), (o), (v)) +#endif + +int apei_nmi_handler(void); + +static const char * +apei_severity(uint32_t s) +{ + switch (s) { + case ACPI_HEST_GEN_ERROR_RECOVERABLE: + return ("Recoverable"); + case ACPI_HEST_GEN_ERROR_FATAL: + return ("Fatal"); + case ACPI_HEST_GEN_ERROR_CORRECTED: + return ("Corrected"); + case ACPI_HEST_GEN_ERROR_NONE: + return ("Informational"); + } + return ("???"); +} + +static int +apei_mem_handler(ACPI_HEST_GENERIC_DATA *ged) +{ + struct apei_mem_error *p = (struct apei_mem_error *)(ged + 1); + + printf("APEI %s Memory Error:\n", apei_severity(ged->ErrorSeverity)); + if (p->ValidationBits & 0x01) + printf(" Error Status: 0x%jx\n", p->ErrorStatus); + if (p->ValidationBits & 0x02) + printf(" Physical Address: 0x%jx\n", p->PhysicalAddress); + if (p->ValidationBits & 0x04) + printf(" Physical Address Mask: 0x%jx\n", p->PhysicalAddressMask); + if (p->ValidationBits & 0x08) + printf(" Node: %u\n", p->Node); + if (p->ValidationBits & 0x10) + printf(" Card: %u\n", p->Card); + if (p->ValidationBits & 0x20) + printf(" Module: %u\n", p->Module); + if (p->ValidationBits & 0x40) + printf(" Bank: %u\n", p->Bank); + if (p->ValidationBits & 0x80) + printf(" Device: %u\n", p->Device); + if (p->ValidationBits & 0x100) + printf(" Row: %u\n", p->Row); + if (p->ValidationBits & 0x200) + printf(" Column: %u\n", p->Column); + if (p->ValidationBits & 0x400) + printf(" Bit Position: %u\n", p->BitPosition); + if (p->ValidationBits & 0x800) + printf(" Requester ID: 0x%jx\n", p->RequesterID); + if (p->ValidationBits & 0x1000) + printf(" Responder ID: 0x%jx\n", p->ResponderID); + if (p->ValidationBits & 0x2000) + printf(" Target ID: 0x%jx\n", p->TargetID); + if (p->ValidationBits & 0x4000) + printf(" Memory Error Type: %u\n", p->MemoryErrorType); + if (p->ValidationBits & 0x8000) + printf(" Rank Number: %u\n", p->RankNumber); + if (p->ValidationBits & 0x10000) + printf(" Card Handle: 0x%x\n", p->CardHandle); + if (p->ValidationBits & 0x20000) + printf(" Module Handle: 0x%x\n", p->ModuleHandle); + if (p->ValidationBits & 0x40000) + printf(" Extended Row: %u\n", + (uint32_t)(p->Extended & 0x3) << 16 | p->Row); + if (p->ValidationBits & 0x80000) + printf(" Bank Group: %u\n", p->Bank >> 8); + if (p->ValidationBits & 0x100000) + printf(" Bank Address: %u\n", p->Bank & 0xff); + if (p->ValidationBits & 0x200000) + printf(" Chip Identification: %u\n", (p->Extended >> 5) & 0x7); + + return (0); +} + +static int +apei_pcie_handler(ACPI_HEST_GENERIC_DATA *ged) +{ + struct apei_pcie_error *p = (struct apei_pcie_error *)(ged + 1); + device_t dev; + int h = 0, off, sev; + + if ((p->ValidationBits & 0x8) == 0x8) { + mtx_lock(&Giant); + dev = pci_find_dbsf((uint32_t)p->DeviceID[10] << 8 | + p->DeviceID[9], p->DeviceID[11], p->DeviceID[8], + p->DeviceID[7]); + if (dev != NULL) { + switch (ged->ErrorSeverity) { + case ACPI_HEST_GEN_ERROR_FATAL: + sev = PCIEM_STA_FATAL_ERROR; + break; + case ACPI_HEST_GEN_ERROR_RECOVERABLE: + sev = PCIEM_STA_NON_FATAL_ERROR; + break; + default: + sev = PCIEM_STA_CORRECTABLE_ERROR; + break; + } + pcie_apei_error(dev, sev, + (p->ValidationBits & 0x80) ? p->AERInfo : NULL); + h = 1; + } + mtx_unlock(&Giant); + } + if (h) + return (h); + + printf("APEI %s PCIe Error:\n", apei_severity(ged->ErrorSeverity)); + if (p->ValidationBits & 0x01) + printf(" Port Type: %u\n", p->PortType); + if (p->ValidationBits & 0x02) + printf(" Version: %x\n", p->Version); + if (p->ValidationBits & 0x04) + printf(" Command Status: 0x%08x\n", p->CommandStatus); + if (p->ValidationBits & 0x08) { + printf(" DeviceID:"); + for (off = 0; off < sizeof(p->DeviceID); off++) + printf(" %02x", p->DeviceID[off]); + printf("\n"); + } + if (p->ValidationBits & 0x10) { + printf(" Device Serial Number:"); + for (off = 0; off < sizeof(p->DeviceSerialNumber); off++) + printf(" %02x", p->DeviceSerialNumber[off]); + printf("\n"); + } + if (p->ValidationBits & 0x20) { + printf(" Bridge Control Status:"); + for (off = 0; off < sizeof(p->BridgeControlStatus); off++) + printf(" %02x", p->BridgeControlStatus[off]); + printf("\n"); + } + if (p->ValidationBits & 0x40) { + printf(" Capability Structure:\n"); + for (off = 0; off < sizeof(p->CapabilityStructure); off++) { + printf(" %02x", p->CapabilityStructure[off]); + if ((off % 16) == 15 || + off + 1 == sizeof(p->CapabilityStructure)) + printf("\n"); + } + } + if (p->ValidationBits & 0x80) { + printf(" AER Info:\n"); + for (off = 0; off < sizeof(p->AERInfo); off++) { + printf(" %02x", p->AERInfo[off]); + if ((off % 16) == 15 || off + 1 == sizeof(p->AERInfo)) + printf("\n"); + } + } + return (h); +} + +static void +apei_ged_handler(ACPI_HEST_GENERIC_DATA *ged) +{ + ACPI_HEST_GENERIC_DATA_V300 *ged3 = (ACPI_HEST_GENERIC_DATA_V300 *)ged; + /* A5BC1114-6F64-4EDE-B863-3E83ED7C83B1 */ + static uint8_t mem_uuid[ACPI_UUID_LENGTH] = { + 0x14, 0x11, 0xBC, 0xA5, 0x64, 0x6F, 0xDE, 0x4E, + 0xB8, 0x63, 0x3E, 0x83, 0xED, 0x7C, 0x83, 0xB1 + }; + /* D995E954-BBC1-430F-AD91-B44DCB3C6F35 */ + static uint8_t pcie_uuid[ACPI_UUID_LENGTH] = { + 0x54, 0xE9, 0x95, 0xD9, 0xC1, 0xBB, 0x0F, 0x43, + 0xAD, 0x91, 0xB4, 0x4D, 0xCB, 0x3C, 0x6F, 0x35 + }; + uint8_t *t; + int h = 0, off; + + if (memcmp(mem_uuid, ged->SectionType, ACPI_UUID_LENGTH) == 0) { + h = apei_mem_handler(ged); + } else if (memcmp(pcie_uuid, ged->SectionType, ACPI_UUID_LENGTH) == 0) { + h = apei_pcie_handler(ged); + } else { + t = ged->SectionType; + printf("APEI %s Error %02x%02x%02x%02x-%02x%02x-" + "%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x:\n", + apei_severity(ged->ErrorSeverity), + t[3], t[2], t[1], t[0], t[5], t[4], t[7], t[6], + t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]); + printf(" Error Data:\n"); + t = (uint8_t *)(ged + 1); + for (off = 0; off < ged->ErrorDataLength; off++) { + printf(" %02x", t[off]); + if ((off % 16) == 15 || off + 1 == ged->ErrorDataLength) + printf("\n"); + } + } + if (h) + return; + + printf(" Flags: 0x%x\n", ged->Flags); + if (ged->ValidationBits & ACPI_HEST_GEN_VALID_FRU_ID) { + t = ged->FruId; + printf(" FRU Id: %02x%02x%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x-%02x%02x%02x%02x%02x%02x\n", + t[3], t[2], t[1], t[0], t[5], t[4], t[7], t[6], + t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]); + } + if (ged->ValidationBits & ACPI_HEST_GEN_VALID_FRU_STRING) + printf(" FRU Text: %.20s", ged->FruText); + if (ged->Revision == 0x300 && + ged->ValidationBits & ACPI_HEST_GEN_VALID_TIMESTAMP) + printf(" Timestamp: %016jx", ged3->TimeStamp); +} + +static int +apei_ge_handler(struct apei_ge *ge, bool copy) +{ + uint8_t *buf = copy ? ge->copybuf : ge->buf; + ACPI_HEST_GENERIC_STATUS *ges = (ACPI_HEST_GENERIC_STATUS *)buf; + ACPI_HEST_GENERIC_DATA *ged; + uint32_t sev; + int i, c, off; + + if (ges->BlockStatus == 0) + return (0); + + c = (ges->BlockStatus >> 4) & 0x3ff; + sev = ges->ErrorSeverity; + + /* Process error entries. */ + for (off = i = 0; i < c && off + sizeof(*ged) <= ges->DataLength; i++) { + ged = (ACPI_HEST_GENERIC_DATA *)&buf[sizeof(*ges) + off]; + apei_ged_handler(ged); + off += sizeof(*ged) + ged->ErrorDataLength; + } + + /* Acknowledge the error has been processed. */ + ges->BlockStatus = 0; + if (!copy && ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2) { + uint64_t val = READ8(ge->res2, 0); + val &= ge->v2.ReadAckPreserve; + val |= ge->v2.ReadAckWrite; + WRITE8(ge->res2, 0, val); + } + + /* If ACPI told the error is fatal -- make it so. */ + if (sev == ACPI_HEST_GEN_ERROR_FATAL) + panic("APEI Fatal Hardware Error!"); + + return (1); +} + +static void +apei_nmi_swi(void *arg) +{ + struct apei_ge *ge = arg; + + apei_ge_handler(ge, true); +} + +int +apei_nmi_handler(void) +{ + struct apei_ge *ge = apei_nmi_ge; + ACPI_HEST_GENERIC_STATUS *ges, *gesc; + + if (ge == NULL) + return (0); + + ges = (ACPI_HEST_GENERIC_STATUS *)ge->buf; + if (ges->BlockStatus == 0) + return (0); + + /* If ACPI told the error is fatal -- make it so. */ + if (ges->ErrorSeverity == ACPI_HEST_GEN_ERROR_FATAL) + panic("APEI Fatal Hardware Error!"); + + /* Copy the buffer for later processing. */ + gesc = (ACPI_HEST_GENERIC_STATUS *)ge->copybuf; + if (gesc->BlockStatus == 0) + memcpy(ge->copybuf, ge->buf, ge->v1.ErrorBlockLength); + + /* Acknowledge the error has been processed. */ + ges->BlockStatus = 0; + if (ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2) { + uint64_t val = READ8(ge->res2, 0); + val &= ge->v2.ReadAckPreserve; + val |= ge->v2.ReadAckWrite; + WRITE8(ge->res2, 0, val); + } + + /* Schedule SWI for real handling. */ + swi_sched(ge->swi_ih, SWI_FROMNMI); + + return (1); +} + +static void +apei_callout_handler(void *context) +{ + struct apei_ge *ge = context; + + apei_ge_handler(ge, false); + callout_schedule(&ge->poll, ge->v1.Notify.PollInterval * hz / 1000); +} + +static void +apei_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) +{ + device_t dev = context; + struct apei_softc *sc = device_get_softc(dev); + struct apei_ge *ge; + + TAILQ_FOREACH(ge, &sc->ges, link) { + if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_SCI || + ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GPIO || + ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GSIV) + apei_ge_handler(ge, false); + } +} + +static int +hest_parse_structure(struct apei_softc *sc, void *addr, int remaining) +{ + ACPI_HEST_HEADER *hdr = addr; + struct apei_ge *ge; + + if (remaining < (int)sizeof(ACPI_HEST_HEADER)) + return (-1); + + switch (hdr->Type) { + case ACPI_HEST_TYPE_IA32_CHECK: { + ACPI_HEST_IA_MACHINE_CHECK *s = addr; + return (sizeof(*s) + s->NumHardwareBanks * + sizeof(ACPI_HEST_IA_ERROR_BANK)); + } + case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: { + ACPI_HEST_IA_CORRECTED *s = addr; + return (sizeof(*s) + s->NumHardwareBanks * + sizeof(ACPI_HEST_IA_ERROR_BANK)); + } + case ACPI_HEST_TYPE_IA32_NMI: { + ACPI_HEST_IA_NMI *s = addr; + return (sizeof(*s)); + } + case ACPI_HEST_TYPE_AER_ROOT_PORT: { + ACPI_HEST_AER_ROOT *s = addr; + return (sizeof(*s)); + } + case ACPI_HEST_TYPE_AER_ENDPOINT: { + ACPI_HEST_AER *s = addr; + return (sizeof(*s)); + } + case ACPI_HEST_TYPE_AER_BRIDGE: { + ACPI_HEST_AER_BRIDGE *s = addr; + return (sizeof(*s)); + } + case ACPI_HEST_TYPE_GENERIC_ERROR: { + ACPI_HEST_GENERIC *s = addr; + ge = malloc(sizeof(*ge), M_DEVBUF, M_WAITOK | M_ZERO); + ge->v1 = *s; + TAILQ_INSERT_TAIL(&sc->ges, ge, link); + return (sizeof(*s)); + } + case ACPI_HEST_TYPE_GENERIC_ERROR_V2: { + ACPI_HEST_GENERIC_V2 *s = addr; + ge = malloc(sizeof(*ge), M_DEVBUF, M_WAITOK | M_ZERO); + ge->v2 = *s; + TAILQ_INSERT_TAIL(&sc->ges, ge, link); + return (sizeof(*s)); + } + case ACPI_HEST_TYPE_IA32_DEFERRED_CHECK: { + ACPI_HEST_IA_DEFERRED_CHECK *s = addr; + return (sizeof(*s) + s->NumHardwareBanks * + sizeof(ACPI_HEST_IA_ERROR_BANK)); + } + default: + return (-1); + } +} + +static void +hest_parse_table(struct apei_softc *sc) +{ + ACPI_TABLE_HEST *hest = sc->hest; + char *cp; + int remaining, consumed; + + remaining = hest->Header.Length - sizeof(ACPI_TABLE_HEST); + while (remaining > 0) { + cp = (char *)hest + hest->Header.Length - remaining; + consumed = hest_parse_structure(sc, cp, remaining); + if (consumed <= 0) + break; + else + remaining -= consumed; + } +} + +static char *apei_ids[] = { "PNP0C33", NULL }; +static devclass_t apei_devclass; + +static ACPI_STATUS +apei_find(ACPI_HANDLE handle, UINT32 level, void *context, + void **status) +{ + int *found = (int *)status; + char **ids; + + for (ids = apei_ids; *ids != NULL; ids++) { + if (acpi_MatchHid(handle, *ids)) { + *found = 1; + break; + } + } + return (AE_OK); +} + +static void +apei_identify(driver_t *driver, device_t parent) +{ + device_t child; + int found; + + if (acpi_disabled("apei")) + return; + if (acpi_find_table(ACPI_SIG_HEST) == 0) + return; + /* Only one APEI device can exist. */ + if (devclass_get_device(apei_devclass, 0)) + return; + /* Search for ACPI error device to be used. */ + found = 0; + AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + 100, apei_find, NULL, NULL, (void *)&found); + if (found) + return; + /* If not found - create a fake one. */ + child = BUS_ADD_CHILD(parent, 2, "apei", 0); + if (child == NULL) + printf("%s: can't add child\n", __func__); +} + +static int +apei_probe(device_t dev) +{ + int rv; + + if (acpi_disabled("apei")) + return (ENXIO); + if (acpi_find_table(ACPI_SIG_HEST) == 0) + return (ENXIO); + if (acpi_get_handle(dev) != NULL) + rv = ACPI_ID_PROBE(device_get_parent(dev), dev, apei_ids, NULL); + else + rv = 0; + if (rv <= 0) + device_set_desc(dev, "Platform Error Interface"); + return (rv); +} + +static int +apei_attach(device_t dev) +{ + struct apei_softc *sc = device_get_softc(dev); + struct apei_ge *ge; + ACPI_STATUS status; + int rid; + + TAILQ_INIT(&sc->ges); + + /* Search and parse HEST table. */ + status = AcpiGetTable(ACPI_SIG_HEST, 0, (ACPI_TABLE_HEADER **)&sc->hest); + if (ACPI_FAILURE(status)) + return (ENXIO); + hest_parse_table(sc); + AcpiPutTable((ACPI_TABLE_HEADER *)sc->hest); + + rid = 0; + TAILQ_FOREACH(ge, &sc->ges, link) { + ge->res_rid = rid++; + acpi_bus_alloc_gas(dev, &ge->res_type, &ge->res_rid, + &ge->v1.ErrorStatusAddress, &ge->res, 0); + if (ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2) { + ge->res2_rid = rid++; + acpi_bus_alloc_gas(dev, &ge->res2_type, &ge->res2_rid, + &ge->v2.ReadAckRegister, &ge->res2, 0); + } + ge->buf = pmap_mapdev_attr(READ8(ge->res, 0), + ge->v1.ErrorBlockLength, VM_MEMATTR_WRITE_COMBINING); + if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_POLLED) { + callout_init(&ge->poll, 1); + callout_reset(&ge->poll, + ge->v1.Notify.PollInterval * hz / 1000, + apei_callout_handler, ge); + } else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_NMI) { + ge->copybuf = malloc(ge->v1.ErrorBlockLength, + M_DEVBUF, M_WAITOK | M_ZERO); + swi_add(&clk_intr_event, "apei", apei_nmi_swi, ge, + SWI_CLOCK, INTR_MPSAFE, &ge->swi_ih); + apei_nmi_ge = ge; + apei_nmi = apei_nmi_handler; + } + } + + if (acpi_get_handle(dev) != NULL) { + AcpiInstallNotifyHandler(acpi_get_handle(dev), + ACPI_DEVICE_NOTIFY, apei_notify_handler, dev); + } + return (0); +} + +static int +apei_detach(device_t dev) +{ + struct apei_softc *sc = device_get_softc(dev); + struct apei_ge *ge; + + apei_nmi = NULL; + apei_nmi_ge = NULL; + if (acpi_get_handle(dev) != NULL) { + AcpiRemoveNotifyHandler(acpi_get_handle(dev), + ACPI_DEVICE_NOTIFY, apei_notify_handler); + } + + while ((ge = TAILQ_FIRST(&sc->ges)) != NULL) { + TAILQ_REMOVE(&sc->ges, ge, link); + bus_release_resource(dev, ge->res_type, ge->res_rid, ge->res); + if (ge->res2) { + bus_release_resource(dev, ge->res2_type, + ge->res2_rid, ge->res2); + } + if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_POLLED) { + callout_drain(&ge->poll); + } else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_NMI) { + swi_remove(&ge->swi_ih); + free(ge->copybuf, M_DEVBUF); + } + pmap_unmapdev((vm_offset_t)ge->buf, ge->v1.ErrorBlockLength); + free(ge, M_DEVBUF); + } + return (0); +} + +static device_method_t apei_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, apei_identify), + DEVMETHOD(device_probe, apei_probe), + DEVMETHOD(device_attach, apei_attach), + DEVMETHOD(device_detach, apei_detach), + DEVMETHOD_END +}; + +static driver_t apei_driver = { + "apei", + apei_methods, + sizeof(struct apei_softc), +}; + +DRIVER_MODULE(apei, acpi, apei_driver, apei_devclass, 0, 0); +MODULE_DEPEND(apei, acpi, 1, 1, 1); diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index e740caa7fc8a..379ad427b6b6 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -6306,6 +6306,67 @@ pcie_get_max_completion_timeout(device_t dev) } } +void +pcie_apei_error(device_t dev, int sev, uint8_t *aerp) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + const char *s; + int aer; + uint32_t r, r1; + uint16_t rs; + + if (sev == PCIEM_STA_CORRECTABLE_ERROR) + s = "Correctable"; + else if (sev == PCIEM_STA_NON_FATAL_ERROR) + s = "Uncorrectable (Non-Fatal)"; + else + s = "Uncorrectable (Fatal)"; + device_printf(dev, "%s PCIe error reported by APEI\n", s); + if (aerp) { + if (sev == PCIEM_STA_CORRECTABLE_ERROR) { + r = le32dec(aerp + PCIR_AER_COR_STATUS); + r1 = le32dec(aerp + PCIR_AER_COR_MASK); + } else { + r = le32dec(aerp + PCIR_AER_UC_STATUS); + r1 = le32dec(aerp + PCIR_AER_UC_MASK); + } + device_printf(dev, "status 0x%08x mask 0x%08x", r, r1); + if (sev != PCIEM_STA_CORRECTABLE_ERROR) { + r = le32dec(aerp + PCIR_AER_UC_SEVERITY); + rs = le16dec(aerp + PCIR_AER_CAP_CONTROL); + printf(" severity 0x%08x first %d\n", + r, rs & 0x1f); + } else + printf("\n"); + } + + /* As kind of recovery just report and clear the error statuses. */ + if (pci_find_extcap(dev, PCIZ_AER, &aer) == 0) { + r = pci_read_config(dev, aer + PCIR_AER_UC_STATUS, 4); + if (r != 0) { + pci_write_config(dev, aer + PCIR_AER_UC_STATUS, r, 4); + device_printf(dev, "Clearing UC AER errors 0x%08x\n", r); + } + + r = pci_read_config(dev, aer + PCIR_AER_COR_STATUS, 4); + if (r != 0) { + pci_write_config(dev, aer + PCIR_AER_COR_STATUS, r, 4); + device_printf(dev, "Clearing COR AER errors 0x%08x\n", r); + } + } + if (dinfo->cfg.pcie.pcie_location != 0) { + rs = pci_read_config(dev, dinfo->cfg.pcie.pcie_location + + PCIER_DEVICE_STA, 2); + if ((rs & (PCIEM_STA_CORRECTABLE_ERROR | + PCIEM_STA_NON_FATAL_ERROR | PCIEM_STA_FATAL_ERROR | + PCIEM_STA_UNSUPPORTED_REQ)) != 0) { + pci_write_config(dev, dinfo->cfg.pcie.pcie_location + + PCIER_DEVICE_STA, rs, 2); + device_printf(dev, "Clearing PCIe errors 0x%04x\n", rs); + } + } +} + /* * Perform a Function Level Reset (FLR) on a device. * diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index 37ad9242ebe1..29de6dad93f0 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -686,6 +686,7 @@ uint32_t pcie_read_config(device_t dev, int reg, int width); void pcie_write_config(device_t dev, int reg, uint32_t value, int width); uint32_t pcie_adjust_config(device_t dev, int reg, uint32_t mask, uint32_t value, int width); +void pcie_apei_error(device_t dev, int sev, uint8_t *aer); bool pcie_flr(device_t dev, u_int max_delay, bool force); int pcie_get_max_completion_timeout(device_t dev); bool pcie_wait_for_pending_transactions(device_t dev, u_int max_delay); diff --git a/sys/x86/include/acpica_machdep.h b/sys/x86/include/acpica_machdep.h index 89012b3f4bc4..05e8711c16fa 100644 --- a/sys/x86/include/acpica_machdep.h +++ b/sys/x86/include/acpica_machdep.h @@ -84,6 +84,7 @@ void madt_parse_interrupt_values(void *entry, enum intr_trigger *trig, enum intr_polarity *pol); extern int madt_found_sci_override; +extern int (*apei_nmi)(void); #endif /* _KERNEL */ diff --git a/sys/x86/x86/cpu_machdep.c b/sys/x86/x86/cpu_machdep.c index 74a5261f9112..21efb6d6b122 100644 --- a/sys/x86/x86/cpu_machdep.c +++ b/sys/x86/x86/cpu_machdep.c @@ -831,6 +831,7 @@ int nmi_is_broadcast = 1; SYSCTL_INT(_machdep, OID_AUTO, nmi_is_broadcast, CTLFLAG_RWTUN, &nmi_is_broadcast, 0, "Chipset NMI is broadcast"); +int (*apei_nmi)(void); void nmi_call_kdb(u_int cpu, u_int type, struct trapframe *frame) @@ -846,6 +847,10 @@ nmi_call_kdb(u_int cpu, u_int type, struct trapframe *frame) } #endif /* DEV_ISA */ + /* ACPI Platform Error Interfaces callback. */ + if (apei_nmi != NULL && (*apei_nmi)()) + claimed = true; + /* * NMIs can be useful for debugging. They can be hooked up to a * pushbutton, usually on an ISA, PCI, or PCIe card. They can also be From 952d18a214951dc47ba425047669fe64bfcd3454 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Tue, 28 Jul 2020 00:24:12 +0000 Subject: [PATCH 218/287] ssh: Remove AES-CBC ciphers from default server and client lists A base system OpenSSH update in 2016 or so removed a number of ciphers from the default lists offered by the server/client, due to known weaknesses. This caused POLA issues for some users and prompted PR207679; the ciphers were restored to the default lists in r296634. When upstream removed these ciphers from the default server list, they moved them to the client-only default list. They were subsequently removed from the client default, in OpenSSH 7.9p1. The change has persisted long enough. Remove these extra ciphers from both the server and client default lists, in advance of FreeBSD 13. Reviewed by: markm, rgrimes Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25833 --- crypto/openssh/FREEBSD-upgrade | 7 ------- crypto/openssh/myproposal.h | 4 +--- crypto/openssh/sshd_config.5 | 3 +-- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/crypto/openssh/FREEBSD-upgrade b/crypto/openssh/FREEBSD-upgrade index 6dcfae91fb1d..27e738bee2d4 100644 --- a/crypto/openssh/FREEBSD-upgrade +++ b/crypto/openssh/FREEBSD-upgrade @@ -168,13 +168,6 @@ ignore HPN-related configuration options to avoid breaking existing configurations. -9) AES-CBC - - The AES-CBC ciphers were removed from the server-side proposal list - in 6.7p1 due to theoretical weaknesses and the availability of - superior ciphers (including AES-CTR and AES-GCM). We have re-added - them for compatibility with third-party clients. - This port was brought to you by (in no particular order) DARPA, NAI diff --git a/crypto/openssh/myproposal.h b/crypto/openssh/myproposal.h index d5a1b7a2fa24..27b4a15a1279 100644 --- a/crypto/openssh/myproposal.h +++ b/crypto/openssh/myproposal.h @@ -1,5 +1,4 @@ /* $OpenBSD: myproposal.h,v 1.57 2018/09/12 01:34:02 djm Exp $ */ -/* $FreeBSD$ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -122,8 +121,7 @@ #define KEX_SERVER_ENCRYPT \ "chacha20-poly1305@openssh.com," \ "aes128-ctr,aes192-ctr,aes256-ctr" \ - AESGCM_CIPHER_MODES \ - ",aes128-cbc,aes192-cbc,aes256-cbc" + AESGCM_CIPHER_MODES #define KEX_CLIENT_ENCRYPT KEX_SERVER_ENCRYPT diff --git a/crypto/openssh/sshd_config.5 b/crypto/openssh/sshd_config.5 index 8176078319d1..3f935da9b572 100644 --- a/crypto/openssh/sshd_config.5 +++ b/crypto/openssh/sshd_config.5 @@ -495,8 +495,7 @@ The default is: .Bd -literal -offset indent chacha20-poly1305@openssh.com, aes128-ctr,aes192-ctr,aes256-ctr, -aes128-gcm@openssh.com,aes256-gcm@openssh.com, -aes128-cbc,aes192-cbc,aes256-cbc +aes128-gcm@openssh.com,aes256-gcm@openssh.com .Ed .Pp The list of available ciphers may also be obtained using From fd35bfaecf13d595d63803057869e9d5b2a2145b Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Tue, 28 Jul 2020 01:05:40 +0000 Subject: [PATCH 219/287] makesyscalls.sh: improve the 'this is going away' message Reported by: Ronald Klop, rgrimes --- sys/kern/makesyscalls.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/kern/makesyscalls.sh b/sys/kern/makesyscalls.sh index 8ee34837ccfb..8cbd00a69fcd 100644 --- a/sys/kern/makesyscalls.sh +++ b/sys/kern/makesyscalls.sh @@ -60,7 +60,8 @@ case $# in ;; esac -1>&2 echo "$0: This script is deprecated and will be removed before FreeBSD 13." +1>&2 echo "$0: This script has been replaced by sys/tools/makesyscalls.lua and" +1>&2 echo "$0: will be removed before FreeBSD 13. See also: sys/conf/sysent.mk" if [ -n "$2" ]; then . "$2" From 24e337bec5a5b3bc6e7eba6cda818ef5a8b7c625 Mon Sep 17 00:00:00 2001 From: Ryan Moeller Date: Tue, 28 Jul 2020 02:56:26 +0000 Subject: [PATCH 220/287] libpmc: Use known pmc_cpuid buffer size Use the existing PMC_CPUID_LEN to size pmc_cpuid in the kernel and various buffers for reading it in libpmc. This avoids some extra syscalls and malloc/frees. While in here, use strlcpy to copy a user-provided cpuid string instead of memcpy, to make sure we terminate the buffer. Reviewed by: mav MFC after: 1 week Sponsored by: iXsystems, Inc. Differential Revision: https://reviews.freebsd.org/D25679 --- lib/libpmc/libpmc_pmu_util.c | 24 +++++++----------------- sys/dev/hwpmc/hwpmc_mod.c | 2 +- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/lib/libpmc/libpmc_pmu_util.c b/lib/libpmc/libpmc_pmu_util.c index 11949a3ad3cd..d652573a883f 100644 --- a/lib/libpmc/libpmc_pmu_util.c +++ b/lib/libpmc/libpmc_pmu_util.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -89,20 +90,13 @@ static struct pmu_alias pmu_amd_alias_table[] = { static pmu_mfr_t pmu_events_mfr(void) { - char *buf; - size_t s; + char buf[PMC_CPUID_LEN]; + size_t s = sizeof(buf); pmu_mfr_t mfr; - if (sysctlbyname("kern.hwpmc.cpuid", (void *)NULL, &s, + if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, (void *)NULL, 0) == -1) return (PMU_INVALID); - if ((buf = malloc(s + 1)) == NULL) - return (PMU_INVALID); - if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, - (void *)NULL, 0) == -1) { - free(buf); - return (PMU_INVALID); - } if (strcasestr(buf, "AuthenticAMD") != NULL || strcasestr(buf, "HygonGenuine") != NULL) mfr = PMU_AMD; @@ -110,7 +104,6 @@ pmu_events_mfr(void) mfr = PMU_INTEL; else mfr = PMU_INVALID; - free(buf); return (mfr); } @@ -169,17 +162,14 @@ pmu_events_map_get(const char *cpuid) { regex_t re; regmatch_t pmatch[1]; - size_t s; - char buf[64]; + char buf[PMC_CPUID_LEN]; + size_t s = sizeof(buf); int match; const struct pmu_events_map *pme; if (cpuid != NULL) { - memcpy(buf, cpuid, 64); + strlcpy(buf, cpuid, s); } else { - if (sysctlbyname("kern.hwpmc.cpuid", (void *)NULL, &s, - (void *)NULL, 0) == -1) - return (NULL); if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, (void *)NULL, 0) == -1) return (NULL); diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c index df7400f73528..d343bdced22d 100644 --- a/sys/dev/hwpmc/hwpmc_mod.c +++ b/sys/dev/hwpmc/hwpmc_mod.c @@ -305,7 +305,7 @@ static int pmc_callchaindepth = PMC_CALLCHAIN_DEPTH; SYSCTL_INT(_kern_hwpmc, OID_AUTO, callchaindepth, CTLFLAG_RDTUN, &pmc_callchaindepth, 0, "depth of call chain records"); -char pmc_cpuid[64]; +char pmc_cpuid[PMC_CPUID_LEN]; SYSCTL_STRING(_kern_hwpmc, OID_AUTO, cpuid, CTLFLAG_RD, pmc_cpuid, 0, "cpu version string"); #ifdef HWPMC_DEBUG From 22b33ca4b22e960dab4724b61ca137b078cf3069 Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Tue, 28 Jul 2020 09:29:56 +0000 Subject: [PATCH 221/287] Add an ACPI attachment for if_smc This is needed by some of the Arm simulators as they implement a smc based network interface, but use ACPI rather than FDT. Sponsored by: Innovate UK --- sys/conf/files | 1 + sys/dev/smc/if_smc.c | 23 +++++++++++ sys/dev/smc/if_smc_acpi.c | 80 +++++++++++++++++++++++++++++++++++++++ sys/dev/smc/if_smc_fdt.c | 45 +--------------------- sys/dev/smc/if_smcvar.h | 2 + 5 files changed, 108 insertions(+), 43 deletions(-) create mode 100644 sys/dev/smc/if_smc_acpi.c diff --git a/sys/conf/files b/sys/conf/files index dd9b4bfa8581..59ef9368419e 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3029,6 +3029,7 @@ dev/smbus/smbconf.c optional smbus dev/smbus/smbus.c optional smbus dev/smbus/smbus_if.m optional smbus dev/smc/if_smc.c optional smc +dev/smc/if_smc_acpi.c optional smc acpi dev/smc/if_smc_fdt.c optional smc fdt dev/snp/snp.c optional snp dev/sound/clone.c optional sound diff --git a/sys/dev/smc/if_smc.c b/sys/dev/smc/if_smc.c index d3f911d8327c..627787eab641 100644 --- a/sys/dev/smc/if_smc.c +++ b/sys/dev/smc/if_smc.c @@ -80,6 +80,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include "miibus_if.h" + #define SMC_LOCK(sc) mtx_lock(&(sc)->smc_mtx) #define SMC_UNLOCK(sc) mtx_unlock(&(sc)->smc_mtx) #define SMC_ASSERT_LOCKED(sc) mtx_assert(&(sc)->smc_mtx, MA_OWNED) @@ -480,6 +482,27 @@ smc_detach(device_t dev) return (0); } +static device_method_t smc_methods[] = { + /* Device interface */ + DEVMETHOD(device_attach, smc_attach), + DEVMETHOD(device_detach, smc_detach), + + /* MII interface */ + DEVMETHOD(miibus_readreg, smc_miibus_readreg), + DEVMETHOD(miibus_writereg, smc_miibus_writereg), + DEVMETHOD(miibus_statchg, smc_miibus_statchg), + + { 0, 0 } +}; + +driver_t smc_driver = { + "smc", + smc_methods, + sizeof(struct smc_softc), +}; + +DRIVER_MODULE(miibus, smc, miibus_driver, miibus_devclass, 0, 0); + static void smc_start(struct ifnet *ifp) { diff --git a/sys/dev/smc/if_smc_acpi.c b/sys/dev/smc/if_smc_acpi.c new file mode 100644 index 000000000000..74f591493167 --- /dev/null +++ b/sys/dev/smc/if_smc_acpi.c @@ -0,0 +1,80 @@ +/*- + * Copyright (c) 2008 Benno Rice + * All rights reserved. + * Copyright (c) 2020 Andrew Turner + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +static int smc_acpi_probe(device_t); + +static int +smc_acpi_probe(device_t dev) +{ + struct smc_softc *sc; + ACPI_HANDLE h; + + if ((h = acpi_get_handle(dev)) == NULL) + return (ENXIO); + + if (!acpi_MatchHid(h, "LNRO0003")) + return (ENXIO); + + sc = device_get_softc(dev); + sc->smc_usemem = 1; + + return (smc_probe(dev)); +} + +static device_method_t smc_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, smc_acpi_probe), + { 0, 0 } +}; + +DEFINE_CLASS_1(smc, smc_acpi_driver, smc_acpi_methods, + sizeof(struct smc_softc), smc_driver); + +extern devclass_t smc_devclass; + +DRIVER_MODULE(smc, acpi, smc_acpi_driver, smc_devclass, 0, 0); +MODULE_DEPEND(smc, acpi, 1, 1, 1); +MODULE_DEPEND(smc, ether, 1, 1, 1); +MODULE_DEPEND(smc, miibus, 1, 1, 1); diff --git a/sys/dev/smc/if_smc_fdt.c b/sys/dev/smc/if_smc_fdt.c index baca0bd6113e..2c63b9f94d49 100644 --- a/sys/dev/smc/if_smc_fdt.c +++ b/sys/dev/smc/if_smc_fdt.c @@ -35,29 +35,16 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include - -#include #include -#include -#include #include -#include -#include - #include #include #include #include -#include "miibus_if.h" - static int smc_fdt_probe(device_t); -static int smc_fdt_attach(device_t); -static int smc_fdt_detach(device_t); static int smc_fdt_probe(device_t dev) @@ -81,46 +68,18 @@ smc_fdt_probe(device_t dev) return (ENXIO); } -static int -smc_fdt_attach(device_t dev) -{ - - return smc_attach(dev); -} - -static int -smc_fdt_detach(device_t dev) -{ - - smc_detach(dev); - - return (0); -} - static device_method_t smc_fdt_methods[] = { /* Device interface */ DEVMETHOD(device_probe, smc_fdt_probe), - DEVMETHOD(device_attach, smc_fdt_attach), - DEVMETHOD(device_detach, smc_fdt_detach), - - /* MII interface */ - DEVMETHOD(miibus_readreg, smc_miibus_readreg), - DEVMETHOD(miibus_writereg, smc_miibus_writereg), - DEVMETHOD(miibus_statchg, smc_miibus_statchg), - { 0, 0 } }; -static driver_t smc_fdt_driver = { - "smc", - smc_fdt_methods, - sizeof(struct smc_softc), -}; +DEFINE_CLASS_1(smc, smc_fdt_driver, smc_fdt_methods, + sizeof(struct smc_softc), smc_driver); extern devclass_t smc_devclass; DRIVER_MODULE(smc, simplebus, smc_fdt_driver, smc_devclass, 0, 0); -DRIVER_MODULE(miibus, smc, miibus_driver, miibus_devclass, 0, 0); MODULE_DEPEND(smc, fdt, 1, 1, 1); MODULE_DEPEND(smc, ether, 1, 1, 1); MODULE_DEPEND(smc, miibus, 1, 1, 1); diff --git a/sys/dev/smc/if_smcvar.h b/sys/dev/smc/if_smcvar.h index a58eb0df0374..8de30706a0a5 100644 --- a/sys/dev/smc/if_smcvar.h +++ b/sys/dev/smc/if_smcvar.h @@ -68,6 +68,8 @@ struct smc_softc { void *smc_read_arg; }; +DECLARE_CLASS(smc_driver); + int smc_probe(device_t); int smc_attach(device_t); int smc_detach(device_t); From b77fd846925d3b3d569f0eaeace9adaf10dca6cd Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Tue, 28 Jul 2020 09:46:58 +0000 Subject: [PATCH 222/287] Enable use of the regulator in the Broadcom SDHCI controller This will be needed before a future GPIO controller driver is added as the later enables regulators that leave the SDHCI controller disabled. Reviewed by: manu Sponsored by: Innovate UK Differential Revision: https://reviews.freebsd.org/D25834 --- sys/arm/broadcom/bcm2835/bcm2835_sdhci.c | 36 +++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c index 0140afcc4a97..8bf8049fc1ae 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include @@ -155,6 +156,7 @@ struct bcm_sdhci_softc { void * sc_intrhand; struct mmc_request * sc_req; struct sdhci_slot sc_slot; + struct mmc_fdt_helper sc_mmc_helper; int sc_dma_ch; bus_dma_tag_t sc_dma_tag; bus_dmamap_t sc_dma_map; @@ -315,6 +317,7 @@ bcm_sdhci_attach(device_t dev) sc->sc_slot.quirks = sc->conf->quirks; sdhci_init_slot(dev, &sc->sc_slot, 0); + mmc_fdt_parse(dev, 0, &sc->sc_mmc_helper, &sc->sc_slot.host); sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_ANY); if (sc->sc_dma_ch == BCM_DMA_CH_INVALID) @@ -388,6 +391,37 @@ bcm_sdhci_intr(void *arg) sdhci_generic_intr(&sc->sc_slot); } +static int +bcm_sdhci_update_ios(device_t bus, device_t child) +{ + struct bcm_sdhci_softc *sc; + struct mmc_ios *ios; + int rv; + + sc = device_get_softc(bus); + ios = &sc->sc_slot.host.ios; + + if (ios->power_mode == power_up) { + if (sc->sc_mmc_helper.vmmc_supply) + regulator_enable(sc->sc_mmc_helper.vmmc_supply); + if (sc->sc_mmc_helper.vqmmc_supply) + regulator_enable(sc->sc_mmc_helper.vqmmc_supply); + } + + rv = sdhci_generic_update_ios(bus, child); + if (rv != 0) + return (rv); + + if (ios->power_mode == power_off) { + if (sc->sc_mmc_helper.vmmc_supply) + regulator_disable(sc->sc_mmc_helper.vmmc_supply); + if (sc->sc_mmc_helper.vqmmc_supply) + regulator_disable(sc->sc_mmc_helper.vqmmc_supply); + } + + return (0); +} + static int bcm_sdhci_get_ro(device_t bus, device_t child) { @@ -787,7 +821,7 @@ static device_method_t bcm_sdhci_methods[] = { DEVMETHOD(bus_add_child, bus_generic_add_child), /* MMC bridge interface */ - DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), + DEVMETHOD(mmcbr_update_ios, bcm_sdhci_update_ios), DEVMETHOD(mmcbr_request, sdhci_generic_request), DEVMETHOD(mmcbr_get_ro, bcm_sdhci_get_ro), DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), From cd21fc6a4dc6ef009f62f15a8f2a4bfcabfe856a Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Tue, 28 Jul 2020 10:08:07 +0000 Subject: [PATCH 223/287] Fix ENA build when integrated into kernel Provide missing rules for ena_datapath.c and ena_netmap.c, which prevented the ENA driver from building. This issue was showing up only when building the driver statically into the kernel. PR: 248116 Submitted by: Artur Rojek MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D25796 Obtained from: Semihalf Sponsored by: Amazon, Inc. --- sys/conf/files | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/conf/files b/sys/conf/files index 59ef9368419e..2f9e75d73d41 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1641,6 +1641,10 @@ dev/e1000/e1000_osdep.c optional em \ dev/et/if_et.c optional et dev/ena/ena.c optional ena \ compile-with "${NORMAL_C} -I$S/contrib" +dev/ena/ena_datapath.c optional ena \ + compile-with "${NORMAL_C} -I$S/contrib" +dev/ena/ena_netmap.c optional ena \ + compile-with "${NORMAL_C} -I$S/contrib" dev/ena/ena_sysctl.c optional ena \ compile-with "${NORMAL_C} -I$S/contrib" contrib/ena-com/ena_com.c optional ena From feecedb1c6dca9f39bab114bc89f7d3077d0dc59 Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Tue, 28 Jul 2020 10:37:58 +0000 Subject: [PATCH 224/287] Have the bcm2835 firmware driver depend on the mailbox driver The firmware driver uses the mailbox driver to communicate with the firmware. Make this a more formal dependency. Reviewed by: manu Sponsored by: Innovate UK --- sys/arm/broadcom/bcm2835/bcm2835_firmware.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/arm/broadcom/bcm2835/bcm2835_firmware.c b/sys/arm/broadcom/bcm2835/bcm2835_firmware.c index dcc23fe1cd61..44201ec80f7d 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_firmware.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_firmware.c @@ -177,5 +177,6 @@ static driver_t bcm2835_firmware_driver = { sizeof(struct bcm2835_firmware_softc), }; -DRIVER_MODULE(bcm2835_firmware, simplebus, bcm2835_firmware_driver, - bcm2835_firmware_devclass, 0, 0); +EARLY_DRIVER_MODULE(bcm2835_firmware, simplebus, bcm2835_firmware_driver, + bcm2835_firmware_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); +MODULE_DEPEND(bcm2835_firmware, mbox, 1, 1, 1); From 4b24f9a0a8362feeafe4058be707ae2187763888 Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Tue, 28 Jul 2020 10:40:00 +0000 Subject: [PATCH 225/287] Move the bcm2835 mailbox driver earlier in the boot This will be needed before the firmware driver is loaded --- sys/arm/broadcom/bcm2835/bcm2835_mbox.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/arm/broadcom/bcm2835/bcm2835_mbox.c b/sys/arm/broadcom/bcm2835/bcm2835_mbox.c index 4d6ab7e9a6c3..b3d012a417fe 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_mbox.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_mbox.c @@ -293,7 +293,8 @@ static driver_t bcm_mbox_driver = { static devclass_t bcm_mbox_devclass; -DRIVER_MODULE(mbox, simplebus, bcm_mbox_driver, bcm_mbox_devclass, 0, 0); +EARLY_DRIVER_MODULE(mbox, simplebus, bcm_mbox_driver, bcm_mbox_devclass, 0, 0, + BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); static void bcm2835_mbox_dma_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) From 73d0751a819e96c1eb8e780cb05541d2ed535a62 Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Tue, 28 Jul 2020 10:41:43 +0000 Subject: [PATCH 226/287] Revert r363639 so I can use a more correct commit message --- sys/arm/broadcom/bcm2835/bcm2835_firmware.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sys/arm/broadcom/bcm2835/bcm2835_firmware.c b/sys/arm/broadcom/bcm2835/bcm2835_firmware.c index 44201ec80f7d..dcc23fe1cd61 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_firmware.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_firmware.c @@ -177,6 +177,5 @@ static driver_t bcm2835_firmware_driver = { sizeof(struct bcm2835_firmware_softc), }; -EARLY_DRIVER_MODULE(bcm2835_firmware, simplebus, bcm2835_firmware_driver, - bcm2835_firmware_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); -MODULE_DEPEND(bcm2835_firmware, mbox, 1, 1, 1); +DRIVER_MODULE(bcm2835_firmware, simplebus, bcm2835_firmware_driver, + bcm2835_firmware_devclass, 0, 0); From 0083fb5d491c5c539425e4196e573490659beedf Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Tue, 28 Jul 2020 10:43:52 +0000 Subject: [PATCH 227/287] Move the bcm2835 firmware driver earlier in the boot. It will be needed by other eaarly drivers. While here make the dependency of the mailbox formal with MODULE_DEPEND. Reviewed by: manu Sponsored by: Innovate UK --- sys/arm/broadcom/bcm2835/bcm2835_firmware.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/arm/broadcom/bcm2835/bcm2835_firmware.c b/sys/arm/broadcom/bcm2835/bcm2835_firmware.c index dcc23fe1cd61..44201ec80f7d 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_firmware.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_firmware.c @@ -177,5 +177,6 @@ static driver_t bcm2835_firmware_driver = { sizeof(struct bcm2835_firmware_softc), }; -DRIVER_MODULE(bcm2835_firmware, simplebus, bcm2835_firmware_driver, - bcm2835_firmware_devclass, 0, 0); +EARLY_DRIVER_MODULE(bcm2835_firmware, simplebus, bcm2835_firmware_driver, + bcm2835_firmware_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); +MODULE_DEPEND(bcm2835_firmware, mbox, 1, 1, 1); From 7413ae0ee548a888e3a62f8d5c8332302fad9fc1 Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Tue, 28 Jul 2020 10:45:29 +0000 Subject: [PATCH 228/287] Switch the bcm2835 cpufreq driver to use the firmware interface Use the new Raspberry Pi firmware driver in the cpufreq driver. It is intended all drivers that need to interact with the firmware will move to use the firmware driver, this is the first. Reviewed by: manu Sponsored by: Innovate UK Differential Revision: https://reviews.freebsd.org/D25609 --- sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c | 363 ++++++++----------- sys/arm/broadcom/bcm2835/bcm2835_firmware.h | 109 ++++++ sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h | 58 --- 3 files changed, 267 insertions(+), 263 deletions(-) diff --git a/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c b/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c index 1b5e3a63e09e..15c1106cf36f 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c @@ -47,12 +47,10 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include +#include #include #include "cpufreq_if.h" -#include "mbox_if.h" #ifdef DEBUG #define DPRINTF(fmt, ...) do { \ @@ -101,6 +99,7 @@ static struct sysctl_ctx_list bcm2835_sysctl_ctx; struct bcm2835_cpufreq_softc { device_t dev; + device_t firmware; int arm_max_freq; int arm_min_freq; int core_max_freq; @@ -161,7 +160,7 @@ static int bcm2835_cpufreq_get_clock_rate(struct bcm2835_cpufreq_softc *sc, uint32_t clock_id) { - struct msg_get_clock_rate msg; + union msg_get_clock_rate_body msg; int rate; int err; @@ -181,16 +180,11 @@ bcm2835_cpufreq_get_clock_rate(struct bcm2835_cpufreq_softc *sc, /* setup single tag buffer */ memset(&msg, 0, sizeof(msg)); - msg.hdr.buf_size = sizeof(msg); - msg.hdr.code = BCM2835_MBOX_CODE_REQ; - msg.tag_hdr.tag = BCM2835_MBOX_TAG_GET_CLOCK_RATE; - msg.tag_hdr.val_buf_size = sizeof(msg.body); - msg.tag_hdr.val_len = sizeof(msg.body.req); - msg.body.req.clock_id = clock_id; - msg.end_tag = 0; + msg.req.clock_id = clock_id; /* call mailbox property */ - err = bcm2835_mbox_property(&msg, sizeof(msg)); + err = bcm2835_firmware_property(sc->firmware, + BCM2835_FIRMWARE_TAG_GET_CLOCK_RATE, &msg, sizeof(msg)); if (err) { device_printf(sc->dev, "can't get clock rate (id=%u)\n", clock_id); @@ -198,7 +192,7 @@ bcm2835_cpufreq_get_clock_rate(struct bcm2835_cpufreq_softc *sc, } /* result (Hz) */ - rate = (int)msg.body.resp.rate_hz; + rate = (int)msg.resp.rate_hz; DPRINTF("clock = %d(Hz)\n", rate); return (rate); } @@ -207,7 +201,7 @@ static int bcm2835_cpufreq_get_max_clock_rate(struct bcm2835_cpufreq_softc *sc, uint32_t clock_id) { - struct msg_get_max_clock_rate msg; + union msg_get_clock_rate_body msg; int rate; int err; @@ -227,16 +221,11 @@ bcm2835_cpufreq_get_max_clock_rate(struct bcm2835_cpufreq_softc *sc, /* setup single tag buffer */ memset(&msg, 0, sizeof(msg)); - msg.hdr.buf_size = sizeof(msg); - msg.hdr.code = BCM2835_MBOX_CODE_REQ; - msg.tag_hdr.tag = BCM2835_MBOX_TAG_GET_MAX_CLOCK_RATE; - msg.tag_hdr.val_buf_size = sizeof(msg.body); - msg.tag_hdr.val_len = sizeof(msg.body.req); - msg.body.req.clock_id = clock_id; - msg.end_tag = 0; + msg.req.clock_id = clock_id; /* call mailbox property */ - err = bcm2835_mbox_property(&msg, sizeof(msg)); + err = bcm2835_firmware_property(sc->firmware, + BCM2835_FIRMWARE_TAG_GET_MAX_CLOCK_RATE, &msg, sizeof(msg)); if (err) { device_printf(sc->dev, "can't get max clock rate (id=%u)\n", clock_id); @@ -244,7 +233,7 @@ bcm2835_cpufreq_get_max_clock_rate(struct bcm2835_cpufreq_softc *sc, } /* result (Hz) */ - rate = (int)msg.body.resp.rate_hz; + rate = (int)msg.resp.rate_hz; DPRINTF("clock = %d(Hz)\n", rate); return (rate); } @@ -253,7 +242,7 @@ static int bcm2835_cpufreq_get_min_clock_rate(struct bcm2835_cpufreq_softc *sc, uint32_t clock_id) { - struct msg_get_min_clock_rate msg; + union msg_get_clock_rate_body msg; int rate; int err; @@ -273,16 +262,11 @@ bcm2835_cpufreq_get_min_clock_rate(struct bcm2835_cpufreq_softc *sc, /* setup single tag buffer */ memset(&msg, 0, sizeof(msg)); - msg.hdr.buf_size = sizeof(msg); - msg.hdr.code = BCM2835_MBOX_CODE_REQ; - msg.tag_hdr.tag = BCM2835_MBOX_TAG_GET_MIN_CLOCK_RATE; - msg.tag_hdr.val_buf_size = sizeof(msg.body); - msg.tag_hdr.val_len = sizeof(msg.body.req); - msg.body.req.clock_id = clock_id; - msg.end_tag = 0; + msg.req.clock_id = clock_id; /* call mailbox property */ - err = bcm2835_mbox_property(&msg, sizeof(msg)); + err = bcm2835_firmware_property(sc->firmware, + BCM2835_FIRMWARE_TAG_GET_MIN_CLOCK_RATE, &msg, sizeof(msg)); if (err) { device_printf(sc->dev, "can't get min clock rate (id=%u)\n", clock_id); @@ -290,7 +274,7 @@ bcm2835_cpufreq_get_min_clock_rate(struct bcm2835_cpufreq_softc *sc, } /* result (Hz) */ - rate = (int)msg.body.resp.rate_hz; + rate = (int)msg.resp.rate_hz; DPRINTF("clock = %d(Hz)\n", rate); return (rate); } @@ -299,7 +283,7 @@ static int bcm2835_cpufreq_set_clock_rate(struct bcm2835_cpufreq_softc *sc, uint32_t clock_id, uint32_t rate_hz) { - struct msg_set_clock_rate msg; + union msg_set_clock_rate_body msg; int rate; int err; @@ -320,17 +304,12 @@ bcm2835_cpufreq_set_clock_rate(struct bcm2835_cpufreq_softc *sc, /* setup single tag buffer */ memset(&msg, 0, sizeof(msg)); - msg.hdr.buf_size = sizeof(msg); - msg.hdr.code = BCM2835_MBOX_CODE_REQ; - msg.tag_hdr.tag = BCM2835_MBOX_TAG_SET_CLOCK_RATE; - msg.tag_hdr.val_buf_size = sizeof(msg.body); - msg.tag_hdr.val_len = sizeof(msg.body.req); - msg.body.req.clock_id = clock_id; - msg.body.req.rate_hz = rate_hz; - msg.end_tag = 0; + msg.req.clock_id = clock_id; + msg.req.rate_hz = rate_hz; /* call mailbox property */ - err = bcm2835_mbox_property(&msg, sizeof(msg)); + err = bcm2835_firmware_property(sc->firmware, + BCM2835_FIRMWARE_TAG_SET_CLOCK_RATE, &msg, sizeof(msg)); if (err) { device_printf(sc->dev, "can't set clock rate (id=%u)\n", clock_id); @@ -338,7 +317,7 @@ bcm2835_cpufreq_set_clock_rate(struct bcm2835_cpufreq_softc *sc, } /* workaround for core clock */ - if (clock_id == BCM2835_MBOX_CLOCK_ID_CORE) { + if (clock_id == BCM2835_FIRMWARE_CLOCK_ID_CORE) { /* for safety (may change voltage without changing clock) */ DELAY(TRANSITION_LATENCY); @@ -349,17 +328,12 @@ bcm2835_cpufreq_set_clock_rate(struct bcm2835_cpufreq_softc *sc, /* setup single tag buffer */ memset(&msg, 0, sizeof(msg)); - msg.hdr.buf_size = sizeof(msg); - msg.hdr.code = BCM2835_MBOX_CODE_REQ; - msg.tag_hdr.tag = BCM2835_MBOX_TAG_SET_CLOCK_RATE; - msg.tag_hdr.val_buf_size = sizeof(msg.body); - msg.tag_hdr.val_len = sizeof(msg.body.req); - msg.body.req.clock_id = clock_id; - msg.body.req.rate_hz = rate_hz; - msg.end_tag = 0; + msg.req.clock_id = clock_id; + msg.req.rate_hz = rate_hz; /* call mailbox property */ - err = bcm2835_mbox_property(&msg, sizeof(msg)); + err = bcm2835_firmware_property(sc->firmware, + BCM2835_FIRMWARE_TAG_SET_CLOCK_RATE, &msg, sizeof(msg)); if (err) { device_printf(sc->dev, "can't set clock rate (id=%u)\n", clock_id); @@ -368,7 +342,7 @@ bcm2835_cpufreq_set_clock_rate(struct bcm2835_cpufreq_softc *sc, } /* result (Hz) */ - rate = (int)msg.body.resp.rate_hz; + rate = (int)msg.resp.rate_hz; DPRINTF("clock = %d(Hz)\n", rate); return (rate); } @@ -376,7 +350,7 @@ bcm2835_cpufreq_set_clock_rate(struct bcm2835_cpufreq_softc *sc, static int bcm2835_cpufreq_get_turbo(struct bcm2835_cpufreq_softc *sc) { - struct msg_get_turbo msg; + union msg_get_turbo_body msg; int level; int err; @@ -396,23 +370,18 @@ bcm2835_cpufreq_get_turbo(struct bcm2835_cpufreq_softc *sc) /* setup single tag buffer */ memset(&msg, 0, sizeof(msg)); - msg.hdr.buf_size = sizeof(msg); - msg.hdr.code = BCM2835_MBOX_CODE_REQ; - msg.tag_hdr.tag = BCM2835_MBOX_TAG_GET_TURBO; - msg.tag_hdr.val_buf_size = sizeof(msg.body); - msg.tag_hdr.val_len = sizeof(msg.body.req); - msg.body.req.id = 0; - msg.end_tag = 0; + msg.req.id = 0; /* call mailbox property */ - err = bcm2835_mbox_property(&msg, sizeof(msg)); + err = bcm2835_firmware_property(sc->firmware, + BCM2835_FIRMWARE_TAG_GET_TURBO, &msg, sizeof(msg)); if (err) { device_printf(sc->dev, "can't get turbo\n"); return (MSG_ERROR); } /* result 0=non-turbo, 1=turbo */ - level = (int)msg.body.resp.level; + level = (int)msg.resp.level; DPRINTF("level = %d\n", level); return (level); } @@ -420,7 +389,7 @@ bcm2835_cpufreq_get_turbo(struct bcm2835_cpufreq_softc *sc) static int bcm2835_cpufreq_set_turbo(struct bcm2835_cpufreq_softc *sc, uint32_t level) { - struct msg_set_turbo msg; + union msg_set_turbo_body msg; int value; int err; @@ -440,29 +409,25 @@ bcm2835_cpufreq_set_turbo(struct bcm2835_cpufreq_softc *sc, uint32_t level) */ /* replace unknown value to OFF */ - if (level != BCM2835_MBOX_TURBO_ON && level != BCM2835_MBOX_TURBO_OFF) - level = BCM2835_MBOX_TURBO_OFF; + if (level != BCM2835_FIRMWARE_TURBO_ON && + level != BCM2835_FIRMWARE_TURBO_OFF) + level = BCM2835_FIRMWARE_TURBO_OFF; /* setup single tag buffer */ memset(&msg, 0, sizeof(msg)); - msg.hdr.buf_size = sizeof(msg); - msg.hdr.code = BCM2835_MBOX_CODE_REQ; - msg.tag_hdr.tag = BCM2835_MBOX_TAG_SET_TURBO; - msg.tag_hdr.val_buf_size = sizeof(msg.body); - msg.tag_hdr.val_len = sizeof(msg.body.req); - msg.body.req.id = 0; - msg.body.req.level = level; - msg.end_tag = 0; + msg.req.id = 0; + msg.req.level = level; /* call mailbox property */ - err = bcm2835_mbox_property(&msg, sizeof(msg)); + err = bcm2835_firmware_property(sc->firmware, + BCM2835_FIRMWARE_TAG_SET_TURBO, &msg, sizeof(msg)); if (err) { device_printf(sc->dev, "can't set turbo\n"); return (MSG_ERROR); } /* result 0=non-turbo, 1=turbo */ - value = (int)msg.body.resp.level; + value = (int)msg.resp.level; DPRINTF("level = %d\n", value); return (value); } @@ -471,7 +436,7 @@ static int bcm2835_cpufreq_get_voltage(struct bcm2835_cpufreq_softc *sc, uint32_t voltage_id) { - struct msg_get_voltage msg; + union msg_get_voltage_body msg; int value; int err; @@ -491,23 +456,18 @@ bcm2835_cpufreq_get_voltage(struct bcm2835_cpufreq_softc *sc, /* setup single tag buffer */ memset(&msg, 0, sizeof(msg)); - msg.hdr.buf_size = sizeof(msg); - msg.hdr.code = BCM2835_MBOX_CODE_REQ; - msg.tag_hdr.tag = BCM2835_MBOX_TAG_GET_VOLTAGE; - msg.tag_hdr.val_buf_size = sizeof(msg.body); - msg.tag_hdr.val_len = sizeof(msg.body.req); - msg.body.req.voltage_id = voltage_id; - msg.end_tag = 0; + msg.req.voltage_id = voltage_id; /* call mailbox property */ - err = bcm2835_mbox_property(&msg, sizeof(msg)); + err = bcm2835_firmware_property(sc->firmware, + BCM2835_FIRMWARE_TAG_GET_VOLTAGE, &msg, sizeof(msg)); if (err) { device_printf(sc->dev, "can't get voltage\n"); return (MSG_ERROR); } /* result (offset from 1.2V) */ - value = (int)msg.body.resp.value; + value = (int)msg.resp.value; DPRINTF("value = %d\n", value); return (value); } @@ -516,7 +476,7 @@ static int bcm2835_cpufreq_get_max_voltage(struct bcm2835_cpufreq_softc *sc, uint32_t voltage_id) { - struct msg_get_max_voltage msg; + union msg_get_voltage_body msg; int value; int err; @@ -536,23 +496,18 @@ bcm2835_cpufreq_get_max_voltage(struct bcm2835_cpufreq_softc *sc, /* setup single tag buffer */ memset(&msg, 0, sizeof(msg)); - msg.hdr.buf_size = sizeof(msg); - msg.hdr.code = BCM2835_MBOX_CODE_REQ; - msg.tag_hdr.tag = BCM2835_MBOX_TAG_GET_MAX_VOLTAGE; - msg.tag_hdr.val_buf_size = sizeof(msg.body); - msg.tag_hdr.val_len = sizeof(msg.body.req); - msg.body.req.voltage_id = voltage_id; - msg.end_tag = 0; + msg.req.voltage_id = voltage_id; /* call mailbox property */ - err = bcm2835_mbox_property(&msg, sizeof(msg)); + err = bcm2835_firmware_property(sc->firmware, + BCM2835_FIRMWARE_TAG_GET_MAX_VOLTAGE, &msg, sizeof(msg)); if (err) { device_printf(sc->dev, "can't get max voltage\n"); return (MSG_ERROR); } /* result (offset from 1.2V) */ - value = (int)msg.body.resp.value; + value = (int)msg.resp.value; DPRINTF("value = %d\n", value); return (value); } @@ -560,7 +515,7 @@ static int bcm2835_cpufreq_get_min_voltage(struct bcm2835_cpufreq_softc *sc, uint32_t voltage_id) { - struct msg_get_min_voltage msg; + union msg_get_voltage_body msg; int value; int err; @@ -580,23 +535,18 @@ bcm2835_cpufreq_get_min_voltage(struct bcm2835_cpufreq_softc *sc, /* setup single tag buffer */ memset(&msg, 0, sizeof(msg)); - msg.hdr.buf_size = sizeof(msg); - msg.hdr.code = BCM2835_MBOX_CODE_REQ; - msg.tag_hdr.tag = BCM2835_MBOX_TAG_GET_MIN_VOLTAGE; - msg.tag_hdr.val_buf_size = sizeof(msg.body); - msg.tag_hdr.val_len = sizeof(msg.body.req); - msg.body.req.voltage_id = voltage_id; - msg.end_tag = 0; + msg.req.voltage_id = voltage_id; /* call mailbox property */ - err = bcm2835_mbox_property(&msg, sizeof(msg)); + err = bcm2835_firmware_property(sc->firmware, + BCM2835_FIRMWARE_TAG_GET_MIN_VOLTAGE, &msg, sizeof(msg)); if (err) { device_printf(sc->dev, "can't get min voltage\n"); return (MSG_ERROR); } /* result (offset from 1.2V) */ - value = (int)msg.body.resp.value; + value = (int)msg.resp.value; DPRINTF("value = %d\n", value); return (value); } @@ -605,7 +555,7 @@ static int bcm2835_cpufreq_set_voltage(struct bcm2835_cpufreq_softc *sc, uint32_t voltage_id, int32_t value) { - struct msg_set_voltage msg; + union msg_set_voltage_body msg; int err; /* @@ -636,24 +586,19 @@ bcm2835_cpufreq_set_voltage(struct bcm2835_cpufreq_softc *sc, /* setup single tag buffer */ memset(&msg, 0, sizeof(msg)); - msg.hdr.buf_size = sizeof(msg); - msg.hdr.code = BCM2835_MBOX_CODE_REQ; - msg.tag_hdr.tag = BCM2835_MBOX_TAG_SET_VOLTAGE; - msg.tag_hdr.val_buf_size = sizeof(msg.body); - msg.tag_hdr.val_len = sizeof(msg.body.req); - msg.body.req.voltage_id = voltage_id; - msg.body.req.value = (uint32_t)value; - msg.end_tag = 0; + msg.req.voltage_id = voltage_id; + msg.req.value = (uint32_t)value; /* call mailbox property */ - err = bcm2835_mbox_property(&msg, sizeof(msg)); + err = bcm2835_firmware_property(sc->firmware, + BCM2835_FIRMWARE_TAG_SET_VOLTAGE, &msg, sizeof(msg)); if (err) { device_printf(sc->dev, "can't set voltage\n"); return (MSG_ERROR); } /* result (offset from 1.2V) */ - value = (int)msg.body.resp.value; + value = (int)msg.resp.value; DPRINTF("value = %d\n", value); return (value); } @@ -661,7 +606,7 @@ bcm2835_cpufreq_set_voltage(struct bcm2835_cpufreq_softc *sc, static int bcm2835_cpufreq_get_temperature(struct bcm2835_cpufreq_softc *sc) { - struct msg_get_temperature msg; + union msg_get_temperature_body msg; int value; int err; @@ -681,23 +626,18 @@ bcm2835_cpufreq_get_temperature(struct bcm2835_cpufreq_softc *sc) /* setup single tag buffer */ memset(&msg, 0, sizeof(msg)); - msg.hdr.buf_size = sizeof(msg); - msg.hdr.code = BCM2835_MBOX_CODE_REQ; - msg.tag_hdr.tag = BCM2835_MBOX_TAG_GET_TEMPERATURE; - msg.tag_hdr.val_buf_size = sizeof(msg.body); - msg.tag_hdr.val_len = sizeof(msg.body.req); - msg.body.req.temperature_id = 0; - msg.end_tag = 0; + msg.req.temperature_id = 0; /* call mailbox property */ - err = bcm2835_mbox_property(&msg, sizeof(msg)); + err = bcm2835_firmware_property(sc->firmware, + BCM2835_FIRMWARE_TAG_GET_TEMPERATURE, &msg, sizeof(msg)); if (err) { device_printf(sc->dev, "can't get temperature\n"); return (MSG_ERROR); } /* result (temperature of degree C) */ - value = (int)msg.body.resp.value; + value = (int)msg.resp.value; DPRINTF("value = %d\n", value); return (value); } @@ -713,7 +653,7 @@ sysctl_bcm2835_cpufreq_arm_freq(SYSCTL_HANDLER_ARGS) /* get realtime value */ VC_LOCK(sc); - val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM); + val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_FIRMWARE_CLOCK_ID_ARM); VC_UNLOCK(sc); if (val == MSG_ERROR) return (EIO); @@ -724,7 +664,7 @@ sysctl_bcm2835_cpufreq_arm_freq(SYSCTL_HANDLER_ARGS) /* write request */ VC_LOCK(sc); - err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM, + err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_FIRMWARE_CLOCK_ID_ARM, val); VC_UNLOCK(sc); if (err == MSG_ERROR) { @@ -745,7 +685,8 @@ sysctl_bcm2835_cpufreq_core_freq(SYSCTL_HANDLER_ARGS) /* get realtime value */ VC_LOCK(sc); - val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE); + val = bcm2835_cpufreq_get_clock_rate(sc, + BCM2835_FIRMWARE_CLOCK_ID_CORE); VC_UNLOCK(sc); if (val == MSG_ERROR) return (EIO); @@ -756,7 +697,7 @@ sysctl_bcm2835_cpufreq_core_freq(SYSCTL_HANDLER_ARGS) /* write request */ VC_LOCK(sc); - err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE, + err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_FIRMWARE_CLOCK_ID_CORE, val); if (err == MSG_ERROR) { VC_UNLOCK(sc); @@ -778,7 +719,8 @@ sysctl_bcm2835_cpufreq_sdram_freq(SYSCTL_HANDLER_ARGS) /* get realtime value */ VC_LOCK(sc); - val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_SDRAM); + val = bcm2835_cpufreq_get_clock_rate(sc, + BCM2835_FIRMWARE_CLOCK_ID_SDRAM); VC_UNLOCK(sc); if (val == MSG_ERROR) return (EIO); @@ -789,8 +731,8 @@ sysctl_bcm2835_cpufreq_sdram_freq(SYSCTL_HANDLER_ARGS) /* write request */ VC_LOCK(sc); - err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_SDRAM, - val); + err = bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_FIRMWARE_CLOCK_ID_SDRAM, val); VC_UNLOCK(sc); if (err == MSG_ERROR) { device_printf(sc->dev, "set clock sdram_freq error\n"); @@ -821,9 +763,9 @@ sysctl_bcm2835_cpufreq_turbo(SYSCTL_HANDLER_ARGS) /* write request */ if (val > 0) - sc->turbo_mode = BCM2835_MBOX_TURBO_ON; + sc->turbo_mode = BCM2835_FIRMWARE_TURBO_ON; else - sc->turbo_mode = BCM2835_MBOX_TURBO_OFF; + sc->turbo_mode = BCM2835_FIRMWARE_TURBO_OFF; VC_LOCK(sc); err = bcm2835_cpufreq_set_turbo(sc, sc->turbo_mode); @@ -846,7 +788,7 @@ sysctl_bcm2835_cpufreq_voltage_core(SYSCTL_HANDLER_ARGS) /* get realtime value */ VC_LOCK(sc); - val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_CORE); + val = bcm2835_cpufreq_get_voltage(sc, BCM2835_FIRMWARE_VOLTAGE_ID_CORE); VC_UNLOCK(sc); if (val == MSG_ERROR) return (EIO); @@ -861,7 +803,7 @@ sysctl_bcm2835_cpufreq_voltage_core(SYSCTL_HANDLER_ARGS) sc->voltage_core = val; VC_LOCK(sc); - err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_CORE, + err = bcm2835_cpufreq_set_voltage(sc, BCM2835_FIRMWARE_VOLTAGE_ID_CORE, sc->voltage_core); VC_UNLOCK(sc); if (err == MSG_ERROR) { @@ -882,7 +824,8 @@ sysctl_bcm2835_cpufreq_voltage_sdram_c(SYSCTL_HANDLER_ARGS) /* get realtime value */ VC_LOCK(sc); - val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); + val = bcm2835_cpufreq_get_voltage(sc, + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C); VC_UNLOCK(sc); if (val == MSG_ERROR) return (EIO); @@ -897,7 +840,8 @@ sysctl_bcm2835_cpufreq_voltage_sdram_c(SYSCTL_HANDLER_ARGS) sc->voltage_sdram_c = val; VC_LOCK(sc); - err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_C, + err = bcm2835_cpufreq_set_voltage(sc, + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C, sc->voltage_sdram_c); VC_UNLOCK(sc); if (err == MSG_ERROR) { @@ -918,7 +862,8 @@ sysctl_bcm2835_cpufreq_voltage_sdram_i(SYSCTL_HANDLER_ARGS) /* get realtime value */ VC_LOCK(sc); - val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); + val = bcm2835_cpufreq_get_voltage(sc, + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I); VC_UNLOCK(sc); if (val == MSG_ERROR) return (EIO); @@ -933,8 +878,8 @@ sysctl_bcm2835_cpufreq_voltage_sdram_i(SYSCTL_HANDLER_ARGS) sc->voltage_sdram_i = val; VC_LOCK(sc); - err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_I, - sc->voltage_sdram_i); + err = bcm2835_cpufreq_set_voltage(sc, + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I, sc->voltage_sdram_i); VC_UNLOCK(sc); if (err == MSG_ERROR) { device_printf(sc->dev, "set voltage sdram_i error\n"); @@ -954,7 +899,8 @@ sysctl_bcm2835_cpufreq_voltage_sdram_p(SYSCTL_HANDLER_ARGS) /* get realtime value */ VC_LOCK(sc); - val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); + val = bcm2835_cpufreq_get_voltage(sc, + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P); VC_UNLOCK(sc); if (val == MSG_ERROR) return (EIO); @@ -969,8 +915,8 @@ sysctl_bcm2835_cpufreq_voltage_sdram_p(SYSCTL_HANDLER_ARGS) sc->voltage_sdram_p = val; VC_LOCK(sc); - err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_P, - sc->voltage_sdram_p); + err = bcm2835_cpufreq_set_voltage(sc, + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P, sc->voltage_sdram_p); VC_UNLOCK(sc); if (err == MSG_ERROR) { device_printf(sc->dev, "set voltage sdram_p error\n"); @@ -1002,22 +948,22 @@ sysctl_bcm2835_cpufreq_voltage_sdram(SYSCTL_HANDLER_ARGS) sc->voltage_sdram = val; VC_LOCK(sc); - err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_C, - val); + err = bcm2835_cpufreq_set_voltage(sc, + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C, val); if (err == MSG_ERROR) { VC_UNLOCK(sc); device_printf(sc->dev, "set voltage sdram_c error\n"); return (EIO); } - err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_I, - val); + err = bcm2835_cpufreq_set_voltage(sc, + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I, val); if (err == MSG_ERROR) { VC_UNLOCK(sc); device_printf(sc->dev, "set voltage sdram_i error\n"); return (EIO); } - err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_P, - val); + err = bcm2835_cpufreq_set_voltage(sc, + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P, val); if (err == MSG_ERROR) { VC_UNLOCK(sc); device_printf(sc->dev, "set voltage sdram_p error\n"); @@ -1097,42 +1043,42 @@ bcm2835_cpufreq_init(void *arg) /* current clock */ arm_freq = bcm2835_cpufreq_get_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_ARM); + BCM2835_FIRMWARE_CLOCK_ID_ARM); core_freq = bcm2835_cpufreq_get_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_CORE); + BCM2835_FIRMWARE_CLOCK_ID_CORE); sdram_freq = bcm2835_cpufreq_get_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_SDRAM); + BCM2835_FIRMWARE_CLOCK_ID_SDRAM); /* max/min clock */ arm_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_ARM); + BCM2835_FIRMWARE_CLOCK_ID_ARM); arm_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_ARM); + BCM2835_FIRMWARE_CLOCK_ID_ARM); core_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_CORE); + BCM2835_FIRMWARE_CLOCK_ID_CORE); core_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_CORE); + BCM2835_FIRMWARE_CLOCK_ID_CORE); sdram_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_SDRAM); + BCM2835_FIRMWARE_CLOCK_ID_SDRAM); sdram_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_SDRAM); + BCM2835_FIRMWARE_CLOCK_ID_SDRAM); /* turbo mode */ turbo = bcm2835_cpufreq_get_turbo(sc); if (turbo > 0) - sc->turbo_mode = BCM2835_MBOX_TURBO_ON; + sc->turbo_mode = BCM2835_FIRMWARE_TURBO_ON; else - sc->turbo_mode = BCM2835_MBOX_TURBO_OFF; + sc->turbo_mode = BCM2835_FIRMWARE_TURBO_OFF; /* voltage */ voltage_core = bcm2835_cpufreq_get_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_CORE); + BCM2835_FIRMWARE_VOLTAGE_ID_CORE); voltage_sdram_c = bcm2835_cpufreq_get_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C); voltage_sdram_i = bcm2835_cpufreq_get_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I); voltage_sdram_p = bcm2835_cpufreq_get_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P); /* current values (offset from 1.2V) */ sc->voltage_core = voltage_core; @@ -1143,21 +1089,21 @@ bcm2835_cpufreq_init(void *arg) /* max/min voltage */ max_voltage_core = bcm2835_cpufreq_get_max_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_CORE); + BCM2835_FIRMWARE_VOLTAGE_ID_CORE); min_voltage_core = bcm2835_cpufreq_get_min_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_CORE); + BCM2835_FIRMWARE_VOLTAGE_ID_CORE); max_voltage_sdram_c = bcm2835_cpufreq_get_max_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C); max_voltage_sdram_i = bcm2835_cpufreq_get_max_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I); max_voltage_sdram_p = bcm2835_cpufreq_get_max_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P); min_voltage_sdram_c = bcm2835_cpufreq_get_min_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C); min_voltage_sdram_i = bcm2835_cpufreq_get_min_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I); min_voltage_sdram_p = bcm2835_cpufreq_get_min_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); + BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P); /* temperature */ temperature = bcm2835_cpufreq_get_temperature(sc); @@ -1168,7 +1114,7 @@ bcm2835_cpufreq_init(void *arg) device_printf(sc->dev, "current ARM %dMHz, Core %dMHz, SDRAM %dMHz, Turbo %s\n", HZ2MHZ(arm_freq), HZ2MHZ(core_freq), HZ2MHZ(sdram_freq), - (sc->turbo_mode == BCM2835_MBOX_TURBO_ON) ? "ON" : "OFF"); + (sc->turbo_mode == BCM2835_FIRMWARE_TURBO_ON) ? "ON":"OFF"); device_printf(sc->dev, "max/min ARM %d/%dMHz, Core %d/%dMHz, SDRAM %d/%dMHz\n", @@ -1202,7 +1148,7 @@ bcm2835_cpufreq_init(void *arg) device_printf(sc->dev, "ARM %dMHz, Core %dMHz, SDRAM %dMHz, Turbo %s\n", HZ2MHZ(arm_freq), HZ2MHZ(core_freq), HZ2MHZ(sdram_freq), - (sc->turbo_mode == BCM2835_MBOX_TURBO_ON) ? "ON" : "OFF"); + (sc->turbo_mode == BCM2835_FIRMWARE_TURBO_ON) ? "ON":"OFF"); } /* keep in softc (MHz/mV) */ @@ -1216,25 +1162,25 @@ bcm2835_cpufreq_init(void *arg) sc->min_voltage_core = OFFSET2MVOLT(min_voltage_core); /* if turbo is on, set to max values */ - if (sc->turbo_mode == BCM2835_MBOX_TURBO_ON) { - bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM, - arm_max_freq); - DELAY(TRANSITION_LATENCY); - bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE, - core_max_freq); + if (sc->turbo_mode == BCM2835_FIRMWARE_TURBO_ON) { + bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_FIRMWARE_CLOCK_ID_ARM, arm_max_freq); DELAY(TRANSITION_LATENCY); bcm2835_cpufreq_set_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_SDRAM, sdram_max_freq); + BCM2835_FIRMWARE_CLOCK_ID_CORE, core_max_freq); + DELAY(TRANSITION_LATENCY); + bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_FIRMWARE_CLOCK_ID_SDRAM, sdram_max_freq); DELAY(TRANSITION_LATENCY); } else { - bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM, - arm_min_freq); - DELAY(TRANSITION_LATENCY); - bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE, - core_min_freq); + bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_FIRMWARE_CLOCK_ID_ARM, arm_min_freq); DELAY(TRANSITION_LATENCY); bcm2835_cpufreq_set_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_SDRAM, sdram_min_freq); + BCM2835_FIRMWARE_CLOCK_ID_CORE, core_min_freq); + DELAY(TRANSITION_LATENCY); + bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_FIRMWARE_CLOCK_ID_SDRAM, sdram_min_freq); DELAY(TRANSITION_LATENCY); } @@ -1297,6 +1243,12 @@ bcm2835_cpufreq_attach(device_t dev) /* set self dev */ sc = device_get_softc(dev); sc->dev = dev; + sc->firmware = devclass_get_device( + devclass_find("bcm2835_firmware"), 0); + if (sc->firmware == NULL) { + device_printf(dev, "Unable to find firmware device\n"); + return (ENXIO); + } /* initial values */ sc->arm_max_freq = -1; @@ -1430,7 +1382,7 @@ bcm2835_cpufreq_set(device_t dev, const struct cf_setting *cf) /* adjust min freq */ min_freq = sc->arm_min_freq; - if (sc->turbo_mode != BCM2835_MBOX_TURBO_ON) + if (sc->turbo_mode != BCM2835_FIRMWARE_TURBO_ON) if (min_freq > cpufreq_lowest_freq) min_freq = cpufreq_lowest_freq; @@ -1441,28 +1393,28 @@ bcm2835_cpufreq_set(device_t dev, const struct cf_setting *cf) VC_LOCK(sc); #ifdef DEBUG cur_freq = bcm2835_cpufreq_get_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_ARM); + BCM2835_FIRMWARE_CLOCK_ID_ARM); #endif resp_freq = bcm2835_cpufreq_set_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_ARM, rate_hz); + BCM2835_FIRMWARE_CLOCK_ID_ARM, rate_hz); DELAY(TRANSITION_LATENCY); arm_freq = bcm2835_cpufreq_get_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_ARM); + BCM2835_FIRMWARE_CLOCK_ID_ARM); /* * if non-turbo and lower than or equal min_freq, * clock down core and sdram to default first. */ - if (sc->turbo_mode != BCM2835_MBOX_TURBO_ON) { + if (sc->turbo_mode != BCM2835_FIRMWARE_TURBO_ON) { core_freq = bcm2835_cpufreq_get_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_CORE); + BCM2835_FIRMWARE_CLOCK_ID_CORE); if (rate_hz > MHZ2HZ(sc->arm_min_freq)) { bcm2835_cpufreq_set_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_CORE, + BCM2835_FIRMWARE_CLOCK_ID_CORE, MHZ2HZ(sc->core_max_freq)); DELAY(TRANSITION_LATENCY); bcm2835_cpufreq_set_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_SDRAM, + BCM2835_FIRMWARE_CLOCK_ID_SDRAM, MHZ2HZ(sc->sdram_max_freq)); DELAY(TRANSITION_LATENCY); } else { @@ -1471,20 +1423,20 @@ bcm2835_cpufreq_set(device_t dev, const struct cf_setting *cf) /* first, down to 250, then down to min */ DELAY(TRANSITION_LATENCY); bcm2835_cpufreq_set_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_CORE, + BCM2835_FIRMWARE_CLOCK_ID_CORE, MHZ2HZ(DEFAULT_CORE_FREQUENCY)); DELAY(TRANSITION_LATENCY); /* reset core voltage */ bcm2835_cpufreq_set_voltage(sc, - BCM2835_MBOX_VOLTAGE_ID_CORE, 0); + BCM2835_FIRMWARE_VOLTAGE_ID_CORE, 0); DELAY(TRANSITION_LATENCY); } bcm2835_cpufreq_set_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_CORE, + BCM2835_FIRMWARE_CLOCK_ID_CORE, MHZ2HZ(sc->core_min_freq)); DELAY(TRANSITION_LATENCY); bcm2835_cpufreq_set_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_SDRAM, + BCM2835_FIRMWARE_CLOCK_ID_SDRAM, MHZ2HZ(sc->sdram_min_freq)); DELAY(TRANSITION_LATENCY); } @@ -1517,7 +1469,7 @@ bcm2835_cpufreq_get(device_t dev, struct cf_setting *cf) /* get cuurent value */ VC_LOCK(sc); arm_freq = bcm2835_cpufreq_get_clock_rate(sc, - BCM2835_MBOX_CLOCK_ID_ARM); + BCM2835_FIRMWARE_CLOCK_ID_ARM); VC_UNLOCK(sc); if (arm_freq < 0) { device_printf(dev, "can't get clock\n"); @@ -1557,7 +1509,7 @@ bcm2835_cpufreq_make_freq_list(device_t dev, struct cf_setting *sets, freq = min_freq; /* if non-turbo, add extra low freq */ - if (sc->turbo_mode != BCM2835_MBOX_TURBO_ON) + if (sc->turbo_mode != BCM2835_FIRMWARE_TURBO_ON) if (min_freq > cpufreq_lowest_freq) min_freq = cpufreq_lowest_freq; @@ -1654,3 +1606,4 @@ static driver_t bcm2835_cpufreq_driver = { DRIVER_MODULE(bcm2835_cpufreq, cpu, bcm2835_cpufreq_driver, bcm2835_cpufreq_devclass, 0, 0); +MODULE_DEPEND(bcm2835_cpufreq, bcm2835_firmware, 1, 1, 1); diff --git a/sys/arm/broadcom/bcm2835/bcm2835_firmware.h b/sys/arm/broadcom/bcm2835/bcm2835_firmware.h index da6a137083ed..c88b03e62d38 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_firmware.h +++ b/sys/arm/broadcom/bcm2835/bcm2835_firmware.h @@ -33,6 +33,115 @@ #ifndef _BCM2835_FIRMWARE_H_ #define _BCM2835_FIRMWARE_H_ +#define BCM2835_FIRMWARE_TAG_GET_CLOCK_RATE 0x00030002 +#define BCM2835_FIRMWARE_TAG_SET_CLOCK_RATE 0x00038002 +#define BCM2835_FIRMWARE_TAG_GET_MAX_CLOCK_RATE 0x00030004 +#define BCM2835_FIRMWARE_TAG_GET_MIN_CLOCK_RATE 0x00030007 + +#define BCM2835_FIRMWARE_CLOCK_ID_EMMC 0x00000001 +#define BCM2835_FIRMWARE_CLOCK_ID_UART 0x00000002 +#define BCM2835_FIRMWARE_CLOCK_ID_ARM 0x00000003 +#define BCM2835_FIRMWARE_CLOCK_ID_CORE 0x00000004 +#define BCM2835_FIRMWARE_CLOCK_ID_V3D 0x00000005 +#define BCM2835_FIRMWARE_CLOCK_ID_H264 0x00000006 +#define BCM2835_FIRMWARE_CLOCK_ID_ISP 0x00000007 +#define BCM2835_FIRMWARE_CLOCK_ID_SDRAM 0x00000008 +#define BCM2835_FIRMWARE_CLOCK_ID_PIXEL 0x00000009 +#define BCM2835_FIRMWARE_CLOCK_ID_PWM 0x0000000a +#define BCM2838_FIRMWARE_CLOCK_ID_EMMC2 0x0000000c + +union msg_get_clock_rate_body { + struct { + uint32_t clock_id; + } req; + struct { + uint32_t clock_id; + uint32_t rate_hz; + } resp; +}; + +union msg_set_clock_rate_body { + struct { + uint32_t clock_id; + uint32_t rate_hz; + } req; + struct { + uint32_t clock_id; + uint32_t rate_hz; + } resp; +}; + +#define BCM2835_FIRMWARE_TAG_GET_VOLTAGE 0x00030003 +#define BCM2835_FIRMWARE_TAG_SET_VOLTAGE 0x00038003 +#define BCM2835_FIRMWARE_TAG_GET_MAX_VOLTAGE 0x00030005 +#define BCM2835_FIRMWARE_TAG_GET_MIN_VOLTAGE 0x00030008 + +#define BCM2835_FIRMWARE_VOLTAGE_ID_CORE 0x00000001 +#define BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C 0x00000002 +#define BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P 0x00000003 +#define BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I 0x00000004 + +union msg_get_voltage_body { + struct { + uint32_t voltage_id; + } req; + struct { + uint32_t voltage_id; + uint32_t value; + } resp; +}; + +union msg_set_voltage_body { + struct { + uint32_t voltage_id; + uint32_t value; + } req; + struct { + uint32_t voltage_id; + uint32_t value; + } resp; +}; + +#define BCM2835_FIRMWARE_TAG_GET_TEMPERATURE 0x00030006 +#define BCM2835_FIRMWARE_TAG_GET_MAX_TEMPERATURE 0x0003000a + +union msg_get_temperature_body { + struct { + uint32_t temperature_id; + } req; + struct { + uint32_t temperature_id; + uint32_t value; + } resp; +}; + +#define BCM2835_FIRMWARE_TAG_GET_TURBO 0x00030009 +#define BCM2835_FIRMWARE_TAG_SET_TURBO 0x00038009 + +#define BCM2835_FIRMWARE_TURBO_ON 1 +#define BCM2835_FIRMWARE_TURBO_OFF 0 + +union msg_get_turbo_body { + struct { + uint32_t id; + } req; + struct { + uint32_t id; + uint32_t level; + } resp; +}; + +union msg_set_turbo_body { + struct { + uint32_t id; + uint32_t level; + } req; + struct { + uint32_t id; + uint32_t level; + } resp; +}; + int bcm2835_firmware_property(device_t, uint32_t, void *, size_t); #endif diff --git a/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h b/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h index 211820c09c31..15f48aefa536 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h +++ b/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h @@ -113,21 +113,9 @@ struct msg_set_power_state { int bcm2835_mbox_set_power_state(uint32_t, boolean_t); #define BCM2835_MBOX_CLOCK_ID_EMMC 0x00000001 -#define BCM2835_MBOX_CLOCK_ID_UART 0x00000002 -#define BCM2835_MBOX_CLOCK_ID_ARM 0x00000003 -#define BCM2835_MBOX_CLOCK_ID_CORE 0x00000004 -#define BCM2835_MBOX_CLOCK_ID_V3D 0x00000005 -#define BCM2835_MBOX_CLOCK_ID_H264 0x00000006 -#define BCM2835_MBOX_CLOCK_ID_ISP 0x00000007 -#define BCM2835_MBOX_CLOCK_ID_SDRAM 0x00000008 -#define BCM2835_MBOX_CLOCK_ID_PIXEL 0x00000009 -#define BCM2835_MBOX_CLOCK_ID_PWM 0x0000000a #define BCM2838_MBOX_CLOCK_ID_EMMC2 0x0000000c #define BCM2835_MBOX_TAG_GET_CLOCK_RATE 0x00030002 -#define BCM2835_MBOX_TAG_SET_CLOCK_RATE 0x00038002 -#define BCM2835_MBOX_TAG_GET_MAX_CLOCK_RATE 0x00030004 -#define BCM2835_MBOX_TAG_GET_MIN_CLOCK_RATE 0x00030007 struct msg_get_clock_rate { struct bcm2835_mbox_hdr hdr; @@ -144,52 +132,6 @@ struct msg_get_clock_rate { uint32_t end_tag; }; -struct msg_set_clock_rate { - struct bcm2835_mbox_hdr hdr; - struct bcm2835_mbox_tag_hdr tag_hdr; - union { - struct { - uint32_t clock_id; - uint32_t rate_hz; - } req; - struct { - uint32_t clock_id; - uint32_t rate_hz; - } resp; - } body; - uint32_t end_tag; -}; - -struct msg_get_max_clock_rate { - struct bcm2835_mbox_hdr hdr; - struct bcm2835_mbox_tag_hdr tag_hdr; - union { - struct { - uint32_t clock_id; - } req; - struct { - uint32_t clock_id; - uint32_t rate_hz; - } resp; - } body; - uint32_t end_tag; -}; - -struct msg_get_min_clock_rate { - struct bcm2835_mbox_hdr hdr; - struct bcm2835_mbox_tag_hdr tag_hdr; - union { - struct { - uint32_t clock_id; - } req; - struct { - uint32_t clock_id; - uint32_t rate_hz; - } resp; - } body; - uint32_t end_tag; -}; - int bcm2835_mbox_get_clock_rate(uint32_t, uint32_t *); #define BCM2835_MBOX_TURBO_ON 1 From 8f11c997150d17d72a801874bd486aad1ef7c239 Mon Sep 17 00:00:00 2001 From: Yoshihiro Takahashi Date: Tue, 28 Jul 2020 10:58:37 +0000 Subject: [PATCH 229/287] - Cleanups related to sparc64 removal. - Remove remains of sparc64 files. Reviewed by: imp Differential Revision: https://reviews.freebsd.org/D25831 --- cddl/lib/Makefile | 9 +- cddl/lib/libdtrace/Makefile | 3 - cddl/lib/libzpool/Makefile | 2 - etc/mtree/BSD.usr.dist | 4 - release/sparc64/mkisoimages.sh | 86 ------------------- release/sparc64/sparc64.conf | 10 --- rescue/rescue/Makefile | 4 - sbin/init/ttys.sparc64 | 54 ------------ sys/kern/kern_dump.c | 6 +- sys/modules/esp/Makefile | 2 +- sys/modules/uart/Makefile | 2 +- .../bsdinstall/partedit/partedit_sparc64.c | 84 ------------------ usr.sbin/kldxref/ef_sparc64.c | 71 --------------- 13 files changed, 5 insertions(+), 332 deletions(-) delete mode 100644 release/sparc64/mkisoimages.sh delete mode 100644 release/sparc64/sparc64.conf delete mode 100644 sbin/init/ttys.sparc64 delete mode 100644 usr.sbin/bsdinstall/partedit/partedit_sparc64.c delete mode 100644 usr.sbin/kldxref/ef_sparc64.c diff --git a/cddl/lib/Makefile b/cddl/lib/Makefile index 69a0e381dfec..b65983dd64a7 100644 --- a/cddl/lib/Makefile +++ b/cddl/lib/Makefile @@ -2,10 +2,10 @@ .include -SUBDIR= ${_drti} \ +SUBDIR= drti \ libavl \ libctf \ - ${_libdtrace} \ + libdtrace \ libnvpair \ libumem \ libuutil \ @@ -23,11 +23,6 @@ _libzpool= libzpool .endif .endif -.if ${MACHINE_CPUARCH} != "sparc64" -_drti= drti -_libdtrace= libdtrace -.endif - SUBDIR_DEPEND_libdtrace= libctf SUBDIR_DEPEND_libzfs_core= libnvpair SUBDIR_DEPEND_libzfs= libavl libnvpair libumem libuutil libzfs_core diff --git a/cddl/lib/libdtrace/Makefile b/cddl/lib/libdtrace/Makefile index bc58855ffc5d..11565b03b0ac 100644 --- a/cddl/lib/libdtrace/Makefile +++ b/cddl/lib/libdtrace/Makefile @@ -103,9 +103,6 @@ CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/powerpc CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/riscv .PATH: ${SRCTOP}/cddl/contrib/opensolaris/lib/libdtrace/riscv .PATH: ${SRCTOP}/sys/cddl/dev/dtrace/riscv -.elif ${MACHINE_CPUARCH} == "sparc64" -CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/sparc -.PATH: ${SRCTOP}/cddl/contrib/opensolaris/lib/libdtrace/sparc .else # temporary hack CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/intel diff --git a/cddl/lib/libzpool/Makefile b/cddl/lib/libzpool/Makefile index 1c545e0260d1..576b89b7725a 100644 --- a/cddl/lib/libzpool/Makefile +++ b/cddl/lib/libzpool/Makefile @@ -18,9 +18,7 @@ .if exists(${SRCTOP}/sys/cddl/contrib/opensolaris/common/atomic/${MACHINE_ARCH}/opensolaris_atomic.S) .PATH: ${SRCTOP}/sys/cddl/contrib/opensolaris/common/atomic/${MACHINE_ARCH} ATOMIC_SRCS= opensolaris_atomic.S -.if ${MACHINE_ARCH} != "sparc64" ACFLAGS+= -Wa,--noexecstack -.endif .else .PATH: ${SRCTOP}/sys/cddl/compat/opensolaris/kern ATOMIC_SRCS= opensolaris_atomic.c diff --git a/etc/mtree/BSD.usr.dist b/etc/mtree/BSD.usr.dist index 3c7350ea24e1..e3164c7d76ba 100644 --- a/etc/mtree/BSD.usr.dist +++ b/etc/mtree/BSD.usr.dist @@ -864,8 +864,6 @@ .. powerpc .. - sparc64 - .. .. man5 .. @@ -880,8 +878,6 @@ .. powerpc .. - sparc64 - .. .. man9 .. diff --git a/release/sparc64/mkisoimages.sh b/release/sparc64/mkisoimages.sh deleted file mode 100644 index 80894096f01e..000000000000 --- a/release/sparc64/mkisoimages.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/sh -# -# Module: mkisoimages.sh -# Author: Jordan K Hubbard -# Date: 22 June 2001 -# -# $FreeBSD$ -# -# This script is used by release/Makefile to build the (optional) ISO images -# for a FreeBSD release. It is considered architecture dependent since each -# platform has a slightly unique way of making bootable CDs. This script -# is also allowed to generate any number of images since that is more of -# publishing decision than anything else. -# -# Usage: -# -# mkisoimages.sh [-b] image-label image-name base-bits-dir [extra-bits-dir] -# -# Where -b is passed if the ISO image should be made "bootable" by -# whatever standards this architecture supports (may be unsupported), -# image-label is the ISO image label, image-name is the filename of the -# resulting ISO image, base-bits-dir contains the image contents and -# extra-bits-dir, if provided, contains additional files to be merged -# into base-bits-dir as part of making the image. -set -e - -if [ $# -lt 3 ]; then - echo "Usage: $0 [-b] image-label image-name base-bits-dir [extra-bits-dir]" > /dev/stderr - exit 1 -fi - -case "$1" in --b) BOPT="$1"; shift ;; -esac -LABEL=`echo "$1" | tr '[:lower:]' '[:upper:]'`; shift -NAME="$1"; shift -BASEBITSDIR="$1" - -# Create an ISO image -publisher="The FreeBSD Project. https://www.FreeBSD.org/" -echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > "$BASEBITSDIR/etc/fstab" -makefs -t cd9660 -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME.tmp" "$@" -rm -f "$BASEBITSDIR/etc/fstab" - -if [ "$BOPT" != "-b" ]; then - mv "$NAME.tmp" "$NAME" - exit 0 -fi - -TMPIMGDIR=`mktemp -d /tmp/bootfs.XXXXXXXX` || exit 1 -BOOTFSDIR="$TMPIMGDIR/bootfs" -BOOTFSIMG="$TMPIMGDIR/bootfs.img" - -# Create a boot filesystem -mkdir -p "$BOOTFSDIR/boot" -cp -p "$BASEBITSDIR/boot/loader" "$BOOTFSDIR/boot" -makefs -t ffs -B be -M 512k "$BOOTFSIMG" "$BOOTFSDIR" -dd if="$BASEBITSDIR/boot/boot1" of="$BOOTFSIMG" bs=512 conv=notrunc,sync - -# Create a boot ISO image -: ${CYLSIZE:=640} -ISOSIZE=$(stat -f %z "$NAME.tmp") -ISOBLKS=$((($ISOSIZE + 511) / 512)) -ISOCYLS=$((($ISOBLKS + ($CYLSIZE - 1)) / $CYLSIZE)) - -BOOTFSSIZE=$(stat -f %z "$BOOTFSIMG") -BOOTFSBLKS=$((($BOOTFSSIZE + 511) / 512)) -BOOTFSCYLS=$((($BOOTFSBLKS + ($CYLSIZE - 1)) / $CYLSIZE)) - -ENDCYL=$(($ISOCYLS + $BOOTFSCYLS)) -NSECTS=$(($ENDCYL * 1 * $CYLSIZE)) - -dd if="$NAME.tmp" of="$NAME" bs="${CYLSIZE}b" conv=notrunc,sync -dd if="$BOOTFSIMG" of="$NAME" bs="${CYLSIZE}b" seek=$ISOCYLS conv=notrunc,sync -# The number of alternative cylinders is always 2. -dd if=/dev/zero of="$NAME" bs="${CYLSIZE}b" seek=$ENDCYL count=2 conv=notrunc,sync -rm -rf "$NAME.tmp" "$TMPIMGDIR" - -# Write VTOC8 label to boot ISO image -MD=`mdconfig -a -t vnode -S 512 -y 1 -x "$CYLSIZE" -f "$NAME"` -gpart create -s VTOC8 $MD -# !4: usr, for ISO image part -gpart add -i 1 -s "$(($ISOCYLS * $CYLSIZE * 512))b" -t \!4 $MD -# !2: root, for bootfs part. -gpart add -i 6 -s "$(($BOOTFSCYLS * $CYLSIZE * 512))b" -t \!2 $MD -mdconfig -d -u ${MD#md} diff --git a/release/sparc64/sparc64.conf b/release/sparc64/sparc64.conf deleted file mode 100644 index c0579eaadb4b..000000000000 --- a/release/sparc64/sparc64.conf +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# -# $FreeBSD$ -# - -# Configuration file for release/release.sh to build sparc64/sparc64. - -TARGET="sparc64" -TARGET_ARCH="sparc64" -KERNEL="GENERIC" diff --git a/rescue/rescue/Makefile b/rescue/rescue/Makefile index 9249e00a7250..9681ebaddfa3 100644 --- a/rescue/rescue/Makefile +++ b/rescue/rescue/Makefile @@ -147,10 +147,6 @@ CRUNCH_ALIAS_bsdlabel= disklabel #CRUNCH_LIBS+= -lsmb .endif -.if ${MACHINE_CPUARCH} == "sparc64" -CRUNCH_PROGS_sbin+= bsdlabel sunlabel -.endif - .if ${MACHINE_CPUARCH} == "amd64" CRUNCH_PROGS_sbin+= bsdlabel fdisk CRUNCH_ALIAS_bsdlabel= disklabel diff --git a/sbin/init/ttys.sparc64 b/sbin/init/ttys.sparc64 deleted file mode 100644 index 5c7f3cff6a3f..000000000000 --- a/sbin/init/ttys.sparc64 +++ /dev/null @@ -1,54 +0,0 @@ -# -# $FreeBSD$ -# @(#)ttys 5.1 (Berkeley) 4/17/89 -# -# This file specifies various information about terminals on the system. -# It is used by several different programs. Common entries for the -# various columns include: -# -# name The name of the terminal device. -# -# getty The program to start running on the terminal. Typically a -# getty program, as the name implies. Other common entries -# include none, when no getty is needed, and xdm, to start the -# X Window System. -# -# type The initial terminal type for this port. For hardwired -# terminal lines, this will contain the type of terminal used. -# For virtual consoles, the correct type is typically xterm. -# Other common values include dialup for incoming modem ports, and -# unknown when the terminal type cannot be predetermined. -# -# status Must be on or off. If on, init will run the getty program on -# the specified port. If the word "secure" appears, this tty -# allows root login. -# -# name getty type status comments -# -# If console is marked "insecure", then init will ask for the root password -# when going to single-user mode. -console none unknown off secure -# ofw_console(4) -screen "/usr/libexec/getty Pc" vt100 off secure -ttya "/usr/libexec/getty 3wire.9600" vt100 off secure -ttyb "/usr/libexec/getty 3wire.9600" vt100 off secure -# syscons(4) -ttyv0 "/usr/libexec/getty Pc" xterm onifexists secure -# Virtual terminals -ttyv1 "/usr/libexec/getty Pc" xterm onifexists secure -ttyv2 "/usr/libexec/getty Pc" xterm onifexists secure -ttyv3 "/usr/libexec/getty Pc" xterm onifexists secure -ttyv4 "/usr/libexec/getty Pc" xterm onifexists secure -ttyv5 "/usr/libexec/getty Pc" xterm onifexists secure -ttyv6 "/usr/libexec/getty Pc" xterm onifexists secure -ttyv7 "/usr/libexec/getty Pc" xterm onifexists secure -ttyv8 "/usr/local/bin/xdm -nodaemon" xterm off secure -# Serial terminals -# The 'dialup' keyword identifies dialin lines to login, fingerd etc. -# uart(4) -ttyu0 "/usr/libexec/getty 3wire" vt100 onifconsole secure -ttyu1 "/usr/libexec/getty 3wire" vt100 onifconsole secure -ttyu2 "/usr/libexec/getty 3wire" vt100 onifconsole secure -ttyu3 "/usr/libexec/getty 3wire" vt100 onifconsole secure -# Dumb console -dcons "/usr/libexec/getty std.9600" vt100 off secure diff --git a/sys/kern/kern_dump.c b/sys/kern/kern_dump.c index e5e6a5d1208c..79dc7766a964 100644 --- a/sys/kern/kern_dump.c +++ b/sys/kern/kern_dump.c @@ -54,7 +54,7 @@ static size_t fragsz; struct dump_pa dump_map[DUMPSYS_MD_PA_NPAIRS]; -#if !defined(__powerpc__) && !defined(__sparc__) +#if !defined(__powerpc__) void dumpsys_gen_pa_init(void) { @@ -97,14 +97,12 @@ dumpsys_gen_unmap_chunk(vm_paddr_t pa __unused, size_t chunk __unused, } -#if !defined(__sparc__) int dumpsys_gen_write_aux_headers(struct dumperinfo *di) { return (0); } -#endif int dumpsys_buf_seek(struct dumperinfo *di, size_t sz) @@ -240,7 +238,6 @@ dumpsys_foreach_chunk(dumpsys_callback_t cb, void *arg) return (seqnr); } -#if !defined(__sparc__) static off_t fileofs; static int @@ -387,4 +384,3 @@ dumpsys_generic(struct dumperinfo *di) printf("\n** DUMP FAILED (ERROR %d) **\n", error); return (error); } -#endif diff --git a/sys/modules/esp/Makefile b/sys/modules/esp/Makefile index 1880d385dfb8..8540b4434ae3 100644 --- a/sys/modules/esp/Makefile +++ b/sys/modules/esp/Makefile @@ -3,7 +3,7 @@ .PATH: ${SRCTOP}/sys/dev/esp KMOD= esp -SRCS= device_if.h esp_pci.c ${esp_sbus} bus_if.h ncr53c9x.c ${ofw_bus_if} +SRCS= device_if.h esp_pci.c bus_if.h ncr53c9x.c SRCS+= opt_cam.h pci_if.h .include diff --git a/sys/modules/uart/Makefile b/sys/modules/uart/Makefile index b6bba88da9ca..5832f4c1696d 100644 --- a/sys/modules/uart/Makefile +++ b/sys/modules/uart/Makefile @@ -28,7 +28,7 @@ uart_dev_mu=uart_dev_mu.c .endif KMOD= uart -SRCS= ${uart_bus_acpi} ${uart_bus_ebus} uart_bus_isa.c uart_bus_pccard.c \ +SRCS= ${uart_bus_acpi} uart_bus_isa.c uart_bus_pccard.c \ uart_bus_pci.c uart_bus_puc.c uart_bus_scc.c \ uart_core.c ${uart_cpu_acpi} ${uart_cpu_machine} uart_dbg.c \ ${uart_dev_mvebu} uart_dev_ns8250.c ${uart_dev_mu} \ diff --git a/usr.sbin/bsdinstall/partedit/partedit_sparc64.c b/usr.sbin/bsdinstall/partedit/partedit_sparc64.c deleted file mode 100644 index 514c0e9ffd1d..000000000000 --- a/usr.sbin/bsdinstall/partedit/partedit_sparc64.c +++ /dev/null @@ -1,84 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2011 Nathan Whitehorn - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -#include "partedit.h" - -const char * -default_scheme(void) { - return ("VTOC8"); -} - -int -is_scheme_bootable(const char *part_type) { - if (strcmp(part_type, "VTOC8") == 0) - return (1); - return (0); -} - -int -is_fs_bootable(const char *part_type, const char *fs) -{ - if (strcmp(fs, "freebsd-ufs") == 0 || strcmp(fs, "freebsd-zfs") == 0) - return (1); - return (0); -} - - -size_t -bootpart_size(const char *part_type) { - /* No standalone boot partition */ - - return (0); -} - -const char * -bootpart_type(const char *scheme, const char **mountpoint) { - return ("freebsd-boot"); -} - -const char * -bootcode_path(const char *part_type) { - return (NULL); -} - -const char * -partcode_path(const char *part_type, const char *fs_type) { - if (strcmp(part_type, "VTOC8") == 0) { - if (strcmp(fs_type, "ufs") == 0) { - return ("/boot/boot1"); - } else if (strcmp(fs_type, "zfs") == 0) { - return ("/boot/zfsboot"); - } - } - return (NULL); -} - diff --git a/usr.sbin/kldxref/ef_sparc64.c b/usr.sbin/kldxref/ef_sparc64.c deleted file mode 100644 index 27abfc7b31ec..000000000000 --- a/usr.sbin/kldxref/ef_sparc64.c +++ /dev/null @@ -1,71 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2003 Jake Burkholder. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include - -#include -#include - -#include "ef.h" - -/* - * Apply relocations to the values we got from the file. `relbase' is the - * target relocation address of the section, and `dataoff' is the target - * relocation address of the data in `dest'. - */ -int -ef_reloc(struct elf_file *ef, const void *reldata, int reltype, Elf_Off relbase, - Elf_Off dataoff, size_t len, void *dest) -{ - const Elf_Rela *a; - Elf_Size w; - - switch (reltype) { - case EF_RELOC_RELA: - a = reldata; - if (relbase + a->r_offset >= dataoff && relbase + a->r_offset < - dataoff + len) { - switch (ELF_R_TYPE(a->r_info)) { - case R_SPARC_RELATIVE: - w = a->r_addend + relbase; - memcpy((u_char *)dest + (relbase + a->r_offset - - dataoff), &w, sizeof(w)); - break; - default: - warnx("unhandled relocation type %u", - (unsigned int)ELF_R_TYPE(a->r_info)); - break; - } - } - break; - } - return (0); -} From d9501cbab542bc875acba5396342a47b097e7e8d Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Tue, 28 Jul 2020 11:13:37 +0000 Subject: [PATCH 230/287] Aadd Raspberry Pi firmware messages to manage GPIOs Some GPIOs are managed by an external IO expaandder through the firmware. Add the message details for these. Sponsored by: Innovate UK --- sys/arm/broadcom/bcm2835/bcm2835_firmware.h | 55 +++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/sys/arm/broadcom/bcm2835/bcm2835_firmware.h b/sys/arm/broadcom/bcm2835/bcm2835_firmware.h index c88b03e62d38..666e450914f8 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_firmware.h +++ b/sys/arm/broadcom/bcm2835/bcm2835_firmware.h @@ -142,6 +142,61 @@ union msg_set_turbo_body { } resp; }; +#define BCM2835_FIRMWARE_TAG_GET_GPIO_STATE 0x00030041 +#define BCM2835_FIRMWARE_TAG_SET_GPIO_STATE 0x00038041 +#define BCM2835_FIRMWARE_TAG_GET_GPIO_CONFIG 0x00030043 +#define BCM2835_FIRMWARE_TAG_SET_GPIO_CONFIG 0x00038043 + +#define BCM2835_FIRMWARE_GPIO_IN 0 +#define BCM2835_FIRMWARE_GPIO_OUT 1 + +union msg_get_gpio_state { + struct { + uint32_t gpio; + } req; + struct { + uint32_t gpio; + uint32_t state; + } resp; +}; + +union msg_set_gpio_state { + struct { + uint32_t gpio; + uint32_t state; + } req; + struct { + uint32_t gpio; + } resp; +}; + +union msg_get_gpio_config { + struct { + uint32_t gpio; + } req; + struct { + uint32_t gpio; + uint32_t dir; + uint32_t pol; + uint32_t term_en; + uint32_t term_pull_up; + } resp; +}; + +union msg_set_gpio_config { + struct { + uint32_t gpio; + uint32_t dir; + uint32_t pol; + uint32_t term_en; + uint32_t term_pull_up; + uint32_t state; + } req; + struct { + uint32_t gpio; + } resp; +}; + int bcm2835_firmware_property(device_t, uint32_t, void *, size_t); #endif From a4dea1415906e5d4d685eaf743994cd053293a71 Mon Sep 17 00:00:00 2001 From: Alfredo Dal'Ava Junior Date: Tue, 28 Jul 2020 11:23:37 +0000 Subject: [PATCH 231/287] virtio: fix mips regression introduced by r357596 PowerPC support was fixed in r357596 by changing PCI bustag to BE as part of the solution, but this caused regression on mips. This change implements byte swapping of virtio PCI config area in the driver, leaving lower layer untouched. Submittnd by: Fernando Valle Reported by: arichardson Reviewed by: alfredo, arichardson Sponsored by: Eldorado Research Institute (eldorado.org.br) Differential Revision: https://reviews.freebsd.org/D25416 --- sys/dev/virtio/pci/virtio_pci.c | 37 +++++++++++++-------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/sys/dev/virtio/pci/virtio_pci.c b/sys/dev/virtio/pci/virtio_pci.c index aba35eb38ff5..05a632f526a8 100644 --- a/sys/dev/virtio/pci/virtio_pci.c +++ b/sys/dev/virtio/pci/virtio_pci.c @@ -179,22 +179,24 @@ static void vtpci_config_intr(void *); * I/O port read/write wrappers. */ #define vtpci_read_config_1(sc, o) bus_read_1((sc)->vtpci_res, (o)) -#define vtpci_read_config_2(sc, o) bus_read_2((sc)->vtpci_res, (o)) -#define vtpci_read_config_4(sc, o) bus_read_4((sc)->vtpci_res, (o)) #define vtpci_write_config_1(sc, o, v) bus_write_1((sc)->vtpci_res, (o), (v)) -#define vtpci_write_config_2(sc, o, v) bus_write_2((sc)->vtpci_res, (o), (v)) -#define vtpci_write_config_4(sc, o, v) bus_write_4((sc)->vtpci_res, (o), (v)) /* - * Legacy VirtIO header is always PCI endianness (little), so if we - * are in a BE machine we need to swap bytes from LE to BE when reading - * and from BE to LE when writing. - * If we are in a LE machine, there will be no swaps. + * Virtio-pci specifies that PCI Configuration area is guest endian. However, + * since PCI devices are inherently little-endian, on BE systems the bus layer + * transparently converts it to BE. For virtio-legacy, this conversion is + * undesired, so an extra byte swap is required to fix it. */ -#define vtpci_read_header_2(sc, o) le16toh(vtpci_read_config_2(sc, o)) -#define vtpci_read_header_4(sc, o) le32toh(vtpci_read_config_4(sc, o)) -#define vtpci_write_header_2(sc, o, v) vtpci_write_config_2(sc, o, (htole16(v))) -#define vtpci_write_header_4(sc, o, v) vtpci_write_config_4(sc, o, (htole32(v))) +#define vtpci_read_config_2(sc, o) le16toh(bus_read_2((sc)->vtpci_res, (o))) +#define vtpci_read_config_4(sc, o) le32toh(bus_read_4((sc)->vtpci_res, (o))) +#define vtpci_write_config_2(sc, o, v) bus_write_2((sc)->vtpci_res, (o), (htole16(v))) +#define vtpci_write_config_4(sc, o, v) bus_write_4((sc)->vtpci_res, (o), (htole32(v))) + +/* PCI Header LE. On BE systems the bus layer takes care of byte swapping */ +#define vtpci_read_header_2(sc, o) (bus_read_2((sc)->vtpci_res, (o))) +#define vtpci_read_header_4(sc, o) (bus_read_4((sc)->vtpci_res, (o))) +#define vtpci_write_header_2(sc, o, v) bus_write_2((sc)->vtpci_res, (o), (v)) +#define vtpci_write_header_4(sc, o, v) bus_write_4((sc)->vtpci_res, (o), (v)) /* Tunables. */ static int vtpci_disable_msix = 0; @@ -290,17 +292,6 @@ vtpci_attach(device_t dev) return (ENXIO); } -/* - * For legacy VirtIO, the device-specific configuration is guest - * endian, while the common configuration header is always - * PCI (little) endian and will be handled specifically in - * other parts of this file via functions - * 'vtpci_[read|write]_header_[2|4]' - */ -#if _BYTE_ORDER == _BIG_ENDIAN - rman_set_bustag(sc->vtpci_res, &bs_be_tag); -#endif - if (pci_find_cap(dev, PCIY_MSI, NULL) != 0) sc->vtpci_flags |= VTPCI_FLAG_NO_MSI; From ce69217c7b8f81e5bcdf1337ceb729100acf8747 Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Tue, 28 Jul 2020 11:32:45 +0000 Subject: [PATCH 232/287] Add a workaround for a bug when setting the Raspberry GIO config and state The Raspberry Pi GPIO config and state messages incorrectly return with the tag length set to 0. We then check this value to have the response flag set. Work around this by setting the response flag when setting the GPIO config or state and this value is zero. Sponsored by: Innovate UK --- sys/arm/broadcom/bcm2835/bcm2835_mbox.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sys/arm/broadcom/bcm2835/bcm2835_mbox.c b/sys/arm/broadcom/bcm2835/bcm2835_mbox.c index b3d012a417fe..d722c7aae7a7 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_mbox.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_mbox.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -362,6 +363,16 @@ bcm2835_mbox_err(device_t dev, bus_addr_t msg_phys, uint32_t resp_phys, tag = (struct bcm2835_mbox_tag_hdr *)(msg + 1); last = (uint8_t *)msg + len; for (idx = 0; tag->tag != 0; idx++) { + /* + * When setting the GPIO config or state the firmware doesn't + * set tag->val_len correctly. + */ + if ((tag->tag == BCM2835_FIRMWARE_TAG_SET_GPIO_CONFIG || + tag->tag == BCM2835_FIRMWARE_TAG_SET_GPIO_STATE) && + tag->val_len == 0) { + tag->val_len = BCM2835_MBOX_TAG_VAL_LEN_RESPONSE | + tag->val_buf_size; + } if ((tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE) == 0) { device_printf(dev, "tag %d response error\n", idx); return (EIO); From c7f893a42b9572f1152d163290202b855953a768 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Tue, 28 Jul 2020 15:26:19 +0000 Subject: [PATCH 233/287] ps(1): Fix formatting of the "command" field for kernel threads. When -H is specified, for kernel threads the command is formatted as "/" and truncated to MAXCOMLEN. But each of the proc name and td name may be up to MAXCOMLEN bytes in length. Also handle the ki_moretdname field to ensure that the full thread name gets printed. This is already handled correctly when formatting for "-o tdname". Reported by: freqlabs Reviewed by: freqlabs MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25840 --- bin/ps/ps.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bin/ps/ps.c b/bin/ps/ps.c index f6d32e5411fe..d3cfc669d581 100644 --- a/bin/ps/ps.c +++ b/bin/ps/ps.c @@ -1264,6 +1264,7 @@ fmt(char **(*fn)(kvm_t *, const struct kinfo_proc *, int), KINFO *ki, static void saveuser(KINFO *ki) { + char tdname[COMMLEN + 1]; char *argsp; if (ki->ki_p->ki_flag & P_INMEM) { @@ -1280,12 +1281,14 @@ saveuser(KINFO *ki) * save arguments if needed */ if (needcomm) { - if (ki->ki_p->ki_stat == SZOMB) + if (ki->ki_p->ki_stat == SZOMB) { ki->ki_args = strdup(""); - else if (UREADOK(ki) || (ki->ki_p->ki_args != NULL)) + } else if (UREADOK(ki) || (ki->ki_p->ki_args != NULL)) { + (void)snprintf(tdname, sizeof(tdname), "%s%s", + ki->ki_p->ki_tdname, ki->ki_p->ki_moretdname); ki->ki_args = fmt(kvm_getargv, ki, - ki->ki_p->ki_comm, ki->ki_p->ki_tdname, MAXCOMLEN); - else { + ki->ki_p->ki_comm, tdname, COMMLEN * 2 + 1); + } else { asprintf(&argsp, "(%s)", ki->ki_p->ki_comm); ki->ki_args = argsp; } From ea4c01156a9244a084a4044bc77147adfd9167ce Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Tue, 28 Jul 2020 16:08:14 +0000 Subject: [PATCH 234/287] o Move the buswide_ctxs bitmap to iommu_unit and rename related functions. o Rename bus_dma_dmar_load_ident() as well. Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25852 --- sys/dev/iommu/busdma_iommu.c | 8 ++++---- sys/dev/iommu/iommu.h | 12 +++++++++++- sys/dev/ntb/ntb_hw/ntb_hw_intel.c | 2 +- sys/dev/ntb/ntb_hw/ntb_hw_plx.c | 2 +- sys/x86/include/bus_dma.h | 4 ++-- sys/x86/iommu/intel_ctx.c | 8 +++++--- sys/x86/iommu/intel_dmar.h | 13 ++----------- sys/x86/iommu/intel_drv.c | 13 +++++-------- sys/x86/x86/busdma_machdep.c | 4 ++-- 9 files changed, 33 insertions(+), 33 deletions(-) diff --git a/sys/dev/iommu/busdma_iommu.c b/sys/dev/iommu/busdma_iommu.c index a4fe8ee9d063..0fd54e8b641a 100644 --- a/sys/dev/iommu/busdma_iommu.c +++ b/sys/dev/iommu/busdma_iommu.c @@ -299,7 +299,7 @@ acpi_iommu_get_dma_tag(device_t dev, device_t child) } bool -bus_dma_dmar_set_buswide(device_t dev) +bus_dma_iommu_set_buswide(device_t dev) { struct iommu_unit *unit; device_t parent; @@ -317,12 +317,12 @@ bus_dma_dmar_set_buswide(device_t dev) if (slot != 0 || func != 0) { if (bootverbose) { device_printf(dev, - "dmar%d pci%d:%d:%d requested buswide busdma\n", + "iommu%d pci%d:%d:%d requested buswide busdma\n", unit->unit, busno, slot, func); } return (false); } - dmar_set_buswide_ctx(unit, busno); + iommu_set_buswide_ctx(unit, busno); return (true); } @@ -987,7 +987,7 @@ iommu_fini_busdma(struct iommu_unit *unit) } int -bus_dma_dmar_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map1, +bus_dma_iommu_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map1, vm_paddr_t start, vm_size_t length, int flags) { struct bus_dma_tag_common *tc; diff --git a/sys/dev/iommu/iommu.h b/sys/dev/iommu/iommu.h index c3bc3d26b765..380f4cdfe5f6 100644 --- a/sys/dev/iommu/iommu.h +++ b/sys/dev/iommu/iommu.h @@ -34,11 +34,13 @@ #ifndef _SYS_IOMMU_H_ #define _SYS_IOMMU_H_ +#include #include #include #include #include -#include + +#include /* Host or physical memory address, after translation. */ typedef uint64_t iommu_haddr_t; @@ -96,6 +98,14 @@ struct iommu_unit { struct task dmamap_load_task; TAILQ_HEAD(, bus_dmamap_iommu) delayed_maps; struct taskqueue *delayed_taskqueue; + + /* + * Bitmap of buses for which context must ignore slot:func, + * duplicating the page table pointer into all context table + * entries. This is a client-controlled quirk to support some + * NTBs. + */ + uint32_t buswide_ctxs[(PCI_BUSMAX + 1) / NBBY / sizeof(uint32_t)]; }; /* diff --git a/sys/dev/ntb/ntb_hw/ntb_hw_intel.c b/sys/dev/ntb/ntb_hw/ntb_hw_intel.c index 9182461fe9a5..ba61fdc9ffcd 100644 --- a/sys/dev/ntb/ntb_hw/ntb_hw_intel.c +++ b/sys/dev/ntb/ntb_hw/ntb_hw_intel.c @@ -811,7 +811,7 @@ intel_ntb_map_pci_bars(struct ntb_softc *ntb) device_printf(ntb->device, "Unable to create BAR0 map\n"); return (ENOMEM); } - if (bus_dma_dmar_load_ident(ntb->bar0_dma_tag, ntb->bar0_dma_map, + if (bus_dma_iommu_load_ident(ntb->bar0_dma_tag, ntb->bar0_dma_map, bar->pbase, bar->size, 0)) { device_printf(ntb->device, "Unable to load BAR0 map\n"); return (ENOMEM); diff --git a/sys/dev/ntb/ntb_hw/ntb_hw_plx.c b/sys/dev/ntb/ntb_hw/ntb_hw_plx.c index 97df9ce3a4cc..a9654e7f6725 100644 --- a/sys/dev/ntb/ntb_hw/ntb_hw_plx.c +++ b/sys/dev/ntb/ntb_hw/ntb_hw_plx.c @@ -343,7 +343,7 @@ ntb_plx_attach(device_t dev) * The device occupies whole bus. In translated TLP slot field * keeps LUT index (original bus/slot), function is passed through. */ - bus_dma_dmar_set_buswide(dev); + bus_dma_iommu_set_buswide(dev); /* Identify chip port we are connected to. */ val = bus_read_4(sc->conf_res, 0x360); diff --git a/sys/x86/include/bus_dma.h b/sys/x86/include/bus_dma.h index 5bb70419726a..a87143609259 100644 --- a/sys/x86/include/bus_dma.h +++ b/sys/x86/include/bus_dma.h @@ -192,8 +192,8 @@ _bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map, } #ifdef _KERNEL -bool bus_dma_dmar_set_buswide(device_t dev); -int bus_dma_dmar_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map, +bool bus_dma_iommu_set_buswide(device_t dev); +int bus_dma_iommu_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t start, vm_size_t length, int flags); #endif diff --git a/sys/x86/iommu/intel_ctx.c b/sys/x86/iommu/intel_ctx.c index 45151c8dd355..edd59e5f2477 100644 --- a/sys/x86/iommu/intel_ctx.c +++ b/sys/x86/iommu/intel_ctx.c @@ -196,7 +196,7 @@ ctx_id_entry_init(struct dmar_ctx *ctx, dmar_ctx_entry_t *ctxp, bool move, IOMMU_PGF_NOALLOC); } - if (dmar_is_buswide_ctx(unit, busno)) { + if (iommu_is_buswide_ctx((struct iommu_unit *)unit, busno)) { MPASS(!move); for (i = 0; i <= PCI_BUSMAX; i++) { ctx_id_entry_init_one(&ctxp[i], domain, ctx_root); @@ -464,6 +464,7 @@ dmar_get_ctx_for_dev1(struct dmar_unit *dmar, device_t dev, uint16_t rid, { struct dmar_domain *domain, *domain1; struct dmar_ctx *ctx, *ctx1; + struct iommu_unit *unit; dmar_ctx_entry_t *ctxp; struct sf_buf *sf; int bus, slot, func, error; @@ -480,9 +481,10 @@ dmar_get_ctx_for_dev1(struct dmar_unit *dmar, device_t dev, uint16_t rid, } enable = false; TD_PREP_PINNED_ASSERT; + unit = (struct iommu_unit *)dmar; DMAR_LOCK(dmar); - KASSERT(!dmar_is_buswide_ctx(dmar, bus) || (slot == 0 && func == 0), - ("dmar%d pci%d:%d:%d get_ctx for buswide", dmar->iommu.unit, bus, + KASSERT(!iommu_is_buswide_ctx(unit, bus) || (slot == 0 && func == 0), + ("iommu%d pci%d:%d:%d get_ctx for buswide", dmar->iommu.unit, bus, slot, func)); ctx = dmar_find_ctx_locked(dmar, rid); error = 0; diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h index fba5e36f95cd..49a94190b496 100644 --- a/sys/x86/iommu/intel_dmar.h +++ b/sys/x86/iommu/intel_dmar.h @@ -167,15 +167,6 @@ struct dmar_unit { struct iommu_map_entries_tailq tlb_flush_entries; struct task qi_task; struct taskqueue *qi_taskqueue; - - /* - * Bitmap of buses for which context must ignore slot:func, - * duplicating the page table pointer into all context table - * entries. This is a client-controlled quirk to support some - * NTBs. - */ - uint32_t buswide_ctxs[(PCI_BUSMAX + 1) / NBBY / sizeof(uint32_t)]; - }; #define DMAR_LOCK(dmar) mtx_lock(&(dmar)->iommu.lock) @@ -290,8 +281,8 @@ void dmar_quirks_pre_use(struct iommu_unit *dmar); int dmar_init_irt(struct dmar_unit *unit); void dmar_fini_irt(struct dmar_unit *unit); -void dmar_set_buswide_ctx(struct iommu_unit *unit, u_int busno); -bool dmar_is_buswide_ctx(struct dmar_unit *unit, u_int busno); +void iommu_set_buswide_ctx(struct iommu_unit *unit, u_int busno); +bool iommu_is_buswide_ctx(struct iommu_unit *unit, u_int busno); extern iommu_haddr_t dmar_high; extern int haw; diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c index a8a2bc7cf770..4af5da538840 100644 --- a/sys/x86/iommu/intel_drv.c +++ b/sys/x86/iommu/intel_drv.c @@ -593,21 +593,18 @@ DRIVER_MODULE(dmar, acpi, dmar_driver, dmar_devclass, 0, 0); MODULE_DEPEND(dmar, acpi, 1, 1, 1); void -dmar_set_buswide_ctx(struct iommu_unit *unit, u_int busno) +iommu_set_buswide_ctx(struct iommu_unit *unit, u_int busno) { - struct dmar_unit *dmar; - - dmar = (struct dmar_unit *)unit; MPASS(busno <= PCI_BUSMAX); - DMAR_LOCK(dmar); - dmar->buswide_ctxs[busno / NBBY / sizeof(uint32_t)] |= + IOMMU_LOCK(unit); + unit->buswide_ctxs[busno / NBBY / sizeof(uint32_t)] |= 1 << (busno % (NBBY * sizeof(uint32_t))); - DMAR_UNLOCK(dmar); + IOMMU_UNLOCK(unit); } bool -dmar_is_buswide_ctx(struct dmar_unit *unit, u_int busno) +iommu_is_buswide_ctx(struct iommu_unit *unit, u_int busno) { MPASS(busno <= PCI_BUSMAX); diff --git a/sys/x86/x86/busdma_machdep.c b/sys/x86/x86/busdma_machdep.c index 3442313f55c8..3dade64692d6 100644 --- a/sys/x86/x86/busdma_machdep.c +++ b/sys/x86/x86/busdma_machdep.c @@ -301,13 +301,13 @@ bus_dma_tag_destroy(bus_dma_tag_t dmat) #ifndef ACPI_DMAR bool -bus_dma_dmar_set_buswide(device_t dev) +bus_dma_iommu_set_buswide(device_t dev) { return (false); } int -bus_dma_dmar_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map, +bus_dma_iommu_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t start, vm_size_t length, int flags) { return (0); From b027b6637a7d7bf97868bba37a43e53fcee5c222 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Tue, 28 Jul 2020 17:09:15 +0000 Subject: [PATCH 235/287] Add further clarification on si_addr and si_trapno. - In the initial description of si_addr, do not claim that it is always the faulting instruction. - For si_addr, document that it is generally set to the PC for synchronous signals, but that it can be set to the the address of the faulting memory reference for some signals including SIGSEGV and SIGBUS. In particular, while SIGSEGV generally sets si_addr to the faulting memory reference, SIGBUS can vary. On some platforms, some SIGBUS signals set si_addr to the PC and other SIGBUS signals set si_addr to the faulting address depending on the specific hardware exception. - For si_trapno, synchronous signals should set this to some value. Reviewed by: kib Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D25777 --- share/man/man3/siginfo.3 | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/share/man/man3/siginfo.3 b/share/man/man3/siginfo.3 index f0cc9aa2487b..fc4ea2ba1df7 100644 --- a/share/man/man3/siginfo.3 +++ b/share/man/man3/siginfo.3 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 8, 2020 +.Dd July 28, 2020 .Dt SIGINFO 3 .Os .Sh NAME @@ -68,7 +68,7 @@ sending process ID .It Vt uid_t Ta Va si_uid Ta sending process's real user ID .It Vt void Ta Va *si_addr Ta -address of faulting instruction +virtual address .It Vt int Ta Va si_status Ta exit value or signal .It Vt long Ta Va si_band Ta @@ -208,25 +208,24 @@ signal sent by .Xr pthread_kill 3 .El .Pp +For synchronous signals, +.Va si_addr +is generally set to the address of the faulting instruction. +However, synchronous signals raised by a faulting memory access such as +.Dv SIGSEGV +and +.Dv SIGBUS +may report the address of the faulting memory access (if available) in +.Va si_addr +instead. +.Pp +Sychronous signals set +.Va si_trapno +to a machine-dependent trap number. +.Pp In addition, the following signal-specific information is available: .Bl -column ".Dv SIGPOLL" ".Dv CLD_CONTINUED" .It Sy Signal Ta Sy Member Ta Sy Value -.It Dv SIGILL Ta Va si_addr Ta -address of faulting instruction -.It Ta Va si_trapno Ta -machine dependent of trap code -.It Dv SIGFPE Ta Va si_addr Ta -address of faulting instruction -.It Ta Va si_trapno Ta -machine dependent of trap code -.It Dv SIGSEGV Ta Va si_addr Ta -address of faulting memory reference -.It Ta Va si_trapno Ta -machine dependent of trap code -.It Dv SIGBUS Ta Va si_addr Ta -address of faulting instruction -.It Ta Va si_trapno Ta -machine dependent of trap code .It Dv SIGCHLD Ta Va si_pid Ta child process ID .It Ta Va si_status Ta From f72e5be58adce556812ecec568bd480759f15969 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Tue, 28 Jul 2020 19:50:39 +0000 Subject: [PATCH 236/287] vm_page_xbusy_claim(): Use atomics to update busy lock state. vm_page_xbusy_claim() could clobber the waiter bit. For its original use, kernel memory pages, this was not a problem since nothing would ever block on the busy lock for such pages. r363607 introduced a new use where this could in principle be a problem. Fix the problem by using atomic_cmpset to update the lock owner. Since this macro is defined only for INVARIANTS kernels the extra overhead doesn't seem prohibitive. Reported by: vangyzen Reviewed by: alc, kib, vangyzen Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25859 --- sys/vm/vm_page.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index 4a073cec8e51..c96979cf236b 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -772,8 +772,13 @@ void vm_page_assert_pga_writeable(vm_page_t m, uint16_t bits); #define VM_PAGE_ASSERT_PGA_WRITEABLE(m, bits) \ vm_page_assert_pga_writeable(m, bits) #define vm_page_xbusy_claim(m) do { \ + u_int _busy_lock; \ + \ vm_page_assert_xbusied_unchecked((m)); \ - (m)->busy_lock = VPB_CURTHREAD_EXCLUSIVE; \ + do { \ + _busy_lock = atomic_load_int(&(m)->busy_lock); \ + } while (!atomic_cmpset_int(&(m)->busy_lock, _busy_lock, \ + (_busy_lock & VPB_BIT_FLAGMASK) | VPB_CURTHREAD_EXCLUSIVE)); \ } while (0) #else #define VM_PAGE_OBJECT_BUSY_ASSERT(m) (void)0 From 3008333d442f4daf0318cb1d249240e086208d68 Mon Sep 17 00:00:00 2001 From: "Christian S.J. Peron" Date: Tue, 28 Jul 2020 20:06:16 +0000 Subject: [PATCH 237/287] Fixup some incorrect information and some comments. These changes were cherry picked up the upstream OpenBSD repository. At some point we will look at doing another import, but the diffs are substantial and will require some careful testing. Differential Revision: https://reviews.freebsd.org/D25021 MFC after: 2 weeks Submitted by: gbe Reviewed by: myself, bcr --- contrib/openbsm/CREDITS | 3 +++ contrib/openbsm/bin/auditd/auditd.c | 2 +- contrib/openbsm/bin/auditdistd/auditdistd.c | 2 +- contrib/openbsm/bin/auditdistd/proto_tls.c | 4 ++-- contrib/openbsm/libauditd/auditd_lib.c | 2 +- contrib/openbsm/libbsm/au_control.3 | 2 +- contrib/openbsm/libbsm/au_domain.3 | 2 +- contrib/openbsm/libbsm/au_errno.3 | 2 +- contrib/openbsm/libbsm/au_socket_type.3 | 2 +- contrib/openbsm/man/audit.log.5 | 6 +++--- contrib/openbsm/man/getaudit.2 | 3 ++- contrib/openbsm/sys/bsm/audit.h | 8 ++++---- 12 files changed, 21 insertions(+), 17 deletions(-) diff --git a/contrib/openbsm/CREDITS b/contrib/openbsm/CREDITS index 18b3ad7dc03f..2721de1e487d 100644 --- a/contrib/openbsm/CREDITS +++ b/contrib/openbsm/CREDITS @@ -36,6 +36,9 @@ the development of OpenBSM: Ryan Steinmetz The FreeBSD Foundation Brooks Davis + Mateusz Piotrowski + Alan Somers + Aniket Pandey In addition, Coverity, Inc.'s Prevent(tm) static analysis tool and Gimpel Software's FlexeLint tool were used to identify a number of bugs in the diff --git a/contrib/openbsm/bin/auditd/auditd.c b/contrib/openbsm/bin/auditd/auditd.c index a165cf314e08..bd00a6b16191 100644 --- a/contrib/openbsm/bin/auditd/auditd.c +++ b/contrib/openbsm/bin/auditd/auditd.c @@ -712,7 +712,7 @@ auditd_config_controls(void) */ err = auditd_set_qsize(); if (err) { - auditd_log_err("audit_set_qsize() %s: %m", + auditd_log_err("auditd_set_qsize() %s: %m", auditd_strerror(err)); ret = -1; } else diff --git a/contrib/openbsm/bin/auditdistd/auditdistd.c b/contrib/openbsm/bin/auditdistd/auditdistd.c index 696f0488b27a..8468353f4cbc 100644 --- a/contrib/openbsm/bin/auditdistd/auditdistd.c +++ b/contrib/openbsm/bin/auditdistd/auditdistd.c @@ -523,7 +523,7 @@ main_loop(void) } TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { if (adhost->adh_role == ADIST_ROLE_SENDER) { - /* Only sender workers asks for connections. */ + /* Only sender workers ask for connections. */ PJDLOG_ASSERT(adhost->adh_conn != NULL); fd = proto_descriptor(adhost->adh_conn); PJDLOG_ASSERT(fd >= 0); diff --git a/contrib/openbsm/bin/auditdistd/proto_tls.c b/contrib/openbsm/bin/auditdistd/proto_tls.c index ff251c5b0c81..31673084d5b5 100644 --- a/contrib/openbsm/bin/auditdistd/proto_tls.c +++ b/contrib/openbsm/bin/auditdistd/proto_tls.c @@ -413,7 +413,7 @@ tls_exec_client(const char *user, int startfd, const char *srcaddr, tls_certificate_verify(ssl, fingerprint); /* - * The following byte is send to make proto_connect_wait() to work. + * The following byte is sent to make proto_connect_wait() work. */ connected = 1; for (;;) { @@ -460,7 +460,7 @@ tls_call_exec_client(struct proto_conn *sock, const char *srcaddr, proto_close(sock); } else { /* - * The FD_CLOEXEC is cleared by dup2(2), so when we not + * The FD_CLOEXEC is cleared by dup2(2), so when we do not * call it, we have to clear it by hand in case it is set. */ if (fcntl(startfd, F_SETFD, 0) == -1) diff --git a/contrib/openbsm/libauditd/auditd_lib.c b/contrib/openbsm/libauditd/auditd_lib.c index 1e21adb39bb7..e6c1312bf49f 100644 --- a/contrib/openbsm/libauditd/auditd_lib.c +++ b/contrib/openbsm/libauditd/auditd_lib.c @@ -498,7 +498,7 @@ auditd_expire_trails(int (*warn_expired)(char *)) * update the mtime of the trail file to the current * time. This is so we don't prematurely remove a trail * file that was created while the system clock reset - * to the * "beginning of time" but later the system + * to the "beginning of time" but later the system * clock is set to the correct current time. */ if (current_time >= JAN_01_2000 && diff --git a/contrib/openbsm/libbsm/au_control.3 b/contrib/openbsm/libbsm/au_control.3 index fbf37b50b21c..c5a28f557222 100644 --- a/contrib/openbsm/libbsm/au_control.3 +++ b/contrib/openbsm/libbsm/au_control.3 @@ -201,7 +201,7 @@ converts an audit policy flags string, .Fa polstr , to a numeric audit policy mask returned via .Fa policy . -.Sh RETURN VALULES +.Sh RETURN VALUES The .Fn getacfilesz , .Fn getacdir , diff --git a/contrib/openbsm/libbsm/au_domain.3 b/contrib/openbsm/libbsm/au_domain.3 index 2f16b3848151..9d3415fb3c30 100644 --- a/contrib/openbsm/libbsm/au_domain.3 +++ b/contrib/openbsm/libbsm/au_domain.3 @@ -62,7 +62,7 @@ The function accepts a local domain, and returns the BSM domain for it. This call cannot fail, and instead returns a BSM domain indicating to a later decoder that the domain could not be encoded. -.Sh RETURN VALULES +.Sh RETURN VALUES On success, .Fn au_bsm_to_domain returns 0 and a converted domain; on failure, it returns -1 but does not set diff --git a/contrib/openbsm/libbsm/au_errno.3 b/contrib/openbsm/libbsm/au_errno.3 index 93873cec7323..9a3d51db0123 100644 --- a/contrib/openbsm/libbsm/au_errno.3 +++ b/contrib/openbsm/libbsm/au_errno.3 @@ -76,7 +76,7 @@ function converts a BSM error value to a string, generally by converting first t local error number and using the local .Xr strerror 3 function, but will also work for errors that are not locally defined. -.Sh RETURN VALULES +.Sh RETURN VALUES On success, .Fn au_bsm_to_errno returns 0 and a converted error value; on failure, it returns -1 but does not diff --git a/contrib/openbsm/libbsm/au_socket_type.3 b/contrib/openbsm/libbsm/au_socket_type.3 index 5668569f7b4d..54534b3fe80f 100644 --- a/contrib/openbsm/libbsm/au_socket_type.3 +++ b/contrib/openbsm/libbsm/au_socket_type.3 @@ -61,7 +61,7 @@ operating system. function accepts a local socket type, and returns the BSM socket type for it. This call cannot fail, and instead returns a BSM socket type indicating to a later decoder that the socket type could not be encoded. -.Sh RETURN VALULES +.Sh RETURN VALUES On success, .Fn au_bsm_to_socket_type returns 0 and a converted socket type; on failure, it returns -1 but does not diff --git a/contrib/openbsm/man/audit.log.5 b/contrib/openbsm/man/audit.log.5 index d85fdccb2bf0..a1db9981acd6 100644 --- a/contrib/openbsm/man/audit.log.5 +++ b/contrib/openbsm/man/audit.log.5 @@ -102,7 +102,7 @@ token can be created using .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Record Byte Count 4 bytes Number of bytes in record" -.It "Version Number 2 bytes Record version number" +.It "Version Number 1 byte Record version number" .It "Event Type 2 bytes Event type" .It "Event Modifier 2 bytes Event sub-type" .It "Seconds 4/8 bytes Record time stamp (32/64-bits)" @@ -126,7 +126,7 @@ token can be created using .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Record Byte Count 4 bytes Number of bytes in record" -.It "Version Number 2 bytes Record version number" +.It "Version Number 1 byte Record version number" .It "Event Type 2 bytes Event type" .It "Event Modifier 2 bytes Event sub-type" .It "Address Type/Length 1 byte Host address type and length" @@ -325,7 +325,7 @@ or .It "Process ID 4 bytes Process ID" .It "Session ID 4 bytes Audit session ID" .It "Terminal Port ID 4/8 bytes Terminal port ID (32/64-bits)" -.It "Terminal Address Type/Length 1 byte Length of machine address" +.It "Terminal Address Type/Length 4 bytes Length of machine address" .It "Terminal Machine Address 4 bytes IPv4 or IPv6 address of machine" .El .Ss Return Token diff --git a/contrib/openbsm/man/getaudit.2 b/contrib/openbsm/man/getaudit.2 index ae5843d45a25..8165c8819007 100644 --- a/contrib/openbsm/man/getaudit.2 +++ b/contrib/openbsm/man/getaudit.2 @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd October 19, 2008 +.Dd March 14, 2018 .Dt GETAUDIT 2 .Os .Sh NAME @@ -62,6 +62,7 @@ struct auditinfo { au_mask_t ai_mask; /* Audit masks */ au_tid_t ai_termid; /* Terminal ID */ au_asid_t ai_asid; /* Audit session ID */ + au_asflgs_t ai_flags; /* Audit session flags. */ }; typedef struct auditinfo auditinfo_t; .Ed diff --git a/contrib/openbsm/sys/bsm/audit.h b/contrib/openbsm/sys/bsm/audit.h index 73077b33bd53..26ac4cbf7584 100644 --- a/contrib/openbsm/sys/bsm/audit.h +++ b/contrib/openbsm/sys/bsm/audit.h @@ -46,7 +46,7 @@ #define MIN_AUDIT_FILE_SIZE (512 * 1024) /* - * Minimum noumber of free blocks on the filesystem containing the audit + * Minimum number of free blocks on the filesystem containing the audit * log necessary to avoid a hard log rotation. DO NOT SET THIS VALUE TO 0 * as the kernel does an unsigned compare, plus we want to leave a few blocks * free so userspace can terminate the log, etc. @@ -249,14 +249,14 @@ typedef struct au_token token_t; /* * Kernel audit queue control parameters: * Default: Maximum: - * aq_hiwater: AQ_HIWATER (100) AQ_MAXHIGH (10000) + * aq_hiwater: AQ_HIWATER (100) AQ_MAXHIGH (10000) * aq_lowater: AQ_LOWATER (10) Date: Tue, 28 Jul 2020 22:32:50 +0000 Subject: [PATCH 238/287] When modifying LUN pass "special" options too. Before switching to nvlists CTL merged previous and new options, so any options not passed just kept previous value. Now CTL completely replaces them, so we must pass everything still relevant. MFC after: 1 week Sponsored by: iXsystems, Inc. --- usr.sbin/ctld/kernel.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c index 4da7c05f1e66..ed8d46d27a0e 100644 --- a/usr.sbin/ctld/kernel.c +++ b/usr.sbin/ctld/kernel.c @@ -777,6 +777,30 @@ kernel_lun_modify(struct lun *lun) req.reqdata.modify.lun_id = lun->l_ctl_lun; req.reqdata.modify.lun_size_bytes = lun->l_size; + if (lun->l_path != NULL) { + o = option_find(&lun->l_options, "file"); + if (o != NULL) { + option_set(o, lun->l_path); + } else { + o = option_new(&lun->l_options, "file", lun->l_path); + assert(o != NULL); + } + } + + o = option_find(&lun->l_options, "ctld_name"); + if (o != NULL) { + option_set(o, lun->l_name); + } else { + o = option_new(&lun->l_options, "ctld_name", lun->l_name); + assert(o != NULL); + } + + o = option_find(&lun->l_options, "scsiname"); + if (o == NULL && lun->l_scsiname != NULL) { + o = option_new(&lun->l_options, "scsiname", lun->l_scsiname); + assert(o != NULL); + } + if (!TAILQ_EMPTY(&lun->l_options)) { req.args_nvl = nvlist_create(0); if (req.args_nvl == NULL) { From e426c74375ef7cb3afda3c8e3010a7ea2dbd69d0 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Wed, 29 Jul 2020 00:34:24 +0000 Subject: [PATCH 239/287] sshd: allow UseBlocklist alias for UseBlacklist blacklistd has been renamed to blocklistd upstream, and a future import into FreeBSD will follow that change. Support the new name as an alias in config files. Reviewed by: bz, delphij MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25865 --- crypto/openssh/servconf.c | 1 + crypto/openssh/sshd_config.5 | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/crypto/openssh/servconf.c b/crypto/openssh/servconf.c index 5032fa6556d0..8b07e4b923ae 100644 --- a/crypto/openssh/servconf.c +++ b/crypto/openssh/servconf.c @@ -660,6 +660,7 @@ static struct { { "rdomain", sRDomain, SSHCFG_ALL }, { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, { "useblacklist", sUseBlacklist, SSHCFG_GLOBAL }, + { "useblocklist", sUseBlacklist, SSHCFG_GLOBAL }, /* alias */ { "noneenabled", sUnsupported, SSHCFG_ALL }, { "hpndisabled", sDeprecated, SSHCFG_ALL }, { "hpnbuffersize", sDeprecated, SSHCFG_ALL }, diff --git a/crypto/openssh/sshd_config.5 b/crypto/openssh/sshd_config.5 index 3f935da9b572..d28622d984a1 100644 --- a/crypto/openssh/sshd_config.5 +++ b/crypto/openssh/sshd_config.5 @@ -35,7 +35,7 @@ .\" .\" $OpenBSD: sshd_config.5,v 1.282 2018/09/20 03:28:06 djm Exp $ .\" $FreeBSD$ -.Dd $Mdocdate: September 20 2018 $ +.Dd $Mdocdate: July 28 2020 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -1602,6 +1602,11 @@ to the daemon. The default is .Cm no . +For forward compatibility with an upcoming +.Xr blacklistd +rename, the +.Cm UseBlocklist +alias can be used instead. .It Cm UseDNS Specifies whether .Xr sshd 8 From 055f26947290a353987b8e1eb6e6f55710067ee9 Mon Sep 17 00:00:00 2001 From: Robert Wing Date: Wed, 29 Jul 2020 05:27:19 +0000 Subject: [PATCH 240/287] Add myself (rew) as src committer. Reviewed by: kevans (mentor), allanjude (mentor) Approved by: kevans (mentor), allanjude (mentor) Differential Revision: https://reviews.freebsd.org/D25837 --- share/misc/committers-src.dot | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/share/misc/committers-src.dot b/share/misc/committers-src.dot index a7550b9a6ce2..212c1b613029 100644 --- a/share/misc/committers-src.dot +++ b/share/misc/committers-src.dot @@ -300,6 +300,7 @@ ram [label="Ram Kishore Vegesna\nram@FreeBSD.org\n2018/04/04"] ray [label="Aleksandr Rybalko\nray@FreeBSD.org\n2011/05/25"] rdivacky [label="Roman Divacky\nrdivacky@FreeBSD.org\n2008/03/13"] remko [label="Remko Lodder\nremko@FreeBSD.org\n2007/02/23"] +rew [label="Robert Wing\nrew@FreeBSD.org\n2020/07/23"] rgrimes [label="Rodney W. Grimes\nrgrimes@FreeBSD.org\n1993/06/12\n2017/03/03"] rik [label="Roman Kurakin\nrik@FreeBSD.org\n2003/12/18"] rlibby [label="Ryan Libby\nrlibby@FreeBSD.org\n2017/06/07"] @@ -404,6 +405,7 @@ adrian -> sgalabov ae -> melifaro +allanjude -> rew allanjude -> tsoome alc -> davide @@ -673,6 +675,8 @@ ken -> ram ken -> slm ken -> will +kevans -> rew + kib -> ae kib -> badger kib -> dchagin From 65e305af3db085cae735c8f1ee54cf32ac1f14ad Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Wed, 29 Jul 2020 08:24:40 +0000 Subject: [PATCH 241/287] Only try managing the regulator when EXT_RESOURCES is defined Not all Raspberry Pi kernel configs define EXT_RESOURCES. Check for this before trying to manage the regulator. Sponsored by: Innovate UK --- sys/arm/broadcom/bcm2835/bcm2835_sdhci.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c index 8bf8049fc1ae..cd9b60743be3 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c @@ -394,10 +394,13 @@ bcm_sdhci_intr(void *arg) static int bcm_sdhci_update_ios(device_t bus, device_t child) { +#ifdef EXT_RESOURCES struct bcm_sdhci_softc *sc; struct mmc_ios *ios; +#endif int rv; +#ifdef EXT_RESOURCES sc = device_get_softc(bus); ios = &sc->sc_slot.host.ios; @@ -407,17 +410,20 @@ bcm_sdhci_update_ios(device_t bus, device_t child) if (sc->sc_mmc_helper.vqmmc_supply) regulator_enable(sc->sc_mmc_helper.vqmmc_supply); } +#endif rv = sdhci_generic_update_ios(bus, child); if (rv != 0) return (rv); +#ifdef EXT_RESOURCES if (ios->power_mode == power_off) { if (sc->sc_mmc_helper.vmmc_supply) regulator_disable(sc->sc_mmc_helper.vmmc_supply); if (sc->sc_mmc_helper.vqmmc_supply) regulator_disable(sc->sc_mmc_helper.vqmmc_supply); } +#endif return (0); } From eb83321d4452ee135d66385e481bd77687c23cf0 Mon Sep 17 00:00:00 2001 From: Daniel Ebdrup Jensen Date: Wed, 29 Jul 2020 11:17:44 +0000 Subject: [PATCH 242/287] Outline mentorship As part of onboarding and while listening to Holy Ghost by The Bar-Kays, outline my mentorship. 0mp is mentor, with allanjude and bcr as co-mentor. Reviewed by: 0mp, allanjude, bcr Approved by: 0mp (mentor), allanjude (mentor), bcr (mentor) Differential Revision: D25855 --- share/misc/committers-doc.dot | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/share/misc/committers-doc.dot b/share/misc/committers-doc.dot index 691248727521..4edffffeed1b 100644 --- a/share/misc/committers-doc.dot +++ b/share/misc/committers-doc.dot @@ -62,6 +62,7 @@ carlavilla [label="Sergio Carlavilla\ncarlavilla@FreeBSD.org\n2019/05/16"] chinsan [label="Chinsan Huang\nchinsan@FreeBSD.org\n2006/09/20"] crees [label="Chris Rees\ncrees@FreeBSD.org\n2013/05/27"] danger [label="Daniel Gerzo\ndanger@FreeBSD.org\n2006/08/20"] +debdrup [label="Daniel Ebdrup Jensen\ndebdrup@FreeBSD.org\n2020/07/26"] delphij [label="Xin Li\ndelphij@FreeBSD.org\n2004/09/14"] dexter [label="Michael Dexter\ndexter@FreeBSD.org\n2016/11/15"] dru [label="Dru Lavigne\ndru@FreeBSD.org\n2013/01/22"] @@ -103,6 +104,10 @@ zeising [label="Niclas Zeising\nzeising@FreeBSD.org\n2012/07/03"] # Group together all the mentees for a particular mentor. # Keep the list sorted by mentor login. +"0mp" -> debdrup + +allanjude -> debdrup + bcr -> gavin bcr -> wblock bcr -> eadler @@ -117,6 +122,7 @@ bcr -> sg bcr -> carlavilla bcr -> "0mp" bcr -> gbe +bcr -> debdrup blackend -> ale From ee49c1d3e5a4ac22aeb414b16f560a6a4172523f Mon Sep 17 00:00:00 2001 From: Daniel Ebdrup Jensen Date: Wed, 29 Jul 2020 11:19:57 +0000 Subject: [PATCH 243/287] Add my entry to the calendar file As part of onboarding, ensure that I'm listed in the FreeBSD calendar file, while listening to Don't Take Away The Music by Tavares. Reviewed by: 0mp, bcr Approved by: 0mp (mentor), allanjude (mentor) Differential Revision: D25856 --- usr.bin/calendar/calendars/calendar.freebsd | 1 + 1 file changed, 1 insertion(+) diff --git a/usr.bin/calendar/calendars/calendar.freebsd b/usr.bin/calendar/calendars/calendar.freebsd index 7becc0dc2830..93b714ede7fb 100644 --- a/usr.bin/calendar/calendars/calendar.freebsd +++ b/usr.bin/calendar/calendars/calendar.freebsd @@ -404,6 +404,7 @@ 10/20 Joel Dahl born in Bitterna, Skaraborg, Sweden, 1983 10/20 Dmitry Marakasov born in Moscow, Russian Federation, 1984 10/21 Ben Smithurst born in Sheffield, South Yorkshire, United Kingdom, 1981 +10/21 Daniel Ebdrup Jensen born in Aalborg, Denmark, 19XX 10/22 Jean-Sebastien Pedron born in Redon, Ille-et-Vilaine, France, 1980 10/23 Mario Sergio Fujikawa Ferreira born in Brasilia, Distrito Federal, Brazil, 1976 10/23 Romain Tartière born in Clermont-Ferrand, France, 1984 From 1b0c9c21d9fd27935b4bfd6f739716cb12e3349c Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Wed, 29 Jul 2020 13:23:27 +0000 Subject: [PATCH 244/287] o Move iommu_set_buswide_ctx, iommu_is_buswide_ctx to the generic iommu busdma backend; o Move bus_dma_iommu_set_buswide, bus_dma_iommu_load_ident prototypes to iommu.h. Reviewed by: kib Sponsored by: DARPA, AFRL Differential Revision: https://reviews.freebsd.org/D25866 --- sys/dev/iommu/busdma_iommu.c | 20 ++++++++++++++++++++ sys/dev/iommu/iommu.h | 7 +++++++ sys/x86/include/bus_dma.h | 6 ------ sys/x86/iommu/intel_dmar.h | 3 --- sys/x86/iommu/intel_drv.c | 20 -------------------- 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/sys/dev/iommu/busdma_iommu.c b/sys/dev/iommu/busdma_iommu.c index 0fd54e8b641a..dd1309fd7dc6 100644 --- a/sys/dev/iommu/busdma_iommu.c +++ b/sys/dev/iommu/busdma_iommu.c @@ -326,6 +326,26 @@ bus_dma_iommu_set_buswide(device_t dev) return (true); } +void +iommu_set_buswide_ctx(struct iommu_unit *unit, u_int busno) +{ + + MPASS(busno <= PCI_BUSMAX); + IOMMU_LOCK(unit); + unit->buswide_ctxs[busno / NBBY / sizeof(uint32_t)] |= + 1 << (busno % (NBBY * sizeof(uint32_t))); + IOMMU_UNLOCK(unit); +} + +bool +iommu_is_buswide_ctx(struct iommu_unit *unit, u_int busno) +{ + + MPASS(busno <= PCI_BUSMAX); + return ((unit->buswide_ctxs[busno / NBBY / sizeof(uint32_t)] & + (1U << (busno % (NBBY * sizeof(uint32_t))))) != 0); +} + static MALLOC_DEFINE(M_IOMMU_DMAMAP, "iommu_dmamap", "IOMMU DMA Map"); static void iommu_bus_schedule_dmamap(struct iommu_unit *unit, diff --git a/sys/dev/iommu/iommu.h b/sys/dev/iommu/iommu.h index 380f4cdfe5f6..cf90e7884951 100644 --- a/sys/dev/iommu/iommu.h +++ b/sys/dev/iommu/iommu.h @@ -221,6 +221,13 @@ int iommu_gas_map_region(struct iommu_domain *domain, int iommu_gas_reserve_region(struct iommu_domain *domain, iommu_gaddr_t start, iommu_gaddr_t end); +void iommu_set_buswide_ctx(struct iommu_unit *unit, u_int busno); +bool iommu_is_buswide_ctx(struct iommu_unit *unit, u_int busno); + +bool bus_dma_iommu_set_buswide(device_t dev); +int bus_dma_iommu_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map, + vm_paddr_t start, vm_size_t length, int flags); + SYSCTL_DECL(_hw_iommu); #endif /* !_SYS_IOMMU_H_ */ diff --git a/sys/x86/include/bus_dma.h b/sys/x86/include/bus_dma.h index a87143609259..b4da787e9cfc 100644 --- a/sys/x86/include/bus_dma.h +++ b/sys/x86/include/bus_dma.h @@ -191,11 +191,5 @@ _bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map, return (tc->impl->map_complete(dmat, map, segs, nsegs, error)); } -#ifdef _KERNEL -bool bus_dma_iommu_set_buswide(device_t dev); -int bus_dma_iommu_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map, - vm_paddr_t start, vm_size_t length, int flags); -#endif - #endif /* !_X86_BUS_DMA_H_ */ diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h index 49a94190b496..eae01bcc134d 100644 --- a/sys/x86/iommu/intel_dmar.h +++ b/sys/x86/iommu/intel_dmar.h @@ -281,9 +281,6 @@ void dmar_quirks_pre_use(struct iommu_unit *dmar); int dmar_init_irt(struct dmar_unit *unit); void dmar_fini_irt(struct dmar_unit *unit); -void iommu_set_buswide_ctx(struct iommu_unit *unit, u_int busno); -bool iommu_is_buswide_ctx(struct iommu_unit *unit, u_int busno); - extern iommu_haddr_t dmar_high; extern int haw; extern int dmar_tbl_pagecnt; diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c index 4af5da538840..9ae8e37d4fa0 100644 --- a/sys/x86/iommu/intel_drv.c +++ b/sys/x86/iommu/intel_drv.c @@ -592,26 +592,6 @@ static driver_t dmar_driver = { DRIVER_MODULE(dmar, acpi, dmar_driver, dmar_devclass, 0, 0); MODULE_DEPEND(dmar, acpi, 1, 1, 1); -void -iommu_set_buswide_ctx(struct iommu_unit *unit, u_int busno) -{ - - MPASS(busno <= PCI_BUSMAX); - IOMMU_LOCK(unit); - unit->buswide_ctxs[busno / NBBY / sizeof(uint32_t)] |= - 1 << (busno % (NBBY * sizeof(uint32_t))); - IOMMU_UNLOCK(unit); -} - -bool -iommu_is_buswide_ctx(struct iommu_unit *unit, u_int busno) -{ - - MPASS(busno <= PCI_BUSMAX); - return ((unit->buswide_ctxs[busno / NBBY / sizeof(uint32_t)] & - (1U << (busno % (NBBY * sizeof(uint32_t))))) != 0); -} - static void dmar_print_path(int busno, int depth, const ACPI_DMAR_PCI_PATH *path) { From 9abb92653894a0f70d372758c2c965fc99b69866 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Wed, 29 Jul 2020 15:46:17 +0000 Subject: [PATCH 245/287] Fix build. Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25879 --- sys/dev/ntb/ntb_hw/ntb_hw_intel.c | 1 + sys/dev/ntb/ntb_hw/ntb_hw_plx.c | 1 + 2 files changed, 2 insertions(+) diff --git a/sys/dev/ntb/ntb_hw/ntb_hw_intel.c b/sys/dev/ntb/ntb_hw/ntb_hw_intel.c index ba61fdc9ffcd..0a839157a90c 100644 --- a/sys/dev/ntb/ntb_hw/ntb_hw_intel.c +++ b/sys/dev/ntb/ntb_hw/ntb_hw_intel.c @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include "ntb_hw_intel.h" #include "../ntb.h" diff --git a/sys/dev/ntb/ntb_hw/ntb_hw_plx.c b/sys/dev/ntb/ntb_hw/ntb_hw_plx.c index a9654e7f6725..e1a65178be81 100644 --- a/sys/dev/ntb/ntb_hw/ntb_hw_plx.c +++ b/sys/dev/ntb/ntb_hw/ntb_hw_plx.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include "../ntb.h" From fd8c6a48abe0ad2ba64b611fe044830f89b30138 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Wed, 29 Jul 2020 17:04:33 +0000 Subject: [PATCH 246/287] vfs: honor error code returned by mac_vnode_check_rename_from MFC after: 3 days --- sys/kern/vfs_syscalls.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 2caf09f3412c..c16da32de6dc 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -3556,20 +3556,27 @@ kern_renameat(struct thread *td, int oldfd, const char *old, int newfd, NDINIT_ATRIGHTS(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART | AUDITVNODE1, pathseg, old, oldfd, &cap_renameat_source_rights, td); -#else - NDINIT_ATRIGHTS(&fromnd, DELETE, WANTPARENT | SAVESTART | AUDITVNODE1, - pathseg, old, oldfd, - &cap_renameat_source_rights, td); -#endif - if ((error = namei(&fromnd)) != 0) return (error); -#ifdef MAC error = mac_vnode_check_rename_from(td->td_ucred, fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd); VOP_UNLOCK(fromnd.ni_dvp); if (fromnd.ni_dvp != fromnd.ni_vp) VOP_UNLOCK(fromnd.ni_vp); + if (error != 0) { + NDFREE(&fromnd, NDF_ONLY_PNBUF); + vrele(fromnd.ni_dvp); + vrele(fromnd.ni_vp); + if (fromnd.ni_startdir) + vrele(fromnd.ni_startdir); + return (error); + } +#else + NDINIT_ATRIGHTS(&fromnd, DELETE, WANTPARENT | SAVESTART | AUDITVNODE1, + pathseg, old, oldfd, + &cap_renameat_source_rights, td); + if ((error = namei(&fromnd)) != 0) + return (error); #endif fvp = fromnd.ni_vp; NDINIT_ATRIGHTS(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | From fad6dd772d15214036aeea34a1c280dc8390fdfb Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Wed, 29 Jul 2020 17:05:31 +0000 Subject: [PATCH 247/287] vfs: elide MAC-induced locking on rename if there are no relevant hoooks --- sys/kern/vfs_syscalls.c | 58 ++++++++++++++++++++------------ sys/security/mac/mac_framework.c | 3 ++ sys/security/mac/mac_framework.h | 4 +++ 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index c16da32de6dc..9e9c53d3327c 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -3541,6 +3541,33 @@ sys_renameat(struct thread *td, struct renameat_args *uap) UIO_USERSPACE)); } +#ifdef MAC +static int +kern_renameat_mac(struct thread *td, int oldfd, const char *old, int newfd, + const char *new, enum uio_seg pathseg, struct nameidata *fromnd) +{ + int error; + + NDINIT_ATRIGHTS(fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART | + AUDITVNODE1, pathseg, old, oldfd, &cap_renameat_source_rights, td); + if ((error = namei(fromnd)) != 0) + return (error); + error = mac_vnode_check_rename_from(td->td_ucred, fromnd->ni_dvp, + fromnd->ni_vp, &fromnd->ni_cnd); + VOP_UNLOCK(fromnd->ni_dvp); + if (fromnd->ni_dvp != fromnd->ni_vp) + VOP_UNLOCK(fromnd->ni_vp); + if (error != 0) { + NDFREE(fromnd, NDF_ONLY_PNBUF); + vrele(fromnd->ni_dvp); + vrele(fromnd->ni_vp); + if (fromnd->ni_startdir) + vrele(fromnd->ni_startdir); + } + return (error); +} +#endif + int kern_renameat(struct thread *td, int oldfd, const char *old, int newfd, const char *new, enum uio_seg pathseg) @@ -3553,30 +3580,19 @@ kern_renameat(struct thread *td, int oldfd, const char *old, int newfd, again: bwillwrite(); #ifdef MAC - NDINIT_ATRIGHTS(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART | - AUDITVNODE1, pathseg, old, oldfd, - &cap_renameat_source_rights, td); - if ((error = namei(&fromnd)) != 0) - return (error); - error = mac_vnode_check_rename_from(td->td_ucred, fromnd.ni_dvp, - fromnd.ni_vp, &fromnd.ni_cnd); - VOP_UNLOCK(fromnd.ni_dvp); - if (fromnd.ni_dvp != fromnd.ni_vp) - VOP_UNLOCK(fromnd.ni_vp); - if (error != 0) { - NDFREE(&fromnd, NDF_ONLY_PNBUF); - vrele(fromnd.ni_dvp); - vrele(fromnd.ni_vp); - if (fromnd.ni_startdir) - vrele(fromnd.ni_startdir); - return (error); - } -#else + if (mac_vnode_check_rename_from_enabled()) { + error = kern_renameat_mac(td, oldfd, old, newfd, new, pathseg, + &fromnd); + if (error != 0) + return (error); + } else { +#endif NDINIT_ATRIGHTS(&fromnd, DELETE, WANTPARENT | SAVESTART | AUDITVNODE1, - pathseg, old, oldfd, - &cap_renameat_source_rights, td); + pathseg, old, oldfd, &cap_renameat_source_rights, td); if ((error = namei(&fromnd)) != 0) return (error); +#ifdef MAC + } #endif fvp = fromnd.ni_vp; NDINIT_ATRIGHTS(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | diff --git a/sys/security/mac/mac_framework.c b/sys/security/mac/mac_framework.c index aea3789d572f..41c0779fa78e 100644 --- a/sys/security/mac/mac_framework.c +++ b/sys/security/mac/mac_framework.c @@ -139,6 +139,7 @@ FPFLAG(vnode_check_read); FPFLAG(vnode_check_write); FPFLAG(vnode_check_mmap); FPFLAG_RARE(vnode_check_poll); +FPFLAG_RARE(vnode_check_rename_from); #undef FPFLAG #undef FPFLAG_RARE @@ -427,6 +428,8 @@ struct mac_policy_fastpath_elem mac_policy_fastpath_array[] = { .flag = &mac_vnode_check_mmap_fp_flag }, { .offset = FPO(vnode_check_poll), .flag = &mac_vnode_check_poll_fp_flag }, + { .offset = FPO(vnode_check_rename_from), + .flag = &mac_vnode_check_rename_from_fp_flag }, }; static void diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h index e917eeb3c893..7ef13dcce758 100644 --- a/sys/security/mac/mac_framework.h +++ b/sys/security/mac/mac_framework.h @@ -482,6 +482,10 @@ mac_vnode_check_poll(struct ucred *active_cred, struct ucred *file_cred, #endif int mac_vnode_check_readdir(struct ucred *cred, struct vnode *vp); int mac_vnode_check_readlink(struct ucred *cred, struct vnode *vp); +#define mac_vnode_check_rename_from_enabled() __predict_false(mac_vnode_check_rename_from_fp_flag) +#ifdef MAC +extern bool mac_vnode_check_rename_from_fp_flag; +#endif int mac_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp, struct vnode *vp, struct componentname *cnp); int mac_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp, From 386f81fca7583e9568862daafba7740f3a7f00d8 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Wed, 29 Jul 2020 19:22:50 +0000 Subject: [PATCH 248/287] Fix !ACPI_DMAR build. Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25882 --- sys/x86/x86/busdma_machdep.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/x86/x86/busdma_machdep.c b/sys/x86/x86/busdma_machdep.c index 3dade64692d6..168645702bc5 100644 --- a/sys/x86/x86/busdma_machdep.c +++ b/sys/x86/x86/busdma_machdep.c @@ -300,6 +300,10 @@ bus_dma_tag_destroy(bus_dma_tag_t dmat) } #ifndef ACPI_DMAR +bool bus_dma_iommu_set_buswide(device_t dev); +int bus_dma_iommu_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map, + vm_paddr_t start, vm_size_t length, int flags); + bool bus_dma_iommu_set_buswide(device_t dev) { From 12b2f3daaa597f346a4b0065bf7f75378524ef88 Mon Sep 17 00:00:00 2001 From: Cy Schubert Date: Wed, 29 Jul 2020 19:36:24 +0000 Subject: [PATCH 249/287] Continued ipfilter #ifdef cleanup. The r343701 log entry contains a complete description. MFC after: 1 week --- contrib/ipfilter/iplang/iplang_y.y | 9 -- contrib/ipfilter/ipsend/arp.c | 4 - contrib/ipfilter/ipsend/ipresend.c | 8 -- contrib/ipfilter/ipsend/ipsend.c | 8 -- contrib/ipfilter/ipsend/iptest.c | 8 -- contrib/ipfilter/ipsend/iptests.c | 13 +-- contrib/ipfilter/ipsend/sock.c | 135 +---------------------------- 7 files changed, 4 insertions(+), 181 deletions(-) diff --git a/contrib/ipfilter/iplang/iplang_y.y b/contrib/ipfilter/iplang/iplang_y.y index 98c8f1a983ea..f223b1eb8b32 100644 --- a/contrib/ipfilter/iplang/iplang_y.y +++ b/contrib/ipfilter/iplang/iplang_y.y @@ -45,11 +45,6 @@ #include "ipf.h" #include "iplang.h" -#if !defined(__NetBSD__) && (!defined(__FreeBSD_version) && \ - __FreeBSD_version < 400020) && (!SOLARIS || SOLARIS2 < 10) -extern struct ether_addr *ether_aton __P((char *)); -#endif - extern int opts; extern struct ipopt_names ionames[]; extern int state, state, lineNum, token; @@ -58,11 +53,7 @@ extern char yytext[]; extern FILE *yyin; int yylex __P((void)); #define YYDEBUG 1 -#if !defined(ultrix) && !defined(hpux) int yydebug = 1; -#else -extern int yydebug; -#endif iface_t *iflist = NULL, **iftail = &iflist; iface_t *cifp = NULL; diff --git a/contrib/ipfilter/ipsend/arp.c b/contrib/ipfilter/ipsend/arp.c index 05f255ea47d2..31b70d3e8987 100644 --- a/contrib/ipfilter/ipsend/arp.c +++ b/contrib/ipfilter/ipsend/arp.c @@ -11,17 +11,13 @@ static const char rcsid[] = "@(#)$Id$"; #endif #include #include -#if !defined(ultrix) && !defined(hpux) && !defined(__hpux) && !defined(__osf__) && !defined(_AIX51) # include -#endif #include #include #include #include #include -#ifndef ultrix # include -#endif #include #include #include diff --git a/contrib/ipfilter/ipsend/ipresend.c b/contrib/ipfilter/ipsend/ipresend.c index ea0b4211c101..1e7b9049169a 100644 --- a/contrib/ipfilter/ipsend/ipresend.c +++ b/contrib/ipfilter/ipsend/ipresend.c @@ -38,15 +38,7 @@ int opts = 0; # ifdef sun char default_device[] = "le0"; # else -# ifdef ultrix -char default_device[] = "ln0"; -# else -# ifdef __bsdi__ -char default_device[] = "ef0"; -# else char default_device[] = "lan0"; -# endif -# endif # endif #else char default_device[] = DEFAULT_DEVICE; diff --git a/contrib/ipfilter/ipsend/ipsend.c b/contrib/ipfilter/ipsend/ipsend.c index 95a1bb1e5c78..b7617734f66e 100644 --- a/contrib/ipfilter/ipsend/ipsend.c +++ b/contrib/ipfilter/ipsend/ipsend.c @@ -33,15 +33,7 @@ extern void iplang __P((FILE *)); char options[68]; int opts; -# ifdef ultrix -char default_device[] = "ln0"; -# else -# ifdef __bsdi__ -char default_device[] = "ef0"; -# else char default_device[] = "le0"; -# endif /* __bsdi__ */ -# endif /* ultrix */ static void usage __P((char *)); diff --git a/contrib/ipfilter/ipsend/iptest.c b/contrib/ipfilter/ipsend/iptest.c index bc93106c8b89..ffabaf37b5bc 100644 --- a/contrib/ipfilter/ipsend/iptest.c +++ b/contrib/ipfilter/ipsend/iptest.c @@ -34,15 +34,7 @@ char options[68]; # ifdef sun char default_device[] = "le0"; # else -# ifdef ultrix -char default_device[] = "ln0"; -# else -# ifdef __bsdi__ -char default_device[] = "ef0"; -# else char default_device[] = "lan0"; -# endif -# endif # endif static void usage __P((char *)); diff --git a/contrib/ipfilter/ipsend/iptests.c b/contrib/ipfilter/ipsend/iptests.c index af8772cc2097..86b850d319bb 100644 --- a/contrib/ipfilter/ipsend/iptests.c +++ b/contrib/ipfilter/ipsend/iptests.c @@ -36,18 +36,13 @@ typedef int boolean_t; # endif # undef _KERNEL # undef KERNEL -#if !defined(solaris) && !defined(linux) && !defined(__sgi) +#if !defined(solaris) # include # include # include #endif -#if !defined(ultrix) && !defined(hpux) && !defined(linux) && \ - !defined(__sgi) && !defined(__osf__) && !defined(_AIX51) # include -#endif -#ifndef ultrix # include -#endif #if defined(solaris) # include #else @@ -57,11 +52,9 @@ typedef int boolean_t; #include #include #endif -#if BSD >= 199103 # include # include # include -#endif #include #include #include @@ -74,7 +67,7 @@ typedef int boolean_t; #include #include #include -#if defined(__SVR4) || defined(__svr4__) || defined(__sgi) +#if defined(__SVR4) || defined(__svr4__) # include #endif #include @@ -82,7 +75,7 @@ typedef int boolean_t; #include #include # include -# if !defined(__hpux) && !defined(solaris) +# if !defined(solaris) # include # endif #include "ipsend.h" diff --git a/contrib/ipfilter/ipsend/sock.c b/contrib/ipfilter/ipsend/sock.c index d7eae8a13196..66e1a0aa897e 100644 --- a/contrib/ipfilter/ipsend/sock.c +++ b/contrib/ipfilter/ipsend/sock.c @@ -21,14 +21,8 @@ static const char rcsid[] = "@(#)$Id$"; */ typedef int boolean_t; #endif -#ifndef ultrix #include -#endif -#if (__FreeBSD_version >= 300000) # include -#else -# include -#endif # ifdef __NetBSD__ # include # endif @@ -38,10 +32,6 @@ typedef int boolean_t; # define _KERNEL # define KERNEL # endif -# ifdef ultrix -# undef LOCORE -# include -# endif # include # ifdef __FreeBSD__ # undef _WANT_FILE @@ -54,18 +44,14 @@ typedef int boolean_t; #include #include #include -#if !defined(ultrix) && !defined(hpux) && !defined(__osf__) # include -#endif #ifdef sun #include #include #endif -#if BSD >= 199103 #include #include #include -#endif #include #include #include @@ -143,128 +129,10 @@ int kmemcpy(buf, pos, n) struct nlist names[4] = { { "_proc" }, { "_nproc" }, -#ifdef ultrix - { "_u" }, -#else { NULL }, -#endif { NULL } }; -#if BSD < 199103 -static struct proc *getproc() -{ - struct proc *p; - pid_t pid = getpid(); - int siz, n; - - n = nlist(KERNEL, names); - if (n != 0) - { - fprintf(stderr, "nlist(%#x) == %d\n", names, n); - return NULL; - } - if (KMCPY(&nproc, names[1].n_value, sizeof(nproc)) == -1) - { - fprintf(stderr, "read nproc (%#x)\n", names[1].n_value); - return NULL; - } - siz = nproc * sizeof(struct proc); - if (KMCPY(&p, names[0].n_value, sizeof(p)) == -1) - { - fprintf(stderr, "read(%#x,%#x,%d) proc\n", - names[0].n_value, &p, sizeof(p)); - return NULL; - } - proc = (struct proc *)malloc(siz); - if (KMCPY(proc, p, siz) == -1) - { - fprintf(stderr, "read(%#x,%#x,%d) proc\n", - p, proc, siz); - return NULL; - } - - p = proc; - - for (n = nproc; n; n--, p++) - if (p->p_pid == pid) - break; - if (!n) - return NULL; - - return p; -} - - -struct tcpcb *find_tcp(fd, ti) - int fd; - struct tcpiphdr *ti; -{ - struct tcpcb *t; - struct inpcb *i; - struct socket *s; - struct user *up; - struct proc *p; - struct file *f, **o; - - if (!(p = getproc())) - return NULL; - up = (struct user *)malloc(sizeof(*up)); -#ifndef ultrix - if (KMCPY(up, p->p_uarea, sizeof(*up)) == -1) - { - fprintf(stderr, "read(%#x,%#x) failed\n", p, p->p_uarea); - return NULL; - } -#else - if (KMCPY(up, names[2].n_value, sizeof(*up)) == -1) - { - fprintf(stderr, "read(%#x,%#x) failed\n", p, names[2].n_value); - return NULL; - } -#endif - - o = (struct file **)calloc(up->u_lastfile + 1, sizeof(*o)); - if (KMCPY(o, up->u_ofile, (up->u_lastfile + 1) * sizeof(*o)) == -1) - { - fprintf(stderr, "read(%#x,%#x,%d) - u_ofile - failed\n", - up->u_ofile, o, sizeof(*o)); - return NULL; - } - f = (struct file *)calloc(1, sizeof(*f)); - if (KMCPY(f, o[fd], sizeof(*f)) == -1) - { - fprintf(stderr, "read(%#x,%#x,%d) - o[fd] - failed\n", - up->u_ofile[fd], f, sizeof(*f)); - return NULL; - } - - s = (struct socket *)calloc(1, sizeof(*s)); - if (KMCPY(s, f->f_data, sizeof(*s)) == -1) - { - fprintf(stderr, "read(%#x,%#x,%d) - f_data - failed\n", - o[fd], s, sizeof(*s)); - return NULL; - } - - i = (struct inpcb *)calloc(1, sizeof(*i)); - if (KMCPY(i, s->so_pcb, sizeof(*i)) == -1) - { - fprintf(stderr, "kvm_read(%#x,%#x,%d) - so_pcb - failed\n", - s->so_pcb, i, sizeof(*i)); - return NULL; - } - - t = (struct tcpcb *)calloc(1, sizeof(*t)); - if (KMCPY(t, i->inp_ppcb, sizeof(*t)) == -1) - { - fprintf(stderr, "read(%#x,%#x,%d) - inp_ppcb - failed\n", - i->inp_ppcb, t, sizeof(*t)); - return NULL; - } - return (struct tcpcb *)i->inp_ppcb; -} -#else static struct kinfo_proc *getproc() { static struct kinfo_proc kp; @@ -304,7 +172,7 @@ struct tcpcb *find_tcp(tfd, ti) fd = (struct filedesc *)malloc(sizeof(*fd)); if (fd == NULL) return NULL; -#if defined( __FreeBSD_version) && __FreeBSD_version >= 500013 +#if defined( __FreeBSD_version) if (KMCPY(fd, p->ki_fd, sizeof(*fd)) == -1) { fprintf(stderr, "read(%#lx,%#lx) failed\n", @@ -381,7 +249,6 @@ struct tcpcb *find_tcp(tfd, ti) free(t); return NULL; } -#endif /* BSD < 199301 */ int do_socket(dev, mtu, ti, gwip) char *dev; From 958d8f527c29658bd55a67e5e970de4447cc47e4 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 29 Jul 2020 19:38:49 +0000 Subject: [PATCH 250/287] Remove the volatile qualifier from busy_lock. Use atomic(9) to load the lock state. Some places were doing this already, so it was inconsistent. In initialization code, the lock state is still initialized with plain stores. Reviewed by: alc, kib Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25861 --- sys/vm/vm_page.c | 18 +++++++++--------- sys/vm/vm_page.h | 26 +++++++++++++++++--------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index 8c2df3e78e17..ce107645d6a6 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -908,7 +908,7 @@ vm_page_busy_downgrade(vm_page_t m) vm_page_assert_xbusied(m); - x = m->busy_lock; + x = vm_page_busy_fetch(m); for (;;) { if (atomic_fcmpset_rel_int(&m->busy_lock, &x, VPB_SHARERS_WORD(1))) @@ -931,7 +931,7 @@ vm_page_busy_tryupgrade(vm_page_t m) vm_page_assert_sbusied(m); - x = m->busy_lock; + x = vm_page_busy_fetch(m); ce = VPB_CURTHREAD_EXCLUSIVE; for (;;) { if (VPB_SHARERS(x) > 1) @@ -955,7 +955,7 @@ vm_page_sbusied(vm_page_t m) { u_int x; - x = m->busy_lock; + x = vm_page_busy_fetch(m); return ((x & VPB_BIT_SHARED) != 0 && x != VPB_UNBUSIED); } @@ -971,7 +971,7 @@ vm_page_sunbusy(vm_page_t m) vm_page_assert_sbusied(m); - x = m->busy_lock; + x = vm_page_busy_fetch(m); for (;;) { KASSERT(x != VPB_FREED, ("vm_page_sunbusy: Unlocking freed page.")); @@ -1072,7 +1072,7 @@ _vm_page_busy_sleep(vm_object_t obj, vm_page_t m, vm_pindex_t pindex, xsleep = (allocflags & (VM_ALLOC_SBUSY | VM_ALLOC_IGN_SBUSY)) != 0; sleepq_lock(m); - x = atomic_load_int(&m->busy_lock); + x = vm_page_busy_fetch(m); do { /* * If the page changes objects or becomes unlocked we can @@ -1110,7 +1110,7 @@ vm_page_trysbusy(vm_page_t m) u_int x; obj = m->object; - x = m->busy_lock; + x = vm_page_busy_fetch(m); for (;;) { if ((x & VPB_BIT_SHARED) == 0) return (0); @@ -1146,7 +1146,7 @@ vm_page_tryxbusy(vm_page_t m) { vm_object_t obj; - if (atomic_cmpset_acq_int(&(m)->busy_lock, VPB_UNBUSIED, + if (atomic_cmpset_acq_int(&m->busy_lock, VPB_UNBUSIED, VPB_CURTHREAD_EXCLUSIVE) == 0) return (0); @@ -1354,7 +1354,7 @@ vm_page_readahead_finish(vm_page_t m) * have shown that deactivating the page is usually the best choice, * unless the page is wanted by another thread. */ - if ((m->busy_lock & VPB_BIT_WAITERS) != 0) + if ((vm_page_busy_fetch(m) & VPB_BIT_WAITERS) != 0) vm_page_activate(m); else vm_page_deactivate(m); @@ -1719,7 +1719,7 @@ vm_page_busy_release(vm_page_t m) { u_int x; - x = atomic_load_int(&m->busy_lock); + x = vm_page_busy_fetch(m); for (;;) { if (x == VPB_FREED) break; diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index c96979cf236b..93b3dc411925 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -100,7 +100,8 @@ * field and is described in detail below. * * The following annotations are possible: - * (A) the field is atomic and may require additional synchronization. + * (A) the field must be accessed using atomic(9) and may require + * additional synchronization. * (B) the page busy lock. * (C) the field is immutable. * (F) the per-domain lock for the free queues @@ -243,8 +244,8 @@ struct vm_page { vm_paddr_t phys_addr; /* physical address of page (C) */ struct md_page md; /* machine dependent stuff */ u_int ref_count; /* page references (A) */ - volatile u_int busy_lock; /* busy owners lock */ - union vm_page_astate a; /* state accessed atomically */ + u_int busy_lock; /* busy owners lock (A) */ + union vm_page_astate a; /* state accessed atomically (A) */ uint8_t order; /* index of the buddy queue (F) */ uint8_t pool; /* vm_phys freepool index (F) */ uint8_t flags; /* page PG_* flags (P) */ @@ -701,6 +702,8 @@ void vm_page_assert_locked_KBI(vm_page_t m, const char *file, int line); void vm_page_lock_assert_KBI(vm_page_t m, int a, const char *file, int line); #endif +#define vm_page_busy_fetch(m) atomic_load_int(&(m)->busy_lock) + #define vm_page_assert_busied(m) \ KASSERT(vm_page_busied(m), \ ("vm_page_assert_busied: page %p not busy @ %s:%d", \ @@ -712,7 +715,7 @@ void vm_page_lock_assert_KBI(vm_page_t m, int a, const char *file, int line); (m), __FILE__, __LINE__)) #define vm_page_assert_unbusied(m) \ - KASSERT((m->busy_lock & ~VPB_BIT_WAITERS) != \ + KASSERT((vm_page_busy_fetch(m) & ~VPB_BIT_WAITERS) != \ VPB_CURTHREAD_EXCLUSIVE, \ ("vm_page_assert_xbusied: page %p busy_lock %#x owned" \ " by me @ %s:%d", \ @@ -725,7 +728,7 @@ void vm_page_lock_assert_KBI(vm_page_t m, int a, const char *file, int line); } while (0) #define vm_page_assert_xbusied(m) do { \ vm_page_assert_xbusied_unchecked(m); \ - KASSERT((m->busy_lock & ~VPB_BIT_WAITERS) == \ + KASSERT((vm_page_busy_fetch(m) & ~VPB_BIT_WAITERS) == \ VPB_CURTHREAD_EXCLUSIVE, \ ("vm_page_assert_xbusied: page %p busy_lock %#x not owned" \ " by me @ %s:%d", \ @@ -733,7 +736,7 @@ void vm_page_lock_assert_KBI(vm_page_t m, int a, const char *file, int line); } while (0) #define vm_page_busied(m) \ - ((m)->busy_lock != VPB_UNBUSIED) + (vm_page_busy_fetch(m) != VPB_UNBUSIED) #define vm_page_sbusy(m) do { \ if (!vm_page_trysbusy(m)) \ @@ -742,10 +745,10 @@ void vm_page_lock_assert_KBI(vm_page_t m, int a, const char *file, int line); } while (0) #define vm_page_xbusied(m) \ - (((m)->busy_lock & VPB_SINGLE_EXCLUSIVE) != 0) + ((vm_page_busy_fetch(m) & VPB_SINGLE_EXCLUSIVE) != 0) #define vm_page_busy_freed(m) \ - ((m)->busy_lock == VPB_FREED) + (vm_page_busy_fetch(m) == VPB_FREED) #define vm_page_xbusy(m) do { \ if (!vm_page_tryxbusy(m)) \ @@ -771,12 +774,17 @@ void vm_page_object_busy_assert(vm_page_t m); void vm_page_assert_pga_writeable(vm_page_t m, uint16_t bits); #define VM_PAGE_ASSERT_PGA_WRITEABLE(m, bits) \ vm_page_assert_pga_writeable(m, bits) +/* + * Claim ownership of a page's xbusy state. In non-INVARIANTS kernels this + * operation is a no-op since ownership is not tracked. In particular + * this macro does not provide any synchronization with the previous owner. + */ #define vm_page_xbusy_claim(m) do { \ u_int _busy_lock; \ \ vm_page_assert_xbusied_unchecked((m)); \ do { \ - _busy_lock = atomic_load_int(&(m)->busy_lock); \ + _busy_lock = vm_page_busy_fetch(m); \ } while (!atomic_cmpset_int(&(m)->busy_lock, _busy_lock, \ (_busy_lock & VPB_BIT_FLAGMASK) | VPB_CURTHREAD_EXCLUSIVE)); \ } while (0) From 40326c17180e46c9cb774e99c97a64ed0eb7294d Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Wed, 29 Jul 2020 21:15:06 +0000 Subject: [PATCH 251/287] add link to crypto(7) page, and drop a link to unrelated crypt(3) page.. --- share/man/man4/aesni.4 | 3 ++- share/man/man4/hifn.4 | 4 ++-- share/man/man4/man4.aarch64/armv8crypto.4 | 3 ++- share/man/man4/man4.i386/glxsb.4 | 3 ++- share/man/man4/padlock.4 | 3 ++- share/man/man4/safe.4 | 3 ++- share/man/man4/safexcel.4 | 3 ++- 7 files changed, 14 insertions(+), 8 deletions(-) diff --git a/share/man/man4/aesni.4 b/share/man/man4/aesni.4 index aacbe79cc337..08465bdf5e88 100644 --- a/share/man/man4/aesni.4 +++ b/share/man/man4/aesni.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 26, 2017 +.Dd July 29, 2020 .Dt AESNI 4 .Os .Sh NAME @@ -88,6 +88,7 @@ implementations. .Xr ipsec 4 , .Xr padlock 4 , .Xr random 4 , +.Xr crypto 7 , .Xr crypto 9 .Sh HISTORY The diff --git a/share/man/man4/hifn.4 b/share/man/man4/hifn.4 index f9952ac153ad..a9a06c1fbd91 100644 --- a/share/man/man4/hifn.4 +++ b/share/man/man4/hifn.4 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 11, 2020 +.Dd July 29, 2020 .Dt HIFN 4 .Os .Sh NAME @@ -101,11 +101,11 @@ See Contains a 7955 and supports symmetric and random number operations. .El .Sh SEE ALSO -.Xr crypt 3 , .Xr crypto 4 , .Xr intro 4 , .Xr ipsec 4 , .Xr random 4 , +.Xr crypto 7 , .Xr crypto 9 .Sh HISTORY The diff --git a/share/man/man4/man4.aarch64/armv8crypto.4 b/share/man/man4/man4.aarch64/armv8crypto.4 index 5b91049d404e..a80b0801d722 100644 --- a/share/man/man4/man4.aarch64/armv8crypto.4 +++ b/share/man/man4/man4.aarch64/armv8crypto.4 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 20, 2016 +.Dd July 29, 2020 .Dt ARMV8CRYPTO 4 .Os .Sh NAME @@ -69,6 +69,7 @@ driver registers itself to accelerate AES operations for .Xr intro 4 , .Xr ipsec 4 , .Xr random 4 , +.Xr crypto 7 , .Xr crypto 9 .Sh HISTORY The diff --git a/share/man/man4/man4.i386/glxsb.4 b/share/man/man4/man4.i386/glxsb.4 index d2a30352fe7f..c08d57906136 100644 --- a/share/man/man4/man4.i386/glxsb.4 +++ b/share/man/man4/man4.i386/glxsb.4 @@ -16,7 +16,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 8, 2008 +.Dd July 29, 2020 .Dt GLXSB 4 i386 .Os .Sh NAME @@ -73,6 +73,7 @@ device driver with AES keys of length != 128 bits. .Xr ipsec 4 , .Xr pci 4 , .Xr random 4 , +.Xr crypto 7 , .Xr crypto 9 .Sh HISTORY The diff --git a/share/man/man4/padlock.4 b/share/man/man4/padlock.4 index ad648af9d946..44963d0fd140 100644 --- a/share/man/man4/padlock.4 +++ b/share/man/man4/padlock.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 8, 2010 +.Dd July 29, 2020 .Dt PADLOCK 4 .Os .Sh NAME @@ -72,6 +72,7 @@ subsystem. .Xr intro 4 , .Xr ipsec 4 , .Xr random 4 , +.Xr crypto 7 , .Xr crypto 9 .Sh HISTORY The diff --git a/share/man/man4/safe.4 b/share/man/man4/safe.4 index 4680a9b3710f..3d5cbec03784 100644 --- a/share/man/man4/safe.4 +++ b/share/man/man4/safe.4 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\"/ -.Dd May 11, 2020 +.Dd July 29, 2020 .Dt SAFE 4 .Os .Sh NAME @@ -124,6 +124,7 @@ A faster version of the 1141. .Xr intro 4 , .Xr ipsec 4 , .Xr random 4 , +.Xr crypto 7 , .Xr crypto 9 .Sh BUGS Public key support is not implemented. diff --git a/share/man/man4/safexcel.4 b/share/man/man4/safexcel.4 index 6751570713f9..774dfddfb053 100644 --- a/share/man/man4/safexcel.4 +++ b/share/man/man4/safexcel.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 23, 2020 +.Dd July 29, 2020 .Dt SAFEXCEL 4 .Os .Sh NAME @@ -75,6 +75,7 @@ with SHA1-HMAC and SHA2-HMAC for encrypt-then-authenticate operations. .Xr crypto 4 , .Xr ipsec 4 , .Xr random 4 , +.Xr crypto 7 , .Xr geli 8 , .Xr crypto 9 .Sh HISTORY From c8597a1f9f9eba71a884e38fa2133e556105a0f4 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Wed, 29 Jul 2020 22:08:54 +0000 Subject: [PATCH 252/287] o Don't include headers from iommu.h, include them from the header consumers instead; o Order includes properly. Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25878 --- sys/dev/iommu/iommu.h | 8 -------- sys/dev/iommu/iommu_gas.c | 8 ++++---- sys/dev/ntb/ntb_hw/ntb_hw_intel.c | 2 ++ sys/dev/ntb/ntb_hw/ntb_hw_plx.c | 2 ++ sys/x86/iommu/intel_ctx.c | 10 +++++----- sys/x86/iommu/intel_drv.c | 16 ++++++++-------- sys/x86/iommu/intel_idpgtbl.c | 4 ++-- sys/x86/iommu/intel_intrmap.c | 11 ++++++----- sys/x86/iommu/intel_qi.c | 12 ++++++------ sys/x86/iommu/intel_quirks.c | 16 ++++++++-------- sys/x86/iommu/intel_utils.c | 6 +++--- 11 files changed, 46 insertions(+), 49 deletions(-) diff --git a/sys/dev/iommu/iommu.h b/sys/dev/iommu/iommu.h index cf90e7884951..e6ad0569a9ac 100644 --- a/sys/dev/iommu/iommu.h +++ b/sys/dev/iommu/iommu.h @@ -34,14 +34,6 @@ #ifndef _SYS_IOMMU_H_ #define _SYS_IOMMU_H_ -#include -#include -#include -#include -#include - -#include - /* Host or physical memory address, after translation. */ typedef uint64_t iommu_haddr_t; /* Guest or bus address, before translation. */ diff --git a/sys/dev/iommu/iommu_gas.c b/sys/dev/iommu/iommu_gas.c index 5a6e48850b5b..04d7d9667109 100644 --- a/sys/dev/iommu/iommu_gas.c +++ b/sys/dev/iommu/iommu_gas.c @@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -60,6 +59,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include +#include #include #include #include @@ -67,11 +69,9 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include -#include #include #endif +#include /* * Guest Address Space management. diff --git a/sys/dev/ntb/ntb_hw/ntb_hw_intel.c b/sys/dev/ntb/ntb_hw/ntb_hw_intel.c index 0a839157a90c..2dfe49cc1fd9 100644 --- a/sys/dev/ntb/ntb_hw/ntb_hw_intel.c +++ b/sys/dev/ntb/ntb_hw/ntb_hw_intel.c @@ -50,6 +50,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include #include diff --git a/sys/dev/ntb/ntb_hw/ntb_hw_plx.c b/sys/dev/ntb/ntb_hw/ntb_hw_plx.c index e1a65178be81..f3d8af4971a4 100644 --- a/sys/dev/ntb/ntb_hw/ntb_hw_plx.c +++ b/sys/dev/ntb/ntb_hw/ntb_hw_plx.c @@ -42,6 +42,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include #include diff --git a/sys/x86/iommu/intel_ctx.c b/sys/x86/iommu/intel_ctx.c index edd59e5f2477..234a920d1ded 100644 --- a/sys/x86/iommu/intel_ctx.c +++ b/sys/x86/iommu/intel_ctx.c @@ -58,18 +58,18 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include +#include +#include #include #include #include #include -#include -#include #include -#include #include -#include +#include #include -#include static MALLOC_DEFINE(M_DMAR_CTX, "dmar_ctx", "Intel DMAR Context"); static MALLOC_DEFINE(M_DMAR_DOMAIN, "dmar_dom", "Intel DMAR Domain"); diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c index 9ae8e37d4fa0..17fea13d1387 100644 --- a/sys/x86/iommu/intel_drv.c +++ b/sys/x86/iommu/intel_drv.c @@ -54,11 +54,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include -#include -#include -#include #include #include #include @@ -66,11 +61,16 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include -#include +#include +#include +#include #include #include +#include +#include +#include +#include +#include #include #ifdef DEV_APIC diff --git a/sys/x86/iommu/intel_idpgtbl.c b/sys/x86/iommu/intel_idpgtbl.c index d85abefc54c4..4c151ffffef8 100644 --- a/sys/x86/iommu/intel_idpgtbl.c +++ b/sys/x86/iommu/intel_idpgtbl.c @@ -58,15 +58,15 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include #include #include #include -#include #include -#include +#include #include static int domain_unmap_buf_locked(struct dmar_domain *domain, diff --git a/sys/x86/iommu/intel_intrmap.c b/sys/x86/iommu/intel_intrmap.c index d2bce59c4c2e..e95d8a8090b3 100644 --- a/sys/x86/iommu/intel_intrmap.c +++ b/sys/x86/iommu/intel_intrmap.c @@ -40,24 +40,25 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include -#include -#include #include #include #include #include #include +#include +#include +#include +#include #include #include #include -#include #include -#include +#include #include -#include #include static struct dmar_unit *dmar_ir_find(device_t src, uint16_t *rid, diff --git a/sys/x86/iommu/intel_qi.c b/sys/x86/iommu/intel_qi.c index 5377ac448df8..ab2c4d4e80fc 100644 --- a/sys/x86/iommu/intel_qi.c +++ b/sys/x86/iommu/intel_qi.c @@ -45,20 +45,20 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include -#include -#include #include #include #include #include #include +#include +#include +#include +#include +#include #include #include -#include #include -#include +#include #include static bool diff --git a/sys/x86/iommu/intel_quirks.c b/sys/x86/iommu/intel_quirks.c index d0eac82e7298..1a025b3419eb 100644 --- a/sys/x86/iommu/intel_quirks.c +++ b/sys/x86/iommu/intel_quirks.c @@ -46,10 +46,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include -#include -#include #include #include #include @@ -57,12 +53,16 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include -#include +#include +#include +#include #include -#include #include +#include +#include +#include +#include +#include typedef void (*dmar_quirk_cpu_fun)(struct dmar_unit *); diff --git a/sys/x86/iommu/intel_utils.c b/sys/x86/iommu/intel_utils.c index 7e89465240af..43a00428c46c 100644 --- a/sys/x86/iommu/intel_utils.c +++ b/sys/x86/iommu/intel_utils.c @@ -51,7 +51,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -59,14 +58,15 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include #include #include #include -#include #include -#include +#include #include u_int From ea83d07e82995d58a4fbe9a810e95ff815939671 Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Wed, 29 Jul 2020 22:58:08 +0000 Subject: [PATCH 253/287] Add support for ext_pgs mbufs to nfsrvd_readdir() and nfsrvd_readdirplus(). This patch code that optionally (based on ND_TLS, never set yet) generates readdir replies in ext_pgs mbufs. To trim the list back, a new function that is ext_pgs aware called nfsm_trimtrailing() replaces newnfs_trimtrailing(). newnfs_trimtrailing() is no longer used, but will be removed in a future commit, since its removal does modify the internal kpi between the NFS modules. This is another in the series of commits that add support to the NFS client and server for building RPC messages in ext_pgs mbufs with anonymous pages. This is useful so that the entire mbuf list does not need to be copied before calling sosend() when NFS over TLS is enabled. Use of ext_pgs mbufs will not be enabled until the kernel RPC is updated to handle TLS. --- sys/fs/nfsserver/nfs_nfsdport.c | 76 ++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 34066585c3a3..eb971d73d534 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -144,6 +144,8 @@ static int nfsrv_dsremove(struct vnode *, char *, struct ucred *, NFSPROC_T *); static int nfsrv_dssetacl(struct vnode *, struct acl *, struct ucred *, NFSPROC_T *); static int nfsrv_pnfsstatfs(struct statfs *, struct mount *); +static void nfsm_trimtrailing(struct nfsrv_descript *, struct mbuf *, + char *, int, int); int nfs_pnfsio(task_fn_t *, void *); @@ -2042,6 +2044,17 @@ nfsrvd_readdir(struct nfsrv_descript *nd, int isdgram, } vput(vp); + /* + * If cnt > MCLBYTES and the reply will not be saved, use + * ext_pgs mbufs for TLS. + * For NFSv4.0, we do not know for sure if the reply will + * be saved, so do not use ext_pgs mbufs for NFSv4.0. + */ + if (cnt > MCLBYTES && siz > MCLBYTES && + (nd->nd_flag & (ND_TLS | ND_EXTPG | ND_SAVEREPLY)) == ND_TLS && + (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4) + nd->nd_flag |= ND_EXTPG; + /* * dirlen is the size of the reply, including all XDR and must * not exceed cnt. For NFSv2, RFC1094 didn't clearly indicate @@ -2146,6 +2159,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram, struct mount *mp, *new_mp; uint64_t mounted_on_fileno; struct thread *p = curthread; + int bextpg0, bextpg1, bextpgsiz0, bextpgsiz1; if (nd->nd_repstat) { nfsrv_postopattr(nd, getret, &at); @@ -2358,12 +2372,28 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram, vput(nvp); } + /* + * If the reply is likely to exceed MCLBYTES and the reply will + * not be saved, use ext_pgs mbufs for TLS. + * It is difficult to predict how large each entry will be and + * how many entries have been read, so just assume the directory + * entries grow by a factor of 4 when attributes are included. + * For NFSv4.0, we do not know for sure if the reply will + * be saved, so do not use ext_pgs mbufs for NFSv4.0. + */ + if (cnt > MCLBYTES && siz > MCLBYTES / 4 && + (nd->nd_flag & (ND_TLS | ND_EXTPG | ND_SAVEREPLY)) == ND_TLS && + (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4) + nd->nd_flag |= ND_EXTPG; + /* * Save this position, in case there is an error before one entry * is created. */ mb0 = nd->nd_mb; bpos0 = nd->nd_bpos; + bextpg0 = nd->nd_bextpg; + bextpgsiz0 = nd->nd_bextpgsiz; /* * Fill in the first part of the reply. @@ -2385,6 +2415,8 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram, */ mb1 = nd->nd_mb; bpos1 = nd->nd_bpos; + bextpg1 = nd->nd_bextpg; + bextpgsiz1 = nd->nd_bextpgsiz; /* Loop through the records and build reply */ entrycnt = 0; @@ -2401,6 +2433,8 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram, */ mb1 = nd->nd_mb; bpos1 = nd->nd_bpos; + bextpg1 = nd->nd_bextpg; + bextpgsiz1 = nd->nd_bextpgsiz; /* * For readdir_and_lookup get the vnode using @@ -2626,11 +2660,11 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram, if (!nd->nd_repstat && entrycnt == 0) nd->nd_repstat = NFSERR_TOOSMALL; if (nd->nd_repstat) { - newnfs_trimtrailing(nd, mb0, bpos0); + nfsm_trimtrailing(nd, mb0, bpos0, bextpg0, bextpgsiz0); if (nd->nd_flag & ND_NFSV3) nfsrv_postopattr(nd, getret, &at); } else - newnfs_trimtrailing(nd, mb1, bpos1); + nfsm_trimtrailing(nd, mb1, bpos1, bextpg1, bextpgsiz1); eofflag = 0; } else if (cpos < cend) eofflag = 0; @@ -6418,6 +6452,44 @@ nfsvno_listxattr(struct vnode *vp, uint64_t cookie, struct ucred *cred, return (error); } +/* + * Trim trailing data off the mbuf list being built. + */ +static void +nfsm_trimtrailing(struct nfsrv_descript *nd, struct mbuf *mb, char *bpos, + int bextpg, int bextpgsiz) +{ + vm_page_t pg; + int fullpgsiz, i; + + if (mb->m_next != NULL) { + m_freem(mb->m_next); + mb->m_next = NULL; + } + if ((mb->m_flags & M_EXTPG) != 0) { + /* First, get rid of any pages after this position. */ + for (i = mb->m_epg_npgs - 1; i > bextpg; i--) { + pg = PHYS_TO_VM_PAGE(mb->m_epg_pa[i]); + vm_page_unwire_noq(pg); + vm_page_free(pg); + } + mb->m_epg_npgs = bextpg + 1; + if (bextpg == 0) + fullpgsiz = PAGE_SIZE - mb->m_epg_1st_off; + else + fullpgsiz = PAGE_SIZE; + mb->m_epg_last_len = fullpgsiz - bextpgsiz; + mb->m_len = m_epg_pagelen(mb, 0, mb->m_epg_1st_off); + for (i = 1; i < mb->m_epg_npgs; i++) + mb->m_len += m_epg_pagelen(mb, i, 0); + nd->nd_bextpgsiz = bextpgsiz; + nd->nd_bextpg = bextpg; + } else + mb->m_len = bpos - mtod(mb, char *); + nd->nd_mb = mb; + nd->nd_bpos = bpos; +} + extern int (*nfsd_call_nfsd)(struct thread *, struct nfssvc_args *); /* From adeebf4cd47c3e85155d92f386bda5e519b75ab2 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Wed, 29 Jul 2020 23:21:56 +0000 Subject: [PATCH 254/287] regex(3): Interpret many escaped ordinary characters as EESCAPE In IEEE 1003.1-2008 [1] and earlier revisions, BRE/ERE grammar allows for any character to be escaped, but "ORD_CHAR preceded by an unescaped character [gives undefined results]". Historically, we've interpreted an escaped ordinary character as the ordinary character itself. This becomes problematic when some extensions give special meanings to an otherwise ordinary character (e.g. GNU's \b, \s, \w), meaning we may have two different valid interpretations of the same sequence. To make this easier to deal with and given that the standard calls this undefined, we should throw an error (EESCAPE) if we run into this scenario to ease transition into a state where some escaped ordinaries are blessed with a special meaning -- it will either error out or have extended behavior, rather than have two entirely different versions of undefined behavior that leave the consumer of regex(3) guessing as to what behavior will be used or leaving them with false impressions. This change bumps the symbol version of regcomp to FBSD_1.6 and provides the old escape semantics for legacy applications, just in case one has an older application that would immediately turn into a pumpkin because of an extraneous escape that's embedded or otherwise critical to its operation. This is the final piece needed before enhancing libregex with GNU extensions and flipping the switch on bsdgrep. [1] http://pubs.opengroup.org/onlinepubs/9699919799.2016edition/ PR: 229925 (exp-run, courtesy of antoine) Differential Revision: https://reviews.freebsd.org/D10510 --- .../netbsd-tests/lib/libc/regex/data/meta.in | 4 +- .../lib/libc/regex/data/subexp.in | 2 +- lib/libc/regex/Symbol.map | 5 +- lib/libc/regex/regcomp.c | 119 +++++++++++++++--- 4 files changed, 110 insertions(+), 20 deletions(-) diff --git a/contrib/netbsd-tests/lib/libc/regex/data/meta.in b/contrib/netbsd-tests/lib/libc/regex/data/meta.in index 4533d3591bc6..eb24075aea62 100644 --- a/contrib/netbsd-tests/lib/libc/regex/data/meta.in +++ b/contrib/netbsd-tests/lib/libc/regex/data/meta.in @@ -4,7 +4,9 @@ a[bc]d & abd abd a\*c & a*c a*c a\\b & a\b a\b a\\\*b & a\*b a\*b -a\bc & abc abc +# Begin FreeBSD +a\bc &C EESCAPE +# End FreeBSD a\ &C EESCAPE a\\bc & a\bc a\bc \{ bC BADRPT diff --git a/contrib/netbsd-tests/lib/libc/regex/data/subexp.in b/contrib/netbsd-tests/lib/libc/regex/data/subexp.in index d3efe2eab270..e3d376bb7cb3 100644 --- a/contrib/netbsd-tests/lib/libc/regex/data/subexp.in +++ b/contrib/netbsd-tests/lib/libc/regex/data/subexp.in @@ -12,7 +12,7 @@ a(b+)c - abbbc abbbc bbb a(b*)c - ac ac @c (a|ab)(bc([de]+)f|cde) - abcdef abcdef a,bcdef,de # Begin FreeBSD -a\(b\|c\)d b ab|cd ab|cd b|c +a\(b|c\)d b ab|cd ab|cd b|c # End FreeBSD # the regression tester only asks for 9 subexpressions a(b)(c)(d)(e)(f)(g)(h)(i)(j)k - abcdefghijk abcdefghijk b,c,d,e,f,g,h,i,j diff --git a/lib/libc/regex/Symbol.map b/lib/libc/regex/Symbol.map index 5821f62b6430..1da7b81ba11b 100644 --- a/lib/libc/regex/Symbol.map +++ b/lib/libc/regex/Symbol.map @@ -3,8 +3,11 @@ */ FBSD_1.0 { - regcomp; regerror; regexec; regfree; }; + +FBSD_1.6 { + regcomp; +}; diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c index 5e772c21d381..28bad13ac365 100644 --- a/lib/libc/regex/regcomp.c +++ b/lib/libc/regex/regcomp.c @@ -102,11 +102,14 @@ struct parse { sopno pend[NPAREN]; /* -> ) ([0] unused) */ bool allowbranch; /* can this expression branch? */ bool bre; /* convenience; is this a BRE? */ + int pflags; /* other parsing flags -- legacy escapes? */ bool (*parse_expr)(struct parse *, struct branchc *); void (*pre_parse)(struct parse *, struct branchc *); void (*post_parse)(struct parse *, struct branchc *); }; +#define PFLAG_LEGACY_ESC 0x00000001 + /* ========= begin header generated by ./mkh ========= */ #ifdef __cplusplus extern "C" { @@ -132,6 +135,7 @@ static void p_b_cclass(struct parse *p, cset *cs); static void p_b_eclass(struct parse *p, cset *cs); static wint_t p_b_symbol(struct parse *p); static wint_t p_b_coll_elem(struct parse *p, wint_t endc); +static bool may_escape(struct parse *p, const wint_t ch); static wint_t othercase(wint_t ch); static void bothcases(struct parse *p, wint_t ch); static void ordinary(struct parse *p, wint_t ch); @@ -199,22 +203,10 @@ static char nuls[10]; /* place to point scanner in event of error */ /* Macro used by computejump()/computematchjump() */ #define MIN(a,b) ((a)<(b)?(a):(b)) -/* - - regcomp - interface for parser and compilation - = extern int regcomp(regex_t *, const char *, int); - = #define REG_BASIC 0000 - = #define REG_EXTENDED 0001 - = #define REG_ICASE 0002 - = #define REG_NOSUB 0004 - = #define REG_NEWLINE 0010 - = #define REG_NOSPEC 0020 - = #define REG_PEND 0040 - = #define REG_DUMP 0200 - */ -int /* 0 success, otherwise REG_something */ -regcomp(regex_t * __restrict preg, +static int /* 0 success, otherwise REG_something */ +regcomp_internal(regex_t * __restrict preg, const char * __restrict pattern, - int cflags) + int cflags, int pflags) { struct parse pa; struct re_guts *g; @@ -273,6 +265,7 @@ regcomp(regex_t * __restrict preg, p->end = p->next + len; p->error = 0; p->ncsalloc = 0; + p->pflags = pflags; for (i = 0; i < NPAREN; i++) { p->pbegin[i] = 0; p->pend[i] = 0; @@ -345,6 +338,43 @@ regcomp(regex_t * __restrict preg, return(p->error); } +/* + - regcomp - interface for parser and compilation + = extern int regcomp(regex_t *, const char *, int); + = #define REG_BASIC 0000 + = #define REG_EXTENDED 0001 + = #define REG_ICASE 0002 + = #define REG_NOSUB 0004 + = #define REG_NEWLINE 0010 + = #define REG_NOSPEC 0020 + = #define REG_PEND 0040 + = #define REG_DUMP 0200 + */ +int /* 0 success, otherwise REG_something */ +regcomp(regex_t * __restrict preg, + const char * __restrict pattern, + int cflags) +{ + + return (regcomp_internal(preg, pattern, cflags, 0)); +} + +#ifndef LIBREGEX +/* + * Legacy interface that requires more lax escaping behavior. + */ +int +freebsd12_regcomp(regex_t * __restrict preg, + const char * __restrict pattern, + int cflags, int pflags) +{ + + return (regcomp_internal(preg, pattern, cflags, PFLAG_LEGACY_ESC)); +} + +__sym_compat(regcomp, freebsd12_regcomp, FBSD_1.0); +#endif /* !LIBREGEX */ + /* - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op, - return whether we should terminate or not @@ -435,7 +465,10 @@ p_ere_exp(struct parse *p, struct branchc *bc) EMIT(OEOW, 0); break; default: - ordinary(p, wc); + if (may_escape(p, wc)) + ordinary(p, wc); + else + SETERROR(REG_EESCAPE); break; } break; @@ -797,7 +830,10 @@ p_simp_re(struct parse *p, struct branchc *bc) return (false); /* Definitely not $... */ p->next--; wc = WGETNEXT(); - ordinary(p, wc); + if ((c & BACKSL) == 0 || may_escape(p, wc)) + ordinary(p, wc); + else + SETERROR(REG_EESCAPE); break; } @@ -1094,6 +1130,55 @@ p_b_coll_elem(struct parse *p, return(0); } +/* + - may_escape - determine whether 'ch' is escape-able in the current context + == static int may_escape(struct parse *p, const wint_t ch) + */ +static bool +may_escape(struct parse *p, const wint_t ch) +{ + + if ((p->pflags & PFLAG_LEGACY_ESC) != 0) + return (true); + if (isalpha(ch) || ch == '\'' || ch == '`') + return (false); + return (true); +#ifdef NOTYET + /* + * Build a whitelist of characters that may be escaped to produce an + * ordinary in the current context. This assumes that these have not + * been otherwise interpreted as a special character. Escaping an + * ordinary character yields undefined results according to + * IEEE 1003.1-2008. Some extensions (notably, some GNU extensions) take + * advantage of this and use escaped ordinary characters to provide + * special meaning, e.g. \b, \B, \w, \W, \s, \S. + */ + switch(ch) { + case '|': + case '+': + case '?': + /* The above characters may not be escaped in BREs */ + if (!(p->g->cflags®_EXTENDED)) + return (false); + /* Fallthrough */ + case '(': + case ')': + case '{': + case '}': + case '.': + case '[': + case ']': + case '\\': + case '*': + case '^': + case '$': + return (true); + default: + return (false); + } +#endif +} + /* - othercase - return the case counterpart of an alphabetic == static wint_t othercase(wint_t ch); From 0f70a1489d0701e4c1840d13d4ed89e7bf624eac Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Wed, 29 Jul 2020 23:24:32 +0000 Subject: [PATCH 255/287] Properly handle a closed TLS socket with pending receive data. If the remote end closes a TLS socket and the socket buffer still contains not-yet-decrypted TLS records but no decrypted TLS records, soreceive needs to block or fail with EWOULDBLOCK. Previously it was trying to return data and dereferencing a NULL pointer. Reviewed by: np Sponsored by: Chelsio Differential Revision: https://reviews.freebsd.org/D25838 --- sys/kern/uipc_socket.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 15a8b1439463..ac138679c850 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1965,12 +1965,17 @@ soreceive_generic(struct socket *so, struct sockaddr **psa, struct uio *uio, } SOCKBUF_LOCK_ASSERT(&so->so_rcv); if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { - if (m == NULL && so->so_rcv.sb_tlsdcc == 0 && + if (m != NULL) + goto dontblock; +#ifdef KERN_TLS + else if (so->so_rcv.sb_tlsdcc == 0 && so->so_rcv.sb_tlscc == 0) { +#else + else { +#endif SOCKBUF_UNLOCK(&so->so_rcv); goto release; - } else - goto dontblock; + } } for (; m != NULL; m = m->m_next) if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) { From d2090a40d02b9d93d1d8ac3d0f7419f9b3302ed7 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Wed, 29 Jul 2020 23:59:35 +0000 Subject: [PATCH 256/287] UPDATING / RELNOTES: Document new regcomp(3) behavior This is a breaking change that had a not-insignificant impact in ports, it is worth documenting it well. --- RELNOTES | 4 ++++ UPDATING | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/RELNOTES b/RELNOTES index c78f92c68977..d34c504ca760 100644 --- a/RELNOTES +++ b/RELNOTES @@ -10,6 +10,10 @@ newline. Entries should be separated by a newline. Changes to this file should not be MFCed. +r363679: + Applications using regex(3), e.g. sed/grep, will no longer accept + redundant escapes for most ordinary characters. + r363253: SCTP support has been removed from GENERIC kernel configurations. The SCTP stack is now built as sctp.ko and can be dynamically loaded. diff --git a/UPDATING b/UPDATING index ee69605d9f28..be57064412b7 100644 --- a/UPDATING +++ b/UPDATING @@ -26,6 +26,13 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW: disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20200729: + r363679 has redefined some undefined behavior in regcomp(3); notably, + extraneous escapes of most ordinary characters will no longer be + accepted. An exp-run has identified all of the problems with this in + ports, but other non-ports software may need extra escapes removed to + continue to function. + 20200627: A new implementation of bc and dc has been imorted in r362681. This implementation corrects non-conformant behavior of the previous bc From 1b778ba2609fcc754b217a33a9fdbbdd2b7b4ed5 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 30 Jul 2020 00:52:37 +0000 Subject: [PATCH 257/287] Fix a logic error in uipc_ready_scan(). When processing the last record in a socket buffer, take care to avoid a NULL pointer dereference when advancing the record iterator. Reported by: syzbot+6a689cc9c27bd265237a@syzkaller.appspotmail.com Fixes: r359778 MFC after: 1 week Sponsored by: The FreeBSD Foundation --- sys/kern/uipc_usrreq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index bd9447d0fb55..efd592f82fe2 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -1279,7 +1279,8 @@ uipc_ready_scan(struct socket *so, struct mbuf *m, int count, int *errorp) mb = mb->m_next; if (mb == NULL) { mb = n; - n = mb->m_nextpkt; + if (mb != NULL) + n = mb->m_nextpkt; } } } From aa6ea9b6ce25a7f55123b97c55a40ac1d6e36f62 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Thu, 30 Jul 2020 00:53:56 +0000 Subject: [PATCH 258/287] remove some long abandonded serial drivers (cy, rc, rp) since 2008 Reviewed by: phk (earlier version) Reviewed by: emaste (earlier version) Reviewed by: bcr (earlier version) Reviewed by: zeising (earlier version) Differential Revision: https://reviews.freebsd.org/D25874 --- ObsoleteFiles.inc | 5 + share/man/man4/Makefile | 3 - share/man/man4/cy.4 | 257 ----- share/man/man4/rc.4 | 124 --- share/man/man4/rp.4 | 195 ---- sys/conf/files | 7 - sys/dev/cy/cy.c | 2242 --------------------------------------- sys/dev/cy/cy_isa.c | 152 --- sys/dev/cy/cy_pci.c | 194 ---- sys/dev/cy/cyreg.h | 77 -- sys/dev/cy/cyvar.h | 38 - sys/dev/rc/rc.c | 1314 ----------------------- sys/dev/rc/rcreg.h | 72 -- sys/dev/rp/rp.c | 1113 ------------------- sys/dev/rp/rp_isa.c | 508 --------- sys/dev/rp/rp_pci.c | 368 ------- sys/dev/rp/rpreg.h | 1033 ------------------ sys/dev/rp/rpvar.h | 76 -- sys/modules/rc/Makefile | 8 - sys/modules/rp/Makefile | 8 - 20 files changed, 5 insertions(+), 7789 deletions(-) delete mode 100644 share/man/man4/cy.4 delete mode 100644 share/man/man4/rc.4 delete mode 100644 share/man/man4/rp.4 delete mode 100644 sys/dev/cy/cy.c delete mode 100644 sys/dev/cy/cy_isa.c delete mode 100644 sys/dev/cy/cy_pci.c delete mode 100644 sys/dev/cy/cyreg.h delete mode 100644 sys/dev/cy/cyvar.h delete mode 100644 sys/dev/rc/rc.c delete mode 100644 sys/dev/rc/rcreg.h delete mode 100644 sys/dev/rp/rp.c delete mode 100644 sys/dev/rp/rp_isa.c delete mode 100644 sys/dev/rp/rp_pci.c delete mode 100644 sys/dev/rp/rpreg.h delete mode 100644 sys/dev/rp/rpvar.h delete mode 100644 sys/modules/rc/Makefile delete mode 100644 sys/modules/rp/Makefile diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 9e2baf525f22..6db60ca13866 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -36,6 +36,11 @@ # xargs -n1 | sort | uniq -d; # done +# 20200729: remove long expired serial drivers +OLD_FILES+=usr/share/man/man4/cy.4.gz +OLD_FILES+=usr/share/man/man4/rc.4.gz +OLD_FILES+=usr/share/man/man4/rp.4.gz + # 20200715: rework of devstat(9) man page OLD_FILES+=usr/share/man/man9/devstat_add_entry.9.gz diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index fe715f48288d..9049f3feb5e3 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -121,7 +121,6 @@ MAN= aac.4 \ cxgb.4 \ cxgbe.4 \ cxgbev.4 \ - cy.4 \ cyapa.4 \ da.4 \ dc.4 \ @@ -434,7 +433,6 @@ MAN= aac.4 \ ${_qlnxe.4} \ ral.4 \ random.4 \ - rc.4 \ rctl.4 \ re.4 \ rgephy.4 \ @@ -442,7 +440,6 @@ MAN= aac.4 \ rl.4 \ rndtest.4 \ route.4 \ - rp.4 \ rtwn.4 \ rtwnfw.4 \ rtwn_pci.4 \ diff --git a/share/man/man4/cy.4 b/share/man/man4/cy.4 deleted file mode 100644 index c0c807286f1e..000000000000 --- a/share/man/man4/cy.4 +++ /dev/null @@ -1,257 +0,0 @@ -.\" Copyright (c) 1990, 1991 The Regents of the University of California. -.\" All rights reserved. -.\" -.\" This code is derived from software contributed to Berkeley by -.\" the Systems Programming Group of the University of Utah Computer -.\" Science Department. -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" from: @(#)dca.4 5.2 (Berkeley) 3/27/91 -.\" from: com.4,v 1.1 1993/08/06 11:19:07 cgd Exp -.\" from: sio.4,v 1.16 1995/06/26 06:05:30 bde Exp $ -.\" $FreeBSD$ -.\" -.Dd May 24, 2004 -.Dt CY 4 -.Os -.Sh NAME -.Nm cy -.Nd Cyclades Cyclom-Y serial driver -.Sh SYNOPSIS -For one ISA card: -.Bd -ragged -offset indent -compact -.Cd "device cy" -.Pp -In -.Pa /boot/device.hints : -.Cd hint.cy.0.at="isa" -.Cd hint.cy.0.irq="10" -.Cd hint.cy.0.maddr="0xd4000" -.Cd hint.cy.0.msize="0x2000" -.Ed -.Pp -For two ISA cards: -.Bd -ragged -offset indent -compact -.Cd "device cy" -.Pp -In -.Pa /boot/device.hints : -.Cd hint.cy.0.at="isa" -.Cd hint.cy.0.irq="10" -.Cd hint.cy.0.maddr="0xd4000" -.Cd hint.cy.0.msize="0x2000" -.Cd hint.cy.1.at="isa" -.Cd hint.cy.1.irq="11" -.Cd hint.cy.1.maddr="0xd6000" -.Cd hint.cy.1.msize="0x2000" -.Ed -.Pp -For PCI cards: -.Bd -ragged -offset indent -compact -.Cd "device cy" -.Cd "options CY_PCI_FASTINTR" -.Pp -No lines are required in -.Pa /boot/device.hints -for PCI cards. -.Ed -.Pp -Minor numbering: -.Bd -literal -offset indent -compact -0b\fIMMMMMMMMMMMMMMMMxxxxxxxxOLIMMMMM\fR - call\fBO\fRut - \fBL\fRock - \fBI\fRnitial - \fBMMMMMMMMMMMMMMMM MMMMMM\fRinor -.Ed -.Sh DESCRIPTION -The -.Nm -driver provides support for Cirrus Logic CD1400-based -.Tn EIA -.Tn RS-232C -.Pf ( Tn CCITT -.Tn V.24 ) -communications interfaces (ports) on Cyclades Cyclom-Y boards. -Each CD1400 provides 4 ports. -Cyclom-Y boards with various numbers of CD1400's are available. -This driver supports up to 8 CD1400's (32 ports) per board. -.Pp -Input and output for each line may set independently -to the following speeds: -50, 75, 110, 134.5, 150, 300, 600, 1200, 1800, 2400, 4800, 9600, -19200, 38400, 57600, or 115200 bps. -Other speeds of up to 150000 are supported by the termios interface -but not by the sgttyb compatibility interface. -The CD1400 is not fast enough to handle speeds above 115200 bps -effectively. -It can transmit on a single line at slightly more than 115200 bps, -but when 4 lines are active in both directions its limit is about -90000 bps on each line. -.\" XXX the following should be true for all serial drivers and -.\" should not be repeated in the man pages for all serial drivers. -.\" It was copied from sio.4. The only change was s/sio/cy/g. -.Pp -Serial ports controlled by the -.Nm -driver can be used for both `callin' and `callout'. -For each port there is a callin device and a callout device. -The minor number of the callout device is 128 higher -than that of the corresponding callin port. -The callin device is general purpose. -Processes opening it normally wait for carrier -and for the callout device to become inactive. -The callout device is used to steal the port from -processes waiting for carrier on the callin device. -Processes opening it do not wait for carrier -and put any processes waiting for carrier on the callin device into -a deeper sleep so that they do not conflict with the callout session. -The callout device is abused for handling programs that are supposed -to work on general ports and need to open the port without waiting -but are too stupid to do so. -.Pp -The -.Nm -driver also supports an initial-state and a lock-state control -device for each of the callin and the callout "data" devices. -The minor number of the initial-state device is 32 higher -than that of the corresponding data device. -The minor number of the lock-state device is 64 higher -than that of the corresponding data device. -The termios settings of a data device are copied -from those of the corresponding initial-state device -on first opens and are not inherited from previous opens. -Use -.Xr stty 1 -in the normal way on the initial-state devices to program -initial termios states suitable for your setup. -.Pp -The lock termios state acts as flags to disable changing -the termios state. -E.g., to lock a flag variable such as -CRTSCTS, use -.Em "stty crtscts" -on the lock-state device. -Speeds and special characters -may be locked by setting the corresponding value in the lock-state -device to any nonzero value. -.Pp -Correct programs talking to correctly wired external devices -work with almost arbitrary initial states and almost no locking, -but other setups may benefit from changing some of the default -initial state and locking the state. -In particular, the initial states for non (POSIX) standard flags -should be set to suit the devices attached and may need to be -locked to prevent buggy programs from changing them. -E.g., CRTSCTS should be locked on for devices that support -RTS/CTS handshaking at all times and off for devices that do not -support it at all. -CLOCAL should be locked on for devices -that do not support carrier. -HUPCL may be locked off if you do not -want to hang up for some reason. -In general, very bad things happen -if something is locked to the wrong state, and things should not -be locked for devices that support more than one setting. -The -CLOCAL flag on callin ports should be locked off for logins -to avoid certain security holes, but this needs to be done by -getty if the callin port is used for anything else. -.Ss Kernel Configuration Options -The -.Em CY_PCI_FASTINTR -option should be used to avoid suboptimal interrupt handling for -PCI Cyclades boards. -The PCI BIOS must be configured with the -.Nm -interrupt not shared with any other active device -for this option to work. -This option is not the default because it is currently harmful in -certain cases where it does not work. -.Sh FILES -.\" XXX more cloning: s/d/c/g and add a ? for the card number. -.Bl -tag -width /dev/ttyic?? -compact -.It Pa /dev/ttyc?? -for callin ports -.It Pa /dev/ttyic?? -.It Pa /dev/ttylc?? -corresponding callin initial-state and lock-state devices -.Pp -.\" XXX more cloning: s/a/c/g. No consistency :-(. -.It Pa /dev/cuac?? -for callout ports -.It Pa /dev/cuaic?? -.It Pa /dev/cualc?? -corresponding callout initial-state and lock-state devices -.El -.Pp -.Bl -tag -width /etc/rc.serial -compact -.It Pa /etc/rc.serial -examples of setting the initial-state and lock-state devices -.El -.Pp -The first question mark in these device names is short for the -card number -(a decimal number between 0 and 65535 inclusive). -The second question mark is short for the port number -(a letter in the range [0-9a-v]). -.Sh DIAGNOSTICS -.Bl -diag -.\" XXX back to s/sio/cy/g. -.It cy%d: silo overflow. -Problem in the interrupt handler. -.El -.Bl -diag -.It cy%d: interrupt-level buffer overflow. -Problem in the bottom half of the driver. -.El -.Bl -diag -.It cy%d: tty-level buffer overflow. -Problem in the application. -Input has arrived faster than the given module could process it -and some has been lost. -.El -.\" .Bl -diag -.\" .It sio%d: reduced fifo trigger level to %d. -.\" Attempting to avoid further silo overflows. -.\" .El -.Sh SEE ALSO -.Xr stty 1 , -.Xr termios 4 , -.Xr tty 4 , -.Xr comcontrol 8 , -.Xr pstat 8 -.Sh HISTORY -The -.Nm -driver is derived from the -.Nm sio -driver and the -.Nx -.Nm -driver and is -.Ud -.Sh BUGS -Serial consoles are not implemented. diff --git a/share/man/man4/rc.4 b/share/man/man4/rc.4 deleted file mode 100644 index 95bcae6c3981..000000000000 --- a/share/man/man4/rc.4 +++ /dev/null @@ -1,124 +0,0 @@ -.\" -.\" Copyright (c) 2004 Tom Rhodes -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $FreeBSD$ -.\" -.Dd March 18, 2005 -.Dt RC 4 -.Os -.Sh NAME -.Nm rc -.Nd RISCom/8 multiport card -.Sh SYNOPSIS -.Cd device isa -.Cd device rc -.Sh DESCRIPTION -The -.Tn RISCom/8 -is an eight port -.Tn ISA -.Tn RS-232C -communications multiplexer with a built in -.Tn RISC -processor. -It uses a block of sixteen -.Tn I/O -ports in the range 0x200 to 0x3f0 selectable by on-board -switches or jumpers. -The block must be aligned on a sixteen port boundary. -The jumper-selectable hardware interrupt level may be set to -be detected during system -initialization using settings found in the -.Pa /boot/device.hints -file. -.Pp -This driver is mostly based on the Cirrus Logic CL-CD180 driver. -.Sh HARDWARE -The -.Nm -driver provides support for the -.Tn SDL -Communications -.Tn RISCom/8 -boards. -.Sh DIAGNOSTICS -The following driver specific error messages -may be reported: -.Bl -diag -.It "rc%d channel%d: interrupt-level buffer overflow" -An internal buffer overflow error has occurred on -the listed channel. -The -.Nm -driver will need to be reloaded to correct this. -.It "rc%d: Bad char chan %d" -The channel has obtained a bad set of characters. -.It "rc%d: Got extra chars chan %d" -The -.Nm -driver got more characters than expected on the channel shown. -.It "rc%d: data mismatch chan %d ptr %d (%d != %d)" -Data sent from channel -.Ar %d -to the rx buffer was different then expected. -.It "rc%d: channel %d command timeout, rc.c line: %d" -A command timeout has occurred on the channel, the -.Pa src/sys/dev/rc/rc.c -file can be consulted for more information. -.El -.Sh SEE ALSO -.Xr tty 1 , -.Xr ttyname 3 , -.Xr tty 4 , -.Xr device.hints 5 , -.Xr comcontrol 8 , -.Xr getty 8 , -.Xr mutex 9 , -.Xr splx 9 -.Pp -.Pa http://www.sdlcomm.com -.Sh HISTORY -The -.Nm -driver first appeared in -.Fx 2.0.5 . -This manual page first appeared in -.Fx 5.3 . -.Sh AUTHORS -This manual page was written by -.An Tom Rhodes Aq Mt trhodes@FreeBSD.org . -.Sh BUGS -The -.Nm -driver code still uses the -.Xr spl 9 -functions. -These should be replaced by -.Xr mutex 9 -functions. -.Pp -The various -.Fn ttyld_* -functions should be documented. diff --git a/share/man/man4/rp.4 b/share/man/man4/rp.4 deleted file mode 100644 index d8a130c810b3..000000000000 --- a/share/man/man4/rp.4 +++ /dev/null @@ -1,195 +0,0 @@ -.\" Copyright (c) 1995 Comtrol, Inc. -.\" All rights reserved. -.\" -.\" $FreeBSD$ -.Dd November 15, 1995 -.Dt RP 4 -.Os -.Sh NAME -.Nm rp -.Nd "driver for Comtrol RocketPort Intelligent Serial Port Cards" -.Sh SYNOPSIS -.Cd "device rp" -.Pp -For ISA cards, you must specify the port address in -.Pa /boot/device.hints : -.Cd hint.rp.0.at="isa" -.Cd hint.rp.0.port="0x100" -.Sh DESCRIPTION -This driver provides a kernel device driver for the -.Tn RocketPort -and -.Tn RocketPort RA -serial boards. -These boards provide 8, 16, or 32 high-speed serial ports -while requiring only 68 bytes of I/O space for all 8, 16, -or 32 ports, and do not require an interrupt channel. -This driver supports up to four -.Tn RocketPort -or -.Tn RocketPort RA -boards in one machine simultaneously. -If you are using four 32 port -.Tn RocketPort -boards, you can put as many as 128 intelligent serial ports -on your system. -.Pp -The -.Nm -driver supports the following speeds: 50, 75, 110, 134, 150, -200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 7200, -14400, 57600, 76800, 115200, and 230400. -(You must use -.Xr termios 4 , -rather than the old style ioctl interface to use non-traditional -speeds.) -.Pp -An open on the -.Nm -driver will block until carrier is present, unless -.Dv O_NONBLOCK -or -.Dv CLOCAL -is set. -.Sh HARDWARE CONFIGURATION -The first -.Tn RocketPort -or -.Tn RocketPort RA -card requires a 68-byte contiguous block of I/O addresses, -starting at one of the following: -0x100h, 0x140h, 0x180h, 0x200h, 0x240h, 0x280h, 0x300h, 0x340h, -0x380h. -The second, third, and fourth -.Tn RocketPort -cards require only a -64-byte contiguous block of I/O addresses, starting at one of the -above address ranges. -The I/O address range used by any of the -.Tn RocketPort -cards must not conflict with any other cards in the system, -including other -.Tn RocketPort -cards. -The starting range of the I/O ports used by each card -must match with the I/O address specified in -.Pa /boot/device.hints . -.Pp -Since the first -.Tn RocketPort -uses 68 I/O addresses, if the first card is -set to use an I/O block starting at 0x100, -it will occupy the I/O ports between 0x100 and 0x143. -This means that the second, third, or fourth -.Tn RocketPort -board may not use the block of addresses starting at 0x140, -since the first three I/O addresses of that range -are used by the first board. -This is an important point to keep in mind. -.Pp -If you have two ISA cards, one installed at 0x100 and the -second installed at 0x180, then you should add the following to -.Pa /boot/device.hints : -.Pp -.Dl hint.rp.0.at="isa" -.Dl hint.rp.0.port="0x100" -.Dl hint.rp.1.at="isa" -.Dl hint.rp.1.port="0x180" -.Pp -The configuration of the -.Tn RocketPort -cards is done via the set of 8 DIP switches, -labeled SW1 on the -.Tn RocketPort -card: -.Bd -literal -offset indent -+-------------------------------+ -| 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | -+-------+-------+---------------+ -| Unused| Card | I/O Port Block| -+-------------------------------+ -.Ed -.Pp -DIP switches 7 and 8 are unused, and must be left on. -.Pp -DIP switches 6 and 5 identify the card number of each -.Tn RocketPort -card. -The first card installed in the system must have its DIP switches set -as card number one; the second card installed in the system must have -its DIP switches set as card number two; and so on. -As shipped from -the factory, DIP switches 6 and 5 are both on by default, indicating -that this is the first card installed on the system: -.Bd -literal -offset indent -DIP Switches -6 5 -=================== -On On First Card -On Off Second Card -Off On Third Card -Off Off Fourth Card -.Ed -.Pp -DIP switches 4, 3, 2, and 1 indicate the I/O address range used by the -first -.Tn RocketPort -card. -If there are more than one -.Tn RocketPort -cards installed in a system, -the second, third and fourth -.Tn RocketPort -cards must -also be set to the I/O address range used by the first -.Tn RocketPort -card; -all cards must have these DIP switches set identically -for proper operation. -As shipped from the factory, DIP switch 4 is on, -and switches 3, 2, and 1 are off by default, -indicating an I/O address range used by the first -card which starts at 0x180 and extends to 0x1C3. -.Bd -literal -offset indent -DIP Switches I/O Address Range -4 3 2 1 Used by the First Card -===================================== -On Off On Off 100-143 -On Off Off On 140-183 -On Off Off Off 180-1C3 -Off On On Off 200-243 -Off On Off On 240-283 -Off On Off Off 280-2C3 -Off Off On Off 300-343 -Off Off Off On 340-383 -Off Off Off Off 380-3C3 -.Ed -.Sh FILES -.Bl -tag -width ".Pa /dev/ttyR[0-4][0-9a-f]" -.It Pa /dev/ttyR[0-4][0-9a-f] -.El -.Sh AUTHORS -.An Theodore Ts'o Aq Mt tytso@mit.edu -.Pp -This driver was written under contract for Comtrol Corporation. -For dealer, distributor and other information regarding Comtrol -.Tn RocketPort , -contact Comtrol Corporation at (800) 926-6876 or send email to -.Aq Mt info@comtrol.com . -To report bugs for this driver, please send email to -.Aq Mt bug-bsdi-rocketport@comtrol.com . -.Sh BUGS -If incoming software flow control is enabled on a 486 or Pentium -machine, and the flow control is very heavily exercised, on rare occasions -a character will get dropped. -This problem does not occur on a 386, and -it is not currently known whether the bug is in the -.Nm -driver -or in the -.Bsx -tty layer. -.\" (Although my bet is that it's in the higher-level tty layer; -.\" given the bugs I found while writing this driver, it's clear -.\" the BSD software flow control code has not been tested very much -.\" at all! -- TYT) diff --git a/sys/conf/files b/sys/conf/files index 2f9e75d73d41..cbb29fa45663 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1541,9 +1541,6 @@ t6fw.fw optional cxgbe \ clean "t6fw.fw" dev/cxgbe/crypto/t4_crypto.c optional ccr \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" -dev/cy/cy.c optional cy -dev/cy/cy_isa.c optional cy isa -dev/cy/cy_pci.c optional cy pci dev/cyapa/cyapa.c optional cyapa iicbus dev/dc/if_dc.c optional dc pci dev/dc/dcphy.c optional dc pci @@ -2775,14 +2772,10 @@ dev/random/random_harvestq.c standard dev/random/randomdev.c optional !random_loadable dev/random/fortuna.c optional !random_loadable dev/random/hash.c optional !random_loadable -dev/rc/rc.c optional rc dev/rccgpio/rccgpio.c optional rccgpio gpio dev/re/if_re.c optional re dev/rl/if_rl.c optional rl pci dev/rndtest/rndtest.c optional rndtest -dev/rp/rp.c optional rp -dev/rp/rp_isa.c optional rp isa -dev/rp/rp_pci.c optional rp pci # dev/rtwn/if_rtwn.c optional rtwn dev/rtwn/if_rtwn_beacon.c optional rtwn diff --git a/sys/dev/cy/cy.c b/sys/dev/cy/cy.c deleted file mode 100644 index 3d397ae775cc..000000000000 --- a/sys/dev/cy/cy.c +++ /dev/null @@ -1,2242 +0,0 @@ -/*- - * cyclades cyclom-y serial driver - * Andrew Herbert , 17 August 1993 - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 1993 Andrew Herbert. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name Andrew Herbert may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* - * TODO: - * Atomic COR change. - * Consoles. - */ - -/* - * Temporary compile-time configuration options. - */ -#define RxFifoThreshold (CD1400_RX_FIFO_SIZE / 2) - /* Number of chars in the receiver FIFO before an - * an interrupt is generated. Should depend on - * line speed. Needs to be about 6 on a 486DX33 - * for 4 active ports at 115200 bps. Why doesn't - * 10 work? - */ -#define PollMode /* Use polling-based irq service routine, not the - * hardware svcack lines. Must be defined for - * Cyclom-16Y boards. Less efficient for Cyclom-8Ys, - * and stops 4 * 115200 bps from working. - */ -#undef Smarts /* Enable slightly more CD1400 intelligence. Mainly - * the output CR/LF processing, plus we can avoid a - * few checks usually done in ttyinput(). - * - * XXX not fully implemented, and not particularly - * worthwhile. - */ -#undef CyDebug /* Include debugging code (not very expensive). */ - -/* These will go away. */ -#undef SOFT_CTS_OFLOW -#define SOFT_HOTCHAR - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#define NCY 10 /* KLUDGE */ - -#define NPORTS (NCY * CY_MAX_PORTS) - -#define CY_MAX_PORTS (CD1400_NO_OF_CHANNELS * CY_MAX_CD1400s) - -/* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */ -#define CD1400_xIVR_CHAN_SHIFT 3 -#define CD1400_xIVR_CHAN 0x1F - -/* - * ETC states. com->etc may also contain a hardware ETC command value, - * meaning that execution of that command is pending. - */ -#define ETC_NONE 0 /* we depend on bzero() setting this */ -#define ETC_BREAK_STARTING 1 -#define ETC_BREAK_STARTED 2 -#define ETC_BREAK_ENDING 3 -#define ETC_BREAK_ENDED 4 - -#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ - -/* - * com state bits. - * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher - * than the other bits so that they can be tested as a group without masking - * off the low bits. - * - * The following com and tty flags correspond closely: - * CS_BUSY = TS_BUSY (maintained by cystart(), cypoll() and - * comstop()) - * CS_TTGO = ~TS_TTSTOP (maintained by cyparam() and cystart()) - * CS_CTS_OFLOW = CCTS_OFLOW (maintained by cyparam()) - * CS_RTS_IFLOW = CRTS_IFLOW (maintained by cyparam()) - * TS_FLUSH is not used. - * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. - * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state). - */ -#define CS_BUSY 0x80 /* output in progress */ -#define CS_TTGO 0x40 /* output not stopped by XOFF */ -#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */ -#define CS_CHECKMSR 1 /* check of MSR scheduled */ -#define CS_CTS_OFLOW 2 /* use CTS output flow control */ -#define CS_ODONE 4 /* output completed */ -#define CS_RTS_IFLOW 8 /* use RTS input flow control */ -#define CSE_ODONE 1 /* output transmitted */ - -static char const * const error_desc[] = { -#define CE_OVERRUN 0 - "silo overflow", -#define CE_INTERRUPT_BUF_OVERFLOW 1 - "interrupt-level buffer overflow", -#define CE_TTY_BUF_OVERFLOW 2 - "tty-level buffer overflow", -}; - -#define CE_NTYPES 3 -#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum]) - -#ifdef SMP -#define COM_LOCK() mtx_lock_spin(&cy_lock) -#define COM_UNLOCK() mtx_unlock_spin(&cy_lock) -#else -#define COM_LOCK() -#define COM_UNLOCK() -#endif - -/* types. XXX - should be elsewhere */ -typedef u_char bool_t; /* boolean */ - -/* queue of linear buffers */ -struct lbq { - u_char *l_head; /* next char to process */ - u_char *l_tail; /* one past the last char to process */ - struct lbq *l_next; /* next in queue */ - bool_t l_queued; /* nonzero if queued */ -}; - -/* com device structure */ -struct com_s { - u_char state; /* miscellaneous flag bits */ - u_char etc; /* pending Embedded Transmit Command */ - u_char extra_state; /* more flag bits, separate for order trick */ - u_char gfrcr_image; /* copy of value read from GFRCR */ - u_char mcr_dtr; /* MCR bit that is wired to DTR */ - u_char mcr_image; /* copy of value written to MCR */ - u_char mcr_rts; /* MCR bit that is wired to RTS */ - int unit; /* unit number */ - - /* - * The high level of the driver never reads status registers directly - * because there would be too many side effects to handle conveniently. - * Instead, it reads copies of the registers stored here by the - * interrupt handler. - */ - u_char last_modem_status; /* last MSR read by intr handler */ - u_char prev_modem_status; /* last MSR handled by high level */ - - u_char *ibuf; /* start of input buffer */ - u_char *ibufend; /* end of input buffer */ - u_char *ibufold; /* old input buffer, to be freed */ - u_char *ihighwater; /* threshold in input buffer */ - u_char *iptr; /* next free spot in input buffer */ - int ibufsize; /* size of ibuf (not include error bytes) */ - int ierroff; /* offset of error bytes in ibuf */ - - struct lbq obufq; /* head of queue of output buffers */ - struct lbq obufs[2]; /* output buffers */ - - int cy_align; /* index for register alignment */ - cy_addr cy_iobase; /* base address of this port's cyclom */ - cy_addr iobase; /* base address of this port's cd1400 */ - int mcr_rts_reg; /* cd1400 reg number of reg holding mcr_rts */ - - struct tty *tp; /* cross reference */ - - u_long bytes_in; /* statistics */ - u_long bytes_out; - u_int delta_error_counts[CE_NTYPES]; - u_long error_counts[CE_NTYPES]; - - u_int recv_exception; /* exception chars received */ - u_int mdm; /* modem signal changes */ -#ifdef CyDebug - u_int start_count; /* no. of calls to cystart() */ - u_int start_real; /* no. of calls that did something */ -#endif - u_char car; /* CD1400 CAR shadow (if first unit in cd) */ - u_char channel_control;/* CD1400 CCR control command shadow */ - u_char cor[3]; /* CD1400 COR1-3 shadows */ - u_char intr_enable; /* CD1400 SRER shadow */ - - /* - * Data area for output buffers. Someday we should build the output - * buffer queue without copying data. - */ - u_char obuf1[256]; - u_char obuf2[256]; -}; - -devclass_t cy_devclass; -char cy_driver_name[] = "cy"; - -static void cd1400_channel_cmd(struct com_s *com, int cmd); -static void cd1400_channel_cmd_wait(struct com_s *com); -static void cd_etc(struct com_s *com, int etc); -static int cd_getreg(struct com_s *com, int reg); -static void cd_setreg(struct com_s *com, int reg, int val); -static void cyinput(struct com_s *com); -static int cyparam(struct tty *tp, struct termios *t); -static void cypoll(void *arg); -static void cysettimeout(void); -static int cysetwater(struct com_s *com, speed_t speed); -static int cyspeed(speed_t speed, u_long cy_clock, int *prescaler_io); -static void cystart(struct tty *tp); -static void comstop(struct tty *tp, int rw); -static timeout_t cywakeup; -static void disc_optim(struct tty *tp, struct termios *t, - struct com_s *com); - -static t_break_t cybreak; -static t_modem_t cymodem; -static t_open_t cyopen; -static t_close_t cyclose; - -#ifdef CyDebug -void cystatus(int unit); -#endif - -static struct mtx cy_lock; -static int cy_inited; - -/* table and macro for fast conversion from a unit number to its com struct */ -static struct com_s *p_cy_addr[NPORTS]; -#define cy_addr(unit) (p_cy_addr[unit]) - -static u_int cy_events; /* input chars + weighted output completions */ -static void *cy_fast_ih; -static void *cy_slow_ih; -static int cy_timeout; -static int cy_timeouts_until_log; -static struct callout_handle cy_timeout_handle - = CALLOUT_HANDLE_INITIALIZER(&cy_timeout_handle); - -#ifdef CyDebug -static u_int cd_inbs; -static u_int cy_inbs; -static u_int cd_outbs; -static u_int cy_outbs; -static u_int cy_svrr_probes; -static u_int cy_timeouts; -#endif - -static int cy_chip_offset[] = { - 0x0000, 0x0400, 0x0800, 0x0c00, 0x0200, 0x0600, 0x0a00, 0x0e00, -}; -static int cy_nr_cd1400s[NCY]; -static int cy_total_devices; -#undef RxFifoThreshold -static int volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2); - -int -cy_units(cy_addr cy_iobase, int cy_align) -{ - int cyu; - u_char firmware_version; - int i; - cy_addr iobase; - - for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu) { - iobase = cy_iobase + (cy_chip_offset[cyu] << cy_align); - - /* wait for chip to become ready for new command */ - for (i = 0; i < 10; i++) { - DELAY(50); - if (!cd_inb(iobase, CD1400_CCR, cy_align)) - break; - } - - /* clear the GFRCR register */ - cd_outb(iobase, CD1400_GFRCR, cy_align, 0); - - /* issue a reset command */ - cd_outb(iobase, CD1400_CCR, cy_align, - CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET); - - /* XXX bogus initialization to avoid a gcc bug/warning. */ - firmware_version = 0; - - /* wait for the CD1400 to initialize itself */ - for (i = 0; i < 200; i++) { - DELAY(50); - - /* retrieve firmware version */ - firmware_version = cd_inb(iobase, CD1400_GFRCR, - cy_align); - if ((firmware_version & 0xf0) == 0x40) - break; - } - - /* - * Anything in the 0x40-0x4F range is fine. - * If one CD1400 is bad then we don't support higher - * numbered good ones on this board. - */ - if ((firmware_version & 0xf0) != 0x40) - break; - } - return (cyu); -} - -void * -cyattach_common(cy_addr cy_iobase, int cy_align) -{ - int adapter; - int cyu; - u_char firmware_version; - cy_addr iobase; - int ncyu; - int unit; - struct tty *tp; - - while (cy_inited != 2) - if (atomic_cmpset_int(&cy_inited, 0, 1)) { - mtx_init(&cy_lock, cy_driver_name, NULL, MTX_SPIN); - atomic_store_rel_int(&cy_inited, 2); - } - - adapter = cy_total_devices; - if ((u_int)adapter >= NCY) { - printf( - "cy%d: can't attach adapter: insufficient cy devices configured\n", - adapter); - return (NULL); - } - ncyu = cy_units(cy_iobase, cy_align); - if (ncyu == 0) - return (NULL); - cy_nr_cd1400s[adapter] = ncyu; - cy_total_devices++; - - unit = adapter * CY_MAX_PORTS; - for (cyu = 0; cyu < ncyu; ++cyu) { - int cdu; - - iobase = (cy_addr) (cy_iobase - + (cy_chip_offset[cyu] << cy_align)); - firmware_version = cd_inb(iobase, CD1400_GFRCR, cy_align); - - /* Set up a receive timeout period of than 1+ ms. */ - cd_outb(iobase, CD1400_PPR, cy_align, - howmany(CY_CLOCK(firmware_version) - / CD1400_PPR_PRESCALER, 1000)); - - for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; ++cdu, ++unit) { - struct com_s *com; - int s; - - com = malloc(sizeof *com, M_DEVBUF, M_NOWAIT | M_ZERO); - if (com == NULL) - break; - com->unit = unit; - com->gfrcr_image = firmware_version; - if (CY_RTS_DTR_SWAPPED(firmware_version)) { - com->mcr_dtr = CD1400_MSVR1_RTS; - com->mcr_rts = CD1400_MSVR2_DTR; - com->mcr_rts_reg = CD1400_MSVR2; - } else { - com->mcr_dtr = CD1400_MSVR2_DTR; - com->mcr_rts = CD1400_MSVR1_RTS; - com->mcr_rts_reg = CD1400_MSVR1; - } - com->obufs[0].l_head = com->obuf1; - com->obufs[1].l_head = com->obuf2; - - com->cy_align = cy_align; - com->cy_iobase = cy_iobase; - com->iobase = iobase; - com->car = ~CD1400_CAR_CHAN; - - tp = com->tp = ttyalloc(); - tp->t_open = cyopen; - tp->t_close = cyclose; - tp->t_oproc = cystart; - tp->t_stop = comstop; - tp->t_param = cyparam; - tp->t_break = cybreak; - tp->t_modem = cymodem; - tp->t_sc = com; - - if (cysetwater(com, tp->t_init_in.c_ispeed) != 0) { - free(com, M_DEVBUF); - return (NULL); - } - - s = spltty(); - cy_addr(unit) = com; - splx(s); - - if (cy_fast_ih == NULL) { - swi_add(&tty_intr_event, "cy", cypoll, NULL, SWI_TTY, 0, - &cy_fast_ih); - swi_add(&clk_intr_event, "cy", cypoll, NULL, SWI_CLOCK, 0, - &cy_slow_ih); - } - ttycreate(tp, TS_CALLOUT, "c%r%r", - adapter, unit % CY_MAX_PORTS); - } - } - - /* ensure an edge for the next interrupt */ - cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0); - - return (cy_addr(adapter * CY_MAX_PORTS)); -} - -static int -cyopen(struct tty *tp, struct cdev *dev) -{ - struct com_s *com; - int s; - - com = tp->t_sc; - s = spltty(); - /* - * We jump to this label after all non-interrupted sleeps to pick - * up any changes of the device state. - */ - - /* Encode per-board unit in LIVR for access in intr routines. */ - cd_setreg(com, CD1400_LIVR, - (com->unit & CD1400_xIVR_CHAN) << CD1400_xIVR_CHAN_SHIFT); - - /* - * Flush fifos. This requires a full channel reset which - * also disables the transmitter and receiver. Recover - * from this. - */ - cd1400_channel_cmd(com, - CD1400_CCR_CMDRESET | CD1400_CCR_CHANRESET); - cd1400_channel_cmd(com, com->channel_control); - - critical_enter(); - COM_LOCK(); - com->prev_modem_status = com->last_modem_status - = cd_getreg(com, CD1400_MSVR2); - cd_setreg(com, CD1400_SRER, - com->intr_enable - = CD1400_SRER_MDMCH | CD1400_SRER_RXDATA); - COM_UNLOCK(); - critical_exit(); - cysettimeout(); - return (0); -} - - -static void -cyclose(struct tty *tp) -{ - cy_addr iobase; - struct com_s *com; - int s; - int unit; - - com = tp->t_sc; - unit = com->unit; - iobase = com->iobase; - s = spltty(); - /* XXX */ - critical_enter(); - COM_LOCK(); - com->etc = ETC_NONE; - cd_setreg(com, CD1400_COR2, com->cor[1] &= ~CD1400_COR2_ETC); - COM_UNLOCK(); - critical_exit(); - cd_etc(com, CD1400_ETC_STOPBREAK); - cd1400_channel_cmd(com, CD1400_CCR_CMDRESET | CD1400_CCR_FTF); - - { - critical_enter(); - COM_LOCK(); - cd_setreg(com, CD1400_SRER, com->intr_enable = 0); - COM_UNLOCK(); - critical_exit(); - tp = com->tp; - if ((tp->t_cflag & HUPCL) - /* - * XXX we will miss any carrier drop between here and the - * next open. Perhaps we should watch DCD even when the - * port is closed; it is not sufficient to check it at - * the next open because it might go up and down while - * we're not watching. - */ - || (!tp->t_actout - && !(com->prev_modem_status & CD1400_MSVR2_CD) - && !(tp->t_init_in.c_cflag & CLOCAL)) - || !(tp->t_state & TS_ISOPEN)) { - (void)cymodem(tp, 0, SER_DTR); - - /* Disable receiver (leave transmitter enabled). */ - com->channel_control = CD1400_CCR_CMDCHANCTL - | CD1400_CCR_XMTEN - | CD1400_CCR_RCVDIS; - cd1400_channel_cmd(com, com->channel_control); - - ttydtrwaitstart(tp); - } - } - tp->t_actout = FALSE; - wakeup(&tp->t_actout); - wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */ - splx(s); -} - -/* - * This function: - * a) needs to be called with COM_LOCK() held, and - * b) needs to return with COM_LOCK() held. - */ -static void -cyinput(struct com_s *com) -{ - u_char *buf; - int incc; - u_char line_status; - int recv_data; - struct tty *tp; - - buf = com->ibuf; - tp = com->tp; - if (!(tp->t_state & TS_ISOPEN)) { - cy_events -= (com->iptr - com->ibuf); - com->iptr = com->ibuf; - return; - } - if (tp->t_state & TS_CAN_BYPASS_L_RINT) { - /* - * Avoid the grotesquely inefficient lineswitch routine - * (ttyinput) in "raw" mode. It usually takes about 450 - * instructions (that's without canonical processing or echo!). - * slinput is reasonably fast (usually 40 instructions plus - * call overhead). - */ - - do { - /* - * This may look odd, but it is using save-and-enable - * semantics instead of the save-and-disable semantics - * that are used everywhere else. - */ - COM_UNLOCK(); - critical_exit(); - incc = com->iptr - buf; - if (tp->t_rawq.c_cc + incc > tp->t_ihiwat - && (com->state & CS_RTS_IFLOW - || tp->t_iflag & IXOFF) - && !(tp->t_state & TS_TBLOCK)) - ttyblock(tp); - com->delta_error_counts[CE_TTY_BUF_OVERFLOW] - += b_to_q((char *)buf, incc, &tp->t_rawq); - buf += incc; - tk_nin += incc; - tk_rawcc += incc; - tp->t_rawcc += incc; - ttwakeup(tp); - if (tp->t_state & TS_TTSTOP - && (tp->t_iflag & IXANY - || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { - tp->t_state &= ~TS_TTSTOP; - tp->t_lflag &= ~FLUSHO; - cystart(tp); - } - critical_enter(); - COM_LOCK(); - } while (buf < com->iptr); - } else { - do { - /* - * This may look odd, but it is using save-and-enable - * semantics instead of the save-and-disable semantics - * that are used everywhere else. - */ - COM_UNLOCK(); - critical_exit(); - line_status = buf[com->ierroff]; - recv_data = *buf++; - if (line_status - & (CD1400_RDSR_BREAK | CD1400_RDSR_FE | CD1400_RDSR_OE | CD1400_RDSR_PE)) { - if (line_status & CD1400_RDSR_BREAK) - recv_data |= TTY_BI; - if (line_status & CD1400_RDSR_FE) - recv_data |= TTY_FE; - if (line_status & CD1400_RDSR_OE) - recv_data |= TTY_OE; - if (line_status & CD1400_RDSR_PE) - recv_data |= TTY_PE; - } - ttyld_rint(tp, recv_data); - critical_enter(); - COM_LOCK(); - } while (buf < com->iptr); - } - cy_events -= (com->iptr - com->ibuf); - com->iptr = com->ibuf; - - /* - * There is now room for another low-level buffer full of input, - * so enable RTS if it is now disabled and there is room in the - * high-level buffer. - */ - if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & com->mcr_rts) && - !(tp->t_state & TS_TBLOCK)) - cd_setreg(com, com->mcr_rts_reg, - com->mcr_image |= com->mcr_rts); -} - -int -cyintr(void *vcom) -{ - struct com_s *basecom; - int baseu; - int cy_align; - cy_addr cy_iobase; - int cyu; - cy_addr iobase; - u_char status; - int unit; - - COM_LOCK(); /* XXX could this be placed down lower in the loop? */ - - basecom = (struct com_s *)vcom; - baseu = basecom->unit; - cy_align = basecom->cy_align; - cy_iobase = basecom->cy_iobase; - unit = baseu / CY_MAX_PORTS; - - /* check each CD1400 in turn */ - for (cyu = 0; cyu < cy_nr_cd1400s[unit]; ++cyu) { - iobase = (cy_addr) (cy_iobase - + (cy_chip_offset[cyu] << cy_align)); - /* poll to see if it has any work */ - status = cd_inb(iobase, CD1400_SVRR, cy_align); - if (status == 0) - continue; // XXX - FILTER_STRAY? -#ifdef CyDebug - ++cy_svrr_probes; -#endif - /* service requests as appropriate, giving priority to RX */ - if (status & CD1400_SVRR_RXRDY) { - struct com_s *com; - u_int count; - u_char *ioptr; - u_char line_status; - u_char recv_data; - u_char serv_type; -#ifdef PollMode - u_char save_rir; -#endif - -#ifdef PollMode - save_rir = cd_inb(iobase, CD1400_RIR, cy_align); - - /* enter rx service */ - cd_outb(iobase, CD1400_CAR, cy_align, save_rir); - cy_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car - = save_rir & CD1400_CAR_CHAN; - - serv_type = cd_inb(iobase, CD1400_RIVR, cy_align); - com = cy_addr(baseu - + ((serv_type >> CD1400_xIVR_CHAN_SHIFT) - & CD1400_xIVR_CHAN)); -#else - /* ack receive service */ - serv_type = cy_inb(iobase, CY8_SVCACKR, cy_align); - - com = cy_addr(baseu + - + ((serv_type >> CD1400_xIVR_CHAN_SHIFT) - & CD1400_xIVR_CHAN)); -#endif - - if (serv_type & CD1400_RIVR_EXCEPTION) { - ++com->recv_exception; - line_status = cd_inb(iobase, CD1400_RDSR, cy_align); - /* break/unnattached error bits or real input? */ - recv_data = cd_inb(iobase, CD1400_RDSR, cy_align); -#ifndef SOFT_HOTCHAR - if (line_status & CD1400_RDSR_SPECIAL - && com->tp->t_hotchar != 0) - swi_sched(cy_fast_ih, 0); - -#endif -#if 1 /* XXX "intelligent" PFO error handling would break O error handling */ - if (line_status & (CD1400_RDSR_PE|CD1400_RDSR_FE|CD1400_RDSR_BREAK)) { - /* - Don't store PE if IGNPAR and BI if IGNBRK, - this hack allows "raw" tty optimization - works even if IGN* is set. - */ - if ( com->tp == NULL - || !(com->tp->t_state & TS_ISOPEN) - || ((line_status & (CD1400_RDSR_PE|CD1400_RDSR_FE)) - && (com->tp->t_iflag & IGNPAR)) - || ((line_status & CD1400_RDSR_BREAK) - && (com->tp->t_iflag & IGNBRK))) - goto cont; - if ( (line_status & (CD1400_RDSR_PE|CD1400_RDSR_FE)) - && (com->tp->t_state & TS_CAN_BYPASS_L_RINT) - && ((line_status & CD1400_RDSR_FE) - || ((line_status & CD1400_RDSR_PE) - && (com->tp->t_iflag & INPCK)))) - recv_data = 0; - } -#endif /* 1 */ - ++com->bytes_in; -#ifdef SOFT_HOTCHAR - if (com->tp->t_hotchar != 0 && recv_data == com->tp->t_hotchar) - swi_sched(cy_fast_ih, 0); -#endif - ioptr = com->iptr; - if (ioptr >= com->ibufend) - CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW); - else { - if (com->tp != NULL && com->tp->t_do_timestamp) - microtime(&com->tp->t_timestamp); - ++cy_events; - ioptr[0] = recv_data; - ioptr[com->ierroff] = line_status; - com->iptr = ++ioptr; - if (ioptr == com->ihighwater - && com->state & CS_RTS_IFLOW) - cd_outb(iobase, com->mcr_rts_reg, - cy_align, - com->mcr_image &= - ~com->mcr_rts); - if (line_status & CD1400_RDSR_OE) - CE_RECORD(com, CE_OVERRUN); - } - goto cont; - } else { - int ifree; - - count = cd_inb(iobase, CD1400_RDCR, cy_align); - if (!count) - goto cont; - com->bytes_in += count; - ioptr = com->iptr; - ifree = com->ibufend - ioptr; - if (count > ifree) { - count -= ifree; - cy_events += ifree; - if (ifree != 0) { - if (com->tp != NULL && com->tp->t_do_timestamp) - microtime(&com->tp->t_timestamp); - do { - recv_data = cd_inb(iobase, - CD1400_RDSR, - cy_align); -#ifdef SOFT_HOTCHAR - if (com->tp->t_hotchar != 0 - && recv_data - == com->tp->t_hotchar) - swi_sched(cy_fast_ih, - 0); -#endif - ioptr[0] = recv_data; - ioptr[com->ierroff] = 0; - ++ioptr; - } while (--ifree != 0); - } - com->delta_error_counts - [CE_INTERRUPT_BUF_OVERFLOW] += count; - do { - recv_data = cd_inb(iobase, CD1400_RDSR, - cy_align); -#ifdef SOFT_HOTCHAR - if (com->tp->t_hotchar != 0 - && recv_data == com->tp->t_hotchar) - swi_sched(cy_fast_ih, 0); -#endif - } while (--count != 0); - } else { - if (com->tp != NULL && com->tp->t_do_timestamp) - microtime(&com->tp->t_timestamp); - if (ioptr <= com->ihighwater - && ioptr + count > com->ihighwater - && com->state & CS_RTS_IFLOW) - cd_outb(iobase, com->mcr_rts_reg, - cy_align, - com->mcr_image - &= ~com->mcr_rts); - cy_events += count; - do { - recv_data = cd_inb(iobase, CD1400_RDSR, - cy_align); -#ifdef SOFT_HOTCHAR - if (com->tp->t_hotchar != 0 - && recv_data == com->tp->t_hotchar) - swi_sched(cy_fast_ih, 0); -#endif - ioptr[0] = recv_data; - ioptr[com->ierroff] = 0; - ++ioptr; - } while (--count != 0); - } - com->iptr = ioptr; - } -cont: - - /* terminate service context */ -#ifdef PollMode - cd_outb(iobase, CD1400_RIR, cy_align, - save_rir - & ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY)); -#else - cd_outb(iobase, CD1400_EOSRR, cy_align, 0); -#endif - } - if (status & CD1400_SVRR_MDMCH) { - struct com_s *com; - u_char modem_status; -#ifdef PollMode - u_char save_mir; -#else - u_char vector; -#endif - -#ifdef PollMode - save_mir = cd_inb(iobase, CD1400_MIR, cy_align); - - /* enter modem service */ - cd_outb(iobase, CD1400_CAR, cy_align, save_mir); - cy_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car - = save_mir & CD1400_CAR_CHAN; - - com = cy_addr(baseu + cyu * CD1400_NO_OF_CHANNELS - + (save_mir & CD1400_MIR_CHAN)); -#else - /* ack modem service */ - vector = cy_inb(iobase, CY8_SVCACKM, cy_align); - - com = cy_addr(baseu - + ((vector >> CD1400_xIVR_CHAN_SHIFT) - & CD1400_xIVR_CHAN)); -#endif - ++com->mdm; - modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align); - if (modem_status != com->last_modem_status) { - /* - * Schedule high level to handle DCD changes. Note - * that we don't use the delta bits anywhere. Some - * UARTs mess them up, and it's easy to remember the - * previous bits and calculate the delta. - */ - com->last_modem_status = modem_status; - if (!(com->state & CS_CHECKMSR)) { - cy_events += LOTS_OF_EVENTS; - com->state |= CS_CHECKMSR; - swi_sched(cy_fast_ih, 0); - } - -#ifdef SOFT_CTS_OFLOW - /* handle CTS change immediately for crisp flow ctl */ - if (com->state & CS_CTS_OFLOW) { - if (modem_status & CD1400_MSVR2_CTS) { - com->state |= CS_ODEVREADY; - if (com->state >= (CS_BUSY | CS_TTGO - | CS_ODEVREADY) - && !(com->intr_enable - & CD1400_SRER_TXRDY)) - cd_outb(iobase, CD1400_SRER, - cy_align, - com->intr_enable - = com->intr_enable - & ~CD1400_SRER_TXMPTY - | CD1400_SRER_TXRDY); - } else { - com->state &= ~CS_ODEVREADY; - if (com->intr_enable - & CD1400_SRER_TXRDY) - cd_outb(iobase, CD1400_SRER, - cy_align, - com->intr_enable - = com->intr_enable - & ~CD1400_SRER_TXRDY - | CD1400_SRER_TXMPTY); - } - } -#endif - } - - /* terminate service context */ -#ifdef PollMode - cd_outb(iobase, CD1400_MIR, cy_align, - save_mir - & ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY)); -#else - cd_outb(iobase, CD1400_EOSRR, cy_align, 0); -#endif - } - if (status & CD1400_SVRR_TXRDY) { - struct com_s *com; -#ifdef PollMode - u_char save_tir; -#else - u_char vector; -#endif - -#ifdef PollMode - save_tir = cd_inb(iobase, CD1400_TIR, cy_align); - - /* enter tx service */ - cd_outb(iobase, CD1400_CAR, cy_align, save_tir); - cy_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car - = save_tir & CD1400_CAR_CHAN; - - com = cy_addr(baseu - + cyu * CD1400_NO_OF_CHANNELS - + (save_tir & CD1400_TIR_CHAN)); -#else - /* ack transmit service */ - vector = cy_inb(iobase, CY8_SVCACKT, cy_align); - - com = cy_addr(baseu - + ((vector >> CD1400_xIVR_CHAN_SHIFT) - & CD1400_xIVR_CHAN)); -#endif - - if (com->etc != ETC_NONE) { - if (com->intr_enable & CD1400_SRER_TXRDY) { - /* - * Here due to sloppy SRER_TXRDY - * enabling. Ignore. Come back when - * tx is empty. - */ - cd_outb(iobase, CD1400_SRER, cy_align, - com->intr_enable - = (com->intr_enable - & ~CD1400_SRER_TXRDY) - | CD1400_SRER_TXMPTY); - goto terminate_tx_service; - } - switch (com->etc) { - case CD1400_ETC_SENDBREAK: - case CD1400_ETC_STOPBREAK: - /* - * Start the command. Come back on - * next tx empty interrupt, hopefully - * after command has been executed. - */ - cd_outb(iobase, CD1400_COR2, cy_align, - com->cor[1] |= CD1400_COR2_ETC); - cd_outb(iobase, CD1400_TDR, cy_align, - CD1400_ETC_CMD); - cd_outb(iobase, CD1400_TDR, cy_align, - com->etc); - if (com->etc == CD1400_ETC_SENDBREAK) - com->etc = ETC_BREAK_STARTING; - else - com->etc = ETC_BREAK_ENDING; - goto terminate_tx_service; - case ETC_BREAK_STARTING: - /* - * BREAK is now on. Continue with - * SRER_TXMPTY processing, hopefully - * don't come back. - */ - com->etc = ETC_BREAK_STARTED; - break; - case ETC_BREAK_STARTED: - /* - * Came back due to sloppy SRER_TXMPTY - * enabling. Hope again. - */ - break; - case ETC_BREAK_ENDING: - /* - * BREAK is now off. Continue with - * SRER_TXMPTY processing and don't - * come back. The SWI handler will - * restart tx interrupts if necessary. - */ - cd_outb(iobase, CD1400_COR2, cy_align, - com->cor[1] - &= ~CD1400_COR2_ETC); - com->etc = ETC_BREAK_ENDED; - if (!(com->state & CS_ODONE)) { - cy_events += LOTS_OF_EVENTS; - com->state |= CS_ODONE; - swi_sched(cy_fast_ih, 0); - } - break; - case ETC_BREAK_ENDED: - /* - * Shouldn't get here. Hope again. - */ - break; - } - } - if (com->intr_enable & CD1400_SRER_TXMPTY) { - if (!(com->extra_state & CSE_ODONE)) { - cy_events += LOTS_OF_EVENTS; - com->extra_state |= CSE_ODONE; - swi_sched(cy_fast_ih, 0); - } - cd_outb(iobase, CD1400_SRER, cy_align, - com->intr_enable - &= ~CD1400_SRER_TXMPTY); - goto terminate_tx_service; - } - if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { - u_char *ioptr; - u_int ocount; - - ioptr = com->obufq.l_head; - ocount = com->obufq.l_tail - ioptr; - if (ocount > CD1400_TX_FIFO_SIZE) - ocount = CD1400_TX_FIFO_SIZE; - com->bytes_out += ocount; - do - cd_outb(iobase, CD1400_TDR, cy_align, - *ioptr++); - while (--ocount != 0); - com->obufq.l_head = ioptr; - if (ioptr >= com->obufq.l_tail) { - struct lbq *qp; - - qp = com->obufq.l_next; - qp->l_queued = FALSE; - qp = qp->l_next; - if (qp != NULL) { - com->obufq.l_head = qp->l_head; - com->obufq.l_tail = qp->l_tail; - com->obufq.l_next = qp; - } else { - /* output just completed */ - com->state &= ~CS_BUSY; - - /* - * The setting of CSE_ODONE may be - * stale here. We currently only - * use it when CS_BUSY is set, and - * fixing it when we clear CS_BUSY - * is easiest. - */ - if (com->extra_state & CSE_ODONE) { - cy_events -= LOTS_OF_EVENTS; - com->extra_state &= ~CSE_ODONE; - } - - cd_outb(iobase, CD1400_SRER, cy_align, - com->intr_enable - = (com->intr_enable - & ~CD1400_SRER_TXRDY) - | CD1400_SRER_TXMPTY); - } - if (!(com->state & CS_ODONE)) { - cy_events += LOTS_OF_EVENTS; - com->state |= CS_ODONE; - - /* handle at high level ASAP */ - swi_sched(cy_fast_ih, 0); - } - } - } - - /* terminate service context */ -terminate_tx_service: -#ifdef PollMode - cd_outb(iobase, CD1400_TIR, cy_align, - save_tir - & ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY)); -#else - cd_outb(iobase, CD1400_EOSRR, cy_align, 0); -#endif - } - } - - /* ensure an edge for the next interrupt */ - cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0); - - swi_sched(cy_slow_ih, SWI_DELAY); - - COM_UNLOCK(); - return (FILTER_HANDLED); -} - -static void -cybreak(struct tty *tp, int sig) -{ - struct com_s *com; - - com = tp->t_sc; - if (sig) - cd_etc(com, CD1400_ETC_SENDBREAK); - else - cd_etc(com, CD1400_ETC_STOPBREAK); -} - -static void -cypoll(void *arg) -{ - int unit; - -#ifdef CyDebug - ++cy_timeouts; -#endif - if (cy_events == 0) - return; -repeat: - for (unit = 0; unit < NPORTS; ++unit) { - struct com_s *com; - int incc; - struct tty *tp; - - com = cy_addr(unit); - if (com == NULL) - continue; - tp = com->tp; - if (tp == NULL) { - /* - * XXX forget any events related to closed devices - * (actually never opened devices) so that we don't - * loop. - */ - critical_enter(); - COM_LOCK(); - incc = com->iptr - com->ibuf; - com->iptr = com->ibuf; - if (com->state & CS_CHECKMSR) { - incc += LOTS_OF_EVENTS; - com->state &= ~CS_CHECKMSR; - } - cy_events -= incc; - COM_UNLOCK(); - critical_exit(); - if (incc != 0) - log(LOG_DEBUG, - "cy%d: %d events for device with no tp\n", - unit, incc); - continue; - } - if (com->iptr != com->ibuf) { - critical_enter(); - COM_LOCK(); - cyinput(com); - COM_UNLOCK(); - critical_exit(); - } - if (com->state & CS_CHECKMSR) { - u_char delta_modem_status; - - critical_enter(); - COM_LOCK(); - cyinput(com); - delta_modem_status = com->last_modem_status - ^ com->prev_modem_status; - com->prev_modem_status = com->last_modem_status; - cy_events -= LOTS_OF_EVENTS; - com->state &= ~CS_CHECKMSR; - COM_UNLOCK(); - critical_exit(); - if (delta_modem_status & CD1400_MSVR2_CD) - ttyld_modem(tp, - com->prev_modem_status & CD1400_MSVR2_CD); - } - if (com->extra_state & CSE_ODONE) { - critical_enter(); - COM_LOCK(); - cy_events -= LOTS_OF_EVENTS; - com->extra_state &= ~CSE_ODONE; - COM_UNLOCK(); - critical_exit(); - if (!(com->state & CS_BUSY)) { - tp->t_state &= ~TS_BUSY; - ttwwakeup(com->tp); - } - if (com->etc != ETC_NONE) { - if (com->etc == ETC_BREAK_ENDED) - com->etc = ETC_NONE; - wakeup(&com->etc); - } - } - if (com->state & CS_ODONE) { - critical_enter(); - COM_LOCK(); - cy_events -= LOTS_OF_EVENTS; - com->state &= ~CS_ODONE; - COM_UNLOCK(); - critical_exit(); - ttyld_start(tp); - } - if (cy_events == 0) - break; - } - if (cy_events >= LOTS_OF_EVENTS) - goto repeat; -} - -static int -cyparam(struct tty *tp, struct termios *t) -{ - int bits; - int cflag; - struct com_s *com; - u_char cor_change; - u_long cy_clock; - int idivisor; - int iflag; - int iprescaler; - int itimeout; - int odivisor; - int oprescaler; - u_char opt; - int s; - - com = tp->t_sc; - - /* check requested parameters */ - cy_clock = CY_CLOCK(com->gfrcr_image); - idivisor = cyspeed(t->c_ispeed, cy_clock, &iprescaler); - if (idivisor <= 0) - return (EINVAL); - odivisor = cyspeed(t->c_ospeed != 0 ? t->c_ospeed : tp->t_ospeed, - cy_clock, &oprescaler); - if (odivisor <= 0) - return (EINVAL); - - /* parameters are OK, convert them to the com struct and the device */ - s = spltty(); - if (t->c_ospeed == 0) - (void)cymodem(tp, 0, SER_DTR); - else - (void)cymodem(tp, SER_DTR, 0); - - (void) cysetwater(com, t->c_ispeed); - - /* XXX we don't actually change the speed atomically. */ - - cd_setreg(com, CD1400_RBPR, idivisor); - cd_setreg(com, CD1400_RCOR, iprescaler); - cd_setreg(com, CD1400_TBPR, odivisor); - cd_setreg(com, CD1400_TCOR, oprescaler); - - /* - * channel control - * receiver enable - * transmitter enable (always set) - */ - cflag = t->c_cflag; - opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN - | (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS); - if (opt != com->channel_control) { - com->channel_control = opt; - cd1400_channel_cmd(com, opt); - } - -#ifdef Smarts - /* set special chars */ - /* XXX if one is _POSIX_VDISABLE, can't use some others */ - if (t->c_cc[VSTOP] != _POSIX_VDISABLE) - cd_setreg(com, CD1400_SCHR1, t->c_cc[VSTOP]); - if (t->c_cc[VSTART] != _POSIX_VDISABLE) - cd_setreg(com, CD1400_SCHR2, t->c_cc[VSTART]); - if (t->c_cc[VINTR] != _POSIX_VDISABLE) - cd_setreg(com, CD1400_SCHR3, t->c_cc[VINTR]); - if (t->c_cc[VSUSP] != _POSIX_VDISABLE) - cd_setreg(com, CD1400_SCHR4, t->c_cc[VSUSP]); -#endif - - /* - * set channel option register 1 - - * parity mode - * stop bits - * char length - */ - opt = 0; - /* parity */ - if (cflag & PARENB) { - if (cflag & PARODD) - opt |= CD1400_COR1_PARODD; - opt |= CD1400_COR1_PARNORMAL; - } - iflag = t->c_iflag; - if (!(iflag & INPCK)) - opt |= CD1400_COR1_NOINPCK; - bits = 1 + 1; - /* stop bits */ - if (cflag & CSTOPB) { - ++bits; - opt |= CD1400_COR1_STOP2; - } - /* char length */ - switch (cflag & CSIZE) { - case CS5: - bits += 5; - opt |= CD1400_COR1_CS5; - break; - case CS6: - bits += 6; - opt |= CD1400_COR1_CS6; - break; - case CS7: - bits += 7; - opt |= CD1400_COR1_CS7; - break; - default: - bits += 8; - opt |= CD1400_COR1_CS8; - break; - } - cor_change = 0; - if (opt != com->cor[0]) { - cor_change |= CD1400_CCR_COR1; - cd_setreg(com, CD1400_COR1, com->cor[0] = opt); - } - - /* - * Set receive time-out period, normally to max(one char time, 5 ms). - */ - itimeout = howmany(1000 * bits, t->c_ispeed); -#ifdef SOFT_HOTCHAR -#define MIN_RTP 1 -#else -#define MIN_RTP 5 -#endif - if (itimeout < MIN_RTP) - itimeout = MIN_RTP; - if (!(t->c_lflag & ICANON) && t->c_cc[VMIN] != 0 && t->c_cc[VTIME] != 0 - && t->c_cc[VTIME] * 10 > itimeout) - itimeout = t->c_cc[VTIME] * 10; - if (itimeout > 255) - itimeout = 255; - cd_setreg(com, CD1400_RTPR, itimeout); - - /* - * set channel option register 2 - - * flow control - */ - opt = 0; -#ifdef Smarts - if (iflag & IXANY) - opt |= CD1400_COR2_IXANY; - if (iflag & IXOFF) - opt |= CD1400_COR2_IXOFF; -#endif -#ifndef SOFT_CTS_OFLOW - if (cflag & CCTS_OFLOW) - opt |= CD1400_COR2_CCTS_OFLOW; -#endif - critical_enter(); - COM_LOCK(); - if (opt != com->cor[1]) { - cor_change |= CD1400_CCR_COR2; - cd_setreg(com, CD1400_COR2, com->cor[1] = opt); - } - COM_UNLOCK(); - critical_exit(); - - /* - * set channel option register 3 - - * receiver FIFO interrupt threshold - * flow control - */ - opt = RxFifoThreshold; -#ifdef Smarts - if (t->c_lflag & ICANON) - opt |= CD1400_COR3_SCD34; /* detect INTR & SUSP chars */ - if (iflag & IXOFF) - /* detect and transparently handle START and STOP chars */ - opt |= CD1400_COR3_FCT | CD1400_COR3_SCD12; -#endif - if (opt != com->cor[2]) { - cor_change |= CD1400_CCR_COR3; - cd_setreg(com, CD1400_COR3, com->cor[2] = opt); - } - - /* notify the CD1400 if COR1-3 have changed */ - if (cor_change) - cd1400_channel_cmd(com, CD1400_CCR_CMDCORCHG | cor_change); - - /* - * set channel option register 4 - - * CR/NL processing - * break processing - * received exception processing - */ - opt = 0; - if (iflag & IGNCR) - opt |= CD1400_COR4_IGNCR; -#ifdef Smarts - /* - * we need a new ttyinput() for this, as we don't want to - * have ICRNL && INLCR being done in both layers, or to have - * synchronisation problems - */ - if (iflag & ICRNL) - opt |= CD1400_COR4_ICRNL; - if (iflag & INLCR) - opt |= CD1400_COR4_INLCR; -#endif - if (iflag & IGNBRK) - opt |= CD1400_COR4_IGNBRK | CD1400_COR4_NOBRKINT; - /* - * The `-ignbrk -brkint parmrk' case is not handled by the hardware, - * so only tell the hardware about -brkint if -parmrk. - */ - if (!(iflag & (BRKINT | PARMRK))) - opt |= CD1400_COR4_NOBRKINT; -#if 0 - /* XXX using this "intelligence" breaks reporting of overruns. */ - if (iflag & IGNPAR) - opt |= CD1400_COR4_PFO_DISCARD; - else { - if (iflag & PARMRK) - opt |= CD1400_COR4_PFO_ESC; - else - opt |= CD1400_COR4_PFO_NUL; - } -#else - opt |= CD1400_COR4_PFO_EXCEPTION; -#endif - cd_setreg(com, CD1400_COR4, opt); - - /* - * set channel option register 5 - - */ - opt = 0; - if (iflag & ISTRIP) - opt |= CD1400_COR5_ISTRIP; - if (t->c_iflag & IEXTEN) - /* enable LNEXT (e.g. ctrl-v quoting) handling */ - opt |= CD1400_COR5_LNEXT; -#ifdef Smarts - if (t->c_oflag & ONLCR) - opt |= CD1400_COR5_ONLCR; - if (t->c_oflag & OCRNL) - opt |= CD1400_COR5_OCRNL; -#endif - cd_setreg(com, CD1400_COR5, opt); - - /* - * We always generate modem status change interrupts for CD changes. - * Among other things, this is necessary to track TS_CARR_ON for - * pstat to print even when the driver doesn't care. CD changes - * should be rare so interrupts for them are not worth extra code to - * avoid. We avoid interrupts for other modem status changes (except - * for CTS changes when SOFT_CTS_OFLOW is configured) since this is - * simplest and best. - */ - - /* - * set modem change option register 1 - * generate modem interrupts on which 1 -> 0 input transitions - * also controls auto-DTR output flow-control, which we don't use - */ - opt = CD1400_MCOR1_CDzd; -#ifdef SOFT_CTS_OFLOW - if (cflag & CCTS_OFLOW) - opt |= CD1400_MCOR1_CTSzd; -#endif - cd_setreg(com, CD1400_MCOR1, opt); - - /* - * set modem change option register 2 - * generate modem interrupts on specific 0 -> 1 input transitions - */ - opt = CD1400_MCOR2_CDod; -#ifdef SOFT_CTS_OFLOW - if (cflag & CCTS_OFLOW) - opt |= CD1400_MCOR2_CTSod; -#endif - cd_setreg(com, CD1400_MCOR2, opt); - - /* - * XXX should have done this long ago, but there is too much state - * to change all atomically. - */ - critical_enter(); - COM_LOCK(); - - com->state &= ~CS_TTGO; - if (!(tp->t_state & TS_TTSTOP)) - com->state |= CS_TTGO; - if (cflag & CRTS_IFLOW) { - com->state |= CS_RTS_IFLOW; - /* - * If CS_RTS_IFLOW just changed from off to on, the change - * needs to be propagated to CD1400_MSVR1_RTS. This isn't urgent, - * so do it later by calling cystart() instead of repeating - * a lot of code from cystart() here. - */ - } else if (com->state & CS_RTS_IFLOW) { - com->state &= ~CS_RTS_IFLOW; - /* - * CS_RTS_IFLOW just changed from on to off. Force CD1400_MSVR1_RTS - * on here, since cystart() won't do it later. - */ - cd_setreg(com, com->mcr_rts_reg, - com->mcr_image |= com->mcr_rts); - } - - /* - * Set up state to handle output flow control. - * XXX - worth handling MDMBUF (DCD) flow control at the lowest level? - * Now has 10+ msec latency, while CTS flow has 50- usec latency. - */ - com->state |= CS_ODEVREADY; -#ifdef SOFT_CTS_OFLOW - com->state &= ~CS_CTS_OFLOW; - if (cflag & CCTS_OFLOW) { - com->state |= CS_CTS_OFLOW; - if (!(com->last_modem_status & CD1400_MSVR2_CTS)) - com->state &= ~CS_ODEVREADY; - } -#endif - /* XXX shouldn't call functions while intrs are disabled. */ - disc_optim(tp, t, com); -#if 0 - /* - * Recover from fiddling with CS_TTGO. We used to call cyintr1() - * unconditionally, but that defeated the careful discarding of - * stale input in cyopen(). - */ - if (com->state >= (CS_BUSY | CS_TTGO)) - cyintr1(com); -#endif - if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { - if (!(com->intr_enable & CD1400_SRER_TXRDY)) - cd_setreg(com, CD1400_SRER, - com->intr_enable - = (com->intr_enable & ~CD1400_SRER_TXMPTY) - | CD1400_SRER_TXRDY); - } else { - if (com->intr_enable & CD1400_SRER_TXRDY) - cd_setreg(com, CD1400_SRER, - com->intr_enable - = (com->intr_enable & ~CD1400_SRER_TXRDY) - | CD1400_SRER_TXMPTY); - } - - COM_UNLOCK(); - critical_exit(); - splx(s); - cystart(tp); - if (com->ibufold != NULL) { - free(com->ibufold, M_DEVBUF); - com->ibufold = NULL; - } - return (0); -} - -static int -cysetwater(struct com_s *com, speed_t speed) -{ - int cp4ticks; - u_char *ibuf; - int ibufsize; - struct tty *tp; - - /* - * Make the buffer size large enough to handle a softtty interrupt - * latency of about 2 ticks without loss of throughput or data - * (about 3 ticks if input flow control is not used or not honoured, - * but a bit less for CS5-CS7 modes). - */ - cp4ticks = speed / 10 / hz * 4; - for (ibufsize = 128; ibufsize < cp4ticks;) - ibufsize <<= 1; - if (ibufsize == com->ibufsize) { - return (0); - } - - /* - * Allocate input buffer. The extra factor of 2 in the size is - * to allow for an error byte for each input byte. - */ - ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT); - if (ibuf == NULL) { - return (ENOMEM); - } - - /* Initialize non-critical variables. */ - com->ibufold = com->ibuf; - com->ibufsize = ibufsize; - tp = com->tp; - if (tp != NULL) { - tp->t_ififosize = 2 * ibufsize; - tp->t_ispeedwat = (speed_t)-1; - tp->t_ospeedwat = (speed_t)-1; - } - - /* - * Read current input buffer, if any. Continue with interrupts - * disabled. - */ - critical_enter(); - COM_LOCK(); - if (com->iptr != com->ibuf) - cyinput(com); - - /*- - * Initialize critical variables, including input buffer watermarks. - * The external device is asked to stop sending when the buffer - * exactly reaches high water, or when the high level requests it. - * The high level is notified immediately (rather than at a later - * clock tick) when this watermark is reached. - * The buffer size is chosen so the watermark should almost never - * be reached. - * The low watermark is invisibly 0 since the buffer is always - * emptied all at once. - */ - com->iptr = com->ibuf = ibuf; - com->ibufend = ibuf + ibufsize; - com->ierroff = ibufsize; - com->ihighwater = ibuf + 3 * ibufsize / 4; - - COM_UNLOCK(); - critical_exit(); - return (0); -} - -static void -cystart(struct tty *tp) -{ - struct com_s *com; - int s; -#ifdef CyDebug - bool_t started; -#endif - - com = tp->t_sc; - s = spltty(); - -#ifdef CyDebug - ++com->start_count; - started = FALSE; -#endif - - critical_enter(); - COM_LOCK(); - if (tp->t_state & TS_TTSTOP) { - com->state &= ~CS_TTGO; - if (com->intr_enable & CD1400_SRER_TXRDY) - cd_setreg(com, CD1400_SRER, - com->intr_enable - = (com->intr_enable & ~CD1400_SRER_TXRDY) - | CD1400_SRER_TXMPTY); - } else { - com->state |= CS_TTGO; - if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY) - && !(com->intr_enable & CD1400_SRER_TXRDY)) - cd_setreg(com, CD1400_SRER, - com->intr_enable - = (com->intr_enable & ~CD1400_SRER_TXMPTY) - | CD1400_SRER_TXRDY); - } - if (tp->t_state & TS_TBLOCK) { - if (com->mcr_image & com->mcr_rts && com->state & CS_RTS_IFLOW) -#if 0 - outb(com->modem_ctl_port, com->mcr_image &= ~CD1400_MSVR1_RTS); -#else - cd_setreg(com, com->mcr_rts_reg, - com->mcr_image &= ~com->mcr_rts); -#endif - } else { - if (!(com->mcr_image & com->mcr_rts) - && com->iptr < com->ihighwater - && com->state & CS_RTS_IFLOW) -#if 0 - outb(com->modem_ctl_port, com->mcr_image |= CD1400_MSVR1_RTS); -#else - cd_setreg(com, com->mcr_rts_reg, - com->mcr_image |= com->mcr_rts); -#endif - } - COM_UNLOCK(); - critical_exit(); - if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { - ttwwakeup(tp); - splx(s); - return; - } - if (tp->t_outq.c_cc != 0) { - struct lbq *qp; - struct lbq *next; - - if (!com->obufs[0].l_queued) { -#ifdef CyDebug - started = TRUE; -#endif - com->obufs[0].l_tail - = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1, - sizeof com->obuf1); - com->obufs[0].l_next = NULL; - com->obufs[0].l_queued = TRUE; - critical_enter(); - COM_LOCK(); - if (com->state & CS_BUSY) { - qp = com->obufq.l_next; - while ((next = qp->l_next) != NULL) - qp = next; - qp->l_next = &com->obufs[0]; - } else { - com->obufq.l_head = com->obufs[0].l_head; - com->obufq.l_tail = com->obufs[0].l_tail; - com->obufq.l_next = &com->obufs[0]; - com->state |= CS_BUSY; - if (com->state >= (CS_BUSY | CS_TTGO - | CS_ODEVREADY)) - cd_setreg(com, CD1400_SRER, - com->intr_enable - = (com->intr_enable - & ~CD1400_SRER_TXMPTY) - | CD1400_SRER_TXRDY); - } - COM_UNLOCK(); - critical_exit(); - } - if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) { -#ifdef CyDebug - started = TRUE; -#endif - com->obufs[1].l_tail - = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2, - sizeof com->obuf2); - com->obufs[1].l_next = NULL; - com->obufs[1].l_queued = TRUE; - critical_enter(); - COM_LOCK(); - if (com->state & CS_BUSY) { - qp = com->obufq.l_next; - while ((next = qp->l_next) != NULL) - qp = next; - qp->l_next = &com->obufs[1]; - } else { - com->obufq.l_head = com->obufs[1].l_head; - com->obufq.l_tail = com->obufs[1].l_tail; - com->obufq.l_next = &com->obufs[1]; - com->state |= CS_BUSY; - if (com->state >= (CS_BUSY | CS_TTGO - | CS_ODEVREADY)) - cd_setreg(com, CD1400_SRER, - com->intr_enable - = (com->intr_enable - & ~CD1400_SRER_TXMPTY) - | CD1400_SRER_TXRDY); - } - COM_UNLOCK(); - critical_exit(); - } - tp->t_state |= TS_BUSY; - } -#ifdef CyDebug - if (started) - ++com->start_real; -#endif -#if 0 - critical_enter(); - COM_LOCK(); - if (com->state >= (CS_BUSY | CS_TTGO)) - cyintr1(com); /* fake interrupt to start output */ - COM_UNLOCK(); - critical_exit(); -#endif - ttwwakeup(tp); - splx(s); -} - -static void -comstop(struct tty *tp, int rw) -{ - struct com_s *com; - bool_t wakeup_etc; - - com = tp->t_sc; - wakeup_etc = FALSE; - critical_enter(); - COM_LOCK(); - if (rw & FWRITE) { - com->obufs[0].l_queued = FALSE; - com->obufs[1].l_queued = FALSE; - if (com->extra_state & CSE_ODONE) { - cy_events -= LOTS_OF_EVENTS; - com->extra_state &= ~CSE_ODONE; - if (com->etc != ETC_NONE) { - if (com->etc == ETC_BREAK_ENDED) - com->etc = ETC_NONE; - wakeup_etc = TRUE; - } - } - com->tp->t_state &= ~TS_BUSY; - if (com->state & CS_ODONE) - cy_events -= LOTS_OF_EVENTS; - com->state &= ~(CS_ODONE | CS_BUSY); - } - if (rw & FREAD) { - /* XXX no way to reset only input fifo. */ - cy_events -= (com->iptr - com->ibuf); - com->iptr = com->ibuf; - } - COM_UNLOCK(); - critical_exit(); - if (wakeup_etc) - wakeup(&com->etc); - if (rw & FWRITE && com->etc == ETC_NONE) - cd1400_channel_cmd(com, CD1400_CCR_CMDRESET | CD1400_CCR_FTF); - cystart(tp); -} - -static int -cymodem(struct tty *tp, int sigon, int sigoff) -{ - struct com_s *com; - int mcr; - int msr; - - com = tp->t_sc; - if (sigon == 0 && sigoff == 0) { - sigon = 0; - mcr = com->mcr_image; - if (mcr & com->mcr_dtr) - sigon |= SER_DTR; - if (mcr & com->mcr_rts) - /* XXX wired on for Cyclom-8Ys */ - sigon |= SER_RTS; - - /* - * We must read the modem status from the hardware because - * we don't generate modem status change interrupts for all - * changes, so com->prev_modem_status is not guaranteed to - * be up to date. This is safe, unlike for sio, because - * reading the status register doesn't clear pending modem - * status change interrupts. - */ - msr = cd_getreg(com, CD1400_MSVR2); - - if (msr & CD1400_MSVR2_CTS) - sigon |= SER_CTS; - if (msr & CD1400_MSVR2_CD) - sigon |= SER_DCD; - if (msr & CD1400_MSVR2_DSR) - sigon |= SER_DSR; - if (msr & CD1400_MSVR2_RI) - /* XXX not connected except for Cyclom-16Y? */ - sigon |= SER_RI; - return (sigon); - } - mcr = com->mcr_image; - if (sigon & SER_DTR) - mcr |= com->mcr_dtr; - if (sigoff & SER_DTR) - mcr &= ~com->mcr_dtr; - if (sigon & SER_RTS) - mcr |= com->mcr_rts; - if (sigoff & SER_RTS) - mcr &= ~com->mcr_rts; - critical_enter(); - COM_LOCK(); - com->mcr_image = mcr; - cd_setreg(com, CD1400_MSVR1, mcr); - cd_setreg(com, CD1400_MSVR2, mcr); - COM_UNLOCK(); - critical_exit(); - return (0); -} - -static void -cysettimeout() -{ - struct com_s *com; - bool_t someopen; - int unit; - - /* - * Set our timeout period to 1 second if no polled devices are open. - * Otherwise set it to max(1/200, 1/hz). - * Enable timeouts iff some device is open. - */ - untimeout(cywakeup, (void *)NULL, cy_timeout_handle); - cy_timeout = hz; - someopen = FALSE; - for (unit = 0; unit < NPORTS; ++unit) { - com = cy_addr(unit); - if (com != NULL && com->tp != NULL - && com->tp->t_state & TS_ISOPEN) { - someopen = TRUE; - } - } - if (someopen) { - cy_timeouts_until_log = hz / cy_timeout; - cy_timeout_handle = timeout(cywakeup, (void *)NULL, - cy_timeout); - } else { - /* Flush error messages, if any. */ - cy_timeouts_until_log = 1; - cywakeup((void *)NULL); - untimeout(cywakeup, (void *)NULL, cy_timeout_handle); - } -} - -static void -cywakeup(void *chan) -{ - struct com_s *com; - int unit; - - cy_timeout_handle = timeout(cywakeup, (void *)NULL, cy_timeout); - - /* - * Check for and log errors, but not too often. - */ - if (--cy_timeouts_until_log > 0) - return; - cy_timeouts_until_log = hz / cy_timeout; - for (unit = 0; unit < NPORTS; ++unit) { - int errnum; - - com = cy_addr(unit); - if (com == NULL) - continue; - for (errnum = 0; errnum < CE_NTYPES; ++errnum) { - u_int delta; - u_long total; - - critical_enter(); - COM_LOCK(); - delta = com->delta_error_counts[errnum]; - com->delta_error_counts[errnum] = 0; - COM_UNLOCK(); - critical_exit(); - if (delta == 0) - continue; - total = com->error_counts[errnum] += delta; - log(LOG_ERR, "cy%d: %u more %s%s (total %lu)\n", - unit, delta, error_desc[errnum], - delta == 1 ? "" : "s", total); - } - } -} - -static void -disc_optim(struct tty *tp, struct termios *t, struct com_s *com) -{ -#ifndef SOFT_HOTCHAR - u_char opt; -#endif - - ttyldoptim(tp); -#ifndef SOFT_HOTCHAR - opt = com->cor[2] & ~CD1400_COR3_SCD34; - if (com->tp->t_hotchar != 0) { - cd_setreg(com, CD1400_SCHR3, com->tp->t_hotchar); - cd_setreg(com, CD1400_SCHR4, com->tp->t_hotchar); - opt |= CD1400_COR3_SCD34; - } - if (opt != com->cor[2]) { - cd_setreg(com, CD1400_COR3, com->cor[2] = opt); - cd1400_channel_cmd(com, CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3); - } -#endif -} - -#ifdef Smarts -/* standard line discipline input routine */ -int -cyinput(int c, struct tty *tp) -{ - /* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK - * bits, as they are done by the CD1400. Hardly worth the effort, - * given that high-throughput session are raw anyhow. - */ -} -#endif /* Smarts */ - -static int -cyspeed(speed_t speed, u_long cy_clock, int *prescaler_io) -{ - int actual; - int error; - int divider; - int prescaler; - int prescaler_unit; - - if (speed == 0) - return (0); - if (speed < 0 || speed > 150000) - return (-1); - - /* determine which prescaler to use */ - for (prescaler_unit = 4, prescaler = 2048; prescaler_unit; - prescaler_unit--, prescaler >>= 2) { - if (cy_clock / prescaler / speed > 63) - break; - } - - divider = (cy_clock / prescaler * 2 / speed + 1) / 2; /* round off */ - if (divider > 255) - divider = 255; - actual = cy_clock/prescaler/divider; - - /* 10 times error in percent: */ - error = ((actual - (long)speed) * 2000 / (long)speed + 1) / 2; - - /* 3.0% max error tolerance */ - if (error < -30 || error > 30) - return (-1); - - *prescaler_io = prescaler_unit; - return (divider); -} - -static void -cd1400_channel_cmd(struct com_s *com, int cmd) -{ - cd1400_channel_cmd_wait(com); - cd_setreg(com, CD1400_CCR, cmd); - cd1400_channel_cmd_wait(com); -} - -static void -cd1400_channel_cmd_wait(struct com_s *com) -{ - struct timeval start; - struct timeval tv; - long usec; - - if (cd_getreg(com, CD1400_CCR) == 0) - return; - microtime(&start); - for (;;) { - if (cd_getreg(com, CD1400_CCR) == 0) - return; - microtime(&tv); - usec = 1000000 * (tv.tv_sec - start.tv_sec) + - tv.tv_usec - start.tv_usec; - if (usec >= 5000) { - log(LOG_ERR, - "cy%d: channel command timeout (%ld usec)\n", - com->unit, usec); - return; - } - } -} - -static void -cd_etc(struct com_s *com, int etc) -{ - - /* - * We can't change the hardware's ETC state while there are any - * characters in the tx fifo, since those characters would be - * interpreted as commands! Unputting characters from the fifo - * is difficult, so we wait up to 12 character times for the fifo - * to drain. The command will be delayed for up to 2 character - * times for the tx to become empty. Unputting characters from - * the tx holding and shift registers is impossible, so we wait - * for the tx to become empty so that the command is sure to be - * executed soon after we issue it. - */ - critical_enter(); - COM_LOCK(); - if (com->etc == etc) - goto wait; - if ((etc == CD1400_ETC_SENDBREAK - && (com->etc == ETC_BREAK_STARTING - || com->etc == ETC_BREAK_STARTED)) - || (etc == CD1400_ETC_STOPBREAK - && (com->etc == ETC_BREAK_ENDING || com->etc == ETC_BREAK_ENDED - || com->etc == ETC_NONE))) { - COM_UNLOCK(); - critical_exit(); - return; - } - com->etc = etc; - cd_setreg(com, CD1400_SRER, - com->intr_enable - = (com->intr_enable & ~CD1400_SRER_TXRDY) | CD1400_SRER_TXMPTY); -wait: - COM_UNLOCK(); - critical_exit(); - while (com->etc == etc - && tsleep(&com->etc, TTIPRI | PCATCH, "cyetc", 0) == 0) - continue; -} - -static int -cd_getreg(struct com_s *com, int reg) -{ - struct com_s *basecom; - u_char car; - int cy_align; - cy_addr iobase; -#ifdef SMP - int need_unlock; -#endif - int val; - - basecom = cy_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1)); - car = com->unit & CD1400_CAR_CHAN; - cy_align = com->cy_align; - iobase = com->iobase; - critical_enter(); -#ifdef SMP - need_unlock = 0; - if (!mtx_owned(&cy_lock)) { - COM_LOCK(); - need_unlock = 1; - } -#endif - if (basecom->car != car) - cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car); - val = cd_inb(iobase, reg, cy_align); -#ifdef SMP - if (need_unlock) - COM_UNLOCK(); -#endif - critical_exit(); - return (val); -} - -static void -cd_setreg(struct com_s *com, int reg, int val) -{ - struct com_s *basecom; - u_char car; - int cy_align; - cy_addr iobase; -#ifdef SMP - int need_unlock; -#endif - - basecom = cy_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1)); - car = com->unit & CD1400_CAR_CHAN; - cy_align = com->cy_align; - iobase = com->iobase; - critical_enter(); -#ifdef SMP - need_unlock = 0; - if (!mtx_owned(&cy_lock)) { - COM_LOCK(); - need_unlock = 1; - } -#endif - if (basecom->car != car) - cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car); - cd_outb(iobase, reg, cy_align, val); -#ifdef SMP - if (need_unlock) - COM_UNLOCK(); -#endif - critical_exit(); -} - -#ifdef CyDebug -/* useful in ddb */ -void -cystatus(int unit) -{ - struct com_s *com; - cy_addr iobase; - u_int ocount; - struct tty *tp; - - com = cy_addr(unit); - printf("info for channel %d\n", unit); - printf("------------------\n"); - printf("total cyclom service probes:\t%d\n", cy_svrr_probes); - printf("calls to upper layer:\t\t%d\n", cy_timeouts); - if (com == NULL) - return; - iobase = com->iobase; - printf("\n"); - printf("cd1400 base address:\\tt%p\n", iobase); - printf("saved channel_control:\t\t0x%02x\n", com->channel_control); - printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n", - com->cor[0], com->cor[1], com->cor[2]); - printf("service request enable reg:\t0x%02x (0x%02x cached)\n", - cd_getreg(com, CD1400_SRER), com->intr_enable); - printf("service request register:\t0x%02x\n", - cd_inb(iobase, CD1400_SVRR, com->cy_align)); - printf("modem status:\t\t\t0x%02x (0x%02x cached)\n", - cd_getreg(com, CD1400_MSVR2), com->prev_modem_status); - printf("rx/tx/mdm interrupt registers:\t0x%02x 0x%02x 0x%02x\n", - cd_inb(iobase, CD1400_RIR, com->cy_align), - cd_inb(iobase, CD1400_TIR, com->cy_align), - cd_inb(iobase, CD1400_MIR, com->cy_align)); - printf("\n"); - printf("com state:\t\t\t0x%02x\n", com->state); - printf("calls to cystart():\t\t%d (%d useful)\n", - com->start_count, com->start_real); - printf("rx buffer chars free:\t\t%d\n", com->iptr - com->ibuf); - ocount = 0; - if (com->obufs[0].l_queued) - ocount += com->obufs[0].l_tail - com->obufs[0].l_head; - if (com->obufs[1].l_queued) - ocount += com->obufs[1].l_tail - com->obufs[1].l_head; - printf("tx buffer chars:\t\t%u\n", ocount); - printf("received chars:\t\t\t%d\n", com->bytes_in); - printf("received exceptions:\t\t%d\n", com->recv_exception); - printf("modem signal deltas:\t\t%d\n", com->mdm); - printf("transmitted chars:\t\t%d\n", com->bytes_out); - printf("\n"); - tp = com->tp; - if (tp != NULL) { - printf("tty state:\t\t\t0x%08x\n", tp->t_state); - printf( - "upper layer queue lengths:\t%d raw, %d canon, %d output\n", - tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc); - } else - printf("tty state:\t\t\tclosed\n"); -} -#endif /* CyDebug */ diff --git a/sys/dev/cy/cy_isa.c b/sys/dev/cy/cy_isa.c deleted file mode 100644 index a53da4fc33e6..000000000000 --- a/sys/dev/cy/cy_isa.c +++ /dev/null @@ -1,152 +0,0 @@ -/*- - * cyclades cyclom-y serial driver - * Andrew Herbert , 17 August 1993 - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 1993 Andrew Herbert. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name Andrew Herbert may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Cyclades Y ISA serial interface driver - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include - -static int cy_isa_attach(device_t dev); -static int cy_isa_probe(device_t dev); - -static device_method_t cy_isa_methods[] = { - /* Device interface. */ - DEVMETHOD(device_probe, cy_isa_probe), - DEVMETHOD(device_attach, cy_isa_attach), - - { 0, 0 } -}; - -static driver_t cy_isa_driver = { - cy_driver_name, - cy_isa_methods, - 0, -}; - -DRIVER_MODULE(cy, isa, cy_isa_driver, cy_devclass, 0, 0); - -static int -cy_isa_probe(device_t dev) -{ - struct resource *mem_res; - cy_addr iobase; - int error, mem_rid; - - if (isa_get_logicalid(dev) != 0) /* skip PnP probes */ - return (ENXIO); - - mem_rid = 0; - mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &mem_rid, - RF_ACTIVE); - if (mem_res == NULL) { - device_printf(dev, "ioport resource allocation failed\n"); - return (ENXIO); - } - iobase = rman_get_virtual(mem_res); - - /* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */ - cy_inb(iobase, CY16_RESET, 0); /* XXX? */ - DELAY(500); /* wait for the board to get its act together */ - - /* this is needed to get the board out of reset */ - cy_outb(iobase, CY_CLEAR_INTR, 0, 0); - DELAY(500); - - error = (cy_units(iobase, 0) == 0 ? ENXIO : 0); - bus_release_resource(dev, SYS_RES_MEMORY, mem_rid, mem_res); - return (error); -} - -static int -cy_isa_attach(device_t dev) -{ - struct resource *irq_res, *mem_res; - void *irq_cookie, *vaddr, *vsc; - int irq_rid, mem_rid; - - irq_res = NULL; - mem_res = NULL; - - mem_rid = 0; - mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &mem_rid, - RF_ACTIVE); - if (mem_res == NULL) { - device_printf(dev, "memory resource allocation failed\n"); - goto fail; - } - vaddr = rman_get_virtual(mem_res); - - vsc = cyattach_common(vaddr, 0); - if (vsc == NULL) { - device_printf(dev, "no ports found!\n"); - goto fail; - } - - irq_rid = 0; - irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irq_rid, - RF_SHAREABLE | RF_ACTIVE); - if (irq_res == NULL) { - device_printf(dev, "interrupt resource allocation failed\n"); - goto fail; - } - if (bus_setup_intr(dev, irq_res, INTR_TYPE_TTY, - cyintr, NULL, vsc, &irq_cookie) != 0) { - device_printf(dev, "interrupt setup failed\n"); - goto fail; - } - - return (0); - -fail: - if (irq_res != NULL) - bus_release_resource(dev, SYS_RES_IRQ, irq_rid, irq_res); - if (mem_res != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, mem_rid, mem_res); - return (ENXIO); -} diff --git a/sys/dev/cy/cy_pci.c b/sys/dev/cy/cy_pci.c deleted file mode 100644 index 4bd833e27b19..000000000000 --- a/sys/dev/cy/cy_pci.c +++ /dev/null @@ -1,194 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 1996, David Greenman - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Cyclades Y PCI serial interface driver - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "opt_cy_pci_fastintr.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include - -#define CY_PCI_BASE_ADDR0 0x10 -#define CY_PCI_BASE_ADDR1 0x14 -#define CY_PCI_BASE_ADDR2 0x18 - -#define CY_PLX_9050_ICS 0x4c -#define CY_PLX_9060_ICS 0x68 -#define CY_PLX_9050_ICS_IENABLE 0x040 -#define CY_PLX_9050_ICS_LOCAL_IENABLE 0x001 -#define CY_PLX_9050_ICS_LOCAL_IPOLARITY 0x002 -#define CY_PLX_9060_ICS_IENABLE 0x100 -#define CY_PLX_9060_ICS_LOCAL_IENABLE 0x800 - -/* Cyclom-Y Custom Register for PLX ID. */ -#define PLX_VER 0x3400 -#define PLX_9050 0x0b -#define PLX_9060 0x0c -#define PLX_9080 0x0d - -static int cy_pci_attach(device_t dev); -static int cy_pci_probe(device_t dev); - -static device_method_t cy_pci_methods[] = { - /* Device interface. */ - DEVMETHOD(device_probe, cy_pci_probe), - DEVMETHOD(device_attach, cy_pci_attach), - - { 0, 0 } -}; - -static driver_t cy_pci_driver = { - cy_driver_name, - cy_pci_methods, - 0, -}; - -DRIVER_MODULE(cy, pci, cy_pci_driver, cy_devclass, 0, 0); -MODULE_DEPEND(cy, pci, 1, 1, 1); - -static int -cy_pci_probe(dev) - device_t dev; -{ - u_int32_t device_id; - - device_id = pci_get_devid(dev); - device_id &= ~0x00060000; - if (device_id != 0x0100120e && device_id != 0x0101120e) - return (ENXIO); - device_set_desc(dev, "Cyclades Cyclom-Y Serial Adapter"); - return (BUS_PROBE_DEFAULT); -} - -static int -cy_pci_attach(dev) - device_t dev; -{ - struct resource *ioport_res, *irq_res, *mem_res; - void *irq_cookie, *vaddr, *vsc; - u_int32_t ioport; - int irq_setup, ioport_rid, irq_rid, mem_rid; - u_char plx_ver; - - ioport_res = NULL; - irq_res = NULL; - mem_res = NULL; - - ioport_rid = CY_PCI_BASE_ADDR1; - ioport_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &ioport_rid, - RF_ACTIVE); - if (ioport_res == NULL) { - device_printf(dev, "ioport resource allocation failed\n"); - goto fail; - } - ioport = rman_get_start(ioport_res); - - mem_rid = CY_PCI_BASE_ADDR2; - mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &mem_rid, - RF_ACTIVE); - if (mem_res == NULL) { - device_printf(dev, "memory resource allocation failed\n"); - goto fail; - } - vaddr = rman_get_virtual(mem_res); - - vsc = cyattach_common(vaddr, 1); - if (vsc == NULL) { - device_printf(dev, "no ports found!\n"); - goto fail; - } - - irq_rid = 0; - irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irq_rid, - RF_SHAREABLE | RF_ACTIVE); - if (irq_res == NULL) { - device_printf(dev, "interrupt resource allocation failed\n"); - goto fail; - } -#ifdef CY_PCI_FASTINTR - irq_setup = bus_setup_intr(dev, irq_res, INTR_TYPE_TTY, - cyintr, NULL, vsc, &irq_cookie); -#else - irq_setup = ENXIO; -#endif - if (irq_setup != 0) - irq_setup = bus_setup_intr(dev, irq_res, INTR_TYPE_TTY, - NULL, (driver_intr_t *)cyintr, vsc, &irq_cookie); - if (irq_setup != 0) { - device_printf(dev, "interrupt setup failed\n"); - goto fail; - } - - /* - * Enable the "local" interrupt input to generate a - * PCI interrupt. - */ - plx_ver = *((u_char *)vaddr + PLX_VER) & 0x0f; - switch (plx_ver) { - case PLX_9050: - outw(ioport + CY_PLX_9050_ICS, - CY_PLX_9050_ICS_IENABLE | CY_PLX_9050_ICS_LOCAL_IENABLE | - CY_PLX_9050_ICS_LOCAL_IPOLARITY); - break; - case PLX_9060: - case PLX_9080: - default: /* Old board, use PLX_9060 values. */ - outw(ioport + CY_PLX_9060_ICS, - inw(ioport + CY_PLX_9060_ICS) | CY_PLX_9060_ICS_IENABLE | - CY_PLX_9060_ICS_LOCAL_IENABLE); - break; - } - - return (0); - -fail: - if (ioport_res != NULL) - bus_release_resource(dev, SYS_RES_IOPORT, ioport_rid, - ioport_res); - if (irq_res != NULL) - bus_release_resource(dev, SYS_RES_IRQ, irq_rid, irq_res); - if (mem_res != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, mem_rid, mem_res); - return (ENXIO); -} diff --git a/sys/dev/cy/cyreg.h b/sys/dev/cy/cyreg.h deleted file mode 100644 index bb29064b471e..000000000000 --- a/sys/dev/cy/cyreg.h +++ /dev/null @@ -1,77 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 1995 Bruce Evans. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the author nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * Definitions for Cyclades Cyclom-Y serial boards. - */ - -/* - * Cyclades register offsets. These are physical offsets for ISA boards - * and physical offsets divided by 2 for PCI boards. - */ -#define CY8_SVCACKR 0x100 /* (r) */ -#define CY8_SVCACKT 0x200 /* (r) */ -#define CY8_SVCACKM 0x300 /* (r) */ -#define CY16_RESET 0x1400 /* (r) */ -#define CY_CLEAR_INTR 0x1800 /* intr ack address (w) */ - -#define CY_MAX_CD1400s 8 /* for Cyclom-32Y */ - -#define CY_CLOCK(version) ((version) >= 0x48 ? 60000000 : 25000000) -#define CY_RTS_DTR_SWAPPED(version) ((version) >= 0x48) - -/* - * The `cd' macros are for access to cd1400 registers. The `cy' macros - * are for access to Cyclades registers. Both sets of macros scale the - * register number to get an offset, but the scales are different for - * mostly historical reasons. - */ -#ifdef CyDebug -#define cd_inb(iobase, reg, cy_align) \ - (++cd_inbs, *((iobase) + (2 * (reg) << (cy_align)))) -#define cy_inb(iobase, reg, cy_align) \ - (++cy_inbs, *((iobase) + ((reg) << (cy_align)))) -#define cd_outb(iobase, reg, cy_align, val) \ - (++cd_outbs, (void)(*((iobase) + (2 * (reg) << (cy_align))) = (val))) -#define cy_outb(iobase, reg, cy_align, val) \ - (++cy_outbs, (void)(*((iobase) + ((reg) << (cy_align))) = (val))) -#else -#define cd_inb(iobase, reg, cy_align) \ - (*((iobase) + (2 * (reg) << (cy_align)))) -#define cy_inb(iobase, reg, cy_align) \ - (*((iobase) + ((reg) << (cy_align)))) -#define cd_outb(iobase, reg, cy_align, val) \ - ((void)(*((iobase) + (2 * (reg) << (cy_align))) = (val))) -#define cy_outb(iobase, reg, cy_align, val) \ - ((void)(*((iobase) + ((reg) << (cy_align))) = (val))) -#endif diff --git a/sys/dev/cy/cyvar.h b/sys/dev/cy/cyvar.h deleted file mode 100644 index 0289ecba4f3e..000000000000 --- a/sys/dev/cy/cyvar.h +++ /dev/null @@ -1,38 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2004 Bruce D. Evans - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -typedef u_char volatile *cy_addr; - -extern devclass_t cy_devclass; -extern char cy_driver_name[]; - -void *cyattach_common(cy_addr cy_iobase, int cy_align); -driver_filter_t cyintr; -int cy_units(cy_addr cy_iobase, int cy_align); diff --git a/sys/dev/rc/rc.c b/sys/dev/rc/rc.c deleted file mode 100644 index c4c4370af5fe..000000000000 --- a/sys/dev/rc/rc.c +++ /dev/null @@ -1,1314 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 1995 by Pavel Antonov, Moscow, Russia. - * Copyright (C) 1995 by Andrey A. Chernov, Moscow, Russia. - * All rights reserved. - * Copyright (C) 2002 by John Baldwin - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * SDL Communications Riscom/8 (based on Cirrus Logic CL-CD180) driver - * - */ - -/*#define RCDEBUG*/ - -#include "opt_tty.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define IOBASE_ADDRS 14 - -#define rcin(sc, port) RC_IN(sc, port) -#define rcout(sc, port, v) RC_OUT(sc, port, v) - -#define WAITFORCCR(sc, chan) rc_wait0((sc), (chan), __LINE__) - -#define CCRCMD(sc, chan, cmd) do { \ - WAITFORCCR((sc), (chan)); \ - rcout((sc), CD180_CCR, (cmd)); \ -} while (0) - -#define RC_IBUFSIZE 256 -#define RB_I_HIGH_WATER (TTYHOG - 2 * RC_IBUFSIZE) -#define RC_OBUFSIZE 512 -#define RC_IHIGHWATER (3 * RC_IBUFSIZE / 4) -#define INPUT_FLAGS_SHIFT (2 * RC_IBUFSIZE) -#define LOTS_OF_EVENTS 64 - -#define RC_FAKEID 0x10 - -/* Per-channel structure */ -struct rc_chans { - struct rc_softc *rc_rcb; /* back ptr */ - u_short rc_flags; /* Misc. flags */ - int rc_chan; /* Channel # */ - u_char rc_ier; /* intr. enable reg */ - u_char rc_msvr; /* modem sig. status */ - u_char rc_cor2; /* options reg */ - u_char rc_pendcmd; /* special cmd pending */ - u_int rc_dcdwaits; /* how many waits DCD in open */ - struct tty *rc_tp; /* tty struct */ - u_char *rc_iptr; /* Chars input buffer */ - u_char *rc_hiwat; /* hi-water mark */ - u_char *rc_bufend; /* end of buffer */ - u_char *rc_optr; /* ptr in output buf */ - u_char *rc_obufend; /* end of output buf */ - u_char rc_ibuf[4 * RC_IBUFSIZE]; /* input buffer */ - u_char rc_obuf[RC_OBUFSIZE]; /* output buffer */ - struct callout rc_dtrcallout; -}; - -/* Per-board structure */ -struct rc_softc { - device_t sc_dev; - struct resource *sc_irq; - struct resource *sc_port[IOBASE_ADDRS]; - int sc_irqrid; - void *sc_hwicookie; - bus_space_tag_t sc_bt; - bus_space_handle_t sc_bh; - u_int sc_unit; /* unit # */ - u_char sc_dtr; /* DTR status */ - int sc_scheduled_event; - void *sc_swicookie; - struct rc_chans sc_channels[CD180_NCHAN]; /* channels */ -}; - -/* Static prototypes */ -static t_close_t rc_close; -static void rc_break(struct tty *, int); -static void rc_release_resources(device_t dev); -static void rc_intr(void *); -static void rc_hwreset(struct rc_softc *, unsigned int); -static int rc_test(struct rc_softc *); -static void rc_discard_output(struct rc_chans *); -static int rc_modem(struct tty *, int, int); -static void rc_start(struct tty *); -static void rc_stop(struct tty *, int rw); -static int rc_param(struct tty *, struct termios *); -static void rc_pollcard(void *); -static void rc_reinit(struct rc_softc *); -#ifdef RCDEBUG -static void printrcflags(); -#endif -static void rc_wait0(struct rc_softc *sc, int chan, int line); - -static devclass_t rc_devclass; - -/* Flags */ -#define RC_DTR_OFF 0x0001 /* DTR wait, for close/open */ -#define RC_ACTOUT 0x0002 /* Dial-out port active */ -#define RC_RTSFLOW 0x0004 /* RTS flow ctl enabled */ -#define RC_CTSFLOW 0x0008 /* CTS flow ctl enabled */ -#define RC_DORXFER 0x0010 /* RXFER event planned */ -#define RC_DOXXFER 0x0020 /* XXFER event planned */ -#define RC_MODCHG 0x0040 /* Modem status changed */ -#define RC_OSUSP 0x0080 /* Output suspended */ -#define RC_OSBUSY 0x0100 /* start() routine in progress */ -#define RC_WAS_BUFOVFL 0x0200 /* low-level buffer ovferflow */ -#define RC_WAS_SILOVFL 0x0400 /* silo buffer overflow */ -#define RC_SEND_RDY 0x0800 /* ready to send */ - -/* Table for translation of RCSR status bits to internal form */ -static int rc_rcsrt[16] = { - 0, TTY_OE, TTY_FE, - TTY_FE|TTY_OE, TTY_PE, TTY_PE|TTY_OE, - TTY_PE|TTY_FE, TTY_PE|TTY_FE|TTY_OE, TTY_BI, - TTY_BI|TTY_OE, TTY_BI|TTY_FE, TTY_BI|TTY_FE|TTY_OE, - TTY_BI|TTY_PE, TTY_BI|TTY_PE|TTY_OE, TTY_BI|TTY_PE|TTY_FE, - TTY_BI|TTY_PE|TTY_FE|TTY_OE -}; - -static int rc_ports[] = - { 0x220, 0x240, 0x250, 0x260, 0x2a0, 0x2b0, 0x300, 0x320 }; -static int iobase_addrs[IOBASE_ADDRS] = - { 0, 0x400, 0x800, 0xc00, 0x1400, 0x1800, 0x1c00, 0x2000, - 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x8000 }; - -/**********************************************/ - -static int -rc_probe(device_t dev) -{ - u_int port; - int i, found; - - /* - * We don't know of any PnP ID's for these cards. - */ - if (isa_get_logicalid(dev) != 0) - return (ENXIO); - - /* - * We have to have an IO port hint that is valid. - */ - port = isa_get_port(dev); - if (port == -1) - return (ENXIO); - found = 0; - for (i = 0; i < nitems(rc_ports); i++) - if (rc_ports[i] == port) { - found = 1; - break; - } - if (!found) - return (ENXIO); - - /* - * We have to have an IRQ hint. - */ - if (isa_get_irq(dev) == -1) - return (ENXIO); - - device_set_desc(dev, "SDL Riscom/8"); - return (0); -} - -static int -rc_attach(device_t dev) -{ - struct rc_chans *rc; - struct tty *tp; - struct rc_softc *sc; - u_int port; - int base, chan, error, i, x; - - sc = device_get_softc(dev); - sc->sc_dev = dev; - - /* - * We need to have IO ports. Lots of them. We need - * the following ranges relative to the base port: - * 0x0 - 0x10 - * 0x400 - 0x410 - * 0x800 - 0x810 - * 0xc00 - 0xc10 - * 0x1400 - 0x1410 - * 0x1800 - 0x1810 - * 0x1c00 - 0x1c10 - * 0x2000 - 0x2010 - * 0x3000 - 0x3010 - * 0x3400 - 0x3410 - * 0x3800 - 0x3810 - * 0x3c00 - 0x3c10 - * 0x4000 - 0x4010 - * 0x8000 - 0x8010 - */ - port = isa_get_port(dev); - for (i = 0; i < IOBASE_ADDRS; i++) - if (bus_set_resource(dev, SYS_RES_IOPORT, i, - port + iobase_addrs[i], 0x10) != 0) - return (ENXIO); - error = ENOMEM; - for (i = 0; i < IOBASE_ADDRS; i++) { - x = i; - sc->sc_port[i] = bus_alloc_resource_anywhere(dev, - SYS_RES_IOPORT, &x, 0x10, RF_ACTIVE); - if (x != i) { - device_printf(dev, "ioport %d was rid %d\n", i, x); - goto fail; - } - if (sc->sc_port[i] == NULL) { - device_printf(dev, "failed to alloc ioports %x-%x\n", - port + iobase_addrs[i], - port + iobase_addrs[i] + 0x10); - goto fail; - } - } - sc->sc_bt = rman_get_bustag(sc->sc_port[0]); - sc->sc_bh = rman_get_bushandle(sc->sc_port[0]); - - sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqrid, - RF_ACTIVE); - if (sc->sc_irq == NULL) { - device_printf(dev, "failed to alloc IRQ\n"); - goto fail; - } - - /* - * Now do some actual tests to make sure it works. - */ - error = ENXIO; - rcout(sc, CD180_PPRL, 0x22); /* Random values to Prescale reg. */ - rcout(sc, CD180_PPRH, 0x11); - if (rcin(sc, CD180_PPRL) != 0x22 || rcin(sc, CD180_PPRH) != 0x11) - goto fail; - if (rc_test(sc)) - goto fail; - - /* - * Ok, start actually hooking things up. - */ - sc->sc_unit = device_get_unit(dev); - /*sc->sc_chipid = 0x10 + device_get_unit(dev);*/ - device_printf(dev, "%d chans, firmware rev. %c\n", - CD180_NCHAN, (rcin(sc, CD180_GFRCR) & 0xF) + 'A'); - rc = sc->sc_channels; - base = CD180_NCHAN * sc->sc_unit; - for (chan = 0; chan < CD180_NCHAN; chan++, rc++) { - rc->rc_rcb = sc; - rc->rc_chan = chan; - rc->rc_iptr = rc->rc_ibuf; - rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; - rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; - rc->rc_optr = rc->rc_obufend = rc->rc_obuf; - callout_init(&rc->rc_dtrcallout, 0); - tp = rc->rc_tp = ttyalloc(); - tp->t_sc = rc; - tp->t_oproc = rc_start; - tp->t_param = rc_param; - tp->t_modem = rc_modem; - tp->t_break = rc_break; - tp->t_close = rc_close; - tp->t_stop = rc_stop; - ttycreate(tp, TS_CALLOUT, "m%d", chan + base); - } - - error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_TTY, NULL, rc_intr, - sc, &sc->sc_hwicookie); - if (error) { - device_printf(dev, "failed to register interrupt handler\n"); - goto fail; - } - - swi_add(&tty_intr_event, "rc", rc_pollcard, sc, SWI_TTY, 0, - &sc->sc_swicookie); - return (0); - -fail: - rc_release_resources(dev); - return (error); -} - -static int -rc_detach(device_t dev) -{ - struct rc_softc *sc; - struct rc_chans *rc; - int error, i; - - sc = device_get_softc(dev); - - rc = sc->sc_channels; - for (i = 0; i < CD180_NCHAN; i++, rc++) - ttyfree(rc->rc_tp); - - error = bus_teardown_intr(dev, sc->sc_irq, sc->sc_hwicookie); - if (error) - device_printf(dev, "failed to deregister interrupt handler\n"); - swi_remove(sc->sc_swicookie); - rc_release_resources(dev); - - return (0); -} - -static void -rc_release_resources(device_t dev) -{ - struct rc_softc *sc; - int i; - - sc = device_get_softc(dev); - if (sc->sc_irq != NULL) { - bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, - sc->sc_irq); - sc->sc_irq = NULL; - } - for (i = 0; i < IOBASE_ADDRS; i++) { - if (sc->sc_port[i] == NULL) - break; - bus_release_resource(dev, SYS_RES_IOPORT, i, sc->sc_port[i]); - sc->sc_port[i] = NULL; - } -} - -/* RC interrupt handling */ -static void -rc_intr(void *arg) -{ - struct rc_softc *sc; - struct rc_chans *rc; - int resid, chan; - u_char val, iack, bsr, ucnt, *optr; - int good_data, t_state; - - sc = (struct rc_softc *)arg; - bsr = ~(rcin(sc, RC_BSR)); - if (!(bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT))) { - device_printf(sc->sc_dev, "extra interrupt\n"); - rcout(sc, CD180_EOIR, 0); - return; - } - - while (bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT)) { -#ifdef RCDEBUG_DETAILED - device_printf(sc->sc_dev, "intr (%p) %s%s%s%s\n", arg, bsr, - (bsr & RC_BSR_TOUT)?"TOUT ":"", - (bsr & RC_BSR_RXINT)?"RXINT ":"", - (bsr & RC_BSR_TXINT)?"TXINT ":"", - (bsr & RC_BSR_MOINT)?"MOINT":""); -#endif - if (bsr & RC_BSR_TOUT) { - device_printf(sc->sc_dev, - "hardware failure, reset board\n"); - rcout(sc, RC_CTOUT, 0); - rc_reinit(sc); - return; - } - if (bsr & RC_BSR_RXINT) { - iack = rcin(sc, RC_PILR_RX); - good_data = (iack == (GIVR_IT_RGDI | RC_FAKEID)); - if (!good_data && iack != (GIVR_IT_REI | RC_FAKEID)) { - device_printf(sc->sc_dev, - "fake rxint: %02x\n", iack); - goto more_intrs; - } - chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); - rc = &sc->sc_channels[chan]; - t_state = rc->rc_tp->t_state; - /* Do RTS flow control stuff */ - if ( (rc->rc_flags & RC_RTSFLOW) - || !(t_state & TS_ISOPEN) - ) { - if ( ( !(t_state & TS_ISOPEN) - || (t_state & TS_TBLOCK) - ) - && (rc->rc_msvr & MSVR_RTS) - ) - rcout(sc, CD180_MSVR, - rc->rc_msvr &= ~MSVR_RTS); - else if (!(rc->rc_msvr & MSVR_RTS)) - rcout(sc, CD180_MSVR, - rc->rc_msvr |= MSVR_RTS); - } - ucnt = rcin(sc, CD180_RDCR) & 0xF; - resid = 0; - - if (t_state & TS_ISOPEN) { - /* check for input buffer overflow */ - if ((rc->rc_iptr + ucnt) >= rc->rc_bufend) { - resid = ucnt; - ucnt = rc->rc_bufend - rc->rc_iptr; - resid -= ucnt; - if (!(rc->rc_flags & RC_WAS_BUFOVFL)) { - rc->rc_flags |= RC_WAS_BUFOVFL; - sc->sc_scheduled_event++; - } - } - optr = rc->rc_iptr; - /* check foor good data */ - if (good_data) { - while (ucnt-- > 0) { - val = rcin(sc, CD180_RDR); - optr[0] = val; - optr[INPUT_FLAGS_SHIFT] = 0; - optr++; - sc->sc_scheduled_event++; - if (val != 0 && val == rc->rc_tp->t_hotchar) - swi_sched(sc->sc_swicookie, 0); - } - } else { - /* Store also status data */ - while (ucnt-- > 0) { - iack = rcin(sc, CD180_RCSR); - if (iack & RCSR_Timeout) - break; - if ( (iack & RCSR_OE) - && !(rc->rc_flags & RC_WAS_SILOVFL)) { - rc->rc_flags |= RC_WAS_SILOVFL; - sc->sc_scheduled_event++; - } - val = rcin(sc, CD180_RDR); - /* - Don't store PE if IGNPAR and BREAK if IGNBRK, - this hack allows "raw" tty optimization - works even if IGN* is set. - */ - if ( !(iack & (RCSR_PE|RCSR_FE|RCSR_Break)) - || ((!(iack & (RCSR_PE|RCSR_FE)) - || !(rc->rc_tp->t_iflag & IGNPAR)) - && (!(iack & RCSR_Break) - || !(rc->rc_tp->t_iflag & IGNBRK)))) { - if ( (iack & (RCSR_PE|RCSR_FE)) - && (t_state & TS_CAN_BYPASS_L_RINT) - && ((iack & RCSR_FE) - || ((iack & RCSR_PE) - && (rc->rc_tp->t_iflag & INPCK)))) - val = 0; - else if (val != 0 && val == rc->rc_tp->t_hotchar) - swi_sched(sc->sc_swicookie, 0); - optr[0] = val; - optr[INPUT_FLAGS_SHIFT] = iack; - optr++; - sc->sc_scheduled_event++; - } - } - } - rc->rc_iptr = optr; - rc->rc_flags |= RC_DORXFER; - } else - resid = ucnt; - /* Clear FIFO if necessary */ - while (resid-- > 0) { - if (!good_data) - iack = rcin(sc, CD180_RCSR); - else - iack = 0; - if (iack & RCSR_Timeout) - break; - (void) rcin(sc, CD180_RDR); - } - goto more_intrs; - } - if (bsr & RC_BSR_MOINT) { - iack = rcin(sc, RC_PILR_MODEM); - if (iack != (GIVR_IT_MSCI | RC_FAKEID)) { - device_printf(sc->sc_dev, "fake moint: %02x\n", - iack); - goto more_intrs; - } - chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); - rc = &sc->sc_channels[chan]; - iack = rcin(sc, CD180_MCR); - rc->rc_msvr = rcin(sc, CD180_MSVR); - rcout(sc, CD180_MCR, 0); -#ifdef RCDEBUG - printrcflags(rc, "moint"); -#endif - if (rc->rc_flags & RC_CTSFLOW) { - if (rc->rc_msvr & MSVR_CTS) - rc->rc_flags |= RC_SEND_RDY; - else - rc->rc_flags &= ~RC_SEND_RDY; - } else - rc->rc_flags |= RC_SEND_RDY; - if ((iack & MCR_CDchg) && !(rc->rc_flags & RC_MODCHG)) { - sc->sc_scheduled_event += LOTS_OF_EVENTS; - rc->rc_flags |= RC_MODCHG; - swi_sched(sc->sc_swicookie, 0); - } - goto more_intrs; - } - if (bsr & RC_BSR_TXINT) { - iack = rcin(sc, RC_PILR_TX); - if (iack != (GIVR_IT_TDI | RC_FAKEID)) { - device_printf(sc->sc_dev, "fake txint: %02x\n", - iack); - goto more_intrs; - } - chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); - rc = &sc->sc_channels[chan]; - if ( (rc->rc_flags & RC_OSUSP) - || !(rc->rc_flags & RC_SEND_RDY) - ) - goto more_intrs; - /* Handle breaks and other stuff */ - if (rc->rc_pendcmd) { - rcout(sc, CD180_COR2, rc->rc_cor2 |= COR2_ETC); - rcout(sc, CD180_TDR, CD180_C_ESC); - rcout(sc, CD180_TDR, rc->rc_pendcmd); - rcout(sc, CD180_COR2, rc->rc_cor2 &= ~COR2_ETC); - rc->rc_pendcmd = 0; - goto more_intrs; - } - optr = rc->rc_optr; - resid = rc->rc_obufend - optr; - if (resid > CD180_NFIFO) - resid = CD180_NFIFO; - while (resid-- > 0) - rcout(sc, CD180_TDR, *optr++); - rc->rc_optr = optr; - - /* output completed? */ - if (optr >= rc->rc_obufend) { - rcout(sc, CD180_IER, rc->rc_ier &= ~IER_TxRdy); -#ifdef RCDEBUG - device_printf(sc->sc_dev, - "channel %d: output completed\n", - rc->rc_chan); -#endif - if (!(rc->rc_flags & RC_DOXXFER)) { - sc->sc_scheduled_event += LOTS_OF_EVENTS; - rc->rc_flags |= RC_DOXXFER; - swi_sched(sc->sc_swicookie, 0); - } - } - } - more_intrs: - rcout(sc, CD180_EOIR, 0); /* end of interrupt */ - rcout(sc, RC_CTOUT, 0); - bsr = ~(rcin(sc, RC_BSR)); - } -} - -/* Feed characters to output buffer */ -static void -rc_start(struct tty *tp) -{ - struct rc_softc *sc; - struct rc_chans *rc; - int s; - - rc = tp->t_sc; - if (rc->rc_flags & RC_OSBUSY) - return; - sc = rc->rc_rcb; - s = spltty(); - rc->rc_flags |= RC_OSBUSY; - critical_enter(); - if (tp->t_state & TS_TTSTOP) - rc->rc_flags |= RC_OSUSP; - else - rc->rc_flags &= ~RC_OSUSP; - /* Do RTS flow control stuff */ - if ( (rc->rc_flags & RC_RTSFLOW) - && (tp->t_state & TS_TBLOCK) - && (rc->rc_msvr & MSVR_RTS) - ) { - rcout(sc, CD180_CAR, rc->rc_chan); - rcout(sc, CD180_MSVR, rc->rc_msvr &= ~MSVR_RTS); - } else if (!(rc->rc_msvr & MSVR_RTS)) { - rcout(sc, CD180_CAR, rc->rc_chan); - rcout(sc, CD180_MSVR, rc->rc_msvr |= MSVR_RTS); - } - critical_exit(); - if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) - goto out; -#ifdef RCDEBUG - printrcflags(rc, "rcstart"); -#endif - ttwwakeup(tp); -#ifdef RCDEBUG - printf("rcstart: outq = %d obuf = %d\n", - tp->t_outq.c_cc, rc->rc_obufend - rc->rc_optr); -#endif - if (tp->t_state & TS_BUSY) - goto out; /* output still in progress ... */ - - if (tp->t_outq.c_cc > 0) { - u_int ocnt; - - tp->t_state |= TS_BUSY; - ocnt = q_to_b(&tp->t_outq, rc->rc_obuf, sizeof rc->rc_obuf); - critical_enter(); - rc->rc_optr = rc->rc_obuf; - rc->rc_obufend = rc->rc_optr + ocnt; - critical_exit(); - if (!(rc->rc_ier & IER_TxRdy)) { -#ifdef RCDEBUG - device_printf(sc->sc_dev, - "channel %d: rcstart enable txint\n", rc->rc_chan); -#endif - rcout(sc, CD180_CAR, rc->rc_chan); - rcout(sc, CD180_IER, rc->rc_ier |= IER_TxRdy); - } - } -out: - rc->rc_flags &= ~RC_OSBUSY; - (void) splx(s); -} - -/* Handle delayed events. */ -void -rc_pollcard(void *arg) -{ - struct rc_softc *sc; - struct rc_chans *rc; - struct tty *tp; - u_char *tptr, *eptr; - int chan, icnt; - - sc = (struct rc_softc *)arg; - if (sc->sc_scheduled_event == 0) - return; - do { - rc = sc->sc_channels; - for (chan = 0; chan < CD180_NCHAN; rc++, chan++) { - tp = rc->rc_tp; -#ifdef RCDEBUG - if (rc->rc_flags & (RC_DORXFER|RC_DOXXFER|RC_MODCHG| - RC_WAS_BUFOVFL|RC_WAS_SILOVFL)) - printrcflags(rc, "rcevent"); -#endif - if (rc->rc_flags & RC_WAS_BUFOVFL) { - critical_enter(); - rc->rc_flags &= ~RC_WAS_BUFOVFL; - sc->sc_scheduled_event--; - critical_exit(); - device_printf(sc->sc_dev, - "channel %d: interrupt-level buffer overflow\n", - chan); - } - if (rc->rc_flags & RC_WAS_SILOVFL) { - critical_enter(); - rc->rc_flags &= ~RC_WAS_SILOVFL; - sc->sc_scheduled_event--; - critical_exit(); - device_printf(sc->sc_dev, - "channel %d: silo overflow\n", chan); - } - if (rc->rc_flags & RC_MODCHG) { - critical_enter(); - rc->rc_flags &= ~RC_MODCHG; - sc->sc_scheduled_event -= LOTS_OF_EVENTS; - critical_exit(); - ttyld_modem(tp, !!(rc->rc_msvr & MSVR_CD)); - } - if (rc->rc_flags & RC_DORXFER) { - critical_enter(); - rc->rc_flags &= ~RC_DORXFER; - eptr = rc->rc_iptr; - if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) - tptr = &rc->rc_ibuf[RC_IBUFSIZE]; - else - tptr = rc->rc_ibuf; - icnt = eptr - tptr; - if (icnt > 0) { - if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { - rc->rc_iptr = rc->rc_ibuf; - rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; - rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; - } else { - rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; - rc->rc_bufend = &rc->rc_ibuf[2 * RC_IBUFSIZE]; - rc->rc_hiwat = - &rc->rc_ibuf[RC_IBUFSIZE + RC_IHIGHWATER]; - } - if ( (rc->rc_flags & RC_RTSFLOW) - && (tp->t_state & TS_ISOPEN) - && !(tp->t_state & TS_TBLOCK) - && !(rc->rc_msvr & MSVR_RTS) - ) { - rcout(sc, CD180_CAR, chan); - rcout(sc, CD180_MSVR, - rc->rc_msvr |= MSVR_RTS); - } - sc->sc_scheduled_event -= icnt; - } - critical_exit(); - - if (icnt <= 0 || !(tp->t_state & TS_ISOPEN)) - goto done1; - - if ( (tp->t_state & TS_CAN_BYPASS_L_RINT) - && !(tp->t_state & TS_LOCAL)) { - if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER - && ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF)) - && !(tp->t_state & TS_TBLOCK)) - ttyblock(tp); - tk_nin += icnt; - tk_rawcc += icnt; - tp->t_rawcc += icnt; - if (b_to_q(tptr, icnt, &tp->t_rawq)) - device_printf(sc->sc_dev, - "channel %d: tty-level buffer overflow\n", - chan); - ttwakeup(tp); - if ((tp->t_state & TS_TTSTOP) && ((tp->t_iflag & IXANY) - || (tp->t_cc[VSTART] == tp->t_cc[VSTOP]))) { - tp->t_state &= ~TS_TTSTOP; - tp->t_lflag &= ~FLUSHO; - rc_start(tp); - } - } else { - for (; tptr < eptr; tptr++) - ttyld_rint(tp, - (tptr[0] | - rc_rcsrt[tptr[INPUT_FLAGS_SHIFT] & 0xF])); - } -done1: ; - } - if (rc->rc_flags & RC_DOXXFER) { - critical_enter(); - sc->sc_scheduled_event -= LOTS_OF_EVENTS; - rc->rc_flags &= ~RC_DOXXFER; - rc->rc_tp->t_state &= ~TS_BUSY; - critical_exit(); - ttyld_start(tp); - } - if (sc->sc_scheduled_event == 0) - break; - } - } while (sc->sc_scheduled_event >= LOTS_OF_EVENTS); -} - -static void -rc_stop(struct tty *tp, int rw) -{ - struct rc_softc *sc; - struct rc_chans *rc; - u_char *tptr, *eptr; - - rc = tp->t_sc; - sc = rc->rc_rcb; -#ifdef RCDEBUG - device_printf(sc->sc_dev, "channel %d: rc_stop %s%s\n", - rc->rc_chan, (rw & FWRITE)?"FWRITE ":"", (rw & FREAD)?"FREAD":""); -#endif - if (rw & FWRITE) - rc_discard_output(rc); - critical_enter(); - if (rw & FREAD) { - rc->rc_flags &= ~RC_DORXFER; - eptr = rc->rc_iptr; - if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { - tptr = &rc->rc_ibuf[RC_IBUFSIZE]; - rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; - } else { - tptr = rc->rc_ibuf; - rc->rc_iptr = rc->rc_ibuf; - } - sc->sc_scheduled_event -= eptr - tptr; - } - if (tp->t_state & TS_TTSTOP) - rc->rc_flags |= RC_OSUSP; - else - rc->rc_flags &= ~RC_OSUSP; - critical_exit(); -} - -static void -rc_close(struct tty *tp) -{ - struct rc_chans *rc; - struct rc_softc *sc; - int s; - - rc = tp->t_sc; - sc = rc->rc_rcb; - s = spltty(); - rcout(sc, CD180_CAR, rc->rc_chan); - - /* Disable rx/tx intrs */ - rcout(sc, CD180_IER, rc->rc_ier = 0); - if ( (tp->t_cflag & HUPCL) - || (!(rc->rc_flags & RC_ACTOUT) - && !(rc->rc_msvr & MSVR_CD) - && !(tp->t_cflag & CLOCAL)) - || !(tp->t_state & TS_ISOPEN) - ) { - CCRCMD(sc, rc->rc_chan, CCR_ResetChan); - WAITFORCCR(sc, rc->rc_chan); - (void) rc_modem(tp, SER_RTS, 0); - ttydtrwaitstart(tp); - } - rc->rc_flags &= ~RC_ACTOUT; - wakeup( &rc->rc_rcb); /* wake bi */ - wakeup(TSA_CARR_ON(tp)); - (void) splx(s); -} - -/* Reset the bastard */ -static void -rc_hwreset(struct rc_softc *sc, u_int chipid) -{ - CCRCMD(sc, -1, CCR_HWRESET); /* Hardware reset */ - DELAY(20000); - WAITFORCCR(sc, -1); - - rcout(sc, RC_CTOUT, 0); /* Clear timeout */ - rcout(sc, CD180_GIVR, chipid); - rcout(sc, CD180_GICR, 0); - - /* Set Prescaler Registers (1 msec) */ - rcout(sc, CD180_PPRL, ((RC_OSCFREQ + 999) / 1000) & 0xFF); - rcout(sc, CD180_PPRH, ((RC_OSCFREQ + 999) / 1000) >> 8); - - /* Initialize Priority Interrupt Level Registers */ - rcout(sc, CD180_PILR1, RC_PILR_MODEM); - rcout(sc, CD180_PILR2, RC_PILR_TX); - rcout(sc, CD180_PILR3, RC_PILR_RX); - - /* Reset DTR */ - rcout(sc, RC_DTREG, ~0); -} - -/* Set channel parameters */ -static int -rc_param(struct tty *tp, struct termios *ts) -{ - struct rc_softc *sc; - struct rc_chans *rc; - int idivs, odivs, s, val, cflag, iflag, lflag, inpflow; - - if ( ts->c_ospeed < 0 || ts->c_ospeed > 76800 - || ts->c_ispeed < 0 || ts->c_ispeed > 76800 - ) - return (EINVAL); - if (ts->c_ispeed == 0) - ts->c_ispeed = ts->c_ospeed; - odivs = RC_BRD(ts->c_ospeed); - idivs = RC_BRD(ts->c_ispeed); - - rc = tp->t_sc; - sc = rc->rc_rcb; - s = spltty(); - - /* Select channel */ - rcout(sc, CD180_CAR, rc->rc_chan); - - /* If speed == 0, hangup line */ - if (ts->c_ospeed == 0) { - CCRCMD(sc, rc->rc_chan, CCR_ResetChan); - WAITFORCCR(sc, rc->rc_chan); - (void) rc_modem(tp, 0, SER_DTR); - } - - tp->t_state &= ~TS_CAN_BYPASS_L_RINT; - cflag = ts->c_cflag; - iflag = ts->c_iflag; - lflag = ts->c_lflag; - - if (idivs > 0) { - rcout(sc, CD180_RBPRL, idivs & 0xFF); - rcout(sc, CD180_RBPRH, idivs >> 8); - } - if (odivs > 0) { - rcout(sc, CD180_TBPRL, odivs & 0xFF); - rcout(sc, CD180_TBPRH, odivs >> 8); - } - - /* set timeout value */ - if (ts->c_ispeed > 0) { - int itm = ts->c_ispeed > 2400 ? 5 : 10000 / ts->c_ispeed + 1; - - if ( !(lflag & ICANON) - && ts->c_cc[VMIN] != 0 && ts->c_cc[VTIME] != 0 - && ts->c_cc[VTIME] * 10 > itm) - itm = ts->c_cc[VTIME] * 10; - - rcout(sc, CD180_RTPR, itm <= 255 ? itm : 255); - } - - switch (cflag & CSIZE) { - case CS5: val = COR1_5BITS; break; - case CS6: val = COR1_6BITS; break; - case CS7: val = COR1_7BITS; break; - default: - case CS8: val = COR1_8BITS; break; - } - if (cflag & PARENB) { - val |= COR1_NORMPAR; - if (cflag & PARODD) - val |= COR1_ODDP; - if (!(cflag & INPCK)) - val |= COR1_Ignore; - } else - val |= COR1_Ignore; - if (cflag & CSTOPB) - val |= COR1_2SB; - rcout(sc, CD180_COR1, val); - - /* Set FIFO threshold */ - val = ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2; - inpflow = 0; - if ( (iflag & IXOFF) - && ( ts->c_cc[VSTOP] != _POSIX_VDISABLE - && ( ts->c_cc[VSTART] != _POSIX_VDISABLE - || (iflag & IXANY) - ) - ) - ) { - inpflow = 1; - val |= COR3_SCDE|COR3_FCT; - } - rcout(sc, CD180_COR3, val); - - /* Initialize on-chip automatic flow control */ - val = 0; - rc->rc_flags &= ~(RC_CTSFLOW|RC_SEND_RDY); - if (cflag & CCTS_OFLOW) { - rc->rc_flags |= RC_CTSFLOW; - val |= COR2_CtsAE; - } else - rc->rc_flags |= RC_SEND_RDY; - if (tp->t_state & TS_TTSTOP) - rc->rc_flags |= RC_OSUSP; - else - rc->rc_flags &= ~RC_OSUSP; - if (cflag & CRTS_IFLOW) - rc->rc_flags |= RC_RTSFLOW; - else - rc->rc_flags &= ~RC_RTSFLOW; - - if (inpflow) { - if (ts->c_cc[VSTART] != _POSIX_VDISABLE) - rcout(sc, CD180_SCHR1, ts->c_cc[VSTART]); - rcout(sc, CD180_SCHR2, ts->c_cc[VSTOP]); - val |= COR2_TxIBE; - if (iflag & IXANY) - val |= COR2_IXM; - } - - rcout(sc, CD180_COR2, rc->rc_cor2 = val); - - CCRCMD(sc, rc->rc_chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); - - ttyldoptim(tp); - - /* modem ctl */ - val = cflag & CLOCAL ? 0 : MCOR1_CDzd; - if (cflag & CCTS_OFLOW) - val |= MCOR1_CTSzd; - rcout(sc, CD180_MCOR1, val); - - val = cflag & CLOCAL ? 0 : MCOR2_CDod; - if (cflag & CCTS_OFLOW) - val |= MCOR2_CTSod; - rcout(sc, CD180_MCOR2, val); - - /* enable i/o and interrupts */ - CCRCMD(sc, rc->rc_chan, - CCR_XMTREN | ((cflag & CREAD) ? CCR_RCVREN : CCR_RCVRDIS)); - WAITFORCCR(sc, rc->rc_chan); - - rc->rc_ier = cflag & CLOCAL ? 0 : IER_CD; - if (cflag & CCTS_OFLOW) - rc->rc_ier |= IER_CTS; - if (cflag & CREAD) - rc->rc_ier |= IER_RxData; - if (tp->t_state & TS_BUSY) - rc->rc_ier |= IER_TxRdy; - if (ts->c_ospeed != 0) - rc_modem(tp, SER_DTR, 0); - if ((cflag & CCTS_OFLOW) && (rc->rc_msvr & MSVR_CTS)) - rc->rc_flags |= RC_SEND_RDY; - rcout(sc, CD180_IER, rc->rc_ier); - (void) splx(s); - return 0; -} - -/* Re-initialize board after bogus interrupts */ -static void -rc_reinit(struct rc_softc *sc) -{ - struct rc_chans *rc; - int i; - - rc_hwreset(sc, RC_FAKEID); - rc = sc->sc_channels; - for (i = 0; i < CD180_NCHAN; i++, rc++) - (void) rc_param(rc->rc_tp, &rc->rc_tp->t_termios); -} - -/* Modem control routines */ - -static int -rc_modem(struct tty *tp, int biton, int bitoff) -{ - struct rc_chans *rc; - struct rc_softc *sc; - u_char *dtr; - u_char msvr; - - rc = tp->t_sc; - sc = rc->rc_rcb; - dtr = &sc->sc_dtr; - rcout(sc, CD180_CAR, rc->rc_chan); - - if (biton == 0 && bitoff == 0) { - msvr = rc->rc_msvr = rcin(sc, CD180_MSVR); - - if (msvr & MSVR_RTS) - biton |= SER_RTS; - if (msvr & MSVR_CTS) - biton |= SER_CTS; - if (msvr & MSVR_DSR) - biton |= SER_DSR; - if (msvr & MSVR_DTR) - biton |= SER_DTR; - if (msvr & MSVR_CD) - biton |= SER_DCD; - if (~rcin(sc, RC_RIREG) & (1 << rc->rc_chan)) - biton |= SER_RI; - return biton; - } - if (biton & SER_DTR) - rcout(sc, RC_DTREG, ~(*dtr |= 1 << rc->rc_chan)); - if (bitoff & SER_DTR) - rcout(sc, RC_DTREG, ~(*dtr &= ~(1 << rc->rc_chan))); - msvr = rcin(sc, CD180_MSVR); - if (biton & SER_DTR) - msvr |= MSVR_DTR; - if (bitoff & SER_DTR) - msvr &= ~MSVR_DTR; - if (biton & SER_RTS) - msvr |= MSVR_RTS; - if (bitoff & SER_RTS) - msvr &= ~MSVR_RTS; - rcout(sc, CD180_MSVR, msvr); - return 0; -} - -static void -rc_break(struct tty *tp, int brk) -{ - struct rc_chans *rc; - - rc = tp->t_sc; - - if (brk) - rc->rc_pendcmd = CD180_C_SBRK; - else - rc->rc_pendcmd = CD180_C_EBRK; -} - -#define ERR(s) do { \ - device_printf(sc->sc_dev, "%s", ""); \ - printf s ; \ - printf("\n"); \ - (void) splx(old_level); \ - return 1; \ -} while (0) - -/* Test the board. */ -int -rc_test(struct rc_softc *sc) -{ - int chan = 0; - int i = 0, rcnt, old_level; - unsigned int iack, chipid; - unsigned short divs; - static u_char ctest[] = "\377\125\252\045\244\0\377"; -#define CTLEN 8 - - struct rtest { - u_char txbuf[CD180_NFIFO]; /* TX buffer */ - u_char rxbuf[CD180_NFIFO]; /* RX buffer */ - int rxptr; /* RX pointer */ - int txptr; /* TX pointer */ - } tchans[CD180_NCHAN]; - - old_level = spltty(); - - chipid = RC_FAKEID; - - /* First, reset board to initial state */ - rc_hwreset(sc, chipid); - - divs = RC_BRD(19200); - - /* Initialize channels */ - for (chan = 0; chan < CD180_NCHAN; chan++) { - - /* Select and reset channel */ - rcout(sc, CD180_CAR, chan); - CCRCMD(sc, chan, CCR_ResetChan); - WAITFORCCR(sc, chan); - - /* Set speed */ - rcout(sc, CD180_RBPRL, divs & 0xFF); - rcout(sc, CD180_RBPRH, divs >> 8); - rcout(sc, CD180_TBPRL, divs & 0xFF); - rcout(sc, CD180_TBPRH, divs >> 8); - - /* set timeout value */ - rcout(sc, CD180_RTPR, 0); - - /* Establish local loopback */ - rcout(sc, CD180_COR1, COR1_NOPAR | COR1_8BITS | COR1_1SB); - rcout(sc, CD180_COR2, COR2_LLM); - rcout(sc, CD180_COR3, CD180_NFIFO); - CCRCMD(sc, chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); - CCRCMD(sc, chan, CCR_RCVREN | CCR_XMTREN); - WAITFORCCR(sc, chan); - rcout(sc, CD180_MSVR, MSVR_RTS); - - /* Fill TXBUF with test data */ - for (i = 0; i < CD180_NFIFO; i++) { - tchans[chan].txbuf[i] = ctest[i]; - tchans[chan].rxbuf[i] = 0; - } - tchans[chan].txptr = tchans[chan].rxptr = 0; - - /* Now, start transmit */ - rcout(sc, CD180_IER, IER_TxMpty|IER_RxData); - } - /* Pseudo-interrupt poll stuff */ - for (rcnt = 10000; rcnt-- > 0; rcnt--) { - i = ~(rcin(sc, RC_BSR)); - if (i & RC_BSR_TOUT) - ERR(("BSR timeout bit set\n")); - else if (i & RC_BSR_TXINT) { - iack = rcin(sc, RC_PILR_TX); - if (iack != (GIVR_IT_TDI | chipid)) - ERR(("Bad TX intr ack (%02x != %02x)\n", - iack, GIVR_IT_TDI | chipid)); - chan = (rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH; - /* If no more data to transmit, disable TX intr */ - if (tchans[chan].txptr >= CD180_NFIFO) { - iack = rcin(sc, CD180_IER); - rcout(sc, CD180_IER, iack & ~IER_TxMpty); - } else { - for (iack = tchans[chan].txptr; - iack < CD180_NFIFO; iack++) - rcout(sc, CD180_TDR, - tchans[chan].txbuf[iack]); - tchans[chan].txptr = iack; - } - rcout(sc, CD180_EOIR, 0); - } else if (i & RC_BSR_RXINT) { - u_char ucnt; - - iack = rcin(sc, RC_PILR_RX); - if (iack != (GIVR_IT_RGDI | chipid) && - iack != (GIVR_IT_REI | chipid)) - ERR(("Bad RX intr ack (%02x != %02x)\n", - iack, GIVR_IT_RGDI | chipid)); - chan = (rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH; - ucnt = rcin(sc, CD180_RDCR) & 0xF; - while (ucnt-- > 0) { - iack = rcin(sc, CD180_RCSR); - if (iack & RCSR_Timeout) - break; - if (iack & 0xF) - ERR(("Bad char chan %d (RCSR = %02X)\n", - chan, iack)); - if (tchans[chan].rxptr > CD180_NFIFO) - ERR(("Got extra chars chan %d\n", - chan)); - tchans[chan].rxbuf[tchans[chan].rxptr++] = - rcin(sc, CD180_RDR); - } - rcout(sc, CD180_EOIR, 0); - } - rcout(sc, RC_CTOUT, 0); - for (iack = chan = 0; chan < CD180_NCHAN; chan++) - if (tchans[chan].rxptr >= CD180_NFIFO) - iack++; - if (iack == CD180_NCHAN) - break; - } - for (chan = 0; chan < CD180_NCHAN; chan++) { - /* Select and reset channel */ - rcout(sc, CD180_CAR, chan); - CCRCMD(sc, chan, CCR_ResetChan); - } - - if (!rcnt) - ERR(("looses characters during local loopback\n")); - /* Now, check data */ - for (chan = 0; chan < CD180_NCHAN; chan++) - for (i = 0; i < CD180_NFIFO; i++) - if (ctest[i] != tchans[chan].rxbuf[i]) - ERR(("data mismatch chan %d ptr %d (%d != %d)\n", - chan, i, ctest[i], tchans[chan].rxbuf[i])); - (void) splx(old_level); - return 0; -} - -#ifdef RCDEBUG -static void -printrcflags(struct rc_chans *rc, char *comment) -{ - struct rc_softc *sc; - u_short f = rc->rc_flags; - - sc = rc->rc_rcb; - printf("rc%d/%d: %s flags: %s%s%s%s%s%s%s%s%s%s%s%s\n", - rc->rc_rcb->rcb_unit, rc->rc_chan, comment, - (f & RC_DTR_OFF)?"DTR_OFF " :"", - (f & RC_ACTOUT) ?"ACTOUT " :"", - (f & RC_RTSFLOW)?"RTSFLOW " :"", - (f & RC_CTSFLOW)?"CTSFLOW " :"", - (f & RC_DORXFER)?"DORXFER " :"", - (f & RC_DOXXFER)?"DOXXFER " :"", - (f & RC_MODCHG) ?"MODCHG " :"", - (f & RC_OSUSP) ?"OSUSP " :"", - (f & RC_OSBUSY) ?"OSBUSY " :"", - (f & RC_WAS_BUFOVFL) ?"BUFOVFL " :"", - (f & RC_WAS_SILOVFL) ?"SILOVFL " :"", - (f & RC_SEND_RDY) ?"SEND_RDY":""); - - rcout(sc, CD180_CAR, rc->rc_chan); - - printf("rc%d/%d: msvr %02x ier %02x ccsr %02x\n", - rc->rc_rcb->rcb_unit, rc->rc_chan, - rcin(sc, CD180_MSVR), - rcin(sc, CD180_IER), - rcin(sc, CD180_CCSR)); -} -#endif /* RCDEBUG */ - -static void -rc_discard_output(struct rc_chans *rc) -{ - critical_enter(); - if (rc->rc_flags & RC_DOXXFER) { - rc->rc_rcb->sc_scheduled_event -= LOTS_OF_EVENTS; - rc->rc_flags &= ~RC_DOXXFER; - } - rc->rc_optr = rc->rc_obufend; - rc->rc_tp->t_state &= ~TS_BUSY; - critical_exit(); - ttwwakeup(rc->rc_tp); -} - -static void -rc_wait0(struct rc_softc *sc, int chan, int line) -{ - int rcnt; - - for (rcnt = 50; rcnt && rcin(sc, CD180_CCR); rcnt--) - DELAY(30); - if (rcnt == 0) - device_printf(sc->sc_dev, - "channel %d command timeout, rc.c line: %d\n", chan, line); -} - -static device_method_t rc_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, rc_probe), - DEVMETHOD(device_attach, rc_attach), - DEVMETHOD(device_detach, rc_detach), - { 0, 0 } -}; - -static driver_t rc_driver = { - "rc", - rc_methods, sizeof(struct rc_softc), -}; - -DRIVER_MODULE(rc, isa, rc_driver, rc_devclass, 0, 0); diff --git a/sys/dev/rc/rcreg.h b/sys/dev/rc/rcreg.h deleted file mode 100644 index 832a1cbe1e54..000000000000 --- a/sys/dev/rc/rcreg.h +++ /dev/null @@ -1,72 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 1995 by Pavel Antonov, Moscow, Russia. - * Copyright (C) 1995 by Andrey A. Chernov, Moscow, Russia. - * All rights reserved. - * Copyright (C) 2002 by John Baldwin - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * Cirrus Logic CD180 -based RISCom/8 board definitions - */ - -/* Oscillator frequency - 19660.08Mhz / 2 */ -#define RC_OSCFREQ 9830400 - -#define RC_BRD(s) ((s) == 0 ? 0 : \ - (((RC_OSCFREQ + (s) / 2) / (s)) + CD180_CTICKS/2) / CD180_CTICKS) - -/* Riscom/8 board ISA I/O mapping */ -#define RC_IOMAP(r) ((((r) & 07) << 1) | (((r) & ~07) << 7)) - -/* I/O commands */ -#define RC_OUT(sc, addr, value) \ - bus_space_write_1((sc)->sc_bt, (sc)->sc_bh, RC_IOMAP(addr), (value)) -#define RC_IN(sc, addr) \ - bus_space_read_1((sc)->sc_bt, (sc)->sc_bh, RC_IOMAP(addr)) - -/* Riscom on-board registers (mapping assumed) */ -#define RC_RIREG 0x100 /* Ring Indicator Register (read-only) */ -#define RC_DTREG 0x100 /* DTR Register (write-only) */ -#define RC_BSR 0x101 /* Board Status Register (read-only) */ -#define RC_CTOUT 0x101 /* Clear Timeout (write-only) */ - -/* Board Status Register */ -#define RC_BSR_TOUT 0x08 /* Timeout */ -#define RC_BSR_RXINT 0x04 /* Receiver Interrupt */ -#define RC_BSR_TXINT 0x02 /* Transmitter Interrupt */ -#define RC_BSR_MOINT 0x01 /* Modem Control Interrupt */ - -/* Interrupt groups */ -#define RC_MODEMGRP 0x01 /* Modem interrupt group */ -#define RC_RXGRP 0x02 /* Receiver interrupt group */ -#define RC_TXGRP 0x04 /* Transmitter interrupt group */ - -/* Priority Interrupt Level definitions */ -#define RC_PILR_MODEM (0x80 | RC_MODEMGRP) -#define RC_PILR_RX (0x80 | RC_RXGRP ) -#define RC_PILR_TX (0x80 | RC_TXGRP ) diff --git a/sys/dev/rp/rp.c b/sys/dev/rp/rp.c deleted file mode 100644 index 390ab733d2ae..000000000000 --- a/sys/dev/rp/rp.c +++ /dev/null @@ -1,1113 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) Comtrol Corporation - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted prodived that the follwoing conditions - * are met. - * 1. Redistributions of source code must retain the above copyright - * notive, this list of conditions and the following disclainer. - * 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 prodided 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 Comtrol Corporation. - * 4. The name of Comtrol Corporation may not be used to endorse or - * promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY COMTROL 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 COMTROL 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, LIFE 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$"); - -/* - * rp.c - for RocketPort FreeBSD - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ROCKET_C -#include -#include - -static const char RocketPortVersion[] = "3.02"; - -static Byte_t RData[RDATASIZE] = -{ - 0x00, 0x09, 0xf6, 0x82, - 0x02, 0x09, 0x86, 0xfb, - 0x04, 0x09, 0x00, 0x0a, - 0x06, 0x09, 0x01, 0x0a, - 0x08, 0x09, 0x8a, 0x13, - 0x0a, 0x09, 0xc5, 0x11, - 0x0c, 0x09, 0x86, 0x85, - 0x0e, 0x09, 0x20, 0x0a, - 0x10, 0x09, 0x21, 0x0a, - 0x12, 0x09, 0x41, 0xff, - 0x14, 0x09, 0x82, 0x00, - 0x16, 0x09, 0x82, 0x7b, - 0x18, 0x09, 0x8a, 0x7d, - 0x1a, 0x09, 0x88, 0x81, - 0x1c, 0x09, 0x86, 0x7a, - 0x1e, 0x09, 0x84, 0x81, - 0x20, 0x09, 0x82, 0x7c, - 0x22, 0x09, 0x0a, 0x0a -}; - -static Byte_t RRegData[RREGDATASIZE]= -{ - 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ - 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ - 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ - 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ - 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ - 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ - 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ - 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ - 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ - 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ - 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ - 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ - 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ -}; - -#if 0 -/* IRQ number to MUDBAC register 2 mapping */ -Byte_t sIRQMap[16] = -{ - 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80 -}; -#endif - -Byte_t rp_sBitMapClrTbl[8] = -{ - 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f -}; - -Byte_t rp_sBitMapSetTbl[8] = -{ - 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 -}; - -static void rpfree(void *); - -/*************************************************************************** -Function: sReadAiopID -Purpose: Read the AIOP idenfication number directly from an AIOP. -Call: sReadAiopID(CtlP, aiop) - CONTROLLER_T *CtlP; Ptr to controller structure - int aiop: AIOP index -Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X - is replace by an identifying number. - Flag AIOPID_NULL if no valid AIOP is found -Warnings: No context switches are allowed while executing this function. - -*/ -int sReadAiopID(CONTROLLER_T *CtlP, int aiop) -{ - Byte_t AiopID; /* ID byte from AIOP */ - - rp_writeaiop1(CtlP, aiop, _CMD_REG, RESET_ALL); /* reset AIOP */ - rp_writeaiop1(CtlP, aiop, _CMD_REG, 0x0); - AiopID = rp_readaiop1(CtlP, aiop, _CHN_STAT0) & 0x07; - if(AiopID == 0x06) - return(1); - else /* AIOP does not exist */ - return(-1); -} - -/*************************************************************************** -Function: sReadAiopNumChan -Purpose: Read the number of channels available in an AIOP directly from - an AIOP. -Call: sReadAiopNumChan(CtlP, aiop) - CONTROLLER_T *CtlP; Ptr to controller structure - int aiop: AIOP index -Return: int: The number of channels available -Comments: The number of channels is determined by write/reads from identical - offsets within the SRAM address spaces for channels 0 and 4. - If the channel 4 space is mirrored to channel 0 it is a 4 channel - AIOP, otherwise it is an 8 channel. -Warnings: No context switches are allowed while executing this function. -*/ -int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop) -{ - Word_t x, y; - - rp_writeaiop4(CtlP, aiop, _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */ - rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0); /* read from SRAM, chan 0 */ - x = rp_readaiop2(CtlP, aiop, _INDX_DATA); - rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0x4000); /* read from SRAM, chan 4 */ - y = rp_readaiop2(CtlP, aiop, _INDX_DATA); - if(x != y) /* if different must be 8 chan */ - return(8); - else - return(4); -} - -/*************************************************************************** -Function: sInitChan -Purpose: Initialization of a channel and channel structure -Call: sInitChan(CtlP,ChP,AiopNum,ChanNum) - CONTROLLER_T *CtlP; Ptr to controller structure - CHANNEL_T *ChP; Ptr to channel structure - int AiopNum; AIOP number within controller - int ChanNum; Channel number within AIOP -Return: int: TRUE if initialization succeeded, FALSE if it fails because channel - number exceeds number of channels available in AIOP. -Comments: This function must be called before a channel can be used. -Warnings: No range checking on any of the parameters is done. - - No context switches are allowed while executing this function. -*/ -int sInitChan( CONTROLLER_T *CtlP, - CHANNEL_T *ChP, - int AiopNum, - int ChanNum) -{ - int i, ChOff; - Byte_t *ChR; - static Byte_t R[4]; - - if(ChanNum >= CtlP->AiopNumChan[AiopNum]) - return(FALSE); /* exceeds num chans in AIOP */ - - /* Channel, AIOP, and controller identifiers */ - ChP->CtlP = CtlP; - ChP->ChanID = CtlP->AiopID[AiopNum]; - ChP->AiopNum = AiopNum; - ChP->ChanNum = ChanNum; - - /* Initialize the channel from the RData array */ - for(i=0; i < RDATASIZE; i+=4) - { - R[0] = RData[i]; - R[1] = RData[i+1] + 0x10 * ChanNum; - R[2] = RData[i+2]; - R[3] = RData[i+3]; - rp_writech4(ChP,_INDX_ADDR,le32dec(R)); - } - - ChR = ChP->R; - for(i=0; i < RREGDATASIZE; i+=4) - { - ChR[i] = RRegData[i]; - ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum; - ChR[i+2] = RRegData[i+2]; - ChR[i+3] = RRegData[i+3]; - } - - /* Indexed registers */ - ChOff = (Word_t)ChanNum * 0x1000; - - ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD); - ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8); - ChP->BaudDiv[2] = (Byte_t)BRD9600; - ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8); - rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->BaudDiv)); - - ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL); - ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8); - ChP->TxControl[2] = 0; - ChP->TxControl[3] = 0; - rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl)); - - ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL); - ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8); - ChP->RxControl[2] = 0; - ChP->RxControl[3] = 0; - rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl)); - - ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS); - ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8); - ChP->TxEnables[2] = 0; - ChP->TxEnables[3] = 0; - rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxEnables)); - - ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1); - ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8); - ChP->TxCompare[2] = 0; - ChP->TxCompare[3] = 0; - rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxCompare)); - - ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1); - ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8); - ChP->TxReplace1[2] = 0; - ChP->TxReplace1[3] = 0; - rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxReplace1)); - - ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2); - ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8); - ChP->TxReplace2[2] = 0; - ChP->TxReplace2[3] = 0; - rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxReplace2)); - - ChP->TxFIFOPtrs = ChOff + _TXF_OUTP; - ChP->TxFIFO = ChOff + _TX_FIFO; - - rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */ - rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum); /* remove reset Tx FIFO count */ - rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ - rp_writech2(ChP,_INDX_DATA,0); - ChP->RxFIFOPtrs = ChOff + _RXF_OUTP; - ChP->RxFIFO = ChOff + _RX_FIFO; - - rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */ - rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum); /* remove reset Rx FIFO count */ - rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */ - rp_writech2(ChP,_INDX_DATA,0); - rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ - rp_writech2(ChP,_INDX_DATA,0); - ChP->TxPrioCnt = ChOff + _TXP_CNT; - rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); - rp_writech1(ChP,_INDX_DATA,0); - ChP->TxPrioPtr = ChOff + _TXP_PNTR; - rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioPtr); - rp_writech1(ChP,_INDX_DATA,0); - ChP->TxPrioBuf = ChOff + _TXP_BUF; - sEnRxProcessor(ChP); /* start the Rx processor */ - - return(TRUE); -} - -/*************************************************************************** -Function: sStopRxProcessor -Purpose: Stop the receive processor from processing a channel. -Call: sStopRxProcessor(ChP) - CHANNEL_T *ChP; Ptr to channel structure - -Comments: The receive processor can be started again with sStartRxProcessor(). - This function causes the receive processor to skip over the - stopped channel. It does not stop it from processing other channels. - -Warnings: No context switches are allowed while executing this function. - - Do not leave the receive processor stopped for more than one - character time. - - After calling this function a delay of 4 uS is required to ensure - that the receive processor is no longer processing this channel. -*/ -void sStopRxProcessor(CHANNEL_T *ChP) -{ - Byte_t R[4]; - - R[0] = ChP->R[0]; - R[1] = ChP->R[1]; - R[2] = 0x0a; - R[3] = ChP->R[3]; - rp_writech4(ChP,_INDX_ADDR,le32dec(R)); -} - -/*************************************************************************** -Function: sFlushRxFIFO -Purpose: Flush the Rx FIFO -Call: sFlushRxFIFO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: void -Comments: To prevent data from being enqueued or dequeued in the Tx FIFO - while it is being flushed the receive processor is stopped - and the transmitter is disabled. After these operations a - 4 uS delay is done before clearing the pointers to allow - the receive processor to stop. These items are handled inside - this function. -Warnings: No context switches are allowed while executing this function. -*/ -void sFlushRxFIFO(CHANNEL_T *ChP) -{ - int i; - Byte_t Ch; /* channel number within AIOP */ - int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */ - - if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ - return; /* don't need to flush */ - - RxFIFOEnabled = FALSE; - if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */ - { - RxFIFOEnabled = TRUE; - sDisRxFIFO(ChP); /* disable it */ - for(i=0; i < 2000/200; i++) /* delay 2 uS to allow proc to disable FIFO*/ - rp_readch1(ChP,_INT_CHAN); /* depends on bus i/o timing */ - } - sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */ - Ch = (Byte_t)sGetChanNum(ChP); - rp_writech1(ChP,_CMD_REG,Ch | RESRXFCNT); /* apply reset Rx FIFO count */ - rp_writech1(ChP,_CMD_REG,Ch); /* remove reset Rx FIFO count */ - rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */ - rp_writech2(ChP,_INDX_DATA,0); - rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ - rp_writech2(ChP,_INDX_DATA,0); - if(RxFIFOEnabled) - sEnRxFIFO(ChP); /* enable Rx FIFO */ -} - -/*************************************************************************** -Function: sFlushTxFIFO -Purpose: Flush the Tx FIFO -Call: sFlushTxFIFO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: void -Comments: To prevent data from being enqueued or dequeued in the Tx FIFO - while it is being flushed the receive processor is stopped - and the transmitter is disabled. After these operations a - 4 uS delay is done before clearing the pointers to allow - the receive processor to stop. These items are handled inside - this function. -Warnings: No context switches are allowed while executing this function. -*/ -void sFlushTxFIFO(CHANNEL_T *ChP) -{ - int i; - Byte_t Ch; /* channel number within AIOP */ - int TxEnabled; /* TRUE if transmitter enabled */ - - if(sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ - return; /* don't need to flush */ - - TxEnabled = FALSE; - if(ChP->TxControl[3] & TX_ENABLE) - { - TxEnabled = TRUE; - sDisTransmit(ChP); /* disable transmitter */ - } - sStopRxProcessor(ChP); /* stop Rx processor */ - for(i = 0; i < 4000/200; i++) /* delay 4 uS to allow proc to stop */ - rp_readch1(ChP,_INT_CHAN); /* depends on bus i/o timing */ - Ch = (Byte_t)sGetChanNum(ChP); - rp_writech1(ChP,_CMD_REG,Ch | RESTXFCNT); /* apply reset Tx FIFO count */ - rp_writech1(ChP,_CMD_REG,Ch); /* remove reset Tx FIFO count */ - rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ - rp_writech2(ChP,_INDX_DATA,0); - if(TxEnabled) - sEnTransmit(ChP); /* enable transmitter */ - sStartRxProcessor(ChP); /* restart Rx processor */ -} - -/*************************************************************************** -Function: sWriteTxPrioByte -Purpose: Write a byte of priority transmit data to a channel -Call: sWriteTxPrioByte(ChP,Data) - CHANNEL_T *ChP; Ptr to channel structure - Byte_t Data; The transmit data byte - -Return: int: 1 if the bytes is successfully written, otherwise 0. - -Comments: The priority byte is transmitted before any data in the Tx FIFO. - -Warnings: No context switches are allowed while executing this function. -*/ -int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data) -{ - Byte_t DWBuf[4]; /* buffer for double word writes */ - - if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */ - { - rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); /* get priority buffer status */ - if(rp_readch1(ChP,_INDX_DATA) & PRI_PEND) /* priority buffer busy */ - return(0); /* nothing sent */ - - le16enc(DWBuf,ChP->TxPrioBuf); /* data byte address */ - - DWBuf[2] = Data; /* data byte value */ - DWBuf[3] = 0; /* priority buffer pointer */ - rp_writech4(ChP,_INDX_ADDR,le32dec(DWBuf)); /* write it out */ - - le16enc(DWBuf,ChP->TxPrioCnt); /* Tx priority count address */ - - DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */ - DWBuf[3] = 0; /* priority buffer pointer */ - rp_writech4(ChP,_INDX_ADDR,le32dec(DWBuf)); /* write it out */ - } - else /* write it to Tx FIFO */ - { - sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data); - } - return(1); /* 1 byte sent */ -} - -/*************************************************************************** -Function: sEnInterrupts -Purpose: Enable one or more interrupts for a channel -Call: sEnInterrupts(ChP,Flags) - CHANNEL_T *ChP; Ptr to channel structure - Word_t Flags: Interrupt enable flags, can be any combination - of the following flags: - TXINT_EN: Interrupt on Tx FIFO empty - RXINT_EN: Interrupt on Rx FIFO at trigger level (see - sSetRxTrigger()) - SRCINT_EN: Interrupt on SRC (Special Rx Condition) - MCINT_EN: Interrupt on modem input change - CHANINT_EN: Allow channel interrupt signal to the AIOP's - Interrupt Channel Register. -Return: void -Comments: If an interrupt enable flag is set in Flags, that interrupt will be - enabled. If an interrupt enable flag is not set in Flags, that - interrupt will not be changed. Interrupts can be disabled with - function sDisInterrupts(). - - This function sets the appropriate bit for the channel in the AIOP's - Interrupt Mask Register if the CHANINT_EN flag is set. This allows - this channel's bit to be set in the AIOP's Interrupt Channel Register. - - Interrupts must also be globally enabled before channel interrupts - will be passed on to the host. This is done with function - sEnGlobalInt(). - - In some cases it may be desirable to disable interrupts globally but - enable channel interrupts. This would allow the global interrupt - status register to be used to determine which AIOPs need service. -*/ -void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags) -{ - Byte_t Mask; /* Interrupt Mask Register */ - - ChP->RxControl[2] |= - ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); - - rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl)); - - ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN); - - rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl)); - - if(Flags & CHANINT_EN) - { - Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum]; - rp_writech1(ChP,_INT_MASK,Mask); - } -} - -/*************************************************************************** -Function: sDisInterrupts -Purpose: Disable one or more interrupts for a channel -Call: sDisInterrupts(ChP,Flags) - CHANNEL_T *ChP; Ptr to channel structure - Word_t Flags: Interrupt flags, can be any combination - of the following flags: - TXINT_EN: Interrupt on Tx FIFO empty - RXINT_EN: Interrupt on Rx FIFO at trigger level (see - sSetRxTrigger()) - SRCINT_EN: Interrupt on SRC (Special Rx Condition) - MCINT_EN: Interrupt on modem input change - CHANINT_EN: Disable channel interrupt signal to the - AIOP's Interrupt Channel Register. -Return: void -Comments: If an interrupt flag is set in Flags, that interrupt will be - disabled. If an interrupt flag is not set in Flags, that - interrupt will not be changed. Interrupts can be enabled with - function sEnInterrupts(). - - This function clears the appropriate bit for the channel in the AIOP's - Interrupt Mask Register if the CHANINT_EN flag is set. This blocks - this channel's bit from being set in the AIOP's Interrupt Channel - Register. -*/ -void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags) -{ - Byte_t Mask; /* Interrupt Mask Register */ - - ChP->RxControl[2] &= - ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); - rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl)); - ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN); - rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl)); - - if(Flags & CHANINT_EN) - { - Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum]; - rp_writech1(ChP,_INT_MASK,Mask); - } -} - -/********************************************************************* - Begin FreeBsd-specific driver code -**********************************************************************/ - -#define POLL_INTERVAL (hz / 100) - -#define RP_ISMULTIPORT(dev) ((dev)->id_flags & 0x1) -#define RP_MPMASTER(dev) (((dev)->id_flags >> 8) & 0xff) -#define RP_NOTAST4(dev) ((dev)->id_flags & 0x04) - -/* - * The top-level routines begin here - */ - -static void rpclose(struct tty *tp); -static void rphardclose(struct tty *tp); -static int rpmodem(struct tty *, int, int); -static int rpparam(struct tty *, struct termios *); -static void rpstart(struct tty *); -static int rpioctl(struct tty *, u_long, caddr_t, struct thread *); -static int rpopen(struct tty *); - -static void rp_do_receive(struct rp_port *rp, struct tty *tp, - CHANNEL_t *cp, unsigned int ChanStatus) -{ - unsigned int CharNStat; - int ToRecv, ch, err = 0; - - ToRecv = sGetRxCnt(cp); - if(ToRecv == 0) - return; - -/* If status indicates there are errored characters in the - FIFO, then enter status mode (a word in FIFO holds - characters and status) -*/ - - if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) { - if(!(ChanStatus & STATMODE)) { - ChanStatus |= STATMODE; - sEnRxStatusMode(cp); - } - } -/* - if we previously entered status mode then read down the - FIFO one word at a time, pulling apart the character and - the status. Update error counters depending on status. -*/ - tty_lock(tp); - if(ChanStatus & STATMODE) { - while(ToRecv) { - CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp)); - ch = CharNStat & 0xff; - - if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH)) - err |= TRE_FRAMING; - else if (CharNStat & STMPARITYH) - err |= TRE_PARITY; - else if (CharNStat & STMRCVROVRH) { - rp->rp_overflows++; - err |= TRE_OVERRUN; - } - - ttydisc_rint(tp, ch, err); - ToRecv--; - } -/* - After emtying FIFO in status mode, turn off status mode -*/ - - if(sGetRxCnt(cp) == 0) { - sDisRxStatusMode(cp); - } - } else { - ToRecv = sGetRxCnt(cp); - while (ToRecv) { - ch = rp_readch1(cp,sGetTxRxDataIO(cp)); - ttydisc_rint(tp, ch & 0xff, err); - ToRecv--; - } - } - ttydisc_rint_done(tp); - tty_unlock(tp); -} - -static void rp_handle_port(struct rp_port *rp) -{ - CHANNEL_t *cp; - struct tty *tp; - unsigned int IntMask, ChanStatus; - - if(!rp) - return; - - cp = &rp->rp_channel; - tp = rp->rp_tty; - IntMask = sGetChanIntID(cp); - IntMask = IntMask & rp->rp_intmask; - ChanStatus = sGetChanStatus(cp); - if(IntMask & RXF_TRIG) - rp_do_receive(rp, tp, cp, ChanStatus); - if(IntMask & DELTA_CD) { - if(ChanStatus & CD_ACT) { - (void)ttydisc_modem(tp, 1); - } else { - (void)ttydisc_modem(tp, 0); - } - } -/* oldcts = rp->rp_cts; - rp->rp_cts = ((ChanStatus & CTS_ACT) != 0); - if(oldcts != rp->rp_cts) { - printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port); - } -*/ -} - -static void rp_do_poll(void *arg) -{ - CONTROLLER_t *ctl; - struct rp_port *rp; - struct tty *tp; - int count; - unsigned char CtlMask, AiopMask; - - rp = arg; - tp = rp->rp_tty; - tty_assert_locked(tp); - ctl = rp->rp_ctlp; - CtlMask = ctl->ctlmask(ctl); - if (CtlMask & (1 << rp->rp_aiop)) { - AiopMask = sGetAiopIntStatus(ctl, rp->rp_aiop); - if (AiopMask & (1 << rp->rp_chan)) { - rp_handle_port(rp); - } - } - - count = sGetTxCnt(&rp->rp_channel); - if (count >= 0 && (count <= rp->rp_restart)) { - rpstart(tp); - } - callout_schedule(&rp->rp_timer, POLL_INTERVAL); -} - -static struct ttydevsw rp_tty_class = { - .tsw_flags = TF_INITLOCK|TF_CALLOUT, - .tsw_open = rpopen, - .tsw_close = rpclose, - .tsw_outwakeup = rpstart, - .tsw_ioctl = rpioctl, - .tsw_param = rpparam, - .tsw_modem = rpmodem, - .tsw_free = rpfree, -}; - - -static void -rpfree(void *softc) -{ - struct rp_port *rp = softc; - CONTROLLER_t *ctlp = rp->rp_ctlp; - - atomic_subtract_32(&ctlp->free, 1); -} - -int -rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports) -{ - int unit; - int num_chan; - int aiop, chan, port; - int ChanStatus; - int retval; - struct rp_port *rp; - struct tty *tp; - - unit = device_get_unit(ctlp->dev); - - printf("RocketPort%d (Version %s) %d ports.\n", unit, - RocketPortVersion, num_ports); - - ctlp->num_ports = num_ports; - ctlp->rp = rp = (struct rp_port *) - malloc(sizeof(struct rp_port) * num_ports, M_DEVBUF, M_NOWAIT | M_ZERO); - if (rp == NULL) { - device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n"); - retval = ENOMEM; - goto nogo; - } - - port = 0; - for(aiop=0; aiop < num_aiops; aiop++) { - num_chan = sGetAiopNumChan(ctlp, aiop); - for(chan=0; chan < num_chan; chan++, port++, rp++) { - rp->rp_tty = tp = tty_alloc(&rp_tty_class, rp); - callout_init_mtx(&rp->rp_timer, tty_getlock(tp), 0); - rp->rp_port = port; - rp->rp_ctlp = ctlp; - rp->rp_unit = unit; - rp->rp_chan = chan; - rp->rp_aiop = aiop; - - rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | - DELTA_CD | DELTA_CTS | DELTA_DSR; -#ifdef notdef - ChanStatus = sGetChanStatus(&rp->rp_channel); -#endif /* notdef */ - if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) { - device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n", - unit, aiop, chan); - retval = ENXIO; - goto nogo; - } - ChanStatus = sGetChanStatus(&rp->rp_channel); - rp->rp_cts = (ChanStatus & CTS_ACT) != 0; - tty_makedev(tp, NULL, "R%r%r", unit, port); - } - } - - mtx_init(&ctlp->hwmtx, "rp_hwmtx", NULL, MTX_DEF); - ctlp->hwmtx_init = 1; - return (0); - -nogo: - rp_releaseresource(ctlp); - - return (retval); -} - -void -rp_releaseresource(CONTROLLER_t *ctlp) -{ - struct rp_port *rp; - int i; - - if (ctlp->rp != NULL) { - for (i = 0; i < ctlp->num_ports; i++) { - rp = ctlp->rp + i; - atomic_add_32(&ctlp->free, 1); - tty_lock(rp->rp_tty); - tty_rel_gone(rp->rp_tty); - } - free(ctlp->rp, M_DEVBUF); - ctlp->rp = NULL; - } - - while (ctlp->free != 0) { - pause("rpwt", hz / 10); - } - - if (ctlp->hwmtx_init) - mtx_destroy(&ctlp->hwmtx); -} - -static int -rpopen(struct tty *tp) -{ - struct rp_port *rp; - int flags; - unsigned int IntMask, ChanStatus; - - rp = tty_softc(tp); - - flags = 0; - flags |= SET_RTS; - flags |= SET_DTR; - rp->rp_channel.TxControl[3] = - ((rp->rp_channel.TxControl[3] - & ~(SET_RTS | SET_DTR)) | flags); - rp_writech4(&rp->rp_channel,_INDX_ADDR, - le32dec(rp->rp_channel.TxControl)); - sSetRxTrigger(&rp->rp_channel, TRIG_1); - sDisRxStatusMode(&rp->rp_channel); - sFlushRxFIFO(&rp->rp_channel); - sFlushTxFIFO(&rp->rp_channel); - - sEnInterrupts(&rp->rp_channel, - (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); - sSetRxTrigger(&rp->rp_channel, TRIG_1); - - sDisRxStatusMode(&rp->rp_channel); - sClrTxXOFF(&rp->rp_channel); - -/* sDisRTSFlowCtl(&rp->rp_channel); - sDisCTSFlowCtl(&rp->rp_channel); -*/ - sDisTxSoftFlowCtl(&rp->rp_channel); - - sStartRxProcessor(&rp->rp_channel); - - sEnRxFIFO(&rp->rp_channel); - sEnTransmit(&rp->rp_channel); - -/* sSetDTR(&rp->rp_channel); - sSetRTS(&rp->rp_channel); -*/ - - IntMask = sGetChanIntID(&rp->rp_channel); - IntMask = IntMask & rp->rp_intmask; - ChanStatus = sGetChanStatus(&rp->rp_channel); - - callout_reset(&rp->rp_timer, POLL_INTERVAL, rp_do_poll, rp); - - device_busy(rp->rp_ctlp->dev); - return(0); -} - -static void -rpclose(struct tty *tp) -{ - struct rp_port *rp; - - rp = tty_softc(tp); - callout_stop(&rp->rp_timer); - rphardclose(tp); - device_unbusy(rp->rp_ctlp->dev); -} - -static void -rphardclose(struct tty *tp) -{ - struct rp_port *rp; - CHANNEL_t *cp; - - rp = tty_softc(tp); - cp = &rp->rp_channel; - - sFlushRxFIFO(cp); - sFlushTxFIFO(cp); - sDisTransmit(cp); - sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN); - sDisRTSFlowCtl(cp); - sDisCTSFlowCtl(cp); - sDisTxSoftFlowCtl(cp); - sClrTxXOFF(cp); - -#ifdef DJA - if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !tp->t_actout) { - sClrDTR(cp); - } - if(ISCALLOUT(tp->t_dev)) { - sClrDTR(cp); - } - tp->t_actout = FALSE; - wakeup(&tp->t_actout); - wakeup(TSA_CARR_ON(tp)); -#endif /* DJA */ -} - -static int -rpioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) -{ - struct rp_port *rp; - - rp = tty_softc(tp); - switch (cmd) { - case TIOCSBRK: - sSendBreak(&rp->rp_channel); - return (0); - case TIOCCBRK: - sClrBreak(&rp->rp_channel); - return (0); - default: - return ENOIOCTL; - } -} - -static int -rpmodem(struct tty *tp, int sigon, int sigoff) -{ - struct rp_port *rp; - int i, j, k; - - rp = tty_softc(tp); - if (sigon != 0 || sigoff != 0) { - i = j = 0; - if (sigon & SER_DTR) - i = SET_DTR; - if (sigoff & SER_DTR) - j = SET_DTR; - if (sigon & SER_RTS) - i = SET_RTS; - if (sigoff & SER_RTS) - j = SET_RTS; - rp->rp_channel.TxControl[3] &= ~i; - rp->rp_channel.TxControl[3] |= j; - rp_writech4(&rp->rp_channel,_INDX_ADDR, - le32dec(rp->rp_channel.TxControl)); - } else { - i = sGetChanStatusLo(&rp->rp_channel); - j = rp->rp_channel.TxControl[3]; - k = 0; - if (j & SET_DTR) - k |= SER_DTR; - if (j & SET_RTS) - k |= SER_RTS; - if (i & CD_ACT) - k |= SER_DCD; - if (i & DSR_ACT) - k |= SER_DSR; - if (i & CTS_ACT) - k |= SER_CTS; - return(k); - } - return (0); -} - -static struct -{ - int baud; - int conversion; -} baud_table[] = { - {B0, 0}, {B50, BRD50}, {B75, BRD75}, - {B110, BRD110}, {B134, BRD134}, {B150, BRD150}, - {B200, BRD200}, {B300, BRD300}, {B600, BRD600}, - {B1200, BRD1200}, {B1800, BRD1800}, {B2400, BRD2400}, - {B4800, BRD4800}, {B9600, BRD9600}, {B19200, BRD19200}, - {B38400, BRD38400}, {B7200, BRD7200}, {B14400, BRD14400}, - {B57600, BRD57600}, {B76800, BRD76800}, - {B115200, BRD115200}, {B230400, BRD230400}, - {-1, -1} -}; - -static int rp_convert_baud(int baud) { - int i; - - for (i = 0; baud_table[i].baud >= 0; i++) { - if (baud_table[i].baud == baud) - break; - } - - return baud_table[i].conversion; -} - -static int -rpparam(tp, t) - struct tty *tp; - struct termios *t; -{ - struct rp_port *rp; - CHANNEL_t *cp; - int cflag, iflag, oflag, lflag; - int ospeed; -#ifdef RPCLOCAL - int devshift; -#endif - - rp = tty_softc(tp); - cp = &rp->rp_channel; - - cflag = t->c_cflag; -#ifdef RPCLOCAL - devshift = umynor / 32; - devshift = 1 << devshift; - if ( devshift & RPCLOCAL ) { - cflag |= CLOCAL; - } -#endif - iflag = t->c_iflag; - oflag = t->c_oflag; - lflag = t->c_lflag; - - ospeed = rp_convert_baud(t->c_ispeed); - if(ospeed < 0 || t->c_ispeed != t->c_ospeed) - return(EINVAL); - - if(t->c_ospeed == 0) { - sClrDTR(cp); - return(0); - } - rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1; - - /* Set baud rate ----- we only pay attention to ispeed */ - sSetDTR(cp); - sSetRTS(cp); - sSetBaud(cp, ospeed); - - if(cflag & CSTOPB) { - sSetStop2(cp); - } else { - sSetStop1(cp); - } - - if(cflag & PARENB) { - sEnParity(cp); - if(cflag & PARODD) { - sSetOddParity(cp); - } else { - sSetEvenParity(cp); - } - } - else { - sDisParity(cp); - } - if((cflag & CSIZE) == CS8) { - sSetData8(cp); - rp->rp_imask = 0xFF; - } else { - sSetData7(cp); - rp->rp_imask = 0x7F; - } - - if(iflag & ISTRIP) { - rp->rp_imask &= 0x7F; - } - - if(cflag & CLOCAL) { - rp->rp_intmask &= ~DELTA_CD; - } else { - rp->rp_intmask |= DELTA_CD; - } - - /* Put flow control stuff here */ - - if(cflag & CCTS_OFLOW) { - sEnCTSFlowCtl(cp); - } else { - sDisCTSFlowCtl(cp); - } - - if(cflag & CRTS_IFLOW) { - rp->rp_rts_iflow = 1; - } else { - rp->rp_rts_iflow = 0; - } - - if(cflag & CRTS_IFLOW) { - sEnRTSFlowCtl(cp); - } else { - sDisRTSFlowCtl(cp); - } - - return(0); -} - -static void -rpstart(struct tty *tp) -{ - struct rp_port *rp; - CHANNEL_t *cp; - char flags; - int xmit_fifo_room; - int i, count, wcount; - - rp = tty_softc(tp); - cp = &rp->rp_channel; - flags = rp->rp_channel.TxControl[3]; - - if(rp->rp_xmit_stopped) { - sEnTransmit(cp); - rp->rp_xmit_stopped = 0; - } - - xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); - count = ttydisc_getc(tp, &rp->TxBuf, xmit_fifo_room); - if(xmit_fifo_room > 0) { - for( i = 0, wcount = count >> 1; wcount > 0; i += 2, wcount-- ) { - rp_writech2(cp, sGetTxRxDataIO(cp), le16dec(&rp->TxBuf[i])); - } - if ( count & 1 ) { - rp_writech1(cp, sGetTxRxDataIO(cp), rp->TxBuf[(count-1)]); - } - } -} diff --git a/sys/dev/rp/rp_isa.c b/sys/dev/rp/rp_isa.c deleted file mode 100644 index 7a96d54bd607..000000000000 --- a/sys/dev/rp/rp_isa.c +++ /dev/null @@ -1,508 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) Comtrol Corporation - * All rights reserved. - * - * ISA-specific part separated from: - * sys/i386/isa/rp.c,v 1.33 1999/09/28 11:45:27 phk Exp - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted prodived that the follwoing conditions - * are met. - * 1. Redistributions of source code must retain the above copyright - * notive, this list of conditions and the following disclainer. - * 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 prodided 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 Comtrol Corporation. - * 4. The name of Comtrol Corporation may not be used to endorse or - * promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY COMTROL 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 COMTROL 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, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ROCKET_C -#include -#include - -#include - -/* ISA-specific part of CONTROLLER_t */ -struct ISACONTROLLER_T { - int MBaseIO; /* rid of the Mudbac controller for this controller */ - int MReg0IO; /* offset0 of the Mudbac controller for this controller */ - int MReg1IO; /* offset1 of the Mudbac controller for this controller */ - int MReg2IO; /* offset2 of the Mudbac controller for this controller */ - int MReg3IO; /* offset3 of the Mudbac controller for this controller */ - Byte_t MReg2; - Byte_t MReg3; -}; -typedef struct ISACONTROLLER_T ISACONTROLLER_t; - -#define ISACTL(ctlp) ((ISACONTROLLER_t *)((ctlp)->bus_ctlp)) - -/*************************************************************************** -Function: sControllerEOI -Purpose: Strobe the MUDBAC's End Of Interrupt bit. -Call: sControllerEOI(MudbacCtlP,CtlP) - CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure - CONTROLLER_T *CtlP; Ptr to controller structure -*/ -#define sControllerEOI(MudbacCtlP,CtlP) \ - rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg2IO,ISACTL(CtlP)->MReg2 | INT_STROB) - -/*************************************************************************** -Function: sDisAiop -Purpose: Disable I/O access to an AIOP -Call: sDisAiop(MudbacCtlP,CtlP) - CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure - CONTROLLER_T *CtlP; Ptr to controller structure - int AiopNum; Number of AIOP on controller -*/ -#define sDisAiop(MudbacCtlP,CtlP,AIOPNUM) \ -{ \ - ISACTL(CtlP)->MReg3 &= rp_sBitMapClrTbl[AIOPNUM]; \ - rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); \ -} - -/*************************************************************************** -Function: sEnAiop -Purpose: Enable I/O access to an AIOP -Call: sEnAiop(MudbacCtlP,CtlP) - CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure - CONTROLLER_T *CtlP; Ptr to controller structure - int AiopNum; Number of AIOP on controller -*/ -#define sEnAiop(MudbacCtlP,CtlP,AIOPNUM) \ -{ \ - ISACTL(CtlP)->MReg3 |= rp_sBitMapSetTbl[AIOPNUM]; \ - rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); \ -} - -/*************************************************************************** -Function: sGetControllerIntStatus -Purpose: Get the controller interrupt status -Call: sGetControllerIntStatus(MudbacCtlP,CtlP) - CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure - CONTROLLER_T *CtlP; Ptr to controller structure -Return: Byte_t: The controller interrupt status in the lower 4 - bits. Bits 0 through 3 represent AIOP's 0 - through 3 respectively. If a bit is set that - AIOP is interrupting. Bits 4 through 7 will - always be cleared. -*/ -#define sGetControllerIntStatus(MudbacCtlP,CtlP) \ - (rp_readio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg1IO) & 0x0f) - -static devclass_t rp_devclass; -static CONTROLLER_t *rp_controller; -static int rp_nisadevs; - -static int rp_probe(device_t dev); -static int rp_attach(device_t dev); -static void rp_isareleaseresource(CONTROLLER_t *ctlp); -static int sInitController(CONTROLLER_T *CtlP, - CONTROLLER_T *MudbacCtlP, - int AiopNum, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly); -static rp_aiop2rid_t rp_isa_aiop2rid; -static rp_aiop2off_t rp_isa_aiop2off; -static rp_ctlmask_t rp_isa_ctlmask; - -static int -rp_probe(device_t dev) -{ - int unit; - CONTROLLER_t *controller; - int num_aiops; - CONTROLLER_t *ctlp; - int retval; - - /* - * We have no PnP RocketPort cards. - * (At least according to LINT) - */ - if (isa_get_logicalid(dev) != 0) - return (ENXIO); - - /* We need IO port resource to configure an ISA device. */ - if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 0) - return (ENXIO); - - unit = device_get_unit(dev); - if (unit >= 4) { - device_printf(dev, "rpprobe: unit number %d invalid.\n", unit); - return (ENXIO); - } - device_printf(dev, "probing for RocketPort(ISA) unit %d.\n", unit); - - ctlp = device_get_softc(dev); - bzero(ctlp, sizeof(*ctlp)); - ctlp->dev = dev; - ctlp->aiop2rid = rp_isa_aiop2rid; - ctlp->aiop2off = rp_isa_aiop2off; - ctlp->ctlmask = rp_isa_ctlmask; - - /* The IO ports of AIOPs for an ISA controller are discrete. */ - ctlp->io_num = 1; - ctlp->io_rid = malloc(sizeof(*(ctlp->io_rid)) * MAX_AIOPS_PER_BOARD, M_DEVBUF, M_NOWAIT | M_ZERO); - ctlp->io = malloc(sizeof(*(ctlp->io)) * MAX_AIOPS_PER_BOARD, M_DEVBUF, M_NOWAIT | M_ZERO); - if (ctlp->io_rid == NULL || ctlp->io == NULL) { - device_printf(dev, "rp_attach: Out of memory.\n"); - retval = ENOMEM; - goto nogo; - } - - ctlp->bus_ctlp = malloc(sizeof(ISACONTROLLER_t) * 1, M_DEVBUF, M_NOWAIT | M_ZERO); - if (ctlp->bus_ctlp == NULL) { - device_printf(dev, "rp_attach: Out of memory.\n"); - retval = ENOMEM; - goto nogo; - } - - ctlp->io_rid[0] = 0; - if (rp_controller != NULL) { - controller = rp_controller; - ctlp->io[0] = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0x40, RF_ACTIVE); - } else { - controller = rp_controller = ctlp; - ctlp->io[0] = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0x44, RF_ACTIVE); - } - if (ctlp->io[0] == NULL) { - device_printf(dev, "rp_attach: Resource not available.\n"); - retval = ENXIO; - goto nogo; - } - - num_aiops = sInitController(ctlp, - controller, - MAX_AIOPS_PER_BOARD, 0, - FREQ_DIS, 0); - if (num_aiops <= 0) { - device_printf(dev, "board%d init failed.\n", unit); - retval = ENXIO; - goto nogo; - } - - if (rp_controller == NULL) - rp_controller = controller; - rp_nisadevs++; - - device_set_desc(dev, "RocketPort ISA"); - - return (0); - -nogo: - rp_isareleaseresource(ctlp); - - return (retval); -} - -static int -rp_attach(device_t dev) -{ - int unit; - int num_ports, num_aiops; - int aiop; - CONTROLLER_t *ctlp; - int retval; - - unit = device_get_unit(dev); - - ctlp = device_get_softc(dev); - -#ifdef notdef - num_aiops = sInitController(ctlp, - rp_controller, - MAX_AIOPS_PER_BOARD, 0, - FREQ_DIS, 0); -#else - num_aiops = ctlp->NumAiop; -#endif /* notdef */ - - num_ports = 0; - for(aiop=0; aiop < num_aiops; aiop++) { - sResetAiopByNum(ctlp, aiop); - sEnAiop(rp_controller, ctlp, aiop); - num_ports += sGetAiopNumChan(ctlp, aiop); - } - - retval = rp_attachcommon(ctlp, num_aiops, num_ports); - if (retval != 0) - goto nogo; - - return (0); - -nogo: - rp_isareleaseresource(ctlp); - - return (retval); -} - -static void -rp_isareleaseresource(CONTROLLER_t *ctlp) -{ - int i; - - rp_releaseresource(ctlp); - - if (ctlp == rp_controller) - rp_controller = NULL; - if (ctlp->io != NULL) { - for (i = 0 ; i < MAX_AIOPS_PER_BOARD ; i++) - if (ctlp->io[i] != NULL) - bus_release_resource(ctlp->dev, SYS_RES_IOPORT, ctlp->io_rid[i], ctlp->io[i]); - free(ctlp->io, M_DEVBUF); - } - if (ctlp->io_rid != NULL) - free(ctlp->io_rid, M_DEVBUF); - if (rp_controller != NULL && rp_controller->io[ISACTL(ctlp)->MBaseIO] != NULL) { - bus_release_resource(rp_controller->dev, SYS_RES_IOPORT, rp_controller->io_rid[ISACTL(ctlp)->MBaseIO], rp_controller->io[ISACTL(ctlp)->MBaseIO]); - rp_controller->io[ISACTL(ctlp)->MBaseIO] = NULL; - rp_controller->io_rid[ISACTL(ctlp)->MBaseIO] = 0; - } - if (ctlp->bus_ctlp != NULL) - free(ctlp->bus_ctlp, M_DEVBUF); -} - -/*************************************************************************** -Function: sInitController -Purpose: Initialization of controller global registers and controller - structure. -Call: sInitController(CtlP,MudbacCtlP,AiopNum, - IRQNum,Frequency,PeriodicOnly) - CONTROLLER_T *CtlP; Ptr to controller structure - CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure - int AiopNum; Number of Aiops - int IRQNum; Interrupt Request number. Can be any of the following: - 0: Disable global interrupts - 3: IRQ 3 - 4: IRQ 4 - 5: IRQ 5 - 9: IRQ 9 - 10: IRQ 10 - 11: IRQ 11 - 12: IRQ 12 - 15: IRQ 15 - Byte_t Frequency: A flag identifying the frequency - of the periodic interrupt, can be any one of the following: - FREQ_DIS - periodic interrupt disabled - FREQ_137HZ - 137 Hertz - FREQ_69HZ - 69 Hertz - FREQ_34HZ - 34 Hertz - FREQ_17HZ - 17 Hertz - FREQ_9HZ - 9 Hertz - FREQ_4HZ - 4 Hertz - If IRQNum is set to 0 the Frequency parameter is - overidden, it is forced to a value of FREQ_DIS. - int PeriodicOnly: TRUE if all interrupts except the periodic - interrupt are to be blocked. - FALSE is both the periodic interrupt and - other channel interrupts are allowed. - If IRQNum is set to 0 the PeriodicOnly parameter is - overidden, it is forced to a value of FALSE. -Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller - initialization failed. - -Comments: - If periodic interrupts are to be disabled but AIOP interrupts - are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE. - - If interrupts are to be completely disabled set IRQNum to 0. - - Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an - invalid combination. - - This function performs initialization of global interrupt modes, - but it does not actually enable global interrupts. To enable - and disable global interrupts use functions sEnGlobalInt() and - sDisGlobalInt(). Enabling of global interrupts is normally not - done until all other initializations are complete. - - Even if interrupts are globally enabled, they must also be - individually enabled for each channel that is to generate - interrupts. - -Warnings: No range checking on any of the parameters is done. - - No context switches are allowed while executing this function. - - After this function all AIOPs on the controller are disabled, - they can be enabled with sEnAiop(). -*/ -static int -sInitController( CONTROLLER_T *CtlP, - CONTROLLER_T *MudbacCtlP, - int AiopNum, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly) -{ - int i; - int ctl_base, aiop_base, aiop_size; - - CtlP->CtlID = CTLID_0001; /* controller release 1 */ - - ISACTL(CtlP)->MBaseIO = rp_nisadevs; - if (MudbacCtlP->io[ISACTL(CtlP)->MBaseIO] != NULL) { - ISACTL(CtlP)->MReg0IO = 0x40 + 0; - ISACTL(CtlP)->MReg1IO = 0x40 + 1; - ISACTL(CtlP)->MReg2IO = 0x40 + 2; - ISACTL(CtlP)->MReg3IO = 0x40 + 3; - } else { - MudbacCtlP->io_rid[ISACTL(CtlP)->MBaseIO] = ISACTL(CtlP)->MBaseIO; - ctl_base = rman_get_start(MudbacCtlP->io[0]) + 0x40 + 0x400 * rp_nisadevs; - MudbacCtlP->io[ISACTL(CtlP)->MBaseIO] = bus_alloc_resource(MudbacCtlP->dev, SYS_RES_IOPORT, &CtlP->io_rid[ISACTL(CtlP)->MBaseIO], ctl_base, ctl_base + 3, 4, RF_ACTIVE); - ISACTL(CtlP)->MReg0IO = 0; - ISACTL(CtlP)->MReg1IO = 1; - ISACTL(CtlP)->MReg2IO = 2; - ISACTL(CtlP)->MReg3IO = 3; - } -#if 1 - ISACTL(CtlP)->MReg2 = 0; /* interrupt disable */ - ISACTL(CtlP)->MReg3 = 0; /* no periodic interrupts */ -#else - if(sIRQMap[IRQNum] == 0) /* interrupts globally disabled */ - { - ISACTL(CtlP)->MReg2 = 0; /* interrupt disable */ - ISACTL(CtlP)->MReg3 = 0; /* no periodic interrupts */ - } - else - { - ISACTL(CtlP)->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */ - ISACTL(CtlP)->MReg3 = Frequency; /* set frequency */ - if(PeriodicOnly) /* periodic interrupt only */ - { - ISACTL(CtlP)->MReg3 |= PERIODIC_ONLY; - } - } -#endif - rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg2IO,ISACTL(CtlP)->MReg2); - rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); - sControllerEOI(MudbacCtlP,CtlP); /* clear EOI if warm init */ - - /* Init AIOPs */ - CtlP->NumAiop = 0; - for(i=0; i < AiopNum; i++) - { - if (CtlP->io[i] == NULL) { - CtlP->io_rid[i] = i; - aiop_base = rman_get_start(CtlP->io[0]) + 0x400 * i; - if (rp_nisadevs == 0) - aiop_size = 0x44; - else - aiop_size = 0x40; - CtlP->io[i] = bus_alloc_resource(CtlP->dev, SYS_RES_IOPORT, &CtlP->io_rid[i], aiop_base, aiop_base + aiop_size - 1, aiop_size, RF_ACTIVE); - } else - aiop_base = rman_get_start(CtlP->io[i]); - rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO, - ISACTL(CtlP)->MReg2IO, - ISACTL(CtlP)->MReg2 | (i & 0x03)); /* AIOP index */ - rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO, - ISACTL(CtlP)->MReg0IO, - (Byte_t)(aiop_base >> 6)); /* set up AIOP I/O in MUDBAC */ - sEnAiop(MudbacCtlP,CtlP,i); /* enable the AIOP */ - - CtlP->AiopID[i] = sReadAiopID(CtlP, i); /* read AIOP ID */ - if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ - { - sDisAiop(MudbacCtlP,CtlP,i); /* disable AIOP */ - bus_release_resource(CtlP->dev, SYS_RES_IOPORT, CtlP->io_rid[i], CtlP->io[i]); - CtlP->io[i] = NULL; - break; /* done looking for AIOPs */ - } - - CtlP->AiopNumChan[i] = sReadAiopNumChan(CtlP, i); /* num channels in AIOP */ - rp_writeaiop2(CtlP,i,_INDX_ADDR,_CLK_PRE); /* clock prescaler */ - rp_writeaiop1(CtlP,i,_INDX_DATA,CLOCK_PRESC); - CtlP->NumAiop++; /* bump count of AIOPs */ - sDisAiop(MudbacCtlP,CtlP,i); /* disable AIOP */ - } - - if(CtlP->NumAiop == 0) - return(-1); - else - return(CtlP->NumAiop); -} - -/* - * ARGSUSED - * Maps (aiop, offset) to rid. - */ -static int -rp_isa_aiop2rid(int aiop, int offset) -{ - /* rid equals to aiop for an ISA controller. */ - return aiop; -} - -/* - * ARGSUSED - * Maps (aiop, offset) to the offset of resource. - */ -static int -rp_isa_aiop2off(int aiop, int offset) -{ - /* Each aiop has its own resource. */ - return offset; -} - -/* Read the int status for an ISA controller. */ -static unsigned char -rp_isa_ctlmask(CONTROLLER_t *ctlp) -{ - return sGetControllerIntStatus(rp_controller,ctlp); -} - -static device_method_t rp_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, rp_probe), - DEVMETHOD(device_attach, rp_attach), - - { 0, 0 } -}; - -static driver_t rp_driver = { - "rp", - rp_methods, - sizeof(CONTROLLER_t), -}; - -/* - * rp can be attached to an isa bus. - */ -DRIVER_MODULE(rp, isa, rp_driver, rp_devclass, 0, 0); diff --git a/sys/dev/rp/rp_pci.c b/sys/dev/rp/rp_pci.c deleted file mode 100644 index afd378c3c119..000000000000 --- a/sys/dev/rp/rp_pci.c +++ /dev/null @@ -1,368 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) Comtrol Corporation - * All rights reserved. - * - * PCI-specific part separated from: - * sys/i386/isa/rp.c,v 1.33 1999/09/28 11:45:27 phk Exp - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted prodived that the follwoing conditions - * are met. - * 1. Redistributions of source code must retain the above copyright - * notive, this list of conditions and the following disclainer. - * 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 prodided 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 Comtrol Corporation. - * 4. The name of Comtrol Corporation may not be used to endorse or - * promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY COMTROL 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 COMTROL 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, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ROCKET_C -#include -#include - -#include -#include - -/* PCI IDs */ -#define RP_VENDOR_ID 0x11FE -#define RP_DEVICE_ID_32I 0x0001 -#define RP_DEVICE_ID_8I 0x0002 -#define RP_DEVICE_ID_16I 0x0003 -#define RP_DEVICE_ID_4Q 0x0004 -#define RP_DEVICE_ID_8O 0x0005 -#define RP_DEVICE_ID_8J 0x0006 -#define RP_DEVICE_ID_4J 0x0007 -#define RP_DEVICE_ID_6M 0x000C -#define RP_DEVICE_ID_4M 0x000D -#define RP_DEVICE_ID_UPCI_32 0x0801 -#define RP_DEVICE_ID_UPCI_16 0x0803 -#define RP_DEVICE_ID_UPCI_8O 0x0805 - -/************************************************************************** - MUDBAC remapped for PCI -**************************************************************************/ - -#define _CFG_INT_PCI 0x40 -#define _PCI_INT_FUNC 0x3A - -#define PCI_STROB 0x2000 -#define INTR_EN_PCI 0x0010 - -/*************************************************************************** -Function: sPCIControllerEOI -Purpose: Strobe the MUDBAC's End Of Interrupt bit. -Call: sPCIControllerEOI(CtlP) - CONTROLLER_T *CtlP; Ptr to controller structure -*/ -#define sPCIControllerEOI(CtlP) rp_writeio2(CtlP, 0, _PCI_INT_FUNC, PCI_STROB) - -/*************************************************************************** -Function: sPCIGetControllerIntStatus -Purpose: Get the controller interrupt status -Call: sPCIGetControllerIntStatus(CtlP) - CONTROLLER_T *CtlP; Ptr to controller structure -Return: Byte_t: The controller interrupt status in the lower 4 - bits. Bits 0 through 3 represent AIOP's 0 - through 3 respectively. If a bit is set that - AIOP is interrupting. Bits 4 through 7 will - always be cleared. -*/ -#define sPCIGetControllerIntStatus(CTLP) ((rp_readio2(CTLP, 0, _PCI_INT_FUNC) >> 8) & 0x1f) - -static devclass_t rp_devclass; - -static int rp_pciprobe(device_t dev); -static int rp_pciattach(device_t dev); -#ifdef notdef -static int rp_pcidetach(device_t dev); -static int rp_pcishutdown(device_t dev); -#endif /* notdef */ -static void rp_pcireleaseresource(CONTROLLER_t *ctlp); -static int sPCIInitController( CONTROLLER_t *CtlP, - int AiopNum, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly, - int VendorDevice); -static rp_aiop2rid_t rp_pci_aiop2rid; -static rp_aiop2off_t rp_pci_aiop2off; -static rp_ctlmask_t rp_pci_ctlmask; - -/* - * The following functions are the pci-specific part - * of rp driver. - */ - -static int -rp_pciprobe(device_t dev) -{ - char *s; - - s = NULL; - if (pci_get_vendor(dev) == RP_VENDOR_ID) - s = "RocketPort PCI"; - - if (s != NULL) { - device_set_desc(dev, s); - return (BUS_PROBE_DEFAULT); - } - - return (ENXIO); -} - -static int -rp_pciattach(device_t dev) -{ - int num_ports, num_aiops; - int aiop; - CONTROLLER_t *ctlp; - int unit; - int retval; - - ctlp = device_get_softc(dev); - bzero(ctlp, sizeof(*ctlp)); - ctlp->dev = dev; - unit = device_get_unit(dev); - ctlp->aiop2rid = rp_pci_aiop2rid; - ctlp->aiop2off = rp_pci_aiop2off; - ctlp->ctlmask = rp_pci_ctlmask; - - /* The IO ports of AIOPs for a PCI controller are continuous. */ - ctlp->io_num = 1; - ctlp->io_rid = malloc(sizeof(*(ctlp->io_rid)) * ctlp->io_num, M_DEVBUF, M_NOWAIT | M_ZERO); - ctlp->io = malloc(sizeof(*(ctlp->io)) * ctlp->io_num, M_DEVBUF, M_NOWAIT | M_ZERO); - if (ctlp->io_rid == NULL || ctlp->io == NULL) { - device_printf(dev, "rp_pciattach: Out of memory.\n"); - retval = ENOMEM; - goto nogo; - } - - ctlp->bus_ctlp = NULL; - - switch (pci_get_device(dev)) { - case RP_DEVICE_ID_UPCI_16: - case RP_DEVICE_ID_UPCI_32: - case RP_DEVICE_ID_UPCI_8O: - ctlp->io_rid[0] = PCIR_BAR(2); - break; - default: - ctlp->io_rid[0] = PCIR_BAR(0); - break; - } - ctlp->io[0] = bus_alloc_resource_any(dev, SYS_RES_IOPORT, - &ctlp->io_rid[0], RF_ACTIVE); - if(ctlp->io[0] == NULL) { - device_printf(dev, "ioaddr mapping failed for RocketPort(PCI).\n"); - retval = ENXIO; - goto nogo; - } - - num_aiops = sPCIInitController(ctlp, - MAX_AIOPS_PER_BOARD, 0, - FREQ_DIS, 0, pci_get_device(dev)); - - num_ports = 0; - for(aiop=0; aiop < num_aiops; aiop++) { - sResetAiopByNum(ctlp, aiop); - num_ports += sGetAiopNumChan(ctlp, aiop); - } - - retval = rp_attachcommon(ctlp, num_aiops, num_ports); - if (retval != 0) - goto nogo; - - return (0); - -nogo: - rp_pcireleaseresource(ctlp); - - return (retval); -} - -static int -rp_pcidetach(device_t dev) -{ - CONTROLLER_t *ctlp; - - ctlp = device_get_softc(dev); - rp_pcireleaseresource(ctlp); - - return (0); -} - -static int -rp_pcishutdown(device_t dev) -{ - CONTROLLER_t *ctlp; - - ctlp = device_get_softc(dev); - rp_pcireleaseresource(ctlp); - - return (0); -} - -static void -rp_pcireleaseresource(CONTROLLER_t *ctlp) -{ - rp_releaseresource(ctlp); - if (ctlp->io != NULL) { - if (ctlp->io[0] != NULL) - bus_release_resource(ctlp->dev, SYS_RES_IOPORT, ctlp->io_rid[0], ctlp->io[0]); - free(ctlp->io, M_DEVBUF); - ctlp->io = NULL; - } - if (ctlp->io_rid != NULL) { - free(ctlp->io_rid, M_DEVBUF); - ctlp->io = NULL; - } -} - -static int -sPCIInitController( CONTROLLER_t *CtlP, - int AiopNum, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly, - int VendorDevice) -{ - int i; - - CtlP->CtlID = CTLID_0001; /* controller release 1 */ - - sPCIControllerEOI(CtlP); - - /* Init AIOPs */ - CtlP->NumAiop = 0; - for(i=0; i < AiopNum; i++) - { - /*device_printf(CtlP->dev, "aiop %d.\n", i);*/ - CtlP->AiopID[i] = sReadAiopID(CtlP, i); /* read AIOP ID */ - /*device_printf(CtlP->dev, "ID = %d.\n", CtlP->AiopID[i]);*/ - if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ - { - break; /* done looking for AIOPs */ - } - - switch( VendorDevice ) { - case RP_DEVICE_ID_4Q: - case RP_DEVICE_ID_4J: - case RP_DEVICE_ID_4M: - CtlP->AiopNumChan[i] = 4; - break; - case RP_DEVICE_ID_6M: - CtlP->AiopNumChan[i] = 6; - break; - case RP_DEVICE_ID_8O: - case RP_DEVICE_ID_8J: - case RP_DEVICE_ID_8I: - case RP_DEVICE_ID_16I: - case RP_DEVICE_ID_32I: - CtlP->AiopNumChan[i] = 8; - break; - default: -#ifdef notdef - CtlP->AiopNumChan[i] = 8; -#else - CtlP->AiopNumChan[i] = sReadAiopNumChan(CtlP, i); -#endif /* notdef */ - break; - } - /*device_printf(CtlP->dev, "%d channels.\n", CtlP->AiopNumChan[i]);*/ - rp_writeaiop2(CtlP, i, _INDX_ADDR,_CLK_PRE); /* clock prescaler */ - /*device_printf(CtlP->dev, "configuring clock prescaler.\n");*/ - rp_writeaiop1(CtlP, i, _INDX_DATA,CLOCK_PRESC); - /*device_printf(CtlP->dev, "configured clock prescaler.\n");*/ - CtlP->NumAiop++; /* bump count of AIOPs */ - } - - if(CtlP->NumAiop == 0) - return(-1); - else - return(CtlP->NumAiop); -} - -/* - * ARGSUSED - * Maps (aiop, offset) to rid. - */ -static int -rp_pci_aiop2rid(int aiop, int offset) -{ - /* Always return zero for a PCI controller. */ - return 0; -} - -/* - * ARGSUSED - * Maps (aiop, offset) to the offset of resource. - */ -static int -rp_pci_aiop2off(int aiop, int offset) -{ - /* Each AIOP reserves 0x40 bytes. */ - return aiop * 0x40 + offset; -} - -/* Read the int status for a PCI controller. */ -static unsigned char -rp_pci_ctlmask(CONTROLLER_t *ctlp) -{ - return sPCIGetControllerIntStatus(ctlp); -} - -static device_method_t rp_pcimethods[] = { - /* Device interface */ - DEVMETHOD(device_probe, rp_pciprobe), - DEVMETHOD(device_attach, rp_pciattach), - DEVMETHOD(device_detach, rp_pcidetach), - DEVMETHOD(device_shutdown, rp_pcishutdown), - - { 0, 0 } -}; - -static driver_t rp_pcidriver = { - "rp", - rp_pcimethods, - sizeof(CONTROLLER_t), -}; - -/* - * rp can be attached to a pci bus. - */ -DRIVER_MODULE(rp, pci, rp_pcidriver, rp_devclass, 0, 0); diff --git a/sys/dev/rp/rpreg.h b/sys/dev/rp/rpreg.h deleted file mode 100644 index bd1de316028d..000000000000 --- a/sys/dev/rp/rpreg.h +++ /dev/null @@ -1,1033 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) Comtrol Corporation - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted prodived that the follwoing conditions - * are met. - * 1. Redistributions of source code must retain the above copyright - * notive, this list of conditions and the following disclainer. - * 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 prodided 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 Comtrol Corporation. - * 4. The name of Comtrol Corporation may not be used to endorse or - * promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY COMTROL 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 COMTROL 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, LIFE 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$ - */ - -/* - * Begin OS-specific defines - rpreg.h - for RocketPort FreeBSD - */ - -typedef uint8_t Byte_t; -typedef uint8_t ByteIO_t; - -typedef uint16_t Word_t; -typedef uint16_t WordIO_t; - -typedef uint32_t DWord_t; -typedef uint32_t DWordIO_t; - -#define rp_readio(size, ctlp, rid, offset) \ - (bus_read_##size(ctlp->io[rid], offset)) -#define rp_readmultiio(size, ctlp, rid, offset, addr, count) \ - (bus_read_multi_##size(ctlp->io[rid], offset, addr, count)) -#define rp_writeio(size, ctlp, rid, offset, data) \ - (bus_write_##size(ctlp->io[rid], offset, data)) -#define rp_writemultiio(size, ctlp, rid, offset, addr, count) \ - (bus_write_multi_##size(ctlp->io[rid], offset, addr, count)) - -#define rp_readio1(ctlp, rid, offset) rp_readio(1, ctlp, rid, offset) -#define rp_readio2(ctlp, rid, offset) rp_readio(2, ctlp, rid, offset) -#define rp_readio4(ctlp, rid, offset) rp_readio(4, ctlp, rid, offset) -#define rp_writeio1(ctlp, rid, offset, data) rp_writeio(1, ctlp, rid, offset, data) -#define rp_writeio2(ctlp, rid, offset, data) rp_writeio(2, ctlp, rid, offset, data) -#define rp_writeio4(ctlp, rid, offset, data) rp_writeio(4, ctlp, rid, offset, data) -#define rp_readmultiio1(ctlp, rid, offset, addr, count) rp_readmultiio(1, ctlp, rid, offset, addr, count) -#define rp_readmultiio2(ctlp, rid, offset, addr, count) rp_readmultiio(2, ctlp, rid, offset, addr, count) -#define rp_readmultiio4(ctlp, rid, offset, addr, count) rp_readmultiio(4, ctlp, rid, offset, addr, count) -#define rp_writemultiio1(ctlp, rid, offset, addr, count) rp_writemultiio(1, ctlp, rid, offset, addr, count) -#define rp_writemultiio2(ctlp, rid, offset, addr, count) rp_writemultiio(2, ctlp, rid, offset, addr, count) -#define rp_writemultiio4(ctlp, rid, offset, addr, count) rp_writemultiio(4, ctlp, rid, offset, addr, count) - -#define rp_readaiop1(ctlp, aiop, offset) \ - (rp_readio1((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset))) -#define rp_readaiop2(ctlp, aiop, offset) \ - (rp_readio2((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset))) -#define rp_readaiop4(ctlp, aiop, offset) \ - (rp_readio4((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset))) -#define rp_readmultiaiop1(ctlp, aiop, offset, addr, count) \ - (rp_readmultiio1((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), addr, count)) -#define rp_readmultiaiop2(ctlp, aiop, offset, addr, count) \ - (rp_readmultiio2((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), addr, count)) -#define rp_readmultiaiop4(ctlp, aiop, offset, addr, count) \ - (rp_readmultiio4((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), addr, count)) -#define rp_writeaiop1(ctlp, aiop, offset, data) \ - (rp_writeio1((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), data)) -#define rp_writeaiop2(ctlp, aiop, offset, data) \ - (rp_writeio2((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), data)) -#define rp_writeaiop4(ctlp, aiop, offset, data) \ - (rp_writeio4((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), data)) -#define rp_writemultiaiop1(ctlp, aiop, offset, addr, count) \ - (rp_writemultiio1((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), addr, count)) -#define rp_writemultiaiop2(ctlp, aiop, offset, addr, count) \ - (rp_writemultiio2((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), addr, count)) -#define rp_writemultiaiop4(ctlp, aiop, offset, addr, count) \ - (rp_writemultiio4((ctlp), (ctlp)->aiop2rid(aiop, offset), (ctlp)->aiop2off(aiop, offset), addr, count)) - -#define rp_readch1(chp, offset) \ - (rp_readaiop1((chp)->CtlP, (chp)->AiopNum, offset)) -#define rp_readch2(chp, offset) \ - (rp_readaiop2((chp)->CtlP, (chp)->AiopNum, offset)) -#define rp_readch4(chp, offset) \ - (rp_readaiop4((chp)->CtlP, (chp)->AiopNum, offset)) -#define rp_readmultich1(chp, offset, addr, count) \ - (rp_readmultiaiop1((chp)->CtlP, (chp)->AiopNum, offset, addr, count)) -#define rp_readmultich2(chp, offset, addr, count) \ - (rp_readmultiaiop2((chp)->CtlP, (chp)->AiopNum, offset, addr, count)) -#define rp_readmultich4(chp, offset, addr, count) \ - (rp_readmultiaiop4((chp)->CtlP, (chp)->AiopNum, offset, addr, count)) -#define rp_writech1(chp, offset, data) \ - (rp_writeaiop1((chp)->CtlP, (chp)->AiopNum, offset, data)) -#define rp_writech2(chp, offset, data) \ - (rp_writeaiop2((chp)->CtlP, (chp)->AiopNum, offset, data)) -#define rp_writech4(chp, offset, data) \ - (rp_writeaiop4((chp)->CtlP, (chp)->AiopNum, offset, data)) -#define rp_writemultich1(chp, offset, addr, count) \ - (rp_writemultiaiop1((chp)->CtlP, (chp)->AiopNum, offset, addr, count)) -#define rp_writemultich2(chp, offset, addr, count) \ - (rp_writemultiaiop2((chp)->CtlP, (chp)->AiopNum, offset, addr, count)) -#define rp_writemultich4(chp, offset, addr, count) \ - (rp_writemultiaiop4((chp)->CtlP, (chp)->AiopNum, offset, addr, count)) - -/* - * End of OS-specific defines - */ - -#define ROCKET_H - -#define CTL_SIZE 4 -#define AIOP_CTL_SIZE 4 -#define CHAN_AIOP_SIZE 8 -#define MAX_PORTS_PER_AIOP 8 -#define MAX_AIOPS_PER_BOARD 4 -#define MAX_PORTS_PER_BOARD 32 - -/* Controller ID numbers */ -#define CTLID_NULL -1 /* no controller exists */ -#define CTLID_0001 0x0001 /* controller release 1 */ - -/* AIOP ID numbers, identifies AIOP type implementing channel */ -#define AIOPID_NULL -1 /* no AIOP or channel exists */ -#define AIOPID_0001 0x0001 /* AIOP release 1 */ - -#define NULLDEV -1 /* identifies non-existant device */ -#define NULLCTL -1 /* identifies non-existant controller */ -#define NULLCTLPTR (CONTROLLER_T *)0 /* identifies non-existant controller */ -#define NULLAIOP -1 /* identifies non-existant AIOP */ -#define NULLCHAN -1 /* identifies non-existant channel */ - -/************************************************************************ - Global Register Offsets - Direct Access - Fixed values -************************************************************************/ - -#define _CMD_REG 0x38 /* Command Register 8 Write */ -#define _INT_CHAN 0x39 /* Interrupt Channel Register 8 Read */ -#define _INT_MASK 0x3A /* Interrupt Mask Register 8 Read / Write */ -#define _UNUSED 0x3B /* Unused 8 */ -#define _INDX_ADDR 0x3C /* Index Register Address 16 Write */ -#define _INDX_DATA 0x3E /* Index Register Data 8/16 Read / Write */ - -/************************************************************************ - Channel Register Offsets for 1st channel in AIOP - Direct Access -************************************************************************/ -#define _TD0 0x00 /* Transmit Data 16 Write */ -#define _RD0 0x00 /* Receive Data 16 Read */ -#define _CHN_STAT0 0x20 /* Channel Status 8/16 Read / Write */ -#define _FIFO_CNT0 0x10 /* Transmit/Receive FIFO Count 16 Read */ -#define _INT_ID0 0x30 /* Interrupt Identification 8 Read */ - -/************************************************************************ - Tx Control Register Offsets - Indexed - External - Fixed -************************************************************************/ -#define _TX_ENBLS 0x980 /* Tx Processor Enables Register 8 Read / Write */ -#define _TXCMP1 0x988 /* Transmit Compare Value #1 8 Read / Write */ -#define _TXCMP2 0x989 /* Transmit Compare Value #2 8 Read / Write */ -#define _TXREP1B1 0x98A /* Tx Replace Value #1 - Byte 1 8 Read / Write */ -#define _TXREP1B2 0x98B /* Tx Replace Value #1 - Byte 2 8 Read / Write */ -#define _TXREP2 0x98C /* Transmit Replace Value #2 8 Read / Write */ - -/************************************************************************ - Receive FIFO -************************************************************************/ -#define RXFIFO_DATA 0x5f -#define RXFIFO_OUT 0x5c -#define RXFIFO_EN 0x08 -#define RXFIFO_DIS 0xa7 - -/************************************************************************ -Memory Controller Register Offsets - Indexed - External - Fixed -************************************************************************/ -#define _RX_FIFO 0x000 /* Rx FIFO */ -#define _TX_FIFO 0x800 /* Tx FIFO */ -#define _RXF_OUTP 0x990 /* Rx FIFO OUT pointer 16 Read / Write */ -#define _RXF_INP 0x992 /* Rx FIFO IN pointer 16 Read / Write */ -#define _TXF_OUTP 0x994 /* Tx FIFO OUT pointer 8 Read / Write */ -#define _TXF_INP 0x995 /* Tx FIFO IN pointer 8 Read / Write */ -#define _TXP_CNT 0x996 /* Tx Priority Count 8 Read / Write */ -#define _TXP_PNTR 0x997 /* Tx Priority Pointer 8 Read / Write */ - -#define PRI_PEND 0x80 /* Priority data pending (bit7, Tx pri cnt) */ -#define TXFIFO_SIZE 255 /* size of Tx FIFO */ -#define RXFIFO_SIZE 1023 /* size of Rx FIFO */ - -/************************************************************************ -Tx Priority Buffer - Indexed - External - Fixed -************************************************************************/ -#define _TXP_BUF 0x9C0 /* Tx Priority Buffer 32 Bytes Read / Write */ -#define TXP_SIZE 0x20 /* 32 bytes */ - -/************************************************************************ -Channel Register Offsets - Indexed - Internal - Fixed -************************************************************************/ - -#define _TX_CTRL 0xFF0 /* Transmit Control 16 Write */ -#define _RX_CTRL 0xFF2 /* Receive Control 8 Write */ -#define _BAUD 0xFF4 /* Baud Rate 16 Write */ -#define _CLK_PRE 0xFF6 /* Clock Prescaler 8 Write */ - -#define CLOCK_PRESC 0x19 /* mod 9 (divide by 10) prescale */ - -#define BRD50 4607 -#define BRD75 3071 -#define BRD110 2094 -#define BRD134 1712 -#define BRD150 1535 -#define BRD200 1151 -#define BRD300 767 -#define BRD600 383 -#define BRD1200 191 -#define BRD1800 127 -#define BRD2000 114 -#define BRD2400 95 -#define BRD3600 64 -#define BRD4800 47 -#define BRD7200 31 -#define BRD9600 23 -#define BRD14400 15 -#define BRD19200 11 -#define BRD38400 5 -#define BRD57600 3 -#define BRD76800 2 -#define BRD115200 1 -#define BRD230400 0 - -#define STMBREAK 0x08 /* BREAK */ -#define STMFRAME 0x04 /* framing error */ -#define STMRCVROVR 0x02 /* receiver over run error */ -#define STMPARITY 0x01 /* parity error */ -#define STMERROR (STMBREAK | STMFRAME | STMPARITY) -#define STMBREAKH 0x800 /* BREAK */ -#define STMFRAMEH 0x400 /* framing error */ -#define STMRCVROVRH 0x200 /* receiver over run error */ -#define STMPARITYH 0x100 /* parity error */ -#define STMERRORH (STMBREAKH | STMFRAMEH | STMPARITYH) - -#define CTS_ACT 0x20 /* CTS input asserted */ -#define DSR_ACT 0x10 /* DSR input asserted */ -#define CD_ACT 0x08 /* CD input asserted */ -#define TXFIFOMT 0x04 /* Tx FIFO is empty */ -#define TXSHRMT 0x02 /* Tx shift register is empty */ -#define RDA 0x01 /* Rx data available */ -#define DRAINED (TXFIFOMT | TXSHRMT) /* indicates Tx is drained */ - -#define STATMODE 0x8000 /* status mode enable bit */ -#define RXFOVERFL 0x2000 /* receive FIFO overflow */ -#define RX2MATCH 0x1000 /* receive compare byte 2 match */ -#define RX1MATCH 0x0800 /* receive compare byte 1 match */ -#define RXBREAK 0x0400 /* received BREAK */ -#define RXFRAME 0x0200 /* received framing error */ -#define RXPARITY 0x0100 /* received parity error */ -#define STATERROR (RXBREAK | RXFRAME | RXPARITY) - -#define CTSFC_EN 0x80 /* CTS flow control enable bit */ -#define RTSTOG_EN 0x40 /* RTS toggle enable bit */ -#define TXINT_EN 0x10 /* transmit interrupt enable */ -#define STOP2 0x08 /* enable 2 stop bits (0 = 1 stop) */ -#define PARITY_EN 0x04 /* enable parity (0 = no parity) */ -#define EVEN_PAR 0x02 /* even parity (0 = odd parity) */ -#define DATA8BIT 0x01 /* 8 bit data (0 = 7 bit data) */ - -#define SETBREAK 0x10 /* send break condition (must clear) */ -#define LOCALLOOP 0x08 /* local loopback set for test */ -#define SET_DTR 0x04 /* assert DTR */ -#define SET_RTS 0x02 /* assert RTS */ -#define TX_ENABLE 0x01 /* enable transmitter */ - -#define RTSFC_EN 0x40 /* RTS flow control enable */ -#define RXPROC_EN 0x20 /* receive processor enable */ -#define TRIG_NO 0x00 /* Rx FIFO trigger level 0 (no trigger) */ -#define TRIG_1 0x08 /* trigger level 1 char */ -#define TRIG_1_2 0x10 /* trigger level 1/2 */ -#define TRIG_7_8 0x18 /* trigger level 7/8 */ -#define TRIG_MASK 0x18 /* trigger level mask */ -#define SRCINT_EN 0x04 /* special Rx condition interrupt enable */ -#define RXINT_EN 0x02 /* Rx interrupt enable */ -#define MCINT_EN 0x01 /* modem change interrupt enable */ - -#define RXF_TRIG 0x20 /* Rx FIFO trigger level interrupt */ -#define TXFIFO_MT 0x10 /* Tx FIFO empty interrupt */ -#define SRC_INT 0x08 /* special receive condition interrupt */ -#define DELTA_CD 0x04 /* CD change interrupt */ -#define DELTA_CTS 0x02 /* CTS change interrupt */ -#define DELTA_DSR 0x01 /* DSR change interrupt */ - -#define REP1W2_EN 0x10 /* replace byte 1 with 2 bytes enable */ -#define IGN2_EN 0x08 /* ignore byte 2 enable */ -#define IGN1_EN 0x04 /* ignore byte 1 enable */ -#define COMP2_EN 0x02 /* compare byte 2 enable */ -#define COMP1_EN 0x01 /* compare byte 1 enable */ - -#define RESET_ALL 0x80 /* reset AIOP (all channels) */ -#define TXOVERIDE 0x40 /* Transmit software off override */ -#define RESETUART 0x20 /* reset channel's UART */ -#define RESTXFCNT 0x10 /* reset channel's Tx FIFO count register */ -#define RESRXFCNT 0x08 /* reset channel's Rx FIFO count register */ - -#define INTSTAT0 0x01 /* AIOP 0 interrupt status */ -#define INTSTAT1 0x02 /* AIOP 1 interrupt status */ -#define INTSTAT2 0x04 /* AIOP 2 interrupt status */ -#define INTSTAT3 0x08 /* AIOP 3 interrupt status */ - -#define INTR_EN 0x08 /* allow interrupts to host */ -#define INT_STROB 0x04 /* strobe and clear interrupt line (EOI) */ - -#define CHAN3_EN 0x08 /* enable AIOP 3 */ -#define CHAN2_EN 0x04 /* enable AIOP 2 */ -#define CHAN1_EN 0x02 /* enable AIOP 1 */ -#define CHAN0_EN 0x01 /* enable AIOP 0 */ -#define FREQ_DIS 0x00 -#define FREQ_274HZ 0x60 -#define FREQ_137HZ 0x50 -#define FREQ_69HZ 0x40 -#define FREQ_34HZ 0x30 -#define FREQ_17HZ 0x20 -#define FREQ_9HZ 0x10 -#define PERIODIC_ONLY 0x80 /* only PERIODIC interrupt */ - -#define CHANINT_EN 0x0100 /* flags to enable/disable channel ints */ - -#define RDATASIZE 72 -#define RREGDATASIZE 52 - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -struct CONTROLLER_str; -struct CHANNEL_str; - -/* The types of bus-specific methods */ -typedef int rp_aiop2rid_t(int, int); -typedef int rp_aiop2off_t(int, int); -typedef unsigned char rp_ctlmask_t(struct CONTROLLER_str *); - -/* Controller level information structure */ -struct CONTROLLER_str -{ - int CtlID; - int NumAiop; - int AiopID[AIOP_CTL_SIZE]; - int AiopNumChan[AIOP_CTL_SIZE]; - - struct mtx hwmtx; /* Spinlock protecting hardware. */ - int hwmtx_init; - int free; - int num_ports; - - /* Device and resource management */ - device_t dev; /* device */ - int io_num; /* Number of IO resources */ - int *io_rid; /* IO resource IDs */ - struct resource **io; /* IO resources */ - - struct rp_port *rp; /* port */ - - /* Device nodes */ - struct cdev **dev_nodes; - - /* Bus-specific properties */ - void *bus_ctlp; - - /* Bus-specific methods */ - rp_aiop2rid_t *aiop2rid; /* (aiop, offset) -> rid */ - rp_aiop2off_t *aiop2off; /* (aiop, offset) -> off */ - rp_ctlmask_t *ctlmask; /* Int status */ -}; -typedef struct CONTROLLER_str CONTROLLER_T; -typedef CONTROLLER_T CONTROLLER_t; - -/* Channel level information structure */ -struct CHANNEL_str -{ - CONTROLLER_t *CtlP; - int AiopNum; - int ChanID; - int ChanNum; - - Word_t TxFIFO; - Word_t TxFIFOPtrs; - Word_t RxFIFO; - Word_t RxFIFOPtrs; - Word_t TxPrioCnt; - Word_t TxPrioPtr; - Word_t TxPrioBuf; - - Byte_t R[RREGDATASIZE]; - - Byte_t BaudDiv[4]; - Byte_t TxControl[4]; - Byte_t RxControl[4]; - Byte_t TxEnables[4]; - Byte_t TxCompare[4]; - Byte_t TxReplace1[4]; - Byte_t TxReplace2[4]; -}; - -typedef struct CHANNEL_str CHANNEL_T; -typedef CHANNEL_T CHANNEL_t; -typedef CHANNEL_T * CHANPTR_T; - -#define CHNOFF_TXRXDATA(chp) ((chp)->ChanNum * 2 + _TD0) -#define CHNOFF_CHANSTAT(chp) ((chp)->ChanNum * 2 + _CHN_STAT0) -#define CHNOFF_TXRXCOUNT(chp) ((chp)->ChanNum * 2 + _FIFO_CNT0) -#define CHNOFF_INTID(chp) ((chp)->ChanNum + _INT_ID0) - -/*************************************************************************** -Function: sClrBreak -Purpose: Stop sending a transmit BREAK signal -Call: sClrBreak(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sClrBreak(ChP) \ -{ \ - (ChP)->TxControl[3] &= ~SETBREAK; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sClrDTR -Purpose: Clr the DTR output -Call: sClrDTR(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sClrDTR(ChP) \ -{ \ - (ChP)->TxControl[3] &= ~SET_DTR; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sClrRTS -Purpose: Clr the RTS output -Call: sClrRTS(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sClrRTS(ChP) \ -{ \ - (ChP)->TxControl[3] &= ~SET_RTS; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sClrTxXOFF -Purpose: Clear any existing transmit software flow control off condition -Call: sClrTxXOFF(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sClrTxXOFF(ChP) \ -{ \ - rp_writech1(ChP,_CMD_REG,TXOVERIDE | (Byte_t)(ChP)->ChanNum); \ - rp_writech1(ChP,_CMD_REG,(Byte_t)(ChP)->ChanNum); \ -} - -/*************************************************************************** -Function: sDisCTSFlowCtl -Purpose: Disable output flow control using CTS -Call: sDisCTSFlowCtl(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisCTSFlowCtl(ChP) \ -{ \ - (ChP)->TxControl[2] &= ~CTSFC_EN; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: DisParity -Purpose: Disable parity -Call: sDisParity(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: Function sSetParity() can be used in place of functions sEnParity(), - sDisParity(), sSetOddParity(), and sSetEvenParity(). -*/ -#define sDisParity(ChP) \ -{ \ - (ChP)->TxControl[2] &= ~PARITY_EN; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sDisRxFIFO -Purpose: Disable Rx FIFO -Call: sDisRxFIFO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisRxFIFO(ChP) \ -{ \ - (ChP)->R[0x32] = 0x0a; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->R + 0x30)); \ -} - -/*************************************************************************** -Function: sDisRxStatusMode -Purpose: Disable the Rx status mode -Call: sDisRxStatusMode(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This takes the channel out of the receive status mode. All - subsequent reads of receive data using sReadRxWord() will return - two data bytes. -*/ -#define sDisRxStatusMode(ChP) rp_writech2(ChP,CHNOFF_CHANSTAT(ChP),0) - -/*************************************************************************** -Function: sDisTransmit -Purpose: Disable transmit -Call: sDisTransmit(ChP) - CHANNEL_T *ChP; Ptr to channel structure - This disables movement of Tx data from the Tx FIFO into the 1 byte - Tx buffer. Therefore there could be up to a 2 byte latency - between the time sDisTransmit() is called and the transmit buffer - and transmit shift register going completely empty. -*/ -#define sDisTransmit(ChP) \ -{ \ - (ChP)->TxControl[3] &= ~TX_ENABLE; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sDisTxSoftFlowCtl -Purpose: Disable Tx Software Flow Control -Call: sDisTxSoftFlowCtl(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisTxSoftFlowCtl(ChP) \ -{ \ - (ChP)->R[0x06] = 0x8a; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->R + 0x04)); \ -} - -/*************************************************************************** -Function: sEnCTSFlowCtl -Purpose: Enable output flow control using CTS -Call: sEnCTSFlowCtl(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnCTSFlowCtl(ChP) \ -{ \ - (ChP)->TxControl[2] |= CTSFC_EN; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: EnParity -Purpose: Enable parity -Call: sEnParity(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: Function sSetParity() can be used in place of functions sEnParity(), - sDisParity(), sSetOddParity(), and sSetEvenParity(). - -Warnings: Before enabling parity odd or even parity should be chosen using - functions sSetOddParity() or sSetEvenParity(). -*/ -#define sEnParity(ChP) \ -{ \ - (ChP)->TxControl[2] |= PARITY_EN; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sEnRTSFlowCtl -Return: void -*/ -#define sEnRTSFlowCtl(ChP) \ -{ \ - (ChP)->TxControl[2] &= ~RTSTOG_EN; \ - (ChP)->TxControl[3] &= ~SET_RTS; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ - (ChP)->RxControl[2] |= RTSFC_EN; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->RxControl)); \ -} - -/*************************************************************************** -Function: sDisRTSFlowCtl -Return: void -*/ -#define sDisRTSFlowCtl(ChP) \ -{ \ - (ChP)->RxControl[2] &= ~RTSFC_EN; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->RxControl)); \ -} - -/*************************************************************************** -Function: sEnRxFIFO -Purpose: Enable Rx FIFO -Call: sEnRxFIFO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnRxFIFO(ChP) \ -{ \ - (ChP)->R[0x32] = 0x08; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->R + 0x30)); \ -} - -/*************************************************************************** -Function: sEnRxProcessor -Purpose: Enable the receive processor -Call: sEnRxProcessor(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This function is used to start the receive processor. When - the channel is in the reset state the receive processor is not - running. This is done to prevent the receive processor from - executing invalid microcode instructions prior to the - downloading of the microcode. - -Warnings: This function must be called after valid microcode has been - downloaded to the AIOP, and it must not be called before the - microcode has been downloaded. -*/ -#define sEnRxProcessor(ChP) \ -{ \ - (ChP)->RxControl[2] |= RXPROC_EN; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->RxControl)); \ -} - -/*************************************************************************** -Function: sEnRxStatusMode -Purpose: Enable the Rx status mode -Call: sEnRxStatusMode(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This places the channel in the receive status mode. All subsequent - reads of receive data using sReadRxWord() will return a data byte - in the low word and a status byte in the high word. - -*/ -#define sEnRxStatusMode(ChP) rp_writech2(ChP,CHNOFF_CHANSTAT(ChP),STATMODE) - -/*************************************************************************** -Function: sEnTransmit -Purpose: Enable transmit -Call: sEnTransmit(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnTransmit(ChP) \ -{ \ - (ChP)->TxControl[3] |= TX_ENABLE; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sGetAiopIntStatus -Purpose: Get the AIOP interrupt status -Call: sGetAiopIntStatus(CtlP,AiopNum) - CONTROLLER_T *CtlP; Ptr to controller structure - int AiopNum; AIOP number -Return: Byte_t: The AIOP interrupt status. Bits 0 through 7 - represent channels 0 through 7 respectively. If a - bit is set that channel is interrupting. -*/ -#define sGetAiopIntStatus(CtlP,AIOPNUM) rp_readaiop1(CtlP,AIOPNUM,_INT_CHAN) - -/*************************************************************************** -Function: sGetAiopNumChan -Purpose: Get the number of channels supported by an AIOP -Call: sGetAiopNumChan(CtlP,AiopNum) - CONTROLLER_T *CtlP; Ptr to controller structure - int AiopNum; AIOP number -Return: int: The number of channels supported by the AIOP -*/ -#define sGetAiopNumChan(CtlP,AIOPNUM) CtlP->AiopNumChan[AIOPNUM] - -/*************************************************************************** -Function: sGetChanIntID -Purpose: Get a channel's interrupt identification byte -Call: sGetChanIntID(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: Byte_t: The channel interrupt ID. Can be any - combination of the following flags: - RXF_TRIG: Rx FIFO trigger level interrupt - TXFIFO_MT: Tx FIFO empty interrupt - SRC_INT: Special receive condition interrupt - DELTA_CD: CD change interrupt - DELTA_CTS: CTS change interrupt - DELTA_DSR: DSR change interrupt -*/ -#define sGetChanIntID(ChP) (rp_readch1(ChP,(ChP)->ChanNum+_INT_ID0) & (RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR)) - -/*************************************************************************** -Function: sGetChanNum -Purpose: Get the number of a channel within an AIOP -Call: sGetChanNum(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: int: Channel number within AIOP, or NULLCHAN if channel does - not exist. -*/ -#define sGetChanNum(ChP) (ChP)->ChanNum - -/*************************************************************************** -Function: sGetChanStatus -Purpose: Get the channel status -Call: sGetChanStatus(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: Word_t: The channel status. Can be any combination of - the following flags: - LOW BYTE FLAGS - CTS_ACT: CTS input asserted - DSR_ACT: DSR input asserted - CD_ACT: CD input asserted - TXFIFOMT: Tx FIFO is empty - TXSHRMT: Tx shift register is empty - RDA: Rx data available - - HIGH BYTE FLAGS - STATMODE: status mode enable bit - RXFOVERFL: receive FIFO overflow - RX2MATCH: receive compare byte 2 match - RX1MATCH: receive compare byte 1 match - RXBREAK: received BREAK - RXFRAME: received framing error - RXPARITY: received parity error -Warnings: This function will clear the high byte flags in the Channel - Status Register. -*/ -#define sGetChanStatus(ChP) rp_readch2(ChP,CHNOFF_CHANSTAT(ChP)) - -/*************************************************************************** -Function: sGetChanStatusLo -Purpose: Get the low byte only of the channel status -Call: sGetChanStatusLo(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: Byte_t: The channel status low byte. Can be any combination - of the following flags: - CTS_ACT: CTS input asserted - DSR_ACT: DSR input asserted - CD_ACT: CD input asserted - TXFIFOMT: Tx FIFO is empty - TXSHRMT: Tx shift register is empty - RDA: Rx data available -*/ -#define sGetChanStatusLo(ChP) rp_readch1(ChP,CHNOFF_CHANSTAT(ChP)) - -/*************************************************************************** -Function: sGetRxCnt -Purpose: Get the number of data bytes in the Rx FIFO -Call: sGetRxCnt(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: int: The number of data bytes in the Rx FIFO. -Comments: Byte read of count register is required to obtain Rx count. - -*/ -#define sGetRxCnt(ChP) rp_readch2(ChP,CHNOFF_TXRXCOUNT(ChP)) - -/*************************************************************************** -Function: sGetTxCnt -Purpose: Get the number of data bytes in the Tx FIFO -Call: sGetTxCnt(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: Byte_t: The number of data bytes in the Tx FIFO. -Comments: Byte read of count register is required to obtain Tx count. - -*/ -#define sGetTxCnt(ChP) rp_readch1(ChP,CHNOFF_TXRXCOUNT(ChP)) - -/***************************************************************************** -Function: sGetTxRxDataIO -Purpose: Get the offset of a channel's TxRx Data register -Call: sGetTxRxDataIO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: WordIO_t: offset of a channel's TxRx Data register -*/ -#define sGetTxRxDataIO(ChP) CHNOFF_TXRXDATA(ChP) - -/*************************************************************************** -Function: sInitChanDefaults -Purpose: Initialize a channel structure to its default state. -Call: sInitChanDefaults(ChP) - CHANNEL_T *ChP; Ptr to the channel structure -Comments: This function must be called once for every channel structure - that exists before any other SSCI calls can be made. - -*/ -#define sInitChanDefaults(ChP) \ -{ \ - (ChP)->CtlP = NULLCTLPTR; \ - (ChP)->AiopNum = NULLAIOP; \ - (ChP)->ChanID = AIOPID_NULL; \ - (ChP)->ChanNum = NULLCHAN; \ -} - -/*************************************************************************** -Function: sResetAiopByNum -Purpose: Reset the AIOP by number -Call: sResetAiopByNum(CTLP,AIOPNUM) - CONTROLLER_T CTLP; Ptr to controller structure - AIOPNUM; AIOP index -*/ -#define sResetAiopByNum(CTLP,AIOPNUM) \ -{ \ - rp_writeaiop1(CTLP,AIOPNUM,_CMD_REG,RESET_ALL); \ - rp_writeaiop1(CTLP,AIOPNUM,_CMD_REG,0x0); \ -} - -/*************************************************************************** -Function: sSendBreak -Purpose: Send a transmit BREAK signal -Call: sSendBreak(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSendBreak(ChP) \ -{ \ - (ChP)->TxControl[3] |= SETBREAK; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sSetBaud -Purpose: Set baud rate -Call: sSetBaud(ChP,Divisor) - CHANNEL_T *ChP; Ptr to channel structure - Word_t Divisor; 16 bit baud rate divisor for channel -*/ -#define sSetBaud(ChP,DIVISOR) \ -{ \ - (ChP)->BaudDiv[2] = (Byte_t)(DIVISOR); \ - (ChP)->BaudDiv[3] = (Byte_t)((DIVISOR) >> 8); \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->BaudDiv)); \ -} - -/*************************************************************************** -Function: sSetData7 -Purpose: Set data bits to 7 -Call: sSetData7(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetData7(ChP) \ -{ \ - (ChP)->TxControl[2] &= ~DATA8BIT; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sSetData8 -Purpose: Set data bits to 8 -Call: sSetData8(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetData8(ChP) \ -{ \ - (ChP)->TxControl[2] |= DATA8BIT; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sSetDTR -Purpose: Set the DTR output -Call: sSetDTR(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetDTR(ChP) \ -{ \ - (ChP)->TxControl[3] |= SET_DTR; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sSetEvenParity -Purpose: Set even parity -Call: sSetEvenParity(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: Function sSetParity() can be used in place of functions sEnParity(), - sDisParity(), sSetOddParity(), and sSetEvenParity(). - -Warnings: This function has no effect unless parity is enabled with function - sEnParity(). -*/ -#define sSetEvenParity(ChP) \ -{ \ - (ChP)->TxControl[2] |= EVEN_PAR; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sSetOddParity -Purpose: Set odd parity -Call: sSetOddParity(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: Function sSetParity() can be used in place of functions sEnParity(), - sDisParity(), sSetOddParity(), and sSetEvenParity(). - -Warnings: This function has no effect unless parity is enabled with function - sEnParity(). -*/ -#define sSetOddParity(ChP) \ -{ \ - (ChP)->TxControl[2] &= ~EVEN_PAR; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sSetRTS -Purpose: Set the RTS output -Call: sSetRTS(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetRTS(ChP) \ -{ \ - (ChP)->TxControl[3] |= SET_RTS; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sSetRxTrigger -Purpose: Set the Rx FIFO trigger level -Call: sSetRxProcessor(ChP,Level) - CHANNEL_T *ChP; Ptr to channel structure - Byte_t Level; Number of characters in Rx FIFO at which the - interrupt will be generated. Can be any of the following flags: - - TRIG_NO: no trigger - TRIG_1: 1 character in FIFO - TRIG_1_2: FIFO 1/2 full - TRIG_7_8: FIFO 7/8 full -Comments: An interrupt will be generated when the trigger level is reached - only if function sEnInterrupt() has been called with flag - RXINT_EN set. The RXF_TRIG flag in the Interrupt Idenfification - register will be set whenever the trigger level is reached - regardless of the setting of RXINT_EN. - -*/ -#define sSetRxTrigger(ChP,LEVEL) \ -{ \ - (ChP)->RxControl[2] &= ~TRIG_MASK; \ - (ChP)->RxControl[2] |= LEVEL; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->RxControl)); \ -} - -/*************************************************************************** -Function: sSetStop1 -Purpose: Set stop bits to 1 -Call: sSetStop1(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetStop1(ChP) \ -{ \ - (ChP)->TxControl[2] &= ~STOP2; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sSetStop2 -Purpose: Set stop bits to 2 -Call: sSetStop2(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetStop2(ChP) \ -{ \ - (ChP)->TxControl[2] |= STOP2; \ - rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->TxControl)); \ -} - -/*************************************************************************** -Function: sStartRxProcessor -Purpose: Start a channel's receive processor -Call: sStartRxProcessor(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This function is used to start a Rx processor after it was - stopped with sStopRxProcessor() or sStopSWInFlowCtl(). It - will restart both the Rx processor and software input flow control. - -*/ -#define sStartRxProcessor(ChP) rp_writech4(ChP,_INDX_ADDR,le32dec((ChP)->R)) - -/*************************************************************************** -Function: sWriteTxByte -Purpose: Write a transmit data byte to a channel. - CHANNEL_T *ChP; Ptr to channel structure - ByteIO_t io: Channel transmit register I/O address. This can - be obtained with sGetTxRxDataIO(). - Byte_t Data; The transmit data byte. -Warnings: This function writes the data byte without checking to see if - sMaxTxSize is exceeded in the Tx FIFO. -*/ -#define sWriteTxByte(ChP,IO,DATA) rp_writech1(ChP,IO,DATA) - -int sReadAiopID(CONTROLLER_T *CtlP, int aiop); -int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop); -int sInitChan( CONTROLLER_T *CtlP, - CHANNEL_T *ChP, - int AiopNum, - int ChanNum); -Byte_t sGetRxErrStatus(CHANNEL_T *ChP); -void sStopRxProcessor(CHANNEL_T *ChP); -void sStopSWInFlowCtl(CHANNEL_T *ChP); -void sFlushRxFIFO(CHANNEL_T *ChP); -void sFlushTxFIFO(CHANNEL_T *ChP); -int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data); -void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags); -void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags); -int rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports); -void rp_releaseresource(CONTROLLER_t *ctlp); -static __inline void -rp_lock(CONTROLLER_T *CtlP) -{ - if (CtlP->hwmtx_init != 0) - mtx_lock(&CtlP->hwmtx); -} -static __inline void -rp_unlock(CONTROLLER_T *CtlP) -{ - if (CtlP->hwmtx_init != 0) - mtx_unlock(&CtlP->hwmtx); -} - -#ifndef ROCKET_C -extern Byte_t R[RDATASIZE]; -extern CONTROLLER_T sController[CTL_SIZE]; -extern Byte_t sIRQMap[16]; -#endif -extern Byte_t rp_sBitMapClrTbl[8]; -extern Byte_t rp_sBitMapSetTbl[8]; diff --git a/sys/dev/rp/rpvar.h b/sys/dev/rp/rpvar.h deleted file mode 100644 index a93f48971469..000000000000 --- a/sys/dev/rp/rpvar.h +++ /dev/null @@ -1,76 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) Comtrol Corporation - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted prodived that the follwoing conditions - * are met. - * 1. Redistributions of source code must retain the above copyright - * notive, this list of conditions and the following disclainer. - * 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 prodided 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 Comtrol Corporation. - * 4. The name of Comtrol Corporation may not be used to endorse or - * promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY COMTROL 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 COMTROL 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, LIFE 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$ - */ - -/* - * rpvar.h --- RocketPort data structure includes for FreeBSD - */ - -#define RP_UNIT(x) dv_unit(x) -#define RP_PORT(x) (dev2unit(x) & 0x3f) -#define MAX_RP_PORTS 128 - - -struct rp_port { - struct tty * rp_tty; /* cross reference */ - struct callout rp_timer; - - unsigned char state; /* state of dtr */ - - int rp_port; - int rp_flags; - int rp_unit:2; - int rp_aiop:2; - int rp_chan:3; - int rp_intmask; - int rp_imask; /* Input mask */ - int rp_fifo_lw; - int rp_restart; - int rp_overflows; - int rp_rts_iflow:1; - int rp_disable_writes:1; - int rp_cts:1; - int rp_waiting:1; - int rp_xmit_stopped:1; - CONTROLLER_t * rp_ctlp; - CHANNEL_t rp_channel; - unsigned char TxBuf[TXFIFO_SIZE]; - unsigned char RxBuf[RXFIFO_SIZE]; -}; - -/* Actually not used */ -#ifdef notdef -extern struct termios deftermios; -#endif /* notdef */ diff --git a/sys/modules/rc/Makefile b/sys/modules/rc/Makefile deleted file mode 100644 index a30f91d516e3..000000000000 --- a/sys/modules/rc/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# $FreeBSD$ - -.PATH: ${SRCTOP}/sys/dev/rc - -KMOD= rc -SRCS= rc.c device_if.h bus_if.h isa_if.h - -.include diff --git a/sys/modules/rp/Makefile b/sys/modules/rp/Makefile deleted file mode 100644 index 530fc12898ce..000000000000 --- a/sys/modules/rp/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# $FreeBSD$ - -.PATH: ${SRCTOP}/sys/dev/rp - -KMOD= rp -SRCS= rp.c rp_pci.c device_if.h bus_if.h pci_if.h - -.include From d3e63e8eb23a3dd4e9d36af2a725063c99687067 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 30 Jul 2020 07:11:08 +0000 Subject: [PATCH 259/287] vfs: make sure startdir_used is always assigned to before use CID: 1431070 --- sys/kern/vfs_lookup.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 13e1d6ddce99..34e3573c8c35 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -289,11 +289,13 @@ namei_setup(struct nameidata *ndp, struct vnode **dpp, struct pwd **pwdp) struct pwd *pwd; cap_rights_t rights; struct filecaps dirfd_caps; - int error, startdir_used; + int error; + bool startdir_used; cnp = &ndp->ni_cnd; td = cnp->cn_thread; + startdir_used = false; *pwdp = NULL; #ifdef CAPABILITY_MODE @@ -340,7 +342,7 @@ namei_setup(struct nameidata *ndp, struct vnode **dpp, struct pwd **pwdp) } else { if (ndp->ni_startdir != NULL) { *dpp = ndp->ni_startdir; - startdir_used = 1; + startdir_used = true; } else if (ndp->ni_dirfd == AT_FDCWD) { *dpp = pwd->pwd_cdir; vrefact(*dpp); From c565776195f2f2b62427af07f6b1a9b7670cbc1f Mon Sep 17 00:00:00 2001 From: Wei Hu Date: Thu, 30 Jul 2020 07:26:11 +0000 Subject: [PATCH 260/287] Prevent framebuffer mmio space from being allocated to other devices on HyperV. On Gen2 VMs, Hyper-V provides mmio space for framebuffer. This mmio address range is not useable for other PCI devices. Currently only efifb driver is using this range without reserving it from system. Therefore, vmbus driver reserves it before any other PCI device drivers start to request mmio addresses. PR: 222996 Submitted by: weh@microsoft.com Reported by: dmitry_kuleshov@ukr.net Reviewed by: decui@microsoft.com Sponsored by: Microsoft --- sys/dev/hyperv/vmbus/vmbus.c | 57 ++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/sys/dev/hyperv/vmbus/vmbus.c b/sys/dev/hyperv/vmbus/vmbus.c index 9d4f5e77fa97..38e9cd7b4c26 100644 --- a/sys/dev/hyperv/vmbus/vmbus.c +++ b/sys/dev/hyperv/vmbus/vmbus.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -1332,12 +1334,66 @@ vmbus_get_mmio_res(device_t dev) vmbus_get_mmio_res_pass(dev, parse_32); } +/* + * On Gen2 VMs, Hyper-V provides mmio space for framebuffer. + * This mmio address range is not useable for other PCI devices. + * Currently only efifb driver is using this range without reserving + * it from system. + * Therefore, vmbus driver reserves it before any other PCI device + * drivers start to request mmio addresses. + */ +static struct resource *hv_fb_res; + +static void +vmbus_fb_mmio_res(device_t dev) +{ + struct efi_fb *efifb; + caddr_t kmdp; + + struct vmbus_softc *sc = device_get_softc(dev); + int rid = 0; + + kmdp = preload_search_by_type("elf kernel"); + if (kmdp == NULL) + kmdp = preload_search_by_type("elf64 kernel"); + efifb = (struct efi_fb *)preload_search_info(kmdp, + MODINFO_METADATA | MODINFOMD_EFI_FB); + if (efifb == NULL) { + if (bootverbose) + device_printf(dev, + "fb has no preloaded kernel efi information\n"); + /* We are on Gen1 VM, just return. */ + return; + } else { + if (bootverbose) + device_printf(dev, + "efifb: fb_addr: %#jx, size: %#jx, " + "actual size needed: 0x%x\n", + efifb->fb_addr, efifb->fb_size, + (int) efifb->fb_height * efifb->fb_width); + } + + hv_fb_res = pcib_host_res_alloc(&sc->vmbus_mmio_res, dev, + SYS_RES_MEMORY, &rid, + efifb->fb_addr, efifb->fb_addr + efifb->fb_size, efifb->fb_size, + RF_ACTIVE | rman_make_alignment_flags(PAGE_SIZE)); + + if (hv_fb_res && bootverbose) + device_printf(dev, + "successfully reserved memory for framebuffer " + "starting at %#jx, size %#jx\n", + efifb->fb_addr, efifb->fb_size); +} + static void vmbus_free_mmio_res(device_t dev) { struct vmbus_softc *sc = device_get_softc(dev); pcib_host_res_free(dev, &sc->vmbus_mmio_res); + + if (hv_fb_res) + hv_fb_res = NULL; } #endif /* NEW_PCIB */ @@ -1387,6 +1443,7 @@ vmbus_doattach(struct vmbus_softc *sc) #ifdef NEW_PCIB vmbus_get_mmio_res(sc->vmbus_dev); + vmbus_fb_mmio_res(sc->vmbus_dev); #endif sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; From ac05de17883d6981f9ff3d52154ec336203fc683 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Thu, 30 Jul 2020 13:33:45 +0000 Subject: [PATCH 261/287] diff: fix side_by_side after r363679 It's currently unclear to me how this could have worked previously; \n here is not a literal newline but actual '\' 'n', and was getting passed to the underlying regex engine as such. regex(3) does not translate this to a newline, and this became an error because we don't really allow escaping of arbitrary ordinary characters anymore. Run the pattern strings through printf to make sure we're dealing with real newlines before passing them through to atf_check, which ultimately feeds them directly to regcomp(3). This fix is different than that will be needed for sed, in that this is the proper way to inject newlines into search strings as long as regex(3) won't combine \ + n as folks might expect. Reported by: Jenkins via lwhsu MFC after: 1 week --- usr.bin/diff/tests/diff_test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr.bin/diff/tests/diff_test.sh b/usr.bin/diff/tests/diff_test.sh index 67a7300f8dd3..9f460231f480 100755 --- a/usr.bin/diff/tests/diff_test.sh +++ b/usr.bin/diff/tests/diff_test.sh @@ -108,8 +108,8 @@ side_by_side_body() atf_check -o save:A printf "A\nB\nC\n" atf_check -o save:B printf "D\nB\nE\n" - exp_output="A[[:space:]]+|[[:space:]]+D\nB[[:space:]]+B\nC[[:space:]]+|[[:space:]]+E" - exp_output_suppressed="A[[:space:]]+|[[:space:]]+D\nC[[:space:]]+|[[:space:]]+E" + exp_output=$(printf "A[[:space:]]+|[[:space:]]+D\nB[[:space:]]+B\nC[[:space:]]+|[[:space:]]+E") + exp_output_suppressed=$(printf "A[[:space:]]+|[[:space:]]+D\nC[[:space:]]+|[[:space:]]+E") atf_check -o match:"$exp_output" -s exit:1 \ diff --side-by-side A B From 98369a6980f5448fa9ab8bde9f04ba10c4ca3c93 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Thu, 30 Jul 2020 13:36:24 +0000 Subject: [PATCH 262/287] sed: fix hex_subst test after after r363679 r363679 is in-fact the future change referenced by the comment, helpfully left and forgotten by kevans. Instead of just silently not matching, we should now be erroring out with vigor. --- usr.bin/sed/tests/sed2_test.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/usr.bin/sed/tests/sed2_test.sh b/usr.bin/sed/tests/sed2_test.sh index 9f831e0ed673..07f1ec844814 100755 --- a/usr.bin/sed/tests/sed2_test.sh +++ b/usr.bin/sed/tests/sed2_test.sh @@ -109,11 +109,9 @@ hex_subst_body() # Single digit \x should work as well. atf_check -o "inline:xn" sed 's/\xd/x/' c - # Invalid digit should cause us to ignore the sequence. This test - # invokes UB, escapes of an ordinary character. A future change will - # make regex(3) on longer tolerate this and we'll need to adjust what - # we're doing, but for now this will suffice. - atf_check -o "inline:" sed 's/\xx//' d + # This should get passed through to the underlying regex engine as + # \xx, which is an invalid escape of an ordinary character. + atf_check -s exit:1 -e not-empty sed 's/\xx//' d } atf_test_case commands_on_stdin From 0050ea241584f931c6089f7b7a7aca3804131397 Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Thu, 30 Jul 2020 14:45:05 +0000 Subject: [PATCH 263/287] Move Ti AM335x to dev/extres/clk framework. Re-implement clocks for these SoC by using now standard extres/clk framework. This is necessary for future expansion of these. The new implementation is (due to the size of the patch) only the initial (minimum) version. It will be updated/expanded with a subsequent set of particular patches. This patch is also not tested on OMAP4 based boards (BeagleBone), so all possible issues should be (and will be) fixed by ASAP once identified. Submited by: Oskar Holmlund (oskar.holmlund@ohdata.se) Differential Revision: https://reviews.freebsd.org/D25118 --- sys/arm/ti/am335x/am3359_cppi41.c | 192 +++++++ sys/arm/ti/am335x/am335x_dmtimer.c | 84 ++- sys/arm/ti/am335x/am335x_dmtpps.c | 114 +++- sys/arm/ti/am335x/am335x_dmtreg.h | 12 + sys/arm/ti/am335x/am335x_gpio.c | 1 + sys/arm/ti/am335x/am335x_lcd.c | 33 +- sys/arm/ti/am335x/am335x_musb.c | 71 ++- sys/arm/ti/am335x/am335x_prcm.c | 884 ----------------------------- sys/arm/ti/am335x/am335x_pwmss.c | 66 ++- sys/arm/ti/am335x/am335x_rtc.c | 6 +- sys/arm/ti/am335x/am335x_scm.c | 44 +- sys/arm/ti/am335x/am335x_usb_phy.c | 121 ++++ sys/arm/ti/am335x/am335x_usbss.c | 226 -------- sys/arm/ti/am335x/files.am335x | 4 +- sys/arm/ti/clk/clock_common.c | 152 +++++ sys/arm/ti/clk/clock_common.h | 43 ++ sys/arm/ti/clk/ti_clk_clkctrl.c | 219 +++++++ sys/arm/ti/clk/ti_clk_clkctrl.h | 43 ++ sys/arm/ti/clk/ti_clk_dpll.c | 341 +++++++++++ sys/arm/ti/clk/ti_clk_dpll.h | 97 ++++ sys/arm/ti/clk/ti_clkctrl.c | 353 ++++++++++++ sys/arm/ti/clk/ti_divider_clock.c | 264 +++++++++ sys/arm/ti/clk/ti_dpll_clock.c | 375 ++++++++++++ sys/arm/ti/clk/ti_gate_clock.c | 266 +++++++++ sys/arm/ti/clk/ti_mux_clock.c | 249 ++++++++ sys/arm/ti/cpsw/if_cpsw.c | 28 +- sys/arm/ti/files.ti | 13 +- sys/arm/ti/omap4/files.omap4 | 2 +- sys/arm/ti/ti_adc.c | 7 +- sys/arm/ti/ti_edma3.c | 13 +- sys/arm/ti/ti_gpio.c | 82 ++- sys/arm/ti/ti_hwmods.c | 214 ------- sys/arm/ti/ti_hwmods.h | 37 -- sys/arm/ti/ti_i2c.c | 20 +- sys/arm/ti/ti_mbox.c | 9 +- sys/arm/ti/ti_omap4_cm.c | 151 +++++ sys/arm/ti/ti_omap4_cm.h | 34 ++ sys/arm/ti/ti_pinmux.c | 2 + sys/arm/ti/ti_prcm.c | 642 ++++++++++----------- sys/arm/ti/ti_prcm.h | 208 +------ sys/arm/ti/ti_prm.c | 210 +++++++ sys/arm/ti/ti_prm.h | 38 ++ sys/arm/ti/ti_pruss.c | 96 +++- sys/arm/ti/ti_scm.c | 203 +++---- sys/arm/ti/ti_scm_syscon.c | 294 ++++++++++ sys/arm/ti/ti_sdhci.c | 63 +- sys/arm/ti/ti_sdma.c | 19 +- sys/arm/ti/ti_spi.c | 24 +- sys/arm/ti/ti_sysc.c | 540 +++++++++++++++++- sys/arm/ti/ti_sysc.h | 43 ++ sys/arm/ti/ti_wdt.c | 2 +- sys/arm/ti/usb/omap_ehci.c | 1 - sys/arm/ti/usb/omap_host.c | 9 +- sys/arm/ti/usb/omap_tll.c | 8 +- sys/dev/uart/uart_dev_ti8250.c | 15 +- sys/modules/Makefile | 2 +- 56 files changed, 5050 insertions(+), 2239 deletions(-) create mode 100644 sys/arm/ti/am335x/am3359_cppi41.c delete mode 100644 sys/arm/ti/am335x/am335x_prcm.c create mode 100644 sys/arm/ti/am335x/am335x_usb_phy.c delete mode 100644 sys/arm/ti/am335x/am335x_usbss.c create mode 100644 sys/arm/ti/clk/clock_common.c create mode 100644 sys/arm/ti/clk/clock_common.h create mode 100644 sys/arm/ti/clk/ti_clk_clkctrl.c create mode 100644 sys/arm/ti/clk/ti_clk_clkctrl.h create mode 100644 sys/arm/ti/clk/ti_clk_dpll.c create mode 100644 sys/arm/ti/clk/ti_clk_dpll.h create mode 100644 sys/arm/ti/clk/ti_clkctrl.c create mode 100644 sys/arm/ti/clk/ti_divider_clock.c create mode 100644 sys/arm/ti/clk/ti_dpll_clock.c create mode 100644 sys/arm/ti/clk/ti_gate_clock.c create mode 100644 sys/arm/ti/clk/ti_mux_clock.c delete mode 100644 sys/arm/ti/ti_hwmods.c delete mode 100644 sys/arm/ti/ti_hwmods.h create mode 100644 sys/arm/ti/ti_omap4_cm.c create mode 100644 sys/arm/ti/ti_omap4_cm.h create mode 100644 sys/arm/ti/ti_prm.c create mode 100644 sys/arm/ti/ti_prm.h create mode 100644 sys/arm/ti/ti_scm_syscon.c create mode 100644 sys/arm/ti/ti_sysc.h diff --git a/sys/arm/ti/am335x/am3359_cppi41.c b/sys/arm/ti/am335x/am3359_cppi41.c new file mode 100644 index 000000000000..a3e4e8bee155 --- /dev/null +++ b/sys/arm/ti/am335x/am3359_cppi41.c @@ -0,0 +1,192 @@ +/*- + * Copyright (c) 2019 Emmanuel Vadot + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +/* Based on sys/arm/ti/ti_sysc.c */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +struct ti_am3359_cppi41_softc { + device_t dev; + struct syscon * syscon; + struct resource * res[4]; + bus_space_tag_t bst; + bus_space_handle_t bsh; + struct mtx mtx; +}; + +static struct resource_spec ti_am3359_cppi41_res_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_SHAREABLE }, + { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_SHAREABLE }, + { SYS_RES_MEMORY, 2, RF_ACTIVE | RF_SHAREABLE }, + { SYS_RES_MEMORY, 3, RF_ACTIVE | RF_SHAREABLE }, + { -1, 0 } +}; + +/* Device */ +static struct ofw_compat_data compat_data[] = { + { "ti,am3359-cppi41", 1 }, + { NULL, 0 } +}; + +static int +ti_am3359_cppi41_write_4(device_t dev, bus_addr_t addr, uint32_t val) +{ + struct ti_am3359_cppi41_softc *sc; + + sc = device_get_softc(dev); + DPRINTF(sc->dev, "offset=%lx write %x\n", addr, val); + mtx_lock(&sc->mtx); + bus_space_write_4(sc->bst, sc->bsh, addr, val); + mtx_unlock(&sc->mtx); + return (0); +} + +static uint32_t +ti_am3359_cppi41_read_4(device_t dev, bus_addr_t addr) +{ + struct ti_am3359_cppi41_softc *sc; + uint32_t val; + + sc = device_get_softc(dev); + + mtx_lock(&sc->mtx); + val = bus_space_read_4(sc->bst, sc->bsh, addr); + mtx_unlock(&sc->mtx); + DPRINTF(sc->dev, "offset=%lx Read %x\n", addr, val); + return (val); +} + +/* device interface */ +static int +ti_am3359_cppi41_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI AM3359 CPPI 41"); + return(BUS_PROBE_DEFAULT); +} + +static int +ti_am3359_cppi41_attach(device_t dev) +{ + struct ti_am3359_cppi41_softc *sc; + phandle_t node; + uint32_t reg, reset_bit, timeout=10; + uint64_t sysc_address; + device_t parent; + + sc = device_get_softc(dev); + sc->dev = dev; + + if (bus_alloc_resources(dev, ti_am3359_cppi41_res_spec, sc->res)) { + device_printf(sc->dev, "Cant allocate resources\n"); + return (ENXIO); + } + + sc->dev = dev; + sc->bst = rman_get_bustag(sc->res[0]); + sc->bsh = rman_get_bushandle(sc->res[0]); + + mtx_init(&sc->mtx, device_get_nameunit(sc->dev), NULL, MTX_DEF); + node = ofw_bus_get_node(sc->dev); + + /* variant of am335x_usbss.c */ + DPRINTF(dev, "-- RESET USB --\n"); + parent = device_get_parent(dev); + reset_bit = ti_sysc_get_soft_reset_bit(parent); + if (reset_bit == 0) { + DPRINTF(dev, "Dont have reset bit\n"); + return (0); + } + sysc_address = ti_sysc_get_sysc_address_offset_host(parent); + DPRINTF(dev, "sysc_address %x\n", sysc_address); + ti_am3359_cppi41_write_4(dev, sysc_address, reset_bit); + DELAY(100); + reg = ti_am3359_cppi41_read_4(dev, sysc_address); + if ((reg & reset_bit) && timeout--) { + DPRINTF(dev, "Reset still ongoing - wait a little bit longer\n"); + DELAY(100); + reg = ti_am3359_cppi41_read_4(dev, sysc_address); + } + if (timeout == 0) + device_printf(dev, "USB Reset timeout\n"); + + return (0); +} + + +static device_method_t ti_am3359_cppi41_methods[] = { + DEVMETHOD(device_probe, ti_am3359_cppi41_probe), + DEVMETHOD(device_attach, ti_am3359_cppi41_attach), + + DEVMETHOD_END +}; + + +DEFINE_CLASS_1(ti_am3359_cppi41, ti_am3359_cppi41_driver, + ti_am3359_cppi41_methods,sizeof(struct ti_am3359_cppi41_softc), + simplebus_driver); + +static devclass_t ti_am3359_cppi41_devclass; + +EARLY_DRIVER_MODULE(ti_am3359_cppi41, simplebus, ti_am3359_cppi41_driver, + ti_am3359_cppi41_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_am3359_cppi41, 1); +MODULE_DEPEND(ti_am3359_cppi41, ti_sysc, 1, 1, 1); diff --git a/sys/arm/ti/am335x/am335x_dmtimer.c b/sys/arm/ti/am335x/am335x_dmtimer.c index a36c66e56ed0..eb869ca88b94 100644 --- a/sys/arm/ti/am335x/am335x_dmtimer.c +++ b/sys/arm/ti/am335x/am335x_dmtimer.c @@ -42,12 +42,13 @@ __FBSDID("$FreeBSD$"); #include /* For arm_set_delay */ +#include + #include #include #include -#include -#include +#include #include "am335x_dmtreg.h" @@ -58,7 +59,8 @@ struct am335x_dmtimer_softc { int tmr_irq_rid; struct resource * tmr_irq_res; void *tmr_irq_handler; - uint32_t sysclk_freq; + clk_t clk_fck; + uint64_t sysclk_freq; uint32_t tclr; /* Cached TCLR register. */ union { struct timecounter tc; @@ -251,6 +253,7 @@ am335x_dmtimer_probe(device_t dev) { char strbuf[32]; int tmr_num; + uint64_t rev_address; if (!ofw_bus_status_okay(dev)) return (ENXIO); @@ -259,13 +262,22 @@ am335x_dmtimer_probe(device_t dev) return (ENXIO); /* - * Get the hardware unit number (the N from ti,hwmods="timerN"). + * Get the hardware unit number from address of rev register. * If this isn't the hardware unit we're going to use for either the * eventtimer or the timecounter, no point in instantiating the device. */ - tmr_num = ti_hwmods_get_unit(dev, "timer"); - if (tmr_num != ET_TMR_NUM && tmr_num != TC_TMR_NUM) - return (ENXIO); + rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); + switch (rev_address) { + case DMTIMER2_REV: + tmr_num = 2; + break; + case DMTIMER3_REV: + tmr_num = 3; + break; + default: + /* Not DMTIMER2 or DMTIMER3 */ + return (ENXIO); + } snprintf(strbuf, sizeof(strbuf), "AM335x DMTimer%d", tmr_num); device_set_desc_copy(dev, strbuf); @@ -277,23 +289,46 @@ static int am335x_dmtimer_attach(device_t dev) { struct am335x_dmtimer_softc *sc; - clk_ident_t timer_id; int err; + uint64_t rev_address; + clk_t sys_clkin; sc = device_get_softc(dev); sc->dev = dev; - /* Get the base clock frequency. */ - if ((err = ti_prcm_clk_get_source_freq(SYS_CLK, &sc->sysclk_freq)) != 0) - return (err); + /* expect one clock */ + err = clk_get_by_ofw_index(dev, 0, 0, &sc->clk_fck); + if (err != 0) { + device_printf(dev, "Cant find clock index 0. err: %d\n", err); + return (ENXIO); + } + + err = clk_get_by_name(dev, "sys_clkin_ck@40", &sys_clkin); + if (err != 0) { + device_printf(dev, "Cant find sys_clkin_ck@40 err: %d\n", err); + return (ENXIO); + } + + /* Select M_OSC as DPLL parent */ + err = clk_set_parent_by_clk(sc->clk_fck, sys_clkin); + if (err != 0) { + device_printf(dev, "Cant set mux to CLK_M_OSC\n"); + return (ENXIO); + } /* Enable clocks and power on the device. */ - if ((timer_id = ti_hwmods_get_clock(dev)) == INVALID_CLK_IDENT) + err = ti_sysc_clock_enable(device_get_parent(dev)); + if (err != 0) { + device_printf(dev, "Cant enable sysc clkctrl, err %d\n", err); return (ENXIO); - if ((err = ti_prcm_clk_set_source(timer_id, SYSCLK_CLK)) != 0) - return (err); - if ((err = ti_prcm_clk_enable(timer_id)) != 0) - return (err); + } + + /* Get the base clock frequency. */ + err = clk_get_freq(sc->clk_fck, &sc->sysclk_freq); + if (err != 0) { + device_printf(dev, "Cant get sysclk frequency, err %d\n", err); + return (ENXIO); + } /* Request the memory resources. */ sc->tmr_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, @@ -302,7 +337,20 @@ am335x_dmtimer_attach(device_t dev) return (ENXIO); } - sc->tmr_num = ti_hwmods_get_unit(dev, "timer"); + rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); + switch (rev_address) { + case DMTIMER2_REV: + sc->tmr_num = 2; + break; + case DMTIMER3_REV: + sc->tmr_num = 3; + break; + default: + device_printf(dev, "Not timer 2 or 3! %#jx\n", + rev_address); + return (ENXIO); + } + snprintf(sc->tmr_name, sizeof(sc->tmr_name), "DMTimer%d", sc->tmr_num); /* @@ -334,7 +382,7 @@ static driver_t am335x_dmtimer_driver = { static devclass_t am335x_dmtimer_devclass; DRIVER_MODULE(am335x_dmtimer, simplebus, am335x_dmtimer_driver, am335x_dmtimer_devclass, 0, 0); -MODULE_DEPEND(am335x_dmtimer, am335x_prcm, 1, 1, 1); +MODULE_DEPEND(am335x_dmtimer, ti_sysc, 1, 1, 1); static void am335x_dmtimer_delay(int usec, void *arg) diff --git a/sys/arm/ti/am335x/am335x_dmtpps.c b/sys/arm/ti/am335x/am335x_dmtpps.c index 6aa374a0f76f..24d83f248eef 100644 --- a/sys/arm/ti/am335x/am335x_dmtpps.c +++ b/sys/arm/ti/am335x/am335x_dmtpps.c @@ -43,6 +43,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_platform.h" + #include #include #include @@ -60,9 +62,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include -#include -#include +#include #include #include @@ -82,6 +84,8 @@ struct dmtpps_softc { struct cdev * pps_cdev; struct pps_state pps_state; struct mtx pps_mtx; + clk_t clk_fck; + uint64_t sysclk_freq; }; static int dmtpps_tmr_num; /* Set by probe() */ @@ -383,6 +387,7 @@ dmtpps_probe(device_t dev) { char strbuf[64]; int tmr_num; + uint64_t rev_address; if (!ofw_bus_status_okay(dev)) return (ENXIO); @@ -402,7 +407,33 @@ dmtpps_probe(device_t dev) * Figure out which hardware timer is being probed and see if it matches * the configured timer number determined earlier. */ - tmr_num = ti_hwmods_get_unit(dev, "timer"); + rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); + switch (rev_address) { + case DMTIMER1_1MS_REV: + tmr_num = 1; + break; + case DMTIMER2_REV: + tmr_num = 2; + break; + case DMTIMER3_REV: + tmr_num = 3; + break; + case DMTIMER4_REV: + tmr_num = 4; + break; + case DMTIMER5_REV: + tmr_num = 5; + break; + case DMTIMER6_REV: + tmr_num = 6; + break; + case DMTIMER7_REV: + tmr_num = 7; + break; + default: + return (ENXIO); + } + if (dmtpps_tmr_num != tmr_num) return (ENXIO); @@ -418,23 +449,73 @@ dmtpps_attach(device_t dev) { struct dmtpps_softc *sc; struct make_dev_args mda; - clk_ident_t timer_id; - int err, sysclk_freq; + int err; + clk_t sys_clkin; + uint64_t rev_address; sc = device_get_softc(dev); sc->dev = dev; - /* Get the base clock frequency. */ - err = ti_prcm_clk_get_source_freq(SYS_CLK, &sysclk_freq); + /* Figure out which hardware timer this is and set the name string. */ + rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); + switch (rev_address) { + case DMTIMER1_1MS_REV: + sc->tmr_num = 1; + break; + case DMTIMER2_REV: + sc->tmr_num = 2; + break; + case DMTIMER3_REV: + sc->tmr_num = 3; + break; + case DMTIMER4_REV: + sc->tmr_num = 4; + break; + case DMTIMER5_REV: + sc->tmr_num = 5; + break; + case DMTIMER6_REV: + sc->tmr_num = 6; + break; + case DMTIMER7_REV: + sc->tmr_num = 7; + break; + } + snprintf(sc->tmr_name, sizeof(sc->tmr_name), "DMTimer%d", sc->tmr_num); + + /* expect one clock */ + err = clk_get_by_ofw_index(dev, 0, 0, &sc->clk_fck); + if (err != 0) { + device_printf(dev, "Cant find clock index 0. err: %d\n", err); + return (ENXIO); + } + + err = clk_get_by_name(dev, "sys_clkin_ck@40", &sys_clkin); + if (err != 0) { + device_printf(dev, "Cant find sys_clkin_ck@40 err: %d\n", err); + return (ENXIO); + } + + /* Select M_OSC as DPLL parent */ + err = clk_set_parent_by_clk(sc->clk_fck, sys_clkin); + if (err != 0) { + device_printf(dev, "Cant set mux to CLK_M_OSC\n"); + return (ENXIO); + } /* Enable clocks and power on the device. */ - if ((timer_id = ti_hwmods_get_clock(dev)) == INVALID_CLK_IDENT) + err = ti_sysc_clock_enable(device_get_parent(dev)); + if (err != 0) { + device_printf(dev, "Cant enable sysc clkctrl, err %d\n", err); return (ENXIO); - if ((err = ti_prcm_clk_set_source(timer_id, SYSCLK_CLK)) != 0) - return (err); - if ((err = ti_prcm_clk_enable(timer_id)) != 0) - return (err); + } + /* Get the base clock frequency. */ + err = clk_get_freq(sc->clk_fck, &sc->sysclk_freq); + if (err != 0) { + device_printf(dev, "Cant get sysclk frequency, err %d\n", err); + return (ENXIO); + } /* Request the memory resources. */ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); @@ -442,10 +523,6 @@ dmtpps_attach(device_t dev) return (ENXIO); } - /* Figure out which hardware timer this is and set the name string. */ - sc->tmr_num = ti_hwmods_get_unit(dev, "timer"); - snprintf(sc->tmr_name, sizeof(sc->tmr_name), "DMTimer%d", sc->tmr_num); - /* * Configure the timer pulse/capture pin to input/capture mode. This is * required in addition to configuring the pin as input with the pinmux @@ -468,7 +545,7 @@ dmtpps_attach(device_t dev) sc->tc.tc_name = sc->tmr_name; sc->tc.tc_get_timecount = dmtpps_get_timecount; sc->tc.tc_counter_mask = ~0u; - sc->tc.tc_frequency = sysclk_freq; + sc->tc.tc_frequency = sc->sysclk_freq; sc->tc.tc_quality = 1000; sc->tc.tc_priv = sc; @@ -541,5 +618,4 @@ static driver_t dmtpps_driver = { static devclass_t dmtpps_devclass; DRIVER_MODULE(am335x_dmtpps, simplebus, dmtpps_driver, dmtpps_devclass, 0, 0); -MODULE_DEPEND(am335x_dmtpps, am335x_prcm, 1, 1, 1); - +MODULE_DEPEND(am335x_dmtpps, ti_sysc, 1, 1, 1); diff --git a/sys/arm/ti/am335x/am335x_dmtreg.h b/sys/arm/ti/am335x/am335x_dmtreg.h index f2ef54ddb917..c91a30570bd8 100644 --- a/sys/arm/ti/am335x/am335x_dmtreg.h +++ b/sys/arm/ti/am335x/am335x_dmtreg.h @@ -73,4 +73,16 @@ #define DMT_TSICR_RESET (1 << 1) /* TSICR perform soft reset */ #define DMT_TCAR2 0x48 /* Capture Reg */ +/* Location of revision register from TRM Memory map chapter 2 */ +/* L4_WKUP */ +#define DMTIMER0_REV 0x05000 +#define DMTIMER1_1MS_REV 0x31000 +/* L4_PER */ +#define DMTIMER2_REV 0x40000 +#define DMTIMER3_REV 0x42000 +#define DMTIMER4_REV 0x44000 +#define DMTIMER5_REV 0x46000 +#define DMTIMER6_REV 0x48000 +#define DMTIMER7_REV 0x4A000 + #endif /* AM335X_DMTREG_H */ diff --git a/sys/arm/ti/am335x/am335x_gpio.c b/sys/arm/ti/am335x/am335x_gpio.c index cbfde175c2e7..beb169b3e4b5 100644 --- a/sys/arm/ti/am335x/am335x_gpio.c +++ b/sys/arm/ti/am335x/am335x_gpio.c @@ -155,3 +155,4 @@ DEFINE_CLASS_1(gpio, am335x_gpio_driver, am335x_gpio_methods, sizeof(struct ti_gpio_softc), ti_gpio_driver); DRIVER_MODULE(am335x_gpio, simplebus, am335x_gpio_driver, am335x_gpio_devclass, 0, 0); +MODULE_DEPEND(am335x_gpio, ti_sysc, 1, 1, 1); diff --git a/sys/arm/ti/am335x/am335x_lcd.c b/sys/arm/ti/am335x/am335x_lcd.c index 5c60bf4be6bf..387bd37e3ebf 100644 --- a/sys/arm/ti/am335x/am335x_lcd.c +++ b/sys/arm/ti/am335x/am335x_lcd.c @@ -50,6 +50,8 @@ __FBSDID("$FreeBSD$"); #include +#include + #include #include #include @@ -65,7 +67,7 @@ __FBSDID("$FreeBSD$"); #include #endif -#include +#include #include #include "am335x_lcd.h" @@ -219,6 +221,9 @@ struct am335x_lcd_softc { /* HDMI framer */ phandle_t sc_hdmi_framer; eventhandler_tag sc_hdmi_evh; + + /* Clock */ + clk_t sc_clk_dpll_disp_ck; }; static void @@ -615,24 +620,28 @@ am335x_lcd_configure(struct am335x_lcd_softc *sc) uint32_t hbp, hfp, hsw; uint32_t vbp, vfp, vsw; uint32_t width, height; - unsigned int ref_freq; + uint64_t ref_freq; int err; /* * try to adjust clock to get double of requested frequency * HDMI/DVI displays are very sensitive to error in frequncy value */ - if (ti_prcm_clk_set_source_freq(LCDC_CLK, sc->sc_panel.panel_pxl_clk*2)) { + + err = clk_set_freq(sc->sc_clk_dpll_disp_ck, sc->sc_panel.panel_pxl_clk*2, + CLK_SET_ROUND_ANY); + if (err != 0) { device_printf(sc->sc_dev, "can't set source frequency\n"); return (ENXIO); } - if (ti_prcm_clk_get_source_freq(LCDC_CLK, &ref_freq)) { + err = clk_get_freq(sc->sc_clk_dpll_disp_ck, &ref_freq); + if (err != 0) { device_printf(sc->sc_dev, "can't get reference frequency\n"); return (ENXIO); } - /* Panle initialization */ + /* Panel initialization */ dma_size = round_page(sc->sc_panel.panel_width*sc->sc_panel.panel_height*sc->sc_panel.bpp/8); /* @@ -967,6 +976,13 @@ am335x_lcd_attach(device_t dev) return (ENXIO); } + /* Fixme: Cant find any reference in DTS for dpll_disp_ck@498 for now. */ + err = clk_get_by_name(dev, "dpll_disp_ck@498", &sc->sc_clk_dpll_disp_ck); + if (err != 0) { + device_printf(dev, "Cant get dpll_disp_ck@49\n"); + return (ENXIO); + } + sc->sc_panel.ac_bias = 255; sc->sc_panel.ac_bias_intrpt = 0; sc->sc_panel.dma_burst_sz = 16; @@ -989,7 +1005,11 @@ am335x_lcd_attach(device_t dev) } } - ti_prcm_clk_enable(LCDC_CLK); + err = ti_sysc_clock_enable(device_get_parent(dev)); + if (err != 0) { + device_printf(dev, "Failed to enable sysc clkctrl, err %d\n", err); + return (ENXIO); + } rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, @@ -1081,3 +1101,4 @@ static devclass_t am335x_lcd_devclass; DRIVER_MODULE(am335x_lcd, simplebus, am335x_lcd_driver, am335x_lcd_devclass, 0, 0); MODULE_VERSION(am335x_lcd, 1); MODULE_DEPEND(am335x_lcd, simplebus, 1, 1, 1); +MODULE_DEPEND(am335x_lcd, ti_sysc, 1, 1, 1); diff --git a/sys/arm/ti/am335x/am335x_musb.c b/sys/arm/ti/am335x/am335x_musb.c index cbe4d06338c9..d868e8a64f8b 100644 --- a/sys/arm/ti/am335x/am335x_musb.c +++ b/sys/arm/ti/am335x/am335x_musb.c @@ -66,9 +66,11 @@ __FBSDID("$FreeBSD$"); #include -#include -#include #include +#include +#include +#include +#include "syscon_if.h" #define USBCTRL_REV 0x00 #define USBCTRL_CTRL 0x14 @@ -130,6 +132,7 @@ struct musbotg_super_softc { struct musbotg_softc sc_otg; struct resource *sc_mem_res[2]; int sc_irq_rid; + struct syscon *syscon; }; static void @@ -155,30 +158,33 @@ static void musbotg_clocks_on(void *arg) { struct musbotg_softc *sc; - uint32_t c, reg; + struct musbotg_super_softc *ssc; + uint32_t reg; sc = arg; - reg = USB_CTRL[sc->sc_id]; + ssc = sc->sc_platform_data; - ti_scm_reg_read_4(reg, &c); - c &= ~3; /* Enable power */ - c |= 1 << 19; /* VBUS detect enable */ - c |= 1 << 20; /* Session end enable */ - ti_scm_reg_write_4(reg, c); + reg = SYSCON_READ_4(ssc->syscon, USB_CTRL[sc->sc_id]); + reg &= ~3; /* Enable power */ + reg |= 1 << 19; /* VBUS detect enable */ + reg |= 1 << 20; /* Session end enable */ + + SYSCON_WRITE_4(ssc->syscon, USB_CTRL[sc->sc_id], reg); } static void musbotg_clocks_off(void *arg) { struct musbotg_softc *sc; - uint32_t c, reg; + struct musbotg_super_softc *ssc; + uint32_t reg; sc = arg; - reg = USB_CTRL[sc->sc_id]; + ssc = sc->sc_platform_data; /* Disable power to PHY */ - ti_scm_reg_read_4(reg, &c); - ti_scm_reg_write_4(reg, c | 3); + reg = SYSCON_READ_4(ssc->syscon, USB_CTRL[sc->sc_id]); + SYSCON_WRITE_4(ssc->syscon, USB_CTRL[sc->sc_id], reg | 3); } static void @@ -241,9 +247,42 @@ musbotg_attach(device_t dev) char mode[16]; int err; uint32_t reg; + phandle_t opp_table; + clk_t clk_usbotg_fck; sc->sc_otg.sc_id = device_get_unit(dev); + /* FIXME: The devicetree needs to be updated to get a handle to the gate + * usbotg_fck@47c. see TRM 8.1.12.2 CM_WKUP CM_CLKDCOLDO_DPLL_PER. + */ + err = clk_get_by_name(dev, "usbotg_fck@47c", &clk_usbotg_fck); + if (err) { + device_printf(dev, "Can not find usbotg_fck@47c\n"); + return (ENXIO); + } + + err = clk_enable(clk_usbotg_fck); + if (err) { + device_printf(dev, "Can not enable usbotg_fck@47c\n"); + return (ENXIO); + } + + /* FIXME: For now; Go and kidnap syscon from opp-table */ + opp_table = OF_finddevice("/opp-table"); + if (opp_table == -1) { + device_printf(dev, "Cant find /opp-table\n"); + return (ENXIO); + } + if (!OF_hasprop(opp_table, "syscon")) { + device_printf(dev, "/opp-table missing syscon property\n"); + return (ENXIO); + } + err = syscon_get_by_ofw_property(dev, opp_table, "syscon", &sc->syscon); + if (err) { + device_printf(dev, "Failed to get syscon\n"); + return (ENXIO); + } + /* Request the memory resources */ err = bus_alloc_resources(dev, am335x_musbotg_mem_spec, sc->sc_mem_res); @@ -417,5 +456,7 @@ static driver_t musbotg_driver = { static devclass_t musbotg_devclass; -DRIVER_MODULE(musbotg, usbss, musbotg_driver, musbotg_devclass, 0, 0); -MODULE_DEPEND(musbotg, usbss, 1, 1, 1); +DRIVER_MODULE(musbotg, ti_sysc, musbotg_driver, musbotg_devclass, 0, 0); +MODULE_DEPEND(musbotg, ti_sysc, 1, 1, 1); +MODULE_DEPEND(musbotg, ti_am3359_cppi41, 1, 1, 1); +MODULE_DEPEND(usbss, usb, 1, 1, 1); diff --git a/sys/arm/ti/am335x/am335x_prcm.c b/sys/arm/ti/am335x/am335x_prcm.c deleted file mode 100644 index 875be72f4937..000000000000 --- a/sys/arm/ti/am335x/am335x_prcm.c +++ /dev/null @@ -1,884 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2012 Damjan Marion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include - -#include "am335x_scm.h" - -#define CM_PER 0 -#define CM_PER_L4LS_CLKSTCTRL (CM_PER + 0x000) -#define CM_PER_L3S_CLKSTCTRL (CM_PER + 0x004) -#define CM_PER_L3_CLKSTCTRL (CM_PER + 0x00C) -#define CM_PER_CPGMAC0_CLKCTRL (CM_PER + 0x014) -#define CM_PER_LCDC_CLKCTRL (CM_PER + 0x018) -#define CM_PER_USB0_CLKCTRL (CM_PER + 0x01C) -#define CM_PER_TPTC0_CLKCTRL (CM_PER + 0x024) -#define CM_PER_UART5_CLKCTRL (CM_PER + 0x038) -#define CM_PER_MMC0_CLKCTRL (CM_PER + 0x03C) -#define CM_PER_I2C2_CLKCTRL (CM_PER + 0x044) -#define CM_PER_I2C1_CLKCTRL (CM_PER + 0x048) -#define CM_PER_SPI0_CLKCTRL (CM_PER + 0x04C) -#define CM_PER_SPI1_CLKCTRL (CM_PER + 0x050) -#define CM_PER_UART1_CLKCTRL (CM_PER + 0x06C) -#define CM_PER_UART2_CLKCTRL (CM_PER + 0x070) -#define CM_PER_UART3_CLKCTRL (CM_PER + 0x074) -#define CM_PER_UART4_CLKCTRL (CM_PER + 0x078) -#define CM_PER_TIMER7_CLKCTRL (CM_PER + 0x07C) -#define CM_PER_TIMER2_CLKCTRL (CM_PER + 0x080) -#define CM_PER_TIMER3_CLKCTRL (CM_PER + 0x084) -#define CM_PER_TIMER4_CLKCTRL (CM_PER + 0x088) -#define CM_PER_GPIO1_CLKCTRL (CM_PER + 0x0AC) -#define CM_PER_GPIO2_CLKCTRL (CM_PER + 0x0B0) -#define CM_PER_GPIO3_CLKCTRL (CM_PER + 0x0B4) -#define CM_PER_TPCC_CLKCTRL (CM_PER + 0x0BC) -#define CM_PER_EPWMSS1_CLKCTRL (CM_PER + 0x0CC) -#define CM_PER_EPWMSS0_CLKCTRL (CM_PER + 0x0D4) -#define CM_PER_EPWMSS2_CLKCTRL (CM_PER + 0x0D8) -#define CM_PER_L3_INSTR_CLKCTRL (CM_PER + 0x0DC) -#define CM_PER_L3_CLKCTRL (CM_PER + 0x0E0) -#define CM_PER_PRUSS_CLKCTRL (CM_PER + 0x0E8) -#define CM_PER_TIMER5_CLKCTRL (CM_PER + 0x0EC) -#define CM_PER_TIMER6_CLKCTRL (CM_PER + 0x0F0) -#define CM_PER_MMC1_CLKCTRL (CM_PER + 0x0F4) -#define CM_PER_MMC2_CLKCTRL (CM_PER + 0x0F8) -#define CM_PER_TPTC1_CLKCTRL (CM_PER + 0x0FC) -#define CM_PER_TPTC2_CLKCTRL (CM_PER + 0x100) -#define CM_PER_SPINLOCK0_CLKCTRL (CM_PER + 0x10C) -#define CM_PER_MAILBOX0_CLKCTRL (CM_PER + 0x110) -#define CM_PER_OCPWP_L3_CLKSTCTRL (CM_PER + 0x12C) -#define CM_PER_OCPWP_CLKCTRL (CM_PER + 0x130) -#define CM_PER_CPSW_CLKSTCTRL (CM_PER + 0x144) -#define CM_PER_PRUSS_CLKSTCTRL (CM_PER + 0x140) - -#define CM_WKUP 0x400 -#define CM_WKUP_CLKSTCTRL (CM_WKUP + 0x000) -#define CM_WKUP_CONTROL_CLKCTRL (CM_WKUP + 0x004) -#define CM_WKUP_GPIO0_CLKCTRL (CM_WKUP + 0x008) -#define CM_WKUP_CM_L3_AON_CLKSTCTRL (CM_WKUP + 0x01C) -#define CM_WKUP_CM_CLKSEL_DPLL_MPU (CM_WKUP + 0x02C) -#define CM_WKUP_CM_IDLEST_DPLL_DISP (CM_WKUP + 0x048) -#define CM_WKUP_CM_CLKSEL_DPLL_DISP (CM_WKUP + 0x054) -#define CM_WKUP_CM_CLKDCOLDO_DPLL_PER (CM_WKUP + 0x07C) -#define CM_WKUP_CM_CLKMODE_DPLL_DISP (CM_WKUP + 0x098) -#define CM_WKUP_I2C0_CLKCTRL (CM_WKUP + 0x0B8) -#define CM_WKUP_ADC_TSC_CLKCTRL (CM_WKUP + 0x0BC) - -#define CM_DPLL 0x500 -#define CLKSEL_TIMER7_CLK (CM_DPLL + 0x004) -#define CLKSEL_TIMER2_CLK (CM_DPLL + 0x008) -#define CLKSEL_TIMER3_CLK (CM_DPLL + 0x00C) -#define CLKSEL_TIMER4_CLK (CM_DPLL + 0x010) -#define CLKSEL_TIMER5_CLK (CM_DPLL + 0x018) -#define CLKSEL_TIMER6_CLK (CM_DPLL + 0x01C) -#define CLKSEL_PRUSS_OCP_CLK (CM_DPLL + 0x030) - -#define CM_RTC 0x800 -#define CM_RTC_RTC_CLKCTRL (CM_RTC + 0x000) -#define CM_RTC_CLKSTCTRL (CM_RTC + 0x004) - -#define PRM_PER 0xC00 -#define PRM_PER_RSTCTRL (PRM_PER + 0x00) - -#define PRM_DEVICE_OFFSET 0xF00 -#define PRM_RSTCTRL (PRM_DEVICE_OFFSET + 0x00) - -struct am335x_prcm_softc { - struct resource * res[2]; - bus_space_tag_t bst; - bus_space_handle_t bsh; - int attach_done; -}; - -static struct resource_spec am335x_prcm_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { -1, 0 } -}; - -static struct am335x_prcm_softc *am335x_prcm_sc = NULL; - -static int am335x_clk_noop_activate(struct ti_clock_dev *clkdev); -static int am335x_clk_generic_activate(struct ti_clock_dev *clkdev); -static int am335x_clk_gpio_activate(struct ti_clock_dev *clkdev); -static int am335x_clk_noop_deactivate(struct ti_clock_dev *clkdev); -static int am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev); -static int am335x_clk_noop_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc); -static int am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc); -static int am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq); -static int am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq); -static int am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq); -static int am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq); -static int am335x_clk_set_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int freq); -static void am335x_prcm_reset(void); -static int am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev); -static int am335x_clk_musb0_activate(struct ti_clock_dev *clkdev); -static int am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev); -static int am335x_clk_pruss_activate(struct ti_clock_dev *clkdev); - -#define AM335X_NOOP_CLOCK_DEV(i) \ - { .id = (i), \ - .clk_activate = am335x_clk_noop_activate, \ - .clk_deactivate = am335x_clk_noop_deactivate, \ - .clk_set_source = am335x_clk_noop_set_source, \ - .clk_accessible = NULL, \ - .clk_get_source_freq = NULL, \ - .clk_set_source_freq = NULL \ - } - -#define AM335X_GENERIC_CLOCK_DEV(i) \ - { .id = (i), \ - .clk_activate = am335x_clk_generic_activate, \ - .clk_deactivate = am335x_clk_generic_deactivate, \ - .clk_set_source = am335x_clk_generic_set_source, \ - .clk_accessible = NULL, \ - .clk_get_source_freq = NULL, \ - .clk_set_source_freq = NULL \ - } - -#define AM335X_GPIO_CLOCK_DEV(i) \ - { .id = (i), \ - .clk_activate = am335x_clk_gpio_activate, \ - .clk_deactivate = am335x_clk_generic_deactivate, \ - .clk_set_source = am335x_clk_generic_set_source, \ - .clk_accessible = NULL, \ - .clk_get_source_freq = NULL, \ - .clk_set_source_freq = NULL \ - } - -#define AM335X_MMCHS_CLOCK_DEV(i) \ - { .id = (i), \ - .clk_activate = am335x_clk_generic_activate, \ - .clk_deactivate = am335x_clk_generic_deactivate, \ - .clk_set_source = am335x_clk_generic_set_source, \ - .clk_accessible = NULL, \ - .clk_get_source_freq = am335x_clk_hsmmc_get_source_freq, \ - .clk_set_source_freq = NULL \ - } - -struct ti_clock_dev ti_am335x_clk_devmap[] = { - /* System clocks */ - { .id = SYS_CLK, - .clk_activate = NULL, - .clk_deactivate = NULL, - .clk_set_source = NULL, - .clk_accessible = NULL, - .clk_get_source_freq = am335x_clk_get_sysclk_freq, - .clk_set_source_freq = NULL, - }, - /* MPU (ARM) core clocks */ - { .id = MPU_CLK, - .clk_activate = NULL, - .clk_deactivate = NULL, - .clk_set_source = NULL, - .clk_accessible = NULL, - .clk_get_source_freq = am335x_clk_get_arm_fclk_freq, - .clk_set_source_freq = NULL, - }, - /* CPSW Ethernet Switch core clocks */ - { .id = CPSW_CLK, - .clk_activate = am335x_clk_cpsw_activate, - .clk_deactivate = NULL, - .clk_set_source = NULL, - .clk_accessible = NULL, - .clk_get_source_freq = NULL, - .clk_set_source_freq = NULL, - }, - - /* Mentor USB HS controller core clocks */ - { .id = MUSB0_CLK, - .clk_activate = am335x_clk_musb0_activate, - .clk_deactivate = NULL, - .clk_set_source = NULL, - .clk_accessible = NULL, - .clk_get_source_freq = NULL, - .clk_set_source_freq = NULL, - }, - - /* LCD controller clocks */ - { .id = LCDC_CLK, - .clk_activate = am335x_clk_lcdc_activate, - .clk_deactivate = NULL, - .clk_set_source = NULL, - .clk_accessible = NULL, - .clk_get_source_freq = am335x_clk_get_arm_disp_freq, - .clk_set_source_freq = am335x_clk_set_arm_disp_freq, - }, - - /* UART */ - AM335X_NOOP_CLOCK_DEV(UART1_CLK), - AM335X_GENERIC_CLOCK_DEV(UART2_CLK), - AM335X_GENERIC_CLOCK_DEV(UART3_CLK), - AM335X_GENERIC_CLOCK_DEV(UART4_CLK), - AM335X_GENERIC_CLOCK_DEV(UART5_CLK), - AM335X_GENERIC_CLOCK_DEV(UART6_CLK), - - /* DMTimer */ - AM335X_GENERIC_CLOCK_DEV(TIMER2_CLK), - AM335X_GENERIC_CLOCK_DEV(TIMER3_CLK), - AM335X_GENERIC_CLOCK_DEV(TIMER4_CLK), - AM335X_GENERIC_CLOCK_DEV(TIMER5_CLK), - AM335X_GENERIC_CLOCK_DEV(TIMER6_CLK), - AM335X_GENERIC_CLOCK_DEV(TIMER7_CLK), - - /* GPIO, we use hwmods as reference, not units in spec */ - AM335X_GPIO_CLOCK_DEV(GPIO1_CLK), - AM335X_GPIO_CLOCK_DEV(GPIO2_CLK), - AM335X_GPIO_CLOCK_DEV(GPIO3_CLK), - AM335X_GPIO_CLOCK_DEV(GPIO4_CLK), - - /* I2C we use hwmods as reference, not units in spec */ - AM335X_GENERIC_CLOCK_DEV(I2C1_CLK), - AM335X_GENERIC_CLOCK_DEV(I2C2_CLK), - AM335X_GENERIC_CLOCK_DEV(I2C3_CLK), - - /* McSPI we use hwmods as reference, not units in spec */ - AM335X_GENERIC_CLOCK_DEV(SPI0_CLK), - AM335X_GENERIC_CLOCK_DEV(SPI1_CLK), - - /* TSC_ADC */ - AM335X_GENERIC_CLOCK_DEV(TSC_ADC_CLK), - - /* EDMA */ - AM335X_GENERIC_CLOCK_DEV(EDMA_TPCC_CLK), - AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC0_CLK), - AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC1_CLK), - AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC2_CLK), - - /* MMCHS */ - AM335X_MMCHS_CLOCK_DEV(MMC1_CLK), - AM335X_MMCHS_CLOCK_DEV(MMC2_CLK), - AM335X_MMCHS_CLOCK_DEV(MMC3_CLK), - - /* PWMSS */ - AM335X_GENERIC_CLOCK_DEV(PWMSS0_CLK), - AM335X_GENERIC_CLOCK_DEV(PWMSS1_CLK), - AM335X_GENERIC_CLOCK_DEV(PWMSS2_CLK), - - /* System Mailbox clock */ - AM335X_GENERIC_CLOCK_DEV(MAILBOX0_CLK), - - /* SPINLOCK */ - AM335X_GENERIC_CLOCK_DEV(SPINLOCK0_CLK), - - /* PRU-ICSS */ - { .id = PRUSS_CLK, - .clk_activate = am335x_clk_pruss_activate, - .clk_deactivate = NULL, - .clk_set_source = NULL, - .clk_accessible = NULL, - .clk_get_source_freq = NULL, - .clk_set_source_freq = NULL, - }, - - /* RTC */ - AM335X_GENERIC_CLOCK_DEV(RTC_CLK), - - { INVALID_CLK_IDENT, NULL, NULL, NULL, NULL } -}; - -struct am335x_clk_details { - clk_ident_t id; - uint32_t clkctrl_reg; - uint32_t clksel_reg; -}; - -#define _CLK_DETAIL(i, c, s) \ - { .id = (i), \ - .clkctrl_reg = (c), \ - .clksel_reg = (s), \ - } - -static struct am335x_clk_details g_am335x_clk_details[] = { - - /* UART. UART0 clock not controllable. */ - _CLK_DETAIL(UART1_CLK, 0, 0), - _CLK_DETAIL(UART2_CLK, CM_PER_UART1_CLKCTRL, 0), - _CLK_DETAIL(UART3_CLK, CM_PER_UART2_CLKCTRL, 0), - _CLK_DETAIL(UART4_CLK, CM_PER_UART3_CLKCTRL, 0), - _CLK_DETAIL(UART5_CLK, CM_PER_UART4_CLKCTRL, 0), - _CLK_DETAIL(UART6_CLK, CM_PER_UART5_CLKCTRL, 0), - - /* DMTimer modules */ - _CLK_DETAIL(TIMER2_CLK, CM_PER_TIMER2_CLKCTRL, CLKSEL_TIMER2_CLK), - _CLK_DETAIL(TIMER3_CLK, CM_PER_TIMER3_CLKCTRL, CLKSEL_TIMER3_CLK), - _CLK_DETAIL(TIMER4_CLK, CM_PER_TIMER4_CLKCTRL, CLKSEL_TIMER4_CLK), - _CLK_DETAIL(TIMER5_CLK, CM_PER_TIMER5_CLKCTRL, CLKSEL_TIMER5_CLK), - _CLK_DETAIL(TIMER6_CLK, CM_PER_TIMER6_CLKCTRL, CLKSEL_TIMER6_CLK), - _CLK_DETAIL(TIMER7_CLK, CM_PER_TIMER7_CLKCTRL, CLKSEL_TIMER7_CLK), - - /* GPIO modules, hwmods start with gpio1 */ - _CLK_DETAIL(GPIO1_CLK, CM_WKUP_GPIO0_CLKCTRL, 0), - _CLK_DETAIL(GPIO2_CLK, CM_PER_GPIO1_CLKCTRL, 0), - _CLK_DETAIL(GPIO3_CLK, CM_PER_GPIO2_CLKCTRL, 0), - _CLK_DETAIL(GPIO4_CLK, CM_PER_GPIO3_CLKCTRL, 0), - - /* I2C modules, hwmods start with i2c1 */ - _CLK_DETAIL(I2C1_CLK, CM_WKUP_I2C0_CLKCTRL, 0), - _CLK_DETAIL(I2C2_CLK, CM_PER_I2C1_CLKCTRL, 0), - _CLK_DETAIL(I2C3_CLK, CM_PER_I2C2_CLKCTRL, 0), - - /* McSPI modules, hwmods start with spi0 */ - _CLK_DETAIL(SPI0_CLK, CM_PER_SPI0_CLKCTRL, 0), - _CLK_DETAIL(SPI1_CLK, CM_PER_SPI1_CLKCTRL, 0), - - /* TSC_ADC module */ - _CLK_DETAIL(TSC_ADC_CLK, CM_WKUP_ADC_TSC_CLKCTRL, 0), - - /* EDMA modules */ - _CLK_DETAIL(EDMA_TPCC_CLK, CM_PER_TPCC_CLKCTRL, 0), - _CLK_DETAIL(EDMA_TPTC0_CLK, CM_PER_TPTC0_CLKCTRL, 0), - _CLK_DETAIL(EDMA_TPTC1_CLK, CM_PER_TPTC1_CLKCTRL, 0), - _CLK_DETAIL(EDMA_TPTC2_CLK, CM_PER_TPTC2_CLKCTRL, 0), - - /* MMCHS modules, hwmods start with mmc1*/ - _CLK_DETAIL(MMC1_CLK, CM_PER_MMC0_CLKCTRL, 0), - _CLK_DETAIL(MMC2_CLK, CM_PER_MMC1_CLKCTRL, 0), - _CLK_DETAIL(MMC3_CLK, CM_PER_MMC1_CLKCTRL, 0), - - /* PWMSS modules */ - _CLK_DETAIL(PWMSS0_CLK, CM_PER_EPWMSS0_CLKCTRL, 0), - _CLK_DETAIL(PWMSS1_CLK, CM_PER_EPWMSS1_CLKCTRL, 0), - _CLK_DETAIL(PWMSS2_CLK, CM_PER_EPWMSS2_CLKCTRL, 0), - - _CLK_DETAIL(MAILBOX0_CLK, CM_PER_MAILBOX0_CLKCTRL, 0), - _CLK_DETAIL(SPINLOCK0_CLK, CM_PER_SPINLOCK0_CLKCTRL, 0), - - /* RTC module */ - _CLK_DETAIL(RTC_CLK, CM_RTC_RTC_CLKCTRL, 0), - - { INVALID_CLK_IDENT, 0}, -}; - -/* Read/Write macros */ -#define prcm_read_4(reg) \ - bus_space_read_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg) -#define prcm_write_4(reg, val) \ - bus_space_write_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg, val) - -void am335x_prcm_setup_dmtimer(int); - -static int -am335x_prcm_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (ofw_bus_is_compatible(dev, "ti,am3-prcm")) { - device_set_desc(dev, "AM335x Power and Clock Management"); - return(BUS_PROBE_DEFAULT); - } - - return (ENXIO); -} - -static int -am335x_prcm_attach(device_t dev) -{ - struct am335x_prcm_softc *sc = device_get_softc(dev); - - if (am335x_prcm_sc) - return (ENXIO); - - if (bus_alloc_resources(dev, am335x_prcm_spec, sc->res)) { - device_printf(dev, "could not allocate resources\n"); - return (ENXIO); - } - - sc->bst = rman_get_bustag(sc->res[0]); - sc->bsh = rman_get_bushandle(sc->res[0]); - - am335x_prcm_sc = sc; - ti_cpu_reset = am335x_prcm_reset; - - return (0); -} - -static void -am335x_prcm_new_pass(device_t dev) -{ - struct am335x_prcm_softc *sc = device_get_softc(dev); - unsigned int sysclk, fclk; - - sc = device_get_softc(dev); - if (sc->attach_done || - bus_current_pass < (BUS_PASS_TIMER + BUS_PASS_ORDER_EARLY)) { - bus_generic_new_pass(dev); - return; - } - - sc->attach_done = 1; - - if (am335x_clk_get_sysclk_freq(NULL, &sysclk) != 0) - sysclk = 0; - if (am335x_clk_get_arm_fclk_freq(NULL, &fclk) != 0) - fclk = 0; - if (sysclk && fclk) - device_printf(dev, "Clocks: System %u.%01u MHz, CPU %u MHz\n", - sysclk/1000000, (sysclk % 1000000)/100000, fclk/1000000); - else { - device_printf(dev, "can't read frequencies yet (SCM device not ready?)\n"); - goto fail; - } - - return; - -fail: - device_detach(dev); - return; -} - -static device_method_t am335x_prcm_methods[] = { - DEVMETHOD(device_probe, am335x_prcm_probe), - DEVMETHOD(device_attach, am335x_prcm_attach), - - /* Bus interface */ - DEVMETHOD(bus_new_pass, am335x_prcm_new_pass), - { 0, 0 } -}; - -static driver_t am335x_prcm_driver = { - "am335x_prcm", - am335x_prcm_methods, - sizeof(struct am335x_prcm_softc), -}; - -static devclass_t am335x_prcm_devclass; - -EARLY_DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver, - am335x_prcm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); -MODULE_VERSION(am335x_prcm, 1); -MODULE_DEPEND(am335x_prcm, ti_scm, 1, 1, 1); - -static struct am335x_clk_details* -am335x_clk_details(clk_ident_t id) -{ - struct am335x_clk_details *walker; - - for (walker = g_am335x_clk_details; walker->id != INVALID_CLK_IDENT; walker++) { - if (id == walker->id) - return (walker); - } - - return NULL; -} - -static int -am335x_clk_noop_activate(struct ti_clock_dev *clkdev) -{ - - return (0); -} - -static int -am335x_clk_generic_activate(struct ti_clock_dev *clkdev) -{ - struct am335x_prcm_softc *sc = am335x_prcm_sc; - struct am335x_clk_details* clk_details; - - if (sc == NULL) - return ENXIO; - - clk_details = am335x_clk_details(clkdev->id); - - if (clk_details == NULL) - return (ENXIO); - - /* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */ - prcm_write_4(clk_details->clkctrl_reg, 2); - while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 2) - DELAY(10); - - return (0); -} - -static int -am335x_clk_gpio_activate(struct ti_clock_dev *clkdev) -{ - struct am335x_prcm_softc *sc = am335x_prcm_sc; - struct am335x_clk_details* clk_details; - - if (sc == NULL) - return ENXIO; - - clk_details = am335x_clk_details(clkdev->id); - - if (clk_details == NULL) - return (ENXIO); - - /* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */ - /* set *_CLKCTRL register OPTFCLKEN_GPIO_1_G DBCLK[18] to FCLK_EN(1) */ - prcm_write_4(clk_details->clkctrl_reg, 2 | (1 << 18)); - while ((prcm_read_4(clk_details->clkctrl_reg) & - (3 | (1 << 18) )) != (2 | (1 << 18))) - DELAY(10); - - return (0); -} - -static int -am335x_clk_noop_deactivate(struct ti_clock_dev *clkdev) -{ - - return(0); -} - -static int -am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev) -{ - struct am335x_prcm_softc *sc = am335x_prcm_sc; - struct am335x_clk_details* clk_details; - - if (sc == NULL) - return ENXIO; - - clk_details = am335x_clk_details(clkdev->id); - - if (clk_details == NULL) - return (ENXIO); - - /* set *_CLKCTRL register MODULEMODE[1:0] to disable(0) */ - prcm_write_4(clk_details->clkctrl_reg, 0); - while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 0) - DELAY(10); - - return (0); -} - -static int -am335x_clk_noop_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc) -{ - - return (0); -} - -static int -am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc) -{ - struct am335x_prcm_softc *sc = am335x_prcm_sc; - struct am335x_clk_details* clk_details; - uint32_t reg; - - if (sc == NULL) - return ENXIO; - - clk_details = am335x_clk_details(clkdev->id); - - if (clk_details == NULL) - return (ENXIO); - - switch (clksrc) { - case EXT_CLK: - reg = 0; /* SEL2: TCLKIN clock */ - break; - case SYSCLK_CLK: - reg = 1; /* SEL1: CLK_M_OSC clock */ - break; - case F32KHZ_CLK: - reg = 2; /* SEL3: CLK_32KHZ clock */ - break; - default: - return (ENXIO); - } - - prcm_write_4(clk_details->clksel_reg, reg); - while ((prcm_read_4(clk_details->clksel_reg) & 0x3) != reg) - DELAY(10); - - return (0); -} - -static int -am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq) -{ - *freq = 96000000; - return (0); -} - -static int -am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq) -{ - uint32_t ctrl_status; - - /* Read the input clock freq from the control module. */ - if (ti_scm_reg_read_4(SCM_CTRL_STATUS, &ctrl_status)) - return (ENXIO); - - switch ((ctrl_status>>22) & 0x3) { - case 0x0: - /* 19.2Mhz */ - *freq = 19200000; - break; - case 0x1: - /* 24Mhz */ - *freq = 24000000; - break; - case 0x2: - /* 25Mhz */ - *freq = 25000000; - break; - case 0x3: - /* 26Mhz */ - *freq = 26000000; - break; - } - - return (0); -} - -#define DPLL_BYP_CLKSEL(reg) ((reg>>23) & 1) -#define DPLL_DIV(reg) ((reg & 0x7f)+1) -#define DPLL_MULT(reg) ((reg>>8) & 0x7FF) -#define DPLL_MAX_MUL 0x800 -#define DPLL_MAX_DIV 0x80 - -static int -am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq) -{ - uint32_t reg; - uint32_t sysclk; - - reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_MPU); - - /*Check if we are running in bypass */ - if (DPLL_BYP_CLKSEL(reg)) - return ENXIO; - - am335x_clk_get_sysclk_freq(NULL, &sysclk); - *freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg)); - return(0); -} - -static int -am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq) -{ - uint32_t reg; - uint32_t sysclk; - - reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_DISP); - - /*Check if we are running in bypass */ - if (DPLL_BYP_CLKSEL(reg)) - return ENXIO; - - am335x_clk_get_sysclk_freq(NULL, &sysclk); - *freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg)); - return(0); -} - -static int -am335x_clk_set_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int freq) -{ - uint32_t sysclk; - uint32_t mul, div; - uint32_t i, j; - unsigned int delta, min_delta; - - am335x_clk_get_sysclk_freq(NULL, &sysclk); - - /* Bypass mode */ - prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x4); - - /* Make sure it's in bypass mode */ - while (!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP) - & (1 << 8))) - DELAY(10); - - /* Dumb and non-optimal implementation */ - min_delta = freq; - for (i = 1; i < DPLL_MAX_MUL; i++) { - for (j = 1; j < DPLL_MAX_DIV; j++) { - delta = abs(freq - i*(sysclk/j)); - if (delta < min_delta) { - mul = i; - div = j; - min_delta = delta; - } - if (min_delta == 0) - break; - } - } - - prcm_write_4(CM_WKUP_CM_CLKSEL_DPLL_DISP, (mul << 8) | (div - 1)); - - /* Locked mode */ - prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x7); - - int timeout = 10000; - while ((!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP) - & (1 << 0))) && timeout--) - DELAY(10); - - return(0); -} - -static void -am335x_prcm_reset(void) -{ - prcm_write_4(PRM_RSTCTRL, (1<<1)); -} - -static int -am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev) -{ - struct am335x_prcm_softc *sc = am335x_prcm_sc; - - if (sc == NULL) - return ENXIO; - - /* set MODULENAME to ENABLE */ - prcm_write_4(CM_PER_CPGMAC0_CLKCTRL, 2); - - /* wait for IDLEST to become Func(0) */ - while(prcm_read_4(CM_PER_CPGMAC0_CLKCTRL) & (3<<16)); - - /*set CLKTRCTRL to SW_WKUP(2) */ - prcm_write_4(CM_PER_CPSW_CLKSTCTRL, 2); - - /* wait for 125 MHz OCP clock to become active */ - while((prcm_read_4(CM_PER_CPSW_CLKSTCTRL) & (1<<4)) == 0); - return(0); -} - -static int -am335x_clk_musb0_activate(struct ti_clock_dev *clkdev) -{ - struct am335x_prcm_softc *sc = am335x_prcm_sc; - - if (sc == NULL) - return ENXIO; - - /* set ST_DPLL_CLKDCOLDO(9) to CLK_GATED(1) */ - /* set DPLL_CLKDCOLDO_GATE_CTRL(8) to CLK_ENABLE(1)*/ - prcm_write_4(CM_WKUP_CM_CLKDCOLDO_DPLL_PER, 0x300); - - /*set MODULEMODE to ENABLE(2) */ - prcm_write_4(CM_PER_USB0_CLKCTRL, 2); - - /* wait for MODULEMODE to become ENABLE(2) */ - while ((prcm_read_4(CM_PER_USB0_CLKCTRL) & 0x3) != 2) - DELAY(10); - - /* wait for IDLEST to become Func(0) */ - while(prcm_read_4(CM_PER_USB0_CLKCTRL) & (3<<16)) - DELAY(10); - - return(0); -} - -static int -am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev) -{ - struct am335x_prcm_softc *sc = am335x_prcm_sc; - - if (sc == NULL) - return (ENXIO); - - /* - * For now set frequency to 2*VGA_PIXEL_CLOCK - */ - am335x_clk_set_arm_disp_freq(clkdev, 25175000*2); - - /*set MODULEMODE to ENABLE(2) */ - prcm_write_4(CM_PER_LCDC_CLKCTRL, 2); - - /* wait for MODULEMODE to become ENABLE(2) */ - while ((prcm_read_4(CM_PER_LCDC_CLKCTRL) & 0x3) != 2) - DELAY(10); - - /* wait for IDLEST to become Func(0) */ - while(prcm_read_4(CM_PER_LCDC_CLKCTRL) & (3<<16)) - DELAY(10); - - return (0); -} - -static int -am335x_clk_pruss_activate(struct ti_clock_dev *clkdev) -{ - struct am335x_prcm_softc *sc = am335x_prcm_sc; - - if (sc == NULL) - return (ENXIO); - - /* Set MODULEMODE to ENABLE(2) */ - prcm_write_4(CM_PER_PRUSS_CLKCTRL, 2); - - /* Wait for MODULEMODE to become ENABLE(2) */ - while ((prcm_read_4(CM_PER_PRUSS_CLKCTRL) & 0x3) != 2) - DELAY(10); - - /* Set CLKTRCTRL to SW_WKUP(2) */ - prcm_write_4(CM_PER_PRUSS_CLKSTCTRL, 2); - - /* Wait for the 200 MHz OCP clock to become active */ - while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<4)) == 0) - DELAY(10); - - /* Wait for the 200 MHz IEP clock to become active */ - while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<5)) == 0) - DELAY(10); - - /* Wait for the 192 MHz UART clock to become active */ - while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<6)) == 0) - DELAY(10); - - /* Select L3F as OCP clock */ - prcm_write_4(CLKSEL_PRUSS_OCP_CLK, 0); - while ((prcm_read_4(CLKSEL_PRUSS_OCP_CLK) & 0x3) != 0) - DELAY(10); - - /* Clear the RESET bit */ - prcm_write_4(PRM_PER_RSTCTRL, prcm_read_4(PRM_PER_RSTCTRL) & ~2); - - return (0); -} diff --git a/sys/arm/ti/am335x/am335x_pwmss.c b/sys/arm/ti/am335x/am335x_pwmss.c index 814865d6b762..287b6ce9e8fe 100644 --- a/sys/arm/ti/am335x/am335x_pwmss.c +++ b/sys/arm/ti/am335x/am335x_pwmss.c @@ -46,9 +46,10 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include +#include + +#include +#include "syscon_if.h" #include "am335x_pwm.h" #include "am335x_scm.h" @@ -59,6 +60,11 @@ __FBSDID("$FreeBSD$"); #define CLKCONFIG_EPWMCLK_EN (1 << 8) #define PWMSS_CLKSTATUS 0x0C +/* TRM chapter 2 memory map table 2-3 + VER register location */ +#define PWMSS_REV_0 0x0000 +#define PWMSS_REV_1 0x2000 +#define PWMSS_REV_2 0x4000 + static device_probe_t am335x_pwmss_probe; static device_attach_t am335x_pwmss_attach; static device_detach_t am335x_pwmss_detach; @@ -66,7 +72,7 @@ static device_detach_t am335x_pwmss_detach; struct am335x_pwmss_softc { struct simplebus_softc sc_simplebus; device_t sc_dev; - clk_ident_t sc_clk; + struct syscon *syscon; }; static device_method_t am335x_pwmss_methods[] = { @@ -97,36 +103,45 @@ am335x_pwmss_attach(device_t dev) { struct am335x_pwmss_softc *sc; uint32_t reg, id; - phandle_t node; + uint64_t rev_address; + phandle_t node, opp_table; sc = device_get_softc(dev); sc->sc_dev = dev; - sc->sc_clk = ti_hwmods_get_clock(dev); - if (sc->sc_clk == INVALID_CLK_IDENT) { - device_printf(dev, "failed to get device id based on ti,hwmods\n"); - return (EINVAL); + /* FIXME: For now; Go and kidnap syscon from opp-table */ + opp_table = OF_finddevice("/opp-table"); + if (opp_table == -1) { + device_printf(dev, "Cant find /opp-table\n"); + return (ENXIO); + } + if (!OF_hasprop(opp_table, "syscon")) { + device_printf(dev, "/opp-table doesnt have required syscon property\n"); + return (ENXIO); + } + if (syscon_get_by_ofw_property(dev, opp_table, "syscon", &sc->syscon) != 0) { + device_printf(dev, "Failed to get syscon\n"); + return (ENXIO); } - ti_prcm_clk_enable(sc->sc_clk); - ti_scm_reg_read_4(SCM_PWMSS_CTRL, ®); - switch (sc->sc_clk) { - case PWMSS0_CLK: - id = 0; - break; - case PWMSS1_CLK: - id = 1; - break; + ti_sysc_clock_enable(device_get_parent(dev)); - case PWMSS2_CLK: - id = 2; - break; - default: - device_printf(dev, "unknown pwmss clock id: %d\n", sc->sc_clk); - return (EINVAL); + rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); + switch (rev_address) { + case PWMSS_REV_0: + id = 0; + break; + case PWMSS_REV_1: + id = 1; + break; + case PWMSS_REV_2: + id = 2; + break; } + + reg = SYSCON_READ_4(sc->syscon, SCM_PWMSS_CTRL); reg |= (1 << id); - ti_scm_reg_write_4(SCM_PWMSS_CTRL, reg); + SYSCON_WRITE_4(sc->syscon, SCM_PWMSS_CTRL, reg); node = ofw_bus_get_node(dev); @@ -161,3 +176,4 @@ DEFINE_CLASS_1(am335x_pwmss, am335x_pwmss_driver, am335x_pwmss_methods, static devclass_t am335x_pwmss_devclass; DRIVER_MODULE(am335x_pwmss, simplebus, am335x_pwmss_driver, am335x_pwmss_devclass, 0, 0); MODULE_VERSION(am335x_pwmss, 1); +MODULE_DEPEND(am335x_pwmss, ti_sysc, 1, 1, 1); diff --git a/sys/arm/ti/am335x/am335x_rtc.c b/sys/arm/ti/am335x/am335x_rtc.c index 9620f5284e84..c2612d2fc7a9 100644 --- a/sys/arm/ti/am335x/am335x_rtc.c +++ b/sys/arm/ti/am335x/am335x_rtc.c @@ -39,8 +39,9 @@ __FBSDID("$FreeBSD$"); #include +#include #include -#include +#include #include #include @@ -110,7 +111,7 @@ am335x_rtc_attach(device_t dev) RTC_LOCK_INIT(sc); /* Enable the RTC module. */ - ti_prcm_clk_enable(RTC_CLK); + ti_sysc_clock_enable(device_get_parent(dev)); rev = RTC_READ4(sc, RTC_REVISION); device_printf(dev, "AM335X RTC v%d.%d.%d\n", (rev >> 8) & 0x7, (rev >> 6) & 0x3, rev & 0x3f); @@ -209,3 +210,4 @@ static devclass_t am335x_rtc_devclass; DRIVER_MODULE(am335x_rtc, simplebus, am335x_rtc_driver, am335x_rtc_devclass, 0, 0); MODULE_VERSION(am335x_rtc, 1); MODULE_DEPEND(am335x_rtc, simplebus, 1, 1, 1); +MODULE_DEPEND(am335x_rtc, ti_sysc, 1, 1, 1); diff --git a/sys/arm/ti/am335x/am335x_scm.c b/sys/arm/ti/am335x/am335x_scm.c index 6f040ed74b7d..e72c14ba58ad 100644 --- a/sys/arm/ti/am335x/am335x_scm.c +++ b/sys/arm/ti/am335x/am335x_scm.c @@ -40,11 +40,15 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include "syscon_if.h" + #define TZ_ZEROC 2731 struct am335x_scm_softc { int sc_last_temp; struct sysctl_oid *sc_temp_oid; + struct syscon *syscon; }; static int @@ -60,7 +64,7 @@ am335x_scm_temp_sysctl(SYSCTL_HANDLER_ARGS) /* Read the temperature and convert to Kelvin. */ for(i = 50; i > 0; i--) { - ti_scm_reg_read_4(SCM_BGAP_CTRL, ®); + reg = SYSCON_READ_4(sc->syscon, SCM_BGAP_CTRL); if ((reg & SCM_BGAP_EOCZ) == 0) break; DELAY(50); @@ -96,6 +100,9 @@ am335x_scm_identify(driver_t *driver, device_t parent) static int am335x_scm_probe(device_t dev) { + /* Just allow the first one */ + if (strcmp(device_get_nameunit(dev), "am335x_scm0") != 0) + return (ENXIO); device_set_desc(dev, "AM335x Control Module Extension"); @@ -109,21 +116,40 @@ am335x_scm_attach(device_t dev) struct sysctl_ctx_list *ctx; struct sysctl_oid_list *tree; uint32_t reg; + phandle_t opp_table; + int err; + + sc = device_get_softc(dev); + + /* FIXME: For now; Go and kidnap syscon from opp-table */ + opp_table = OF_finddevice("/opp-table"); + if (opp_table == -1) { + device_printf(dev, "Cant find /opp-table\n"); + return (ENXIO); + } + if (!OF_hasprop(opp_table, "syscon")) { + device_printf(dev, "/opp-table missing syscon property\n"); + return (ENXIO); + } + err = syscon_get_by_ofw_property(dev, opp_table, "syscon", &sc->syscon); + if (err) { + device_printf(dev, "Failed to get syscon\n"); + return (ENXIO); + } /* Reset the digital outputs. */ - ti_scm_reg_write_4(SCM_BGAP_CTRL, 0); - ti_scm_reg_read_4(SCM_BGAP_CTRL, ®); + SYSCON_WRITE_4(sc->syscon, SCM_BGAP_CTRL, 0); + reg = SYSCON_READ_4(sc->syscon, SCM_BGAP_CTRL); DELAY(500); /* Set continous mode. */ - ti_scm_reg_write_4(SCM_BGAP_CTRL, SCM_BGAP_CONTCONV); - ti_scm_reg_read_4(SCM_BGAP_CTRL, ®); + SYSCON_WRITE_4(sc->syscon, SCM_BGAP_CTRL, SCM_BGAP_CONTCONV); + reg = SYSCON_READ_4(sc->syscon, SCM_BGAP_CTRL); DELAY(500); /* Start the ADC conversion. */ reg = SCM_BGAP_CLRZ | SCM_BGAP_CONTCONV | SCM_BGAP_SOC; - ti_scm_reg_write_4(SCM_BGAP_CTRL, reg); + SYSCON_WRITE_4(sc->syscon, SCM_BGAP_CTRL, reg); /* Temperature sysctl. */ - sc = device_get_softc(dev); ctx = device_get_sysctl_ctx(dev); tree = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); sc->sc_temp_oid = SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, @@ -145,7 +171,7 @@ am335x_scm_detach(device_t dev) sysctl_remove_oid(sc->sc_temp_oid, 1, 0); /* Stop the bandgap ADC. */ - ti_scm_reg_write_4(SCM_BGAP_CTRL, SCM_BGAP_BGOFF); + SYSCON_WRITE_4(sc->syscon, SCM_BGAP_CTRL, SCM_BGAP_BGOFF); return (0); } @@ -169,4 +195,4 @@ static devclass_t am335x_scm_devclass; DRIVER_MODULE(am335x_scm, ti_scm, am335x_scm_driver, am335x_scm_devclass, 0, 0); MODULE_VERSION(am335x_scm, 1); -MODULE_DEPEND(am335x_scm, ti_scm, 1, 1, 1); +MODULE_DEPEND(am335x_scm, ti_scm_syscon, 1, 1, 1); diff --git a/sys/arm/ti/am335x/am335x_usb_phy.c b/sys/arm/ti/am335x/am335x_usb_phy.c new file mode 100644 index 000000000000..00e28122dcec --- /dev/null +++ b/sys/arm/ti/am335x/am335x_usb_phy.c @@ -0,0 +1,121 @@ +/*- + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define TI_AM335X_USB_PHY 1 +#define TI_AM335X_USB_PHY_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,am335x-usb-phy", TI_AM335X_USB_PHY }, + { NULL, TI_AM335X_USB_PHY_END } +}; + +struct ti_usb_phy_softc { + device_t dev; +}; + +static int ti_usb_phy_probe(device_t dev); +static int ti_usb_phy_attach(device_t dev); +static int ti_usb_phy_detach(device_t dev); + +static int +ti_usb_phy_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI AM335x USB PHY"); + if (!bootverbose) + device_quiet(dev); + + return (BUS_PROBE_DEFAULT); +} + +static int +ti_usb_phy_attach(device_t dev) +{ + struct ti_usb_phy_softc *sc; + phandle_t node; + + sc = device_get_softc(dev); + sc->dev = dev; + node = ofw_bus_get_node(dev); + + /* FIXME: Add dev/extres/phy/ interface */ + + return (bus_generic_attach(dev)); +} + +static int +ti_usb_phy_detach(device_t dev) +{ + return (EBUSY); +} + +static device_method_t ti_usb_phy_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_usb_phy_probe), + DEVMETHOD(device_attach, ti_usb_phy_attach), + DEVMETHOD(device_detach, ti_usb_phy_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(ti_usb_phy, ti_usb_phy_driver, ti_usb_phy_methods, + sizeof(struct ti_usb_phy_softc), simplebus_driver); + +static devclass_t ti_usb_phy_devclass; + +EARLY_DRIVER_MODULE(ti_usb_phy, simplebus, ti_usb_phy_driver, + ti_usb_phy_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_FIRST); +MODULE_VERSION(ti_usb_phy, 1); +MODULE_DEPEND(ti_usb_phy, ti_sysc, 1, 1, 1); diff --git a/sys/arm/ti/am335x/am335x_usbss.c b/sys/arm/ti/am335x/am335x_usbss.c deleted file mode 100644 index ce78a7b64315..000000000000 --- a/sys/arm/ti/am335x/am335x_usbss.c +++ /dev/null @@ -1,226 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2013 Oleksandr Tymoshenko - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#define AM335X_USB_PORTS 2 - -#define USBSS_REVREG 0x00 -#define USBSS_SYSCONFIG 0x10 -#define USBSS_SYSCONFIG_SRESET 1 - -#define USBCTRL_REV 0x00 -#define USBCTRL_CTRL 0x14 -#define USBCTRL_STAT 0x18 -#define USBCTRL_IRQ_STAT0 0x30 -#define IRQ_STAT0_RXSHIFT 16 -#define IRQ_STAT0_TXSHIFT 0 -#define USBCTRL_IRQ_STAT1 0x34 -#define IRQ_STAT1_DRVVBUS (1 << 8) -#define USBCTRL_INTEN_SET0 0x38 -#define USBCTRL_INTEN_SET1 0x3C -#define USBCTRL_INTEN_USB_ALL 0x1ff -#define USBCTRL_INTEN_USB_SOF (1 << 3) -#define USBCTRL_INTEN_CLR0 0x40 -#define USBCTRL_INTEN_CLR1 0x44 -#define USBCTRL_UTMI 0xE0 -#define USBCTRL_UTMI_FSDATAEXT (1 << 1) -#define USBCTRL_MODE 0xE8 -#define USBCTRL_MODE_IDDIG (1 << 8) -#define USBCTRL_MODE_IDDIGMUX (1 << 7) - -#define USBSS_WRITE4(sc, reg, val) \ - bus_write_4((sc)->sc_mem_res, (reg), (val)) -#define USBSS_READ4(sc, reg) \ - bus_read_4((sc)->sc_mem_res, (reg)) - -static device_probe_t usbss_probe; -static device_attach_t usbss_attach; -static device_detach_t usbss_detach; - -struct usbss_softc { - struct simplebus_softc simplebus_sc; - struct resource *sc_mem_res; - int sc_mem_rid; -}; - -static int -usbss_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (!ofw_bus_is_compatible(dev, "ti,am33xx-usb")) - return (ENXIO); - - device_set_desc(dev, "TI AM33xx integrated USB OTG controller"); - - return (BUS_PROBE_DEFAULT); -} - -static int -usbss_attach(device_t dev) -{ - struct usbss_softc *sc = device_get_softc(dev); - int i; - uint32_t rev; - phandle_t node; - - /* Request the memory resources */ - sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &sc->sc_mem_rid, RF_ACTIVE); - if (sc->sc_mem_res == NULL) { - device_printf(dev, - "Error: could not allocate mem resources\n"); - return (ENXIO); - } - - /* Enable device clocks. */ - ti_prcm_clk_enable(MUSB0_CLK); - - /* - * Reset USBSS, USB0 and USB1. - * The registers of USB subsystem must not be accessed while the - * reset pulse is active (200ns). - */ - USBSS_WRITE4(sc, USBSS_SYSCONFIG, USBSS_SYSCONFIG_SRESET); - DELAY(100); - i = 10; - while (USBSS_READ4(sc, USBSS_SYSCONFIG) & USBSS_SYSCONFIG_SRESET) { - DELAY(100); - if (i-- == 0) { - device_printf(dev, "reset timeout.\n"); - return (ENXIO); - } - } - - /* Read the module revision. */ - rev = USBSS_READ4(sc, USBSS_REVREG); - device_printf(dev, "TI AM335X USBSS v%d.%d.%d\n", - (rev >> 8) & 7, (rev >> 6) & 3, rev & 63); - - node = ofw_bus_get_node(dev); - - if (node == -1) { - usbss_detach(dev); - return (ENXIO); - } - - simplebus_init(dev, node); - - /* - * Allow devices to identify. - */ - bus_generic_probe(dev); - - /* - * Now walk the OFW tree and attach top-level devices. - */ - for (node = OF_child(node); node > 0; node = OF_peer(node)) - simplebus_add_device(dev, node, 0, NULL, -1, NULL); - - return (bus_generic_attach(dev)); -} - -static int -usbss_detach(device_t dev) -{ - struct usbss_softc *sc = device_get_softc(dev); - - /* Free resources if any */ - if (sc->sc_mem_res) - bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, - sc->sc_mem_res); - - /* during module unload there are lots of children leftover */ - device_delete_children(dev); - - return (0); -} - -static device_method_t usbss_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, usbss_probe), - DEVMETHOD(device_attach, usbss_attach), - DEVMETHOD(device_detach, usbss_detach), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - - DEVMETHOD_END -}; - -DEFINE_CLASS_1(usbss, usbss_driver, usbss_methods, - sizeof(struct usbss_softc), simplebus_driver); -static devclass_t usbss_devclass; -DRIVER_MODULE(usbss, simplebus, usbss_driver, usbss_devclass, 0, 0); -MODULE_DEPEND(usbss, usb, 1, 1, 1); diff --git a/sys/arm/ti/am335x/files.am335x b/sys/arm/ti/am335x/files.am335x index 66af0d867847..4ecdc1e35b43 100644 --- a/sys/arm/ti/am335x/files.am335x +++ b/sys/arm/ti/am335x/files.am335x @@ -8,7 +8,6 @@ arm/ti/am335x/am335x_gpio.c optional gpio 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 arm/ti/am335x/am335x_pwmss.c standard dev/pwm/pwmbus_if.m standard arm/ti/am335x/am335x_ehrpwm.c standard @@ -16,8 +15,9 @@ arm/ti/am335x/am335x_ecap.c standard arm/ti/am335x/am335x_rtc.c optional am335x_rtc arm/ti/am335x/am335x_scm.c standard arm/ti/am335x/am335x_scm_padconf.c standard -arm/ti/am335x/am335x_usbss.c optional musb fdt arm/ti/am335x/am335x_musb.c optional musb fdt +arm/ti/am335x/am335x_usb_phy.c optional musb fdt +arm/ti/am335x/am3359_cppi41.c optional musb fdt arm/ti/am335x/tda19988.c optional hdmi diff --git a/sys/arm/ti/clk/clock_common.c b/sys/arm/ti/clk/clock_common.c new file mode 100644 index 000000000000..15b0e75a8a1e --- /dev/null +++ b/sys/arm/ti/clk/clock_common.c @@ -0,0 +1,152 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "clock_common.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +void +read_clock_cells(device_t dev, struct clock_cell_info *clk) { + ssize_t numbytes_clocks; + phandle_t node, parent, *cells; + int index, ncells, rv; + + node = ofw_bus_get_node(dev); + + /* Get names of parent clocks */ + numbytes_clocks = OF_getproplen(node, "clocks"); + clk->num_clock_cells = numbytes_clocks / sizeof(cell_t); + + /* Allocate space and get clock cells content */ + /* clock_cells / clock_cells_ncells will be freed in + * find_parent_clock_names() + */ + clk->clock_cells = malloc(numbytes_clocks, M_DEVBUF, M_WAITOK|M_ZERO); + clk->clock_cells_ncells = malloc(clk->num_clock_cells*sizeof(uint8_t), + M_DEVBUF, M_WAITOK|M_ZERO); + OF_getencprop(node, "clocks", clk->clock_cells, numbytes_clocks); + + /* Count number of clocks */ + clk->num_real_clocks = 0; + for (index = 0; index < clk->num_clock_cells; index++) { + rv = ofw_bus_parse_xref_list_alloc(node, "clocks", "#clock-cells", + clk->num_real_clocks, &parent, &ncells, &cells); + if (rv != 0) + continue; + + if (cells != NULL) + OF_prop_free(cells); + + clk->clock_cells_ncells[index] = ncells; + index += ncells; + clk->num_real_clocks++; + } +} + +int +find_parent_clock_names(device_t dev, struct clock_cell_info *clk, struct clknode_init_def *def) { + int index, clock_index, err; + bool found_all = true; + clk_t parent; + + /* Figure out names */ + for (index = 0, clock_index = 0; index < clk->num_clock_cells; index++) { + /* Get name of parent clock */ + err = clk_get_by_ofw_index(dev, 0, clock_index, &parent); + if (err != 0) { + clock_index++; + found_all = false; + DPRINTF(dev, "Failed to find clock_cells[%d]=0x%x\n", + index, clk->clock_cells[index]); + + index += clk->clock_cells_ncells[index]; + continue; + } + + def->parent_names[clock_index] = clk_get_name(parent); + clk_release(parent); + + DPRINTF(dev, "Found parent clock[%d/%d]: %s\n", + clock_index, clk->num_real_clocks, + def->parent_names[clock_index]); + + clock_index++; + index += clk->clock_cells_ncells[index]; + } + + if (!found_all) { + return 1; + } + + free(clk->clock_cells, M_DEVBUF); + free(clk->clock_cells_ncells, M_DEVBUF); + return 0; +} + +void +create_clkdef(device_t dev, struct clock_cell_info *clk, struct clknode_init_def *def) { + def->id = 1; + + clk_parse_ofw_clk_name(dev, ofw_bus_get_node(dev), &def->name); + + DPRINTF(dev, "node name: %s\n", def->name); + + def->parent_cnt = clk->num_real_clocks; + def->parent_names = malloc(clk->num_real_clocks*sizeof(char *), + M_OFWPROP, M_WAITOK); +} +void +free_clkdef(struct clknode_init_def *def) { + OF_prop_free(__DECONST(char *, def->name)); + OF_prop_free(def->parent_names); +} diff --git a/sys/arm/ti/clk/clock_common.h b/sys/arm/ti/clk/clock_common.h new file mode 100644 index 000000000000..148494f90331 --- /dev/null +++ b/sys/arm/ti/clk/clock_common.h @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +struct clock_cell_info { + cell_t *clock_cells; + uint8_t *clock_cells_ncells; + uint32_t num_clock_cells; + uint8_t num_real_clocks; +}; + +void read_clock_cells(device_t dev, struct clock_cell_info *clk); +int find_parent_clock_names(device_t dev, struct clock_cell_info *clk, struct clknode_init_def *def); +void create_clkdef(device_t dev, struct clock_cell_info *clk, struct clknode_init_def *def); +void free_clkdef(struct clknode_init_def *def); diff --git a/sys/arm/ti/clk/ti_clk_clkctrl.c b/sys/arm/ti/clk/ti_clk_clkctrl.c new file mode 100644 index 000000000000..6b2fff5e12bb --- /dev/null +++ b/sys/arm/ti/clk/ti_clk_clkctrl.c @@ -0,0 +1,219 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +#include + +#include "clkdev_if.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* + * clknode for clkctrl, implements gate and mux (for gpioc) + */ + +#define GPIO_X_GDBCLK_MASK 0x00040000 +#define IDLEST_MASK 0x00030000 +#define MODULEMODE_MASK 0x00000003 + +#define GPIOX_GDBCLK_ENABLE 0x00040000 +#define GPIOX_GDBCLK_DISABLE 0x00000000 +#define IDLEST_FUNC 0x00000000 +#define IDLEST_TRANS 0x00010000 +#define IDLEST_IDLE 0x00020000 +#define IDLEST_DISABLE 0x00030000 + +#define MODULEMODE_DISABLE 0x0 +#define MODULEMODE_ENABLE 0x2 + +struct ti_clkctrl_clknode_sc { + device_t dev; + bool gdbclk; + /* omap4-cm range.host + ti,clkctrl reg[0] */ + uint32_t register_offset; +}; + +#define WRITE4(_clk, off, val) \ + CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) +#define READ4(_clk, off, val) \ + CLKDEV_READ_4(clknode_get_device(_clk), off, val) +#define DEVICE_LOCK(_clk) \ + CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) +#define DEVICE_UNLOCK(_clk) \ + CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) + +static int +ti_clkctrl_init(struct clknode *clk, device_t dev) +{ + struct ti_clkctrl_clknode_sc *sc; + + sc = clknode_get_softc(clk); + sc->dev = dev; + + clknode_init_parent_idx(clk, 0); + return (0); +} + +static int +ti_clkctrl_set_gdbclk_gate(struct clknode *clk, bool enable) +{ + struct ti_clkctrl_clknode_sc *sc; + uint32_t val, gpio_x_gdbclk; + uint32_t timeout = 100; + + sc = clknode_get_softc(clk); + + READ4(clk, sc->register_offset, &val); + DPRINTF(sc->dev, "val(%x) & (%x | %x = %x)\n", + val, GPIO_X_GDBCLK_MASK, MODULEMODE_MASK, + GPIO_X_GDBCLK_MASK | MODULEMODE_MASK); + + if (enable) { + val = val & MODULEMODE_MASK; + val |= GPIOX_GDBCLK_ENABLE; + } else { + val = val & MODULEMODE_MASK; + val |= GPIOX_GDBCLK_DISABLE; + } + + DPRINTF(sc->dev, "val %x\n", val); + WRITE4(clk, sc->register_offset, val); + + /* Wait */ + while (timeout) { + READ4(clk, sc->register_offset, &val); + gpio_x_gdbclk = val & GPIO_X_GDBCLK_MASK; + if (enable && (gpio_x_gdbclk == GPIOX_GDBCLK_ENABLE)) + break; + else if (!enable && (gpio_x_gdbclk == GPIOX_GDBCLK_DISABLE)) + break; + DELAY(10); + timeout--; + } + if (timeout == 0) { + device_printf(sc->dev, "ti_clkctrl_set_gdbclk_gate: Timeout\n"); + return (1); + } + + return (0); +} + +static int +ti_clkctrl_set_gate(struct clknode *clk, bool enable) +{ + struct ti_clkctrl_clknode_sc *sc; + uint32_t val, idlest, module; + uint32_t timeout=100; + int err; + + sc = clknode_get_softc(clk); + + if (sc->gdbclk) { + err = ti_clkctrl_set_gdbclk_gate(clk, enable); + return (err); + } + + READ4(clk, sc->register_offset, &val); + + if (enable) + WRITE4(clk, sc->register_offset, MODULEMODE_ENABLE); + else + WRITE4(clk, sc->register_offset, MODULEMODE_DISABLE); + + while (timeout) { + READ4(clk, sc->register_offset, &val); + idlest = val & IDLEST_MASK; + module = val & MODULEMODE_MASK; + if (enable && + (idlest == IDLEST_FUNC || idlest == IDLEST_TRANS) && + module == MODULEMODE_ENABLE) + break; + else if (!enable && + idlest == IDLEST_DISABLE && + module == MODULEMODE_DISABLE) + break; + DELAY(10); + timeout--; + } + + if (timeout == 0) { + device_printf(sc->dev, "ti_clkctrl_set_gate: Timeout\n"); + return (1); + } + + return (0); +} + +static clknode_method_t ti_clkctrl_clknode_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, ti_clkctrl_init), + CLKNODEMETHOD(clknode_set_gate, ti_clkctrl_set_gate), + CLKNODEMETHOD_END +}; + +DEFINE_CLASS_1(ti_clkctrl_clknode, ti_clkctrl_clknode_class, + ti_clkctrl_clknode_methods, sizeof(struct ti_clkctrl_clknode_sc), + clknode_class); + +int +ti_clknode_clkctrl_register(struct clkdom *clkdom, + struct ti_clk_clkctrl_def *clkdef) +{ + struct clknode *clk; + struct ti_clkctrl_clknode_sc *sc; + + clk = clknode_create(clkdom, &ti_clkctrl_clknode_class, + &clkdef->clkdef); + + if (clk == NULL) { + return (1); + } + + sc = clknode_get_softc(clk); + sc->register_offset = clkdef->register_offset; + sc->gdbclk = clkdef->gdbclk; + + if (clknode_register(clkdom, clk) == NULL) { + return (2); + } + return (0); +} diff --git a/sys/arm/ti/clk/ti_clk_clkctrl.h b/sys/arm/ti/clk/ti_clk_clkctrl.h new file mode 100644 index 000000000000..d78736244815 --- /dev/null +++ b/sys/arm/ti/clk/ti_clk_clkctrl.h @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _TI_CLK_CLKCTRL_H_ +#define _TI_CLK_CLKCTRL_H_ + +#include + +struct ti_clk_clkctrl_def { + struct clknode_init_def clkdef; + bool gdbclk; + uint32_t register_offset; +}; + +int ti_clknode_clkctrl_register(struct clkdom *clkdom, struct ti_clk_clkctrl_def *clkdef); + +#endif /* _TI_CLK_CLKCTRL_H_ */ diff --git a/sys/arm/ti/clk/ti_clk_dpll.c b/sys/arm/ti/clk/ti_clk_dpll.c new file mode 100644 index 000000000000..14e48dc95026 --- /dev/null +++ b/sys/arm/ti/clk/ti_clk_dpll.c @@ -0,0 +1,341 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Emmanuel Vadot + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * based on sys/arm/allwinner/clkng/aw_clk_np.c + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include + +#include + +#include "clkdev_if.h" + +/* + * clknode for clocks matching the formula : + * + * clk = clkin * n / p + * + */ + +struct ti_dpll_clknode_sc { + uint32_t ti_clkmode_offset; /* control */ + uint8_t ti_clkmode_flags; + + uint32_t ti_idlest_offset; + + uint32_t ti_clksel_offset; /* mult-div1 */ + struct ti_clk_factor n; /* ti_clksel_mult */ + struct ti_clk_factor p; /* ti_clksel_div */ + + uint32_t ti_autoidle_offset; +}; + +#define WRITE4(_clk, off, val) \ + CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) +#define READ4(_clk, off, val) \ + CLKDEV_READ_4(clknode_get_device(_clk), off, val) +#define DEVICE_LOCK(_clk) \ + CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) +#define DEVICE_UNLOCK(_clk) \ + CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) + +static int +ti_dpll_clk_init(struct clknode *clk, device_t dev) +{ + struct ti_dpll_clknode_sc *sc; + + sc = clknode_get_softc(clk); + + clknode_init_parent_idx(clk, 0); + return (0); +} + +/* helper to keep aw_clk_np_find_best "intact" */ +static inline uint32_t +ti_clk_factor_get_max(struct ti_clk_factor *factor) +{ + uint32_t max; + + if (factor->flags & TI_CLK_FACTOR_FIXED) + max = factor->value; + else { + max = (1 << factor->width); + } + + return (max); +} + +static inline uint32_t +ti_clk_factor_get_min(struct ti_clk_factor *factor) +{ + uint32_t min; + + if (factor->flags & TI_CLK_FACTOR_FIXED) + min = factor->value; + else if (factor->flags & TI_CLK_FACTOR_ZERO_BASED) + min = 0; + else if (factor->flags & TI_CLK_FACTOR_MIN_VALUE) + min = factor->min_value; + else + min = 1; + + return (min); +} + +static uint64_t +ti_dpll_clk_find_best(struct ti_dpll_clknode_sc *sc, uint64_t fparent, + uint64_t *fout, uint32_t *factor_n, uint32_t *factor_p) +{ + uint64_t cur, best; + uint32_t n, p, max_n, max_p, min_n, min_p; + + *factor_n = *factor_p = 0; + + max_n = ti_clk_factor_get_max(&sc->n); + max_p = ti_clk_factor_get_max(&sc->p); + min_n = ti_clk_factor_get_min(&sc->n); + min_p = ti_clk_factor_get_min(&sc->p); + + for (p = min_p; p <= max_p; ) { + for (n = min_n; n <= max_n; ) { + cur = fparent * n / p; + if (abs(*fout - cur) < abs(*fout - best)) { + best = cur; + *factor_n = n; + *factor_p = p; + } + + n++; + } + p++; + } + + return (best); +} + +static inline uint32_t +ti_clk_get_factor(uint32_t val, struct ti_clk_factor *factor) +{ + uint32_t factor_val; + + if (factor->flags & TI_CLK_FACTOR_FIXED) + return (factor->value); + + factor_val = (val & factor->mask) >> factor->shift; + if (!(factor->flags & TI_CLK_FACTOR_ZERO_BASED)) + factor_val += 1; + + return (factor_val); +} + +static inline uint32_t +ti_clk_factor_get_value(struct ti_clk_factor *factor, uint32_t raw) +{ + uint32_t val; + + if (factor->flags & TI_CLK_FACTOR_FIXED) + return (factor->value); + + if (factor->flags & TI_CLK_FACTOR_ZERO_BASED) + val = raw; + else if (factor->flags & TI_CLK_FACTOR_MAX_VALUE && + raw > factor->max_value) + val = factor->max_value; + else + val = raw - 1; + + return (val); +} + + +static int +ti_dpll_clk_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, + int flags, int *stop) +{ + struct ti_dpll_clknode_sc *sc; + uint64_t cur, best; + uint32_t val, n, p, best_n, best_p, timeout; + + sc = clknode_get_softc(clk); + + best = cur = 0; + + best = ti_dpll_clk_find_best(sc, fparent, fout, + &best_n, &best_p); + + if ((flags & CLK_SET_DRYRUN) != 0) { + *fout = best; + *stop = 1; + return (0); + } + + if ((best < *fout) && + (flags == CLK_SET_ROUND_DOWN)) { + *stop = 1; + return (ERANGE); + } + if ((best > *fout) && + (flags == CLK_SET_ROUND_UP)) { + *stop = 1; + return (ERANGE); + } + + DEVICE_LOCK(clk); + /* 1 switch PLL to bypass mode */ + WRITE4(clk, sc->ti_clkmode_offset, DPLL_EN_MN_BYPASS_MODE); + + /* 2 Ensure PLL is in bypass */ + timeout = 10000; + do { + DELAY(10); + READ4(clk, sc->ti_idlest_offset, &val); + } while (!(val & ST_MN_BYPASS_MASK) && timeout--); + + if (timeout == 0) { + DEVICE_UNLOCK(clk); + return (ERANGE); // FIXME: Better return value? + } + + /* 3 Set DPLL_MULT & DPLL_DIV bits */ + READ4(clk, sc->ti_clksel_offset, &val); + + n = ti_clk_factor_get_value(&sc->n, best_n); + p = ti_clk_factor_get_value(&sc->p, best_p); + val &= ~sc->n.mask; + val &= ~sc->p.mask; + val |= n << sc->n.shift; + val |= p << sc->p.shift; + + WRITE4(clk, sc->ti_clksel_offset, val); + + /* 4. configure M2, M4, M5 and M6 */ + /* + * FIXME: According to documentation M2/M4/M5/M6 can be set "later" + * See note in TRM 8.1.6.7.1 + */ + + /* 5 Switch over to lock mode */ + WRITE4(clk, sc->ti_clkmode_offset, DPLL_EN_LOCK_MODE); + + /* 6 Ensure PLL is locked */ + timeout = 10000; + do { + DELAY(10); + READ4(clk, sc->ti_idlest_offset, &val); + } while (!(val & ST_DPLL_CLK_MASK) && timeout--); + + DEVICE_UNLOCK(clk); + if (timeout == 0) { + return (ERANGE); // FIXME: Better return value? + } + + *fout = best; + *stop = 1; + + return (0); +} + +static int +ti_dpll_clk_recalc(struct clknode *clk, uint64_t *freq) +{ + struct ti_dpll_clknode_sc *sc; + uint32_t val, n, p; + + sc = clknode_get_softc(clk); + + DEVICE_LOCK(clk); + READ4(clk, sc->ti_clksel_offset, &val); + DEVICE_UNLOCK(clk); + + n = ti_clk_get_factor(val, &sc->n); + p = ti_clk_get_factor(val, &sc->p); + + *freq = *freq * n / p; + + return (0); +} + +static clknode_method_t ti_dpll_clknode_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, ti_dpll_clk_init), + CLKNODEMETHOD(clknode_recalc_freq, ti_dpll_clk_recalc), + CLKNODEMETHOD(clknode_set_freq, ti_dpll_clk_set_freq), + CLKNODEMETHOD_END +}; + +DEFINE_CLASS_1(ti_dpll_clknode, ti_dpll_clknode_class, ti_dpll_clknode_methods, + sizeof(struct ti_dpll_clknode_sc), clknode_class); + +int +ti_clknode_dpll_register(struct clkdom *clkdom, struct ti_clk_dpll_def *clkdef) +{ + struct clknode *clk; + struct ti_dpll_clknode_sc *sc; + + clk = clknode_create(clkdom, &ti_dpll_clknode_class, &clkdef->clkdef); + if (clk == NULL) + return (1); + + sc = clknode_get_softc(clk); + + sc->ti_clkmode_offset = clkdef->ti_clkmode_offset; + sc->ti_clkmode_flags = clkdef->ti_clkmode_flags; + sc->ti_idlest_offset = clkdef->ti_idlest_offset; + sc->ti_clksel_offset = clkdef->ti_clksel_offset; + + sc->n.shift = clkdef->ti_clksel_mult.shift; + sc->n.mask = clkdef->ti_clksel_mult.mask; + sc->n.width = clkdef->ti_clksel_mult.width; + sc->n.value = clkdef->ti_clksel_mult.value; + sc->n.min_value = clkdef->ti_clksel_mult.min_value; + sc->n.max_value = clkdef->ti_clksel_mult.max_value; + sc->n.flags = clkdef->ti_clksel_mult.flags; + + sc->p.shift = clkdef->ti_clksel_div.shift; + sc->p.mask = clkdef->ti_clksel_div.mask; + sc->p.width = clkdef->ti_clksel_div.width; + sc->p.value = clkdef->ti_clksel_div.value; + sc->p.min_value = clkdef->ti_clksel_div.min_value; + sc->p.max_value = clkdef->ti_clksel_div.max_value; + sc->p.flags = clkdef->ti_clksel_div.flags; + + sc->ti_autoidle_offset = clkdef->ti_autoidle_offset; + + clknode_register(clkdom, clk); + + return (0); +} diff --git a/sys/arm/ti/clk/ti_clk_dpll.h b/sys/arm/ti/clk/ti_clk_dpll.h new file mode 100644 index 000000000000..54bc0b988d6e --- /dev/null +++ b/sys/arm/ti/clk/ti_clk_dpll.h @@ -0,0 +1,97 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2017 Emmanuel Vadot + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _TI_DPLL_CLOCK_H_ +#define _TI_DPLL_CLOCK_H_ + +#include + +/* Registers are described in AM335x TRM chapter 8.1.12.2.* */ + +/* Register offsets */ +#define CM_CLKSEL_DPLL_PERIPH 0x49C + +/* CM_IDLEST_DPLL_xxx */ +#define ST_MN_BYPASS_MASK 0x0100 +#define ST_MN_BYPASS_SHIFT 8 +#define ST_DPLL_CLK_MASK 0x0001 + +/* CM_CLKMODE_DPLL_DPLL_EN feature flag */ +#define LOW_POWER_STOP_MODE_FLAG 0x01 +#define MN_BYPASS_MODE_FLAG 0x02 +#define IDLE_BYPASS_LOW_POWER_MODE_FLAG 0x04 +#define IDLE_BYPASS_FAST_RELOCK_MODE_FLAG 0x08 +#define LOCK_MODE_FLAG 0x10 + +/* CM_CLKMODE_DPLL_xxx */ +#define DPLL_EN_LOW_POWER_STOP_MODE 0x01 +#define DPLL_EN_MN_BYPASS_MODE 0x04 +#define DPLL_EN_IDLE_BYPASS_LOW_POWER_MODE 0x05 +#define DPLL_EN_IDLE_BYPASS_FAST_RELOCK_MODE 0x06 +#define DPLL_EN_LOCK_MODE 0x07 + + +#define TI_CLK_FACTOR_ZERO_BASED 0x0002 +#define TI_CLK_FACTOR_FIXED 0x0008 +#define TI_CLK_FACTOR_MIN_VALUE 0x0020 +#define TI_CLK_FACTOR_MAX_VALUE 0x0040 + +/* Based on aw_clk_factor sys/arm/allwinner/clkng/aw_clk.h */ +struct ti_clk_factor { + uint32_t shift; /* Shift bits for the factor */ + uint32_t mask; /* Mask to get the factor */ + uint32_t width; /* Number of bits for the factor */ + uint32_t value; /* Fixed value */ + + uint32_t min_value; + uint32_t max_value; + + uint32_t flags; /* Flags */ +}; + +struct ti_clk_dpll_def { + struct clknode_init_def clkdef; + + uint32_t ti_clkmode_offset; /* control */ + uint8_t ti_clkmode_flags; + + uint32_t ti_idlest_offset; + + uint32_t ti_clksel_offset; /* mult-div1 */ + struct ti_clk_factor ti_clksel_mult; + struct ti_clk_factor ti_clksel_div; + + uint32_t ti_autoidle_offset; +}; + +int ti_clknode_dpll_register(struct clkdom *clkdom, struct ti_clk_dpll_def *clkdef); + +#endif /* _TI_DPLL_CLOCK_H_ */ diff --git a/sys/arm/ti/clk/ti_clkctrl.c b/sys/arm/ti/clk/ti_clkctrl.c new file mode 100644 index 000000000000..5ba0dbe19b79 --- /dev/null +++ b/sys/arm/ti/clk/ti_clkctrl.c @@ -0,0 +1,353 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright 2016 Michal Meloun + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +#define L4LS_CLKCTRL_38 2 +#define L4_WKUP_CLKCTRL_0 1 +#define NO_SPECIAL_REG 0 + +/* Documentation/devicetree/bindings/clock/ti-clkctrl.txt */ + +#define TI_CLKCTRL_L4_WKUP 5 +#define TI_CLKCTRL_L4_SECURE 4 +#define TI_CLKCTRL_L4_PER 3 +#define TI_CLKCTRL_L4_CFG 2 +#define TI_CLKCTRL 1 +#define TI_CLKCTRL_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,clkctrl-l4-wkup", TI_CLKCTRL_L4_WKUP }, + { "ti,clkctrl-l4-secure", TI_CLKCTRL_L4_SECURE }, + { "ti,clkctrl-l4-per", TI_CLKCTRL_L4_PER }, + { "ti,clkctrl-l4-cfg", TI_CLKCTRL_L4_CFG }, + { "ti,clkctrl", TI_CLKCTRL }, + { NULL, TI_CLKCTRL_END } +}; + +struct ti_clkctrl_softc { + device_t dev; + + struct clkdom *clkdom; +}; + +static int ti_clkctrl_probe(device_t dev); +static int ti_clkctrl_attach(device_t dev); +static int ti_clkctrl_detach(device_t dev); +int clkctrl_ofw_map(struct clkdom *clkdom, uint32_t ncells, + phandle_t *cells, struct clknode **clk); +static int +create_clkctrl(struct ti_clkctrl_softc *sc, cell_t *reg, uint32_t index, uint32_t reg_offset, + uint64_t parent_offset, const char *org_name, bool special_gdbclk_reg); + +static int +ti_clkctrl_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI clkctrl"); + + return (BUS_PROBE_DEFAULT); +} + +static int +ti_clkctrl_attach(device_t dev) +{ + struct ti_clkctrl_softc *sc; + phandle_t node; + cell_t *reg; + ssize_t numbytes_reg; + int num_reg, err, ti_clock_cells; + uint32_t index, reg_offset, reg_address; + const char *org_name; + uint64_t parent_offset; + uint8_t special_reg = NO_SPECIAL_REG; + + sc = device_get_softc(dev); + sc->dev = dev; + node = ofw_bus_get_node(dev); + + /* Sanity check */ + err = OF_searchencprop(node, "#clock-cells", + &ti_clock_cells, sizeof(ti_clock_cells)); + if (err == -1) { + device_printf(sc->dev, "Failed to get #clock-cells\n"); + return (ENXIO); + } + + if (ti_clock_cells != 2) { + device_printf(sc->dev, "clock cells(%d) != 2\n", + ti_clock_cells); + return (ENXIO); + } + + /* Grab the content of reg properties */ + numbytes_reg = OF_getproplen(node, "reg"); + if (numbytes_reg == 0) { + device_printf(sc->dev, "reg property empty - check your devicetree\n"); + return (ENXIO); + } + num_reg = numbytes_reg / sizeof(cell_t); + + reg = malloc(numbytes_reg, M_DEVBUF, M_WAITOK); + OF_getencprop(node, "reg", reg, numbytes_reg); + + /* Create clock domain */ + sc->clkdom = clkdom_create(sc->dev); + if (sc->clkdom == NULL) { + free(reg, M_DEVBUF); + DPRINTF(sc->dev, "Failed to create clkdom\n"); + return (ENXIO); + } + clkdom_set_ofw_mapper(sc->clkdom, clkctrl_ofw_map); + + /* Create clock nodes */ + /* name */ + clk_parse_ofw_clk_name(sc->dev, node, &org_name); + + /* Get parent range */ + parent_offset = ti_omap4_cm_get_simplebus_base_host(device_get_parent(dev)); + + /* Check if this is a clkctrl with special registers like gpio */ + switch (ti_chip()) { +#ifdef SOC_OMAP4 + case CHIP_OMAP_4: + /* FIXME: Todo */ + break; + +#endif /* SOC_OMAP4 */ +#ifdef SOC_TI_AM335X + /* Checkout TRM 8.1.12.1.29 - 8.1.12.31 and 8.1.12.2.3 + * and the DTS. + */ + case CHIP_AM335X: + if (strcmp(org_name, "l4ls-clkctrl@38") == 0) + special_reg = L4LS_CLKCTRL_38; + else if (strcmp(org_name, "l4-wkup-clkctrl@0") == 0) + special_reg = L4_WKUP_CLKCTRL_0; + break; +#endif /* SOC_TI_AM335X */ + default: + break; + } + + /* reg property has a pair of (base address, length) */ + for (index = 0; index < num_reg; index += 2) { + for (reg_offset = 0; reg_offset < reg[index+1]; reg_offset += sizeof(cell_t)) { + + err = create_clkctrl(sc, reg, index, reg_offset, parent_offset, + org_name, false); + if (err) + goto cleanup; + + /* Create special clkctrl for GDBCLK in GPIO registers */ + switch (special_reg) { + case NO_SPECIAL_REG: + break; + case L4LS_CLKCTRL_38: + reg_address = reg[index] + reg_offset-reg[0]; + if (reg_address == 0x74 || + reg_address == 0x78 || + reg_address == 0x7C) + { + err = create_clkctrl(sc, reg, index, reg_offset, + parent_offset, org_name, true); + if (err) + goto cleanup; + } + break; + case L4_WKUP_CLKCTRL_0: + reg_address = reg[index] + reg_offset - reg[0]; + if (reg_address == 0x8) + { + err = create_clkctrl(sc, reg, index, reg_offset, + parent_offset, org_name, true); + if (err) + goto cleanup; + } + break; + } /* switch (special_reg) */ + } /* inner for */ + } /* for */ + + err = clkdom_finit(sc->clkdom); + if (err) { + DPRINTF(sc->dev, "Clk domain finit fails %x.\n", err); + err = ENXIO; + goto cleanup; + } + +cleanup: + OF_prop_free(__DECONST(char *, org_name)); + + free(reg, M_DEVBUF); + + if (err) + return (err); + + return (bus_generic_attach(dev)); +} + +static int +ti_clkctrl_detach(device_t dev) +{ + return (EBUSY); +} + +/* modified version of default mapper from clk.c */ +int +clkctrl_ofw_map(struct clkdom *clkdom, uint32_t ncells, + phandle_t *cells, struct clknode **clk) { + if (ncells == 0) + *clk = clknode_find_by_id(clkdom, 1); + else if (ncells == 1) + *clk = clknode_find_by_id(clkdom, cells[0]); + else if (ncells == 2) { + /* To avoid collision with other IDs just add one. + * All other registers has an offset of 4 from each other. + */ + if (cells[1]) + *clk = clknode_find_by_id(clkdom, cells[0]+1); + else + *clk = clknode_find_by_id(clkdom, cells[0]); + } + else + return (ERANGE); + + if (*clk == NULL) + return (ENXIO); + + return (0); +} + +static int +create_clkctrl(struct ti_clkctrl_softc *sc, cell_t *reg, uint32_t index, uint32_t reg_offset, + uint64_t parent_offset, const char *org_name, bool special_gdbclk_reg) { + struct ti_clk_clkctrl_def def; + char *name; + size_t name_len; + int err; + + name_len = strlen(org_name) + 1 + 5; /* 5 = _xxxx */ + name = malloc(name_len, M_OFWPROP, M_WAITOK); + + /* + * Check out XX_CLKCTRL-INDEX(offset)-macro dance in + * sys/gnu/dts/dts/include/dt-bindings/clock/am3.h + * sys/gnu/dts/dts/include/dt-bindings/clock/am4.h + * sys/gnu/dts/dts/include/dt-bindings/clock/dra7.h + * reg[0] are in practice the same as the offset described in the dts. + */ + /* special_gdbclk_reg are 0 or 1 */ + def.clkdef.id = reg[index] + reg_offset - reg[0] + special_gdbclk_reg; + def.register_offset = parent_offset + reg[index] + reg_offset; + + /* Indicate this clkctrl is special and dont use IDLEST/MODULEMODE */ + def.gdbclk = special_gdbclk_reg; + + /* Make up an uniq name in the namespace for each clkctrl */ + snprintf(name, name_len, "%s_%x", + org_name, def.clkdef.id); + def.clkdef.name = (const char *) name; + + DPRINTF(sc->dev, "ti_clkctrl_attach: reg[%d]: %s %x\n", + index, def.clkdef.name, def.clkdef.id); + + /* No parent name */ + def.clkdef.parent_cnt = 0; + + /* set flags */ + def.clkdef.flags = 0x0; + + /* Register the clkctrl */ + err = ti_clknode_clkctrl_register(sc->clkdom, &def); + if (err) { + DPRINTF(sc->dev, + "ti_clknode_clkctrl_register[%d:%d] failed %x\n", + index, reg_offset, err); + err = ENXIO; + } + OF_prop_free(name); + return (err); +} + +static device_method_t ti_clkctrl_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_clkctrl_probe), + DEVMETHOD(device_attach, ti_clkctrl_attach), + DEVMETHOD(device_detach, ti_clkctrl_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(ti_clkctrl, ti_clkctrl_driver, ti_clkctrl_methods, + sizeof(struct ti_clkctrl_softc)); + +static devclass_t ti_clkctrl_devclass; + +EARLY_DRIVER_MODULE(ti_clkctrl, simplebus, ti_clkctrl_driver, +ti_clkctrl_devclass, 0, 0, BUS_PASS_BUS+BUS_PASS_ORDER_MIDDLE); + +MODULE_VERSION(ti_clkctrl, 1); diff --git a/sys/arm/ti/clk/ti_divider_clock.c b/sys/arm/ti/clk/ti_divider_clock.c new file mode 100644 index 000000000000..753b5f535d29 --- /dev/null +++ b/sys/arm/ti/clk/ti_divider_clock.c @@ -0,0 +1,264 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "clock_common.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* + * Devicetree description + * Documentation/devicetree/bindings/clock/ti/divider.txt + */ + +struct ti_divider_softc { + device_t sc_dev; + bool attach_done; + struct clk_div_def div_def; + + struct clock_cell_info clock_cell; + struct clkdom *clkdom; +}; + +static int ti_divider_probe(device_t dev); +static int ti_divider_attach(device_t dev); +static int ti_divider_detach(device_t dev); + +#define TI_DIVIDER_CLOCK 2 +#define TI_COMPOSITE_DIVIDER_CLOCK 1 +#define TI_DIVIDER_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,divider-clock", TI_DIVIDER_CLOCK }, + { "ti,composite-divider-clock", TI_COMPOSITE_DIVIDER_CLOCK }, + { NULL, TI_DIVIDER_END } +}; + +static int +register_clk(struct ti_divider_softc *sc) { + int err; + + sc->clkdom = clkdom_create(sc->sc_dev); + if (sc->clkdom == NULL) { + DPRINTF(sc->sc_dev, "Failed to create clkdom\n"); + return (ENXIO); + } + + err = clknode_div_register(sc->clkdom, &sc->div_def); + if (err) { + DPRINTF(sc->sc_dev, "clknode_div_register failed %x\n", err); + return (ENXIO); + } + + err = clkdom_finit(sc->clkdom); + if (err) { + DPRINTF(sc->sc_dev, "Clk domain finit fails %x.\n", err); + return (ENXIO); + } + + return (0); +} + +static int +ti_divider_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI Divider Clock"); + + return (BUS_PROBE_DEFAULT); +} + +static int +ti_divider_attach(device_t dev) +{ + struct ti_divider_softc *sc; + phandle_t node; + int err; + cell_t value; + uint32_t ti_max_div; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + node = ofw_bus_get_node(dev); + + /* Grab the content of reg properties */ + OF_getencprop(node, "reg", &value, sizeof(value)); + sc->div_def.offset = value; + + if (OF_hasprop(node, "ti,bit-shift")) { + OF_getencprop(node, "ti,bit-shift", &value, sizeof(value)); + sc->div_def.i_shift = value; + } + + if (OF_hasprop(node, "ti,index-starts-at-one")) { + sc->div_def.div_flags = CLK_DIV_ZERO_BASED; + } + + if (OF_hasprop(node, "ti,index-power-of-two")) { + /* FIXME: later */ + device_printf(sc->sc_dev, "ti,index-power-of-two - Not implemented\n"); + /* remember to update i_width a few lines below */ + } + if (OF_hasprop(node, "ti,max-div")) { + OF_getencprop(node, "ti,max-div", &value, sizeof(value)); + ti_max_div = value; + } + + if (OF_hasprop(node, "clock-output-names")) + device_printf(sc->sc_dev, "clock-output-names\n"); + if (OF_hasprop(node, "ti,dividers")) + device_printf(sc->sc_dev, "ti,dividers\n"); + if (OF_hasprop(node, "ti,min-div")) + device_printf(sc->sc_dev, "ti,min-div - Not implemented\n"); + + if (OF_hasprop(node, "ti,autoidle-shift")) + device_printf(sc->sc_dev, "ti,autoidle-shift - Not implemented\n"); + if (OF_hasprop(node, "ti,set-rate-parent")) + device_printf(sc->sc_dev, "ti,set-rate-parent - Not implemented\n"); + if (OF_hasprop(node, "ti,latch-bit")) + device_printf(sc->sc_dev, "ti,latch-bit - Not implemented\n"); + + /* Figure out the width from ti_max_div */ + if (sc->div_def.div_flags) + sc->div_def.i_width = fls(ti_max_div-1); + else + sc->div_def.i_width = fls(ti_max_div); + + DPRINTF(sc->sc_dev, "div_def.i_width %x\n", sc->div_def.i_width); + + read_clock_cells(sc->sc_dev, &sc->clock_cell); + + create_clkdef(sc->sc_dev, &sc->clock_cell, &sc->div_def.clkdef); + + err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->div_def.clkdef); + + if (err) { + /* free_clkdef will be called in ti_divider_new_pass */ + DPRINTF(sc->sc_dev, "find_parent_clock_names failed\n"); + return (bus_generic_attach(sc->sc_dev)); + } + + err = register_clk(sc); + + if (err) { + /* free_clkdef will be called in ti_divider_new_pass */ + DPRINTF(sc->sc_dev, "register_clk failed\n"); + return (bus_generic_attach(sc->sc_dev)); + } + + sc->attach_done = true; + + free_clkdef(&sc->div_def.clkdef); + + return (bus_generic_attach(sc->sc_dev)); +} + +static int +ti_divider_detach(device_t dev) +{ + return (EBUSY); +} + +static void +ti_divider_new_pass(device_t dev) +{ + struct ti_divider_softc *sc; + int err; + + sc = device_get_softc(dev); + + if (sc->attach_done) { + return; + } + + err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->div_def.clkdef); + if (err) { + /* free_clkdef will be called in a later call to ti_divider_new_pass */ + DPRINTF(sc->sc_dev, "new_pass find_parent_clock_names failed\n"); + return; + } + + err = register_clk(sc); + if (err) { + /* free_clkdef will be called in a later call to ti_divider_new_pass */ + DPRINTF(sc->sc_dev, "new_pass register_clk failed\n"); + return; + } + + sc->attach_done = true; + + free_clkdef(&sc->div_def.clkdef); +} + +static device_method_t ti_divider_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_divider_probe), + DEVMETHOD(device_attach, ti_divider_attach), + DEVMETHOD(device_detach, ti_divider_detach), + + /* Bus interface */ + DEVMETHOD(bus_new_pass, ti_divider_new_pass), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(ti_divider, ti_divider_driver, ti_divider_methods, + sizeof(struct ti_divider_softc)); + +static devclass_t ti_divider_devclass; + +EARLY_DRIVER_MODULE(ti_divider, simplebus, ti_divider_driver, + ti_divider_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_divider, 1); diff --git a/sys/arm/ti/clk/ti_dpll_clock.c b/sys/arm/ti/clk/ti_dpll_clock.c new file mode 100644 index 000000000000..91127c570c4d --- /dev/null +++ b/sys/arm/ti/clk/ti_dpll_clock.c @@ -0,0 +1,375 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include "clock_common.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* + * Devicetree description + * Documentation/devicetree/bindings/clock/ti/dpll.txt + */ + +struct ti_dpll_softc { + device_t dev; + uint8_t dpll_type; + + bool attach_done; + struct ti_clk_dpll_def dpll_def; + + struct clock_cell_info clock_cell; + struct clkdom *clkdom; +}; + +static int ti_dpll_probe(device_t dev); +static int ti_dpll_attach(device_t dev); +static int ti_dpll_detach(device_t dev); + +#define TI_OMAP3_DPLL_CLOCK 17 +#define TI_OMAP3_DPLL_CORE_CLOCK 16 +#define TI_OMAP3_DPLL_PER_CLOCK 15 +#define TI_OMAP3_DPLL_PER_J_TYPE_CLOCK 14 +#define TI_OMAP4_DPLL_CLOCK 13 +#define TI_OMAP4_DPLL_X2_CLOCK 12 +#define TI_OMAP4_DPLL_CORE_CLOCK 11 +#define TI_OMAP4_DPLL_M4XEN_CLOCK 10 +#define TI_OMAP4_DPLL_J_TYPE_CLOCK 9 +#define TI_OMAP5_MPU_DPLL_CLOCK 8 +#define TI_AM3_DPLL_NO_GATE_CLOCK 7 +#define TI_AM3_DPLL_J_TYPE_CLOCK 6 +#define TI_AM3_DPLL_NO_GATE_J_TYPE_CLOCK 5 +#define TI_AM3_DPLL_CLOCK 4 +#define TI_AM3_DPLL_CORE_CLOCK 3 +#define TI_AM3_DPLL_X2_CLOCK 2 +#define TI_OMAP2_DPLL_CORE_CLOCK 1 +#define TI_DPLL_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,omap3-dpll-clock", TI_OMAP3_DPLL_CLOCK }, + { "ti,omap3-dpll-core-clock", TI_OMAP3_DPLL_CORE_CLOCK }, + { "ti,omap3-dpll-per-clock", TI_OMAP3_DPLL_PER_CLOCK }, + { "ti,omap3-dpll-per-j-type-clock",TI_OMAP3_DPLL_PER_J_TYPE_CLOCK }, + { "ti,omap4-dpll-clock", TI_OMAP4_DPLL_CLOCK }, + { "ti,omap4-dpll-x2-clock", TI_OMAP4_DPLL_X2_CLOCK }, + { "ti,omap4-dpll-core-clock", TI_OMAP4_DPLL_CORE_CLOCK }, + { "ti,omap4-dpll-m4xen-clock", TI_OMAP4_DPLL_M4XEN_CLOCK }, + { "ti,omap4-dpll-j-type-clock", TI_OMAP4_DPLL_J_TYPE_CLOCK }, + { "ti,omap5-mpu-dpll-clock", TI_OMAP5_MPU_DPLL_CLOCK }, + { "ti,am3-dpll-no-gate-clock", TI_AM3_DPLL_NO_GATE_CLOCK }, + { "ti,am3-dpll-j-type-clock", TI_AM3_DPLL_J_TYPE_CLOCK }, + { "ti,am3-dpll-no-gate-j-type-clock",TI_AM3_DPLL_NO_GATE_J_TYPE_CLOCK }, + { "ti,am3-dpll-clock", TI_AM3_DPLL_CLOCK }, + { "ti,am3-dpll-core-clock", TI_AM3_DPLL_CORE_CLOCK }, + { "ti,am3-dpll-x2-clock", TI_AM3_DPLL_X2_CLOCK }, + { "ti,omap2-dpll-core-clock", TI_OMAP2_DPLL_CORE_CLOCK }, + { NULL, TI_DPLL_END } +}; + +static int +register_clk(struct ti_dpll_softc *sc) { + int err; + + sc->clkdom = clkdom_create(sc->dev); + if (sc->clkdom == NULL) { + DPRINTF(sc->dev, "Failed to create clkdom\n"); + return (ENXIO); + } + + err = ti_clknode_dpll_register(sc->clkdom, &sc->dpll_def); + if (err) { + DPRINTF(sc->dev, + "ti_clknode_dpll_register failed %x\n", err); + return (ENXIO); + } + + err = clkdom_finit(sc->clkdom); + if (err) { + DPRINTF(sc->dev, "Clk domain finit fails %x.\n", err); + return (ENXIO); + } + + return (0); +} + +static int +ti_dpll_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI DPLL Clock"); + + return (BUS_PROBE_DEFAULT); +} + +static int +parse_dpll_reg(struct ti_dpll_softc *sc) { + ssize_t numbytes_regs; + uint32_t num_regs; + phandle_t node; + cell_t reg_cells[4]; + + if (sc->dpll_type == TI_AM3_DPLL_X2_CLOCK || + sc->dpll_type == TI_OMAP4_DPLL_X2_CLOCK) { + sc->dpll_def.ti_clksel_mult.value = 2; + sc->dpll_def.ti_clksel_mult.flags = TI_CLK_FACTOR_FIXED; + + sc->dpll_def.ti_clksel_div.value = 1; + sc->dpll_def.ti_clksel_div.flags = TI_CLK_FACTOR_FIXED; + return (0); + } + + node = ofw_bus_get_node(sc->dev); + + numbytes_regs = OF_getproplen(node, "reg"); + num_regs = numbytes_regs / sizeof(cell_t); + + /* Sanity check */ + if (num_regs > 4) + return (ENXIO); + + OF_getencprop(node, "reg", reg_cells, numbytes_regs); + + switch (sc->dpll_type) { + case TI_AM3_DPLL_NO_GATE_CLOCK: + case TI_AM3_DPLL_J_TYPE_CLOCK: + case TI_AM3_DPLL_NO_GATE_J_TYPE_CLOCK: + case TI_AM3_DPLL_CLOCK: + case TI_AM3_DPLL_CORE_CLOCK: + case TI_AM3_DPLL_X2_CLOCK: + if (num_regs != 3) + return (ENXIO); + sc->dpll_def.ti_clkmode_offset = reg_cells[0]; + sc->dpll_def.ti_idlest_offset = reg_cells[1]; + sc->dpll_def.ti_clksel_offset = reg_cells[2]; + break; + + case TI_OMAP2_DPLL_CORE_CLOCK: + if (num_regs != 2) + return (ENXIO); + sc->dpll_def.ti_clkmode_offset = reg_cells[0]; + sc->dpll_def.ti_clksel_offset = reg_cells[1]; + break; + + default: + sc->dpll_def.ti_clkmode_offset = reg_cells[0]; + sc->dpll_def.ti_idlest_offset = reg_cells[1]; + sc->dpll_def.ti_clksel_offset = reg_cells[2]; + sc->dpll_def.ti_autoidle_offset = reg_cells[3]; + break; + } + + /* AM335x */ + if (sc->dpll_def.ti_clksel_offset == CM_CLKSEL_DPLL_PERIPH) { + sc->dpll_def.ti_clksel_mult.shift = 8; + sc->dpll_def.ti_clksel_mult.mask = 0x000FFF00; + sc->dpll_def.ti_clksel_mult.width = 12; + sc->dpll_def.ti_clksel_mult.value = 0; + sc->dpll_def.ti_clksel_mult.min_value = 2; + sc->dpll_def.ti_clksel_mult.max_value = 4095; + sc->dpll_def.ti_clksel_mult.flags = TI_CLK_FACTOR_ZERO_BASED | + TI_CLK_FACTOR_MIN_VALUE | + TI_CLK_FACTOR_MAX_VALUE; + + sc->dpll_def.ti_clksel_div.shift = 0; + sc->dpll_def.ti_clksel_div.mask = 0x000000FF; + sc->dpll_def.ti_clksel_div.width = 8; + sc->dpll_def.ti_clksel_div.value = 0; + sc->dpll_def.ti_clksel_div.min_value = 0; + sc->dpll_def.ti_clksel_div.max_value = 255; + sc->dpll_def.ti_clksel_div.flags = TI_CLK_FACTOR_MIN_VALUE | + TI_CLK_FACTOR_MAX_VALUE; + } else { + sc->dpll_def.ti_clksel_mult.shift = 8; + sc->dpll_def.ti_clksel_mult.mask = 0x0007FF00; + sc->dpll_def.ti_clksel_mult.width = 11; + sc->dpll_def.ti_clksel_mult.value = 0; + sc->dpll_def.ti_clksel_mult.min_value = 2; + sc->dpll_def.ti_clksel_mult.max_value = 2047; + sc->dpll_def.ti_clksel_mult.flags = TI_CLK_FACTOR_ZERO_BASED | + TI_CLK_FACTOR_MIN_VALUE | + TI_CLK_FACTOR_MAX_VALUE; + + sc->dpll_def.ti_clksel_div.shift = 0; + sc->dpll_def.ti_clksel_div.mask = 0x0000007F; + sc->dpll_def.ti_clksel_div.width = 7; + sc->dpll_def.ti_clksel_div.value = 0; + sc->dpll_def.ti_clksel_div.min_value = 0; + sc->dpll_def.ti_clksel_div.max_value = 127; + sc->dpll_def.ti_clksel_div.flags = TI_CLK_FACTOR_MIN_VALUE | + TI_CLK_FACTOR_MAX_VALUE; + } + DPRINTF(sc->dev, "clkmode %x idlest %x clksel %x autoidle %x\n", + sc->dpll_def.ti_clkmode_offset, sc->dpll_def.ti_idlest_offset, + sc->dpll_def.ti_clksel_offset, + sc->dpll_def.ti_autoidle_offset); + + return (0); +} +static int +ti_dpll_attach(device_t dev) +{ + struct ti_dpll_softc *sc; + phandle_t node; + int err; + + sc = device_get_softc(dev); + sc->dev = dev; + + sc->dpll_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; + node = ofw_bus_get_node(dev); + + /* Grab the content of reg properties */ + parse_dpll_reg(sc); + + /* default flags (OMAP4&AM335x) not present in the dts at moment */ + sc->dpll_def.ti_clkmode_flags = MN_BYPASS_MODE_FLAG | LOCK_MODE_FLAG; + + if (OF_hasprop(node, "ti,low-power-stop")) { + sc->dpll_def.ti_clkmode_flags |= LOW_POWER_STOP_MODE_FLAG; + } + if (OF_hasprop(node, "ti,low-power-bypass")) { + sc->dpll_def.ti_clkmode_flags |= IDLE_BYPASS_LOW_POWER_MODE_FLAG; + } + if (OF_hasprop(node, "ti,lock")) { + sc->dpll_def.ti_clkmode_flags |= LOCK_MODE_FLAG; + } + + read_clock_cells(sc->dev, &sc->clock_cell); + + create_clkdef(sc->dev, &sc->clock_cell, &sc->dpll_def.clkdef); + + err = find_parent_clock_names(sc->dev, &sc->clock_cell, + &sc->dpll_def.clkdef); + + if (err) { + /* free_clkdef will be called in ti_dpll_new_pass */ + DPRINTF(sc->dev, "find_parent_clock_names failed\n"); + return (bus_generic_attach(sc->dev)); + } + + err = register_clk(sc); + + if (err) { + /* free_clkdef will be called in ti_dpll_new_pass */ + DPRINTF(sc->dev, "register_clk failed\n"); + return (bus_generic_attach(sc->dev)); + } + + sc->attach_done = true; + + free_clkdef(&sc->dpll_def.clkdef); + + return (bus_generic_attach(sc->dev)); +} + +static int +ti_dpll_detach(device_t dev) +{ + return (EBUSY); +} + +static void +ti_dpll_new_pass(device_t dev) +{ + struct ti_dpll_softc *sc; + int err; + + sc = device_get_softc(dev); + + if (sc->attach_done) { + return; + } + + err = find_parent_clock_names(sc->dev, &sc->clock_cell, + &sc->dpll_def.clkdef); + if (err) { + /* free_clkdef will be called in a later call to ti_dpll_new_pass */ + DPRINTF(sc->dev, + "new_pass find_parent_clock_names failed\n"); + return; + } + + err = register_clk(sc); + if (err) { + /* free_clkdef will be called in a later call to ti_dpll_new_pass */ + DPRINTF(sc->dev, "new_pass register_clk failed\n"); + return; + } + + sc->attach_done = true; + free_clkdef(&sc->dpll_def.clkdef); +} + +static device_method_t ti_dpll_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_dpll_probe), + DEVMETHOD(device_attach, ti_dpll_attach), + DEVMETHOD(device_detach, ti_dpll_detach), + + /* Bus interface */ + DEVMETHOD(bus_new_pass, ti_dpll_new_pass), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(ti_dpll, ti_dpll_driver, ti_dpll_methods, + sizeof(struct ti_dpll_softc)); + +static devclass_t ti_dpll_devclass; + +EARLY_DRIVER_MODULE(ti_dpll, simplebus, ti_dpll_driver, + ti_dpll_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_dpll, 1); diff --git a/sys/arm/ti/clk/ti_gate_clock.c b/sys/arm/ti/clk/ti_gate_clock.c new file mode 100644 index 000000000000..b4fb65995e74 --- /dev/null +++ b/sys/arm/ti/clk/ti_gate_clock.c @@ -0,0 +1,266 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "clock_common.h" + +#define DEBUG_GATE 0 + +#if DEBUG_GATE +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* + * Devicetree description + * Documentation/devicetree/bindings/clock/ti/gate.txt + */ + +struct ti_gate_softc { + device_t sc_dev; + bool attach_done; + uint8_t sc_type; + + struct clk_gate_def gate_def; + struct clock_cell_info clock_cell; + struct clkdom *clkdom; +}; + +static int ti_gate_probe(device_t dev); +static int ti_gate_attach(device_t dev); +static int ti_gate_detach(device_t dev); + +#define TI_GATE_CLOCK 7 +#define TI_WAIT_GATE_CLOCK 6 +#define TI_DSS_GATE_CLOCK 5 +#define TI_AM35XX_GATE_CLOCK 4 +#define TI_CLKDM_GATE_CLOCK 3 +#define TI_HSDIV_GATE_CLOCK 2 +#define TI_COMPOSITE_NO_WAIT_GATE_CLOCK 1 +#define TI_GATE_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,gate-clock", TI_GATE_CLOCK }, + { "ti,wait-gate-clock", TI_WAIT_GATE_CLOCK }, + { "ti,dss-gate-clock", TI_DSS_GATE_CLOCK }, + { "ti,am35xx-gate-clock", TI_AM35XX_GATE_CLOCK }, + { "ti,clkdm-gate-clock", TI_CLKDM_GATE_CLOCK }, + { "ti,hsdiv-gate-cloc", TI_HSDIV_GATE_CLOCK }, + { "ti,composite-no-wait-gate-clock", TI_COMPOSITE_NO_WAIT_GATE_CLOCK }, + { NULL, TI_GATE_END } +}; + +static int +ti_gate_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI Gate Clock"); + + return (BUS_PROBE_DEFAULT); +} + +static int +register_clk(struct ti_gate_softc *sc) { + int err; + sc->clkdom = clkdom_create(sc->sc_dev); + if (sc->clkdom == NULL) { + DPRINTF(sc->sc_dev, "Failed to create clkdom\n"); + return ENXIO; + } + + err = clknode_gate_register(sc->clkdom, &sc->gate_def); + if (err) { + DPRINTF(sc->sc_dev, "clknode_gate_register failed %x\n", err); + return ENXIO; + } + + err = clkdom_finit(sc->clkdom); + if (err) { + DPRINTF(sc->sc_dev, "Clk domain finit fails %x.\n", err); + return ENXIO; + } + + return (0); +} + +static int +ti_gate_attach(device_t dev) +{ + struct ti_gate_softc *sc; + phandle_t node; + int err; + cell_t value; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + node = ofw_bus_get_node(dev); + + /* Get the compatible type */ + sc->sc_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; + + /* Get the content of reg properties */ + if (sc->sc_type != TI_CLKDM_GATE_CLOCK) { + OF_getencprop(node, "reg", &value, sizeof(value)); + sc->gate_def.offset = value; + } +#if DEBUG_GATE + else { + DPRINTF(sc->sc_dev, "no reg (TI_CLKDM_GATE_CLOCK)\n"); + } +#endif + + if (OF_hasprop(node, "ti,bit-shift")) { + OF_getencprop(node, "ti,bit-shift", &value, sizeof(value)); + sc->gate_def.shift = value; + DPRINTF(sc->sc_dev, "ti,bit-shift => shift %x\n", sc->gate_def.shift); + } + if (OF_hasprop(node, "ti,set-bit-to-disable")) { + sc->gate_def.on_value = 0; + sc->gate_def.off_value = 1; + DPRINTF(sc->sc_dev, + "on_value = 0, off_value = 1 (ti,set-bit-to-disable)\n"); + } else { + sc->gate_def.on_value = 1; + sc->gate_def.off_value = 0; + DPRINTF(sc->sc_dev, "on_value = 1, off_value = 0\n"); + } + + sc->gate_def.gate_flags = 0x0; + + read_clock_cells(sc->sc_dev, &sc->clock_cell); + + create_clkdef(sc->sc_dev, &sc->clock_cell, &sc->gate_def.clkdef); + + /* Calculate mask */ + sc->gate_def.mask = (1 << fls(sc->clock_cell.num_real_clocks)) - 1; + DPRINTF(sc->sc_dev, "num_real_clocks %x gate_def.mask %x\n", + sc->clock_cell.num_real_clocks, sc->gate_def.mask); + + err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->gate_def.clkdef); + + if (err) { + /* free_clkdef will be called in ti_gate_new_pass */ + DPRINTF(sc->sc_dev, "find_parent_clock_names failed\n"); + return (bus_generic_attach(sc->sc_dev)); + } + + err = register_clk(sc); + + if (err) { + /* free_clkdef will be called in ti_gate_new_pass */ + DPRINTF(sc->sc_dev, "register_clk failed\n"); + return (bus_generic_attach(sc->sc_dev)); + } + + sc->attach_done = true; + + free_clkdef(&sc->gate_def.clkdef); + + return (bus_generic_attach(sc->sc_dev)); +} + +static int +ti_gate_detach(device_t dev) +{ + return (EBUSY); +} + +static void +ti_gate_new_pass(device_t dev) { + struct ti_gate_softc *sc; + int err; + + sc = device_get_softc(dev); + + if (sc->attach_done) { + return; + } + + err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->gate_def.clkdef); + if (err) { + /* free_clkdef will be called in later call to ti_gate_new_pass */ + DPRINTF(sc->sc_dev, "new_pass find_parent_clock_names failed\n"); + return; + } + + err = register_clk(sc); + if (err) { + /* free_clkdef will be called in later call to ti_gate_new_pass */ + DPRINTF(sc->sc_dev, "new_pass register_clk failed\n"); + return; + } + + sc->attach_done = true; + + free_clkdef(&sc->gate_def.clkdef); +} + +static device_method_t ti_gate_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_gate_probe), + DEVMETHOD(device_attach, ti_gate_attach), + DEVMETHOD(device_detach, ti_gate_detach), + + /* Bus interface */ + DEVMETHOD(bus_new_pass, ti_gate_new_pass), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(ti_gate, ti_gate_driver, ti_gate_methods, + sizeof(struct ti_gate_softc)); + +static devclass_t ti_gate_devclass; + +EARLY_DRIVER_MODULE(ti_gate, simplebus, ti_gate_driver, + ti_gate_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_gate, 1); diff --git a/sys/arm/ti/clk/ti_mux_clock.c b/sys/arm/ti/clk/ti_mux_clock.c new file mode 100644 index 000000000000..bd232290e6a0 --- /dev/null +++ b/sys/arm/ti/clk/ti_mux_clock.c @@ -0,0 +1,249 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "clock_common.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* + * Devicetree description + * Documentation/devicetree/bindings/clock/ti/mux.txt + */ + +struct ti_mux_softc { + device_t sc_dev; + bool attach_done; + + struct clk_mux_def mux_def; + struct clock_cell_info clock_cell; + struct clkdom *clkdom; +}; + +static int ti_mux_probe(device_t dev); +static int ti_mux_attach(device_t dev); +static int ti_mux_detach(device_t dev); + +#define TI_MUX_CLOCK 2 +#define TI_COMPOSITE_MUX_CLOCK 1 +#define TI_MUX_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,mux-clock", TI_MUX_CLOCK }, + { "ti,composite-mux-clock", TI_COMPOSITE_MUX_CLOCK }, + { NULL, TI_MUX_END } +}; + +static int +ti_mux_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI Mux Clock"); + + return (BUS_PROBE_DEFAULT); +} + +static int +register_clk(struct ti_mux_softc *sc) { + int err; + + sc->clkdom = clkdom_create(sc->sc_dev); + if (sc->clkdom == NULL) { + DPRINTF(sc->sc_dev, "Failed to create clkdom\n"); + return ENXIO; + } + + err = clknode_mux_register(sc->clkdom, &sc->mux_def); + if (err) { + DPRINTF(sc->sc_dev, "clknode_mux_register failed %x\n", err); + return ENXIO; + } + + err = clkdom_finit(sc->clkdom); + if (err) { + DPRINTF(sc->sc_dev, "Clk domain finit fails %x.\n", err); + return ENXIO; + } + + return 0; +} + +static int +ti_mux_attach(device_t dev) +{ + struct ti_mux_softc *sc; + phandle_t node; + int err; + cell_t value; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + node = ofw_bus_get_node(dev); + + /* Grab the content of reg properties */ + OF_getencprop(node, "reg", &value, sizeof(value)); + sc->mux_def.offset = value; + + if (OF_hasprop(node, "ti,bit-shift")) { + OF_getencprop(node, "ti,bit-shift", &value, sizeof(value)); + sc->mux_def.shift = value; + DPRINTF(sc->sc_dev, "ti,bit-shift => shift %x\n", sc->mux_def.shift); + } + if (OF_hasprop(node, "ti,index-starts-at-one")) { + /* FIXME: Add support in dev/extres/clk */ + /*sc->mux_def.mux_flags = ... */ + device_printf(sc->sc_dev, "ti,index-starts-at-one - Not implemented\n"); + } + + if (OF_hasprop(node, "ti,set-rate-parent")) + device_printf(sc->sc_dev, "ti,set-rate-parent - Not implemented\n"); + if (OF_hasprop(node, "ti,latch-bit")) + device_printf(sc->sc_dev, "ti,latch-bit - Not implemented\n"); + + read_clock_cells(sc->sc_dev, &sc->clock_cell); + + create_clkdef(sc->sc_dev, &sc->clock_cell, &sc->mux_def.clkdef); + + /* Figure out the width from ti_max_div */ + if (sc->mux_def.mux_flags) + sc->mux_def.width = fls(sc->clock_cell.num_real_clocks-1); + else + sc->mux_def.width = fls(sc->clock_cell.num_real_clocks); + + DPRINTF(sc->sc_dev, "sc->clock_cell.num_real_clocks %x def.width %x\n", + sc->clock_cell.num_real_clocks, sc->mux_def.width); + + err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->mux_def.clkdef); + + if (err) { + /* free_clkdef will be called in ti_mux_new_pass */ + DPRINTF(sc->sc_dev, "find_parent_clock_names failed\n"); + return (bus_generic_attach(sc->sc_dev)); + } + + err = register_clk(sc); + + if (err) { + /* free_clkdef will be called in ti_mux_new_pass */ + DPRINTF(sc->sc_dev, "register_clk failed\n"); + return (bus_generic_attach(sc->sc_dev)); + } + + sc->attach_done = true; + + free_clkdef(&sc->mux_def.clkdef); + + return (bus_generic_attach(sc->sc_dev)); +} + +static void +ti_mux_new_pass(device_t dev) +{ + struct ti_mux_softc *sc; + int err; + + sc = device_get_softc(dev); + + if (sc->attach_done) { + return; + } + + err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->mux_def.clkdef); + if (err) { + /* free_clkdef will be called in later call to ti_mux_new_pass */ + DPRINTF(sc->sc_dev, "ti_mux_new_pass find_parent_clock_names failed\n"); + return; + } + + err = register_clk(sc); + if (err) { + /* free_clkdef will be called in later call to ti_mux_new_pass */ + DPRINTF(sc->sc_dev, "ti_mux_new_pass register_clk failed\n"); + return; + } + + sc->attach_done = true; + + free_clkdef(&sc->mux_def.clkdef); +} + +static int +ti_mux_detach(device_t dev) +{ + return (EBUSY); +} + +static device_method_t ti_mux_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_mux_probe), + DEVMETHOD(device_attach, ti_mux_attach), + DEVMETHOD(device_detach, ti_mux_detach), + + /* Bus interface */ + DEVMETHOD(bus_new_pass, ti_mux_new_pass), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(ti_mux, ti_mux_driver, ti_mux_methods, + sizeof(struct ti_mux_softc)); + +static devclass_t ti_mux_devclass; + +EARLY_DRIVER_MODULE(ti_mux, simplebus, ti_mux_driver, + ti_mux_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_mux, 1); diff --git a/sys/arm/ti/cpsw/if_cpsw.c b/sys/arm/ti/cpsw/if_cpsw.c index 4503304e7b5b..9c43419d568b 100644 --- a/sys/arm/ti/cpsw/if_cpsw.c +++ b/sys/arm/ti/cpsw/if_cpsw.c @@ -74,7 +74,8 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include +#include "syscon_if.h" #include #include @@ -1004,6 +1005,8 @@ cpswp_attach(device_t dev) struct cpswp_softc *sc; uint32_t reg; uint8_t mac_addr[ETHER_ADDR_LEN]; + phandle_t opp_table; + struct syscon *syscon; sc = device_get_softc(dev); sc->dev = dev; @@ -1047,15 +1050,34 @@ cpswp_attach(device_t dev) IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); IFQ_SET_READY(&ifp->if_snd); + /* FIXME: For now; Go and kidnap syscon from opp-table */ + /* ti,cpsw actually have an optional syscon reference but only for am33xx?? */ + opp_table = OF_finddevice("/opp-table"); + if (opp_table == -1) { + device_printf(dev, "Cant find /opp-table\n"); + cpswp_detach(dev); + return (ENXIO); + } + if (!OF_hasprop(opp_table, "syscon")) { + device_printf(dev, "/opp-table doesnt have required syscon property\n"); + cpswp_detach(dev); + return (ENXIO); + } + if (syscon_get_by_ofw_property(dev, opp_table, "syscon", &syscon) != 0) { + device_printf(dev, "Failed to get syscon\n"); + cpswp_detach(dev); + return (ENXIO); + } + /* Get high part of MAC address from control module (mac_id[0|1]_hi) */ - ti_scm_reg_read_4(SCM_MAC_ID0_HI + sc->unit * 8, ®); + reg = SYSCON_READ_4(syscon, SCM_MAC_ID0_HI + sc->unit * 8); mac_addr[0] = reg & 0xFF; mac_addr[1] = (reg >> 8) & 0xFF; mac_addr[2] = (reg >> 16) & 0xFF; mac_addr[3] = (reg >> 24) & 0xFF; /* Get low part of MAC address from control module (mac_id[0|1]_lo) */ - ti_scm_reg_read_4(SCM_MAC_ID0_LO + sc->unit * 8, ®); + reg = SYSCON_READ_4(syscon, SCM_MAC_ID0_LO + sc->unit * 8); mac_addr[4] = reg & 0xFF; mac_addr[5] = (reg >> 8) & 0xFF; diff --git a/sys/arm/ti/files.ti b/sys/arm/ti/files.ti index 83b3c2ed8d89..87beccd120a0 100644 --- a/sys/arm/ti/files.ti +++ b/sys/arm/ti/files.ti @@ -1,14 +1,16 @@ #$FreeBSD$ arm/ti/ti_cpuid.c standard -arm/ti/ti_hwmods.c standard arm/ti/ti_machdep.c standard arm/ti/ti_prcm.c standard +arm/ti/ti_omap4_cm.c standard arm/ti/ti_scm.c standard +arm/ti/ti_scm_syscon.c standard arm/ti/ti_pinmux.c standard dev/mbox/mbox_if.m optional ti_mbox arm/ti/ti_mbox.c optional ti_mbox arm/ti/ti_pruss.c optional ti_pruss +arm/ti/ti_prm.c optional ti_pruss arm/ti/ti_wdt.c optional ti_wdt arm/ti/ti_adc.c optional ti_adc arm/ti/ti_gpio.c optional gpio @@ -18,6 +20,15 @@ arm/ti/ti_sdhci.c optional sdhci arm/ti/ti_spi.c optional ti_spi arm/ti/ti_sysc.c standard +arm/ti/clk/clock_common.c standard +arm/ti/clk/ti_clk_clkctrl.c standard +arm/ti/clk/ti_clkctrl.c standard +arm/ti/clk/ti_clk_dpll.c standard +arm/ti/clk/ti_dpll_clock.c standard +arm/ti/clk/ti_mux_clock.c standard +arm/ti/clk/ti_divider_clock.c standard +arm/ti/clk/ti_gate_clock.c standard + dev/uart/uart_dev_ti8250.c optional uart dev/uart/uart_dev_ns8250.c optional uart diff --git a/sys/arm/ti/omap4/files.omap4 b/sys/arm/ti/omap4/files.omap4 index ddae056d3fc4..0b2f2d3bf26d 100644 --- a/sys/arm/ti/omap4/files.omap4 +++ b/sys/arm/ti/omap4/files.omap4 @@ -9,7 +9,7 @@ arm/ti/ti_sdma.c optional ti_sdma arm/ti/omap4/omap4_gpio.c optional gpio arm/ti/omap4/omap4_l2cache.c optional pl310 -arm/ti/omap4/omap4_prcm_clks.c standard +#arm/ti/omap4/omap4_prcm_clks.c standard arm/ti/omap4/omap4_scm_padconf.c standard arm/ti/omap4/omap4_mp.c optional smp arm/ti/omap4/omap4_wugen.c standard diff --git a/sys/arm/ti/ti_adc.c b/sys/arm/ti/ti_adc.c index 7d7f1deae580..3c67500f3ebc 100644 --- a/sys/arm/ti/ti_adc.c +++ b/sys/arm/ti/ti_adc.c @@ -58,7 +58,7 @@ __FBSDID("$FreeBSD$"); #include #endif -#include +#include #include #include @@ -824,7 +824,7 @@ ti_adc_attach(device_t dev) } /* Activate the ADC_TSC module. */ - err = ti_prcm_clk_enable(TSC_ADC_CLK); + err = ti_sysc_clock_enable(device_get_parent(dev)); if (err) return (err); @@ -846,7 +846,7 @@ ti_adc_attach(device_t dev) } /* Check the ADC revision. */ - rev = ADC_READ4(sc, ADC_REVISION); + rev = ADC_READ4(sc, ti_sysc_get_rev_address_offset_host(device_get_parent(dev))); device_printf(dev, "scheme: %#x func: %#x rtl: %d rev: %d.%d custom rev: %d\n", (rev & ADC_REV_SCHEME_MSK) >> ADC_REV_SCHEME_SHIFT, @@ -964,6 +964,7 @@ static devclass_t ti_adc_devclass; DRIVER_MODULE(ti_adc, simplebus, ti_adc_driver, ti_adc_devclass, 0, 0); MODULE_VERSION(ti_adc, 1); MODULE_DEPEND(ti_adc, simplebus, 1, 1, 1); +MODULE_DEPEND(ti_adc, ti_sysc, 1, 1, 1); #ifdef EVDEV_SUPPORT MODULE_DEPEND(ti_adc, evdev, 1, 1, 1); #endif diff --git a/sys/arm/ti/ti_edma3.c b/sys/arm/ti/ti_edma3.c index f8736e001553..7804ee6b1d8d 100644 --- a/sys/arm/ti/ti_edma3.c +++ b/sys/arm/ti/ti_edma3.c @@ -54,7 +54,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include @@ -181,8 +181,10 @@ ti_edma3_attach(device_t dev) return (ENXIO); } + /* FIXME: Require DTS from Linux kernel 5.7 */ + /* FIXME: OK to enable clkctrl here? */ /* Enable Channel Controller */ - ti_prcm_clk_enable(EDMA_TPCC_CLK); + ti_sysc_clock_enable(device_get_parent(dev)); reg = ti_edma3_cc_rd_4(TI_EDMA3CC_PID); @@ -218,7 +220,7 @@ static driver_t ti_edma3_driver = { static devclass_t ti_edma3_devclass; DRIVER_MODULE(ti_edma3, simplebus, ti_edma3_driver, ti_edma3_devclass, 0, 0); -MODULE_DEPEND(ti_edma3, ti_prcm, 1, 1, 1); +MODULE_DEPEND(ti_edma3, ti_sysc, 1, 1, 1); static void ti_edma3_intr_comp(void *arg) @@ -244,11 +246,6 @@ ti_edma3_init(unsigned int eqn) uint32_t reg; int i; - /* on AM335x Event queue 0 is always mapped to Transfer Controller 0, - * event queue 1 to TC2, etc. So we are asking PRCM to power on specific - * TC based on what event queue we need to initialize */ - ti_prcm_clk_enable(EDMA_TPTC0_CLK + eqn); - /* Clear Event Missed Regs */ ti_edma3_cc_wr_4(TI_EDMA3CC_EMCR, 0xFFFFFFFF); ti_edma3_cc_wr_4(TI_EDMA3CC_EMCRH, 0xFFFFFFFF); diff --git a/sys/arm/ti/ti_gpio.c b/sys/arm/ti/ti_gpio.c index ccdeeb502be4..8754a4769beb 100644 --- a/sys/arm/ti/ti_gpio.c +++ b/sys/arm/ti/ti_gpio.c @@ -57,8 +57,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include +#include #include #include @@ -117,6 +116,18 @@ __FBSDID("$FreeBSD$"); #define PINS_PER_BANK 32 #define TI_GPIO_MASK(p) (1U << ((p) % PINS_PER_BANK)) +#define OMAP4_GPIO1_REV 0x00000 +#define OMAP4_GPIO2_REV 0x55000 +#define OMAP4_GPIO3_REV 0x57000 +#define OMAP4_GPIO4_REV 0x59000 +#define OMAP4_GPIO5_REV 0x5b000 +#define OMAP4_GPIO6_REV 0x5d000 + +#define AM335X_GPIO0_REV 0x07000 +#define AM335X_GPIO1_REV 0x4C000 +#define AM335X_GPIO2_REV 0xAC000 +#define AM335X_GPIO3_REV 0xAE000 + static int ti_gpio_intr(void *arg); static int ti_gpio_detach(device_t); @@ -434,7 +445,7 @@ ti_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) oe &= ~TI_GPIO_MASK(pin); ti_gpio_write_4(sc, TI_GPIO_OE, oe); TI_GPIO_UNLOCK(sc); - + return (0); } @@ -499,7 +510,7 @@ ti_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) return (EINVAL); /* - * Return data from output latch when set as output and from the + * Return data from output latch when set as output and from the * input register otherwise. */ TI_GPIO_LOCK(sc); @@ -553,29 +564,72 @@ ti_gpio_pin_toggle(device_t dev, uint32_t pin) static int ti_gpio_bank_init(device_t dev) { - int pin; + int pin, err; struct ti_gpio_softc *sc; uint32_t flags, reg_oe, reg_set, rev; - clk_ident_t clk; + uint64_t rev_address; sc = device_get_softc(dev); /* Enable the interface and functional clocks for the module. */ - clk = ti_hwmods_get_clock(dev); - if (clk == INVALID_CLK_IDENT) { - device_printf(dev, "failed to get device id based on ti,hwmods\n"); + rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); + /* AM335x + * sc->sc_bank used in am335x/am335x_gpio.c and omap4/omap4_gpio.c */ + switch(ti_chip()) { +#ifdef SOC_OMAP4 + case CHIP_OMAP_4: + switch (rev_address) { + case OMAP4_GPIO1_REV: + sc->sc_bank = 0; + break; + case OMAP4_GPIO2_REV: + sc->sc_bank = 1; + break; + case OMAP4_GPIO3_REV: + sc->sc_bank = 2; + break; + case OMAP4_GPIO4_REV: + sc->sc_bank = 3; + break; + case OMAP4_GPIO5_REV: + sc->sc_bank = 4; + break; + case OMAP4_GPIO6_REV: + sc->sc_bank = 5; + break; + } +#endif +#ifdef SOC_TI_AM335X + case CHIP_AM335X: + switch (rev_address) { + case AM335X_GPIO0_REV: + sc->sc_bank = 0; + break; + case AM335X_GPIO1_REV: + sc->sc_bank = 1; + break; + case AM335X_GPIO2_REV: + sc->sc_bank = 2; + break; + case AM335X_GPIO3_REV: + sc->sc_bank = 3; + break; + } +#endif + } + err = ti_sysc_clock_enable(device_get_parent(dev)); + if (err) { + device_printf(dev, "Failed to enable clock\n"); return (EINVAL); } - sc->sc_bank = clk - GPIO1_CLK + ti_first_gpio_bank(); - ti_prcm_clk_enable(clk); - /* * Read the revision number of the module. TI don't publish the * actual revision numbers, so instead the values have been * determined by experimentation. */ - rev = ti_gpio_read_4(sc, TI_GPIO_REVISION); + rev = ti_gpio_read_4(sc, + ti_sysc_get_rev_address_offset_host(device_get_parent(dev))); /* Check the revision. */ if (rev != ti_gpio_rev()) { @@ -669,7 +723,7 @@ ti_gpio_attach(device_t dev) /* We need to go through each block and ensure the clocks are running and * the module is enabled. It might be better to do this only when the * pins are configured which would result in less power used if the GPIO - * pins weren't used ... + * pins weren't used ... */ if (sc->sc_mem_res != NULL) { /* Initialize the GPIO module. */ diff --git a/sys/arm/ti/ti_hwmods.c b/sys/arm/ti/ti_hwmods.c deleted file mode 100644 index 97c8f99c828a..000000000000 --- a/sys/arm/ti/ti_hwmods.c +++ /dev/null @@ -1,214 +0,0 @@ -/*- - * Copyright (c) 2015 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, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include - -struct hwmod { - const char *name; - int clock_id; -}; - -struct hwmod ti_hwmods[] = { - {"i2c1", I2C1_CLK}, - {"i2c2", I2C2_CLK}, - {"i2c3", I2C3_CLK}, - {"i2c4", I2C4_CLK}, - {"i2c5", I2C5_CLK}, - - {"gpio1", GPIO1_CLK}, - {"gpio2", GPIO2_CLK}, - {"gpio3", GPIO3_CLK}, - {"gpio4", GPIO4_CLK}, - {"gpio5", GPIO5_CLK}, - {"gpio6", GPIO6_CLK}, - {"gpio7", GPIO7_CLK}, - - {"mmc1", MMC1_CLK}, - {"mmc2", MMC2_CLK}, - {"mmc3", MMC3_CLK}, - {"mmc4", MMC4_CLK}, - {"mmc5", MMC5_CLK}, - {"mmc6", MMC6_CLK}, - - {"epwmss0", PWMSS0_CLK}, - {"epwmss1", PWMSS1_CLK}, - {"epwmss2", PWMSS2_CLK}, - - {"spi0", SPI0_CLK}, - {"spi1", SPI1_CLK}, - - {"timer1", TIMER1_CLK}, - {"timer2", TIMER2_CLK}, - {"timer3", TIMER3_CLK}, - {"timer4", TIMER4_CLK}, - {"timer5", TIMER5_CLK}, - {"timer6", TIMER6_CLK}, - {"timer7", TIMER7_CLK}, - - {"uart1", UART1_CLK}, - {"uart2", UART2_CLK}, - {"uart3", UART3_CLK}, - {"uart4", UART4_CLK}, - {"uart5", UART5_CLK}, - {"uart6", UART6_CLK}, - {"uart7", UART7_CLK}, - - {NULL, 0} -}; - -static inline int -ti_get_hwmods_prop(phandle_t node, void **name) -{ - int len; - - if ((len = OF_getprop_alloc(node, "ti,hwmods", name)) > 0) - return (len); - return (OF_getprop_alloc(OF_parent(node), "ti,hwmods", name)); -} - -clk_ident_t -ti_hwmods_get_clock(device_t dev) -{ - phandle_t node; - int len, l; - char *name; - char *buf; - int clk; - struct hwmod *hw; - - if ((node = ofw_bus_get_node(dev)) == 0) - return (INVALID_CLK_IDENT); - - if ((len = ti_get_hwmods_prop(node, (void **)&name)) <= 0) - return (INVALID_CLK_IDENT); - - buf = name; - - clk = INVALID_CLK_IDENT; - while ((len > 0) && (clk == INVALID_CLK_IDENT)) { - for (hw = ti_hwmods; hw->name != NULL; ++hw) { - if (strcmp(hw->name, name) == 0) { - clk = hw->clock_id; - break; - } - } - - /* Slide to the next sub-string. */ - l = strlen(name) + 1; - name += l; - len -= l; - } - - if (len > 0) - device_printf(dev, "WARNING: more than one ti,hwmod \n"); - - OF_prop_free(buf); - return (clk); -} - -int ti_hwmods_contains(device_t dev, const char *hwmod) -{ - phandle_t node; - int len, l; - char *name; - char *buf; - int result; - - if ((node = ofw_bus_get_node(dev)) == 0) - return (0); - - if ((len = ti_get_hwmods_prop(node, (void **)&name)) <= 0) - return (0); - - buf = name; - - result = 0; - while (len > 0) { - if (strcmp(name, hwmod) == 0) { - result = 1; - break; - } - - /* Slide to the next sub-string. */ - l = strlen(name) + 1; - name += l; - len -= l; - } - - OF_prop_free(buf); - - return (result); -} - -int -ti_hwmods_get_unit(device_t dev, const char *hwmod) -{ - phandle_t node; - int l, len, hwmodlen, result; - char *name; - char *buf; - - if ((node = ofw_bus_get_node(dev)) == 0) - return (0); - - if ((len = ti_get_hwmods_prop(node, (void **)&name)) <= 0) - return (0); - - buf = name; - hwmodlen = strlen(hwmod); - result = 0; - while (len > 0) { - if (strncmp(name, hwmod, hwmodlen) == 0) { - result = (int)strtoul(name + hwmodlen, NULL, 10); - break; - } - /* Slide to the next sub-string. */ - l = strlen(name) + 1; - name += l; - len -= l; - } - - OF_prop_free(buf); - return (result); -} diff --git a/sys/arm/ti/ti_hwmods.h b/sys/arm/ti/ti_hwmods.h deleted file mode 100644 index c236cc0d0db0..000000000000 --- a/sys/arm/ti/ti_hwmods.h +++ /dev/null @@ -1,37 +0,0 @@ -/*- - * Copyright (c) 2015 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, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _TI_HWMODS_H_ -#define _TI_HWMODS_H_ - -clk_ident_t ti_hwmods_get_clock(device_t dev); -int ti_hwmods_contains(device_t dev, const char *hwmod); - -/* Returns the N from "hwmodN" in the ti,hwmods property; 0 on failure. */ -int ti_hwmods_get_unit(device_t dev, const char *hwmod); - -#endif /* _TI_HWMODS_H_ */ diff --git a/sys/arm/ti/ti_i2c.c b/sys/arm/ti/ti_i2c.c index 4a9313d6f501..526cb45481f0 100644 --- a/sys/arm/ti/ti_i2c.c +++ b/sys/arm/ti/ti_i2c.c @@ -63,8 +63,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include +#include #include #include @@ -79,7 +78,6 @@ __FBSDID("$FreeBSD$"); struct ti_i2c_softc { device_t sc_dev; - clk_ident_t clk_id; struct resource* sc_irq_res; struct resource* sc_mem_res; device_t sc_iicbus; @@ -700,7 +698,7 @@ ti_i2c_activate(device_t dev) * 1. Enable the functional and interface clocks (see Section * 23.1.5.1.1.1.1). */ - err = ti_prcm_clk_enable(sc->clk_id); + err = ti_sysc_clock_enable(device_get_parent(dev)); if (err) return (err); @@ -748,7 +746,7 @@ ti_i2c_deactivate(device_t dev) } /* Finally disable the functional and interface clocks. */ - ti_prcm_clk_disable(sc->clk_id); + ti_sysc_clock_disable(device_get_parent(dev)); } static int @@ -818,7 +816,6 @@ static int ti_i2c_attach(device_t dev) { int err, rid; - phandle_t node; struct ti_i2c_softc *sc; struct sysctl_ctx_list *ctx; struct sysctl_oid_list *tree; @@ -827,15 +824,6 @@ ti_i2c_attach(device_t dev) sc = device_get_softc(dev); sc->sc_dev = dev; - /* Get the i2c device id from FDT. */ - node = ofw_bus_get_node(dev); - /* i2c ti,hwmods bindings is special: it start with index 1 */ - sc->clk_id = ti_hwmods_get_clock(dev); - if (sc->clk_id == INVALID_CLK_IDENT) { - device_printf(dev, "failed to get device id using ti,hwmod\n"); - return (ENXIO); - } - /* Get the memory resource for the register mapping. */ rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, @@ -986,5 +974,5 @@ static devclass_t ti_i2c_devclass; DRIVER_MODULE(ti_iic, simplebus, ti_i2c_driver, ti_i2c_devclass, 0, 0); DRIVER_MODULE(iicbus, ti_iic, iicbus_driver, iicbus_devclass, 0, 0); -MODULE_DEPEND(ti_iic, ti_prcm, 1, 1, 1); +MODULE_DEPEND(ti_iic, ti_sysc, 1, 1, 1); MODULE_DEPEND(ti_iic, iicbus, 1, 1, 1); diff --git a/sys/arm/ti/ti_mbox.c b/sys/arm/ti/ti_mbox.c index ea8454f96f7a..f77f2d9eafbf 100644 --- a/sys/arm/ti/ti_mbox.c +++ b/sys/arm/ti/ti_mbox.c @@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include "mbox_if.h" @@ -102,6 +102,7 @@ static driver_t ti_mbox_driver = { static devclass_t ti_mbox_devclass; DRIVER_MODULE(ti_mbox, simplebus, ti_mbox_driver, ti_mbox_devclass, 0, 0); +MODULE_DEPEND(ti_mbox, ti_sysc, 1, 1, 1); static __inline uint32_t ti_mbox_reg_read(struct ti_mbox_softc *sc, uint16_t reg) @@ -137,10 +138,11 @@ ti_mbox_attach(device_t dev) int rid, delay, chan; uint32_t rev, sysconfig; - if (ti_prcm_clk_enable(MAILBOX0_CLK) != 0) { + if (ti_sysc_clock_enable(device_get_parent(dev)) != 0) { device_printf(dev, "could not enable MBOX clock\n"); return (ENXIO); } + sc = device_get_softc(dev); rid = 0; mtx_init(&sc->sc_mtx, "TI mbox", NULL, MTX_DEF); @@ -188,7 +190,8 @@ ti_mbox_attach(device_t dev) */ ti_mbox_reg_write(sc, TI_MBOX_SYSCONFIG, ti_mbox_reg_read(sc, TI_MBOX_SYSCONFIG) | TI_MBOX_SYSCONFIG_SMARTIDLE); - rev = ti_mbox_reg_read(sc, TI_MBOX_REVISION); + rev = ti_mbox_reg_read(sc, + ti_sysc_get_rev_address_offset_host(device_get_parent(dev))); DPRINTF("rev %d\n", rev); device_printf(dev, "revision %d.%d\n", (rev >> 8) & 0x4, rev & 0x40); /* diff --git a/sys/arm/ti/ti_omap4_cm.c b/sys/arm/ti/ti_omap4_cm.c new file mode 100644 index 000000000000..c9545a612e1f --- /dev/null +++ b/sys/arm/ti/ti_omap4_cm.c @@ -0,0 +1,151 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Emmanuel Vadot + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Based on sys/arm/ti/ti_sysc.c + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +static struct ofw_compat_data compat_data[] = { + { "ti,omap4-cm", 1 }, + { NULL, 0 } +}; + +struct ti_omap4_cm_softc { + struct simplebus_softc sc; + device_t dev; +}; + +uint64_t +ti_omap4_cm_get_simplebus_base_host(device_t dev) { + struct ti_omap4_cm_softc *sc; + + sc = device_get_softc(dev); + if (sc->sc.nranges == 0) + return (0); + + return (sc->sc.ranges[0].host); +} + +static int ti_omap4_cm_probe(device_t dev); +static int ti_omap4_cm_attach(device_t dev); +static int ti_omap4_cm_detach(device_t dev); + +static int +ti_omap4_cm_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI OMAP4-CM"); + if (!bootverbose) + device_quiet(dev); + + return (BUS_PROBE_DEFAULT); +} + +static int +ti_omap4_cm_attach(device_t dev) +{ + struct ti_omap4_cm_softc *sc; + device_t cdev; + phandle_t node, child; + + sc = device_get_softc(dev); + sc->dev = dev; + node = ofw_bus_get_node(dev); + + simplebus_init(dev, node); + if (simplebus_fill_ranges(node, &sc->sc) < 0) { + device_printf(dev, "could not get ranges\n"); + return (ENXIO); + } + + bus_generic_probe(sc->dev); + + for (child = OF_child(node); child > 0; child = OF_peer(child)) { + cdev = simplebus_add_device(dev, child, 0, NULL, -1, NULL); + if (cdev != NULL) + device_probe_and_attach(cdev); + } + + return (bus_generic_attach(dev)); +} + +static int +ti_omap4_cm_detach(device_t dev) +{ + return (EBUSY); +} + +static device_method_t ti_omap4_cm_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_omap4_cm_probe), + DEVMETHOD(device_attach, ti_omap4_cm_attach), + DEVMETHOD(device_detach, ti_omap4_cm_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(ti_omap4_cm, ti_omap4_cm_driver, ti_omap4_cm_methods, + sizeof(struct ti_omap4_cm_softc), simplebus_driver); + +static devclass_t ti_omap4_cm_devclass; + +EARLY_DRIVER_MODULE(ti_omap4_cm, simplebus, ti_omap4_cm_driver, +ti_omap4_cm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_FIRST); + +EARLY_DRIVER_MODULE(ti_omap4_cm, ofwbus, ti_omap4_cm_driver, +ti_omap4_cm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_FIRST); + diff --git a/sys/arm/ti/ti_omap4_cm.h b/sys/arm/ti/ti_omap4_cm.h new file mode 100644 index 000000000000..4da56520cc97 --- /dev/null +++ b/sys/arm/ti/ti_omap4_cm.h @@ -0,0 +1,34 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#ifndef __TI_OMAP4_CM__ +#define __TI_OMAP4_CM__ + +uint64_t ti_omap4_cm_get_simplebus_base_host(device_t dev); + +#endif /* __TI_OMAP4_CM__ */ diff --git a/sys/arm/ti/ti_pinmux.c b/sys/arm/ti/ti_pinmux.c index b532d9124ce6..da4b8a85526c 100644 --- a/sys/arm/ti/ti_pinmux.c +++ b/sys/arm/ti/ti_pinmux.c @@ -459,3 +459,5 @@ static driver_t ti_pinmux_driver = { static devclass_t ti_pinmux_devclass; DRIVER_MODULE(ti_pinmux, simplebus, ti_pinmux_driver, ti_pinmux_devclass, 0, 0); +MODULE_VERSION(ti_pinmux, 1); +MODULE_DEPEND(ti_pinmux, ti_scm, 1, 1, 1); diff --git a/sys/arm/ti/ti_prcm.c b/sys/arm/ti/ti_prcm.c index 3b6bbabe6910..ff85e724ada4 100644 --- a/sys/arm/ti/ti_prcm.c +++ b/sys/arm/ti/ti_prcm.c @@ -1,8 +1,310 @@ /*- - * SPDX-License-Identifier: BSD-4-Clause + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2010 - * Ben Gray . + * Copyright (c) 2012 Damjan Marion + * All rights reserved. + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* Based on sys/arm/ti/am335x/am335x_prcm.c */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include "clkdev_if.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +struct ti_prcm_softc { + struct simplebus_softc sc_simplebus; + device_t dev; + struct resource * mem_res; + bus_space_tag_t bst; + bus_space_handle_t bsh; + int attach_done; + struct mtx mtx; +}; + +static struct ti_prcm_softc *ti_prcm_sc = NULL; +static void omap4_prcm_reset(void); +static void am335x_prcm_reset(void); + +#define TI_AM3_PRCM 18 +#define TI_AM4_PRCM 17 +#define TI_OMAP2_PRCM 16 +#define TI_OMAP3_PRM 15 +#define TI_OMAP3_CM 14 +#define TI_OMAP4_CM1 13 +#define TI_OMAP4_PRM 12 +#define TI_OMAP4_CM2 11 +#define TI_OMAP4_SCRM 10 +#define TI_OMAP5_PRM 9 +#define TI_OMAP5_CM_CORE_AON 8 +#define TI_OMAP5_SCRM 7 +#define TI_OMAP5_CM_CORE 6 +#define TI_DRA7_PRM 5 +#define TI_DRA7_CM_CORE_AON 4 +#define TI_DRA7_CM_CORE 3 +#define TI_DM814_PRCM 2 +#define TI_DM816_PRCM 1 +#define TI_PRCM_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,am3-prcm", TI_AM3_PRCM }, + { "ti,am4-prcm", TI_AM4_PRCM }, + { "ti,omap2-prcm", TI_OMAP2_PRCM }, + { "ti,omap3-prm", TI_OMAP3_PRM }, + { "ti,omap3-cm", TI_OMAP3_CM }, + { "ti,omap4-cm1", TI_OMAP4_CM1 }, + { "ti,omap4-prm", TI_OMAP4_PRM }, + { "ti,omap4-cm2", TI_OMAP4_CM2 }, + { "ti,omap4-scrm", TI_OMAP4_SCRM }, + { "ti,omap5-prm", TI_OMAP5_PRM }, + { "ti,omap5-cm-core-aon", TI_OMAP5_CM_CORE_AON }, + { "ti,omap5-scrm", TI_OMAP5_SCRM }, + { "ti,omap5-cm-core", TI_OMAP5_CM_CORE }, + { "ti,dra7-prm", TI_DRA7_PRM }, + { "ti,dra7-cm-core-aon", TI_DRA7_CM_CORE_AON }, + { "ti,dra7-cm-core", TI_DRA7_CM_CORE }, + { "ti,dm814-prcm", TI_DM814_PRCM }, + { "ti,dm816-prcm", TI_DM816_PRCM }, + { NULL, TI_PRCM_END} +}; + +static int +ti_prcm_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) { + return (ENXIO); + } + + device_set_desc(dev, "TI Power and Clock Management"); + return(BUS_PROBE_DEFAULT); +} + +static int +ti_prcm_attach(device_t dev) +{ + struct ti_prcm_softc *sc; + phandle_t node, child; + int rid; + + sc = device_get_softc(dev); + sc->dev = dev; + + node = ofw_bus_get_node(sc->dev); + simplebus_init(sc->dev, node); + + if (simplebus_fill_ranges(node, &sc->sc_simplebus) < 0) { + device_printf(sc->dev, "could not get ranges\n"); + return (ENXIO); + } + if (sc->sc_simplebus.nranges == 0) { + device_printf(sc->dev, "nranges == 0\n"); + return (ENXIO); + } + + sc->mem_res = bus_alloc_resource(sc->dev, SYS_RES_MEMORY, &rid, + sc->sc_simplebus.ranges[0].host, + (sc->sc_simplebus.ranges[0].host + + sc->sc_simplebus.ranges[0].size - 1), + sc->sc_simplebus.ranges[0].size, + RF_ACTIVE | RF_SHAREABLE); + + if (sc->mem_res == NULL) { + return (ENXIO); + } + + sc->bst = rman_get_bustag(sc->mem_res); + sc->bsh = rman_get_bushandle(sc->mem_res); + + mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); + + /* Fixme: for xxx_prcm_reset functions. + * Get rid of global variables? + */ + ti_prcm_sc = sc; + + switch(ti_chip()) { +#ifdef SOC_OMAP4 + case CHIP_OMAP_4: + ti_cpu_reset = omap4_prcm_reset; + break; +#endif +#ifdef SOC_TI_AM335X + case CHIP_AM335X: + ti_cpu_reset = am335x_prcm_reset; + break; +#endif + } + + bus_generic_probe(sc->dev); + for (child = OF_child(node); child != 0; child = OF_peer(child)) { + simplebus_add_device(dev, child, 0, NULL, -1, NULL); + } + + return (bus_generic_attach(sc->dev)); +} + +int +ti_prcm_write_4(device_t dev, bus_addr_t addr, uint32_t val) +{ + struct ti_prcm_softc *sc; + + sc = device_get_softc(dev); + DPRINTF(sc->dev, "offset=%lx write %x\n", addr, val); + bus_space_write_4(sc->bst, sc->bsh, addr, val); + return (0); +} +int +ti_prcm_read_4(device_t dev, bus_addr_t addr, uint32_t *val) +{ + struct ti_prcm_softc *sc; + + sc = device_get_softc(dev); + + *val = bus_space_read_4(sc->bst, sc->bsh, addr); + DPRINTF(sc->dev, "offset=%lx Read %x\n", addr, *val); + return (0); +} + +int +ti_prcm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) +{ + struct ti_prcm_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + + reg = bus_space_read_4(sc->bst, sc->bsh, addr); + reg &= ~clr; + reg |= set; + bus_space_write_4(sc->bst, sc->bsh, addr, reg); + DPRINTF(sc->dev, "offset=%lx reg: %x (clr %x set %x)\n", addr, reg, clr, set); + + return (0); +} + +void +ti_prcm_device_lock(device_t dev) +{ + struct ti_prcm_softc *sc; + + sc = device_get_softc(dev); + mtx_lock(&sc->mtx); +} + +void +ti_prcm_device_unlock(device_t dev) +{ + struct ti_prcm_softc *sc; + + sc = device_get_softc(dev); + mtx_unlock(&sc->mtx); +} + +static device_method_t ti_prcm_methods[] = { + DEVMETHOD(device_probe, ti_prcm_probe), + DEVMETHOD(device_attach, ti_prcm_attach), + + /* clkdev interface */ + DEVMETHOD(clkdev_write_4, ti_prcm_write_4), + DEVMETHOD(clkdev_read_4, ti_prcm_read_4), + DEVMETHOD(clkdev_modify_4, ti_prcm_modify_4), + DEVMETHOD(clkdev_device_lock, ti_prcm_device_lock), + DEVMETHOD(clkdev_device_unlock, ti_prcm_device_unlock), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(ti_prcm, ti_prcm_driver, ti_prcm_methods, + sizeof(struct ti_prcm_softc), simplebus_driver); + +static devclass_t ti_prcm_devclass; + +EARLY_DRIVER_MODULE(ti_prcm, ofwbus, ti_prcm_driver, + ti_prcm_devclass, 0, 0, BUS_PASS_BUS); +EARLY_DRIVER_MODULE(ti_prcm, simplebus, ti_prcm_driver, + ti_prcm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_prcm, 1); +MODULE_DEPEND(ti_prcm, ti_scm, 1, 1, 1); + + +/* From sys/arm/ti/am335x/am335x_prcm.c + * Copyright (c) 2012 Damjan Marion + */ +#define PRM_DEVICE_OFFSET 0xF00 +#define AM335x_PRM_RSTCTRL (PRM_DEVICE_OFFSET + 0x00) + +static void +am335x_prcm_reset(void) +{ + ti_prcm_write_4(ti_prcm_sc->dev, AM335x_PRM_RSTCTRL, (1<<1)); +} + +/* FIXME: Is this correct - or should the license part be ontop? */ + +/* From sys/arm/ti/omap4/omap4_prcm_clks.c */ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2011 + * Ben Gray . * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -13,10 +315,7 @@ * 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 Ben Gray. - * 4. The name of the company nor the name of the author may be used to + * 3. 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. * @@ -31,327 +330,16 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define PRM_RSTCTRL 0x1b00 +#define PRM_RSTCTRL_RESET 0x2 -/** - * Power, Reset and Clock Management Module - * - * This is a very simple driver wrapper around the PRCM set of registers in - * the OMAP3 chip. It allows you to turn on and off things like the functional - * and interface clocks to the various on-chip modules. - * - */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -/** - * ti_*_clk_devmap - Array of clock devices, should be defined one per SoC - * - * This array is typically defined in one of the targeted *_prcm_clk.c - * files and is specific to the given SoC platform. Each entry in the array - * corresponds to an individual clock device. - */ -extern struct ti_clock_dev ti_omap4_clk_devmap[]; -extern struct ti_clock_dev ti_am335x_clk_devmap[]; - -/** - * ti_prcm_clk_dev - returns a pointer to the clock device with given id - * @clk: the ID of the clock device to get - * - * Simply iterates through the clk_devmap global array and returns a pointer - * to the clock device if found. - * - * LOCKING: - * None - * - * RETURNS: - * The pointer to the clock device on success, on failure NULL is returned. - */ -static struct ti_clock_dev * -ti_prcm_clk_dev(clk_ident_t clk) +static void +omap4_prcm_reset(void) { - struct ti_clock_dev *clk_dev; - - /* Find the clock within the devmap - it's a bit inefficent having a for - * loop for this, but this function should only called when a driver is - * being activated so IMHO not a big issue. - */ - clk_dev = NULL; - switch(ti_chip()) { -#ifdef SOC_OMAP4 - case CHIP_OMAP_4: - clk_dev = &(ti_omap4_clk_devmap[0]); - break; -#endif -#ifdef SOC_TI_AM335X - case CHIP_AM335X: - clk_dev = &(ti_am335x_clk_devmap[0]); - break; -#endif - } - if (clk_dev == NULL) - panic("No clock devmap found"); - while (clk_dev->id != INVALID_CLK_IDENT) { - if (clk_dev->id == clk) { - return (clk_dev); - } - clk_dev++; - } + uint32_t reg; - /* Sanity check we managed to find the clock */ - printf("ti_prcm: Failed to find clock device (%d)\n", clk); - return (NULL); -} - -/** - * ti_prcm_clk_valid - enables a clock for a particular module - * @clk: identifier for the module to enable, see ti_prcm.h for a list - * of possible modules. - * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. - * - * This function can enable either a functional or interface clock. - * - * The real work done to enable the clock is really done in the callback - * function associated with the clock, this function is simply a wrapper - * around that. - * - * LOCKING: - * Internally locks the driver context. - * - * RETURNS: - * Returns 0 on success or positive error code on failure. - */ -int -ti_prcm_clk_valid(clk_ident_t clk) -{ - int ret = 0; - - if (ti_prcm_clk_dev(clk) == NULL) - ret = EINVAL; - - return (ret); -} - - -/** - * ti_prcm_clk_enable - enables a clock for a particular module - * @clk: identifier for the module to enable, see ti_prcm.h for a list - * of possible modules. - * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. - * - * This function can enable either a functional or interface clock. - * - * The real work done to enable the clock is really done in the callback - * function associated with the clock, this function is simply a wrapper - * around that. - * - * LOCKING: - * Internally locks the driver context. - * - * RETURNS: - * Returns 0 on success or positive error code on failure. - */ -int -ti_prcm_clk_enable(clk_ident_t clk) -{ - struct ti_clock_dev *clk_dev; - int ret; - - /* Find the clock within the devmap - it's a bit inefficent having a for - * loop for this, but this function should only called when a driver is - * being activated so IMHO not a big issue. - */ - clk_dev = ti_prcm_clk_dev(clk); - - /* Sanity check we managed to find the clock */ - if (clk_dev == NULL) - return (EINVAL); - - /* Activate the clock */ - if (clk_dev->clk_activate) - ret = clk_dev->clk_activate(clk_dev); - else - ret = EINVAL; - - return (ret); -} - - -/** - * ti_prcm_clk_disable - disables a clock for a particular module - * @clk: identifier for the module to enable, see ti_prcm.h for a list - * of possible modules. - * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. - * - * This function can enable either a functional or interface clock. - * - * The real work done to enable the clock is really done in the callback - * function associated with the clock, this function is simply a wrapper - * around that. - * - * LOCKING: - * Internally locks the driver context. - * - * RETURNS: - * Returns 0 on success or positive error code on failure. - */ -int -ti_prcm_clk_disable(clk_ident_t clk) -{ - struct ti_clock_dev *clk_dev; - int ret; - - /* Find the clock within the devmap - it's a bit inefficent having a for - * loop for this, but this function should only called when a driver is - * being activated so IMHO not a big issue. - */ - clk_dev = ti_prcm_clk_dev(clk); - - /* Sanity check we managed to find the clock */ - if (clk_dev == NULL) - return (EINVAL); - - /* Activate the clock */ - if (clk_dev->clk_deactivate) - ret = clk_dev->clk_deactivate(clk_dev); - else - ret = EINVAL; - - return (ret); -} - -/** - * ti_prcm_clk_set_source - sets the source - * @clk: identifier for the module to enable, see ti_prcm.h for a list - * of possible modules. - * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. - * - * This function can enable either a functional or interface clock. - * - * The real work done to enable the clock is really done in the callback - * function associated with the clock, this function is simply a wrapper - * around that. - * - * LOCKING: - * Internally locks the driver context. - * - * RETURNS: - * Returns 0 on success or positive error code on failure. - */ -int -ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc) -{ - struct ti_clock_dev *clk_dev; - int ret; - - /* Find the clock within the devmap - it's a bit inefficent having a for - * loop for this, but this function should only called when a driver is - * being activated so IMHO not a big issue. - */ - clk_dev = ti_prcm_clk_dev(clk); - - /* Sanity check we managed to find the clock */ - if (clk_dev == NULL) - return (EINVAL); - - /* Activate the clock */ - if (clk_dev->clk_set_source) - ret = clk_dev->clk_set_source(clk_dev, clksrc); - else - ret = EINVAL; - - return (ret); -} - - -/** - * ti_prcm_clk_get_source_freq - gets the source clock frequency - * @clk: identifier for the module to enable, see ti_prcm.h for a list - * of possible modules. - * @freq: pointer to an integer that upon return will contain the src freq - * - * This function returns the frequency of the source clock. - * - * The real work done to enable the clock is really done in the callback - * function associated with the clock, this function is simply a wrapper - * around that. - * - * LOCKING: - * Internally locks the driver context. - * - * RETURNS: - * Returns 0 on success or positive error code on failure. - */ -int -ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq) -{ - struct ti_clock_dev *clk_dev; - int ret; - - /* Find the clock within the devmap - it's a bit inefficent having a for - * loop for this, but this function should only called when a driver is - * being activated so IMHO not a big issue. - */ - clk_dev = ti_prcm_clk_dev(clk); - - /* Sanity check we managed to find the clock */ - if (clk_dev == NULL) - return (EINVAL); - - /* Get the source frequency of the clock */ - if (clk_dev->clk_get_source_freq) - ret = clk_dev->clk_get_source_freq(clk_dev, freq); - else - ret = EINVAL; - - return (ret); -} - -/** - * ti_prcm_clk_set_source_freq - sets the source clock frequency as close to freq as possible - * @clk: identifier for the module to enable, see ti_prcm.h for a list - * of possible modules. - * @freq: requested freq - * - * LOCKING: - * Internally locks the driver context. - * - * RETURNS: - * Returns 0 on success or positive error code on failure. - */ -int -ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq) -{ - struct ti_clock_dev *clk_dev; - int ret; - - clk_dev = ti_prcm_clk_dev(clk); - - /* Sanity check we managed to find the clock */ - if (clk_dev == NULL) - return (EINVAL); - - /* Get the source frequency of the clock */ - if (clk_dev->clk_set_source_freq) - ret = clk_dev->clk_set_source_freq(clk_dev, freq); - else - ret = EINVAL; - - return (ret); + ti_prcm_read_4(ti_prcm_sc->dev, PRM_RSTCTRL, ®); + reg = reg | PRM_RSTCTRL_RESET; + ti_prcm_write_4(ti_prcm_sc->dev, PRM_RSTCTRL, reg); + ti_prcm_read_4(ti_prcm_sc->dev, PRM_RSTCTRL, ®); } diff --git a/sys/arm/ti/ti_prcm.h b/sys/arm/ti/ti_prcm.h index 6df39436cb2f..98f8abc15dd7 100644 --- a/sys/arm/ti/ti_prcm.h +++ b/sys/arm/ti/ti_prcm.h @@ -1,9 +1,7 @@ /*- - * SPDX-License-Identifier: BSD-4-Clause + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2010 - * Ben Gray . - * All rights reserved. + * Copyright (c) 2020 Oskar Holmlund * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -13,197 +11,29 @@ * 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 Ben Gray. - * 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 BEN GRAY ``AS IS'' AND ANY EXPRESS OR + * 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 BEN GRAY 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. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. * * $FreeBSD$ */ +#ifndef __TI_PRCM_H__ +#define __TI_PRCM_H__ -/* - * Texas Instruments - OMAP3xxx series processors - * - * Reference: - * OMAP35x Applications Processor - * Technical Reference Manual - * (omap35xx_techref.pdf) - */ -#ifndef _TI_PRCM_H_ -#define _TI_PRCM_H_ +int ti_prcm_write_4(device_t dev, bus_addr_t addr, uint32_t val); +int ti_prcm_read_4(device_t dev, bus_addr_t addr, uint32_t *val); +int ti_prcm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set); +void ti_prcm_device_lock(device_t dev); +void ti_prcm_device_unlock(device_t dev); -typedef enum { - - INVALID_CLK_IDENT = 0, - - /* System clocks, typically you can only call ti_prcm_clk_get_source_freq() - * on these clocks as they are enabled by default. - */ - SYS_CLK = 1, - - /* The MPU (ARM) core clock */ - MPU_CLK = 20, - - /* MMC modules */ - MMC1_CLK = 100, - MMC2_CLK, - MMC3_CLK, - MMC4_CLK, - MMC5_CLK, - MMC6_CLK, - - /* I2C modules */ - I2C1_CLK = 200, - I2C2_CLK, - I2C3_CLK, - I2C4_CLK, - I2C5_CLK, - - /* USB module(s) */ - USBTLL_CLK = 300, - USBHSHOST_CLK, - USBFSHOST_CLK, - USBP1_PHY_CLK, - USBP2_PHY_CLK, - USBP1_UTMI_CLK, - USBP2_UTMI_CLK, - USBP1_HSIC_CLK, - USBP2_HSIC_CLK, - - /* UART modules */ - UART1_CLK = 400, - UART2_CLK, - UART3_CLK, - UART4_CLK, - UART5_CLK, - UART6_CLK, - UART7_CLK, - UART8_CLK, - UART9_CLK, - - /* General purpose timer modules */ - TIMER1_CLK = 500, - TIMER2_CLK, - TIMER3_CLK, - TIMER4_CLK, - TIMER5_CLK, - TIMER6_CLK, - TIMER7_CLK, - TIMER8_CLK, - TIMER9_CLK, - TIMER10_CLK, - TIMER11_CLK, - TIMER12_CLK, - - /* McBSP module(s) */ - MCBSP1_CLK = 600, - MCBSP2_CLK, - MCBSP3_CLK, - MCBSP4_CLK, - MCBSP5_CLK, - - /* General purpose I/O modules */ - GPIO1_CLK = 700, - GPIO2_CLK, - GPIO3_CLK, - GPIO4_CLK, - GPIO5_CLK, - GPIO6_CLK, - GPIO7_CLK, - - /* sDMA module */ - SDMA_CLK = 800, - - /* CPSW modules */ - CPSW_CLK = 1000, - - /* Mentor USB modules */ - MUSB0_CLK = 1100, - - /* EDMA module */ - EDMA_TPCC_CLK = 1200, - EDMA_TPTC0_CLK, - EDMA_TPTC1_CLK, - EDMA_TPTC2_CLK, - - /* LCD controller module */ - LCDC_CLK = 1300, - - /* PWM modules */ - PWMSS0_CLK = 1400, - PWMSS1_CLK, - PWMSS2_CLK, - - /* Mailbox modules */ - MAILBOX0_CLK = 1500, - - /* Spinlock modules */ - SPINLOCK0_CLK = 1600, - - PRUSS_CLK = 1700, - - TSC_ADC_CLK = 1800, - - /* RTC module */ - RTC_CLK = 1900, - - /* McSPI */ - SPI0_CLK = 2000, - SPI1_CLK, -} clk_ident_t; - -/* - * - */ -typedef enum { - SYSCLK_CLK, /* System clock */ - EXT_CLK, - - F32KHZ_CLK, /* 32KHz clock */ - F48MHZ_CLK, /* 48MHz clock */ - F64MHZ_CLK, /* 64MHz clock */ - F96MHZ_CLK, /* 96MHz clock */ - -} clk_src_t; - -struct ti_clock_dev { - /* The profile of the timer */ - clk_ident_t id; - - /* A bunch of callbacks associated with the clock device */ - int (*clk_activate)(struct ti_clock_dev *clkdev); - int (*clk_deactivate)(struct ti_clock_dev *clkdev); - int (*clk_set_source)(struct ti_clock_dev *clkdev, - clk_src_t clksrc); - int (*clk_accessible)(struct ti_clock_dev *clkdev); - int (*clk_set_source_freq)(struct ti_clock_dev *clkdev, - unsigned int freq); - int (*clk_get_source_freq)(struct ti_clock_dev *clkdev, - unsigned int *freq); -}; - -int ti_prcm_clk_valid(clk_ident_t clk); -int ti_prcm_clk_enable(clk_ident_t clk); -int ti_prcm_clk_disable(clk_ident_t clk); -int ti_prcm_clk_accessible(clk_ident_t clk); -int ti_prcm_clk_disable_autoidle(clk_ident_t clk); -int ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc); -int ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq); -int ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq); -void ti_prcm_reset(void); - -#endif /* _TI_PRCM_H_ */ +#endif diff --git a/sys/arm/ti/ti_prm.c b/sys/arm/ti/ti_prm.c new file mode 100644 index 000000000000..4a57fbb8b972 --- /dev/null +++ b/sys/arm/ti/ti_prm.c @@ -0,0 +1,210 @@ +/*- + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +/* + * Power management - simple driver to handle reset and give access to + * memory space region for other drivers through prcm driver. + * Documentation/devicetree/binding/arm/omap/prm-inst.txt + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* relative to prcm address range */ +#define TI_PRM_PER_RSTCTRL 0xC00 + +struct ti_prm_softc { + device_t dev; + uint8_t type; + bool has_reset; +}; + +/* Device */ +#define TI_OMAP_PRM_INST 10 + +#define TI_AM3_PRM_INST 5 +#define TI_AM4_PRM_INST 4 +#define TI_OMAP4_PRM_INST 3 +#define TI_OMAP5_PRM_INST 2 +#define TI_DRA7_PRM_INST 1 +#define TI_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,am3-prm-inst", TI_AM3_PRM_INST }, + { "ti,am4-prm-inst", TI_AM4_PRM_INST }, + { "ti,omap4-prm-inst", TI_OMAP4_PRM_INST }, + { "ti,omap5-prm-inst", TI_OMAP5_PRM_INST }, + { "ti,dra7-prm-inst", TI_DRA7_PRM_INST }, + { NULL, TI_END } +}; + +static struct ofw_compat_data required_data[] = { + { "ti,omap-prm-inst", TI_OMAP_PRM_INST }, + { NULL, TI_END } +}; + +/* device interface */ +static int +ti_prm_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, required_data)->ocd_data == 0) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI OMAP Power Management"); + return(BUS_PROBE_DEFAULT); +} + +static int +ti_prm_attach(device_t dev) +{ + struct ti_prm_softc *sc; + phandle_t node; + + sc = device_get_softc(dev); + sc->dev = dev; + sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; + + node = ofw_bus_get_node(sc->dev); + + if (OF_hasprop(node, "#reset-cells")) { + sc->has_reset = true; + } else + sc->has_reset = false; + + /* Make device visible for other drivers */ + OF_device_register_xref(OF_xref_from_node(node), sc->dev); + + return (0); +} + +static int +ti_prm_detach(device_t dev) { + return (EBUSY); +} + +int +ti_prm_reset(device_t dev) +{ + struct ti_prm_softc *sc; + int err; + + sc = device_get_softc(dev); + if (sc->has_reset == false) + return 1; + + err = ti_prm_modify_4(dev, TI_PRM_PER_RSTCTRL, 0x2, 0x00); + return (err); +} + +int +ti_prm_write_4(device_t dev, bus_addr_t addr, uint32_t val) +{ + struct ti_prm_softc *sc; + device_t parent; + + parent = device_get_parent(dev); + sc = device_get_softc(dev); + DPRINTF(sc->dev, "offset=%lx write %x\n", addr, val); + ti_prcm_device_lock(parent); + ti_prcm_write_4(parent, addr, val); + ti_prcm_device_unlock(parent); + return (0); +} + +int +ti_prm_read_4(device_t dev, bus_addr_t addr, uint32_t *val) +{ + struct ti_prm_softc *sc; + device_t parent; + + parent = device_get_parent(dev); + sc = device_get_softc(dev); + + ti_prcm_device_lock(parent); + ti_prcm_read_4(parent, addr, val); + ti_prcm_device_unlock(parent); + DPRINTF(sc->dev, "offset=%lx Read %x\n", addr, *val); + return (0); +} + +int +ti_prm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) +{ + struct ti_prm_softc *sc; + device_t parent; + + parent = device_get_parent(dev); + sc = device_get_softc(dev); + + ti_prcm_device_lock(parent); + ti_prcm_modify_4(parent, addr, clr, set); + ti_prcm_device_unlock(parent); + DPRINTF(sc->dev, "offset=%lx (clr %x set %x)\n", addr, clr, set); + + return (0); +} + +static device_method_t ti_prm_methods[] = { + DEVMETHOD(device_probe, ti_prm_probe), + DEVMETHOD(device_attach, ti_prm_attach), + DEVMETHOD(device_detach, ti_prm_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(ti_prm, ti_prm_driver, ti_prm_methods, + sizeof(struct ti_prm_softc), simplebus_driver); + +static devclass_t ti_prm_devclass; + +EARLY_DRIVER_MODULE(ti_prm, simplebus, ti_prm_driver, + ti_prm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_prm, 1); +MODULE_DEPEND(ti_prm, ti_sysc, 1, 1, 1); diff --git a/sys/arm/ti/ti_prm.h b/sys/arm/ti/ti_prm.h new file mode 100644 index 000000000000..bc3e991088f0 --- /dev/null +++ b/sys/arm/ti/ti_prm.h @@ -0,0 +1,38 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#ifndef __TI_PRM__ +#define __TI_PRM__ + +int ti_prm_reset(device_t dev); + +int ti_prm_write_4(device_t dev, bus_addr_t addr, uint32_t val); +int ti_prm_read_4(device_t dev, bus_addr_t addr, uint32_t *val); +int ti_prm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set); + +#endif /* __TI_PRM__ */ diff --git a/sys/arm/ti/ti_pruss.c b/sys/arm/ti/ti_pruss.c index 48c6b17f3ac8..a8dc15ab80b0 100644 --- a/sys/arm/ti/ti_pruss.c +++ b/sys/arm/ti/ti_pruss.c @@ -57,8 +57,11 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include + +#include #include +#include #ifdef DEBUG #define DPRINTF(fmt, ...) do { \ @@ -161,7 +164,8 @@ static driver_t ti_pruss_driver = { static devclass_t ti_pruss_devclass; DRIVER_MODULE(ti_pruss, simplebus, ti_pruss_driver, ti_pruss_devclass, 0, 0); -MODULE_DEPEND(ti_pruss, ti_prcm, 1, 1, 1); +MODULE_DEPEND(ti_pruss, ti_sysc, 1, 1, 1); +MODULE_DEPEND(ti_pruss, ti_prm, 1, 1, 1); static struct resource_spec ti_pruss_irq_spec[] = { { SYS_RES_IRQ, 0, RF_ACTIVE }, @@ -515,14 +519,89 @@ static int ti_pruss_attach(device_t dev) { struct ti_pruss_softc *sc; - int rid, i; + int rid, i, err, ncells; + uint32_t reg; + phandle_t node; + clk_t l3_gclk, pruss_ocp_gclk; + phandle_t ti_prm_ref, *cells; + device_t ti_prm_dev; - if (ti_prcm_clk_enable(PRUSS_CLK) != 0) { - device_printf(dev, "could not enable PRUSS clock\n"); + rid = 0; + sc = device_get_softc(dev); + node = ofw_bus_get_node(device_get_parent(dev)); + if (node <= 0) { + device_printf(dev, "Cant get ofw node\n"); return (ENXIO); } - sc = device_get_softc(dev); - rid = 0; + + /* + * Follow activate pattern from sys/arm/ti/am335x/am335x_prcm.c + * by Damjan Marion + */ + + /* Set MODULEMODE to ENABLE(2) */ + /* Wait for MODULEMODE to become ENABLE(2) */ + if (ti_sysc_clock_enable(device_get_parent(dev)) != 0) { + device_printf(dev, "Could not enable PRUSS clock\n"); + return (ENXIO); + } + + /* Set CLKTRCTRL to SW_WKUP(2) */ + /* Wait for the 200 MHz OCP clock to become active */ + /* Wait for the 200 MHz IEP clock to become active */ + /* Wait for the 192 MHz UART clock to become active */ + /* + * At the moment there is no reference to CM_PER_PRU_ICSS_CLKSTCTRL@140 + * in the devicetree. The register reset state are SW_WKUP(2) as default + * so at the moment ignore setting this register. + */ + + /* Select L3F as OCP clock */ + /* Get the clock and set the parent */ + err = clk_get_by_name(dev, "l3_gclk", &l3_gclk); + if (err) { + device_printf(dev, "Cant get l3_gclk err %d\n", err); + return (ENXIO); + } + + err = clk_get_by_name(dev, "pruss_ocp_gclk@530", &pruss_ocp_gclk); + if (err) { + device_printf(dev, "Cant get pruss_ocp_gclk@530 err %d\n", err); + return (ENXIO); + } + + err = clk_set_parent_by_clk(pruss_ocp_gclk, l3_gclk); + if (err) { + device_printf(dev, + "Cant set pruss_ocp_gclk parent to l3_gclk err %d\n", err); + return (ENXIO); + } + + /* Clear the RESET bit */ + /* Find the ti_prm */ + /* #reset-cells should not been used in this way but... */ + err = ofw_bus_parse_xref_list_alloc(node, "resets", "#reset-cells", 0, + &ti_prm_ref, &ncells, &cells); + OF_prop_free(cells); + if (err) { + device_printf(dev, + "Cant fetch \"resets\" reference %x\n", err); + return (ENXIO); + } + + ti_prm_dev = OF_device_from_xref(ti_prm_ref); + if (ti_prm_dev == NULL) { + device_printf(dev, "Cant get device from \"resets\"\n"); + return (ENXIO); + } + + err = ti_prm_reset(ti_prm_dev); + if (err) { + device_printf(dev, "ti_prm_reset failed %d\n", err); + return (ENXIO); + } + /* End of clock activation */ + mtx_init(&sc->sc_mtx, "TI PRUSS", NULL, MTX_DEF); sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); @@ -602,6 +681,9 @@ ti_pruss_attach(device_t dev) } } + reg = ti_pruss_reg_read(sc, + ti_sysc_get_sysc_address_offset_host(device_get_parent(dev))); + if (ti_pruss_reg_read(sc, PRUSS_AM33XX_INTC) == PRUSS_AM33XX_REV) device_printf(dev, "AM33xx PRU-ICSS\n"); diff --git a/sys/arm/ti/ti_scm.c b/sys/arm/ti/ti_scm.c index fbc87eeb4f92..896a8d09cbf3 100644 --- a/sys/arm/ti/ti_scm.c +++ b/sys/arm/ti/ti_scm.c @@ -1,9 +1,7 @@ /*- - * SPDX-License-Identifier: BSD-4-Clause + * Copyright (c) 2019 Emmanuel Vadot * - * Copyright (c) 2010 - * Ben Gray . - * All rights reserved. + * Copyright (c) 2020 Oskar Holmlund * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -13,169 +11,152 @@ * 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 Ben Gray. - * 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 BEN GRAY ``AS IS'' AND ANY EXPRESS OR + * 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 BEN GRAY 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. + * 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$ */ -/** - * SCM - System Control Module - * - * Hopefully in the end this module will contain a bunch of utility functions - * for configuring and querying the general system control registers, but for - * now it only does pin(pad) multiplexing. - * - * This is different from the GPIO module in that it is used to configure the - * pins between modules not just GPIO input/output. - * - * This file contains the generic top level driver, however it relies on chip - * specific settings and therefore expects an array of ti_scm_padconf structs - * call ti_padconf_devmap to be located somewhere in the kernel. - * - */ #include __FBSDID("$FreeBSD$"); + +/* Based on sys/arm/ti/ti_sysc.c */ + #include #include +#include +#include #include #include -#include -#include #include -#include -#include - +#include #include -#include +#include +#include +#include +#include + +#include -#include #include #include -#include -#include "ti_scm.h" -#include "ti_cpuid.h" +#define TI_AM3_SCM 14 +#define TI_AM4_SCM 13 +#define TI_DM814_SCRM 12 +#define TI_DM816_SCRM 11 +#define TI_OMAP2_SCM 10 +#define TI_OMAP3_SCM 9 +#define TI_OMAP4_SCM_CORE 8 +#define TI_OMAP4_SCM_PADCONF_CORE 7 +#define TI_OMAP4_SCM_WKUP 6 +#define TI_OMAP4_SCM_PADCONF_WKUP 5 +#define TI_OMAP5_SCM_CORE 4 +#define TI_OMAP5_SCM_PADCONF_CORE 3 +#define TI_OMAP5_SCM_WKUP_PAD_CONF 2 +#define TI_DRA7_SCM_CORE 1 +#define TI_SCM_END 0 -static struct resource_spec ti_scm_res_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Control memory window */ - { -1, 0 } +static struct ofw_compat_data compat_data[] = { + { "ti,am3-scm", TI_AM3_SCM }, + { "ti,am4-scm", TI_AM4_SCM }, + { "ti,dm814-scrm", TI_DM814_SCRM }, + { "ti,dm816-scrm", TI_DM816_SCRM }, + { "ti,omap2-scm", TI_OMAP2_SCM }, + { "ti,omap3-scm", TI_OMAP3_SCM }, + { "ti,omap4-scm-core", TI_OMAP4_SCM_CORE }, + { "ti,omap4-scm-padconf-core", TI_OMAP4_SCM_PADCONF_CORE }, + { "ti,omap4-scm-wkup", TI_OMAP4_SCM_WKUP }, + { "ti,omap4-scm-padconf-wkup", TI_OMAP4_SCM_PADCONF_WKUP }, + { "ti,omap5-scm-core", TI_OMAP5_SCM_CORE }, + { "ti,omap5-scm-padconf-core", TI_OMAP5_SCM_PADCONF_CORE }, + { "ti,omap5-scm-wkup-pad-conf", TI_OMAP5_SCM_WKUP_PAD_CONF }, + { "ti,dra7-scm-core", TI_DRA7_SCM_CORE }, + { NULL, TI_SCM_END } }; -static struct ti_scm_softc *ti_scm_sc; +struct ti_scm_softc { + struct simplebus_softc sc; + device_t dev; +}; -#define ti_scm_read_4(sc, reg) \ - bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) -#define ti_scm_write_4(sc, reg, val) \ - bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) +static int ti_scm_probe(device_t dev); +static int ti_scm_attach(device_t dev); +static int ti_scm_detach(device_t dev); -/* - * Device part of OMAP SCM driver - */ static int ti_scm_probe(device_t dev) { - - if (!ti_soc_is_supported()) - return (ENXIO); - if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "syscon")) + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); - if (ti_scm_sc) { - return (EEXIST); - } + device_set_desc(dev, "TI OMAP Control Module"); - device_set_desc(dev, "TI Control Module"); return (BUS_PROBE_DEFAULT); } -/** - * ti_scm_attach - attaches the timer to the simplebus - * @dev: new device - * - * Reserves memory and interrupt resources, stores the softc structure - * globally and registers both the timecount and eventtimer objects. - * - * RETURNS - * Zero on success or ENXIO if an error occuried. - */ static int ti_scm_attach(device_t dev) { - struct ti_scm_softc *sc = device_get_softc(dev); + struct ti_scm_softc *sc; + device_t cdev; + phandle_t node, child; - sc->sc_dev = dev; + sc = device_get_softc(dev); + sc->dev = dev; + node = ofw_bus_get_node(dev); - if (bus_alloc_resources(dev, ti_scm_res_spec, sc->sc_res)) { - device_printf(dev, "could not allocate resources\n"); + simplebus_init(dev, node); + if (simplebus_fill_ranges(node, &sc->sc) < 0) { + device_printf(dev, "could not get ranges\n"); return (ENXIO); } - /* Global timer interface */ - sc->sc_bst = rman_get_bustag(sc->sc_res[0]); - sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); - - ti_scm_sc = sc; - - /* Attach platform extensions, if any. */ - bus_generic_probe(dev); + for (child = OF_child(node); child > 0; child = OF_peer(child)) { + cdev = simplebus_add_device(dev, child, 0, NULL, -1, NULL); + if (cdev != NULL) + device_probe_and_attach(cdev); + } return (bus_generic_attach(dev)); } -int -ti_scm_reg_read_4(uint32_t reg, uint32_t *val) +static int +ti_scm_detach(device_t dev) { - if (!ti_scm_sc) - return (ENXIO); - - *val = ti_scm_read_4(ti_scm_sc, reg); - return (0); + return (EBUSY); } -int -ti_scm_reg_write_4(uint32_t reg, uint32_t val) -{ - if (!ti_scm_sc) - return (ENXIO); - - ti_scm_write_4(ti_scm_sc, reg, val); - return (0); -} - - static device_method_t ti_scm_methods[] = { + /* Device interface */ DEVMETHOD(device_probe, ti_scm_probe), DEVMETHOD(device_attach, ti_scm_attach), + DEVMETHOD(device_detach, ti_scm_detach), - { 0, 0 } + DEVMETHOD_END }; -static driver_t ti_scm_driver = { - "ti_scm", - ti_scm_methods, - sizeof(struct ti_scm_softc), -}; +DEFINE_CLASS_1(ti_scm, ti_scm_driver, ti_scm_methods, + sizeof(struct ti_scm_softc), simplebus_driver); static devclass_t ti_scm_devclass; -EARLY_DRIVER_MODULE(ti_scm, simplebus, ti_scm_driver, ti_scm_devclass, 0, 0, - BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +EARLY_DRIVER_MODULE(ti_scm, simplebus, ti_scm_driver, + ti_scm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_FIRST); +MODULE_VERSION(ti_scm, 1); +MODULE_DEPEND(ti_scm, ti_sysc, 1, 1, 1); + diff --git a/sys/arm/ti/ti_scm_syscon.c b/sys/arm/ti/ti_scm_syscon.c new file mode 100644 index 000000000000..2c3fa9345210 --- /dev/null +++ b/sys/arm/ti/ti_scm_syscon.c @@ -0,0 +1,294 @@ +/*- + * Copyright (c) 2019 Emmanuel Vadot + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +/* Based on sys/arm/ti/ti_sysc.c */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include "syscon_if.h" +#include +#include "clkdev_if.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +MALLOC_DECLARE(M_SYSCON); + +struct ti_scm_syscon_softc { + struct simplebus_softc sc_simplebus; + device_t dev; + struct syscon * syscon; + struct resource * res[1]; + bus_space_tag_t bst; + bus_space_handle_t bsh; + struct mtx mtx; +}; + +static struct resource_spec ti_scm_syscon_res_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_SHAREABLE }, + { -1, 0 } +}; + +/* Device */ +static struct ofw_compat_data compat_data[] = { + { "syscon", 1 }, + { NULL, 0 } +}; + +/* --- dev/extres/syscon syscon_method_t interface --- */ +static int +ti_scm_syscon_write_4(struct syscon *syscon, bus_size_t offset, uint32_t val) +{ + struct ti_scm_syscon_softc *sc; + + sc = device_get_softc(syscon->pdev); + DPRINTF(sc->dev, "offset=%lx write %x\n", offset, val); + mtx_lock(&sc->mtx); + bus_space_write_4(sc->bst, sc->bsh, offset, val); + mtx_unlock(&sc->mtx); + return (0); +} + +static uint32_t +ti_scm_syscon_read_4(struct syscon *syscon, bus_size_t offset) +{ + struct ti_scm_syscon_softc *sc; + uint32_t val; + + sc = device_get_softc(syscon->pdev); + + mtx_lock(&sc->mtx); + val = bus_space_read_4(sc->bst, sc->bsh, offset); + mtx_unlock(&sc->mtx); + DPRINTF(sc->dev, "offset=%lx Read %x\n", offset, val); + return (val); +} +static int +ti_scm_syscon_modify_4(struct syscon *syscon, bus_size_t offset, uint32_t clr, uint32_t set) +{ + struct ti_scm_syscon_softc *sc; + uint32_t reg; + + sc = device_get_softc(syscon->pdev); + + mtx_lock(&sc->mtx); + reg = bus_space_read_4(sc->bst, sc->bsh, offset); + reg &= ~clr; + reg |= set; + bus_space_write_4(sc->bst, sc->bsh, offset, reg); + mtx_unlock(&sc->mtx); + DPRINTF(sc->dev, "offset=%lx reg: %x (clr %x set %x)\n", offset, reg, clr, set); + + return (0); +} + +static syscon_method_t ti_scm_syscon_reg_methods[] = { + SYSCONMETHOD(syscon_read_4, ti_scm_syscon_read_4), + SYSCONMETHOD(syscon_write_4, ti_scm_syscon_write_4), + SYSCONMETHOD(syscon_modify_4, ti_scm_syscon_modify_4), + + SYSCONMETHOD_END +}; + +DEFINE_CLASS_1(ti_scm_syscon_reg, ti_scm_syscon_reg_class, ti_scm_syscon_reg_methods, + 0, syscon_class); + +/* device interface */ +static int +ti_scm_syscon_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI OMAP Control Module Syscon"); + return(BUS_PROBE_DEFAULT); +} + +static int +ti_scm_syscon_attach(device_t dev) +{ + struct ti_scm_syscon_softc *sc; + phandle_t node, child; + int err; + + sc = device_get_softc(dev); + sc->dev = dev; + + if (bus_alloc_resources(dev, ti_scm_syscon_res_spec, sc->res)) { + device_printf(sc->dev, "Cant allocate resources\n"); + return (ENXIO); + } + + sc->dev = dev; + sc->bst = rman_get_bustag(sc->res[0]); + sc->bsh = rman_get_bushandle(sc->res[0]); + + mtx_init(&sc->mtx, device_get_nameunit(sc->dev), NULL, MTX_DEF); + node = ofw_bus_get_node(sc->dev); + + /* dev/extres/syscon interface */ + sc->syscon = syscon_create_ofw_node(dev, &ti_scm_syscon_reg_class, node); + if (sc->syscon == NULL) { + device_printf(dev, "Failed to create/register syscon\n"); + return (ENXIO); + } + + simplebus_init(sc->dev, node); + + err = bus_generic_probe(sc->dev); + for (child = OF_child(node); child != 0; child = OF_peer(child)) { + simplebus_add_device(sc->dev, child, 0, NULL, -1, NULL); + } + + return (bus_generic_attach(sc->dev)); +} + +/* syscon interface */ +static int +ti_scm_syscon_get_handle(device_t dev, struct syscon **syscon) +{ + struct ti_scm_syscon_softc *sc; + + sc = device_get_softc(dev); + *syscon = sc->syscon; + if (*syscon == NULL) + return (ENODEV); + return (0); +} + +/* clkdev interface */ +static int +ti_scm_syscon_clk_write_4(device_t dev, bus_addr_t addr, uint32_t val) +{ + struct ti_scm_syscon_softc *sc; + + sc = device_get_softc(dev); + DPRINTF(sc->dev, "offset=%lx write %x\n", addr, val); + bus_space_write_4(sc->bst, sc->bsh, addr, val); + return (0); +} + +static int +ti_scm_syscon_clk_read_4(device_t dev, bus_addr_t addr, uint32_t *val) +{ + struct ti_scm_syscon_softc *sc; + + sc = device_get_softc(dev); + + *val = bus_space_read_4(sc->bst, sc->bsh, addr); + DPRINTF(sc->dev, "offset=%lx Read %x\n", addr, *val); + return (0); +} + +static int +ti_scm_syscon_clk_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) +{ + struct ti_scm_syscon_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + + reg = bus_space_read_4(sc->bst, sc->bsh, addr); + reg &= ~clr; + reg |= set; + bus_space_write_4(sc->bst, sc->bsh, addr, reg); + DPRINTF(sc->dev, "offset=%lx reg: %x (clr %x set %x)\n", addr, reg, clr, set); + + return (0); +} + +static void +ti_scm_syscon_clk_device_lock(device_t dev) +{ + struct ti_scm_syscon_softc *sc; + + sc = device_get_softc(dev); + mtx_lock(&sc->mtx); +} + +static void +ti_scm_syscon_clk_device_unlock(device_t dev) +{ + struct ti_scm_syscon_softc *sc; + sc = device_get_softc(dev); + mtx_unlock(&sc->mtx); +} + +static device_method_t ti_scm_syscon_methods[] = { + DEVMETHOD(device_probe, ti_scm_syscon_probe), + DEVMETHOD(device_attach, ti_scm_syscon_attach), + + /* syscon interface */ + DEVMETHOD(syscon_get_handle, ti_scm_syscon_get_handle), + + /* clkdev interface */ + DEVMETHOD(clkdev_write_4, ti_scm_syscon_clk_write_4), + DEVMETHOD(clkdev_read_4, ti_scm_syscon_clk_read_4), + DEVMETHOD(clkdev_modify_4, ti_scm_syscon_clk_modify_4), + DEVMETHOD(clkdev_device_lock, ti_scm_syscon_clk_device_lock), + DEVMETHOD(clkdev_device_unlock, ti_scm_syscon_clk_device_unlock), + + DEVMETHOD_END +}; + + +DEFINE_CLASS_1(ti_scm_syscon, ti_scm_syscon_driver, ti_scm_syscon_methods, + sizeof(struct ti_scm_syscon_softc), simplebus_driver); + +static devclass_t ti_scm_syscon_devclass; + +EARLY_DRIVER_MODULE(ti_scm_syscon, simplebus, ti_scm_syscon_driver, + ti_scm_syscon_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_scm_syscon, 1); +MODULE_DEPEND(ti_scm_syscon, ti_scm, 1, 1, 1); diff --git a/sys/arm/ti/ti_sdhci.c b/sys/arm/ti/ti_sdhci.c index a76453d92588..4d19f4663d2f 100644 --- a/sys/arm/ti/ti_sdhci.c +++ b/sys/arm/ti/ti_sdhci.c @@ -44,10 +44,11 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include +#include +#include +#include "gpio_if.h" +#include #include #include @@ -59,10 +60,10 @@ __FBSDID("$FreeBSD$"); #include #include "sdhci_if.h" -#include -#include -#include -#include "gpio_if.h" +#include +#include +#include + #include "opt_mmccam.h" @@ -73,10 +74,9 @@ struct ti_sdhci_softc { struct resource * irq_res; void * intr_cookie; struct sdhci_slot slot; - clk_ident_t mmchs_clk_id; uint32_t mmchs_reg_off; uint32_t sdhci_reg_off; - uint32_t baseclk_hz; + uint64_t baseclk_hz; uint32_t cmd_and_mode; uint32_t sdhci_clkdiv; boolean_t disable_highspeed; @@ -414,24 +414,32 @@ ti_sdhci_detach(device_t dev) return (EBUSY); } -static void +static int ti_sdhci_hw_init(device_t dev) { struct ti_sdhci_softc *sc = device_get_softc(dev); uint32_t regval; unsigned long timeout; + clk_t mmc_clk; + int err; /* Enable the controller and interface/functional clocks */ - if (ti_prcm_clk_enable(sc->mmchs_clk_id) != 0) { + if (ti_sysc_clock_enable(device_get_parent(dev)) != 0) { device_printf(dev, "Error: failed to enable MMC clock\n"); - return; + return (ENXIO); } - /* Get the frequency of the source clock */ - if (ti_prcm_clk_get_source_freq(sc->mmchs_clk_id, - &sc->baseclk_hz) != 0) { - device_printf(dev, "Error: failed to get source clock freq\n"); - return; + /* FIXME: Devicetree dosent have any reference to mmc_clk */ + err = clk_get_by_name(dev, "mmc_clk", &mmc_clk); + if (err) { + device_printf(dev, "Can not find mmc_clk\n"); + return (ENXIO); + } + err = clk_get_freq(mmc_clk, &sc->baseclk_hz); + if (err) { + device_printf(dev, "Cant get mmc_clk frequency\n"); + /* AM335x TRM 8.1.6.8 table 8-24 96MHz @ OPP100 */ + sc->baseclk_hz = 96000000; } /* Issue a softreset to the controller */ @@ -499,6 +507,8 @@ ti_sdhci_hw_init(device_t dev) /* Set the initial controller configuration. */ ti_mmchs_write_4(sc, MMCHS_CON, MMCHS_CON_DVAL_8_4MS); + + return (0); } static int @@ -512,16 +522,9 @@ ti_sdhci_attach(device_t dev) sc->dev = dev; /* - * Get the MMCHS device id from FDT. If it's not there use the newbus - * unit number (which will work as long as the devices are in order and - * none are skipped in the fdt). Note that this is a property we made - * up and added in freebsd, it doesn't exist in the published bindings. + * Get the MMCHS device id from FDT. Use rev address to identify the unit. */ node = ofw_bus_get_node(dev); - sc->mmchs_clk_id = ti_hwmods_get_clock(dev); - if (sc->mmchs_clk_id == INVALID_CLK_IDENT) { - device_printf(dev, "failed to get clock based on hwmods property\n"); - } /* * The hardware can inherently do dual-voltage (1p8v, 3p0v) on the first @@ -531,7 +534,8 @@ ti_sdhci_attach(device_t dev) * that it can set the right values in the CAPA register. */ sc->slot.host.caps |= MMC_OCR_LOW_VOLTAGE; - if (sc->mmchs_clk_id == MMC1_CLK || OF_hasprop(node, "ti,dual-volt")) { + + if (OF_hasprop(node, "ti,dual-volt")) { sc->slot.host.caps |= MMC_OCR_290_300 | MMC_OCR_300_310; } @@ -603,7 +607,11 @@ ti_sdhci_attach(device_t dev) sc->disable_readonly = true; /* Initialise the MMCHS hardware. */ - ti_sdhci_hw_init(dev); + err = ti_sdhci_hw_init(dev); + if (err != 0) { + /* err should already contain ENXIO from ti_sdhci_hw_init() */ + goto fail; + } /* * The capabilities register can only express base clock frequencies in @@ -754,6 +762,7 @@ static driver_t ti_sdhci_driver = { DRIVER_MODULE(sdhci_ti, simplebus, ti_sdhci_driver, ti_sdhci_devclass, NULL, NULL); +MODULE_DEPEND(sdhci_ti, ti_sysc, 1, 1, 1); SDHCI_DEPEND(sdhci_ti); #ifndef MMCCAM diff --git a/sys/arm/ti/ti_sdma.c b/sys/arm/ti/ti_sdma.c index b5c47a109b6f..3df674a33dcd 100644 --- a/sys/arm/ti/ti_sdma.c +++ b/sys/arm/ti/ti_sdma.c @@ -51,7 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include #include @@ -79,7 +79,7 @@ __FBSDID("$FreeBSD$"); */ struct ti_sdma_channel { - /* + /* * The configuration registers for the given channel, these are modified * by the set functions and only written to the actual registers when a * transaction is started. @@ -109,7 +109,7 @@ struct ti_sdma_softc { struct resource* sc_irq_res; struct resource* sc_mem_res; - /* + /* * I guess in theory we should have a mutex per DMA channel for register * modifications. But since we know we are never going to be run on a SMP * system, we can use just the single lock for all channels. @@ -119,7 +119,7 @@ struct ti_sdma_softc { /* Stores the H/W revision read from the registers */ uint32_t sc_hw_rev; - /* + /* * Bits in the sc_active_channels data field indicate if the channel has * been activated. */ @@ -266,7 +266,7 @@ ti_sdma_intr(void *arg) if (csr & DMA4_CSR_TRANS_ERR) { device_printf(sc->sc_dev, "Transaction error event on " "channel %u\n", ch); - /* + /* * Apparently according to linux code, there is an errata * that says the channel is not disabled upon this error. * They explicitly disable the channel here .. since I @@ -1175,10 +1175,11 @@ ti_sdma_attach(device_t dev) panic("%s: Cannot map registers", device_get_name(dev)); /* Enable the interface and functional clocks */ - ti_prcm_clk_enable(SDMA_CLK); + ti_sysc_clock_enable(device_get_parent(dev)); /* Read the sDMA revision register and sanity check it's known */ - sc->sc_hw_rev = ti_sdma_read_4(sc, DMA4_REVISION); + sc->sc_hw_rev = ti_sdma_read_4(sc, + ti_sysc_get_rev_address_offset_host(device_get_parent(dev))); device_printf(dev, "sDMA revision %08x\n", sc->sc_hw_rev); if (!ti_sdma_is_omap4_rev(sc) && !ti_sdma_is_omap3_rev(sc)) { @@ -1213,7 +1214,7 @@ ti_sdma_attach(device_t dev) } } - /* + /* * Install interrupt handlers for the for possible interrupts. Any channel * can trip one of the four IRQs */ @@ -1248,4 +1249,4 @@ static driver_t ti_sdma_driver = { static devclass_t ti_sdma_devclass; DRIVER_MODULE(ti_sdma, simplebus, ti_sdma_driver, ti_sdma_devclass, 0, 0); -MODULE_DEPEND(ti_sdma, ti_prcm, 1, 1, 1); +MODULE_DEPEND(ti_sdma, ti_sysc, 1, 1, 1); diff --git a/sys/arm/ti/ti_spi.c b/sys/arm/ti/ti_spi.c index a424f36b8683..19b80605b9b6 100644 --- a/sys/arm/ti/ti_spi.c +++ b/sys/arm/ti/ti_spi.c @@ -48,8 +48,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include +#include #include #include @@ -166,28 +165,15 @@ ti_spi_probe(device_t dev) static int ti_spi_attach(device_t dev) { - int clk_id, err, i, rid, timeout; + int err, i, rid, timeout; struct ti_spi_softc *sc; uint32_t rev; sc = device_get_softc(dev); sc->sc_dev = dev; - /* - * Get the MMCHS device id from FDT. If it's not there use the newbus - * unit number (which will work as long as the devices are in order and - * none are skipped in the fdt). Note that this is a property we made - * up and added in freebsd, it doesn't exist in the published bindings. - */ - clk_id = ti_hwmods_get_clock(dev); - if (clk_id == INVALID_CLK_IDENT) { - device_printf(dev, - "failed to get clock based on hwmods property\n"); - return (EINVAL); - } - /* Activate the McSPI module. */ - err = ti_prcm_clk_enable(clk_id); + err = ti_sysc_clock_enable(device_get_parent(dev)); if (err) { device_printf(dev, "Error: failed to activate source clock\n"); return (err); @@ -245,7 +231,8 @@ ti_spi_attach(device_t dev) } /* Print the McSPI module revision. */ - rev = TI_SPI_READ(sc, MCSPI_REVISION); + rev = TI_SPI_READ(sc, + ti_sysc_get_rev_address_offset_host(device_get_parent(dev))); device_printf(dev, "scheme: %#x func: %#x rtl: %d rev: %d.%d custom rev: %d\n", (rev >> MCSPI_REVISION_SCHEME_SHIFT) & MCSPI_REVISION_SCHEME_MSK, @@ -592,3 +579,4 @@ static driver_t ti_spi_driver = { }; DRIVER_MODULE(ti_spi, simplebus, ti_spi_driver, ti_spi_devclass, 0, 0); +MODULE_DEPEND(ti_spi, ti_sysc, 1, 1, 1); diff --git a/sys/arm/ti/ti_sysc.c b/sys/arm/ti/ti_sysc.c index d428dd44a1ab..171520643c13 100644 --- a/sys/arm/ti/ti_sysc.c +++ b/sys/arm/ti/ti_sysc.c @@ -1,6 +1,8 @@ /*- * Copyright (c) 2019 Emmanuel Vadot * + * Copyright (c) 2020 Oskar Holmlund + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -47,20 +50,401 @@ __FBSDID("$FreeBSD$"); #include #include -static struct ofw_compat_data compat_data[] = { - { "ti,sysc", 1 }, - { NULL, 0 } -}; +#include -struct ti_sysc_softc { - struct simplebus_softc sc; - device_t dev; -}; +#include +#include + +#define DEBUG_SYSC 0 + +#if DEBUG_SYSC +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* Documentation/devicetree/bindings/bus/ti-sysc.txt + * + * Documentation/devicetree/clock/clock-bindings.txt + * Defines phandle + optional pair + * Documentation/devicetree/clock/ti-clkctl.txt + */ static int ti_sysc_probe(device_t dev); static int ti_sysc_attach(device_t dev); static int ti_sysc_detach(device_t dev); +#define TI_SYSC_DRA7_MCAN 15 +#define TI_SYSC_USB_HOST_FS 14 +#define TI_SYSC_DRA7_MCASP 13 +#define TI_SYSC_MCASP 12 +#define TI_SYSC_OMAP_AES 11 +#define TI_SYSC_OMAP3_SHAM 10 +#define TI_SYSC_OMAP4_SR 9 +#define TI_SYSC_OMAP3630_SR 8 +#define TI_SYSC_OMAP3430_SR 7 +#define TI_SYSC_OMAP4_TIMER 6 +#define TI_SYSC_OMAP2_TIMER 5 +/* Above needs special workarounds */ +#define TI_SYSC_OMAP4_SIMPLE 4 +#define TI_SYSC_OMAP4 3 +#define TI_SYSC_OMAP2 2 +#define TI_SYSC 1 +#define TI_SYSC_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,sysc-dra7-mcan", TI_SYSC_DRA7_MCAN }, + { "ti,sysc-usb-host-fs", TI_SYSC_USB_HOST_FS }, + { "ti,sysc-dra7-mcasp", TI_SYSC_DRA7_MCASP }, + { "ti,sysc-mcasp", TI_SYSC_MCASP }, + { "ti,sysc-omap-aes", TI_SYSC_OMAP_AES }, + { "ti,sysc-omap3-sham", TI_SYSC_OMAP3_SHAM }, + { "ti,sysc-omap4-sr", TI_SYSC_OMAP4_SR }, + { "ti,sysc-omap3630-sr", TI_SYSC_OMAP3630_SR }, + { "ti,sysc-omap3430-sr", TI_SYSC_OMAP3430_SR }, + { "ti,sysc-omap4-timer", TI_SYSC_OMAP4_TIMER }, + { "ti,sysc-omap2-timer", TI_SYSC_OMAP2_TIMER }, + /* Above needs special workarounds */ + { "ti,sysc-omap4-simple", TI_SYSC_OMAP4_SIMPLE }, + { "ti,sysc-omap4", TI_SYSC_OMAP4 }, + { "ti,sysc-omap2", TI_SYSC_OMAP2 }, + { "ti,sysc", TI_SYSC }, + { NULL, TI_SYSC_END } +}; + +/* reg-names can be "rev", "sysc" and "syss" */ +static const char * reg_names[] = { "rev", "sysc", "syss" }; +#define REG_REV 0 +#define REG_SYSC 1 +#define REG_SYSS 2 +#define REG_MAX 3 + +/* master idle / slave idle mode defined in 8.1.3.2.1 / 8.1.3.2.2 */ +#include +#define SYSC_IDLE_MAX 4 + +struct sysc_reg { + uint64_t address; + uint64_t size; +}; + +struct clk_list { + TAILQ_ENTRY(clk_list) next; + clk_t clk; +}; + +struct ti_sysc_softc { + struct simplebus_softc sc; + bool attach_done; + + device_t dev; + int device_type; + + struct sysc_reg reg[REG_MAX]; + /* Offset from host base address */ + uint64_t offset_reg[REG_MAX]; + + uint32_t ti_sysc_mask; + int32_t ti_sysc_midle[SYSC_IDLE_MAX]; + int32_t ti_sysc_sidle[SYSC_IDLE_MAX]; + uint32_t ti_sysc_delay_us; + uint32_t ti_syss_mask; + + int num_clocks; + TAILQ_HEAD(, clk_list) clk_list; + + /* deprecated ti_hwmods */ + bool ti_no_reset_on_init; + bool ti_no_idle_on_init; + bool ti_no_idle; +}; + +/* + * All sysc seems to have a reg["rev"] register. + * Lets use that for identification of which module the driver are connected to. + */ +uint64_t +ti_sysc_get_rev_address(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + + return (sc->reg[REG_REV].address); +} + +uint64_t +ti_sysc_get_rev_address_offset_host(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + + return (sc->offset_reg[REG_REV]); +} + +uint64_t +ti_sysc_get_sysc_address(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + + return (sc->reg[REG_SYSC].address); +} + +uint64_t +ti_sysc_get_sysc_address_offset_host(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + + return (sc->offset_reg[REG_SYSC]); +} + +uint64_t +ti_sysc_get_syss_address(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + + return (sc->reg[REG_SYSS].address); +} + +uint64_t +ti_sysc_get_syss_address_offset_host(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + + return (sc->offset_reg[REG_SYSS]); +} + +/* + * Due no memory region is assigned the sysc driver the children needs to + * handle the practical read/writes to the registers. + * Check if sysc has reset bit. + */ +uint32_t +ti_sysc_get_soft_reset_bit(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + switch (sc->device_type) { + case TI_SYSC_OMAP4_TIMER: + case TI_SYSC_OMAP4_SIMPLE: + case TI_SYSC_OMAP4: + if (sc->ti_sysc_mask & SYSC_OMAP4_SOFTRESET) { + return (SYSC_OMAP4_SOFTRESET); + } + break; + + case TI_SYSC_OMAP2_TIMER: + case TI_SYSC_OMAP2: + case TI_SYSC: + if (sc->ti_sysc_mask & SYSC_OMAP2_SOFTRESET) { + return (SYSC_OMAP2_SOFTRESET); + } + break; + default: + break; + } + + return (0); +} + +int +ti_sysc_clock_enable(device_t dev) { + struct clk_list *clkp, *clkp_tmp; + struct ti_sysc_softc *sc = device_get_softc(dev); + int err; + + TAILQ_FOREACH_SAFE(clkp, &sc->clk_list, next, clkp_tmp) { + err = clk_enable(clkp->clk); + + if (err) { + DPRINTF(sc->dev, "clk_enable %s failed %d\n", + clk_get_name(clkp->clk), err); + break; + } + } + return (err); +} + +int +ti_sysc_clock_disable(device_t dev) { + struct clk_list *clkp, *clkp_tmp; + struct ti_sysc_softc *sc = device_get_softc(dev); + int err = 0; + + TAILQ_FOREACH_SAFE(clkp, &sc->clk_list, next, clkp_tmp) { + err = clk_disable(clkp->clk); + + if (err) { + DPRINTF(sc->dev, "clk_enable %s failed %d\n", + clk_get_name(clkp->clk), err); + break; + } + } + return (err); +} + +static int +parse_regfields(struct ti_sysc_softc *sc) { + phandle_t node; + uint32_t parent_address_cells; + uint32_t parent_size_cells; + cell_t *reg; + ssize_t nreg; + int err, k, reg_i, prop_idx; + uint32_t idx; + + node = ofw_bus_get_node(sc->dev); + + /* Get parents address and size properties */ + err = OF_searchencprop(OF_parent(node), "#address-cells", + &parent_address_cells, sizeof(parent_address_cells)); + if (err == -1) + return (ENXIO); + if (!(parent_address_cells == 1 || parent_address_cells == 2)) { + DPRINTF(sc->dev, "Expect parent #address-cells=[1||2]\n"); + return (ENXIO); + } + + err = OF_searchencprop(OF_parent(node), "#size-cells", + &parent_size_cells, sizeof(parent_size_cells)); + if (err == -1) + return (ENXIO); + + if (!(parent_size_cells == 1 || parent_size_cells == 2)) { + DPRINTF(sc->dev, "Expect parent #size-cells = [1||2]\n"); + return (ENXIO); + } + + /* Grab the content of reg properties */ + nreg = OF_getproplen(node, "reg"); + reg = malloc(nreg, M_DEVBUF, M_WAITOK); + OF_getencprop(node, "reg", reg, nreg); + + /* Make sure address & size are 0 */ + for (idx = 0; idx < REG_MAX; idx++) { + sc->reg[idx].address = 0; + sc->reg[idx].size = 0; + } + + /* Loop through reg-names and figure out which reg-name corresponds to + * index populate the values into the reg array. + */ + for (idx = 0, reg_i = 0; idx < REG_MAX && reg_i < nreg; idx++) { + err = ofw_bus_find_string_index(node, "reg-names", + reg_names[idx], &prop_idx); + if (err != 0) + continue; + + for (k = 0; k < parent_address_cells; k++) { + sc->reg[prop_idx].address <<= 32; + sc->reg[prop_idx].address |= reg[reg_i++]; + } + + for (k = 0; k < parent_size_cells; k++) { + sc->reg[prop_idx].size <<= 32; + sc->reg[prop_idx].size |= reg[reg_i++]; + } + + if (sc->sc.nranges == 0) + sc->offset_reg[prop_idx] = sc->reg[prop_idx].address; + else + sc->offset_reg[prop_idx] = sc->reg[prop_idx].address - + sc->sc.ranges[REG_REV].host; + + DPRINTF(sc->dev, "reg[%s] adress %#jx size %#jx\n", + reg_names[idx], + sc->reg[prop_idx].address, + sc->reg[prop_idx].size); + } + free(reg, M_DEVBUF); + return (0); +} + +static void +parse_idle(struct ti_sysc_softc *sc, const char *name, uint32_t *idle) { + phandle_t node; + cell_t value[SYSC_IDLE_MAX]; + int len, no, i; + + node = ofw_bus_get_node(sc->dev); + + if (!OF_hasprop(node, name)) { + return; + } + + len = OF_getproplen(node, name); + no = len / sizeof(cell_t); + if (no >= SYSC_IDLE_MAX) { + DPRINTF(sc->dev, "Limit %s\n", name); + no = SYSC_IDLE_MAX-1; + len = no * sizeof(cell_t); + } + + OF_getencprop(node, name, value, len); + for (i = 0; i < no; i++) { + idle[i] = value[i]; +#if DEBUG_SYSC + DPRINTF(sc->dev, "%s[%d] = %d ", + name, i, value[i]); + switch(value[i]) { + case SYSC_IDLE_FORCE: + DPRINTF(sc->dev, "SYSC_IDLE_FORCE\n"); + break; + case SYSC_IDLE_NO: + DPRINTF(sc->dev, "SYSC_IDLE_NO\n"); + break; + case SYSC_IDLE_SMART: + DPRINTF(sc->dev, "SYSC_IDLE_SMART\n"); + break; + case SYSC_IDLE_SMART_WKUP: + DPRINTF(sc->dev, "SYSC_IDLE_SMART_WKUP\n"); + break; + } +#endif + } + for ( ; i < SYSC_IDLE_MAX; i++) + idle[i] = -1; +} + +static int +ti_sysc_attach_clocks(struct ti_sysc_softc *sc) { + clk_t *clk; + struct clk_list *clkp; + int index, err; + phandle_t cnode; + + clk = malloc(sc->num_clocks*sizeof(clk_t), M_DEVBUF, M_WAITOK | M_ZERO); + + cnode = ofw_bus_get_node(sc->dev); + + /* Check if all clocks can be found */ + for (index = 0; index < sc->num_clocks; index++) { + err = clk_get_by_ofw_index(sc->dev, 0, index, &clk[index]); + + if (err != 0) { + free(clk, M_DEVBUF); + return (1); + } + } + + /* All clocks are found, add to list */ + for (index = 0; index < sc->num_clocks; index++) { + clkp = malloc(sizeof(*clkp), M_DEVBUF, M_WAITOK | M_ZERO); + clkp->clk = clk[index]; + TAILQ_INSERT_TAIL(&sc->clk_list, clkp, next); + } + + /* Release the clk array */ + free(clk, M_DEVBUF); + return (0); +} + +static int +ti_sysc_simplebus_attach_child(device_t dev) { + device_t cdev; + phandle_t node, child; + struct ti_sysc_softc *sc = device_get_softc(dev); + + node = ofw_bus_get_node(sc->dev); + + for (child = OF_child(node); child > 0; child = OF_peer(child)) { + cdev = simplebus_add_device(sc->dev, child, 0, NULL, -1, NULL); + if (cdev != NULL) + device_probe_and_attach(cdev); + } + return (0); +} + +/* Device interface */ static int ti_sysc_probe(device_t dev) { @@ -71,8 +455,6 @@ ti_sysc_probe(device_t dev) return (ENXIO); device_set_desc(dev, "TI SYSC Interconnect"); - if (!bootverbose) - device_quiet(dev); return (BUS_PROBE_DEFAULT); } @@ -81,48 +463,160 @@ static int ti_sysc_attach(device_t dev) { struct ti_sysc_softc *sc; - device_t cdev; - phandle_t node, child; + phandle_t node; + int err; + cell_t value; sc = device_get_softc(dev); sc->dev = dev; - node = ofw_bus_get_node(dev); + sc->device_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; - simplebus_init(dev, node); + node = ofw_bus_get_node(sc->dev); + /* ranges - use simplebus */ + simplebus_init(sc->dev, node); if (simplebus_fill_ranges(node, &sc->sc) < 0) { - device_printf(dev, "could not get ranges\n"); + DPRINTF(sc->dev, "could not get ranges\n"); return (ENXIO); } - for (child = OF_child(node); child > 0; child = OF_peer(child)) { - cdev = simplebus_add_device(dev, child, 0, NULL, -1, NULL); - if (cdev != NULL) - device_probe_and_attach(cdev); + if (sc->sc.nranges == 0) { + DPRINTF(sc->dev, "nranges == 0\n"); + return (ENXIO); } - return (bus_generic_attach(dev)); + /* Required field reg & reg-names - assume at least "rev" exists */ + err = parse_regfields(sc); + if (err) { + DPRINTF(sc->dev, "parse_regfields failed %d\n", err); + return (ENXIO); + } + + /* Optional */ + if (OF_hasprop(node, "ti,sysc-mask")) { + OF_getencprop(node, "ti,sysc-mask", &value, sizeof(cell_t)); + sc->ti_sysc_mask = value; + } + if (OF_hasprop(node, "ti,syss-mask")) { + OF_getencprop(node, "ti,syss-mask", &value, sizeof(cell_t)); + sc->ti_syss_mask = value; + } + if (OF_hasprop(node, "ti,sysc-delay-us")) { + OF_getencprop(node, "ti,sysc-delay-us", &value, sizeof(cell_t)); + sc->ti_sysc_delay_us = value; + } + + DPRINTF(sc->dev, "sysc_mask %x syss_mask %x delay_us %x\n", + sc->ti_sysc_mask, sc->ti_syss_mask, sc->ti_sysc_delay_us); + + parse_idle(sc, "ti,sysc-midle", sc->ti_sysc_midle); + parse_idle(sc, "ti,sysc-sidle", sc->ti_sysc_sidle); + + if (OF_hasprop(node, "ti,no-reset-on-init")) + sc->ti_no_reset_on_init = true; + else + sc->ti_no_reset_on_init = false; + + if (OF_hasprop(node, "ti,no-idle-on-init")) + sc->ti_no_idle_on_init = true; + else + sc->ti_no_idle_on_init = false; + + if (OF_hasprop(node, "ti,no-idle")) + sc->ti_no_idle = true; + else + sc->ti_no_idle = false; + + DPRINTF(sc->dev, + "no-reset-on-init %d, no-idle-on-init %d, no-idle %d\n", + sc->ti_no_reset_on_init, + sc->ti_no_idle_on_init, + sc->ti_no_idle); + + if (OF_hasprop(node, "clocks")) { + struct clock_cell_info cell_info; + read_clock_cells(sc->dev, &cell_info); + free(cell_info.clock_cells, M_DEVBUF); + free(cell_info.clock_cells_ncells, M_DEVBUF); + + sc->num_clocks = cell_info.num_real_clocks; + TAILQ_INIT(&sc->clk_list); + + err = ti_sysc_attach_clocks(sc); + if (err) { + DPRINTF(sc->dev, "Failed to attach clocks\n"); + return (bus_generic_attach(sc->dev)); + } + } + + err = ti_sysc_simplebus_attach_child(sc->dev); + if (err) { + DPRINTF(sc->dev, "ti_sysc_simplebus_attach_child %d\n", + err); + return (err); + } + + sc->attach_done = true; + + return (bus_generic_attach(sc->dev)); } static int ti_sysc_detach(device_t dev) { - return (EBUSY); } +/* Bus interface */ +static void +ti_sysc_new_pass(device_t dev) +{ + struct ti_sysc_softc *sc; + int err; + phandle_t node; + + sc = device_get_softc(dev); + + if (sc->attach_done) { + bus_generic_new_pass(sc->dev); + return; + } + + node = ofw_bus_get_node(sc->dev); + if (OF_hasprop(node, "clocks")) { + err = ti_sysc_attach_clocks(sc); + if (err) { + DPRINTF(sc->dev, "Failed to attach clocks\n"); + return; + } + } + + err = ti_sysc_simplebus_attach_child(sc->dev); + if (err) { + DPRINTF(sc->dev, + "ti_sysc_simplebus_attach_child failed %d\n", err); + return; + } + sc->attach_done = true; + + bus_generic_attach(sc->dev); +} + static device_method_t ti_sysc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ti_sysc_probe), DEVMETHOD(device_attach, ti_sysc_attach), DEVMETHOD(device_detach, ti_sysc_detach), + /* Bus interface */ + DEVMETHOD(bus_new_pass, ti_sysc_new_pass), + DEVMETHOD_END }; DEFINE_CLASS_1(ti_sysc, ti_sysc_driver, ti_sysc_methods, - sizeof(struct ti_sysc_softc), simplebus_driver); + sizeof(struct ti_sysc_softc), simplebus_driver); static devclass_t ti_sysc_devclass; EARLY_DRIVER_MODULE(ti_sysc, simplebus, ti_sysc_driver, -ti_sysc_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_FIRST); + ti_sysc_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_FIRST); diff --git a/sys/arm/ti/ti_sysc.h b/sys/arm/ti/ti_sysc.h new file mode 100644 index 000000000000..b74222f05772 --- /dev/null +++ b/sys/arm/ti/ti_sysc.h @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#ifndef __TI_SYSC__ +#define __TI_SYSC__ + +uint64_t ti_sysc_get_rev_address(device_t dev); +uint64_t ti_sysc_get_rev_address_offset_host(device_t dev); +uint64_t ti_sysc_get_sysc_address(device_t dev); +uint64_t ti_sysc_get_sysc_address_offset_host(device_t dev); +uint64_t ti_sysc_get_syss_address(device_t dev); +uint64_t ti_sysc_get_syss_address_offset_host(device_t dev); +int ti_sysc_clock_enable(device_t dev); +int ti_sysc_clock_disable(device_t dev); + +uint32_t ti_sysc_get_soft_reset_bit(device_t dev); + +#endif /* __TI_SYSC__ */ diff --git a/sys/arm/ti/ti_wdt.c b/sys/arm/ti/ti_wdt.c index 539e4d93950f..29ae41eac531 100644 --- a/sys/arm/ti/ti_wdt.c +++ b/sys/arm/ti/ti_wdt.c @@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$"); #include -#include #include #ifdef DEBUG @@ -93,6 +92,7 @@ static driver_t ti_wdt_driver = { static devclass_t ti_wdt_devclass; DRIVER_MODULE(ti_wdt, simplebus, ti_wdt_driver, ti_wdt_devclass, 0, 0); +MODULE_DEPEND(ti_wdt, ti_sysc, 1, 1, 1); static __inline uint32_t ti_wdt_reg_read(struct ti_wdt_softc *sc, uint32_t reg) diff --git a/sys/arm/ti/usb/omap_ehci.c b/sys/arm/ti/usb/omap_ehci.c index c14a483b7175..adc2c122f054 100644 --- a/sys/arm/ti/usb/omap_ehci.c +++ b/sys/arm/ti/usb/omap_ehci.c @@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include diff --git a/sys/arm/ti/usb/omap_host.c b/sys/arm/ti/usb/omap_host.c index 304e80d33df8..736ccf17262e 100644 --- a/sys/arm/ti/usb/omap_host.c +++ b/sys/arm/ti/usb/omap_host.c @@ -40,7 +40,7 @@ __FBSDID("$FreeBSD$"); #include -#include +#include #include /* @@ -139,12 +139,14 @@ omap_uhh_init(struct omap_uhh_softc *isc) int i; /* Enable Clocks for high speed USBHOST */ - ti_prcm_clk_enable(USBHSHOST_CLK); + ti_sysc_clock_enable(device_get_parent(isc->sc_dev)); /* Read the UHH revision */ isc->uhh_rev = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_REVISION); device_printf(isc->sc_dev, "UHH revision 0x%08x\n", isc->uhh_rev); + /* FIXME */ +#if 0 if (isc->uhh_rev == OMAP_UHH_REV2) { /* For OMAP44xx devices you have to enable the per-port clocks: * PHY_MODE - External ULPI clock @@ -200,6 +202,7 @@ omap_uhh_init(struct omap_uhh_softc *isc) device_printf(isc->sc_dev, "unknown port mode %d for port 1\n", isc->port_mode[1]); } } +#endif /* Put UHH in SmartIdle/SmartStandby mode */ reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSCONFIG); @@ -327,7 +330,7 @@ omap_uhh_fini(struct omap_uhh_softc *isc) } /* Disable functional and interface clocks for the TLL and HOST modules */ - ti_prcm_clk_disable(USBHSHOST_CLK); + ti_sysc_clock_disable(device_get_parent(isc->sc_dev)); device_printf(isc->sc_dev, "Clock to USB host has been disabled\n"); } diff --git a/sys/arm/ti/usb/omap_tll.c b/sys/arm/ti/usb/omap_tll.c index eb3e246a61d6..c5383e3d52d3 100644 --- a/sys/arm/ti/usb/omap_tll.c +++ b/sys/arm/ti/usb/omap_tll.c @@ -39,7 +39,7 @@ __FBSDID("$FreeBSD$"); #include -#include +#include #include /* @@ -212,7 +212,7 @@ omap_tll_init(struct omap_tll_softc *sc) int ret = 0; /* Enable the USB TLL */ - ti_prcm_clk_enable(USBTLL_CLK); + ti_sysc_clock_enable(device_get_parent(sc->sc_dev)); /* Perform TLL soft reset, and wait until reset is complete */ omap_tll_write_4(sc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET); @@ -248,7 +248,7 @@ omap_tll_init(struct omap_tll_softc *sc) err_sys_status: /* Disable the TLL clocks */ - ti_prcm_clk_disable(USBTLL_CLK); + ti_sysc_clock_disable(device_get_parent(sc->sc_dev)); return(ret); } @@ -273,7 +273,7 @@ omap_tll_disable(struct omap_tll_softc *sc) } /* Disable functional and interface clocks for the TLL and HOST modules */ - ti_prcm_clk_disable(USBTLL_CLK); + ti_sysc_clock_disable(device_get_parent(sc->sc_dev)); } static int diff --git a/sys/dev/uart/uart_dev_ti8250.c b/sys/dev/uart/uart_dev_ti8250.c index f5a230908da3..ebe777ed7fdb 100644 --- a/sys/dev/uart/uart_dev_ti8250.c +++ b/sys/dev/uart/uart_dev_ti8250.c @@ -39,9 +39,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include - #include #include #include @@ -52,6 +49,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #include "uart_if.h" /* @@ -74,16 +73,8 @@ static int ti8250_bus_probe(struct uart_softc *sc) { int status; - clk_ident_t clkid; - /* Enable clocks for this device. We can't continue if that fails. */ - clkid = ti_hwmods_get_clock(sc->sc_dev); - if (clkid == INVALID_CLK_IDENT) { - device_printf(sc->sc_dev, - "failed to get clock based on hwmods\n"); - clkid = UART1_CLK + device_get_unit(sc->sc_dev); - } - if ((status = ti_prcm_clk_enable(clkid)) != 0) + if ((status = ti_sysc_clock_enable(device_get_parent(sc->sc_dev))) != 0) return (status); /* diff --git a/sys/modules/Makefile b/sys/modules/Makefile index dff871fa7338..dc4e04736670 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -755,7 +755,7 @@ _pst= pst _sbni= sbni .endif -.if ${MACHINE_CPUARCH} == "arm" +.if ${MACHINE_ARCH} == "armv7" _cfi= cfi _cpsw= cpsw .endif From 4057e3eaaaaaf393d78d1fb0ac4d8447a9f0e41a Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 30 Jul 2020 15:43:16 +0000 Subject: [PATCH 264/287] vfs: add NOMACCHECK and AUDITVNODE2 to lockless lookup They are both nops since lookup does not progress with either mac or audit enabled. Tested by: pho --- sys/kern/vfs_cache.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 16c493a1e39a..7e994e9e74a4 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -3002,7 +3002,8 @@ cache_fpl_handled_impl(struct cache_fpl *fpl, int error, int line) #define cache_fpl_handled(x, e) cache_fpl_handled_impl((x), (e), __LINE__) #define CACHE_FPL_SUPPORTED_CN_FLAGS \ - (LOCKLEAF | FOLLOW | LOCKSHARED | SAVENAME | ISOPEN | AUDITVNODE1) + (LOCKLEAF | FOLLOW | LOCKSHARED | SAVENAME | ISOPEN | NOMACCHECK | \ + AUDITVNODE1 | AUDITVNODE2) static bool cache_can_fplookup(struct cache_fpl *fpl) From 8230d2935730d0768d2dc5c9d0ce6ac0ca0c75e0 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 30 Jul 2020 15:44:10 +0000 Subject: [PATCH 265/287] vfs: support negative entry promotion in lockless lookup Tested by: pho --- sys/kern/vfs_cache.c | 113 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 6 deletions(-) diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 7e994e9e74a4..32e66cc8a01f 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -807,6 +807,15 @@ cache_negative_remove(struct namecache *ncp) } else { list_locked = true; mtx_lock(&neglist->nl_lock); + /* + * We may be racing against promotion in lockless lookup. + */ + if ((negstate->neg_flag & NEG_HOT) != 0) { + mtx_unlock(&neglist->nl_lock); + hot_locked = true; + mtx_lock(&ncneg_hot.nl_lock); + mtx_lock(&neglist->nl_lock); + } } if ((negstate->neg_flag & NEG_HOT) != 0) { mtx_assert(&ncneg_hot.nl_lock, MA_OWNED); @@ -3060,6 +3069,103 @@ cache_fplookup_vnode_supported(struct vnode *vp) return (vp->v_type != VLNK); } +/* + * Move a negative entry to the hot list. + * + * We have to take locks, but they may be contended and in the worst + * case we may need to go off CPU. We don't want to spin within the + * smr section and we can't block with it. Instead we are going to + * look up the entry again. + */ +static int __noinline +cache_fplookup_negative_promote(struct cache_fpl *fpl, struct namecache *oncp, + uint32_t hash) +{ + struct componentname *cnp; + struct namecache *ncp; + struct neglist *neglist; + struct negstate *negstate; + struct vnode *dvp; + u_char nc_flag; + + cnp = fpl->cnp; + dvp = fpl->dvp; + + if (!vhold_smr(dvp)) + return (cache_fpl_aborted(fpl)); + + neglist = NCP2NEGLIST(oncp); + cache_fpl_smr_exit(fpl); + + mtx_lock(&ncneg_hot.nl_lock); + mtx_lock(&neglist->nl_lock); + /* + * For hash iteration. + */ + cache_fpl_smr_enter(fpl); + + /* + * Avoid all surprises by only succeeding if we got the same entry and + * bailing completely otherwise. + * + * In particular at this point there can be a new ncp which matches the + * search but hashes to a different neglist. + */ + CK_LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) { + if (ncp == oncp) + break; + } + + /* + * No match to begin with. + */ + if (__predict_false(ncp == NULL)) { + goto out_abort; + } + + /* + * The newly found entry may be something different... + */ + if (!(ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen && + !bcmp(ncp->nc_name, cnp->cn_nameptr, ncp->nc_nlen))) { + goto out_abort; + } + + /* + * ... and not even negative. + */ + nc_flag = atomic_load_char(&ncp->nc_flag); + if ((nc_flag & NCF_NEGATIVE) == 0) { + goto out_abort; + } + + if (__predict_false(cache_ncp_invalid(ncp))) { + goto out_abort; + } + + negstate = NCP2NEGSTATE(ncp); + if ((negstate->neg_flag & NEG_HOT) == 0) { + numhotneg++; + TAILQ_REMOVE(&neglist->nl_list, ncp, nc_dst); + TAILQ_INSERT_TAIL(&ncneg_hot.nl_list, ncp, nc_dst); + negstate->neg_flag |= NEG_HOT; + } + + SDT_PROBE2(vfs, namecache, lookup, hit__negative, dvp, ncp->nc_name); + counter_u64_add(numneghits, 1); + cache_fpl_smr_exit(fpl); + mtx_unlock(&neglist->nl_lock); + mtx_unlock(&ncneg_hot.nl_lock); + vdrop(dvp); + return (cache_fpl_handled(fpl, ENOENT)); +out_abort: + cache_fpl_smr_exit(fpl); + mtx_unlock(&neglist->nl_lock); + mtx_unlock(&ncneg_hot.nl_lock); + vdrop(dvp); + return (cache_fpl_aborted(fpl)); +} + /* * The target vnode is not supported, prepare for the slow path to take over. */ @@ -3204,12 +3310,7 @@ cache_fplookup_next(struct cache_fpl *fpl) return (cache_fpl_partial(fpl)); } if (!neg_hot) { - /* - * TODO - * Promoting to hot negative requires locks, thus is - * left not yet supported for simplicity. - */ - return (cache_fpl_partial(fpl)); + return (cache_fplookup_negative_promote(fpl, ncp, hash)); } SDT_PROBE2(vfs, namecache, lookup, hit__negative, dvp, ncp->nc_name); From 404927357d36a8a561f2747cdc56e384acb4693a Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 30 Jul 2020 15:45:11 +0000 Subject: [PATCH 266/287] vfs: add support for WANTPARENT and LOCKPARENT to lockless lookup This makes the realpath syscall operational with the new lookup. Note that the walk to obtain the full path name still takes locks. Tested by: pho Differential Revision: https://reviews.freebsd.org/D23917 --- sys/kern/vfs_cache.c | 129 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 23 deletions(-) diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 32e66cc8a01f..62f31fc47ee9 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -3011,8 +3011,8 @@ cache_fpl_handled_impl(struct cache_fpl *fpl, int error, int line) #define cache_fpl_handled(x, e) cache_fpl_handled_impl((x), (e), __LINE__) #define CACHE_FPL_SUPPORTED_CN_FLAGS \ - (LOCKLEAF | FOLLOW | LOCKSHARED | SAVENAME | ISOPEN | NOMACCHECK | \ - AUDITVNODE1 | AUDITVNODE2) + (LOCKLEAF | LOCKPARENT | WANTPARENT | FOLLOW | LOCKSHARED | SAVENAME | \ + ISOPEN | NOMACCHECK | AUDITVNODE1 | AUDITVNODE2) static bool cache_can_fplookup(struct cache_fpl *fpl) @@ -3208,35 +3208,17 @@ cache_fplookup_partial_setup(struct cache_fpl *fpl) } static int -cache_fplookup_final(struct cache_fpl *fpl) +cache_fplookup_final_child(struct cache_fpl *fpl, enum vgetstate tvs) { struct componentname *cnp; - enum vgetstate tvs; - struct vnode *dvp, *tvp; - seqc_t dvp_seqc, tvp_seqc; + struct vnode *tvp; + seqc_t tvp_seqc; int error; cnp = fpl->cnp; - dvp = fpl->dvp; - dvp_seqc = fpl->dvp_seqc; tvp = fpl->tvp; tvp_seqc = fpl->tvp_seqc; - VNPASS(cache_fplookup_vnode_supported(dvp), dvp); - - tvs = vget_prep_smr(tvp); - if (tvs == VGET_NONE) { - return (cache_fpl_partial(fpl)); - } - - if (!vn_seqc_consistent(dvp, dvp_seqc)) { - cache_fpl_smr_exit(fpl); - vget_abort(tvp, tvs); - return (cache_fpl_aborted(fpl)); - } - - cache_fpl_smr_exit(fpl); - if ((cnp->cn_flags & LOCKLEAF) != 0) { error = vget_finish(tvp, cnp->cn_lkflags, tvs); if (error != 0) { @@ -3257,6 +3239,107 @@ cache_fplookup_final(struct cache_fpl *fpl) return (cache_fpl_handled(fpl, 0)); } +static int __noinline +cache_fplookup_final_withparent(struct cache_fpl *fpl) +{ + enum vgetstate dvs, tvs; + struct componentname *cnp; + struct vnode *dvp, *tvp; + seqc_t dvp_seqc, tvp_seqc; + int error; + + cnp = fpl->cnp; + dvp = fpl->dvp; + dvp_seqc = fpl->dvp_seqc; + tvp = fpl->tvp; + tvp_seqc = fpl->tvp_seqc; + + MPASS((cnp->cn_flags & (LOCKPARENT|WANTPARENT)) != 0); + + /* + * This is less efficient than it can be for simplicity. + */ + dvs = vget_prep_smr(dvp); + if (dvs == VGET_NONE) { + return (cache_fpl_aborted(fpl)); + } + tvs = vget_prep_smr(tvp); + if (tvs == VGET_NONE) { + cache_fpl_smr_exit(fpl); + vget_abort(dvp, dvs); + return (cache_fpl_aborted(fpl)); + } + + cache_fpl_smr_exit(fpl); + + if ((cnp->cn_flags & LOCKPARENT) != 0) { + error = vget_finish(dvp, LK_EXCLUSIVE, dvs); + if (error != 0) { + vget_abort(tvp, tvs); + return (cache_fpl_aborted(fpl)); + } + } else { + vget_finish_ref(dvp, dvs); + } + + if (!vn_seqc_consistent(dvp, dvp_seqc)) { + vget_abort(tvp, tvs); + if ((cnp->cn_flags & LOCKPARENT) != 0) + vput(dvp); + else + vrele(dvp); + cache_fpl_aborted(fpl); + return (error); + } + + error = cache_fplookup_final_child(fpl, tvs); + if (error != 0) { + MPASS(fpl->status == CACHE_FPL_STATUS_ABORTED); + if ((cnp->cn_flags & LOCKPARENT) != 0) + vput(dvp); + else + vrele(dvp); + return (error); + } + + MPASS(fpl->status == CACHE_FPL_STATUS_HANDLED); + return (0); +} + +static int +cache_fplookup_final(struct cache_fpl *fpl) +{ + struct componentname *cnp; + enum vgetstate tvs; + struct vnode *dvp, *tvp; + seqc_t dvp_seqc, tvp_seqc; + + cnp = fpl->cnp; + dvp = fpl->dvp; + dvp_seqc = fpl->dvp_seqc; + tvp = fpl->tvp; + tvp_seqc = fpl->tvp_seqc; + + VNPASS(cache_fplookup_vnode_supported(dvp), dvp); + + if ((cnp->cn_flags & (LOCKPARENT|WANTPARENT)) != 0) + return (cache_fplookup_final_withparent(fpl)); + + tvs = vget_prep_smr(tvp); + if (tvs == VGET_NONE) { + return (cache_fpl_partial(fpl)); + } + + if (!vn_seqc_consistent(dvp, dvp_seqc)) { + cache_fpl_smr_exit(fpl); + vget_abort(tvp, tvs); + return (cache_fpl_aborted(fpl)); + } + + cache_fpl_smr_exit(fpl); + return (cache_fplookup_final_child(fpl, tvs)); +} + static int cache_fplookup_next(struct cache_fpl *fpl) { From b1f910e02c457d9d1d1db74976270de8d0c9ac2d Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 30 Jul 2020 15:47:41 +0000 Subject: [PATCH 267/287] vfs: short-circuit the common case NDFREE calls Almost all consumers use the NDF_ONLY_PNBUF macro, making them avoidably branch a lot in the NDFREE routine. Also note most of them should not need to call any cleanup anyway as they don't request HASBUF. --- sys/kern/vfs_lookup.c | 18 +++++++++++++----- sys/sys/namei.h | 8 ++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 34e3573c8c35..7e90d86bb6a1 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -1390,7 +1390,17 @@ NDINIT_ALL(struct nameidata *ndp, u_long op, u_long flags, enum uio_seg segflg, * Free data allocated by namei(); see namei(9) for details. */ void -NDFREE(struct nameidata *ndp, const u_int flags) +NDFREE_PNBUF(struct nameidata *ndp) +{ + + if ((ndp->ni_cnd.cn_flags & HASBUF) != 0) { + uma_zfree(namei_zone, ndp->ni_cnd.cn_pnbuf); + ndp->ni_cnd.cn_flags &= ~HASBUF; + } +} + +void +(NDFREE)(struct nameidata *ndp, const u_int flags) { int unlock_dvp; int unlock_vp; @@ -1398,10 +1408,8 @@ NDFREE(struct nameidata *ndp, const u_int flags) unlock_dvp = 0; unlock_vp = 0; - if (!(flags & NDF_NO_FREE_PNBUF) && - (ndp->ni_cnd.cn_flags & HASBUF)) { - uma_zfree(namei_zone, ndp->ni_cnd.cn_pnbuf); - ndp->ni_cnd.cn_flags &= ~HASBUF; + if (!(flags & NDF_NO_FREE_PNBUF)) { + NDFREE_PNBUF(ndp); } if (!(flags & NDF_NO_VP_UNLOCK) && (ndp->ni_cnd.cn_flags & LOCKLEAF) && ndp->ni_vp) diff --git a/sys/sys/namei.h b/sys/sys/namei.h index 1fa20081a552..0950b0a8f583 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -210,7 +210,15 @@ void NDINIT_ALL(struct nameidata *ndp, u_long op, u_long flags, #define NDF_NO_FREE_PNBUF 0x00000020 #define NDF_ONLY_PNBUF (~NDF_NO_FREE_PNBUF) +void NDFREE_PNBUF(struct nameidata *); void NDFREE(struct nameidata *, const u_int); +#define NDFREE(ndp, flags) do { \ + struct nameidata *_ndp = (ndp); \ + if (__builtin_constant_p(flags) && flags == NDF_ONLY_PNBUF) \ + NDFREE_PNBUF(_ndp); \ + else \ + NDFREE(_ndp, flags); \ +} while (0) int namei(struct nameidata *ndp); int lookup(struct nameidata *ndp); From 2e4f8220e8a14671a715c34ab3bdbb9dcee3ab06 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 30 Jul 2020 15:48:56 +0000 Subject: [PATCH 268/287] vfs: fold poll_no_poll into vop_nopoll The logic was almost completely present in vop_stdpoll anyway. --- sys/kern/vfs_default.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index 9dc4e714ed79..f67bc9bf3ef0 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -616,7 +616,9 @@ vop_nopoll(ap) } */ *ap; { - return (poll_no_poll(ap->a_events)); + if (ap->a_events & ~POLLSTANDARD) + return (POLLNVAL); + return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); } /* From 848f8effdd69456368366a6bbdba322d0341c98e Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 30 Jul 2020 15:50:51 +0000 Subject: [PATCH 269/287] vfs: inline vops if there are no pre/post associated calls This removes a level of indirection from frequently used methods, most notably VOP_LOCK1 and VOP_UNLOCK1. Tested by: pho --- sys/kern/vfs_subr.c | 16 ++++++++-------- sys/kern/vnode_if.src | 16 ++++++++-------- sys/sys/vnode.h | 32 +++++++++++++++---------------- sys/tools/vnode_if.awk | 43 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 74 insertions(+), 33 deletions(-) diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 2eec46774327..d7a69b49d7f0 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -5597,21 +5597,21 @@ vop_rename_pre(void *ap) #ifdef DEBUG_VFS_LOCKS void -vop_fplookup_vexec_pre(void *ap __unused) +vop_fplookup_vexec_debugpre(void *ap __unused) { VFS_SMR_ASSERT_ENTERED(); } void -vop_fplookup_vexec_post(void *ap __unused, int rc __unused) +vop_fplookup_vexec_debugpost(void *ap __unused, int rc __unused) { VFS_SMR_ASSERT_ENTERED(); } void -vop_strategy_pre(void *ap) +vop_strategy_debugpre(void *ap) { struct vop_strategy_args *a; struct buf *bp; @@ -5635,7 +5635,7 @@ vop_strategy_pre(void *ap) } void -vop_lock_pre(void *ap) +vop_lock_debugpre(void *ap) { struct vop_lock1_args *a = ap; @@ -5646,7 +5646,7 @@ vop_lock_pre(void *ap) } void -vop_lock_post(void *ap, int rc) +vop_lock_debugpost(void *ap, int rc) { struct vop_lock1_args *a = ap; @@ -5656,7 +5656,7 @@ vop_lock_post(void *ap, int rc) } void -vop_unlock_pre(void *ap) +vop_unlock_debugpre(void *ap) { struct vop_unlock_args *a = ap; @@ -5664,7 +5664,7 @@ vop_unlock_pre(void *ap) } void -vop_need_inactive_pre(void *ap) +vop_need_inactive_debugpre(void *ap) { struct vop_need_inactive_args *a = ap; @@ -5672,7 +5672,7 @@ vop_need_inactive_pre(void *ap) } void -vop_need_inactive_post(void *ap, int rc) +vop_need_inactive_debugpost(void *ap, int rc) { struct vop_need_inactive_args *a = ap; diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src index 5c0649fdadaf..e5a7b389fb30 100644 --- a/sys/kern/vnode_if.src +++ b/sys/kern/vnode_if.src @@ -147,8 +147,8 @@ vop_close { %% fplookup_vexec vp - - - -%! fplookup_vexec pre vop_fplookup_vexec_pre -%! fplookup_vexec post vop_fplookup_vexec_post +%! fplookup_vexec debugpre vop_fplookup_vexec_debugpre +%! fplookup_vexec debugpost vop_fplookup_vexec_debugpost vop_fplookup_vexec { IN struct vnode *vp; @@ -379,8 +379,8 @@ vop_inactive { IN struct thread *td; }; -%! need_inactive pre vop_need_inactive_pre -%! need_inactive post vop_need_inactive_post +%! need_inactive debugpre vop_need_inactive_debugpre +%! need_inactive debugpost vop_need_inactive_debugpost vop_need_inactive { IN struct vnode *vp; @@ -395,8 +395,8 @@ vop_reclaim { }; -%! lock1 pre vop_lock_pre -%! lock1 post vop_lock_post +%! lock1 debugpre vop_lock_debugpre +%! lock1 debugpost vop_lock_debugpost vop_lock1 { IN struct vnode *vp; @@ -406,7 +406,7 @@ vop_lock1 { }; -%! unlock pre vop_unlock_pre +%! unlock debugpre vop_unlock_debugpre vop_unlock { IN struct vnode *vp; @@ -426,7 +426,7 @@ vop_bmap { %% strategy vp L L L -%! strategy pre vop_strategy_pre +%! strategy debugpre vop_strategy_debugpre vop_strategy { IN struct vnode *vp; diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 8273842a91f5..3a83ea5af6e1 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -869,23 +869,23 @@ void vop_symlink_post(void *a, int rc); int vop_sigdefer(struct vop_vector *vop, struct vop_generic_args *a); #ifdef DEBUG_VFS_LOCKS -void vop_fplookup_vexec_pre(void *a); -void vop_fplookup_vexec_post(void *a, int rc); -void vop_strategy_pre(void *a); -void vop_lock_pre(void *a); -void vop_lock_post(void *a, int rc); -void vop_unlock_pre(void *a); -void vop_need_inactive_pre(void *a); -void vop_need_inactive_post(void *a, int rc); +void vop_fplookup_vexec_debugpre(void *a); +void vop_fplookup_vexec_debugpost(void *a, int rc); +void vop_strategy_debugpre(void *a); +void vop_lock_debugpre(void *a); +void vop_lock_debugpost(void *a, int rc); +void vop_unlock_debugpre(void *a); +void vop_need_inactive_debugpre(void *a); +void vop_need_inactive_debugpost(void *a, int rc); #else -#define vop_fplookup_vexec_pre(x) do { } while (0) -#define vop_fplookup_vexec_post(x, y) do { } while (0) -#define vop_strategy_pre(x) do { } while (0) -#define vop_lock_pre(x) do { } while (0) -#define vop_lock_post(x, y) do { } while (0) -#define vop_unlock_pre(x) do { } while (0) -#define vop_need_inactive_pre(x) do { } while (0) -#define vop_need_inactive_post(x, y) do { } while (0) +#define vop_fplookup_vexec_debugpre(x) do { } while (0) +#define vop_fplookup_vexec_debugpost(x, y) do { } while (0) +#define vop_strategy_debugpre(x) do { } while (0) +#define vop_lock_debugpre(x) do { } while (0) +#define vop_lock_debugpost(x, y) do { } while (0) +#define vop_unlock_debugpre(x) do { } while (0) +#define vop_need_inactive_debugpre(x) do { } while (0) +#define vop_need_inactive_debugpost(x, y) do { } while (0) #endif void vop_rename_fail(struct vop_rename_args *ap); diff --git a/sys/tools/vnode_if.awk b/sys/tools/vnode_if.awk index cd138bef75da..486f0e6b2ce1 100644 --- a/sys/tools/vnode_if.awk +++ b/sys/tools/vnode_if.awk @@ -87,6 +87,24 @@ function add_debug_code(name, arg, pos, ind) } } +function add_debugpre(name) +{ + if (lockdata[name, "debugpre"]) { + printc("#ifdef DEBUG_VFS_LOCKS"); + printc("\t"lockdata[name, "debugpre"]"(a);"); + printc("#endif"); + } +} + +function add_debugpost(name) +{ + if (lockdata[name, "debugpost"]) { + printc("#ifdef DEBUG_VFS_LOCKS"); + printc("\t"lockdata[name, "debugpost"]"(a, rc);"); + printc("#endif"); + } +} + function add_pre(name) { if (lockdata[name, "pre"]) { @@ -101,6 +119,15 @@ function add_post(name) } } +function can_inline(name) +{ + if (lockdata[name, "pre"]) + return 0; + if (lockdata[name, "post"]) + return 0; + return 1; +} + function find_arg_with_type (type) { for (jj = 0; jj < numargs; jj++) { @@ -213,7 +240,8 @@ while ((getline < srcfile) > 0) { if ($1 ~ /^%!/) { if (NF != 4 || - ($3 != "pre" && $3 != "post")) { + ($3 != "pre" && $3 != "post" && + $3 != "debugpre" && $3 != "debugpost")) { die("Invalid %s construction", "%!"); continue; } @@ -316,7 +344,18 @@ while ((getline < srcfile) > 0) { printh("\ta.a_gen.a_desc = &" name "_desc;"); for (i = 0; i < numargs; ++i) printh("\ta.a_" args[i] " = " args[i] ";"); + if (can_inline(name)) { + printh("\n#if !defined(DEBUG_VFS_LOCKS) && !defined(INVARIANTS) && !defined(KTR)"); + printh("\tif (!SDT_PROBES_ENABLED())"); + printh("\t\treturn (" args[0]"->v_op->"name"(&a));"); + printh("\telse"); + printh("\t\treturn (" uname "_APV("args[0]"->v_op, &a));"); + printh("#else"); + } printh("\treturn (" uname "_APV("args[0]"->v_op, &a));"); + if (can_inline(name)) + printh("#endif"); + printh("}"); printh(""); @@ -364,6 +403,7 @@ while ((getline < srcfile) > 0) { printc("\t (\"Wrong a_desc in " name "(%p, %p)\", a->a_" args[0]", a));"); printc("\tVNASSERT(vop != NULL, a->a_" args[0]", (\"No "name"(%p, %p)\", a->a_" args[0]", a));") printc("\tKTR_START" ctrstr); + add_debugpre(name); add_pre(name); for (i = 0; i < numargs; ++i) add_debug_code(name, args[i], "Entry", "\t"); @@ -382,6 +422,7 @@ while ((getline < srcfile) > 0) { add_debug_code(name, args[i], "Error", "\t\t"); printc("\t}"); add_post(name); + add_debugpost(name); printc("\tKTR_STOP" ctrstr); printc("\treturn (rc);"); printc("}\n"); From 19afc65a7ef34ec6de28a3639e39792a292dc3c2 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 30 Jul 2020 17:43:23 +0000 Subject: [PATCH 270/287] ip6_output(): Check the return value of in6_getlinkifnet(). If the destination address has an embedded scope ID, make sure that it corresponds to a valid ifnet before proceeding. Otherwise a sendto() with a bogus link-local address can trigger a NULL pointer dereference. Reported by: syzkaller Reviewed by: ae Fixes: r358572 Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25887 --- sys/netinet6/ip6_output.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 941af58d367a..975a000f1c81 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -761,6 +761,10 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, IN6_IS_ADDR_MC_NODELOCAL(&dst_sa.sin6_addr)) { if (scopeid > 0) { ifp = in6_getlinkifnet(scopeid); + if (ifp == NULL) { + error = EHOSTUNREACH; + goto bad; + } *dst = dst_sa; /* XXX */ goto nonh6lookup; } From 551cf5ab71bb44ccf22e0c317cc83bf199bde37b Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 30 Jul 2020 22:13:15 +0000 Subject: [PATCH 271/287] fd: predict in fdrop --- sys/sys/file.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/sys/sys/file.h b/sys/sys/file.h index 65b73158f8d9..10d483764467 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -279,21 +279,22 @@ int fgetvp_read(struct thread *td, int fd, cap_rights_t *rightsp, int fgetvp_write(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp); -static __inline int -_fnoop(void) -{ - - return (0); -} - static __inline __result_use_check bool fhold(struct file *fp) { return (refcount_acquire_checked(&fp->f_count)); } -#define fdrop(fp, td) \ - (refcount_release(&(fp)->f_count) ? _fdrop((fp), (td)) : _fnoop()) +#define fdrop(fp, td) ({ \ + struct file *_fp; \ + int _error; \ + \ + _error = 0; \ + _fp = (fp); \ + if (__predict_false(refcount_release(&_fp->f_count))) \ + _error = _fdrop(_fp, td); \ + _error; \ +}) static __inline fo_rdwr_t fo_read; static __inline fo_rdwr_t fo_write; From 952759111eada77759b5e447feb21c1457dc5349 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 30 Jul 2020 22:14:04 +0000 Subject: [PATCH 272/287] Further depessimize priv_check_cred_vfs_generation --- sys/kern/kern_priv.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/sys/kern/kern_priv.c b/sys/kern/kern_priv.c index a912336cbbca..710e9b90894f 100644 --- a/sys/kern/kern_priv.c +++ b/sys/kern/kern_priv.c @@ -247,8 +247,8 @@ priv_check(struct thread *td, int priv) return (priv_check_cred(td->td_ucred, priv)); } -int -priv_check_cred_vfs_generation(struct ucred *cred) +static int __noinline +priv_check_cred_vfs_generation_slow(struct ucred *cred) { int error; @@ -271,3 +271,18 @@ priv_check_cred_vfs_generation(struct ucred *cred) return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, true)); } + +int +priv_check_cred_vfs_generation(struct ucred *cred) +{ + int error; + + if (__predict_false(mac_priv_check_fp_flag || + mac_priv_grant_fp_flag || SDT_PROBES_ENABLED())) + return (priv_check_cred_vfs_generation_slow(cred)); + + error = EPERM; + if (!jailed(cred) && cred->cr_uid == 0 && suser_enabled) + error = 0; + return (error); +} From cb90ef28758d355d151c32036c809f46e661f6ed Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 30 Jul 2020 22:52:18 +0000 Subject: [PATCH 273/287] cache: drop the useless numchecks counter --- sys/kern/vfs_cache.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 62f31fc47ee9..6eff71606ac9 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -419,7 +419,6 @@ STATNODE_COUNTER(numcachehv, "Number of namecache entries with vnodes held"); STATNODE_COUNTER(numdrops, "Number of dropped entries due to reaching the limit"); STATNODE_COUNTER(dothits, "Number of '.' hits"); STATNODE_COUNTER(dotdothits, "Number of '..' hits"); -STATNODE_COUNTER(numchecks, "Number of checks in lookup"); STATNODE_COUNTER(nummiss, "Number of cache misses"); STATNODE_COUNTER(nummisszap, "Number of cache misses we do not want to cache"); STATNODE_COUNTER(numposzaps, @@ -1315,7 +1314,6 @@ cache_lookup_nomakeentry(struct vnode *dvp, struct vnode **vpp, rw_wlock(blp); CK_LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) { - counter_u64_add(numchecks, 1); if (ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen && !bcmp(ncp->nc_name, cnp->cn_nameptr, ncp->nc_nlen)) break; @@ -1460,7 +1458,6 @@ cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, } CK_LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) { - counter_u64_add(numchecks, 1); if (ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen && !bcmp(ncp->nc_name, cnp->cn_nameptr, ncp->nc_nlen)) break; @@ -3366,7 +3363,6 @@ cache_fplookup_next(struct cache_fpl *fpl) hash = cache_get_hash(cnp->cn_nameptr, cnp->cn_namelen, dvp); CK_LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) { - counter_u64_add(numchecks, 1); if (ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen && !bcmp(ncp->nc_name, cnp->cn_nameptr, ncp->nc_nlen)) break; From 5b0acaf75ff8d416a51c820b1c062dada0edaf66 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 30 Jul 2020 22:56:57 +0000 Subject: [PATCH 274/287] Fix tinderbox build after r363714 --- sys/security/mac/mac_framework.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h index 7ef13dcce758..6ae634bd2dfe 100644 --- a/sys/security/mac/mac_framework.h +++ b/sys/security/mac/mac_framework.h @@ -259,7 +259,11 @@ void mac_posixshm_destroy(struct shmfd *); void mac_posixshm_init(struct shmfd *); int mac_priv_check_impl(struct ucred *cred, int priv); +#ifdef MAC extern bool mac_priv_check_fp_flag; +#else +#define mac_priv_check_fp_flag 0 +#endif static inline int mac_priv_check(struct ucred *cred, int priv) { @@ -270,7 +274,11 @@ mac_priv_check(struct ucred *cred, int priv) } int mac_priv_grant_impl(struct ucred *cred, int priv); +#ifdef MAC extern bool mac_priv_grant_fp_flag; +#else +#define mac_priv_grant_fp_flag 0 +#endif static inline int mac_priv_grant(struct ucred *cred, int priv) { From 8ae93acf475c3c02f1770372d7f8cdf58d96eab4 Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Thu, 30 Jul 2020 23:17:30 +0000 Subject: [PATCH 275/287] Import PCG-C master, 2019-07-18 (83252d9c23df9c82ecb42210afed61a7b42402d7) --- include/pcg_variants.h | 2544 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2544 insertions(+) create mode 100644 include/pcg_variants.h diff --git a/include/pcg_variants.h b/include/pcg_variants.h new file mode 100644 index 000000000000..768fb75ae93b --- /dev/null +++ b/include/pcg_variants.h @@ -0,0 +1,2544 @@ +/* + * PCG Random Number Generation for C. + * + * Copyright 2014-2019 Melissa O'Neill , + * and the PCG Project contributors. + * + * SPDX-License-Identifier: (Apache-2.0 OR MIT) + * + * Licensed under the Apache License, Version 2.0 (provided in + * LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0) + * or under the MIT license (provided in LICENSE-MIT.txt and at + * http://opensource.org/licenses/MIT), at your option. This file may not + * be copied, modified, or distributed except according to those terms. + * + * Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See your chosen license for details. + * + * For additional information about the PCG random number generation scheme, + * visit http://www.pcg-random.org/. + */ + +/* + * This code is derived from the canonical C++ PCG implementation, which + * has many additional features and is preferable if you can use C++ in + * your project. + * + * Much of the derivation was performed mechanically. In particular, the + * output functions were generated by compiling the C++ output functions + * into LLVM bitcode and then transforming that using the LLVM C backend + * (from https://github.com/draperlaboratory/llvm-cbe), and then + * postprocessing and hand editing the output. + * + * Much of the remaining code was generated by C-preprocessor metaprogramming. + */ + +#ifndef PCG_VARIANTS_H_INCLUDED +#define PCG_VARIANTS_H_INCLUDED 1 + +#include + +#if __SIZEOF_INT128__ + typedef __uint128_t pcg128_t; + #define PCG_128BIT_CONSTANT(high,low) \ + ((((pcg128_t)high) << 64) + low) + #define PCG_HAS_128BIT_OPS 1 +#endif + +#if __GNUC_GNU_INLINE__ && !defined(__cplusplus) + #error Nonstandard GNU inlining semantics. Compile with -std=c99 or better. + /* We could instead use macros PCG_INLINE and PCG_EXTERN_INLINE + but better to just reject ancient C code. */ +#endif + +#if __cplusplus +extern "C" { +#endif + +/* + * Rotate helper functions. + */ + +inline uint8_t pcg_rotr_8(uint8_t value, unsigned int rot) +{ +/* Unfortunately, clang is kinda pathetic when it comes to properly + * recognizing idiomatic rotate code, so for clang we actually provide + * assembler directives (enabled with PCG_USE_INLINE_ASM). Boo, hiss. + */ +#if PCG_USE_INLINE_ASM && __clang__ && (__x86_64__ || __i386__) + asm ("rorb %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +#else + return (value >> rot) | (value << ((- rot) & 7)); +#endif +} + +inline uint16_t pcg_rotr_16(uint16_t value, unsigned int rot) +{ +#if PCG_USE_INLINE_ASM && __clang__ && (__x86_64__ || __i386__) + asm ("rorw %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +#else + return (value >> rot) | (value << ((- rot) & 15)); +#endif +} + +inline uint32_t pcg_rotr_32(uint32_t value, unsigned int rot) +{ +#if PCG_USE_INLINE_ASM && __clang__ && (__x86_64__ || __i386__) + asm ("rorl %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +#else + return (value >> rot) | (value << ((- rot) & 31)); +#endif +} + +inline uint64_t pcg_rotr_64(uint64_t value, unsigned int rot) +{ +#if 0 && PCG_USE_INLINE_ASM && __clang__ && __x86_64__ + /* For whatever reason, clang actually *does* generate rotq by + itself, so we don't need this code. */ + asm ("rorq %%cl, %0" : "=r" (value) : "0" (value), "c" (rot)); + return value; +#else + return (value >> rot) | (value << ((- rot) & 63)); +#endif +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_rotr_128(pcg128_t value, unsigned int rot) +{ + return (value >> rot) | (value << ((- rot) & 127)); +} +#endif + +/* + * Output functions. These are the core of the PCG generation scheme. + */ + +/* XSH RS */ + +inline uint8_t pcg_output_xsh_rs_16_8(uint16_t state) +{ + return (uint8_t)(((state >> 7u) ^ state) >> ((state >> 14u) + 3u)); +} + +inline uint16_t pcg_output_xsh_rs_32_16(uint32_t state) +{ + return (uint16_t)(((state >> 11u) ^ state) >> ((state >> 30u) + 11u)); +} + +inline uint32_t pcg_output_xsh_rs_64_32(uint64_t state) +{ + + return (uint32_t)(((state >> 22u) ^ state) >> ((state >> 61u) + 22u)); +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_output_xsh_rs_128_64(pcg128_t state) +{ + return (uint64_t)(((state >> 43u) ^ state) >> ((state >> 124u) + 45u)); +} +#endif + +/* XSH RR */ + +inline uint8_t pcg_output_xsh_rr_16_8(uint16_t state) +{ + return pcg_rotr_8(((state >> 5u) ^ state) >> 5u, state >> 13u); +} + +inline uint16_t pcg_output_xsh_rr_32_16(uint32_t state) +{ + return pcg_rotr_16(((state >> 10u) ^ state) >> 12u, state >> 28u); +} + +inline uint32_t pcg_output_xsh_rr_64_32(uint64_t state) +{ + return pcg_rotr_32(((state >> 18u) ^ state) >> 27u, state >> 59u); +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_output_xsh_rr_128_64(pcg128_t state) +{ + return pcg_rotr_64(((state >> 35u) ^ state) >> 58u, state >> 122u); +} +#endif + +/* RXS M XS */ + +inline uint8_t pcg_output_rxs_m_xs_8_8(uint8_t state) +{ + uint8_t word = ((state >> ((state >> 6u) + 2u)) ^ state) * 217u; + return (word >> 6u) ^ word; +} + +inline uint16_t pcg_output_rxs_m_xs_16_16(uint16_t state) +{ + uint16_t word = ((state >> ((state >> 13u) + 3u)) ^ state) * 62169u; + return (word >> 11u) ^ word; +} + +inline uint32_t pcg_output_rxs_m_xs_32_32(uint32_t state) +{ + uint32_t word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +inline uint64_t pcg_output_rxs_m_xs_64_64(uint64_t state) +{ + uint64_t word = ((state >> ((state >> 59u) + 5u)) ^ state) + * 12605985483714917081ull; + return (word >> 43u) ^ word; +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_output_rxs_m_xs_128_128(pcg128_t state) +{ + pcg128_t word = ((state >> ((state >> 122u) + 6u)) ^ state) + * (PCG_128BIT_CONSTANT(17766728186571221404ULL, + 12605985483714917081ULL)); + /* 327738287884841127335028083622016905945 */ + return (word >> 86u) ^ word; +} +#endif + +/* RXS M */ + +inline uint8_t pcg_output_rxs_m_16_8(uint16_t state) +{ + return (((state >> ((state >> 13u) + 3u)) ^ state) * 62169u) >> 8u; +} + +inline uint16_t pcg_output_rxs_m_32_16(uint32_t state) +{ + return (((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u) >> 16u; +} + +inline uint32_t pcg_output_rxs_m_64_32(uint64_t state) +{ + return (((state >> ((state >> 59u) + 5u)) ^ state) + * 12605985483714917081ull) >> 32u; +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_output_rxs_m_128_64(pcg128_t state) +{ + return (((state >> ((state >> 122u) + 6u)) ^ state) + * (PCG_128BIT_CONSTANT(17766728186571221404ULL, + 12605985483714917081ULL))) >> 64u; + /* 327738287884841127335028083622016905945 */ +} +#endif + +/* XSL RR (only defined for >= 64 bits) */ + +inline uint32_t pcg_output_xsl_rr_64_32(uint64_t state) +{ + return pcg_rotr_32(((uint32_t)(state >> 32u)) ^ (uint32_t)state, + state >> 59u); +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) +{ + return pcg_rotr_64(((uint64_t)(state >> 64u)) ^ (uint64_t)state, + state >> 122u); +} +#endif + +/* XSL RR RR (only defined for >= 64 bits) */ + +inline uint64_t pcg_output_xsl_rr_rr_64_64(uint64_t state) +{ + uint32_t rot1 = (uint32_t)(state >> 59u); + uint32_t high = (uint32_t)(state >> 32u); + uint32_t low = (uint32_t)state; + uint32_t xored = high ^ low; + uint32_t newlow = pcg_rotr_32(xored, rot1); + uint32_t newhigh = pcg_rotr_32(high, newlow & 31u); + return (((uint64_t)newhigh) << 32u) | newlow; +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_output_xsl_rr_rr_128_128(pcg128_t state) +{ + uint32_t rot1 = (uint32_t)(state >> 122u); + uint64_t high = (uint64_t)(state >> 64u); + uint64_t low = (uint64_t)state; + uint64_t xored = high ^ low; + uint64_t newlow = pcg_rotr_64(xored, rot1); + uint64_t newhigh = pcg_rotr_64(high, newlow & 63u); + return (((pcg128_t)newhigh) << 64u) | newlow; +} +#endif + +#define PCG_DEFAULT_MULTIPLIER_8 141U +#define PCG_DEFAULT_MULTIPLIER_16 12829U +#define PCG_DEFAULT_MULTIPLIER_32 747796405U +#define PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL + +#define PCG_DEFAULT_INCREMENT_8 77U +#define PCG_DEFAULT_INCREMENT_16 47989U +#define PCG_DEFAULT_INCREMENT_32 2891336453U +#define PCG_DEFAULT_INCREMENT_64 1442695040888963407ULL + +#if PCG_HAS_128BIT_OPS +#define PCG_DEFAULT_MULTIPLIER_128 \ + PCG_128BIT_CONSTANT(2549297995355413924ULL,4865540595714422341ULL) +#define PCG_DEFAULT_INCREMENT_128 \ + PCG_128BIT_CONSTANT(6364136223846793005ULL,1442695040888963407ULL) +#endif + +/* + * Static initialization constants (if you can't call srandom for some + * bizarre reason). + */ + +#define PCG_STATE_ONESEQ_8_INITIALIZER { 0xd7U } +#define PCG_STATE_ONESEQ_16_INITIALIZER { 0x20dfU } +#define PCG_STATE_ONESEQ_32_INITIALIZER { 0x46b56677U } +#define PCG_STATE_ONESEQ_64_INITIALIZER { 0x4d595df4d0f33173ULL } +#if PCG_HAS_128BIT_OPS +#define PCG_STATE_ONESEQ_128_INITIALIZER \ + { PCG_128BIT_CONSTANT(0xb8dc10e158a92392ULL, 0x98046df007ec0a53ULL) } +#endif + +#define PCG_STATE_UNIQUE_8_INITIALIZER PCG_STATE_ONESEQ_8_INITIALIZER +#define PCG_STATE_UNIQUE_16_INITIALIZER PCG_STATE_ONESEQ_16_INITIALIZER +#define PCG_STATE_UNIQUE_32_INITIALIZER PCG_STATE_ONESEQ_32_INITIALIZER +#define PCG_STATE_UNIQUE_64_INITIALIZER PCG_STATE_ONESEQ_64_INITIALIZER +#if PCG_HAS_128BIT_OPS +#define PCG_STATE_UNIQUE_128_INITIALIZER PCG_STATE_ONESEQ_128_INITIALIZER +#endif + +#define PCG_STATE_MCG_8_INITIALIZER { 0xe5U } +#define PCG_STATE_MCG_16_INITIALIZER { 0xa5e5U } +#define PCG_STATE_MCG_32_INITIALIZER { 0xd15ea5e5U } +#define PCG_STATE_MCG_64_INITIALIZER { 0xcafef00dd15ea5e5ULL } +#if PCG_HAS_128BIT_OPS +#define PCG_STATE_MCG_128_INITIALIZER \ + { PCG_128BIT_CONSTANT(0x0000000000000000ULL, 0xcafef00dd15ea5e5ULL) } +#endif + +#define PCG_STATE_SETSEQ_8_INITIALIZER { 0x9bU, 0xdbU } +#define PCG_STATE_SETSEQ_16_INITIALIZER { 0xe39bU, 0x5bdbU } +#define PCG_STATE_SETSEQ_32_INITIALIZER { 0xec02d89bU, 0x94b95bdbU } +#define PCG_STATE_SETSEQ_64_INITIALIZER \ + { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL } +#if PCG_HAS_128BIT_OPS +#define PCG_STATE_SETSEQ_128_INITIALIZER \ + { PCG_128BIT_CONSTANT(0x979c9a98d8462005ULL, 0x7d3e9cb6cfe0549bULL), \ + PCG_128BIT_CONSTANT(0x0000000000000001ULL, 0xda3e39cb94b95bdbULL) } +#endif + +/* Representations for the oneseq, mcg, and unique variants */ + +struct pcg_state_8 { + uint8_t state; +}; + +struct pcg_state_16 { + uint16_t state; +}; + +struct pcg_state_32 { + uint32_t state; +}; + +struct pcg_state_64 { + uint64_t state; +}; + +#if PCG_HAS_128BIT_OPS +struct pcg_state_128 { + pcg128_t state; +}; +#endif + +/* Representations setseq variants */ + +struct pcg_state_setseq_8 { + uint8_t state; + uint8_t inc; +}; + +struct pcg_state_setseq_16 { + uint16_t state; + uint16_t inc; +}; + +struct pcg_state_setseq_32 { + uint32_t state; + uint32_t inc; +}; + +struct pcg_state_setseq_64 { + uint64_t state; + uint64_t inc; +}; + +#if PCG_HAS_128BIT_OPS +struct pcg_state_setseq_128 { + pcg128_t state; + pcg128_t inc; +}; +#endif + +/* Multi-step advance functions (jump-ahead, jump-back) */ + +extern uint8_t pcg_advance_lcg_8(uint8_t state, uint8_t delta, uint8_t cur_mult, + uint8_t cur_plus); +extern uint16_t pcg_advance_lcg_16(uint16_t state, uint16_t delta, + uint16_t cur_mult, uint16_t cur_plus); +extern uint32_t pcg_advance_lcg_32(uint32_t state, uint32_t delta, + uint32_t cur_mult, uint32_t cur_plus); +extern uint64_t pcg_advance_lcg_64(uint64_t state, uint64_t delta, + uint64_t cur_mult, uint64_t cur_plus); + +#if PCG_HAS_128BIT_OPS +extern pcg128_t pcg_advance_lcg_128(pcg128_t state, pcg128_t delta, + pcg128_t cur_mult, pcg128_t cur_plus); +#endif + +/* Functions to advance the underlying LCG, one version for each size and + * each style. These functions are considered semi-private. There is rarely + * a good reason to call them directly. + */ + +inline void pcg_oneseq_8_step_r(struct pcg_state_8* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_8 + + PCG_DEFAULT_INCREMENT_8; +} + +inline void pcg_oneseq_8_advance_r(struct pcg_state_8* rng, uint8_t delta) +{ + rng->state = pcg_advance_lcg_8(rng->state, delta, PCG_DEFAULT_MULTIPLIER_8, + PCG_DEFAULT_INCREMENT_8); +} + +inline void pcg_mcg_8_step_r(struct pcg_state_8* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_8; +} + +inline void pcg_mcg_8_advance_r(struct pcg_state_8* rng, uint8_t delta) +{ + rng->state + = pcg_advance_lcg_8(rng->state, delta, PCG_DEFAULT_MULTIPLIER_8, 0u); +} + +inline void pcg_unique_8_step_r(struct pcg_state_8* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_8 + + (uint8_t)(((intptr_t)rng) | 1u); +} + +inline void pcg_unique_8_advance_r(struct pcg_state_8* rng, uint8_t delta) +{ + rng->state = pcg_advance_lcg_8(rng->state, delta, PCG_DEFAULT_MULTIPLIER_8, + (uint8_t)(((intptr_t)rng) | 1u)); +} + +inline void pcg_setseq_8_step_r(struct pcg_state_setseq_8* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_8 + rng->inc; +} + +inline void pcg_setseq_8_advance_r(struct pcg_state_setseq_8* rng, + uint8_t delta) +{ + rng->state = pcg_advance_lcg_8(rng->state, delta, PCG_DEFAULT_MULTIPLIER_8, + rng->inc); +} + +inline void pcg_oneseq_16_step_r(struct pcg_state_16* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_16 + + PCG_DEFAULT_INCREMENT_16; +} + +inline void pcg_oneseq_16_advance_r(struct pcg_state_16* rng, uint16_t delta) +{ + rng->state = pcg_advance_lcg_16( + rng->state, delta, PCG_DEFAULT_MULTIPLIER_16, PCG_DEFAULT_INCREMENT_16); +} + +inline void pcg_mcg_16_step_r(struct pcg_state_16* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_16; +} + +inline void pcg_mcg_16_advance_r(struct pcg_state_16* rng, uint16_t delta) +{ + rng->state + = pcg_advance_lcg_16(rng->state, delta, PCG_DEFAULT_MULTIPLIER_16, 0u); +} + +inline void pcg_unique_16_step_r(struct pcg_state_16* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_16 + + (uint16_t)(((intptr_t)rng) | 1u); +} + +inline void pcg_unique_16_advance_r(struct pcg_state_16* rng, uint16_t delta) +{ + rng->state + = pcg_advance_lcg_16(rng->state, delta, PCG_DEFAULT_MULTIPLIER_16, + (uint16_t)(((intptr_t)rng) | 1u)); +} + +inline void pcg_setseq_16_step_r(struct pcg_state_setseq_16* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_16 + rng->inc; +} + +inline void pcg_setseq_16_advance_r(struct pcg_state_setseq_16* rng, + uint16_t delta) +{ + rng->state = pcg_advance_lcg_16(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_16, rng->inc); +} + +inline void pcg_oneseq_32_step_r(struct pcg_state_32* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_32 + + PCG_DEFAULT_INCREMENT_32; +} + +inline void pcg_oneseq_32_advance_r(struct pcg_state_32* rng, uint32_t delta) +{ + rng->state = pcg_advance_lcg_32( + rng->state, delta, PCG_DEFAULT_MULTIPLIER_32, PCG_DEFAULT_INCREMENT_32); +} + +inline void pcg_mcg_32_step_r(struct pcg_state_32* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_32; +} + +inline void pcg_mcg_32_advance_r(struct pcg_state_32* rng, uint32_t delta) +{ + rng->state + = pcg_advance_lcg_32(rng->state, delta, PCG_DEFAULT_MULTIPLIER_32, 0u); +} + +inline void pcg_unique_32_step_r(struct pcg_state_32* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_32 + + (uint32_t)(((intptr_t)rng) | 1u); +} + +inline void pcg_unique_32_advance_r(struct pcg_state_32* rng, uint32_t delta) +{ + rng->state + = pcg_advance_lcg_32(rng->state, delta, PCG_DEFAULT_MULTIPLIER_32, + (uint32_t)(((intptr_t)rng) | 1u)); +} + +inline void pcg_setseq_32_step_r(struct pcg_state_setseq_32* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_32 + rng->inc; +} + +inline void pcg_setseq_32_advance_r(struct pcg_state_setseq_32* rng, + uint32_t delta) +{ + rng->state = pcg_advance_lcg_32(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_32, rng->inc); +} + +inline void pcg_oneseq_64_step_r(struct pcg_state_64* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64 + + PCG_DEFAULT_INCREMENT_64; +} + +inline void pcg_oneseq_64_advance_r(struct pcg_state_64* rng, uint64_t delta) +{ + rng->state = pcg_advance_lcg_64( + rng->state, delta, PCG_DEFAULT_MULTIPLIER_64, PCG_DEFAULT_INCREMENT_64); +} + +inline void pcg_mcg_64_step_r(struct pcg_state_64* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64; +} + +inline void pcg_mcg_64_advance_r(struct pcg_state_64* rng, uint64_t delta) +{ + rng->state + = pcg_advance_lcg_64(rng->state, delta, PCG_DEFAULT_MULTIPLIER_64, 0u); +} + +inline void pcg_unique_64_step_r(struct pcg_state_64* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64 + + (uint64_t)(((intptr_t)rng) | 1u); +} + +inline void pcg_unique_64_advance_r(struct pcg_state_64* rng, uint64_t delta) +{ + rng->state + = pcg_advance_lcg_64(rng->state, delta, PCG_DEFAULT_MULTIPLIER_64, + (uint64_t)(((intptr_t)rng) | 1u)); +} + +inline void pcg_setseq_64_step_r(struct pcg_state_setseq_64* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_64 + rng->inc; +} + +inline void pcg_setseq_64_advance_r(struct pcg_state_setseq_64* rng, + uint64_t delta) +{ + rng->state = pcg_advance_lcg_64(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_64, rng->inc); +} + +#if PCG_HAS_128BIT_OPS +inline void pcg_oneseq_128_step_r(struct pcg_state_128* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + + PCG_DEFAULT_INCREMENT_128; +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_oneseq_128_advance_r(struct pcg_state_128* rng, pcg128_t delta) +{ + rng->state + = pcg_advance_lcg_128(rng->state, delta, PCG_DEFAULT_MULTIPLIER_128, + PCG_DEFAULT_INCREMENT_128); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_mcg_128_step_r(struct pcg_state_128* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128; +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_mcg_128_advance_r(struct pcg_state_128* rng, pcg128_t delta) +{ + rng->state = pcg_advance_lcg_128(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_128, 0u); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_unique_128_step_r(struct pcg_state_128* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + + (pcg128_t)(((intptr_t)rng) | 1u); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_unique_128_advance_r(struct pcg_state_128* rng, pcg128_t delta) +{ + rng->state + = pcg_advance_lcg_128(rng->state, delta, PCG_DEFAULT_MULTIPLIER_128, + (pcg128_t)(((intptr_t)rng) | 1u)); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_setseq_128_step_r(struct pcg_state_setseq_128* rng) +{ + rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + rng->inc; +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_setseq_128_advance_r(struct pcg_state_setseq_128* rng, + pcg128_t delta) +{ + rng->state = pcg_advance_lcg_128(rng->state, delta, + PCG_DEFAULT_MULTIPLIER_128, rng->inc); +} +#endif + +/* Functions to seed the RNG state, one version for each size and each + * style. Unlike the step functions, regular users can and should call + * these functions. + */ + +inline void pcg_oneseq_8_srandom_r(struct pcg_state_8* rng, uint8_t initstate) +{ + rng->state = 0U; + pcg_oneseq_8_step_r(rng); + rng->state += initstate; + pcg_oneseq_8_step_r(rng); +} + +inline void pcg_mcg_8_srandom_r(struct pcg_state_8* rng, uint8_t initstate) +{ + rng->state = initstate | 1u; +} + +inline void pcg_unique_8_srandom_r(struct pcg_state_8* rng, uint8_t initstate) +{ + rng->state = 0U; + pcg_unique_8_step_r(rng); + rng->state += initstate; + pcg_unique_8_step_r(rng); +} + +inline void pcg_setseq_8_srandom_r(struct pcg_state_setseq_8* rng, + uint8_t initstate, uint8_t initseq) +{ + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_8_step_r(rng); + rng->state += initstate; + pcg_setseq_8_step_r(rng); +} + +inline void pcg_oneseq_16_srandom_r(struct pcg_state_16* rng, + uint16_t initstate) +{ + rng->state = 0U; + pcg_oneseq_16_step_r(rng); + rng->state += initstate; + pcg_oneseq_16_step_r(rng); +} + +inline void pcg_mcg_16_srandom_r(struct pcg_state_16* rng, uint16_t initstate) +{ + rng->state = initstate | 1u; +} + +inline void pcg_unique_16_srandom_r(struct pcg_state_16* rng, + uint16_t initstate) +{ + rng->state = 0U; + pcg_unique_16_step_r(rng); + rng->state += initstate; + pcg_unique_16_step_r(rng); +} + +inline void pcg_setseq_16_srandom_r(struct pcg_state_setseq_16* rng, + uint16_t initstate, uint16_t initseq) +{ + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_16_step_r(rng); + rng->state += initstate; + pcg_setseq_16_step_r(rng); +} + +inline void pcg_oneseq_32_srandom_r(struct pcg_state_32* rng, + uint32_t initstate) +{ + rng->state = 0U; + pcg_oneseq_32_step_r(rng); + rng->state += initstate; + pcg_oneseq_32_step_r(rng); +} + +inline void pcg_mcg_32_srandom_r(struct pcg_state_32* rng, uint32_t initstate) +{ + rng->state = initstate | 1u; +} + +inline void pcg_unique_32_srandom_r(struct pcg_state_32* rng, + uint32_t initstate) +{ + rng->state = 0U; + pcg_unique_32_step_r(rng); + rng->state += initstate; + pcg_unique_32_step_r(rng); +} + +inline void pcg_setseq_32_srandom_r(struct pcg_state_setseq_32* rng, + uint32_t initstate, uint32_t initseq) +{ + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_32_step_r(rng); + rng->state += initstate; + pcg_setseq_32_step_r(rng); +} + +inline void pcg_oneseq_64_srandom_r(struct pcg_state_64* rng, + uint64_t initstate) +{ + rng->state = 0U; + pcg_oneseq_64_step_r(rng); + rng->state += initstate; + pcg_oneseq_64_step_r(rng); +} + +inline void pcg_mcg_64_srandom_r(struct pcg_state_64* rng, uint64_t initstate) +{ + rng->state = initstate | 1u; +} + +inline void pcg_unique_64_srandom_r(struct pcg_state_64* rng, + uint64_t initstate) +{ + rng->state = 0U; + pcg_unique_64_step_r(rng); + rng->state += initstate; + pcg_unique_64_step_r(rng); +} + +inline void pcg_setseq_64_srandom_r(struct pcg_state_setseq_64* rng, + uint64_t initstate, uint64_t initseq) +{ + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_64_step_r(rng); + rng->state += initstate; + pcg_setseq_64_step_r(rng); +} + +#if PCG_HAS_128BIT_OPS +inline void pcg_oneseq_128_srandom_r(struct pcg_state_128* rng, + pcg128_t initstate) +{ + rng->state = 0U; + pcg_oneseq_128_step_r(rng); + rng->state += initstate; + pcg_oneseq_128_step_r(rng); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_mcg_128_srandom_r(struct pcg_state_128* rng, pcg128_t initstate) +{ + rng->state = initstate | 1u; +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_unique_128_srandom_r(struct pcg_state_128* rng, + pcg128_t initstate) +{ + rng->state = 0U; + pcg_unique_128_step_r(rng); + rng->state += initstate; + pcg_unique_128_step_r(rng); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline void pcg_setseq_128_srandom_r(struct pcg_state_setseq_128* rng, + pcg128_t initstate, pcg128_t initseq) +{ + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg_setseq_128_step_r(rng); + rng->state += initstate; + pcg_setseq_128_step_r(rng); +} +#endif + +/* Now, finally we create each of the individual generators. We provide + * a random_r function that provides a random number of the appropriate + * type (using the full range of the type) and a boundedrand_r version + * that provides + * + * Implementation notes for boundedrand_r: + * + * To avoid bias, we need to make the range of the RNG a multiple of + * bound, which we do by dropping output less than a threshold. + * Let's consider a 32-bit case... A naive scheme to calculate the + * threshold would be to do + * + * uint32_t threshold = 0x100000000ull % bound; + * + * but 64-bit div/mod is slower than 32-bit div/mod (especially on + * 32-bit platforms). In essence, we do + * + * uint32_t threshold = (0x100000000ull-bound) % bound; + * + * because this version will calculate the same modulus, but the LHS + * value is less than 2^32. + * + * (Note that using modulo is only wise for good RNGs, poorer RNGs + * such as raw LCGs do better using a technique based on division.) + * Empricical tests show that division is preferable to modulus for + * reducting the range of an RNG. It's faster, and sometimes it can + * even be statistically prefereable. + */ + +/* Generation functions for XSH RS */ + +inline uint8_t pcg_oneseq_16_xsh_rs_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_oneseq_16_step_r(rng); + return pcg_output_xsh_rs_16_8(oldstate); +} + +inline uint8_t pcg_oneseq_16_xsh_rs_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_oneseq_16_xsh_rs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_oneseq_32_xsh_rs_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_oneseq_32_step_r(rng); + return pcg_output_xsh_rs_32_16(oldstate); +} + +inline uint16_t pcg_oneseq_32_xsh_rs_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_oneseq_32_xsh_rs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_oneseq_64_xsh_rs_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_xsh_rs_64_32(oldstate); +} + +inline uint32_t pcg_oneseq_64_xsh_rs_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_64_xsh_rs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_oneseq_128_xsh_rs_64_random_r(struct pcg_state_128* rng) +{ + pcg_oneseq_128_step_r(rng); + return pcg_output_xsh_rs_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_oneseq_128_xsh_rs_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_128_xsh_rs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_unique_16_xsh_rs_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_unique_16_step_r(rng); + return pcg_output_xsh_rs_16_8(oldstate); +} + +inline uint8_t pcg_unique_16_xsh_rs_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_unique_16_xsh_rs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_unique_32_xsh_rs_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_unique_32_step_r(rng); + return pcg_output_xsh_rs_32_16(oldstate); +} + +inline uint16_t pcg_unique_32_xsh_rs_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_unique_32_xsh_rs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_unique_64_xsh_rs_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_xsh_rs_64_32(oldstate); +} + +inline uint32_t pcg_unique_64_xsh_rs_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_64_xsh_rs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_unique_128_xsh_rs_64_random_r(struct pcg_state_128* rng) +{ + pcg_unique_128_step_r(rng); + return pcg_output_xsh_rs_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_unique_128_xsh_rs_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_128_xsh_rs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_setseq_16_xsh_rs_8_random_r(struct pcg_state_setseq_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_setseq_16_step_r(rng); + return pcg_output_xsh_rs_16_8(oldstate); +} + +inline uint8_t +pcg_setseq_16_xsh_rs_8_boundedrand_r(struct pcg_state_setseq_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_setseq_16_xsh_rs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t +pcg_setseq_32_xsh_rs_16_random_r(struct pcg_state_setseq_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_setseq_32_step_r(rng); + return pcg_output_xsh_rs_32_16(oldstate); +} + +inline uint16_t +pcg_setseq_32_xsh_rs_16_boundedrand_r(struct pcg_state_setseq_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_setseq_32_xsh_rs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t +pcg_setseq_64_xsh_rs_32_random_r(struct pcg_state_setseq_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsh_rs_64_32(oldstate); +} + +inline uint32_t +pcg_setseq_64_xsh_rs_32_boundedrand_r(struct pcg_state_setseq_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_64_xsh_rs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsh_rs_64_random_r(struct pcg_state_setseq_128* rng) +{ + pcg_setseq_128_step_r(rng); + return pcg_output_xsh_rs_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsh_rs_64_boundedrand_r(struct pcg_state_setseq_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_128_xsh_rs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_mcg_16_xsh_rs_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_mcg_16_step_r(rng); + return pcg_output_xsh_rs_16_8(oldstate); +} + +inline uint8_t pcg_mcg_16_xsh_rs_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_mcg_16_xsh_rs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_mcg_32_xsh_rs_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_mcg_32_step_r(rng); + return pcg_output_xsh_rs_32_16(oldstate); +} + +inline uint16_t pcg_mcg_32_xsh_rs_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_mcg_32_xsh_rs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_mcg_64_xsh_rs_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_mcg_64_step_r(rng); + return pcg_output_xsh_rs_64_32(oldstate); +} + +inline uint32_t pcg_mcg_64_xsh_rs_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_mcg_64_xsh_rs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsh_rs_64_random_r(struct pcg_state_128* rng) +{ + pcg_mcg_128_step_r(rng); + return pcg_output_xsh_rs_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsh_rs_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_mcg_128_xsh_rs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for XSH RR */ + +inline uint8_t pcg_oneseq_16_xsh_rr_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_oneseq_16_step_r(rng); + return pcg_output_xsh_rr_16_8(oldstate); +} + +inline uint8_t pcg_oneseq_16_xsh_rr_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_oneseq_16_xsh_rr_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_oneseq_32_xsh_rr_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_oneseq_32_step_r(rng); + return pcg_output_xsh_rr_32_16(oldstate); +} + +inline uint16_t pcg_oneseq_32_xsh_rr_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_oneseq_32_xsh_rr_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_oneseq_64_xsh_rr_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline uint32_t pcg_oneseq_64_xsh_rr_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_64_xsh_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_oneseq_128_xsh_rr_64_random_r(struct pcg_state_128* rng) +{ + pcg_oneseq_128_step_r(rng); + return pcg_output_xsh_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_oneseq_128_xsh_rr_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_128_xsh_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_unique_16_xsh_rr_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_unique_16_step_r(rng); + return pcg_output_xsh_rr_16_8(oldstate); +} + +inline uint8_t pcg_unique_16_xsh_rr_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_unique_16_xsh_rr_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_unique_32_xsh_rr_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_unique_32_step_r(rng); + return pcg_output_xsh_rr_32_16(oldstate); +} + +inline uint16_t pcg_unique_32_xsh_rr_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_unique_32_xsh_rr_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_unique_64_xsh_rr_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline uint32_t pcg_unique_64_xsh_rr_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_64_xsh_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_unique_128_xsh_rr_64_random_r(struct pcg_state_128* rng) +{ + pcg_unique_128_step_r(rng); + return pcg_output_xsh_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_unique_128_xsh_rr_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_128_xsh_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_setseq_16_xsh_rr_8_random_r(struct pcg_state_setseq_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_setseq_16_step_r(rng); + return pcg_output_xsh_rr_16_8(oldstate); +} + +inline uint8_t +pcg_setseq_16_xsh_rr_8_boundedrand_r(struct pcg_state_setseq_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_setseq_16_xsh_rr_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t +pcg_setseq_32_xsh_rr_16_random_r(struct pcg_state_setseq_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_setseq_32_step_r(rng); + return pcg_output_xsh_rr_32_16(oldstate); +} + +inline uint16_t +pcg_setseq_32_xsh_rr_16_boundedrand_r(struct pcg_state_setseq_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_setseq_32_xsh_rr_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t +pcg_setseq_64_xsh_rr_32_random_r(struct pcg_state_setseq_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline uint32_t +pcg_setseq_64_xsh_rr_32_boundedrand_r(struct pcg_state_setseq_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_64_xsh_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsh_rr_64_random_r(struct pcg_state_setseq_128* rng) +{ + pcg_setseq_128_step_r(rng); + return pcg_output_xsh_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsh_rr_64_boundedrand_r(struct pcg_state_setseq_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_128_xsh_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_mcg_16_xsh_rr_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_mcg_16_step_r(rng); + return pcg_output_xsh_rr_16_8(oldstate); +} + +inline uint8_t pcg_mcg_16_xsh_rr_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_mcg_16_xsh_rr_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_mcg_32_xsh_rr_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_mcg_32_step_r(rng); + return pcg_output_xsh_rr_32_16(oldstate); +} + +inline uint16_t pcg_mcg_32_xsh_rr_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_mcg_32_xsh_rr_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_mcg_64_xsh_rr_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_mcg_64_step_r(rng); + return pcg_output_xsh_rr_64_32(oldstate); +} + +inline uint32_t pcg_mcg_64_xsh_rr_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_mcg_64_xsh_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsh_rr_64_random_r(struct pcg_state_128* rng) +{ + pcg_mcg_128_step_r(rng); + return pcg_output_xsh_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsh_rr_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_mcg_128_xsh_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for RXS M XS (no MCG versions because they + * don't make sense when you want to use the entire state) + */ + +inline uint8_t pcg_oneseq_8_rxs_m_xs_8_random_r(struct pcg_state_8* rng) +{ + uint8_t oldstate = rng->state; + pcg_oneseq_8_step_r(rng); + return pcg_output_rxs_m_xs_8_8(oldstate); +} + +inline uint8_t pcg_oneseq_8_rxs_m_xs_8_boundedrand_r(struct pcg_state_8* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_oneseq_8_rxs_m_xs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_oneseq_16_rxs_m_xs_16_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_oneseq_16_step_r(rng); + return pcg_output_rxs_m_xs_16_16(oldstate); +} + +inline uint16_t +pcg_oneseq_16_rxs_m_xs_16_boundedrand_r(struct pcg_state_16* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_oneseq_16_rxs_m_xs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_oneseq_32_rxs_m_xs_32_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_oneseq_32_step_r(rng); + return pcg_output_rxs_m_xs_32_32(oldstate); +} + +inline uint32_t +pcg_oneseq_32_rxs_m_xs_32_boundedrand_r(struct pcg_state_32* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_32_rxs_m_xs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint64_t pcg_oneseq_64_rxs_m_xs_64_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_rxs_m_xs_64_64(oldstate); +} + +inline uint64_t +pcg_oneseq_64_rxs_m_xs_64_boundedrand_r(struct pcg_state_64* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_64_rxs_m_xs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_oneseq_128_rxs_m_xs_128_random_r(struct pcg_state_128* rng) +{ + pcg_oneseq_128_step_r(rng); + return pcg_output_rxs_m_xs_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_oneseq_128_rxs_m_xs_128_boundedrand_r(struct pcg_state_128* rng, + pcg128_t bound) +{ + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_oneseq_128_rxs_m_xs_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint16_t pcg_unique_16_rxs_m_xs_16_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_unique_16_step_r(rng); + return pcg_output_rxs_m_xs_16_16(oldstate); +} + +inline uint16_t +pcg_unique_16_rxs_m_xs_16_boundedrand_r(struct pcg_state_16* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_unique_16_rxs_m_xs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_unique_32_rxs_m_xs_32_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_unique_32_step_r(rng); + return pcg_output_rxs_m_xs_32_32(oldstate); +} + +inline uint32_t +pcg_unique_32_rxs_m_xs_32_boundedrand_r(struct pcg_state_32* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_32_rxs_m_xs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint64_t pcg_unique_64_rxs_m_xs_64_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_rxs_m_xs_64_64(oldstate); +} + +inline uint64_t +pcg_unique_64_rxs_m_xs_64_boundedrand_r(struct pcg_state_64* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_64_rxs_m_xs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_unique_128_rxs_m_xs_128_random_r(struct pcg_state_128* rng) +{ + pcg_unique_128_step_r(rng); + return pcg_output_rxs_m_xs_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_unique_128_rxs_m_xs_128_boundedrand_r(struct pcg_state_128* rng, + pcg128_t bound) +{ + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_unique_128_rxs_m_xs_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_setseq_8_rxs_m_xs_8_random_r(struct pcg_state_setseq_8* rng) +{ + uint8_t oldstate = rng->state; + pcg_setseq_8_step_r(rng); + return pcg_output_rxs_m_xs_8_8(oldstate); +} + +inline uint8_t +pcg_setseq_8_rxs_m_xs_8_boundedrand_r(struct pcg_state_setseq_8* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_setseq_8_rxs_m_xs_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t +pcg_setseq_16_rxs_m_xs_16_random_r(struct pcg_state_setseq_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_setseq_16_step_r(rng); + return pcg_output_rxs_m_xs_16_16(oldstate); +} + +inline uint16_t +pcg_setseq_16_rxs_m_xs_16_boundedrand_r(struct pcg_state_setseq_16* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_setseq_16_rxs_m_xs_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t +pcg_setseq_32_rxs_m_xs_32_random_r(struct pcg_state_setseq_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_setseq_32_step_r(rng); + return pcg_output_rxs_m_xs_32_32(oldstate); +} + +inline uint32_t +pcg_setseq_32_rxs_m_xs_32_boundedrand_r(struct pcg_state_setseq_32* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_32_rxs_m_xs_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint64_t +pcg_setseq_64_rxs_m_xs_64_random_r(struct pcg_state_setseq_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_rxs_m_xs_64_64(oldstate); +} + +inline uint64_t +pcg_setseq_64_rxs_m_xs_64_boundedrand_r(struct pcg_state_setseq_64* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_64_rxs_m_xs_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_setseq_128_rxs_m_xs_128_random_r(struct pcg_state_setseq_128* rng) +{ + pcg_setseq_128_step_r(rng); + return pcg_output_rxs_m_xs_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_setseq_128_rxs_m_xs_128_boundedrand_r(struct pcg_state_setseq_128* rng, + pcg128_t bound) +{ + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_setseq_128_rxs_m_xs_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for RXS M */ + +inline uint8_t pcg_oneseq_16_rxs_m_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_oneseq_16_step_r(rng); + return pcg_output_rxs_m_16_8(oldstate); +} + +inline uint8_t pcg_oneseq_16_rxs_m_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_oneseq_16_rxs_m_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_oneseq_32_rxs_m_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_oneseq_32_step_r(rng); + return pcg_output_rxs_m_32_16(oldstate); +} + +inline uint16_t pcg_oneseq_32_rxs_m_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_oneseq_32_rxs_m_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_oneseq_64_rxs_m_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_rxs_m_64_32(oldstate); +} + +inline uint32_t pcg_oneseq_64_rxs_m_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_64_rxs_m_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_oneseq_128_rxs_m_64_random_r(struct pcg_state_128* rng) +{ + pcg_oneseq_128_step_r(rng); + return pcg_output_rxs_m_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_oneseq_128_rxs_m_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_128_rxs_m_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_unique_16_rxs_m_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_unique_16_step_r(rng); + return pcg_output_rxs_m_16_8(oldstate); +} + +inline uint8_t pcg_unique_16_rxs_m_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_unique_16_rxs_m_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_unique_32_rxs_m_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_unique_32_step_r(rng); + return pcg_output_rxs_m_32_16(oldstate); +} + +inline uint16_t pcg_unique_32_rxs_m_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_unique_32_rxs_m_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_unique_64_rxs_m_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_rxs_m_64_32(oldstate); +} + +inline uint32_t pcg_unique_64_rxs_m_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_64_rxs_m_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_unique_128_rxs_m_64_random_r(struct pcg_state_128* rng) +{ + pcg_unique_128_step_r(rng); + return pcg_output_rxs_m_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_unique_128_rxs_m_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_128_rxs_m_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_setseq_16_rxs_m_8_random_r(struct pcg_state_setseq_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_setseq_16_step_r(rng); + return pcg_output_rxs_m_16_8(oldstate); +} + +inline uint8_t +pcg_setseq_16_rxs_m_8_boundedrand_r(struct pcg_state_setseq_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_setseq_16_rxs_m_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_setseq_32_rxs_m_16_random_r(struct pcg_state_setseq_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_setseq_32_step_r(rng); + return pcg_output_rxs_m_32_16(oldstate); +} + +inline uint16_t +pcg_setseq_32_rxs_m_16_boundedrand_r(struct pcg_state_setseq_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_setseq_32_rxs_m_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_setseq_64_rxs_m_32_random_r(struct pcg_state_setseq_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_rxs_m_64_32(oldstate); +} + +inline uint32_t +pcg_setseq_64_rxs_m_32_boundedrand_r(struct pcg_state_setseq_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_64_rxs_m_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_rxs_m_64_random_r(struct pcg_state_setseq_128* rng) +{ + pcg_setseq_128_step_r(rng); + return pcg_output_rxs_m_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_rxs_m_64_boundedrand_r(struct pcg_state_setseq_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_128_rxs_m_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint8_t pcg_mcg_16_rxs_m_8_random_r(struct pcg_state_16* rng) +{ + uint16_t oldstate = rng->state; + pcg_mcg_16_step_r(rng); + return pcg_output_rxs_m_16_8(oldstate); +} + +inline uint8_t pcg_mcg_16_rxs_m_8_boundedrand_r(struct pcg_state_16* rng, + uint8_t bound) +{ + uint8_t threshold = ((uint8_t)(-bound)) % bound; + for (;;) { + uint8_t r = pcg_mcg_16_rxs_m_8_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint16_t pcg_mcg_32_rxs_m_16_random_r(struct pcg_state_32* rng) +{ + uint32_t oldstate = rng->state; + pcg_mcg_32_step_r(rng); + return pcg_output_rxs_m_32_16(oldstate); +} + +inline uint16_t pcg_mcg_32_rxs_m_16_boundedrand_r(struct pcg_state_32* rng, + uint16_t bound) +{ + uint16_t threshold = ((uint16_t)(-bound)) % bound; + for (;;) { + uint16_t r = pcg_mcg_32_rxs_m_16_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +inline uint32_t pcg_mcg_64_rxs_m_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_mcg_64_step_r(rng); + return pcg_output_rxs_m_64_32(oldstate); +} + +inline uint32_t pcg_mcg_64_rxs_m_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_mcg_64_rxs_m_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_rxs_m_64_random_r(struct pcg_state_128* rng) +{ + pcg_mcg_128_step_r(rng); + return pcg_output_rxs_m_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_rxs_m_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_mcg_128_rxs_m_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for XSL RR (only defined for "large" types) */ + +inline uint32_t pcg_oneseq_64_xsl_rr_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_xsl_rr_64_32(oldstate); +} + +inline uint32_t pcg_oneseq_64_xsl_rr_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_oneseq_64_xsl_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_oneseq_128_xsl_rr_64_random_r(struct pcg_state_128* rng) +{ + pcg_oneseq_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_oneseq_128_xsl_rr_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint32_t pcg_unique_64_xsl_rr_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_xsl_rr_64_32(oldstate); +} + +inline uint32_t pcg_unique_64_xsl_rr_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_unique_64_xsl_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_unique_128_xsl_rr_64_random_r(struct pcg_state_128* rng) +{ + pcg_unique_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_unique_128_xsl_rr_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint32_t +pcg_setseq_64_xsl_rr_32_random_r(struct pcg_state_setseq_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsl_rr_64_32(oldstate); +} + +inline uint32_t +pcg_setseq_64_xsl_rr_32_boundedrand_r(struct pcg_state_setseq_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_setseq_64_xsl_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsl_rr_64_random_r(struct pcg_state_setseq_128* rng) +{ + pcg_setseq_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t +pcg_setseq_128_xsl_rr_64_boundedrand_r(struct pcg_state_setseq_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint32_t pcg_mcg_64_xsl_rr_32_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_mcg_64_step_r(rng); + return pcg_output_xsl_rr_64_32(oldstate); +} + +inline uint32_t pcg_mcg_64_xsl_rr_32_boundedrand_r(struct pcg_state_64* rng, + uint32_t bound) +{ + uint32_t threshold = -bound % bound; + for (;;) { + uint32_t r = pcg_mcg_64_xsl_rr_32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsl_rr_64_random_r(struct pcg_state_128* rng) +{ + pcg_mcg_128_step_r(rng); + return pcg_output_xsl_rr_128_64(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline uint64_t pcg_mcg_128_xsl_rr_64_boundedrand_r(struct pcg_state_128* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_mcg_128_xsl_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/* Generation functions for XSL RR RR (only defined for "large" types) */ + +inline uint64_t pcg_oneseq_64_xsl_rr_rr_64_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_oneseq_64_step_r(rng); + return pcg_output_xsl_rr_rr_64_64(oldstate); +} + +inline uint64_t +pcg_oneseq_64_xsl_rr_rr_64_boundedrand_r(struct pcg_state_64* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_oneseq_64_xsl_rr_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_oneseq_128_xsl_rr_rr_128_random_r(struct pcg_state_128* rng) +{ + pcg_oneseq_128_step_r(rng); + return pcg_output_xsl_rr_rr_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_oneseq_128_xsl_rr_rr_128_boundedrand_r(struct pcg_state_128* rng, + pcg128_t bound) +{ + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_oneseq_128_xsl_rr_rr_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint64_t pcg_unique_64_xsl_rr_rr_64_random_r(struct pcg_state_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_unique_64_step_r(rng); + return pcg_output_xsl_rr_rr_64_64(oldstate); +} + +inline uint64_t +pcg_unique_64_xsl_rr_rr_64_boundedrand_r(struct pcg_state_64* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_unique_64_xsl_rr_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t pcg_unique_128_xsl_rr_rr_128_random_r(struct pcg_state_128* rng) +{ + pcg_unique_128_step_r(rng); + return pcg_output_xsl_rr_rr_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_unique_128_xsl_rr_rr_128_boundedrand_r(struct pcg_state_128* rng, + pcg128_t bound) +{ + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_unique_128_xsl_rr_rr_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +inline uint64_t +pcg_setseq_64_xsl_rr_rr_64_random_r(struct pcg_state_setseq_64* rng) +{ + uint64_t oldstate = rng->state; + pcg_setseq_64_step_r(rng); + return pcg_output_xsl_rr_rr_64_64(oldstate); +} + +inline uint64_t +pcg_setseq_64_xsl_rr_rr_64_boundedrand_r(struct pcg_state_setseq_64* rng, + uint64_t bound) +{ + uint64_t threshold = -bound % bound; + for (;;) { + uint64_t r = pcg_setseq_64_xsl_rr_rr_64_random_r(rng); + if (r >= threshold) + return r % bound; + } +} + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_setseq_128_xsl_rr_rr_128_random_r(struct pcg_state_setseq_128* rng) +{ + pcg_setseq_128_step_r(rng); + return pcg_output_xsl_rr_rr_128_128(rng->state); +} +#endif + +#if PCG_HAS_128BIT_OPS +inline pcg128_t +pcg_setseq_128_xsl_rr_rr_128_boundedrand_r(struct pcg_state_setseq_128* rng, + pcg128_t bound) +{ + pcg128_t threshold = -bound % bound; + for (;;) { + pcg128_t r = pcg_setseq_128_xsl_rr_rr_128_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#endif + +/*** Typedefs */ +typedef struct pcg_state_setseq_64 pcg32_random_t; +typedef struct pcg_state_64 pcg32s_random_t; +typedef struct pcg_state_64 pcg32u_random_t; +typedef struct pcg_state_64 pcg32f_random_t; +/*** random_r */ +#define pcg32_random_r pcg_setseq_64_xsh_rr_32_random_r +#define pcg32s_random_r pcg_oneseq_64_xsh_rr_32_random_r +#define pcg32u_random_r pcg_unique_64_xsh_rr_32_random_r +#define pcg32f_random_r pcg_mcg_64_xsh_rs_32_random_r +/*** boundedrand_r */ +#define pcg32_boundedrand_r pcg_setseq_64_xsh_rr_32_boundedrand_r +#define pcg32s_boundedrand_r pcg_oneseq_64_xsh_rr_32_boundedrand_r +#define pcg32u_boundedrand_r pcg_unique_64_xsh_rr_32_boundedrand_r +#define pcg32f_boundedrand_r pcg_mcg_64_xsh_rs_32_boundedrand_r +/*** srandom_r */ +#define pcg32_srandom_r pcg_setseq_64_srandom_r +#define pcg32s_srandom_r pcg_oneseq_64_srandom_r +#define pcg32u_srandom_r pcg_unique_64_srandom_r +#define pcg32f_srandom_r pcg_mcg_64_srandom_r +/*** advance_r */ +#define pcg32_advance_r pcg_setseq_64_advance_r +#define pcg32s_advance_r pcg_oneseq_64_advance_r +#define pcg32u_advance_r pcg_unique_64_advance_r +#define pcg32f_advance_r pcg_mcg_64_advance_r + +#if PCG_HAS_128BIT_OPS +/*** Typedefs */ +typedef struct pcg_state_setseq_128 pcg64_random_t; +typedef struct pcg_state_128 pcg64s_random_t; +typedef struct pcg_state_128 pcg64u_random_t; +typedef struct pcg_state_128 pcg64f_random_t; +/*** random_r */ +#define pcg64_random_r pcg_setseq_128_xsl_rr_64_random_r +#define pcg64s_random_r pcg_oneseq_128_xsl_rr_64_random_r +#define pcg64u_random_r pcg_unique_128_xsl_rr_64_random_r +#define pcg64f_random_r pcg_mcg_128_xsl_rr_64_random_r +/*** boundedrand_r */ +#define pcg64_boundedrand_r pcg_setseq_128_xsl_rr_64_boundedrand_r +#define pcg64s_boundedrand_r pcg_oneseq_128_xsl_rr_64_boundedrand_r +#define pcg64u_boundedrand_r pcg_unique_128_xsl_rr_64_boundedrand_r +#define pcg64f_boundedrand_r pcg_mcg_128_xsl_rr_64_boundedrand_r +/*** srandom_r */ +#define pcg64_srandom_r pcg_setseq_128_srandom_r +#define pcg64s_srandom_r pcg_oneseq_128_srandom_r +#define pcg64u_srandom_r pcg_unique_128_srandom_r +#define pcg64f_srandom_r pcg_mcg_128_srandom_r +/*** advance_r */ +#define pcg64_advance_r pcg_setseq_128_advance_r +#define pcg64s_advance_r pcg_oneseq_128_advance_r +#define pcg64u_advance_r pcg_unique_128_advance_r +#define pcg64f_advance_r pcg_mcg_128_advance_r +#endif + +/*** Typedefs */ +typedef struct pcg_state_8 pcg8si_random_t; +typedef struct pcg_state_16 pcg16si_random_t; +typedef struct pcg_state_32 pcg32si_random_t; +typedef struct pcg_state_64 pcg64si_random_t; +/*** random_r */ +#define pcg8si_random_r pcg_oneseq_8_rxs_m_xs_8_random_r +#define pcg16si_random_r pcg_oneseq_16_rxs_m_xs_16_random_r +#define pcg32si_random_r pcg_oneseq_32_rxs_m_xs_32_random_r +#define pcg64si_random_r pcg_oneseq_64_rxs_m_xs_64_random_r +/*** boundedrand_r */ +#define pcg8si_boundedrand_r pcg_oneseq_8_rxs_m_xs_8_boundedrand_r +#define pcg16si_boundedrand_r pcg_oneseq_16_rxs_m_xs_16_boundedrand_r +#define pcg32si_boundedrand_r pcg_oneseq_32_rxs_m_xs_32_boundedrand_r +#define pcg64si_boundedrand_r pcg_oneseq_64_rxs_m_xs_64_boundedrand_r +/*** srandom_r */ +#define pcg8si_srandom_r pcg_oneseq_8_srandom_r +#define pcg16si_srandom_r pcg_oneseq_16_srandom_r +#define pcg32si_srandom_r pcg_oneseq_32_srandom_r +#define pcg64si_srandom_r pcg_oneseq_64_srandom_r +/*** advance_r */ +#define pcg8si_advance_r pcg_oneseq_8_advance_r +#define pcg16si_advance_r pcg_oneseq_16_advance_r +#define pcg32si_advance_r pcg_oneseq_32_advance_r +#define pcg64si_advance_r pcg_oneseq_64_advance_r + +#if PCG_HAS_128BIT_OPS +typedef struct pcg_state_128 pcg128si_random_t; +#define pcg128si_random_r pcg_oneseq_128_rxs_m_xs_128_random_r +#define pcg128si_boundedrand_r pcg_oneseq_128_rxs_m_xs_128_boundedrand_r +#define pcg128si_srandom_r pcg_oneseq_128_srandom_r +#define pcg128si_advance_r pcg_oneseq_128_advance_r +#endif + +/*** Typedefs */ +typedef struct pcg_state_setseq_8 pcg8i_random_t; +typedef struct pcg_state_setseq_16 pcg16i_random_t; +typedef struct pcg_state_setseq_32 pcg32i_random_t; +typedef struct pcg_state_setseq_64 pcg64i_random_t; +/*** random_r */ +#define pcg8i_random_r pcg_setseq_8_rxs_m_xs_8_random_r +#define pcg16i_random_r pcg_setseq_16_rxs_m_xs_16_random_r +#define pcg32i_random_r pcg_setseq_32_rxs_m_xs_32_random_r +#define pcg64i_random_r pcg_setseq_64_rxs_m_xs_64_random_r +/*** boundedrand_r */ +#define pcg8i_boundedrand_r pcg_setseq_8_rxs_m_xs_8_boundedrand_r +#define pcg16i_boundedrand_r pcg_setseq_16_rxs_m_xs_16_boundedrand_r +#define pcg32i_boundedrand_r pcg_setseq_32_rxs_m_xs_32_boundedrand_r +#define pcg64i_boundedrand_r pcg_setseq_64_rxs_m_xs_64_boundedrand_r +/*** srandom_r */ +#define pcg8i_srandom_r pcg_setseq_8_srandom_r +#define pcg16i_srandom_r pcg_setseq_16_srandom_r +#define pcg32i_srandom_r pcg_setseq_32_srandom_r +#define pcg64i_srandom_r pcg_setseq_64_srandom_r +/*** advance_r */ +#define pcg8i_advance_r pcg_setseq_8_advance_r +#define pcg16i_advance_r pcg_setseq_16_advance_r +#define pcg32i_advance_r pcg_setseq_32_advance_r +#define pcg64i_advance_r pcg_setseq_64_advance_r + +#if PCG_HAS_128BIT_OPS +typedef struct pcg_state_setseq_128 pcg128i_random_t; +#define pcg128i_random_r pcg_setseq_128_rxs_m_xs_128_random_r +#define pcg128i_boundedrand_r pcg_setseq_128_rxs_m_xs_128_boundedrand_r +#define pcg128i_srandom_r pcg_setseq_128_srandom_r +#define pcg128i_advance_r pcg_setseq_128_advance_r +#endif + +extern uint32_t pcg32_random(void); +extern uint32_t pcg32_boundedrand(uint32_t bound); +extern void pcg32_srandom(uint64_t seed, uint64_t seq); +extern void pcg32_advance(uint64_t delta); + +#if PCG_HAS_128BIT_OPS +extern uint64_t pcg64_random(void); +extern uint64_t pcg64_boundedrand(uint64_t bound); +extern void pcg64_srandom(pcg128_t seed, pcg128_t seq); +extern void pcg64_advance(pcg128_t delta); +#endif + +/* + * Static initialization constants (if you can't call srandom for some + * bizarre reason). + */ + +#define PCG32_INITIALIZER PCG_STATE_SETSEQ_64_INITIALIZER +#define PCG32U_INITIALIZER PCG_STATE_UNIQUE_64_INITIALIZER +#define PCG32S_INITIALIZER PCG_STATE_ONESEQ_64_INITIALIZER +#define PCG32F_INITIALIZER PCG_STATE_MCG_64_INITIALIZER + +#if PCG_HAS_128BIT_OPS +#define PCG64_INITIALIZER PCG_STATE_SETSEQ_128_INITIALIZER +#define PCG64U_INITIALIZER PCG_STATE_UNIQUE_128_INITIALIZER +#define PCG64S_INITIALIZER PCG_STATE_ONESEQ_128_INITIALIZER +#define PCG64F_INITIALIZER PCG_STATE_MCG_128_INITIALIZER +#endif + +#define PCG8SI_INITIALIZER PCG_STATE_ONESEQ_8_INITIALIZER +#define PCG16SI_INITIALIZER PCG_STATE_ONESEQ_16_INITIALIZER +#define PCG32SI_INITIALIZER PCG_STATE_ONESEQ_32_INITIALIZER +#define PCG64SI_INITIALIZER PCG_STATE_ONESEQ_64_INITIALIZER +#if PCG_HAS_128BIT_OPS +#define PCG128SI_INITIALIZER PCG_STATE_ONESEQ_128_INITIALIZER +#endif + +#define PCG8I_INITIALIZER PCG_STATE_SETSEQ_8_INITIALIZER +#define PCG16I_INITIALIZER PCG_STATE_SETSEQ_16_INITIALIZER +#define PCG32I_INITIALIZER PCG_STATE_SETSEQ_32_INITIALIZER +#define PCG64I_INITIALIZER PCG_STATE_SETSEQ_64_INITIALIZER +#if PCG_HAS_128BIT_OPS +#define PCG128I_INITIALIZER PCG_STATE_SETSEQ_128_INITIALIZER +#endif + +#if __cplusplus +} +#endif + +#endif /* PCG_VARIANTS_H_INCLUDED */ + From 872f4e99f48bd2d78f944291330a12326fb41059 Mon Sep 17 00:00:00 2001 From: Peter Grehan Date: Thu, 30 Jul 2020 23:49:49 +0000 Subject: [PATCH 276/287] Definition for the 'removable media flag' from word 0 in the Identify page. This will be used to remove a magic number in the bhyve AHCI emulation. Reported by: rpokala Reviewed by: imp, rpokala Approved by: imp, rpokala MFC after: 3 weeks Differential Revision: https://reviews.freebsd.org/D25893 --- sys/sys/ata.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/sys/ata.h b/sys/sys/ata.h index a08d5253578f..7ec4526be7df 100644 --- a/sys/sys/ata.h +++ b/sys/sys/ata.h @@ -46,6 +46,7 @@ struct ata_params { #define ATA_ATAPI_TYPE_TAPE 0x0100 /* streaming tape */ #define ATA_ATAPI_TYPE_CDROM 0x0500 /* CD-ROM device */ #define ATA_ATAPI_TYPE_OPTICAL 0x0700 /* optical disk */ +#define ATA_ATAPI_REMOVABLE 0x0080 #define ATA_DRQ_MASK 0x0060 #define ATA_DRQ_SLOW 0x0000 /* cpu 3 ms delay */ #define ATA_DRQ_INTR 0x0020 /* interrupt 10 ms delay */ From 59d13f615418fab119911e8df9799303cd6be222 Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Fri, 31 Jul 2020 00:07:01 +0000 Subject: [PATCH 277/287] getblk: Avoid sleeping on wrong buf in lockless path If the buffer identity changed during lookup, sleeping could introduce a lock order reversal. Since we do not know if the identity changed until we get the lock, we must try-lock (LK_NOWAIT) only. EINTR and ERESTART error handling becomes irrelevant, as we no longer sleep. Reported by: kib Reviewed by: kib X-MFC-With: r363482 Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D25898 --- sys/kern/vfs_bio.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 0deb5ff785c4..bf9f46b7a72a 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -3844,7 +3844,7 @@ getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag, struct buf *bp; struct bufobj *bo; daddr_t d_blkno; - int bsize, error, maxsize, vmio, lockflags; + int bsize, error, maxsize, vmio; off_t offset; CTR3(KTR_BUF, "getblk(%p, %ld, %d)", vp, (long)blkno, size); @@ -3865,14 +3865,9 @@ getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag, if (bp == NULL) goto newbuf_unlocked; - lockflags = LK_EXCLUSIVE | LK_SLEEPFAIL | - ((flags & GB_LOCK_NOWAIT) ? LK_NOWAIT : 0); - - error = BUF_TIMELOCK(bp, lockflags, NULL, "getblku", slpflag, - slptimeo); - if (error == EINTR || error == ERESTART) - return (error); - else if (error != 0) + error = BUF_TIMELOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL, "getblku", 0, + 0); + if (error != 0) goto loop; /* Verify buf identify has not changed since lookup. */ @@ -3886,6 +3881,8 @@ getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag, BO_RLOCK(bo); bp = gbincore(bo, blkno); if (bp != NULL) { + int lockflags; + /* * Buffer is in-core. If the buffer is not busy nor managed, * it must be on a queue. From d6a75d39e9ec2bcebeb3ee79e9b839b6af4a934e Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Fri, 31 Jul 2020 00:13:40 +0000 Subject: [PATCH 278/287] getblk: Remove a non-sensical LK_NOWAIT | LK_SLEEPFAIL No functional change. LK_SLEEPFAIL implies a behavior that is only possible if the lock operation can sleep. LK_NOWAIT prevents the lock operation from sleeping. Discussed with: kib --- sys/kern/vfs_bio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index bf9f46b7a72a..524554cdd48f 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -3887,10 +3887,8 @@ getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag, * Buffer is in-core. If the buffer is not busy nor managed, * it must be on a queue. */ - lockflags = LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK; - - if ((flags & GB_LOCK_NOWAIT) != 0) - lockflags |= LK_NOWAIT; + lockflags = LK_EXCLUSIVE | LK_INTERLOCK | + ((flags & GB_LOCK_NOWAIT) ? LK_NOWAIT : LK_SLEEPFAIL); error = BUF_TIMELOCK(bp, lockflags, BO_LOCKPTR(bo), "getblk", slpflag, slptimeo); From d6391a26d6395586558cbd54958c8393162d5ca1 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Fri, 31 Jul 2020 02:21:19 +0000 Subject: [PATCH 279/287] UPDATING: Add a note about running installworld twice Some folks seem to be hitting issues with build orchestration; presumably some of our .WAIT-removal optimizations are going awry, and they're ending up with applications linked against new libc being installed before the new libc. Letting installworld complete the first time should ensure that the new libc is installed by the end of it, then the second installworld will ensure consistency as everything should succeed. --- UPDATING | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/UPDATING b/UPDATING index be57064412b7..9cd27c5f4f37 100644 --- a/UPDATING +++ b/UPDATING @@ -33,6 +33,11 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW: ports, but other non-ports software may need extra escapes removed to continue to function. + Because of this change, installworld may encounter the following error + from rtld: Undefined symbol "regcomp@FBSD_1.6" -- It is imperative that + you do not halt installworld. Instead, let it run to completion (whether + successful or not) and run installworld once more. + 20200627: A new implementation of bc and dc has been imorted in r362681. This implementation corrects non-conformant behavior of the previous bc From 8315f1ea26626b1b2c814c35032944bca8615fa8 Mon Sep 17 00:00:00 2001 From: Randall Stewart Date: Fri, 31 Jul 2020 10:03:32 +0000 Subject: [PATCH 280/287] The recent changes to move the ref count increment back from the end of the function created an issue. If one of the routines returns NULL during setup we have inp's with extra references (which is why the increment was at the end). Also the stack switch return code was being ignored and actually has meaning if the stack cannot take over it should return NULL. Fix both of these situation by being sure to test the return code and of course in any case of return NULL (there are 3) make sure we properly reduce the ref count. Sponsored by: Netflix Inc. Differential Revision: https://reviews.freebsd.org/D25903 --- sys/netinet/tcp_subr.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 777fd7200ccd..bf4b413bd4de 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -1713,6 +1713,7 @@ tcp_newtcpcb(struct inpcb *inp) if (CC_ALGO(tp)->cb_init(tp->ccv) > 0) { if (tp->t_fb->tfb_tcp_fb_fini) (*tp->t_fb->tfb_tcp_fb_fini)(tp, 1); + in_pcbrele_wlocked(inp); refcount_release(&tp->t_fb->tfb_refcnt); uma_zfree(V_tcpcb_zone, tm); return (NULL); @@ -1723,6 +1724,7 @@ tcp_newtcpcb(struct inpcb *inp) if (khelp_init_osd(HELPER_CLASS_TCP, tp->osd)) { if (tp->t_fb->tfb_tcp_fb_fini) (*tp->t_fb->tfb_tcp_fb_fini)(tp, 1); + in_pcbrele_wlocked(inp); refcount_release(&tp->t_fb->tfb_refcnt); uma_zfree(V_tcpcb_zone, tm); return (NULL); @@ -1783,7 +1785,12 @@ tcp_newtcpcb(struct inpcb *inp) tcp_log_tcpcbinit(tp); #endif if (tp->t_fb->tfb_tcp_fb_init) { - (*tp->t_fb->tfb_tcp_fb_init)(tp); + if ((*tp->t_fb->tfb_tcp_fb_init)(tp)) { + refcount_release(&tp->t_fb->tfb_refcnt); + in_pcbrele_wlocked(inp); + uma_zfree(V_tcpcb_zone, tm); + return (NULL); + } } #ifdef STATS if (V_tcp_perconn_stats_enable == 1) From 74d677ebfdbb2889926f078250d070ba66073369 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Fri, 31 Jul 2020 11:28:09 +0000 Subject: [PATCH 281/287] Include virtio support in std.MALTA The MALTA kernel config is generally used for QEMU and having support for VirtIO there by default is quite useful. Reviewed By: brooks Differential Revision: https://reviews.freebsd.org/D25217 --- sys/mips/conf/std.MALTA | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sys/mips/conf/std.MALTA b/sys/mips/conf/std.MALTA index 26940db1b92f..7b951b926824 100644 --- a/sys/mips/conf/std.MALTA +++ b/sys/mips/conf/std.MALTA @@ -55,3 +55,10 @@ device miibus device bpf device md device uart + +# VirtIO support +device virtio # Generic VirtIO bus (required) +device virtio_pci # VirtIO PCI Interface +device vtnet # VirtIO Ethernet device +device virtio_blk # VirtIO Block device +device virtio_random # VirtIO Entropy device From f1c3dac41471085d59a915db9d0a3ba99cabaf22 Mon Sep 17 00:00:00 2001 From: Peter Grehan Date: Fri, 31 Jul 2020 12:10:28 +0000 Subject: [PATCH 282/287] Replace magic numbers in Identify page register 0 with ATA definitions. No functional change. Verified with objdump output before/after. Requested by: rpokala Reviewed by: rpokala MFC after: 3 weeks --- usr.sbin/bhyve/pci_ahci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c index 6cc0b3b65ef2..dfdf57f664e7 100644 --- a/usr.sbin/bhyve/pci_ahci.c +++ b/usr.sbin/bhyve/pci_ahci.c @@ -999,7 +999,8 @@ ata_identify_init(struct ahci_port* p, int atapi) struct ata_params* ata_ident = &p->ata_ident; if (atapi) { - ata_ident->config = (2 << 14 | 5 << 8 | 1 << 7 | 2 << 5); + ata_ident->config = ATA_PROTO_ATAPI | ATA_ATAPI_TYPE_CDROM | + ATA_ATAPI_REMOVABLE | ATA_DRQ_FAST; ata_ident->capabilities1 = ATA_SUPPORT_LBA | ATA_SUPPORT_DMA; ata_ident->capabilities2 = (1 << 14 | 1); From 7c5ec5fe6afb50ba5c83ad0b3dab036f91b7dafe Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Fri, 31 Jul 2020 12:40:31 +0000 Subject: [PATCH 283/287] : reserve a regcomp field for REG_POSIX For libc regcomp, this will be a nop. libregex will take this to mean that it needs to turn off GNU extensions, effectively switching it back to the POSIX-compliant libc implementation at runtime. --- include/regex.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/regex.h b/include/regex.h index 6b0838a9bd97..3bea3df4f3d4 100644 --- a/include/regex.h +++ b/include/regex.h @@ -71,6 +71,7 @@ typedef struct { #define REG_NOSPEC 0020 #define REG_PEND 0040 #define REG_DUMP 0200 +#define REG_POSIX 0400 /* only POSIX-compliant regex (libregex) */ /* regerror() flags */ #define REG_ENOSYS (-1) From 460a9f9d45f8aad3ec445313c39424e5fcd42dac Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Fri, 31 Jul 2020 14:08:32 +0000 Subject: [PATCH 284/287] ng_iface(4): Set the current VNET before calling netisr_dispatch(). This is normally handled by a netgraph thread, but netgraph messages may be dispatched directly to a node, in which case no VNET is set before ng_iface calls into the network stack. Netgraph could probably handle this more generally, but for now just be sure to set the current VNET in ng_iface. PR: 242406 Tested by: Michael Muenz Reviewed by: Lutz Donnerhacke MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D25788 --- sys/netgraph/ng_iface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/netgraph/ng_iface.c b/sys/netgraph/ng_iface.c index 5f4ce3c82f31..f863b01ee479 100644 --- a/sys/netgraph/ng_iface.c +++ b/sys/netgraph/ng_iface.c @@ -732,9 +732,11 @@ ng_iface_rcvdata(hook_p hook, item_p item) } random_harvest_queue(m, sizeof(*m), RANDOM_NET_NG); M_SETFIB(m, ifp->if_fib); + CURVNET_SET(ifp->if_vnet); NET_EPOCH_ENTER(et); netisr_dispatch(isr, m); NET_EPOCH_EXIT(et); + CURVNET_RESTORE(); return (0); } From 370b7cc90407a84a8b0bbb0b6866ca0c855de5bd Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Fri, 31 Jul 2020 14:08:54 +0000 Subject: [PATCH 285/287] ng_iface(4): Remove unsupported protocols. Update the ng_iface documentation and hooks to reflect the fact that the node currently only supports IPv4 and v6 packets. Reviewed by: Lutz Donnerhacke MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25862 --- share/man/man4/ng_iface.4 | 10 ++-------- sys/netgraph/ng_iface.c | 2 -- sys/netgraph/ng_iface.h | 2 -- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/share/man/man4/ng_iface.4 b/share/man/man4/ng_iface.4 index 0b406cdd298f..2259ea1076d3 100644 --- a/share/man/man4/ng_iface.4 +++ b/share/man/man4/ng_iface.4 @@ -35,7 +35,7 @@ .\" $FreeBSD$ .\" $Whistle: ng_iface.8,v 1.5 1999/01/25 23:46:26 archie Exp $ .\" -.Dd February 6, 2019 +.Dd July 31, 2020 .Dt NG_IFACE 4 .Os .Sh NAME @@ -70,7 +70,7 @@ Packets transmitted via the interface flow out the corresponding protocol-specific hook. Similarly, packets received on a hook appear on the interface as packets received into the corresponding protocol stack. -The currently supported protocols are IP, IPv6, ATM, NATM, and NS. +The currently supported protocols are IP and IPv6. .Pp An .Nm iface @@ -87,12 +87,6 @@ This node type supports the following hooks: Transmission and reception of IP packets. .It Va inet6 Transmission and reception of IPv6 packets. -.It Va atm -Transmission and reception of ATM packets. -.It Va natm -Transmission and reception of NATM packets. -.It Va ns -Transmission and reception of NS packets. .El .Sh CONTROL MESSAGES This node type supports the generic control messages, plus the following: diff --git a/sys/netgraph/ng_iface.c b/sys/netgraph/ng_iface.c index f863b01ee479..a91c202ef832 100644 --- a/sys/netgraph/ng_iface.c +++ b/sys/netgraph/ng_iface.c @@ -111,8 +111,6 @@ typedef const struct iffam *iffam_p; const static struct iffam gFamilies[] = { { AF_INET, NG_IFACE_HOOK_INET }, { AF_INET6, NG_IFACE_HOOK_INET6 }, - { AF_ATM, NG_IFACE_HOOK_ATM }, - { AF_NATM, NG_IFACE_HOOK_NATM }, }; #define NUM_FAMILIES nitems(gFamilies) diff --git a/sys/netgraph/ng_iface.h b/sys/netgraph/ng_iface.h index 891422b4b359..49c75832384d 100644 --- a/sys/netgraph/ng_iface.h +++ b/sys/netgraph/ng_iface.h @@ -54,8 +54,6 @@ /* My hook names */ #define NG_IFACE_HOOK_INET "inet" #define NG_IFACE_HOOK_INET6 "inet6" -#define NG_IFACE_HOOK_ATM "atm" -#define NG_IFACE_HOOK_NATM "natm" /* MTU bounds */ #define NG_IFACE_MTU_MIN 72 From 0b87619ffeabf8bc516ab2064b964077099ffc75 Mon Sep 17 00:00:00 2001 From: Mateusz Piotrowski <0mp@FreeBSD.org> Date: Fri, 31 Jul 2020 14:13:26 +0000 Subject: [PATCH 286/287] Point to rc(8) for more details about the autoboot variable Reviewed by: bcr, imp MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25904 --- share/man/man8/rc.subr.8 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/share/man/man8/rc.subr.8 b/share/man/man8/rc.subr.8 index fd23ca20c36c..f522a5d162c3 100644 --- a/share/man/man8/rc.subr.8 +++ b/share/man/man8/rc.subr.8 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 24, 2020 +.Dd July 31, 2020 .Dt RC.SUBR 8 .Os .Sh NAME @@ -882,7 +882,11 @@ Prevent booting to multiuser mode. If the .Va autoboot variable is set to -.Ql yes , +.Ql yes +(see +.Xr rc 8 +to learn more about +.Va autoboot ) , or .Ic checkyesno Ar always indicates a truth value, then a From fafe230db0cd8d96ac5f3f74643e0c71e949d623 Mon Sep 17 00:00:00 2001 From: "Stephen J. Kiernan" Date: Fri, 31 Jul 2020 16:08:25 +0000 Subject: [PATCH 287/287] Fix compilation error for install.c in loader Fix typo in interp_include() invocation (missing 'p') Remove setting tftpip, as servip is used by the tftp code in libsa. There is no separate tftpip global variable any more. Obtained from: Juniper Networks, Inc. MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D25897 --- stand/common/install.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/stand/common/install.c b/stand/common/install.c index de0fd88fc4e3..ea6eaaa7cebc 100644 --- a/stand/common/install.c +++ b/stand/common/install.c @@ -286,10 +286,6 @@ install(char *pkgname) setenv("serverip", inet_ntoa(servip), 1); - if (proto == &tftp_fsops) { - tftpip.s_addr = servip.s_addr; - } - *pkgname = '/'; } else pkgname = s; @@ -340,7 +336,7 @@ install(char *pkgname) fd = open(s, O_RDONLY); if (fd != -1) { close(fd); - error = inter_include(s); + error = interp_include(s); if (error == CMD_ERROR) goto fail; }