Date: Tue, 2 Aug 2016 15:52:14 +0000 (UTC) From: Alan Cox <alc@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r303667 - in user/alc/PQ_LAUNDRY: sbin/pfctl sys/arm64/arm64 sys/boot/fdt/dts/riscv sys/cddl/contrib/opensolaris/uts/common/sys sys/cddl/dev/dtrace/riscv sys/conf sys/kern sys/netinet s... Message-ID: <201608021552.u72FqEjN006587@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: alc Date: Tue Aug 2 15:52:14 2016 New Revision: 303667 URL: https://svnweb.freebsd.org/changeset/base/303667 Log: MFH r303666 Modified: user/alc/PQ_LAUNDRY/sbin/pfctl/parse.y user/alc/PQ_LAUNDRY/sys/arm64/arm64/pmap.c user/alc/PQ_LAUNDRY/sys/boot/fdt/dts/riscv/spike.dts user/alc/PQ_LAUNDRY/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h user/alc/PQ_LAUNDRY/sys/cddl/dev/dtrace/riscv/dtrace_asm.S user/alc/PQ_LAUNDRY/sys/cddl/dev/dtrace/riscv/dtrace_subr.c user/alc/PQ_LAUNDRY/sys/conf/ldscript.riscv user/alc/PQ_LAUNDRY/sys/kern/kern_mutex.c user/alc/PQ_LAUNDRY/sys/kern/kern_rwlock.c user/alc/PQ_LAUNDRY/sys/kern/kern_sx.c user/alc/PQ_LAUNDRY/sys/netinet/tcp_lro.c user/alc/PQ_LAUNDRY/sys/netinet/tcp_lro.h user/alc/PQ_LAUNDRY/sys/netinet6/ip6_output.c user/alc/PQ_LAUNDRY/sys/riscv/conf/GENERIC user/alc/PQ_LAUNDRY/sys/riscv/htif/htif.c user/alc/PQ_LAUNDRY/sys/riscv/htif/htif_block.c user/alc/PQ_LAUNDRY/sys/riscv/htif/htif_console.c user/alc/PQ_LAUNDRY/sys/riscv/include/cpu.h user/alc/PQ_LAUNDRY/sys/riscv/include/cpufunc.h user/alc/PQ_LAUNDRY/sys/riscv/include/db_machdep.h user/alc/PQ_LAUNDRY/sys/riscv/include/intr.h user/alc/PQ_LAUNDRY/sys/riscv/include/pte.h user/alc/PQ_LAUNDRY/sys/riscv/include/riscvreg.h user/alc/PQ_LAUNDRY/sys/riscv/include/vmparam.h user/alc/PQ_LAUNDRY/sys/riscv/riscv/exception.S user/alc/PQ_LAUNDRY/sys/riscv/riscv/genassym.c user/alc/PQ_LAUNDRY/sys/riscv/riscv/identcpu.c user/alc/PQ_LAUNDRY/sys/riscv/riscv/intr_machdep.c user/alc/PQ_LAUNDRY/sys/riscv/riscv/locore.S user/alc/PQ_LAUNDRY/sys/riscv/riscv/machdep.c user/alc/PQ_LAUNDRY/sys/riscv/riscv/pmap.c user/alc/PQ_LAUNDRY/sys/riscv/riscv/swtch.S user/alc/PQ_LAUNDRY/sys/riscv/riscv/timer.c user/alc/PQ_LAUNDRY/sys/riscv/riscv/trap.c user/alc/PQ_LAUNDRY/sys/riscv/riscv/vm_machdep.c user/alc/PQ_LAUNDRY/usr.bin/sed/Makefile user/alc/PQ_LAUNDRY/usr.bin/sed/compile.c user/alc/PQ_LAUNDRY/usr.bin/sed/defs.h user/alc/PQ_LAUNDRY/usr.bin/sed/extern.h user/alc/PQ_LAUNDRY/usr.bin/sed/main.c user/alc/PQ_LAUNDRY/usr.bin/sed/misc.c user/alc/PQ_LAUNDRY/usr.bin/sed/process.c Directory Properties: user/alc/PQ_LAUNDRY/ (props changed) user/alc/PQ_LAUNDRY/sys/cddl/contrib/opensolaris/ (props changed) Modified: user/alc/PQ_LAUNDRY/sbin/pfctl/parse.y ============================================================================== --- user/alc/PQ_LAUNDRY/sbin/pfctl/parse.y Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sbin/pfctl/parse.y Tue Aug 2 15:52:14 2016 (r303667) @@ -3593,8 +3593,8 @@ tos : STRING { else if ($1[0] == '0' && $1[1] == 'x') $$ = strtoul($1, NULL, 16); else - $$ = 0; /* flag bad argument */ - if (!$$ || $$ > 255) { + $$ = 256; /* flag bad argument */ + if ($$ < 0 || $$ > 255) { yyerror("illegal tos value %s", $1); free($1); YYERROR; @@ -3603,7 +3603,7 @@ tos : STRING { } | NUMBER { $$ = $1; - if (!$$ || $$ > 255) { + if ($$ < 0 || $$ > 255) { yyerror("illegal tos value %s", $1); YYERROR; } Modified: user/alc/PQ_LAUNDRY/sys/arm64/arm64/pmap.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/arm64/arm64/pmap.c Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/arm64/arm64/pmap.c Tue Aug 2 15:52:14 2016 (r303667) @@ -782,7 +782,7 @@ pmap_bootstrap(vm_offset_t l0pt, vm_offs virtual_avail = roundup2(freemempos, L1_SIZE); virtual_end = VM_MAX_KERNEL_ADDRESS - L2_SIZE; kernel_vm_end = virtual_avail; - + pa = pmap_early_vtophys(l1pt, freemempos); /* Finish initialising physmap */ @@ -908,7 +908,7 @@ pmap_invalidate_all(pmap_t pmap) * Extract the physical page address associated * with the given map/virtual_address pair. */ -vm_paddr_t +vm_paddr_t pmap_extract(pmap_t pmap, vm_offset_t va) { pt_entry_t *pte, tpte; @@ -1243,7 +1243,7 @@ pmap_add_delayed_free_list(vm_page_t m, m->flags &= ~PG_ZERO; SLIST_INSERT_HEAD(free, m, plinks.s.ss); } - + /* * Decrements a page table page's wire count, which is used to record the * number of valid page table entries within the page. If the wire count @@ -1321,7 +1321,7 @@ _pmap_unwire_l3(pmap_t pmap, vm_offset_t */ atomic_subtract_rel_int(&vm_cnt.v_wire_count, 1); - /* + /* * Put page on a list so that it is released after * *ALL* TLB shootdown is done */ @@ -1591,7 +1591,7 @@ kvm_size(SYSCTL_HANDLER_ARGS) return sysctl_handle_long(oidp, &ksize, 0, req); } -SYSCTL_PROC(_vm, OID_AUTO, kvm_size, CTLTYPE_LONG|CTLFLAG_RD, +SYSCTL_PROC(_vm, OID_AUTO, kvm_size, CTLTYPE_LONG|CTLFLAG_RD, 0, 0, kvm_size, "LU", "Size of KVM"); static int @@ -1601,7 +1601,7 @@ kvm_free(SYSCTL_HANDLER_ARGS) return sysctl_handle_long(oidp, &kfree, 0, req); } -SYSCTL_PROC(_vm, OID_AUTO, kvm_free, CTLTYPE_LONG|CTLFLAG_RD, +SYSCTL_PROC(_vm, OID_AUTO, kvm_free, CTLTYPE_LONG|CTLFLAG_RD, 0, 0, kvm_free, "LU", "Amount of KVM free"); #endif /* 0 */ @@ -1645,7 +1645,7 @@ pmap_growkernel(vm_offset_t addr) kernel_vm_end = (kernel_vm_end + L2_SIZE) & ~L2_OFFSET; if (kernel_vm_end - 1 >= kernel_map->max_offset) { kernel_vm_end = kernel_map->max_offset; - break; + break; } continue; } @@ -1665,7 +1665,7 @@ pmap_growkernel(vm_offset_t addr) kernel_vm_end = (kernel_vm_end + L2_SIZE) & ~L2_OFFSET; if (kernel_vm_end - 1 >= kernel_map->max_offset) { kernel_vm_end = kernel_map->max_offset; - break; + break; } } } @@ -1926,7 +1926,7 @@ pmap_try_insert_pv_entry(pmap_t pmap, vm * pmap_remove_l3: do the things to unmap a page in a process */ static int -pmap_remove_l3(pmap_t pmap, pt_entry_t *l3, vm_offset_t va, +pmap_remove_l3(pmap_t pmap, pt_entry_t *l3, vm_offset_t va, pd_entry_t l2e, struct spglist *free, struct rwlock **lockp) { pt_entry_t old_l3; @@ -2057,7 +2057,7 @@ pmap_remove(pmap_t pmap, vm_offset_t sva rw_wunlock(lock); if (anyvalid) pmap_invalidate_all(pmap); - rw_runlock(&pvh_global_lock); + rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); pmap_free_zero_pages(&free); } @@ -2724,7 +2724,7 @@ pmap_zero_page(vm_page_t m) } /* - * pmap_zero_page_area zeros the specified hardware page by mapping + * pmap_zero_page_area zeros the specified hardware page by mapping * the page into KVM and using bzero to clear its contents. * * off and size may not cover an area beyond a single hardware page. @@ -2741,7 +2741,7 @@ pmap_zero_page_area(vm_page_t m, int off } /* - * pmap_zero_page_idle zeros the specified hardware page by mapping + * pmap_zero_page_idle zeros the specified hardware page by mapping * the page into KVM and using bzero to clear its contents. This * is intended to be called from the vm_pagezero process only and * outside of Giant. @@ -2902,7 +2902,7 @@ restart: * Destroy all managed, non-wired mappings in the given user-space * pmap. This pmap cannot be active on any processor besides the * caller. - * + * * This function cannot be applied to the kernel pmap. Moreover, it * is not intended for general use. It is only to be used during * process termination. Consequently, it can be implemented in ways Modified: user/alc/PQ_LAUNDRY/sys/boot/fdt/dts/riscv/spike.dts ============================================================================== --- user/alc/PQ_LAUNDRY/sys/boot/fdt/dts/riscv/spike.dts Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/boot/fdt/dts/riscv/spike.dts Tue Aug 2 15:52:14 2016 (r303667) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> + * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com> * All rights reserved. * * Portions of this software were developed by SRI International and the @@ -37,8 +37,8 @@ /dts-v1/; / { - model = "UC Berkeley Spike Simulator RV64I"; - compatible = "riscv,rv64i"; + model = "UC Berkeley Spike Simulator RV64"; + compatible = "riscv,rv64"; #address-cells = <1>; #size-cells = <1>; #interrupt-cells = <1>; @@ -49,14 +49,14 @@ cpu@0 { device_type = "cpu"; - compatible = "riscv,rv64i"; - reg = <0x40002000>; + compatible = "riscv,rv64"; + reg = <0x40001000>; }; cpu@1 { device_type = "cpu"; - compatible = "riscv,rv64i"; - reg = <0x4000a000>; + compatible = "riscv,rv64"; + reg = <0x40002000>; }; }; @@ -66,12 +66,12 @@ memory { device_type = "memory"; - reg = <0x0 0x40000000>; /* 1GB at 0x0 */ + reg = <0x80000000 0x40000000>; /* 1GB at 0x80000000 */ }; soc { - #address-cells = <2>; - #size-cells = <2>; + #address-cells = <1>; + #size-cells = <1>; #interrupt-cells = <1>; compatible = "simple-bus"; @@ -84,14 +84,15 @@ timer0: timer@0 { compatible = "riscv,timer"; - interrupts = < 1 >; + reg = < 0x40000000 0x100 >; + interrupts = < 5 >; interrupt-parent = < &pic0 >; clock-frequency = < 1000000 >; }; htif0: htif@0 { compatible = "riscv,htif"; - interrupts = < 0 >; + interrupts = < 1 >; interrupt-parent = < &pic0 >; console0: console@0 { Modified: user/alc/PQ_LAUNDRY/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h ============================================================================== --- user/alc/PQ_LAUNDRY/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h Tue Aug 2 15:52:14 2016 (r303667) @@ -2498,8 +2498,8 @@ extern void dtrace_helpers_destroy(proc_ #elif defined(__riscv__) -#define SD_RA_SP_MASK 0x1fff07f -#define SD_RA_SP 0x0113023 +#define SD_RA_SP_MASK 0x01fff07f +#define SD_RA_SP 0x00113023 #define DTRACE_INVOP_SD 1 #define DTRACE_INVOP_RET 2 Modified: user/alc/PQ_LAUNDRY/sys/cddl/dev/dtrace/riscv/dtrace_asm.S ============================================================================== --- user/alc/PQ_LAUNDRY/sys/cddl/dev/dtrace/riscv/dtrace_asm.S Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/cddl/dev/dtrace/riscv/dtrace_asm.S Tue Aug 2 15:52:14 2016 (r303667) @@ -57,8 +57,8 @@ END(dtrace_membar_consumer) dtrace_icookie_t dtrace_interrupt_disable(void) */ ENTRY(dtrace_interrupt_disable) - csrrci a0, sstatus, SSTATUS_IE - andi a0, a0, SSTATUS_IE + csrrci a0, sstatus, (SSTATUS_SIE) + andi a0, a0, (SSTATUS_SIE) RET END(dtrace_interrupt_disable) Modified: user/alc/PQ_LAUNDRY/sys/cddl/dev/dtrace/riscv/dtrace_subr.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/cddl/dev/dtrace/riscv/dtrace_subr.c Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/cddl/dev/dtrace/riscv/dtrace_subr.c Tue Aug 2 15:52:14 2016 (r303667) @@ -203,9 +203,9 @@ dtrace_trap(struct trapframe *frame, u_i * All the rest will be handled in the usual way. */ switch (type) { - case EXCP_LOAD_ACCESS_FAULT: - case EXCP_STORE_ACCESS_FAULT: - case EXCP_INSTR_ACCESS_FAULT: + case EXCP_FAULT_LOAD: + case EXCP_FAULT_STORE: + case EXCP_FAULT_FETCH: /* Flag a bad address. */ cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR; cpu_core[curcpu].cpuc_dtrace_illval = 0; Modified: user/alc/PQ_LAUNDRY/sys/conf/ldscript.riscv ============================================================================== --- user/alc/PQ_LAUNDRY/sys/conf/ldscript.riscv Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/conf/ldscript.riscv Tue Aug 2 15:52:14 2016 (r303667) @@ -6,7 +6,7 @@ SEARCH_DIR(/usr/lib); SECTIONS { /* Read-only sections, merged into text segment: */ - . = kernbase + 0x100; + . = kernbase + 0x80000000 /* KERNENTRY */; .text : AT(ADDR(.text) - kernbase) { *(.text) Modified: user/alc/PQ_LAUNDRY/sys/kern/kern_mutex.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/kern/kern_mutex.c Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/kern/kern_mutex.c Tue Aug 2 15:52:14 2016 (r303667) @@ -452,8 +452,10 @@ __mtx_lock_sleep(volatile uintptr_t *c, if (SCHEDULER_STOPPED()) return; -#if defined(ADAPTIVE_MUTEXES) || defined(KDTRACE_HOOKS) +#if defined(ADAPTIVE_MUTEXES) lock_delay_arg_init(&lda, &mtx_delay); +#elif defined(KDTRACE_HOOKS) + lock_delay_arg_init(&lda, NULL); #endif m = mtxlock2mtx(c); Modified: user/alc/PQ_LAUNDRY/sys/kern/kern_rwlock.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/kern/kern_rwlock.c Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/kern/kern_rwlock.c Tue Aug 2 15:52:14 2016 (r303667) @@ -396,8 +396,10 @@ __rw_rlock(volatile uintptr_t *c, const if (SCHEDULER_STOPPED()) return; -#if defined(ADAPTIVE_RWLOCKS) || defined(KDTRACE_HOOKS) +#if defined(ADAPTIVE_RWLOCKS) lock_delay_arg_init(&lda, &rw_delay); +#elif defined(KDTRACE_HOOKS) + lock_delay_arg_init(&lda, NULL); #endif rw = rwlock2rw(c); @@ -782,8 +784,10 @@ __rw_wlock_hard(volatile uintptr_t *c, u if (SCHEDULER_STOPPED()) return; -#if defined(ADAPTIVE_RWLOCKS) || defined(KDTRACE_HOOKS) +#if defined(ADAPTIVE_RWLOCKS) lock_delay_arg_init(&lda, &rw_delay); +#elif defined(KDTRACE_HOOKS) + lock_delay_arg_init(&lda, NULL); #endif rw = rwlock2rw(c); Modified: user/alc/PQ_LAUNDRY/sys/kern/kern_sx.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/kern/kern_sx.c Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/kern/kern_sx.c Tue Aug 2 15:52:14 2016 (r303667) @@ -554,8 +554,10 @@ _sx_xlock_hard(struct sx *sx, uintptr_t if (SCHEDULER_STOPPED()) return (0); -#if defined(ADAPTIVE_SX) || defined(KDTRACE_HOOKS) +#if defined(ADAPTIVE_SX) lock_delay_arg_init(&lda, &sx_delay); +#elif defined(KDTRACE_HOOKS) + lock_delay_arg_init(&lda, NULL); #endif /* If we already hold an exclusive lock, then recurse. */ @@ -861,8 +863,10 @@ _sx_slock_hard(struct sx *sx, int opts, if (SCHEDULER_STOPPED()) return (0); -#if defined(ADAPTIVE_SX) || defined(KDTRACE_HOOKS) +#if defined(ADAPTIVE_SX) lock_delay_arg_init(&lda, &sx_delay); +#elif defined(KDTRACE_HOOKS) + lock_delay_arg_init(&lda, NULL); #endif #ifdef KDTRACE_HOOKS state = sx->sx_lock; Modified: user/alc/PQ_LAUNDRY/sys/netinet/tcp_lro.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/netinet/tcp_lro.c Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/netinet/tcp_lro.c Tue Aug 2 15:52:14 2016 (r303667) @@ -68,19 +68,24 @@ static MALLOC_DEFINE(M_LRO, "LRO", "LRO #endif static void tcp_lro_rx_done(struct lro_ctrl *lc); +static int tcp_lro_rx2(struct lro_ctrl *lc, struct mbuf *m, + uint32_t csum, int use_hash); static __inline void -tcp_lro_active_insert(struct lro_ctrl *lc, struct lro_entry *le) +tcp_lro_active_insert(struct lro_ctrl *lc, struct lro_head *bucket, + struct lro_entry *le) { LIST_INSERT_HEAD(&lc->lro_active, le, next); + LIST_INSERT_HEAD(bucket, le, hash_next); } static __inline void tcp_lro_active_remove(struct lro_entry *le) { - LIST_REMOVE(le, next); + LIST_REMOVE(le, next); /* active list */ + LIST_REMOVE(le, hash_next); /* hash bucket */ } int @@ -95,7 +100,7 @@ tcp_lro_init_args(struct lro_ctrl *lc, s { struct lro_entry *le; size_t size; - unsigned i; + unsigned i, elements; lc->lro_bad_csum = 0; lc->lro_queued = 0; @@ -110,6 +115,18 @@ tcp_lro_init_args(struct lro_ctrl *lc, s LIST_INIT(&lc->lro_free); LIST_INIT(&lc->lro_active); + /* create hash table to accelerate entry lookup */ + if (lro_entries > lro_mbufs) + elements = lro_entries; + else + elements = lro_mbufs; + lc->lro_hash = phashinit_flags(elements, M_LRO, &lc->lro_hashsz, + HASH_NOWAIT); + if (lc->lro_hash == NULL) { + memset(lc, 0, sizeof(*lc)); + return (ENOMEM); + } + /* compute size to allocate */ size = (lro_mbufs * sizeof(struct lro_mbuf_sort)) + (lro_entries * sizeof(*le)); @@ -147,6 +164,13 @@ tcp_lro_free(struct lro_ctrl *lc) m_freem(le->m_head); } + /* free hash table */ + if (lc->lro_hash != NULL) { + free(lc->lro_hash, M_LRO); + lc->lro_hash = NULL; + } + lc->lro_hashsz = 0; + /* free mbuf array, if any */ for (x = 0; x != lc->lro_mbuf_count; x++) m_freem(lc->lro_mbuf_data[x].mb); @@ -487,7 +511,7 @@ tcp_lro_flush_all(struct lro_ctrl *lc) } /* add packet to LRO engine */ - if (tcp_lro_rx(lc, mb, 0) != 0) { + if (tcp_lro_rx2(lc, mb, 0, 0) != 0) { /* input packet to network layer */ (*lc->ifp->if_input)(lc->ifp, mb); lc->lro_queued++; @@ -561,8 +585,8 @@ tcp_lro_rx_ipv4(struct lro_ctrl *lc, str } #endif -int -tcp_lro_rx(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum) +static int +tcp_lro_rx2(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum, int use_hash) { struct lro_entry *le; struct ether_header *eh; @@ -578,6 +602,7 @@ tcp_lro_rx(struct lro_ctrl *lc, struct m tcp_seq seq; int error, ip_len, l; uint16_t eh_type, tcp_data_len; + struct lro_head *bucket; /* We expect a contiguous header [eh, ip, tcp]. */ @@ -670,8 +695,41 @@ tcp_lro_rx(struct lro_ctrl *lc, struct m seq = ntohl(th->th_seq); + if (!use_hash) { + bucket = &lc->lro_hash[0]; + } else if (M_HASHTYPE_ISHASH(m)) { + bucket = &lc->lro_hash[m->m_pkthdr.flowid % lc->lro_hashsz]; + } else { + uint32_t hash; + + switch (eh_type) { +#ifdef INET + case ETHERTYPE_IP: + hash = ip4->ip_src.s_addr + ip4->ip_dst.s_addr; + break; +#endif +#ifdef INET6 + case ETHERTYPE_IPV6: + hash = ip6->ip6_src.s6_addr32[0] + + ip6->ip6_dst.s6_addr32[0]; + hash += ip6->ip6_src.s6_addr32[1] + + ip6->ip6_dst.s6_addr32[1]; + hash += ip6->ip6_src.s6_addr32[2] + + ip6->ip6_dst.s6_addr32[2]; + hash += ip6->ip6_src.s6_addr32[3] + + ip6->ip6_dst.s6_addr32[3]; + break; +#endif + default: + hash = 0; + break; + } + hash += th->th_sport + th->th_dport; + bucket = &lc->lro_hash[hash % lc->lro_hashsz]; + } + /* Try to find a matching previous segment. */ - LIST_FOREACH(le, &lc->lro_active, next) { + LIST_FOREACH(le, bucket, hash_next) { if (le->eh_type != eh_type) continue; if (le->source_port != th->th_sport || @@ -779,7 +837,7 @@ tcp_lro_rx(struct lro_ctrl *lc, struct m /* Start a new segment chain. */ le = LIST_FIRST(&lc->lro_free); LIST_REMOVE(le, next); - tcp_lro_active_insert(lc, le); + tcp_lro_active_insert(lc, bucket, le); getmicrotime(&le->mtime); /* Start filling in details. */ @@ -837,6 +895,13 @@ tcp_lro_rx(struct lro_ctrl *lc, struct m return (0); } +int +tcp_lro_rx(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum) +{ + + return tcp_lro_rx2(lc, m, csum, 1); +} + void tcp_lro_queue_mbuf(struct lro_ctrl *lc, struct mbuf *mb) { Modified: user/alc/PQ_LAUNDRY/sys/netinet/tcp_lro.h ============================================================================== --- user/alc/PQ_LAUNDRY/sys/netinet/tcp_lro.h Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/netinet/tcp_lro.h Tue Aug 2 15:52:14 2016 (r303667) @@ -40,6 +40,7 @@ struct lro_entry { LIST_ENTRY(lro_entry) next; + LIST_ENTRY(lro_entry) hash_next; struct mbuf *m_head; struct mbuf *m_tail; union { @@ -95,6 +96,8 @@ struct lro_ctrl { unsigned short lro_ackcnt_lim; /* max # of aggregated ACKs */ unsigned lro_length_lim; /* max len of aggregated data */ + u_long lro_hashsz; + struct lro_head *lro_hash; struct lro_head lro_active; struct lro_head lro_free; }; Modified: user/alc/PQ_LAUNDRY/sys/netinet6/ip6_output.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/netinet6/ip6_output.c Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/netinet6/ip6_output.c Tue Aug 2 15:52:14 2016 (r303667) @@ -1058,7 +1058,8 @@ done: * Release the route if using our private route, or if * (with flowtable) we don't have our own reference. */ - if (ro == &ip6route || ro->ro_flags & RT_NORTREF) + if (ro == &ip6route || + (ro != NULL && ro->ro_flags & RT_NORTREF)) RO_RTFREE(ro); return (error); Modified: user/alc/PQ_LAUNDRY/sys/riscv/conf/GENERIC ============================================================================== --- user/alc/PQ_LAUNDRY/sys/riscv/conf/GENERIC Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/riscv/conf/GENERIC Tue Aug 2 15:52:14 2016 (r303667) @@ -26,6 +26,7 @@ makeoptions DEBUG=-g # Build kernel wit # FIXME: linker error. "--relax and -r may not be used together" makeoptions WITHOUT_MODULES="usb otusfw mwlfw ispfw mwlfw ralfw rtwnfw urtwnfw" +# makeoptions NO_MODULES options SCHED_ULE # ULE scheduler options PREEMPTION # Enable kernel thread preemption @@ -40,7 +41,6 @@ options UFS_ACL # Support for access options UFS_DIRHASH # Improve performance on big directories options UFS_GJOURNAL # Enable gjournal-based UFS journaling options QUOTA # Enable disk quotas for UFS -options MD_ROOT # MD is a potential root device options NFSCL # Network Filesystem Client options NFSD # Network Filesystem Server options NFSLOCKD # Network Lock Manager @@ -93,6 +93,7 @@ options INVARIANT_SUPPORT # Extra sanit # options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones # options EARLY_PRINTF +# options VERBOSE_SYSINIT # Pseudo devices. device loop # Network loopback Modified: user/alc/PQ_LAUNDRY/sys/riscv/htif/htif.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/riscv/htif/htif.c Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/riscv/htif/htif.c Tue Aug 2 15:52:14 2016 (r303667) @@ -177,11 +177,6 @@ htif_enumerate(struct htif_softc *sc) htif_command(cmd); - /* Do poll as interrupts are disabled yet */ - while (sc->identify_done == 0) { - htif_handle_entry(sc); - } - len = strnlen(id, sizeof(id)); if (len <= 0) break; Modified: user/alc/PQ_LAUNDRY/sys/riscv/htif/htif_block.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/riscv/htif/htif_block.c Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/riscv/htif/htif_block.c Tue Aug 2 15:52:14 2016 (r303667) @@ -202,6 +202,7 @@ htif_blk_task(void *arg) uint64_t req_paddr; struct bio *bp; uint64_t paddr; + uint64_t resp; uint64_t cmd; int i; @@ -239,7 +240,8 @@ htif_blk_task(void *arg) cmd |= req_paddr; sc->cmd_done = 0; - htif_command(cmd); + resp = htif_command(cmd); + htif_blk_intr(sc, resp); /* Wait for interrupt */ i = 0; Modified: user/alc/PQ_LAUNDRY/sys/riscv/htif/htif_console.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/riscv/htif/htif_console.c Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/riscv/htif/htif_console.c Tue Aug 2 15:52:14 2016 (r303667) @@ -57,8 +57,6 @@ __FBSDID("$FreeBSD$"); #include <ddb/ddb.h> -extern uint64_t console_intr; - static tsw_outwakeup_t riscvtty_outwakeup; static struct ttydevsw riscv_ttydevsw = { @@ -102,7 +100,7 @@ struct queue_entry *entry_last; struct queue_entry *entry_served; static void -htif_putc(int c) +riscv_putc(int c) { uint64_t cmd; @@ -110,57 +108,7 @@ htif_putc(int c) cmd |= (CONSOLE_DEFAULT_ID << HTIF_DEV_ID_SHIFT); cmd |= c; -#ifdef SPIN_IN_MACHINE_MODE - machine_command(ECALL_HTIF_LOWPUTC, cmd); -#else - htif_command(cmd); -#endif - -} - -static uint8_t -htif_getc(void) -{ - uint64_t cmd; - uint8_t res; - - cmd = (HTIF_CMD_READ << HTIF_CMD_SHIFT); - cmd |= (CONSOLE_DEFAULT_ID << HTIF_DEV_ID_SHIFT); - - res = htif_command(cmd); - - return (res); -} - -static void -riscv_putc(int c) -{ - uint64_t counter; - uint64_t *cc; - uint64_t val; - - val = 0; - counter = 0; - - cc = (uint64_t*)&console_intr; - *cc = 0; - - htif_putc(c); - -#ifndef SPIN_IN_MACHINE_MODE - /* Wait for an interrupt */ - __asm __volatile( - "li %0, 1\n" /* counter = 1 */ - "slli %0, %0, 12\n" /* counter <<= 12 */ - "1:" - "addi %0, %0, -1\n" /* counter -= 1 */ - "beqz %0, 2f\n" /* counter == 0 ? finish */ - "ld %1, 0(%2)\n" /* val = *cc */ - "beqz %1, 1b\n" /* val == 0 ? repeat */ - "2:" - : "=&r"(counter), "=&r"(val) : "r"(cc) - ); -#endif + machine_command(ECALL_HTIF_CMD, cmd); } #ifdef EARLY_PRINTF @@ -272,14 +220,19 @@ riscv_cngetc(struct consdev *cp) uint64_t entry; uint64_t devid; #endif + uint64_t cmd; uint8_t data; int ch; - htif_getc(); + cmd = (HTIF_CMD_READ << HTIF_CMD_SHIFT); + cmd |= (CONSOLE_DEFAULT_ID << HTIF_DEV_ID_SHIFT); + + machine_command(ECALL_HTIF_CMD_REQ, cmd); #if defined(KDB) if (kdb_active) { - entry = machine_command(ECALL_HTIF_GET_ENTRY, 0); + + entry = machine_command(ECALL_HTIF_CMD_RESP, 0); while (entry) { devid = HTIF_DEV_ID(entry); devcmd = HTIF_DEV_CMD(entry); @@ -294,7 +247,7 @@ riscv_cngetc(struct consdev *cp) devid); } - entry = machine_command(ECALL_HTIF_GET_ENTRY, 0); + entry = machine_command(ECALL_HTIF_CMD_RESP, 0); } } #endif Modified: user/alc/PQ_LAUNDRY/sys/riscv/include/cpu.h ============================================================================== --- user/alc/PQ_LAUNDRY/sys/riscv/include/cpu.h Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/riscv/include/cpu.h Tue Aug 2 15:52:14 2016 (r303667) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> + * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com> * All rights reserved. * * Portions of this software were developed by SRI International and the @@ -67,11 +67,10 @@ #define CPU_PART_SHIFT 62 #define CPU_PART_MASK (0x3ul << CPU_PART_SHIFT) -#define CPU_PART(mcpuid) ((mcpuid & CPU_PART_MASK) >> CPU_PART_SHIFT) -#define CPU_PART_RV32I 0x0 -#define CPU_PART_RV32E 0x1 -#define CPU_PART_RV64I 0x2 -#define CPU_PART_RV128I 0x3 +#define CPU_PART(misa) ((misa & CPU_PART_MASK) >> CPU_PART_SHIFT) +#define CPU_PART_RV32 0x1 +#define CPU_PART_RV64 0x2 +#define CPU_PART_RV128 0x3 extern char btext[]; extern char etext[]; Modified: user/alc/PQ_LAUNDRY/sys/riscv/include/cpufunc.h ============================================================================== --- user/alc/PQ_LAUNDRY/sys/riscv/include/cpufunc.h Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/riscv/include/cpufunc.h Tue Aug 2 15:52:14 2016 (r303667) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> + * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com> * All rights reserved. * * Portions of this software were developed by SRI International and the @@ -54,11 +54,11 @@ intr_disable(void) uint64_t ret; __asm __volatile( - "csrrci %0, sstatus, 1" - : "=&r" (ret) + "csrrci %0, sstatus, %1" + : "=&r" (ret) : "i" (SSTATUS_SIE) ); - return (ret & SSTATUS_IE); + return (ret & (SSTATUS_SIE)); } static __inline void @@ -76,7 +76,8 @@ intr_enable(void) { __asm __volatile( - "csrsi sstatus, 1" + "csrsi sstatus, %0" + :: "i" (SSTATUS_SIE) ); } Modified: user/alc/PQ_LAUNDRY/sys/riscv/include/db_machdep.h ============================================================================== --- user/alc/PQ_LAUNDRY/sys/riscv/include/db_machdep.h Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/riscv/include/db_machdep.h Tue Aug 2 15:52:14 2016 (r303667) @@ -41,7 +41,7 @@ #include <machine/frame.h> #include <machine/trap.h> -#define T_BREAKPOINT (EXCP_INSTR_BREAKPOINT) +#define T_BREAKPOINT (EXCP_BREAKPOINT) #define T_WATCHPOINT (0) typedef vm_offset_t db_addr_t; Modified: user/alc/PQ_LAUNDRY/sys/riscv/include/intr.h ============================================================================== --- user/alc/PQ_LAUNDRY/sys/riscv/include/intr.h Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/riscv/include/intr.h Tue Aug 2 15:52:14 2016 (r303667) @@ -57,11 +57,23 @@ void riscv_unmask_ipi(void); #endif enum { - IRQ_SOFTWARE, - IRQ_TIMER, - IRQ_HTIF, + IRQ_SOFTWARE_USER, + IRQ_SOFTWARE_SUPERVISOR, + IRQ_SOFTWARE_HYPERVISOR, + IRQ_SOFTWARE_MACHINE, + IRQ_TIMER_USER, + IRQ_TIMER_SUPERVISOR, + IRQ_TIMER_HYPERVISOR, + IRQ_TIMER_MACHINE, + IRQ_EXTERNAL_USER, + IRQ_EXTERNAL_SUPERVISOR, + IRQ_EXTERNAL_HYPERVISOR, + IRQ_EXTERNAL_MACHINE, +#if 0 + /* lowRISC TODO */ IRQ_COP, /* lowRISC only */ IRQ_UART, /* lowRISC only */ +#endif NIRQS }; Modified: user/alc/PQ_LAUNDRY/sys/riscv/include/pte.h ============================================================================== --- user/alc/PQ_LAUNDRY/sys/riscv/include/pte.h Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/riscv/include/pte.h Tue Aug 2 15:52:14 2016 (r303667) @@ -1,6 +1,6 @@ /*- * Copyright (c) 2014 Andrew Turner - * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> + * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com> * All rights reserved. * * Portions of this software were developed by SRI International and the @@ -66,29 +66,18 @@ typedef uint64_t pn_t; /* page number #define Ln_ADDR_MASK (Ln_ENTRIES - 1) /* Bits 9:7 are reserved for software */ -#define PTE_SW_MANAGED (1 << 8) -#define PTE_SW_WIRED (1 << 7) -#define PTE_DIRTY (1 << 6) /* Virtual page is written */ -#define PTE_REF (1 << 5) /* Virtual page is referenced */ -#define PTE_VALID (1 << 0) /* Virtual page is valid */ -#define PTE_TYPE_S 1 -#define PTE_TYPE_M (0xf << PTE_TYPE_S) -#define PTE_TYPE_PTR 0 -#define PTE_TYPE_PTR_G 1 -#define PTE_TYPE_SROURX 2 /* Supervisor read-only, user read-execute page. */ -#define PTE_TYPE_SRWURWX 3 /* Supervisor read-write, user read-write-execute page. */ -#define PTE_TYPE_SURO 4 /* Supervisor and user read-only page. */ -#define PTE_TYPE_SURW 5 /* Supervisor and user read-write page. */ -#define PTE_TYPE_SURX 6 /* Supervisor and user read-execute page. */ -#define PTE_TYPE_SURWX 7 /* Supervisor and User Read Write Execute */ -#define PTE_TYPE_SRO 8 /* Supervisor read-only page. */ -#define PTE_TYPE_SRW 9 /* Supervisor read-write page. */ -#define PTE_TYPE_SRX 10 /* Supervisor read-execute page. */ -#define PTE_TYPE_SRWX 11 /* Supervisor read-write-execute page. */ -#define PTE_TYPE_SRO_G 12 /* Supervisor read-only page--global mapping. */ -#define PTE_TYPE_SRW_G 13 /* Supervisor read-write page--global mapping. */ -#define PTE_TYPE_SRX_G 14 /* Supervisor read-execute page--global mapping. */ -#define PTE_TYPE_SRWX_G 15 /* Supervisor Read Write Execute Global */ +#define PTE_SW_MANAGED (1 << 9) +#define PTE_SW_WIRED (1 << 8) +#define PTE_D (1 << 7) /* Dirty */ +#define PTE_A (1 << 6) /* Accessed */ +#define PTE_G (1 << 5) /* Global */ +#define PTE_U (1 << 4) /* User */ +#define PTE_X (1 << 3) /* Execute */ +#define PTE_W (1 << 2) /* Write */ +#define PTE_R (1 << 1) /* Read */ +#define PTE_V (1 << 0) /* Valid */ +#define PTE_RWX (PTE_R | PTE_W | PTE_X) +#define PTE_RX (PTE_R | PTE_X) #define PTE_PPN0_S 10 #define PTE_PPN1_S 19 Modified: user/alc/PQ_LAUNDRY/sys/riscv/include/riscvreg.h ============================================================================== --- user/alc/PQ_LAUNDRY/sys/riscv/include/riscvreg.h Tue Aug 2 15:49:34 2016 (r303666) +++ user/alc/PQ_LAUNDRY/sys/riscv/include/riscvreg.h Tue Aug 2 15:52:14 2016 (r303667) @@ -39,88 +39,127 @@ /* Machine mode requests */ #define ECALL_MTIMECMP 0x01 -#define ECALL_CLEAR_PENDING 0x02 -#define ECALL_HTIF_CMD 0x03 -#define ECALL_HTIF_GET_ENTRY 0x04 -#define ECALL_MCPUID_GET 0x05 -#define ECALL_MIMPID_GET 0x06 -#define ECALL_SEND_IPI 0x07 -#define ECALL_CLEAR_IPI 0x08 -#define ECALL_HTIF_LOWPUTC 0x09 -#define ECALL_MIE_SET 0x0a -#define ECALL_IO_IRQ_MASK 0x0b +#define ECALL_HTIF_GET_ENTRY 0x02 +#define ECALL_MCPUID_GET 0x03 +#define ECALL_MIMPID_GET 0x04 +#define ECALL_SEND_IPI 0x05 +#define ECALL_CLEAR_IPI 0x06 +#define ECALL_MIE_SET 0x07 +#define ECALL_IO_IRQ_MASK 0x08 +#define ECALL_HTIF_CMD 0x09 +#define ECALL_HTIF_CMD_REQ 0x0a +#define ECALL_HTIF_CMD_RESP 0x0b #define EXCP_SHIFT 0 #define EXCP_MASK (0xf << EXCP_SHIFT) -#define EXCP_INSTR_ADDR_MISALIGNED 0 -#define EXCP_INSTR_ACCESS_FAULT 1 -#define EXCP_INSTR_ILLEGAL 2 -#define EXCP_INSTR_BREAKPOINT 3 -#define EXCP_LOAD_ADDR_MISALIGNED 4 -#define EXCP_LOAD_ACCESS_FAULT 5 -#define EXCP_STORE_ADDR_MISALIGNED 6 -#define EXCP_STORE_ACCESS_FAULT 7 -#define EXCP_UMODE_ENV_CALL 8 -#define EXCP_SMODE_ENV_CALL 9 -#define EXCP_HMODE_ENV_CALL 10 -#define EXCP_MMODE_ENV_CALL 11 -#define EXCP_INTR (1 << 31) +#define EXCP_MISALIGNED_FETCH 0 +#define EXCP_FAULT_FETCH 1 +#define EXCP_ILLEGAL_INSTRUCTION 2 +#define EXCP_BREAKPOINT 3 +#define EXCP_MISALIGNED_LOAD 4 +#define EXCP_FAULT_LOAD 5 +#define EXCP_MISALIGNED_STORE 6 +#define EXCP_FAULT_STORE 7 +#define EXCP_USER_ECALL 8 +#define EXCP_SUPERVISOR_ECALL 9 +#define EXCP_HYPERVISOR_ECALL 10 +#define EXCP_MACHINE_ECALL 11 +#define EXCP_INTR (1ul << 63) #define EXCP_INTR_SOFTWARE 0 #define EXCP_INTR_TIMER 1 #define EXCP_INTR_HTIF 2 -#define SSTATUS_IE (1 << 0) -#define SSTATUS_PIE (1 << 3) -#define SSTATUS_PS (1 << 4) - -#define MSTATUS_MPRV (1 << 16) -#define MSTATUS_PRV_SHIFT 1 -#define MSTATUS_PRV1_SHIFT 4 -#define MSTATUS_PRV2_SHIFT 7 -#define MSTATUS_PRV_MASK (0x3 << MSTATUS_PRV_SHIFT) -#define MSTATUS_PRV_U 0 /* user */ -#define MSTATUS_PRV_S 1 /* supervisor */ -#define MSTATUS_PRV_H 2 /* hypervisor */ -#define MSTATUS_PRV_M 3 /* machine */ - -#define MSTATUS_VM_SHIFT 17 -#define MSTATUS_VM_MASK 0x1f -#define MSTATUS_VM_MBARE 0 -#define MSTATUS_VM_MBB 1 -#define MSTATUS_VM_MBBID 2 -#define MSTATUS_VM_SV32 8 -#define MSTATUS_VM_SV39 9 -#define MSTATUS_VM_SV48 10 +#define SSTATUS_UIE (1 << 0) +#define SSTATUS_SIE (1 << 1) +#define SSTATUS_UPIE (1 << 4) +#define SSTATUS_SPIE (1 << 5) +#define SSTATUS_SPIE_SHIFT 5 +#define SSTATUS_SPP (1 << 8) +#define SSTATUS_SPP_SHIFT 8 +#define SSTATUS_FS_MASK 0x3 +#define SSTATUS_FS_SHIFT 13 +#define SSTATUS_XS_MASK 0x3 +#define SSTATUS_XS_SHIFT 15 +#define SSTATUS_PUM (1 << 18) +#define SSTATUS32_SD (1 << 63) +#define SSTATUS64_SD (1 << 31) + +#define MSTATUS_UIE (1 << 0) +#define MSTATUS_SIE (1 << 1) +#define MSTATUS_HIE (1 << 2) +#define MSTATUS_MIE (1 << 3) +#define MSTATUS_UPIE (1 << 4) +#define MSTATUS_SPIE (1 << 5) +#define MSTATUS_SPIE_SHIFT 5 +#define MSTATUS_HPIE (1 << 6) +#define MSTATUS_MPIE (1 << 7) +#define MSTATUS_MPIE_SHIFT 7 +#define MSTATUS_SPP (1 << 8) +#define MSTATUS_SPP_SHIFT 8 +#define MSTATUS_HPP_MASK 0x3 +#define MSTATUS_HPP_SHIFT 9 +#define MSTATUS_MPP_MASK 0x3 +#define MSTATUS_MPP_SHIFT 11 +#define MSTATUS_FS_MASK 0x3 +#define MSTATUS_FS_SHIFT 13 +#define MSTATUS_XS_MASK 0x3 +#define MSTATUS_XS_SHIFT 15 +#define MSTATUS_MPRV (1 << 17) +#define MSTATUS_PUM (1 << 18) +#define MSTATUS_VM_MASK 0x1f +#define MSTATUS_VM_SHIFT 24 +#define MSTATUS_VM_MBARE 0 +#define MSTATUS_VM_MBB 1 +#define MSTATUS_VM_MBBID 2 +#define MSTATUS_VM_SV32 8 +#define MSTATUS_VM_SV39 9 +#define MSTATUS_VM_SV48 10 +#define MSTATUS_VM_SV57 11 +#define MSTATUS_VM_SV64 12 +#define MSTATUS32_SD (1 << 63) +#define MSTATUS64_SD (1 << 31) + +#define MSTATUS_PRV_U 0 /* user */ +#define MSTATUS_PRV_S 1 /* supervisor */ +#define MSTATUS_PRV_H 2 /* hypervisor */ +#define MSTATUS_PRV_M 3 /* machine */ +#define MIE_USIE (1 << 0) #define MIE_SSIE (1 << 1) #define MIE_HSIE (1 << 2) #define MIE_MSIE (1 << 3) +#define MIE_UTIE (1 << 4) #define MIE_STIE (1 << 5) #define MIE_HTIE (1 << 6) #define MIE_MTIE (1 << 7) +#define MIP_USIP (1 << 0) #define MIP_SSIP (1 << 1) #define MIP_HSIP (1 << 2) #define MIP_MSIP (1 << 3) +#define MIP_UTIP (1 << 4) #define MIP_STIP (1 << 5) *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201608021552.u72FqEjN006587>