From 9e579a58c364cb29e76e8e4c630df63e97d42780 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Sat, 24 Sep 2016 21:40:14 +0000 Subject: [PATCH 01/64] Move implementations of uread() and uwrite() to the illumos compat layer. MFC after: 1 week --- .../opensolaris/kern/opensolaris_proc.c | 57 +++++++++++++++++++ sys/cddl/compat/opensolaris/sys/proc.h | 3 + .../uts/intel/dtrace/fasttrap_isa.c | 28 +-------- .../uts/powerpc/dtrace/fasttrap_isa.c | 26 --------- sys/conf/files | 1 + sys/modules/opensolaris/Makefile | 1 + 6 files changed, 63 insertions(+), 53 deletions(-) create mode 100644 sys/cddl/compat/opensolaris/kern/opensolaris_proc.c diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_proc.c b/sys/cddl/compat/opensolaris/kern/opensolaris_proc.c new file mode 100644 index 000000000000..652fa8928589 --- /dev/null +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_proc.c @@ -0,0 +1,57 @@ +/*- + * Copyright 2016 Mark Johnston + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +int +uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr) +{ + ssize_t n; + + PHOLD(p); + n = proc_readmem(curthread, p, uaddr, kaddr, len); + PRELE(p); + if (n != len) + return (ENOMEM); + return (0); +} + +int +uwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr) +{ + ssize_t n; + + PHOLD(p); + n = proc_writemem(curthread, p, uaddr, kaddr, len); + PRELE(p); + if (n != len) + return (ENOMEM); + return (0); +} diff --git a/sys/cddl/compat/opensolaris/sys/proc.h b/sys/cddl/compat/opensolaris/sys/proc.h index 5c9e8dec78c4..ce503cf724ac 100644 --- a/sys/cddl/compat/opensolaris/sys/proc.h +++ b/sys/cddl/compat/opensolaris/sys/proc.h @@ -92,6 +92,9 @@ do_thread_create(caddr_t stk, size_t stksize, void (*proc)(void *), void *arg, do_thread_create(stk, stksize, proc, arg, len, pp, state, pri) #define thread_exit() kthread_exit() +int uread(proc_t *, void *, size_t, uintptr_t); +int uwrite(proc_t *, void *, size_t, uintptr_t); + #endif /* _KERNEL */ #endif /* _OPENSOLARIS_SYS_PROC_H_ */ diff --git a/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c b/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c index 8555e2ff3335..e1f95de8a8d8 100644 --- a/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c +++ b/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c @@ -59,34 +59,8 @@ #include #else #include - -static int -uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr) -{ - ssize_t n; - - PHOLD(p); - n = proc_readmem(curthread, p, uaddr, kaddr, len); - PRELE(p); - if (n != len) - return (ENOMEM); - return (0); -} - -static int -uwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr) -{ - ssize_t n; - - PHOLD(p); - n = proc_writemem(curthread, p, uaddr, kaddr, len); - PRELE(p); - if (n != len) - return (ENOMEM); - return (0); -} - #endif /* illumos */ + #ifdef __i386__ #define r_rax r_eax #define r_rbx r_ebx diff --git a/sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c b/sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c index e8dd684a4530..b0fc5816c5e3 100644 --- a/sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c +++ b/sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c @@ -44,32 +44,6 @@ #define OP_RA(x) (((x) & 0x001F0000) >> 16) #define OP_RB(x) (((x) & 0x0000F100) >> 11) -static int -uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr) -{ - ssize_t n; - - PHOLD(p); - n = proc_readmem(curthread, p, uaddr, kaddr, len); - PRELE(p); - if (n <= 0 || n < len) - return (ENOMEM); - return (0); -} - -static int -uwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr) -{ - ssize_t n; - - PHOLD(p); - n = proc_writemem(curthread, p, uaddr, kaddr, len); - PRELE(p); - if (n <= 0 || n < len) - return (ENOMEM); - return (0); -} - int fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp) { diff --git a/sys/conf/files b/sys/conf/files index 37683bd47eed..296549639dfb 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -127,6 +127,7 @@ cddl/compat/opensolaris/kern/opensolaris.c optional zfs | dtrace compile-with " cddl/compat/opensolaris/kern/opensolaris_cmn_err.c optional zfs | dtrace compile-with "${CDDL_C}" cddl/compat/opensolaris/kern/opensolaris_kmem.c optional zfs | dtrace compile-with "${CDDL_C}" cddl/compat/opensolaris/kern/opensolaris_misc.c optional zfs | dtrace compile-with "${CDDL_C}" +cddl/compat/opensolaris/kern/opensolaris_proc.c optional zfs | dtrace compile-with "${CDDL_C}" cddl/compat/opensolaris/kern/opensolaris_sunddi.c optional zfs | dtrace compile-with "${CDDL_C}" cddl/compat/opensolaris/kern/opensolaris_taskq.c optional zfs | dtrace compile-with "${CDDL_C}" # zfs specific diff --git a/sys/modules/opensolaris/Makefile b/sys/modules/opensolaris/Makefile index 1620ab971989..c22c64c6367b 100644 --- a/sys/modules/opensolaris/Makefile +++ b/sys/modules/opensolaris/Makefile @@ -9,6 +9,7 @@ SRCS= opensolaris.c \ opensolaris_cmn_err.c \ opensolaris_kmem.c \ opensolaris_misc.c \ + opensolaris_proc.c \ opensolaris_sunddi.c _A=${SYSDIR}/cddl/contrib/opensolaris/common/atomic From 970fe0938e0c22d391f45cf3fed16dc53725ec49 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Sat, 24 Sep 2016 21:40:24 +0000 Subject: [PATCH 02/64] Convert checks in nd6_dad_start() and nd6_dad_timer() to assertions. In particular, these functions can assume they are operating on tentative addresses. MFC after: 2 weeks --- sys/netinet6/nd6_nbr.c | 52 ++++++++++++------------------------------ 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 2ac1d7a10a72..6df012ba4dcc 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -1217,40 +1217,26 @@ nd6_dad_start(struct ifaddr *ifa, int delay) struct dadq *dp; char ip6buf[INET6_ADDRSTRLEN]; + KASSERT((ia->ia6_flags & IN6_IFF_TENTATIVE) != 0, + ("starting DAD on non-tentative address %p", ifa)); + /* * If we don't need DAD, don't do it. * There are several cases: - * - DAD is disabled (ip6_dad_count == 0) + * - DAD is disabled globally or on the interface * - the interface address is anycast */ - if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) { - log(LOG_DEBUG, - "nd6_dad_start: called with non-tentative address " - "%s(%s)\n", - ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), - ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); - return; - } - if (ia->ia6_flags & IN6_IFF_ANYCAST) { + if ((ia->ia6_flags & IN6_IFF_ANYCAST) != 0 || + V_ip6_dad_count == 0 || + (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_NO_DAD) != 0) { ia->ia6_flags &= ~IN6_IFF_TENTATIVE; return; } - if (!V_ip6_dad_count) { - ia->ia6_flags &= ~IN6_IFF_TENTATIVE; + if ((ifa->ifa_ifp->if_flags & IFF_UP) == 0 || + (ifa->ifa_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || + (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_IFDISABLED) != 0) return; - } - if (ifa->ifa_ifp == NULL) - panic("nd6_dad_start: ifa->ifa_ifp == NULL"); - if (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_NO_DAD) { - ia->ia6_flags &= ~IN6_IFF_TENTATIVE; - return; - } - if (!(ifa->ifa_ifp->if_flags & IFF_UP) || - !(ifa->ifa_ifp->if_drv_flags & IFF_DRV_RUNNING) || - (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_IFDISABLED)) { - ia->ia6_flags |= IN6_IFF_TENTATIVE; - return; - } + if ((dp = nd6_dad_find(ifa, NULL)) != NULL) { /* * DAD is already in progress. Let the existing entry @@ -1329,11 +1315,10 @@ nd6_dad_timer(struct dadq *dp) struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; char ip6buf[INET6_ADDRSTRLEN]; - /* Sanity check */ - if (ia == NULL) { - log(LOG_ERR, "nd6_dad_timer: called with null parameter\n"); - goto err; - } + KASSERT(ia != NULL, ("DAD entry %p with no address", dp)); + KASSERT((ia->ia6_flags & IN6_IFF_TENTATIVE) != 0, + ("DAD entry %p for non-tentative address", dp)); + if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) { /* Do not need DAD for ifdisabled interface. */ log(LOG_ERR, "nd6_dad_timer: cancel DAD on %s because of " @@ -1347,13 +1332,6 @@ nd6_dad_timer(struct dadq *dp) ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); goto err; } - if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) { - log(LOG_ERR, "nd6_dad_timer: called with non-tentative address " - "%s(%s)\n", - ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), - ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); - goto err; - } /* Stop DAD if the interface is down even after dad_maxtry attempts. */ if ((dp->dad_ns_tcount > V_dad_maxtry) && From 1c8260b61ddaaa895817ccea281e8f2a44241d19 Mon Sep 17 00:00:00 2001 From: Julian Elischer Date: Sat, 24 Sep 2016 22:56:13 +0000 Subject: [PATCH 03/64] Give the user a clue as to which process hit maxfiles. MFC after: 1 week Sponsored by: Panzura --- sys/kern/kern_descrip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 55d5e441f483..3312b8876df0 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -1761,8 +1761,8 @@ falloc_noinstall(struct thread *td, struct file **resultfp) priv_check(td, PRIV_MAXFILES) != 0) || openfiles >= maxfiles) { if (ppsratecheck(&lastfail, &curfail, 1)) { - printf("kern.maxfiles limit exceeded by uid %i, " - "please see tuning(7).\n", td->td_ucred->cr_ruid); + printf("kern.maxfiles limit exceeded by uid %i, (%s) " + "please see tuning(7).\n", td->td_ucred->cr_ruid, td->td_proc->p_comm); } return (ENFILE); } From b9413b55126867f79e274832bb017188fa56d9c7 Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Sun, 25 Sep 2016 07:48:08 +0000 Subject: [PATCH 04/64] Add the start of a GENERIC armv6 kernel config. This supports the Allwinner SMP SoCs and qemu virt. Further SoCs can be supported if they support the PLATFORM, PLATFORM_SMP, and MULTIDELAY options. Tested by: manu Sponsored by: ABT Systems Ltd --- sys/arm/conf/GENERIC | 145 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 sys/arm/conf/GENERIC diff --git a/sys/arm/conf/GENERIC b/sys/arm/conf/GENERIC new file mode 100644 index 000000000000..d30b1d72368c --- /dev/null +++ b/sys/arm/conf/GENERIC @@ -0,0 +1,145 @@ +# +# GENERICV6 -- Generic(ish) kernel config. +# +# For more information on this file, please read the config(5) manual page, +# and/or the handbook section on Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ + +ident GENERIC + +cpu CPU_CORTEXA +machine arm armv6 +makeoptions CONF_CFLAGS="-march=armv7a" + +makeoptions KERNVIRTADDR=0xc0000000 +options KERNVIRTADDR=0xc0000000 + +include "std.armv6" +files "../allwinner/files.allwinner" +files "../allwinner/a20/files.a20" +files "../allwinner/a31/files.a31" +files "../allwinner/a83t/files.a83t" +files "../allwinner/h3/files.h3" +files "../qemu/files.qemu" + +options SOC_ALLWINNER_A20 +options SOC_ALLWINNER_A31 +options SOC_ALLWINNER_A31S +options SOC_ALLWINNER_A83T +options SOC_ALLWINNER_H3 + +options SCHED_ULE # ULE scheduler +options SMP # Enable multiple cores +options PLATFORM +options PLATFORM_SMP +options MULTIDELAY + +# EXT_RESOURCES pseudo devices +options EXT_RESOURCES +device clk +device phy +device hwreset +device regulator + +# Interrupt controller +options INTRNG +device gic + +# ARM Generic Timer +device generic_timer + +# MMC/SD/SDIO Card slot support +device mmc # mmc/sd bus +device mmcsd # mmc/sd flash cards + +# ATA controllers +device ahci # AHCI-compatible SATA controllers +#device ata # Legacy ATA/SATA controllers + +# VirtIO +device virtio +device virtio_mmio +device virtio_blk +device vtnet + +# Console and misc +device uart +device uart_snps +device pl011 +device pty +device snp +device md +device random # Entropy device +device psci + +# I2C support +device iicbus +device iic +device twsi +device rsb +device axp209 # AXP209 Power Management Unit +device axp81x # AXP813/818 Power Management Unit + +# GPIO +device gpio +device gpioled + +device scbus # SCSI bus (required for ATA/SCSI) +device da # Direct Access (disks) +device pass # Passthrough device (direct ATA/SCSI access) + +# USB support +options USB_HOST_ALIGN=64 # Align usb buffers to cache line size. +device usb +#device uhci +device ohci +device ehci + +device umass + +# Ethernet +device loop +device ether +device mii +device bpf + +#device emac # 10/100 integrated EMAC controller +device dwc # 10/100/1000 integrated GMAC controller +device awg # 10/100/1000 integrated EMAC controller + +# USB ethernet support, requires miibus +device miibus + +# Sound support +device sound + +# Framebuffer support +device vt +device kbdmux +device ums +device ukbd +device videomode +device hdmi + +# Pinmux +device fdt_pinctrl + +# Extensible Firmware Interface +options EFI + +# Flattened Device Tree +options FDT # Configure using FDT/DTB data +makeoptions MODULES_EXTRA=dtb/allwinner From f5435b8bbedbf9ecfd23e77202c601dd15faa449 Mon Sep 17 00:00:00 2001 From: Bruce Evans Date: Sun, 25 Sep 2016 14:56:24 +0000 Subject: [PATCH 05/64] Fix vm86 initialization, part 3 of 2 and a half. (Actually, just fix early printfs and debugging of vm86 initialization and some other early initialization in some cases.) Add an option debug.late_console (with default 1=off) to move console and kdb initialization back where it was. Do the same for amd64 although there is no vm86 there. On my test system, debug.late_console=0 works for the syscons, sio and uart console drivers on amd64 and i386, and for vt on i386 but not on amd64. The early printfs fixed by debug.late_console=0 are: - on i386, the message about lost memory above 4G - with -v in otherwise normal use, about 20 printfs for SMAP - other debugging messages for memory sizing. Mostly under -v and not printed in normal use. Document in a comment how much earlier the initialization and early printf()s can be. That is very early for the console. Not much more than curthread is needed. kdb use obviously needs to be not so early, since it needs IDT initialization and that is done relatively late for convenience and historical reasons. --- sys/amd64/amd64/machdep.c | 37 ++++++++++++++++++++++------- sys/i386/i386/machdep.c | 50 +++++++++++++++++++++++++++------------ 2 files changed, 64 insertions(+), 23 deletions(-) diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index c814f6c796b6..b2283339405f 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -1506,6 +1506,16 @@ native_parse_preload_data(u_int64_t modulep) return (kmdp); } +static void +amd64_kdb_init(void) +{ + kdb_init(); +#ifdef KDB + if (boothowto & RB_KDB) + kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); +#endif +} + u_int64_t hammer_time(u_int64_t modulep, u_int64_t physfree) { @@ -1517,6 +1527,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) u_int64_t msr; char *env; size_t kstack0_sz; + int late_console; /* * This may be done better later if it gets more high level @@ -1561,6 +1572,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) physfree += DPCPU_SIZE; PCPU_SET(prvspace, pc); PCPU_SET(curthread, &thread0); + /* Non-late cninit() and printf() can be moved up to here. */ PCPU_SET(tssp, &common_tss[0]); PCPU_SET(commontssp, &common_tss[0]); PCPU_SET(tss, (struct system_segment_descriptor *)&gdt[GPROC0_SEL]); @@ -1660,12 +1672,26 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) wrmsr(MSR_STAR, msr); wrmsr(MSR_SF_MASK, PSL_NT|PSL_T|PSL_I|PSL_C|PSL_D); + /* + * The console and kdb should be initialized even earlier than here, + * but some console drivers don't work until after getmemsize(). + * Default to late console initialization to support these drivers. + * This loses mainly printf()s in getmemsize() and early debugging. + */ + late_console = 1; + TUNABLE_INT_FETCH("debug.late_console", &late_console); + if (!late_console) { + cninit(); + amd64_kdb_init(); + } + getmemsize(kmdp, physfree); init_param2(physmem); /* now running on new page tables, configured,and u/iom is accessible */ - cninit(); + if (late_console) + cninit(); #ifdef DEV_ISA #ifdef DEV_ATPIC @@ -1686,13 +1712,8 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) #error "have you forgotten the isa device?"; #endif - kdb_init(); - -#ifdef KDB - if (boothowto & RB_KDB) - kdb_enter(KDB_WHY_BOOTFLAGS, - "Boot flags requested debugger"); -#endif + if (late_console) + amd64_kdb_init(); msgbufinit(msgbufp, msgbufsize); fpuinit(); diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index c88c6140a41a..9200d00401f5 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -2089,7 +2089,6 @@ getmemsize(int first) * use that and do not make any VM86 calls. */ physmap_idx = 0; - smapbase = NULL; kmdp = preload_search_by_type("elf kernel"); if (kmdp == NULL) kmdp = preload_search_by_type("elf32 kernel"); @@ -2223,6 +2222,9 @@ getmemsize(int first) * highest page of the physical address space. It should be * called something like "Maxphyspage". We may adjust this * based on ``hw.physmem'' and the results of the memory test. + * + * This is especially confusing when it is much larger than the + * memory size and is displayed as "realmem". */ Maxmem = atop(physmap[physmap_idx + 1]); @@ -2428,6 +2430,19 @@ getmemsize(int first) } #endif /* PC98 */ +static void +i386_kdb_init(void) +{ +#ifdef DDB + db_fetch_ksymtab(bootinfo.bi_symtab, bootinfo.bi_esymtab); +#endif + kdb_init(); +#ifdef KDB + if (boothowto & RB_KDB) + kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); +#endif +} + register_t init386(first) int first; @@ -2438,6 +2453,7 @@ init386(first) #ifdef CPU_ENABLE_SSE struct xstate_hdr *xhdr; #endif + int late_console; thread0.td_kstack = proc0kstack; thread0.td_kstack_pages = TD0_KSTACK_PAGES; @@ -2502,6 +2518,7 @@ init386(first) first += DPCPU_SIZE; PCPU_SET(prvspace, pc); PCPU_SET(curthread, &thread0); + /* Non-late cninit() and printf() can be moved up to here. */ /* * Initialize mutexes. @@ -2668,30 +2685,33 @@ init386(first) #endif #endif + /* + * The console and kdb should be initialized even earlier than here, + * but some console drivers don't work until after getmemsize(). + * Default to late console initialization to support these drivers. + * This loses mainly printf()s in getmemsize() and early debugging. + */ + late_console = 1; + TUNABLE_INT_FETCH("debug.late_console", &late_console); + if (!late_console) { + cninit(); + i386_kdb_init(); + } + vm86_initialize(); getmemsize(first); init_param2(physmem); /* now running on new page tables, configured,and u/iom is accessible */ - /* - * Initialize the console before we print anything out. - */ - cninit(); + if (late_console) + cninit(); if (metadata_missing) printf("WARNING: loader(8) metadata is missing!\n"); -#ifdef DDB - db_fetch_ksymtab(bootinfo.bi_symtab, bootinfo.bi_esymtab); -#endif - - kdb_init(); - -#ifdef KDB - if (boothowto & RB_KDB) - kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); -#endif + if (late_console) + i386_kdb_init(); msgbufinit(msgbufp, msgbufsize); #ifdef DEV_NPX From 808cf02c244239ce0bebb09c9f4a49e11db29f3b Mon Sep 17 00:00:00 2001 From: Bruce Evans Date: Sun, 25 Sep 2016 16:30:29 +0000 Subject: [PATCH 06/64] Determine the operand/address size of %cs in a new function db_segsize(). Use db_segsize() to set the default operand/address size for disassembling. Allow overriding this with the "alternate" display format /I. The API of db_disasm() should be debooleanized to pass a more general request (amd64 needs overrides to sizes of 16, 32, and 64, but this commit doesn't implement anything for amd64 since much larger changes are needed to restore the amd64 disassmbler's support for non-default sizes). Fix db_print_loc_and_inst() to ask for the normal format and not the alternate in normal operation. This is most useful for vm86 mode, but also works for 16-bit protected mode. Use db_segsize() to avoid trying to print a garbage stack trace if %cs is 16 bits. Print something like the stack trace termination message for a trap boundary instead. Document that the alternate format is now useful on i386. --- share/man/man4/ddb.4 | 4 +++- sys/ddb/db_examine.c | 2 +- sys/i386/i386/db_disasm.c | 13 +++++++++++-- sys/i386/i386/db_interface.c | 24 ++++++++++++++++++++++++ sys/i386/i386/db_trace.c | 11 +++++++++++ sys/i386/include/db_machdep.h | 2 ++ 6 files changed, 52 insertions(+), 4 deletions(-) diff --git a/share/man/man4/ddb.4 b/share/man/man4/ddb.4 index cb883216f918..6b072ba1ee36 100644 --- a/share/man/man4/ddb.4 +++ b/share/man/man4/ddb.4 @@ -264,7 +264,9 @@ The location is also displayed in hex at the beginning of each line. display as an instruction .It Cm I display as an instruction with possible alternate formats depending on the -machine, but none of the supported architectures have an alternate format +machine. +On i386, this selects the alternate format for the instruction decoding +(16 bits in a 32-bit code segment and vice versa). .It Cm S display a symbol name for the pointer stored at the address .El diff --git a/sys/ddb/db_examine.c b/sys/ddb/db_examine.c index de2bbe4e7735..a1e5a2858ab7 100644 --- a/sys/ddb/db_examine.c +++ b/sys/ddb/db_examine.c @@ -241,7 +241,7 @@ db_print_loc_and_inst(db_addr_t loc) db_printsym(loc, DB_STGY_PROC); if (db_search_symbol(loc, DB_STGY_PROC, &off) != C_DB_SYM_NULL) { db_printf(":\t"); - (void)db_disasm(loc, true); + (void)db_disasm(loc, false); } } diff --git a/sys/i386/i386/db_disasm.c b/sys/i386/i386/db_disasm.c index 2b398da8e96c..5728fe5def08 100644 --- a/sys/i386/i386/db_disasm.c +++ b/sys/i386/i386/db_disasm.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); * Instruction disassembler. */ #include +#include #include #include @@ -1168,9 +1169,17 @@ db_disasm(db_addr_t loc, bool altfmt) int len; struct i_addr address; + if (db_segsize(kdb_frame) == 16) + altfmt = !altfmt; get_value_inc(inst, loc, 1, FALSE); - short_addr = FALSE; - size = LONG; + if (altfmt) { + short_addr = TRUE; + size = WORD; + } + else { + short_addr = FALSE; + size = LONG; + } seg = NULL; /* diff --git a/sys/i386/i386/db_interface.c b/sys/i386/i386/db_interface.c index 7079e5688b85..3c0ac813ff65 100644 --- a/sys/i386/i386/db_interface.c +++ b/sys/i386/i386/db_interface.c @@ -135,6 +135,30 @@ db_write_bytes(vm_offset_t addr, size_t size, char *data) return (ret); } +int +db_segsize(struct trapframe *tfp) +{ + struct proc_ldt *plp; + struct segment_descriptor *sdp; + int sel; + + if (tfp == NULL) + return (32); + if (tfp->tf_eflags & PSL_VM) + return (16); + sel = tfp->tf_cs & 0xffff; + if (sel == GSEL(GCODE_SEL, SEL_KPL)) + return (32); + /* Rare cases follow. User mode cases are currently unreachable. */ + if (ISLDT(sel)) { + plp = curthread->td_proc->p_md.md_ldt; + sdp = (plp != NULL) ? &plp->ldt_sd : &ldt[0].sd; + } else { + sdp = &gdt[PCPU_GET(cpuid) * NGDT].sd; + } + return (sdp[IDXSEL(sel)].sd_def32 == 0 ? 16 : 32); +} + void db_show_mdpcpu(struct pcpu *pc) { diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c index 4918ed232dd3..4f5f4130f2a4 100644 --- a/sys/i386/i386/db_trace.c +++ b/sys/i386/i386/db_trace.c @@ -421,6 +421,17 @@ db_backtrace(struct thread *td, struct trapframe *tf, struct i386_frame *frame, int instr, narg; boolean_t first; + if (db_segsize(tf) == 16) { + db_printf( +"--- 16-bit%s, cs:eip = %#x:%#x, ss:esp = %#x:%#x, ebp = %#x, tf = %p ---\n", + (tf->tf_eflags & PSL_VM) ? " (vm86)" : "", + tf->tf_cs, tf->tf_eip, + TF_HAS_STACKREGS(tf) ? tf->tf_ss : rss(), + TF_HAS_STACKREGS(tf) ? tf->tf_esp : (intptr_t)&tf->tf_esp, + tf->tf_ebp, tf); + return (0); + } + /* * If an indirect call via an invalid pointer caused a trap, * %pc contains the invalid address while the return address diff --git a/sys/i386/include/db_machdep.h b/sys/i386/include/db_machdep.h index 3ab06486a3fb..e8d1d8eab95e 100644 --- a/sys/i386/include/db_machdep.h +++ b/sys/i386/include/db_machdep.h @@ -98,4 +98,6 @@ do { \ #define DB_SMALL_VALUE_MAX 0x7fffffff #define DB_SMALL_VALUE_MIN (-0x400001) +int db_segsize(struct trapframe *tfp); + #endif /* !_MACHINE_DB_MACHDEP_H_ */ From bba95d2d7e1df56c08fe490c5652aafd63de0d0d Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Sun, 25 Sep 2016 16:39:18 +0000 Subject: [PATCH 07/64] Relocatable object files are renamed from *.So to *.pico Reminder by: imp@ --- UPDATING | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/UPDATING b/UPDATING index ad49262b69bb..b2114f59df85 100644 --- a/UPDATING +++ b/UPDATING @@ -31,6 +31,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 12.x IS SLOW: disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20160924: + Relocatable object files with the extension of .So have been renamed + to use an extension of .pico instead. The purpose of this change is + to avoid a name clash with shared libraries on case-insensitive file + systems. On those file systems, foo.So is the same file as foo.so. + 20160918: GNU rcs has been turned off by default. It can (temporarily) be built again by adding WITH_RCS knob in src.conf. From 6d93a08d0aeb0bed8284fdeafc70dc23f4e36c21 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Sun, 25 Sep 2016 16:50:31 +0000 Subject: [PATCH 08/64] Document the ".pico" extension for object files. Suggested by: emaste@ --- share/mk/bsd.README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/mk/bsd.README b/share/mk/bsd.README index 210e6008246c..81aad40a96f2 100644 --- a/share/mk/bsd.README +++ b/share/mk/bsd.README @@ -114,7 +114,7 @@ the tree where the file gets installed. The profiled libraries are no longer built in a different directory than the regular libraries. A new suffix, ".po", is used to denote a profiled -object. +object, and ".pico" denotes a position-independent relocatable object. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= From 81d7ca7761ba1224a98686a8c5ca3f454636b9bc Mon Sep 17 00:00:00 2001 From: Tijl Coosemans Date: Sun, 25 Sep 2016 18:29:02 +0000 Subject: [PATCH 09/64] MFamd64: r266901 Allocate a zeroed LDT. Failing to do this might result in the LDT appearing to run out of free descriptors because of random junk in the descriptor's 'sd_type' field. http://lists.freebsd.org/pipermail/freebsd-amd64/2014-May/016088.html PR: 212639 Submitted by: wheelcomplex@gmail.com MFC after: 2 weeks --- sys/i386/i386/sys_machdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c index 9c8d94b44b81..bbf631781d1d 100644 --- a/sys/i386/i386/sys_machdep.c +++ b/sys/i386/i386/sys_machdep.c @@ -438,7 +438,7 @@ user_ldt_alloc(struct mdproc *mdp, int len) new_ldt->ldt_len = len = NEW_MAX_LD(len); new_ldt->ldt_base = (caddr_t)kmem_malloc(kernel_arena, - len * sizeof(union descriptor), M_WAITOK); + len * sizeof(union descriptor), M_WAITOK | M_ZERO); new_ldt->ldt_refcnt = 1; new_ldt->ldt_active = 0; From 9eeaa0ea1f94111331ef64d4c8f47e267419ee78 Mon Sep 17 00:00:00 2001 From: Bruce Evans Date: Sun, 25 Sep 2016 18:39:24 +0000 Subject: [PATCH 10/64] Minor fixes for 160-bit disassembly: (1) Print the default segment %ss before adresses relative to %bp. This is too cluttered for me, but so is printing some other default prefixes, and this is a reasonable reminder that %ss is quite likely to be different from %ds in 16-bit mode. db_disasm still handles prefixes poorly, by trying to discard redundant ones. This loses information, and sometimes the result is wrong or misleading. Clean up nearby initializations and dead code. (2) Fix decoding of operand and address size prefixes in 16-bit mode. They reverse the default in all modes. Obtained from: (1) is partly from r1.4 (2003/11/08) in DFlyBSD (?) --- sys/i386/i386/db_disasm.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sys/i386/i386/db_disasm.c b/sys/i386/i386/db_disasm.c index 5728fe5def08..b3a67636dd08 100644 --- a/sys/i386/i386/db_disasm.c +++ b/sys/i386/i386/db_disasm.c @@ -884,6 +884,7 @@ struct i_addr { const char * base; const char * index; int ss; + bool defss; /* set if %ss is the default segment */ }; static const char * const db_index_reg_16[8] = { @@ -955,10 +956,12 @@ db_read_address(loc, short_addr, regmodrm, addrp) } addrp->is_reg = FALSE; addrp->index = NULL; + addrp->ss = 0; + addrp->defss = FALSE; if (short_addr) { - addrp->index = NULL; - addrp->ss = 0; + if (rm == 2 || rm == 3 || (rm == 6 && mod != 0)) + addrp->defss = TRUE; switch (mod) { case 0: if (rm == 6) { @@ -985,7 +988,7 @@ db_read_address(loc, short_addr, regmodrm, addrp) } } else { - if (mod != 3 && rm == 4) { + if (rm == 4) { get_value_inc(sib, loc, 1, FALSE); rm = sib_base(sib); index = sib_index(sib); @@ -1036,6 +1039,9 @@ db_print_address(seg, size, addrp) if (seg) { db_printf("%s:", seg); } + else if (addrp->defss) { + db_printf("%%ss:"); + } db_printsym((db_addr_t)addrp->disp, DB_STGY_ANY); if (addrp->base != NULL || addrp->index != NULL) { @@ -1189,11 +1195,11 @@ db_disasm(db_addr_t loc, bool altfmt) prefix = TRUE; do { switch (inst) { - case 0x66: /* data16 */ - size = WORD; + case 0x66: + size = (altfmt ? LONG : WORD); break; case 0x67: - short_addr = TRUE; + short_addr = !altfmt; break; case 0x26: seg = "%es"; From fbc9d202d8476261f9242a92c7be7414194b9115 Mon Sep 17 00:00:00 2001 From: Andriy Voskoboinyk Date: Sun, 25 Sep 2016 19:13:07 +0000 Subject: [PATCH 11/64] rsu: do not restart calibration task when going out of RUN state. Clear 'sc_calibrating' flag and stop calibration task when interface is not associated; this fixes possible panic after detach. Reported and tested by: hselasky Reviewed by: adrian MFC after: 6 days --- sys/dev/usb/wlan/if_rsu.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sys/dev/usb/wlan/if_rsu.c b/sys/dev/usb/wlan/if_rsu.c index c08b4af5dc74..4ee9decf4e2b 100644 --- a/sys/dev/usb/wlan/if_rsu.c +++ b/sys/dev/usb/wlan/if_rsu.c @@ -1270,9 +1270,12 @@ rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) default: break; } - sc->sc_calibrating = 1; - /* Start periodic calibration. */ - taskqueue_enqueue_timeout(taskqueue_thread, &sc->calib_task, hz); + if (startcal != 0) { + sc->sc_calibrating = 1; + /* Start periodic calibration. */ + taskqueue_enqueue_timeout(taskqueue_thread, &sc->calib_task, + hz); + } RSU_UNLOCK(sc); IEEE80211_LOCK(ic); return (uvp->newstate(vap, nstate, arg)); From 85bc19eb22375c7e1bbf22758429603178c2038b Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sun, 25 Sep 2016 22:07:41 +0000 Subject: [PATCH 12/64] [ath_hal] Add FCC6_FCCA regulatory domain (0x0014). Tested: * TP-Link N900, AR9380, regdomain 0x0014 (FCC6_FCCA). --- sys/dev/ath/ath_hal/ah_internal.h | 2 +- .../ath/ath_hal/ah_regdomain/ah_rd_domains.h | 11 +++++++ .../ath_hal/ah_regdomain/ah_rd_freqbands.h | 31 +++++++++++++------ .../ath/ath_hal/ah_regdomain/ah_rd_regmap.h | 1 + 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/sys/dev/ath/ath_hal/ah_internal.h b/sys/dev/ath/ath_hal/ah_internal.h index 6583c73dd11a..0d650ded7587 100644 --- a/sys/dev/ath/ath_hal/ah_internal.h +++ b/sys/dev/ath/ath_hal/ah_internal.h @@ -134,7 +134,7 @@ struct ath_hal_rf *ath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode); * right now. */ #ifndef AH_MAXCHAN -#define AH_MAXCHAN 96 +#define AH_MAXCHAN 128 #endif #define HAL_NF_CAL_HIST_LEN_FULL 5 diff --git a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h index 04a6ccdebd84..0ebb6d174472 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h +++ b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h @@ -242,6 +242,17 @@ static REG_DOMAIN regDomains[] = { .chan11a_quarter = BM3(F8_5180_5240, F8_5260_5320,F10_5745_5825), }, + {.regDmnEnum = FCC6, + .conformanceTestLimit = FCC, + .chan11a = BM5(F8_5180_5240, F5_5260_5320, F1_5500_5580, F2_5660_5720, F6_5745_5825), + .chan11a_turbo = BM3(T7_5210_5210, T3_5250_5290, T2_5760_5800), + .chan11a_dyn_turbo = BM4(T7_5200_5200, T1_5240_5240, T2_5280_5280, T1_5765_5805), +#if 0 + .chan11a_half = BM3(F7_5180_5240, F7_5260_5320, F9_5745_5825), + .chan11a_quarter = BM3(F8_5180_5240, F8_5260_5320,F10_5745_5825), +#endif + }, + {.regDmnEnum = MKK1, .conformanceTestLimit = MKK, .pscan = PSCAN_MKK1, diff --git a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h index 79d418f3c728..84e7af7f5afd 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h +++ b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h @@ -125,8 +125,11 @@ static REG_DMN_FREQ_BAND regDmn5GhzFreq[] = { { 5280, 5320, 17, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC }, #define F1_5280_5320 AFTER(F3_5260_5700) + { 5500, 5580, 23, 6, 20, 20, DFS_FCC3, PSCAN_FCC }, +#define F1_5500_5580 AFTER(F1_5280_5320) + { 5500, 5620, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI }, -#define F1_5500_5620 AFTER(F1_5280_5320) +#define F1_5500_5620 AFTER(F1_5500_5580) { 5500, 5700, 20, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC }, #define F1_5500_5700 AFTER(F1_5500_5620) @@ -136,9 +139,11 @@ static REG_DMN_FREQ_BAND regDmn5GhzFreq[] = { #define F3_5500_5700 AFTER(F2_5500_5700) { 5500, 5700, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, PSCAN_MKK3 | PSCAN_FCC }, #define F4_5500_5700 AFTER(F3_5500_5700) + { 5660, 5720, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI }, +#define F2_5660_5720 AFTER(F4_5500_5700) { 5745, 5805, 23, 0, 20, 20, NO_DFS, NO_PSCAN }, -#define F1_5745_5805 AFTER(F4_5500_5700) +#define F1_5745_5805 AFTER(F2_5660_5720) { 5745, 5805, 30, 6, 20, 20, NO_DFS, NO_PSCAN }, #define F2_5745_5805 AFTER(F1_5745_5805) { 5745, 5805, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI }, @@ -191,6 +196,7 @@ static REG_DMN_FREQ_BAND regDmn5GhzFreq[] = { #define W2_5825_5825 AFTER(W2_5180_5240) }; + /* * 5GHz Turbo (dynamic & static) tags */ @@ -203,13 +209,14 @@ static REG_DMN_FREQ_BAND regDmn5GhzTurboFreq[] = { #define T1_5370_5490 AFTER(T1_5250_5330) { 5530, 5650, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN }, #define T1_5530_5650 AFTER(T1_5370_5490) - + { 5200, 5200, 23, 6, 40, 40, NO_DFS, NO_PSCAN }, +#define T7_5200_5200 AFTER(T1_5530_5650) { 5150, 5190, 5, 6, 40, 40, NO_DFS, NO_PSCAN }, -#define T1_5150_5190 AFTER(T1_5530_5650) - { 5230, 5310, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN }, -#define T1_5230_5310 AFTER(T1_5150_5190) +#define T1_5230_5310 AFTER(T7_5200_5200) { 5350, 5470, 5, 6, 40, 40, NO_DFS, NO_PSCAN }, -#define T1_5350_5470 AFTER(T1_5230_5310) +#define T1_5150_5190 AFTER(T1_5230_5310) + { 5230, 5310, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN }, +#define T1_5350_5470 AFTER(T1_5150_5190) { 5510, 5670, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN }, #define T1_5510_5670 AFTER(T1_5350_5470) @@ -221,9 +228,13 @@ static REG_DMN_FREQ_BAND regDmn5GhzTurboFreq[] = { #define T1_5210_5210 AFTER(T2_5200_5240) { 5210, 5210, 23, 0, 40, 40, NO_DFS, NO_PSCAN }, #define T2_5210_5210 AFTER(T1_5210_5210) + { 5210, 5210, 23, 6, 40, 40, NO_DFS, NO_PSCAN }, +#define T7_5210_5210 AFTER(T2_5210_5210) + { 5240, 5240, 23, 6, 40, 40, NO_DFS, PSCAN_FCC_T }, +#define T1_5240_5240 AFTER(T7_5210_5210) { 5280, 5280, 23, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T }, -#define T1_5280_5280 AFTER(T2_5210_5210) +#define T1_5280_5280 AFTER(T1_5240_5240) { 5280, 5280, 20, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T }, #define T2_5280_5280 AFTER(T1_5280_5280) { 5250, 5250, 17, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T }, @@ -234,9 +245,11 @@ static REG_DMN_FREQ_BAND regDmn5GhzTurboFreq[] = { #define T1_5250_5290 AFTER(T1_5290_5290) { 5250, 5290, 23, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T }, #define T2_5250_5290 AFTER(T1_5250_5290) + { 5250, 5290, 23, 6, 40, 40, NO_DFS, PSCAN_FCC_T }, +#define T3_5250_5290 AFTER(T2_5250_5290) { 5540, 5660, 20, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T }, -#define T1_5540_5660 AFTER(T2_5250_5290) +#define T1_5540_5660 AFTER(T3_5250_5290) { 5760, 5800, 20, 0, 40, 40, NO_DFS, NO_PSCAN }, #define T1_5760_5800 AFTER(T1_5540_5660) { 5760, 5800, 30, 6, 40, 40, NO_DFS, NO_PSCAN }, diff --git a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h index f77be2268ba7..33a6a7c531f6 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h +++ b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h @@ -41,6 +41,7 @@ static REG_DMN_PAIR_MAPPING regDomainPairs[] = { {FCC3_WORLD, FCC3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, CTRY_DEFAULT }, {FCC4_FCCA, FCC4, FCCA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, CTRY_DEFAULT }, {FCC5_FCCB, FCC5, FCCB, NO_REQ, NO_REQ, PSCAN_DEFER, CTRY_DEFAULT }, + {FCC6_FCCA, FCC6, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, CTRY_DEFAULT }, {ETSI1_WORLD, ETSI1, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, CTRY_DEFAULT }, {ETSI2_WORLD, ETSI2, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, CTRY_DEFAULT }, From 5b06614ce34dfe9b8ee98e226e93fb776bdc079c Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sun, 25 Sep 2016 22:17:46 +0000 Subject: [PATCH 13/64] [ath_hal] add a comment for the channel 144 regdomain flag. I'm .. still trying to figure out what's going on. --- sys/dev/ath/ath_hal/ah_regdomain.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sys/dev/ath/ath_hal/ah_regdomain.c b/sys/dev/ath/ath_hal/ah_regdomain.c index d388e12c75ef..d3770356d7ea 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain.c +++ b/sys/dev/ath/ath_hal/ah_regdomain.c @@ -548,6 +548,14 @@ add_chanlist_mode(struct ath_hal *ah, struct ieee80211_channel chans[], continue; } #endif + + /* + * XXX TODO: handle REG_EXT_FCC_CH_144. + * + * Figure out which instances/uses cause us to not + * be allowed to use channel 144 (pri or sec overlap.) + */ + bfreq_lo = MAX(fband->lowChannel + low_adj, freq_lo); bfreq_hi = MIN(fband->highChannel + hi_adj, freq_hi); if (fband->channelSep >= channelSep) From 5a1302ab2e3250c158817bcb7880cb7a1ea856b4 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Sun, 25 Sep 2016 22:57:59 +0000 Subject: [PATCH 14/64] Replace the use of linker sets with constructors for both the formats and schemes. Formats and schemes are registered at runtime now, rather than collected at link time. --- usr.bin/mkimg/format.c | 24 +++++++++++++++++++----- usr.bin/mkimg/format.h | 13 ++++++++----- usr.bin/mkimg/mkimg.c | 21 ++++++++++----------- usr.bin/mkimg/scheme.c | 23 ++++++++++++++++++----- usr.bin/mkimg/scheme.h | 10 ++++++---- 5 files changed, 61 insertions(+), 30 deletions(-) diff --git a/usr.bin/mkimg/format.c b/usr.bin/mkimg/format.c index a21b08ad0e7e..010da7c11235 100644 --- a/usr.bin/mkimg/format.c +++ b/usr.bin/mkimg/format.c @@ -28,8 +28,6 @@ __FBSDID("$FreeBSD$"); #include -#include -#include #include #include #include @@ -42,8 +40,24 @@ __FBSDID("$FreeBSD$"); #include "format.h" #include "mkimg.h" +static struct mkimg_format *first; static struct mkimg_format *format; +struct mkimg_format * +format_iterate(struct mkimg_format *f) +{ + + return ((f == NULL) ? first : f->next); +} + +void +format_register(struct mkimg_format *f) +{ + + f->next = first; + first = f; +} + int format_resize(lba_t end) { @@ -56,10 +70,10 @@ format_resize(lba_t end) int format_select(const char *spec) { - struct mkimg_format *f, **iter; + struct mkimg_format *f; - SET_FOREACH(iter, formats) { - f = *iter; + f = NULL; + while ((f = format_iterate(f)) != NULL) { if (strcasecmp(spec, f->name) == 0) { format = f; return (0); diff --git a/usr.bin/mkimg/format.h b/usr.bin/mkimg/format.h index aa00e6e2e27b..e50fe3dc26cb 100644 --- a/usr.bin/mkimg/format.h +++ b/usr.bin/mkimg/format.h @@ -29,21 +29,24 @@ #ifndef _MKIMG_FORMAT_H_ #define _MKIMG_FORMAT_H_ -#include - struct mkimg_format { + struct mkimg_format *next; const char *name; const char *description; int (*resize)(lba_t); int (*write)(int); }; -SET_DECLARE(formats, struct mkimg_format); -#define FORMAT_DEFINE(nm) DATA_SET(formats, nm) +#define FORMAT_DEFINE(nm) \ +static void format_register_##nm(void) __attribute__((constructor)); \ +static void format_register_##nm(void) { format_register(&nm); } -int format_resize(lba_t); +struct mkimg_format *format_iterate(struct mkimg_format *); +void format_register(struct mkimg_format *); int format_select(const char *); struct mkimg_format *format_selected(void); + +int format_resize(lba_t); int format_write(int); #endif /* _MKIMG_FORMAT_H_ */ diff --git a/usr.bin/mkimg/mkimg.c b/usr.bin/mkimg/mkimg.c index 5d41e3bbd48b..3dfc10a3617d 100644 --- a/usr.bin/mkimg/mkimg.c +++ b/usr.bin/mkimg/mkimg.c @@ -27,7 +27,6 @@ #include __FBSDID("$FreeBSD$"); -#include #include #include #include @@ -77,20 +76,20 @@ u_int blksz = 0; static void print_formats(int usage) { - struct mkimg_format *f, **f_iter; + struct mkimg_format *f; const char *sep; if (usage) { fprintf(stderr, " formats:\n"); - SET_FOREACH(f_iter, formats) { - f = *f_iter; + f = NULL; + while ((f = format_iterate(f)) != NULL) { fprintf(stderr, "\t%s\t- %s\n", f->name, f->description); } } else { sep = ""; - SET_FOREACH(f_iter, formats) { - f = *f_iter; + f = NULL; + while ((f = format_iterate(f)) != NULL) { printf("%s%s", sep, f->name); sep = " "; } @@ -101,20 +100,20 @@ print_formats(int usage) static void print_schemes(int usage) { - struct mkimg_scheme *s, **s_iter; + struct mkimg_scheme *s; const char *sep; if (usage) { fprintf(stderr, " schemes:\n"); - SET_FOREACH(s_iter, schemes) { - s = *s_iter; + s = NULL; + while ((s = scheme_iterate(s)) != NULL) { fprintf(stderr, "\t%s\t- %s\n", s->name, s->description); } } else { sep = ""; - SET_FOREACH(s_iter, schemes) { - s = *s_iter; + s = NULL; + while ((s = scheme_iterate(s)) != NULL) { printf("%s%s", sep, s->name); sep = " "; } diff --git a/usr.bin/mkimg/scheme.c b/usr.bin/mkimg/scheme.c index 6cd332f2a946..34047e751bc5 100644 --- a/usr.bin/mkimg/scheme.c +++ b/usr.bin/mkimg/scheme.c @@ -28,8 +28,6 @@ __FBSDID("$FreeBSD$"); #include -#include -#include #include #include #include @@ -65,6 +63,7 @@ static struct { { NULL, ALIAS_NONE } /* Keep last! */ }; +static struct mkimg_scheme *first; static struct mkimg_scheme *scheme; static void *bootcode; @@ -82,13 +81,27 @@ scheme_parse_alias(const char *name) return (ALIAS_NONE); } +struct mkimg_scheme * +scheme_iterate(struct mkimg_scheme *s) +{ + + return ((s == NULL) ? first : s->next); +} + +void +scheme_register(struct mkimg_scheme *s) +{ + s->next = first; + first = s; +} + int scheme_select(const char *spec) { - struct mkimg_scheme *s, **iter; + struct mkimg_scheme *s; - SET_FOREACH(iter, schemes) { - s = *iter; + s = NULL; + while ((s = scheme_iterate(s)) != NULL) { if (strcasecmp(spec, s->name) == 0) { scheme = s; return (0); diff --git a/usr.bin/mkimg/scheme.h b/usr.bin/mkimg/scheme.h index 552d0313f32d..5826036622a1 100644 --- a/usr.bin/mkimg/scheme.h +++ b/usr.bin/mkimg/scheme.h @@ -29,8 +29,6 @@ #ifndef _MKIMG_SCHEME_H_ #define _MKIMG_SCHEME_H_ -#include - enum alias { ALIAS_NONE, /* Keep first! */ /* start */ @@ -62,6 +60,7 @@ struct mkimg_alias { }; struct mkimg_scheme { + struct mkimg_scheme *next; const char *name; const char *description; struct mkimg_alias *aliases; @@ -77,9 +76,12 @@ struct mkimg_scheme { u_int maxsecsz; }; -SET_DECLARE(schemes, struct mkimg_scheme); -#define SCHEME_DEFINE(nm) DATA_SET(schemes, nm) +#define SCHEME_DEFINE(nm) \ +static void scheme_register_##nm(void) __attribute__((constructor)); \ +static void scheme_register_##nm(void) { scheme_register(&nm); } +struct mkimg_scheme *scheme_iterate(struct mkimg_scheme *); +void scheme_register(struct mkimg_scheme *); int scheme_select(const char *); struct mkimg_scheme *scheme_selected(void); From 23ea1f2b1d1ff6666a1b4a10d7074569b64cdcc3 Mon Sep 17 00:00:00 2001 From: Oleksandr Tymoshenko Date: Sun, 25 Sep 2016 23:45:49 +0000 Subject: [PATCH 15/64] Update AHCI driver to match new dts tree phy name parameter was changed from "sata-phy" to "sata-0" in new dts tree introduced in r306197 --- sys/arm/nvidia/tegra_ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/arm/nvidia/tegra_ahci.c b/sys/arm/nvidia/tegra_ahci.c index fcd6e300f96f..e981e000406a 100644 --- a/sys/arm/nvidia/tegra_ahci.c +++ b/sys/arm/nvidia/tegra_ahci.c @@ -255,7 +255,7 @@ get_fdt_resources(struct tegra_ahci_sc *sc, phandle_t node) return (ENXIO); } - rv = phy_get_by_ofw_name(sc->dev, 0, "sata-phy", &sc->phy); + rv = phy_get_by_ofw_name(sc->dev, 0, "sata-0", &sc->phy); if (rv != 0) { device_printf(sc->dev, "Cannot get 'sata' phy\n"); return (ENXIO); From ee484d5bd3bbbb3a670041d793be050f12fa4a9b Mon Sep 17 00:00:00 2001 From: Oleksandr Tymoshenko Date: Sun, 25 Sep 2016 23:48:15 +0000 Subject: [PATCH 16/64] Update PCI driver to match new dts tree In new dts tree phy is a property of port, not the controller node, also the name was changed from "pcie" to "pcie-0" --- sys/arm/nvidia/tegra_pcie.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/sys/arm/nvidia/tegra_pcie.c b/sys/arm/nvidia/tegra_pcie.c index 47471b82f8bf..154471b3eecc 100644 --- a/sys/arm/nvidia/tegra_pcie.c +++ b/sys/arm/nvidia/tegra_pcie.c @@ -266,6 +266,7 @@ struct tegra_pcib_port { int port_idx; /* chip port index */ int num_lanes; /* number of lanes */ bus_size_t afi_pex_ctrl; /* offset of afi_pex_ctrl */ + phy_t phy; /* port phy */ /* Config space properties. */ bus_addr_t rp_base_addr; /* PA of config window */ @@ -291,7 +292,6 @@ struct tegra_pcib_softc { struct ofw_pci_range pref_mem_range; struct ofw_pci_range io_range; - phy_t phy; clk_t clk_pex; clk_t clk_afi; clk_t clk_pll_e; @@ -963,6 +963,15 @@ tegra_pcib_parse_port(struct tegra_pcib_softc *sc, phandle_t node) port->afi_pex_ctrl = tegra_pcib_pex_ctrl(sc, port->port_idx); sc->lanes_cfg |= port->num_lanes << (4 * port->port_idx); + /* Phy. */ + rv = phy_get_by_ofw_name(sc->dev, node, "pcie-0", &port->phy); + if (rv != 0) { + device_printf(sc->dev, + "Cannot get 'pcie-0' phy for port %d\n", + port->port_idx); + goto fail; + } + return (port); fail: free(port, M_DEVBUF); @@ -1067,13 +1076,6 @@ tegra_pcib_parse_fdt_resources(struct tegra_pcib_softc *sc, phandle_t node) return (ENXIO); } - /* Phy. */ - rv = phy_get_by_ofw_name(sc->dev, 0, "pcie", &sc->phy); - if (rv != 0) { - device_printf(sc->dev, "Cannot get 'pcie' phy\n"); - return (ENXIO); - } - /* Ports */ sc->num_ports = 0; for (child = OF_child(node); child != 0; child = OF_peer(child)) { @@ -1306,13 +1308,19 @@ tegra_pcib_enable(struct tegra_pcib_softc *sc) reg &= ~AFI_FUSE_PCIE_T0_GEN2_DIS; AFI_WR4(sc, AFI_FUSE, reg); - /* Enable PCIe phy. */ - rv = phy_enable(sc->dev, sc->phy); - if (rv != 0) { - device_printf(sc->dev, "Cannot enable phy\n"); - return (rv); + for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { + if (sc->ports[i] != NULL) { + rv = phy_enable(sc->dev, sc->ports[i]->phy); + if (rv != 0) { + device_printf(sc->dev, + "Cannot enable phy for port %d\n", + sc->ports[i]->port_idx); + return (rv); + } + } } + rv = hwreset_deassert(sc->hwreset_pcie_x); if (rv != 0) { device_printf(sc->dev, "Cannot unreset 'pci_x' reset\n"); From 4039ea7c9b05c98a3e81950a11ef326007bd63fc Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Mon, 26 Sep 2016 00:41:08 +0000 Subject: [PATCH 17/64] Eliminate the use of EDOOFUS. The error code was used to signal programming errors, but is really a poor substitute for assert. And less portable as well. --- usr.bin/mkimg/image.c | 5 ++--- usr.bin/mkimg/qcow.c | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/usr.bin/mkimg/image.c b/usr.bin/mkimg/image.c index 2527f2891848..39ae41230808 100644 --- a/usr.bin/mkimg/image.c +++ b/usr.bin/mkimg/image.c @@ -456,8 +456,7 @@ image_copyin_mapped(lba_t blk, int fd, uint64_t *sizep) * I don't know what this means or whether it * can happen at all... */ - error = EDOOFUS; - break; + assert(0); } } if (error) @@ -602,7 +601,7 @@ image_copyout_region(int fd, lba_t blk, lba_t size) error = image_copyout_memory(fd, sz, ch->ch_u.mem.ptr); break; default: - return (EDOOFUS); + assert(0); } size -= sz; blk += sz / secsz; diff --git a/usr.bin/mkimg/qcow.c b/usr.bin/mkimg/qcow.c index a89761b80107..64c437a9202c 100644 --- a/usr.bin/mkimg/qcow.c +++ b/usr.bin/mkimg/qcow.c @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -102,7 +103,7 @@ qcow_resize(lba_t imgsz, u_int version) clstr_log2sz = QCOW2_CLSTR_LOG2SZ; break; default: - return (EDOOFUS); + assert(0); } imagesz = round_clstr(imgsz * secsz); @@ -143,8 +144,7 @@ qcow_write(int fd, u_int version) u_int clstrsz, l1idx, l2idx; int error; - if (clstr_log2sz == 0) - return (EDOOFUS); + assert(clstr_log2sz != 0); clstrsz = 1U << clstr_log2sz; blk_clstrsz = clstrsz / secsz; @@ -203,7 +203,7 @@ qcow_write(int fd, u_int version) be32enc(&hdr->u.v2.refcnt_clstrs, refcnt_clstrs); break; default: - return (EDOOFUS); + assert(0); } if (sparse_write(fd, hdr, clstrsz) < 0) { From 5aad7d9a874abf493b80737c67f6cffe9394b27e Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Mon, 26 Sep 2016 01:06:32 +0000 Subject: [PATCH 18/64] Avoid depending on the header for le*enc and be*enc. Not only is the header unportable, the encoding/decoding functions are as well. Instead, duplicate the handful of small inlines we need into a private header called endian.h. Aside: an alternative approach is to move the encoding/decoding functions to a separate system header. While the header is still nonportable, such an approach would make it possible to re-use the definitions by playing games with include paths. This may be the preferred approach if more (build) utilities need this. This change does not preclude that. In fact, it makes it easier. --- usr.bin/mkimg/apm.c | 2 +- usr.bin/mkimg/bsd.c | 2 +- usr.bin/mkimg/ebr.c | 2 +- usr.bin/mkimg/endian.h | 106 +++++++++++++++++++++++++++++++++++++++++ usr.bin/mkimg/gpt.c | 2 +- usr.bin/mkimg/mbr.c | 2 +- usr.bin/mkimg/pc98.c | 2 +- usr.bin/mkimg/qcow.c | 2 +- usr.bin/mkimg/raw.c | 1 - usr.bin/mkimg/vhd.c | 2 +- usr.bin/mkimg/vmdk.c | 2 +- usr.bin/mkimg/vtoc8.c | 2 +- 12 files changed, 116 insertions(+), 11 deletions(-) create mode 100644 usr.bin/mkimg/endian.h diff --git a/usr.bin/mkimg/apm.c b/usr.bin/mkimg/apm.c index de92cc0e9b92..2948faeeeab5 100644 --- a/usr.bin/mkimg/apm.c +++ b/usr.bin/mkimg/apm.c @@ -29,12 +29,12 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include #include #include +#include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" diff --git a/usr.bin/mkimg/bsd.c b/usr.bin/mkimg/bsd.c index 75e554f39b4f..2d52dd806d2e 100644 --- a/usr.bin/mkimg/bsd.c +++ b/usr.bin/mkimg/bsd.c @@ -29,12 +29,12 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include #include #include +#include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" diff --git a/usr.bin/mkimg/ebr.c b/usr.bin/mkimg/ebr.c index 526c494084cf..bbe9fa6c6990 100644 --- a/usr.bin/mkimg/ebr.c +++ b/usr.bin/mkimg/ebr.c @@ -29,12 +29,12 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include #include #include +#include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" diff --git a/usr.bin/mkimg/endian.h b/usr.bin/mkimg/endian.h new file mode 100644 index 000000000000..a8d31208db70 --- /dev/null +++ b/usr.bin/mkimg/endian.h @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 2002 Thomas Moestl + * 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 _MKIMG_ENDIAN_H_ +#define _MKIMG_ENDIAN_H_ + +static __inline uint16_t +be16dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return ((p[0] << 8) | p[1]); +} + +static __inline void +be16enc(void *pp, uint16_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = (u >> 8) & 0xff; + p[1] = u & 0xff; +} + +static __inline void +be32enc(void *pp, uint32_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = (u >> 24) & 0xff; + p[1] = (u >> 16) & 0xff; + p[2] = (u >> 8) & 0xff; + p[3] = u & 0xff; +} + +static __inline void +be64enc(void *pp, uint64_t u) +{ + uint8_t *p = (uint8_t *)pp; + + be32enc(p, (uint32_t)(u >> 32)); + be32enc(p + 4, (uint32_t)(u & 0xffffffffU)); +} + +static __inline uint16_t +le16dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return ((p[1] << 8) | p[0]); +} + +static __inline void +le16enc(void *pp, uint16_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = u & 0xff; + p[1] = (u >> 8) & 0xff; +} + +static __inline void +le32enc(void *pp, uint32_t u) +{ + uint8_t *p = (uint8_t *)pp; + + p[0] = u & 0xff; + p[1] = (u >> 8) & 0xff; + p[2] = (u >> 16) & 0xff; + p[3] = (u >> 24) & 0xff; +} + +static __inline void +le64enc(void *pp, uint64_t u) +{ + uint8_t *p = (uint8_t *)pp; + + le32enc(p, (uint32_t)(u & 0xffffffffU)); + le32enc(p + 4, (uint32_t)(u >> 32)); +} + +#endif /* _MKIMG_ENDIAN_H_ */ diff --git a/usr.bin/mkimg/gpt.c b/usr.bin/mkimg/gpt.c index 678e63653760..d63c04ae93fe 100644 --- a/usr.bin/mkimg/gpt.c +++ b/usr.bin/mkimg/gpt.c @@ -29,7 +29,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include #include @@ -39,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" diff --git a/usr.bin/mkimg/mbr.c b/usr.bin/mkimg/mbr.c index 071bcf5fe70d..72e67ad2727f 100644 --- a/usr.bin/mkimg/mbr.c +++ b/usr.bin/mkimg/mbr.c @@ -29,12 +29,12 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include #include #include +#include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" diff --git a/usr.bin/mkimg/pc98.c b/usr.bin/mkimg/pc98.c index 2db0394fb296..979d1b4dc934 100644 --- a/usr.bin/mkimg/pc98.c +++ b/usr.bin/mkimg/pc98.c @@ -29,12 +29,12 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include #include #include +#include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" diff --git a/usr.bin/mkimg/qcow.c b/usr.bin/mkimg/qcow.c index 64c437a9202c..b41c2d2da07d 100644 --- a/usr.bin/mkimg/qcow.c +++ b/usr.bin/mkimg/qcow.c @@ -28,7 +28,6 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include #include @@ -37,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include "endian.h" #include "image.h" #include "format.h" #include "mkimg.h" diff --git a/usr.bin/mkimg/raw.c b/usr.bin/mkimg/raw.c index 759debf322bf..5686f79a6760 100644 --- a/usr.bin/mkimg/raw.c +++ b/usr.bin/mkimg/raw.c @@ -28,7 +28,6 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include #include diff --git a/usr.bin/mkimg/vhd.c b/usr.bin/mkimg/vhd.c index c4c1d1d45b8b..822c8fdd9f08 100644 --- a/usr.bin/mkimg/vhd.c +++ b/usr.bin/mkimg/vhd.c @@ -28,7 +28,6 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include #include @@ -36,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include "endian.h" #include "image.h" #include "format.h" #include "mkimg.h" diff --git a/usr.bin/mkimg/vmdk.c b/usr.bin/mkimg/vmdk.c index 743418bbea97..0f963de5b2a0 100644 --- a/usr.bin/mkimg/vmdk.c +++ b/usr.bin/mkimg/vmdk.c @@ -28,7 +28,6 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include #include @@ -36,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include "endian.h" #include "image.h" #include "format.h" #include "mkimg.h" diff --git a/usr.bin/mkimg/vtoc8.c b/usr.bin/mkimg/vtoc8.c index 2f5cf0f706e3..dfb499dedf39 100644 --- a/usr.bin/mkimg/vtoc8.c +++ b/usr.bin/mkimg/vtoc8.c @@ -28,7 +28,6 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include #include @@ -36,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" From 3e0d0fcee9bd5987a4bbfb482a728c00b3f875b4 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Mon, 26 Sep 2016 02:05:02 +0000 Subject: [PATCH 19/64] [ath_hal] add a new regdomain flag - I think this means "yes, you can use this NIC in channel 144 if you're in FCC6." I have to go figure out more details about this before I enable it.. --- sys/dev/ath/ath_hal/ah.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/dev/ath/ath_hal/ah.h b/sys/dev/ath/ath_hal/ah.h index 7dd8b9b19857..57a7abd4b773 100644 --- a/sys/dev/ath/ath_hal/ah.h +++ b/sys/dev/ath/ath_hal/ah.h @@ -635,7 +635,8 @@ typedef enum { REG_EXT_JAPAN_MIDBAND = 1, REG_EXT_FCC_DFS_HT40 = 2, REG_EXT_JAPAN_NONDFS_HT40 = 3, - REG_EXT_JAPAN_DFS_HT40 = 4 + REG_EXT_JAPAN_DFS_HT40 = 4, + REG_EXT_FCC_CH_144 = 5, } REG_EXT_BITMAP; enum { From d191be26c0b1758ca940ac0a7ad53eca88f34b2b Mon Sep 17 00:00:00 2001 From: "Pedro F. Giffuni" Date: Mon, 26 Sep 2016 02:29:28 +0000 Subject: [PATCH 20/64] btree(3): don't shortcut closing if the metadata is dirty. Obtained from: NetBSD (from krb5 tree) MFC after: 3 weeks --- lib/libc/db/btree/bt_close.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/libc/db/btree/bt_close.c b/lib/libc/db/btree/bt_close.c index 1f85992f8e4f..f1e7c8ddef06 100644 --- a/lib/libc/db/btree/bt_close.c +++ b/lib/libc/db/btree/bt_close.c @@ -134,7 +134,8 @@ __bt_sync(const DB *dbp, u_int flags) return (RET_ERROR); } - if (F_ISSET(t, B_INMEM | B_RDONLY) || !F_ISSET(t, B_MODIFIED)) + if (F_ISSET(t, B_INMEM | B_RDONLY) || + !F_ISSET(t, B_MODIFIED | B_METADIRTY)) return (RET_SUCCESS); if (F_ISSET(t, B_METADIRTY) && bt_meta(t) == RET_ERROR) From 7b5a53ea4da12961edde4df7af211adb6df6b65c Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Mon, 26 Sep 2016 04:14:00 +0000 Subject: [PATCH 21/64] Portability changes: 1. macOS nor Linux have MAP_NOCORE nor MAP_NOSYNC. Define as 0. 2. macOS doesn't have SEEK_DATA nor SEEK_HOLE. Define as -1 so that lseek will return -1 (with errno set to EINVAL). 3. gcc correctly warns that error is assigned but not used in image_copyout_region(). Fix by returning on the first error. --- usr.bin/mkimg/image.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/usr.bin/mkimg/image.c b/usr.bin/mkimg/image.c index 39ae41230808..3a2936c20131 100644 --- a/usr.bin/mkimg/image.c +++ b/usr.bin/mkimg/image.c @@ -45,6 +45,20 @@ __FBSDID("$FreeBSD$"); #include "image.h" #include "mkimg.h" +#ifndef MAP_NOCORE +#define MAP_NOCORE 0 +#endif +#ifndef MAP_NOSYNC +#define MAP_NOSYNC 0 +#endif + +#ifndef SEEK_DATA +#define SEEK_DATA -1 +#endif +#ifndef SEEK_HOLE +#define SEEK_HOLE -1 +#endif + struct chunk { STAILQ_ENTRY(chunk) ch_list; size_t ch_size; /* Size of chunk in bytes. */ @@ -582,10 +596,13 @@ image_copyout_region(int fd, lba_t blk, lba_t size) size *= secsz; - while (size > 0) { + error = 0; + while (!error && size > 0) { ch = image_chunk_find(blk); - if (ch == NULL) - return (EINVAL); + if (ch == NULL) { + error = EINVAL; + break; + } ofs = (blk - ch->ch_block) * secsz; sz = ch->ch_size - ofs; sz = ((lba_t)sz < size) ? sz : (size_t)size; @@ -606,7 +623,7 @@ image_copyout_region(int fd, lba_t blk, lba_t size) size -= sz; blk += sz / secsz; } - return (0); + return (error); } int From fd6c95c09fdb247f96aa9a3c89bed883f196868b Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Mon, 26 Sep 2016 08:18:34 +0000 Subject: [PATCH 22/64] Document thr_suspend(2) and thr_wake(2). Reviewed by: bjk, jilles Discussed with: emaste, wblock Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D8016 --- lib/libc/sys/Makefile.inc | 2 + lib/libc/sys/thr_suspend.2 | 130 +++++++++++++++++++++++++++++++++++++ lib/libc/sys/thr_wake.2 | 112 ++++++++++++++++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100644 lib/libc/sys/thr_suspend.2 create mode 100644 lib/libc/sys/thr_wake.2 diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 9e83a7f1e3ff..02a0a5377cf0 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -322,6 +322,8 @@ MAN+= sctp_generic_recvmsg.2 \ thr_new.2 \ thr_self.2 \ thr_set_name.2 \ + thr_suspend.2 \ + thr_wake.2 \ timer_create.2 \ timer_delete.2 \ timer_settime.2 \ diff --git a/lib/libc/sys/thr_suspend.2 b/lib/libc/sys/thr_suspend.2 new file mode 100644 index 000000000000..61320ead8c74 --- /dev/null +++ b/lib/libc/sys/thr_suspend.2 @@ -0,0 +1,130 @@ +.\" Copyright (c) 2016 The FreeBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This documentation was written by +.\" Konstantin Belousov under sponsorship +.\" from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 23, 2016 +.Dt THR_SUSPEND 2 +.Os +.Sh NAME +.Nm thr_suspend +.Nd suspend the calling thread +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/thr.h +.Ft int +.Fn thr_suspend "struct timespec *timeout" +.Sh DESCRIPTION +.Bf -symbolic +This function is intended for implementing threading. +Normal applications should use +.Xr pthread_cond_timedwait 3 +together with +.Xr pthread_cond_broadcast 3 +for typical safe suspension with cooperation of the thread +being suspended, or +.Xr pthread_suspend_np 3 +and +.Xr pthread_resume_np 3 +in some specific situations, instead. +.Ef +.Pp +The +.Fn thr_suspend +system call puts the calling thread in a suspended state, where it is +not eligible for CPU time. +This state is exited by another thread calling +.Xr thr_wake 2 , +by expiration of the timeout specified in the +.Fa timeout +argument, +or by the delivery of a signal to the suspended thread. +.Pp +If the +.Fa timeout +argument is +.Dv NULL , +the suspended state can be only terminated by explicit +.Fn thr_wake +or signal. +.Pp +If a wake from +.Xr thr_wake 2 +was delivered before the +.Nm +call, the thread is not put into a suspended state. +Instead, the call +returns immediately without an error. +.Pp +If a thread previously called +.Xr thr_wake 2 +with its own thread identifier, which resulted in setting the internal kernel +flag to immediately abort interruptible sleeps with an +.Er EINTR +error +.Po +see +.Xr thr_wake 2 +.Pc , +the flag is cleared. +As with +.Xr thr_wake 2 +called from another thread, the next +.Nm +call does not result in suspension. +.Pp +.Sh RETURN VALUES +.Rv -std thr_suspend +.Sh ERRORS +The +.Fn thr_suspend +operation returns the following errors: +.Bl -tag -width Er +.It Bq Er EFAULT +The memory pointed to by the +.Fa timeout +argument is not valid. +.It Bq Er ETIMEDOUT +The specified timeout expired. +.It Bq Er ETIMEDOUT +The +.Fa timeout +argument specified a zero time interval. +.It Bq Er EINTR +The sleep was interrupted by a signal. +.El +.Sh SEE ALSO +.Xr ps 1 , +.Xr thr_wake 2 , +.Xr pthread_resume_np 3 , +.Xr pthread_suspend_np 3 +.Sh STANDARDS +The +.Fn thr_suspend +system call is non-standard. diff --git a/lib/libc/sys/thr_wake.2 b/lib/libc/sys/thr_wake.2 new file mode 100644 index 000000000000..59df7d2c903a --- /dev/null +++ b/lib/libc/sys/thr_wake.2 @@ -0,0 +1,112 @@ +.\" Copyright (c) 2016 The FreeBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This documentation was written by +.\" Konstantin Belousov under sponsorship +.\" from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 23, 2016 +.Dt THR_WAKE 2 +.Os +.Sh NAME +.Nm thr_wake +.Nd wake up the suspended thread +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/thr.h +.Ft int +.Fn thr_wake "long id" +.Sh DESCRIPTION +.Bf -symbolic +This function is intended for implementing threading. +Normal applications should use +.Xr pthread_cond_timedwait 3 +together with +.Xr pthread_cond_broadcast 3 +for typical safe suspension with cooperation of the thread +being suspended, or +.Xr pthread_suspend_np 3 +and +.Xr pthread_resume_np 3 +in some specific situations, instead. +.Ef +.Pp +Passing the thread identifier of the calling thread +.Po +see +.Xr thr_self 2 +.Pc +to +.Fn thr_wake +sets a thread's flag to cause the next signal-interruptible sleep +of that thread in the kernel to fail immediately with the +.Er EINTR +error. +The flag is cleared by an interruptible sleep attempt or by a call to +.Xr thr_suspend 2. +This is used by the system threading library to implement cancellation. +.Pp +If +.Fa id +is not equal to the current thread identifier, the specified thread is +woken up if suspended by the +.Xr thr_suspend +system call. +If the thread is not suspended at the time of the +.Nm +call, the wake is remembered and the next attempt of the thread to +suspend itself with the +.Xr thr_suspend 2 +results in immediate return with success. +Only one wake is remembered. +.Sh RETURN VALUES +.Rv -std thr_wake +.Sh ERRORS +The +.Fn thr_wake +operation returns these errors: +.Bl -tag -width Er +.It Bq Er ESRCH +The specified thread was not found or does not belong to the process +of the calling thread. +.El +.Sh SEE ALSO +.Xr ps 1 , +.Xr thr_self 2 +.Xr thr_suspend 2 , +.Xr pthread_cancel 3 , +.Xr pthread_resume_np 3 , +.Xr pthread_suspend_np 3 +.Sh STANDARDS +The +.Fn thr_suspend +system call is non-standard and is used by +.Lb libthr +to implement +.St -p1003.1-2001 +.Xr pthread 3 +functionality. From 41bb1a25a922a0cafe11ea2e7aa3fa091ef64e1a Mon Sep 17 00:00:00 2001 From: Hiren Panchasara Date: Mon, 26 Sep 2016 10:13:58 +0000 Subject: [PATCH 23/64] In sendit(), if mp->msg_control is present, then in sockargs() we are allocating mbuf to store mp->msg_control. Later in kern_sendit(), call to getsock_cap(), will check validity of file pointer passed, if this fails EBADF is returned but mbuf allocated in sockargs() is not freed. Fix this possible leak. Submitted by: Lohith Bellad Reviewed by: adrian MFC after: 3 weeks Differential Revision: https://reviews.freebsd.org/D7910 --- sys/kern/uipc_syscalls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index e282665f75e5..197148cefb75 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -685,7 +685,7 @@ sys_socketpair(struct thread *td, struct socketpair_args *uap) static int sendit(struct thread *td, int s, struct msghdr *mp, int flags) { - struct mbuf *control; + struct mbuf *control = NULL; struct sockaddr *to; int error; @@ -737,6 +737,8 @@ sendit(struct thread *td, int s, struct msghdr *mp, int flags) bad: free(to, M_SONAME); + if (control) + m_freem(control); return (error); } From 60e5fa86df18c1ee5e48b8570e1496f346e86054 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Mon, 26 Sep 2016 13:59:18 +0000 Subject: [PATCH 24/64] Increase timeout for legacy_test from 300 (default) to 600 seconds. It takes about 7 minutes to pass the test on MIPS64EB in QEMU. Sponsored by: DARPA, AFRL Sponsored by: HEIF5 --- usr.bin/calendar/tests/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/usr.bin/calendar/tests/Makefile b/usr.bin/calendar/tests/Makefile index 4491e22aeb03..c92b0e692746 100644 --- a/usr.bin/calendar/tests/Makefile +++ b/usr.bin/calendar/tests/Makefile @@ -4,6 +4,8 @@ PACKAGE= tests TAP_TESTS_SH= legacy_test +TEST_METADATA.legacy_test+= timeout="600" + ${PACKAGE}FILES+= calendar.calibrate ${PACKAGE}FILES+= regress.a1.out ${PACKAGE}FILES+= regress.a2.out From 5b1b1405e3fb8883d5d2b2749eecd9115206c07d Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Mon, 26 Sep 2016 14:01:41 +0000 Subject: [PATCH 25/64] Use bsdlabel as we don't have hardlink disklabel -> bsdlabel on MIPS. Sponsored by: DARPA, AFRL Sponsored by: HEIF5 --- sbin/growfs/tests/legacy_test.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbin/growfs/tests/legacy_test.pl b/sbin/growfs/tests/legacy_test.pl index 7316951c92b3..727960290d1a 100755 --- a/sbin/growfs/tests/legacy_test.pl +++ b/sbin/growfs/tests/legacy_test.pl @@ -14,7 +14,7 @@ END { system "mdconfig -du$unit" if defined $unit }; sub setsize { my ($partszMB, $unitszMB) = @_; - open my $fd, "|-", "disklabel -R md$unit /dev/stdin" or die; + open my $fd, "|-", "bsdlabel -R md$unit /dev/stdin" or die; print $fd "a: ", ($partszMB * BLKS_PER_MB), " 0 4.2BSD 1024 8192\n"; print $fd "c: ", ($unitszMB * BLKS_PER_MB), " 0 unused 0 0\n"; close $fd; From e656c34a188598ebce6423c4fbc4860921d41be4 Mon Sep 17 00:00:00 2001 From: Jung-uk Kim Date: Mon, 26 Sep 2016 14:13:11 +0000 Subject: [PATCH 26/64] Import OpenSSL 1.0.2j. --- CHANGES | 12 ++++++++++++ FREEBSD-upgrade | 4 ++-- Makefile | 2 +- NEWS | 4 ++++ README | 2 +- crypto/engine/eng_cryptodev.c | 2 +- crypto/opensslv.h | 6 +++--- crypto/x509/x509_vfy.c | 4 ++-- ssl/t1_ext.c | 2 ++ 9 files changed, 28 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index 4bdd39064655..042afe37246c 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,18 @@ OpenSSL CHANGES _______________ + Changes between 1.0.2i and 1.0.2j [26 Sep 2016] + + *) Missing CRL sanity check + + A bug fix which included a CRL sanity check was added to OpenSSL 1.1.0 + but was omitted from OpenSSL 1.0.2i. As a result any attempt to use + CRLs in OpenSSL 1.0.2i will crash with a null pointer exception. + + This issue only affects the OpenSSL 1.0.2i + (CVE-2016-7052) + [Matt Caswell] + Changes between 1.0.2h and 1.0.2i [22 Sep 2016] *) OCSP Status Request extension unbounded memory growth diff --git a/FREEBSD-upgrade b/FREEBSD-upgrade index 8259537bc150..03b02f8b77d6 100644 --- a/FREEBSD-upgrade +++ b/FREEBSD-upgrade @@ -11,8 +11,8 @@ First, read http://wiki.freebsd.org/SubversionPrimer/VendorImports # Xlist setenv XLIST /FreeBSD/work/openssl/svn-FREEBSD-files/FREEBSD-Xlist setenv FSVN "svn+ssh://repo.freebsd.org/base" -setenv OSSLVER 1.0.2i -# OSSLTAG format: v1_0_2i +setenv OSSLVER 1.0.2j +# OSSLTAG format: v1_0_2j ###setenv OSSLTAG v`echo ${OSSLVER} | tr . _` diff --git a/Makefile b/Makefile index 58daaa5548ce..04bfb11a1701 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ ## Makefile for OpenSSL ## -VERSION=1.0.2i +VERSION=1.0.2j MAJOR=1 MINOR=0.2 SHLIB_VERSION_NUMBER=1.0.0 diff --git a/NEWS b/NEWS index 5a652841cfcd..c0579632b2eb 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,10 @@ This file gives a brief overview of the major changes between each OpenSSL release. For more details please read the CHANGES file. + Major changes between OpenSSL 1.0.2i and OpenSSL 1.0.2j [26 Sep 2016] + + o Fix Use After Free for large message sizes (CVE-2016-6309) + Major changes between OpenSSL 1.0.2h and OpenSSL 1.0.2i [22 Sep 2016] o OCSP Status Request extension unbounded memory growth (CVE-2016-6304) diff --git a/README b/README index 70d4ddd93bea..6dedfc019738 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ - OpenSSL 1.0.2i 22 Sep 2016 + OpenSSL 1.0.2j 26 Sep 2016 Copyright (c) 1998-2015 The OpenSSL Project Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson diff --git a/crypto/engine/eng_cryptodev.c b/crypto/engine/eng_cryptodev.c index 65a74df2362e..2a2b95ce837e 100644 --- a/crypto/engine/eng_cryptodev.c +++ b/crypto/engine/eng_cryptodev.c @@ -939,7 +939,7 @@ static int cryptodev_digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) if (fstate->mac_len != 0) { if (fstate->mac_data != NULL) { dstate->mac_data = OPENSSL_malloc(fstate->mac_len); - if (dstate->ac_data == NULL) { + if (dstate->mac_data == NULL) { printf("cryptodev_digest_init: malloc failed\n"); return 0; } diff --git a/crypto/opensslv.h b/crypto/opensslv.h index 2f585f0e0480..88faad652259 100644 --- a/crypto/opensslv.h +++ b/crypto/opensslv.h @@ -30,11 +30,11 @@ extern "C" { * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for * major minor fix final patch/beta) */ -# define OPENSSL_VERSION_NUMBER 0x1000209fL +# define OPENSSL_VERSION_NUMBER 0x100020afL # ifdef OPENSSL_FIPS -# define OPENSSL_VERSION_TEXT "OpenSSL 1.0.2i-fips 22 Sep 2016" +# define OPENSSL_VERSION_TEXT "OpenSSL 1.0.2j-fips 26 Sep 2016" # else -# define OPENSSL_VERSION_TEXT "OpenSSL 1.0.2i 22 Sep 2016" +# define OPENSSL_VERSION_TEXT "OpenSSL 1.0.2j 26 Sep 2016" # endif # define OPENSSL_VERSION_PTEXT " part of " OPENSSL_VERSION_TEXT diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 8334b3fcff7f..b1472018baf7 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -1124,10 +1124,10 @@ static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl, crl = sk_X509_CRL_value(crls, i); reasons = *preasons; crl_score = get_crl_score(ctx, &crl_issuer, &reasons, crl, x); - if (crl_score < best_score) + if (crl_score < best_score || crl_score == 0) continue; /* If current CRL is equivalent use it if it is newer */ - if (crl_score == best_score) { + if (crl_score == best_score && best_crl != NULL) { int day, sec; if (ASN1_TIME_diff(&day, &sec, X509_CRL_get_lastUpdate(best_crl), X509_CRL_get_lastUpdate(crl)) == 0) diff --git a/ssl/t1_ext.c b/ssl/t1_ext.c index 724ddf76acb3..79ed946a5142 100644 --- a/ssl/t1_ext.c +++ b/ssl/t1_ext.c @@ -275,7 +275,9 @@ int SSL_extension_supported(unsigned int ext_type) case TLSEXT_TYPE_ec_point_formats: case TLSEXT_TYPE_elliptic_curves: case TLSEXT_TYPE_heartbeat: +# ifndef OPENSSL_NO_NEXTPROTONEG case TLSEXT_TYPE_next_proto_neg: +# endif case TLSEXT_TYPE_padding: case TLSEXT_TYPE_renegotiate: case TLSEXT_TYPE_server_name: From 310ab671b897683cddcba284b3bf947e60dd5d81 Mon Sep 17 00:00:00 2001 From: Eric van Gyzen Date: Mon, 26 Sep 2016 15:30:30 +0000 Subject: [PATCH 27/64] Make no assertions about mutex state when the scheduler is stopped. This changes the assert path to match the lock and unlock paths. MFC after: 1 week Sponsored by: Dell EMC --- sys/kern/kern_mutex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/kern/kern_mutex.c b/sys/kern/kern_mutex.c index 69f8a0c766b9..bd053c7bb7be 100644 --- a/sys/kern/kern_mutex.c +++ b/sys/kern/kern_mutex.c @@ -924,7 +924,7 @@ __mtx_assert(const volatile uintptr_t *c, int what, const char *file, int line) { const struct mtx *m; - if (panicstr != NULL || dumping) + if (panicstr != NULL || dumping || SCHEDULER_STOPPED()) return; m = mtxlock2mtx(c); From ed8f18ded41b1856f275d2608a555d66fe63286e Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Mon, 26 Sep 2016 15:38:02 +0000 Subject: [PATCH 28/64] Don't build SSP tests on MIPS as we dont have stack-protector supported on this platform. Discussed with: brooks Sponsored by: DARPA, AFRL Sponsored by: HEIF5 --- lib/libc/tests/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/libc/tests/Makefile b/lib/libc/tests/Makefile index 4ead70aceaa0..157e411357e6 100644 --- a/lib/libc/tests/Makefile +++ b/lib/libc/tests/Makefile @@ -30,7 +30,8 @@ SUBDIR_DEPEND_tls= tls_dso TESTS_SUBDIRS+= locale .endif -.if ${MK_SSP} != "no" +.if ${MK_SSP} != "no" && \ + ${MACHINE_CPUARCH} != "mips" TESTS_SUBDIRS+= ssp .endif From 7c9a4d09d62bab79293f55898583f7d698a91dbf Mon Sep 17 00:00:00 2001 From: Hiren Panchasara Date: Mon, 26 Sep 2016 15:45:30 +0000 Subject: [PATCH 29/64] Revert r306337. dhw@ reproted a panic which seems related to this and bde@ has raised some issues. --- sys/kern/uipc_syscalls.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 197148cefb75..e282665f75e5 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -685,7 +685,7 @@ sys_socketpair(struct thread *td, struct socketpair_args *uap) static int sendit(struct thread *td, int s, struct msghdr *mp, int flags) { - struct mbuf *control = NULL; + struct mbuf *control; struct sockaddr *to; int error; @@ -737,8 +737,6 @@ sendit(struct thread *td, int s, struct msghdr *mp, int flags) bad: free(to, M_SONAME); - if (control) - m_freem(control); return (error); } From 70e7268bd5eb7579eae29ef57830562be34ef21e Mon Sep 17 00:00:00 2001 From: "Pedro F. Giffuni" Date: Mon, 26 Sep 2016 16:06:50 +0000 Subject: [PATCH 30/64] hash(3): protect in-memory page when using cross-endianness. When writing out pages in the "other endian" format, make a copy instead of trashing the in-memory one. Obtained from: NetBSD (CVS rev. 1.29) --- lib/libc/db/hash/hash_page.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/libc/db/hash/hash_page.c b/lib/libc/db/hash/hash_page.c index a2bb7cfc84d2..ec2d184fe23b 100644 --- a/lib/libc/db/hash/hash_page.c +++ b/lib/libc/db/hash/hash_page.c @@ -572,7 +572,9 @@ __get_page(HTAB *hashp, char *p, u_int32_t bucket, int is_bucket, int is_disk, int __put_page(HTAB *hashp, char *p, u_int32_t bucket, int is_bucket, int is_bitmap) { - int fd, page, size, wsize; + int fd, page, size; + ssize_t wsize; + char pbuf[MAX_BSIZE]; size = hashp->BSIZE; if ((hashp->fp == -1) && open_temp(hashp)) @@ -582,15 +584,18 @@ __put_page(HTAB *hashp, char *p, u_int32_t bucket, int is_bucket, int is_bitmap) if (hashp->LORDER != BYTE_ORDER) { int i, max; + memcpy(pbuf, p, size); if (is_bitmap) { max = hashp->BSIZE >> 2; /* divide by 4 */ for (i = 0; i < max; i++) - M_32_SWAP(((int *)p)[i]); + M_32_SWAP(((int *)pbuf)[i]); } else { - max = ((u_int16_t *)p)[0] + 2; + uint16_t *bp = (uint16_t *)(void *)pbuf; + max = bp[0] + 2; for (i = 0; i <= max; i++) - M_16_SWAP(((u_int16_t *)p)[i]); + M_16_SWAP(bp[i]); } + p = pbuf; } if (is_bucket) page = BUCKET_TO_PAGE(bucket); From 20692187eab9fbbcafa4bfd160839278466b65e7 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Mon, 26 Sep 2016 17:22:44 +0000 Subject: [PATCH 31/64] For machines which support PCID but not have INVPCID instruction, i.e. SandyBridge and IvyBridge, correct a race between pmap_activate() and invltlb_pcid_handler(). Reported by and tested by: Slawa Olhovchenkov MFC after: 1 week --- sys/amd64/amd64/pmap.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 63042e41dd14..59e1b676d00b 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -6842,6 +6842,7 @@ pmap_activate_sw(struct thread *td) { pmap_t oldpmap, pmap; uint64_t cached, cr3; + register_t rflags; u_int cpuid; oldpmap = PCPU_GET(curpmap); @@ -6865,16 +6866,43 @@ pmap_activate_sw(struct thread *td) pmap == kernel_pmap, ("non-kernel pmap thread %p pmap %p cpu %d pcid %#x", td, pmap, cpuid, pmap->pm_pcids[cpuid].pm_pcid)); + + /* + * If the INVPCID instruction is not available, + * invltlb_pcid_handler() is used for handle + * invalidate_all IPI, which checks for curpmap == + * smp_tlb_pmap. Below operations sequence has a + * window where %CR3 is loaded with the new pmap's + * PML4 address, but curpmap value is not yet updated. + * This causes invltlb IPI handler, called between the + * updates, to execute as 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 IPI + * happends after curpmap is updated. Protect other + * callers in a similar way, by disabling interrupts + * around the %cr3 register reload and curpmap + * assignment. + */ + if (!invpcid_works) + rflags = intr_disable(); + if (!cached || (cr3 & ~CR3_PCID_MASK) != pmap->pm_cr3) { load_cr3(pmap->pm_cr3 | pmap->pm_pcids[cpuid].pm_pcid | cached); if (cached) PCPU_INC(pm_save_cnt); } + PCPU_SET(curpmap, pmap); + if (!invpcid_works) + intr_restore(rflags); } else if (cr3 != pmap->pm_cr3) { load_cr3(pmap->pm_cr3); + PCPU_SET(curpmap, pmap); } - PCPU_SET(curpmap, pmap); #ifdef SMP CPU_CLR_ATOMIC(cpuid, &oldpmap->pm_active); #else From 9fc97c9010c9aeaa5737862811714ddf869fe435 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Mon, 26 Sep 2016 17:25:25 +0000 Subject: [PATCH 32/64] Handle TLB shootdown IPI during the EFI runtime calls, on SandyBridge and IvyBridge machines, which support PCID but do not have INVPCID instruction. MFC after: 1 week --- sys/amd64/amd64/efirt.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/sys/amd64/amd64/efirt.c b/sys/amd64/amd64/efirt.c index 626cfb0232b0..8db768b9d619 100644 --- a/sys/amd64/amd64/efirt.c +++ b/sys/amd64/amd64/efirt.c @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -301,6 +302,17 @@ efi_enter(void) PMAP_UNLOCK(curpmap); return (error); } + + /* + * IPI TLB shootdown handler invltlb_pcid_handler() reloads + * %cr3 from the curpmap->pm_cr3, which would disable runtime + * segments mappings. Block the handler's action by setting + * curpmap to impossible value. See also comment in + * pmap.c:pmap_activate_sw(). + */ + if (pmap_pcid_enabled && !invpcid_works) + PCPU_SET(curpmap, NULL); + load_cr3(VM_PAGE_TO_PHYS(efi_pml4_page) | (pmap_pcid_enabled ? curpmap->pm_pcids[PCPU_GET(cpuid)].pm_pcid : 0)); /* @@ -317,7 +329,9 @@ efi_leave(void) { pmap_t curpmap; - curpmap = PCPU_GET(curpmap); + curpmap = &curproc->p_vmspace->vm_pmap; + if (pmap_pcid_enabled && !invpcid_works) + PCPU_SET(curpmap, curpmap); load_cr3(curpmap->pm_cr3 | (pmap_pcid_enabled ? curpmap->pm_pcids[PCPU_GET(cpuid)].pm_pcid : 0)); if (!pmap_pcid_enabled) From cda20f96df2294da4f5d8ab87050d0ca7110525f Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Mon, 26 Sep 2016 20:13:33 +0000 Subject: [PATCH 33/64] Increase timeout from 300 (default) to 600 seconds. It takes 6-7 minutes to proceed the test on MIPS64EB. Sponsored by: DARPA, AFRL Sponsored by: HEIF5 --- lib/libarchive/tests/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/libarchive/tests/Makefile b/lib/libarchive/tests/Makefile index 3b7eb01593bd..71dca87e619c 100644 --- a/lib/libarchive/tests/Makefile +++ b/lib/libarchive/tests/Makefile @@ -6,6 +6,8 @@ _LIBARCHIVEDIR= ${SRCTOP}/contrib/libarchive ATF_TESTS_SH+= functional_test +TEST_METADATA.functional_test+= timeout="600" + BINDIR= ${TESTSDIR} PROGS+= libarchive_test From 0fe98e8f2c3826c9503db7c650397762f266bd17 Mon Sep 17 00:00:00 2001 From: Oleksandr Tymoshenko Date: Mon, 26 Sep 2016 22:06:19 +0000 Subject: [PATCH 34/64] Add Elantech trackpad support Elantech trackpads are found in some laptops like the Asus UX31E. They are "synaptics compatible" but use a slightly different protocol. Elantech hardware support is not enabled by default and just like Synaptic or TrackPoint devices it should be enabled by setting tunable, in this case hw.psm.elantech_support, to non-zero value PR: 205690 Submitted by: Vladimir Kondratyev MFC after: 1 week --- sys/dev/atkbdc/psm.c | 2219 ++++++++++++++++++++++++++++++++---------- sys/sys/mouse.h | 4 + 2 files changed, 1705 insertions(+), 518 deletions(-) diff --git a/sys/dev/atkbdc/psm.c b/sys/dev/atkbdc/psm.c index 56a5c62bae6d..d1c525430184 100644 --- a/sys/dev/atkbdc/psm.c +++ b/sys/dev/atkbdc/psm.c @@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -161,40 +162,6 @@ typedef struct packetbuf { #define PSM_PACKETQUEUE 128 #endif -enum { - SYNAPTICS_SYSCTL_MIN_PRESSURE, - SYNAPTICS_SYSCTL_MAX_PRESSURE, - SYNAPTICS_SYSCTL_MAX_WIDTH, - SYNAPTICS_SYSCTL_MARGIN_TOP, - SYNAPTICS_SYSCTL_MARGIN_RIGHT, - SYNAPTICS_SYSCTL_MARGIN_BOTTOM, - SYNAPTICS_SYSCTL_MARGIN_LEFT, - SYNAPTICS_SYSCTL_NA_TOP, - SYNAPTICS_SYSCTL_NA_RIGHT, - SYNAPTICS_SYSCTL_NA_BOTTOM, - SYNAPTICS_SYSCTL_NA_LEFT, - SYNAPTICS_SYSCTL_WINDOW_MIN, - SYNAPTICS_SYSCTL_WINDOW_MAX, - SYNAPTICS_SYSCTL_MULTIPLICATOR, - SYNAPTICS_SYSCTL_WEIGHT_CURRENT, - SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS, - SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA, - SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED, - SYNAPTICS_SYSCTL_DIV_MIN, - SYNAPTICS_SYSCTL_DIV_MAX, - SYNAPTICS_SYSCTL_DIV_MAX_NA, - SYNAPTICS_SYSCTL_DIV_LEN, - SYNAPTICS_SYSCTL_TAP_MAX_DELTA, - SYNAPTICS_SYSCTL_TAP_MIN_QUEUE, - SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT, - SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA, - SYNAPTICS_SYSCTL_VSCROLL_VER_AREA, - SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA, - SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN, - SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX, - SYNAPTICS_SYSCTL_TOUCHPAD_OFF -}; - typedef struct synapticsinfo { struct sysctl_ctx_list sysctl_ctx; struct sysctl_oid *sysctl_tree; @@ -231,6 +198,11 @@ typedef struct synapticsinfo { int vscroll_div_min; int vscroll_div_max; int touchpad_off; + int softbuttons_y; + int softbutton2_x; + int softbutton3_x; + int max_x; + int max_y; } synapticsinfo_t; typedef struct synapticspacket { @@ -246,22 +218,29 @@ typedef struct synapticspacket { ((synhw).infoMajor > (major) || \ ((synhw).infoMajor == (major) && (synhw).infoMinor >= (minor))) -typedef struct synapticsaction { +typedef struct smoother { synapticspacket_t queue[SYNAPTICS_PACKETQUEUE]; int queue_len; int queue_cursor; - int window_min; int start_x; int start_y; int avg_dx; int avg_dy; int squelch_x; int squelch_y; + int is_fuzzy; + int active; +} smoother_t; + +typedef struct gesture { + int window_min; int fingers_nb; int tap_button; int in_taphold; int in_vscroll; -} synapticsaction_t; + int zmax; /* maximum pressure value */ + struct timeval taptimeout; /* tap timeout for touchpads */ +} gesture_t; enum { TRACKPOINT_SYSCTL_SENSITIVITY, @@ -295,6 +274,100 @@ typedef struct trackpointinfo { int skipback; } trackpointinfo_t; +typedef struct finger { + int x; + int y; + int p; + int w; + int flags; +} finger_t; +#define PSM_FINGERS 2 /* # of processed fingers */ +#define PSM_FINGER_IS_PEN (1<<0) +#define PSM_FINGER_FUZZY (1<<1) +#define PSM_FINGER_DEFAULT_P tap_threshold +#define PSM_FINGER_DEFAULT_W 1 +#define PSM_FINGER_IS_SET(f) ((f).x != -1 && (f).y != -1 && (f).p != 0) +#define PSM_FINGER_RESET(f) do { \ + (f) = (finger_t) { .x = -1, .y = -1, .p = 0, .w = 0, .flags = 0 }; \ +} while (0) + +typedef struct elantechhw { + int hwversion; + int fwversion; + int sizex; + int sizey; + int dpmmx; + int dpmmy; + int ntracesx; + int ntracesy; + int issemimt; + int isclickpad; + int hascrc; + int hastrackpoint; + int haspressure; +} elantechhw_t; + +/* minimum versions supported by this driver */ +#define ELANTECH_HW_IS_V1(fwver) ((fwver) < 0x020030 || (fwver) == 0x020600) + +#define ELANTECH_MAGIC(magic) \ + ((magic)[0] == 0x3c && (magic)[1] == 0x03 && \ + ((magic)[2] == 0xc8 || (magic)[2] == 0x00)) + +#define ELANTECH_FW_ID 0x00 +#define ELANTECH_FW_VERSION 0x01 +#define ELANTECH_CAPABILITIES 0x02 +#define ELANTECH_SAMPLE 0x03 +#define ELANTECH_RESOLUTION 0x04 +#define ELANTECH_REG_READ 0x10 +#define ELANTECH_REG_WRITE 0x11 +#define ELANTECH_REG_RDWR 0x00 +#define ELANTECH_CUSTOM_CMD 0xf8 + +#define ELANTECH_MAX_FINGERS PSM_FINGERS + +#define ELANTECH_FINGER_SET_XYP(pb) (finger_t) { \ + .x = (((pb)->ipacket[1] & 0x0f) << 8) | (pb)->ipacket[2], \ + .y = (((pb)->ipacket[4] & 0x0f) << 8) | (pb)->ipacket[5], \ + .p = ((pb)->ipacket[1] & 0xf0) | (((pb)->ipacket[4] >> 4) & 0x0f), \ + .w = PSM_FINGER_DEFAULT_W, \ + .flags = 0 \ +} + +enum { + ELANTECH_PKT_NOP, + ELANTECH_PKT_TRACKPOINT, + ELANTECH_PKT_V2_COMMON, + ELANTECH_PKT_V2_2FINGER, + ELANTECH_PKT_V3, + ELANTECH_PKT_V4_STATUS, + ELANTECH_PKT_V4_HEAD, + ELANTECH_PKT_V4_MOTION +}; + +#define ELANTECH_PKT_IS_TRACKPOINT(pb) (((pb)->ipacket[3] & 0x0f) == 0x06) +#define ELANTECH_PKT_IS_DEBOUNCE(pb, hwversion) ((hwversion) == 4 ? 0 : \ + (pb)->ipacket[0] == ((hwversion) == 2 ? 0x84 : 0xc4) && \ + (pb)->ipacket[1] == 0xff && (pb)->ipacket[2] == 0xff && \ + (pb)->ipacket[3] == 0x02 && (pb)->ipacket[4] == 0xff && \ + (pb)->ipacket[5] == 0xff) +#define ELANTECH_PKT_IS_V2(pb) \ + (((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x0f) == 0x02) +#define ELANTECH_PKT_IS_V3_HEAD(pb, hascrc) ((hascrc) ? \ + ((pb)->ipacket[3] & 0x09) == 0x08 : \ + ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0xcf) == 0x02) +#define ELANTECH_PKT_IS_V3_TAIL(pb, hascrc) ((hascrc) ? \ + ((pb)->ipacket[3] & 0x09) == 0x09 : \ + ((pb)->ipacket[0] & 0x0c) == 0x0c && ((pb)->ipacket[3] & 0xce) == 0x0c) +#define ELANTECH_PKT_IS_V4(pb, hascrc) ((hascrc) ? \ + ((pb)->ipacket[3] & 0x08) == 0x00 : \ + ((pb)->ipacket[0] & 0x0c) == 0x04 && ((pb)->ipacket[3] & 0x1c) == 0x10) + +typedef struct elantechaction { + finger_t fingers[ELANTECH_MAX_FINGERS]; + int mask; +} elantechaction_t; + /* driver control block */ struct psm_softc { /* Driver status information */ int unit; @@ -308,7 +381,10 @@ struct psm_softc { /* Driver status information */ mousehw_t hw; /* hardware information */ synapticshw_t synhw; /* Synaptics hardware information */ synapticsinfo_t syninfo; /* Synaptics configuration */ - synapticsaction_t synaction; /* Synaptics action context */ + smoother_t smoother[PSM_FINGERS]; /* Motion smoothing */ + gesture_t gesture; /* Gesture context */ + elantechhw_t elanhw; /* Elantech hardware information */ + elantechaction_t elanaction; /* Elantech action context */ int tphw; /* TrackPoint hardware information */ trackpointinfo_t tpinfo; /* TrackPoint configuration */ mousemode_t mode; /* operation mode */ @@ -324,13 +400,13 @@ struct psm_softc { /* Driver status information */ int xaverage; /* average X position */ int yaverage; /* average Y position */ int squelch; /* level to filter movement at low speed */ - int zmax; /* maximum pressure value for touchpads */ int syncerrors; /* # of bytes discarded to synchronize */ int pkterrors; /* # of packets failed during quaranteen. */ struct timeval inputtimeout; struct timeval lastsoftintr; /* time of last soft interrupt */ struct timeval lastinputerr; /* time last sync error happened */ - struct timeval taptimeout; /* tap timeout for touchpads */ + struct timeval idletimeout; + packetbuf_t idlepacket; /* packet to send after idle timeout */ int watchdog; /* watchdog timer flag */ struct callout callout; /* watchdog timer call out */ struct callout softcallout; /* buffer timer call out */ @@ -389,6 +465,9 @@ TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support); static int trackpoint_support = 0; TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support); +static int elantech_support = 0; +TUNABLE_INT("hw.psm.elantech_support", &elantech_support); + static int verbose = PSM_DEBUG; TUNABLE_INT("debug.psm.loglevel", &verbose); @@ -411,6 +490,44 @@ typedef struct old_mousemode { int accelfactor; } old_mousemode_t; +#define SYN_OFFSET(field) offsetof(struct psm_softc, syninfo.field) +enum { + SYNAPTICS_SYSCTL_MIN_PRESSURE = SYN_OFFSET(min_pressure), + SYNAPTICS_SYSCTL_MAX_PRESSURE = SYN_OFFSET(max_pressure), + SYNAPTICS_SYSCTL_MAX_WIDTH = SYN_OFFSET(max_width), + SYNAPTICS_SYSCTL_MARGIN_TOP = SYN_OFFSET(margin_top), + SYNAPTICS_SYSCTL_MARGIN_RIGHT = SYN_OFFSET(margin_right), + SYNAPTICS_SYSCTL_MARGIN_BOTTOM = SYN_OFFSET(margin_bottom), + SYNAPTICS_SYSCTL_MARGIN_LEFT = SYN_OFFSET(margin_left), + SYNAPTICS_SYSCTL_NA_TOP = SYN_OFFSET(na_top), + SYNAPTICS_SYSCTL_NA_RIGHT = SYN_OFFSET(na_right), + SYNAPTICS_SYSCTL_NA_BOTTOM = SYN_OFFSET(na_bottom), + SYNAPTICS_SYSCTL_NA_LEFT = SYN_OFFSET(na_left), + SYNAPTICS_SYSCTL_WINDOW_MIN = SYN_OFFSET(window_min), + SYNAPTICS_SYSCTL_WINDOW_MAX = SYN_OFFSET(window_max), + SYNAPTICS_SYSCTL_MULTIPLICATOR = SYN_OFFSET(multiplicator), + SYNAPTICS_SYSCTL_WEIGHT_CURRENT = SYN_OFFSET(weight_current), + SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS = SYN_OFFSET(weight_previous), + SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA = SYN_OFFSET(weight_previous_na), + SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED = SYN_OFFSET(weight_len_squared), + SYNAPTICS_SYSCTL_DIV_MIN = SYN_OFFSET(div_min), + SYNAPTICS_SYSCTL_DIV_MAX = SYN_OFFSET(div_max), + SYNAPTICS_SYSCTL_DIV_MAX_NA = SYN_OFFSET(div_max_na), + SYNAPTICS_SYSCTL_DIV_LEN = SYN_OFFSET(div_len), + SYNAPTICS_SYSCTL_TAP_MAX_DELTA = SYN_OFFSET(tap_max_delta), + SYNAPTICS_SYSCTL_TAP_MIN_QUEUE = SYN_OFFSET(tap_min_queue), + SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT = SYN_OFFSET(taphold_timeout), + SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA = SYN_OFFSET(vscroll_hor_area), + SYNAPTICS_SYSCTL_VSCROLL_VER_AREA = SYN_OFFSET(vscroll_ver_area), + SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA = SYN_OFFSET(vscroll_min_delta), + SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN = SYN_OFFSET(vscroll_div_min), + SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX = SYN_OFFSET(vscroll_div_max), + SYNAPTICS_SYSCTL_TOUCHPAD_OFF = SYN_OFFSET(touchpad_off), + SYNAPTICS_SYSCTL_SOFTBUTTONS_Y = SYN_OFFSET(softbuttons_y), + SYNAPTICS_SYSCTL_SOFTBUTTON2_X = SYN_OFFSET(softbutton2_x), + SYNAPTICS_SYSCTL_SOFTBUTTON3_X = SYN_OFFSET(softbutton3_x), +}; + /* packet formatting function */ typedef int packetfunc_t(struct psm_softc *, u_char *, int *, int, mousestatus_t *); @@ -446,6 +563,7 @@ static int doopen(struct psm_softc *, int); static int reinitialize(struct psm_softc *, int); static char *model_name(int); static void psmsoftintr(void *); +static void psmsoftintridle(void *); static void psmintr(void *); static void psmtimeout(void *); static int timeelapsed(const struct timeval *, int, int, @@ -458,6 +576,13 @@ static int proc_synaptics(struct psm_softc *, packetbuf_t *, mousestatus_t *, int *, int *, int *); static void proc_versapad(struct psm_softc *, packetbuf_t *, mousestatus_t *, int *, int *, int *); +static int proc_elantech(struct psm_softc *, packetbuf_t *, + mousestatus_t *, int *, int *, int *); +static int psmpalmdetect(struct psm_softc *, finger_t *, int); +static void psmgestures(struct psm_softc *, finger_t *, int, + mousestatus_t *); +static void psmsmoother(struct psm_softc *, finger_t *, int, + mousestatus_t *, int *, int *); static int tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *, u_char *); @@ -480,6 +605,7 @@ static probefunc_t enable_mmanplus; static probefunc_t enable_synaptics; static probefunc_t enable_trackpoint; static probefunc_t enable_versapad; +static probefunc_t enable_elantech; static void set_trackpoint_parameters(struct psm_softc *sc); static void synaptics_passthrough_on(struct psm_softc *sc); @@ -511,6 +637,8 @@ static struct { 0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus }, { MOUSE_MODEL_SYNAPTICS, /* Synaptics Touchpad */ 0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics }, + { MOUSE_MODEL_ELANTECH, /* Elantech Touchpad */ + 0x04, MOUSE_ELANTECH_PACKETSIZE, enable_elantech }, { MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */ 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli }, { MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */ @@ -762,6 +890,7 @@ model_name(int model) { MOUSE_MODEL_4DPLUS, "4D+ Mouse" }, { MOUSE_MODEL_SYNAPTICS, "Synaptics Touchpad" }, { MOUSE_MODEL_TRACKPOINT, "IBM/Lenovo TrackPoint" }, + { MOUSE_MODEL_ELANTECH, "Elantech Touchpad" }, { MOUSE_MODEL_GENERIC, "Generic PS/2 mouse" }, { MOUSE_MODEL_UNKNOWN, "Unknown" }, }; @@ -1504,6 +1633,7 @@ psmattach(device_t dev) case MOUSE_MODEL_SYNAPTICS: case MOUSE_MODEL_GLIDEPOINT: case MOUSE_MODEL_VERSAPAD: + case MOUSE_MODEL_ELANTECH: sc->config |= PSM_CONFIG_INITAFTERSUSPEND; break; default: @@ -1512,6 +1642,11 @@ psmattach(device_t dev) break; } + /* Elantech trackpad`s sync bit differs from touchpad`s one */ + if (sc->hw.model == MOUSE_MODEL_ELANTECH && + (sc->elanhw.hascrc || sc->elanhw.hastrackpoint)) + sc->config |= PSM_CONFIG_NOCHECKSYNC; + if (!verbose) printf("psm%d: model %s, device ID %d\n", unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff); @@ -2165,20 +2300,6 @@ psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, (*(int *)addr > PSM_LEVEL_MAX)) return (EINVAL); sc->mode.level = *(int *)addr; - - if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) { - /* - * If we are entering PSM_LEVEL_NATIVE, we want to - * enable sending of "extended W mode" packets to - * userland. Reset the mode of the touchpad so that the - * change in the level is picked up. - */ - error = block_mouse_data(sc, &command_byte); - if (error) - return (error); - synaptics_set_mode(sc, synaptics_preferred_mode(sc)); - unblock_mouse_data(sc, command_byte); - } break; case MOUSE_GETSTATUS: @@ -2627,7 +2748,8 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, { static int touchpad_buttons; static int guest_buttons; - int w, x0, y0; + static finger_t f[PSM_FINGERS]; + int w, id, nfingers, ewcode; /* TouchPad PS/2 absolute mode message format with capFourButtons: * @@ -2683,6 +2805,7 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, return (-1); *x = *y = 0; + ms->button = ms->obutton; /* * Pressure value. @@ -2718,34 +2841,79 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, w = 4; } - /* - * Handle packets from the guest device. See: - * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1 - */ - if (w == 3 && sc->synhw.capPassthrough) { - *x = ((pb->ipacket[1] & 0x10) ? - pb->ipacket[4] - 256 : pb->ipacket[4]); - *y = ((pb->ipacket[1] & 0x20) ? - pb->ipacket[5] - 256 : pb->ipacket[5]); - *z = 0; + switch (w) { + case 3: + /* + * Handle packets from the guest device. See: + * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1 + */ + if (sc->synhw.capPassthrough) { + *x = ((pb->ipacket[1] & 0x10) ? + pb->ipacket[4] - 256 : pb->ipacket[4]); + *y = ((pb->ipacket[1] & 0x20) ? + pb->ipacket[5] - 256 : pb->ipacket[5]); + *z = 0; - guest_buttons = 0; - if (pb->ipacket[1] & 0x01) - guest_buttons |= MOUSE_BUTTON1DOWN; - if (pb->ipacket[1] & 0x04) - guest_buttons |= MOUSE_BUTTON2DOWN; - if (pb->ipacket[1] & 0x02) - guest_buttons |= MOUSE_BUTTON3DOWN; + guest_buttons = 0; + if (pb->ipacket[1] & 0x01) + guest_buttons |= MOUSE_BUTTON1DOWN; + if (pb->ipacket[1] & 0x04) + guest_buttons |= MOUSE_BUTTON2DOWN; + if (pb->ipacket[1] & 0x02) + guest_buttons |= MOUSE_BUTTON3DOWN; - ms->button = touchpad_buttons | guest_buttons; + ms->button = touchpad_buttons | guest_buttons; + } goto SYNAPTICS_END; + + case 2: + /* Handle Extended W mode packets */ + ewcode = (pb->ipacket[5] & 0xf0) >> 4; +#if PSM_FINGERS > 1 + switch (ewcode) { + case 1: + /* Secondary finger */ + if (sc->synhw.capAdvancedGestures) + f[1] = (finger_t) { + .x = (((pb->ipacket[4] & 0x0f) << 8) | + pb->ipacket[1]) << 1, + .y = (((pb->ipacket[4] & 0xf0) << 4) | + pb->ipacket[2]) << 1, + .p = ((pb->ipacket[3] & 0x30) | + (pb->ipacket[5] & 0x0f)) << 1, + .w = PSM_FINGER_DEFAULT_W, + .flags = PSM_FINGER_FUZZY, + }; + else if (sc->synhw.capReportsV) + f[1] = (finger_t) { + .x = (((pb->ipacket[4] & 0x0f) << 8) | + (pb->ipacket[1] & 0xfe)) << 1, + .y = (((pb->ipacket[4] & 0xf0) << 4) | + (pb->ipacket[2] & 0xfe)) << 1, + .p = ((pb->ipacket[3] & 0x30) | + (pb->ipacket[5] & 0x0e)) << 1, + .w = (((pb->ipacket[5] & 0x01) << 2) | + ((pb->ipacket[2] & 0x01) << 1) | + (pb->ipacket[1] & 0x01)) + 8, + .flags = PSM_FINGER_FUZZY, + }; + default: + break; + } +#endif + goto SYNAPTICS_END; + + case 1: + case 0: + nfingers = w + 2; + break; + + default: + nfingers = 1; } - if (sc->syninfo.touchpad_off) { - *x = *y = *z = 0; - ms->button = ms->obutton; + if (sc->syninfo.touchpad_off) goto SYNAPTICS_END; - } /* Button presses */ touchpad_buttons = 0; @@ -2764,6 +2932,10 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, /* Middle Button */ if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01) touchpad_buttons |= MOUSE_BUTTON2DOWN; + } else if (sc->synhw.capExtended && sc->synhw.capClickPad) { + /* ClickPad Button */ + if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01) + touchpad_buttons = MOUSE_BUTTON1DOWN; } else if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) { /* Extended Buttons */ if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) { @@ -2806,7 +2978,7 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, pb->ipacket[4] &= ~(mask); pb->ipacket[5] &= ~(mask); } else if (!sc->syninfo.directional_scrolls && - !sc->synaction.in_vscroll) { + !sc->gesture.in_vscroll) { /* * Keep reporting MOUSE DOWN until we get a new packet * indicating otherwise. @@ -2814,19 +2986,473 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, touchpad_buttons |= sc->extended_buttons; } } - /* Handle ClickPad. */ - if (sc->synhw.capClickPad && - ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01)) - touchpad_buttons |= MOUSE_BUTTON1DOWN; + + if (sc->synhw.capReportsV && nfingers > 1) + f[0] = (finger_t) { + .x = ((pb->ipacket[3] & 0x10) << 8) | + ((pb->ipacket[1] & 0x0f) << 8) | + (pb->ipacket[4] & 0xfd), + .y = ((pb->ipacket[3] & 0x20) << 7) | + ((pb->ipacket[1] & 0xf0) << 4) | + (pb->ipacket[5] & 0xfd), + .p = *z & 0xfe, + .w = (((pb->ipacket[2] & 0x01) << 2) | + (pb->ipacket[5] & 0x02) | + ((pb->ipacket[4] & 0x02) >> 1)) + 8, + .flags = PSM_FINGER_FUZZY, + }; + else + f[0] = (finger_t) { + .x = ((pb->ipacket[3] & 0x10) << 8) | + ((pb->ipacket[1] & 0x0f) << 8) | + pb->ipacket[4], + .y = ((pb->ipacket[3] & 0x20) << 7) | + ((pb->ipacket[1] & 0xf0) << 4) | + pb->ipacket[5], + .p = *z, + .w = w, + .flags = nfingers > 1 ? PSM_FINGER_FUZZY : 0, + }; + + /* Ignore hovering and unmeasurable touches */ + if (f[0].p < sc->syninfo.min_pressure || f[0].x < 2) + nfingers = 0; + + for (id = 0; id < PSM_FINGERS; id++) + if (id >= nfingers) + PSM_FINGER_RESET(f[id]); ms->button = touchpad_buttons | guest_buttons; + /* Palm detection doesn't terminate the current action. */ + if (!psmpalmdetect(sc, &f[0], nfingers)) { + psmgestures(sc, &f[0], nfingers, ms); + for (id = 0; id < PSM_FINGERS; id++) + psmsmoother(sc, &f[id], id, ms, x, y); + } else { + VLOG(2, (LOG_DEBUG, "synaptics: palm detected! (%d)\n", f[0].w)); + } + +SYNAPTICS_END: + /* + * Use the extra buttons as a scrollwheel + * + * XXX X.Org uses the Z axis for vertical wheel only, + * whereas moused(8) understands special values to differ + * vertical and horizontal wheels. + * + * xf86-input-mouse needs therefore a small patch to + * understand these special values. Without it, the + * horizontal wheel acts as a vertical wheel in X.Org. + * + * That's why the horizontal wheel is disabled by + * default for now. + */ + if (ms->button & MOUSE_BUTTON4DOWN) + *z = -1; + else if (ms->button & MOUSE_BUTTON5DOWN) + *z = 1; + else if (ms->button & MOUSE_BUTTON6DOWN) + *z = -2; + else if (ms->button & MOUSE_BUTTON7DOWN) + *z = 2; + else + *z = 0; + ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN | + MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN); + + return (0); +} + +static int +psmpalmdetect(struct psm_softc *sc, finger_t *f, int nfingers) +{ + if (!( + ((sc->synhw.capMultiFinger || + sc->synhw.capAdvancedGestures) && nfingers > 1) || + (sc->synhw.capPalmDetect && f->w <= sc->syninfo.max_width) || + (!sc->synhw.capPalmDetect && f->p <= sc->syninfo.max_pressure) || + (sc->synhw.capPen && f->flags & PSM_FINGER_IS_PEN))) { + /* + * We consider the packet irrelevant for the current + * action when: + * - the width isn't comprised in: + * [1; max_width] + * - the pressure isn't comprised in: + * [min_pressure; max_pressure] + * - pen aren't supported but PSM_FINGER_IS_PEN is set + */ + return (1); + } + return (0); +} + +static void +psmgestures(struct psm_softc *sc, finger_t *fingers, int nfingers, + mousestatus_t *ms) +{ + smoother_t *smoother; + gesture_t *gest; + finger_t *f; + int y_ok, center_button, center_x, right_button, right_x, i; + + f = &fingers[0]; + smoother = &sc->smoother[0]; + gest = &sc->gesture; + + /* Find first active finger. */ + if (nfingers > 0) { + for (i = 0; i < PSM_FINGERS; i++) { + if (PSM_FINGER_IS_SET(fingers[i])) { + f = &fingers[i]; + smoother = &sc->smoother[i]; + break; + } + } + } + /* * Check pressure to detect a real wanted action on the * touchpad. */ - if (*z >= sc->syninfo.min_pressure) { - synapticsaction_t *synaction; + if (f->p >= sc->syninfo.min_pressure) { + int x0, y0; + int dxp, dyp; + int start_x, start_y; + int queue_len; + int margin_top, margin_right, margin_bottom, margin_left; + int window_min, window_max; + int vscroll_hor_area, vscroll_ver_area; + int two_finger_scroll; + int max_x, max_y; + + /* Read sysctl. */ + /* XXX Verify values? */ + margin_top = sc->syninfo.margin_top; + margin_right = sc->syninfo.margin_right; + margin_bottom = sc->syninfo.margin_bottom; + margin_left = sc->syninfo.margin_left; + window_min = sc->syninfo.window_min; + window_max = sc->syninfo.window_max; + vscroll_hor_area = sc->syninfo.vscroll_hor_area; + vscroll_ver_area = sc->syninfo.vscroll_ver_area; + two_finger_scroll = sc->syninfo.two_finger_scroll; + max_x = sc->syninfo.max_x; + max_y = sc->syninfo.max_y; + + /* Read current absolute position. */ + x0 = f->x; + y0 = f->y; + + /* + * Limit the coordinates to the specified margins because + * this area isn't very reliable. + */ + if (x0 <= margin_left) + x0 = margin_left; + else if (x0 >= max_x - margin_right) + x0 = max_x - margin_right; + if (y0 <= margin_bottom) + y0 = margin_bottom; + else if (y0 >= max_y - margin_top) + y0 = max_y - margin_top; + + VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n", + x0, y0, f->p, f->w)); + + /* + * If the action is just beginning, init the structure and + * compute tap timeout. + */ + if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) { + VLOG(3, (LOG_DEBUG, "synaptics: ----\n")); + + /* Initialize queue. */ + gest->window_min = window_min; + + /* Reset pressure peak. */ + gest->zmax = 0; + + /* Reset fingers count. */ + gest->fingers_nb = 0; + + /* Reset virtual scrolling state. */ + gest->in_vscroll = 0; + + /* Compute tap timeout. */ + gest->taptimeout.tv_sec = tap_timeout / 1000000; + gest->taptimeout.tv_usec = tap_timeout % 1000000; + timevaladd(&gest->taptimeout, &sc->lastsoftintr); + + sc->flags |= PSM_FLAGS_FINGERDOWN; + + /* Smoother has not been reset yet */ + queue_len = 1; + start_x = x0; + start_y = y0; + } else { + queue_len = smoother->queue_len + 1; + start_x = smoother->start_x; + start_y = smoother->start_y; + } + + /* Process ClickPad softbuttons */ + if (sc->synhw.capClickPad && ms->button & MOUSE_BUTTON1DOWN) { + y_ok = sc->syninfo.softbuttons_y >= 0 ? + start_y < sc->syninfo.softbuttons_y : + start_y > max_y - sc->syninfo.softbuttons_y; + + center_button = MOUSE_BUTTON2DOWN; + center_x = sc->syninfo.softbutton2_x; + right_button = MOUSE_BUTTON3DOWN; + right_x = sc->syninfo.softbutton3_x; + + if (center_x > 0 && right_x > 0 && center_x > right_x) { + center_button = MOUSE_BUTTON3DOWN; + center_x = sc->syninfo.softbutton3_x; + right_button = MOUSE_BUTTON2DOWN; + right_x = sc->syninfo.softbutton2_x; + } + + if (right_x > 0 && start_x > right_x && y_ok) + ms->button = (ms->button & + ~MOUSE_BUTTON1DOWN) | right_button; + else if (center_x > 0 && start_x > center_x && y_ok) + ms->button = (ms->button & + ~MOUSE_BUTTON1DOWN) | center_button; + } + + /* If in tap-hold, add the recorded button. */ + if (gest->in_taphold) + ms->button |= gest->tap_button; + + /* + * For tap, we keep the maximum number of fingers and the + * pressure peak. Also with multiple fingers, we increase + * the minimum window. + */ + if (nfingers > 1) + gest->window_min = window_max; + gest->fingers_nb = imax(nfingers, gest->fingers_nb); + gest->zmax = imax(f->p, gest->zmax); + + /* Do we have enough packets to consider this a gesture? */ + if (queue_len < gest->window_min) + return; + + /* Is a scrolling action occurring? */ + if (!gest->in_taphold && !ms->button && + (!gest->in_vscroll || two_finger_scroll)) { + /* + * A scrolling action must not conflict with a tap + * action. Here are the conditions to consider a + * scrolling action: + * - the action in a configurable area + * - one of the following: + * . the distance between the last packet and the + * first should be above a configurable minimum + * . tap timed out + */ + dxp = abs(x0 - start_x); + dyp = abs(y0 - start_y); + + if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, >) || + dxp >= sc->syninfo.vscroll_min_delta || + dyp >= sc->syninfo.vscroll_min_delta) { + /* + * Handle two finger scrolling. + * Note that we don't rely on fingers_nb + * as that keeps the maximum number of fingers. + */ + if (two_finger_scroll) { + if (nfingers == 2) { + gest->in_vscroll += + dyp ? 2 : 0; + gest->in_vscroll += + dxp ? 1 : 0; + } + } else { + /* Check for horizontal scrolling. */ + if ((vscroll_hor_area > 0 && + start_y <= vscroll_hor_area) || + (vscroll_hor_area < 0 && + start_y >= + max_y + vscroll_hor_area)) + gest->in_vscroll += 2; + + /* Check for vertical scrolling. */ + if ((vscroll_ver_area > 0 && + start_x <= vscroll_ver_area) || + (vscroll_ver_area < 0 && + start_x >= + max_x + vscroll_ver_area)) + gest->in_vscroll += 1; + } + + /* Avoid conflicts if area overlaps. */ + if (gest->in_vscroll >= 3) + gest->in_vscroll = + (dxp > dyp) ? 2 : 1; + } + } + /* + * Reset two finger scrolling when the number of fingers + * is different from two or any button is pressed. + */ + if (two_finger_scroll && gest->in_vscroll != 0 && + (nfingers != 2 || ms->button)) + gest->in_vscroll = 0; + + VLOG(5, (LOG_DEBUG, + "synaptics: virtual scrolling: %s " + "(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n", + gest->in_vscroll ? "YES" : "NO", + gest->in_vscroll, dxp, dyp, + gest->fingers_nb)); + + } else if (sc->flags & PSM_FLAGS_FINGERDOWN) { + /* + * An action is currently taking place but the pressure + * dropped under the minimum, putting an end to it. + */ + int taphold_timeout, dx, dy, tap_max_delta; + + dx = abs(smoother->queue[smoother->queue_cursor].x - + smoother->start_x); + dy = abs(smoother->queue[smoother->queue_cursor].y - + smoother->start_y); + + /* Max delta is disabled for multi-fingers tap. */ + if (gest->fingers_nb > 1) + tap_max_delta = imax(dx, dy); + else + tap_max_delta = sc->syninfo.tap_max_delta; + + sc->flags &= ~PSM_FLAGS_FINGERDOWN; + + /* Check for tap. */ + VLOG(3, (LOG_DEBUG, + "synaptics: zmax=%d, dx=%d, dy=%d, " + "delta=%d, fingers=%d, queue=%d\n", + gest->zmax, dx, dy, tap_max_delta, gest->fingers_nb, + smoother->queue_len)); + if (!gest->in_vscroll && gest->zmax >= tap_threshold && + timevalcmp(&sc->lastsoftintr, &gest->taptimeout, <=) && + dx <= tap_max_delta && dy <= tap_max_delta && + smoother->queue_len >= sc->syninfo.tap_min_queue) { + /* + * We have a tap if: + * - the maximum pressure went over tap_threshold + * - the action ended before tap_timeout + * + * To handle tap-hold, we must delay any button push to + * the next action. + */ + if (gest->in_taphold) { + /* + * This is the second and last tap of a + * double tap action, not a tap-hold. + */ + gest->in_taphold = 0; + + /* + * For double-tap to work: + * - no button press is emitted (to + * simulate a button release) + * - PSM_FLAGS_FINGERDOWN is set to + * force the next packet to emit a + * button press) + */ + VLOG(2, (LOG_DEBUG, + "synaptics: button RELEASE: %d\n", + gest->tap_button)); + sc->flags |= PSM_FLAGS_FINGERDOWN; + + /* Schedule button press on next interrupt */ + sc->idletimeout.tv_sec = psmhz > 1 ? + 0 : 1; + sc->idletimeout.tv_usec = psmhz > 1 ? + 1000000 / psmhz : 0; + } else { + /* + * This is the first tap: we set the + * tap-hold state and notify the button + * down event. + */ + gest->in_taphold = 1; + taphold_timeout = sc->syninfo.taphold_timeout; + gest->taptimeout.tv_sec = taphold_timeout / + 1000000; + gest->taptimeout.tv_usec = taphold_timeout % + 1000000; + sc->idletimeout = gest->taptimeout; + timevaladd(&gest->taptimeout, + &sc->lastsoftintr); + + switch (gest->fingers_nb) { + case 3: + gest->tap_button = + MOUSE_BUTTON2DOWN; + break; + case 2: + gest->tap_button = + MOUSE_BUTTON3DOWN; + break; + default: + gest->tap_button = + MOUSE_BUTTON1DOWN; + } + VLOG(2, (LOG_DEBUG, + "synaptics: button PRESS: %d\n", + gest->tap_button)); + ms->button |= gest->tap_button; + } + } else { + /* + * Not enough pressure or timeout: reset + * tap-hold state. + */ + if (gest->in_taphold) { + VLOG(2, (LOG_DEBUG, + "synaptics: button RELEASE: %d\n", + gest->tap_button)); + gest->in_taphold = 0; + } else { + VLOG(2, (LOG_DEBUG, + "synaptics: not a tap-hold\n")); + } + } + } else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) && gest->in_taphold) { + /* + * For a tap-hold to work, the button must remain down at + * least until timeout (where the in_taphold flags will be + * cleared) or during the next action. + */ + if (timevalcmp(&sc->lastsoftintr, &gest->taptimeout, <=)) { + ms->button |= gest->tap_button; + } else { + VLOG(2, (LOG_DEBUG, "synaptics: button RELEASE: %d\n", + gest->tap_button)); + gest->in_taphold = 0; + } + } + + return; +} + +static void +psmsmoother(struct psm_softc *sc, finger_t *f, int smoother_id, + mousestatus_t *ms, int *x, int *y) +{ + smoother_t *smoother = &sc->smoother[smoother_id]; + gesture_t *gest = &(sc->gesture); + + /* + * Check pressure to detect a real wanted action on the + * touchpad. + */ + if (f->p >= sc->syninfo.min_pressure) { + int x0, y0; int cursor, peer, window; int dx, dy, dxp, dyp; int max_width, max_pressure; @@ -2838,9 +3464,10 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, int div_min, div_max, div_len; int vscroll_hor_area, vscroll_ver_area; int two_finger_scroll; + int max_x, max_y; int len, weight_prev_x, weight_prev_y; int div_max_x, div_max_y, div_x, div_y; - int exiting_scroll; + int is_fuzzy; /* Read sysctl. */ /* XXX Verify values? */ @@ -2866,97 +3493,14 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, vscroll_hor_area = sc->syninfo.vscroll_hor_area; vscroll_ver_area = sc->syninfo.vscroll_ver_area; two_finger_scroll = sc->syninfo.two_finger_scroll; + max_x = sc->syninfo.max_x; + max_y = sc->syninfo.max_y; - exiting_scroll = 0; - - /* Palm detection. */ - if (!( - ((sc->synhw.capMultiFinger || - sc->synhw.capAdvancedGestures) && (w == 0 || w == 1)) || - (sc->synhw.capPalmDetect && w >= 4 && w <= max_width) || - (!sc->synhw.capPalmDetect && *z <= max_pressure) || - (sc->synhw.capPen && w == 2))) { - /* - * We consider the packet irrelevant for the current - * action when: - * - the width isn't comprised in: - * [4; max_width] - * - the pressure isn't comprised in: - * [min_pressure; max_pressure] - * - pen aren't supported but w is 2 - * - * Note that this doesn't terminate the current action. - */ - VLOG(2, (LOG_DEBUG, - "synaptics: palm detected! (%d)\n", w)); - goto SYNAPTICS_END; - } + is_fuzzy = (f->flags & PSM_FINGER_FUZZY) != 0; /* Read current absolute position. */ - x0 = ((pb->ipacket[3] & 0x10) << 8) | - ((pb->ipacket[1] & 0x0f) << 8) | - pb->ipacket[4]; - y0 = ((pb->ipacket[3] & 0x20) << 7) | - ((pb->ipacket[1] & 0xf0) << 4) | - pb->ipacket[5]; - - synaction = &(sc->synaction); - - /* - * If the action is just beginning, init the structure and - * compute tap timeout. - */ - if (!(sc->flags & PSM_FLAGS_FINGERDOWN)) { - VLOG(3, (LOG_DEBUG, "synaptics: ----\n")); - - /* Store the first point of this action. */ - synaction->start_x = x0; - synaction->start_y = y0; - dx = dy = 0; - - /* Initialize queue. */ - synaction->queue_cursor = SYNAPTICS_PACKETQUEUE; - synaction->queue_len = 0; - synaction->window_min = window_min; - - /* Reset average. */ - synaction->avg_dx = 0; - synaction->avg_dy = 0; - - /* Reset squelch. */ - synaction->squelch_x = 0; - synaction->squelch_y = 0; - - /* Reset pressure peak. */ - sc->zmax = 0; - - /* Reset fingers count. */ - synaction->fingers_nb = 0; - - /* Reset virtual scrolling state. */ - synaction->in_vscroll = 0; - - /* Compute tap timeout. */ - sc->taptimeout.tv_sec = tap_timeout / 1000000; - sc->taptimeout.tv_usec = tap_timeout % 1000000; - timevaladd(&sc->taptimeout, &sc->lastsoftintr); - - sc->flags |= PSM_FLAGS_FINGERDOWN; - } else { - /* Calculate the current delta. */ - cursor = synaction->queue_cursor; - dx = x0 - synaction->queue[cursor].x; - dy = y0 - synaction->queue[cursor].y; - } - - /* If in tap-hold, add the recorded button. */ - if (synaction->in_taphold) - ms->button |= synaction->tap_button; - - /* - * From now on, we can use the SYNAPTICS_END label to skip - * the current packet. - */ + x0 = f->x; + y0 = f->y; /* * Limit the coordinates to the specified margins because @@ -2964,128 +3508,65 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, */ if (x0 <= margin_left) x0 = margin_left; - else if (x0 >= 6143 - margin_right) - x0 = 6143 - margin_right; + else if (x0 >= max_x - margin_right) + x0 = max_x - margin_right; if (y0 <= margin_bottom) y0 = margin_bottom; - else if (y0 >= 6143 - margin_top) - y0 = 6143 - margin_top; + else if (y0 >= max_y - margin_top) + y0 = max_y - margin_top; - VLOG(3, (LOG_DEBUG, "synaptics: ipacket: [%d, %d], %d, %d\n", - x0, y0, *z, w)); + /* If the action is just beginning, init the structure. */ + if (smoother->active == 0) { + VLOG(3, (LOG_DEBUG, "smoother%d: ---\n", smoother_id)); + + /* Store the first point of this action. */ + smoother->start_x = x0; + smoother->start_y = y0; + dx = dy = 0; + + /* Initialize queue. */ + smoother->queue_cursor = SYNAPTICS_PACKETQUEUE; + smoother->queue_len = 0; + + /* Reset average. */ + smoother->avg_dx = 0; + smoother->avg_dy = 0; + + /* Reset squelch. */ + smoother->squelch_x = 0; + smoother->squelch_y = 0; + + /* Activate queue */ + smoother->active = 1; + } else { + /* Calculate the current delta. */ + cursor = smoother->queue_cursor; + dx = x0 - smoother->queue[cursor].x; + dy = y0 - smoother->queue[cursor].y; + } + + VLOG(3, (LOG_DEBUG, "smoother%d: ipacket: [%d, %d], %d, %d\n", + smoother_id, x0, y0, f->p, f->w)); /* Queue this new packet. */ - cursor = SYNAPTICS_QUEUE_CURSOR(synaction->queue_cursor - 1); - synaction->queue[cursor].x = x0; - synaction->queue[cursor].y = y0; - synaction->queue_cursor = cursor; - if (synaction->queue_len < SYNAPTICS_PACKETQUEUE) - synaction->queue_len++; + cursor = SYNAPTICS_QUEUE_CURSOR(smoother->queue_cursor - 1); + smoother->queue[cursor].x = x0; + smoother->queue[cursor].y = y0; + smoother->queue_cursor = cursor; + if (smoother->queue_len < SYNAPTICS_PACKETQUEUE) + smoother->queue_len++; VLOG(5, (LOG_DEBUG, - "synaptics: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n", - cursor, x0, y0, dx, dy)); - - /* - * For tap, we keep the maximum number of fingers and the - * pressure peak. Also with multiple fingers, we increase - * the minimum window. - */ - switch (w) { - case 1: /* Three or more fingers. */ - synaction->fingers_nb = imax(3, synaction->fingers_nb); - synaction->window_min = window_max; - break; - case 0: /* Two fingers. */ - synaction->fingers_nb = imax(2, synaction->fingers_nb); - synaction->window_min = window_max; - break; - default: /* One finger or undetectable. */ - synaction->fingers_nb = imax(1, synaction->fingers_nb); - } - sc->zmax = imax(*z, sc->zmax); + "smoother%d: cursor[%d]: x=%d, y=%d, dx=%d, dy=%d\n", + smoother_id, cursor, x0, y0, dx, dy)); /* Do we have enough packets to consider this a movement? */ - if (synaction->queue_len < synaction->window_min) - goto SYNAPTICS_END; - - /* Is a scrolling action occurring? */ - if (!synaction->in_taphold && !synaction->in_vscroll) { - /* - * A scrolling action must not conflict with a tap - * action. Here are the conditions to consider a - * scrolling action: - * - the action in a configurable area - * - one of the following: - * . the distance between the last packet and the - * first should be above a configurable minimum - * . tap timed out - */ - dxp = abs(synaction->queue[synaction->queue_cursor].x - - synaction->start_x); - dyp = abs(synaction->queue[synaction->queue_cursor].y - - synaction->start_y); - - if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, >) || - dxp >= sc->syninfo.vscroll_min_delta || - dyp >= sc->syninfo.vscroll_min_delta) { - /* - * Handle two finger scrolling. - * Note that we don't rely on fingers_nb - * as that keeps the maximum number of fingers. - */ - if (two_finger_scroll) { - if (w == 0) { - synaction->in_vscroll += - dyp ? 2 : 0; - synaction->in_vscroll += - dxp ? 1 : 0; - } - } else { - /* Check for horizontal scrolling. */ - if ((vscroll_hor_area > 0 && - synaction->start_y <= - vscroll_hor_area) || - (vscroll_hor_area < 0 && - synaction->start_y >= - 6143 + vscroll_hor_area)) - synaction->in_vscroll += 2; - - /* Check for vertical scrolling. */ - if ((vscroll_ver_area > 0 && - synaction->start_x <= - vscroll_ver_area) || - (vscroll_ver_area < 0 && - synaction->start_x >= - 6143 + vscroll_ver_area)) - synaction->in_vscroll += 1; - } - - /* Avoid conflicts if area overlaps. */ - if (synaction->in_vscroll >= 3) - synaction->in_vscroll = - (dxp > dyp) ? 2 : 1; - } - } - /* - * Reset two finger scrolling when the number of fingers - * is different from two. - */ - if (two_finger_scroll && w != 0 && synaction->in_vscroll != 0) { - synaction->in_vscroll = 0; - exiting_scroll = 1; - } - - VLOG(5, (LOG_DEBUG, - "synaptics: virtual scrolling: %s " - "(direction=%d, dxp=%d, dyp=%d, fingers=%d)\n", - synaction->in_vscroll ? "YES" : "NO", - synaction->in_vscroll, dxp, dyp, - synaction->fingers_nb)); + if (smoother->queue_len < gest->window_min) + return; weight_prev_x = weight_prev_y = weight_previous; div_max_x = div_max_y = div_max; - if (synaction->in_vscroll) { + if (gest->in_vscroll) { /* Dividers are different with virtual scrolling. */ div_min = sc->syninfo.vscroll_div_min; div_max_x = div_max_y = sc->syninfo.vscroll_div_max; @@ -3096,12 +3577,12 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, * using this area, we apply a special weight and * div. */ - if (x0 <= na_left || x0 >= 6143 - na_right) { + if (x0 <= na_left || x0 >= max_x - na_right) { weight_prev_x = sc->syninfo.weight_previous_na; div_max_x = sc->syninfo.div_max_na; } - if (y0 <= na_bottom || y0 >= 6143 - na_top) { + if (y0 <= na_bottom || y0 >= max_y - na_top) { weight_prev_y = sc->syninfo.weight_previous_na; div_max_y = sc->syninfo.div_max_na; } @@ -3113,10 +3594,10 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, * the current packet and a previous one (based on the * window width). */ - window = imin(synaction->queue_len, window_max); + window = imin(smoother->queue_len, window_max); peer = SYNAPTICS_QUEUE_CURSOR(cursor + window - 1); - dxp = abs(x0 - synaction->queue[peer].x) + 1; - dyp = abs(y0 - synaction->queue[peer].y) + 1; + dxp = abs(x0 - smoother->queue[peer].x) + 1; + dyp = abs(y0 - smoother->queue[peer].y) + 1; len = (dxp * dxp) + (dyp * dyp); weight_prev_x = imin(weight_prev_x, weight_len_squared * weight_prev_x / len); @@ -3132,215 +3613,442 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, div_y = imax(div_min, div_y); VLOG(3, (LOG_DEBUG, - "synaptics: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n", - peer, len, weight_prev_x, weight_prev_y, div_x, div_y)); + "smoother%d: peer=%d, len=%d, weight=%d/%d, div=%d/%d\n", + smoother_id, peer, len, weight_prev_x, weight_prev_y, + div_x, div_y)); /* Compute averages. */ - synaction->avg_dx = + smoother->avg_dx = (weight_current * dx * multiplicator + - weight_prev_x * synaction->avg_dx) / + weight_prev_x * smoother->avg_dx) / (weight_current + weight_prev_x); - synaction->avg_dy = + smoother->avg_dy = (weight_current * dy * multiplicator + - weight_prev_y * synaction->avg_dy) / + weight_prev_y * smoother->avg_dy) / (weight_current + weight_prev_y); VLOG(5, (LOG_DEBUG, - "synaptics: avg_dx~=%d, avg_dy~=%d\n", - synaction->avg_dx / multiplicator, - synaction->avg_dy / multiplicator)); + "smoother%d: avg_dx~=%d, avg_dy~=%d\n", smoother_id, + smoother->avg_dx / multiplicator, + smoother->avg_dy / multiplicator)); /* Use these averages to calculate x & y. */ - synaction->squelch_x += synaction->avg_dx; - *x = synaction->squelch_x / (div_x * multiplicator); - synaction->squelch_x = synaction->squelch_x % + smoother->squelch_x += smoother->avg_dx; + dxp = smoother->squelch_x / (div_x * multiplicator); + smoother->squelch_x = smoother->squelch_x % (div_x * multiplicator); - synaction->squelch_y += synaction->avg_dy; - *y = synaction->squelch_y / (div_y * multiplicator); - synaction->squelch_y = synaction->squelch_y % + smoother->squelch_y += smoother->avg_dy; + dyp = smoother->squelch_y / (div_y * multiplicator); + smoother->squelch_y = smoother->squelch_y % (div_y * multiplicator); - if (synaction->in_vscroll) { - switch(synaction->in_vscroll) { - case 1: /* Vertical scrolling. */ - if (*y != 0) - ms->button |= (*y > 0) ? - MOUSE_BUTTON4DOWN : - MOUSE_BUTTON5DOWN; - break; - case 2: /* Horizontal scrolling. */ - if (*x != 0) - ms->button |= (*x > 0) ? - MOUSE_BUTTON7DOWN : - MOUSE_BUTTON6DOWN; - break; + switch(gest->in_vscroll) { + case 0: /* Pointer movement. */ + /* On real<->fuzzy finger switch the x/y pos jumps */ + if (is_fuzzy == smoother->is_fuzzy) { + *x += dxp; + *y += dyp; } - /* The pointer is not moved. */ - *x = *y = 0; - } else { - /* On exit the x/y pos may jump, ignore this */ - if (exiting_scroll) - *x = *y = 0; - - VLOG(3, (LOG_DEBUG, "synaptics: [%d, %d] -> [%d, %d]\n", - dx, dy, *x, *y)); + VLOG(3, (LOG_DEBUG, "smoother%d: [%d, %d] -> [%d, %d]\n", + smoother_id, dx, dy, dxp, dyp)); + break; + case 1: /* Vertical scrolling. */ + if (dyp != 0) + ms->button |= (dyp > 0) ? + MOUSE_BUTTON4DOWN : MOUSE_BUTTON5DOWN; + break; + case 2: /* Horizontal scrolling. */ + if (dxp != 0) + ms->button |= (dxp > 0) ? + MOUSE_BUTTON7DOWN : MOUSE_BUTTON6DOWN; + break; } - } else if (sc->flags & PSM_FLAGS_FINGERDOWN) { + + smoother->is_fuzzy = is_fuzzy; + + } else { /* - * An action is currently taking place but the pressure - * dropped under the minimum, putting an end to it. + * Deactivate queue. Note: We can not just reset queue here + * as these values are still used by gesture processor. + * So postpone reset till next touch. */ - synapticsaction_t *synaction; - int taphold_timeout, dx, dy, tap_max_delta; + smoother->active = 0; + } +} - synaction = &(sc->synaction); - dx = abs(synaction->queue[synaction->queue_cursor].x - - synaction->start_x); - dy = abs(synaction->queue[synaction->queue_cursor].y - - synaction->start_y); +static int +proc_elantech(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, + int *x, int *y, int *z) +{ + static int touchpad_button, trackpoint_button; + finger_t fn, f[ELANTECH_MAX_FINGERS]; + int pkt, id, scale, i, nfingers, mask; - /* Max delta is disabled for multi-fingers tap. */ - if (synaction->fingers_nb > 1) - tap_max_delta = imax(dx, dy); - else - tap_max_delta = sc->syninfo.tap_max_delta; + if (!elantech_support) + return (0); - sc->flags &= ~PSM_FLAGS_FINGERDOWN; + /* Determine packet format and do a sanity check for out of sync packets. */ + if (ELANTECH_PKT_IS_DEBOUNCE(pb, sc->elanhw.hwversion)) + pkt = ELANTECH_PKT_NOP; + else if (ELANTECH_PKT_IS_TRACKPOINT(pb)) + pkt = ELANTECH_PKT_TRACKPOINT; + else + switch (sc->elanhw.hwversion) { + case 2: + if (!ELANTECH_PKT_IS_V2(pb)) + return (-1); - /* Check for tap. */ - VLOG(3, (LOG_DEBUG, - "synaptics: zmax=%d, dx=%d, dy=%d, " - "delta=%d, fingers=%d, queue=%d\n", - sc->zmax, dx, dy, tap_max_delta, synaction->fingers_nb, - synaction->queue_len)); - if (!synaction->in_vscroll && sc->zmax >= tap_threshold && - timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=) && - dx <= tap_max_delta && dy <= tap_max_delta && - synaction->queue_len >= sc->syninfo.tap_min_queue) { - /* - * We have a tap if: - * - the maximum pressure went over tap_threshold - * - the action ended before tap_timeout - * - * To handle tap-hold, we must delay any button push to - * the next action. - */ - if (synaction->in_taphold) { - /* - * This is the second and last tap of a - * double tap action, not a tap-hold. - */ - synaction->in_taphold = 0; + pkt = (pb->ipacket[0] & 0xc0) == 0x80 ? + ELANTECH_PKT_V2_2FINGER : ELANTECH_PKT_V2_COMMON; + break; + case 3: + if (!ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc) && + !ELANTECH_PKT_IS_V3_TAIL(pb, sc->elanhw.hascrc)) + return (-1); - /* - * For double-tap to work: - * - no button press is emitted (to - * simulate a button release) - * - PSM_FLAGS_FINGERDOWN is set to - * force the next packet to emit a - * button press) - */ - VLOG(2, (LOG_DEBUG, - "synaptics: button RELEASE: %d\n", - synaction->tap_button)); - sc->flags |= PSM_FLAGS_FINGERDOWN; - } else { - /* - * This is the first tap: we set the - * tap-hold state and notify the button - * down event. - */ - synaction->in_taphold = 1; - taphold_timeout = sc->syninfo.taphold_timeout; - sc->taptimeout.tv_sec = taphold_timeout / - 1000000; - sc->taptimeout.tv_usec = taphold_timeout % - 1000000; - timevaladd(&sc->taptimeout, &sc->lastsoftintr); + pkt = ELANTECH_PKT_V3; + break; + case 4: + if (!ELANTECH_PKT_IS_V4(pb, sc->elanhw.hascrc)) + return (-1); - switch (synaction->fingers_nb) { - case 3: - synaction->tap_button = - MOUSE_BUTTON2DOWN; - break; - case 2: - synaction->tap_button = - MOUSE_BUTTON3DOWN; - break; - default: - synaction->tap_button = - MOUSE_BUTTON1DOWN; - } - VLOG(2, (LOG_DEBUG, - "synaptics: button PRESS: %d\n", - synaction->tap_button)); - ms->button |= synaction->tap_button; - } - } else { - /* - * Not enough pressure or timeout: reset - * tap-hold state. - */ - if (synaction->in_taphold) { - VLOG(2, (LOG_DEBUG, - "synaptics: button RELEASE: %d\n", - synaction->tap_button)); - synaction->in_taphold = 0; - } else { - VLOG(2, (LOG_DEBUG, - "synaptics: not a tap-hold\n")); - } - } - } else if (!(sc->flags & PSM_FLAGS_FINGERDOWN) && - sc->synaction.in_taphold) { - /* - * For a tap-hold to work, the button must remain down at - * least until timeout (where the in_taphold flags will be - * cleared) or during the next action. - */ - if (timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) { - ms->button |= sc->synaction.tap_button; - } else { - VLOG(2, (LOG_DEBUG, - "synaptics: button RELEASE: %d\n", - sc->synaction.tap_button)); - sc->synaction.in_taphold = 0; + switch (pb->ipacket[3] & 0x03) { + case 0x00: + pkt = ELANTECH_PKT_V4_STATUS; + break; + case 0x01: + pkt = ELANTECH_PKT_V4_HEAD; + break; + case 0x02: + pkt = ELANTECH_PKT_V4_MOTION; + break; + default: + return (-1); } + break; + default: + return (-1); } -SYNAPTICS_END: - /* - * Use the extra buttons as a scrollwheel - * - * XXX X.Org uses the Z axis for vertical wheel only, - * whereas moused(8) understands special values to differ - * vertical and horizontal wheels. - * - * xf86-input-mouse needs therefore a small patch to - * understand these special values. Without it, the - * horizontal wheel acts as a vertical wheel in X.Org. - * - * That's why the horizontal wheel is disabled by - * default for now. - */ + VLOG(5, (LOG_DEBUG, "elantech: ipacket format: %d\n", pkt)); - if (ms->button & MOUSE_BUTTON4DOWN) { + for (id = 0; id < ELANTECH_MAX_FINGERS; id++) + PSM_FINGER_RESET(f[id]); + + *x = *y = *z = 0; + ms->button = ms->obutton; + + if (sc->syninfo.touchpad_off) + return (0); + + /* Common legend + * L: Left mouse button pressed + * R: Right mouse button pressed + * N: number of fingers on touchpad + * X: absolute x value (horizontal) + * Y: absolute y value (vertical) + * W; width of the finger touch + * P: pressure + */ + switch (pkt) { + case ELANTECH_PKT_V2_COMMON: /* HW V2. One/Three finger touch */ + /* 7 6 5 4 3 2 1 0 (LSB) + * ------------------------------------------- + * ipacket[0]: N1 N0 W3 W2 . . R L + * ipacket[1]: P7 P6 P5 P4 X11 X10 X9 X8 + * ipacket[2]: X7 X6 X5 X4 X3 X2 X1 X0 + * ipacket[3]: N4 VF W1 W0 . . . B2 + * ipacket[4]: P3 P1 P2 P0 Y11 Y10 Y9 Y8 + * ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 + * ------------------------------------------- + * N4: set if more than 3 fingers (only in 3 fingers mode) + * VF: a kind of flag? (only on EF123, 0 when finger + * is over one of the buttons, 1 otherwise) + * B2: (on EF113 only, 0 otherwise), one button pressed + * P & W is not reported on EF113 touchpads + */ + nfingers = (pb->ipacket[0] & 0xc0) >> 6; + if (nfingers == 3 && (pb->ipacket[3] & 0x80)) + nfingers = 4; + mask = (1 << nfingers) - 1; + + fn = ELANTECH_FINGER_SET_XYP(pb); + if (sc->elanhw.haspressure) { + fn.w = ((pb->ipacket[0] & 0x30) >> 2) | + ((pb->ipacket[3] & 0x30) >> 4); + } else { + fn.p = PSM_FINGER_DEFAULT_P; + fn.w = PSM_FINGER_DEFAULT_W; + } + + /* + * HW v2 dont report exact finger positions when 3 or more + * fingers are on touchpad. Use reported value as fingers + * position as it is required for tap detection + */ + if (nfingers > 2) + fn.flags = PSM_FINGER_FUZZY; + + for (id = 0; id < imin(nfingers, ELANTECH_MAX_FINGERS); id++) + f[id] = fn; + break; + + case ELANTECH_PKT_V2_2FINGER: /*HW V2. Two finger touch */ + /* 7 6 5 4 3 2 1 0 (LSB) + * ------------------------------------------- + * ipacket[0]: N1 N0 AY8 AX8 . . R L + * ipacket[1]: AX7 AX6 AX5 AX4 AX3 AX2 AX1 AX0 + * ipacket[2]: AY7 AY6 AY5 AY4 AY3 AY2 AY1 AY0 + * ipacket[3]: . . BY8 BX8 . . . . + * ipacket[4]: BX7 BX6 BX5 BX4 BX3 BX2 BX1 BX0 + * ipacket[5]: BY7 BY6 BY5 BY4 BY3 BY2 BY1 BY0 + * ------------------------------------------- + * AX: lower-left finger absolute x value + * AY: lower-left finger absolute y value + * BX: upper-right finger absolute x value + * BY: upper-right finger absolute y value + */ + nfingers = 2; + mask = (1 << nfingers) - 1; + + for (id = 0; id < imin(2, ELANTECH_MAX_FINGERS); id ++) + f[id] = (finger_t) { + .x = (((pb->ipacket[id * 3] & 0x10) << 4) | + pb->ipacket[id * 3 + 1]) << 2, + .y = (((pb->ipacket[id * 3] & 0x20) << 3) | + pb->ipacket[id * 3 + 2]) << 2, + .p = PSM_FINGER_DEFAULT_P, + .w = PSM_FINGER_DEFAULT_W, + /* HW ver.2 sends bounding box */ + .flags = PSM_FINGER_FUZZY + }; + break; + + case ELANTECH_PKT_V3: /* HW Version 3 */ + /* 7 6 5 4 3 2 1 0 (LSB) + * ------------------------------------------- + * ipacket[0]: N1 N0 W3 W2 0 1 R L + * ipacket[1]: P7 P6 P5 P4 X11 X10 X9 X8 + * ipacket[2]: X7 X6 X5 X4 X3 X2 X1 X0 + * ipacket[3]: 0 0 W1 W0 0 0 1 0 + * ipacket[4]: P3 P1 P2 P0 Y11 Y10 Y9 Y8 + * ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 + * ------------------------------------------- + */ + nfingers = (pb->ipacket[0] & 0xc0) >> 6; + mask = (1 << nfingers) - 1; + id = nfingers - 1; + + fn = ELANTECH_FINGER_SET_XYP(pb); + fn.w = ((pb->ipacket[0] & 0x30) >> 2) | + ((pb->ipacket[3] & 0x30) >> 4); + + /* + * HW v3 dont report exact finger positions when 3 or more + * fingers are on touchpad. Use reported value as fingers + * position as it is required for tap detection + */ + if (nfingers > 1) + fn.flags = PSM_FINGER_FUZZY; + + for (id = 0; id < imin(nfingers, ELANTECH_MAX_FINGERS); id++) + f[id] = fn; + + if (nfingers == 2) { + if (ELANTECH_PKT_IS_V3_HEAD(pb, sc->elanhw.hascrc)) { + sc->elanaction.fingers[0] = fn; + return (0); + } else + f[0] = sc->elanaction.fingers[0]; + } + break; + + case ELANTECH_PKT_V4_STATUS: /* HW Version 4. Status packet */ + /* 7 6 5 4 3 2 1 0 (LSB) + * ------------------------------------------- + * ipacket[0]: . . . . 0 1 R L + * ipacket[1]: . . . F4 F3 F2 F1 F0 + * ipacket[2]: . . . . . . . . + * ipacket[3]: . . . 1 0 0 0 0 + * ipacket[4]: PL . . . . . . . + * ipacket[5]: . . . . . . . . + * ------------------------------------------- + * Fn: finger n is on touchpad + * PL: palm + * HV ver4 sends a status packet to indicate that the numbers + * or identities of the fingers has been changed + */ + + mask = pb->ipacket[1] & 0x1f; + nfingers = bitcount(mask); + + /* Skip "new finger is on touchpad" packets */ + if ((sc->elanaction.mask & mask) == sc->elanaction.mask && + (mask & ~sc->elanaction.mask)) { + sc->elanaction.mask = mask; + return (0); + } + + break; + + case ELANTECH_PKT_V4_HEAD: /* HW Version 4. Head packet */ + /* 7 6 5 4 3 2 1 0 (LSB) + * ------------------------------------------- + * ipacket[0]: W3 W2 W1 W0 0 1 R L + * ipacket[1]: P7 P6 P5 P4 X11 X10 X9 X8 + * ipacket[2]: X7 X6 X5 X4 X3 X2 X1 X0 + * ipacket[3]: ID2 ID1 ID0 1 0 0 0 1 + * ipacket[4]: P3 P1 P2 P0 Y11 Y10 Y9 Y8 + * ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 + * ------------------------------------------- + * ID: finger id + * HW ver 4 sends head packets in two cases: + * 1. One finger touch and movement. + * 2. Next after status packet to tell new finger positions. + */ + mask = sc->elanaction.mask; + nfingers = bitcount(mask); + id = ((pb->ipacket[3] & 0xe0) >> 5) - 1; + + if (id >= 0 && id < ELANTECH_MAX_FINGERS) { + f[id] = ELANTECH_FINGER_SET_XYP(pb); + f[id].w = (pb->ipacket[0] & 0xf0) >> 4; + } + break; + + case ELANTECH_PKT_V4_MOTION: /* HW Version 4. Motion packet */ + /* 7 6 5 4 3 2 1 0 (LSB) + * ------------------------------------------- + * ipacket[0]: ID2 ID1 ID0 OF 0 1 R L + * ipacket[1]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0 + * ipacket[2]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0 + * ipacket[3]: ID2 ID1 ID0 1 0 0 1 0 + * ipacket[4]: DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0 + * ipacket[5]: DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0 + * ------------------------------------------- + * OF: delta overflows (> 127 or < -128), in this case + * firmware sends us (delta x / 5) and (delta y / 5) + * ID: finger id + * DX: delta x (two's complement) + * XY: delta y (two's complement) + * byte 0 ~ 2 for one finger + * byte 3 ~ 5 for another finger + */ + mask = sc->elanaction.mask; + nfingers = bitcount(mask); + + scale = (pb->ipacket[0] & 0x10) ? 5 : 1; + for (i = 0; i <= 3; i += 3) { + id = ((pb->ipacket[i] & 0xe0) >> 5) - 1; + if (id < 0 || id >= ELANTECH_MAX_FINGERS) + continue; + + if (PSM_FINGER_IS_SET(sc->elanaction.fingers[id])) { + f[id] = sc->elanaction.fingers[id]; + f[id].x += imax(-f[id].x, + (signed char)pb->ipacket[i+1] * scale); + f[id].y += imax(-f[id].y, + (signed char)pb->ipacket[i+2] * scale); + } else { + VLOG(3, (LOG_DEBUG, "elantech: " + "HW v4 motion packet skipped\n")); + } + } + + break; + + case ELANTECH_PKT_TRACKPOINT: + /* 7 6 5 4 3 2 1 0 (LSB) + * ------------------------------------------- + * ipacket[0]: 0 0 SX SY 0 M R L + * ipacket[1]: ~SX 0 0 0 0 0 0 0 + * ipacket[2]: ~SY 0 0 0 0 0 0 0 + * ipacket[3]: 0 0 ~SY ~SX 0 1 1 0 + * ipacket[4]: X7 X6 X5 X4 X3 X2 X1 X0 + * ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 + * ------------------------------------------- + * X and Y are written in two's complement spread + * over 9 bits with SX/SY the relative top bit and + * X7..X0 and Y7..Y0 the lower bits. + */ + *x = (pb->ipacket[0] & 0x20) ? + pb->ipacket[4] - 256 : pb->ipacket[4]; + *y = (pb->ipacket[0] & 0x10) ? + pb->ipacket[5] - 256 : pb->ipacket[5]; + + trackpoint_button = + ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) | + ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0) | + ((pb->ipacket[0] & 0x04) ? MOUSE_BUTTON2DOWN : 0); + + ms->button = touchpad_button | trackpoint_button; + return (0); + + case ELANTECH_PKT_NOP: + return (0); + + default: + return (-1); + } + + for (id = 0; id < ELANTECH_MAX_FINGERS; id++) + if (PSM_FINGER_IS_SET(f[id])) + VLOG(2, (LOG_DEBUG, "elantech: " + "finger %d: down [%d, %d], %d, %d, %d\n", id + 1, + f[id].x, f[id].y, f[id].p, f[id].w, f[id].flags)); + + /* Touchpad button presses */ + if (sc->elanhw.isclickpad) { + touchpad_button = + ((pb->ipacket[0] & 0x03) ? MOUSE_BUTTON1DOWN : 0); + } else { + touchpad_button = + ((pb->ipacket[0] & 0x01) ? MOUSE_BUTTON1DOWN : 0) | + ((pb->ipacket[0] & 0x02) ? MOUSE_BUTTON3DOWN : 0); + } + + ms->button = touchpad_button | trackpoint_button; + + /* Palm detection doesn't terminate the current action. */ + if (!psmpalmdetect(sc, &f[0], nfingers)) { + /* Send finger 1 position to gesture processor */ + if (PSM_FINGER_IS_SET(f[0]) || PSM_FINGER_IS_SET(f[1]) || + nfingers == 0) + psmgestures(sc, &f[0], imin(nfingers, 3), ms); + /* Send fingers positions to movement smoothers */ + for (id = 0; id < PSM_FINGERS; id++) + if (PSM_FINGER_IS_SET(f[id]) || !(mask & (1 << id))) + psmsmoother(sc, &f[id], id, ms, x, y); + } else { + VLOG(2, (LOG_DEBUG, "elantech: palm detected! (%d)\n", + f[0].w)); + } + + /* Store current finger positions in action context */ + for (id = 0; id < ELANTECH_MAX_FINGERS; id++) { + if (PSM_FINGER_IS_SET(f[id])) + sc->elanaction.fingers[id] = f[id]; + if ((sc->elanaction.mask & (1 << id)) && !(mask & (1 << id))) + PSM_FINGER_RESET(sc->elanaction.fingers[id]); + } + sc->elanaction.mask = mask; + + /* Use the extra buttons as a scrollwheel */ + if (ms->button & MOUSE_BUTTON4DOWN) *z = -1; - ms->button &= ~MOUSE_BUTTON4DOWN; - } else if (ms->button & MOUSE_BUTTON5DOWN) { + else if (ms->button & MOUSE_BUTTON5DOWN) *z = 1; - ms->button &= ~MOUSE_BUTTON5DOWN; - } else if (ms->button & MOUSE_BUTTON6DOWN) { + else if (ms->button & MOUSE_BUTTON6DOWN) *z = -2; - ms->button &= ~MOUSE_BUTTON6DOWN; - } else if (ms->button & MOUSE_BUTTON7DOWN) { + else if (ms->button & MOUSE_BUTTON7DOWN) *z = 2; - ms->button &= ~MOUSE_BUTTON7DOWN; - } else + else *z = 0; + ms->button &= ~(MOUSE_BUTTON4DOWN | MOUSE_BUTTON5DOWN | + MOUSE_BUTTON6DOWN | MOUSE_BUTTON7DOWN); return (0); } @@ -3412,6 +4120,31 @@ proc_versapad(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms, sc->flags &= ~PSM_FLAGS_FINGERDOWN; } +static void +psmsoftintridle(void *arg) +{ + struct psm_softc *sc = arg; + packetbuf_t *pb; + + /* Invoke soft handler only when pqueue is empty. Otherwise it will be + * invoked from psmintr soon with pqueue filled with real data */ + if (sc->pqueue_start == sc->pqueue_end && + sc->idlepacket.inputbytes > 0) { + /* Grow circular queue backwards to avoid race with psmintr */ + if (--sc->pqueue_start < 0) + sc->pqueue_start = PSM_PACKETQUEUE - 1; + + pb = &sc->pqueue[sc->pqueue_start]; + memcpy(pb, &sc->idlepacket, sizeof(packetbuf_t)); + VLOG(4, (LOG_DEBUG, + "psmsoftintridle: %02x %02x %02x %02x %02x %02x\n", + pb->ipacket[0], pb->ipacket[1], pb->ipacket[2], + pb->ipacket[3], pb->ipacket[4], pb->ipacket[5])); + + psmsoftintr(arg); + } +} + static void psmsoftintr(void *arg) { @@ -3465,6 +4198,8 @@ psmsoftintr(void *arg) if (sc->config & PSM_CONFIG_FORCETAP) ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN; + timevalclear(&sc->idletimeout); + sc->idlepacket.inputbytes = 0; switch (sc->hw.model) { @@ -3603,6 +4338,11 @@ psmsoftintr(void *arg) goto next; break; + case MOUSE_MODEL_ELANTECH: + if (proc_elantech(sc, pb, &ms, &x, &y, &z) != 0) + goto next; + break; + case MOUSE_MODEL_TRACKPOINT: case MOUSE_MODEL_GENERIC: default: @@ -3627,6 +4367,10 @@ psmsoftintr(void *arg) } } + /* Store last packet for reinjection if it has not been set already */ + if (timevalisset(&sc->idletimeout) && sc->idlepacket.inputbytes == 0) + sc->idlepacket = *pb; + ms.dx = x; ms.dy = y; ms.dz = z; @@ -3673,6 +4417,16 @@ psmsoftintr(void *arg) pgsigio(&sc->async, SIGIO, 0); } sc->state &= ~PSM_SOFTARMED; + + /* schedule injection of predefined packet after idletimeout + * if no data packets have been received from psmintr */ + if (timevalisset(&sc->idletimeout)) { + sc->state |= PSM_SOFTARMED; + callout_reset(&sc->softcallout, tvtohz(&sc->idletimeout), + psmsoftintridle, sc); + VLOG(2, (LOG_DEBUG, "softintr: callout set: %d ticks\n", + tvtohz(&sc->idletimeout))); + } splx(s); } @@ -4106,10 +4860,17 @@ enable_4dplus(struct psm_softc *sc, enum probearg arg) static int synaptics_sysctl(SYSCTL_HANDLER_ARGS) { + struct psm_softc *sc; int error, arg; + if (oidp->oid_arg1 == NULL || oidp->oid_arg2 < 0 || + oidp->oid_arg2 > SYNAPTICS_SYSCTL_SOFTBUTTON3_X) + return (EINVAL); + + sc = oidp->oid_arg1; + /* Read the current value. */ - arg = *(int *)oidp->oid_arg1; + arg = *(int *)((char *)sc + oidp->oid_arg2); error = sysctl_handle_int(oidp, &arg, 0, req); /* Sanity check. */ @@ -4131,14 +4892,23 @@ synaptics_sysctl(SYSCTL_HANDLER_ARGS) return (EINVAL); break; case SYNAPTICS_SYSCTL_MARGIN_TOP: - case SYNAPTICS_SYSCTL_MARGIN_RIGHT: case SYNAPTICS_SYSCTL_MARGIN_BOTTOM: - case SYNAPTICS_SYSCTL_MARGIN_LEFT: case SYNAPTICS_SYSCTL_NA_TOP: - case SYNAPTICS_SYSCTL_NA_RIGHT: case SYNAPTICS_SYSCTL_NA_BOTTOM: + if (arg < 0 || arg > sc->synhw.maximumYCoord) + return (EINVAL); + break; + case SYNAPTICS_SYSCTL_SOFTBUTTON2_X: + case SYNAPTICS_SYSCTL_SOFTBUTTON3_X: + /* Softbuttons is clickpad only feature */ + if (!sc->synhw.capClickPad && arg != 0) + return (EINVAL); + /* FALLTHROUGH */ + case SYNAPTICS_SYSCTL_MARGIN_RIGHT: + case SYNAPTICS_SYSCTL_MARGIN_LEFT: + case SYNAPTICS_SYSCTL_NA_RIGHT: case SYNAPTICS_SYSCTL_NA_LEFT: - if (arg < 0 || arg > 6143) + if (arg < 0 || arg > sc->synhw.maximumXCoord) return (EINVAL); break; case SYNAPTICS_SYSCTL_WINDOW_MIN: @@ -4168,8 +4938,18 @@ synaptics_sysctl(SYSCTL_HANDLER_ARGS) return (EINVAL); break; case SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA: + if (arg < -sc->synhw.maximumXCoord || + arg > sc->synhw.maximumXCoord) + return (EINVAL); + break; + case SYNAPTICS_SYSCTL_SOFTBUTTONS_Y: + /* Softbuttons is clickpad only feature */ + if (!sc->synhw.capClickPad && arg != 0) + return (EINVAL); + /* FALLTHROUGH */ case SYNAPTICS_SYSCTL_VSCROLL_VER_AREA: - if (arg < -6143 || arg > 6143) + if (arg < -sc->synhw.maximumYCoord || + arg > sc->synhw.maximumYCoord) return (EINVAL); break; case SYNAPTICS_SYSCTL_TOUCHPAD_OFF: @@ -4181,13 +4961,51 @@ synaptics_sysctl(SYSCTL_HANDLER_ARGS) } /* Update. */ - *(int *)oidp->oid_arg1 = arg; + *(int *)((char *)sc + oidp->oid_arg2) = arg; return (error); } static void -synaptics_sysctl_create_tree(struct psm_softc *sc) +synaptics_sysctl_create_softbuttons_tree(struct psm_softc *sc) +{ + /* + * Set predefined sizes for softbuttons. + * Values are taken to match HP Pavilion dv6 clickpad drawings + * with thin middle softbutton placed on separator + */ + + /* hw.psm.synaptics.softbuttons_y */ + sc->syninfo.softbuttons_y = 1700; + SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, + "softbuttons_y", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, + sc, SYNAPTICS_SYSCTL_SOFTBUTTONS_Y, + synaptics_sysctl, "I", + "Vertical size of softbuttons area"); + + /* hw.psm.synaptics.softbutton2_x */ + sc->syninfo.softbutton2_x = 3100; + SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, + "softbutton2_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, + sc, SYNAPTICS_SYSCTL_SOFTBUTTON2_X, + synaptics_sysctl, "I", + "Horisontal position of 2-nd softbutton left edge (0-disable)"); + + /* hw.psm.synaptics.softbutton3_x */ + sc->syninfo.softbutton3_x = 3900; + SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, + "softbutton3_x", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, + sc, SYNAPTICS_SYSCTL_SOFTBUTTON3_X, + synaptics_sysctl, "I", + "Horisontal position of 3-rd softbutton left edge (0-disable)"); +} + +static void +synaptics_sysctl_create_tree(struct psm_softc *sc, const char *name, + const char *descr) { if (sc->syninfo.sysctl_tree != NULL) @@ -4196,8 +5014,8 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) /* Attach extra synaptics sysctl nodes under hw.psm.synaptics */ sysctl_ctx_init(&sc->syninfo.sysctl_ctx); sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx, - SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", CTLFLAG_RD, - 0, "Synaptics TouchPad"); + SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, name, CTLFLAG_RD, + 0, descr); /* hw.psm.synaptics.directional_scrolls. */ sc->syninfo.directional_scrolls = 0; @@ -4208,6 +5026,22 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) "Enable hardware scrolling pad (if non-zero) or register it as " "extended buttons (if 0)"); + /* hw.psm.synaptics.max_x. */ + sc->syninfo.max_x = 6143; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, + "max_x", CTLFLAG_RD|CTLFLAG_ANYBODY, + &sc->syninfo.max_x, 0, + "Horizontal reporting range"); + + /* hw.psm.synaptics.max_y. */ + sc->syninfo.max_y = 6143; + SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, + SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, + "max_y", CTLFLAG_RD|CTLFLAG_ANYBODY, + &sc->syninfo.max_y, 0, + "Vertical reporting range"); + /* * Turn off two finger scroll if we have a * physical area reserved for scrolling or when @@ -4230,7 +5064,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "min_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.min_pressure, SYNAPTICS_SYSCTL_MIN_PRESSURE, + sc, SYNAPTICS_SYSCTL_MIN_PRESSURE, synaptics_sysctl, "I", "Minimum pressure required to start an action"); @@ -4239,7 +5073,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "max_pressure", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.max_pressure, SYNAPTICS_SYSCTL_MAX_PRESSURE, + sc, SYNAPTICS_SYSCTL_MAX_PRESSURE, synaptics_sysctl, "I", "Maximum pressure to detect palm"); @@ -4248,7 +5082,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "max_width", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.max_width, SYNAPTICS_SYSCTL_MAX_WIDTH, + sc, SYNAPTICS_SYSCTL_MAX_WIDTH, synaptics_sysctl, "I", "Maximum finger width to detect palm"); @@ -4257,7 +5091,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "margin_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.margin_top, SYNAPTICS_SYSCTL_MARGIN_TOP, + sc, SYNAPTICS_SYSCTL_MARGIN_TOP, synaptics_sysctl, "I", "Top margin"); @@ -4266,7 +5100,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "margin_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.margin_right, SYNAPTICS_SYSCTL_MARGIN_RIGHT, + sc, SYNAPTICS_SYSCTL_MARGIN_RIGHT, synaptics_sysctl, "I", "Right margin"); @@ -4275,7 +5109,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "margin_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.margin_bottom, SYNAPTICS_SYSCTL_MARGIN_BOTTOM, + sc, SYNAPTICS_SYSCTL_MARGIN_BOTTOM, synaptics_sysctl, "I", "Bottom margin"); @@ -4284,7 +5118,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "margin_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.margin_left, SYNAPTICS_SYSCTL_MARGIN_LEFT, + sc, SYNAPTICS_SYSCTL_MARGIN_LEFT, synaptics_sysctl, "I", "Left margin"); @@ -4293,7 +5127,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "na_top", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.na_top, SYNAPTICS_SYSCTL_NA_TOP, + sc, SYNAPTICS_SYSCTL_NA_TOP, synaptics_sysctl, "I", "Top noisy area, where weight_previous_na is used instead " "of weight_previous"); @@ -4303,7 +5137,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "na_right", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.na_right, SYNAPTICS_SYSCTL_NA_RIGHT, + sc, SYNAPTICS_SYSCTL_NA_RIGHT, synaptics_sysctl, "I", "Right noisy area, where weight_previous_na is used instead " "of weight_previous"); @@ -4313,7 +5147,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "na_bottom", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.na_bottom, SYNAPTICS_SYSCTL_NA_BOTTOM, + sc, SYNAPTICS_SYSCTL_NA_BOTTOM, synaptics_sysctl, "I", "Bottom noisy area, where weight_previous_na is used instead " "of weight_previous"); @@ -4323,7 +5157,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "na_left", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.na_left, SYNAPTICS_SYSCTL_NA_LEFT, + sc, SYNAPTICS_SYSCTL_NA_LEFT, synaptics_sysctl, "I", "Left noisy area, where weight_previous_na is used instead " "of weight_previous"); @@ -4333,7 +5167,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "window_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.window_min, SYNAPTICS_SYSCTL_WINDOW_MIN, + sc, SYNAPTICS_SYSCTL_WINDOW_MIN, synaptics_sysctl, "I", "Minimum window size to start an action"); @@ -4342,7 +5176,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "window_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.window_max, SYNAPTICS_SYSCTL_WINDOW_MAX, + sc, SYNAPTICS_SYSCTL_WINDOW_MAX, synaptics_sysctl, "I", "Maximum window size"); @@ -4351,7 +5185,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "multiplicator", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.multiplicator, SYNAPTICS_SYSCTL_MULTIPLICATOR, + sc, SYNAPTICS_SYSCTL_MULTIPLICATOR, synaptics_sysctl, "I", "Multiplicator to increase precision in averages and divisions"); @@ -4360,7 +5194,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "weight_current", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.weight_current, SYNAPTICS_SYSCTL_WEIGHT_CURRENT, + sc, SYNAPTICS_SYSCTL_WEIGHT_CURRENT, synaptics_sysctl, "I", "Weight of the current movement in the new average"); @@ -4369,7 +5203,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "weight_previous", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.weight_previous, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS, + sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS, synaptics_sysctl, "I", "Weight of the previous average"); @@ -4378,8 +5212,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "weight_previous_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.weight_previous_na, - SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA, + sc, SYNAPTICS_SYSCTL_WEIGHT_PREVIOUS_NA, synaptics_sysctl, "I", "Weight of the previous average (inside the noisy area)"); @@ -4388,8 +5221,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "weight_len_squared", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.weight_len_squared, - SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED, + sc, SYNAPTICS_SYSCTL_WEIGHT_LEN_SQUARED, synaptics_sysctl, "I", "Length (squared) of segments where weight_previous " "starts to decrease"); @@ -4399,7 +5231,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.div_min, SYNAPTICS_SYSCTL_DIV_MIN, + sc, SYNAPTICS_SYSCTL_DIV_MIN, synaptics_sysctl, "I", "Divisor for fast movements"); @@ -4408,7 +5240,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.div_max, SYNAPTICS_SYSCTL_DIV_MAX, + sc, SYNAPTICS_SYSCTL_DIV_MAX, synaptics_sysctl, "I", "Divisor for slow movements"); @@ -4417,7 +5249,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "div_max_na", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.div_max_na, SYNAPTICS_SYSCTL_DIV_MAX_NA, + sc, SYNAPTICS_SYSCTL_DIV_MAX_NA, synaptics_sysctl, "I", "Divisor with slow movements (inside the noisy area)"); @@ -4426,7 +5258,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "div_len", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.div_len, SYNAPTICS_SYSCTL_DIV_LEN, + sc, SYNAPTICS_SYSCTL_DIV_LEN, synaptics_sysctl, "I", "Length of segments where div_max starts to decrease"); @@ -4435,7 +5267,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "tap_max_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.tap_max_delta, SYNAPTICS_SYSCTL_TAP_MAX_DELTA, + sc, SYNAPTICS_SYSCTL_TAP_MAX_DELTA, synaptics_sysctl, "I", "Length of segments above which a tap is ignored"); @@ -4444,17 +5276,17 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "tap_min_queue", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.tap_min_queue, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE, + sc, SYNAPTICS_SYSCTL_TAP_MIN_QUEUE, synaptics_sysctl, "I", "Number of packets required to consider a tap"); /* hw.psm.synaptics.taphold_timeout. */ - sc->synaction.in_taphold = 0; + sc->gesture.in_taphold = 0; sc->syninfo.taphold_timeout = tap_timeout; SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "taphold_timeout", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.taphold_timeout, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT, + sc, SYNAPTICS_SYSCTL_TAPHOLD_TIMEOUT, synaptics_sysctl, "I", "Maximum elapsed time between two taps to consider a tap-hold " "action"); @@ -4464,16 +5296,16 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "vscroll_hor_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.vscroll_hor_area, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA, + sc, SYNAPTICS_SYSCTL_VSCROLL_HOR_AREA, synaptics_sysctl, "I", "Area reserved for horizontal virtual scrolling"); /* hw.psm.synaptics.vscroll_ver_area. */ - sc->syninfo.vscroll_ver_area = -600; + sc->syninfo.vscroll_ver_area = -400 - sc->syninfo.margin_right; SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "vscroll_ver_area", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.vscroll_ver_area, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA, + sc, SYNAPTICS_SYSCTL_VSCROLL_VER_AREA, synaptics_sysctl, "I", "Area reserved for vertical virtual scrolling"); @@ -4482,8 +5314,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "vscroll_min_delta", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.vscroll_min_delta, - SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA, + sc, SYNAPTICS_SYSCTL_VSCROLL_MIN_DELTA, synaptics_sysctl, "I", "Minimum movement to consider virtual scrolling"); @@ -4492,7 +5323,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "vscroll_div_min", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.vscroll_div_min, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN, + sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MIN, synaptics_sysctl, "I", "Divisor for fast scrolling"); @@ -4501,7 +5332,7 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "vscroll_div_max", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.vscroll_div_max, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX, + sc, SYNAPTICS_SYSCTL_VSCROLL_DIV_MAX, synaptics_sysctl, "I", "Divisor for slow scrolling"); @@ -4510,28 +5341,29 @@ synaptics_sysctl_create_tree(struct psm_softc *sc) SYSCTL_ADD_PROC(&sc->syninfo.sysctl_ctx, SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO, "touchpad_off", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY, - &sc->syninfo.touchpad_off, SYNAPTICS_SYSCTL_TOUCHPAD_OFF, + sc, SYNAPTICS_SYSCTL_TOUCHPAD_OFF, synaptics_sysctl, "I", "Turn off touchpad"); + + sc->syninfo.softbuttons_y = 0; + sc->syninfo.softbutton2_x = 0; + sc->syninfo.softbutton3_x = 0; + + /* skip softbuttons sysctl on not clickpads */ + if (sc->synhw.capClickPad) + synaptics_sysctl_create_softbuttons_tree(sc); } static int synaptics_preferred_mode(struct psm_softc *sc) { int mode_byte; - mode_byte = 0xc0; + mode_byte = 0xc4; /* request wmode where available */ if (sc->synhw.capExtended) mode_byte |= 1; - /* - * Disable gesture processing when native packets are requested. This - * enables sending of encapsulated "extended W mode" packets. - */ - if (sc->mode.level == PSM_LEVEL_NATIVE) - mode_byte |= (1 << 2); - return mode_byte; } @@ -4546,7 +5378,8 @@ synaptics_set_mode(struct psm_softc *sc, int mode_byte) { * Enable advanced gestures mode if supported and we are not entering * passthrough mode. */ - if (sc->synhw.capAdvancedGestures && !(mode_byte & (1 << 5))) { + if ((sc->synhw.capAdvancedGestures || sc->synhw.capReportsV) && + !(mode_byte & (1 << 5))) { mouse_ext_command(sc->kbdc, 3); set_mouse_sampling_rate(sc->kbdc, 0xc8); } @@ -4754,7 +5587,15 @@ enable_synaptics(struct psm_softc *sc, enum probearg arg) ((status[1] & 0x0f) << 1); synhw.maximumYCoord = (status[2] << 5) | ((status[1] & 0xf0) >> 3); + } else { + /* + * Typical bezel limits. Taken from 'Synaptics + * PS/2 * TouchPad Interfacing Guide' p.3.2.3. + */ + synhw.maximumXCoord = 5472; + synhw.maximumYCoord = 4448; } + if (synhw.capReportsMin) { if (!set_mouse_scaling(kbdc, 1)) return (FALSE); @@ -4767,6 +5608,13 @@ enable_synaptics(struct psm_softc *sc, enum probearg arg) ((status[1] & 0x0f) << 1); synhw.minimumYCoord = (status[2] << 5) | ((status[1] & 0xf0) >> 3); + } else { + /* + * Typical bezel limits. Taken from 'Synaptics + * PS/2 * TouchPad Interfacing Guide' p.3.2.3. + */ + synhw.minimumXCoord = 1472; + synhw.minimumYCoord = 1408; } if (verbose >= 2) { @@ -4854,7 +5702,8 @@ enable_synaptics(struct psm_softc *sc, enum probearg arg) if (arg == PROBE) { /* Create sysctl tree. */ - synaptics_sysctl_create_tree(sc); + synaptics_sysctl_create_tree(sc, "synaptics", + "Synaptics TouchPad"); sc->hw.buttons = buttons; } @@ -5171,6 +6020,340 @@ enable_versapad(struct psm_softc *sc, enum probearg arg) return (TRUE); /* PS/2 absolute mode */ } +/* Elantech Touchpad */ +static int +elantech_read_1(KBDC kbdc, int hwversion, int reg, int *val) +{ + int res, readcmd, retidx; + int resp[3]; + + readcmd = hwversion == 2 ? ELANTECH_REG_READ : ELANTECH_REG_RDWR; + retidx = hwversion == 4 ? 1 : 0; + + res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; + res |= send_aux_command(kbdc, readcmd) != PSM_ACK; + res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; + res |= send_aux_command(kbdc, reg) != PSM_ACK; + res |= get_mouse_status(kbdc, resp, 0, 3) != 3; + + if (res == 0) + *val = resp[retidx]; + + return (res); +} + +static int +elantech_write_1(KBDC kbdc, int hwversion, int reg, int val) +{ + int res, writecmd; + + writecmd = hwversion == 2 ? ELANTECH_REG_WRITE : ELANTECH_REG_RDWR; + + res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; + res |= send_aux_command(kbdc, writecmd) != PSM_ACK; + res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; + res |= send_aux_command(kbdc, reg) != PSM_ACK; + if (hwversion == 4) { + res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; + res |= send_aux_command(kbdc, writecmd) != PSM_ACK; + } + res |= send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; + res |= send_aux_command(kbdc, val) != PSM_ACK; + res |= set_mouse_scaling(kbdc, 1) == 0; + + return (res); +} + +static int +elantech_cmd(KBDC kbdc, int hwversion, int cmd, int *resp) +{ + int res; + + if (hwversion == 2) { + res = set_mouse_scaling(kbdc, 1) == 0; + res |= mouse_ext_command(kbdc, cmd) == 0; + } else { + res = send_aux_command(kbdc, ELANTECH_CUSTOM_CMD) != PSM_ACK; + res |= send_aux_command(kbdc, cmd) != PSM_ACK; + } + res |= get_mouse_status(kbdc, resp, 0, 3) != 3; + + return (res); +} + +static int +elantech_init(KBDC kbdc, elantechhw_t *elanhw) +{ + int i, val, res, hwversion, reg10; + + /* set absolute mode */ + hwversion = elanhw->hwversion; + reg10 = -1; + switch (hwversion) { + case 2: + reg10 = elanhw->fwversion == 0x020030 ? 0x54 : 0xc4; + res = elantech_write_1(kbdc, hwversion, 0x10, reg10); + if (res) + break; + res = elantech_write_1(kbdc, hwversion, 0x11, 0x8A); + break; + case 3: + reg10 = 0x0b; + res = elantech_write_1(kbdc, hwversion, 0x10, reg10); + break; + case 4: + res = elantech_write_1(kbdc, hwversion, 0x07, 0x01); + break; + default: + res = 1; + } + + /* Read back reg 0x10 to ensure hardware is ready. */ + if (res == 0 && reg10 >= 0) { + for (i = 0; i < 5; i++) { + if (elantech_read_1(kbdc, hwversion, 0x10, &val) == 0) + break; + DELAY(2000); + } + if (i == 5) + res = 1; + } + + if (res) + printf("couldn't set absolute mode\n"); + + return (res); +} + +static void +elantech_init_synaptics(struct psm_softc *sc) +{ + + /* Set capabilites required by movement smother */ + sc->synhw.infoMajor = sc->elanhw.hwversion; + sc->synhw.infoMinor = sc->elanhw.fwversion; + sc->synhw.infoXupmm = sc->elanhw.dpmmx; + sc->synhw.infoYupmm = sc->elanhw.dpmmy; + sc->synhw.verticalScroll = 0; + sc->synhw.nExtendedQueries = 4; + sc->synhw.capExtended = 1; + sc->synhw.capPassthrough = sc->elanhw.hastrackpoint; + sc->synhw.capClickPad = sc->elanhw.isclickpad; + sc->synhw.capMultiFinger = 1; + sc->synhw.capAdvancedGestures = 1; + sc->synhw.capPalmDetect = 1; + sc->synhw.capPen = 0; + sc->synhw.capReportsMax = 1; + sc->synhw.maximumXCoord = sc->elanhw.sizex; + sc->synhw.maximumYCoord = sc->elanhw.sizey; + sc->synhw.capReportsMin = 1; + sc->synhw.minimumXCoord = 0; + sc->synhw.minimumYCoord = 0; + + if (sc->syninfo.sysctl_tree == NULL) { + synaptics_sysctl_create_tree(sc, "elantech", + "Elantech Touchpad"); + + /* + * Adjust synaptic smoother tunables + * 1. Disable finger detection pressure threshold. Unlike + * synaptics we assume the finger is acting when packet with + * its X&Y arrives not when pressure exceedes some threshold + * 2. Disable unrelated features like margins and noisy areas + * 3. Disable virtual scroll areas as 2nd finger is preferable + * 4. For clickpads set bottom quarter as 42% - 16% - 42% sized + * softbuttons + * 5. Scale down divisors and movement lengths by a factor of 3 + * where 3 is Synaptics to Elantech (~2200/800) dpi ratio + */ + + /* Set reporting range to be equal touchpad size */ + sc->syninfo.max_x = sc->elanhw.sizex; + sc->syninfo.max_y = sc->elanhw.sizey; + + /* Disable finger detection pressure threshold */ + sc->syninfo.min_pressure = 1; + + /* Use full area of touchpad */ + sc->syninfo.margin_top = 0; + sc->syninfo.margin_right = 0; + sc->syninfo.margin_bottom = 0; + sc->syninfo.margin_left = 0; + + /* Disable noisy area */ + sc->syninfo.na_top = 0; + sc->syninfo.na_right = 0; + sc->syninfo.na_bottom = 0; + sc->syninfo.na_left = 0; + + /* Tune divisors and movement lengths */ + sc->syninfo.weight_len_squared = 200; + sc->syninfo.div_min = 3; + sc->syninfo.div_max = 6; + sc->syninfo.div_max_na = 10; + sc->syninfo.div_len = 30; + sc->syninfo.tap_max_delta = 25; + + /* Disable virtual scrolling areas and tune its divisors */ + sc->syninfo.vscroll_hor_area = 0; + sc->syninfo.vscroll_ver_area = 0; + sc->syninfo.vscroll_min_delta = 15; + sc->syninfo.vscroll_div_min = 30; + sc->syninfo.vscroll_div_max = 50; + + /* Set bottom quarter as 42% - 16% - 42% sized softbuttons */ + if (sc->elanhw.isclickpad) { + sc->syninfo.softbuttons_y = sc->elanhw.sizey / 4; + sc->syninfo.softbutton2_x = sc->elanhw.sizex * 11 / 25; + sc->syninfo.softbutton3_x = sc->elanhw.sizex * 14 / 25; + } + } + + return; +} + +static int +enable_elantech(struct psm_softc *sc, enum probearg arg) +{ + static const int ic2hw[] = + /*IC: 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + { 0, 0, 2, 0, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0 }; + elantechhw_t elanhw; + int icversion, hwversion, dptracex, dptracey, id, resp[3], dpix, dpiy; + KBDC kbdc = sc->kbdc; + + VLOG(3, (LOG_DEBUG, "elantech: BEGIN init\n")); + + set_mouse_scaling(kbdc, 1); + set_mouse_scaling(kbdc, 1); + set_mouse_scaling(kbdc, 1); + if (get_mouse_status(kbdc, resp, 0, 3) != 3) + return (FALSE); + + if (!ELANTECH_MAGIC(resp)) + return (FALSE); + + /* Identify the Touchpad version. */ + if (elantech_cmd(kbdc, 2, ELANTECH_FW_VERSION, resp)) + return (FALSE); + + bzero(&elanhw, sizeof(elanhw)); + + elanhw.fwversion = (resp[0] << 16) | (resp[1] << 8) | resp[2]; + icversion = resp[0] & 0x0f; + hwversion = ic2hw[icversion]; + + if (verbose >= 2) + printf("Elantech touchpad hardware v.%d firmware v.0x%06x\n", + hwversion, elanhw.fwversion); + + if (ELANTECH_HW_IS_V1(elanhw.fwversion)) { + printf (" Unsupported touchpad hardware (v1)\n"); + return (FALSE); + } + if (hwversion == 0) { + printf (" Unknown touchpad hardware (firmware v.0x%06x)\n", + elanhw.fwversion); + return (FALSE); + } + + /* Get the Touchpad model information. */ + elanhw.hwversion = hwversion; + elanhw.issemimt = hwversion == 2; + elanhw.isclickpad = (resp[1] & 0x10) != 0; + elanhw.hascrc = (resp[1] & 0x40) != 0; + elanhw.haspressure = elanhw.fwversion >= 0x020800; + + /* Read the capability bits. */ + if (elantech_cmd(kbdc, hwversion, ELANTECH_CAPABILITIES, resp) != 0) { + printf(" Failed to read capability bits\n"); + return (FALSE); + } + + elanhw.ntracesx = resp[1] - 1; + elanhw.ntracesy = resp[2] - 1; + elanhw.hastrackpoint = (resp[0] & 0x80) != 0; + + /* Get the touchpad resolution */ + switch (hwversion) { + case 4: + if (elantech_cmd(kbdc, hwversion, ELANTECH_RESOLUTION, resp) + == 0) { + dpix = (resp[1] & 0x0f) * 10 + 790; + dpiy = ((resp[1] & 0xf0) >> 4) * 10 + 790; + elanhw.dpmmx = (dpix * 10 + 5) / 254; + elanhw.dpmmy = (dpiy * 10 + 5) / 254; + break; + } + /* FALLTHROUGH */ + case 2: + case 3: + elanhw.dpmmx = elanhw.dpmmy = 32; /* 800 dpi */ + break; + } + + if (!elantech_support) + return (FALSE); + + if (elantech_init(kbdc, &elanhw)) { + printf("couldn't initialize elantech touchpad\n"); + return (FALSE); + } + + /* + * Get the touchpad reporting range. + * On HW v.3 touchpads it should be done after switching hardware + * to real resolution mode (by setting bit 3 of reg10) + */ + if (elantech_cmd(kbdc, hwversion, ELANTECH_FW_ID, resp) != 0) { + printf(" Failed to read touchpad size\n"); + elanhw.sizex = 10000; /* Arbitrary high values to */ + elanhw.sizey = 10000; /* prevent clipping in smoother */ + } else if (hwversion == 2) { + dptracex = dptracey = 64; + if ((elanhw.fwversion >> 16) == 0x14 && (resp[1] & 0x10) && + !elantech_cmd(kbdc, hwversion, ELANTECH_SAMPLE, resp)) { + dptracex = resp[1] / 2; + dptracey = resp[2] / 2; + } + elanhw.sizex = (elanhw.ntracesx - 1) * dptracex; + elanhw.sizey = (elanhw.ntracesy - 1) * dptracey; + } else { + elanhw.sizex = (resp[0] & 0x0f) << 8 | resp[1]; + elanhw.sizey = (resp[0] & 0xf0) << 4 | resp[2]; + } + + if (verbose >= 2) { + printf(" Model information:\n"); + printf(" MaxX: %d\n", elanhw.sizex); + printf(" MaxY: %d\n", elanhw.sizey); + printf(" DpmmX: %d\n", elanhw.dpmmx); + printf(" DpmmY: %d\n", elanhw.dpmmy); + printf(" TracesX: %d\n", elanhw.ntracesx); + printf(" TracesY: %d\n", elanhw.ntracesy); + printf(" SemiMT: %d\n", elanhw.issemimt); + printf(" Clickpad: %d\n", elanhw.isclickpad); + printf(" Trackpoint: %d\n", elanhw.hastrackpoint); + printf(" CRC: %d\n", elanhw.hascrc); + printf(" Pressure: %d\n", elanhw.haspressure); + } + + VLOG(3, (LOG_DEBUG, "elantech: END init\n")); + + if (arg == PROBE) { + sc->elanhw = elanhw; + sc->hw.buttons = 3; + + /* Initialize synaptics movement smoother */ + elantech_init_synaptics(sc); + + for (id = 0; id < ELANTECH_MAX_FINGERS; id++) + PSM_FINGER_RESET(sc->elanaction.fingers[id]); + } + + return (TRUE); +} + /* * Return true if 'now' is earlier than (start + (secs.usecs)). * Now may be NULL and the function will fetch the current time from diff --git a/sys/sys/mouse.h b/sys/sys/mouse.h index 24d0ffc7a561..9fd1d6d8c085 100644 --- a/sys/sys/mouse.h +++ b/sys/sys/mouse.h @@ -170,6 +170,7 @@ typedef struct synapticshw { #define MOUSE_MODEL_4DPLUS 12 #define MOUSE_MODEL_SYNAPTICS 13 #define MOUSE_MODEL_TRACKPOINT 14 +#define MOUSE_MODEL_ELANTECH 15 typedef struct mousemode { int protocol; /* MOUSE_PROTO_XXX */ @@ -240,6 +241,9 @@ typedef struct mousevar { /* Synaptics Touchpad */ #define MOUSE_SYNAPTICS_PACKETSIZE 6 /* '3' works better */ +/* Elantech Touchpad */ +#define MOUSE_ELANTECH_PACKETSIZE 6 + /* Microsoft Serial mouse data packet */ #define MOUSE_MSS_PACKETSIZE 3 #define MOUSE_MSS_SYNCMASK 0x40 From 4f57f07e373cddc9239e604a50ecca2f85848f4c Mon Sep 17 00:00:00 2001 From: Oleksandr Tymoshenko Date: Mon, 26 Sep 2016 22:07:45 +0000 Subject: [PATCH 35/64] Add Elantech trackpad to the list of known models PR: 205690 Submitted by: Vladimir Kondratyev MFC after: 1 week --- usr.sbin/moused/moused.c | 1 + 1 file changed, 1 insertion(+) diff --git a/usr.sbin/moused/moused.c b/usr.sbin/moused/moused.c index bf0767b1e181..51f2b9a0b627 100644 --- a/usr.sbin/moused/moused.c +++ b/usr.sbin/moused/moused.c @@ -246,6 +246,7 @@ static symtab_t rmodels[] = { { "4D+ Mouse", MOUSE_MODEL_4DPLUS, 0 }, { "Synaptics Touchpad", MOUSE_MODEL_SYNAPTICS, 0 }, { "TrackPoint", MOUSE_MODEL_TRACKPOINT, 0 }, + { "Elantech Touchpad", MOUSE_MODEL_ELANTECH, 0 }, { "generic", MOUSE_MODEL_GENERIC, 0 }, { NULL, MOUSE_MODEL_UNKNOWN, 0 }, }; From 89d7100b1f7606ce6e58cf3df88b182638ea2e3b Mon Sep 17 00:00:00 2001 From: Oleksandr Tymoshenko Date: Mon, 26 Sep 2016 22:08:35 +0000 Subject: [PATCH 36/64] Document hw.psm.elantech_support in psm(4) PR: 205690 Submitted by: Vladimir Kondratyev MFC after: 1 week --- share/man/man4/psm.4 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/share/man/man4/psm.4 b/share/man/man4/psm.4 index df65c2c860b6..f5c9f9053ea5 100644 --- a/share/man/man4/psm.4 +++ b/share/man/man4/psm.4 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 18, 2013 +.Dd September 26, 2016 .Dt PSM 4 .Os .Sh NAME @@ -340,10 +340,12 @@ at boot-time. This will enable .Nm to handle packets from guest devices (sticks) and extra buttons. -Similarly, extended support for IBM/Lenovo TrackPoint can be enabled -by setting +Similarly, extended support for IBM/Lenovo TrackPoint and Elantech touchpads +can be enabled by setting .Va hw.psm.trackpoint_support -to +or +.Va hw.psm.elantech_support, +respectively, to .Em 1 at boot-time. .Pp From 1e6afa0eaf695245847715dd4d187c4a830bdabb Mon Sep 17 00:00:00 2001 From: Justin Hibbits Date: Tue, 27 Sep 2016 00:53:41 +0000 Subject: [PATCH 37/64] Add NXP/Freescale DIU driver for PowerPC SoCs Summary: This enables some features of the DIU, using a static configuration, specified either via a 'edid' property on the 'display' FDT node, or a 'video-mode' environment variable (bootarg). 'video-mode' was chosen because it matches u-boot's naming, so it can be set with: setenv bootargs video-mode=${video-mode} at the u-boot CLI. Mouse cursor is not supported currently, as a hardware cursor is not supported by framebuffer VT yet. Currently it only supports a 32bpp ARGB (actually BGRA) format, and only a single composite plane, at up to 1280x1024. Differential Revision: https://reviews.freebsd.org/D8022 --- sys/conf/files.powerpc | 1 + sys/powerpc/conf/MPC85XX | 4 + sys/powerpc/mpc85xx/fsl_diu.c | 479 ++++++++++++++++++++++++++++++++++ sys/powerpc/mpc85xx/mpc85xx.h | 7 + 4 files changed, 491 insertions(+) create mode 100644 sys/powerpc/mpc85xx/fsl_diu.c diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index 0a8a05db85a5..aee0a1022b9c 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -135,6 +135,7 @@ powerpc/mikrotik/platform_rb.c optional mikrotik powerpc/mpc85xx/atpic.c optional mpc85xx isa powerpc/mpc85xx/ds1553_bus_fdt.c optional ds1553 fdt powerpc/mpc85xx/ds1553_core.c optional ds1553 +powerpc/mpc85xx/fsl_diu.c optional mpc85xx diu powerpc/mpc85xx/fsl_sdhc.c optional mpc85xx sdhc powerpc/mpc85xx/i2c.c optional iicbus fdt powerpc/mpc85xx/isa.c optional mpc85xx isa diff --git a/sys/powerpc/conf/MPC85XX b/sys/powerpc/conf/MPC85XX index 6cd84ef86ad5..97464e84949c 100644 --- a/sys/powerpc/conf/MPC85XX +++ b/sys/powerpc/conf/MPC85XX @@ -93,3 +93,7 @@ device ehci device umass device usb device vlan + +# P1022 DIU +device diu +device videomode diff --git a/sys/powerpc/mpc85xx/fsl_diu.c b/sys/powerpc/mpc85xx/fsl_diu.c new file mode 100644 index 000000000000..da9fe4251ede --- /dev/null +++ b/sys/powerpc/mpc85xx/fsl_diu.c @@ -0,0 +1,479 @@ +/*- + * Copyright (c) 2015 Justin Hibbits + * 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 + +#include +#include + +#include +#include + +#include + +#include "gpio_if.h" + +#include +#include + +#include "fb_if.h" + +#define DIU_DESC_1 0x000 /* Plane1 Area Descriptor Pointer Register */ +#define DIU_DESC_2 0x004 /* Plane2 Area Descriptor Pointer Register */ +#define DIU_DESC_3 0x008 /* Plane3 Area Descriptor Pointer Register */ +#define DIU_GAMMA 0x00C /* Gamma Register */ +#define DIU_PALETTE 0x010 /* Palette Register */ +#define DIU_CURSOR 0x014 /* Cursor Register */ +#define DIU_CURS_POS 0x018 /* Cursor Position Register */ +#define CURSOR_Y_SHIFT 16 +#define CURSOR_X_SHIFT 0 +#define DIU_DIU_MODE 0x01C /* DIU4 Mode */ +#define DIU_MODE_M 0x7 +#define DIU_MODE_S 0 +#define DIU_MODE_NORMAL 0x1 +#define DIU_MODE_2 0x2 +#define DIU_MODE_3 0x3 +#define DIU_MODE_COLBAR 0x4 +#define DIU_BGND 0x020 /* Background */ +#define DIU_BGND_WB 0x024 /* Background Color in write back Mode Register */ +#define DIU_DISP_SIZE 0x028 /* Display Size */ +#define DELTA_Y_S 16 +#define DELTA_X_S 0 +#define DIU_WB_SIZE 0x02C /* Write back Plane Size Register */ +#define DELTA_Y_WB_S 16 +#define DELTA_X_WB_S 0 +#define DIU_WB_MEM_ADDR 0x030 /* Address to Store the write back Plane Register */ +#define DIU_HSYN_PARA 0x034 /* Horizontal Sync Parameter */ +#define BP_H_SHIFT 22 +#define PW_H_SHIFT 11 +#define FP_H_SHIFT 0 +#define DIU_VSYN_PARA 0x038 /* Vertical Sync Parameter */ +#define BP_V_SHIFT 22 +#define PW_V_SHIFT 11 +#define FP_V_SHIFT 0 +#define DIU_SYNPOL 0x03C /* Synchronize Polarity */ +#define BP_VS (1 << 4) +#define BP_HS (1 << 3) +#define INV_CS (1 << 2) +#define INV_VS (1 << 1) +#define INV_HS (1 << 0) +#define INV_PDI_VS (1 << 8) /* Polarity of PDI input VSYNC. */ +#define INV_PDI_HS (1 << 9) /* Polarity of PDI input HSYNC. */ +#define INV_PDI_DE (1 << 10) /* Polarity of PDI input DE. */ +#define DIU_THRESHOLD 0x040 /* Threshold */ +#define LS_BF_VS_SHIFT 16 +#define OUT_BUF_LOW_SHIFT 0 +#define DIU_INT_STATUS 0x044 /* Interrupt Status */ +#define DIU_INT_MASK 0x048 /* Interrupt Mask */ +#define DIU_COLBAR_1 0x04C /* COLBAR_1 */ +#define DIU_COLORBARn_R(x) ((x & 0xff) << 16) +#define DIU_COLORBARn_G(x) ((x & 0xff) << 8) +#define DIU_COLORBARn_B(x) ((x & 0xff) << 0) +#define DIU_COLBAR_2 0x050 /* COLBAR_2 */ +#define DIU_COLBAR_3 0x054 /* COLBAR_3 */ +#define DIU_COLBAR_4 0x058 /* COLBAR_4 */ +#define DIU_COLBAR_5 0x05c /* COLBAR_5 */ +#define DIU_COLBAR_6 0x060 /* COLBAR_6 */ +#define DIU_COLBAR_7 0x064 /* COLBAR_7 */ +#define DIU_COLBAR_8 0x068 /* COLBAR_8 */ +#define DIU_FILLING 0x06C /* Filling Register */ +#define DIU_PLUT 0x070 /* Priority Look Up Table Register */ + +/* Control Descriptor */ +#define DIU_CTRLDESCL(n, m) 0x200 + (0x40 * n) + 0x4 * (m - 1) +#define DIU_CTRLDESCLn_1(n) DIU_CTRLDESCL(n, 1) +#define DIU_CTRLDESCLn_2(n) DIU_CTRLDESCL(n, 2) +#define DIU_CTRLDESCLn_3(n) DIU_CTRLDESCL(n, 3) +#define TRANS_SHIFT 20 +#define DIU_CTRLDESCLn_4(n) DIU_CTRLDESCL(n, 4) +#define BPP_MASK 0xf /* Bit per pixel Mask */ +#define BPP_SHIFT 16 /* Bit per pixel Shift */ +#define BPP24 0x5 +#define EN_LAYER (1 << 31) /* Enable the layer */ +#define DIU_CTRLDESCLn_5(n) DIU_CTRLDESCL(n, 5) +#define DIU_CTRLDESCLn_6(n) DIU_CTRLDESCL(n, 6) +#define DIU_CTRLDESCLn_7(n) DIU_CTRLDESCL(n, 7) +#define DIU_CTRLDESCLn_8(n) DIU_CTRLDESCL(n, 8) +#define DIU_CTRLDESCLn_9(n) DIU_CTRLDESCL(n, 9) + +#define NUM_LAYERS 1 + +struct panel_info { + uint32_t panel_width; + uint32_t panel_height; + uint32_t panel_hbp; + uint32_t panel_hpw; + uint32_t panel_hfp; + uint32_t panel_vbp; + uint32_t panel_vpw; + uint32_t panel_vfp; + uint32_t panel_freq; + uint32_t clk_div; +}; + +struct diu_area_descriptor { + uint32_t pixel_format; + uint32_t bitmap_address; + uint32_t source_size; + uint32_t aoi_size; + uint32_t aoi_offset; + uint32_t display_offset; + uint32_t chroma_key_max; + uint32_t chroma_key_min; + uint32_t next_ad_addr; +} __aligned(32); + +struct diu_softc { + struct resource *res[2]; + void *ih; + device_t sc_dev; + device_t sc_fbd; /* fbd child */ + struct fb_info sc_info; + struct panel_info sc_panel; + struct diu_area_descriptor *sc_planes[3]; + uint8_t *sc_gamma; + uint8_t *sc_cursor; +}; + +static struct resource_spec diu_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { -1, 0 } +}; + +static int +diu_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "fsl,diu")) + return (ENXIO); + + device_set_desc(dev, "Freescale Display Interface Unit"); + return (BUS_PROBE_DEFAULT); +} + +static void +diu_intr(void *arg) +{ + struct diu_softc *sc; + int reg; + + sc = arg; + + /* Ack interrupts */ + reg = bus_read_4(sc->res[0], DIU_INT_STATUS); + bus_write_4(sc->res[0], DIU_INT_STATUS, reg); + + /* TODO interrupt handler */ +} + +static int +diu_set_pxclk(device_t dev, unsigned int freq) +{ + phandle_t node; + unsigned long bus_freq; + uint32_t pxclk_set; + uint32_t clkdvd; + int res; + + node = ofw_bus_get_node(device_get_parent(dev)); + if ((res = OF_getencprop(node, "bus-frequency", + (pcell_t *)&bus_freq, sizeof(bus_freq)) <= 0)) { + device_printf(dev, "Unable to get bus frequency\n"); + return (ENXIO); + } + + /* freq is in kHz */ + freq *= 1000; + /* adding freq/2 to round-to-closest */ + pxclk_set = min(max((bus_freq + freq/2) / freq, 2), 255) << 16; + pxclk_set |= OCP85XX_CLKDVDR_PXCKEN; + clkdvd = ccsr_read4(OCP85XX_CLKDVDR); + clkdvd &= ~(OCP85XX_CLKDVDR_PXCKEN | OCP85XX_CLKDVDR_PXCKINV | + OCP85XX_CLKDVDR_PXCLK_MASK); + ccsr_write4(OCP85XX_CLKDVDR, clkdvd); + ccsr_write4(OCP85XX_CLKDVDR, clkdvd | pxclk_set); + + return (0); +} + +static int +diu_init(struct diu_softc *sc) +{ + struct panel_info *panel; + int reg; + + panel = &sc->sc_panel; + + /* Temporarily disable the DIU while configuring */ + reg = bus_read_4(sc->res[0], DIU_DIU_MODE); + reg &= ~(DIU_MODE_M << DIU_MODE_S); + bus_write_4(sc->res[0], DIU_DIU_MODE, reg); + + if (diu_set_pxclk(sc->sc_dev, panel->panel_freq) < 0) { + return (ENXIO); + } + + /* Configure DIU */ + /* Need to set these somehow later... */ + bus_write_4(sc->res[0], DIU_GAMMA, vtophys(sc->sc_gamma)); + bus_write_4(sc->res[0], DIU_CURSOR, vtophys(sc->sc_cursor)); + bus_write_4(sc->res[0], DIU_CURS_POS, 0); + + reg = ((sc->sc_info.fb_height) << DELTA_Y_S); + reg |= sc->sc_info.fb_width; + bus_write_4(sc->res[0], DIU_DISP_SIZE, reg); + + reg = (panel->panel_hbp << BP_H_SHIFT); + reg |= (panel->panel_hpw << PW_H_SHIFT); + reg |= (panel->panel_hfp << FP_H_SHIFT); + bus_write_4(sc->res[0], DIU_HSYN_PARA, reg); + + reg = (panel->panel_vbp << BP_V_SHIFT); + reg |= (panel->panel_vpw << PW_V_SHIFT); + reg |= (panel->panel_vfp << FP_V_SHIFT); + bus_write_4(sc->res[0], DIU_VSYN_PARA, reg); + + bus_write_4(sc->res[0], DIU_BGND, 0); + + /* Mask all the interrupts */ + bus_write_4(sc->res[0], DIU_INT_MASK, 0x3f); + + /* Reset all layers */ + sc->sc_planes[0] = contigmalloc(sizeof(struct diu_area_descriptor), + M_DEVBUF, M_ZERO, 0, BUS_SPACE_MAXADDR_32BIT, 32, 0); + bus_write_4(sc->res[0], DIU_DESC_1, vtophys(sc->sc_planes[0])); + bus_write_4(sc->res[0], DIU_DESC_2, 0); + bus_write_4(sc->res[0], DIU_DESC_3, 0); + + /* Setup first plane */ + /* Area descriptor fields are little endian, so byte swap. */ + /* Word 0: Pixel format */ + /* Set to 8:8:8:8 ARGB, 4 bytes per pixel, no flip. */ +#define MAKE_PXLFMT(as,rs,gs,bs,a,r,g,b,f,s) \ + htole32((as << (4 * a)) | (rs << 4 * r) | \ + (gs << 4 * g) | (bs << 4 * b) | \ + (f << 28) | (s << 16) | \ + (a << 25) | (r << 19) | \ + (g << 21) | (b << 24)) + reg = MAKE_PXLFMT(8, 8, 8, 8, 3, 2, 1, 0, 1, 3); + sc->sc_planes[0]->pixel_format = reg; + /* Word 1: Bitmap address */ + sc->sc_planes[0]->bitmap_address = htole32(sc->sc_info.fb_pbase); + /* Word 2: Source size/global alpha */ + reg = (sc->sc_info.fb_width | (sc->sc_info.fb_height << 12)); + sc->sc_planes[0]->source_size = htole32(reg); + /* Word 3: AOI Size */ + reg = (sc->sc_info.fb_width | (sc->sc_info.fb_height << 16)); + sc->sc_planes[0]->aoi_size = htole32(reg); + /* Word 4: AOI Offset */ + sc->sc_planes[0]->aoi_offset = 0; + /* Word 5: Display offset */ + sc->sc_planes[0]->display_offset = 0; + /* Word 6: Chroma key max */ + sc->sc_planes[0]->chroma_key_max = 0; + /* Word 7: Chroma key min */ + reg = 255 << 16 | 255 << 8 | 255; + sc->sc_planes[0]->chroma_key_min = htole32(reg); + /* Word 8: Next AD */ + sc->sc_planes[0]->next_ad_addr = 0; + + /* TODO: derive this from the panel size */ + bus_write_4(sc->res[0], DIU_PLUT, 0x1f5f666); + + /* Enable DIU in normal mode */ + reg = bus_read_4(sc->res[0], DIU_DIU_MODE); + reg &= ~(DIU_MODE_M << DIU_MODE_S); + reg |= (DIU_MODE_NORMAL << DIU_MODE_S); + bus_write_4(sc->res[0], DIU_DIU_MODE, reg); + + return (0); +} + +static int +diu_attach(device_t dev) +{ + struct edid_info *edid; + struct diu_softc *sc; + const struct videomode *videomode; + void *edid_cells; + const char *vm_name; + phandle_t node; + int h, r, w; + int err, i; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + if (bus_alloc_resources(dev, diu_spec, sc->res)) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + node = ofw_bus_get_node(dev); + /* Setup interrupt handler */ + err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE, + NULL, diu_intr, sc, &sc->ih); + if (err) { + device_printf(dev, "Unable to alloc interrupt resource.\n"); + return (ENXIO); + } + + /* TODO: Eventually, allow EDID to be dynamically provided. */ + if (OF_getprop_alloc(node, "edid", 1, &edid_cells) <= 0) { + /* + * u-boot uses the environment variable name 'video-mode', so + * just use the same name here. Should allow another variable + * that better fits our design model, but this is fine. + */ + if ((vm_name = kern_getenv("video-mode")) == NULL) { + device_printf(dev, + "No EDID data and no video-mode env set\n"); + return (ENXIO); + } + } + if (edid_cells != NULL) { + if (edid_parse(edid_cells, edid) != 0) { + device_printf(dev, "Error parsing EDID\n"); + OF_prop_free(edid_cells); + return (ENXIO); + } + videomode = edid->edid_preferred_mode; + } else { + /* Parse video-mode kenv variable. */ + if ((err = sscanf(vm_name, "fslfb:%dx%d@%d", &w, &h, &r)) != 3) { + device_printf(dev, + "Cannot parse video mode: %s\n", vm_name); + return (ENXIO); + } + videomode = pick_mode_by_ref(w, h, r); + if (videomode == NULL) { + device_printf(dev, + "Cannot find mode for %dx%d@%d", w, h, r); + return (ENXIO); + } + } + + sc->sc_panel.panel_width = videomode->hdisplay; + sc->sc_panel.panel_height = videomode->vdisplay; + sc->sc_panel.panel_hbp = videomode->hsync_start - videomode->hdisplay; + sc->sc_panel.panel_hfp = videomode->htotal - videomode->hsync_end; + sc->sc_panel.panel_hpw = videomode->hsync_end - videomode->hsync_start; + sc->sc_panel.panel_vbp = videomode->vsync_start - videomode->vdisplay; + sc->sc_panel.panel_vfp = videomode->vtotal - videomode->vsync_end; + sc->sc_panel.panel_vpw = videomode->vsync_end - videomode->vsync_start; + sc->sc_panel.panel_freq = videomode->dot_clock; + + sc->sc_info.fb_width = sc->sc_panel.panel_width; + sc->sc_info.fb_height = sc->sc_panel.panel_height; + sc->sc_info.fb_stride = sc->sc_info.fb_width * 4; + sc->sc_info.fb_bpp = sc->sc_info.fb_depth = 32; + sc->sc_info.fb_size = sc->sc_info.fb_height * sc->sc_info.fb_stride; + sc->sc_info.fb_vbase = (intptr_t)contigmalloc(sc->sc_info.fb_size, + M_DEVBUF, M_ZERO, 0, BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, 0); + sc->sc_info.fb_pbase = (intptr_t)vtophys(sc->sc_info.fb_vbase); + + /* Gamma table is 3 consecutive segments of 256 bytes. */ + sc->sc_gamma = contigmalloc(3 * 256, M_DEVBUF, 0, 0, + BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, 0); + /* Initialize gamma to default */ + for (i = 0; i < 3 * 256; i++) + sc->sc_gamma[i] = (i % 256); + + /* Cursor format is 32x32x16bpp */ + sc->sc_cursor = contigmalloc(32 * 32 * 2, M_DEVBUF, M_ZERO, 0, + BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, 0); + + diu_init(sc); + + sc->sc_info.fb_name = device_get_nameunit(dev); + + /* Ask newbus to attach framebuffer device to me. */ + sc->sc_fbd = device_add_child(dev, "fbd", device_get_unit(dev)); + if (sc->sc_fbd == NULL) + device_printf(dev, "Can't attach fbd device\n"); + + if ((err = device_probe_and_attach(sc->sc_fbd)) != 0) { + device_printf(dev, "Failed to attach fbd device: %d\n", err); + } + + return (0); +} + +static struct fb_info * +diu_fb_getinfo(device_t dev) +{ + struct diu_softc *sc = device_get_softc(dev); + + return (&sc->sc_info); +} + +static device_method_t diu_methods[] = { + DEVMETHOD(device_probe, diu_probe), + DEVMETHOD(device_attach, diu_attach), + + /* Framebuffer service methods */ + DEVMETHOD(fb_getinfo, diu_fb_getinfo), + { 0, 0 } +}; + +static driver_t diu_driver = { + "fb", + diu_methods, + sizeof(struct diu_softc), +}; + +static devclass_t diu_devclass; + +DRIVER_MODULE(fb, simplebus, diu_driver, diu_devclass, 0, 0); diff --git a/sys/powerpc/mpc85xx/mpc85xx.h b/sys/powerpc/mpc85xx/mpc85xx.h index e81e12546933..697533b40af7 100644 --- a/sys/powerpc/mpc85xx/mpc85xx.h +++ b/sys/powerpc/mpc85xx/mpc85xx.h @@ -139,6 +139,13 @@ extern vm_offset_t ccsrbar_va; */ #define OCP85XX_RSTCR (CCSRBAR_VA + 0xe00b0) +#define OCP85XX_CLKDVDR (CCSRBAR_VA + 0xe0800) +#define OCP85XX_CLKDVDR_PXCKEN 0x80000000 +#define OCP85XX_CLKDVDR_SSICKEN 0x20000000 +#define OCP85XX_CLKDVDR_PXCKINV 0x10000000 +#define OCP85XX_CLKDVDR_PXCLK_MASK 0x00FF0000 +#define OCP85XX_CLKDVDR_SSICLK_MASK 0x000000FF + /* * Run Control/Power Management Registers. */ From 4d6e19e457ac4d60c8c8a6b9e1df4d36828a5fe5 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Tue, 27 Sep 2016 06:00:10 +0000 Subject: [PATCH 38/64] pci: Clear the MEM/PORT_EN bit when updating PCI BAR It's unsafe to update the BAR when the related EN bit is set. Submitted by: Dexuan Cui Reviewed by: jhb MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7914 --- sys/dev/pci/pci.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 665f62e0911e..8de548f0e2cc 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -5000,6 +5000,7 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid, struct resource_list *rl = &dinfo->resources; struct resource *res; struct pci_map *pm; + uint16_t cmd; pci_addr_t map, testval; int mapsize; @@ -5089,8 +5090,17 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid, device_printf(child, "Lazy allocation of %#jx bytes rid %#x type %d at %#jx\n", count, *rid, type, rman_get_start(res)); + + /* Disable decoding via the CMD register before updating the BAR */ + cmd = pci_read_config(child, PCIR_COMMAND, 2); + pci_write_config(child, PCIR_COMMAND, + cmd & ~(PCI_BAR_MEM(map) ? PCIM_CMD_MEMEN : PCIM_CMD_PORTEN), 2); + map = rman_get_start(res); pci_write_bar(child, pm, map); + + /* Restore the original value of the CMD register */ + pci_write_config(child, PCIR_COMMAND, cmd, 2); out: return (res); } From 9f06037b0d09891884d7b6e1a761268a5b12d307 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Tue, 27 Sep 2016 06:30:24 +0000 Subject: [PATCH 39/64] hyperv/vmbus: Add dynamic device add and remove support MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D8008 --- sys/dev/hyperv/vmbus/vmbus.c | 153 +++++----- sys/dev/hyperv/vmbus/vmbus_chan.c | 425 ++++++++++++++++++++------- sys/dev/hyperv/vmbus/vmbus_chanvar.h | 14 +- sys/dev/hyperv/vmbus/vmbus_var.h | 13 +- 4 files changed, 421 insertions(+), 184 deletions(-) diff --git a/sys/dev/hyperv/vmbus/vmbus.c b/sys/dev/hyperv/vmbus/vmbus.c index 6753c9e9b524..d9cb81ba3f66 100644 --- a/sys/dev/hyperv/vmbus/vmbus.c +++ b/sys/dev/hyperv/vmbus/vmbus.c @@ -83,9 +83,7 @@ static int vmbus_connect(struct vmbus_softc *, uint32_t); static int vmbus_req_channels(struct vmbus_softc *sc); static void vmbus_disconnect(struct vmbus_softc *); static int vmbus_scan(struct vmbus_softc *); -static void vmbus_scan_wait(struct vmbus_softc *); -static void vmbus_scan_newchan(struct vmbus_softc *); -static void vmbus_scan_newdev(struct vmbus_softc *); +static void vmbus_scan_teardown(struct vmbus_softc *); static void vmbus_scan_done(struct vmbus_softc *, const struct vmbus_message *); static void vmbus_chanmsg_handle(struct vmbus_softc *, @@ -393,50 +391,22 @@ vmbus_req_channels(struct vmbus_softc *sc) } static void -vmbus_scan_newchan(struct vmbus_softc *sc) +vmbus_scan_done_task(void *xsc, int pending __unused) { - mtx_lock(&sc->vmbus_scan_lock); - if ((sc->vmbus_scan_chcnt & VMBUS_SCAN_CHCNT_DONE) == 0) - sc->vmbus_scan_chcnt++; - mtx_unlock(&sc->vmbus_scan_lock); + struct vmbus_softc *sc = xsc; + + mtx_lock(&Giant); + sc->vmbus_scandone = true; + mtx_unlock(&Giant); + wakeup(&sc->vmbus_scandone); } static void vmbus_scan_done(struct vmbus_softc *sc, const struct vmbus_message *msg __unused) { - mtx_lock(&sc->vmbus_scan_lock); - sc->vmbus_scan_chcnt |= VMBUS_SCAN_CHCNT_DONE; - mtx_unlock(&sc->vmbus_scan_lock); - wakeup(&sc->vmbus_scan_chcnt); -} -static void -vmbus_scan_newdev(struct vmbus_softc *sc) -{ - mtx_lock(&sc->vmbus_scan_lock); - sc->vmbus_scan_devcnt++; - mtx_unlock(&sc->vmbus_scan_lock); - wakeup(&sc->vmbus_scan_devcnt); -} - -static void -vmbus_scan_wait(struct vmbus_softc *sc) -{ - uint32_t chancnt; - - mtx_lock(&sc->vmbus_scan_lock); - while ((sc->vmbus_scan_chcnt & VMBUS_SCAN_CHCNT_DONE) == 0) { - mtx_sleep(&sc->vmbus_scan_chcnt, &sc->vmbus_scan_lock, 0, - "waitch", 0); - } - chancnt = sc->vmbus_scan_chcnt & ~VMBUS_SCAN_CHCNT_DONE; - - while (sc->vmbus_scan_devcnt != chancnt) { - mtx_sleep(&sc->vmbus_scan_devcnt, &sc->vmbus_scan_lock, 0, - "waitdev", 0); - } - mtx_unlock(&sc->vmbus_scan_lock); + taskqueue_enqueue(sc->vmbus_devtq, &sc->vmbus_scandone_task); } static int @@ -444,6 +414,30 @@ vmbus_scan(struct vmbus_softc *sc) { int error; + /* + * Identify, probe and attach for non-channel devices. + */ + bus_generic_probe(sc->vmbus_dev); + bus_generic_attach(sc->vmbus_dev); + + /* + * This taskqueue serializes vmbus devices' attach and detach + * for channel offer and rescind messages. + */ + sc->vmbus_devtq = taskqueue_create("vmbus dev", M_WAITOK, + taskqueue_thread_enqueue, &sc->vmbus_devtq); + taskqueue_start_threads(&sc->vmbus_devtq, 1, PI_NET, "vmbusdev"); + TASK_INIT(&sc->vmbus_scandone_task, 0, vmbus_scan_done_task, sc); + + /* + * This taskqueue handles sub-channel detach, so that vmbus + * device's detach running in vmbus_devtq can drain its sub- + * channels. + */ + sc->vmbus_subchtq = taskqueue_create("vmbus subch", M_WAITOK, + taskqueue_thread_enqueue, &sc->vmbus_subchtq); + taskqueue_start_threads(&sc->vmbus_subchtq, 1, PI_NET, "vmbussch"); + /* * Start vmbus scanning. */ @@ -451,25 +445,41 @@ vmbus_scan(struct vmbus_softc *sc) if (error) { device_printf(sc->vmbus_dev, "channel request failed: %d\n", error); - return error; + return (error); } /* - * Wait for all devices are added to vmbus. + * Wait for all vmbus devices from the initial channel offers to be + * attached. */ - vmbus_scan_wait(sc); - - /* - * Identify, probe and attach. - */ - bus_generic_probe(sc->vmbus_dev); - bus_generic_attach(sc->vmbus_dev); + GIANT_REQUIRED; + while (!sc->vmbus_scandone) + mtx_sleep(&sc->vmbus_scandone, &Giant, 0, "vmbusdev", 0); if (bootverbose) { device_printf(sc->vmbus_dev, "device scan, probe and attach " "done\n"); } - return 0; + return (0); +} + +static void +vmbus_scan_teardown(struct vmbus_softc *sc) +{ + + GIANT_REQUIRED; + if (sc->vmbus_devtq != NULL) { + mtx_unlock(&Giant); + taskqueue_free(sc->vmbus_devtq); + mtx_lock(&Giant); + sc->vmbus_devtq = NULL; + } + if (sc->vmbus_subchtq != NULL) { + mtx_unlock(&Giant); + taskqueue_free(sc->vmbus_subchtq); + mtx_lock(&Giant); + sc->vmbus_subchtq = NULL; + } } static void @@ -918,45 +928,35 @@ vmbus_add_child(struct vmbus_channel *chan) { struct vmbus_softc *sc = chan->ch_vmbus; device_t parent = sc->vmbus_dev; - int error = 0; - /* New channel has been offered */ - vmbus_scan_newchan(sc); + mtx_lock(&Giant); chan->ch_dev = device_add_child(parent, NULL, -1); if (chan->ch_dev == NULL) { + mtx_unlock(&Giant); device_printf(parent, "device_add_child for chan%u failed\n", chan->ch_id); - error = ENXIO; - goto done; + return (ENXIO); } device_set_ivars(chan->ch_dev, chan); + device_probe_and_attach(chan->ch_dev); -done: - /* New device has been/should be added to vmbus. */ - vmbus_scan_newdev(sc); - return error; + mtx_unlock(&Giant); + return (0); } int vmbus_delete_child(struct vmbus_channel *chan) { - int error; + int error = 0; - if (chan->ch_dev == NULL) { - /* Failed to add a device. */ - return 0; - } - - /* - * XXXKYS: Ensure that this is the opposite of - * device_add_child() - */ mtx_lock(&Giant); - error = device_delete_child(chan->ch_vmbus->vmbus_dev, chan->ch_dev); + if (chan->ch_dev != NULL) { + error = device_delete_child(chan->ch_vmbus->vmbus_dev, + chan->ch_dev); + } mtx_unlock(&Giant); - - return error; + return (error); } static int @@ -1028,10 +1028,11 @@ vmbus_doattach(struct vmbus_softc *sc) return (0); sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; - mtx_init(&sc->vmbus_scan_lock, "vmbus scan", NULL, MTX_DEF); sc->vmbus_gpadl = VMBUS_GPADL_START; mtx_init(&sc->vmbus_prichan_lock, "vmbus prichan", NULL, MTX_DEF); TAILQ_INIT(&sc->vmbus_prichans); + mtx_init(&sc->vmbus_chan_lock, "vmbus channel", NULL, MTX_DEF); + TAILQ_INIT(&sc->vmbus_chans); sc->vmbus_chmap = malloc( sizeof(struct vmbus_channel *) * VMBUS_CHAN_MAX, M_DEVBUF, M_WAITOK | M_ZERO); @@ -1095,6 +1096,7 @@ vmbus_doattach(struct vmbus_softc *sc) return (ret); cleanup: + vmbus_scan_teardown(sc); vmbus_intr_teardown(sc); vmbus_dma_free(sc); if (sc->vmbus_xc != NULL) { @@ -1102,8 +1104,8 @@ vmbus_doattach(struct vmbus_softc *sc) sc->vmbus_xc = NULL; } free(sc->vmbus_chmap, M_DEVBUF); - mtx_destroy(&sc->vmbus_scan_lock); mtx_destroy(&sc->vmbus_prichan_lock); + mtx_destroy(&sc->vmbus_chan_lock); return (ret); } @@ -1146,8 +1148,11 @@ vmbus_detach(device_t dev) { struct vmbus_softc *sc = device_get_softc(dev); + bus_generic_detach(dev); vmbus_chan_destroy_all(sc); + vmbus_scan_teardown(sc); + vmbus_disconnect(sc); if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) { @@ -1164,8 +1169,8 @@ vmbus_detach(device_t dev) } free(sc->vmbus_chmap, M_DEVBUF); - mtx_destroy(&sc->vmbus_scan_lock); mtx_destroy(&sc->vmbus_prichan_lock); + mtx_destroy(&sc->vmbus_chan_lock); return (0); } diff --git a/sys/dev/hyperv/vmbus/vmbus_chan.c b/sys/dev/hyperv/vmbus/vmbus_chan.c index cfc71211782d..1cd9d3719de1 100644 --- a/sys/dev/hyperv/vmbus/vmbus_chan.c +++ b/sys/dev/hyperv/vmbus/vmbus_chan.c @@ -59,10 +59,30 @@ static struct vmbus_channel *vmbus_chan_alloc(struct vmbus_softc *); static void vmbus_chan_free(struct vmbus_channel *); static int vmbus_chan_add(struct vmbus_channel *); static void vmbus_chan_cpu_default(struct vmbus_channel *); +static int vmbus_chan_release(struct vmbus_channel *); +static void vmbus_chan_set_chmap(struct vmbus_channel *); +static void vmbus_chan_clear_chmap(struct vmbus_channel *); + +static void vmbus_chan_ins_prilist(struct vmbus_softc *, + struct vmbus_channel *); +static void vmbus_chan_rem_prilist(struct vmbus_softc *, + struct vmbus_channel *); +static void vmbus_chan_ins_list(struct vmbus_softc *, + struct vmbus_channel *); +static void vmbus_chan_rem_list(struct vmbus_softc *, + struct vmbus_channel *); +static void vmbus_chan_ins_sublist(struct vmbus_channel *, + struct vmbus_channel *); +static void vmbus_chan_rem_sublist(struct vmbus_channel *, + struct vmbus_channel *); static void vmbus_chan_task(void *, int); static void vmbus_chan_task_nobatch(void *, int); -static void vmbus_chan_detach_task(void *, int); +static void vmbus_chan_clrchmap_task(void *, int); +static void vmbus_prichan_attach_task(void *, int); +static void vmbus_subchan_attach_task(void *, int); +static void vmbus_prichan_detach_task(void *, int); +static void vmbus_subchan_detach_task(void *, int); static void vmbus_chan_msgproc_choffer(struct vmbus_softc *, const struct vmbus_message *); @@ -96,6 +116,83 @@ vmbus_chan_signal_tx(const struct vmbus_channel *chan) hypercall_signal_event(chan->ch_monprm_dma.hv_paddr); } +static void +vmbus_chan_ins_prilist(struct vmbus_softc *sc, struct vmbus_channel *chan) +{ + + mtx_assert(&sc->vmbus_prichan_lock, MA_OWNED); + if (atomic_testandset_int(&chan->ch_stflags, + VMBUS_CHAN_ST_ONPRIL_SHIFT)) + panic("channel is already on the prilist"); + TAILQ_INSERT_TAIL(&sc->vmbus_prichans, chan, ch_prilink); +} + +static void +vmbus_chan_rem_prilist(struct vmbus_softc *sc, struct vmbus_channel *chan) +{ + + mtx_assert(&sc->vmbus_prichan_lock, MA_OWNED); + if (atomic_testandclear_int(&chan->ch_stflags, + VMBUS_CHAN_ST_ONPRIL_SHIFT) == 0) + panic("channel is not on the prilist"); + TAILQ_REMOVE(&sc->vmbus_prichans, chan, ch_prilink); +} + +static void +vmbus_chan_ins_sublist(struct vmbus_channel *prichan, + struct vmbus_channel *chan) +{ + + mtx_assert(&prichan->ch_subchan_lock, MA_OWNED); + + if (atomic_testandset_int(&chan->ch_stflags, + VMBUS_CHAN_ST_ONSUBL_SHIFT)) + panic("channel is already on the sublist"); + TAILQ_INSERT_TAIL(&prichan->ch_subchans, chan, ch_sublink); + + /* Bump sub-channel count. */ + prichan->ch_subchan_cnt++; +} + +static void +vmbus_chan_rem_sublist(struct vmbus_channel *prichan, + struct vmbus_channel *chan) +{ + + mtx_assert(&prichan->ch_subchan_lock, MA_OWNED); + + KASSERT(prichan->ch_subchan_cnt > 0, + ("invalid subchan_cnt %d", prichan->ch_subchan_cnt)); + prichan->ch_subchan_cnt--; + + if (atomic_testandclear_int(&chan->ch_stflags, + VMBUS_CHAN_ST_ONSUBL_SHIFT) == 0) + panic("channel is not on the sublist"); + TAILQ_REMOVE(&prichan->ch_subchans, chan, ch_sublink); +} + +static void +vmbus_chan_ins_list(struct vmbus_softc *sc, struct vmbus_channel *chan) +{ + + mtx_assert(&sc->vmbus_chan_lock, MA_OWNED); + if (atomic_testandset_int(&chan->ch_stflags, + VMBUS_CHAN_ST_ONLIST_SHIFT)) + panic("channel is already on the list"); + TAILQ_INSERT_TAIL(&sc->vmbus_chans, chan, ch_link); +} + +static void +vmbus_chan_rem_list(struct vmbus_softc *sc, struct vmbus_channel *chan) +{ + + mtx_assert(&sc->vmbus_chan_lock, MA_OWNED); + if (atomic_testandclear_int(&chan->ch_stflags, + VMBUS_CHAN_ST_ONLIST_SHIFT) == 0) + panic("channel is not on the list"); + TAILQ_REMOVE(&sc->vmbus_chans, chan, ch_link); +} + static int vmbus_chan_sysctl_mnf(SYSCTL_HANDLER_ARGS) { @@ -235,6 +332,7 @@ vmbus_chan_open_br(struct vmbus_channel *chan, const struct vmbus_chan_br *cbr, struct vmbus_msghc *mh; uint32_t status; int error, txbr_size, rxbr_size; + task_fn_t *task_fn; uint8_t *br; if (udlen > VMBUS_CHANMSG_CHOPEN_UDATA_SIZE) { @@ -269,9 +367,10 @@ vmbus_chan_open_br(struct vmbus_channel *chan, const struct vmbus_chan_br *cbr, chan->ch_tq = VMBUS_PCPU_GET(chan->ch_vmbus, event_tq, chan->ch_cpuid); if (chan->ch_flags & VMBUS_CHAN_FLAG_BATCHREAD) - TASK_INIT(&chan->ch_task, 0, vmbus_chan_task, chan); + task_fn = vmbus_chan_task; else - TASK_INIT(&chan->ch_task, 0, vmbus_chan_task_nobatch, chan); + task_fn = vmbus_chan_task_nobatch; + TASK_INIT(&chan->ch_task, 0, task_fn, chan); /* TX bufring comes first */ vmbus_txbr_setup(&chan->ch_txbr, br, txbr_size); @@ -292,6 +391,12 @@ vmbus_chan_open_br(struct vmbus_channel *chan, const struct vmbus_chan_br *cbr, goto failed; } + /* + * Install this channel, before it is opened, but after everything + * else has been setup. + */ + vmbus_chan_set_chmap(chan); + /* * Open channel w/ the bufring GPADL on the target CPU. */ @@ -341,6 +446,7 @@ vmbus_chan_open_br(struct vmbus_channel *chan, const struct vmbus_chan_br *cbr, error = ENXIO; failed: + vmbus_chan_clear_chmap(chan); if (chan->ch_bufring_gpadl) { vmbus_chan_gpadl_disconnect(chan, chan->ch_bufring_gpadl); chan->ch_bufring_gpadl = 0; @@ -516,13 +622,39 @@ vmbus_chan_gpadl_disconnect(struct vmbus_channel *chan, uint32_t gpadl) return 0; } +static void +vmbus_chan_clrchmap_task(void *xchan, int pending __unused) +{ + struct vmbus_channel *chan = xchan; + + critical_enter(); + chan->ch_vmbus->vmbus_chmap[chan->ch_id] = NULL; + critical_exit(); +} + +static void +vmbus_chan_clear_chmap(struct vmbus_channel *chan) +{ + struct task chmap_task; + + TASK_INIT(&chmap_task, 0, vmbus_chan_clrchmap_task, chan); + taskqueue_enqueue(chan->ch_tq, &chmap_task); + taskqueue_drain(chan->ch_tq, &chmap_task); +} + +static void +vmbus_chan_set_chmap(struct vmbus_channel *chan) +{ + __compiler_membar(); + chan->ch_vmbus->vmbus_chmap[chan->ch_id] = chan; +} + static void vmbus_chan_close_internal(struct vmbus_channel *chan) { struct vmbus_softc *sc = chan->ch_vmbus; struct vmbus_msghc *mh; struct vmbus_chanmsg_chclose *req; - struct taskqueue *tq = chan->ch_tq; int error; /* TODO: stringent check */ @@ -535,12 +667,14 @@ vmbus_chan_close_internal(struct vmbus_channel *chan) sysctl_ctx_free(&chan->ch_sysctl_ctx); /* - * Set ch_tq to NULL to avoid more requests be scheduled. - * XXX pretty broken; need rework. + * NOTE: + * Order is critical. This channel _must_ be uninstalled first, + * else the channel task may be enqueued by the IDT after it has + * been drained. */ + vmbus_chan_clear_chmap(chan); + taskqueue_drain(chan->ch_tq, &chan->ch_task); chan->ch_tq = NULL; - taskqueue_drain(tq, &chan->ch_task); - chan->ch_cb = NULL; /* * Close this channel. @@ -884,10 +1018,11 @@ vmbus_event_flags_proc(struct vmbus_softc *sc, volatile u_long *event_flags, flags &= ~(1UL << chid_ofs); chan = sc->vmbus_chmap[chid_base + chid_ofs]; - - /* if channel is closed or closing */ - if (chan == NULL || chan->ch_tq == NULL) + if (__predict_false(chan == NULL)) { + /* Channel is closed. */ continue; + } + __compiler_membar(); if (chan->ch_flags & VMBUS_CHAN_FLAG_BATCHREAD) vmbus_rxbr_intr_mask(&chan->ch_rxbr); @@ -968,7 +1103,6 @@ vmbus_chan_alloc(struct vmbus_softc *sc) chan->ch_vmbus = sc; mtx_init(&chan->ch_subchan_lock, "vmbus subchan", NULL, MTX_DEF); TAILQ_INIT(&chan->ch_subchans); - TASK_INIT(&chan->ch_detach_task, 0, vmbus_chan_detach_task, chan); vmbus_rxbr_init(&chan->ch_rxbr); vmbus_txbr_init(&chan->ch_txbr); @@ -978,9 +1112,14 @@ vmbus_chan_alloc(struct vmbus_softc *sc) static void vmbus_chan_free(struct vmbus_channel *chan) { - /* TODO: assert sub-channel list is empty */ - /* TODO: asset no longer on the primary channel's sub-channel list */ - /* TODO: asset no longer on the vmbus channel list */ + + KASSERT(TAILQ_EMPTY(&chan->ch_subchans) && chan->ch_subchan_cnt == 0, + ("still owns sub-channels")); + KASSERT((chan->ch_stflags & + (VMBUS_CHAN_ST_OPENED | + VMBUS_CHAN_ST_ONPRIL | + VMBUS_CHAN_ST_ONSUBL | + VMBUS_CHAN_ST_ONLIST)) == 0, ("free busy channel")); hyperv_dmamem_free(&chan->ch_monprm_dma, chan->ch_monprm); mtx_destroy(&chan->ch_subchan_lock); vmbus_rxbr_deinit(&chan->ch_rxbr); @@ -1007,7 +1146,6 @@ vmbus_chan_add(struct vmbus_channel *newchan) newchan->ch_id); return EINVAL; } - sc->vmbus_chmap[newchan->ch_id] = newchan; if (bootverbose) { device_printf(sc->vmbus_dev, "chan%u subidx%u offer\n", @@ -1029,10 +1167,9 @@ vmbus_chan_add(struct vmbus_channel *newchan) if (VMBUS_CHAN_ISPRIMARY(newchan)) { if (prichan == NULL) { /* Install the new primary channel */ - TAILQ_INSERT_TAIL(&sc->vmbus_prichans, newchan, - ch_prilink); + vmbus_chan_ins_prilist(sc, newchan); mtx_unlock(&sc->vmbus_prichan_lock); - return 0; + goto done; } else { mtx_unlock(&sc->vmbus_prichan_lock); device_printf(sc->vmbus_dev, "duplicated primary " @@ -1066,16 +1203,20 @@ vmbus_chan_add(struct vmbus_channel *newchan) newchan->ch_dev = prichan->ch_dev; mtx_lock(&prichan->ch_subchan_lock); - TAILQ_INSERT_TAIL(&prichan->ch_subchans, newchan, ch_sublink); - /* - * Bump up sub-channel count and notify anyone that is - * interested in this sub-channel, after this sub-channel - * is setup. - */ - prichan->ch_subchan_cnt++; + vmbus_chan_ins_sublist(prichan, newchan); mtx_unlock(&prichan->ch_subchan_lock); + /* + * Notify anyone that is interested in this sub-channel, + * after this sub-channel is setup. + */ wakeup(prichan); - +done: + /* + * Hook this channel up for later rescind. + */ + mtx_lock(&sc->vmbus_chan_lock); + vmbus_chan_ins_list(sc, newchan); + mtx_unlock(&sc->vmbus_chan_lock); return 0; } @@ -1126,6 +1267,7 @@ vmbus_chan_msgproc_choffer(struct vmbus_softc *sc, { const struct vmbus_chanmsg_choffer *offer; struct vmbus_channel *chan; + task_fn_t *detach_fn, *attach_fn; int error; offer = (const struct vmbus_chanmsg_choffer *)msg->msg_data; @@ -1174,6 +1316,21 @@ vmbus_chan_msgproc_choffer(struct vmbus_softc *sc, &sc->vmbus_tx_evtflags[chan->ch_id >> VMBUS_EVTFLAG_SHIFT]; chan->ch_evtflag_mask = 1UL << (chan->ch_id & VMBUS_EVTFLAG_MASK); + /* + * Setup attach and detach tasks. + */ + if (VMBUS_CHAN_ISPRIMARY(chan)) { + chan->ch_mgmt_tq = sc->vmbus_devtq; + attach_fn = vmbus_prichan_attach_task; + detach_fn = vmbus_prichan_detach_task; + } else { + chan->ch_mgmt_tq = sc->vmbus_subchtq; + attach_fn = vmbus_subchan_attach_task; + detach_fn = vmbus_subchan_detach_task; + } + TASK_INIT(&chan->ch_attach_task, 0, attach_fn, chan); + TASK_INIT(&chan->ch_detach_task, 0, detach_fn, chan); + /* Select default cpu for this channel. */ vmbus_chan_cpu_default(chan); @@ -1184,22 +1341,9 @@ vmbus_chan_msgproc_choffer(struct vmbus_softc *sc, vmbus_chan_free(chan); return; } - - if (VMBUS_CHAN_ISPRIMARY(chan)) { - /* - * Add device for this primary channel. - * - * NOTE: - * Error is ignored here; don't have much to do if error - * really happens. - */ - vmbus_add_child(chan); - } + taskqueue_enqueue(chan->ch_mgmt_tq, &chan->ch_attach_task); } -/* - * XXX pretty broken; need rework. - */ static void vmbus_chan_msgproc_chrescind(struct vmbus_softc *sc, const struct vmbus_message *msg) @@ -1219,91 +1363,162 @@ vmbus_chan_msgproc_chrescind(struct vmbus_softc *sc, note->chm_chanid); } - chan = sc->vmbus_chmap[note->chm_chanid]; - if (chan == NULL) + /* + * Find and remove the target channel from the channel list. + */ + mtx_lock(&sc->vmbus_chan_lock); + TAILQ_FOREACH(chan, &sc->vmbus_chans, ch_link) { + if (chan->ch_id == note->chm_chanid) + break; + } + if (chan == NULL) { + mtx_unlock(&sc->vmbus_chan_lock); + device_printf(sc->vmbus_dev, "chan%u is not offered\n", + note->chm_chanid); return; - sc->vmbus_chmap[note->chm_chanid] = NULL; + } + vmbus_chan_rem_list(sc, chan); + mtx_unlock(&sc->vmbus_chan_lock); - taskqueue_enqueue(taskqueue_thread, &chan->ch_detach_task); + if (VMBUS_CHAN_ISPRIMARY(chan)) { + /* + * The target channel is a primary channel; remove the + * target channel from the primary channel list now, + * instead of later, so that it will not be found by + * other sub-channel offers, which are processed in + * this thread. + */ + mtx_lock(&sc->vmbus_prichan_lock); + vmbus_chan_rem_prilist(sc, chan); + mtx_unlock(&sc->vmbus_prichan_lock); + } + + /* Detach the target channel. */ + taskqueue_enqueue(chan->ch_mgmt_tq, &chan->ch_detach_task); +} + +static int +vmbus_chan_release(struct vmbus_channel *chan) +{ + struct vmbus_softc *sc = chan->ch_vmbus; + struct vmbus_chanmsg_chfree *req; + struct vmbus_msghc *mh; + int error; + + mh = vmbus_msghc_get(sc, sizeof(*req)); + if (mh == NULL) { + device_printf(sc->vmbus_dev, "can not get msg hypercall for " + "chfree(chan%u)\n", chan->ch_id); + return (ENXIO); + } + + req = vmbus_msghc_dataptr(mh); + req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHFREE; + req->chm_chanid = chan->ch_id; + + error = vmbus_msghc_exec_noresult(mh); + vmbus_msghc_put(sc, mh); + + if (error) { + device_printf(sc->vmbus_dev, "chfree(chan%u) failed: %d", + chan->ch_id, error); + } else { + if (bootverbose) { + device_printf(sc->vmbus_dev, "chan%u freed\n", + chan->ch_id); + } + } + return (error); } static void -vmbus_chan_detach_task(void *xchan, int pending __unused) +vmbus_prichan_detach_task(void *xchan, int pending __unused) { struct vmbus_channel *chan = xchan; - if (VMBUS_CHAN_ISPRIMARY(chan)) { - /* Only primary channel owns the device */ - vmbus_delete_child(chan); - /* NOTE: DO NOT free primary channel for now */ - } else { - struct vmbus_softc *sc = chan->ch_vmbus; - struct vmbus_channel *pri_chan = chan->ch_prichan; - struct vmbus_chanmsg_chfree *req; - struct vmbus_msghc *mh; - int error; + KASSERT(VMBUS_CHAN_ISPRIMARY(chan), + ("chan%u is not primary channel", chan->ch_id)); - mh = vmbus_msghc_get(sc, sizeof(*req)); - if (mh == NULL) { - device_printf(sc->vmbus_dev, - "can not get msg hypercall for chfree(chan%u)\n", - chan->ch_id); - goto remove; - } + /* Delete and detach the device associated with this channel. */ + vmbus_delete_child(chan); - req = vmbus_msghc_dataptr(mh); - req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHFREE; - req->chm_chanid = chan->ch_id; + /* Release this channel (back to vmbus). */ + vmbus_chan_release(chan); - error = vmbus_msghc_exec_noresult(mh); - vmbus_msghc_put(sc, mh); - - if (error) { - device_printf(sc->vmbus_dev, - "chfree(chan%u) failed: %d", - chan->ch_id, error); - /* NOTE: Move on! */ - } else { - if (bootverbose) { - device_printf(sc->vmbus_dev, "chan%u freed\n", - chan->ch_id); - } - } -remove: - mtx_lock(&pri_chan->ch_subchan_lock); - TAILQ_REMOVE(&pri_chan->ch_subchans, chan, ch_sublink); - KASSERT(pri_chan->ch_subchan_cnt > 0, - ("invalid subchan_cnt %d", pri_chan->ch_subchan_cnt)); - pri_chan->ch_subchan_cnt--; - mtx_unlock(&pri_chan->ch_subchan_lock); - wakeup(pri_chan); - - vmbus_chan_free(chan); - } + /* Free this channel's resource. */ + vmbus_chan_free(chan); +} + +static void +vmbus_subchan_detach_task(void *xchan, int pending __unused) +{ + struct vmbus_channel *chan = xchan; + struct vmbus_channel *pri_chan = chan->ch_prichan; + + KASSERT(!VMBUS_CHAN_ISPRIMARY(chan), + ("chan%u is primary channel", chan->ch_id)); + + /* Release this channel (back to vmbus). */ + vmbus_chan_release(chan); + + /* Unlink from its primary channel's sub-channel list. */ + mtx_lock(&pri_chan->ch_subchan_lock); + vmbus_chan_rem_sublist(pri_chan, chan); + mtx_unlock(&pri_chan->ch_subchan_lock); + /* Notify anyone that is waiting for this sub-channel to vanish. */ + wakeup(pri_chan); + + /* Free this channel's resource. */ + vmbus_chan_free(chan); +} + +static void +vmbus_prichan_attach_task(void *xchan, int pending __unused) +{ + + /* + * Add device for this primary channel. + */ + vmbus_add_child(xchan); +} + +static void +vmbus_subchan_attach_task(void *xchan __unused, int pending __unused) +{ + + /* Nothing */ } -/* - * Detach all devices and destroy the corresponding primary channels. - */ void vmbus_chan_destroy_all(struct vmbus_softc *sc) { - struct vmbus_channel *chan; - mtx_lock(&sc->vmbus_prichan_lock); - while ((chan = TAILQ_FIRST(&sc->vmbus_prichans)) != NULL) { - KASSERT(VMBUS_CHAN_ISPRIMARY(chan), ("not primary channel")); - TAILQ_REMOVE(&sc->vmbus_prichans, chan, ch_prilink); - mtx_unlock(&sc->vmbus_prichan_lock); + /* + * Detach all devices and destroy the corresponding primary + * channels. + */ + for (;;) { + struct vmbus_channel *chan; - vmbus_delete_child(chan); - vmbus_chan_free(chan); + mtx_lock(&sc->vmbus_chan_lock); + TAILQ_FOREACH(chan, &sc->vmbus_chans, ch_link) { + if (VMBUS_CHAN_ISPRIMARY(chan)) + break; + } + if (chan == NULL) { + /* No more primary channels; done. */ + mtx_unlock(&sc->vmbus_chan_lock); + break; + } + vmbus_chan_rem_list(sc, chan); + mtx_unlock(&sc->vmbus_chan_lock); mtx_lock(&sc->vmbus_prichan_lock); + vmbus_chan_rem_prilist(sc, chan); + mtx_unlock(&sc->vmbus_prichan_lock); + + taskqueue_enqueue(chan->ch_mgmt_tq, &chan->ch_detach_task); } - bzero(sc->vmbus_chmap, - sizeof(struct vmbus_channel *) * VMBUS_CHAN_MAX); - mtx_unlock(&sc->vmbus_prichan_lock); } /* diff --git a/sys/dev/hyperv/vmbus/vmbus_chanvar.h b/sys/dev/hyperv/vmbus/vmbus_chanvar.h index 68a134d3f2fb..b415d0079eb3 100644 --- a/sys/dev/hyperv/vmbus/vmbus_chanvar.h +++ b/sys/dev/hyperv/vmbus/vmbus_chanvar.h @@ -124,8 +124,14 @@ struct vmbus_channel { struct hyperv_dma ch_bufring_dma; uint32_t ch_bufring_gpadl; - struct task ch_detach_task; + struct task ch_attach_task; /* run in ch_mgmt_tq */ + struct task ch_detach_task; /* run in ch_mgmt_tq */ + struct taskqueue *ch_mgmt_tq; + + /* If this is a primary channel */ TAILQ_ENTRY(vmbus_channel) ch_prilink; /* primary chan link */ + + TAILQ_ENTRY(vmbus_channel) ch_link; /* channel link */ uint32_t ch_subidx; /* subchan index */ volatile uint32_t ch_stflags; /* atomic-op */ /* VMBUS_CHAN_ST_ */ @@ -150,7 +156,13 @@ struct vmbus_channel { #define VMBUS_CHAN_TXF_HASMNF 0x0001 #define VMBUS_CHAN_ST_OPENED_SHIFT 0 +#define VMBUS_CHAN_ST_ONPRIL_SHIFT 1 +#define VMBUS_CHAN_ST_ONSUBL_SHIFT 2 +#define VMBUS_CHAN_ST_ONLIST_SHIFT 3 #define VMBUS_CHAN_ST_OPENED (1 << VMBUS_CHAN_ST_OPENED_SHIFT) +#define VMBUS_CHAN_ST_ONPRIL (1 << VMBUS_CHAN_ST_ONPRIL_SHIFT) +#define VMBUS_CHAN_ST_ONSUBL (1 << VMBUS_CHAN_ST_ONSUBL_SHIFT) +#define VMBUS_CHAN_ST_ONLIST (1 << VMBUS_CHAN_ST_ONLIST_SHIFT) struct vmbus_softc; struct vmbus_message; diff --git a/sys/dev/hyperv/vmbus/vmbus_var.h b/sys/dev/hyperv/vmbus/vmbus_var.h index 47d9004e5719..df4553a9e401 100644 --- a/sys/dev/hyperv/vmbus/vmbus_var.h +++ b/sys/dev/hyperv/vmbus/vmbus_var.h @@ -107,14 +107,19 @@ struct vmbus_softc { struct hyperv_dma vmbus_mnf1_dma; struct hyperv_dma vmbus_mnf2_dma; - struct mtx vmbus_scan_lock; - uint32_t vmbus_scan_chcnt; -#define VMBUS_SCAN_CHCNT_DONE 0x80000000 - uint32_t vmbus_scan_devcnt; + bool vmbus_scandone; + struct task vmbus_scandone_task; + + struct taskqueue *vmbus_devtq; /* for dev attach/detach */ + struct taskqueue *vmbus_subchtq; /* for sub-chan attach/detach */ /* Primary channels */ struct mtx vmbus_prichan_lock; TAILQ_HEAD(, vmbus_channel) vmbus_prichans; + + /* Complete channel list */ + struct mtx vmbus_chan_lock; + TAILQ_HEAD(, vmbus_channel) vmbus_chans; }; #define VMBUS_FLAG_ATTACHED 0x0001 /* vmbus was attached */ From 3ff511d3163f1ce84b91290eb76d542378649a1d Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Tue, 27 Sep 2016 08:11:09 +0000 Subject: [PATCH 40/64] Remove a comment about the size of the ifnet structure. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D8036 --- sys/net/if_var.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/sys/net/if_var.h b/sys/net/if_var.h index 2298de5a2816..d04c871d1f22 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -178,9 +178,6 @@ struct if_encap_req { /* * Structure defining a network interface. - * - * Size ILP32: 592 (approx) - * LP64: 1048 (approx) */ struct ifnet { /* General book keeping of interface lists. */ From 3925fe313553e2eefc7658e90a1e29b661027c82 Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Tue, 27 Sep 2016 08:47:02 +0000 Subject: [PATCH 41/64] - Prefer if_addrhead (FreeBSD) to if_addrlist (BSD compat) naming for the interface address list - Update IFF_RENAMING macro descriptions --- share/man/man9/ifnet.9 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/share/man/man9/ifnet.9 b/share/man/man9/ifnet.9 index d6a51964fb28..f34e5f0e7be6 100644 --- a/share/man/man9/ifnet.9 +++ b/share/man/man9/ifnet.9 @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 11, 2016 +.Dd September 27, 2016 .Dt IFNET 9 .Os .Sh NAME @@ -642,7 +642,7 @@ structure of this interface is being released and still has .Va if_refcount references. .It Dv IFF_RENAMING -.Aq D* +.Aq D Set when this interface is being renamed. .El .Ss "Interface Capabilities Flags" @@ -1014,7 +1014,7 @@ Every interface is associated with a list (or, rather, a .Li TAILQ ) of addresses, rooted at the interface structure's -.Va if_addrlist +.Va if_addrhead member. The first element in this list is always an .Dv AF_LINK From 5bec6d5513fd22ffca0f6b6162e51baa81006d00 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Tue, 27 Sep 2016 09:44:30 +0000 Subject: [PATCH 42/64] Mark SSP broken on MIPS. Sponsored by: DARPA, AFRL Sponsored by: HEIF5 --- lib/libc/tests/Makefile | 3 +-- share/mk/src.opts.mk | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/libc/tests/Makefile b/lib/libc/tests/Makefile index 157e411357e6..4ead70aceaa0 100644 --- a/lib/libc/tests/Makefile +++ b/lib/libc/tests/Makefile @@ -30,8 +30,7 @@ SUBDIR_DEPEND_tls= tls_dso TESTS_SUBDIRS+= locale .endif -.if ${MK_SSP} != "no" && \ - ${MACHINE_CPUARCH} != "mips" +.if ${MK_SSP} != "no" TESTS_SUBDIRS+= ssp .endif diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index bec699fe12a5..21c7c5967576 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -260,6 +260,9 @@ BROKEN_OPTIONS+=LLDB .if ${__T} != "armv6" BROKEN_OPTIONS+=LIBSOFT .endif +.if ${__T} == "mips" || ${__T} == "mips64" +BROKEN_OPTIONS+=SSP +.endif .include From 5925fff002a5cf19b5c4321ba8801723bedd08e1 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Tue, 27 Sep 2016 11:31:53 +0000 Subject: [PATCH 43/64] Editing fixes for r306257, documentation for trapcap. Suggested by: wblock Discussed with: jilles Reviewed by: cem (previous version) Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D8023 --- lib/libc/sys/cap_enter.2 | 8 ++++---- lib/libc/sys/procctl.2 | 18 +++++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/libc/sys/cap_enter.2 b/lib/libc/sys/cap_enter.2 index 1186f22d5e6a..046395188ba0 100644 --- a/lib/libc/sys/cap_enter.2 +++ b/lib/libc/sys/cap_enter.2 @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 22, 2016 +.Dd September 27, 2016 .Dt CAP_ENTER 2 .Os .Sh NAME @@ -72,15 +72,15 @@ sandbox. .Sh RUN-TIME SETTINGS If the .Dv kern.trap_enocap -sysctl MIB is set to non-zero value, then for any process executing in a +sysctl MIB is set to a non-zero value, then for any process executing in a capability mode sandbox, any syscall which results in either .Er ENOTCAPABLE or .Er ECAPMODE -error, also generates the synchronous +error also generates the synchronous .Dv SIGTRAP signal to the thread on the syscall return. -On the signal delivery, the +On signal delivery, the .Va si_errno member of the .Fa siginfo diff --git a/lib/libc/sys/procctl.2 b/lib/libc/sys/procctl.2 index 7d2fc728206b..da73fb04f93d 100644 --- a/lib/libc/sys/procctl.2 +++ b/lib/libc/sys/procctl.2 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 22, 2016 +.Dd September 27, 2016 .Dt PROCCTL 2 .Os .Sh NAME @@ -328,14 +328,17 @@ If a debugger is attached, .Fa data is set to the pid of the debugger process. .It Dv PROC_TRAPCAP_CTL -Enable or disable, for the specified processes which are executing in a -capability mode sandbox, the synchronous -.Dv SIGTRAP -signal on return from any syscall which gives either +Controls the capability mode sandbox actions for the specified +sandboxed processes, +on a return from any syscall which gives either a .Er ENOTCAPABLE or .Er ECAPMODE error. +If the control is enabled, such errors from the syscalls cause +delivery of the synchronous +.Dv SIGTRAP +signal to the thread immediately before returning from the syscalls. .Pp Possible values for the .Fa data @@ -353,7 +356,8 @@ calls. Disable the signal delivery on capability mode access violations. Note that the global sysctl .Dv kern.trap_enocap -might still cause the signal to be delivered; see +might still cause the signal to be delivered. +See .Xr capsicum 4 . .El .Pp @@ -371,7 +375,7 @@ See .Xr capsicum 4 for more information about the capability mode. .It Dv PROC_TRAPCAP_STATUS -Returns the current status of signalling capability mode access +Return the current status of signalling capability mode access violations for the specified process. The integer value pointed to by the .Fa data From 615216628b4628df08a1eccf10c8c0d200c0b599 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Tue, 27 Sep 2016 13:46:00 +0000 Subject: [PATCH 44/64] Allow up to 6 arguments only on MIPS. Sponsored by: DARPA, AFRL Sponsored by: HEIF5 --- contrib/netbsd-tests/lib/libc/sys/t_getcontext.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contrib/netbsd-tests/lib/libc/sys/t_getcontext.c b/contrib/netbsd-tests/lib/libc/sys/t_getcontext.c index 20a9e42c37c7..9f21b3e344c0 100644 --- a/contrib/netbsd-tests/lib/libc/sys/t_getcontext.c +++ b/contrib/netbsd-tests/lib/libc/sys/t_getcontext.c @@ -55,6 +55,8 @@ run(int n, ...) for (i = 0; i < 5; i++) { #elif defined(__FreeBSD__) && defined(__aarch64__) for (i = 0; i < 7; i++) { +#elif defined(__FreeBSD__) && defined(__mips__) + for (i = 0; i < 5; i++) { #else for (i = 0; i < 9; i++) { #endif @@ -122,6 +124,10 @@ ATF_TC_BODY(setcontext_link, tc) /* FreeBSD/arm64 only permits up to 8 arguments. */ makecontext(&uc[i], (void *)run, 8, i, 0, 1, 2, 3, 4, 5, 6); +#elif defined(__FreeBSD__) && defined(__mips__) + /* FreeBSD/mips only permits up to 6 arguments. */ + makecontext(&uc[i], (void *)run, 6, i, + 0, 1, 2, 3, 4); #else makecontext(&uc[i], (void *)run, 10, i, 0, 1, 2, 3, 4, 5, 6, 7, 8); From dc7c777336056d6c8fbe7e9a23b445791ce39479 Mon Sep 17 00:00:00 2001 From: Marcelo Araujo Date: Tue, 27 Sep 2016 17:37:23 +0000 Subject: [PATCH 45/64] Indicate that this is a locally administered MAC address. Submitted by: lidl Differential Revision: https://reviews.freebsd.org/D7903 --- sbin/ifconfig/af_link.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sbin/ifconfig/af_link.c b/sbin/ifconfig/af_link.c index 361c82e50fe2..2b32131663e4 100644 --- a/sbin/ifconfig/af_link.c +++ b/sbin/ifconfig/af_link.c @@ -96,8 +96,9 @@ link_getaddr(const char *addr, int which) sdl.sdl_nlen = 0; sdl.sdl_family = AF_LINK; arc4random_buf(&sdl.sdl_data, ETHER_ADDR_LEN); - /* Non-multicast and claim it is a hardware address */ + /* Non-multicast and claim it is locally administered. */ sdl.sdl_data[0] &= 0xfc; + sdl.sdl_data[0] |= 0x02; } else { if ((temp = malloc(strlen(addr) + 2)) == NULL) errx(1, "malloc failed"); From f987297fc922c229de89a065ed138a26ae66c8c8 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Tue, 27 Sep 2016 18:08:38 +0000 Subject: [PATCH 46/64] Add a WITHOUT_DIALOG src.conf(5) knob It also turns off dependencies (bsdinstall, bsdconfig, dpv, tzsetup). Reviewed by: dteske Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D7969 --- Makefile.inc1 | 10 ++++++---- gnu/usr.bin/Makefile | 3 ++- lib/Makefile | 3 ++- share/mk/src.opts.mk | 5 +++++ tools/build/mk/OptionalObsoleteFiles.inc | 21 +++++++++++++++++++++ tools/build/options/WITHOUT_DIALOG | 2 ++ usr.bin/Makefile | 2 +- usr.sbin/Makefile | 4 ++-- 8 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 tools/build/options/WITHOUT_DIALOG diff --git a/Makefile.inc1 b/Makefile.inc1 index 29ec4262251f..8393e865893f 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -2032,8 +2032,7 @@ _prebuild_libs= ${_kerberos5_lib_libasn1} \ ${_cddl_lib_libctf} \ lib/libutil lib/libpjdlog ${_lib_libypclnt} lib/libz lib/msun \ ${_secure_lib_libcrypto} ${_lib_libldns} \ - ${_secure_lib_libssh} ${_secure_lib_libssl} \ - gnu/lib/libdialog + ${_secure_lib_libssh} ${_secure_lib_libssl} .if ${MK_GNUCXX} != "no" _prebuild_libs+= gnu/lib/libstdc++ gnu/lib/libsupc++ @@ -2041,6 +2040,11 @@ gnu/lib/libstdc++__L: lib/msun__L gnu/lib/libsupc++__L: gnu/lib/libstdc++__L .endif +.if ${MK_DIALOG} != "no" +_prebuild_libs+= gnu/lib/libdialog +gnu/lib/libdialog__L: lib/msun__L lib/ncurses/ncursesw__L +.endif + .if ${MK_LIBCPLUSPLUS} != "no" _prebuild_libs+= lib/libc++ .endif @@ -2190,8 +2194,6 @@ lib/libproc__L: gnu/lib/libsupc++__L .endif .endif -gnu/lib/libdialog__L: lib/msun__L lib/ncurses/ncursesw__L - .for _lib in ${_prereq_libs} ${_lib}__PL: .PHONY .MAKE .if exists(${.CURDIR}/${_lib}) diff --git a/gnu/usr.bin/Makefile b/gnu/usr.bin/Makefile index 63cbd0b629a6..6ba9ef2e1fe3 100644 --- a/gnu/usr.bin/Makefile +++ b/gnu/usr.bin/Makefile @@ -4,7 +4,6 @@ SUBDIR= ${_binutils} \ ${_cc} \ - dialog \ diff \ diff3 \ ${_dtc} \ @@ -49,6 +48,8 @@ _gdb= gdb _cc= cc .endif +SUBDIR.${MK_DIALOG}+= dialog + SUBDIR_PARALLEL= .include diff --git a/lib/Makefile b/lib/Makefile index 16f746803305..841018406328 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -46,7 +46,6 @@ SUBDIR= ${SUBDIR_BOOTSTRAP} \ ${_libdevdctl} \ libdevinfo \ libdevstat \ - libdpv \ libdwarf \ libedit \ ${_libelftc} \ @@ -197,6 +196,8 @@ _libelftc= libelftc _libpe= libpe .endif +SUBDIR.${MK_DIALOG}+= libdpv + .if ${MK_FILE} != "no" _libmagic= libmagic .endif diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index 21c7c5967576..2a08b8344e52 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -76,6 +76,7 @@ __DEFAULT_YES_OPTIONS = \ CTM \ CUSE \ CXX \ + DIALOG \ DICT \ DMAGENT \ DYNAMICROOT \ @@ -328,6 +329,10 @@ MK_GNUCXX:= no MK_TESTS:= no .endif +.if ${MK_DIALOG} == "no" +MK_BSDINSTALL:= no +.endif + .if ${MK_MAIL} == "no" MK_MAILWRAPPER:= no MK_SENDMAIL:= no diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index 4edd5f7c2c87..a4525313af7c 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -1340,6 +1340,27 @@ OLD_FILES+=usr/bin/g++ OLD_FILES+=usr/libexec/cc1plus .endif +.if ${MK_DIALOG} == no +OLD_FILES+=usr/bin/dialog +OLD_FILES+=usr/bin/dpv +OLD_FILES+=usr/lib/libdialog.a +OLD_FILES+=usr/lib/libdialog.so +OLD_FILES+=usr/lib/libdialog.so.8 +OLD_FILES+=usr/lib/libdialog_p.a +OLD_FILES+=usr/lib/libdpv.a +OLD_FILES+=usr/lib/libdpv.so +OLD_FILES+=usr/lib/libdpv.so.1 +OLD_FILES+=usr/lib/libdpv_p.a +OLD_FILES+=usr/sbin/bsdconfig +OLD_FILES+=usr/sbin/tzsetup +OLD_FILES+=usr/share/man/man1/dialog.1.gz +OLD_FILES+=usr/share/man/man1/dpv.1.gz +OLD_FILES+=usr/share/man/man3/dialog.3.gz +OLD_FILES+=usr/share/man/man3/dpv.3.gz +OLD_FILES+=usr/share/man/man8/tzsetup.8.gz +OLD_FILES+=usr/share/man/man8/bsdconfig.8.gz +.endif + .if ${MK_FMTREE} == no OLD_FILES+=usr/sbin/fmtree OLD_FILES+=usr/share/man/man8/fmtree.8.gz diff --git a/tools/build/options/WITHOUT_DIALOG b/tools/build/options/WITHOUT_DIALOG new file mode 100644 index 000000000000..f5bc50849466 --- /dev/null +++ b/tools/build/options/WITHOUT_DIALOG @@ -0,0 +1,2 @@ +.\" $FreeBSD$ +Set to not build dialog(1), dialog(1,3), and dpv(1,3). diff --git a/usr.bin/Makefile b/usr.bin/Makefile index 5a6911d02dda..58bcfa07f64b 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -36,7 +36,6 @@ SUBDIR= alias \ ctlstat \ cut \ dirname \ - dpv \ du \ elf2aout \ elfdump \ @@ -200,6 +199,7 @@ SUBDIR.${MK_BLUETOOTH}+= bluetooth SUBDIR.${MK_BSD_CPIO}+= cpio SUBDIR.${MK_CALENDAR}+= calendar SUBDIR.${MK_CLANG}+= clang +SUBDIR.${MK_DIALOG}+= dpv SUBDIR.${MK_EE}+= ee SUBDIR.${MK_FILE}+= file SUBDIR.${MK_FINGER}+= finger diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 67499a10b5c6..d9fc76a68294 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -6,7 +6,6 @@ SUBDIR= adduser \ arp \ binmiscctl \ - bsdconfig \ camdd \ cdcontrol \ chkgrp \ @@ -89,7 +88,6 @@ SUBDIR= adduser \ tcpdump \ traceroute \ trpt \ - tzsetup \ uefisign \ ugidfw \ vigr \ @@ -123,6 +121,8 @@ SUBDIR.${MK_BOOTPARAMD}+= bootparamd SUBDIR.${MK_BSDINSTALL}+= bsdinstall SUBDIR.${MK_BSNMP}+= bsnmpd SUBDIR.${MK_CTM}+= ctm +SUBDIR.${MK_DIALOG}+= tzsetup +SUBDIR.${MK_DIALOG}+= bsdconfig SUBDIR.${MK_FLOPPY}+= fdcontrol SUBDIR.${MK_FLOPPY}+= fdformat SUBDIR.${MK_FLOPPY}+= fdread From feeb22f34adad29a29e0060fa0b6f116c4e2a8a6 Mon Sep 17 00:00:00 2001 From: Luiz Otavio O Souza Date: Tue, 27 Sep 2016 18:19:29 +0000 Subject: [PATCH 47/64] Add a sysctl to control the interrupt pacing on AM335x integrated switch. The hardware can be set to limit the number of interrupts from 2 to 63 interrupts per ms. To keep the compatibility with the TI documentation the sysctl take the interval between the interrupts pulses: 16~500 us. Sponsored by: Rubicon Communications, LLC (Netgate) --- sys/arm/ti/cpsw/if_cpsw.c | 54 ++++++++++++++++++++++++++++++++++++ sys/arm/ti/cpsw/if_cpswreg.h | 18 ++++++++++++ sys/arm/ti/cpsw/if_cpswvar.h | 1 + 3 files changed, 73 insertions(+) diff --git a/sys/arm/ti/cpsw/if_cpsw.c b/sys/arm/ti/cpsw/if_cpsw.c index 27f187c05d68..3cc366dd1e51 100644 --- a/sys/arm/ti/cpsw/if_cpsw.c +++ b/sys/arm/ti/cpsw/if_cpsw.c @@ -583,6 +583,11 @@ cpsw_init(struct cpsw_softc *sc) struct cpsw_slot *slot; uint32_t reg; + /* Disable the interrupt pacing. */ + reg = cpsw_read_4(sc, CPSW_WR_INT_CONTROL); + reg &= ~(CPSW_WR_INT_PACE_EN | CPSW_WR_INT_PRESCALE_MASK); + cpsw_write_4(sc, CPSW_WR_INT_CONTROL, reg); + /* Clear ALE */ cpsw_write_4(sc, CPSW_ALE_CONTROL, CPSW_ALE_CTL_CLEAR_TBL); @@ -2491,6 +2496,51 @@ cpsw_stat_attached(SYSCTL_HANDLER_ARGS) return (sysctl_handle_int(oidp, &result, 0, req)); } +static int +cpsw_intr_coalesce(SYSCTL_HANDLER_ARGS) +{ + int error; + struct cpsw_softc *sc; + uint32_t ctrl, intr_per_ms; + + sc = (struct cpsw_softc *)arg1; + error = sysctl_handle_int(oidp, &sc->coal_us, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + + ctrl = cpsw_read_4(sc, CPSW_WR_INT_CONTROL); + ctrl &= ~(CPSW_WR_INT_PACE_EN | CPSW_WR_INT_PRESCALE_MASK); + if (sc->coal_us == 0) { + /* Disable the interrupt pace hardware. */ + cpsw_write_4(sc, CPSW_WR_INT_CONTROL, ctrl); + cpsw_write_4(sc, CPSW_WR_C_RX_IMAX(0), 0); + cpsw_write_4(sc, CPSW_WR_C_TX_IMAX(0), 0); + return (0); + } + + if (sc->coal_us > CPSW_WR_C_IMAX_US_MAX) + sc->coal_us = CPSW_WR_C_IMAX_US_MAX; + if (sc->coal_us < CPSW_WR_C_IMAX_US_MIN) + sc->coal_us = CPSW_WR_C_IMAX_US_MIN; + intr_per_ms = 1000 / sc->coal_us; + /* Just to make sure... */ + if (intr_per_ms > CPSW_WR_C_IMAX_MAX) + intr_per_ms = CPSW_WR_C_IMAX_MAX; + if (intr_per_ms < CPSW_WR_C_IMAX_MIN) + intr_per_ms = CPSW_WR_C_IMAX_MIN; + + /* Set the prescale to produce 4us pulses from the 125 Mhz clock. */ + ctrl |= (125 * 4) & CPSW_WR_INT_PRESCALE_MASK; + + /* Enable the interrupt pace hardware. */ + cpsw_write_4(sc, CPSW_WR_C_RX_IMAX(0), intr_per_ms); + cpsw_write_4(sc, CPSW_WR_C_TX_IMAX(0), intr_per_ms); + ctrl |= CPSW_WR_INT_C0_RX_PULSE | CPSW_WR_INT_C0_TX_PULSE; + cpsw_write_4(sc, CPSW_WR_INT_CONTROL, ctrl); + + return (0); +} + static int cpsw_stat_uptime(SYSCTL_HANDLER_ARGS) { @@ -2576,6 +2626,10 @@ cpsw_add_sysctls(struct cpsw_softc *sc) CTLTYPE_UINT | CTLFLAG_RD, sc, 0, cpsw_stat_attached, "IU", "Time since driver attach"); + SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, "intr_coalesce_us", + CTLTYPE_UINT | CTLFLAG_RW, sc, 0, cpsw_intr_coalesce, "IU", + "minimum time between interrupts"); + node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "ports", CTLFLAG_RD, NULL, "CPSW Ports Statistics"); ports_parent = SYSCTL_CHILDREN(node); diff --git a/sys/arm/ti/cpsw/if_cpswreg.h b/sys/arm/ti/cpsw/if_cpswreg.h index bea6f1904e3c..9652e03b3614 100644 --- a/sys/arm/ti/cpsw/if_cpswreg.h +++ b/sys/arm/ti/cpsw/if_cpswreg.h @@ -138,6 +138,17 @@ #define CPSW_WR_SOFT_RESET (CPSW_WR_OFFSET + 0x04) #define CPSW_WR_CONTROL (CPSW_WR_OFFSET + 0x08) #define CPSW_WR_INT_CONTROL (CPSW_WR_OFFSET + 0x0c) +#define CPSW_WR_INT_C0_RX_PULSE (1 << 16) +#define CPSW_WR_INT_C0_TX_PULSE (1 << 17) +#define CPSW_WR_INT_C1_RX_PULSE (1 << 18) +#define CPSW_WR_INT_C1_TX_PULSE (1 << 19) +#define CPSW_WR_INT_C2_RX_PULSE (1 << 20) +#define CPSW_WR_INT_C2_TX_PULSE (1 << 21) +#define CPSW_WR_INT_PACE_EN \ + (CPSW_WR_INT_C0_RX_PULSE | CPSW_WR_INT_C0_TX_PULSE | \ + CPSW_WR_INT_C1_RX_PULSE | CPSW_WR_INT_C1_TX_PULSE | \ + CPSW_WR_INT_C2_RX_PULSE | CPSW_WR_INT_C2_TX_PULSE) +#define CPSW_WR_INT_PRESCALE_MASK 0xfff #define CPSW_WR_C_RX_THRESH_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x10) #define CPSW_WR_C_RX_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x14) #define CPSW_WR_C_TX_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x18) @@ -151,6 +162,13 @@ #define CPSW_WR_C_MISC_HOST_PEND (1 << 2) #define CPSW_WR_C_MISC_MDIOLINK (1 << 1) #define CPSW_WR_C_MISC_MDIOUSER (1 << 0) +#define CPSW_WR_C_RX_IMAX(p) (CPSW_WR_OFFSET + (0x08 * (p)) + 0x70) +#define CPSW_WR_C_TX_IMAX(p) (CPSW_WR_OFFSET + (0x08 * (p)) + 0x74) +#define CPSW_WR_C_IMAX_MASK 0x3f +#define CPSW_WR_C_IMAX_MAX 63 +#define CPSW_WR_C_IMAX_MIN 2 +#define CPSW_WR_C_IMAX_US_MAX 500 +#define CPSW_WR_C_IMAX_US_MIN 16 #define CPSW_CPPI_RAM_OFFSET 0x2000 #define CPSW_CPPI_RAM_SIZE 0x2000 diff --git a/sys/arm/ti/cpsw/if_cpswvar.h b/sys/arm/ti/cpsw/if_cpswvar.h index 953766be84f1..a750744a3e44 100644 --- a/sys/arm/ti/cpsw/if_cpswvar.h +++ b/sys/arm/ti/cpsw/if_cpswvar.h @@ -80,6 +80,7 @@ struct cpsw_softc { phandle_t node; struct bintime attach_uptime; /* system uptime when attach happened. */ struct cpsw_port port[2]; + unsigned coal_us; /* RX and TX buffer tracking */ struct cpsw_queue rx, tx; From 040b30497c8d563a244a8f9c39c73a87da6a2630 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Tue, 27 Sep 2016 18:55:45 +0000 Subject: [PATCH 48/64] libcompiler_rt: move file list to Makefile.inc for reuse elsewhere Also switch to the style used in the clang390-import branch to reduce future conflicts. Reviewed by: dim Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D8039 --- lib/libcompiler_rt/Makefile | 218 +------------------------------- lib/libcompiler_rt/Makefile.inc | 216 +++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+), 217 deletions(-) create mode 100644 lib/libcompiler_rt/Makefile.inc diff --git a/lib/libcompiler_rt/Makefile b/lib/libcompiler_rt/Makefile index 88c250ebcaa3..8e3896e4a5ad 100644 --- a/lib/libcompiler_rt/Makefile +++ b/lib/libcompiler_rt/Makefile @@ -10,223 +10,7 @@ WARNS?= 2 CFLAGS+=${PICFLAG} -fvisibility=hidden -DVISIBILITY_HIDDEN CFLAGS+=-I${SRCTOP}/contrib/libcxxrt -.if ${MACHINE_CPUARCH} == "amd64" -CRTARCH=x86_64 -.else -CRTARCH=${MACHINE_CPUARCH} -.endif - -CRTSRC=${SRCTOP}/contrib/compiler-rt/lib/builtins - -.PATH: ${CRTSRC}/${CRTARCH} ${CRTSRC} - -SRCF= absvdi2 \ - absvsi2 \ - absvti2 \ - addvdi3 \ - addvsi3 \ - addvti3 \ - apple_versioning \ - ashldi3 \ - ashlti3 \ - ashrdi3 \ - ashrti3 \ - clear_cache \ - clzdi2 \ - clzsi2 \ - clzti2 \ - cmpdi2 \ - cmpti2 \ - ctzdi2 \ - ctzsi2 \ - ctzti2 \ - divdc3 \ - divdi3 \ - divmoddi4 \ - divmodsi4 \ - divsc3 \ - divtc3 \ - divti3 \ - divxc3 \ - enable_execute_stack \ - eprintf \ - extendhfsf2 \ - ffsdi2 \ - ffsti2 \ - fixdfdi \ - fixdfti \ - fixsfdi \ - fixsfti \ - fixunsdfdi \ - fixunsdfsi \ - fixunsdfti \ - fixunssfdi \ - fixunssfsi \ - fixunssfti \ - fixunsxfdi \ - fixunsxfsi \ - fixunsxfti \ - fixxfdi \ - fixxfti \ - floatdidf \ - floatdisf \ - floatditf \ - floatdixf \ - floatsitf \ - floattidf \ - floattisf \ - floattixf \ - floatundidf \ - floatundisf \ - floatunditf \ - floatundixf \ - floatunsidf \ - floatunsisf \ - floatuntidf \ - floatuntisf \ - floatuntixf \ - gcc_personality_v0 \ - int_util \ - lshrdi3 \ - lshrti3 \ - moddi3 \ - modti3 \ - muldc3 \ - muldi3 \ - mulodi4 \ - mulosi4 \ - muloti4 \ - mulsc3 \ - multi3 \ - mulvdi3 \ - mulvsi3 \ - mulvti3 \ - multc3 \ - mulxc3 \ - negdf2 \ - negdi2 \ - negsf2 \ - negti2 \ - negvdi2 \ - negvsi2 \ - negvti2 \ - paritydi2 \ - paritysi2 \ - parityti2 \ - popcountdi2 \ - popcountsi2 \ - popcountti2 \ - powidf2 \ - powisf2 \ - powitf2 \ - powixf2 \ - subvdi3 \ - subvsi3 \ - subvti3 \ - trampoline_setup \ - truncdfhf2 \ - truncsfhf2 \ - ucmpdi2 \ - ucmpti2 \ - udivdi3 \ - udivmoddi4 \ - udivmodsi4 \ - udivmodti4 \ - udivti3 \ - umoddi3 \ - umodti3 - -# 128-bit quad precision long double support, only used on arm64 -.if ${MACHINE_CPUARCH} == "aarch64" -SRCF+= addtf3 \ - comparetf2 \ - divtf3 \ - extenddftf2 \ - extendsftf2 \ - fixtfdi \ - fixtfsi \ - fixtfti \ - fixunstfdi \ - fixunstfsi \ - fixunstfti \ - floatunsitf \ - multf3 \ - subtf3 \ - trunctfdf2 \ - trunctfsf2 -.endif - -# These are already shipped by libc.a on arm and mips -.if ${MACHINE_CPUARCH} != "arm" && ${MACHINE_CPUARCH} != "mips" -SRCF+= adddf3 \ - addsf3 \ - divdf3 \ - divsf3 \ - extendsfdf2 \ - fixdfsi \ - fixsfsi \ - floatsidf \ - floatsisf \ - muldf3 \ - mulsf3 \ - subdf3 \ - subsf3 \ - truncdfsf2 -.endif - -.if ${MACHINE_CPUARCH} != "arm" -SRCF+= comparedf2 \ - comparesf2 -.endif - -.if ${MACHINE_CPUARCH} != "mips" -SRCF+= divsi3 \ - modsi3 \ - udivsi3 \ - umodsi3 -.endif - -# FreeBSD-specific atomic intrinsics. -.if ${MACHINE_CPUARCH} == "arm" || ${MACHINE_CPUARCH} == "armv6" -.PATH: ${.CURDIR}/../../sys/arm/arm - -SRCF+= stdatomic -CFLAGS+= -DEMIT_SYNC_ATOMICS -.elif ${MACHINE_CPUARCH} == "mips" -.PATH: ${.CURDIR}/../../sys/mips/mips - -SRCF+= stdatomic -.endif - -.for file in ${SRCF} -.if ${MACHINE_ARCH:Marmv6*} && (!defined(CPUTYPE) || ${CPUTYPE:M*soft*} == "") && \ - exists(${CRTSRC}/${CRTARCH}/${file}vfp.S) -SRCS+= ${file}vfp.S -. elif exists(${CRTSRC}/${CRTARCH}/${file}.S) -SRCS+= ${file}.S -. else -SRCS+= ${file}.c -. endif -.endfor - -.if ${MACHINE_CPUARCH} == "arm" -SRCS+= aeabi_div0.c \ - aeabi_idivmod.S \ - aeabi_ldivmod.S \ - aeabi_memcmp.S \ - aeabi_memcpy.S \ - aeabi_memmove.S \ - aeabi_memset.S \ - aeabi_uidivmod.S \ - aeabi_uldivmod.S \ - bswapdi2.S \ - bswapsi2.S \ - switch16.S \ - switch32.S \ - switch8.S \ - switchu8.S \ - sync_synchronize.S -.endif +.include "Makefile.inc" .if ${MK_INSTALLLIB} != "no" SYMLINKS+=libcompiler_rt.a ${LIBDIR}/libgcc.a diff --git a/lib/libcompiler_rt/Makefile.inc b/lib/libcompiler_rt/Makefile.inc new file mode 100644 index 000000000000..cd665edfecbd --- /dev/null +++ b/lib/libcompiler_rt/Makefile.inc @@ -0,0 +1,216 @@ +# $FreeBSD$ + +CRTARCH= ${MACHINE_CPUARCH:C/amd64/x86_64/} + +CRTSRC= ${SRCTOP}/contrib/compiler-rt/lib/builtins + +.PATH: ${CRTSRC}/${CRTARCH} +.PATH: ${CRTSRC} + +SRCF+= absvdi2 +SRCF+= absvsi2 +SRCF+= absvti2 +SRCF+= addvdi3 +SRCF+= addvsi3 +SRCF+= addvti3 +SRCF+= apple_versioning +SRCF+= ashldi3 +SRCF+= ashlti3 +SRCF+= ashrdi3 +SRCF+= ashrti3 +SRCF+= clear_cache +SRCF+= clzdi2 +SRCF+= clzsi2 +SRCF+= clzti2 +SRCF+= cmpdi2 +SRCF+= cmpti2 +SRCF+= ctzdi2 +SRCF+= ctzsi2 +SRCF+= ctzti2 +SRCF+= divdc3 +SRCF+= divdi3 +SRCF+= divmoddi4 +SRCF+= divmodsi4 +SRCF+= divsc3 +SRCF+= divtc3 +SRCF+= divti3 +SRCF+= divxc3 +SRCF+= enable_execute_stack +SRCF+= eprintf +SRCF+= extendhfsf2 +SRCF+= ffsdi2 +SRCF+= ffsti2 +SRCF+= fixdfdi +SRCF+= fixdfti +SRCF+= fixsfdi +SRCF+= fixsfti +SRCF+= fixunsdfdi +SRCF+= fixunsdfsi +SRCF+= fixunsdfti +SRCF+= fixunssfdi +SRCF+= fixunssfsi +SRCF+= fixunssfti +SRCF+= fixunsxfdi +SRCF+= fixunsxfsi +SRCF+= fixunsxfti +SRCF+= fixxfdi +SRCF+= fixxfti +SRCF+= floatdidf +SRCF+= floatdisf +SRCF+= floatditf +SRCF+= floatdixf +SRCF+= floatsitf +SRCF+= floattidf +SRCF+= floattisf +SRCF+= floattixf +SRCF+= floatundidf +SRCF+= floatundisf +SRCF+= floatunditf +SRCF+= floatundixf +SRCF+= floatunsidf +SRCF+= floatunsisf +SRCF+= floatuntidf +SRCF+= floatuntisf +SRCF+= floatuntixf +SRCF+= gcc_personality_v0 +SRCF+= int_util +SRCF+= lshrdi3 +SRCF+= lshrti3 +SRCF+= moddi3 +SRCF+= modti3 +SRCF+= muldc3 +SRCF+= muldi3 +SRCF+= mulodi4 +SRCF+= mulosi4 +SRCF+= muloti4 +SRCF+= mulsc3 +SRCF+= multi3 +SRCF+= mulvdi3 +SRCF+= mulvsi3 +SRCF+= mulvti3 +SRCF+= multc3 +SRCF+= mulxc3 +SRCF+= negdf2 +SRCF+= negdi2 +SRCF+= negsf2 +SRCF+= negti2 +SRCF+= negvdi2 +SRCF+= negvsi2 +SRCF+= negvti2 +SRCF+= paritydi2 +SRCF+= paritysi2 +SRCF+= parityti2 +SRCF+= popcountdi2 +SRCF+= popcountsi2 +SRCF+= popcountti2 +SRCF+= powidf2 +SRCF+= powisf2 +SRCF+= powitf2 +SRCF+= powixf2 +SRCF+= subvdi3 +SRCF+= subvsi3 +SRCF+= subvti3 +SRCF+= trampoline_setup +SRCF+= truncdfhf2 +SRCF+= truncsfhf2 +SRCF+= ucmpdi2 +SRCF+= ucmpti2 +SRCF+= udivdi3 +SRCF+= udivmoddi4 +SRCF+= udivmodsi4 +SRCF+= udivmodti4 +SRCF+= udivti3 +SRCF+= umoddi3 +SRCF+= umodti3 + +# 128-bit quad precision long double support, only used on arm64 +.if ${MACHINE_CPUARCH} == "aarch64" +SRCF+= addtf3 +SRCF+= comparetf2 +SRCF+= divtf3 +SRCF+= extenddftf2 +SRCF+= extendsftf2 +SRCF+= fixtfdi +SRCF+= fixtfsi +SRCF+= fixtfti +SRCF+= fixunstfdi +SRCF+= fixunstfsi +SRCF+= fixunstfti +SRCF+= floatunsitf +SRCF+= multf3 +SRCF+= subtf3 +SRCF+= trunctfdf2 +SRCF+= trunctfsf2 +.endif + +# These are already shipped by libc.a on arm and mips +.if ${MACHINE_CPUARCH} != "arm" && ${MACHINE_CPUARCH} != "mips" +SRCF+= adddf3 +SRCF+= addsf3 +SRCF+= divdf3 +SRCF+= divsf3 +SRCF+= extendsfdf2 +SRCF+= fixdfsi +SRCF+= fixsfsi +SRCF+= floatsidf +SRCF+= floatsisf +SRCF+= muldf3 +SRCF+= mulsf3 +SRCF+= subdf3 +SRCF+= subsf3 +SRCF+= truncdfsf2 +.endif + +.if ${MACHINE_CPUARCH} != "arm" +SRCF+= comparedf2 +SRCF+= comparesf2 +.endif + +.if ${MACHINE_CPUARCH} != "mips" +SRCF+= divsi3 +SRCF+= modsi3 +SRCF+= udivsi3 +SRCF+= umodsi3 +.endif + +# FreeBSD-specific atomic intrinsics. +.if ${MACHINE_CPUARCH} == "arm" || ${MACHINE_CPUARCH} == "armv6" +.PATH: ${SRCTOP}/sys/arm/arm + +SRCF+= stdatomic +CFLAGS+= -DEMIT_SYNC_ATOMICS +.elif ${MACHINE_CPUARCH} == "mips" +.PATH: ${SRCTOP}/sys/mips/mips + +SRCF+= stdatomic +.endif + +.for file in ${SRCF} +.if ${MACHINE_ARCH:Marmv6*} && (!defined(CPUTYPE) || ${CPUTYPE:M*soft*} == "") \ + && exists(${CRTSRC}/${CRTARCH}/${file}vfp.S) +SRCS+= ${file}vfp.S +. elif exists(${CRTSRC}/${CRTARCH}/${file}.S) +SRCS+= ${file}.S +. else +SRCS+= ${file}.c +. endif +.endfor + +.if ${MACHINE_CPUARCH} == "arm" +SRCS+= aeabi_div0.c +SRCS+= aeabi_idivmod.S +SRCS+= aeabi_ldivmod.S +SRCS+= aeabi_memcmp.S +SRCS+= aeabi_memcpy.S +SRCS+= aeabi_memmove.S +SRCS+= aeabi_memset.S +SRCS+= aeabi_uidivmod.S +SRCS+= aeabi_uldivmod.S +SRCS+= bswapdi2.S +SRCS+= bswapsi2.S +SRCS+= switch16.S +SRCS+= switch32.S +SRCS+= switch8.S +SRCS+= switchu8.S +SRCS+= sync_synchronize.S +.endif From 92a85eb9d767e97489bd423ee3a55bd58f961575 Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Tue, 27 Sep 2016 20:40:44 +0000 Subject: [PATCH 49/64] loader command interpreter should reset command_errmsg The command interpreter does leave command_errmsg as is after printing its content, assuming the next command will reset it in bf_command(). However, in case the forth native word is defined as builtin, the bf_command is not used and forth words will also end up the command_errmsg content printed. Since command_errmsg is pointer to actual error message, which can be static read only string, we can not just set *command_errmsg = '\0', instead we need to reset the pointer itself. Illumos issue: https://www.illumos.org/issues/7405 Reported by: Igor Kozhukhov. Reviewed by: allanjude Approved by: allanjude (mentor) Differential Revision: https://reviews.freebsd.org/D8032 --- sys/boot/common/interp_forth.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sys/boot/common/interp_forth.c b/sys/boot/common/interp_forth.c index aedac6af09a2..bd59e0dda096 100644 --- a/sys/boot/common/interp_forth.c +++ b/sys/boot/common/interp_forth.c @@ -325,13 +325,15 @@ bf_run(char *line) printf("Parse error!\n"); break; default: - /* Hopefully, all other codes filled this buffer */ - printf("%s\n", command_errmsg); + if (command_errmsg != NULL) { + printf("%s\n", command_errmsg); + command_errmsg = NULL; + } } if (result == VM_USEREXIT) panic("interpreter exit"); setenv("interpret", bf_vm->state ? "" : "OK", 1); - return result; + return (result); } From e8223cc6cfd838db7f174b22a0e81bed00cc48dc Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Wed, 28 Sep 2016 04:08:20 +0000 Subject: [PATCH 50/64] hyperv/vmbus: Add functions to test RX/TX bufring emptiness MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D8044 --- sys/dev/hyperv/include/vmbus.h | 2 ++ sys/dev/hyperv/vmbus/vmbus_brvar.h | 14 ++++++++++++++ sys/dev/hyperv/vmbus/vmbus_chan.c | 14 ++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/sys/dev/hyperv/include/vmbus.h b/sys/dev/hyperv/include/vmbus.h index 090f9b1fcd93..50f3148d35d7 100644 --- a/sys/dev/hyperv/include/vmbus.h +++ b/sys/dev/hyperv/include/vmbus.h @@ -173,5 +173,7 @@ const struct hyperv_guid * vmbus_chan_guid_inst(const struct vmbus_channel *chan); int vmbus_chan_prplist_nelem(int br_size, int prpcnt_max, int dlen_max); +bool vmbus_chan_rx_empty(const struct vmbus_channel *chan); +bool vmbus_chan_tx_empty(const struct vmbus_channel *chan); #endif /* !_VMBUS_H_ */ diff --git a/sys/dev/hyperv/vmbus/vmbus_brvar.h b/sys/dev/hyperv/vmbus/vmbus_brvar.h index bd967f6e869b..cbec3ebdd501 100644 --- a/sys/dev/hyperv/vmbus/vmbus_brvar.h +++ b/sys/dev/hyperv/vmbus/vmbus_brvar.h @@ -83,6 +83,20 @@ vmbus_txbr_maxpktsz(const struct vmbus_txbr *tbr) return (tbr->txbr_dsize - sizeof(uint64_t) - 1); } +static __inline bool +vmbus_txbr_empty(const struct vmbus_txbr *tbr) +{ + + return (tbr->txbr_windex == tbr->txbr_rindex ? true : false); +} + +static __inline bool +vmbus_rxbr_empty(const struct vmbus_rxbr *rbr) +{ + + return (rbr->rxbr_windex == rbr->rxbr_rindex ? true : false); +} + static __inline int vmbus_br_nelem(int br_size, int elem_size) { diff --git a/sys/dev/hyperv/vmbus/vmbus_chan.c b/sys/dev/hyperv/vmbus/vmbus_chan.c index 1cd9d3719de1..68a80d38790e 100644 --- a/sys/dev/hyperv/vmbus/vmbus_chan.c +++ b/sys/dev/hyperv/vmbus/vmbus_chan.c @@ -1692,3 +1692,17 @@ vmbus_chan_prplist_nelem(int br_size, int prpcnt_max, int dlen_max) return (vmbus_br_nelem(br_size, elem_size)); } + +bool +vmbus_chan_tx_empty(const struct vmbus_channel *chan) +{ + + return (vmbus_txbr_empty(&chan->ch_txbr)); +} + +bool +vmbus_chan_rx_empty(const struct vmbus_channel *chan) +{ + + return (vmbus_rxbr_empty(&chan->ch_rxbr)); +} From 5de11ef9510d0129c9a756b008a633ba3113f094 Mon Sep 17 00:00:00 2001 From: Luiz Otavio O Souza Date: Wed, 28 Sep 2016 04:22:06 +0000 Subject: [PATCH 51/64] Fix a typo. Pointy hat to: loos --- sys/arm/ti/cpsw/if_cpsw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/arm/ti/cpsw/if_cpsw.c b/sys/arm/ti/cpsw/if_cpsw.c index 3cc366dd1e51..3d4bc020cb5b 100644 --- a/sys/arm/ti/cpsw/if_cpsw.c +++ b/sys/arm/ti/cpsw/if_cpsw.c @@ -1941,7 +1941,7 @@ cpsw_tx_dequeue(struct cpsw_softc *sc) /* TearDown complete is only marked on the SOP for the packet. */ if ((flags & (CPDMA_BD_SOP | CPDMA_BD_TDOWNCMPLT)) == - (CPDMA_BD_EOP | CPDMA_BD_TDOWNCMPLT)) { + (CPDMA_BD_SOP | CPDMA_BD_TDOWNCMPLT)) { CPSW_DEBUGF(sc, ("TX teardown in progress")); cpsw_write_cp(sc, &sc->tx, 0xfffffffc); // TODO: Increment a count of dropped TX packets From c8e8d13398eef7cf113f121c41c77905c5d4ed3e Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Wed, 28 Sep 2016 04:25:25 +0000 Subject: [PATCH 52/64] hyperv/vmbus: Add function to drain channel interrupt task. MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D8045 --- sys/dev/hyperv/include/vmbus.h | 1 + sys/dev/hyperv/vmbus/vmbus_chan.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/sys/dev/hyperv/include/vmbus.h b/sys/dev/hyperv/include/vmbus.h index 50f3148d35d7..43831eb4b955 100644 --- a/sys/dev/hyperv/include/vmbus.h +++ b/sys/dev/hyperv/include/vmbus.h @@ -133,6 +133,7 @@ int vmbus_chan_open_br(struct vmbus_channel *chan, const struct vmbus_chan_br *cbr, const void *udata, int udlen, vmbus_chan_callback_t cb, void *cbarg); void vmbus_chan_close(struct vmbus_channel *chan); +void vmbus_chan_intr_drain(struct vmbus_channel *chan); int vmbus_chan_gpadl_connect(struct vmbus_channel *chan, bus_addr_t paddr, int size, uint32_t *gpadl); diff --git a/sys/dev/hyperv/vmbus/vmbus_chan.c b/sys/dev/hyperv/vmbus/vmbus_chan.c index 68a80d38790e..e7e194715273 100644 --- a/sys/dev/hyperv/vmbus/vmbus_chan.c +++ b/sys/dev/hyperv/vmbus/vmbus_chan.c @@ -756,6 +756,13 @@ vmbus_chan_close(struct vmbus_channel *chan) vmbus_chan_close_internal(chan); } +void +vmbus_chan_intr_drain(struct vmbus_channel *chan) +{ + + taskqueue_drain(chan->ch_tq, &chan->ch_task); +} + int vmbus_chan_send(struct vmbus_channel *chan, uint16_t type, uint16_t flags, void *data, int dlen, uint64_t xactid) From 65fe5a46278262410804a5f953fef2e10137d0c2 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Wed, 28 Sep 2016 04:34:21 +0000 Subject: [PATCH 53/64] hyperv/hn: Suspend and resume the backend properly upon MTU change. Suspend: - Prevent the backend from being touched on TX path. - Clear the RNDIS RX filter, and wait for RX to drain. - Make sure that NVS see the chimney sending buffer and RXBUF disconnection, before unlink these buffers from the channel. Resume: - Reconfigure the RNDIS filter. - Allow TX path to work on the backend. - Kick start the TX eof task, in case the OACTIVE is set. This fixes various panics, when the interface has traffic and MTU is being changed. MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D8046 --- sys/dev/hyperv/netvsc/hv_net_vsc.c | 21 +++ sys/dev/hyperv/netvsc/hv_net_vsc.h | 1 + sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c | 161 ++++++++++++++++-- 3 files changed, 173 insertions(+), 10 deletions(-) diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.c b/sys/dev/hyperv/netvsc/hv_net_vsc.c index 575f0808bf9b..ad175fc31602 100644 --- a/sys/dev/hyperv/netvsc/hv_net_vsc.c +++ b/sys/dev/hyperv/netvsc/hv_net_vsc.c @@ -348,6 +348,16 @@ hn_nvs_disconn_rxbuf(struct hn_softc *sc) return (error); } sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED; + + /* + * Wait for the hypervisor to receive this NVS request. + */ + while (!vmbus_chan_tx_empty(sc->hn_prichan)) + pause("waittx", 1); + /* + * Linger long enough for NVS to disconnect RXBUF. + */ + pause("lingtx", (200 * hz) / 1000); } if (sc->hn_rxbuf_gpadl != 0) { @@ -389,6 +399,17 @@ hn_nvs_disconn_chim(struct hn_softc *sc) return (error); } sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED; + + /* + * Wait for the hypervisor to receive this NVS request. + */ + while (!vmbus_chan_tx_empty(sc->hn_prichan)) + pause("waittx", 1); + /* + * Linger long enough for NVS to disconnect chimney + * sending buffer. + */ + pause("lingtx", (200 * hz) / 1000); } if (sc->hn_chim_gpadl != 0) { diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.h b/sys/dev/hyperv/netvsc/hv_net_vsc.h index 6f54446e84ee..81e072dd2434 100644 --- a/sys/dev/hyperv/netvsc/hv_net_vsc.h +++ b/sys/dev/hyperv/netvsc/hv_net_vsc.h @@ -178,6 +178,7 @@ struct hn_tx_ring { bus_dma_tag_t hn_tx_data_dtag; uint64_t hn_csum_assist; + int hn_suspended; int hn_gpa_cnt; struct vmbus_gpa hn_gpa[NETVSC_PACKET_MAXPAGE]; diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c index 2c08a2d22158..f52fcf91d9f0 100644 --- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c +++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c @@ -348,6 +348,10 @@ static void hn_detach_allchans(struct hn_softc *); static void hn_chan_callback(struct vmbus_channel *chan, void *xrxr); static void hn_set_ring_inuse(struct hn_softc *, int); static int hn_synth_attach(struct hn_softc *, int); +static bool hn_tx_ring_pending(struct hn_tx_ring *); +static void hn_suspend(struct hn_softc *); +static void hn_resume(struct hn_softc *); +static void hn_tx_ring_qflush(struct hn_tx_ring *); static void hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt); @@ -905,6 +909,23 @@ hn_txdesc_hold(struct hn_txdesc *txd) atomic_add_int(&txd->refs, 1); } +static bool +hn_tx_ring_pending(struct hn_tx_ring *txr) +{ + bool pending = false; + +#ifndef HN_USE_TXDESC_BUFRING + mtx_lock_spin(&txr->hn_txlist_spin); + if (txr->hn_txdesc_avail != txr->hn_txdesc_cnt) + pending = true; + mtx_unlock_spin(&txr->hn_txlist_spin); +#else + if (!buf_ring_full(txr->hn_txdesc_br)) + pending = true; +#endif + return (pending); +} + static __inline void hn_txeof(struct hn_tx_ring *txr) { @@ -1241,6 +1262,9 @@ hn_start_locked(struct hn_tx_ring *txr, int len) KASSERT(txr == &sc->hn_tx_ring[0], ("not the first TX ring")); mtx_assert(&txr->hn_tx_lock, MA_OWNED); + if (__predict_false(txr->hn_suspended)) + return 0; + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) return 0; @@ -1627,6 +1651,9 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp)); #endif + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + hn_suspend(sc); + /* We must remove and add back the device to cause the new * MTU to take effect. This includes tearing down, but not * deleting the channel, then bringing it back up. @@ -1651,7 +1678,9 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax) hn_set_chim_size(sc, sc->hn_chim_szmax); - hn_init_locked(sc); + /* All done! Resume now. */ + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + hn_resume(sc); HN_UNLOCK(sc); break; @@ -2984,6 +3013,9 @@ hn_xmit(struct hn_tx_ring *txr, int len) KASSERT(hn_use_if_start == 0, ("hn_xmit is called, when if_start is enabled")); + if (__predict_false(txr->hn_suspended)) + return 0; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || txr->hn_oactive) return 0; @@ -3069,21 +3101,25 @@ hn_transmit(struct ifnet *ifp, struct mbuf *m) return 0; } +static void +hn_tx_ring_qflush(struct hn_tx_ring *txr) +{ + struct mbuf *m; + + mtx_lock(&txr->hn_tx_lock); + while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL) + m_freem(m); + mtx_unlock(&txr->hn_tx_lock); +} + static void hn_xmit_qflush(struct ifnet *ifp) { struct hn_softc *sc = ifp->if_softc; int i; - for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { - struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; - struct mbuf *m; - - mtx_lock(&txr->hn_tx_lock); - while ((m = buf_ring_dequeue_sc(txr->hn_mbuf_br)) != NULL) - m_freem(m); - mtx_unlock(&txr->hn_tx_lock); - } + for (i = 0; i < sc->hn_tx_ring_inuse; ++i) + hn_tx_ring_qflush(&sc->hn_tx_ring[i]); if_qflush(ifp); } @@ -3502,6 +3538,111 @@ hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt) } } +static void +hn_rx_drain(struct vmbus_channel *chan) +{ + + while (!vmbus_chan_rx_empty(chan) || !vmbus_chan_tx_empty(chan)) + pause("waitch", 1); + vmbus_chan_intr_drain(chan); +} + +static void +hn_suspend(struct hn_softc *sc) +{ + struct vmbus_channel **subch = NULL; + int i, nsubch; + + HN_LOCK_ASSERT(sc); + + /* + * Suspend TX. + */ + for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { + struct hn_tx_ring *txr = &sc->hn_tx_ring[i]; + + mtx_lock(&txr->hn_tx_lock); + txr->hn_suspended = 1; + mtx_unlock(&txr->hn_tx_lock); + /* No one is able send more packets now. */ + + /* Wait for all pending sends to finish. */ + while (hn_tx_ring_pending(txr)) + pause("hnwtx", 1 /* 1 tick */); + } + + /* + * Disable RX. + */ + hv_rf_on_close(sc); + + /* Give RNDIS enough time to flush all pending data packets. */ + pause("waitrx", (200 * hz) / 1000); + + nsubch = sc->hn_rx_ring_inuse - 1; + if (nsubch > 0) + subch = vmbus_subchan_get(sc->hn_prichan, nsubch); + + /* + * Drain RX/TX bufrings and interrupts. + */ + if (subch != NULL) { + for (i = 0; i < nsubch; ++i) + hn_rx_drain(subch[i]); + } + hn_rx_drain(sc->hn_prichan); + + if (subch != NULL) + vmbus_subchan_rel(subch, nsubch); +} + +static void +hn_resume(struct hn_softc *sc) +{ + struct hn_tx_ring *txr; + int i; + + HN_LOCK_ASSERT(sc); + + /* + * Re-enable RX. + */ + hv_rf_on_open(sc); + + /* + * Make sure to clear suspend status on "all" TX rings, + * since hn_tx_ring_inuse can be changed after hn_suspend(). + */ + for (i = 0; i < sc->hn_tx_ring_cnt; ++i) { + txr = &sc->hn_tx_ring[i]; + + mtx_lock(&txr->hn_tx_lock); + txr->hn_suspended = 0; + mtx_unlock(&txr->hn_tx_lock); + } + + if (!hn_use_if_start) { + /* + * Flush unused drbrs, since hn_tx_ring_inuse may be + * reduced. + */ + for (i = sc->hn_tx_ring_inuse; i < sc->hn_tx_ring_cnt; ++i) + hn_tx_ring_qflush(&sc->hn_tx_ring[i]); + } + + /* + * Kick start TX. + */ + for (i = 0; i < sc->hn_tx_ring_inuse; ++i) { + txr = &sc->hn_tx_ring[i]; + /* + * Use txeof task, so that any pending oactive can be + * cleared properly. + */ + taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task); + } +} + static void hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt) { From c04dad64e294c663e431dcfca8c60411fd6b3237 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Wed, 28 Sep 2016 04:45:00 +0000 Subject: [PATCH 54/64] hyperv/hn: Reorganize the synthetic parts detach. MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D8047 --- sys/dev/hyperv/netvsc/hv_net_vsc.c | 20 ++---- sys/dev/hyperv/netvsc/hv_net_vsc.h | 2 - sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c | 64 ++++++++++--------- sys/dev/hyperv/netvsc/hv_rndis_filter.c | 22 ++----- sys/dev/hyperv/netvsc/hv_rndis_filter.h | 1 - sys/dev/hyperv/netvsc/if_hnvar.h | 2 + 6 files changed, 45 insertions(+), 66 deletions(-) diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.c b/sys/dev/hyperv/netvsc/hv_net_vsc.c index ad175fc31602..21504c3584c6 100644 --- a/sys/dev/hyperv/netvsc/hv_net_vsc.c +++ b/sys/dev/hyperv/netvsc/hv_net_vsc.c @@ -618,27 +618,15 @@ hn_nvs_attach(struct hn_softc *sc, int mtu) return (0); } -/* - * Net VSC disconnect from VSP - */ -static void -hv_nv_disconnect_from_vsp(struct hn_softc *sc) +void +hn_nvs_detach(struct hn_softc *sc) { + + /* NOTE: there are no requests to stop the NVS. */ hn_nvs_disconn_rxbuf(sc); hn_nvs_disconn_chim(sc); } -/* - * Net VSC on device remove - */ -int -hv_nv_on_device_remove(struct hn_softc *sc) -{ - - hv_nv_disconnect_from_vsp(sc); - return (0); -} - void hn_nvs_sent_xact(struct hn_send_ctx *sndc, struct hn_softc *sc __unused, struct vmbus_channel *chan __unused, diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.h b/sys/dev/hyperv/netvsc/hv_net_vsc.h index 81e072dd2434..d0f3cc105c1f 100644 --- a/sys/dev/hyperv/netvsc/hv_net_vsc.h +++ b/sys/dev/hyperv/netvsc/hv_net_vsc.h @@ -269,8 +269,6 @@ extern int hv_promisc_mode; struct hn_send_ctx; void netvsc_linkstatus_callback(struct hn_softc *sc, uint32_t status); -int hn_nvs_attach(struct hn_softc *sc, int mtu); -int hv_nv_on_device_remove(struct hn_softc *sc); int hv_nv_on_send(struct vmbus_channel *chan, uint32_t rndis_mtype, struct hn_send_ctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt); diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c index f52fcf91d9f0..816f2c727182 100644 --- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c +++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c @@ -348,6 +348,7 @@ static void hn_detach_allchans(struct hn_softc *); static void hn_chan_callback(struct vmbus_channel *chan, void *xrxr); static void hn_set_ring_inuse(struct hn_softc *, int); static int hn_synth_attach(struct hn_softc *, int); +static void hn_synth_detach(struct hn_softc *); static bool hn_tx_ring_pending(struct hn_tx_ring *); static void hn_suspend(struct hn_softc *); static void hn_resume(struct hn_softc *); @@ -744,29 +745,19 @@ netvsc_attach(device_t dev) } /* - * Standard detach entry point + * TODO: Use this for error handling on attach path. */ static int netvsc_detach(device_t dev) { struct hn_softc *sc = device_get_softc(dev); - if (bootverbose) - printf("netvsc_detach\n"); + /* TODO: ether_ifdetach */ - /* - * XXXKYS: Need to clean up all our - * driver state; this is the driver - * unloading. - */ - - /* - * XXXKYS: Need to stop outgoing traffic and unregister - * the netdevice. - */ - - hv_rf_on_device_remove(sc); - hn_detach_allchans(sc); + HN_LOCK(sc); + /* TODO: hn_stop */ + hn_synth_detach(sc); + HN_UNLOCK(sc); hn_stop_tx_tasks(sc); @@ -779,6 +770,8 @@ netvsc_detach(device_t dev) vmbus_xact_ctx_destroy(sc->hn_xact); HN_LOCK_DESTROY(sc); + + /* TODO: if_free */ return (0); } @@ -1654,23 +1647,14 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if (ifp->if_drv_flags & IFF_DRV_RUNNING) hn_suspend(sc); - /* We must remove and add back the device to cause the new - * MTU to take effect. This includes tearing down, but not - * deleting the channel, then bringing it back up. + /* + * Detach the synthetics parts, i.e. NVS and RNDIS. */ - error = hv_rf_on_device_remove(sc); - if (error) { - HN_UNLOCK(sc); - break; - } + hn_synth_detach(sc); /* - * Detach all of the channels. - */ - hn_detach_allchans(sc); - - /* - * Attach the synthetic parts, i.e. NVS and RNDIS. + * Reattach the synthetic parts, i.e. NVS and RNDIS, + * with the new MTU setting. * XXX check error. */ hn_synth_attach(sc, ifr->ifr_mtu); @@ -3520,6 +3504,26 @@ hn_synth_attach(struct hn_softc *sc, int mtu) return (0); } +/* + * NOTE: + * The interface must have been suspended though hn_suspend(), before + * this function get called. + */ +static void +hn_synth_detach(struct hn_softc *sc) +{ + HN_LOCK_ASSERT(sc); + + /* Detach the RNDIS first. */ + hn_rndis_detach(sc); + + /* Detach NVS. */ + hn_nvs_detach(sc); + + /* Detach all of the channels. */ + hn_detach_allchans(sc); +} + static void hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt) { diff --git a/sys/dev/hyperv/netvsc/hv_rndis_filter.c b/sys/dev/hyperv/netvsc/hv_rndis_filter.c index 451e7d7150d4..46b5641ac51a 100644 --- a/sys/dev/hyperv/netvsc/hv_rndis_filter.c +++ b/sys/dev/hyperv/netvsc/hv_rndis_filter.c @@ -957,11 +957,8 @@ hn_rndis_init(struct hn_softc *sc) return (error); } -/* - * RNDIS filter halt device - */ static int -hv_rf_halt_device(struct hn_softc *sc) +hn_rndis_halt(struct hn_softc *sc) { struct vmbus_xact *xact; struct rndis_halt_req *halt; @@ -1008,21 +1005,12 @@ hn_rndis_attach(struct hn_softc *sc) return (0); } -/* - * RNDIS filter on device remove - */ -int -hv_rf_on_device_remove(struct hn_softc *sc) +void +hn_rndis_detach(struct hn_softc *sc) { - int ret; - /* Halt and release the rndis device */ - ret = hv_rf_halt_device(sc); - - /* Pass control to inner driver to remove the device */ - ret |= hv_nv_on_device_remove(sc); - - return (ret); + /* Halt the RNDIS. */ + hn_rndis_halt(sc); } /* diff --git a/sys/dev/hyperv/netvsc/hv_rndis_filter.h b/sys/dev/hyperv/netvsc/hv_rndis_filter.h index f389cedf283e..f72ab490d761 100644 --- a/sys/dev/hyperv/netvsc/hv_rndis_filter.h +++ b/sys/dev/hyperv/netvsc/hv_rndis_filter.h @@ -43,7 +43,6 @@ struct hn_rx_ring; void hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr, const void *data, int dlen); void hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr); -int hv_rf_on_device_remove(struct hn_softc *sc); int hv_rf_on_open(struct hn_softc *sc); int hv_rf_on_close(struct hn_softc *sc); diff --git a/sys/dev/hyperv/netvsc/if_hnvar.h b/sys/dev/hyperv/netvsc/if_hnvar.h index 38ff16ee72c9..c7db821e1582 100644 --- a/sys/dev/hyperv/netvsc/if_hnvar.h +++ b/sys/dev/hyperv/netvsc/if_hnvar.h @@ -118,6 +118,7 @@ uint32_t hn_chim_alloc(struct hn_softc *sc); void hn_chim_free(struct hn_softc *sc, uint32_t chim_idx); int hn_rndis_attach(struct hn_softc *sc); +void hn_rndis_detach(struct hn_softc *sc); int hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags); void *hn_rndis_pktinfo_append(struct rndis_packet_msg *, size_t pktsize, size_t pi_dlen, uint32_t pi_type); @@ -127,6 +128,7 @@ int hn_rndis_get_linkstatus(struct hn_softc *sc, uint32_t *link_status); int hn_nvs_attach(struct hn_softc *sc, int mtu); +void hn_nvs_detach(struct hn_softc *sc); int hn_nvs_alloc_subchans(struct hn_softc *sc, int *nsubch); void hn_nvs_sent_xact(struct hn_send_ctx *sndc, struct hn_softc *sc, struct vmbus_channel *chan, const void *data, int dlen); From ec3eaa6fb073313c68c3c4f297faac3fcc5227ff Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Wed, 28 Sep 2016 05:01:53 +0000 Subject: [PATCH 55/64] hyperv/hn: Reorder the comment a little bit. MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D8048 --- sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c index 816f2c727182..cff9beb03d86 100644 --- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c +++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c @@ -3580,16 +3580,18 @@ hn_suspend(struct hn_softc *sc) */ hv_rf_on_close(sc); - /* Give RNDIS enough time to flush all pending data packets. */ + /* + * Give RNDIS enough time to flush all pending data packets. + */ pause("waitrx", (200 * hz) / 1000); - nsubch = sc->hn_rx_ring_inuse - 1; - if (nsubch > 0) - subch = vmbus_subchan_get(sc->hn_prichan, nsubch); - /* * Drain RX/TX bufrings and interrupts. */ + nsubch = sc->hn_rx_ring_inuse - 1; + if (nsubch > 0) + subch = vmbus_subchan_get(sc->hn_prichan, nsubch); + if (subch != NULL) { for (i = 0; i < nsubch; ++i) hn_rx_drain(subch[i]); From 2f1f7f4527d2ad33fd69a36085232711801f5399 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Wed, 28 Sep 2016 05:12:09 +0000 Subject: [PATCH 56/64] hyperv/hn: Flatten RX filter configuration. This paves way for more fixes. MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D8049 --- sys/dev/hyperv/netvsc/hv_net_vsc.h | 1 - sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c | 19 ++++++------ sys/dev/hyperv/netvsc/hv_rndis_filter.c | 31 +------------------ sys/dev/hyperv/netvsc/hv_rndis_filter.h | 2 -- sys/dev/hyperv/netvsc/if_hnvar.h | 2 ++ 5 files changed, 12 insertions(+), 43 deletions(-) diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.h b/sys/dev/hyperv/netvsc/hv_net_vsc.h index d0f3cc105c1f..ce94f4e0ee6f 100644 --- a/sys/dev/hyperv/netvsc/hv_net_vsc.h +++ b/sys/dev/hyperv/netvsc/hv_net_vsc.h @@ -265,7 +265,6 @@ struct hn_softc { /* * Externs */ -extern int hv_promisc_mode; struct hn_send_ctx; void netvsc_linkstatus_callback(struct hn_softc *sc, uint32_t status); diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c index cff9beb03d86..f869fe52751e 100644 --- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c +++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c @@ -205,8 +205,6 @@ struct hn_txdesc { * Globals */ -int hv_promisc_mode = 0; /* normal mode by default */ - SYSCTL_NODE(_hw, OID_AUTO, hn, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Hyper-V network interface"); @@ -1779,7 +1777,7 @@ static void hn_stop(struct hn_softc *sc) { struct ifnet *ifp; - int ret, i; + int i; HN_LOCK_ASSERT(sc); @@ -1795,7 +1793,8 @@ hn_stop(struct hn_softc *sc) if_link_state_change(ifp, LINK_STATE_DOWN); - ret = hv_rf_on_close(sc); + /* Disable RX by clearing RX filter. */ + hn_rndis_set_rxfilter(sc, 0); } /* @@ -1870,9 +1869,8 @@ hn_init_locked(struct hn_softc *sc) return; } - hv_promisc_mode = 1; - - ret = hv_rf_on_open(sc); + /* TODO: add hn_rx_filter */ + ret = hn_rndis_set_rxfilter(sc, NDIS_PACKET_TYPE_PROMISCUOUS); if (ret != 0) return; @@ -3576,9 +3574,9 @@ hn_suspend(struct hn_softc *sc) } /* - * Disable RX. + * Disable RX by clearing RX filter. */ - hv_rf_on_close(sc); + hn_rndis_set_rxfilter(sc, 0); /* * Give RNDIS enough time to flush all pending data packets. @@ -3612,8 +3610,9 @@ hn_resume(struct hn_softc *sc) /* * Re-enable RX. + * TODO: add hn_rx_filter. */ - hv_rf_on_open(sc); + hn_rndis_set_rxfilter(sc, NDIS_PACKET_TYPE_PROMISCUOUS); /* * Make sure to clear suspend status on "all" TX rings, diff --git a/sys/dev/hyperv/netvsc/hv_rndis_filter.c b/sys/dev/hyperv/netvsc/hv_rndis_filter.c index 46b5641ac51a..ddd07d551616 100644 --- a/sys/dev/hyperv/netvsc/hv_rndis_filter.c +++ b/sys/dev/hyperv/netvsc/hv_rndis_filter.c @@ -887,7 +887,7 @@ hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags) return (error); } -static int +int hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter) { int error; @@ -1013,35 +1013,6 @@ hn_rndis_detach(struct hn_softc *sc) hn_rndis_halt(sc); } -/* - * RNDIS filter on open - */ -int -hv_rf_on_open(struct hn_softc *sc) -{ - uint32_t filter; - - /* XXX */ - if (hv_promisc_mode != 1) { - filter = NDIS_PACKET_TYPE_BROADCAST | - NDIS_PACKET_TYPE_ALL_MULTICAST | - NDIS_PACKET_TYPE_DIRECTED; - } else { - filter = NDIS_PACKET_TYPE_PROMISCUOUS; - } - return (hn_rndis_set_rxfilter(sc, filter)); -} - -/* - * RNDIS filter on close - */ -int -hv_rf_on_close(struct hn_softc *sc) -{ - - return (hn_rndis_set_rxfilter(sc, 0)); -} - void hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr) { diff --git a/sys/dev/hyperv/netvsc/hv_rndis_filter.h b/sys/dev/hyperv/netvsc/hv_rndis_filter.h index f72ab490d761..3ecda3b80d03 100644 --- a/sys/dev/hyperv/netvsc/hv_rndis_filter.h +++ b/sys/dev/hyperv/netvsc/hv_rndis_filter.h @@ -43,8 +43,6 @@ struct hn_rx_ring; void hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr, const void *data, int dlen); void hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr); -int hv_rf_on_open(struct hn_softc *sc); -int hv_rf_on_close(struct hn_softc *sc); #endif /* __HV_RNDIS_FILTER_H__ */ diff --git a/sys/dev/hyperv/netvsc/if_hnvar.h b/sys/dev/hyperv/netvsc/if_hnvar.h index c7db821e1582..e48033c35ab3 100644 --- a/sys/dev/hyperv/netvsc/if_hnvar.h +++ b/sys/dev/hyperv/netvsc/if_hnvar.h @@ -126,6 +126,8 @@ int hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt); int hn_rndis_get_eaddr(struct hn_softc *sc, uint8_t *eaddr); int hn_rndis_get_linkstatus(struct hn_softc *sc, uint32_t *link_status); +/* filter: NDIS_PACKET_TYPE_ or 0. */ +int hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter); int hn_nvs_attach(struct hn_softc *sc, int mtu); void hn_nvs_detach(struct hn_softc *sc); From 090aa8d18b226ce43b6ff129f47b1c7c47635874 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Wed, 28 Sep 2016 08:11:00 +0000 Subject: [PATCH 57/64] Increase timeouts for geli tests. It takes 2-3x more time to proceed the tests on MIPS64EB in QEMU. Sponsored by: DARPA, AFRL Sponsored by: HEIF5 --- tests/sys/geom/class/eli/Makefile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/sys/geom/class/eli/Makefile b/tests/sys/geom/class/eli/Makefile index d827e1f48d90..a84b93fd2512 100644 --- a/tests/sys/geom/class/eli/Makefile +++ b/tests/sys/geom/class/eli/Makefile @@ -25,13 +25,13 @@ TAP_TESTS_SH+= readonly_test TAP_TESTS_SH+= resize_test TAP_TESTS_SH+= setkey_test -TEST_METADATA.init_a_test+= timeout="1200" -TEST_METADATA.init_test+= timeout="300" -TEST_METADATA.integrity_copy_test+= timeout="1200" -TEST_METADATA.integrity_data_test+= timeout="600" -TEST_METADATA.integrity_hmac_test+= timeout="600" -TEST_METADATA.onetime_a_test+= timeout="600" -TEST_METADATA.onetime_test+= timeout="600" +TEST_METADATA.init_a_test+= timeout="3600" +TEST_METADATA.init_test+= timeout="600" +TEST_METADATA.integrity_copy_test+= timeout="3600" +TEST_METADATA.integrity_data_test+= timeout="1800" +TEST_METADATA.integrity_hmac_test+= timeout="1800" +TEST_METADATA.onetime_a_test+= timeout="1800" +TEST_METADATA.onetime_test+= timeout="1800" ${PACKAGE}FILES+= conf.sh From a11463fd84f836160303802a7506598c3923bd31 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Wed, 28 Sep 2016 08:35:05 +0000 Subject: [PATCH 58/64] cam/ata: Allow drivers to veto ATA disk attachment. This eventhandler is mainly used by VMs, e.g. Hyper-V, whose disk controllers share the disks with the simulated ATA controllers. Submitted by: Hongjiang Zhang Discussed with: mav MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7693 --- sys/cam/ata/ata_xpt.c | 13 +++++++++++++ sys/sys/eventhandler.h | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c index d2c97601a8d0..71445e65331b 100644 --- a/sys/cam/ata/ata_xpt.c +++ b/sys/cam/ata/ata_xpt.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -872,12 +873,24 @@ device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { struct ccb_pathinq cpi; int16_t *ptr; + int veto = 0; ident_buf = &softc->ident_data; for (ptr = (int16_t *)ident_buf; ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { *ptr = le16toh(*ptr); } + + /* + * Allow others to veto this ATA disk attachment. This + * is mainly used by VMs, whose disk controllers may + * share the disks with the simulated ATA controllers. + */ + EVENTHANDLER_INVOKE(ada_probe_veto, path, ident_buf, &veto); + if (veto) { + goto device_fail; + } + if (strncmp(ident_buf->model, "FX", 2) && strncmp(ident_buf->model, "NEC", 3) && strncmp(ident_buf->model, "Pioneer", 7) && diff --git a/sys/sys/eventhandler.h b/sys/sys/eventhandler.h index d82ece71eda9..164b0f07293d 100644 --- a/sys/sys/eventhandler.h +++ b/sys/sys/eventhandler.h @@ -270,4 +270,11 @@ typedef void (*unregister_framebuffer_fn)(void *, struct fb_info *); EVENTHANDLER_DECLARE(register_framebuffer, register_framebuffer_fn); EVENTHANDLER_DECLARE(unregister_framebuffer, unregister_framebuffer_fn); +/* Veto ada attachment */ +struct cam_path; +struct ata_params; +typedef void (*ada_probe_veto_fn)(void *, struct cam_path *, + struct ata_params *, int *); +EVENTHANDLER_DECLARE(ada_probe_veto, ada_probe_veto_fn); + #endif /* _SYS_EVENTHANDLER_H_ */ From de1a9339ea84c61f0e980f15d8c34b7a679f4090 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Wed, 28 Sep 2016 08:45:42 +0000 Subject: [PATCH 59/64] Use right piece of code for FreeBSD. Sponsored by: DARPA, AFRL Sponsored by: HEIF5 --- contrib/netbsd-tests/lib/libc/gen/t_nice.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/netbsd-tests/lib/libc/gen/t_nice.c b/contrib/netbsd-tests/lib/libc/gen/t_nice.c index 7c6d23287dd8..9a0eac7b467c 100644 --- a/contrib/netbsd-tests/lib/libc/gen/t_nice.c +++ b/contrib/netbsd-tests/lib/libc/gen/t_nice.c @@ -125,7 +125,7 @@ ATF_TC_BODY(nice_priority, tc) if (pid == 0) { errno = 0; -#ifdef __FreeBSD__ +#ifdef __NetBSD__ pri = getpriority(PRIO_PROCESS, 0); #else pri2 = getpriority(PRIO_PROCESS, 0); From 2d1c3844700ce11c949362807cbc033c7f5f2cf3 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Wed, 28 Sep 2016 12:23:46 +0000 Subject: [PATCH 60/64] Fill all the siginfo so we have si_value set as well. This fixes timer_create(2) tests. Sponsored by: DARPA, AFRL Sponsored by: HEIF5 --- sys/mips/mips/pm_machdep.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/mips/mips/pm_machdep.c b/sys/mips/mips/pm_machdep.c index 02f915eb512c..577d1104690a 100644 --- a/sys/mips/mips/pm_machdep.c +++ b/sys/mips/mips/pm_machdep.c @@ -143,6 +143,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) /* sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; */ /* fill siginfo structure */ + sf.sf_si = ksi->ksi_info; sf.sf_si.si_signo = sig; sf.sf_si.si_code = ksi->ksi_code; sf.sf_si.si_addr = (void*)(intptr_t)regs->badvaddr; From c7641cd18dfb14591181a493b176227da07e3a3e Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Wed, 28 Sep 2016 13:29:11 +0000 Subject: [PATCH 61/64] Remove ifa_list, use ifa_link (structure field) instead. While here, prefer if_addrhead (FreeBSD) to if_addrlist (BSD compat) naming for the interface address list in sctp_bsd_addr.c Reviewed by: tuexen Differential Revision: https://reviews.freebsd.org/D8051 --- sys/net/if_var.h | 3 --- sys/netinet/sctp_bsd_addr.c | 4 ++-- sys/netpfil/pf/pf_if.c | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/sys/net/if_var.h b/sys/net/if_var.h index d04c871d1f22..191fc87f38a7 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -448,9 +448,6 @@ struct ifaddr { counter_u64_t ifa_obytes; }; -/* For compatibility with other BSDs. SCTP uses it. */ -#define ifa_list ifa_link - struct ifaddr * ifa_alloc(size_t size, int flags); void ifa_free(struct ifaddr *ifa); void ifa_ref(struct ifaddr *ifa); diff --git a/sys/netinet/sctp_bsd_addr.c b/sys/netinet/sctp_bsd_addr.c index deb73e7f4d6b..2cd0416606c4 100644 --- a/sys/netinet/sctp_bsd_addr.c +++ b/sys/netinet/sctp_bsd_addr.c @@ -214,7 +214,7 @@ sctp_init_ifns_for_vrf(int vrfid) continue; } IF_ADDR_RLOCK(ifn); - TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) { + TAILQ_FOREACH(ifa, &ifn->if_addrhead, ifa_link) { if (ifa->ifa_addr == NULL) { continue; } @@ -365,7 +365,7 @@ void if (!(*pred) (ifn)) { continue; } - TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) { + TAILQ_FOREACH(ifa, &ifn->if_addrhead, ifa_link) { sctp_addr_change(ifa, add ? RTM_ADD : RTM_DELETE); } } diff --git a/sys/netpfil/pf/pf_if.c b/sys/netpfil/pf/pf_if.c index 4c05cd2f2f8e..c5c8b5a876f7 100644 --- a/sys/netpfil/pf/pf_if.c +++ b/sys/netpfil/pf/pf_if.c @@ -523,7 +523,7 @@ pfi_instance_add(struct ifnet *ifp, int net, int flags) int net2, af; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_list) { + TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) { if (ia->ifa_addr == NULL) continue; af = ia->ifa_addr->sa_family; From 3af5cc2e50d00665c05a0d89626cbcae6f49cbdf Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Wed, 28 Sep 2016 14:13:41 +0000 Subject: [PATCH 62/64] Use SIGSEGV signal for memory protection failures from userspace on MIPS. (same as ARMv8, RISC-V and other architectures do). This makes mmap tests happy. Sponsored by: DARPA, AFRL Sponsored by: HEIF5 --- sys/mips/mips/trap.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c index e071e34bef6f..e14b12be2139 100644 --- a/sys/mips/mips/trap.c +++ b/sys/mips/mips/trap.c @@ -741,8 +741,11 @@ trap(struct trapframe *trapframe) } goto err; } - ucode = ftype; - i = ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); + i = SIGSEGV; + if (rv == KERN_PROTECTION_FAILURE) + ucode = SEGV_ACCERR; + else + ucode = SEGV_MAPERR; addr = trapframe->pc; msg = "BAD_PAGE_FAULT"; From dcdfa506cc92dedc9e4189d6ee2d33171914532d Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Wed, 28 Sep 2016 14:48:34 +0000 Subject: [PATCH 63/64] libm: fix some unused variable (rcsid) and dangling else warnings s_{fabs,fmax,logb,scalb}{,f,l}.c may be built elsewhere with a higher WARNS setting. Reviewed by: ed Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D8061 --- lib/msun/src/s_fabs.c | 5 ++--- lib/msun/src/s_logbl.c | 5 ++--- lib/msun/src/s_scalbn.c | 12 ++++++------ lib/msun/src/s_scalbnf.c | 11 +++++------ lib/msun/src/s_scalbnl.c | 12 ++++++------ 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/lib/msun/src/s_fabs.c b/lib/msun/src/s_fabs.c index 15529e58576f..48aab252db3c 100644 --- a/lib/msun/src/s_fabs.c +++ b/lib/msun/src/s_fabs.c @@ -10,9 +10,8 @@ * ==================================================== */ -#ifndef lint -static char rcsid[] = "$FreeBSD$"; -#endif +#include +__FBSDID("$FreeBSD$"); /* * fabs(x) returns the absolute value of x. diff --git a/lib/msun/src/s_logbl.c b/lib/msun/src/s_logbl.c index 7e88e36f6ab4..ee1a91fd8385 100644 --- a/lib/msun/src/s_logbl.c +++ b/lib/msun/src/s_logbl.c @@ -10,9 +10,8 @@ * ==================================================== */ -#ifndef lint -static char rcsid[] = "$FreeBSD$"; -#endif +#include +__FBSDID("$FreeBSD$"); #include #include diff --git a/lib/msun/src/s_scalbn.c b/lib/msun/src/s_scalbn.c index e7efaabbf559..b048b0596b67 100644 --- a/lib/msun/src/s_scalbn.c +++ b/lib/msun/src/s_scalbn.c @@ -10,9 +10,8 @@ * ==================================================== */ -#ifndef lint -static char rcsid[] = "$FreeBSD$"; -#endif +#include +__FBSDID("$FreeBSD$"); /* * scalbn (double x, int n) @@ -21,7 +20,6 @@ static char rcsid[] = "$FreeBSD$"; * exponentiation or a multiplication. */ -#include #include #include "math.h" @@ -51,10 +49,12 @@ scalbn (double x, int n) if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */ if (k > 0) /* normal result */ {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;} - if (k <= -54) + if (k <= -54) { if (n > 50000) /* in case integer overflow in n+k */ return huge*copysign(huge,x); /*overflow*/ - else return tiny*copysign(tiny,x); /*underflow*/ + else + return tiny*copysign(tiny,x); /*underflow*/ + } k += 54; /* subnormal result */ SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x*twom54; diff --git a/lib/msun/src/s_scalbnf.c b/lib/msun/src/s_scalbnf.c index 7666c74ab22c..21d001c1faf1 100644 --- a/lib/msun/src/s_scalbnf.c +++ b/lib/msun/src/s_scalbnf.c @@ -13,11 +13,8 @@ * ==================================================== */ -#ifndef lint -static char rcsid[] = "$FreeBSD$"; -#endif - #include +__FBSDID("$FreeBSD$"); #include "math.h" #include "math_private.h" @@ -46,10 +43,12 @@ scalbnf (float x, int n) if (k > 0xfe) return huge*copysignf(huge,x); /* overflow */ if (k > 0) /* normal result */ {SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); return x;} - if (k <= -25) + if (k <= -25) { if (n > 50000) /* in case integer overflow in n+k */ return huge*copysignf(huge,x); /*overflow*/ - else return tiny*copysignf(tiny,x); /*underflow*/ + else + return tiny*copysignf(tiny,x); /*underflow*/ + } k += 25; /* subnormal result */ SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); return x*twom25; diff --git a/lib/msun/src/s_scalbnl.c b/lib/msun/src/s_scalbnl.c index fc89f8d8ac5d..28b0cf9b7294 100644 --- a/lib/msun/src/s_scalbnl.c +++ b/lib/msun/src/s_scalbnl.c @@ -10,9 +10,8 @@ * ==================================================== */ -#ifndef lint -static char rcsid[] = "$FreeBSD$"; -#endif +#include +__FBSDID("$FreeBSD$"); /* * scalbnl (long double x, int n) @@ -27,7 +26,6 @@ static char rcsid[] = "$FreeBSD$"; * for scalbn(), so we don't use this routine. */ -#include #include #include @@ -59,10 +57,12 @@ scalbnl (long double x, int n) if (k >= 0x7fff) return huge*copysignl(huge,x); /* overflow */ if (k > 0) /* normal result */ {u.bits.exp = k; return u.e;} - if (k <= -128) + if (k <= -128) { if (n > 50000) /* in case integer overflow in n+k */ return huge*copysign(huge,x); /*overflow*/ - else return tiny*copysign(tiny,x); /*underflow*/ + else + return tiny*copysign(tiny,x); /*underflow*/ + } k += 128; /* subnormal result */ u.bits.exp = k; return u.e*0x1p-128; From d6e65178c62ff02d5fab093fba302bf3a9e93e8e Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Wed, 28 Sep 2016 17:44:03 +0000 Subject: [PATCH 64/64] libm: simplify i387 subdir logic with make's :S substitution --- lib/msun/Makefile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/msun/Makefile b/lib/msun/Makefile index 820855c86a75..ce586d8afed4 100644 --- a/lib/msun/Makefile +++ b/lib/msun/Makefile @@ -13,11 +13,7 @@ # PACKAGE= clibs -.if ${MACHINE_CPUARCH} == "i386" -ARCH_SUBDIR= i387 -.else -ARCH_SUBDIR= ${MACHINE_CPUARCH} -.endif +ARCH_SUBDIR= ${MACHINE_CPUARCH:S/i386/i387/} .include "${ARCH_SUBDIR}/Makefile.inc"