diff options
| author | Peter Grehan <grehan@FreeBSD.org> | 2011-09-15 22:14:35 +0000 |
|---|---|---|
| committer | Peter Grehan <grehan@FreeBSD.org> | 2011-09-15 22:14:35 +0000 |
| commit | fab4c373af4f465f03ae217f491d8cf3a3eeb26d (patch) | |
| tree | 42ba64b8c25f527cf3d9b56c4ce4c51c11d445d1 /sys | |
| parent | bd2228ab3ee0cde6831fe446d793fffda2f48503 (diff) | |
| parent | 3fb4fa3574e36c997c2cdcaa6f6e39a37e89f572 (diff) | |
Notes
Diffstat (limited to 'sys')
522 files changed, 14263 insertions, 7187 deletions
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S index c537a4f45c832..89ad638c7e3fc 100644 --- a/sys/amd64/amd64/exception.S +++ b/sys/amd64/amd64/exception.S @@ -380,8 +380,11 @@ IDTVEC(fast_syscall) movl $TF_HASSEGS,TF_FLAGS(%rsp) cld FAKE_MCOUNT(TF_RIP(%rsp)) - movq %rsp,%rdi - call syscall + movq PCPU(CURTHREAD),%rdi + movq %rsp,TD_FRAME(%rdi) + movl TF_RFLAGS(%rsp),%esi + andl $PSL_T,%esi + call amd64_syscall 1: movq PCPU(CURPCB),%rax /* Disable interrupts before testing PCB_FULL_IRET. */ cli @@ -390,29 +393,25 @@ IDTVEC(fast_syscall) /* Check for and handle AST's on return to userland. */ movq PCPU(CURTHREAD),%rax testl $TDF_ASTPENDING | TDF_NEEDRESCHED,TD_FLAGS(%rax) - je 2f - sti - movq %rsp, %rdi - call ast - jmp 1b -2: /* Restore preserved registers. */ + jne 2f + /* Restore preserved registers. */ MEXITCOUNT movq TF_RDI(%rsp),%rdi /* bonus; preserve arg 1 */ movq TF_RSI(%rsp),%rsi /* bonus: preserve arg 2 */ movq TF_RDX(%rsp),%rdx /* return value 2 */ movq TF_RAX(%rsp),%rax /* return value 1 */ - movq TF_RBX(%rsp),%rbx /* C preserved */ - movq TF_RBP(%rsp),%rbp /* C preserved */ - movq TF_R12(%rsp),%r12 /* C preserved */ - movq TF_R13(%rsp),%r13 /* C preserved */ - movq TF_R14(%rsp),%r14 /* C preserved */ - movq TF_R15(%rsp),%r15 /* C preserved */ movq TF_RFLAGS(%rsp),%r11 /* original %rflags */ movq TF_RIP(%rsp),%rcx /* original %rip */ - movq TF_RSP(%rsp),%r9 /* user stack pointer */ - movq %r9,%rsp /* original %rsp */ + movq TF_RSP(%rsp),%rsp /* user stack pointer */ swapgs sysretq + +2: /* AST scheduled. */ + sti + movq %rsp,%rdi + call ast + jmp 1b + 3: /* Requested full context restore, use doreti for that. */ MEXITCOUNT jmp doreti diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index 1c9abd5ab1b1d..d133223ffb237 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -87,6 +87,7 @@ ASSYM(TD_PCB, offsetof(struct thread, td_pcb)); ASSYM(TD_PFLAGS, offsetof(struct thread, td_pflags)); ASSYM(TD_PROC, offsetof(struct thread, td_proc)); ASSYM(TD_TID, offsetof(struct thread, td_tid)); +ASSYM(TD_FRAME, offsetof(struct thread, td_frame)); ASSYM(TDF_ASTPENDING, TDF_ASTPENDING); ASSYM(TDF_NEEDRESCHED, TDF_NEEDRESCHED); diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index f90ad03a59170..1e7b26c081f43 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -1309,7 +1309,7 @@ getmemsize(caddr_t kmdp, u_int64_t first) { int i, physmap_idx, pa_indx, da_indx; vm_paddr_t pa, physmap[PHYSMAP_SIZE]; - u_long physmem_tunable; + u_long physmem_tunable, memtest; pt_entry_t *pte; struct bios_smap *smapbase, *smap, *smapend; u_int32_t smapsize; @@ -1372,6 +1372,13 @@ getmemsize(caddr_t kmdp, u_int64_t first) Maxmem = atop(physmem_tunable); /* + * By default keep the memtest enabled. Use a general name so that + * one could eventually do more with the code than just disable it. + */ + memtest = 1; + TUNABLE_ULONG_FETCH("hw.memtest.tests", &memtest); + + /* * Don't allow MAXMEM or hw.physmem to extend the amount of memory * in the system. */ @@ -1433,6 +1440,8 @@ getmemsize(caddr_t kmdp, u_int64_t first) goto do_dump_avail; page_bad = FALSE; + if (memtest == 0) + goto skip_memtest; /* * map page into kernel: valid, read/write,non-cacheable @@ -1470,6 +1479,7 @@ getmemsize(caddr_t kmdp, u_int64_t first) */ *(int *)ptr = tmp; +skip_memtest: /* * Adjust array of valid/good pages. */ diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index bed795b974762..43df8ee15baa9 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -2123,7 +2123,7 @@ pmap_collect(pmap_t locked_pmap, struct vpgqueues *vpq) KASSERT((tpte & PG_W) == 0, ("pmap_collect: wired pte %#lx", tpte)); if (tpte & PG_A) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); if ((tpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); free = NULL; @@ -2137,7 +2137,7 @@ pmap_collect(pmap_t locked_pmap, struct vpgqueues *vpq) } if (TAILQ_EMPTY(&m->md.pv_list) && TAILQ_EMPTY(&pa_to_pvh(VM_PAGE_TO_PHYS(m))->pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } } @@ -2320,7 +2320,7 @@ pmap_pv_demote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa) va_last = va + NBPDR - PAGE_SIZE; do { m++; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_pv_demote_pde: page %p is not managed", m)); va += PAGE_SIZE; pmap_insert_entry(pmap, va, m); @@ -2391,7 +2391,7 @@ pmap_remove_entry(pmap_t pmap, vm_page_t m, vm_offset_t va) if (TAILQ_EMPTY(&m->md.pv_list)) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); if (TAILQ_EMPTY(&pvh->pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } } @@ -2615,10 +2615,10 @@ pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva, if ((oldpde & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); if (oldpde & PG_A) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); if (TAILQ_EMPTY(&m->md.pv_list) && TAILQ_EMPTY(&pvh->pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } } if (pmap == kernel_pmap) { @@ -2659,7 +2659,7 @@ pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t va, if ((oldpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); if (oldpte & PG_A) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); pmap_remove_entry(pmap, m, va); } return (pmap_unuse_pt(pmap, va, ptepde, free)); @@ -2847,7 +2847,7 @@ pmap_remove_all(vm_page_t m) vm_offset_t va; vm_page_t free; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_all: page %p is not managed", m)); free = NULL; vm_page_lock_queues(); @@ -2872,7 +2872,7 @@ pmap_remove_all(vm_page_t m) if (tpte & PG_W) pmap->pm_stats.wired_count--; if (tpte & PG_A) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); /* * Update the vm_page_t clean and reference bits. @@ -2885,7 +2885,7 @@ pmap_remove_all(vm_page_t m) free_pv_entry(pmap, pv); PMAP_UNLOCK(pmap); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); pmap_free_zero_pages(free); } @@ -3194,8 +3194,8 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, KASSERT(va < UPT_MIN_ADDRESS || va >= UPT_MAX_ADDRESS, ("pmap_enter: invalid to pmap_enter page table pages (va: 0x%lx)", va)); - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0 || - (m->oflags & VPO_BUSY) != 0, + KASSERT((m->oflags & (VPO_UNMANAGED | VPO_BUSY)) != 0 || + VM_OBJECT_LOCKED(m->object), ("pmap_enter: page %p is not busy", m)); mpte = NULL; @@ -3276,7 +3276,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, /* * Enter on the PV list if part of our managed memory. */ - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) { + if ((m->oflags & VPO_UNMANAGED) == 0) { KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva, ("pmap_enter: managed mapping within the clean submap")); if (pv == NULL) @@ -3301,7 +3301,7 @@ validate: if ((prot & VM_PROT_WRITE) != 0) { newpte |= PG_RW; if ((newpte & PG_MANAGED) != 0) - vm_page_flag_set(m, PG_WRITEABLE); + vm_page_aflag_set(m, PGA_WRITEABLE); } if ((prot & VM_PROT_EXECUTE) == 0) newpte |= pg_nx; @@ -3325,7 +3325,7 @@ validate: origpte = pte_load_store(pte, newpte); if (origpte & PG_A) { if (origpte & PG_MANAGED) - vm_page_flag_set(om, PG_REFERENCED); + vm_page_aflag_set(om, PGA_REFERENCED); if (opa != VM_PAGE_TO_PHYS(m) || ((origpte & PG_NX) == 0 && (newpte & PG_NX))) invlva = TRUE; @@ -3339,7 +3339,7 @@ validate: if ((origpte & PG_MANAGED) != 0 && TAILQ_EMPTY(&om->md.pv_list) && TAILQ_EMPTY(&pa_to_pvh(opa)->pv_list)) - vm_page_flag_clear(om, PG_WRITEABLE); + vm_page_aflag_clear(om, PGA_WRITEABLE); if (invlva) pmap_invalidate_page(pmap, va); } else @@ -3389,7 +3389,7 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot) } newpde = VM_PAGE_TO_PHYS(m) | pmap_cache_bits(m->md.pat_mode, 1) | PG_PS | PG_V; - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) { + if ((m->oflags & VPO_UNMANAGED) == 0) { newpde |= PG_MANAGED; /* @@ -3498,7 +3498,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_paddr_t pa; KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva || - (m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0, + (m->oflags & VPO_UNMANAGED) != 0, ("pmap_enter_quick_locked: managed mapping within the clean submap")); mtx_assert(&vm_page_queue_mtx, MA_OWNED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); @@ -3556,7 +3556,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, /* * Enter on the PV list if part of our managed memory. */ - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0 && + if ((m->oflags & VPO_UNMANAGED) == 0 && !pmap_try_insert_pv_entry(pmap, va, m)) { if (mpte != NULL) { free = NULL; @@ -3581,7 +3581,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, /* * Now validate mapping with RO protection */ - if (m->flags & (PG_FICTITIOUS|PG_UNMANAGED)) + if ((m->oflags & VPO_UNMANAGED) != 0) pte_store(pte, pa | PG_V | PG_U); else pte_store(pte, pa | PG_V | PG_U | PG_MANAGED); @@ -3958,7 +3958,7 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m) int loops = 0; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_page_exists_quick: page %p is not managed", m)); rv = FALSE; vm_page_lock_queues(); @@ -3999,7 +3999,7 @@ pmap_page_wired_mappings(vm_page_t m) int count; count = 0; - if ((m->flags & PG_FICTITIOUS) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (count); vm_page_lock_queues(); count = pmap_pvh_wired_mappings(&m->md, count); @@ -4041,7 +4041,7 @@ pmap_page_is_mapped(vm_page_t m) { boolean_t rv; - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (FALSE); vm_page_lock_queues(); rv = !TAILQ_EMPTY(&m->md.pv_list) || @@ -4147,7 +4147,7 @@ pmap_remove_pages(pmap_t pmap) if (TAILQ_EMPTY(&pvh->pv_list)) { for (mt = m; mt < &m[NBPDR / PAGE_SIZE]; mt++) if (TAILQ_EMPTY(&mt->md.pv_list)) - vm_page_flag_clear(mt, PG_WRITEABLE); + vm_page_aflag_clear(mt, PGA_WRITEABLE); } mpte = pmap_lookup_pt_page(pmap, pv->pv_va); if (mpte != NULL) { @@ -4165,7 +4165,7 @@ pmap_remove_pages(pmap_t pmap) if (TAILQ_EMPTY(&m->md.pv_list)) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); if (TAILQ_EMPTY(&pvh->pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } } pmap_unuse_pt(pmap, pv->pv_va, ptepde, &free); @@ -4199,17 +4199,17 @@ pmap_is_modified(vm_page_t m) { boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_modified: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be - * concurrently set while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be + * concurrently set while the object is locked. Thus, if PGA_WRITEABLE * is clear, no PTEs can have PG_M set. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return (FALSE); vm_page_lock_queues(); rv = pmap_is_modified_pvh(&m->md) || @@ -4280,7 +4280,7 @@ pmap_is_referenced(vm_page_t m) { boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_referenced: page %p is not managed", m)); vm_page_lock_queues(); rv = pmap_is_referenced_pvh(&m->md) || @@ -4328,17 +4328,17 @@ pmap_remove_write(vm_page_t m) pt_entry_t oldpte, *pte; vm_offset_t va; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_write: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be set by - * another thread while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be set by + * another thread while the object is locked. Thus, if PGA_WRITEABLE * is clear, no page table entries need updating. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); @@ -4370,7 +4370,7 @@ retry: } PMAP_UNLOCK(pmap); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } @@ -4397,7 +4397,7 @@ pmap_ts_referenced(vm_page_t m) vm_offset_t va; int rtval = 0; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_ts_referenced: page %p is not managed", m)); pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); vm_page_lock_queues(); @@ -4471,18 +4471,18 @@ pmap_clear_modify(vm_page_t m) pt_entry_t oldpte, *pte; vm_offset_t va; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_modify: page %p is not managed", m)); VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); KASSERT((m->oflags & VPO_BUSY) == 0, ("pmap_clear_modify: page %p is busy", m)); /* - * If the page is not PG_WRITEABLE, then no PTEs can have PG_M set. + * If the page is not PGA_WRITEABLE, then no PTEs can have PG_M set. * If the object containing the page is locked and the page is not - * VPO_BUSY, then PG_WRITEABLE cannot be concurrently set. + * VPO_BUSY, then PGA_WRITEABLE cannot be concurrently set. */ - if ((m->flags & PG_WRITEABLE) == 0) + if ((m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); @@ -4548,7 +4548,7 @@ pmap_clear_reference(vm_page_t m) pt_entry_t *pte; vm_offset_t va; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_reference: page %p is not managed", m)); vm_page_lock_queues(); pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 4e5f8b8aa9f50..16f151fce3ef1 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -883,41 +883,37 @@ cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) return (error); } +#include "../../kern/subr_syscall.c" + /* * syscall - system call request C handler * * A system call is essentially treated as a trap. */ void -syscall(struct trapframe *frame) +amd64_syscall(struct thread *td, int traced) { - struct thread *td; struct syscall_args sa; - register_t orig_tf_rflags; int error; ksiginfo_t ksi; #ifdef DIAGNOSTIC - if (ISPL(frame->tf_cs) != SEL_UPL) { + if (ISPL(td->td_frame->tf_cs) != SEL_UPL) { panic("syscall"); /* NOT REACHED */ } #endif - orig_tf_rflags = frame->tf_rflags; - td = curthread; - td->td_frame = frame; - error = syscallenter(td, &sa); /* * Traced syscall. */ - if (orig_tf_rflags & PSL_T) { - frame->tf_rflags &= ~PSL_T; + if (__predict_false(traced)) { + td->td_frame->tf_rflags &= ~PSL_T; ksiginfo_init_trap(&ksi); ksi.ksi_signo = SIGTRAP; ksi.ksi_code = TRAP_TRACE; - ksi.ksi_addr = (void *)frame->tf_rip; + ksi.ksi_addr = (void *)td->td_frame->tf_rip; trapsignal(td, &ksi); } diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 7c42038ed056f..036c1b2812308 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -37,7 +37,7 @@ options MD_ROOT # MD is a potential root device options NFSCL # New Network Filesystem Client options NFSD # New Network Filesystem Server options NFSLOCKD # Network Lock Manager -options NFS_ROOT # NFS usable as /, requires NFSCLIENT +options NFS_ROOT # NFS usable as /, requires NFSCL options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) @@ -187,10 +187,7 @@ device plip # TCP/IP over parallel device ppi # Parallel port interface device #device vpo # Requires scbus and da -# If you've got a "dumb" serial or parallel PCI card that is -# supported by the puc(4) glue driver, uncomment the following -# line to enable it (connects to sio, uart and/or ppc drivers): -#device puc +device puc # Multi I/O cards and multi-channel UARTs # PCI Ethernet NICs. device bxe # Broadcom BCM57710/BCM57711/BCM57711E 10Gb Ethernet @@ -330,7 +327,7 @@ device uath # Atheros AR5523 wireless NICs device upgt # Conexant/Intersil PrismGT wireless NICs. device ural # Ralink Technology RT2500USB wireless NICs device urtw # Realtek RTL8187B/L wireless NICs -device zyd # ZyDAS zb1211/zb1211b wireless NICs +device zyd # ZyDAS zd1211/zd1211b wireless NICs # FireWire support device firewire # FireWire bus code diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES index 4a47aceda0b10..07ea7b3135869 100644 --- a/sys/amd64/conf/NOTES +++ b/sys/amd64/conf/NOTES @@ -490,6 +490,14 @@ options ENABLE_ALART # Control alarm on Intel intpm driver # options PMAP_SHPGPERPROC=201 +# +# Number of initial kernel page table pages used for early bootstrap. +# This number should include enough pages to map the kernel and any +# modules or other data loaded with the kernel by the loader. Each +# page table page maps 2MB. +# +options NKPT=31 + ##################################################################### # ABI Emulation diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c index 0b46dae7a5e35..d79272a01dcfb 100644 --- a/sys/amd64/ia32/ia32_syscall.c +++ b/sys/amd64/ia32/ia32_syscall.c @@ -163,6 +163,8 @@ ia32_fetch_syscall_args(struct thread *td, struct syscall_args *sa) return (error); } +#include "../../kern/subr_syscall.c" + void ia32_syscall(struct trapframe *frame) { diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h index 88f3e1dbaed8f..479c84e85f1e2 100644 --- a/sys/amd64/include/md_var.h +++ b/sys/amd64/include/md_var.h @@ -75,6 +75,7 @@ struct fpreg; struct dbreg; struct dumperinfo; +void amd64_syscall(struct thread *td, int traced); void busdma_swi(void); void cpu_setregs(void); void doreti_iret(void) __asm(__STRING(doreti_iret)); diff --git a/sys/amd64/include/param.h b/sys/amd64/include/param.h index 9a742f94e9b95..6dbeb4035925e 100644 --- a/sys/amd64/include/param.h +++ b/sys/amd64/include/param.h @@ -64,7 +64,9 @@ #endif #if defined(SMP) || defined(KLD_MODULE) -#define MAXCPU 32 +#ifndef MAXCPU +#define MAXCPU 64 +#endif #else #define MAXCPU 1 #endif diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c index 26041a3099353..a8ebe7ef1629c 100644 --- a/sys/amd64/linux32/linux32_machdep.c +++ b/sys/amd64/linux32/linux32_machdep.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/file.h> #include <sys/fcntl.h> #include <sys/clock.h> @@ -566,7 +567,7 @@ linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot, * protection options specified. */ - if ((error = fget(td, bsd_args.fd, &fp)) != 0) + if ((error = fget(td, bsd_args.fd, CAP_MMAP, &fp)) != 0) return (error); if (fp->f_type != DTYPE_VNODE) { fdrop(fp, td); diff --git a/sys/arm/arm/irq_dispatch.S b/sys/arm/arm/irq_dispatch.S index e3577565ed32a..c919de006bff7 100644 --- a/sys/arm/arm/irq_dispatch.S +++ b/sys/arm/arm/irq_dispatch.S @@ -109,9 +109,9 @@ _C_LABEL(intrnames): _C_LABEL(intrcnt): .space NIRQ * 4 _C_LABEL(sintrnames): - .word NIRQ * (MAXCOMLEN + 1) + .int NIRQ * (MAXCOMLEN + 1) _C_LABEL(sintrcnt): - .word NIRQ * 4 + .int NIRQ * 4 .global _C_LABEL(current_intr_depth) _C_LABEL(current_intr_depth): diff --git a/sys/arm/arm/pmap.c b/sys/arm/arm/pmap.c index d24a4229611a8..28835ec9362d2 100644 --- a/sys/arm/arm/pmap.c +++ b/sys/arm/arm/pmap.c @@ -1402,7 +1402,7 @@ pmap_fix_cache(struct vm_page *pg, pmap_t pm, vm_offset_t va) if ((kwritable == 0) && (writable == 0)) { pg->md.pvh_attrs &= ~PVF_MOD; - vm_page_flag_clear(pg, PG_WRITEABLE); + vm_page_aflag_clear(pg, PGA_WRITEABLE); return; } } @@ -1568,7 +1568,7 @@ pmap_clearbit(struct vm_page *pg, u_int maskbits) } if (maskbits & PVF_WRITE) - vm_page_flag_clear(pg, PG_WRITEABLE); + vm_page_aflag_clear(pg, PGA_WRITEABLE); vm_page_unlock_queues(); return (count); } @@ -1630,7 +1630,7 @@ pmap_enter_pv(struct vm_page *pg, struct pv_entry *pve, pmap_t pm, pg->md.pvh_attrs |= flags & (PVF_REF | PVF_MOD); if (pve->pv_flags & PVF_WIRED) ++pm->pm_stats.wired_count; - vm_page_flag_set(pg, PG_REFERENCED); + vm_page_aflag_set(pg, PGA_REFERENCED); } /* @@ -1699,7 +1699,7 @@ pmap_nuke_pv(struct vm_page *pg, pmap_t pm, struct pv_entry *pve) if (TAILQ_FIRST(&pg->md.pv_list) == NULL) pg->md.pvh_attrs &= ~PVF_REF; else - vm_page_flag_set(pg, PG_REFERENCED); + vm_page_aflag_set(pg, PGA_REFERENCED); if ((pve->pv_flags & PVF_NC) && ((pm == pmap_kernel()) || (pve->pv_flags & PVF_WRITE) || !(pve->pv_flags & PVF_MWC))) pmap_fix_cache(pg, pm, 0); @@ -1709,7 +1709,7 @@ pmap_nuke_pv(struct vm_page *pg, pmap_t pm, struct pv_entry *pve) break; if (!pve) { pg->md.pvh_attrs &= ~PVF_MOD; - vm_page_flag_clear(pg, PG_WRITEABLE); + vm_page_aflag_clear(pg, PGA_WRITEABLE); } } pv = TAILQ_FIRST(&pg->md.pv_list); @@ -1724,7 +1724,7 @@ pmap_nuke_pv(struct vm_page *pg, pmap_t pm, struct pv_entry *pve) --pm->pm_stats.wired_count; pg->md.pvh_attrs &= ~PVF_REF; pg->md.pvh_attrs &= ~PVF_MOD; - vm_page_flag_clear(pg, PG_WRITEABLE); + vm_page_aflag_clear(pg, PGA_WRITEABLE); pmap_free_pv_entry(pv); } } @@ -2695,7 +2695,7 @@ pmap_remove_pages(pmap_t pmap) npv = TAILQ_NEXT(pv, pv_plist); pmap_nuke_pv(m, pmap, pv); if (TAILQ_EMPTY(&m->md.pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); pmap_free_pv_entry(pv); pmap_free_l2_bucket(pmap, l2b, 1); } @@ -3120,7 +3120,7 @@ pmap_remove_all(vm_page_t m) pmap_t curpm; int flags = 0; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_all: page %p is not managed", m)); if (TAILQ_EMPTY(&m->md.pv_list)) return; @@ -3172,7 +3172,7 @@ pmap_remove_all(vm_page_t m) else pmap_tlb_flushD(curpm); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } @@ -3242,7 +3242,7 @@ pmap_protect(pmap_t pm, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot) PTE_SYNC(ptep); if (pg != NULL) { - if (!(pg->flags & PG_UNMANAGED)) { + if (!(pg->oflags & VPO_UNMANAGED)) { f = pmap_modify_pv(pg, pm, sva, PVF_WRITE, 0); vm_page_dirty(pg); @@ -3327,8 +3327,8 @@ pmap_enter_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, pa = systempage.pv_pa; m = NULL; } else { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0 || - (m->oflags & VPO_BUSY) != 0 || (flags & M_NOWAIT) != 0, + KASSERT((m->oflags & (VPO_UNMANAGED | VPO_BUSY)) != 0 || + (flags & M_NOWAIT) != 0, ("pmap_enter_locked: page %p is not busy", m)); pa = VM_PAGE_TO_PHYS(m); } @@ -3406,7 +3406,7 @@ do_l2b_alloc: vm_page_dirty(m); } if (m && opte) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); } else { /* * Need to do page referenced emulation. @@ -3417,8 +3417,8 @@ do_l2b_alloc: if (prot & VM_PROT_WRITE) { npte |= L2_S_PROT_W; if (m != NULL && - (m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) - vm_page_flag_set(m, PG_WRITEABLE); + (m->oflags & VPO_UNMANAGED) == 0) + vm_page_aflag_set(m, PGA_WRITEABLE); } npte |= pte_l2_s_cache_mode; if (m && m == opg) { @@ -3480,36 +3480,36 @@ do_l2b_alloc: * this physical page is not/is already mapped. */ - if (m && ((m->flags & PG_FICTITIOUS) || - ((m->flags & PG_UNMANAGED) && + if (m && (m->oflags & VPO_UNMANAGED) && !m->md.pv_kva && - TAILQ_EMPTY(&m->md.pv_list)))) { + TAILQ_EMPTY(&m->md.pv_list)) { pmap_free_pv_entry(pve); pve = NULL; } - } else if (m && !(m->flags & PG_FICTITIOUS) && - (!(m->flags & PG_UNMANAGED) || m->md.pv_kva || + } else if (m && + (!(m->oflags & VPO_UNMANAGED) || m->md.pv_kva || !TAILQ_EMPTY(&m->md.pv_list))) pve = pmap_get_pv_entry(); - } else if (m && !(m->flags & PG_FICTITIOUS) && - (!(m->flags & PG_UNMANAGED) || m->md.pv_kva || + } else if (m && + (!(m->oflags & VPO_UNMANAGED) || m->md.pv_kva || !TAILQ_EMPTY(&m->md.pv_list))) pve = pmap_get_pv_entry(); - if (m && !(m->flags & PG_FICTITIOUS)) { - KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva, - ("pmap_enter: managed mapping within the clean submap")); - if (m->flags & PG_UNMANAGED) { + if (m) { + if ((m->oflags & VPO_UNMANAGED)) { if (!TAILQ_EMPTY(&m->md.pv_list) || - m->md.pv_kva) { + m->md.pv_kva) { KASSERT(pve != NULL, ("No pv")); nflags |= PVF_UNMAN; pmap_enter_pv(m, pve, pmap, va, nflags); } else m->md.pv_kva = va; } else { - KASSERT(pve != NULL, ("No pv")); - pmap_enter_pv(m, pve, pmap, va, nflags); + KASSERT(va < kmi.clean_sva || + va >= kmi.clean_eva, + ("pmap_enter: managed mapping within the clean submap")); + KASSERT(pve != NULL, ("No pv")); + pmap_enter_pv(m, pve, pmap, va, nflags); } } } @@ -4423,7 +4423,7 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m) int loops = 0; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_page_exists_quick: page %p is not managed", m)); rv = FALSE; vm_page_lock_queues(); @@ -4453,7 +4453,7 @@ pmap_page_wired_mappings(vm_page_t m) int count; count = 0; - if ((m->flags & PG_FICTITIOUS) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (count); vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) @@ -4472,7 +4472,7 @@ int pmap_ts_referenced(vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_ts_referenced: page %p is not managed", m)); return (pmap_clearbit(m, PVF_REF)); } @@ -4482,7 +4482,7 @@ boolean_t pmap_is_modified(vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_modified: page %p is not managed", m)); if (m->md.pvh_attrs & PVF_MOD) return (TRUE); @@ -4498,18 +4498,18 @@ void pmap_clear_modify(vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_modify: page %p is not managed", m)); VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); KASSERT((m->oflags & VPO_BUSY) == 0, ("pmap_clear_modify: page %p is busy", m)); /* - * If the page is not PG_WRITEABLE, then no mappings can be modified. + * If the page is not PGA_WRITEABLE, then no mappings can be modified. * If the object containing the page is locked and the page is not - * VPO_BUSY, then PG_WRITEABLE cannot be concurrently set. + * VPO_BUSY, then PGA_WRITEABLE cannot be concurrently set. */ - if ((m->flags & PG_WRITEABLE) == 0) + if ((m->aflags & PGA_WRITEABLE) == 0) return; if (m->md.pvh_attrs & PVF_MOD) pmap_clearbit(m, PVF_MOD); @@ -4526,7 +4526,7 @@ boolean_t pmap_is_referenced(vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_referenced: page %p is not managed", m)); return ((m->md.pvh_attrs & PVF_REF) != 0); } @@ -4540,7 +4540,7 @@ void pmap_clear_reference(vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_reference: page %p is not managed", m)); if (m->md.pvh_attrs & PVF_REF) pmap_clearbit(m, PVF_REF); @@ -4554,17 +4554,17 @@ void pmap_remove_write(vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_write: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be set by - * another thread while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be set by + * another thread while the object is locked. Thus, if PGA_WRITEABLE * is clear, no page table entries need updating. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) != 0 || - (m->flags & PG_WRITEABLE) != 0) + (m->aflags & PGA_WRITEABLE) != 0) pmap_clearbit(m, PVF_WRITE); } diff --git a/sys/arm/at91/uart_dev_at91usart.c b/sys/arm/at91/uart_dev_at91usart.c index 94ea9de1d2751..f3d21aae5a0f6 100644 --- a/sys/arm/at91/uart_dev_at91usart.c +++ b/sys/arm/at91/uart_dev_at91usart.c @@ -29,8 +29,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_comconsole.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/bus.h> @@ -485,25 +483,10 @@ at91_usart_bus_param(struct uart_softc *sc, int baudrate, int databits, static __inline void at91_rx_put(struct uart_softc *sc, int key) { -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) - int kdb_brk; - if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) { - if ((kdb_brk = kdb_alt_break(key, &sc->sc_altbrk)) != 0) { - switch (kdb_brk) { - case KDB_REQ_DEBUGGER: - kdb_enter(KDB_WHY_BREAK, - "Break sequence on console"); - break; - case KDB_REQ_PANIC: - kdb_panic("Panic sequence on console"); - break; - case KDB_REQ_REBOOT: - kdb_reboot(); - break; - } - } - } +#if defined(KDB) + if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) + kdb_alt_break(key, &sc->sc_altbrk); #endif uart_rx_put(sc, key); } diff --git a/sys/arm/conf/AVILA b/sys/arm/conf/AVILA index 0140eb0f57a77..7916b2cc68fe9 100644 --- a/sys/arm/conf/AVILA +++ b/sys/arm/conf/AVILA @@ -50,8 +50,8 @@ options SCHED_4BSD #4BSD scheduler options INET #InterNETworking options FFS #Berkeley Fast Filesystem options SOFTUPDATES #Enable FFS soft updates support -options NFSCLIENT #Network Filesystem Client -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFSCL #New Network Filesystem Client +options NFS_ROOT #NFS usable as /, requires NFSCL options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 diff --git a/sys/arm/conf/BWCT b/sys/arm/conf/BWCT index 0fb3b872cba6d..3a28e487d7b28 100644 --- a/sys/arm/conf/BWCT +++ b/sys/arm/conf/BWCT @@ -46,10 +46,10 @@ options SOFTUPDATES #Enable FFS soft updates support #options MD_ROOT_SIZE=4096 # 3MB ram disk #options ROOTDEVNAME=\"ufs:md0\" #options ROOTDEVNAME=\"ufs:/dev/mmcsd0s1a\" -options NFSCLIENT #Network Filesystem Client -#options NFSSERVER #Network Filesystem Server +options NFSCL #New Network Filesystem Client +#options NFSD #New Network Filesystem Server #options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL options BOOTP_NFSROOT options BOOTP diff --git a/sys/arm/conf/CAMBRIA b/sys/arm/conf/CAMBRIA index befe28af72355..19a8daa5572c5 100644 --- a/sys/arm/conf/CAMBRIA +++ b/sys/arm/conf/CAMBRIA @@ -51,8 +51,8 @@ options SCHED_4BSD #4BSD scheduler options INET #InterNETworking options FFS #Berkeley Fast Filesystem options SOFTUPDATES #Enable FFS soft updates support -options NFSCLIENT #Network Filesystem Client -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFSCL #New Network Filesystem Client +options NFS_ROOT #NFS usable as /, requires NFSCL options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 diff --git a/sys/arm/conf/CNS11XXNAS b/sys/arm/conf/CNS11XXNAS index 76db42b4e3630..2832779a5ad5b 100644 --- a/sys/arm/conf/CNS11XXNAS +++ b/sys/arm/conf/CNS11XXNAS @@ -66,10 +66,10 @@ options FFS #Berkeley Fast Filesystem options SOFTUPDATES #Enable FFS soft updates support options UFS_ACL #Support for access control lists options UFS_DIRHASH #Improve performance on big directories -options NFSCLIENT #Network Filesystem Client -#options NFSSERVER #Network Filesystem Server +options NFSCL #New Network Filesystem Client +#options NFSD #New Network Filesystem Server #options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL options MSDOSFS #MSDOS Filesystem #options CD9660 #ISO 9660 Filesystem #options PROCFS #Process filesystem (requires PSEUDOFS) diff --git a/sys/arm/conf/CRB b/sys/arm/conf/CRB index 45f19e03202df..bf12e0b819e0c 100644 --- a/sys/arm/conf/CRB +++ b/sys/arm/conf/CRB @@ -41,10 +41,10 @@ options FFS #Berkeley Fast Filesystem options SOFTUPDATES #Enable FFS soft updates support options UFS_ACL #Support for access control lists options UFS_DIRHASH #Improve performance on big directories -options NFSCLIENT #Network Filesystem Client -options NFSSERVER #Network Filesystem Server +options NFSCL #New Network Filesystem Client +options NFSD #New Network Filesystem Server options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL #options MSDOSFS #MSDOS Filesystem options CD9660 #ISO 9660 Filesystem #options PROCFS #Process filesystem (requires PSEUDOFS) diff --git a/sys/arm/conf/DB-78XXX b/sys/arm/conf/DB-78XXX index 7b58adaa9370a..d38ae55aade3c 100644 --- a/sys/arm/conf/DB-78XXX +++ b/sys/arm/conf/DB-78XXX @@ -17,9 +17,9 @@ options SCHED_4BSD #4BSD scheduler options INET #InterNETworking options INET6 #IPv6 communications protocols options FFS #Berkeley Fast Filesystem -options NFSCLIENT #Network Filesystem Client +options NFSCL #New Network Filesystem Client options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 diff --git a/sys/arm/conf/DB-88F5XXX b/sys/arm/conf/DB-88F5XXX index 655d4a736afaa..d5df863c0158c 100644 --- a/sys/arm/conf/DB-88F5XXX +++ b/sys/arm/conf/DB-88F5XXX @@ -17,9 +17,9 @@ options SCHED_4BSD #4BSD scheduler options INET #InterNETworking options INET6 #IPv6 communications protocols options FFS #Berkeley Fast Filesystem -options NFSCLIENT #Network Filesystem Client +options NFSCL #New Network Filesystem Client options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 diff --git a/sys/arm/conf/DB-88F6XXX b/sys/arm/conf/DB-88F6XXX index ff9f28940bfb5..fec1c4e7f20c0 100644 --- a/sys/arm/conf/DB-88F6XXX +++ b/sys/arm/conf/DB-88F6XXX @@ -17,9 +17,9 @@ options SCHED_4BSD #4BSD scheduler options INET #InterNETworking options INET6 #IPv6 communications protocols options FFS #Berkeley Fast Filesystem -options NFSCLIENT #Network Filesystem Client +options NFSCL #New Network Filesystem Client options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 diff --git a/sys/arm/conf/DOCKSTAR b/sys/arm/conf/DOCKSTAR index 780cb78d4d683..4e5b596394292 100644 --- a/sys/arm/conf/DOCKSTAR +++ b/sys/arm/conf/DOCKSTAR @@ -17,9 +17,9 @@ options SCHED_4BSD #4BSD scheduler options INET #InterNETworking options INET6 #IPv6 communications protocols options FFS #Berkeley Fast Filesystem -options NFSCLIENT #Network Filesystem Client +options NFSCL #New Network Filesystem Client options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 diff --git a/sys/arm/conf/EP80219 b/sys/arm/conf/EP80219 index 23717dfa96335..38b0c2f448899 100644 --- a/sys/arm/conf/EP80219 +++ b/sys/arm/conf/EP80219 @@ -40,10 +40,10 @@ options FFS #Berkeley Fast Filesystem options SOFTUPDATES #Enable FFS soft updates support options UFS_ACL #Support for access control lists options UFS_DIRHASH #Improve performance on big directories -options NFSCLIENT #Network Filesystem Client -options NFSSERVER #Network Filesystem Server +options NFSCL #New Network Filesystem Client +options NFSD #New Network Filesystem Server options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL #options MSDOSFS #MSDOS Filesystem options CD9660 #ISO 9660 Filesystem #options PROCFS #Process filesystem (requires PSEUDOFS) diff --git a/sys/arm/conf/GUMSTIX b/sys/arm/conf/GUMSTIX index e7900f5660c9e..8017a7ae3fde6 100644 --- a/sys/arm/conf/GUMSTIX +++ b/sys/arm/conf/GUMSTIX @@ -45,9 +45,9 @@ options FFS #Berkeley Fast Filesystem options SOFTUPDATES #Enable FFS soft updates support options UFS_ACL #Support for access control lists options UFS_DIRHASH #Improve performance on big directories -options NFSCLIENT #Network Filesystem Client -#options NFSSERVER #Network Filesystem Server -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFSCL #New Network Filesystem Client +#options NFSD #New Network Filesystem Server +options NFS_ROOT #NFS usable as /, requires NFSCL #options MSDOSFS #MSDOS Filesystem #options CD9660 #ISO 9660 Filesystem #options PROCFS #Process filesystem (requires PSEUDOFS) diff --git a/sys/arm/conf/HL200 b/sys/arm/conf/HL200 index dd46a61c2fde9..ffd306ab0ba3a 100644 --- a/sys/arm/conf/HL200 +++ b/sys/arm/conf/HL200 @@ -39,10 +39,10 @@ options FFS #Berkeley Fast Filesystem #options MD_ROOT #MD is a potential root device #options MD_ROOT_SIZE=4096 # 3MB ram disk #options ROOTDEVNAME=\"ufs:/dev/mmcsd0s1a\" -options NFSCLIENT #Network Filesystem Client -#options NFSSERVER #Network Filesystem Server +options NFSCL #New Network Filesystem Client +#options NFSD #New Network Filesystem Server #options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL options BOOTP_NFSROOT options BOOTP options BOOTP_NFSV3 @@ -126,7 +126,7 @@ device udav # Davicom DM9601E USB device rum # Ralink Technology RT2501USB wireless NICs device uath # Atheros AR5523 wireless NICs device ural # Ralink Technology RT2500USB wireless NICs -device zyd # ZyDAS zb1211/zb1211b wireless NICs +device zyd # ZyDAS zd1211/zd1211b wireless NICs # SCSI peripherals device scbus # SCSI bus (required for SCSI) device da # Direct Access (disks) diff --git a/sys/arm/conf/HL201 b/sys/arm/conf/HL201 index 6524cc648e869..157ac21a3ca72 100644 --- a/sys/arm/conf/HL201 +++ b/sys/arm/conf/HL201 @@ -39,10 +39,10 @@ options FFS #Berkeley Fast Filesystem #options MD_ROOT #MD is a potential root device #options MD_ROOT_SIZE=4096 # 3MB ram disk #options ROOTDEVNAME=\"ufs:/dev/mmcsd0s1a\" -options NFSCLIENT #Network Filesystem Client -#options NFSSERVER #Network Filesystem Server +options NFSCL #New Network Filesystem Client +#options NFSD #New Network Filesystem Server #options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL options BOOTP_NFSROOT options BOOTP options BOOTP_NFSV3 @@ -117,7 +117,7 @@ device udav # Davicom DM9601E USB #device rum # Ralink Technology RT2501USB wireless NICs #device uath # Atheros AR5523 wireless NICs #device ural # Ralink Technology RT2500USB wireless NICs -#device zyd # ZyDAS zb1211/zb1211b wireless NICs +#device zyd # ZyDAS zd1211/zd1211b wireless NICs # SCSI peripherals device scbus # SCSI bus (required for SCSI) device da # Direct Access (disks) diff --git a/sys/arm/conf/IQ31244 b/sys/arm/conf/IQ31244 index 56798116c4348..e35427c679da5 100644 --- a/sys/arm/conf/IQ31244 +++ b/sys/arm/conf/IQ31244 @@ -41,10 +41,10 @@ options FFS #Berkeley Fast Filesystem options SOFTUPDATES #Enable FFS soft updates support options UFS_ACL #Support for access control lists options UFS_DIRHASH #Improve performance on big directories -options NFSCLIENT #Network Filesystem Client -options NFSSERVER #Network Filesystem Server +options NFSCL #New Network Filesystem Client +options NFSD #New Network Filesystem Server options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL #options MSDOSFS #MSDOS Filesystem options CD9660 #ISO 9660 Filesystem #options PROCFS #Process filesystem (requires PSEUDOFS) diff --git a/sys/arm/conf/KB920X b/sys/arm/conf/KB920X index f47e9acf09b28..524e38705389c 100644 --- a/sys/arm/conf/KB920X +++ b/sys/arm/conf/KB920X @@ -40,10 +40,10 @@ options FFS #Berkeley Fast Filesystem #options MD_ROOT #MD is a potential root device #options MD_ROOT_SIZE=4096 # 4MB ram disk options ROOTDEVNAME=\"ufs:/dev/mmcsd0s1a\" -options NFSCLIENT #Network Filesystem Client -#options NFSSERVER #Network Filesystem Server +options NFSCL #New Network Filesystem Client +#options NFSD #New Network Filesystem Server #options NFSLOCKD #Network Lock Manager -#options NFS_ROOT #NFS usable as /, requires NFSCLIENT +#options NFS_ROOT #NFS usable as /, requires NFSCL #options BOOTP_NFSROOT #options BOOTP @@ -126,7 +126,7 @@ device udav # Davicom DM9601E USB device rum # Ralink Technology RT2501USB wireless NICs device uath # Atheros AR5523 wireless NICs device ural # Ralink Technology RT2500USB wireless NICs -device zyd # ZyDAS zb1211/zb1211b wireless NICs +device zyd # ZyDAS zd1211/zd1211b wireless NICs # SCSI peripherals device scbus # SCSI bus (required for SCSI) device da # Direct Access (disks) diff --git a/sys/arm/conf/LN2410SBC b/sys/arm/conf/LN2410SBC index e4f3a5445c607..4598aef57ff8a 100644 --- a/sys/arm/conf/LN2410SBC +++ b/sys/arm/conf/LN2410SBC @@ -45,7 +45,7 @@ options ROOTDEVNAME=\"ufs:da0s1\" #options BOOTP #options BOOTP_NFSROOT # NFS mount root filesystem using BOOTP info -#options NFSCLIENT #Network File System client +#options NFSCL #New Network Filesystem Client #options NFS_ROOT #NFS usable as root device options PSEUDOFS #Pseudo-filesystem framework diff --git a/sys/arm/conf/NSLU b/sys/arm/conf/NSLU index d921e34902440..2e4f4b1cc5a27 100644 --- a/sys/arm/conf/NSLU +++ b/sys/arm/conf/NSLU @@ -58,10 +58,10 @@ options FFS #Berkeley Fast Filesystem options SOFTUPDATES #Enable FFS soft updates support options UFS_ACL #Support for access control lists options UFS_DIRHASH #Improve performance on big directories -options NFSCLIENT #Network Filesystem Client -options NFSSERVER #Network Filesystem Server +options NFSCL #New Network Filesystem Client +options NFSD #New Network Filesystem Server options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL #options MSDOSFS #MSDOS Filesystem options CD9660 #ISO 9660 Filesystem #options PROCFS #Process filesystem (requires PSEUDOFS) diff --git a/sys/arm/conf/QILA9G20 b/sys/arm/conf/QILA9G20 index 55839cee1ad11..6318a574df0f6 100644 --- a/sys/arm/conf/QILA9G20 +++ b/sys/arm/conf/QILA9G20 @@ -39,10 +39,10 @@ options FFS #Berkeley Fast Filesystem #options UFS_DIRHASH #Improve performance on big directories #options MD_ROOT #MD is a potential root device #options MD_ROOT_SIZE=4096 # 3MB ram disk -options NFSCLIENT #Network Filesystem Client -#options NFSSERVER #Network Filesystem Server +options NFSCL #New Network Filesystem Client +#options NFSD #New Network Filesystem Server #options NFSLOCKD #Network Lock Manager -#options NFS_ROOT #NFS usable as /, requires NFSCLIENT +#options NFS_ROOT #NFS usable as /, requires NFSCL #options BOOTP_NFSROOT #options BOOTP #options BOOTP_NFSV3 @@ -142,7 +142,7 @@ device udav # Davicom DM9601E USB #device rum # Ralink Technology RT2501USB wireless NICs #device uath # Atheros AR5523 wireless NICs #device ural # Ralink Technology RT2500USB wireless NICs -#device zyd # ZyDAS zb1211/zb1211b wireless NICs +#device zyd # ZyDAS zd1211/zd1211b wireless NICs # Wireless NIC cards #device wlan # 802.11 support diff --git a/sys/arm/conf/SAM9G20EK b/sys/arm/conf/SAM9G20EK index 6c2e94ef1cdcb..e304e9d84b4b0 100644 --- a/sys/arm/conf/SAM9G20EK +++ b/sys/arm/conf/SAM9G20EK @@ -38,10 +38,10 @@ options FFS #Berkeley Fast Filesystem #options UFS_DIRHASH #Improve performance on big directories #options MD_ROOT #MD is a potential root device #options MD_ROOT_SIZE=4096 # 3MB ram disk -options NFSCLIENT #Network Filesystem Client -#options NFSSERVER #Network Filesystem Server +options NFSCL #New Network Filesystem Client +#options NFSD #New Network Filesystem Server #options NFSLOCKD #Network Lock Manager -#options NFS_ROOT #NFS usable as /, requires NFSCLIENT +#options NFS_ROOT #NFS usable as /, requires NFSCL #options BOOTP_NFSROOT #options BOOTP #options BOOTP_NFSV3 @@ -142,7 +142,7 @@ device udav # Davicom DM9601E USB #device rum # Ralink Technology RT2501USB wireless NICs #device uath # Atheros AR5523 wireless NICs #device ural # Ralink Technology RT2500USB wireless NICs -#device zyd # ZyDAS zb1211/zb1211b wireless NICs +#device zyd # ZyDAS zd1211/zd1211b wireless NICs # Wireless NIC cards #device wlan # 802.11 support diff --git a/sys/arm/conf/SHEEVAPLUG b/sys/arm/conf/SHEEVAPLUG index 75a5474517e66..5392c95093ef1 100644 --- a/sys/arm/conf/SHEEVAPLUG +++ b/sys/arm/conf/SHEEVAPLUG @@ -17,9 +17,9 @@ options SCHED_4BSD #4BSD scheduler options INET #InterNETworking options INET6 #IPv6 communications protocols options FFS #Berkeley Fast Filesystem -options NFSCLIENT #Network Filesystem Client +options NFSCL #New Network Filesystem Client options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 diff --git a/sys/arm/conf/SIMICS b/sys/arm/conf/SIMICS index 229c60f9cdeaf..84ff983cde002 100644 --- a/sys/arm/conf/SIMICS +++ b/sys/arm/conf/SIMICS @@ -39,10 +39,10 @@ options UFS_ACL #Support for access control lists options UFS_DIRHASH #Improve performance on big directories options MD_ROOT #MD is a potential root device options ROOTDEVNAME=\"ufs:md0\" -options NFSCLIENT #Network Filesystem Client -options NFSSERVER #Network Filesystem Server +options NFSCL #New Network Filesystem Client +options NFSD #New Network Filesystem Server options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL #options MSDOSFS #MSDOS Filesystem options CD9660 #ISO 9660 Filesystem #options PROCFS #Process filesystem (requires PSEUDOFS) diff --git a/sys/arm/conf/TS7800 b/sys/arm/conf/TS7800 index c72661af00144..5300ccab92f44 100644 --- a/sys/arm/conf/TS7800 +++ b/sys/arm/conf/TS7800 @@ -18,9 +18,9 @@ options INET #InterNETworking options INET6 #IPv6 communications protocols options FFS #Berkeley Fast Filesystem options SOFTUPDATES # Enable FFS soft updates support -options NFSCLIENT #Network Filesystem Client +options NFSCL #New Network Filesystem Client options NFSLOCKD #Network Lock Manager -options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options NFS_ROOT #NFS usable as /, requires NFSCL options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 diff --git a/sys/arm/include/param.h b/sys/arm/include/param.h index 1694bc43c5ed9..96a70388f1f51 100644 --- a/sys/arm/include/param.h +++ b/sys/arm/include/param.h @@ -61,7 +61,9 @@ #define MID_MACHINE MID_ARM6 #if defined(SMP) || defined(KLD_MODULE) +#ifndef MAXCPU #define MAXCPU 2 +#endif #else #define MAXCPU 1 #endif /* SMP || KLD_MODULE */ diff --git a/sys/arm/sa11x0/sa11x0_irq.S b/sys/arm/sa11x0/sa11x0_irq.S index 3cc3d14f7c3bc..1cacc2ddf8468 100644 --- a/sys/arm/sa11x0/sa11x0_irq.S +++ b/sys/arm/sa11x0/sa11x0_irq.S @@ -122,7 +122,7 @@ ENTRY(sa11x0_activateirqs) .global _C_LABEL(intrnames), _C_LABEL(sintrnames) _C_LABEL(intrnames): _C_LABEL(sintrnames): - .word 0 + .int 0 .globl _C_LABEL(intrcnt), _C_LABEL(sintrcnt) diff --git a/sys/boot/common/util.c b/sys/boot/common/util.c index 012106aef8acd..07f69a3b2f91c 100644 --- a/sys/boot/common/util.c +++ b/sys/boot/common/util.c @@ -119,7 +119,7 @@ printf(const char *fmt, ...) { va_list ap; const char *hex = "0123456789abcdef"; - char buf[10], *s; + char buf[32], *s; unsigned long long u; int c, l; diff --git a/sys/boot/forth/loader.conf b/sys/boot/forth/loader.conf index 759d62cf3fd24..c8abe58018e9c 100644 --- a/sys/boot/forth/loader.conf +++ b/sys/boot/forth/loader.conf @@ -55,6 +55,11 @@ module_path="/boot/modules" # Set the module search path #prompt="\\${interpret}" # Set the command prompt #root_disk_unit="0" # Force the root disk unit number #rootdev="disk1s1a" # Set the root filesystem +#tftp.blksize="1428" # Set the RFC 2348 TFTP block size. + # If the TFTP server does not support RFC 2348, + # the block size is set to 512. If the value + # is out of range ( < 8 || > 9008 ) an error is + # returned. ############################################################## @@ -104,6 +109,8 @@ module_path="/boot/modules" # Set the module search path #kern.ncallout="" # Set the maximum # of timer events #kern.ngroups="1023" # Set the maximum # of supplemental groups #kern.sgrowsiz="" # Set the amount to grow stack +#kern.cam.boot_delay="10000" # Delay (in ms) of root mount for CAM bus + # registration, useful for USB sticks as root #kern.cam.scsi_delay="2000" # Delay (in ms) before probing SCSI #kern.ipc.maxsockets="" # Set the maximum number of sockets avaliable #kern.ipc.nmbclusters="" # Set the number of mbuf clusters diff --git a/sys/boot/forth/loader.conf.5 b/sys/boot/forth/loader.conf.5 index c8c61c6dd0756..fa83c8f48a6c9 100644 --- a/sys/boot/forth/loader.conf.5 +++ b/sys/boot/forth/loader.conf.5 @@ -23,7 +23,7 @@ .\" SUCH DAMAGE. .\" .\" $FreeBSD$ -.Dd January 16, 2008 +.Dd July 20, 2011 .Dt LOADER.CONF 5 .Os .Sh NAME @@ -107,6 +107,9 @@ present file. Name of the kernel to be loaded. If no kernel name is set, no additional modules will be loaded. +The name must be a subdirectory of +.Pa /boot +that contains a kernel. .It Ar kernel_options Flags to be passed to the kernel. .It Ar password @@ -190,7 +193,7 @@ replacing it with .Dq spinning character (useful for embedded products and such). .It Va kernel -.Pq Dq Pa /boot/kernel/kernel +.Pq Dq kernel .It Va loader_conf_files .Pq Dq Pa /boot/loader.conf /boot/loader.conf.local .It Va splash_bmp_load diff --git a/sys/boot/forth/menu.4th b/sys/boot/forth/menu.4th index 110ec1c9253eb..fbb6c16b5c04c 100644 --- a/sys/boot/forth/menu.4th +++ b/sys/boot/forth/menu.4th @@ -742,11 +742,12 @@ create init_text8 255 allot else -rot 2drop - \ disable timeout if less than zero + \ boot immediately if less than zero dup 0< if drop - 0 menu_timeout_enabled ! - 0 ( assigned to menu_timeout below ) + menu-create + 0 25 at-xy + 0 boot then then then diff --git a/sys/boot/forth/menu.4th.8 b/sys/boot/forth/menu.4th.8 index 45388f5418521..55cbfd1e109bc 100644 --- a/sys/boot/forth/menu.4th.8 +++ b/sys/boot/forth/menu.4th.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 18, 2011 +.Dd Aug 29, 2011 .Dt MENU.4TH 8 .Os .Sh NAME @@ -96,11 +96,15 @@ will wait before executing by default) unless a key is pressed. If set to .Dq Li NO -(case-insensitive) or -.Dq Li -1 , +(case-insensitive) .Ic menu-display will wait for user input and never execute .Ic menu_timeout_command . +If set to +.Dq Li -1 , +.Ic menu-display +will boot immediately, preventing both interruption of the autoboot process and +escaping to the loader prompt. Default is .Dq Li 10 . See diff --git a/sys/boot/i386/gptboot/Makefile b/sys/boot/i386/gptboot/Makefile index 5642220a34082..48a6d590c8c88 100644 --- a/sys/boot/i386/gptboot/Makefile +++ b/sys/boot/i386/gptboot/Makefile @@ -20,12 +20,7 @@ GPTBOOT_UFS?= UFS1_AND_UFS2 #GPTBOOT_UFS?= UFS1_ONLY CFLAGS= -DBOOTPROG=\"gptboot\" \ - -Os \ - -fno-guess-branch-probability \ - -fomit-frame-pointer \ - -fno-unit-at-a-time \ - -mno-align-long-strings \ - -mrtd \ + -O1 \ -DGPT \ -D${GPTBOOT_UFS} \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ diff --git a/sys/boot/i386/gptzfsboot/Makefile b/sys/boot/i386/gptzfsboot/Makefile index f0ee578ce38ca..2067162a8cd3d 100644 --- a/sys/boot/i386/gptzfsboot/Makefile +++ b/sys/boot/i386/gptzfsboot/Makefile @@ -17,12 +17,7 @@ ORG1= 0x7c00 ORG2= 0x0 CFLAGS= -DBOOTPROG=\"gptzfsboot\" \ - -Os \ - -fno-guess-branch-probability \ - -fomit-frame-pointer \ - -fno-unit-at-a-time \ - -mno-align-long-strings \ - -mrtd \ + -O1 \ -DGPT -DBOOT2 \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} \ diff --git a/sys/boot/i386/zfsboot/Makefile b/sys/boot/i386/zfsboot/Makefile index 8caff2790a663..024fa258583a5 100644 --- a/sys/boot/i386/zfsboot/Makefile +++ b/sys/boot/i386/zfsboot/Makefile @@ -15,12 +15,7 @@ ORG1= 0x7c00 ORG2= 0x2000 CFLAGS= -DBOOTPROG=\"zfsboot\" \ - -Os \ - -fno-guess-branch-probability \ - -fomit-frame-pointer \ - -fno-unit-at-a-time \ - -mno-align-long-strings \ - -mrtd \ + -O1 \ -DBOOT2 \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} \ @@ -85,20 +80,10 @@ zfsboot.bin: zfsboot.out zfsboot.out: ${BTXCRT} zfsboot.o sio.o drv.o cons.o util.o ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} -zfsboot.o: zfsboot.s -.if ${CC:T:Mclang} == "clang" - ${CC} ${ACFLAGS} -c zfsboot.s -.endif - SRCS= zfsboot.c -zfsboot.s: zfsboot.c ${.CURDIR}/../../zfs/zfsimpl.c - ${CC} ${CFLAGS} -S -o zfsboot.s.tmp ${.CURDIR}/zfsboot.c - sed -e '/align/d' -e '/nop/d' < zfsboot.s.tmp > zfsboot.s - rm -f zfsboot.s.tmp - .if ${MACHINE_CPUARCH} == "amd64" -beforedepend zfsboot.s: machine +beforedepend zfsboot.o: machine CLEANFILES+= machine machine: ln -sf ${.CURDIR}/../../../i386/include machine diff --git a/sys/boot/powerpc/ps3/Makefile b/sys/boot/powerpc/ps3/Makefile index 0f0b7829a709f..0dee5f4c7a8db 100644 --- a/sys/boot/powerpc/ps3/Makefile +++ b/sys/boot/powerpc/ps3/Makefile @@ -10,7 +10,8 @@ INSTALLFLAGS= -b # Architecture-specific loader code SRCS= start.S conf.c metadata.c vers.c main.c devicename.c ppc64_elf_freebsd.c -SRCS+= lv1call.S ps3cons.c font.h ps3mmu.c ps3net.c ps3repo.c ps3stor.c ps3disk.c +SRCS+= lv1call.S ps3cons.c font.h ps3mmu.c ps3net.c ps3repo.c \ + ps3stor.c ps3disk.c ps3cdrom.c SRCS+= ucmpdi2.c LOADER_DISK_SUPPORT?= yes diff --git a/sys/boot/powerpc/ps3/conf.c b/sys/boot/powerpc/ps3/conf.c index 200fc7f29c696..3a5ae4c41f028 100644 --- a/sys/boot/powerpc/ps3/conf.c +++ b/sys/boot/powerpc/ps3/conf.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #endif extern struct devsw ps3disk; +extern struct devsw ps3cdrom; /* * We could use linker sets for some or all of these, but @@ -47,7 +48,10 @@ extern struct devsw ps3disk; /* Exported for libstand */ struct devsw *devsw[] = { -#if defined(LOADER_DISK_SUPPORT) || defined(LOADER_CD9660_SUPPORT) +#if defined(LOADER_CD9660_SUPPORT) + &ps3cdrom, +#endif +#if defined(LOADER_DISK_SUPPORT) &ps3disk, #endif #if defined(LOADER_NET_SUPPORT) diff --git a/sys/boot/powerpc/ps3/devicename.c b/sys/boot/powerpc/ps3/devicename.c index c46bc8928047a..041f853986d58 100644 --- a/sys/boot/powerpc/ps3/devicename.c +++ b/sys/boot/powerpc/ps3/devicename.c @@ -157,6 +157,7 @@ ps3_parsedev(struct ps3_devdesc **dev, const char *devspec, const char **path) break; case DEVT_NET: + case DEVT_CD: /* * PS3 only has one network interface (well, two, but * netbooting over wireless is not something I'm going @@ -213,6 +214,7 @@ ps3_fmtdev(void *vdev) break; case DEVT_NET: + case DEVT_CD: sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); break; } diff --git a/sys/boot/powerpc/ps3/lv1call.S b/sys/boot/powerpc/ps3/lv1call.S index 1c1e28ee0bde7..a399a9c3bbf62 100644 --- a/sys/boot/powerpc/ps3/lv1call.S +++ b/sys/boot/powerpc/ps3/lv1call.S @@ -307,14 +307,8 @@ lv1_storage_read: sldi %r6,%r9,32 clrldi %r7,%r10,32 or %r6,%r6,%r7 - lwz %r7,8(%r1) - lwz %r8,12(%r1) - sldi %r7,%r7,32 - or %r7,%r7,%r8 - lwz %r8,16(%r1) - lwz %r9,20(%r1) - sldi %r8,%r8,32 - or %r8,%r8,%r9 + ld %r7,8(%r1) + ld %r8,16(%r1) li %r11,245 hc diff --git a/sys/boot/powerpc/ps3/lv1call.h b/sys/boot/powerpc/ps3/lv1call.h index da47afb4dad86..fb8044825bd08 100644 --- a/sys/boot/powerpc/ps3/lv1call.h +++ b/sys/boot/powerpc/ps3/lv1call.h @@ -69,12 +69,12 @@ int lv1_net_stop_tx_dma(int bus, int dev, int); int lv1_net_stop_rx_dma(int bus, int dev, int); int lv1_get_repository_node_value(uint64_t lpar_id, uint64_t n1, uint64_t n2, - uint64_t n3, uint64_t n4, uint64_t *v1, uint64_t *v2); + uint64_t n3, uint64_t n4, uint64_t *v1, uint64_t *v2); -int lv1_storage_read(uint64_t dev_id, uint64_t region_id, - uint64_t start_sector, uint64_t sector_count, - uint64_t flags, uint64_t buf, uint64_t *tag); -int lv1_storage_check_async_status(uint64_t dev_id, uint64_t tag, uint64_t *status); +int lv1_storage_read(uint64_t dev_id, uint64_t region_id, uint64_t start_sector, + uint64_t sector_count, uint64_t flags, uint64_t buf, uint64_t *tag); +int lv1_storage_check_async_status(uint64_t dev_id, uint64_t tag, + uint64_t *status); #endif diff --git a/sys/boot/powerpc/ps3/main.c b/sys/boot/powerpc/ps3/main.c index db808adba289b..64bd7e9f9a245 100644 --- a/sys/boot/powerpc/ps3/main.c +++ b/sys/boot/powerpc/ps3/main.c @@ -92,11 +92,17 @@ main(void) } } - printf("\nDevice: %s\n", devsw[i]->dv_name); - currdev.d_dev = devsw[i]; currdev.d_type = currdev.d_dev->dv_type; + if (strcmp(devsw[i]->dv_name, "cd") == 0) { + f.f_devdata = &currdev; + currdev.d_unit = 0; + + if (devsw[i]->dv_open(&f, &currdev) == 0) + break; + } + if (strcmp(devsw[i]->dv_name, "disk") == 0) { f.f_devdata = &currdev; currdev.d_unit = 3; @@ -113,6 +119,8 @@ main(void) if (devsw[i] == NULL) panic("No boot device found!"); + else + printf("Boot device: %s\n", devsw[i]->dv_name); /* * Get timebase at boot. diff --git a/sys/boot/powerpc/ps3/ps3cdrom.c b/sys/boot/powerpc/ps3/ps3cdrom.c new file mode 100644 index 0000000000000..843ecd56052f3 --- /dev/null +++ b/sys/boot/powerpc/ps3/ps3cdrom.c @@ -0,0 +1,154 @@ +/*- + * Copyright (C) 2011 glevand <geoffrey.levand@mail.ru> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/endian.h> +#include <machine/stdarg.h> +#include <stand.h> + +#include "bootstrap.h" +#include "ps3bus.h" +#include "ps3devdesc.h" +#include "ps3stor.h" + +#define dev_printf(dev, fmt, args...) \ + printf("%s%d: " fmt "\n", dev->d_dev->dv_name, dev->d_unit, ##args) + +#ifdef CD_DEBUG +#define DEBUG(fmt, args...) printf("%s:%d: " fmt "\n", __func__, __LINE__, ##args) +#else +#define DEBUG(fmt, args...) +#endif + +static int ps3cdrom_init(void); +static int ps3cdrom_strategy(void *devdata, int flag, daddr_t dblk, + size_t size, char *buf, size_t *rsize); +static int ps3cdrom_open(struct open_file *f, ...); +static int ps3cdrom_close(struct open_file *f); +static void ps3cdrom_print(int verbose); + +struct devsw ps3cdrom = { + "cd", + DEVT_CD, + ps3cdrom_init, + ps3cdrom_strategy, + ps3cdrom_open, + ps3cdrom_close, + noioctl, + ps3cdrom_print, +}; + +static struct ps3_stordev stor_dev; + +static int ps3cdrom_init(void) +{ + int err; + + err = ps3stor_setup(&stor_dev, PS3_DEV_TYPE_STOR_CDROM); + if (err) + return err; + + return 0; +} + +static int ps3cdrom_strategy(void *devdata, int flag, daddr_t dblk, + size_t size, char *buf, size_t *rsize) +{ + struct ps3_devdesc *dev = (struct ps3_devdesc *) devdata; + int err; + + DEBUG("d_unit=%u dblk=%llu size=%u", dev->d_unit, dblk, size); + + if (flag != F_READ) { + dev_printf(dev, "write operation is not supported!"); + return EROFS; + } + + if (dblk % (stor_dev.sd_blksize / DEV_BSIZE) != 0) + return EINVAL; + + dblk /= (stor_dev.sd_blksize / DEV_BSIZE); + + if (size % stor_dev.sd_blksize) { + dev_printf(dev, + "size=%u is not multiple of device block size=%llu", size, + stor_dev.sd_blksize); + return EINVAL; + } + + if (rsize) + *rsize = 0; + + err = ps3stor_read_sectors(&stor_dev, dev->d_unit, dblk, + size / stor_dev.sd_blksize, 0, buf); + + if (!err && rsize) + *rsize = size; + + if (err) + dev_printf(dev, + "read operation failed dblk=%llu size=%d err=%d", dblk, + size, err); + + return err; +} + +static int ps3cdrom_open(struct open_file *f, ...) +{ + char buf[2048]; + va_list ap; + struct ps3_devdesc *dev; + int err; + + va_start(ap, f); + dev = va_arg(ap, struct ps3_devdesc *); + va_end(ap); + + if (dev->d_unit > 0) { + dev_printf(dev, "attempt to open nonexistent disk"); + return ENXIO; + } + + err = ps3stor_read_sectors(&stor_dev, dev->d_unit, 16, 1, 0, buf); + if (err) + return EIO; + + /* Do not attach if not ISO9660 (workaround for buggy firmware) */ + if (memcmp(buf, "\001CD001", 6) != 0) + return EIO; + + return 0; +} + +static int ps3cdrom_close(struct open_file *f) +{ + return 0; +} + +static void ps3cdrom_print(int verbose) +{ +} diff --git a/sys/boot/powerpc/ps3/ps3stor.c b/sys/boot/powerpc/ps3/ps3stor.c index 667b39ca5e988..bbfc56a7ae2ac 100644 --- a/sys/boot/powerpc/ps3/ps3stor.c +++ b/sys/boot/powerpc/ps3/ps3stor.c @@ -52,35 +52,39 @@ int ps3stor_setup(struct ps3_stordev *sd, int type) if (err) goto out; - err = ps3repo_read_bus_dev_id(sd->sd_busidx, sd->sd_devidx, &sd->sd_devid); + err = ps3repo_read_bus_dev_id(sd->sd_busidx, sd->sd_devidx, + &sd->sd_devid); if (err) goto out; - err = ps3repo_read_bus_dev_blk_size(sd->sd_busidx, sd->sd_devidx, &sd->sd_blksize); + err = ps3repo_read_bus_dev_blk_size(sd->sd_busidx, sd->sd_devidx, + &sd->sd_blksize); if (err) goto out; - err = ps3repo_read_bus_dev_nblocks(sd->sd_busidx, sd->sd_devidx, &sd->sd_nblocks); + err = ps3repo_read_bus_dev_nblocks(sd->sd_busidx, sd->sd_devidx, + &sd->sd_nblocks); if (err) goto out; - err = ps3repo_read_bus_dev_nregs(sd->sd_busidx, sd->sd_devidx, &sd->sd_nregs); + err = ps3repo_read_bus_dev_nregs(sd->sd_busidx, sd->sd_devidx, + &sd->sd_nregs); if (err) goto out; for (i = 0; i < sd->sd_nregs; i++) { - err = ps3repo_read_bus_dev_reg_id(sd->sd_busidx, sd->sd_devidx, i, - &sd->sd_regs[i].sr_id); + err = ps3repo_read_bus_dev_reg_id(sd->sd_busidx, sd->sd_devidx, + i, &sd->sd_regs[i].sr_id); if (err) goto out; - err = ps3repo_read_bus_dev_reg_start(sd->sd_busidx, sd->sd_devidx, i, - &sd->sd_regs[i].sr_start); + err = ps3repo_read_bus_dev_reg_start(sd->sd_busidx, + sd->sd_devidx, i, &sd->sd_regs[i].sr_start); if (err) goto out; - err = ps3repo_read_bus_dev_reg_size(sd->sd_busidx, sd->sd_devidx, i, - &sd->sd_regs[i].sr_size); + err = ps3repo_read_bus_dev_reg_size(sd->sd_busidx, + sd->sd_devidx, i, &sd->sd_regs[i].sr_size); if (err) goto out; } @@ -109,19 +113,20 @@ out: return err; } +static char dma_buf[2048] __aligned(2048); + int ps3stor_read_sectors(struct ps3_stordev *sd, int regidx, uint64_t start_sector, uint64_t sector_count, uint64_t flags, char *buf) { #define MIN(a, b) ((a) <= (b) ? (a) : (b)) -#define BOUNCE_SECTORS 4 +#define BOUNCE_SECTORS (sizeof(dma_buf) / sd->sd_blksize) #define ASYNC_STATUS_POLL_PERIOD 100 /* microseconds */ struct ps3_storreg *reg = &sd->sd_regs[regidx]; - char dma_buf[sd->sd_blksize * BOUNCE_SECTORS]; uint64_t nleft, nread, nsectors; uint64_t tag, status; unsigned int timeout; - int err; + int err = 0; nleft = sector_count; nread = 0; @@ -129,8 +134,9 @@ int ps3stor_read_sectors(struct ps3_stordev *sd, int regidx, while (nleft) { nsectors = MIN(nleft, BOUNCE_SECTORS); - err = lv1_storage_read(sd->sd_devid, reg->sr_id, start_sector + nread, nsectors, - flags, (uint32_t) dma_buf, &tag); + err = lv1_storage_read(sd->sd_devid, reg->sr_id, + start_sector + nread, nsectors, flags, (uint32_t)dma_buf, + &tag); if (err) return err; @@ -140,7 +146,8 @@ int ps3stor_read_sectors(struct ps3_stordev *sd, int regidx, if (timeout < ASYNC_STATUS_POLL_PERIOD) return ETIMEDOUT; - err = lv1_storage_check_async_status(sd->sd_devid, tag, &status); + err = lv1_storage_check_async_status(sd->sd_devid, tag, + &status); if (!err && !status) break; @@ -148,12 +155,16 @@ int ps3stor_read_sectors(struct ps3_stordev *sd, int regidx, timeout -= ASYNC_STATUS_POLL_PERIOD; } - memcpy(buf + nread * sd->sd_blksize, (u_char *) dma_buf, nsectors * sd->sd_blksize); + if (status != 0) + return EIO; + + memcpy(buf + nread * sd->sd_blksize, (u_char *)dma_buf, + nsectors * sd->sd_blksize); nread += nsectors; nleft -= nsectors; } - return 0; + return err; #undef MIN #undef BOUNCE_SECTORS diff --git a/sys/boot/zfs/zfstest.c b/sys/boot/zfs/zfstest.c index 303ef5f08efed..3e32da57781ee 100644 --- a/sys/boot/zfs/zfstest.c +++ b/sys/boot/zfs/zfstest.c @@ -30,6 +30,7 @@ #include <sys/param.h> #include <sys/queue.h> +#include <errno.h> #include <fcntl.h> #include <stdint.h> #include <stdio.h> @@ -37,14 +38,14 @@ #include <stdarg.h> #include <stddef.h> #include <stdlib.h> -#include <errno.h> +#include <unistd.h> #define NBBY 8 void pager_output(const char *line) { - printf("%s", line); + fprintf(stderr, "%s", line); } #include "zfsimpl.c" @@ -55,8 +56,8 @@ vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) int fd = *(int *) priv; if (pread(fd, buf, bytes, off) != bytes) - return -1; - return 0; + return (-1); + return (0); } static int @@ -69,10 +70,10 @@ zfs_read(spa_t *spa, dnode_phys_t *dn, void *buf, size_t size, off_t off) n = size; if (off + n > zp->zp_size) n = zp->zp_size - off; - + rc = dnode_read(spa, dn, off, buf, n); if (rc) - return (rc); + return (-rc); return (n); } @@ -80,22 +81,24 @@ zfs_read(spa_t *spa, dnode_phys_t *dn, void *buf, size_t size, off_t off) int main(int argc, char** argv) { - int i, n, off; - int fd[99]; - spa_t *spa; - dnode_phys_t dn; char buf[512]; + int fd[100]; + struct stat sb; + dnode_phys_t dn; + spa_t *spa; + int i, n, off; zfs_init(); if (argc == 1) { static char *av[] = { - "zfstest", "/dev/da0p2", "/dev/da1p2", "/dev/da2p2", + "zfstest", "COPYRIGHT", + "/dev/da0p2", "/dev/da1p2", "/dev/da2p2", NULL, }; - argc = 4; + argc = 5; argv = av; } - for (i = 1; i < argc; i++) { + for (i = 2; i < argc; i++) { fd[i] = open(argv[i], O_RDONLY); if (fd[i] < 0) continue; @@ -105,16 +108,37 @@ main(int argc, char** argv) spa_all_status(); spa = STAILQ_FIRST(&zfs_pools); - if (!spa || zfs_mount_pool(spa)) + if (spa == NULL) { + fprintf(stderr, "no pools\n"); exit(1); + } - if (zfs_lookup(spa, "zfs.c", &dn)) + if (zfs_mount_pool(spa)) { + fprintf(stderr, "can't mount pool\n"); exit(1); + } + + if (zfs_lookup(spa, argv[1], &dn)) { + fprintf(stderr, "can't lookup\n"); + exit(1); + } + + if (zfs_dnode_stat(spa, &dn, &sb)) { + fprintf(stderr, "can't stat\n"); + exit(1); + } + off = 0; do { n = zfs_read(spa, &dn, buf, 512, off); + if (n < 0) { + fprintf(stderr, "zfs_read failed\n"); + exit(1); + } write(1, buf, n); off += n; - } while (n == 512); + } while (off < sb.st_size); + + return (0); } diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c index ed0dbef444d74..b1d5ea83eb571 100644 --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$"); #define ATA_MAX_28BIT_LBA 268435455UL typedef enum { + ADA_STATE_RAHEAD, ADA_STATE_WCACHE, ADA_STATE_NORMAL } ada_state; @@ -94,7 +95,8 @@ typedef enum { } ada_quirks; typedef enum { - ADA_CCB_WCACHE = 0x01, + ADA_CCB_RAHEAD = 0x01, + ADA_CCB_WCACHE = 0x02, ADA_CCB_BUFFER_IO = 0x03, ADA_CCB_WAITING = 0x04, ADA_CCB_DUMP = 0x05, @@ -132,6 +134,7 @@ struct ada_softc { int outstanding_cmds; int trim_max_ranges; int trim_running; + int read_ahead; int write_cache; #ifdef ADA_TEST_FAILURE int force_read_error; @@ -294,10 +297,19 @@ static void adaresume(void *arg); #define ADA_DEFAULT_SPINDOWN_SUSPEND 1 #endif +#ifndef ADA_DEFAULT_READ_AHEAD +#define ADA_DEFAULT_READ_AHEAD 1 +#endif + #ifndef ADA_DEFAULT_WRITE_CACHE #define ADA_DEFAULT_WRITE_CACHE 1 #endif +#define ADA_RA (softc->read_ahead >= 0 ? \ + softc->read_ahead : ada_read_ahead) +#define ADA_WC (softc->write_cache >= 0 ? \ + softc->write_cache : ada_write_cache) + /* * Most platforms map firmware geometry to actual, but some don't. If * not overridden, default to nothing. @@ -312,6 +324,7 @@ static int ada_default_timeout = ADA_DEFAULT_TIMEOUT; static int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; static int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN; static int ada_spindown_suspend = ADA_DEFAULT_SPINDOWN_SUSPEND; +static int ada_read_ahead = ADA_DEFAULT_READ_AHEAD; static int ada_write_cache = ADA_DEFAULT_WRITE_CACHE; SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, @@ -334,6 +347,9 @@ TUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown); SYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_suspend, CTLFLAG_RW, &ada_spindown_suspend, 0, "Spin down upon suspend"); TUNABLE_INT("kern.cam.ada.spindown_suspend", &ada_spindown_suspend); +SYSCTL_INT(_kern_cam_ada, OID_AUTO, read_ahead, CTLFLAG_RW, + &ada_read_ahead, 0, "Enable disk read-ahead"); +TUNABLE_INT("kern.cam.ada.read_ahead", &ada_read_ahead); SYSCTL_INT(_kern_cam_ada, OID_AUTO, write_cache, CTLFLAG_RW, &ada_write_cache, 0, "Enable disk write cache"); TUNABLE_INT("kern.cam.ada.write_cache", &ada_write_cache); @@ -425,7 +441,8 @@ adaclose(struct disk *dp) softc = (struct ada_softc *)periph->softc; /* We only sync the cache if the drive is capable of it. */ - if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { + if ((softc->flags & ADA_FLAG_CAN_FLUSHCACHE) != 0 && + (softc->flags & ADA_FLAG_PACK_INVALID) == 0) { ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); cam_fill_ataio(&ccb->ataio, @@ -467,12 +484,20 @@ static void adaschedule(struct cam_periph *periph) { struct ada_softc *softc = (struct ada_softc *)periph->softc; + uint32_t prio; + /* Check if cam_periph_getccb() was called. */ + prio = periph->immediate_priority; + + /* Check if we have more work to do. */ if (bioq_first(&softc->bio_queue) || (!softc->trim_running && bioq_first(&softc->trim_queue))) { - /* Have more work to do, so ensure we stay scheduled */ - xpt_schedule(periph, CAM_PRIORITY_NORMAL); + prio = CAM_PRIORITY_NORMAL; } + + /* Schedule CCB if any of above is true. */ + if (prio != CAM_PRIORITY_NONE) + xpt_schedule(periph, prio); } /* @@ -736,16 +761,19 @@ adaasync(void *callback_arg, u_int32_t code, softc = (struct ada_softc *)periph->softc; cam_periph_async(periph, code, path, arg); - if (ada_write_cache < 0 && softc->write_cache < 0) - break; if (softc->state != ADA_STATE_NORMAL) break; xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); cgd.ccb_h.func_code = XPT_GDEV_TYPE; xpt_action((union ccb *)&cgd); - if ((cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) == 0) - break; - softc->state = ADA_STATE_WCACHE; + if (ADA_RA >= 0 && + cgd.ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) + softc->state = ADA_STATE_RAHEAD; + else if (ADA_WC >= 0 && + cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) + softc->state = ADA_STATE_WCACHE; + else + break; cam_periph_acquire(periph); cam_freeze_devq_arg(periph->path, RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); @@ -788,6 +816,9 @@ adasysctlinit(void *context, int pending) } SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), + OID_AUTO, "read_ahead", CTLFLAG_RW | CTLFLAG_MPSAFE, + &softc->read_ahead, 0, "Enable disk read ahead."); + SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), OID_AUTO, "write_cache", CTLFLAG_RW | CTLFLAG_MPSAFE, &softc->write_cache, 0, "Enable disk write cache."); #ifdef ADA_TEST_FAILURE @@ -921,6 +952,10 @@ adaregister(struct cam_periph *periph, void *arg) quirks = softc->quirks; TUNABLE_INT_FETCH(announce_buf, &quirks); softc->quirks = quirks; + softc->read_ahead = -1; + snprintf(announce_buf, sizeof(announce_buf), + "kern.cam.ada.%d.read_ahead", periph->unit_number); + TUNABLE_INT_FETCH(announce_buf, &softc->read_ahead); softc->write_cache = -1; snprintf(announce_buf, sizeof(announce_buf), "kern.cam.ada.%d.write_cache", periph->unit_number); @@ -1043,7 +1078,14 @@ adaregister(struct cam_periph *periph, void *arg) (ADA_DEFAULT_TIMEOUT * hz) / ADA_ORDEREDTAG_INTERVAL, adasendorderedtag, softc); - if ((ada_write_cache >= 0 || softc->write_cache >= 0) && + if (ADA_RA >= 0 && + cgd->ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) { + softc->state = ADA_STATE_RAHEAD; + cam_periph_acquire(periph); + cam_freeze_devq_arg(periph->path, + RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); + xpt_schedule(periph, CAM_PRIORITY_DEV); + } else if (ADA_WC >= 0 && cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { softc->state = ADA_STATE_WCACHE; cam_periph_acquire(periph); @@ -1316,8 +1358,19 @@ out: adaschedule(periph); break; } + case ADA_STATE_RAHEAD: case ADA_STATE_WCACHE: { + if (softc->flags & ADA_FLAG_PACK_INVALID) { + softc->state = ADA_STATE_NORMAL; + xpt_release_ccb(start_ccb); + cam_release_devq(periph->path, + RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); + adaschedule(periph); + cam_periph_release_locked(periph); + return; + } + cam_fill_ataio(ataio, 1, adadone, @@ -1327,10 +1380,15 @@ out: 0, ada_default_timeout*1000); - ata_28bit_cmd(ataio, ATA_SETFEATURES, (softc->write_cache > 0 || - (softc->write_cache < 0 && ada_write_cache)) ? - ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0); - start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE; + if (softc->state == ADA_STATE_RAHEAD) { + ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_RA ? + ATA_SF_ENAB_RCACHE : ATA_SF_DIS_RCACHE, 0, 0); + start_ccb->ccb_h.ccb_state = ADA_CCB_RAHEAD; + } else { + ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_WC ? + ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0); + start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE; + } xpt_action(start_ccb); break; } @@ -1342,6 +1400,7 @@ adadone(struct cam_periph *periph, union ccb *done_ccb) { struct ada_softc *softc; struct ccb_ataio *ataio; + struct ccb_getdev *cgd; softc = (struct ada_softc *)periph->softc; ataio = &done_ccb->ataio; @@ -1361,7 +1420,8 @@ adadone(struct cam_periph *periph, union ccb *done_ccb) return; } if (error != 0) { - if (error == ENXIO) { + if (error == ENXIO && + (softc->flags & ADA_FLAG_PACK_INVALID) == 0) { /* * Catastrophic error. Mark our pack as * invalid. @@ -1421,6 +1481,47 @@ adadone(struct cam_periph *periph, union ccb *done_ccb) biodone(bp); break; } + case ADA_CCB_RAHEAD: + { + if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + if (adaerror(done_ccb, 0, 0) == ERESTART) { + return; + } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { + cam_release_devq(done_ccb->ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + } + } + + /* + * Since our peripheral may be invalidated by an error + * above or an external event, we must release our CCB + * before releasing the reference on the peripheral. + * The peripheral will only go away once the last reference + * is removed, and we need it around for the CCB release + * operation. + */ + cgd = (struct ccb_getdev *)done_ccb; + xpt_setup_ccb(&cgd->ccb_h, periph->path, CAM_PRIORITY_NORMAL); + cgd->ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)cgd); + if (ADA_WC >= 0 && + cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { + softc->state = ADA_STATE_WCACHE; + xpt_release_ccb(done_ccb); + xpt_schedule(periph, CAM_PRIORITY_DEV); + return; + } + softc->state = ADA_STATE_NORMAL; + xpt_release_ccb(done_ccb); + cam_release_devq(periph->path, + RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); + adaschedule(periph); + cam_periph_release_locked(periph); + return; + } case ADA_CCB_WCACHE: { if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c index f63077220e66f..67c2d01125d67 100644 --- a/sys/cam/cam_periph.c +++ b/sys/cam/cam_periph.c @@ -1550,7 +1550,8 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags, * make sure we actually have retries available. */ if ((err_action & SSQ_DECREMENT_COUNT) != 0) { - if (ccb->ccb_h.retry_count > 0) + if (ccb->ccb_h.retry_count > 0 && + (periph->flags & CAM_PERIPH_INVALID) == 0) ccb->ccb_h.retry_count--; else { *action_string = "Retries exhausted"; @@ -1718,6 +1719,7 @@ int cam_periph_error(union ccb *ccb, cam_flags camflags, u_int32_t sense_flags, union ccb *save_ccb) { + struct cam_periph *periph; const char *action_string; cam_status status; int frozen; @@ -1725,7 +1727,8 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, int openings; u_int32_t relsim_flags; u_int32_t timeout = 0; - + + periph = xpt_path_periph(ccb->ccb_h.path); action_string = NULL; status = ccb->ccb_h.status; frozen = (status & CAM_DEV_QFRZN) != 0; @@ -1787,9 +1790,9 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, xpt_print(ccb->ccb_h.path, "Data overrun\n"); printed++; } - error = EIO; /* we have to kill the command */ /* decrement the number of retries */ - if (ccb->ccb_h.retry_count > 0) { + if (ccb->ccb_h.retry_count > 0 && + (periph->flags & CAM_PERIPH_INVALID) == 0) { ccb->ccb_h.retry_count--; error = ERESTART; } else { @@ -1808,7 +1811,8 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, struct cam_path *newpath; if ((camflags & CAM_RETRY_SELTO) != 0) { - if (ccb->ccb_h.retry_count > 0) { + if (ccb->ccb_h.retry_count > 0 && + (periph->flags & CAM_PERIPH_INVALID) == 0) { ccb->ccb_h.retry_count--; error = ERESTART; @@ -1826,10 +1830,11 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, timeout = periph_selto_delay; break; } + action_string = "Retries exhausted"; } error = ENXIO; /* Should we do more if we can't create the path?? */ - if (xpt_create_path(&newpath, xpt_path_periph(ccb->ccb_h.path), + if (xpt_create_path(&newpath, periph, xpt_path_path_id(ccb->ccb_h.path), xpt_path_target_id(ccb->ccb_h.path), CAM_LUN_WILDCARD) != CAM_REQ_CMP) @@ -1874,11 +1879,16 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, /* FALLTHROUGH */ case CAM_REQUEUE_REQ: /* Unconditional requeue */ - error = ERESTART; if (bootverbose && printed == 0) { xpt_print(ccb->ccb_h.path, "Request requeued\n"); printed++; } + if ((periph->flags & CAM_PERIPH_INVALID) == 0) + error = ERESTART; + else { + action_string = "Retries exhausted"; + error = EIO; + } break; case CAM_RESRC_UNAVAIL: /* Wait a bit for the resource shortage to abate. */ @@ -1893,7 +1903,8 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, /* FALLTHROUGH */ default: /* decrement the number of retries */ - if (ccb->ccb_h.retry_count > 0) { + if (ccb->ccb_h.retry_count > 0 && + (periph->flags & CAM_PERIPH_INVALID) == 0) { ccb->ccb_h.retry_count--; error = ERESTART; if (bootverbose && printed == 0) { diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 013c415d7c7d8..10b89c77b9bec 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -3336,8 +3336,10 @@ xpt_create_path_unlocked(struct cam_path **new_path_ptr, } } status = xpt_compile_path(path, periph, path_id, target_id, lun_id); - if (need_unlock) + if (need_unlock) { CAM_SIM_UNLOCK(bus->sim); + xpt_release_bus(bus); + } if (status != CAM_REQ_CMP) { free(path, M_CAMXPT); path = NULL; @@ -3445,6 +3447,38 @@ xpt_free_path(struct cam_path *path) free(path, M_CAMXPT); } +void +xpt_path_counts(struct cam_path *path, uint32_t *bus_ref, + uint32_t *periph_ref, uint32_t *target_ref, uint32_t *device_ref) +{ + + mtx_lock(&xsoftc.xpt_topo_lock); + if (bus_ref) { + if (path->bus) + *bus_ref = path->bus->refcount; + else + *bus_ref = 0; + } + mtx_unlock(&xsoftc.xpt_topo_lock); + if (periph_ref) { + if (path->periph) + *periph_ref = path->periph->refcount; + else + *periph_ref = 0; + } + if (target_ref) { + if (path->target) + *target_ref = path->target->refcount; + else + *target_ref = 0; + } + if (device_ref) { + if (path->device) + *device_ref = path->device->refcount; + else + *device_ref = 0; + } +} /* * Return -1 for failure, 0 for exact match, 1 for match with wildcards @@ -4264,15 +4298,17 @@ static void xpt_release_bus(struct cam_eb *bus) { + mtx_lock(&xsoftc.xpt_topo_lock); + KASSERT(bus->refcount >= 1, ("bus->refcount >= 1")); if ((--bus->refcount == 0) && (TAILQ_FIRST(&bus->et_entries) == NULL)) { - mtx_lock(&xsoftc.xpt_topo_lock); TAILQ_REMOVE(&xsoftc.xpt_busses, bus, links); xsoftc.bus_generation++; mtx_unlock(&xsoftc.xpt_topo_lock); cam_sim_release(bus->sim); free(bus, M_CAMXPT); - } + } else + mtx_unlock(&xsoftc.xpt_topo_lock); } static struct cam_et * @@ -4296,7 +4332,9 @@ xpt_alloc_target(struct cam_eb *bus, target_id_t target_id) * Hold a reference to our parent bus so it * will not go away before we do. */ + mtx_lock(&xsoftc.xpt_topo_lock); bus->refcount++; + mtx_unlock(&xsoftc.xpt_topo_lock); /* Insertion sort into our bus's target list */ cur_target = TAILQ_FIRST(&bus->et_entries); @@ -4317,15 +4355,17 @@ static void xpt_release_target(struct cam_et *target) { - if ((--target->refcount == 0) - && (TAILQ_FIRST(&target->ed_entries) == NULL)) { - TAILQ_REMOVE(&target->bus->et_entries, target, links); - target->bus->generation++; - xpt_release_bus(target->bus); - if (target->luns) - free(target->luns, M_CAMXPT); - free(target, M_CAMXPT); - } + if (target->refcount == 1) { + if (TAILQ_FIRST(&target->ed_entries) == NULL) { + TAILQ_REMOVE(&target->bus->et_entries, target, links); + target->bus->generation++; + xpt_release_bus(target->bus); + if (target->luns) + free(target->luns, M_CAMXPT); + free(target, M_CAMXPT); + } + } else + target->refcount--; } static struct cam_ed * @@ -4422,7 +4462,7 @@ void xpt_release_device(struct cam_ed *device) { - if (--device->refcount == 0) { + if (device->refcount == 1) { struct cam_devq *devq; if (device->alloc_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX @@ -4430,7 +4470,7 @@ xpt_release_device(struct cam_ed *device) panic("Removing device while still queued for ccbs"); if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) - callout_stop(&device->callout); + callout_stop(&device->callout); TAILQ_REMOVE(&device->target->ed_entries, device,links); device->target->generation++; @@ -4442,7 +4482,8 @@ xpt_release_device(struct cam_ed *device) cam_ccbq_fini(&device->ccbq); xpt_release_target(device->target); free(device, M_CAMXPT); - } + } else + device->refcount--; } u_int32_t diff --git a/sys/cam/cam_xpt.h b/sys/cam/cam_xpt.h index f7d9b428cb70e..1d0e7f7d23817 100644 --- a/sys/cam/cam_xpt.h +++ b/sys/cam/cam_xpt.h @@ -106,6 +106,9 @@ cam_status xpt_create_path_unlocked(struct cam_path **new_path_ptr, int xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path); void xpt_free_path(struct cam_path *path); +void xpt_path_counts(struct cam_path *path, uint32_t *bus_ref, + uint32_t *periph_ref, uint32_t *target_ref, + uint32_t *device_ref); int xpt_path_comp(struct cam_path *path1, struct cam_path *path2); void xpt_print_path(struct cam_path *path); @@ -138,4 +141,3 @@ void xpt_release_path(struct cam_path *path); #endif /* _KERNEL */ #endif /* _CAM_CAM_XPT_H */ - diff --git a/sys/cddl/boot/zfs/zfssubr.c b/sys/cddl/boot/zfs/zfssubr.c index 5022292b995d6..e76c2738939e8 100644 --- a/sys/cddl/boot/zfs/zfssubr.c +++ b/sys/cddl/boot/zfs/zfssubr.c @@ -328,7 +328,7 @@ typedef struct raidz_map { (mask) = (x) & 0x8080808080808080ULL; \ (mask) = ((mask) << 1) - ((mask) >> 7); \ (x) = (((x) << 1) & 0xfefefefefefefefeULL) ^ \ - ((mask) & 0x1d1d1d1d1d1d1d1d); \ + ((mask) & 0x1d1d1d1d1d1d1d1dULL); \ } #define VDEV_RAIDZ_64MUL_4(x, mask) \ diff --git a/sys/cddl/compat/opensolaris/sys/file.h b/sys/cddl/compat/opensolaris/sys/file.h index 811b78cf87a62..7a3df369603a9 100644 --- a/sys/cddl/compat/opensolaris/sys/file.h +++ b/sys/cddl/compat/opensolaris/sys/file.h @@ -36,12 +36,18 @@ #ifdef _KERNEL typedef struct file file_t; +#include <sys/capability.h> + static __inline file_t * getf(int fd) { struct file *fp; - if (fget(curthread, fd, &fp) == 0) + /* + * We wouldn't need all of these rights on every invocation + * if we had more information about intent. + */ + if (fget(curthread, fd, CAP_READ | CAP_WRITE | CAP_SEEK, &fp) == 0) return (fp); return (NULL); } @@ -51,7 +57,8 @@ releasef(int fd) { struct file *fp; - if (fget(curthread, fd, &fp) == 0) { + /* No CAP_ rights required, as we're only releasing. */ + if (fget(curthread, fd, 0, &fp) == 0) { fdrop(fp, curthread); fdrop(fp, curthread); } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h index f7e44aadffe3f..5692dc6f44927 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h @@ -353,7 +353,6 @@ extern void *zfsdev_get_soft_state(minor_t minor, extern minor_t zfsdev_minor_alloc(void); extern void *zfsdev_state; -extern kmutex_t zfsdev_state_lock; #endif /* _KERNEL */ diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/txg.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/txg.c index 0885f27116d4d..7f9b933e7d1d7 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/txg.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/txg.c @@ -488,7 +488,7 @@ void txg_delay(dsl_pool_t *dp, uint64_t txg, int ticks) { tx_state_t *tx = &dp->dp_tx; - int timeout = ddi_get_lbolt() + ticks; + clock_t timeout = ddi_get_lbolt() + ticks; /* don't delay if this txg could transition to quiesing immediately */ if (tx->tx_open_txg > txg || diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c index 4d4b63cb2a074..47c7b4af00965 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c @@ -410,7 +410,7 @@ vdev_geom_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift) struct g_provider *pp; struct g_consumer *cp; size_t bufsize; - int error, lock; + int error; /* * We must have a pathname, and it must be absolute. @@ -422,12 +422,6 @@ vdev_geom_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift) vd->vdev_tsd = NULL; - if (mutex_owned(&spa_namespace_lock)) { - mutex_exit(&spa_namespace_lock); - lock = 1; - } else { - lock = 0; - } DROP_GIANT(); g_topology_lock(); error = 0; @@ -459,11 +453,7 @@ vdev_geom_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift) !ISP2(cp->provider->sectorsize)) { ZFS_LOG(1, "Provider %s has unsupported sectorsize.", vd->vdev_path); - - g_topology_lock(); vdev_geom_detach(cp, 0); - g_topology_unlock(); - error = EINVAL; cp = NULL; } else if (cp->acw == 0 && (spa_mode(vd->vdev_spa) & FWRITE) != 0) { @@ -486,8 +476,6 @@ vdev_geom_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift) } g_topology_unlock(); PICKUP_GIANT(); - if (lock) - mutex_enter(&spa_namespace_lock); if (cp == NULL) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; return (error); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c index ba13747ddb384..17174b29ed9ee 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c @@ -1963,8 +1963,10 @@ top: uint64_t cookie = 0; int len = sizeof (zc->zc_name) - (p - zc->zc_name); - while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0) - (void) dmu_objset_prefetch(zc->zc_name, NULL); + while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0) { + if (!dataset_name_hidden(zc->zc_name)) + (void) dmu_objset_prefetch(zc->zc_name, NULL); + } } do { @@ -4813,7 +4815,7 @@ zfsdev_minor_alloc(void) static minor_t last_minor; minor_t m; - ASSERT(MUTEX_HELD(&zfsdev_state_lock)); + ASSERT(MUTEX_HELD(&spa_namespace_lock)); for (m = last_minor + 1; m != last_minor; m++) { if (m > ZFSDEV_MAX_MINOR) @@ -4833,7 +4835,7 @@ zfs_ctldev_init(struct cdev *devp) minor_t minor; zfs_soft_state_t *zs; - ASSERT(MUTEX_HELD(&zfsdev_state_lock)); + ASSERT(MUTEX_HELD(&spa_namespace_lock)); minor = zfsdev_minor_alloc(); if (minor == 0) @@ -4854,7 +4856,7 @@ zfs_ctldev_init(struct cdev *devp) static void zfs_ctldev_destroy(zfs_onexit_t *zo, minor_t minor) { - ASSERT(MUTEX_HELD(&zfsdev_state_lock)); + ASSERT(MUTEX_HELD(&spa_namespace_lock)); zfs_onexit_destroy(zo); ddi_soft_state_free(zfsdev_state, minor); @@ -4884,9 +4886,9 @@ zfsdev_open(struct cdev *devp, int flag, int mode, struct thread *td) /* This is the control device. Allocate a new minor if requested. */ if (flag & FEXCL) { - mutex_enter(&zfsdev_state_lock); + mutex_enter(&spa_namespace_lock); error = zfs_ctldev_init(devp); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); } return (error); @@ -4901,14 +4903,14 @@ zfsdev_close(void *data) if (minor == 0) return; - mutex_enter(&zfsdev_state_lock); + mutex_enter(&spa_namespace_lock); zo = zfsdev_get_soft_state(minor, ZSST_CTLDEV); if (zo == NULL) { - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return; } zfs_ctldev_destroy(zo, minor); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); } static int diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c index 588ea85593652..8d8ddfcb22de8 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -331,8 +331,7 @@ page_lookup(vnode_t *vp, int64_t start, int64_t off, int64_t nbytes) * sleeping so that the page daemon is less * likely to reclaim it. */ - vm_page_lock_queues(); - vm_page_flag_set(pp, PG_REFERENCED); + vm_page_reference(pp); vm_page_sleep(pp, "zfsmwb"); continue; } @@ -612,7 +611,8 @@ zfs_read(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct) /* * If we're in FRSYNC mode, sync out this znode before reading it. */ - if (ioflag & FRSYNC || zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) + if (zfsvfs->z_log && + (ioflag & FRSYNC || zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)) zil_commit(zfsvfs->z_log, zp->z_id); /* @@ -2642,11 +2642,11 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, uint32_t blksize; u_longlong_t nblocks; uint64_t links; - uint64_t mtime[2], ctime[2], crtime[2]; + uint64_t mtime[2], ctime[2], crtime[2], rdev; xvattr_t *xvap = (xvattr_t *)vap; /* vap may be an xvattr_t * */ xoptattr_t *xoap = NULL; boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE; - sa_bulk_attr_t bulk[3]; + sa_bulk_attr_t bulk[4]; int count = 0; ZFS_ENTER(zfsvfs); @@ -2657,6 +2657,9 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL, &mtime, 16); SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, &ctime, 16); SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, &crtime, 16); + if (vp->v_type == VBLK || vp->v_type == VCHR) + SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_RDEV(zfsvfs), NULL, + &rdev, 8); if ((error = sa_bulk_lookup(zp->z_sa_hdl, bulk, count)) != 0) { ZFS_EXIT(zfsvfs); @@ -2685,7 +2688,11 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, mutex_enter(&zp->z_lock); vap->va_type = IFTOVT(zp->z_mode); vap->va_mode = zp->z_mode & ~S_IFMT; -// vap->va_fsid = zp->z_zfsvfs->z_vfs->vfs_dev; +#ifdef sun + vap->va_fsid = zp->z_zfsvfs->z_vfs->vfs_dev; +#else + vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; +#endif vap->va_nodeid = zp->z_id; if ((vp->v_flag & VROOT) && zfs_show_ctldir(zp)) links = zp->z_links + 1; @@ -2693,8 +2700,12 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, links = zp->z_links; vap->va_nlink = MIN(links, UINT32_MAX); /* nlink_t limit! */ vap->va_size = zp->z_size; - vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; -// vap->va_rdev = zfs_cmpldev(pzp->zp_rdev); +#ifdef sun + vap->va_rdev = vp->v_rdev; +#else + if (vp->v_type == VBLK || vp->v_type == VCHR) + vap->va_rdev = zfs_cmpldev(rdev); +#endif vap->va_seq = zp->z_seq; vap->va_flags = 0; /* FreeBSD: Reset chflags(2) flags. */ @@ -6329,7 +6340,7 @@ vop_getextattr { if (error == 0) *ap->a_size = (size_t)va.va_size; } else if (ap->a_uio != NULL) - error = VOP_READ(vp, ap->a_uio, IO_UNIT | IO_SYNC, ap->a_cred); + error = VOP_READ(vp, ap->a_uio, IO_UNIT, ap->a_cred); VOP_UNLOCK(vp, 0); vn_close(vp, flags, ap->a_cred, td); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c index 1f3d0b2a31f00..285881297f6bf 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c @@ -627,6 +627,18 @@ zfs_znode_dmu_fini(znode_t *zp) zp->z_sa_hdl = NULL; } +static void +zfs_vnode_forget(vnode_t *vp) +{ + + VOP_UNLOCK(vp, 0); + VI_LOCK(vp); + vp->v_usecount--; + vp->v_iflag |= VI_DOOMED; + vp->v_data = NULL; + vdropl(vp); +} + /* * Construct a new znode/vnode and intialize. * @@ -688,6 +700,8 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count) != 0 || zp->z_gen == 0) { if (hdl == NULL) sa_handle_destroy(zp->z_sa_hdl); + zfs_vnode_forget(vp); + zp->z_vnode = NULL; kmem_cache_free(znode_cache, zp); return (NULL); } @@ -700,7 +714,23 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, case VDIR: zp->z_zn_prefetch = B_TRUE; /* z_prefetch default is enabled */ break; +#ifdef sun + case VBLK: + case VCHR: + { + uint64_t rdev; + VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_RDEV(zfsvfs), + &rdev, sizeof (rdev)) == 0); + + vp->v_rdev = zfs_cmpldev(rdev); + } + break; +#endif /* sun */ case VFIFO: +#ifdef sun + case VSOCK: + case VDOOR: +#endif /* sun */ vp->v_op = &zfs_fifoops; break; case VREG: @@ -709,6 +739,14 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, vp->v_op = &zfs_shareops; } break; +#ifdef sun + case VLNK: + vn_setops(vp, zfs_symvnodeops); + break; + default: + vn_setops(vp, zfs_evnodeops); + break; +#endif /* sun */ } if (vp->v_type != VFIFO) VN_LOCK_ASHARE(vp); @@ -1235,6 +1273,7 @@ zfs_rezget(znode_t *zp) zfsvfs_t *zfsvfs = zp->z_zfsvfs; dmu_object_info_t doi; dmu_buf_t *db; + vnode_t *vp; uint64_t obj_num = zp->z_id; uint64_t mode, size; sa_bulk_attr_t bulk[8]; @@ -1310,8 +1349,9 @@ zfs_rezget(znode_t *zp) * that for example regular file was replaced with directory * which has the same object number. */ - if (ZTOV(zp) != NULL && - ZTOV(zp)->v_type != IFTOVT((mode_t)zp->z_mode)) { + vp = ZTOV(zp); + if (vp != NULL && + vp->v_type != IFTOVT((mode_t)zp->z_mode)) { zfs_znode_dmu_fini(zp); ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num); return (EIO); @@ -1319,8 +1359,11 @@ zfs_rezget(znode_t *zp) zp->z_unlinked = (zp->z_links == 0); zp->z_blksz = doi.doi_data_block_size; - if (zp->z_size != size && ZTOV(zp) != NULL) - vnode_pager_setsize(ZTOV(zp), zp->z_size); + if (vp != NULL) { + vn_pages_remove(vp, 0, 0); + if (zp->z_size != size) + vnode_pager_setsize(vp, zp->z_size); + } ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c index 5c7b22e2a3f32..515e613c27b76 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 by Delphix. All rights reserved. */ /* Portions Copyright 2010 Robert Milkowski */ @@ -567,7 +568,7 @@ zil_destroy(zilog_t *zilog, boolean_t keep_first) if (!list_is_empty(&zilog->zl_lwb_list)) { ASSERT(zh->zh_claim_txg == 0); - ASSERT(!keep_first); + VERIFY(!keep_first); while ((lwb = list_head(&zilog->zl_lwb_list)) != NULL) { list_remove(&zilog->zl_lwb_list, lwb); if (lwb->lwb_buf != NULL) @@ -1668,20 +1669,9 @@ zil_alloc(objset_t *os, zil_header_t *zh_phys) void zil_free(zilog_t *zilog) { - lwb_t *head_lwb; - zilog->zl_stop_sync = 1; - /* - * After zil_close() there should only be one lwb with a buffer. - */ - head_lwb = list_head(&zilog->zl_lwb_list); - if (head_lwb) { - ASSERT(head_lwb == list_tail(&zilog->zl_lwb_list)); - list_remove(&zilog->zl_lwb_list, head_lwb); - zio_buf_free(head_lwb->lwb_buf, head_lwb->lwb_sz); - kmem_cache_free(zil_lwb_cache, head_lwb); - } + ASSERT(list_is_empty(&zilog->zl_lwb_list)); list_destroy(&zilog->zl_lwb_list); avl_destroy(&zilog->zl_vdev_tree); @@ -1721,6 +1711,10 @@ zil_open(objset_t *os, zil_get_data_t *get_data) { zilog_t *zilog = dmu_objset_zil(os); + ASSERT(zilog->zl_clean_taskq == NULL); + ASSERT(zilog->zl_get_data == NULL); + ASSERT(list_is_empty(&zilog->zl_lwb_list)); + zilog->zl_get_data = get_data; zilog->zl_clean_taskq = taskq_create("zil_clean", 1, minclsyspri, 2, 2, TASKQ_PREPOPULATE); @@ -1734,7 +1728,7 @@ zil_open(objset_t *os, zil_get_data_t *get_data) void zil_close(zilog_t *zilog) { - lwb_t *tail_lwb; + lwb_t *lwb; uint64_t txg = 0; zil_commit(zilog, 0); /* commit all itx */ @@ -1746,9 +1740,9 @@ zil_close(zilog_t *zilog) * destroy the zl_clean_taskq. */ mutex_enter(&zilog->zl_lock); - tail_lwb = list_tail(&zilog->zl_lwb_list); - if (tail_lwb != NULL) - txg = tail_lwb->lwb_max_txg; + lwb = list_tail(&zilog->zl_lwb_list); + if (lwb != NULL) + txg = lwb->lwb_max_txg; mutex_exit(&zilog->zl_lock); if (txg) txg_wait_synced(zilog->zl_dmu_pool, txg); @@ -1756,6 +1750,19 @@ zil_close(zilog_t *zilog) taskq_destroy(zilog->zl_clean_taskq); zilog->zl_clean_taskq = NULL; zilog->zl_get_data = NULL; + + /* + * We should have only one LWB left on the list; remove it now. + */ + mutex_enter(&zilog->zl_lock); + lwb = list_head(&zilog->zl_lwb_list); + if (lwb != NULL) { + ASSERT(lwb == list_tail(&zilog->zl_lwb_list)); + list_remove(&zilog->zl_lwb_list, lwb); + zio_buf_free(lwb->lwb_buf, lwb->lwb_sz); + kmem_cache_free(zil_lwb_cache, lwb); + } + mutex_exit(&zilog->zl_lock); } /* diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c index a514247321ac8..61c96becdea3e 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c @@ -94,12 +94,11 @@ static char *zvol_tag = "zvol_tag"; #define ZVOL_DUMPSIZE "dumpsize" /* - * This lock protects the zfsdev_state structure from being modified - * while it's being used, e.g. an open that comes in before a create - * finishes. It also protects temporary opens of the dataset so that, + * The spa_namespace_lock protects the zfsdev_state structure from being + * modified while it's being used, e.g. an open that comes in before a + * create finishes. It also protects temporary opens of the dataset so that, * e.g., an open doesn't get a spurious EBUSY. */ -kmutex_t zfsdev_state_lock; static uint32_t zvol_minors; typedef struct zvol_extent { @@ -246,7 +245,7 @@ zvol_minor_lookup(const char *name) struct g_geom *gp; zvol_state_t *zv = NULL; - ASSERT(MUTEX_HELD(&zfsdev_state_lock)); + ASSERT(MUTEX_HELD(&spa_namespace_lock)); g_topology_lock(); LIST_FOREACH(gp, &zfs_zvol_class.geom, geom) { @@ -462,11 +461,11 @@ zvol_name2minor(const char *name, minor_t *minor) { zvol_state_t *zv; - mutex_enter(&zfsdev_state_lock); + mutex_enter(&spa_namespace_lock); zv = zvol_minor_lookup(name); if (minor && zv) *minor = zv->zv_minor; - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (zv ? 0 : -1); } #endif /* sun */ @@ -485,10 +484,10 @@ zvol_create_minor(const char *name) ZFS_LOG(1, "Creating ZVOL %s...", name); - mutex_enter(&zfsdev_state_lock); + mutex_enter(&spa_namespace_lock); if (zvol_minor_lookup(name) != NULL) { - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (EEXIST); } @@ -496,20 +495,20 @@ zvol_create_minor(const char *name) error = dmu_objset_own(name, DMU_OST_ZVOL, B_TRUE, FTAG, &os); if (error) { - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (error); } #ifdef sun if ((minor = zfsdev_minor_alloc()) == 0) { dmu_objset_disown(os, FTAG); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (ENXIO); } if (ddi_soft_state_zalloc(zfsdev_state, minor) != DDI_SUCCESS) { dmu_objset_disown(os, FTAG); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (EAGAIN); } (void) ddi_prop_update_string(minor, zfs_dip, ZVOL_PROP_NAME, @@ -521,7 +520,7 @@ zvol_create_minor(const char *name) minor, DDI_PSEUDO, 0) == DDI_FAILURE) { ddi_soft_state_free(zfsdev_state, minor); dmu_objset_disown(os, FTAG); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (EAGAIN); } @@ -532,7 +531,7 @@ zvol_create_minor(const char *name) ddi_remove_minor_node(zfs_dip, chrbuf); ddi_soft_state_free(zfsdev_state, minor); dmu_objset_disown(os, FTAG); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (EAGAIN); } @@ -572,7 +571,7 @@ zvol_create_minor(const char *name) zvol_minors++; - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); zvol_geom_run(zv); @@ -594,7 +593,7 @@ zvol_remove_zv(zvol_state_t *zv) minor_t minor = zv->zv_minor; #endif - ASSERT(MUTEX_HELD(&zfsdev_state_lock)); + ASSERT(MUTEX_HELD(&spa_namespace_lock)); if (zv->zv_total_opens != 0) return (EBUSY); @@ -620,15 +619,15 @@ zvol_remove_minor(const char *name) zvol_state_t *zv; int rc; - mutex_enter(&zfsdev_state_lock); + mutex_enter(&spa_namespace_lock); if ((zv = zvol_minor_lookup(name)) == NULL) { - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (ENXIO); } g_topology_lock(); rc = zvol_remove_zv(zv); g_topology_unlock(); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (rc); } @@ -730,7 +729,7 @@ zvol_update_volsize(objset_t *os, uint64_t volsize) dmu_tx_t *tx; int error; - ASSERT(MUTEX_HELD(&zfsdev_state_lock)); + ASSERT(MUTEX_HELD(&spa_namespace_lock)); tx = dmu_tx_create(os); dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL); @@ -761,7 +760,7 @@ zvol_remove_minors(const char *name) namelen = strlen(name); DROP_GIANT(); - mutex_enter(&zfsdev_state_lock); + mutex_enter(&spa_namespace_lock); g_topology_lock(); LIST_FOREACH_SAFE(gp, &zfs_zvol_class.geom, geom, gptmp) { @@ -779,7 +778,7 @@ zvol_remove_minors(const char *name) } g_topology_unlock(); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); PICKUP_GIANT(); } @@ -793,10 +792,10 @@ zvol_set_volsize(const char *name, major_t maj, uint64_t volsize) uint64_t old_volsize = 0ULL; uint64_t readonly; - mutex_enter(&zfsdev_state_lock); + mutex_enter(&spa_namespace_lock); zv = zvol_minor_lookup(name); if ((error = dmu_objset_hold(name, FTAG, &os)) != 0) { - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (error); } @@ -863,7 +862,7 @@ zvol_set_volsize(const char *name, major_t maj, uint64_t volsize) out: dmu_objset_rele(os, FTAG); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (error); } @@ -875,18 +874,18 @@ zvol_open(struct g_provider *pp, int flag, int count) zvol_state_t *zv; int err = 0; - mutex_enter(&zfsdev_state_lock); + mutex_enter(&spa_namespace_lock); zv = pp->private; if (zv == NULL) { - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (ENXIO); } if (zv->zv_total_opens == 0) err = zvol_first_open(zv); if (err) { - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (err); } if ((flag & FWRITE) && (zv->zv_flags & ZVOL_RDONLY)) { @@ -908,13 +907,13 @@ zvol_open(struct g_provider *pp, int flag, int count) #endif zv->zv_total_opens += count; - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (err); out: if (zv->zv_total_opens == 0) zvol_last_close(zv); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (err); } @@ -925,11 +924,11 @@ zvol_close(struct g_provider *pp, int flag, int count) zvol_state_t *zv; int error = 0; - mutex_enter(&zfsdev_state_lock); + mutex_enter(&spa_namespace_lock); zv = pp->private; if (zv == NULL) { - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (ENXIO); } @@ -952,7 +951,7 @@ zvol_close(struct g_provider *pp, int flag, int count) if (zv->zv_total_opens == 0) zvol_last_close(zv); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (error); } @@ -1571,12 +1570,12 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) int error = 0; rl_t *rl; - mutex_enter(&zfsdev_state_lock); + mutex_enter(&spa_namespace_lock); zv = zfsdev_get_soft_state(getminor(dev), ZSST_ZVOL); if (zv == NULL) { - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (ENXIO); } ASSERT(zv->zv_total_opens > 0); @@ -1590,7 +1589,7 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) dki.dki_ctype = DKC_UNKNOWN; dki.dki_unit = getminor(dev); dki.dki_maxtransfer = 1 << (SPA_MAXBLOCKSHIFT - zv->zv_min_bs); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); if (ddi_copyout(&dki, (void *)arg, sizeof (dki), flag)) error = EFAULT; return (error); @@ -1600,7 +1599,7 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) dkm.dki_lbsize = 1U << zv->zv_min_bs; dkm.dki_capacity = zv->zv_volsize >> zv->zv_min_bs; dkm.dki_media_type = DK_UNKNOWN; - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); if (ddi_copyout(&dkm, (void *)arg, sizeof (dkm), flag)) error = EFAULT; return (error); @@ -1610,14 +1609,14 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) uint64_t vs = zv->zv_volsize; uint8_t bs = zv->zv_min_bs; - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); error = zvol_getefi((void *)arg, flag, vs, bs); return (error); } case DKIOCFLUSHWRITECACHE: dkc = (struct dk_callback *)arg; - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); zil_commit(zv->zv_zilog, ZVOL_OBJ); if ((flag & FKIOCTL) && dkc != NULL && dkc->dkc_callback) { (*dkc->dkc_callback)(dkc->dkc_cookie, error); @@ -1643,10 +1642,10 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) } if (wce) { zv->zv_flags |= ZVOL_WCE; - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); } else { zv->zv_flags &= ~ZVOL_WCE; - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); zil_commit(zv->zv_zilog, ZVOL_OBJ); } return (0); @@ -1682,7 +1681,7 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) break; } - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); return (error); } #endif /* sun */ @@ -1698,14 +1697,12 @@ zvol_init(void) { VERIFY(ddi_soft_state_init(&zfsdev_state, sizeof (zfs_soft_state_t), 1) == 0); - mutex_init(&zfsdev_state_lock, NULL, MUTEX_DEFAULT, NULL); ZFS_LOG(1, "ZVOL Initialized."); } void zvol_fini(void) { - mutex_destroy(&zfsdev_state_lock); ddi_soft_state_fini(&zfsdev_state); ZFS_LOG(1, "ZVOL Deinitialized."); } @@ -1720,7 +1717,7 @@ zvol_dump_init(zvol_state_t *zv, boolean_t resize) nvlist_t *nv = NULL; uint64_t version = spa_version(dmu_objset_spa(zv->zv_objset)); - ASSERT(MUTEX_HELD(&zfsdev_state_lock)); + ASSERT(MUTEX_HELD(&spa_namespace_lock)); error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, 0, DMU_OBJECT_END); /* wait for dmu_free_long_range to actually free the blocks */ @@ -2200,11 +2197,11 @@ zvol_create_minors(const char *name) p = osname + strlen(osname); len = MAXPATHLEN - (p - osname); - if (strchr(name, '/') == NULL) { - /* Prefetch only for pool name. */ - cookie = 0; - while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0) - (void) dmu_objset_prefetch(p, NULL); + /* Prefetch the datasets. */ + cookie = 0; + while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0) { + if (!dataset_name_hidden(osname)) + (void) dmu_objset_prefetch(osname, NULL); } cookie = 0; @@ -2230,7 +2227,7 @@ zvol_rename_minor(struct g_geom *gp, const char *newname) struct g_provider *pp; zvol_state_t *zv; - ASSERT(MUTEX_HELD(&zfsdev_state_lock)); + ASSERT(MUTEX_HELD(&spa_namespace_lock)); g_topology_assert(); pp = LIST_FIRST(&gp->provider); @@ -2264,7 +2261,7 @@ zvol_rename_minors(const char *oldname, const char *newname) newnamelen = strlen(newname); DROP_GIANT(); - mutex_enter(&zfsdev_state_lock); + mutex_enter(&spa_namespace_lock); g_topology_lock(); LIST_FOREACH(gp, &zfs_zvol_class.geom, geom) { @@ -2287,6 +2284,6 @@ zvol_rename_minors(const char *oldname, const char *newname) } g_topology_unlock(); - mutex_exit(&zfsdev_state_lock); + mutex_exit(&spa_namespace_lock); PICKUP_GIANT(); } diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h index 82bdc53c049f9..5d1a269df4e79 100644 --- a/sys/compat/freebsd32/freebsd32.h +++ b/sys/compat/freebsd32/freebsd32.h @@ -310,7 +310,7 @@ struct kinfo_proc32 { char ki_rqindex; u_char ki_oncpu; u_char ki_lastcpu; - char ki_ocomm[OCOMMLEN+1]; + char ki_tdname[TDNAMLEN+1]; char ki_wmesg[WMESGLEN+1]; char ki_login[LOGNAMELEN+1]; char ki_lockname[LOCKNAMELEN+1]; diff --git a/sys/compat/freebsd32/freebsd32_ioctl.c b/sys/compat/freebsd32/freebsd32_ioctl.c index e662a5d25ed9e..1d773caab3bcb 100644 --- a/sys/compat/freebsd32/freebsd32_ioctl.c +++ b/sys/compat/freebsd32/freebsd32_ioctl.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include <sys/param.h> +#include <sys/capability.h> #include <sys/cdio.h> #include <sys/fcntl.h> #include <sys/filio.h> @@ -354,7 +355,7 @@ freebsd32_ioctl(struct thread *td, struct freebsd32_ioctl_args *uap) struct file *fp; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) + if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) return (error); if ((fp->f_flag & (FREAD | FWRITE)) == 0) { fdrop(fp, td); diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index 692c5a38af50c..8832d3d793702 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -502,6 +502,33 @@ linprocfs_dostat(PFS_FILL_ARGS) return (0); } +static int +linprocfs_doswaps(PFS_FILL_ARGS) +{ + struct xswdev xsw; + uintmax_t total, used; + int n; + char devname[SPECNAMELEN + 1]; + + sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n"); + mtx_lock(&Giant); + for (n = 0; ; n++) { + if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0) + break; + total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024; + used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024; + + /* + * The space and not tab after the device name is on + * purpose. Linux does so. + */ + sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n", + devname, total, used); + } + mtx_unlock(&Giant); + return (0); +} + /* * Filler function for proc/uptime */ @@ -1490,6 +1517,8 @@ linprocfs_init(PFS_INIT_ARGS) NULL, NULL, NULL, 0); pfs_create_file(root, "stat", &linprocfs_dostat, NULL, NULL, NULL, PFS_RD); + pfs_create_file(root, "swaps", &linprocfs_doswaps, + NULL, NULL, NULL, PFS_RD); pfs_create_file(root, "uptime", &linprocfs_douptime, NULL, NULL, NULL, PFS_RD); pfs_create_file(root, "version", &linprocfs_doversion, diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 44ad193c8b706..e923032878031 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/dirent.h> #include <sys/fcntl.h> @@ -141,7 +142,7 @@ linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mod * having the same filedesc could use that fd without * checking below. */ - error = fget(td, fd, &fp); + error = fget(td, fd, CAP_IOCTL, &fp); if (!error) { sx_slock(&proctree_lock); PROC_LOCK(p); @@ -345,7 +346,7 @@ getdents_common(struct thread *td, struct linux_getdents64_args *args, } else justone = 0; - if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, args->fd, CAP_READ, &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { @@ -1041,7 +1042,7 @@ linux_pread(td, uap) if (error == 0) { /* This seems to violate POSIX but linux does it */ - if ((error = fgetvp(td, uap->fd, &vp)) != 0) + if ((error = fgetvp(td, uap->fd, CAP_READ, &vp)) != 0) return (error); if (vp->v_type == VDIR) { vrele(vp); @@ -1390,7 +1391,7 @@ fcntl_common(struct thread *td, struct linux_fcntl64_args *args) * significant effect for pipes (SIGIO is not delivered for * pipes under Linux-2.2.35 at least). */ - error = fget(td, args->fd, &fp); + error = fget(td, args->fd, CAP_FCNTL, &fp); if (error) return (error); if (fp->f_type == DTYPE_PIPE) { diff --git a/sys/compat/linux/linux_fork.c b/sys/compat/linux/linux_fork.c index bf1d45c9ea343..5d2ce5bdb0cb2 100644 --- a/sys/compat/linux/linux_fork.c +++ b/sys/compat/linux/linux_fork.c @@ -64,7 +64,8 @@ linux_fork(struct thread *td, struct linux_fork_args *args) printf(ARGS(fork, "")); #endif - if ((error = fork1(td, RFFDG | RFPROC | RFSTOPPED, 0, &p2)) != 0) + if ((error = fork1(td, RFFDG | RFPROC | RFSTOPPED, 0, &p2, NULL, 0)) + != 0) return (error); td->td_retval[0] = p2->p_pid; @@ -100,7 +101,8 @@ linux_vfork(struct thread *td, struct linux_vfork_args *args) #endif /* Exclude RFPPWAIT */ - if ((error = fork1(td, RFFDG | RFPROC | RFMEM | RFSTOPPED, 0, &p2)) != 0) + if ((error = fork1(td, RFFDG | RFPROC | RFMEM | RFSTOPPED, 0, &p2, + NULL, 0)) != 0) return (error); td->td_retval[0] = p2->p_pid; @@ -190,7 +192,7 @@ linux_clone(struct thread *td, struct linux_clone_args *args) if (args->parent_tidptr == NULL) return (EINVAL); - error = fork1(td, ff, 0, &p2); + error = fork1(td, ff, 0, &p2, NULL, 0); if (error) return (error); diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index 5532c931fb396..d021fbada6509 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/sysproto.h> +#include <sys/capability.h> #include <sys/cdio.h> #include <sys/dvdio.h> #include <sys/conf.h> @@ -193,7 +194,7 @@ linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args) u_int sectorsize, fwcylinders, fwheads, fwsectors; off_t mediasize, bytespercyl; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); switch (args->cmd & 0xffff) { case LINUX_HDIO_GET_GEO: @@ -274,7 +275,7 @@ linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args) u_int sectorsize; off_t mediasize; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); switch (args->cmd & 0xffff) { case LINUX_BLKGETSIZE: @@ -700,7 +701,7 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args) struct file *fp; int error; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); switch (args->cmd & 0xffff) { @@ -1440,7 +1441,7 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args) struct file *fp; int error; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); switch (args->cmd & 0xffff) { @@ -1965,7 +1966,7 @@ linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args) struct file *fp; int error; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); switch (args->cmd & 0xffff) { @@ -2356,7 +2357,7 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) ifp = NULL; error = 0; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); type = fp->f_type; fdrop(fp, td); @@ -2582,7 +2583,7 @@ linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args) struct file *fp; int error, type; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); type = fp->f_type; fdrop(fp, td); @@ -2608,7 +2609,7 @@ linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args) u_long cmd; int error; - if ((error = fget(td, args->fd, &fp)) != 0) { + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) { printf("sg_linux_ioctl: fget returned %d\n", error); return (error); } @@ -2843,7 +2844,7 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) case LINUX_VIDIOCSCHAN: args->cmd = VIDIOCSCHAN; break; case LINUX_VIDIOCGTUNER: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun)); if (error) { @@ -2861,7 +2862,7 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) return (error); case LINUX_VIDIOCSTUNER: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun)); if (error) { @@ -2878,7 +2879,7 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) case LINUX_VIDIOCCAPTURE: args->cmd = VIDIOCCAPTURE; break; case LINUX_VIDIOCGWIN: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td); if (!error) { @@ -2890,7 +2891,7 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) return (error); case LINUX_VIDIOCSWIN: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin)); if (error) { @@ -2913,7 +2914,7 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) return (error); case LINUX_VIDIOCGFBUF: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td); if (!error) { @@ -2925,7 +2926,7 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) return (error); case LINUX_VIDIOCSFBUF: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf)); if (error) { @@ -2953,7 +2954,7 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args) case LINUX_VIDIOCGPLAYINFO: args->cmd = VIDIOCGPLAYINFO; break; case LINUX_VIDIOCSMICROCODE: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode)); if (error) { @@ -3197,7 +3198,7 @@ linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args) error = copyin((void *)args->arg, &l_vformat, sizeof(l_vformat)); if (error) return (error); - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); if (linux_to_bsd_v4l2_format(&l_vformat, &vformat) != 0) error = EINVAL; @@ -3220,7 +3221,7 @@ linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args) if (error) return (error); linux_to_bsd_v4l2_standard(&l_vstd, &vstd); - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = fo_ioctl(fp, VIDIOC_ENUMSTD, (caddr_t)&vstd, td->td_ucred, td); @@ -3242,7 +3243,7 @@ linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args) sizeof(struct l_v4l2_input)); if (error != 0) return (error); - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = fo_ioctl(fp, VIDIOC_ENUMINPUT, (caddr_t)&vinp, td->td_ucred, td); @@ -3261,7 +3262,7 @@ linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args) error = copyin((void *)args->arg, &l_vbuf, sizeof(l_vbuf)); if (error) return (error); - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); linux_to_bsd_v4l2_buffer(&l_vbuf, &vbuf); if ((args->cmd & 0xffff) == LINUX_VIDIOC_QUERYBUF) @@ -3431,7 +3432,7 @@ linux_ioctl(struct thread *td, struct linux_ioctl_args *args) (unsigned long)args->cmd); #endif - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); if ((fp->f_flag & (FREAD|FWRITE)) == 0) { fdrop(fp, td); diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c index 6940e45be0bd2..08728a13db19e 100644 --- a/sys/compat/linux/linux_socket.c +++ b/sys/compat/linux/linux_socket.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/proc.h> #include <sys/systm.h> #include <sys/sysproto.h> +#include <sys/capability.h> #include <sys/fcntl.h> #include <sys/file.h> #include <sys/limits.h> @@ -743,7 +744,7 @@ linux_connect(struct thread *td, struct linux_connect_args *args) * socket and use the file descriptor reference instead of * creating a new one. */ - error = fgetsock(td, args->s, &so, &fflag); + error = fgetsock(td, args->s, CAP_CONNECT, &so, &fflag); if (error == 0) { error = EISCONN; if (fflag & FNONBLOCK) { diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c index 8fa08b690f9ca..90f860d447766 100644 --- a/sys/compat/linux/linux_stats.c +++ b/sys/compat/linux/linux_stats.c @@ -141,8 +141,11 @@ translate_fd_major_minor(struct thread *td, int fd, struct stat *buf) struct vnode *vp; int major, minor; + /* + * No capability rights required here. + */ if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) || - fget(td, fd, &fp) != 0) + fget(td, fd, 0, &fp) != 0) return; vp = fp->f_vnode; if (vp != NULL && vp->v_rdev != NULL && diff --git a/sys/compat/svr4/svr4_fcntl.c b/sys/compat/svr4/svr4_fcntl.c index 88e4fc2bc12df..ce1452a3043bc 100644 --- a/sys/compat/svr4/svr4_fcntl.c +++ b/sys/compat/svr4/svr4_fcntl.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/capability.h> #include <sys/systm.h> #include <sys/file.h> #include <sys/filedesc.h> @@ -261,7 +262,17 @@ fd_revoke(td, fd) int error, *retval; retval = td->td_retval; - if ((error = fgetvp(td, fd, &vp)) != 0) + /* + * If we ever want to support Capsicum on SVR4 processes (unlikely) + * or FreeBSD grows a native frevoke() (more likely), we will need a + * CAP_REVOKE here. + * + * In the meantime, use CAP_MASK_VALID: if a SVR4 process wants to + * do an frevoke(), it needs to do it on either a regular file + * descriptor or a fully-privileged capability (which is effectively + * the same as a non-capability-restricted file descriptor). + */ + if ((error = fgetvp(td, fd, CAP_MASK_VALID, &vp)) != 0) return (error); if (vp->v_type != VCHR && vp->v_type != VBLK) { @@ -313,7 +324,7 @@ fd_truncate(td, fd, flp) /* * We only support truncating the file. */ - if ((error = fget(td, fd, &fp)) != 0) + if ((error = fget(td, fd, CAP_FTRUNCATE, &fp)) != 0) return (error); vp = fp->f_vnode; @@ -392,7 +403,7 @@ svr4_sys_open(td, uap) #if defined(NOTYET) struct file *fp; - error = fget(td, retval, &fp); + error = fget(td, retval, CAP_IOCTL, &fp); PROC_UNLOCK(p); /* * we may have lost a race the above open() and diff --git a/sys/compat/svr4/svr4_filio.c b/sys/compat/svr4/svr4_filio.c index ca85653823ab4..cb7cadae9c4f2 100644 --- a/sys/compat/svr4/svr4_filio.c +++ b/sys/compat/svr4/svr4_filio.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/proc.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/file.h> #include <sys/filio.h> #include <sys/lock.h> @@ -113,7 +114,7 @@ svr4_sys_read(td, uap) ra.buf = uap->buf; ra.nbyte = uap->nbyte; - if (fget(td, uap->fd, &fp) != 0) { + if (fget(td, uap->fd, CAP_READ, &fp) != 0) { DPRINTF(("Something fishy with the user-supplied file descriptor...\n")); return EBADF; } diff --git a/sys/compat/svr4/svr4_ioctl.c b/sys/compat/svr4/svr4_ioctl.c index 1cea41af856b5..36b05803821f6 100644 --- a/sys/compat/svr4/svr4_ioctl.c +++ b/sys/compat/svr4/svr4_ioctl.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/proc.h> +#include <sys/capability.h> #include <sys/file.h> #include <sys/filedesc.h> #include <sys/fcntl.h> @@ -102,7 +103,7 @@ svr4_sys_ioctl(td, uap) retval = td->td_retval; cmd = uap->com; - if ((error = fget(td, uap->fd, &fp)) != 0) + if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) return (error); if ((fp->f_flag & (FREAD | FWRITE)) == 0) { diff --git a/sys/compat/svr4/svr4_misc.c b/sys/compat/svr4/svr4_misc.c index 6f80fe64e6671..c0a74780ee484 100644 --- a/sys/compat/svr4/svr4_misc.c +++ b/sys/compat/svr4/svr4_misc.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/dirent.h> #include <sys/fcntl.h> #include <sys/filedesc.h> @@ -246,7 +247,8 @@ svr4_sys_getdents64(td, uap) DPRINTF(("svr4_sys_getdents64(%d, *, %d)\n", uap->fd, uap->nbytes)); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) { + if ((error = getvnode(td->td_proc->p_fd, uap->fd, + CAP_READ | CAP_SEEK, &fp)) != 0) { return (error); } @@ -427,7 +429,8 @@ svr4_sys_getdents(td, uap) if (uap->nbytes < 0) return (EINVAL); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, uap->fd, + CAP_READ | CAP_SEEK, &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { @@ -615,7 +618,8 @@ svr4_sys_fchroot(td, uap) if ((error = priv_check(td, PRIV_VFS_FCHROOT)) != 0) return error; - if ((error = getvnode(fdp, uap->fd, &fp)) != 0) + /* XXX: we have the chroot priv... what cap might we need? all? */ + if ((error = getvnode(fdp, uap->fd, 0, &fp)) != 0) return error; vp = fp->f_vnode; VREF(vp); diff --git a/sys/compat/svr4/svr4_stream.c b/sys/compat/svr4/svr4_stream.c index ec95eece0e5b7..a1a42c030116b 100644 --- a/sys/compat/svr4/svr4_stream.c +++ b/sys/compat/svr4/svr4_stream.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/fcntl.h> #include <sys/filedesc.h> #include <sys/filio.h> @@ -1448,7 +1449,7 @@ svr4_sys_putmsg(td, uap) struct file *fp; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) { + if ((error = fget(td, uap->fd, CAP_WRITE, &fp)) != 0) { #ifdef DEBUG_SVR4 uprintf("putmsg: bad fp\n"); #endif @@ -1620,7 +1621,7 @@ svr4_sys_getmsg(td, uap) struct file *fp; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) { + if ((error = fget(td, uap->fd, CAP_READ, &fp)) != 0) { #ifdef DEBUG_SVR4 uprintf("getmsg: bad fp\n"); #endif diff --git a/sys/conf/NOTES b/sys/conf/NOTES index d3951e34fc2cc..fd76593362c0a 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -213,6 +213,10 @@ options SCHED_STATS # Mandatory: options SMP # Symmetric MultiProcessor Kernel +# MAXCPU defines the maximum number of CPUs that can boot in the system. +# A default value should be already present, for every architecture. +options MAXCPU=32 + # ADAPTIVE_MUTEXES changes the behavior of blocking mutexes to spin # if the thread that currently owns the mutex is executing on another # CPU. This behaviour is enabled by default, so this option can be used @@ -495,16 +499,6 @@ options DIAGNOSTIC options REGRESSION # -# RESTARTABLE_PANICS allows one to continue from a panic as if it were -# a call to the debugger to continue from a panic as instead. It is only -# useful if a kernel debugger is present. To restart from a panic, reset -# the panicstr variable to NULL and continue execution. This option is -# for development use only and should NOT be used in production systems -# to "workaround" a panic. -# -#options RESTARTABLE_PANICS - -# # This option lets some drivers co-exist that can't co-exist in a running # system. This is used to be able to compile all kernel code in one go for # quality assurance purposes (like this file, which the option takes it name @@ -1165,6 +1159,9 @@ options MAC_TEST options CAPABILITIES # fine-grained rights on file descriptors options CAPABILITY_MODE # sandboxes with no global namespace access +# Support for process descriptors +options PROCDESC + ##################################################################### # CLOCK OPTIONS @@ -2932,7 +2929,6 @@ options SCSI_NCR_MYADDR=7 options SC_DEBUG_LEVEL=5 # Syscons debug level options SC_RENDER_DEBUG # syscons rendering debugging -options SHOW_BUSYBUFS # List buffers that prevent root unmount options VFS_BIO_DEBUG # VFS buffer I/O debugging options KSTACK_MAX_PAGES=32 # Maximum pages to give the kernel stack diff --git a/sys/conf/files b/sys/conf/files index 0dc814e0934aa..5c5d92d6b163f 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2412,6 +2412,7 @@ kern/subr_witness.c optional witness kern/sys_capability.c standard kern/sys_generic.c standard kern/sys_pipe.c standard +kern/sys_procdesc.c standard kern/sys_process.c standard kern/sys_socket.c standard kern/syscalls.c standard diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index 9f5a35701fe07..031a1848f800d 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -207,8 +207,8 @@ powerpc/ps3/ohci_ps3.c optional ps3 ohci powerpc/ps3/if_glc.c optional ps3 glc powerpc/ps3/mmu_ps3.c optional ps3 powerpc/ps3/platform_ps3.c optional ps3 -powerpc/ps3/ps3ata.c optional ps3 ps3ata powerpc/ps3/ps3bus.c optional ps3 +powerpc/ps3/ps3cdrom.c optional ps3 scbus powerpc/ps3/ps3disk.c optional ps3 powerpc/ps3/ps3pic.c optional ps3 powerpc/ps3/ps3_syscons.c optional ps3 sc diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk index e9aa6e23d7980..2320b89fa8b57 100644 --- a/sys/conf/kern.pre.mk +++ b/sys/conf/kern.pre.mk @@ -27,8 +27,12 @@ SIZE?= size _MINUS_O= -O CTFFLAGS+= -g .else +.if ${MACHINE_CPUARCH} == "powerpc" +_MINUS_O= -O # gcc miscompiles some code at -O2 +.else _MINUS_O= -O2 .endif +.endif .if ${MACHINE_CPUARCH} == "amd64" COPTFLAGS?=-O2 -frename-registers -pipe .else diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh index 9681c7904d434..b7d02e7a780a5 100644 --- a/sys/conf/newvers.sh +++ b/sys/conf/newvers.sh @@ -32,7 +32,7 @@ TYPE="FreeBSD" REVISION="9.0" -BRANCH="CURRENT" +BRANCH="BETA2" if [ "X${BRANCH_OVERRIDE}" != "X" ]; then BRANCH=${BRANCH_OVERRIDE} fi diff --git a/sys/conf/options b/sys/conf/options index 9f1ac80dbb96e..a7f12124d9cdc 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -47,6 +47,8 @@ TWA_DEBUG opt_twa.h TWA_FLASH_FIRMWARE opt_twa.h # Debugging options. +ALT_BREAK_TO_DEBUGGER opt_kdb.h +BREAK_TO_DEBUGGER opt_kdb.h DDB DDB_BUFR_SIZE opt_ddb.h DDB_CAPTURE_DEFAULTBUFSIZE opt_ddb.h @@ -149,11 +151,11 @@ PPC_DEBUG opt_ppc.h PPC_PROBE_CHIPSET opt_ppc.h PPS_SYNC opt_ntp.h PREEMPTION opt_sched.h +PROCDESC opt_procdesc.h QUOTA SCHED_4BSD opt_sched.h SCHED_STATS opt_sched.h SCHED_ULE opt_sched.h -SHOW_BUSYBUFS SLEEPQUEUE_PROFILING SLHCI_DEBUG opt_slhci.h SPX_HACK @@ -570,6 +572,7 @@ DFLTPHYS opt_global.h DIAGNOSTIC opt_global.h INVARIANT_SUPPORT opt_global.h INVARIANTS opt_global.h +MAXCPU opt_global.h MAXPHYS opt_global.h MCLSHIFT opt_global.h MUTEX_DEBUG opt_global.h @@ -578,7 +581,6 @@ LOCK_PROFILING opt_global.h LOCK_PROFILING_FAST opt_global.h MSIZE opt_global.h REGRESSION opt_global.h -RESTARTABLE_PANICS opt_global.h RWLOCK_NOINLINE opt_global.h SX_NOINLINE opt_global.h VFS_BIO_DEBUG opt_global.h @@ -636,9 +638,6 @@ BKTR_SIS_VIA_MODE opt_bktr.h BKTR_USE_FREEBSD_SMBUS opt_bktr.h BKTR_NEW_MSP34XX_DRIVER opt_bktr.h -BREAK_TO_DEBUGGER opt_comconsole.h -ALT_BREAK_TO_DEBUGGER opt_comconsole.h - # Options to support PPS UART_PPS_ON_CTS opt_uart.h diff --git a/sys/contrib/pf/net/if_pfsync.c b/sys/contrib/pf/net/if_pfsync.c index ba8a348812ac3..0a093fcf23039 100644 --- a/sys/contrib/pf/net/if_pfsync.c +++ b/sys/contrib/pf/net/if_pfsync.c @@ -2126,8 +2126,8 @@ pfsync_sendout(void) #else struct ifnet *ifp = &sc->sc_if; #endif - struct mbuf *m; #endif + struct mbuf *m; struct ip *ip; struct pfsync_header *ph; struct pfsync_subheader *subh; diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c index 5efd651f4dbb7..9d40371476632 100644 --- a/sys/contrib/pf/net/pf.c +++ b/sys/contrib/pf/net/pf.c @@ -6967,7 +6967,8 @@ done: ipfwtag = m_tag_alloc(MTAG_IPFW_RULE, 0, sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO); if (ipfwtag != NULL) { - ((struct ipfw_rule_ref *)(ipfwtag+1))->info = r->divert.port; + ((struct ipfw_rule_ref *)(ipfwtag+1))->info = + ntohs(r->divert.port); ((struct ipfw_rule_ref *)(ipfwtag+1))->rulenum = dir; m_tag_prepend(m, ipfwtag); diff --git a/sys/ddb/db_break.c b/sys/ddb/db_break.c index ac0c874184875..02833ec0a8289 100644 --- a/sys/ddb/db_break.c +++ b/sys/ddb/db_break.c @@ -35,8 +35,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_comconsole.h" - #include <sys/param.h> #include <vm/vm.h> diff --git a/sys/dev/aac/aac_linux.c b/sys/dev/aac/aac_linux.c index f8852358adec9..049e2be78e5be 100644 --- a/sys/dev/aac/aac_linux.c +++ b/sys/dev/aac/aac_linux.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/kernel.h> #include <sys/module.h> @@ -78,7 +79,7 @@ aac_linux_ioctl(struct thread *td, struct linux_ioctl_args *args) u_long cmd; int error; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); cmd = args->cmd; diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 9352be9c3377c..1d0cc2388cdde 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -574,7 +574,7 @@ acpi_attach(device_t dev) &sc->acpi_suspend_sx, 0, acpi_sleep_state_sysctl, "A", ""); SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "sleep_delay", CTLFLAG_RW, &sc->acpi_sleep_delay, 0, - "sleep delay"); + "sleep delay in seconds"); SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "s4bios", CTLFLAG_RW, &sc->acpi_s4bios, 0, "S4BIOS mode"); SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree), diff --git a/sys/dev/acpica/acpi_hpet.c b/sys/dev/acpica/acpi_hpet.c index 40e8676fceb3f..134a86afe73ae 100644 --- a/sys/dev/acpica/acpi_hpet.c +++ b/sys/dev/acpica/acpi_hpet.c @@ -190,13 +190,10 @@ restart: bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), t->next); } - if (fdiv < 5000) { - bus_read_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num)); - now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); - if ((int32_t)(now - t->next) >= 0) { - fdiv *= 2; - goto restart; - } + now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); + if ((int32_t)(now - t->next + HPET_MIN_CYCLES) >= 0) { + fdiv *= 2; + goto restart; } return (0); } @@ -679,7 +676,8 @@ hpet_attach(device_t dev) t->et.et_quality -= 10; t->et.et_frequency = sc->freq; t->et.et_min_period.sec = 0; - t->et.et_min_period.frac = 0x00008000LLU << 32; + t->et.et_min_period.frac = + (((uint64_t)(HPET_MIN_CYCLES * 2) << 32) / sc->freq) << 32; t->et.et_max_period.sec = 0xfffffffeLLU / sc->freq; t->et.et_max_period.frac = ((0xfffffffeLLU << 32) / sc->freq) << 32; diff --git a/sys/dev/acpica/acpi_hpet.h b/sys/dev/acpica/acpi_hpet.h index 8ca40cdfb3c01..fd495d5267f14 100644 --- a/sys/dev/acpica/acpi_hpet.h +++ b/sys/dev/acpica/acpi_hpet.h @@ -62,4 +62,6 @@ #define HPET_TIMER_FSB_VAL(x) ((x) * 0x20 + 0x110) #define HPET_TIMER_FSB_ADDR(x) ((x) * 0x20 + 0x114) +#define HPET_MIN_CYCLES 128 /* Period considered reliable. */ + #endif /* !__ACPI_HPET_H__ */ diff --git a/sys/dev/acpica/acpi_pcib_acpi.c b/sys/dev/acpica/acpi_pcib_acpi.c index 99e3f1f75cbe8..b96ced52f901f 100644 --- a/sys/dev/acpica/acpi_pcib_acpi.c +++ b/sys/dev/acpica/acpi_pcib_acpi.c @@ -207,9 +207,11 @@ acpi_pcib_producer_handler(ACPI_RESOURCE *res, void *context) length = res->Data.ExtAddress64.AddressLength; break; } - if (length == 0 || - res->Data.Address.MinAddressFixed != ACPI_ADDRESS_FIXED || - res->Data.Address.MaxAddressFixed != ACPI_ADDRESS_FIXED) + if (length == 0) + break; + if (min + length - 1 != max && + (res->Data.Address.MinAddressFixed != ACPI_ADDRESS_FIXED || + res->Data.Address.MaxAddressFixed != ACPI_ADDRESS_FIXED)) break; flags = 0; switch (res->Data.Address.ResourceType) { diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 0bc094edccea0..7be4cdb1f2837 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -128,6 +128,7 @@ static struct { {0x43931002, 0x00, "ATI IXP700", 0}, {0x43941002, 0x00, "ATI IXP800", 0}, {0x43951002, 0x00, "ATI IXP800", 0}, + {0x06121b21, 0x00, "ASMedia ASM1061", 0}, {0x26528086, 0x00, "Intel ICH6", AHCI_Q_NOFORCE}, {0x26538086, 0x00, "Intel ICH6M", AHCI_Q_NOFORCE}, {0x26818086, 0x00, "Intel ESB2", 0}, @@ -264,7 +265,7 @@ static struct { {0x0abe10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0abf10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, {0x0d8410de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, - {0x0d8510de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, + {0x0d8510de, 0x00, "NVIDIA MCP89", AHCI_Q_NOFORCE|AHCI_Q_NOAA}, {0x0d8610de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x0d8710de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, {0x0d8810de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, @@ -1879,12 +1880,13 @@ ahci_execute_transaction(struct ahci_slot *slot) device_printf(dev, "Poll timeout on slot %d port %d\n", slot->slot, port); device_printf(dev, "is %08x cs %08x ss %08x " - "rs %08x tfd %02x serr %08x\n", + "rs %08x tfd %02x serr %08x cmd %08x\n", ATA_INL(ch->r_mem, AHCI_P_IS), ATA_INL(ch->r_mem, AHCI_P_CI), ATA_INL(ch->r_mem, AHCI_P_SACT), ch->rslots, ATA_INL(ch->r_mem, AHCI_P_TFD), - ATA_INL(ch->r_mem, AHCI_P_SERR)); + ATA_INL(ch->r_mem, AHCI_P_SERR), + ATA_INL(ch->r_mem, AHCI_P_CMD)); et = AHCI_ERR_TIMEOUT; } @@ -1960,8 +1962,12 @@ ahci_timeout(struct ahci_slot *slot) ccs = (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CCS_MASK) >> AHCI_P_CMD_CCS_SHIFT; if ((sstatus & (1 << slot->slot)) != 0 || ccs == slot->slot || - ch->fbs_enabled) + ch->fbs_enabled || ch->wrongccs) slot->state = AHCI_SLOT_EXECUTING; + else if ((ch->rslots & (1 << ccs)) == 0) { + ch->wrongccs = 1; + slot->state = AHCI_SLOT_EXECUTING; + } callout_reset(&slot->timeout, (int)slot->ccb->ccb_h.timeout * hz / 2000, @@ -1971,10 +1977,12 @@ ahci_timeout(struct ahci_slot *slot) device_printf(dev, "Timeout on slot %d port %d\n", slot->slot, slot->ccb->ccb_h.target_id & 0x0f); - device_printf(dev, "is %08x cs %08x ss %08x rs %08x tfd %02x serr %08x\n", + device_printf(dev, "is %08x cs %08x ss %08x rs %08x tfd %02x " + "serr %08x cmd %08x\n", ATA_INL(ch->r_mem, AHCI_P_IS), ATA_INL(ch->r_mem, AHCI_P_CI), ATA_INL(ch->r_mem, AHCI_P_SACT), ch->rslots, - ATA_INL(ch->r_mem, AHCI_P_TFD), ATA_INL(ch->r_mem, AHCI_P_SERR)); + ATA_INL(ch->r_mem, AHCI_P_TFD), ATA_INL(ch->r_mem, AHCI_P_SERR), + ATA_INL(ch->r_mem, AHCI_P_CMD)); /* Handle frozen command. */ if (ch->frozen) { @@ -1987,7 +1995,7 @@ ahci_timeout(struct ahci_slot *slot) } xpt_done(fccb); } - if (!ch->fbs_enabled) { + if (!ch->fbs_enabled && !ch->wrongccs) { /* Without FBS we know real timeout source. */ ch->fatalerr = 1; /* Handle command with timeout. */ @@ -2585,6 +2593,7 @@ ahci_reset(device_t dev) xpt_release_simq(ch->sim, TRUE); ch->eslots = 0; ch->toslots = 0; + ch->wrongccs = 0; ch->fatalerr = 0; /* Tell the XPT about the event */ xpt_async(AC_BUS_RESET, ch->path, NULL); diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h index 3ace69fff9259..559c67ab0e4ad 100644 --- a/sys/dev/ahci/ahci.h +++ b/sys/dev/ahci/ahci.h @@ -426,6 +426,7 @@ struct ahci_channel { int resetting; /* Hard-reset in progress. */ int resetpolldiv; /* Hard-reset poll divider. */ int listening; /* SUD bit is cleared. */ + int wrongccs; /* CCS field in CMD was wrong */ union ccb *frozen; /* Frozen command */ struct callout pm_timer; /* Power management events */ struct callout reset_timer; /* Hard-reset timeout */ diff --git a/sys/dev/alc/if_alc.c b/sys/dev/alc/if_alc.c index ff0424ecf8d42..c13cb188dc179 100644 --- a/sys/dev/alc/if_alc.c +++ b/sys/dev/alc/if_alc.c @@ -532,13 +532,11 @@ alc_phy_reset(struct alc_softc *sc) uint16_t data; /* Reset magic from Linux. */ - CSR_WRITE_2(sc, ALC_GPHY_CFG, - GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE | GPHY_CFG_SEL_ANA_RESET); + CSR_WRITE_2(sc, ALC_GPHY_CFG, GPHY_CFG_SEL_ANA_RESET); CSR_READ_2(sc, ALC_GPHY_CFG); DELAY(10 * 1000); - CSR_WRITE_2(sc, ALC_GPHY_CFG, - GPHY_CFG_EXT_RESET | GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE | + CSR_WRITE_2(sc, ALC_GPHY_CFG, GPHY_CFG_EXT_RESET | GPHY_CFG_SEL_ANA_RESET); CSR_READ_2(sc, ALC_GPHY_CFG); DELAY(10 * 1000); @@ -623,6 +621,23 @@ alc_phy_reset(struct alc_softc *sc) alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_DATA, data); DELAY(1000); + + /* Disable hibernation. */ + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_ADDR, + 0x0029); + data = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + data &= ~0x8000; + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_DATA, + data); + + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_ADDR, + 0x000B); + data = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + data &= ~0x8000; + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, ALC_MII_DBG_DATA, + data); } static void @@ -648,8 +663,7 @@ alc_phy_down(struct alc_softc *sc) break; default: /* Force PHY down. */ - CSR_WRITE_2(sc, ALC_GPHY_CFG, - GPHY_CFG_EXT_RESET | GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE | + CSR_WRITE_2(sc, ALC_GPHY_CFG, GPHY_CFG_EXT_RESET | GPHY_CFG_SEL_ANA_RESET | GPHY_CFG_PHY_IDDQ | GPHY_CFG_PWDOWN_HW); DELAY(1000); diff --git a/sys/dev/amr/amr_linux.c b/sys/dev/amr/amr_linux.c index cb8c4573ef6bc..44e858ba804e4 100644 --- a/sys/dev/amr/amr_linux.c +++ b/sys/dev/amr/amr_linux.c @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/kernel.h> #include <sys/module.h> @@ -74,7 +75,7 @@ amr_linux_ioctl(struct thread *p, struct linux_ioctl_args *args) struct file *fp; int error; - if ((error = fget(p, args->fd, &fp)) != 0) + if ((error = fget(p, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = fo_ioctl(fp, args->cmd, (caddr_t)args->arg, p->td_ucred, p); fdrop(fp, p); diff --git a/sys/dev/arcmsr/arcmsr.c b/sys/dev/arcmsr/arcmsr.c index 962f6b87397d9..10bb5042891cc 100644 --- a/sys/dev/arcmsr/arcmsr.c +++ b/sys/dev/arcmsr/arcmsr.c @@ -68,6 +68,7 @@ ** 1.20.00.21 02/08/2011 Ching Huang Implement I/O request timeout ** 02/14/2011 Ching Huang Modified pktRequestCount ** 1.20.00.21 03/03/2011 Ching Huang if a command timeout, then wait its ccb back before free it +** 1.20.00.22 07/04/2011 Ching Huang Fixed multiple MTX panic ****************************************************************************************** * $FreeBSD$ */ @@ -150,7 +151,7 @@ #define arcmsr_callout_init(a) callout_init(a); #endif -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.21 2010-03-03" +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.22 2011-07-04" #include <dev/arcmsr/arcmsr.h> #define SRB_SIZE ((sizeof(struct CommandControlBlock)+0x1f) & 0xffe0) #define ARCMSR_SRBS_POOL_SIZE (SRB_SIZE * ARCMSR_MAX_FREESRB_NUM) @@ -1293,11 +1294,15 @@ static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) static void arcmsr_poll(struct cam_sim * psim) { struct AdapterControlBlock *acb; + int mutex; acb = (struct AdapterControlBlock *)cam_sim_softc(psim); - ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); + mutex = mtx_owned(&acb->qbuffer_lock); + if( mutex == 0 ) + ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); arcmsr_interrupt(acb); - ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); + if( mutex == 0 ) + ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); return; } /* @@ -2089,8 +2094,11 @@ struct CommandControlBlock * arcmsr_get_freesrb(struct AdapterControlBlock *acb) { struct CommandControlBlock *srb=NULL; u_int32_t workingsrb_startindex, workingsrb_doneindex; + int mutex; - ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); + mutex = mtx_owned(&acb->qbuffer_lock); + if( mutex == 0 ) + ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock); workingsrb_doneindex=acb->workingsrb_doneindex; workingsrb_startindex=acb->workingsrb_startindex; srb=acb->srbworkingQ[workingsrb_startindex]; @@ -2101,7 +2109,8 @@ struct CommandControlBlock * arcmsr_get_freesrb(struct AdapterControlBlock *acb) } else { srb=NULL; } - ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); + if( mutex == 0 ) + ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock); return(srb); } /* diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c index cf579f80f2de7..374612ec88b48 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -49,8 +49,7 @@ __FBSDID("$FreeBSD$"); #include <dev/ata/ata-pci.h> #include <ata_if.h> -/* local vars */ -static MALLOC_DEFINE(M_ATAPCI, "ata_pci", "ATA driver PCI"); +MALLOC_DEFINE(M_ATAPCI, "ata_pci", "ATA driver PCI"); /* misc defines */ #define IOMASK 0xfffffffc @@ -146,13 +145,14 @@ ata_pci_detach(device_t dev) device_delete_child(dev, children[i]); free(children, M_TEMP); } - if (ctlr->r_irq) { bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle); bus_release_resource(dev, SYS_RES_IRQ, ctlr->r_irq_rid, ctlr->r_irq); if (ctlr->r_irq_rid != ATA_IRQ_RID) pci_release_msi(dev); } + if (ctlr->chipdeinit != NULL) + ctlr->chipdeinit(dev); if (ctlr->r_res2) bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); if (ctlr->r_res1) diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h index 51064f6d7d5ab..3b90498e96171 100644 --- a/sys/dev/ata/ata-pci.h +++ b/sys/dev/ata/ata-pci.h @@ -55,6 +55,7 @@ struct ata_pci_controller { int channels; int ichannels; int (*chipinit)(device_t); + int (*chipdeinit)(device_t); int (*suspend)(device_t); int (*resume)(device_t); int (*ch_attach)(device_t); @@ -579,6 +580,8 @@ int ata_sii_chipinit(device_t); /* externs */ extern devclass_t ata_pci_devclass; +MALLOC_DECLARE(M_ATAPCI); + /* macro for easy definition of all driver module stuff */ #define ATA_DECLARE_DRIVER(dname) \ static device_method_t __CONCAT(dname,_methods)[] = { \ diff --git a/sys/dev/ata/chipsets/ata-acard.c b/sys/dev/ata/chipsets/ata-acard.c index bb81c48dc4cf2..761ec546efb33 100644 --- a/sys/dev/ata/chipsets/ata-acard.c +++ b/sys/dev/ata/chipsets/ata-acard.c @@ -59,6 +59,7 @@ struct ata_serialize { /* local prototypes */ static int ata_acard_chipinit(device_t dev); +static int ata_acard_chipdeinit(device_t dev); static int ata_acard_ch_attach(device_t dev); static int ata_acard_status(device_t dev); static int ata_acard_850_setmode(device_t dev, int target, int mode); @@ -93,6 +94,7 @@ ata_acard_probe(device_t dev) ata_set_desc(dev); ctlr->chipinit = ata_acard_chipinit; + ctlr->chipdeinit = ata_acard_chipdeinit; return (BUS_PROBE_DEFAULT); } @@ -111,7 +113,7 @@ ata_acard_chipinit(device_t dev) ctlr->setmode = ata_acard_850_setmode; ctlr->locking = ata_serialize; serial = malloc(sizeof(struct ata_serialize), - M_TEMP, M_WAITOK | M_ZERO); + M_ATAPCI, M_WAITOK | M_ZERO); ata_serialize_init(serial); ctlr->chipset_data = serial; } @@ -121,6 +123,21 @@ ata_acard_chipinit(device_t dev) } static int +ata_acard_chipdeinit(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + struct ata_serialize *serial; + + if (ctlr->chip->cfg1 == ATP_OLD) { + serial = ctlr->chipset_data; + mtx_destroy(&serial->locked_mtx); + free(serial, M_ATAPCI); + ctlr->chipset_data = NULL; + } + return (0); +} + +static int ata_acard_ch_attach(device_t dev) { struct ata_channel *ch = device_get_softc(dev); diff --git a/sys/dev/ata/chipsets/ata-acerlabs.c b/sys/dev/ata/chipsets/ata-acerlabs.c index 79e9d1192b16a..9d528daa999dd 100644 --- a/sys/dev/ata/chipsets/ata-acerlabs.c +++ b/sys/dev/ata/chipsets/ata-acerlabs.c @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); /* local prototypes */ static int ata_ali_chipinit(device_t dev); +static int ata_ali_chipdeinit(device_t dev); static int ata_ali_ch_attach(device_t dev); static int ata_ali_sata_ch_attach(device_t dev); static void ata_ali_reset(device_t dev); @@ -95,6 +96,7 @@ ata_ali_probe(device_t dev) ata_set_desc(dev); ctlr->chipinit = ata_ali_chipinit; + ctlr->chipdeinit = ata_ali_chipdeinit; return (BUS_PROBE_DEFAULT); } @@ -122,7 +124,7 @@ ata_ali_chipinit(device_t dev) return 0; /* Allocate resources for later use by channel attach routines. */ - res = malloc(sizeof(struct ali_sata_resources), M_TEMP, M_WAITOK); + res = malloc(sizeof(struct ali_sata_resources), M_ATAPCI, M_WAITOK); for (i = 0; i < 4; i++) { rid = PCIR_BAR(i); res->bars[i] = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, @@ -173,6 +175,27 @@ ata_ali_chipinit(device_t dev) } static int +ata_ali_chipdeinit(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + struct ali_sata_resources *res; + int i; + + if (ctlr->chip->cfg2 == ALI_SATA) { + res = ctlr->chipset_data; + for (i = 0; i < 4; i++) { + if (res->bars[i] != NULL) { + bus_release_resource(dev, SYS_RES_IOPORT, + PCIR_BAR(i), res->bars[i]); + } + } + free(res, M_ATAPCI); + ctlr->chipset_data = NULL; + } + return (0); +} + +static int ata_ali_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); diff --git a/sys/dev/ata/chipsets/ata-intel.c b/sys/dev/ata/chipsets/ata-intel.c index e128051b5023a..c5c22cb9e8b96 100644 --- a/sys/dev/ata/chipsets/ata-intel.c +++ b/sys/dev/ata/chipsets/ata-intel.c @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); /* local prototypes */ static int ata_intel_chipinit(device_t dev); +static int ata_intel_chipdeinit(device_t dev); static int ata_intel_ch_attach(device_t dev); static void ata_intel_reset(device_t dev); static int ata_intel_old_setmode(device_t dev, int target, int mode); @@ -85,6 +86,18 @@ static void ata_intel_31244_reset(device_t dev); #define INTEL_6CH2 8 #define INTEL_ICH7 16 +struct ata_intel_data { + struct mtx lock; + u_char smap[4]; +}; + +#define ATA_INTEL_SMAP(ctlr, ch) \ + &((struct ata_intel_data *)((ctlr)->chipset_data))->smap[(ch)->unit * 2] +#define ATA_INTEL_LOCK(ctlr) \ + mtx_lock(&((struct ata_intel_data *)((ctlr)->chipset_data))->lock) +#define ATA_INTEL_UNLOCK(ctlr) \ + mtx_unlock(&((struct ata_intel_data *)((ctlr)->chipset_data))->lock) + /* * Intel chipset support functions */ @@ -206,6 +219,7 @@ ata_intel_probe(device_t dev) ata_set_desc(dev); ctlr->chipinit = ata_intel_chipinit; + ctlr->chipdeinit = ata_intel_chipdeinit; return (BUS_PROBE_DEFAULT); } @@ -213,11 +227,14 @@ static int ata_intel_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); + struct ata_intel_data *data; if (ata_setup_interrupt(dev, ata_generic_intr)) return ENXIO; - ctlr->chipset_data = NULL; + data = malloc(sizeof(struct ata_intel_data), M_ATAPCI, M_WAITOK | M_ZERO); + mtx_init(&data->lock, "Intel SATA lock", NULL, MTX_DEF); + ctlr->chipset_data = (void *)data; /* good old PIIX needs special treatment (not implemented) */ if (ctlr->chip->chipid == ATA_I82371FB) { @@ -305,6 +322,19 @@ ata_intel_chipinit(device_t dev) } static int +ata_intel_chipdeinit(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + struct ata_intel_data *data; + + data = ctlr->chipset_data; + mtx_destroy(&data->lock); + free(data, M_ATAPCI); + ctlr->chipset_data = NULL; + return (0); +} + +static int ata_intel_ch_attach(device_t dev) { struct ata_pci_controller *ctlr; @@ -329,7 +359,7 @@ ata_intel_ch_attach(device_t dev) ch->flags |= ATA_ALWAYS_DMASTAT; if (ctlr->chip->max_dma >= ATA_SA150) { - smap = (u_char *)&ctlr->chipset_data + ch->unit * 2; + smap = ATA_INTEL_SMAP(ctlr, ch); map = pci_read_config(device_get_parent(dev), 0x90, 1); if (ctlr->chip->cfg1 & INTEL_ICH5) { map &= 0x07; @@ -415,7 +445,7 @@ ata_intel_reset(device_t dev) return (ata_generic_reset(dev)); /* Do hard-reset on respective SATA ports. */ - smap = (u_char *)&ctlr->chipset_data + ch->unit * 2; + smap = ATA_INTEL_SMAP(ctlr, ch); mask = 1 << smap[0]; if ((ch->flags & ATA_NO_SLAVE) == 0) mask |= (1 << smap[1]); @@ -605,7 +635,7 @@ ata_intel_sata_ahci_read(device_t dev, int port, int reg, u_int32_t *result) ctlr = device_get_softc(parent); ch = device_get_softc(dev); port = (port == 1) ? 1 : 0; - smap = (u_char *)&ctlr->chipset_data + ch->unit * 2; + smap = ATA_INTEL_SMAP(ctlr, ch); offset = 0x100 + smap[port] * 0x80; switch (reg) { case ATA_SSTATUS: @@ -635,7 +665,7 @@ ata_intel_sata_cscr_read(device_t dev, int port, int reg, u_int32_t *result) parent = device_get_parent(dev); ctlr = device_get_softc(parent); ch = device_get_softc(dev); - smap = (u_char *)&ctlr->chipset_data + ch->unit * 2; + smap = ATA_INTEL_SMAP(ctlr, ch); port = (port == 1) ? 1 : 0; switch (reg) { case ATA_SSTATUS: @@ -650,9 +680,11 @@ ata_intel_sata_cscr_read(device_t dev, int port, int reg, u_int32_t *result) default: return (EINVAL); } + ATA_INTEL_LOCK(ctlr); pci_write_config(parent, 0xa0, 0x50 + smap[port] * 0x10 + reg * 4, 4); *result = pci_read_config(parent, 0xa4, 4); + ATA_INTEL_UNLOCK(ctlr); return (0); } @@ -680,8 +712,10 @@ ata_intel_sata_sidpr_read(device_t dev, int port, int reg, u_int32_t *result) default: return (EINVAL); } + ATA_INTEL_LOCK(ctlr); ATA_IDX_OUTL(ch, ATA_IDX_ADDR, ((ch->unit * 2 + port) << 8) + reg); *result = ATA_IDX_INL(ch, ATA_IDX_DATA); + ATA_INTEL_UNLOCK(ctlr); return (0); } @@ -698,7 +732,7 @@ ata_intel_sata_ahci_write(device_t dev, int port, int reg, u_int32_t value) ctlr = device_get_softc(parent); ch = device_get_softc(dev); port = (port == 1) ? 1 : 0; - smap = (u_char *)&ctlr->chipset_data + ch->unit * 2; + smap = ATA_INTEL_SMAP(ctlr, ch); offset = 0x100 + smap[port] * 0x80; switch (reg) { case ATA_SSTATUS: @@ -728,7 +762,7 @@ ata_intel_sata_cscr_write(device_t dev, int port, int reg, u_int32_t value) parent = device_get_parent(dev); ctlr = device_get_softc(parent); ch = device_get_softc(dev); - smap = (u_char *)&ctlr->chipset_data + ch->unit * 2; + smap = ATA_INTEL_SMAP(ctlr, ch); port = (port == 1) ? 1 : 0; switch (reg) { case ATA_SSTATUS: @@ -743,9 +777,11 @@ ata_intel_sata_cscr_write(device_t dev, int port, int reg, u_int32_t value) default: return (EINVAL); } + ATA_INTEL_LOCK(ctlr); pci_write_config(parent, 0xa0, 0x50 + smap[port] * 0x10 + reg * 4, 4); pci_write_config(parent, 0xa4, value, 4); + ATA_INTEL_UNLOCK(ctlr); return (0); } @@ -773,8 +809,10 @@ ata_intel_sata_sidpr_write(device_t dev, int port, int reg, u_int32_t value) default: return (EINVAL); } + ATA_INTEL_LOCK(ctlr); ATA_IDX_OUTL(ch, ATA_IDX_ADDR, ((ch->unit * 2 + port) << 8) + reg); ATA_IDX_OUTL(ch, ATA_IDX_DATA, value); + ATA_INTEL_UNLOCK(ctlr); return (0); } diff --git a/sys/dev/ata/chipsets/ata-nvidia.c b/sys/dev/ata/chipsets/ata-nvidia.c index b1da6f0ecccc3..2edc0f1471df1 100644 --- a/sys/dev/ata/chipsets/ata-nvidia.c +++ b/sys/dev/ata/chipsets/ata-nvidia.c @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); /* local prototypes */ static int ata_nvidia_chipinit(device_t dev); static int ata_nvidia_ch_attach(device_t dev); +static int ata_nvidia_ch_attach_dumb(device_t dev); static int ata_nvidia_status(device_t dev); static void ata_nvidia_reset(device_t dev); static int ata_nvidia_setmode(device_t dev, int target, int mode); @@ -62,6 +63,7 @@ static int ata_nvidia_setmode(device_t dev, int target, int mode); #define NV4 0x01 #define NVQ 0x02 #define NVAHCI 0x04 +#define NVNOFORCE 0x08 /* @@ -158,7 +160,7 @@ ata_nvidia_probe(device_t dev) { ATA_NFORCE_MCP79_AA, 0, NVAHCI, 0, ATA_SA300, "nForce MCP79" }, { ATA_NFORCE_MCP79_AB, 0, NVAHCI, 0, ATA_SA300, "nForce MCP79" }, { ATA_NFORCE_MCP89_A0, 0, NVAHCI, 0, ATA_SA300, "nForce MCP89" }, - { ATA_NFORCE_MCP89_A1, 0, NVAHCI, 0, ATA_SA300, "nForce MCP89" }, + { ATA_NFORCE_MCP89_A1, 0, NVAHCI|NVNOFORCE, 0, ATA_SA300, "nForce MCP89" }, { ATA_NFORCE_MCP89_A2, 0, NVAHCI, 0, ATA_SA300, "nForce MCP89" }, { ATA_NFORCE_MCP89_A3, 0, NVAHCI, 0, ATA_SA300, "nForce MCP89" }, { ATA_NFORCE_MCP89_A4, 0, NVAHCI, 0, ATA_SA300, "nForce MCP89" }, @@ -178,7 +180,9 @@ ata_nvidia_probe(device_t dev) return ENXIO; ata_set_desc(dev); - if (ctlr->chip->cfg1 & NVAHCI) + if ((ctlr->chip->cfg1 & NVAHCI) && + ((ctlr->chip->cfg1 & NVNOFORCE) == 0 || + pci_get_subclass(dev) != PCIS_STORAGE_IDE)) ctlr->chipinit = ata_ahci_chipinit; else ctlr->chipinit = ata_nvidia_chipinit; @@ -193,7 +197,10 @@ ata_nvidia_chipinit(device_t dev) if (ata_setup_interrupt(dev, ata_generic_intr)) return ENXIO; - if (ctlr->chip->max_dma >= ATA_SA150) { + if (ctlr->chip->cfg1 & NVAHCI) { + ctlr->ch_attach = ata_nvidia_ch_attach_dumb; + ctlr->setmode = ata_sata_setmode; + } else if (ctlr->chip->max_dma >= ATA_SA150) { if (pci_read_config(dev, PCIR_BAR(5), 1) & 1) ctlr->r_type2 = SYS_RES_IOPORT; else @@ -264,6 +271,17 @@ ata_nvidia_ch_attach(device_t dev) return 0; } +static int +ata_nvidia_ch_attach_dumb(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + if (ata_pci_ch_attach(dev)) + return ENXIO; + ch->flags |= ATA_SATA; + return 0; +} + static int ata_nvidia_status(device_t dev) { diff --git a/sys/dev/ata/chipsets/ata-promise.c b/sys/dev/ata/chipsets/ata-promise.c index bee7bbad89e02..2f8b2a5ec131a 100644 --- a/sys/dev/ata/chipsets/ata-promise.c +++ b/sys/dev/ata/chipsets/ata-promise.c @@ -280,7 +280,7 @@ ata_promise_chipinit(device_t dev) /* setup host packet controls */ hpkt = malloc(sizeof(struct ata_promise_sx4), - M_TEMP, M_NOWAIT | M_ZERO); + M_ATAPCI, M_NOWAIT | M_ZERO); mtx_init(&hpkt->mtx, "ATA promise HPKT lock", NULL, MTX_DEF); TAILQ_INIT(&hpkt->queue); hpkt->busy = 0; diff --git a/sys/dev/ath/ath_dfs/null/dfs_null.c b/sys/dev/ath/ath_dfs/null/dfs_null.c index 2f050a40d1cfa..a3bae91458568 100644 --- a/sys/dev/ath/ath_dfs/null/dfs_null.c +++ b/sys/dev/ath/ath_dfs/null/dfs_null.c @@ -61,7 +61,7 @@ __FBSDID("$FreeBSD$"); #include <net/bpf.h> #ifdef INET -#include <netinet/in.h> +#include <netinet/in.h> #include <netinet/if_ether.h> #endif @@ -141,12 +141,80 @@ ath_dfs_tasklet_needed(struct ath_softc *sc, struct ieee80211_channel *chan) } /* - * Handle ioctl requests from the diagnostic interface + * Handle ioctl requests from the diagnostic interface. + * + * The initial part of this code resembles ath_ioctl_diag(); + * it's likely a good idea to reduce duplication between + * these two routines. */ int ath_ioctl_phyerr(struct ath_softc *sc, struct ath_diag *ad) { - return 1; + unsigned int id = ad->ad_id & ATH_DIAG_ID; + void *indata = NULL; + void *outdata = NULL; + u_int32_t insize = ad->ad_in_size; + u_int32_t outsize = ad->ad_out_size; + int error = 0; + HAL_PHYERR_PARAM peout; + HAL_PHYERR_PARAM *pe; + + if (ad->ad_id & ATH_DIAG_IN) { + /* + * Copy in data. + */ + indata = malloc(insize, M_TEMP, M_NOWAIT); + if (indata == NULL) { + error = ENOMEM; + goto bad; + } + error = copyin(ad->ad_in_data, indata, insize); + if (error) + goto bad; + } + if (ad->ad_id & ATH_DIAG_DYN) { + /* + * Allocate a buffer for the results (otherwise the HAL + * returns a pointer to a buffer where we can read the + * results). Note that we depend on the HAL leaving this + * pointer for us to use below in reclaiming the buffer; + * may want to be more defensive. + */ + outdata = malloc(outsize, M_TEMP, M_NOWAIT); + if (outdata == NULL) { + error = ENOMEM; + goto bad; + } + } + switch (id) { + case DFS_SET_THRESH: + if (insize < sizeof(HAL_PHYERR_PARAM)) { + error = EINVAL; + break; + } + pe = (HAL_PHYERR_PARAM *) indata; + ath_hal_enabledfs(sc->sc_ah, pe); + break; + case DFS_GET_THRESH: + memset(&peout, 0, sizeof(peout)); + outsize = sizeof(HAL_PHYERR_PARAM); + ath_hal_getdfsthresh(sc->sc_ah, &peout); + pe = (HAL_PHYERR_PARAM *) outdata; + memcpy(pe, &peout, sizeof(*pe)); + break; + default: + error = EINVAL; + } + if (outsize < ad->ad_out_size) + ad->ad_out_size = outsize; + if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size)) + error = EFAULT; +bad: + if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) + free(indata, M_TEMP); + if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) + free(outdata, M_TEMP); + return error; } /* diff --git a/sys/dev/ath/ath_hal/ah.c b/sys/dev/ath/ath_hal/ah.c index 647f32205bd38..4055079dc71ca 100644 --- a/sys/dev/ath/ath_hal/ah.c +++ b/sys/dev/ath/ath_hal/ah.c @@ -522,6 +522,9 @@ ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, case HAL_CAP_REG_DMN: /* regulatory domain */ *result = AH_PRIVATE(ah)->ah_currentRD; return HAL_OK; + case HAL_CAP_DFS_DMN: /* DFS Domain */ + *result = AH_PRIVATE(ah)->ah_dfsDomain; + return HAL_OK; case HAL_CAP_CIPHER: /* cipher handled in hardware */ case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ return HAL_ENOTSUPP; @@ -654,6 +657,8 @@ ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, } case HAL_CAP_RXDESC_SELFLINK: /* hardware supports self-linked final RX descriptors correctly */ return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_LONG_RXDESC_TSF: /* 32 bit TSF in RX descriptor? */ + return pCap->halHasLongRxDescTsf ? HAL_OK : HAL_ENOTSUPP; default: return HAL_EINVAL; } @@ -1219,3 +1224,37 @@ ath_ee_interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight, } return rv; } + +/* + * Adjust the TSF. + */ +void +ath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta) +{ + /* XXX handle wrap/overflow */ + OS_REG_WRITE(ah, AR_TSF_L32, OS_REG_READ(ah, AR_TSF_L32) + tsfdelta); +} + +/* + * Enable or disable CCA. + */ +void +ath_hal_setcca(struct ath_hal *ah, int ena) +{ + /* + * NB: fill me in; this is not provided by default because disabling + * CCA in most locales violates regulatory. + */ +} + +/* + * Get CCA setting. + */ +int +ath_hal_getcca(struct ath_hal *ah) +{ + u_int32_t diag; + if (ath_hal_getcapability(ah, HAL_CAP_DIAG, 0, &diag) != HAL_OK) + return 1; + return ((diag & 0x500000) == 0); +} diff --git a/sys/dev/ath/ath_hal/ah.h b/sys/dev/ath/ath_hal/ah.h index f81e6aab27365..f4254c14fa878 100644 --- a/sys/dev/ath/ath_hal/ah.h +++ b/sys/dev/ath/ath_hal/ah.h @@ -148,6 +148,7 @@ typedef enum { HAL_CAP_BSSIDMATCH = 238, /* hardware has disable bssid match */ HAL_CAP_STREAMS = 239, /* how many 802.11n spatial streams are available */ HAL_CAP_RXDESC_SELFLINK = 242, /* support a self-linked tail RX descriptor */ + HAL_CAP_LONG_RXDESC_TSF = 243, /* hardware supports 32bit TSF in RX descriptor */ } HAL_CAPABILITY_TYPE; /* @@ -718,22 +719,32 @@ typedef struct { u_int32_t pe_relpwr; /* Relative power threshold in 0.5dB steps */ u_int32_t pe_relstep; /* Pulse Relative step threshold in 0.5dB steps */ u_int32_t pe_maxlen; /* Max length of radar sign in 0.8us units */ - HAL_BOOL pe_usefir128; /* Use the average in-band power measured over 128 cycles */ - HAL_BOOL pe_blockradar; /* + int32_t pe_usefir128; /* Use the average in-band power measured over 128 cycles */ + int32_t pe_blockradar; /* * Enable to block radar check if pkt detect is done via OFDM * weak signal detect or pkt is detected immediately after tx * to rx transition */ - HAL_BOOL pe_enmaxrssi; /* + int32_t pe_enmaxrssi; /* * Enable to use the max rssi instead of the last rssi during * fine gain changes for radar detection */ - HAL_BOOL pe_extchannel; /* Enable DFS on ext channel */ + int32_t pe_extchannel; /* Enable DFS on ext channel */ + int32_t pe_enabled; /* Whether radar detection is enabled */ } HAL_PHYERR_PARAM; #define HAL_PHYERR_PARAM_NOVAL 65535 #define HAL_PHYERR_PARAM_ENABLE 0x8000 /* Enable/Disable if applicable */ +/* + * DFS operating mode flags. + */ +typedef enum { + HAL_DFS_UNINIT_DOMAIN = 0, /* Uninitialized dfs domain */ + HAL_DFS_FCC_DOMAIN = 1, /* FCC3 dfs domain */ + HAL_DFS_ETSI_DOMAIN = 2, /* ETSI dfs domain */ + HAL_DFS_MKK4_DOMAIN = 3, /* Japan dfs domain */ +} HAL_DFS_DOMAIN; /* * Flag for setting QUIET period @@ -746,15 +757,18 @@ typedef enum { } HAL_QUIET_FLAG; #define HAL_DFS_EVENT_PRICH 0x0000001 +#define HAL_DFS_EVENT_EXTCH 0x0000002 +#define HAL_DFS_EVENT_EXTEARLY 0x0000004 +#define HAL_DFS_EVENT_ISDC 0x0000008 -struct dfs_event { +struct hal_dfs_event { uint64_t re_full_ts; /* 64-bit full timestamp from interrupt time */ uint32_t re_ts; /* Original 15 bit recv timestamp */ uint8_t re_rssi; /* rssi of radar event */ uint8_t re_dur; /* duration of radar pulse */ uint32_t re_flags; /* Flags (see above) */ }; -typedef struct dfs_event HAL_DFS_EVENT; +typedef struct hal_dfs_event HAL_DFS_EVENT; typedef struct { @@ -765,7 +779,7 @@ typedef struct int ah_dma_beacon_response_time;/* in TU's */ int ah_sw_beacon_response_time; /* in TU's */ int ah_additional_swba_backoff; /* in TU's */ -}HAL_OPS_CONFIG; +} HAL_OPS_CONFIG; /* * Hardware Access Layer (HAL) API. @@ -954,6 +968,7 @@ struct ath_hal { HAL_BOOL __ahdecl(*ah_procRadarEvent)(struct ath_hal *ah, struct ath_rx_status *rxs, uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event); + HAL_BOOL __ahdecl(*ah_isFastClockEnabled)(struct ath_hal *ah); /* Key Cache Functions */ uint32_t __ahdecl(*ah_getKeyCacheSize)(struct ath_hal*); @@ -982,6 +997,7 @@ struct ath_hal { void __ahdecl(*ah_setStationBeaconTimers)(struct ath_hal*, const HAL_BEACON_STATE *); void __ahdecl(*ah_resetStationBeaconTimers)(struct ath_hal*); + uint64_t __ahdecl(*ah_getNextTBTT)(struct ath_hal *); /* 802.11n Functions */ HAL_BOOL __ahdecl(*ah_chainTxDesc)(struct ath_hal *, @@ -1124,4 +1140,20 @@ extern uint32_t __ahdecl ath_computedur_ht(uint32_t frameLen, uint16_t rate, extern uint16_t __ahdecl ath_hal_computetxtime(struct ath_hal *, const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix, HAL_BOOL shortPreamble); + +/* + * Adjust the TSF. + */ +extern void __ahdecl ath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta); + +/* + * Enable or disable CCA. + */ +void __ahdecl ath_hal_setcca(struct ath_hal *ah, int ena); + +/* + * Get CCA setting. + */ +int __ahdecl ath_hal_getcca(struct ath_hal *ah); + #endif /* _ATH_AH_H_ */ diff --git a/sys/dev/ath/ath_hal/ah_desc.h b/sys/dev/ath/ath_hal/ah_desc.h index bd3e6a821e9ed..4651fc2d7cc09 100644 --- a/sys/dev/ath/ath_hal/ah_desc.h +++ b/sys/dev/ath/ath_hal/ah_desc.h @@ -158,6 +158,12 @@ enum { HAL_PHYERR_CCK_RATE_ILLEGAL = 27, /* */ HAL_PHYERR_CCK_SERVICE = 30, /* */ HAL_PHYERR_CCK_RESTART = 31, /* */ + HAL_PHYERR_CCK_LENGTH_ILLEGAL = 32, /* */ + HAL_PHYERR_CCK_POWER_DROP = 33, /* */ + /* AR5416 and later */ + HAL_PHYERR_HT_CRC_ERROR = 34, /* */ + HAL_PHYERR_HT_LENGTH_ILLEGAL = 35, /* */ + HAL_PHYERR_HT_RATE_ILLEGAL = 36, /* */ }; /* value found in rs_keyix to mark invalid entries */ diff --git a/sys/dev/ath/ath_hal/ah_eeprom.h b/sys/dev/ath/ath_hal/ah_eeprom.h index 2ca058982f306..b77fb6427c021 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom.h +++ b/sys/dev/ath/ath_hal/ah_eeprom.h @@ -104,6 +104,7 @@ enum { AR_EEP_PWDCLKIND, /* uint8_t* */ AR_EEP_TEMPSENSE_SLOPE, /* int8_t* */ AR_EEP_TEMPSENSE_SLOPE_PAL_ON, /* int8_t* */ + AR_EEP_FRAC_N_5G, /* uint8_t* */ }; typedef struct { diff --git a/sys/dev/ath/ath_hal/ah_eeprom_9287.c b/sys/dev/ath/ath_hal/ah_eeprom_9287.c index 40550939bb6a1..099fe34b2b10d 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_9287.c +++ b/sys/dev/ath/ath_hal/ah_eeprom_9287.c @@ -298,11 +298,18 @@ ath_hal_9287EepromAttach(struct ath_hal *ah) uint32_t sum; HALASSERT(ee == AH_NULL); - - if (!ath_hal_eepromRead(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - HALDEBUG(ah, HAL_DEBUG_ANY, - "%s Error reading Eeprom MAGIC\n", __func__); - return HAL_EEREAD; + + /* + * Don't check magic if we're supplied with an EEPROM block, + * typically this is from Howl but it may also be from later + * boards w/ an embedded WMAC. + */ + if (ah->ah_eepromdata == NULL) { + if (!ath_hal_eepromRead(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s Error reading Eeprom MAGIC\n", __func__); + return HAL_EEREAD; + } } HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s Eeprom Magic = 0x%x\n", __func__, magic); @@ -328,7 +335,11 @@ ath_hal_9287EepromAttach(struct ath_hal *ah) } } /* Convert to eeprom native eeprom endian format */ - if (isBigEndian()) { + /* + * XXX this is likely incorrect but will do for now + * XXX to get embedded boards working. + */ + if (ah->ah_eepromdata == NULL && isBigEndian()) { for (w = 0; w < NW(HAL_EEPROM_9287); w++) eep_data[w] = __bswap16(eep_data[w]); } diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v14.c b/sys/dev/ath/ath_hal/ah_eeprom_v14.c index fdddea10605b9..37e973c16921a 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v14.c +++ b/sys/dev/ath/ath_hal/ah_eeprom_v14.c @@ -97,6 +97,12 @@ v14EepromGet(struct ath_hal *ah, int param, void *val) return HAL_OK; } else return HAL_EIO; + case AR_EEP_FRAC_N_5G: + if (IS_VERS(>=, AR5416_EEP_MINOR_VER_22)) { + *(uint8_t *) val = pBase->frac_n_5g; + } else + *(uint8_t *) val = 0; + return HAL_OK; case AR_EEP_AMODE: HALASSERT(val == AH_NULL); return pBase->opCapFlags & AR5416_OPFLAGS_11A ? diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v14.h b/sys/dev/ath/ath_hal/ah_eeprom_v14.h index 6061b2f85d313..7b2c898ce6ee2 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v14.h +++ b/sys/dev/ath/ath_hal/ah_eeprom_v14.h @@ -187,7 +187,10 @@ typedef struct BaseEepHeader { uint8_t rcChainMask; /* "1" if the card is an HB93 1x2 */ uint8_t desiredScaleCCK; uint8_t pwr_table_offset; - uint8_t frac_n_5g; + uint8_t frac_n_5g; /* + * bit 0: indicates that fracN synth + * mode applies to all 5G channels + */ uint8_t futureBase[21]; } __packed BASE_EEP_HEADER; // 64 B diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v4k.c b/sys/dev/ath/ath_hal/ah_eeprom_v4k.c index 36a6e736f219f..927f08e394da6 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v4k.c +++ b/sys/dev/ath/ath_hal/ah_eeprom_v4k.c @@ -75,8 +75,7 @@ v4kEepromGet(struct ath_hal *ah, int param, void *val) case AR_EEP_RXGAIN_TYPE: return AR5416_EEP_RXGAIN_ORIG; case AR_EEP_TXGAIN_TYPE: - return IS_VERS(>=, AR5416_EEP_MINOR_VER_19) ? - pBase->txGainType : AR5416_EEP_TXGAIN_ORIG; + return pBase->txGainType; case AR_EEP_OL_PWRCTRL: HALASSERT(val == AH_NULL); return HAL_EIO; @@ -288,11 +287,17 @@ ath_hal_v4kEepromAttach(struct ath_hal *ah) uint32_t sum; HALASSERT(ee == AH_NULL); - - if (!ath_hal_eepromRead(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - HALDEBUG(ah, HAL_DEBUG_ANY, - "%s Error reading Eeprom MAGIC\n", __func__); - return HAL_EEREAD; + /* + * Don't check magic if we're supplied with an EEPROM block, + * typically this is from Howl but it may also be from later + * boards w/ an embedded WMAC. + */ + if (ah->ah_eepromdata == NULL) { + if (!ath_hal_eepromRead(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s Error reading Eeprom MAGIC\n", __func__); + return HAL_EEREAD; + } } HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s Eeprom Magic = 0x%x\n", __func__, magic); @@ -318,7 +323,11 @@ ath_hal_v4kEepromAttach(struct ath_hal *ah) } } /* Convert to eeprom native eeprom endian format */ - if (isBigEndian()) { + /* + * XXX this is likely incorrect but will do for now + * XXX to get embedded boards working. + */ + if (ah->ah_eepromdata == NULL && isBigEndian()) { for (w = 0; w < NW(struct ar5416eeprom_4k); w++) eep_data[w] = __bswap16(eep_data[w]); } diff --git a/sys/dev/ath/ath_hal/ah_internal.h b/sys/dev/ath/ath_hal/ah_internal.h index 120620c8751c3..79184bd236508 100644 --- a/sys/dev/ath/ath_hal/ah_internal.h +++ b/sys/dev/ath/ath_hal/ah_internal.h @@ -208,7 +208,8 @@ typedef struct { halBssidMatchSupport : 1, hal4kbSplitTransSupport : 1, halHasRxSelfLinkedTail : 1, - halSupportsFastClock5GHz : 1; /* Hardware supports 5ghz fast clock; check eeprom/channel before using */ + halSupportsFastClock5GHz : 1, /* Hardware supports 5ghz fast clock; check eeprom/channel before using */ + halHasLongRxDescTsf : 1; uint32_t halWirelessModes; uint16_t halTotalQueues; uint16_t halKeyCacheSize; @@ -303,6 +304,7 @@ struct ath_hal_private { */ HAL_REG_DOMAIN ah_currentRD; /* EEPROM regulatory domain */ HAL_REG_DOMAIN ah_currentRDext; /* EEPROM extended regdomain flags */ + HAL_DFS_DOMAIN ah_dfsDomain; /* current DFS domain */ HAL_CHANNEL_INTERNAL ah_channels[AH_MAXCHAN]; /* private chan state */ u_int ah_nchan; /* valid items in ah_channels */ const struct regDomain *ah_rd2GHz; /* reg state for 2G band */ diff --git a/sys/dev/ath/ath_hal/ah_regdomain.c b/sys/dev/ath/ath_hal/ah_regdomain.c index 9aae3324a00da..7298c6bee8af9 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain.c +++ b/sys/dev/ath/ath_hal/ah_regdomain.c @@ -125,6 +125,8 @@ static const struct cmode modes[] = { IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D }, }; +static void ath_hal_update_dfsdomain(struct ath_hal *ah); + static OS_INLINE uint16_t getEepromRD(struct ath_hal *ah) { @@ -526,6 +528,7 @@ getchannels(struct ath_hal *ah, "skip ecm channel\n"); continue; } +#if 0 if ((fband->useDfs & dfsMask) && (cm->flags & IEEE80211_CHAN_HT40)) { /* NB: DFS and HT40 don't mix */ @@ -533,6 +536,7 @@ getchannels(struct ath_hal *ah, "skip HT40 chan, DFS required\n"); continue; } +#endif /* * Make sure that channel separation * meets the requirement. @@ -698,8 +702,12 @@ ath_hal_init_channels(struct ath_hal *ah, ah->ah_countryCode = country->countryCode; HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n", __func__, ah->ah_countryCode); + + /* Update current DFS domain */ + ath_hal_update_dfsdomain(ah); } else status = HAL_EINVAL; + return status; } @@ -744,6 +752,11 @@ ath_hal_set_channels(struct ath_hal *ah, __func__, ah->ah_countryCode); } else status = HAL_EINVAL; + + if (status == HAL_OK) { + /* Update current DFS domain */ + (void) ath_hal_update_dfsdomain(ah); + } return status; } @@ -809,6 +822,33 @@ ath_hal_getctl(struct ath_hal *ah, const struct ieee80211_channel *c) return ctl; } + +/* + * Update the current dfsDomain setting based on the given + * country code. + * + * Since FreeBSD/net80211 allows the channel set to change + * after the card has been setup (via ath_hal_init_channels()) + * this function method is needed to update ah_dfsDomain. + */ +void +ath_hal_update_dfsdomain(struct ath_hal *ah) +{ + const REG_DOMAIN *rd5GHz = AH_PRIVATE(ah)->ah_rd5GHz; + HAL_DFS_DOMAIN dfsDomain = HAL_DFS_UNINIT_DOMAIN; + + if (rd5GHz->dfsMask & DFS_FCC3) + dfsDomain = HAL_DFS_FCC_DOMAIN; + if (rd5GHz->dfsMask & DFS_ETSI) + dfsDomain = HAL_DFS_ETSI_DOMAIN; + if (rd5GHz->dfsMask & DFS_MKK4) + dfsDomain = HAL_DFS_MKK4_DOMAIN; + AH_PRIVATE(ah)->ah_dfsDomain = dfsDomain; + HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s ah_dfsDomain: %d\n", + __func__, AH_PRIVATE(ah)->ah_dfsDomain); +} + + /* * Return the max allowed antenna gain and apply any regulatory * domain specific changes. diff --git a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h index a85bd92d41f89..af4824c3b5a03 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h +++ b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting - * Copyright (c) 2005-2006 Atheros Communications, Inc. + * Copyright (c) 2005-2011 Atheros Communications, Inc. * All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any @@ -34,7 +34,7 @@ static COUNTRY_CODE_TO_ENUM_RD allCountries[] = { { CTRY_ALGERIA, NULL1_WORLD }, { CTRY_ARGENTINA, APL3_WORLD }, { CTRY_ARMENIA, ETSI4_WORLD }, - { CTRY_AUSTRALIA, FCC2_WORLD }, + { CTRY_AUSTRALIA, FCC3_WORLD }, { CTRY_AUSTRIA, ETSI1_WORLD }, { CTRY_AZERBAIJAN, ETSI4_WORLD }, { CTRY_BAHRAIN, APL6_WORLD }, diff --git a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h index f68743b078bf7..bc569cb00a3ed 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h +++ b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting - * Copyright (c) 2005-2006 Atheros Communications, Inc. + * Copyright (c) 2005-2011 Atheros Communications, Inc. * All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any @@ -46,6 +46,7 @@ enum { FCC1_WORLD = 0x11, /* Hong Kong */ FCC4_FCCA = 0x12, /* USA - Public Safety */ FCC5_FCCB = 0x13, /* USA w/ 1/2 and 1/4 width channels */ + FCC6_FCCA = 0x14, /* Canada for AP only */ FCC2_FCCA = 0x20, /* Canada */ FCC2_WORLD = 0x21, /* Australia & HK */ @@ -62,6 +63,8 @@ enum { ETSI4_ETSIC = 0x38, ETSI5_WORLD = 0x39, ETSI6_WORLD = 0x34, /* Bulgaria */ + ETSI8_WORLD = 0x3D, /* Russia */ + ETSI9_WORLD = 0x3E, /* Ukraine */ ETSI_RESERVED = 0x33, /* Reserved (Do not used) */ MKK1_MKKA = 0x40, /* Japan (JP1) */ @@ -77,8 +80,9 @@ enum { MKK1_MKKA1 = 0x4A, /* Japan (JE1) */ MKK1_MKKA2 = 0x4B, /* Japan (JE2) */ MKK1_MKKC = 0x4C, /* Japan (MKK1_MKKA,except Ch14) */ + APL2_FCCA = 0x4D, /* Mobile customer */ - APL3_FCCA = 0x50, + APL3_FCCA = 0x50, APL1_WORLD = 0x52, /* Latin America */ APL1_FCCA = 0x53, APL1_APLA = 0x54, @@ -86,9 +90,10 @@ enum { APL2_ETSIC = 0x56, /* Venezuela */ APL5_WORLD = 0x58, /* Chile */ APL6_WORLD = 0x5B, /* Singapore */ - APL7_FCCA = 0x5C, /* Taiwan 5.47 Band */ - APL8_WORLD = 0x5D, /* Malaysia 5GHz */ - APL9_WORLD = 0x5E, /* Korea 5GHz */ + APL7_FCCA = 0x5C, /* Taiwan 5.47 Band */ + APL8_WORLD = 0x5D, /* Malaysia 5GHz */ + APL9_WORLD = 0x5E, /* Korea 5GHz; before 11/2007; now APs only */ + APL10_WORLD = 0x5F, /* Korea 5GHz; After 11/2007; STAs only */ /* * World mode SKUs @@ -97,16 +102,17 @@ enum { WOR1_WORLD = 0x61, /* World1 (WO1 SKU) */ WOR2_WORLD = 0x62, /* World2 (WO2 SKU) */ WOR3_WORLD = 0x63, /* World3 (WO3 SKU) */ - WOR4_WORLD = 0x64, /* World4 (WO4 SKU) */ - WOR5_ETSIC = 0x65, /* World5 (WO5 SKU) */ + WOR4_WORLD = 0x64, /* World4 (WO4 SKU) */ + WOR5_ETSIC = 0x65, /* World5 (WO5 SKU) */ WOR01_WORLD = 0x66, /* World0-1 (WW0-1 SKU) */ WOR02_WORLD = 0x67, /* World0-2 (WW0-2 SKU) */ EU1_WORLD = 0x68, /* Same as World0-2 (WW0-2 SKU), except active scan ch1-13. No ch14 */ - WOR9_WORLD = 0x69, /* World9 (WO9 SKU) */ - WORA_WORLD = 0x6A, /* WorldA (WOA SKU) */ + WOR9_WORLD = 0x69, /* World9 (WO9 SKU) */ + WORA_WORLD = 0x6A, /* WorldA (WOA SKU) */ WORB_WORLD = 0x6B, /* WorldB (WOB SKU) */ + WORC_WORLD = 0x6C, /* WorldC (WOC SKU) */ MKK3_MKKB = 0x80, /* Japan UNI-1 even + MKKB */ MKK3_MKKA2 = 0x81, /* Japan UNI-1 even + MKKA2 */ @@ -132,17 +138,48 @@ enum { MKK8_MKKA2 = 0x90, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKA2 */ MKK8_MKKC = 0x91, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKC */ - /* Following definitions are used only by s/w to map old - * Japan SKUs. + MKK14_MKKA1 = 0x92, /* Japan UNI-1 even + UNI-1 odd + 4.9GHz + MKKA1 */ + MKK15_MKKA1 = 0x93, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + 4.9GHz + MKKA1 */ + + MKK10_FCCA = 0xD0, /* Japan UNI-1 even + UNI-2 + 4.9GHz + FCCA */ + MKK10_MKKA1 = 0xD1, /* Japan UNI-1 even + UNI-2 + 4.9GHz + MKKA1 */ + MKK10_MKKC = 0xD2, /* Japan UNI-1 even + UNI-2 + 4.9GHz + MKKC */ + MKK10_MKKA2 = 0xD3, /* Japan UNI-1 even + UNI-2 + 4.9GHz + MKKA2 */ + + MKK11_MKKA = 0xD4, /* Japan UNI-1 even + UNI-2 + mid-band + 4.9GHz + MKKA */ + MKK11_FCCA = 0xD5, /* Japan UNI-1 even + UNI-2 + mid-band + 4.9GHz + FCCA */ + MKK11_MKKA1 = 0xD6, /* Japan UNI-1 even + UNI-2 + mid-band + 4.9GHz + MKKA1 */ + MKK11_MKKC = 0xD7, /* Japan UNI-1 even + UNI-2 + mid-band + 4.9GHz + MKKC */ + MKK11_MKKA2 = 0xD8, /* Japan UNI-1 even + UNI-2 + mid-band + 4.9GHz + MKKA2 */ + + MKK12_MKKA = 0xD9, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + 4.9GHz + MKKA */ + MKK12_FCCA = 0xDA, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + 4.9GHz + FCCA */ + MKK12_MKKA1 = 0xDB, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + 4.9GHz + MKKA1 */ + MKK12_MKKC = 0xDC, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + 4.9GHz + MKKC */ + MKK12_MKKA2 = 0xDD, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + 4.9GHz + MKKA2 */ + + MKK13_MKKB = 0xDE, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKB + All passive + no adhoc */ + + /* + * Following definitions are used only by s/w to map old + * Japan SKUs. */ - MKK3_MKKA = 0xF0, /* Japan UNI-1 even + MKKA */ - MKK3_MKKA1 = 0xF1, /* Japan UNI-1 even + MKKA1 */ - MKK3_FCCA = 0xF2, /* Japan UNI-1 even + FCCA */ - MKK4_MKKA = 0xF3, /* Japan UNI-1 even + UNI-2 + MKKA */ - MKK4_MKKA1 = 0xF4, /* Japan UNI-1 even + UNI-2 + MKKA1 */ - MKK4_FCCA = 0xF5, /* Japan UNI-1 even + UNI-2 + FCCA */ - MKK9_MKKA = 0xF6, /* Japan UNI-1 even + 4.9GHz */ - MKK10_MKKA = 0xF7, /* Japan UNI-1 even + UNI-2 + 4.9GHz */ + MKK3_MKKA = 0xF0, /* Japan UNI-1 even + MKKA */ + MKK3_MKKA1 = 0xF1, /* Japan UNI-1 even + MKKA1 */ + MKK3_FCCA = 0xF2, /* Japan UNI-1 even + FCCA */ + MKK4_MKKA = 0xF3, /* Japan UNI-1 even + UNI-2 + MKKA */ + MKK4_MKKA1 = 0xF4, /* Japan UNI-1 even + UNI-2 + MKKA1 */ + MKK4_FCCA = 0xF5, /* Japan UNI-1 even + UNI-2 + FCCA */ + MKK9_MKKA = 0xF6, /* Japan UNI-1 even + 4.9GHz */ + MKK10_MKKA = 0xF7, /* Japan UNI-1 even + UNI-2 + 4.9GHz */ + MKK6_MKKA1 = 0xF8, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKA1 */ + MKK6_FCCA = 0xF9, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + FCCA */ + MKK7_MKKA1 = 0xFA, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKA1 */ + MKK7_FCCA = 0xFB, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + FCCA */ + MKK9_FCCA = 0xFC, /* Japan UNI-1 even + 4.9GHz + FCCA */ + MKK9_MKKA1 = 0xFD, /* Japan UNI-1 even + 4.9GHz + MKKA1 */ + MKK9_MKKC = 0xFE, /* Japan UNI-1 even + 4.9GHz + MKKC */ + MKK9_MKKA2 = 0xFF, /* Japan UNI-1 even + 4.9GHz + MKKA2 */ /* * Regulator domains ending in a number (e.g. APL1, @@ -157,8 +194,10 @@ enum { APL4 = 0x0450, /* Jordan */ APL5 = 0x0550, /* Chile */ APL6 = 0x0650, /* Singapore */ + APL7 = 0x0750, /* Taiwan, disable ch52 */ APL8 = 0x0850, /* Malaysia */ - APL9 = 0x0950, /* Korea (South) ROC 3 */ + APL9 = 0x0950, /* Korea. Before 11/2007. Now used only by APs */ + APL10 = 0x1050, /* Korea. After 11/2007. For STAs only */ ETSI1 = 0x0130, /* Europe & others */ ETSI2 = 0x0230, /* Europe & others */ @@ -166,16 +205,19 @@ enum { ETSI4 = 0x0430, /* Europe & others */ ETSI5 = 0x0530, /* Europe & others */ ETSI6 = 0x0630, /* Europe & others */ + ETSI8 = 0x0830, /* Russia */ + ETSI9 = 0x0930, /* Ukraine */ ETSIA = 0x0A30, /* France */ ETSIB = 0x0B30, /* Israel */ ETSIC = 0x0C30, /* Latin America */ FCC1 = 0x0110, /* US & others */ FCC2 = 0x0120, /* Canada, Australia & New Zealand */ - FCC3 = 0x0160, /* US w/new middle band & DFS */ - FCC4 = 0x0165, /* US Public Safety */ - FCC5 = 0x0166, /* US w/ 1/2 and 1/4 width channels */ - FCCA = 0x0A10, + FCC3 = 0x0160, /* US w/new middle band & DFS */ + FCC4 = 0x0165, /* US Public Safety */ + FCC5 = 0x0166, /* US w/ 1/2 and 1/4 width channels */ + FCC6 = 0x0610, /* Canada and Australia */ + FCCA = 0x0A10, FCCB = 0x0A11, /* US w/ 1/2 and 1/4 width channels */ APLD = 0x0D50, /* South Korea */ @@ -188,8 +230,14 @@ enum { MKK6 = 0x0640, /* Japan (UNI-1 odd + UNI-1 even) */ MKK7 = 0x0740, /* Japan (UNI-1 odd + UNI-1 even + UNI-2 */ MKK8 = 0x0840, /* Japan (UNI-1 odd + UNI-1 even + UNI-2 + mid-band) */ - MKK9 = 0x0940, /* Japan (UNI-1 even + 4.9 GHZ) */ - MKK10 = 0x0B40, /* Japan (UNI-1 even + UNI-2 + 4.9 GHZ) */ + MKK9 = 0x0940, /* Japan (UNI-1 even + 4.9 GHZ) */ + MKK10 = 0x0B40, /* Japan (UNI-1 even + UNI-2 + 4.9 GHZ) */ + MKK11 = 0x1140, /* Japan (UNI-1 even + UNI-2 + 4.9 GHZ) */ + MKK12 = 0x1240, /* Japan (UNI-1 even + UNI-2 + 4.9 GHZ) */ + MKK13 = 0x0C40, /* Same as MKK8 but all passive and no adhoc 11a */ + MKK14 = 0x1440, /* Japan UNI-1 even + UNI-1 odd + 4.9GHz */ + MKK15 = 0x1540, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + 4.9GHz */ + MKKA = 0x0A40, /* Japan */ MKKC = 0x0A50, diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210.h b/sys/dev/ath/ath_hal/ar5210/ar5210.h index a8776726a3ba9..24718531566f3 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210.h +++ b/sys/dev/ath/ath_hal/ar5210/ar5210.h @@ -268,6 +268,7 @@ extern void ar5210BeaconInit(struct ath_hal *, uint32_t, uint32_t); extern void ar5210SetStaBeaconTimers(struct ath_hal *, const HAL_BEACON_STATE *); extern void ar5210ResetStaBeaconTimers(struct ath_hal *); +extern uint64_t ar5210GetNextTBTT(struct ath_hal *); extern HAL_BOOL ar5210IsInterruptPending(struct ath_hal *); extern HAL_BOOL ar5210GetPendingInterrupts(struct ath_hal *, HAL_INT *); diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c index 41d957a614c6f..79c305511e6fd 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c @@ -148,6 +148,7 @@ static const struct ath_hal_private ar5210hal = {{ .ah_beaconInit = ar5210BeaconInit, .ah_setStationBeaconTimers = ar5210SetStaBeaconTimers, .ah_resetStationBeaconTimers = ar5210ResetStaBeaconTimers, + .ah_getNextTBTT = ar5210GetNextTBTT, /* Interrupt Functions */ .ah_isInterruptPending = ar5210IsInterruptPending, diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c b/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c index a613c9ca7d16a..e12b039723e5d 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c @@ -27,6 +27,17 @@ #include "ar5210/ar5210desc.h" /* + * Return the hardware NextTBTT in TSF + */ +uint64_t +ar5210GetNextTBTT(struct ath_hal *ah) +{ +#define TU_TO_TSF(_tu) (((uint64_t)(_tu)) << 10) + return TU_TO_TSF(OS_REG_READ(ah, AR_TIMER0)); +#undef TU_TO_TSF +} + +/* * Initialize all of the hardware registers used to send beacons. */ void diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211.h b/sys/dev/ath/ath_hal/ar5211/ar5211.h index 0057ba425f98d..51acd38862c54 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211.h +++ b/sys/dev/ath/ath_hal/ar5211/ar5211.h @@ -296,6 +296,7 @@ extern void ar5211BeaconInit(struct ath_hal *, uint32_t, uint32_t); extern void ar5211SetStaBeaconTimers(struct ath_hal *, const HAL_BEACON_STATE *); extern void ar5211ResetStaBeaconTimers(struct ath_hal *); +extern uint64_t ar5211GetNextTBTT(struct ath_hal *); extern HAL_BOOL ar5211IsInterruptPending(struct ath_hal *); extern HAL_BOOL ar5211GetPendingInterrupts(struct ath_hal *, HAL_INT *); diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c index 14daa0bffedc5..a0c42b2bf7c41 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c @@ -148,6 +148,7 @@ static const struct ath_hal_private ar5211hal = {{ .ah_beaconInit = ar5211BeaconInit, .ah_setStationBeaconTimers = ar5211SetStaBeaconTimers, .ah_resetStationBeaconTimers = ar5211ResetStaBeaconTimers, + .ah_getNextTBTT = ar5211GetNextTBTT, /* Interrupt Functions */ .ah_isInterruptPending = ar5211IsInterruptPending, diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c b/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c index 31e9c5df8a936..b2775d0376f5a 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c @@ -30,6 +30,17 @@ */ /* + * Return the hardware NextTBTT in TSF + */ +uint64_t +ar5211GetNextTBTT(struct ath_hal *ah) +{ +#define TU_TO_TSF(_tu) (((uint64_t)(_tu)) << 10) + return TU_TO_TSF(OS_REG_READ(ah, AR_TIMER0)); +#undef TU_TO_TSF +} + +/* * Initialize all of the hardware registers used to send beacons. */ void diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212.h b/sys/dev/ath/ath_hal/ar5212/ar5212.h index 8503a629aa367..40e718e46736b 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212.h +++ b/sys/dev/ath/ath_hal/ar5212/ar5212.h @@ -430,6 +430,7 @@ extern void ar5212BeaconInit(struct ath_hal *ah, extern void ar5212ResetStaBeaconTimers(struct ath_hal *ah); extern void ar5212SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *); +extern uint64_t ar5212GetNextTBTT(struct ath_hal *); extern HAL_BOOL ar5212IsInterruptPending(struct ath_hal *ah); extern HAL_BOOL ar5212GetPendingInterrupts(struct ath_hal *ah, HAL_INT *); @@ -625,5 +626,6 @@ extern void ar5212GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe); extern HAL_BOOL ar5212ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs, uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event); +extern HAL_BOOL ar5212IsFastClockEnabled(struct ath_hal *ah); #endif /* _ATH_AR5212_H_ */ diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c b/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c index c0ebd952c219b..b101306a6354c 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c @@ -222,7 +222,14 @@ ar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) typedef int TABLE[]; struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState = ahp->ah_curani; - const struct ar5212AniParams *params = aniState->params; + const struct ar5212AniParams *params = AH_NULL; + + /* + * This function may be called before there's a current + * channel (eg to disable ANI.) + */ + if (aniState != AH_NULL) + params = aniState->params; OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd); @@ -343,8 +350,8 @@ ar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) ahp->ah_procPhyErr &= ~HAL_ANI_ENA; /* Turn off HW counters if we have them */ ar5212AniDetach(ah); - ar5212SetRxFilter(ah, - ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); + ah->ah_setRxFilter(ah, + ah->ah_getRxFilter(ah) &~ HAL_RX_FILTER_PHYERR); } else { /* normal/auto mode */ /* don't mess with state if already enabled */ if (ahp->ah_procPhyErr & HAL_ANI_ENA) @@ -358,8 +365,8 @@ ar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) ahp->ah_curani->params: &ahp->ah_aniParams24 /*XXX*/); } else { - ar5212SetRxFilter(ah, - ar5212GetRxFilter(ah) | HAL_RX_FILTER_PHYERR); + ah->ah_setRxFilter(ah, + ah->ah_getRxFilter(ah) | HAL_RX_FILTER_PHYERR); } ahp->ah_procPhyErr |= HAL_ANI_ENA; } @@ -609,8 +616,20 @@ ar5212AniReset(struct ath_hal *ah, const struct ieee80211_channel *chan, /* * Turn off PHY error frame delivery while we futz with settings. */ - rxfilter = ar5212GetRxFilter(ah); - ar5212SetRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR); + rxfilter = ah->ah_getRxFilter(ah); + ah->ah_setRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR); + + /* + * If ANI is disabled at this point, don't set the default + * ANI parameter settings - leave the HAL settings there. + * This is (currently) needed for reliable radar detection. + */ + if (! ANI_ENA(ah)) { + HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ANI disabled\n", + __func__); + goto finish; + } + /* * Automatic processing is done only in station mode right now. */ @@ -644,10 +663,15 @@ ar5212AniReset(struct ath_hal *ah, const struct ieee80211_channel *chan, ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); ichan->privFlags |= CHANNEL_ANI_SETUP; } + /* + * In case the counters haven't yet been setup; set them up. + */ + enableAniMIBCounters(ah, ahp->ah_curani->params); ar5212AniRestart(ah, aniState); +finish: /* restore RX filter mask */ - ar5212SetRxFilter(ah, rxfilter); + ah->ah_setRxFilter(ah, rxfilter); } /* diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c index 01c0e2c8ad076..eaceaba766e32 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c @@ -133,6 +133,7 @@ static const struct ath_hal_private ar5212hal = {{ .ah_enableDfs = ar5212EnableDfs, .ah_getDfsThresh = ar5212GetDfsThresh, .ah_procRadarEvent = ar5212ProcessRadarEvent, + .ah_isFastClockEnabled = ar5212IsFastClockEnabled, /* Key Cache Functions */ .ah_getKeyCacheSize = ar5212GetKeyCacheSize, @@ -150,6 +151,7 @@ static const struct ath_hal_private ar5212hal = {{ .ah_beaconInit = ar5212BeaconInit, .ah_setStationBeaconTimers = ar5212SetStaBeaconTimers, .ah_resetStationBeaconTimers = ar5212ResetStaBeaconTimers, + .ah_getNextTBTT = ar5212GetNextTBTT, /* Interrupt Functions */ .ah_isInterruptPending = ar5212IsInterruptPending, diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c b/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c index bf0b38a56db7e..1b4b342bc4ae2 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c @@ -26,6 +26,17 @@ #include "ar5212/ar5212desc.h" /* + * Return the hardware NextTBTT in TSF + */ +uint64_t +ar5212GetNextTBTT(struct ath_hal *ah) +{ +#define TU_TO_TSF(_tu) (((uint64_t)(_tu)) << 10) + return TU_TO_TSF(OS_REG_READ(ah, AR_TIMER0)); +#undef TU_TO_TSF +} + +/* * Initialize all of the hardware registers used to * send beacons. Note that for station operation the * driver calls ar5212SetStaBeaconTimers instead. diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c b/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c index 3a6019d993fd2..5bcde762a5d46 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c @@ -1222,3 +1222,13 @@ ar5212ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs, return AH_TRUE; } + +/* + * Return whether 5GHz fast-clock (44MHz) is enabled. + * It's always disabled for AR5212 series NICs. + */ +HAL_BOOL +ar5212IsFastClockEnabled(struct ath_hal *ah) +{ + return AH_FALSE; +} diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416.h b/sys/dev/ath/ath_hal/ar5416/ar5416.h index e5294b0634bb6..a0f5deead8bb2 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416.h +++ b/sys/dev/ath/ath_hal/ar5416/ar5416.h @@ -169,6 +169,7 @@ extern void ar5416BeaconInit(struct ath_hal *ah, extern void ar5416ResetStaBeaconTimers(struct ath_hal *ah); extern void ar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *); +extern uint64_t ar5416GetNextTBTT(struct ath_hal *); extern HAL_BOOL ar5416EepromRead(struct ath_hal *, u_int off, uint16_t *data); extern HAL_BOOL ar5416EepromWrite(struct ath_hal *, u_int off, uint16_t data); @@ -186,6 +187,8 @@ extern void ar5416GpioSetIntr(struct ath_hal *ah, u_int, uint32_t ilevel); extern u_int ar5416GetWirelessModes(struct ath_hal *ah); extern void ar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state); +extern uint64_t ar5416GetTsf64(struct ath_hal *ah); +extern void ar5416SetTsf64(struct ath_hal *ah, uint64_t tsf64); extern void ar5416ResetTsf(struct ath_hal *ah); extern HAL_BOOL ar5416SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING); extern HAL_BOOL ar5416SetDecompMask(struct ath_hal *, uint16_t, int); @@ -208,6 +211,7 @@ extern void ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe); extern HAL_BOOL ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs, uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event); +extern HAL_BOOL ar5416IsFastClockEnabled(struct ath_hal *ah); extern HAL_BOOL ar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip); @@ -218,6 +222,8 @@ extern HAL_BOOL ar5416ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry); extern HAL_BOOL ar5416SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry, const HAL_KEYVAL *k, const uint8_t *mac, int xorKey); +extern uint32_t ar5416GetRxFilter(struct ath_hal *ah); +extern void ar5416SetRxFilter(struct ath_hal *ah, uint32_t bits); extern void ar5416StartPcuReceive(struct ath_hal *ah); extern void ar5416StopPcuReceive(struct ath_hal *ah); extern HAL_BOOL ar5416SetupRxDesc(struct ath_hal *, diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416.ini b/sys/dev/ath/ath_hal/ar5416/ar5416.ini index a1d39f9f4346c..7f8c7934c0d02 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416.ini +++ b/sys/dev/ath/ath_hal/ar5416/ar5416.ini @@ -687,7 +687,7 @@ static const uint32_t ar5416Addac[][2] = { {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 }, - {0x000098cc, 0x00000000 }, + {0x000098c4, 0x00000000 }, }; /* hand-crafted from code that does explicit register writes */ diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c b/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c index e2c8592a13b43..5af6b240b6cc5 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c @@ -156,6 +156,8 @@ ar5416AniAttach(struct ath_hal *ah, const struct ar5212AniParams *params24, /* * Cleanup any ANI state setup. + * + * This doesn't restore registers to their default settings! */ void ar5416AniDetach(struct ath_hal *ah) @@ -173,7 +175,43 @@ ar5416AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) typedef int TABLE[]; struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212AniState *aniState = ahp->ah_curani; - const struct ar5212AniParams *params = aniState->params; + const struct ar5212AniParams *params = AH_NULL; + + /* + * This function may be called before there's a current + * channel (eg to disable ANI.) + */ + if (aniState != AH_NULL) + params = aniState->params; + + OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd); + + /* These commands can't be disabled */ + if (cmd == HAL_ANI_PRESENT) + return AH_TRUE; + + if (cmd == HAL_ANI_MODE) { + if (param == 0) { + ahp->ah_procPhyErr &= ~HAL_ANI_ENA; + /* Turn off HW counters if we have them */ + ar5416AniDetach(ah); + } else { /* normal/auto mode */ + /* don't mess with state if already enabled */ + if (! (ahp->ah_procPhyErr & HAL_ANI_ENA)) { + /* Enable MIB Counters */ + /* + * XXX use 2.4ghz params if no channel is + * available + */ + enableAniMIBCounters(ah, + ahp->ah_curani != AH_NULL ? + ahp->ah_curani->params: + &ahp->ah_aniParams24); + ahp->ah_procPhyErr |= HAL_ANI_ENA; + } + } + return AH_TRUE; + } /* Check whether the particular function is enabled */ if (((1 << cmd) & AH5416(ah)->ah_ani_function) == 0) { @@ -183,7 +221,6 @@ ar5416AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) return AH_FALSE; } - OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd); switch (cmd) { case HAL_ANI_NOISE_IMMUNITY_LEVEL: { @@ -317,23 +354,6 @@ ar5416AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) aniState->spurImmunityLevel = level; break; } - case HAL_ANI_PRESENT: - break; - case HAL_ANI_MODE: - if (param == 0) { - ahp->ah_procPhyErr &= ~HAL_ANI_ENA; - /* Turn off HW counters if we have them */ - ar5416AniDetach(ah); - } else { /* normal/auto mode */ - /* don't mess with state if already enabled */ - if (ahp->ah_procPhyErr & HAL_ANI_ENA) - break; - /* Enable MIB Counters */ - enableAniMIBCounters(ah, ahp->ah_curani != AH_NULL ? - ahp->ah_curani->params: &ahp->ah_aniParams24 /*XXX*/); - ahp->ah_procPhyErr |= HAL_ANI_ENA; - } - break; #ifdef AH_PRIVATE_DIAG case HAL_ANI_PHYERR_RESET: ahp->ah_stats.ast_ani_ofdmerrs = 0; @@ -548,8 +568,21 @@ ar5416AniReset(struct ath_hal *ah, const struct ieee80211_channel *chan, /* * Turn off PHY error frame delivery while we futz with settings. */ - rxfilter = ar5212GetRxFilter(ah); - ar5212SetRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR); + rxfilter = ah->ah_getRxFilter(ah); + ah->ah_setRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR); + + /* + * If ANI is disabled at this point, don't set the default + * ANI parameter settings - leave the HAL settings there. + * This is (currently) needed for reliable radar detection. + */ + if (! ANI_ENA(ah)) { + HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ANI disabled\n", + __func__); + goto finish; + } + + /* * Automatic processing is done only in station mode right now. */ @@ -583,10 +616,16 @@ ar5416AniReset(struct ath_hal *ah, const struct ieee80211_channel *chan, ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0); ichan->privFlags |= CHANNEL_ANI_SETUP; } + + /* + * In case the counters haven't yet been setup; set them up. + */ + enableAniMIBCounters(ah, aniState->params); ar5416AniRestart(ah, aniState); +finish: /* restore RX filter mask */ - ar5212SetRxFilter(ah, rxfilter); + ah->ah_setRxFilter(ah, rxfilter); } /* diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c index 607f97ab481d6..12589f28fff2e 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c @@ -117,6 +117,8 @@ ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc, ah->ah_resetTxQueue = ar5416ResetTxQueue; /* Receive Functions */ + ah->ah_getRxFilter = ar5416GetRxFilter; + ah->ah_setRxFilter = ar5416SetRxFilter; ah->ah_startPcuReceive = ar5416StartPcuReceive; ah->ah_stopPcuReceive = ar5416StopPcuReceive; ah->ah_setupRxDesc = ar5416SetupRxDesc; @@ -134,6 +136,7 @@ ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc, ah->ah_gpioGet = ar5416GpioGet; ah->ah_gpioSet = ar5416GpioSet; ah->ah_gpioSetIntr = ar5416GpioSetIntr; + ah->ah_getTsf64 = ar5416GetTsf64; ah->ah_resetTsf = ar5416ResetTsf; ah->ah_getRfGain = ar5416GetRfgain; ah->ah_setAntennaSwitch = ar5416SetAntennaSwitch; @@ -148,6 +151,7 @@ ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc, ah->ah_enableDfs = ar5416EnableDfs; ah->ah_getDfsThresh = ar5416GetDfsThresh; ah->ah_procRadarEvent = ar5416ProcessRadarEvent; + ah->ah_isFastClockEnabled = ar5416IsFastClockEnabled; /* Power Management Functions */ ah->ah_setPowerMode = ar5416SetPowerMode; @@ -157,6 +161,7 @@ ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc, ah->ah_beaconInit = ar5416BeaconInit; ah->ah_setStationBeaconTimers = ar5416SetStaBeaconTimers; ah->ah_resetStationBeaconTimers = ar5416ResetStaBeaconTimers; + ah->ah_getNextTBTT = ar5416GetNextTBTT; /* 802.11n Functions */ ah->ah_chainTxDesc = ar5416ChainTxDesc; @@ -885,6 +890,8 @@ ar5416FillCapabilityInfo(struct ath_hal *ah) pCap->halGTTSupport = AH_TRUE; pCap->halCSTSupport = AH_TRUE; pCap->halEnhancedDfsSupport = AH_FALSE; + /* Hardware supports 32 bit TSF values in the RX descriptor */ + pCap->halHasLongRxDescTsf = AH_TRUE; if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL) && ath_hal_eepromGet(ah, AR_EEP_RFSILENT, &ahpriv->ah_rfsilent) == HAL_OK) { diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c b/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c index 66b50537de966..8b61e14658ae8 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c @@ -26,6 +26,16 @@ #include "ar5416/ar5416phy.h" #define TU_TO_USEC(_tu) ((_tu) << 10) +#define ONE_EIGHTH_TU_TO_USEC(_tu8) ((_tu8) << 7) + +/* + * Return the hardware NextTBTT in TSF + */ +uint64_t +ar5416GetNextTBTT(struct ath_hal *ah) +{ + return OS_REG_READ(ah, AR_NEXT_TBTT); +} /* * Initialize all of the hardware registers used to @@ -38,8 +48,8 @@ ar5416SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt) uint32_t bperiod; OS_REG_WRITE(ah, AR_NEXT_TBTT, TU_TO_USEC(bt->bt_nexttbtt)); - OS_REG_WRITE(ah, AR_NEXT_DBA, TU_TO_USEC(bt->bt_nextdba) >> 3); - OS_REG_WRITE(ah, AR_NEXT_SWBA, TU_TO_USEC(bt->bt_nextswba) >> 3); + OS_REG_WRITE(ah, AR_NEXT_DBA, ONE_EIGHTH_TU_TO_USEC(bt->bt_nextdba)); + OS_REG_WRITE(ah, AR_NEXT_SWBA, ONE_EIGHTH_TU_TO_USEC(bt->bt_nextswba)); OS_REG_WRITE(ah, AR_NEXT_NDP, TU_TO_USEC(bt->bt_nextatim)); bperiod = TU_TO_USEC(bt->bt_intval & HAL_BEACON_PERIOD); @@ -144,7 +154,7 @@ ar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) /* NB: no cfp setting since h/w automatically takes care */ - OS_REG_WRITE(ah, AR_NEXT_TBTT, bs->bs_nexttbtt); + OS_REG_WRITE(ah, AR_NEXT_TBTT, TU_TO_USEC(bs->bs_nexttbtt)); /* * Start the beacon timers by setting the BEACON register @@ -221,15 +231,19 @@ ar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs) OS_REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP)); /* cab timeout is now in 1/8 TU */ - OS_REG_WRITE(ah, AR_SLEEP1, + OS_REG_WRITE(ah, AR5416_SLEEP1, SM((CAB_TIMEOUT_VAL << 3), AR5416_SLEEP1_CAB_TIMEOUT) - | AR_SLEEP1_ASSUME_DTIM); + | AR5416_SLEEP1_ASSUME_DTIM); + + /* XXX autosleep? Use min beacon timeout; check ath9k -adrian */ /* beacon timeout is now in 1/8 TU */ - OS_REG_WRITE(ah, AR_SLEEP2, + OS_REG_WRITE(ah, AR5416_SLEEP2, SM((BEACON_TIMEOUT_VAL << 3), AR5416_SLEEP2_BEACON_TIMEOUT)); - OS_REG_WRITE(ah, AR_TIM_PERIOD, beaconintval); - OS_REG_WRITE(ah, AR_DTIM_PERIOD, dtimperiod); + /* TIM_PERIOD and DTIM_PERIOD are now in uS. */ + OS_REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); + OS_REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); + OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_TBTT | AR_TIMER_MODE_TIM | AR_TIMER_MODE_DTIM); HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next DTIM %d\n", diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c b/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c index 1356c7d1081b9..d51417f4992a3 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c @@ -72,7 +72,15 @@ ar5416IsCalSupp(struct ath_hal *ah, const struct ieee80211_channel *chan, return !IEEE80211_IS_CHAN_B(chan); case ADC_GAIN_CAL: case ADC_DC_CAL: - /* Run ADC Gain Cal for either 5ghz any or 2ghz HT40 */ + /* + * Run ADC Gain Cal for either 5ghz any or 2ghz HT40. + * + * Don't run ADC calibrations for 5ghz fast clock mode + * in HT20 - only one ADC is used. + */ + if (IEEE80211_IS_CHAN_HT20(chan) && + (IS_5GHZ_FAST_CLOCK_EN(ah, chan))) + return AH_FALSE; if (IEEE80211_IS_CHAN_5GHZ(chan)) return AH_TRUE; if (IEEE80211_IS_CHAN_HT40(chan)) @@ -186,36 +194,22 @@ ar5416RunInitCals(struct ath_hal *ah, int init_cal_count) } #endif + +/* + * AGC calibration for the AR5416, AR9130, AR9160, AR9280. + */ HAL_BOOL ar5416InitCalHardware(struct ath_hal *ah, const struct ieee80211_channel *chan) { - if (AR_SREV_MERLIN_10_OR_LATER(ah)) { - /* Enable Rx Filter Cal */ - OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_FLTR_CAL); - - /* Clear the carrier leak cal bit */ - OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - - /* kick off the cal */ - OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); - /* Poll for offset calibration complete */ - if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { - HALDEBUG(ah, HAL_DEBUG_ANY, - "%s: offset calibration failed to complete in 1ms; " - "noisy environment?\n", __func__); - return AH_FALSE; - } + if (AR_SREV_MERLIN_10_OR_LATER(ah)) { + /* Disable ADC */ + OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, + AR_PHY_ADC_CTL_OFF_PWDADC); - /* Set the cl cal bit and rerun the cal a 2nd time */ /* Enable Rx Filter Cal */ - OS_REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); - - OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); } /* Calibrate the AGC */ @@ -229,6 +223,16 @@ ar5416InitCalHardware(struct ath_hal *ah, const struct ieee80211_channel *chan) return AH_FALSE; } + if (AR_SREV_MERLIN_10_OR_LATER(ah)) { + /* Enable ADC */ + OS_REG_SET_BIT(ah, AR_PHY_ADC_CTL, + AR_PHY_ADC_CTL_OFF_PWDADC); + + /* Disable Rx Filter Cal */ + OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); + } + return AH_TRUE; } @@ -247,7 +251,8 @@ ar5416InitCal(struct ath_hal *ah, const struct ieee80211_channel *chan) /* Do initial chipset-specific calibration */ if (! AH5416(ah)->ah_cal_initcal(ah, chan)) { - HALDEBUG(ah, HAL_DEBUG_ANY, "%s: initial chipset calibration did " + HALDEBUG(ah, HAL_DEBUG_ANY, + "%s: initial chipset calibration did " "not complete in time; noisy environment?\n", __func__); return AH_FALSE; } diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c b/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c index 6266b5813532b..7e61c84930d96 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c @@ -93,6 +93,41 @@ ar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state) } /* + * Get the current hardware tsf for stamlme + */ +uint64_t +ar5416GetTsf64(struct ath_hal *ah) +{ + uint32_t low1, low2, u32; + + /* sync multi-word read */ + low1 = OS_REG_READ(ah, AR_TSF_L32); + u32 = OS_REG_READ(ah, AR_TSF_U32); + low2 = OS_REG_READ(ah, AR_TSF_L32); + if (low2 < low1) { /* roll over */ + /* + * If we are not preempted this will work. If we are + * then we re-reading AR_TSF_U32 does no good as the + * low bits will be meaningless. Likewise reading + * L32, U32, U32, then comparing the last two reads + * to check for rollover doesn't help if preempted--so + * we take this approach as it costs one less PCI read + * which can be noticeable when doing things like + * timestamping packets in monitor mode. + */ + u32++; + } + return (((uint64_t) u32) << 32) | ((uint64_t) low2); +} + +void +ar5416SetTsf64(struct ath_hal *ah, uint64_t tsf64) +{ + OS_REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff); + OS_REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff); +} + +/* * Reset the current hardware tsf for stamlme. */ void @@ -617,10 +652,20 @@ ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) temp = val & AR_PHY_RADAR_1_RELSTEP_CHECK; pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH); if (temp) - pe->pe_relstep |= HAL_PHYERR_PARAM_ENABLE; + pe->pe_enabled = 1; + else + pe->pe_enabled = 0; + pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN); pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) & AR_PHY_RADAR_EXT_ENA); + + pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) & + AR_PHY_RADAR_1_USE_FIR128); + pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) & + AR_PHY_RADAR_1_BLOCK_CHECK); + pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) & + AR_PHY_RADAR_1_MAX_RRSSI); } /* @@ -660,23 +705,36 @@ ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) OS_REG_WRITE(ah, AR_PHY_RADAR_0, val | AR_PHY_RADAR_0_ENA); - val = OS_REG_READ(ah, AR_PHY_RADAR_1); - val |= (AR_PHY_RADAR_1_MAX_RRSSI | AR_PHY_RADAR_1_BLOCK_CHECK); + if (pe->pe_usefir128 == 1) + OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128); + else if (pe->pe_usefir128 == 0) + OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128); + + if (pe->pe_enmaxrssi == 1) + OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI); + else if (pe->pe_enmaxrssi == 0) + OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI); + + if (pe->pe_blockradar == 1) + OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK); + else if (pe->pe_blockradar == 0) + OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK); if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) { + val = OS_REG_READ(ah, AR_PHY_RADAR_1); val &= ~AR_PHY_RADAR_1_MAXLEN; val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN); + OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); } - OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); /* * Enable HT/40 if the upper layer asks; * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS * is available. */ - if (pe->pe_extchannel) + if (pe->pe_extchannel == 1) OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); - else + else if (pe->pe_extchannel == 0) OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) { @@ -708,3 +766,15 @@ ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs, */ return AH_FALSE; } + +/* + * Return whether fast-clock is currently enabled for this + * channel. + */ +HAL_BOOL +ar5416IsFastClockEnabled(struct ath_hal *ah) +{ + struct ath_hal_private *ahp = AH_PRIVATE(ah); + + return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan); +} diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c b/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c index 8a7f3bae3db3f..289da427eb4b1 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c @@ -27,6 +27,46 @@ #include "ar5416/ar5416desc.h" /* + * Get the receive filter. + */ +uint32_t +ar5416GetRxFilter(struct ath_hal *ah) +{ + uint32_t bits = OS_REG_READ(ah, AR_RX_FILTER); + uint32_t phybits = OS_REG_READ(ah, AR_PHY_ERR); + + if (phybits & AR_PHY_ERR_RADAR) + bits |= HAL_RX_FILTER_PHYRADAR; + if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING)) + bits |= HAL_RX_FILTER_PHYERR; + return bits; +} + +/* + * Set the receive filter. + */ +void +ar5416SetRxFilter(struct ath_hal *ah, u_int32_t bits) +{ + uint32_t phybits; + + OS_REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff)); + phybits = 0; + if (bits & HAL_RX_FILTER_PHYRADAR) + phybits |= AR_PHY_ERR_RADAR; + if (bits & HAL_RX_FILTER_PHYERR) + phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING; + OS_REG_WRITE(ah, AR_PHY_ERR, phybits); + if (phybits) { + OS_REG_WRITE(ah, AR_RXCFG, + OS_REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); + } else { + OS_REG_WRITE(ah, AR_RXCFG, + OS_REG_READ(ah, AR_RXCFG) &~ AR_RXCFG_ZLFDMA); + } +} + +/* * Start receive at the PCU engine */ void diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c b/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c index 1da686a3df086..112d9669540fe 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c @@ -147,7 +147,7 @@ ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode, /* For chips on which the RTC reset is done, save TSF before it gets cleared */ if (AR_SREV_HOWL(ah) || (AR_SREV_MERLIN(ah) && ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL))) - tsf = ar5212GetTsf64(ah); + tsf = ar5416GetTsf64(ah); /* Mark PHY as inactive; marked active in ar5416InitBB() */ ar5416MarkPhyInactive(ah); @@ -159,7 +159,7 @@ ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode, /* Restore TSF */ if (tsf) - ar5212SetTsf64(ah, tsf); + ar5416SetTsf64(ah, tsf); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); if (AR_SREV_MERLIN_10_OR_LATER(ah)) @@ -192,9 +192,9 @@ ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode, * value after the initvals have been applied, with an offset * based on measured time difference */ - if (AR_SREV_HOWL(ah) && (ar5212GetTsf64(ah) < tsf)) { + if (AR_SREV_HOWL(ah) && (ar5416GetTsf64(ah) < tsf)) { tsf += 1500; - ar5212SetTsf64(ah, tsf); + ar5416SetTsf64(ah, tsf); } HALDEBUG(ah, HAL_DEBUG_RESET, ">>>2 %s: AR_PHY_DAG_CTRLCCK=0x%x\n", @@ -364,8 +364,7 @@ ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode, OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, 300); OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, 750); -#endif - +#endif ar5416InitBB(ah, chan); /* Setup compression registers */ @@ -503,7 +502,7 @@ ar5416ChannelChange(struct ath_hal *ah, const structu ieee80211_channel *chan) chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; ichan->channel_time = 0; - ichan->tsf_last = ar5212GetTsf64(ah); + ichan->tsf_last = ar5416GetTsf64(ah); ar5212TxEnable(ah, AH_TRUE); return AH_TRUE; } @@ -1423,60 +1422,20 @@ ar5416UpdateChainMasks(struct ath_hal *ah, HAL_BOOL is_ht) void ar5416InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan) { - uint32_t pll; - - if (AR_SREV_MERLIN_20(ah) && - chan != AH_NULL && IEEE80211_IS_CHAN_5GHZ(chan)) { - /* - * PLL WAR for Merlin 2.0/2.1 - * When doing fast clock, set PLL to 0x142c - * Else, set PLL to 0x2850 to prevent reset-to-reset variation - */ - pll = IS_5GHZ_FAST_CLOCK_EN(ah, chan) ? 0x142c : 0x2850; - } else if (AR_SREV_MERLIN_10_OR_LATER(ah)) { - pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV); - if (chan != AH_NULL) { - if (IEEE80211_IS_CHAN_HALF(chan)) - pll |= SM(0x1, AR_RTC_SOWL_PLL_CLKSEL); - else if (IEEE80211_IS_CHAN_QUARTER(chan)) - pll |= SM(0x2, AR_RTC_SOWL_PLL_CLKSEL); - - if (IEEE80211_IS_CHAN_5GHZ(chan)) - pll |= SM(0x28, AR_RTC_SOWL_PLL_DIV); - else - pll |= SM(0x2c, AR_RTC_SOWL_PLL_DIV); - - } else - pll |= SM(0x2c, AR_RTC_SOWL_PLL_DIV); - } else if (AR_SREV_SOWL_10_OR_LATER(ah)) { - pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV); - if (chan != AH_NULL) { - if (IEEE80211_IS_CHAN_HALF(chan)) - pll |= SM(0x1, AR_RTC_SOWL_PLL_CLKSEL); - else if (IEEE80211_IS_CHAN_QUARTER(chan)) - pll |= SM(0x2, AR_RTC_SOWL_PLL_CLKSEL); + uint32_t pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; + if (chan != AH_NULL) { + if (IEEE80211_IS_CHAN_HALF(chan)) + pll |= SM(0x1, AR_RTC_PLL_CLKSEL); + else if (IEEE80211_IS_CHAN_QUARTER(chan)) + pll |= SM(0x2, AR_RTC_PLL_CLKSEL); - if (IEEE80211_IS_CHAN_5GHZ(chan)) - pll |= SM(0x50, AR_RTC_SOWL_PLL_DIV); - else - pll |= SM(0x58, AR_RTC_SOWL_PLL_DIV); - } else - pll |= SM(0x58, AR_RTC_SOWL_PLL_DIV); - } else { - pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; - if (chan != AH_NULL) { - if (IEEE80211_IS_CHAN_HALF(chan)) - pll |= SM(0x1, AR_RTC_PLL_CLKSEL); - else if (IEEE80211_IS_CHAN_QUARTER(chan)) - pll |= SM(0x2, AR_RTC_PLL_CLKSEL); - - if (IEEE80211_IS_CHAN_5GHZ(chan)) - pll |= SM(0xa, AR_RTC_PLL_DIV); - else - pll |= SM(0xb, AR_RTC_PLL_DIV); - } else + if (IEEE80211_IS_CHAN_5GHZ(chan)) + pll |= SM(0xa, AR_RTC_PLL_DIV); + else pll |= SM(0xb, AR_RTC_PLL_DIV); - } + } else + pll |= SM(0xb, AR_RTC_PLL_DIV); + OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); /* TODO: diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416reg.h b/sys/dev/ath/ath_hal/ar5416/ar5416reg.h index 561c5b41b385d..c18c26f90fafe 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416reg.h +++ b/sys/dev/ath/ath_hal/ar5416/ar5416reg.h @@ -40,6 +40,7 @@ #define AR_INTR_ASYNC_MASK 0x4030 /* asynchronous interrupt mask */ #define AR_INTR_SYNC_MASK 0x4034 /* synchronous interrupt mask */ #define AR_INTR_ASYNC_CAUSE 0x4038 /* check pending interrupts */ +#define AR_INTR_ASYNC_CAUSE_CLR 0x4038 /* clear pending interrupts */ #define AR_INTR_ASYNC_ENABLE 0x403c /* enable interrupts */ #define AR5416_PCIE_SERDES 0x4040 #define AR5416_PCIE_SERDES2 0x4044 @@ -79,6 +80,13 @@ #endif /* AH_SUPPORT_AR9130 */ #define AR_RESET_TSF 0x8020 + +/* + * AR_SLEEP1 / AR_SLEEP2 are in the same place as in + * AR5212, however the fields have changed. + */ +#define AR5416_SLEEP1 0x80d4 +#define AR5416_SLEEP2 0x80d8 #define AR_RXFIFO_CFG 0x8114 #define AR_PHY_ERR_1 0x812c #define AR_PHY_ERR_MASK_1 0x8130 /* mask for AR_PHY_ERR_1 */ @@ -402,6 +410,7 @@ #define AR9271_AN_RF2G6_OFFS_S 20 /* Sleep control */ +#define AR5416_SLEEP1_ASSUME_DTIM 0x00080000 #define AR5416_SLEEP1_CAB_TIMEOUT 0xFFE00000 /* Cab timeout (TU) */ #define AR5416_SLEEP1_CAB_TIMEOUT_S 22 diff --git a/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c b/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c index a87d1adc0e716..2234eb35bfb65 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c +++ b/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c @@ -86,6 +86,28 @@ ar9160AniSetup(struct ath_hal *ah) ar5416AniAttach(ah, &aniparams, &aniparams, AH_TRUE); } +static void +ar9160InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan) +{ + uint32_t pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV); + if (chan != AH_NULL) { + if (IEEE80211_IS_CHAN_HALF(chan)) + pll |= SM(0x1, AR_RTC_SOWL_PLL_CLKSEL); + else if (IEEE80211_IS_CHAN_QUARTER(chan)) + pll |= SM(0x2, AR_RTC_SOWL_PLL_CLKSEL); + + if (IEEE80211_IS_CHAN_5GHZ(chan)) + pll |= SM(0x50, AR_RTC_SOWL_PLL_DIV); + else + pll |= SM(0x58, AR_RTC_SOWL_PLL_DIV); + } else + pll |= SM(0x58, AR_RTC_SOWL_PLL_DIV); + + OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); + OS_DELAY(RTC_PLL_SETTLE_DELAY); + OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_SLEEP_DERIVED_CLK); +} + /* * Attach for an AR9160 part. */ @@ -118,6 +140,7 @@ ar9160Attach(uint16_t devid, HAL_SOFTC sc, /* XXX override with 9160 specific state */ /* override 5416 methods for our needs */ + AH5416(ah)->ah_initPLL = ar9160InitPLL; AH5416(ah)->ah_cal.iqCalData.calData = &ar9160_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9160_adc_gain_cal; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280.c b/sys/dev/ath/ath_hal/ar9002/ar9280.c index f1bb4fe3f6bd0..99fd1d790d2e9 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9280.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9280.c @@ -76,6 +76,7 @@ ar9280SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan) uint32_t freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0; CHAN_CENTERS centers; uint32_t refDivA = 24; + uint8_t frac_n_5g; OS_MARK(ah, AH_MARK_SETCHANNEL, chan->ic_freq); @@ -85,6 +86,9 @@ ar9280SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan) reg32 = OS_REG_READ(ah, AR_PHY_SYNTH_CONTROL); reg32 &= 0xc0000000; + if (ath_hal_eepromGet(ah, AR_EEP_FRAC_N_5G, &frac_n_5g) != HAL_OK) + frac_n_5g = 0; + if (freq < 4800) { /* 2 GHz, fractional mode */ uint32_t txctl; @@ -106,11 +110,16 @@ ar9280SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan) bMode = 0; fracMode = 0; - if ((freq % 20) == 0) { - aModeRefSel = 3; - } else if ((freq % 10) == 0) { - aModeRefSel = 2; - } else { + switch (frac_n_5g) { + case 0: + if ((freq % 20) == 0) { + aModeRefSel = 3; + } else if ((freq % 10) == 0) { + aModeRefSel = 2; + } + if (aModeRefSel) break; + case 1: + default: aModeRefSel = 0; /* Enable 2G (fractional) mode for channels which are 5MHz spaced */ fracMode = 1; @@ -121,6 +130,7 @@ ar9280SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan) OS_A_REG_RMW_FIELD(ah, AR_AN_SYNTH9, AR_AN_SYNTH9_REFDIVA, refDivA); } + if (!fracMode) { ndiv = (freq * (refDivA >> aModeRefSel))/60; channelSel = ndiv & 0x1ff; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280.h b/sys/dev/ath/ath_hal/ar9002/ar9280.h index 3ac8fd5c23bbe..e383918abbfa0 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9280.h +++ b/sys/dev/ath/ath_hal/ar9002/ar9280.h @@ -59,5 +59,6 @@ struct ath_hal; HAL_BOOL ar9280SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING); void ar9280SpurMitigate(struct ath_hal *, const struct ieee80211_channel *); - +void ar9280InitPLL(struct ath_hal *ah, + const struct ieee80211_channel *chan); #endif /* _ATH_AR9280_H_ */ diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c index 3743c2195111d..4f4b8baf2b428 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c @@ -42,14 +42,14 @@ static const HAL_PERCAL_DATA ar9280_iq_cal = { /* single sample */ static const HAL_PERCAL_DATA ar9280_adc_gain_cal = { /* single sample */ .calName = "ADC Gain", .calType = ADC_GAIN_CAL, .calNumSamples = MIN_CAL_SAMPLES, - .calCountMax = PER_MIN_LOG_COUNT, + .calCountMax = PER_MAX_LOG_COUNT, .calCollect = ar5416AdcGainCalCollect, .calPostProc = ar5416AdcGainCalibration }; static const HAL_PERCAL_DATA ar9280_adc_dc_cal = { /* single sample */ .calName = "ADC DC", .calType = ADC_DC_CAL, .calNumSamples = MIN_CAL_SAMPLES, - .calCountMax = PER_MIN_LOG_COUNT, + .calCountMax = PER_MAX_LOG_COUNT, .calCollect = ar5416AdcDcCalCollect, .calPostProc = ar5416AdcDcCalibration }; @@ -99,6 +99,39 @@ ar9280AniSetup(struct ath_hal *ah) ar5416AniAttach(ah, &aniparams, &aniparams, AH_TRUE); } +void +ar9280InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan) +{ + uint32_t pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV); + + if (AR_SREV_MERLIN_20(ah) && + chan != AH_NULL && IEEE80211_IS_CHAN_5GHZ(chan)) { + /* + * PLL WAR for Merlin 2.0/2.1 + * When doing fast clock, set PLL to 0x142c + * Else, set PLL to 0x2850 to prevent reset-to-reset variation + */ + pll = IS_5GHZ_FAST_CLOCK_EN(ah, chan) ? 0x142c : 0x2850; + } else if (AR_SREV_MERLIN_10_OR_LATER(ah)) { + pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV); + if (chan != AH_NULL) { + if (IEEE80211_IS_CHAN_HALF(chan)) + pll |= SM(0x1, AR_RTC_SOWL_PLL_CLKSEL); + else if (IEEE80211_IS_CHAN_QUARTER(chan)) + pll |= SM(0x2, AR_RTC_SOWL_PLL_CLKSEL); + if (IEEE80211_IS_CHAN_5GHZ(chan)) + pll |= SM(0x28, AR_RTC_SOWL_PLL_DIV); + else + pll |= SM(0x2c, AR_RTC_SOWL_PLL_DIV); + } else + pll |= SM(0x2c, AR_RTC_SOWL_PLL_DIV); + } + + OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); + OS_DELAY(RTC_PLL_SETTLE_DELAY); + OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_SLEEP_DERIVED_CLK); +} + /* XXX shouldn't be here! */ #define EEP_MINOR(_ah) \ (AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK) @@ -138,6 +171,8 @@ ar9280Attach(uint16_t devid, HAL_SOFTC sc, /* XXX override with 9280 specific state */ /* override 5416 methods for our needs */ + AH5416(ah)->ah_initPLL = ar9280InitPLL; + ah->ah_setAntennaSwitch = ar9280SetAntennaSwitch; ah->ah_configPCIE = ar9280ConfigPCIE; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c index 2547148f838c1..02c7b9892aa83 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c @@ -136,6 +136,8 @@ ar9285Attach(uint16_t devid, HAL_SOFTC sc, /* XXX override with 9285 specific state */ /* override 5416 methods for our needs */ + AH5416(ah)->ah_initPLL = ar9280InitPLL; + ah->ah_setAntennaSwitch = ar9285SetAntennaSwitch; ah->ah_configPCIE = ar9285ConfigPCIE; ah->ah_setTxPower = ar9285SetTransmitPower; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c index ed9feb8fe754f..78400f52f95fd 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c @@ -137,6 +137,8 @@ ar9287Attach(uint16_t devid, HAL_SOFTC sc, /* XXX override with 9280 specific state */ /* override 5416 methods for our needs */ + AH5416(ah)->ah_initPLL = ar9280InitPLL; + ah->ah_setAntennaSwitch = ar9287SetAntennaSwitch; ah->ah_configPCIE = ar9287ConfigPCIE; diff --git a/sys/dev/ath/ath_rate/sample/sample.h b/sys/dev/ath/ath_rate/sample/sample.h index d61868d942767..b39e0be716464 100644 --- a/sys/dev/ath/ath_rate/sample/sample.h +++ b/sys/dev/ath/ath_rate/sample/sample.h @@ -199,8 +199,8 @@ static unsigned calc_usecs_unicast_packet(struct ath_softc *sc, ctsduration += rt->info[cix].spAckDuration; /* XXX assumes short preamble */ - /* XXX assumes HT/20; the node info isn't yet available here */ - ctsduration += ath_hal_pkt_txtime(sc->sc_ah, rt, length, rix, 0, is_ht40); + ctsduration += ath_hal_pkt_txtime(sc->sc_ah, rt, length, rix, + is_ht40, 0); if (cts) /* SIFS + ACK */ ctsduration += rt->info[cix].spAckDuration; @@ -210,8 +210,9 @@ static unsigned calc_usecs_unicast_packet(struct ath_softc *sc, tt += t_difs; /* XXX assumes short preamble */ - /* XXX assumes HT/20; the node info isn't yet available here */ - tt += (long_retries+1)*ath_hal_pkt_txtime(sc->sc_ah, rt, length, rix, 0, is_ht40); + tt += (long_retries+1)*ath_hal_pkt_txtime(sc->sc_ah, rt, length, rix, + is_ht40, 0); + tt += (long_retries+1)*(t_sifs + rt->info[rix].spAckDuration); for (x = 0; x <= short_retries + long_retries; x++) { diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 35592d9b47ad8..af612748f8c29 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -214,24 +214,6 @@ static void ath_tdma_update(struct ieee80211_node *ni, static void ath_tdma_beacon_send(struct ath_softc *sc, struct ieee80211vap *vap); -static __inline void -ath_hal_setcca(struct ath_hal *ah, int ena) -{ - /* - * NB: fill me in; this is not provided by default because disabling - * CCA in most locales violates regulatory. - */ -} - -static __inline int -ath_hal_getcca(struct ath_hal *ah) -{ - u_int32_t diag; - if (ath_hal_getcapability(ah, HAL_CAP_DIAG, 0, &diag) != HAL_OK) - return 1; - return ((diag & 0x500000) == 0); -} - #define TDMA_EP_MULTIPLIER (1<<10) /* pow2 to optimize out * and / */ #define TDMA_LPF_LEN 6 #define TDMA_DUMMY_MARKER 0x127 @@ -613,6 +595,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) sc->sc_hasbmatch = ath_hal_hasbssidmatch(ah); sc->sc_hastsfadd = ath_hal_hastsfadjust(ah); sc->sc_rxslink = ath_hal_self_linked_final_rxdesc(ah); + sc->sc_rxtsf32 = ath_hal_has_long_rxdesc_tsf(ah); if (ath_hal_hasfastframes(ah)) ic->ic_caps |= IEEE80211_C_FF; wmodes = ath_hal_getwirelessmodes(ah); @@ -1389,13 +1372,32 @@ ath_intr(void *arg) } } if (status & HAL_INT_RXEOL) { + int imask = sc->sc_imask; /* * NB: the hardware should re-read the link when * RXE bit is written, but it doesn't work at * least on older hardware revs. */ sc->sc_stats.ast_rxeol++; + /* + * Disable RXEOL/RXORN - prevent an interrupt + * storm until the PCU logic can be reset. + * In case the interface is reset some other + * way before "sc_kickpcu" is called, don't + * modify sc_imask - that way if it is reset + * by a call to ath_reset() somehow, the + * interrupt mask will be correctly reprogrammed. + */ + imask &= ~(HAL_INT_RXEOL | HAL_INT_RXORN); + ath_hal_intrset(ah, imask); + /* + * Enqueue an RX proc, to handled whatever + * is in the RX queue. + * This will then kick the PCU. + */ + taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); sc->sc_rxlink = NULL; + sc->sc_kickpcu = 1; } if (status & HAL_INT_TXURN) { sc->sc_stats.ast_txurn++; @@ -2937,16 +2939,31 @@ ath_descdma_setup(struct ath_softc *sc, { #define DS2PHYS(_dd, _ds) \ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) +#define ATH_DESC_4KB_BOUND_CHECK(_daddr, _len) \ + ((((u_int32_t)(_daddr) & 0xFFF) > (0x1000 - (_len))) ? 1 : 0) struct ifnet *ifp = sc->sc_ifp; - struct ath_desc *ds; + uint8_t *ds; struct ath_buf *bf; int i, bsize, error; + int desc_len; + + desc_len = sizeof(struct ath_desc); DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers %u desc/buf\n", __func__, name, nbuf, ndesc); dd->dd_name = name; - dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; + dd->dd_desc_len = desc_len * nbuf * ndesc; + + /* + * Merlin work-around: + * Descriptors that cross the 4KB boundary can't be used. + * Assume one skipped descriptor per 4KB page. + */ + if (! ath_hal_split4ktrans(sc->sc_ah)) { + int numdescpage = 4096 / (desc_len * ndesc); + dd->dd_desc_len = (nbuf / numdescpage + 1) * 4096; + } /* * Setup DMA descriptor area. @@ -2995,7 +3012,7 @@ ath_descdma_setup(struct ath_softc *sc, goto fail2; } - ds = dd->dd_desc; + ds = (uint8_t *) dd->dd_desc; DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n", __func__, dd->dd_name, ds, (u_long) dd->dd_desc_len, (caddr_t) dd->dd_desc_paddr, /*XXX*/ (u_long) dd->dd_desc_len); @@ -3011,9 +3028,23 @@ ath_descdma_setup(struct ath_softc *sc, dd->dd_bufptr = bf; STAILQ_INIT(head); - for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { - bf->bf_desc = ds; + for (i = 0; i < nbuf; i++, bf++, ds += (ndesc * desc_len)) { + bf->bf_desc = (struct ath_desc *) ds; bf->bf_daddr = DS2PHYS(dd, ds); + if (! ath_hal_split4ktrans(sc->sc_ah)) { + /* + * Merlin WAR: Skip descriptor addresses which + * cause 4KB boundary crossing along any point + * in the descriptor. + */ + if (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr, + desc_len * ndesc)) { + /* Start at the next page */ + ds += 0x1000 - (bf->bf_daddr & 0xFFF); + bf->bf_desc = (struct ath_desc *) ds; + bf->bf_daddr = DS2PHYS(dd, ds); + } + } error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &bf->bf_dmamap); if (error != 0) { @@ -3036,6 +3067,7 @@ fail0: memset(dd, 0, sizeof(*dd)); return error; #undef DS2PHYS +#undef ATH_DESC_4KB_BOUND_CHECK } static void @@ -3245,14 +3277,49 @@ ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) * a full 64-bit TSF using the specified TSF. */ static __inline u_int64_t -ath_extend_tsf(u_int32_t rstamp, u_int64_t tsf) +ath_extend_tsf15(u_int32_t rstamp, u_int64_t tsf) { if ((tsf & 0x7fff) < rstamp) tsf -= 0x8000; + return ((tsf &~ 0x7fff) | rstamp); } /* + * Extend 32-bit time stamp from rx descriptor to + * a full 64-bit TSF using the specified TSF. + */ +static __inline u_int64_t +ath_extend_tsf32(u_int32_t rstamp, u_int64_t tsf) +{ + u_int32_t tsf_low = tsf & 0xffffffff; + u_int64_t tsf64 = (tsf & ~0xffffffffULL) | rstamp; + + if (rstamp > tsf_low && (rstamp - tsf_low > 0x10000000)) + tsf64 -= 0x100000000ULL; + + if (rstamp < tsf_low && (tsf_low - rstamp > 0x10000000)) + tsf64 += 0x100000000ULL; + + return tsf64; +} + +/* + * Extend the TSF from the RX descriptor to a full 64 bit TSF. + * Earlier hardware versions only wrote the low 15 bits of the + * TSF into the RX descriptor; later versions (AR5416 and up) + * include the 32 bit TSF value. + */ +static __inline u_int64_t +ath_extend_tsf(struct ath_softc *sc, u_int32_t rstamp, u_int64_t tsf) +{ + if (sc->sc_rxtsf32) + return ath_extend_tsf32(rstamp, tsf); + else + return ath_extend_tsf15(rstamp, tsf); +} + +/* * Intercept management frames to collect beacon rssi data * and to do ibss merges. */ @@ -3285,7 +3352,7 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, if (vap->iv_opmode == IEEE80211_M_IBSS && vap->iv_state == IEEE80211_S_RUN) { uint32_t rstamp = sc->sc_lastrs->rs_tstamp; - uint64_t tsf = ath_extend_tsf(rstamp, + uint64_t tsf = ath_extend_tsf(sc, rstamp, ath_hal_gettsf64(sc->sc_ah)); /* * Handle ibss merge as needed; check the tsf on the @@ -3357,7 +3424,7 @@ ath_rx_tap(struct ifnet *ifp, struct mbuf *m, sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTGI; } #endif - sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(rs->rs_tstamp, tsf)); + sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(sc, rs->rs_tstamp, tsf)); if (rs->rs_status & HAL_RXERR_CRC) sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; /* XXX propagate other error flags from descriptor */ @@ -3740,6 +3807,25 @@ rx_next: if (ath_dfs_tasklet_needed(sc, sc->sc_curchan)) taskqueue_enqueue(sc->sc_tq, &sc->sc_dfstask); + /* + * Now that all the RX frames were handled that + * need to be handled, kick the PCU if there's + * been an RXEOL condition. + */ + if (sc->sc_kickpcu) { + sc->sc_kickpcu = 0; + ath_stoprecv(sc); + sc->sc_imask |= (HAL_INT_RXEOL | HAL_INT_RXORN); + if (ath_startrecv(sc) != 0) { + if_printf(ifp, + "%s: couldn't restart RX after RXEOL; resetting\n", + __func__); + ath_reset(ifp); + return; + } + ath_hal_intrset(ah, sc->sc_imask); + } + if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { #ifdef IEEE80211_SUPPORT_SUPERG ieee80211_ff_age_all(ic, 100); @@ -4963,6 +5049,7 @@ ath_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *reg, __func__, status); return EINVAL; /* XXX */ } + return 0; } @@ -5344,6 +5431,9 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCGATHDIAG: error = ath_ioctl_diag(sc, (struct ath_diag *) ifr); break; + case SIOCGATHPHYERR: + error = ath_ioctl_phyerr(sc,(struct ath_diag*) ifr); + break; #endif case SIOCGIFADDR: error = ether_ioctl(ifp, cmd, data); @@ -5388,20 +5478,6 @@ ath_announce(struct ath_softc *sc) } #ifdef IEEE80211_SUPPORT_TDMA -static __inline uint32_t -ath_hal_getnexttbtt(struct ath_hal *ah) -{ -#define AR_TIMER0 0x8028 - return OS_REG_READ(ah, AR_TIMER0); -} - -static __inline void -ath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta) -{ - /* XXX handle wrap/overflow */ - OS_REG_WRITE(ah, AR_TSF_L32, OS_REG_READ(ah, AR_TSF_L32) + tsfdelta); -} - static void ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt, u_int32_t bintval) { @@ -5413,6 +5489,8 @@ ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt, u_int32_t bintval) bt.bt_nextdba = (nexttbtt<<3) - sc->sc_tdmadbaprep; bt.bt_nextswba = (nexttbtt<<3) - sc->sc_tdmaswbaprep; bt.bt_nextatim = nexttbtt+1; + /* Enables TBTT, DBA, SWBA timers by default */ + bt.bt_flags = 0; ath_hal_beaconsettimers(ah, &bt); } @@ -5555,8 +5633,8 @@ ath_tdma_update(struct ieee80211_node *ni, struct ath_softc *sc = ic->ic_ifp->if_softc; struct ath_hal *ah = sc->sc_ah; const HAL_RATE_TABLE *rt = sc->sc_currates; - u_int64_t tsf, rstamp, nextslot; - u_int32_t txtime, nextslottu, timer0; + u_int64_t tsf, rstamp, nextslot, nexttbtt; + u_int32_t txtime, nextslottu; int32_t tudelta, tsfdelta; const struct ath_rx_status *rs; int rix; @@ -5587,7 +5665,7 @@ ath_tdma_update(struct ieee80211_node *ni, /* extend rx timestamp to 64 bits */ rs = sc->sc_lastrs; tsf = ath_hal_gettsf64(ah); - rstamp = ath_extend_tsf(rs->rs_tstamp, tsf); + rstamp = ath_extend_tsf(sc, rs->rs_tstamp, tsf); /* * The rx timestamp is set by the hardware on completing * reception (at the point where the rx descriptor is DMA'd @@ -5603,15 +5681,15 @@ ath_tdma_update(struct ieee80211_node *ni, nextslottu = TSF_TO_TU(nextslot>>32, nextslot) & HAL_BEACON_PERIOD; /* - * TIMER0 is the h/w's idea of NextTBTT (in TU's). Convert - * to usecs and calculate the difference between what the + * Retrieve the hardware NextTBTT in usecs + * and calculate the difference between what the * other station thinks and what we have programmed. This * lets us figure how to adjust our timers to match. The * adjustments are done by pulling the TSF forward and possibly * rewriting the beacon timers. */ - timer0 = ath_hal_getnexttbtt(ah); - tsfdelta = (int32_t)((nextslot % TU_TO_TSF(HAL_BEACON_PERIOD+1)) - TU_TO_TSF(timer0)); + nexttbtt = ath_hal_getnexttbtt(ah); + tsfdelta = (int32_t)((nextslot % TU_TO_TSF(HAL_BEACON_PERIOD + 1)) - nexttbtt); DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, "tsfdelta %d avg +%d/-%d\n", tsfdelta, @@ -5631,7 +5709,7 @@ ath_tdma_update(struct ieee80211_node *ni, TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0); TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0); } - tudelta = nextslottu - timer0; + tudelta = nextslottu - TSF_TO_TU(nexttbtt >> 32, nexttbtt); /* * Copy sender's timetstamp into tdma ie so they can @@ -5650,10 +5728,9 @@ ath_tdma_update(struct ieee80211_node *ni, &ni->ni_tstamp.data, 8); #if 0 DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, - "tsf %llu nextslot %llu (%d, %d) nextslottu %u timer0 %u (%d)\n", + "tsf %llu nextslot %llu (%d, %d) nextslottu %u nexttbtt %llu (%d)\n", (unsigned long long) tsf, (unsigned long long) nextslot, - (int)(nextslot - tsf), tsfdelta, - nextslottu, timer0, tudelta); + (int)(nextslot - tsf), tsfdelta, nextslottu, nexttbtt, tudelta); #endif /* * Adjust the beacon timers only when pulling them forward diff --git a/sys/dev/ath/if_ath_sysctl.c b/sys/dev/ath/if_ath_sysctl.c index e3c9966b8f55d..ea6f949bdbe40 100644 --- a/sys/dev/ath/if_ath_sysctl.c +++ b/sys/dev/ath/if_ath_sysctl.c @@ -354,7 +354,21 @@ ath_sysctl_intmit(SYSCTL_HANDLER_ARGS) error = sysctl_handle_int(oidp, &intmit, 0, req); if (error || !req->newptr) return error; - return !ath_hal_setintmit(sc->sc_ah, intmit) ? EINVAL : 0; + + /* reusing error; 1 here means "good"; 0 means "fail" */ + error = ath_hal_setintmit(sc->sc_ah, intmit); + if (! error) + return EINVAL; + + /* + * Reset the hardware here - disabling ANI in the HAL + * doesn't reset ANI related registers, so it'll leave + * things in an inconsistent state. + */ + if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) + ath_reset(sc->sc_ifp); + + return 0; } #ifdef IEEE80211_SUPPORT_TDMA diff --git a/sys/dev/ath/if_athdfs.h b/sys/dev/ath/if_athdfs.h index 88ee7fc7af8ce..a3f27f90e94ef 100644 --- a/sys/dev/ath/if_athdfs.h +++ b/sys/dev/ath/if_athdfs.h @@ -42,6 +42,7 @@ extern int ath_dfs_process_radar_event(struct ath_softc *sc, extern int ath_dfs_tasklet_needed(struct ath_softc *sc, struct ieee80211_channel *chan); extern int ath_ioctl_phyerr(struct ath_softc *sc, struct ath_diag *ad); -extern int ath_dfs_get_thresholds(struct ath_softc *sc, HAL_PHYERR_PARAM *param); +extern int ath_dfs_get_thresholds(struct ath_softc *sc, + HAL_PHYERR_PARAM *param); #endif /* __IF_ATHDFS_H__ */ diff --git a/sys/dev/ath/if_athioctl.h b/sys/dev/ath/if_athioctl.h index 98dd03791d990..4b50d0d8265f7 100644 --- a/sys/dev/ath/if_athioctl.h +++ b/sys/dev/ath/if_athioctl.h @@ -154,6 +154,7 @@ struct ath_diag { }; #define SIOCGATHDIAG _IOWR('i', 138, struct ath_diag) +#define SIOCGATHPHYERR _IOWR('i', 140, struct ath_diag) /* * Radio capture format. @@ -205,4 +206,34 @@ struct ath_tx_radiotap_header { int8_t wt_chan_maxpow; } __packed; +/* + * DFS ioctl commands + */ + +#define DFS_SET_THRESH 2 +#define DFS_GET_THRESH 3 +#define DFS_RADARDETECTS 6 + +/* + * DFS ioctl parameter types + */ +#define DFS_PARAM_FIRPWR 1 +#define DFS_PARAM_RRSSI 2 +#define DFS_PARAM_HEIGHT 3 +#define DFS_PARAM_PRSSI 4 +#define DFS_PARAM_INBAND 5 +#define DFS_PARAM_NOL 6 /* XXX not used in FreeBSD */ +#define DFS_PARAM_RELSTEP_EN 7 +#define DFS_PARAM_RELSTEP 8 +#define DFS_PARAM_RELPWR_EN 9 +#define DFS_PARAM_RELPWR 10 +#define DFS_PARAM_MAXLEN 11 +#define DFS_PARAM_USEFIR128 12 +#define DFS_PARAM_BLOCKRADAR 13 +#define DFS_PARAM_MAXRSSI_EN 14 + +/* FreeBSD-specific start at 32 */ +#define DFS_PARAM_ENABLE 32 +#define DFS_PARAM_EN_EXTCH 33 + #endif /* _DEV_ATH_ATHIOCTL_H */ diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 3bc8522660192..5c468e7f76469 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -254,7 +254,9 @@ struct ath_softc { sc_tdma : 1,/* TDMA in use */ sc_setcca : 1,/* set/clr CCA with TDMA */ sc_resetcal : 1,/* reset cal state next trip */ - sc_rxslink : 1;/* do self-linked final descriptor */ + sc_rxslink : 1,/* do self-linked final descriptor */ + sc_kickpcu : 1,/* kick PCU RX on next RX proc */ + sc_rxtsf32 : 1;/* RX dec TSF is 32 bits */ uint32_t sc_eerd; /* regdomain from EEPROM */ uint32_t sc_eecc; /* country code from EEPROM */ /* rate tables */ @@ -481,6 +483,8 @@ void ath_intr(void *); ((*(_ah)->ah_setBeaconTimers)((_ah), (_bt))) #define ath_hal_beacontimers(_ah, _bs) \ ((*(_ah)->ah_setStationBeaconTimers)((_ah), (_bs))) +#define ath_hal_getnexttbtt(_ah) \ + ((*(_ah)->ah_getNextTBTT)((_ah))) #define ath_hal_setassocid(_ah, _bss, _associd) \ ((*(_ah)->ah_writeAssocid)((_ah), (_bss), (_associd))) #define ath_hal_phydisable(_ah) \ @@ -651,11 +655,13 @@ void ath_intr(void *); #define ath_hal_gettxchainmask(_ah, _ptxchainmask) \ (ath_hal_getcapability(_ah, HAL_CAP_TX_CHAINMASK, 0, _ptxchainmask)) #define ath_hal_split4ktrans(_ah) \ - (ath_hal_getcapability(_ah, HAP_CAP_SPLIT_4KB_TRANS, 0, NULL) == HAL_OK) + (ath_hal_getcapability(_ah, HAL_CAP_SPLIT_4KB_TRANS, 0, NULL) == HAL_OK) #define ath_hal_self_linked_final_rxdesc(_ah) \ (ath_hal_getcapability(_ah, HAL_CAP_RXDESC_SELFLINK, 0, NULL) == HAL_OK) #define ath_hal_gtxto_supported(_ah) \ (ath_hal_getcapability(_ah, HAL_CAP_GTXTO, 0, NULL) == HAL_OK) +#define ath_hal_has_long_rxdesc_tsf(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_LONG_RXDESC_TSF, 0, NULL) == HAL_OK) #define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \ ((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq))) @@ -711,6 +717,8 @@ void ath_intr(void *); ((*(_ah)->ah_getDfsThresh)((_ah), (_param))) #define ath_hal_procradarevent(_ah, _rxs, _fulltsf, _buf, _event) \ ((*(_ah)->ah_procRadarEvent)((_ah), (_rxs), (_fulltsf), (_buf), (_event))) +#define ath_hal_is_fast_clock_enabled(_ah) \ + ((*(_ah)->ah_isFastClockEnabled)((_ah))) #define ath_hal_gpioCfgOutput(_ah, _gpio, _type) \ ((*(_ah)->ah_gpioCfgOutput)((_ah), (_gpio), (_type))) diff --git a/sys/dev/bvm/bvm_console.c b/sys/dev/bvm/bvm_console.c index 392346ee3eae9..291910076f926 100644 --- a/sys/dev/bvm/bvm_console.c +++ b/sys/dev/bvm/bvm_console.c @@ -29,8 +29,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_comconsole.h" - #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> @@ -63,7 +61,7 @@ static int polltime; static struct callout_handle bvm_timeouthandle = CALLOUT_HANDLE_INITIALIZER(&bvm_timeouthandle); -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) +#if defined(KDB) static int alt_break_state; #endif @@ -211,24 +209,8 @@ bvm_cngetc(struct consdev *cp) unsigned char ch; if (bvm_rcons(&ch) == 0) { -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) - int kdb_brk; - - if ((kdb_brk = kdb_alt_break(ch, &alt_break_state)) != 0) { - switch (kdb_brk) { - case KDB_REQ_DEBUGGER: - kdb_enter(KDB_WHY_BREAK, - "Break sequence on console"); - break; - case KDB_REQ_PANIC: - kdb_panic("Panic sequence on console"); - break; - case KDB_REQ_REBOOT: - kdb_reboot(); - break; - - } - } +#if defined(KDB) + kdb_alt_break(ch, &alt_break_state); #endif return (ch); } diff --git a/sys/dev/bxe/if_bxe.c b/sys/dev/bxe/if_bxe.c index e7534f4bb48c1..930a4f03d50e7 100644 --- a/sys/dev/bxe/if_bxe.c +++ b/sys/dev/bxe/if_bxe.c @@ -7188,7 +7188,7 @@ bxe_attn_int(struct bxe_softc* sc) /* sum[hi:lo] += add[hi:lo] */ #define ADD_64(s_hi, a_hi, s_lo, a_lo) do { \ s_lo += a_lo; \ - s_hi += a_hi + (s_lo < a_lo) ? 1 : 0; \ + s_hi += a_hi + ((s_lo < a_lo) ? 1 : 0); \ } while (0) /* Subtraction = minuend -= subtrahend */ diff --git a/sys/dev/cardbus/cardbus_cis.c b/sys/dev/cardbus/cardbus_cis.c index ca1ef4b6ed765..5d7704a53f59e 100644 --- a/sys/dev/cardbus/cardbus_cis.c +++ b/sys/dev/cardbus/cardbus_cis.c @@ -441,6 +441,7 @@ cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid, { if (res != CIS_CONFIG_SPACE) { bus_release_resource(child, SYS_RES_MEMORY, rid, res); + bus_delete_resource(child, SYS_RES_MEMORY, rid); } } diff --git a/sys/dev/cfe/cfe_console.c b/sys/dev/cfe/cfe_console.c index 1461ef21119f1..5a6b0a2bf9ba1 100644 --- a/sys/dev/cfe/cfe_console.c +++ b/sys/dev/cfe/cfe_console.c @@ -27,8 +27,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_comconsole.h" - #include <sys/param.h> #include <sys/kdb.h> #include <sys/kernel.h> @@ -67,7 +65,7 @@ static int polltime; static struct callout_handle cfe_timeouthandle = CALLOUT_HANDLE_INITIALIZER(&cfe_timeouthandle); -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) +#if defined(KDB) static int alt_break_state; #endif @@ -191,24 +189,8 @@ cfe_cngetc(struct consdev *cp) unsigned char ch; if (cfe_read(conhandle, &ch, 1) == 1) { -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) - int kdb_brk; - - if ((kdb_brk = kdb_alt_break(ch, &alt_break_state)) != 0) { - switch (kdb_brk) { - case KDB_REQ_DEBUGGER: - kdb_enter(KDB_WHY_BREAK, - "Break sequence on console"); - break; - case KDB_REQ_PANIC: - kdb_panic("Panic sequence on console"); - break; - case KDB_REQ_REBOOT: - kdb_reboot(); - break; - - } - } +#if defined(KDB) + kdb_alt_break(ch, &alt_break_state); #endif return (ch); } diff --git a/sys/dev/coretemp/coretemp.c b/sys/dev/coretemp/coretemp.c index 411b9eecf167b..cb1cbff3100e9 100644 --- a/sys/dev/coretemp/coretemp.c +++ b/sys/dev/coretemp/coretemp.c @@ -48,12 +48,21 @@ __FBSDID("$FreeBSD$"); #include <machine/cputypes.h> #include <machine/md_var.h> -#define TZ_ZEROC 2732 +#define TZ_ZEROC 2732 + +#define THERM_STATUS_LOG 0x02 +#define THERM_STATUS 0x01 +#define THERM_STATUS_TEMP_SHIFT 16 +#define THERM_STATUS_TEMP_MASK 0x7f +#define THERM_STATUS_RES_SHIFT 27 +#define THERM_STATUS_RES_MASK 0x0f +#define THERM_STATUS_VALID_SHIFT 31 +#define THERM_STATUS_VALID_MASK 0x01 struct coretemp_softc { device_t sc_dev; int sc_tjmax; - struct sysctl_oid *sc_oid; + unsigned int sc_throttle_log; }; /* @@ -64,8 +73,10 @@ static int coretemp_probe(device_t dev); static int coretemp_attach(device_t dev); static int coretemp_detach(device_t dev); -static int coretemp_get_temp(device_t dev); -static int coretemp_get_temp_sysctl(SYSCTL_HANDLER_ARGS); +static uint64_t coretemp_get_thermal_msr(int cpu); +static void coretemp_clear_thermal_msr(int cpu); +static int coretemp_get_val_sysctl(SYSCTL_HANDLER_ARGS); +static int coretemp_throttle_log_sysctl(SYSCTL_HANDLER_ARGS); static device_method_t coretemp_methods[] = { /* Device interface */ @@ -83,8 +94,16 @@ static driver_t coretemp_driver = { sizeof(struct coretemp_softc), }; +enum therm_info { + CORETEMP_TEMP, + CORETEMP_DELTA, + CORETEMP_RESOLUTION, + CORETEMP_TJMAX, +}; + static devclass_t coretemp_devclass; -DRIVER_MODULE(coretemp, cpu, coretemp_driver, coretemp_devclass, NULL, NULL); +DRIVER_MODULE(coretemp, cpu, coretemp_driver, coretemp_devclass, NULL, + NULL); static void coretemp_identify(driver_t *driver, device_t parent) @@ -135,6 +154,8 @@ coretemp_attach(device_t dev) uint64_t msr; int cpu_model, cpu_stepping; int ret, tjtarget; + struct sysctl_oid *oid; + struct sysctl_ctx_list *ctx; sc->sc_dev = dev; pdev = device_get_parent(dev); @@ -149,7 +170,7 @@ coretemp_attach(device_t dev) */ if (cpu_model < 0xe) return (ENXIO); - + #if 0 /* * XXXrpaulo: I have this CPU model and when it returns from C3 * coretemp continues to function properly. @@ -216,7 +237,7 @@ coretemp_attach(device_t dev) ret = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &msr); if (ret == 0) { tjtarget = (msr >> 16) & 0xff; - + /* * On earlier generation of processors, the value * obtained from IA32_TEMPERATURE_TARGET register is @@ -225,12 +246,12 @@ coretemp_attach(device_t dev) * these numbers are, with the publicly available * documents from Intel. * - * For now, we consider [70, 100]C range, as + * For now, we consider [70, 110]C range, as * described in #322683, as "reasonable" and accept * these values whenever the MSR is available for * read, regardless the CPU model. */ - if (tjtarget >= 70 && tjtarget <= 100) + if (tjtarget >= 70 && tjtarget <= 110) sc->sc_tjmax = tjtarget; else device_printf(dev, "Tj(target) value %d " @@ -243,15 +264,35 @@ coretemp_attach(device_t dev) if (bootverbose) device_printf(dev, "Setting TjMax=%d\n", sc->sc_tjmax); + ctx = device_get_sysctl_ctx(dev); + + oid = SYSCTL_ADD_NODE(ctx, + SYSCTL_CHILDREN(device_get_sysctl_tree(pdev)), OID_AUTO, + "coretemp", CTLFLAG_RD, NULL, "Per-CPU thermal information"); + /* - * Add the "temperature" MIB to dev.cpu.N. + * Add the MIBs to dev.cpu.N and dev.cpu.N.coretemp. */ - sc->sc_oid = SYSCTL_ADD_PROC(device_get_sysctl_ctx(pdev), - SYSCTL_CHILDREN(device_get_sysctl_tree(pdev)), - OID_AUTO, "temperature", - CTLTYPE_INT | CTLFLAG_RD, - dev, 0, coretemp_get_temp_sysctl, "IK", + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(pdev)), + OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, dev, + CORETEMP_TEMP, coretemp_get_val_sysctl, "IK", "Current temperature"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "delta", + CTLTYPE_INT | CTLFLAG_RD, dev, CORETEMP_DELTA, + coretemp_get_val_sysctl, "I", + "Delta between TCC activation and current temperature"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "resolution", + CTLTYPE_INT | CTLFLAG_RD, dev, CORETEMP_RESOLUTION, + coretemp_get_val_sysctl, "I", + "Resolution of CPU thermal sensor"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "tjmax", + CTLTYPE_INT | CTLFLAG_RD, dev, CORETEMP_TJMAX, + coretemp_get_val_sysctl, "IK", + "TCC activation temperature"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, + "throttle_log", CTLTYPE_INT | CTLFLAG_RW, dev, 0, + coretemp_throttle_log_sysctl, "I", + "Set to 1 if the thermal sensor has tripped"); return (0); } @@ -259,22 +300,13 @@ coretemp_attach(device_t dev) static int coretemp_detach(device_t dev) { - struct coretemp_softc *sc = device_get_softc(dev); - - sysctl_remove_oid(sc->sc_oid, 1, 0); - return (0); } - -static int -coretemp_get_temp(device_t dev) +static uint64_t +coretemp_get_thermal_msr(int cpu) { uint64_t msr; - int temp; - int cpu = device_get_unit(dev); - struct coretemp_softc *sc = device_get_softc(dev); - char stemp[16]; thread_lock(curthread); sched_bind(curthread, cpu); @@ -296,51 +328,116 @@ coretemp_get_temp(device_t dev) sched_unbind(curthread); thread_unlock(curthread); - /* - * Check for Thermal Status and Thermal Status Log. - */ - if ((msr & 0x3) == 0x3) - device_printf(dev, "PROCHOT asserted\n"); + return (msr); +} + +static void +coretemp_clear_thermal_msr(int cpu) +{ + thread_lock(curthread); + sched_bind(curthread, cpu); + thread_unlock(curthread); + + wrmsr(MSR_THERM_STATUS, 0); + + thread_lock(curthread); + sched_unbind(curthread); + thread_unlock(curthread); +} + +static int +coretemp_get_val_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev; + uint64_t msr; + int val, tmp; + struct coretemp_softc *sc; + enum therm_info type; + char stemp[16]; + + dev = (device_t) arg1; + msr = coretemp_get_thermal_msr(device_get_unit(dev)); + sc = device_get_softc(dev); + type = arg2; + + if (((msr >> THERM_STATUS_VALID_SHIFT) & THERM_STATUS_VALID_MASK) != 1) { + val = -1; + } else { + switch (type) { + case CORETEMP_TEMP: + tmp = (msr >> THERM_STATUS_TEMP_SHIFT) & + THERM_STATUS_TEMP_MASK; + val = (sc->sc_tjmax - tmp) * 10 + TZ_ZEROC; + break; + case CORETEMP_DELTA: + val = (msr >> THERM_STATUS_TEMP_SHIFT) & + THERM_STATUS_TEMP_MASK; + break; + case CORETEMP_RESOLUTION: + val = (msr >> THERM_STATUS_RES_SHIFT) & + THERM_STATUS_RES_MASK; + break; + case CORETEMP_TJMAX: + val = sc->sc_tjmax * 10 + TZ_ZEROC; + break; + } + } + + if (msr & THERM_STATUS_LOG) { + sc->sc_throttle_log = 1; - /* - * Bit 31 contains "Reading valid" - */ - if (((msr >> 31) & 0x1) == 1) { /* - * Starting on bit 16 and ending on bit 22. + * Check for Critical Temperature Status and Critical + * Temperature Log. It doesn't really matter if the + * current temperature is invalid because the "Critical + * Temperature Log" bit will tell us if the Critical + * Temperature has * been reached in past. It's not + * directly related to the current temperature. + * + * If we reach a critical level, allow devctl(4) + * to catch this and shutdown the system. */ - temp = sc->sc_tjmax - ((msr >> 16) & 0x7f); - } else - temp = -1; - - /* - * Check for Critical Temperature Status and Critical - * Temperature Log. - * It doesn't really matter if the current temperature is - * invalid because the "Critical Temperature Log" bit will - * tell us if the Critical Temperature has been reached in - * past. It's not directly related to the current temperature. - * - * If we reach a critical level, allow devctl(4) to catch this - * and shutdown the system. - */ - if (((msr >> 4) & 0x3) == 0x3) { - device_printf(dev, "critical temperature detected, " - "suggest system shutdown\n"); - snprintf(stemp, sizeof(stemp), "%d", temp); - devctl_notify("coretemp", "Thermal", stemp, "notify=0xcc"); + if (msr & THERM_STATUS) { + tmp = (msr >> THERM_STATUS_TEMP_SHIFT) & + THERM_STATUS_TEMP_MASK; + tmp = (sc->sc_tjmax - tmp) * 10 + TZ_ZEROC; + device_printf(dev, "critical temperature detected, " + "suggest system shutdown\n"); + snprintf(stemp, sizeof(stemp), "%d", tmp); + devctl_notify("coretemp", "Thermal", stemp, + "notify=0xcc"); + } } - return (temp); + return (sysctl_handle_int(oidp, &val, 0, req)); } static int -coretemp_get_temp_sysctl(SYSCTL_HANDLER_ARGS) +coretemp_throttle_log_sysctl(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; - int temp; + device_t dev; + uint64_t msr; + int error, val; + struct coretemp_softc *sc; + + dev = (device_t) arg1; + msr = coretemp_get_thermal_msr(device_get_unit(dev)); + sc = device_get_softc(dev); + + if (msr & THERM_STATUS_LOG) + sc->sc_throttle_log = 1; + + val = sc->sc_throttle_log; - temp = coretemp_get_temp(dev) * 10 + TZ_ZEROC; + error = sysctl_handle_int(oidp, &val, 0, req); - return (sysctl_handle_int(oidp, &temp, 0, req)); + if (error || !req->newptr) + return (error); + else if (val != 0) + return (EINVAL); + + coretemp_clear_thermal_msr(device_get_unit(dev)); + sc->sc_throttle_log = 0; + + return (0); } diff --git a/sys/dev/dcons/dcons_os.c b/sys/dev/dcons/dcons_os.c index 3b98cdd255f70..b7de4148ef740 100644 --- a/sys/dev/dcons/dcons_os.c +++ b/sys/dev/dcons/dcons_os.c @@ -64,7 +64,6 @@ #include <vm/vm_param.h> #include <vm/pmap.h> -#include "opt_comconsole.h" #include "opt_dcons.h" #include "opt_kdb.h" #include "opt_gdb.h" @@ -133,38 +132,21 @@ static struct ttydevsw dcons_ttydevsw = { .tsw_outwakeup = dcons_outwakeup, }; -#if (defined(GDB) || defined(DDB)) && defined(ALT_BREAK_TO_DEBUGGER) +#if (defined(GDB) || defined(DDB)) static int dcons_check_break(struct dcons_softc *dc, int c) { - int kdb_brk; if (c < 0) return (c); - if ((kdb_brk = kdb_alt_break(c, &dc->brk_state)) != 0) { - switch (kdb_brk) { - case KDB_REQ_DEBUGGER: - if ((dc->flags & DC_GDB) != 0) { #ifdef GDB - if (gdb_cur == &dcons_gdb_dbgport) { - kdb_dbbe_select("gdb"); - kdb_enter(KDB_WHY_BREAK, - "Break sequence on dcons gdb port"); - } + if ((dc->flags & DC_GDB) != 0 && gdb_cur == &dcons_gdb_dbgport) + kdb_alt_break_gdb(c, &dc->brk_state); + else #endif - } else - kdb_enter(KDB_WHY_BREAK, - "Break sequence on dcons console port"); - break; - case KDB_REQ_PANIC: - kdb_panic("Panic sequence on dcons console port"); - break; - case KDB_REQ_REBOOT: - kdb_reboot(); - break; - } - } + kdb_alt_break(c, &dc->brk_state); + return (c); } #else diff --git a/sys/dev/gem/if_gem.c b/sys/dev/gem/if_gem.c index 6f53eaea1c8b1..d75e1ab8dc61e 100644 --- a/sys/dev/gem/if_gem.c +++ b/sys/dev/gem/if_gem.c @@ -947,10 +947,8 @@ gem_init_locked(struct gem_softc *sc) GEM_LOCK_ASSERT(sc, MA_OWNED); -#ifdef notyet if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) return; -#endif #ifdef GEM_DEBUG CTR2(KTR_GEM, "%s: %s: calling stop", device_get_name(sc->sc_dev), diff --git a/sys/dev/hptiop/hptiop.c b/sys/dev/hptiop/hptiop.c index 77a4ccd5b4c3d..49ffcefe6c578 100644 --- a/sys/dev/hptiop/hptiop.c +++ b/sys/dev/hptiop/hptiop.c @@ -1269,6 +1269,8 @@ static int hptiop_probe(device_t dev) id = pci_get_device(dev); switch (id) { + case 0x4322: + case 0x4321: case 0x4320: sas = 1; case 0x3220: diff --git a/sys/dev/hwpmc/hwpmc_logging.c b/sys/dev/hwpmc/hwpmc_logging.c index 633c6f953b6e9..b85572a3c86fb 100644 --- a/sys/dev/hwpmc/hwpmc_logging.c +++ b/sys/dev/hwpmc/hwpmc_logging.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/capability.h> #include <sys/file.h> #include <sys/kernel.h> #include <sys/kthread.h> @@ -589,7 +590,7 @@ pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd) po->po_file)); /* get a reference to the file state */ - error = fget_write(curthread, logfd, &po->po_file); + error = fget_write(curthread, logfd, CAP_WRITE, &po->po_file); if (error) goto error; diff --git a/sys/dev/ichwd/ichwd.c b/sys/dev/ichwd/ichwd.c index a66826e4c6e42..5d800c963e863 100644 --- a/sys/dev/ichwd/ichwd.c +++ b/sys/dev/ichwd/ichwd.c @@ -402,11 +402,10 @@ ichwd_event(void *arg, unsigned int cmd, int *error) cmd &= WD_INTERVAL; timeout = ((uint64_t)1 << cmd) / ICHWD_TICK; if (cmd) { - if (timeout != sc->timeout) { - if (!sc->active) - ichwd_tmr_enable(sc); + if (!sc->active) + ichwd_tmr_enable(sc); + if (timeout != sc->timeout) ichwd_tmr_set(sc, timeout); - } ichwd_tmr_reload(sc); *error = 0; } else { diff --git a/sys/dev/ipmi/ipmi_linux.c b/sys/dev/ipmi/ipmi_linux.c index fcf2bd50322d6..430bd08589485 100644 --- a/sys/dev/ipmi/ipmi_linux.c +++ b/sys/dev/ipmi/ipmi_linux.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/kernel.h> #include <sys/module.h> @@ -92,7 +93,7 @@ ipmi_linux_ioctl(struct thread *td, struct linux_ioctl_args *args) u_long cmd; int error; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); cmd = args->cmd; diff --git a/sys/dev/iscsi/initiator/iscsi.c b/sys/dev/iscsi/initiator/iscsi.c index d35f6310747a1..292ce8f21fa08 100644 --- a/sys/dev/iscsi/initiator/iscsi.c +++ b/sys/dev/iscsi/initiator/iscsi.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include "opt_iscsi_initiator.h" #include <sys/param.h> +#include <sys/capability.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/conf.h> @@ -387,11 +388,11 @@ i_setsoc(isc_session_t *sp, int fd, struct thread *td) if(sp->soc != NULL) isc_stop_receiver(sp); - error = fget(td, fd, &sp->fp); + error = fget(td, fd, CAP_SOCK_ALL, &sp->fp); if(error) return error; - if((error = fgetsock(td, fd, &sp->soc, 0)) == 0) { + if((error = fgetsock(td, fd, CAP_SOCK_ALL, &sp->soc, 0)) == 0) { sp->td = td; isc_start_receiver(sp); } diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index 95f2add24743c..dfba62e6e0416 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -102,7 +102,6 @@ static const uint8_t alpa_map[] = { /* * Local function prototypes. */ -static void isp_prt_endcmd(ispsoftc_t *, XS_T *); static int isp_parse_async(ispsoftc_t *, uint16_t); static int isp_parse_async_fc(ispsoftc_t *, uint16_t); static int isp_handle_other_response(ispsoftc_t *, int, isphdr_t *, uint32_t *); @@ -5391,7 +5390,7 @@ out: * Support routines. */ -static void +void isp_prt_endcmd(ispsoftc_t *isp, XS_T *xs) { char cdbstr[16 * 5 + 1]; diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index 4a664bfb9a339..8d62f5ebdece4 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -67,7 +67,10 @@ static void isp_intr_enable(void *); static void isp_cam_async(void *, uint32_t, struct cam_path *, void *); static void isp_poll(struct cam_sim *); static timeout_t isp_watchdog; +static timeout_t isp_gdt; +static task_fn_t isp_gdt_task; static timeout_t isp_ldt; +static task_fn_t isp_ldt_task; static void isp_kthread(void *); static void isp_action(struct cam_sim *, union ccb *); #ifdef ISP_INTERNAL_TARGET @@ -105,15 +108,13 @@ isp_attach_chan(ispsoftc_t *isp, struct cam_devq *devq, int chan) return (EIO); } ISP_UNLOCK(isp); - - if (xpt_create_path(&path, NULL, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + if (xpt_create_path_unlocked(&path, NULL, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { ISP_LOCK(isp); xpt_bus_deregister(cam_sim_path(sim)); ISP_UNLOCK(isp); cam_sim_free(sim, FALSE); return (ENXIO); } - xpt_setup_ccb(&csa.ccb_h, path, 5); csa.ccb_h.func_code = XPT_SASYNC_CB; csa.event_enable = AC_LOST_DEVICE; @@ -141,8 +142,11 @@ isp_attach_chan(ispsoftc_t *isp, struct cam_devq *devq, int chan) fc->path = path; fc->isp = isp; fc->ready = 1; + callout_init_mtx(&fc->ldt, &isp->isp_osinfo.lock, 0); callout_init_mtx(&fc->gdt, &isp->isp_osinfo.lock, 0); + TASK_INIT(&fc->ltask, 1, isp_ldt_task, fc); + TASK_INIT(&fc->gtask, 1, isp_gdt_task, fc); /* * We start by being "loop down" if we have an initiator role @@ -184,12 +188,16 @@ isp_attach(ispsoftc_t *isp) isp->isp_osinfo.ehook.ich_func = isp_intr_enable; isp->isp_osinfo.ehook.ich_arg = isp; + /* + * Haha. Set this first, because if we're loaded as a module isp_intr_enable + * will be called right awawy, which will clear isp_osinfo.ehook_active, + * which would be unwise to then set again later. + */ + isp->isp_osinfo.ehook_active = 1; if (config_intrhook_establish(&isp->isp_osinfo.ehook) != 0) { isp_prt(isp, ISP_LOGERR, "could not establish interrupt enable hook"); return (-EIO); } - isp->isp_osinfo.ehook_active = 1; - /* * Create the device queue for our SIM(s). @@ -246,20 +254,33 @@ unwind: return (-1); } -void +int isp_detach(ispsoftc_t *isp) { + struct cam_sim *sim; + struct cam_path *path; + struct ccb_setasync csa; int chan; ISP_LOCK(isp); + for (chan = isp->isp_nchan - 1; chan >= 0; chan -= 1) { + if (IS_FC(isp)) { + sim = ISP_FC_PC(isp, chan)->sim; + path = ISP_FC_PC(isp, chan)->path; + } else { + sim = ISP_SPI_PC(isp, chan)->sim; + path = ISP_SPI_PC(isp, chan)->path; + } + if (sim->refcount > 2) { + ISP_UNLOCK(isp); + return (EBUSY); + } + } if (isp->isp_osinfo.timer_active) { callout_stop(&isp->isp_osinfo.tmo); isp->isp_osinfo.timer_active = 0; } - ISP_UNLOCK(isp); for (chan = isp->isp_nchan - 1; chan >= 0; chan -= 1) { - struct cam_sim *sim; - struct cam_path *path; if (IS_FC(isp)) { sim = ISP_FC_PC(isp, chan)->sim; path = ISP_FC_PC(isp, chan)->path; @@ -267,12 +288,17 @@ isp_detach(ispsoftc_t *isp) sim = ISP_SPI_PC(isp, chan)->sim; path = ISP_SPI_PC(isp, chan)->path; } + xpt_setup_ccb(&csa.ccb_h, path, 5); + csa.ccb_h.func_code = XPT_SASYNC_CB; + csa.event_enable = 0; + csa.callback = isp_cam_async; + csa.callback_arg = sim; + xpt_action((union ccb *)&csa); xpt_free_path(path); - ISP_LOCK(isp); xpt_bus_deregister(cam_sim_path(sim)); - ISP_UNLOCK(isp); cam_sim_free(sim, FALSE); } + ISP_UNLOCK(isp); if (isp->isp_osinfo.cdev) { destroy_dev(isp->isp_osinfo.cdev); isp->isp_osinfo.cdev = NULL; @@ -285,6 +311,7 @@ isp_detach(ispsoftc_t *isp) cam_simq_free(isp->isp_osinfo.devq); isp->isp_osinfo.devq = NULL; } + return (0); } static void @@ -303,6 +330,20 @@ isp_freeze_loopdown(ispsoftc_t *isp, int chan, char *msg) } } +static void +isp_unfreeze_loopdown(ispsoftc_t *isp, int chan) +{ + if (IS_FC(isp)) { + struct isp_fc *fc = ISP_FC_PC(isp, chan); + int wasfrozen = fc->simqfrozen & SIMQFRZ_LOOPDOWN; + fc->simqfrozen &= ~SIMQFRZ_LOOPDOWN; + if (wasfrozen && fc->simqfrozen == 0) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d releasing simq", __func__, chan); + xpt_release_simq(fc->sim, 1); + } + } +} + static int ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td) @@ -696,6 +737,7 @@ isp_intr_enable(void *arg) } } } + isp->isp_osinfo.ehook_active = 0; ISP_UNLOCK(isp); /* Release our hook so that the boot can continue. */ config_intrhook_disestablish(&isp->isp_osinfo.ehook); @@ -1302,7 +1344,7 @@ done: xpt_print(ccb->ccb_h.path, "now disabled for target mode\n"); } if (tptr) { - rls_lun_statep(isp, tptr); + destroy_lun_state(isp, tptr); } isp->isp_osinfo.rptr = NULL; isp->isp_osinfo.tmbusy = 0; @@ -3781,19 +3823,20 @@ static void isp_cam_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg) { struct cam_sim *sim; + int bus, tgt; ispsoftc_t *isp; sim = (struct cam_sim *)cbarg; isp = (ispsoftc_t *) cam_sim_softc(sim); + bus = cam_sim_bus(sim); + tgt = xpt_path_target_id(path); + switch (code) { case AC_LOST_DEVICE: if (IS_SCSI(isp)) { uint16_t oflags, nflags; - int bus = cam_sim_bus(sim); sdparam *sdp = SDPARAM(isp, bus); - int tgt; - tgt = xpt_path_target_id(path); if (tgt >= 0) { nflags = sdp->isp_devparam[tgt].nvrm_flags; #ifndef ISP_TARGET_MODE @@ -3837,11 +3880,32 @@ isp_watchdog(void *arg) { struct ccb_scsiio *xs = arg; ispsoftc_t *isp; - uint32_t handle; + uint32_t ohandle = ISP_HANDLE_FREE, handle; isp = XS_ISP(xs); handle = isp_find_handle(isp, xs); + + if (handle != ISP_HANDLE_FREE && !XS_CMD_WPEND_P(xs)) { + isp_xs_prt(isp, xs, ISP_LOGWARN, "first watchdog (handle 0x%x) timed out- deferring for grace period", handle); + callout_reset(&PISP_PCMD(xs)->wdog, 2 * hz, isp_watchdog, xs); + XS_CMD_S_WPEND(xs); + return; + } + XS_C_TACTIVE(xs); + + /* + * Hand crank the interrupt code just to be sure the command isn't stuck somewhere. + */ + if (handle != ISP_HANDLE_FREE) { + uint32_t isr; + uint16_t sema, mbox; + if (ISP_READ_ISR(isp, &isr, &sema, &mbox) != 0) { + isp_intr(isp, isr, sema, mbox); + } + ohandle = handle; + handle = isp_find_handle(isp, xs); + } if (handle != ISP_HANDLE_FREE) { /* * Try and make sure the command is really dead before @@ -3878,7 +3942,14 @@ isp_watchdog(void *arg) isp_destroy_handle(isp, handle); isp_prt(isp, ISP_LOGERR, "%s: timeout for handle 0x%x", __func__, handle); XS_SETERR(xs, CAM_CMD_TIMEOUT); + isp_prt_endcmd(isp, xs); isp_done(xs); + } else { + if (ohandle != ISP_HANDLE_FREE) { + isp_prt(isp, ISP_LOGWARN, "%s: timeout for handle 0x%x, recovered during interrupt", __func__, ohandle); + } else { + isp_prt(isp, ISP_LOGWARN, "%s: timeout for handle already free", __func__); + } } } @@ -3937,12 +4008,20 @@ static void isp_gdt(void *arg) { struct isp_fc *fc = arg; + taskqueue_enqueue(taskqueue_thread, &fc->gtask); +} + +static void +isp_gdt_task(void *arg, int pending) +{ + struct isp_fc *fc = arg; ispsoftc_t *isp = fc->isp; int chan = fc - isp->isp_osinfo.pc.fc; fcportdb_t *lp; int dbidx, tgt, more_to_do = 0; - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d GDT timer expired @ %lu", chan, (unsigned long) time_uptime); + ISP_LOCK(isp); + isp_prt(isp, ISP_LOGDEBUG0, "Chan %d GDT timer expired", chan); for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { lp = &FCPARAM(isp, chan)->portdb[dbidx]; @@ -3953,6 +4032,7 @@ isp_gdt(void *arg) continue; } if (lp->gone_timer != 0) { + isp_prt(isp, ISP_LOGSANCFG, "%s: Chan %d more to do for target %u (timer=%u)", __func__, chan, lp->dev_map_idx - 1, lp->gone_timer); lp->gone_timer -= 1; more_to_do++; continue; @@ -3968,9 +4048,11 @@ isp_gdt(void *arg) if (more_to_do) { callout_reset(&fc->gdt, hz, isp_gdt, fc); } else { - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d Stopping Gone Device Timer", chan); + callout_deactivate(&fc->gdt); + isp_prt(isp, ISP_LOGSANCFG, "Chan %d Stopping Gone Device Timer @ %lu", chan, (unsigned long) time_uptime); } } + ISP_UNLOCK(isp); } /* @@ -3986,12 +4068,21 @@ static void isp_ldt(void *arg) { struct isp_fc *fc = arg; + taskqueue_enqueue(taskqueue_thread, &fc->ltask); +} + +static void +isp_ldt_task(void *arg, int pending) +{ + struct isp_fc *fc = arg; ispsoftc_t *isp = fc->isp; int chan = fc - isp->isp_osinfo.pc.fc; fcportdb_t *lp; - int dbidx, tgt; + int dbidx, tgt, i; + ISP_LOCK(isp); isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d Loop Down Timer expired @ %lu", chan, (unsigned long) time_uptime); + callout_deactivate(&fc->ldt); /* * Notify to the OS all targets who we now consider have departed. @@ -4009,6 +4100,23 @@ isp_ldt(void *arg) /* * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST! */ + + + for (i = 0; i < isp->isp_maxcmds; i++) { + struct ccb_scsiio *xs; + + if (!ISP_VALID_HANDLE(isp, isp->isp_xflist[i].handle)) { + continue; + } + if ((xs = isp->isp_xflist[i].cmd) == NULL) { + continue; + } + if (dbidx != (FCPARAM(isp, chan)->isp_dev_map[XS_TGT(xs)] - 1)) { + continue; + } + isp_prt(isp, ISP_LOGWARN, "command handle 0x%08x for %d.%d.%d orphaned by loop down timeout", + isp->isp_xflist[i].handle, chan, XS_TGT(xs), XS_LUN(xs)); + } /* * Mark that we've announced that this device is gone.... @@ -4030,6 +4138,9 @@ isp_ldt(void *arg) isp_make_gone(isp, chan, tgt); } + if (FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR) { + isp_unfreeze_loopdown(isp, chan); + } /* * The loop down timer has expired. Wake up the kthread * to notice that fact (or make it false). @@ -4037,6 +4148,7 @@ isp_ldt(void *arg) fc->loop_dead = 1; fc->loop_down_time = fc->loop_down_limit+1; wakeup(fc); + ISP_UNLOCK(isp); } static void @@ -4050,7 +4162,7 @@ isp_kthread(void *arg) mtx_lock(&isp->isp_osinfo.lock); for (;;) { - int wasfrozen, lb, lim; + int lb, lim; isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d checking FC state", __func__, chan); lb = isp_fc_runstate(isp, chan, 250000); @@ -4121,12 +4233,7 @@ isp_kthread(void *arg) */ if (FCPARAM(isp, chan)->loop_seen_once || fc->loop_dead) { - wasfrozen = fc->simqfrozen & SIMQFRZ_LOOPDOWN; - fc->simqfrozen &= ~SIMQFRZ_LOOPDOWN; - if (wasfrozen && fc->simqfrozen == 0) { - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d releasing simq", __func__, chan); - xpt_release_simq(fc->sim, 1); - } + isp_unfreeze_loopdown(isp, chan); } isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep time %d", __func__, chan, slp); @@ -4225,6 +4332,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb) ts = 60*1000; } ts = isp_mstohz(ts); + XS_S_TACTIVE(ccb); callout_reset(&PISP_PCMD(ccb)->wdog, ts, isp_watchdog, ccb); break; case CMD_RQLATER: @@ -4631,7 +4739,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb) if (kp->xport_specific.fc.valid & KNOB_VALID_ADDRESS) { fcp->isp_wwnn = ISP_FC_PC(isp, bus)->def_wwnn = kp->xport_specific.fc.wwnn; fcp->isp_wwpn = ISP_FC_PC(isp, bus)->def_wwpn = kp->xport_specific.fc.wwpn; -isp_prt(isp, ISP_LOGALL, "Setting Channel %d wwns to 0x%jx 0x%jx", bus, fcp->isp_wwnn, fcp->isp_wwpn); + isp_prt(isp, ISP_LOGALL, "Setting Channel %d wwns to 0x%jx 0x%jx", bus, fcp->isp_wwnn, fcp->isp_wwpn); } ccb->ccb_h.status = CAM_REQ_CMP; if (kp->xport_specific.fc.valid & KNOB_VALID_ROLE) { @@ -4751,7 +4859,9 @@ isp_prt(isp, ISP_LOGALL, "Setting Channel %d wwns to 0x%jx 0x%jx", bus, fcp->isp /* * Set base transfer capabilities for Fibre Channel, for this HBA. */ - if (IS_24XX(isp)) { + if (IS_25XX(isp)) { + cpi->base_transfer_speed = 8000000; + } else if (IS_24XX(isp)) { cpi->base_transfer_speed = 4000000; } else if (IS_23XX(isp)) { cpi->base_transfer_speed = 2000000; @@ -4797,6 +4907,7 @@ void isp_done(XS_T *sccb) { ispsoftc_t *isp = XS_ISP(sccb); + uint32_t status; if (XS_NOERR(sccb)) XS_SETERR(sccb, CAM_REQ_CMP); @@ -4811,8 +4922,10 @@ isp_done(XS_T *sccb) } sccb->ccb_h.status &= ~CAM_SIM_QUEUED; - if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - isp_prt(isp, ISP_LOGDEBUG0, "target %d lun %d CAM status 0x%x SCSI status 0x%x", XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status, sccb->scsi_status); + status = sccb->ccb_h.status & CAM_STATUS_MASK; + if (status != CAM_REQ_CMP) { + if (status != CAM_SEL_TIMEOUT) + isp_prt(isp, ISP_LOGDEBUG0, "target %d lun %d CAM status 0x%x SCSI status 0x%x", XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status, sccb->scsi_status); if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { sccb->ccb_h.status |= CAM_DEV_QFRZN; xpt_freeze_devq(sccb->ccb_h.path, 1); @@ -4824,7 +4937,8 @@ isp_done(XS_T *sccb) } XS_CMD_S_DONE(sccb); - callout_stop(&PISP_PCMD(sccb)->wdog); + if (XS_TACTIVE_P(sccb)) + callout_stop(&PISP_PCMD(sccb)->wdog); XS_CMD_S_CLEAR(sccb); isp_free_pcmd(isp, (union ccb *) sccb); xpt_done((union ccb *) sccb); @@ -5423,15 +5537,19 @@ isp_default_wwn(ispsoftc_t * isp, int chan, int isactive, int iswwnn) void isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...) { + int loc; + char lbuf[128]; va_list ap; + if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { return; } - printf("%s: ", device_get_nameunit(isp->isp_dev)); + sprintf(lbuf, "%s: ", device_get_nameunit(isp->isp_dev)); + loc = strlen(lbuf); va_start(ap, fmt); - vprintf(fmt, ap); + vsnprintf(&lbuf[loc], sizeof (lbuf) - loc - 1, fmt, ap); va_end(ap); - printf("\n"); + printf("%s\n", lbuf); } void diff --git a/sys/dev/isp/isp_freebsd.h b/sys/dev/isp/isp_freebsd.h index 0d67630ec3566..1fb5fc56a89fe 100644 --- a/sys/dev/isp/isp_freebsd.h +++ b/sys/dev/isp/isp_freebsd.h @@ -41,6 +41,7 @@ #include <sys/proc.h> #include <sys/bus.h> +#include <sys/taskqueue.h> #include <machine/bus.h> #include <machine/cpu.h> @@ -182,6 +183,8 @@ struct isp_fc { ready : 1; struct callout ldt; /* loop down timer */ struct callout gdt; /* gone device timer */ + struct task ltask; + struct task gtask; #ifdef ISP_TARGET_MODE struct tslist lun_hash[LUN_HASH_SIZE]; #ifdef ISP_INTERNAL_TARGET @@ -579,7 +582,7 @@ default: \ * prototypes for isp_pci && isp_freebsd to share */ extern int isp_attach(ispsoftc_t *); -extern void isp_detach(ispsoftc_t *); +extern int isp_detach(ispsoftc_t *); extern void isp_uninit(ispsoftc_t *); extern uint64_t isp_default_wwn(ispsoftc_t *, int, int, int); @@ -597,12 +600,23 @@ extern int isp_autoconfig; * Platform private flags */ #define ISP_SPRIV_ERRSET 0x1 +#define ISP_SPRIV_TACTIVE 0x2 #define ISP_SPRIV_DONE 0x8 +#define ISP_SPRIV_WPEND 0x10 + +#define XS_S_TACTIVE(sccb) (sccb)->ccb_h.spriv_field0 |= ISP_SPRIV_TACTIVE +#define XS_C_TACTIVE(sccb) (sccb)->ccb_h.spriv_field0 &= ~ISP_SPRIV_TACTIVE +#define XS_TACTIVE_P(sccb) ((sccb)->ccb_h.spriv_field0 & ISP_SPRIV_TACTIVE) #define XS_CMD_S_DONE(sccb) (sccb)->ccb_h.spriv_field0 |= ISP_SPRIV_DONE #define XS_CMD_C_DONE(sccb) (sccb)->ccb_h.spriv_field0 &= ~ISP_SPRIV_DONE #define XS_CMD_DONE_P(sccb) ((sccb)->ccb_h.spriv_field0 & ISP_SPRIV_DONE) +#define XS_CMD_S_WPEND(sccb) (sccb)->ccb_h.spriv_field0 |= ISP_SPRIV_WPEND +#define XS_CMD_C_WPEND(sccb) (sccb)->ccb_h.spriv_field0 &= ~ISP_SPRIV_WPEND +#define XS_CMD_WPEND_P(sccb) ((sccb)->ccb_h.spriv_field0 & ISP_SPRIV_WPEND) + + #define XS_CMD_S_CLEAR(sccb) (sccb)->ccb_h.spriv_field0 = 0 /* diff --git a/sys/dev/isp/isp_pci.c b/sys/dev/isp/isp_pci.c index 5eb073957bc1a..b6b23fafa59d1 100644 --- a/sys/dev/isp/isp_pci.c +++ b/sys/dev/isp/isp_pci.c @@ -347,7 +347,11 @@ static int isp_pci_detach (device_t); struct isp_pcisoftc { ispsoftc_t pci_isp; device_t pci_dev; - struct resource * pci_reg; + struct resource * regs; + void * irq; + int iqd; + int rtp; + int rgd; void * ih; int16_t pci_poff[_NREG_BLKS]; bus_dma_tag_t dmat; @@ -645,8 +649,7 @@ isp_get_specific_options(device_t dev, int chan, ispsoftc_t *isp) static int isp_pci_attach(device_t dev) { - struct resource *regs, *irq; - int rtp, rgd, iqd, i, m1, m2, locksetup = 0; + int i, m1, m2, locksetup = 0; int isp_nvports = 0; uint32_t data, cmd, linesz, did; struct isp_pcisoftc *pcs; @@ -687,32 +690,31 @@ isp_pci_attach(device_t dev) isp_get_pci_options(dev, &m1, &m2); linesz = PCI_DFLT_LNSZ; - irq = regs = NULL; - rgd = rtp = iqd = 0; + pcs->irq = pcs->regs = NULL; + pcs->rgd = pcs->rtp = pcs->iqd = 0; cmd = pci_read_config(dev, PCIR_COMMAND, 2); if (cmd & m1) { - rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; - rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; - regs = bus_alloc_resource_any(dev, rtp, &rgd, RF_ACTIVE); + pcs->rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; + pcs->rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; + pcs->regs = bus_alloc_resource_any(dev, pcs->rtp, &pcs->rgd, RF_ACTIVE); } - if (regs == NULL && (cmd & m2)) { - rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; - rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; - regs = bus_alloc_resource_any(dev, rtp, &rgd, RF_ACTIVE); + if (pcs->regs == NULL && (cmd & m2)) { + pcs->rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; + pcs->rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; + pcs->regs = bus_alloc_resource_any(dev, pcs->rtp, &pcs->rgd, RF_ACTIVE); } - if (regs == NULL) { + if (pcs->regs == NULL) { device_printf(dev, "unable to map any ports\n"); goto bad; } if (bootverbose) { - device_printf(dev, "using %s space register mapping\n", (rgd == IO_MAP_REG)? "I/O" : "Memory"); + device_printf(dev, "using %s space register mapping\n", (pcs->rgd == IO_MAP_REG)? "I/O" : "Memory"); } - isp->isp_bus_tag = rman_get_bustag(regs); - isp->isp_bus_handle = rman_get_bushandle(regs); + isp->isp_bus_tag = rman_get_bustag(pcs->regs); + isp->isp_bus_handle = rman_get_bushandle(pcs->regs); pcs->pci_dev = dev; - pcs->pci_reg = regs; pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF; @@ -931,13 +933,13 @@ isp_pci_attach(device_t dev) pcs->msicount = 1; } if (pci_alloc_msi(dev, &pcs->msicount) == 0) { - iqd = 1; + pcs->iqd = 1; } else { - iqd = 0; + pcs->iqd = 0; } } - irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &iqd, RF_ACTIVE | RF_SHAREABLE); - if (irq == NULL) { + pcs->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &pcs->iqd, RF_ACTIVE | RF_SHAREABLE); + if (pcs->irq == NULL) { device_printf(dev, "could not allocate interrupt\n"); goto bad; } @@ -946,7 +948,7 @@ isp_pci_attach(device_t dev) mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF); locksetup++; - if (isp_setup_intr(dev, irq, ISP_IFLAGS, NULL, isp_platform_intr, isp, &pcs->ih)) { + if (isp_setup_intr(dev, pcs->irq, ISP_IFLAGS, NULL, isp_platform_intr, isp, &pcs->ih)) { device_printf(dev, "could not setup interrupt\n"); goto bad; } @@ -982,19 +984,19 @@ isp_pci_attach(device_t dev) bad: if (pcs->ih) { - (void) bus_teardown_intr(dev, irq, pcs->ih); + (void) bus_teardown_intr(dev, pcs->irq, pcs->ih); } if (locksetup) { mtx_destroy(&isp->isp_osinfo.lock); } - if (irq) { - (void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq); + if (pcs->irq) { + (void) bus_release_resource(dev, SYS_RES_IRQ, pcs->iqd, pcs->irq); } if (pcs->msicount) { pci_release_msi(dev); } - if (regs) { - (void) bus_release_resource(dev, rtp, rgd, regs); + if (pcs->regs) { + (void) bus_release_resource(dev, pcs->rtp, pcs->rgd, pcs->regs); } if (pcs->pci_isp.isp_param) { free(pcs->pci_isp.isp_param, M_DEVBUF); @@ -1012,14 +1014,36 @@ isp_pci_detach(device_t dev) { struct isp_pcisoftc *pcs; ispsoftc_t *isp; + int status; pcs = device_get_softc(dev); if (pcs == NULL) { return (ENXIO); } isp = (ispsoftc_t *) pcs; - ISP_DISABLE_INTS(isp); + status = isp_detach(isp); + if (status) + return (status); + ISP_LOCK(isp); + isp_uninit(isp); + if (pcs->ih) { + (void) bus_teardown_intr(dev, pcs->irq, pcs->ih); + } + ISP_UNLOCK(isp); mtx_destroy(&isp->isp_osinfo.lock); + (void) bus_release_resource(dev, SYS_RES_IRQ, pcs->iqd, pcs->irq); + if (pcs->msicount) { + pci_release_msi(dev); + } + (void) bus_release_resource(dev, pcs->rtp, pcs->rgd, pcs->regs); + if (pcs->pci_isp.isp_param) { + free(pcs->pci_isp.isp_param, M_DEVBUF); + pcs->pci_isp.isp_param = NULL; + } + if (pcs->pci_isp.isp_osinfo.pc.ptr) { + free(pcs->pci_isp.isp_osinfo.pc.ptr, M_DEVBUF); + pcs->pci_isp.isp_osinfo.pc.ptr = NULL; + } return (0); } diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h index d7937949c4885..55edc17228cff 100644 --- a/sys/dev/isp/ispvar.h +++ b/sys/dev/isp/ispvar.h @@ -953,6 +953,11 @@ void isp_async(ispsoftc_t *, ispasync_t, ...); #define ISPASYNC_CHANGE_OTHER 2 /* + * Platform Independent Error Prinout + */ +void isp_prt_endcmd(ispsoftc_t *, XS_T *); + +/* * Platform Dependent Error and Debug Printout * * Two required functions for each platform must be provided: diff --git a/sys/dev/ixgbe/ixgbe.c b/sys/dev/ixgbe/ixgbe.c index a382a5356c4ef..9a709afcc01a7 100644 --- a/sys/dev/ixgbe/ixgbe.c +++ b/sys/dev/ixgbe/ixgbe.c @@ -3849,6 +3849,8 @@ fail: **********************************************************************/ #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 +#define BSIZEPKT_ROUNDUP ((1<<IXGBE_SRRCTL_BSIZEPKT_SHIFT)-1) + static void ixgbe_initialize_receive_units(struct adapter *adapter) { @@ -3882,7 +3884,7 @@ ixgbe_initialize_receive_units(struct adapter *adapter) hlreg &= ~IXGBE_HLREG0_JUMBOEN; IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); - bufsz = adapter->rx_mbuf_sz >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + bufsz = (adapter->rx_mbuf_sz + BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; for (int i = 0; i < adapter->num_queues; i++, rxr++) { u64 rdba = rxr->rxdma.dma_paddr; @@ -4300,9 +4302,10 @@ ixgbe_rxeof(struct ix_queue *que, int count) sendmp = rbuf->fmp; rbuf->m_pack = rbuf->fmp = NULL; - if (sendmp != NULL) /* secondary frag */ + if (sendmp != NULL) { /* secondary frag */ + mp->m_flags &= ~M_PKTHDR; sendmp->m_pkthdr.len += mp->m_len; - else { + } else { /* first desc of a non-ps chain */ sendmp = mp; sendmp->m_flags |= M_PKTHDR; diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c index f9bfffe8786dd..470362d5baa3a 100644 --- a/sys/dev/mfi/mfi.c +++ b/sys/dev/mfi/mfi.c @@ -2132,8 +2132,7 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td if (ioc->mfi_sense_len) { /* get user-space sense ptr then copy out sense */ - bcopy(&((struct mfi_ioc_packet*)arg) - ->mfi_frame.raw[ioc->mfi_sense_off], + bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off], &sense_ptr.sense_ptr_data[0], sizeof(sense_ptr.sense_ptr_data)); #ifdef __amd64__ diff --git a/sys/dev/mfi/mfi_linux.c b/sys/dev/mfi/mfi_linux.c index 44edf49109db1..12135ff2470bc 100644 --- a/sys/dev/mfi/mfi_linux.c +++ b/sys/dev/mfi/mfi_linux.c @@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/kernel.h> #include <sys/module.h> @@ -95,7 +96,7 @@ mfi_linux_ioctl(struct thread *p, struct linux_ioctl_args *args) break; } - if ((error = fget(p, args->fd, &fp)) != 0) + if ((error = fget(p, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = fo_ioctl(fp, cmd, (caddr_t)args->arg, p->td_ucred, p); fdrop(fp, p); diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c index 8e3986a80be1c..88090b7607a47 100644 --- a/sys/dev/mii/brgphy.c +++ b/sys/dev/mii/brgphy.c @@ -876,10 +876,22 @@ brgphy_reset(struct mii_softc *sc) struct bge_softc *bge_sc = NULL; struct bce_softc *bce_sc = NULL; struct ifnet *ifp; - int val; + int i, val; + + /* + * Perform a reset. Note that at least some Broadcom PHYs default to + * being powered down as well as isolated after a reset but don't work + * if one or both of these bits are cleared. However, they just work + * fine if both bits remain set, so we don't use mii_phy_reset() here. + */ + PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_RESET); - /* Perform a standard PHY reset. */ - mii_phy_reset(sc); + /* Wait 100ms for it to complete. */ + for (i = 0; i < 100; i++) { + if ((PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_RESET) == 0) + break; + DELAY(1000); + } /* Handle any PHY specific procedures following the reset. */ switch (sc->mii_mpd_oui) { diff --git a/sys/dev/mii/mii_physubr.c b/sys/dev/mii/mii_physubr.c index be6650595cf2a..8e1476a7df45e 100644 --- a/sys/dev/mii/mii_physubr.c +++ b/sys/dev/mii/mii_physubr.c @@ -273,8 +273,8 @@ mii_phy_reset(struct mii_softc *sc) DELAY(1000); } - /* NB: a PHY may default to isolation. */ - reg &= ~BMCR_ISO; + /* NB: a PHY may default to being powered down and/or isolated. */ + reg &= ~(BMCR_PDOWN | BMCR_ISO); if ((sc->mii_flags & MIIF_NOISOLATE) == 0 && ((ife == NULL && sc->mii_inst != 0) || (ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst))) diff --git a/sys/dev/mmc/mmcsd.c b/sys/dev/mmc/mmcsd.c index cbb64e4409dd7..6dd007c441d3b 100644 --- a/sys/dev/mmc/mmcsd.c +++ b/sys/dev/mmc/mmcsd.c @@ -137,7 +137,7 @@ mmcsd_attach(device_t dev) d->d_drv1 = sc; d->d_maxsize = 4*1024*1024; /* Maximum defined SD card AU size. */ d->d_sectorsize = mmc_get_sector_size(dev); - d->d_mediasize = mmc_get_media_size(dev) * d->d_sectorsize; + d->d_mediasize = (off_t)mmc_get_media_size(dev) * d->d_sectorsize; d->d_stripeoffset = 0; d->d_stripesize = mmc_get_erase_sector(dev) * d->d_sectorsize; d->d_unit = device_get_unit(dev); diff --git a/sys/dev/mps/mps_sas.c b/sys/dev/mps/mps_sas.c index 6fbda923bc445..2aa4773eef915 100644 --- a/sys/dev/mps/mps_sas.c +++ b/sys/dev/mps/mps_sas.c @@ -925,7 +925,7 @@ mpssas_action(struct cam_sim *sim, union ccb *ccb) cpi->hba_misc = PIM_NOBUSRESET; cpi->hba_eng_cnt = 0; cpi->max_target = sassc->sc->facts->MaxTargets - 1; - cpi->max_lun = 0; + cpi->max_lun = 8; cpi->initiator_id = 255; strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN); diff --git a/sys/dev/mpt/mpilib/mpi_ioc.h b/sys/dev/mpt/mpilib/mpi_ioc.h index 107c561aeee72..c0c73d29f81c2 100644 --- a/sys/dev/mpt/mpilib/mpi_ioc.h +++ b/sys/dev/mpt/mpilib/mpi_ioc.h @@ -33,7 +33,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: August 11, 2000 * - * mpi_ioc.h Version: 01.05.14 + * mpi_ioc.h Version: 01.05.16 * * Version History * --------------- @@ -140,6 +140,16 @@ * added _MULTI_PORT_DOMAIN. * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request. * Added Common Boot Block type to FWUpload Request. + * 08-07-07 01.05.15 Added MPI_EVENT_SAS_INIT_RC_REMOVED define. + * Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and + * MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data. + * Added SASAddress field to SAS Initiator Device Table + * Overflow event data structure. + * 03-28-08 01.05.16 Added two new ReasonCode values to SAS Device Status + * Change Event data to indicate completion of internally + * generated task management. + * Added MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE define. + * Added MPI_EVENT_SAS_INIT_RC_INACCESSIBLE define. * -------------------------------------------------------------------------- */ @@ -639,6 +649,8 @@ typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE #define MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) #define MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) #define MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) +#define MPI_EVENT_SAS_DEV_STAT_RC_CMPL_INTERNAL_DEV_RESET (0x0E) +#define MPI_EVENT_SAS_DEV_STAT_RC_CMPL_TASK_ABORT_INTERNAL (0x0F) /* SCSI Event data for Queue Full event */ @@ -735,6 +747,8 @@ typedef struct _MPI_EVENT_DATA_IR2 #define MPI_EVENT_IR2_RC_PD_REMOVED (0x05) #define MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED (0x06) #define MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR (0x07) +#define MPI_EVENT_IR2_RC_DUAL_PORT_ADDED (0x08) +#define MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED (0x09) /* defines for logical disk states */ #define MPI_LD_STATE_OPTIMAL (0x00) @@ -894,6 +908,7 @@ typedef struct _EVENT_DATA_DISCOVERY_ERROR #define MPI_EVENT_DSCVRY_ERR_DS_UNSUPPORTED_DEVICE (0x00000800) #define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000) #define MPI_EVENT_DSCVRY_ERR_DS_MULTI_PORT_DOMAIN (0x00002000) +#define MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE (0x00004000) /* SAS SMP Error Event data */ @@ -929,6 +944,8 @@ typedef struct _EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE /* defines for the ReasonCode field of the SAS Initiator Device Status Change event */ #define MPI_EVENT_SAS_INIT_RC_ADDED (0x01) +#define MPI_EVENT_SAS_INIT_RC_REMOVED (0x02) +#define MPI_EVENT_SAS_INIT_RC_INACCESSIBLE (0x03) /* SAS Initiator Device Table Overflow Event data */ @@ -937,6 +954,7 @@ typedef struct _EVENT_DATA_SAS_INIT_TABLE_OVERFLOW U8 MaxInit; /* 00h */ U8 CurrentInit; /* 01h */ U16 Reserved1; /* 02h */ + U64 SASAddress; /* 04h */ } EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, MPI_POINTER PTR_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, MpiEventDataSasInitTableOverflow_t, diff --git a/sys/dev/mpt/mpt.c b/sys/dev/mpt/mpt.c index fb24025ecffe8..9dfd73b2b3b58 100644 --- a/sys/dev/mpt/mpt.c +++ b/sys/dev/mpt/mpt.c @@ -301,66 +301,75 @@ mpt_modevent(module_t mod, int type, void *data) return (error); } -int +static int mpt_stdload(struct mpt_personality *pers) { + /* Load is always successful. */ return (0); } -int +static int mpt_stdprobe(struct mpt_softc *mpt) { + /* Probe is always successful. */ return (0); } -int +static int mpt_stdattach(struct mpt_softc *mpt) { + /* Attach is always successful. */ return (0); } -int +static int mpt_stdenable(struct mpt_softc *mpt) { + /* Enable is always successful. */ return (0); } -void +static void mpt_stdready(struct mpt_softc *mpt) { -} +} -int +static int mpt_stdevent(struct mpt_softc *mpt, request_t *req, MSG_EVENT_NOTIFY_REPLY *msg) { + mpt_lprt(mpt, MPT_PRT_DEBUG, "mpt_stdevent: 0x%x\n", msg->Event & 0xFF); /* Event was not for us. */ return (0); } -void +static void mpt_stdreset(struct mpt_softc *mpt, int type) { + } -void +static void mpt_stdshutdown(struct mpt_softc *mpt) { + } -void +static void mpt_stddetach(struct mpt_softc *mpt) { + } -int +static int mpt_stdunload(struct mpt_personality *pers) { + /* Unload is always successful. */ return (0); } @@ -383,7 +392,6 @@ mpt_postattach(void *unused) } SYSINIT(mptdev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, mpt_postattach, NULL); - /******************************* Bus DMA Support ******************************/ void mpt_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error) @@ -478,6 +486,7 @@ static int mpt_default_reply_handler(struct mpt_softc *mpt, request_t *req, uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) { + mpt_prt(mpt, "Default Handler Called: req=%p:%u reply_descriptor=%x frame=%p\n", req, req->serno, reply_desc, reply_frame); @@ -494,8 +503,8 @@ static int mpt_config_reply_handler(struct mpt_softc *mpt, request_t *req, uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) { - if (req != NULL) { + if (req != NULL) { if (reply_frame != NULL) { MSG_CONFIG *cfgp; MSG_CONFIG_REPLY *reply; @@ -528,6 +537,7 @@ static int mpt_handshake_reply_handler(struct mpt_softc *mpt, request_t *req, uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) { + /* Nothing to be done. */ return (TRUE); } @@ -650,6 +660,7 @@ static int mpt_core_event(struct mpt_softc *mpt, request_t *req, MSG_EVENT_NOTIFY_REPLY *msg) { + mpt_lprt(mpt, MPT_PRT_DEBUG, "mpt_core_event: 0x%x\n", msg->Event & 0xFF); switch(msg->Event & 0xFF) { @@ -870,6 +881,7 @@ mpt_complete_request_chain(struct mpt_softc *mpt, struct req_queue *chain, void mpt_dump_reply_frame(struct mpt_softc *mpt, MSG_DEFAULT_REPLY *reply_frame) { + mpt_prt(mpt, "Address Reply:\n"); mpt_print_reply(reply_frame); } @@ -881,12 +893,14 @@ static __inline uint32_t mpt_rd_intr(struct mpt_softc *mpt); static __inline uint32_t mpt_rd_db(struct mpt_softc *mpt) { + return mpt_read(mpt, MPT_OFFSET_DOORBELL); } static __inline uint32_t mpt_rd_intr(struct mpt_softc *mpt) { + return mpt_read(mpt, MPT_OFFSET_INTR_STATUS); } @@ -895,6 +909,7 @@ static int mpt_wait_db_ack(struct mpt_softc *mpt) { int i; + for (i=0; i < MPT_MAX_WAIT; i++) { if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) { maxwait_ack = i > maxwait_ack ? i : maxwait_ack; @@ -910,6 +925,7 @@ static int mpt_wait_db_int(struct mpt_softc *mpt) { int i; + for (i = 0; i < MPT_MAX_WAIT; i++) { if (MPT_DB_INTR(mpt_rd_intr(mpt))) { maxwait_int = i > maxwait_int ? i : maxwait_int; @@ -925,6 +941,7 @@ void mpt_check_doorbell(struct mpt_softc *mpt) { uint32_t db = mpt_rd_db(mpt); + if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) { mpt_prt(mpt, "Device not running\n"); mpt_print_db(db); @@ -956,6 +973,7 @@ static int mpt_download_fw(struct mpt_softc *mpt); static int mpt_soft_reset(struct mpt_softc *mpt) { + mpt_lprt(mpt, MPT_PRT_DEBUG, "soft reset\n"); /* Have to use hard reset if we are not in Running state */ @@ -1019,6 +1037,7 @@ mpt_enable_diag_mode(struct mpt_softc *mpt) static void mpt_disable_diag_mode(struct mpt_softc *mpt) { + mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFFFFFFFF); } @@ -1094,6 +1113,7 @@ mpt_hard_reset(struct mpt_softc *mpt) static void mpt_core_ioc_reset(struct mpt_softc *mpt, int type) { + /* * Complete all pending requests with a status * appropriate for an IOC reset. @@ -1102,7 +1122,6 @@ mpt_core_ioc_reset(struct mpt_softc *mpt, int type) MPI_IOCSTATUS_INVALID_STATE); } - /* * Reset the IOC when needed. Try software command first then if needed * poke at the magic diagnostic reset. Note that a hard reset resets @@ -1263,6 +1282,7 @@ retry: void mpt_send_cmd(struct mpt_softc *mpt, request_t *req) { + if (mpt->verbose > MPT_PRT_DEBUG2) { mpt_dump_request(mpt, req); } @@ -2110,6 +2130,7 @@ mpt_send_event_request(struct mpt_softc *mpt, int onoff) void mpt_enable_ints(struct mpt_softc *mpt) { + /* Unmask every thing except door bell int */ mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK); } @@ -2120,6 +2141,7 @@ mpt_enable_ints(struct mpt_softc *mpt) void mpt_disable_ints(struct mpt_softc *mpt) { + /* Mask all interrupts */ mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK); @@ -2219,7 +2241,7 @@ mpt_detach(struct mpt_softc *mpt) return (0); } -int +static int mpt_core_load(struct mpt_personality *pers) { int i; @@ -2245,7 +2267,7 @@ mpt_core_load(struct mpt_personality *pers) * Initialize per-instance driver data and perform * initial controller configuration. */ -int +static int mpt_core_attach(struct mpt_softc *mpt) { int val, error; @@ -2276,9 +2298,10 @@ mpt_core_attach(struct mpt_softc *mpt) return (error); } -int +static int mpt_core_enable(struct mpt_softc *mpt) { + /* * We enter with the IOC enabled, but async events * not enabled, ports not enabled and interrupts @@ -2326,13 +2349,14 @@ mpt_core_enable(struct mpt_softc *mpt) return (0); } -void +static void mpt_core_shutdown(struct mpt_softc *mpt) { + mpt_disable_ints(mpt); } -void +static void mpt_core_detach(struct mpt_softc *mpt) { int val; @@ -2351,9 +2375,10 @@ mpt_core_detach(struct mpt_softc *mpt) mpt_dma_buf_free(mpt); } -int +static int mpt_core_unload(struct mpt_personality *pers) { + /* Unload is always successful. */ return (0); } @@ -2575,6 +2600,7 @@ static void mpt_dma_buf_free(struct mpt_softc *mpt) { int i; + if (mpt->request_dmat == 0) { mpt_lprt(mpt, MPT_PRT_DEBUG, "already released dma memory\n"); return; diff --git a/sys/dev/mpt/mpt.h b/sys/dev/mpt/mpt.h index d12c307c80311..8a20e82b92d5a 100644 --- a/sys/dev/mpt/mpt.h +++ b/sys/dev/mpt/mpt.h @@ -1075,16 +1075,6 @@ mpt_complete_request_chain(struct mpt_softc *, struct req_queue *, u_int); int mpt_reset(struct mpt_softc *, int /*reinit*/); /****************************** Debugging ************************************/ -typedef struct mpt_decode_entry { - char *name; - u_int value; - u_int mask; -} mpt_decode_entry_t; - -int mpt_decode_value(mpt_decode_entry_t *table, u_int num_entries, - const char *name, u_int value, u_int *cur_column, - u_int wrap_point); - void mpt_dump_data(struct mpt_softc *, const char *, void *, int); void mpt_dump_request(struct mpt_softc *, request_t *); @@ -1110,17 +1100,21 @@ do { \ mpt_prt(mpt, __VA_ARGS__); \ } while (0) +#if 0 #define mpt_lprtc(mpt, level, ...) \ do { \ if (level <= (mpt)->verbose) \ mpt_prtc(mpt, __VA_ARGS__); \ } while (0) +#endif #else void mpt_lprt(struct mpt_softc *, int, const char *, ...) __printflike(3, 4); +#if 0 void mpt_lprtc(struct mpt_softc *, int, const char *, ...) __printflike(3, 4); #endif +#endif void mpt_prt(struct mpt_softc *, const char *, ...) __printflike(2, 3); void mpt_prtc(struct mpt_softc *, const char *, ...) @@ -1277,7 +1271,6 @@ void mpt_check_doorbell(struct mpt_softc *mpt); void mpt_dump_reply_frame(struct mpt_softc *mpt, MSG_DEFAULT_REPLY *reply_frame); -void mpt_set_config_regs(struct mpt_softc *); int mpt_issue_cfg_req(struct mpt_softc */*mpt*/, request_t */*req*/, cfgparms_t *params, bus_addr_t /*addr*/, bus_size_t/*len*/, @@ -1331,6 +1324,5 @@ char *mpt_ioc_diag(uint32_t diag); void mpt_req_state(mpt_req_state_t state); void mpt_print_config_request(void *vmsg); void mpt_print_request(void *vmsg); -void mpt_print_scsi_io_request(MSG_SCSI_IO_REQUEST *msg); void mpt_dump_sgl(SGE_IO_UNION *se, int offset); #endif /* _MPT_H_ */ diff --git a/sys/dev/mpt/mpt_cam.c b/sys/dev/mpt/mpt_cam.c index 1b997d155a2d9..d512458c7582b 100644 --- a/sys/dev/mpt/mpt_cam.c +++ b/sys/dev/mpt/mpt_cam.c @@ -193,7 +193,7 @@ MODULE_DEPEND(mpt_cam, cam, 1, 1, 1); int mpt_enable_sata_wc = -1; TUNABLE_INT("hw.mpt.enable_sata_wc", &mpt_enable_sata_wc); -int +static int mpt_cam_probe(struct mpt_softc *mpt) { int role; @@ -215,7 +215,7 @@ mpt_cam_probe(struct mpt_softc *mpt) return (ENODEV); } -int +static int mpt_cam_attach(struct mpt_softc *mpt) { struct cam_devq *devq; @@ -509,7 +509,6 @@ mpt_read_config_info_fc(struct mpt_softc *mpt) static int mpt_set_initial_config_fc(struct mpt_softc *mpt) { - CONFIG_PAGE_FC_PORT_1 fc; U32 fl; int r, doit = 0; @@ -881,8 +880,8 @@ static int mpt_sata_pass_reply_handler(struct mpt_softc *mpt, request_t *req, uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) { - if (req != NULL) { + if (req != NULL) { if (reply_frame != NULL) { req->IOCStatus = le16toh(reply_frame->IOCStatus); } @@ -1114,7 +1113,7 @@ mpt_set_initial_config_spi(struct mpt_softc *mpt) return (0); } -int +static int mpt_cam_enable(struct mpt_softc *mpt) { int error; @@ -1151,9 +1150,10 @@ out: return (error); } -void +static void mpt_cam_ready(struct mpt_softc *mpt) { + /* * If we're in target mode, hang out resources now * so we don't cause the world to hang talking to us. @@ -1171,7 +1171,7 @@ mpt_cam_ready(struct mpt_softc *mpt) mpt->ready = 1; } -void +static void mpt_cam_detach(struct mpt_softc *mpt) { mpt_handler_t handler; @@ -1842,8 +1842,6 @@ bad: memset(se, 0,sizeof (*se)); se->Address = htole32(dm_segs->ds_addr); - - MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len); tf = flags; if (seg == first_lim - 1) { @@ -1958,9 +1956,6 @@ bad: memset(se, 0, sizeof (*se)); se->Address = htole32(dm_segs->ds_addr); - - - MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len); tf = flags; if (seg == this_seg_lim - 1) { @@ -2543,7 +2538,8 @@ mpt_cam_event(struct mpt_softc *mpt, request_t *req, pqf->CurrentDepth = le16toh(pqf->CurrentDepth); mpt_prt(mpt, "QUEUE FULL EVENT: Bus 0x%02x Target 0x%02x Depth " "%d\n", pqf->Bus, pqf->TargetID, pqf->CurrentDepth); - if (mpt->phydisk_sim) { + if (mpt->phydisk_sim && mpt_is_raid_member(mpt, + pqf->TargetID) != 0) { sim = mpt->phydisk_sim; } else { sim = mpt->sim; @@ -2575,9 +2571,85 @@ mpt_cam_event(struct mpt_softc *mpt, request_t *req, mpt_prt(mpt, "IR resync update %d completed\n", (data0 >> 16) & 0xff); break; + case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: + { + union ccb *ccb; + struct cam_sim *sim; + struct cam_path *tmppath; + PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE psdsc; + + psdsc = (PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE)msg->Data; + if (mpt->phydisk_sim && mpt_is_raid_member(mpt, + psdsc->TargetID) != 0) + sim = mpt->phydisk_sim; + else + sim = mpt->sim; + switch(psdsc->ReasonCode) { + case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: + MPTLOCK_2_CAMLOCK(mpt); + ccb = xpt_alloc_ccb_nowait(); + if (ccb == NULL) { + mpt_prt(mpt, + "unable to alloc CCB for rescan\n"); + CAMLOCK_2_MPTLOCK(mpt); + break; + } + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, + cam_sim_path(sim), psdsc->TargetID, + CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + CAMLOCK_2_MPTLOCK(mpt); + mpt_prt(mpt, + "unable to create path for rescan\n"); + xpt_free_ccb(ccb); + break; + } + xpt_rescan(ccb); + CAMLOCK_2_MPTLOCK(mpt); + break; + case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: + MPTLOCK_2_CAMLOCK(mpt); + if (xpt_create_path(&tmppath, NULL, cam_sim_path(sim), + psdsc->TargetID, CAM_LUN_WILDCARD) != + CAM_REQ_CMP) { + mpt_prt(mpt, + "unable to create path for async event"); + CAMLOCK_2_MPTLOCK(mpt); + break; + } + xpt_async(AC_LOST_DEVICE, tmppath, NULL); + xpt_free_path(tmppath); + CAMLOCK_2_MPTLOCK(mpt); + break; + case MPI_EVENT_SAS_DEV_STAT_RC_CMPL_INTERNAL_DEV_RESET: + case MPI_EVENT_SAS_DEV_STAT_RC_CMPL_TASK_ABORT_INTERNAL: + case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: + break; + default: + mpt_lprt(mpt, MPT_PRT_WARN, + "SAS device status change: Bus: 0x%02x TargetID: " + "0x%02x ReasonCode: 0x%02x\n", psdsc->Bus, + psdsc->TargetID, psdsc->ReasonCode); + break; + } + break; + } + case MPI_EVENT_SAS_DISCOVERY_ERROR: + { + PTR_EVENT_DATA_DISCOVERY_ERROR pde; + + pde = (PTR_EVENT_DATA_DISCOVERY_ERROR)msg->Data; + pde->DiscoveryStatus = le32toh(pde->DiscoveryStatus); + mpt_lprt(mpt, MPT_PRT_WARN, + "SAS discovery error: Port: 0x%02x Status: 0x%08x\n", + pde->Port, pde->DiscoveryStatus); + break; + } case MPI_EVENT_EVENT_CHANGE: case MPI_EVENT_INTEGRATED_RAID: - case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: + case MPI_EVENT_IR2: + case MPI_EVENT_LOG_ENTRY_ADDED: + case MPI_EVENT_SAS_DISCOVERY: + case MPI_EVENT_SAS_PHY_LINK_STATUS: case MPI_EVENT_SAS_SES: break; default: @@ -3045,6 +3117,7 @@ mpt_fc_els_reply_handler(struct mpt_softc *mpt, request_t *req, static void mpt_cam_ioc_reset(struct mpt_softc *mpt, int type) { + /* * The pending list is already run down by * the generic handler. Perform the same @@ -3974,6 +4047,7 @@ mpt_spawn_recovery_thread(struct mpt_softc *mpt) static void mpt_terminate_recovery_thread(struct mpt_softc *mpt) { + if (mpt->recovery_thread == NULL) { return; } @@ -4377,6 +4451,7 @@ mpt_add_target_commands(struct mpt_softc *mpt) static int mpt_enable_lun(struct mpt_softc *mpt, target_id_t tgt, lun_id_t lun) { + if (tgt == CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) { mpt->twildcard = 1; } else if (lun >= MPT_MAX_LUNS) { @@ -4402,6 +4477,7 @@ static int mpt_disable_lun(struct mpt_softc *mpt, target_id_t tgt, lun_id_t lun) { int i; + if (tgt == CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) { mpt->twildcard = 0; } else if (lun >= MPT_MAX_LUNS) { @@ -5286,6 +5362,7 @@ mpt_tgt_dump_tgt_state(struct mpt_softc *mpt, request_t *req) static void mpt_tgt_dump_req_state(struct mpt_softc *mpt, request_t *req) { + mpt_prt(mpt, "req %p:%u index %u (%x) state %x\n", req, req->serno, req->index, req->index, req->state); mpt_tgt_dump_tgt_state(mpt, req); diff --git a/sys/dev/mpt/mpt_debug.c b/sys/dev/mpt/mpt_debug.c index e7f75faa5b456..dd70dc9d8160a 100644 --- a/sys/dev/mpt/mpt_debug.c +++ b/sys/dev/mpt/mpt_debug.c @@ -285,6 +285,7 @@ mpt_scsi_state(int code) } return buf; } + static char * mpt_scsi_status(int code) { @@ -298,10 +299,11 @@ mpt_scsi_status(int code) snprintf(buf, sizeof buf, "Unknown (0x%08x)", code); return buf; } -static char * + +static const char * mpt_who(int who_init) { - char *who; + const char *who; switch (who_init) { case MPT_DB_INIT_NOONE: who = "No One"; break; @@ -315,10 +317,10 @@ mpt_who(int who_init) return who; } -static char * +static const char * mpt_state(u_int32_t mb) { - char *text; + const char *text; switch (MPT_STATE(mb)) { case MPT_DB_STATE_RESET: text = "Reset"; break; @@ -347,6 +349,7 @@ mpt_scsi_tm_type(int code) void mpt_print_db(u_int32_t mb) { + printf("mpt mailbox: (0x%x) State %s WhoInit %s\n", mb, mpt_state(mb), mpt_who(MPT_WHO(mb))); } @@ -357,6 +360,7 @@ mpt_print_db(u_int32_t mb) static void mpt_print_reply_hdr(MSG_DEFAULT_REPLY *msg) { + printf("%s Reply @ %p\n", mpt_ioc_function(msg->Function), msg); printf("\tIOC Status %s\n", mpt_ioc_status(msg->IOCStatus)); printf("\tIOCLogInfo 0x%08x\n", msg->IOCLogInfo); @@ -368,6 +372,7 @@ mpt_print_reply_hdr(MSG_DEFAULT_REPLY *msg) static void mpt_print_init_reply(MSG_IOC_INIT_REPLY *msg) { + mpt_print_reply_hdr((MSG_DEFAULT_REPLY *)msg); printf("\tWhoInit %s\n", mpt_who(msg->WhoInit)); printf("\tMaxDevices 0x%02x\n", msg->MaxDevices); @@ -377,6 +382,7 @@ mpt_print_init_reply(MSG_IOC_INIT_REPLY *msg) static void mpt_print_ioc_facts(MSG_IOC_FACTS_REPLY *msg) { + mpt_print_reply_hdr((MSG_DEFAULT_REPLY *)msg); printf("\tIOCNumber %d\n", msg->IOCNumber); printf("\tMaxChainDepth %d\n", msg->MaxChainDepth); @@ -402,6 +408,7 @@ mpt_print_ioc_facts(MSG_IOC_FACTS_REPLY *msg) static void mpt_print_enable_reply(MSG_PORT_ENABLE_REPLY *msg) { + mpt_print_reply_hdr((MSG_DEFAULT_REPLY *)msg); printf("\tPort: %d\n", msg->PortNumber); } @@ -409,6 +416,7 @@ mpt_print_enable_reply(MSG_PORT_ENABLE_REPLY *msg) static void mpt_print_scsi_io_reply(MSG_SCSI_IO_REPLY *msg) { + mpt_print_reply_hdr((MSG_DEFAULT_REPLY *)msg); printf("\tBus: %d\n", msg->Bus); printf("\tTargetID %d\n", msg->TargetID); @@ -420,11 +428,10 @@ mpt_print_scsi_io_reply(MSG_SCSI_IO_REPLY *msg) printf("\tResponseInfo 0x%08x\n", msg->ResponseInfo); } - - static void mpt_print_event_notice(MSG_EVENT_NOTIFY_REPLY *msg) { + mpt_print_reply_hdr((MSG_DEFAULT_REPLY *)msg); printf("\tEvent: %s\n", mpt_ioc_event(msg->Event)); printf("\tEventContext 0x%04x\n", msg->EventContext); @@ -517,7 +524,7 @@ mpt_print_request_hdr(MSG_REQUEST_HEADER *req) printf("\tMsgContext 0x%08x\n", req->MsgContext); } -void +static void mpt_print_scsi_io_request(MSG_SCSI_IO_REQUEST *orig_msg) { MSG_SCSI_IO_REQUEST local, *msg = &local; @@ -575,6 +582,7 @@ mpt_print_scsi_io_request(MSG_SCSI_IO_REQUEST *orig_msg) static void mpt_print_scsi_tmf_request(MSG_SCSI_TASK_MGMT *msg) { + mpt_print_request_hdr((MSG_REQUEST_HEADER *)msg); printf("\tLun 0x%02x\n", msg->LUN[1]); printf("\tTaskType %s\n", mpt_scsi_tm_type(msg->TaskType)); @@ -585,6 +593,7 @@ mpt_print_scsi_tmf_request(MSG_SCSI_TASK_MGMT *msg) static void mpt_print_scsi_target_assist_request(PTR_MSG_TARGET_ASSIST_REQUEST msg) { + mpt_print_request_hdr((MSG_REQUEST_HEADER *)msg); printf("\tStatusCode 0x%02x\n", msg->StatusCode); printf("\tTargetAssist 0x%02x\n", msg->TargetAssistFlags); @@ -600,6 +609,7 @@ static void mpt_print_scsi_target_status_send_request(MSG_TARGET_STATUS_SEND_REQUEST *msg) { SGE_IO_UNION x; + mpt_print_request_hdr((MSG_REQUEST_HEADER *)msg); printf("\tStatusCode 0x%02x\n", msg->StatusCode); printf("\tStatusFlags 0x%02x\n", msg->StatusFlags); @@ -637,7 +647,14 @@ mpt_print_request(void *vreq) } } -int +#if 0 +typedef struct mpt_decode_entry { + char *name; + u_int value; + u_int mask; +} mpt_decode_entry_t; + +static int mpt_decode_value(mpt_decode_entry_t *table, u_int num_entries, const char *name, u_int value, u_int *cur_column, u_int wrap_point) @@ -689,7 +706,7 @@ mpt_decode_value(mpt_decode_entry_t *table, u_int num_entries, return (printed); } -static mpt_decode_entry_t req_state_parse_table[] = { +static const mpt_decode_entry_t req_state_parse_table[] = { { "REQ_FREE", 0x00, 0xff }, { "REQ_ALLOCATED", 0x01, 0x01 }, { "REQ_QUEUED", 0x02, 0x02 }, @@ -698,13 +715,15 @@ static mpt_decode_entry_t req_state_parse_table[] = { { "REQ_NEED_WAKEUP", 0x10, 0x10 } }; -void +static void mpt_req_state(mpt_req_state_t state) { + mpt_decode_value(req_state_parse_table, NUM_ELEMENTS(req_state_parse_table), "REQ_STATE", state, NULL, 80); } +#endif #define LAST_SGE ( \ MPI_SGE_FLAGS_END_OF_LIST | \ @@ -805,6 +824,7 @@ mpt_dump_data(struct mpt_softc *mpt, const char *msg, void *addr, int len) { int offset; uint8_t *cp = addr; + mpt_prt(mpt, "%s:", msg); for (offset = 0; offset < len; offset++) { if ((offset & 0xf) == 0) { @@ -820,6 +840,7 @@ mpt_dump_request(struct mpt_softc *mpt, request_t *req) { uint32_t *pReq = req->req_vbuf; int o; + #if __FreeBSD_version >= 500000 mpt_prt(mpt, "Send Request %d (%jx):", req->index, (uintmax_t) req->req_pbuf); @@ -850,6 +871,7 @@ mpt_lprt(struct mpt_softc *mpt, int level, const char *fmt, ...) } } +#if 0 void mpt_lprtc(struct mpt_softc *mpt, int level, const char *fmt, ...) { @@ -861,6 +883,7 @@ mpt_lprtc(struct mpt_softc *mpt, int level, const char *fmt, ...) } } #endif +#endif void mpt_prt(struct mpt_softc *mpt, const char *fmt, ...) diff --git a/sys/dev/mpt/mpt_pci.c b/sys/dev/mpt/mpt_pci.c index f7201b613e6af..7e3211b4722e7 100644 --- a/sys/dev/mpt/mpt_pci.c +++ b/sys/dev/mpt/mpt_pci.c @@ -201,6 +201,9 @@ static int mpt_pci_shutdown(device_t); static int mpt_dma_mem_alloc(struct mpt_softc *mpt); static void mpt_dma_mem_free(struct mpt_softc *mpt); static void mpt_read_config_regs(struct mpt_softc *mpt); +#if 0 +static void mpt_set_config_regs(struct mpt_softc *mpt); +#endif static void mpt_pci_intr(void *); static device_method_t mpt_methods[] = { @@ -404,6 +407,7 @@ mpt_link_peer(struct mpt_softc *mpt) static void mpt_unlink_peer(struct mpt_softc *mpt) { + if (mpt->mpt2) { mpt->mpt2->mpt2 = NULL; } @@ -654,6 +658,7 @@ bad: static void mpt_free_bus_resources(struct mpt_softc *mpt) { + if (mpt->ih) { bus_teardown_intr(mpt->dev, mpt->pci_irq, mpt->ih); mpt->ih = NULL; @@ -827,6 +832,7 @@ mpt_dma_mem_free(struct mpt_softc *mpt) static void mpt_read_config_regs(struct mpt_softc *mpt) { + mpt->pci_cfg.Command = pci_read_config(mpt->dev, PCIR_COMMAND, 2); mpt->pci_cfg.LatencyTimer_LineSize = pci_read_config(mpt->dev, PCIR_CACHELNSZ, 2); @@ -840,8 +846,9 @@ mpt_read_config_regs(struct mpt_softc *mpt) mpt->pci_cfg.PMCSR = pci_read_config(mpt->dev, 0x44, 4); } +#if 0 /* Sets modifiable config registers */ -void +static void mpt_set_config_regs(struct mpt_softc *mpt) { uint32_t val; @@ -880,6 +887,7 @@ mpt_set_config_regs(struct mpt_softc *mpt) pci_write_config(mpt->dev, PCIR_INTLINE, mpt->pci_cfg.IntLine, 1); pci_write_config(mpt->dev, 0x44, mpt->pci_cfg.PMCSR, 4); } +#endif static void mpt_pci_intr(void *arg) diff --git a/sys/dev/mpt/mpt_raid.c b/sys/dev/mpt/mpt_raid.c index 11650ed7f7c5a..8000a0103ed1d 100644 --- a/sys/dev/mpt/mpt_raid.c +++ b/sys/dev/mpt/mpt_raid.c @@ -81,7 +81,6 @@ struct mpt_raid_action_result #define REQ_IOCSTATUS(req) ((req)->IOCStatus & MPI_IOCSTATUS_MASK) - static mpt_probe_handler_t mpt_raid_probe; static mpt_attach_handler_t mpt_raid_attach; static mpt_enable_handler_t mpt_raid_enable; @@ -125,9 +124,25 @@ static void mpt_adjust_queue_depth(struct mpt_softc *, struct mpt_raid_volume *, static void mpt_raid_sysctl_attach(struct mpt_softc *); #endif +static const char *mpt_vol_type(struct mpt_raid_volume *vol); +static const char *mpt_vol_state(struct mpt_raid_volume *vol); +static const char *mpt_disk_state(struct mpt_raid_disk *disk); +static void mpt_vol_prt(struct mpt_softc *mpt, struct mpt_raid_volume *vol, + const char *fmt, ...); +static void mpt_disk_prt(struct mpt_softc *mpt, struct mpt_raid_disk *disk, + const char *fmt, ...); + +static int mpt_issue_raid_req(struct mpt_softc *mpt, + struct mpt_raid_volume *vol, struct mpt_raid_disk *disk, request_t *req, + u_int Action, uint32_t ActionDataWord, bus_addr_t addr, bus_size_t len, + int write, int wait); + +static int mpt_refresh_raid_data(struct mpt_softc *mpt); +static void mpt_schedule_raid_refresh(struct mpt_softc *mpt); + static uint32_t raid_handler_id = MPT_HANDLER_ID_NONE; -const char * +static const char * mpt_vol_type(struct mpt_raid_volume *vol) { switch (vol->config_page->VolumeType) { @@ -142,7 +157,7 @@ mpt_vol_type(struct mpt_raid_volume *vol) } } -const char * +static const char * mpt_vol_state(struct mpt_raid_volume *vol) { switch (vol->config_page->VolumeStatus.State) { @@ -157,7 +172,7 @@ mpt_vol_state(struct mpt_raid_volume *vol) } } -const char * +static const char * mpt_disk_state(struct mpt_raid_disk *disk) { switch (disk->config_page.PhysDiskStatus.State) { @@ -182,7 +197,7 @@ mpt_disk_state(struct mpt_raid_disk *disk) } } -void +static void mpt_vol_prt(struct mpt_softc *mpt, struct mpt_raid_volume *vol, const char *fmt, ...) { @@ -196,7 +211,7 @@ mpt_vol_prt(struct mpt_softc *mpt, struct mpt_raid_volume *vol, va_end(ap); } -void +static void mpt_disk_prt(struct mpt_softc *mpt, struct mpt_raid_disk *disk, const char *fmt, ...) { @@ -254,16 +269,17 @@ mpt_raid_async(void *callback_arg, u_int32_t code, } } -int +static int mpt_raid_probe(struct mpt_softc *mpt) { + if (mpt->ioc_page2 == NULL || mpt->ioc_page2->MaxPhysDisks == 0) { return (ENODEV); } return (0); } -int +static int mpt_raid_attach(struct mpt_softc *mpt) { struct ccb_setasync csa; @@ -307,13 +323,14 @@ cleanup: return (error); } -int +static int mpt_raid_enable(struct mpt_softc *mpt) { + return (0); } -void +static void mpt_raid_detach(struct mpt_softc *mpt) { struct ccb_setasync csa; @@ -338,6 +355,7 @@ mpt_raid_detach(struct mpt_softc *mpt) static void mpt_raid_ioc_reset(struct mpt_softc *mpt, int type) { + /* Nothing to do yet. */ } @@ -570,7 +588,7 @@ mpt_raid_reply_frame_handler(struct mpt_softc *mpt, request_t *req, /* * Utiltity routine to perform a RAID action command; */ -int +static int mpt_issue_raid_req(struct mpt_softc *mpt, struct mpt_raid_volume *vol, struct mpt_raid_disk *disk, request_t *req, u_int Action, uint32_t ActionDataWord, bus_addr_t addr, bus_size_t len, @@ -719,6 +737,7 @@ mpt_raid_thread(void *arg) static void mpt_raid_quiesce_timeout(void *arg) { + /* Complete the CCB with error */ /* COWWWW */ } @@ -776,7 +795,7 @@ mpt_raid_quiesce_disk(struct mpt_softc *mpt, struct mpt_raid_disk *mpt_disk, /* XXX Ignores that there may be multiple busses/IOCs involved. */ cam_status -mpt_map_physdisk(struct mpt_softc *mpt, union ccb *ccb, u_int *tgt) +mpt_map_physdisk(struct mpt_softc *mpt, union ccb *ccb, target_id_t *tgt) { struct mpt_raid_disk *mpt_disk; @@ -793,7 +812,26 @@ mpt_map_physdisk(struct mpt_softc *mpt, union ccb *ccb, u_int *tgt) /* XXX Ignores that there may be multiple busses/IOCs involved. */ int -mpt_is_raid_volume(struct mpt_softc *mpt, int tgt) +mpt_is_raid_member(struct mpt_softc *mpt, target_id_t tgt) +{ + struct mpt_raid_disk *mpt_disk; + int i; + + if (mpt->ioc_page2 == NULL || mpt->ioc_page2->MaxPhysDisks == 0) + return (0); + for (i = 0; i < mpt->ioc_page2->MaxPhysDisks; i++) { + mpt_disk = &mpt->raid_disks[i]; + if ((mpt_disk->flags & MPT_RDF_ACTIVE) != 0 && + mpt_disk->config_page.PhysDiskID == tgt) + return (1); + } + return (0); + +} + +/* XXX Ignores that there may be multiple busses/IOCs involved. */ +int +mpt_is_raid_volume(struct mpt_softc *mpt, target_id_t tgt) { CONFIG_PAGE_IOC_2_RAID_VOL *ioc_vol; CONFIG_PAGE_IOC_2_RAID_VOL *ioc_last_vol; @@ -1305,7 +1343,7 @@ mpt_refresh_raid_vol(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol, * be updated by our event handler. Interesting changes are displayed * to the console. */ -int +static int mpt_refresh_raid_data(struct mpt_softc *mpt) { CONFIG_PAGE_IOC_2_RAID_VOL *ioc_vol; @@ -1565,9 +1603,10 @@ mpt_raid_timer(void *arg) #endif } -void +static void mpt_schedule_raid_refresh(struct mpt_softc *mpt) { + callout_reset(&mpt->raid_timer, MPT_RAID_SYNC_REPORT_INTERVAL, mpt_raid_timer, mpt); } @@ -1719,7 +1758,8 @@ mpt_raid_set_vol_mwce(struct mpt_softc *mpt, mpt_raid_mwce_t mwce) MPT_UNLOCK(mpt); return (0); } -const char *mpt_vol_mwce_strs[] = + +static const char *mpt_vol_mwce_strs[] = { "On", "Off", diff --git a/sys/dev/mpt/mpt_raid.h b/sys/dev/mpt/mpt_raid.h index bc5aa7dd9fe2c..2047707b155ca 100644 --- a/sys/dev/mpt/mpt_raid.h +++ b/sys/dev/mpt/mpt_raid.h @@ -53,29 +53,14 @@ typedef enum { MPT_RAID_MWCE_NC } mpt_raid_mwce_t; -const char *mpt_vol_type(struct mpt_raid_volume *); -const char *mpt_vol_state(struct mpt_raid_volume *); -const char *mpt_disk_state(struct mpt_raid_disk *); -void -mpt_vol_prt(struct mpt_softc *, struct mpt_raid_volume *, const char *fmt, ...); -void -mpt_disk_prt(struct mpt_softc *, struct mpt_raid_disk *, const char *, ...); - -int -mpt_issue_raid_req(struct mpt_softc *, struct mpt_raid_volume *, - struct mpt_raid_disk *, request_t *, u_int, uint32_t, bus_addr_t, - bus_size_t, int, int); - -cam_status -mpt_map_physdisk(struct mpt_softc *, union ccb *, target_id_t *); -int mpt_is_raid_volume(struct mpt_softc *, int); +cam_status mpt_map_physdisk(struct mpt_softc *, union ccb *, target_id_t *); +int mpt_is_raid_member(struct mpt_softc *, target_id_t); +int mpt_is_raid_volume(struct mpt_softc *, target_id_t); #if 0 cam_status mpt_raid_quiesce_disk(struct mpt_softc *, struct mpt_raid_disk *, request_t *); #endif -int mpt_refresh_raid_data(struct mpt_softc *); -void mpt_schedule_raid_refresh(struct mpt_softc *); void mpt_raid_free_mem(struct mpt_softc *); static __inline void diff --git a/sys/dev/mpt/mpt_user.c b/sys/dev/mpt/mpt_user.c index e6a9d1f5e6058..78762c7511848 100644 --- a/sys/dev/mpt/mpt_user.c +++ b/sys/dev/mpt/mpt_user.c @@ -94,7 +94,7 @@ static MALLOC_DEFINE(M_MPTUSER, "mpt_user", "Buffers for mpt(4) ioctls"); static uint32_t user_handler_id = MPT_HANDLER_ID_NONE; -int +static int mpt_user_probe(struct mpt_softc *mpt) { @@ -102,7 +102,7 @@ mpt_user_probe(struct mpt_softc *mpt) return (0); } -int +static int mpt_user_attach(struct mpt_softc *mpt) { mpt_handler_t handler; @@ -131,19 +131,20 @@ mpt_user_attach(struct mpt_softc *mpt) return (0); } -int +static int mpt_user_enable(struct mpt_softc *mpt) { return (0); } -void +static void mpt_user_ready(struct mpt_softc *mpt) { + } -int +static int mpt_user_event(struct mpt_softc *mpt, request_t *req, MSG_EVENT_NOTIFY_REPLY *msg) { @@ -152,12 +153,13 @@ mpt_user_event(struct mpt_softc *mpt, request_t *req, return (0); } -void +static void mpt_user_reset(struct mpt_softc *mpt, int type) { + } -void +static void mpt_user_detach(struct mpt_softc *mpt) { mpt_handler_t handler; diff --git a/sys/dev/ofw/ofw_console.c b/sys/dev/ofw/ofw_console.c index fd280c97fc894..62dbe51e87e00 100644 --- a/sys/dev/ofw/ofw_console.c +++ b/sys/dev/ofw/ofw_console.c @@ -26,7 +26,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_comconsole.h" #include "opt_ofw.h" #include <sys/param.h> @@ -64,7 +63,7 @@ static int polltime; static struct callout_handle ofw_timeouthandle = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle); -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) +#if defined(KDB) static int alt_break_state; #endif @@ -199,24 +198,8 @@ ofw_cngetc(struct consdev *cp) unsigned char ch; if (OF_read(stdin, &ch, 1) > 0) { -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) - int kdb_brk; - - if ((kdb_brk = kdb_alt_break(ch, &alt_break_state)) != 0) { - switch (kdb_brk) { - case KDB_REQ_DEBUGGER: - kdb_enter(KDB_WHY_BREAK, - "Break sequence on console"); - break; - case KDB_REQ_PANIC: - kdb_panic("Panic sequence on console"); - break; - case KDB_REQ_REBOOT: - kdb_reboot(); - break; - - } - } +#if defined(KDB) + kdb_alt_break(ch, &alt_break_state); #endif return (ch); } diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 7eb84e6e5ee39..9ebb8486913cf 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include <dev/pci/pcivar.h> #include <dev/pci/pci_private.h> +#include <dev/usb/controller/xhcireg.h> #include <dev/usb/controller/ehcireg.h> #include <dev/usb/controller/ohcireg.h> #include <dev/usb/controller/uhcireg.h> @@ -2956,6 +2957,68 @@ ehci_early_takeover(device_t self) bus_release_resource(self, SYS_RES_MEMORY, rid, res); } +/* Perform early XHCI takeover from SMM. */ +static void +xhci_early_takeover(device_t self) +{ + struct resource *res; + uint32_t cparams; + uint32_t eec; + uint8_t eecp; + uint8_t bios_sem; + uint8_t offs; + int rid; + int i; + + rid = PCIR_BAR(0); + res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (res == NULL) + return; + + cparams = bus_read_4(res, XHCI_HCSPARAMS0); + + eec = -1; + + /* Synchronise with the BIOS if it owns the controller. */ + for (eecp = XHCI_HCS0_XECP(cparams) << 2; eecp != 0 && XHCI_XECP_NEXT(eec); + eecp += XHCI_XECP_NEXT(eec) << 2) { + eec = bus_read_4(res, eecp); + + if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) + continue; + + bios_sem = bus_read_1(res, eecp + XHCI_XECP_BIOS_SEM); + if (bios_sem == 0) + continue; + + if (bootverbose) + printf("xhci early: " + "SMM active, request owner change\n"); + + bus_write_1(res, eecp + XHCI_XECP_OS_SEM, 1); + + /* wait a maximum of 5 second */ + + for (i = 0; (i < 5000) && (bios_sem != 0); i++) { + DELAY(1000); + bios_sem = bus_read_1(res, eecp + + XHCI_XECP_BIOS_SEM); + } + + if (bios_sem != 0) { + if (bootverbose) + printf("xhci early: " + "SMM does not respond\n"); + } + + /* Disable interrupts */ + offs = bus_read_1(res, XHCI_CAPLENGTH); + bus_write_4(res, offs + XHCI_USBCMD, 0); + bus_read_4(res, offs + XHCI_USBSTS); + } + bus_release_resource(self, SYS_RES_MEMORY, rid, res); +} + void pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask) { @@ -3002,7 +3065,9 @@ pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask) if (pci_usb_takeover && pci_get_class(dev) == PCIC_SERIALBUS && pci_get_subclass(dev) == PCIS_SERIALBUS_USB) { - if (pci_get_progif(dev) == PCIP_SERIALBUS_USB_EHCI) + if (pci_get_progif(dev) == PCIP_SERIALBUS_USB_XHCI) + xhci_early_takeover(dev); + else if (pci_get_progif(dev) == PCIP_SERIALBUS_USB_EHCI) ehci_early_takeover(dev); else if (pci_get_progif(dev) == PCIP_SERIALBUS_USB_OHCI) ohci_early_takeover(dev); diff --git a/sys/dev/puc/pucdata.c b/sys/dev/puc/pucdata.c index 2b38d9b171efe..f675b69b661ae 100644 --- a/sys/dev/puc/pucdata.c +++ b/sys/dev/puc/pucdata.c @@ -524,6 +524,12 @@ const struct puc_cfg puc_pci_devices[] = { PUC_PORT_4S, 0x18, 0, 8, }, + { 0x1393, 0x1120, 0xffff, 0, + "Moxa Technologies, CP-112UL", + DEFAULT_RCLK * 8, + PUC_PORT_2S, 0x18, 0, 8, + }, + { 0x1393, 0x1141, 0xffff, 0, "Moxa Technologies, Industio CP-114", DEFAULT_RCLK * 8, diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c index 37dd62fa61778..3c45cc97d9c6e 100644 --- a/sys/dev/re/if_re.c +++ b/sys/dev/re/if_re.c @@ -174,6 +174,8 @@ TUNABLE_INT("hw.re.prefer_iomap", &prefer_iomap); static struct rl_type re_devs[] = { { DLINK_VENDORID, DLINK_DEVICEID_528T, 0, "D-Link DGE-528(T) Gigabit Ethernet Adapter" }, + { DLINK_VENDORID, DLINK_DEVICEID_530T_REVC, 0, + "D-Link DGE-530(T) Gigabit Ethernet Adapter" }, { RT_VENDORID, RT_DEVICEID_8139, 0, "RealTek 8139C+ 10/100BaseTX" }, { RT_VENDORID, RT_DEVICEID_8101E, 0, diff --git a/sys/dev/sio/sio.c b/sys/dev/sio/sio.c index f1348c4c35760..7e2054e2070c6 100644 --- a/sys/dev/sio/sio.c +++ b/sys/dev/sio/sio.c @@ -33,7 +33,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_comconsole.h" #include "opt_compat.h" #include "opt_gdb.h" #include "opt_kdb.h" @@ -228,7 +227,7 @@ struct com_s { struct pps_state pps; int pps_bit; -#ifdef ALT_BREAK_TO_DEBUGGER +#ifdef KDB int alt_brk_state; #endif @@ -1102,8 +1101,7 @@ determined_type: ; } if (ret) device_printf(dev, "could not activate interrupt\n"); -#if defined(KDB) && (defined(BREAK_TO_DEBUGGER) || \ - defined(ALT_BREAK_TO_DEBUGGER)) +#if defined(KDB) /* * Enable interrupts for early break-to-debugger support * on the console. @@ -1196,8 +1194,7 @@ comclose(tp) com->poll_output = FALSE; sio_setreg(com, com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); -#if defined(KDB) && (defined(BREAK_TO_DEBUGGER) || \ - defined(ALT_BREAK_TO_DEBUGGER)) +#if defined(KDB) /* * Leave interrupts enabled and don't clear DTR if this is the * console. This allows us to detect break-to-debugger events @@ -1483,9 +1480,8 @@ siointr1(com) u_char modem_status; u_char *ioptr; u_char recv_data; -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) - int kdb_brk; +#ifdef KDB again: #endif @@ -1518,27 +1514,9 @@ again: else recv_data = inb(com->data_port); #ifdef KDB -#ifdef ALT_BREAK_TO_DEBUGGER if (com->unit == comconsole && - (kdb_brk = kdb_alt_break(recv_data, - &com->alt_brk_state)) != 0) { - mtx_unlock_spin(&sio_lock); - switch (kdb_brk) { - case KDB_REQ_DEBUGGER: - kdb_enter(KDB_WHY_BREAK, - "Break sequence on console"); - break; - case KDB_REQ_PANIC: - kdb_panic("panic on console"); - break; - case KDB_REQ_REBOOT: - kdb_reboot(); - break; - } - mtx_lock_spin(&sio_lock); + kdb_alt_break(recv_data, &com->alt_brk_state) != 0) goto again; - } -#endif /* ALT_BREAK_TO_DEBUGGER */ #endif /* KDB */ if (line_status & (LSR_BI | LSR_FE | LSR_PE)) { /* @@ -1554,10 +1532,9 @@ again: * Note: BI together with FE/PE means just BI. */ if (line_status & LSR_BI) { -#if defined(KDB) && defined(BREAK_TO_DEBUGGER) +#if defined(KDB) if (com->unit == comconsole) { - kdb_enter(KDB_WHY_BREAK, - "Line break on console"); + kdb_break(); goto cont; } #endif diff --git a/sys/dev/smc/if_smc.c b/sys/dev/smc/if_smc.c index 22f8bab9e822b..4aa0396fbe88c 100644 --- a/sys/dev/smc/if_smc.c +++ b/sys/dev/smc/if_smc.c @@ -538,6 +538,7 @@ smc_task_tx(void *context, int pending) struct smc_softc *sc; struct mbuf *m, *m0; u_int packet, len; + int last_len; uint8_t *data; (void)pending; @@ -590,16 +591,18 @@ smc_task_tx(void *context, int pending) * Push the data out to the device. */ data = NULL; + last_len = 0; for (; m != NULL; m = m->m_next) { data = mtod(m, uint8_t *); smc_write_multi_2(sc, DATA0, (uint16_t *)data, m->m_len / 2); + last_len = m->m_len; } /* * Push out the control byte and and the odd byte if needed. */ if ((len & 1) != 0 && data != NULL) - smc_write_2(sc, DATA0, (CTRL_ODD << 8) | data[m->m_len - 1]); + smc_write_2(sc, DATA0, (CTRL_ODD << 8) | data[last_len - 1]); else smc_write_2(sc, DATA0, 0); diff --git a/sys/dev/snp/snp.c b/sys/dev/snp/snp.c index b05ad2a81b968..1c02660bec1db 100644 --- a/sys/dev/snp/snp.c +++ b/sys/dev/snp/snp.c @@ -252,6 +252,9 @@ snp_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, SNP_UNLOCK(); return (EBUSY); } + /* + * XXXRW / XXXJA: no capability check here. + */ error = ttyhook_register(&ss->snp_tty, td->td_proc, *(int *)data, &snp_hook, ss); SNP_UNLOCK(); diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c index bb0f3851437ab..66aa162dc3920 100644 --- a/sys/dev/sound/pci/hda/hdac.c +++ b/sys/dev/sound/pci/hda/hdac.c @@ -295,6 +295,7 @@ SND_DECLARE_FILE("$FreeBSD$"); #define LENOVO_VENDORID 0x17aa #define LENOVO_3KN100_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x2066) #define LENOVO_3KN200_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x384e) +#define LENOVO_B450_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x3a0d) #define LENOVO_TCA55_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0x1015) #define LENOVO_ALL_SUBVENDOR HDA_MODEL_CONSTRUCT(LENOVO, 0xffff) @@ -2582,6 +2583,13 @@ hdac_widget_pin_getconfig(struct hdac_widget *w) break; } } + } else if (id == HDA_CODEC_CX20561 && + sc->pci_subvendor == LENOVO_B450_SUBVENDOR) { + switch (nid) { + case 22: + patch = "as=1 seq=15"; + break; + } } if (patch != NULL) diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c index 1d52cbe3c7d11..2cfc1701d3502 100644 --- a/sys/dev/sound/pcm/dsp.c +++ b/sys/dev/sound/pcm/dsp.c @@ -1062,7 +1062,8 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, { struct pcm_channel *chn, *rdch, *wrch; struct snddev_info *d; - int *arg_i, ret, tmp, xcmd; + u_long xcmd; + int *arg_i, ret, tmp; d = dsp_get_info(i_dev); if (!DSP_REGISTERED(d, i_dev)) diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c index 565022c228be8..955b4c5c3e9a9 100644 --- a/sys/dev/sound/usb/uaudio.c +++ b/sys/dev/sound/usb/uaudio.c @@ -927,8 +927,8 @@ uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev, continue; } if (asf1d->bLength < (sizeof(*asf1d) + - (asf1d->bSamFreqType == 0) ? 6 : - (asf1d->bSamFreqType * 3))) { + ((asf1d->bSamFreqType == 0) ? 6 : + (asf1d->bSamFreqType * 3)))) { DPRINTFN(11, "'asf1d' descriptor is too short\n"); asf1d = NULL; continue; diff --git a/sys/dev/streams/streams.c b/sys/dev/streams/streams.c index 00f65a3907c27..ad2817f5ca669 100644 --- a/sys/dev/streams/streams.c +++ b/sys/dev/streams/streams.c @@ -95,7 +95,9 @@ static struct fileops svr4_netops = { .fo_poll = soo_poll, .fo_kqfilter = soo_kqfilter, .fo_stat = soo_stat, - .fo_close = svr4_soo_close + .fo_close = svr4_soo_close, + .fo_chmod = invfo_chmod, + .fo_chown = invfo_chown, }; static struct cdevsw streams_cdevsw = { diff --git a/sys/dev/syscons/syscons.c b/sys/dev/syscons/syscons.c index 69d628e877459..b8f328ee34c3c 100644 --- a/sys/dev/syscons/syscons.c +++ b/sys/dev/syscons/syscons.c @@ -3514,7 +3514,7 @@ next_code: case DBG: #ifndef SC_DISABLE_KDBKEY if (enable_kdbkey) - kdb_enter(KDB_WHY_BREAK, "manual escape to debugger"); + kdb_break(); #endif break; @@ -3562,6 +3562,10 @@ next_code: /* goto next_code */ } else { /* regular keys (maybe MKEY is set) */ +#if !defined(SC_DISABLE_KDBKEY) && defined(KDB) + if (enable_kdbkey) + kdb_alt_break(c, &sc->sc_altbrk); +#endif if (!(sc->flags & SC_SCRN_BLANKED)) return c; } diff --git a/sys/dev/syscons/syscons.h b/sys/dev/syscons/syscons.h index a23f88474a30d..79f531bd47a12 100644 --- a/sys/dev/syscons/syscons.h +++ b/sys/dev/syscons/syscons.h @@ -266,6 +266,9 @@ typedef struct sc_softc { u_char cursor_char; u_char mouse_char; +#ifdef KDB + int sc_altbrk; +#endif } sc_softc_t; /* virtual screen */ diff --git a/sys/dev/tdfx/tdfx_linux.c b/sys/dev/tdfx/tdfx_linux.c index 2e877f6d0173d..0b769f01a2412 100644 --- a/sys/dev/tdfx/tdfx_linux.c +++ b/sys/dev/tdfx/tdfx_linux.c @@ -28,6 +28,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/capability.h> #include <sys/file.h> #include <sys/kernel.h> #include <sys/module.h> @@ -53,7 +54,7 @@ linux_ioctl_tdfx(struct thread *td, struct linux_ioctl_args* args) struct file *fp; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); /* We simply copy the data and send it right to ioctl */ copyin((caddr_t)args->arg, &d_pio, sizeof(d_pio)); diff --git a/sys/dev/uart/uart_core.c b/sys/dev/uart/uart_core.c index 38d2a8f737734..9260d063b9903 100644 --- a/sys/dev/uart/uart_core.c +++ b/sys/dev/uart/uart_core.c @@ -27,10 +27,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#ifndef KLD_MODULE -#include "opt_comconsole.h" -#endif - #include <sys/param.h> #include <sys/systm.h> #include <sys/bus.h> @@ -118,10 +114,10 @@ uart_intr_break(void *arg) { struct uart_softc *sc = arg; -#if defined(KDB) && defined(BREAK_TO_DEBUGGER) +#if defined(KDB) if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) { - kdb_enter(KDB_WHY_BREAK, "Line break on console"); - return (0); + if (kdb_break()) + return (0); } #endif if (sc->sc_opened) @@ -170,26 +166,10 @@ uart_intr_rxready(void *arg) rxp = sc->sc_rxput; UART_RECEIVE(sc); -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) +#if defined(KDB) if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) { while (rxp != sc->sc_rxput) { - int kdb_brk; - - if ((kdb_brk = kdb_alt_break(sc->sc_rxbuf[rxp++], - &sc->sc_altbrk)) != 0) { - switch (kdb_brk) { - case KDB_REQ_DEBUGGER: - kdb_enter(KDB_WHY_BREAK, - "Break sequence on console"); - break; - case KDB_REQ_PANIC: - kdb_panic("Panic sequence on console"); - break; - case KDB_REQ_REBOOT: - kdb_reboot(); - break; - } - } + kdb_alt_break(sc->sc_rxbuf[rxp++], &sc->sc_altbrk); if (rxp == sc->sc_rxbufsz) rxp = 0; } diff --git a/sys/dev/usb/input/ums.c b/sys/dev/usb/input/ums.c index 3c4f36e21ab0e..12d9e89a2eb20 100644 --- a/sys/dev/usb/input/ums.c +++ b/sys/dev/usb/input/ums.c @@ -367,7 +367,9 @@ ums_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); void *d_ptr; - int error; + struct hid_data *hd; + struct hid_item hi; + int error, mdepth, found; uint16_t d_len; DPRINTFN(11, "\n"); @@ -388,14 +390,44 @@ ums_probe(device_t dev) if (error) return (ENXIO); - if (hid_is_collection(d_ptr, d_len, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) - error = BUS_PROBE_DEFAULT; - else - error = ENXIO; - + hd = hid_start_parse(d_ptr, d_len, 1 << hid_input); + if (hd == NULL) + return (0); + mdepth = 0; + found = 0; + while (hid_get_item(hd, &hi)) { + switch (hi.kind) { + case hid_collection: + if (mdepth != 0) + mdepth++; + else if (hi.collection == 1 && + hi.usage == + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)) + mdepth++; + break; + case hid_endcollection: + if (mdepth != 0) + mdepth--; + break; + case hid_input: + if (mdepth == 0) + break; + if (hi.usage == + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) && + (hi.flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) + found++; + if (hi.usage == + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) && + (hi.flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) + found++; + break; + default: + break; + } + } + hid_end_parse(hd); free(d_ptr, M_TEMP); - return (error); + return (found ? BUS_PROBE_DEFAULT : ENXIO); } static void diff --git a/sys/dev/usb/net/uhso.c b/sys/dev/usb/net/uhso.c index cbb0b087b1430..6b42de80a8d3b 100644 --- a/sys/dev/usb/net/uhso.c +++ b/sys/dev/usb/net/uhso.c @@ -249,6 +249,8 @@ static struct unrhdr *uhso_ifnet_unit = NULL; static const STRUCT_USB_HOST_ID uhso_devs[] = { #define UHSO_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } + /* Option GlobeTrotter MAX 7.2 with upgraded firmware */ + UHSO_DEV(OPTION, GTMAX72, UHSO_STATIC_IFACE), /* Option GlobeSurfer iCON 7.2 */ UHSO_DEV(OPTION, GSICON72, UHSO_STATIC_IFACE), /* Option iCON 225 */ diff --git a/sys/dev/usb/quirk/usb_quirk.c b/sys/dev/usb/quirk/usb_quirk.c index e54b9084c2e86..d3093f7ec1fdb 100644 --- a/sys/dev/usb/quirk/usb_quirk.c +++ b/sys/dev/usb/quirk/usb_quirk.c @@ -148,12 +148,10 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { UQ_MSC_FORCE_PROTO_SCSI), USB_QUIRK(AIPTEK, POCKETCAM3M, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI), - USB_QUIRK(AIPTEK2, SUNPLUS_TECH, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(ALCOR, SDCR_6335, 0x0000, 0xffff, UQ_MSC_NO_TEST_UNIT_READY, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(ALCOR, SDCR_6362, 0x0000, 0xffff, UQ_MSC_NO_TEST_UNIT_READY, UQ_MSC_NO_SYNC_CACHE), - USB_QUIRK(ALCOR, AU6390, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(ALCOR, UMCR_9361, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN), USB_QUIRK(ALCOR, TRANSCEND, 0x0000, 0xffff, UQ_MSC_NO_GETMAXLUN, @@ -173,14 +171,12 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(CENTURY, EX35QUAT, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_FORCE_SHORT_INQ, UQ_MSC_NO_START_STOP, UQ_MSC_IGNORE_RESIDUE), - USB_QUIRK(CENTURY, EX35SW4_SB4, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(CYPRESS, XX6830XX, 0x0000, 0xffff, UQ_MSC_NO_GETMAXLUN, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(DESKNOTE, UCR_61S2B, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI), USB_QUIRK(DMI, CFSM_RW, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN), - USB_QUIRK(DMI, DISK, 0x000, 0xffff, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(EPSON, STYLUS_875DC, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY), USB_QUIRK(EPSON, STYLUS_895, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, @@ -188,7 +184,6 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(FEIYA, 5IN1, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI), USB_QUIRK(FREECOM, DVD, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI), - USB_QUIRK(FREECOM, HDD, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(FUJIPHOTO, MASS0100, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI_I, UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_RS_CLEAR_UA, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(GENESYS, GL641USB2IDE, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, @@ -232,7 +227,6 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(IOMEGA, ZIP100, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_TEST_UNIT_READY), /* XXX ZIP drives can also use ATAPI */ - USB_QUIRK(JMICRON, JM20336, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(JMICRON, JM20337, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_SYNC_CACHE), @@ -279,8 +273,6 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { UQ_MSC_FORCE_PROTO_ATAPI), USB_QUIRK(MYSON, HEDEN, 0x0000, 0xffff, UQ_MSC_IGNORE_RESIDUE, UQ_MSC_NO_SYNC_CACHE), - USB_QUIRK(MYSON, HEDEN_8813, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), - USB_QUIRK(MYSON, STARREADER, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(NEODIO, ND3260, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_FORCE_SHORT_INQ), USB_QUIRK(NETAC, CF_CARD, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, @@ -317,7 +309,6 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(PANASONIC, KXLCB35AN, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI), USB_QUIRK(PANASONIC, LS120CAM, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_UFI), - USB_QUIRK(PHILIPS, SPE3030CC, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(PLEXTOR, 40_12_40U, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_TEST_UNIT_READY), USB_QUIRK(PNY, ATTACHE2, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, @@ -328,7 +319,6 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK_VP(USB_VENDOR_SAMSUNG_TECHWIN, USB_PRODUCT_SAMSUNG_TECHWIN_DIGIMAX_410, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY), - USB_QUIRK(SAMSUNG, YP_U4, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(SANDISK, SDDR05A, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_READ_CAP_OFFBY1, UQ_MSC_NO_GETMAXLUN), @@ -448,12 +438,6 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { UQ_MSC_FORCE_PROTO_ATAPI), USB_QUIRK(MEIZU, M6_SL, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY, UQ_MSC_NO_SYNC_CACHE), - USB_QUIRK(ACTIONS, MP4, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, - UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_SYNC_CACHE), - USB_QUIRK(ASUS, GMSC, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), - USB_QUIRK(CHIPSBANK, USBMEMSTICK, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), - USB_QUIRK(CHIPSBANK, USBMEMSTICK1, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), - USB_QUIRK(NEWLINK, USB2IDEBRIDGE, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), /* Non-standard USB MIDI devices */ USB_QUIRK(ROLAND, UM1, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS), @@ -567,9 +551,9 @@ usb_test_quirk_by_info(const struct usbd_lookup_info *info, uint16_t quirk) uint16_t x; uint16_t y; - if (quirk == UQ_NONE) { - return (0); - } + if (quirk == UQ_NONE) + goto done; + mtx_lock(&usb_quirk_mtx); for (x = 0; x != USB_DEV_QUIRKS_MAX; x++) { @@ -603,7 +587,8 @@ usb_test_quirk_by_info(const struct usbd_lookup_info *info, uint16_t quirk) break; } mtx_unlock(&usb_quirk_mtx); - return (0); +done: + return (0); /* no quirk match */ } static struct usb_quirk_entry * diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c index 31e8e112e1903..46a153f4cb8b0 100644 --- a/sys/dev/usb/serial/u3g.c +++ b/sys/dev/usb/serial/u3g.c @@ -280,6 +280,8 @@ static const STRUCT_USB_HOST_ID u3g_devs[] = { U3G_DEV(HUAWEI, E143D, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E143E, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E143F, U3GINIT_HUAWEI), + U3G_DEV(HUAWEI, E173, 0), + U3G_DEV(HUAWEI, E173_INIT, U3GINIT_HUAWEISCSI), U3G_DEV(HUAWEI, E180V, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E220, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E220BIS, U3GINIT_HUAWEI), @@ -293,6 +295,7 @@ static const STRUCT_USB_HOST_ID u3g_devs[] = { U3G_DEV(LONGCHEER, WM66, U3GINIT_HUAWEI), U3G_DEV(LONGCHEER, DISK, U3GINIT_TCT), U3G_DEV(LONGCHEER, W14, 0), + U3G_DEV(LONGCHEER, XSSTICK, 0), U3G_DEV(MERLIN, V620, 0), U3G_DEV(NEOTEL, PRIME, 0), U3G_DEV(NOVATEL, E725, 0), diff --git a/sys/dev/usb/storage/umass.c b/sys/dev/usb/storage/umass.c index 9292c842bcb77..41e98d50c8561 100644 --- a/sys/dev/usb/storage/umass.c +++ b/sys/dev/usb/storage/umass.c @@ -1025,12 +1025,6 @@ umass_attach(device_t dev) sc->cam_scsi_sense.opcode = REQUEST_SENSE; sc->cam_scsi_test_unit_ready.opcode = TEST_UNIT_READY; - /* - * some devices need a delay after that the configuration value is - * set to function properly: - */ - usb_pause_mtx(NULL, hz); - /* register the SIM */ err = umass_cam_attach_sim(sc); if (err) { diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c index dbba08eba496e..990bda22e4c69 100644 --- a/sys/dev/usb/usb_dev.c +++ b/sys/dev/usb/usb_dev.c @@ -911,10 +911,23 @@ usb_close(void *arg) DPRINTFN(2, "cpd=%p\n", cpd); - err = usb_ref_device(cpd, &refs, 1); - if (err) { - free(cpd, M_USBDEV); - return; + err = usb_ref_device(cpd, &refs, 0); + if (err) + goto done; + + /* + * If this function is not called directly from the root HUB + * thread, there is usually a need to lock the enumeration + * lock. Check this. + */ + if (!usbd_enum_is_locked(cpd->udev)) { + + DPRINTFN(2, "Locking enumeration\n"); + + /* reference device */ + err = usb_usb_ref_device(cpd, &refs); + if (err) + goto done; } if (cpd->fflags & FREAD) { usb_fifo_close(refs.rxfifo, cpd->fflags); @@ -922,10 +935,9 @@ usb_close(void *arg) if (cpd->fflags & FWRITE) { usb_fifo_close(refs.txfifo, cpd->fflags); } - usb_unref_device(cpd, &refs); +done: free(cpd, M_USBDEV); - return; } static void @@ -1648,7 +1660,6 @@ usb_fifo_attach(struct usb_device *udev, void *priv_sc, struct usb_fifo *f_rx; char devname[32]; uint8_t n; - struct usb_fs_privdata* pd; f_sc->fp[USB_FIFO_TX] = NULL; f_sc->fp[USB_FIFO_RX] = NULL; @@ -1746,22 +1757,10 @@ usb_fifo_attach(struct usb_device *udev, void *priv_sc, usb_alloc_symlink(devname); } - /* - * Initialize device private data - this is used to find the - * actual USB device itself. - */ - pd = malloc(sizeof(struct usb_fs_privdata), M_USBDEV, M_WAITOK | M_ZERO); - pd->bus_index = device_get_unit(udev->bus->bdev); - pd->dev_index = udev->device_index; - pd->ep_addr = -1; /* not an endpoint */ - pd->fifo_index = f_tx->fifo_index & f_rx->fifo_index; - pd->mode = FREAD|FWRITE; - - /* Now, create the device itself */ - f_sc->dev = make_dev(&usb_devsw, 0, uid, gid, mode, - "%s", devname); - /* XXX setting si_drv1 and creating the device is not atomic! */ - f_sc->dev->si_drv1 = pd; + /* Create the device */ + f_sc->dev = usb_make_dev(udev, devname, -1, + f_tx->fifo_index & f_rx->fifo_index, + FREAD|FWRITE, uid, gid, mode); } DPRINTFN(2, "attached %p/%p\n", f_tx, f_rx); @@ -1814,12 +1813,6 @@ usb_fifo_free_buffer(struct usb_fifo *f) bzero(&f->used_q, sizeof(f->used_q)); } -static void -usb_fifo_cleanup(void* ptr) -{ - free(ptr, M_USBDEV); -} - void usb_fifo_detach(struct usb_fifo_sc *f_sc) { @@ -1832,11 +1825,9 @@ usb_fifo_detach(struct usb_fifo_sc *f_sc) f_sc->fp[USB_FIFO_TX] = NULL; f_sc->fp[USB_FIFO_RX] = NULL; - if (f_sc->dev != NULL) { - destroy_dev_sched_cb(f_sc->dev, - usb_fifo_cleanup, f_sc->dev->si_drv1); - f_sc->dev = NULL; - } + usb_destroy_dev(f_sc->dev); + + f_sc->dev = NULL; DPRINTFN(2, "detached %p\n", f_sc); } diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index 932c0222272b2..7e0de330ed7c3 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -102,10 +102,8 @@ static void usb_notify_addq(const char *type, struct usb_device *); #endif #if USB_HAVE_UGEN static void usb_fifo_free_wrap(struct usb_device *, uint8_t, uint8_t); -static struct cdev *usb_make_dev(struct usb_device *, int, int); static void usb_cdev_create(struct usb_device *); static void usb_cdev_free(struct usb_device *); -static void usb_cdev_cleanup(void *); #endif /* This variable is global to allow easy access to it: */ @@ -1241,7 +1239,7 @@ static void usb_init_attach_arg(struct usb_device *udev, struct usb_attach_arg *uaa) { - bzero(uaa, sizeof(*uaa)); + memset(uaa, 0, sizeof(*uaa)); uaa->device = udev; uaa->usb_mode = udev->flags.usb_mode; @@ -1626,10 +1624,12 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, LIST_INIT(&udev->pd_list); /* Create the control endpoint device */ - udev->ctrl_dev = usb_make_dev(udev, 0, FREAD|FWRITE); + udev->ctrl_dev = usb_make_dev(udev, NULL, 0, 0, + FREAD|FWRITE, UID_ROOT, GID_OPERATOR, 0600); /* Create a link from /dev/ugenX.X to the default endpoint */ - make_dev_alias(udev->ctrl_dev, "%s", udev->ugen_name); + if (udev->ctrl_dev != NULL) + make_dev_alias(udev->ctrl_dev->cdev, "%s", udev->ugen_name); #endif /* Initialise device */ if (bus->methods->device_init != NULL) { @@ -1850,6 +1850,20 @@ repeat_set_config: } } } + if (set_config_failed == 0 && config_index == 0 && + usb_test_quirk(&uaa, UQ_MSC_NO_SYNC_CACHE) == 0) { + + /* + * Try to figure out if there are any MSC quirks we + * should apply automatically: + */ + err = usb_msc_auto_quirk(udev, 0); + + if (err != 0) { + set_config_failed = 1; + goto repeat_set_config; + } + } config_done: DPRINTF("new dev (addr %d), udev=%p, parent_hub=%p\n", @@ -1884,11 +1898,12 @@ done: } #if USB_HAVE_UGEN -static struct cdev * -usb_make_dev(struct usb_device *udev, int ep, int mode) +struct usb_fs_privdata * +usb_make_dev(struct usb_device *udev, const char *devname, int ep, + int fi, int rwmode, uid_t uid, gid_t gid, int mode) { struct usb_fs_privdata* pd; - char devname[20]; + char buffer[32]; /* Store information to locate ourselves again later */ pd = malloc(sizeof(struct usb_fs_privdata), M_USBDEV, @@ -1896,16 +1911,39 @@ usb_make_dev(struct usb_device *udev, int ep, int mode) pd->bus_index = device_get_unit(udev->bus->bdev); pd->dev_index = udev->device_index; pd->ep_addr = ep; - pd->mode = mode; + pd->fifo_index = fi; + pd->mode = rwmode; /* Now, create the device itself */ - snprintf(devname, sizeof(devname), "%u.%u.%u", - pd->bus_index, pd->dev_index, pd->ep_addr); - pd->cdev = make_dev(&usb_devsw, 0, UID_ROOT, - GID_OPERATOR, 0600, USB_DEVICE_DIR "/%s", devname); + if (devname == NULL) { + devname = buffer; + snprintf(buffer, sizeof(buffer), USB_DEVICE_DIR "/%u.%u.%u", + pd->bus_index, pd->dev_index, pd->ep_addr); + } + + pd->cdev = make_dev(&usb_devsw, 0, uid, gid, mode, "%s", devname); + + if (pd->cdev == NULL) { + DPRINTFN(0, "Failed to create device %s\n", devname); + free(pd, M_USBDEV); + return (NULL); + } + + /* XXX setting si_drv1 and creating the device is not atomic! */ pd->cdev->si_drv1 = pd; - return (pd->cdev); + return (pd); +} + +void +usb_destroy_dev(struct usb_fs_privdata *pd) +{ + if (pd == NULL) + return; + + destroy_dev(pd->cdev); + + free(pd, M_USBDEV); } static void @@ -1915,7 +1953,6 @@ usb_cdev_create(struct usb_device *udev) struct usb_endpoint_descriptor *ed; struct usb_descriptor *desc; struct usb_fs_privdata* pd; - struct cdev *dev; int inmode, outmode, inmask, outmask, mode; uint8_t ep; @@ -1957,14 +1994,16 @@ usb_cdev_create(struct usb_device *udev) /* Create all available endpoints except EP0 */ for (ep = 1; ep < 16; ep++) { - mode = inmask & (1 << ep) ? inmode : 0; - mode |= outmask & (1 << ep) ? outmode : 0; + mode = (inmask & (1 << ep)) ? inmode : 0; + mode |= (outmask & (1 << ep)) ? outmode : 0; if (mode == 0) continue; /* no IN or OUT endpoint */ - dev = usb_make_dev(udev, ep, mode); - pd = dev->si_drv1; - LIST_INSERT_HEAD(&udev->pd_list, pd, pd_next); + pd = usb_make_dev(udev, NULL, ep, 0, + mode, UID_ROOT, GID_OPERATOR, 0600); + + if (pd != NULL) + LIST_INSERT_HEAD(&udev->pd_list, pd, pd_next); } } @@ -1972,25 +2011,16 @@ static void usb_cdev_free(struct usb_device *udev) { struct usb_fs_privdata* pd; - struct cdev* pcdev; DPRINTFN(2, "Freeing device nodes\n"); while ((pd = LIST_FIRST(&udev->pd_list)) != NULL) { KASSERT(pd->cdev->si_drv1 == pd, ("privdata corrupt")); - pcdev = pd->cdev; - pd->cdev = NULL; LIST_REMOVE(pd, pd_next); - if (pcdev != NULL) - destroy_dev_sched_cb(pcdev, usb_cdev_cleanup, pd); - } -} -static void -usb_cdev_cleanup(void* arg) -{ - free(arg, M_USBDEV); + usb_destroy_dev(pd); + } } #endif @@ -2046,8 +2076,7 @@ usb_free_device(struct usb_device *udev, uint8_t flag) } mtx_unlock(&usb_ref_lock); - destroy_dev_sched_cb(udev->ctrl_dev, usb_cdev_cleanup, - udev->ctrl_dev->si_drv1); + usb_destroy_dev(udev->ctrl_dev); #endif if (udev->flags.usb_mode == USB_MODE_DEVICE) { @@ -2355,8 +2384,22 @@ uint8_t usb_test_quirk(const struct usb_attach_arg *uaa, uint16_t quirk) { uint8_t found; + uint8_t x; + + if (quirk == UQ_NONE) + return (0); + + /* search the automatic per device quirks first */ + + for (x = 0; x != USB_MAX_AUTO_QUIRK; x++) { + if (uaa->device->autoQuirk[x] == quirk) + return (1); + } + + /* search global quirk table, if any */ found = (usb_test_quirk_p) (&uaa->info, quirk); + return (found); } @@ -2683,3 +2726,17 @@ usbd_set_pnpinfo(struct usb_device *udev, uint8_t iface_index, const char *pnpin return (0); /* success */ } +usb_error_t +usbd_add_dynamic_quirk(struct usb_device *udev, uint16_t quirk) +{ + uint8_t x; + + for (x = 0; x != USB_MAX_AUTO_QUIRK; x++) { + if (udev->autoQuirk[x] == 0 || + udev->autoQuirk[x] == quirk) { + udev->autoQuirk[x] = quirk; + return (0); /* success */ + } + } + return (USB_ERR_NOMEM); +} diff --git a/sys/dev/usb/usb_device.h b/sys/dev/usb/usb_device.h index bf412214dd4f6..bde20b0790e73 100644 --- a/sys/dev/usb/usb_device.h +++ b/sys/dev/usb/usb_device.h @@ -29,6 +29,7 @@ struct usb_symlink; /* UGEN */ struct usb_device; /* linux compat */ +struct usb_fs_privdata; #define USB_CTRL_XFER_MAX 2 @@ -135,7 +136,7 @@ struct usb_device { #if USB_HAVE_UGEN struct usb_fifo *fifo[USB_FIFO_MAX]; struct usb_symlink *ugen_symlink; /* our generic symlink */ - struct cdev *ctrl_dev; /* Control Endpoint 0 device node */ + struct usb_fs_privdata *ctrl_dev; /* Control Endpoint 0 device node */ LIST_HEAD(,usb_fs_privdata) pd_list; char ugen_name[20]; /* name of ugenX.X device */ #endif @@ -148,6 +149,7 @@ struct usb_device { uint16_t power; /* mA the device uses */ uint16_t langid; /* language for strings */ + uint16_t autoQuirk[USB_MAX_AUTO_QUIRK]; /* dynamic quirks */ uint8_t address; /* device addess */ uint8_t device_index; /* device index in "bus->devices" */ @@ -202,6 +204,11 @@ struct usb_device *usb_alloc_device(device_t parent_dev, struct usb_bus *bus, struct usb_device *parent_hub, uint8_t depth, uint8_t port_index, uint8_t port_no, enum usb_dev_speed speed, enum usb_hc_mode mode); +#if USB_HAVE_UGEN +struct usb_fs_privdata *usb_make_dev(struct usb_device *, const char *, + int, int, int, uid_t, gid_t, int); +void usb_destroy_dev(struct usb_fs_privdata *); +#endif usb_error_t usb_probe_and_attach(struct usb_device *udev, uint8_t iface_index); void usb_detach_device(struct usb_device *, uint8_t, uint8_t); diff --git a/sys/dev/usb/usb_freebsd.h b/sys/dev/usb/usb_freebsd.h index ae69cdb8926e3..349e13e8477d7 100644 --- a/sys/dev/usb/usb_freebsd.h +++ b/sys/dev/usb/usb_freebsd.h @@ -68,6 +68,8 @@ #define USB_EP0_BUFSIZE 1024 /* bytes */ #define USB_CS_RESET_LIMIT 20 /* failures = 20 * 50 ms = 1sec */ +#define USB_MAX_AUTO_QUIRK 4 /* maximum number of dynamic quirks */ + typedef uint32_t usb_timeout_t; /* milliseconds */ typedef uint32_t usb_frlength_t; /* bytes */ typedef uint32_t usb_frcount_t; /* units */ diff --git a/sys/dev/usb/usb_msctest.c b/sys/dev/usb/usb_msctest.c index 0b6024b3d76ce..0355653fbd039 100644 --- a/sys/dev/usb/usb_msctest.c +++ b/sys/dev/usb/usb_msctest.c @@ -1,6 +1,6 @@ /* $FreeBSD$ */ /*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. + * Copyright (c) 2008,2011 Hans Petter Selasky. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -83,7 +83,10 @@ enum { DIR_NONE, }; +#define SCSI_MAX_LEN 0x100 #define SCSI_INQ_LEN 0x24 +#define SCSI_SENSE_LEN 0xFF + static uint8_t scsi_test_unit_ready[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static uint8_t scsi_inquiry[] = { 0x12, 0x00, 0x00, 0x00, SCSI_INQ_LEN, 0x00 }; static uint8_t scsi_rezero_init[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -96,6 +99,10 @@ static uint8_t scsi_huawei_eject[] = { 0x11, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static uint8_t scsi_tct_eject[] = { 0x06, 0xf5, 0x04, 0x02, 0x52, 0x70 }; +static uint8_t scsi_sync_cache[] = { 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; +static uint8_t scsi_request_sense[] = { 0x03, 0x00, 0x00, 0x00, 0x12, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #define BULK_SIZE 64 /* dummy */ #define ERR_CSW_FAILED -1 @@ -149,7 +156,7 @@ struct bbb_transfer { uint8_t status_try; int error; - uint8_t buffer[256]; + uint8_t buffer[SCSI_MAX_LEN] __aligned(4); }; static usb_callback_t bbb_command_callback; @@ -163,7 +170,7 @@ static void bbb_done(struct bbb_transfer *, int); static void bbb_transfer_start(struct bbb_transfer *, uint8_t); static void bbb_data_clear_stall_callback(struct usb_xfer *, uint8_t, uint8_t); -static uint8_t bbb_command_start(struct bbb_transfer *, uint8_t, uint8_t, +static int bbb_command_start(struct bbb_transfer *, uint8_t, uint8_t, void *, size_t, void *, size_t, usb_timeout_t); static struct bbb_transfer *bbb_attach(struct usb_device *, uint8_t); static void bbb_detach(struct bbb_transfer *); @@ -175,6 +182,7 @@ static const struct usb_config bbb_config[ST_MAX] = { .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .bufsize = sizeof(struct bbb_cbw), + .flags = {.ext_buffer = 1,}, .callback = &bbb_command_callback, .timeout = 4 * USB_MS_HZ, /* 4 seconds */ }, @@ -184,7 +192,7 @@ static const struct usb_config bbb_config[ST_MAX] = { .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .bufsize = BULK_SIZE, - .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,}, + .flags = {.ext_buffer = 1,.proxy_buffer = 1,.short_xfer_ok = 1,}, .callback = &bbb_data_read_callback, .timeout = 4 * USB_MS_HZ, /* 4 seconds */ }, @@ -203,7 +211,7 @@ static const struct usb_config bbb_config[ST_MAX] = { .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .bufsize = BULK_SIZE, - .flags = {.proxy_buffer = 1,}, + .flags = {.ext_buffer = 1,.proxy_buffer = 1,}, .callback = &bbb_data_write_callback, .timeout = 4 * USB_MS_HZ, /* 4 seconds */ }, @@ -222,7 +230,7 @@ static const struct usb_config bbb_config[ST_MAX] = { .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .bufsize = sizeof(struct bbb_csw), - .flags = {.short_xfer_ok = 1,}, + .flags = {.ext_buffer = 1,.short_xfer_ok = 1,}, .callback = &bbb_status_callback, .timeout = 1 * USB_MS_HZ, /* 1 second */ }, @@ -454,7 +462,7 @@ bbb_status_callback(struct usb_xfer *xfer, usb_error_t error) * 0: Success * Else: Failure *------------------------------------------------------------------------*/ -static uint8_t +static int bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun, void *data_ptr, size_t data_len, void *cmd_ptr, size_t cmd_len, usb_timeout_t data_timeout) @@ -566,9 +574,10 @@ int usb_iface_is_cdrom(struct usb_device *udev, uint8_t iface_index) { struct bbb_transfer *sc; - usb_error_t err; - uint8_t timeout, is_cdrom; + uint8_t timeout; + uint8_t is_cdrom; uint8_t sid_type; + int err; sc = bbb_attach(udev, iface_index); if (sc == NULL) @@ -595,6 +604,114 @@ usb_iface_is_cdrom(struct usb_device *udev, uint8_t iface_index) } usb_error_t +usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index) +{ + struct bbb_transfer *sc; + uint8_t timeout; + uint8_t is_no_direct; + uint8_t sid_type; + int err; + + sc = bbb_attach(udev, iface_index); + if (sc == NULL) + return (0); + + /* + * Some devices need a delay after that the configuration + * value is set to function properly: + */ + usb_pause_mtx(NULL, hz); + + is_no_direct = 1; + for (timeout = 4; timeout; timeout--) { + err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, + SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry), + USB_MS_HZ); + + if (err == 0 && sc->actlen > 0) { + sid_type = sc->buffer[0] & 0x1F; + if (sid_type == 0x00) + is_no_direct = 0; + break; + } else if (err != ERR_CSW_FAILED) + break; /* non retryable error */ + usb_pause_mtx(NULL, hz); + } + + if (is_no_direct) { + DPRINTF("Device is not direct access.\n"); + goto done; + } + + err = bbb_command_start(sc, DIR_IN, 0, NULL, 0, + &scsi_test_unit_ready, sizeof(scsi_test_unit_ready), + USB_MS_HZ); + + if (err != 0) { + + if (err != ERR_CSW_FAILED) + goto error; + } + + err = bbb_command_start(sc, DIR_IN, 0, NULL, 0, + &scsi_sync_cache, sizeof(scsi_sync_cache), + USB_MS_HZ); + + if (err != 0) { + + if (err != ERR_CSW_FAILED) + goto error; + + DPRINTF("Device doesn't handle synchronize cache\n"); + + usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE); + } + + /* clear sense status of any failed commands on the device */ + + err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, + SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry), + USB_MS_HZ); + + DPRINTF("Inquiry = %d\n", err); + + if (err != 0) { + + if (err != ERR_CSW_FAILED) + goto error; + } + + err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, + SCSI_SENSE_LEN, &scsi_request_sense, + sizeof(scsi_request_sense), USB_MS_HZ); + + DPRINTF("Request sense = %d\n", err); + + if (err != 0) { + + if (err != ERR_CSW_FAILED) + goto error; + } + +done: + bbb_detach(sc); + return (0); + +error: + bbb_detach(sc); + + DPRINTF("Device did not respond, enabling all quirks\n"); + + usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE); + usbd_add_dynamic_quirk(udev, UQ_MSC_NO_TEST_UNIT_READY); + + /* Need to re-enumerate the device */ + usbd_req_re_enumerate(udev, NULL); + + return (USB_ERR_STALLED); +} + +usb_error_t usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method) { struct bbb_transfer *sc; diff --git a/sys/dev/usb/usb_msctest.h b/sys/dev/usb/usb_msctest.h index 807d5f5d5d5b9..e4a717feb31e0 100644 --- a/sys/dev/usb/usb_msctest.h +++ b/sys/dev/usb/usb_msctest.h @@ -40,5 +40,7 @@ int usb_iface_is_cdrom(struct usb_device *udev, uint8_t iface_index); usb_error_t usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method); +usb_error_t usb_msc_auto_quirk(struct usb_device *udev, + uint8_t iface_index); #endif /* _USB_MSCTEST_H_ */ diff --git a/sys/dev/usb/usb_request.c b/sys/dev/usb/usb_request.c index bb5e0daa8591d..347f9464a6f47 100644 --- a/sys/dev/usb/usb_request.c +++ b/sys/dev/usb/usb_request.c @@ -67,6 +67,11 @@ #include <dev/usb/usb_bus.h> #include <sys/ctype.h> +static int usb_no_cs_fail; + +SYSCTL_INT(_hw_usb, OID_AUTO, no_cs_fail, CTLFLAG_RW, + &usb_no_cs_fail, 0, "USB clear stall failures are ignored, if set"); + #ifdef USB_DEBUG static int usb_pr_poll_delay = USB_PORT_RESET_DELAY; static int usb_pr_recovery_delay = USB_PORT_RESET_RECOVERY; @@ -238,7 +243,7 @@ usb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: - +tr_transferred: /* reset error counter */ udev->clear_stall_errors = 0; @@ -297,6 +302,13 @@ tr_setup: break; DPRINTF("Clear stall failed.\n"); + + /* + * Some VMs like VirtualBox always return failure on + * clear-stall which we sometimes should just ignore. + */ + if (usb_no_cs_fail) + goto tr_transferred; if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) goto tr_setup; @@ -1769,7 +1781,7 @@ usbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data, struct usb_interface *iface = usbd_get_iface(udev, iface_index); struct usb_device_request req; - if ((iface == NULL) || (iface->idesc == NULL) || (id == 0)) { + if ((iface == NULL) || (iface->idesc == NULL)) { return (USB_ERR_INVAL); } DPRINTFN(5, "len=%d\n", len); diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index 386e5461daa04..6a729a2ef61ba 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -1874,6 +1874,8 @@ product HUAWEI E1752 0x1446 3G modem product HUAWEI K3765 0x1465 3G modem product HUAWEI E1820 0x14ac E1820 HSPA+ USB Slider product HUAWEI K3765_INIT 0x1520 K3765 Initial +product HUAWEI E173 0x1c05 3G modem +product HUAWEI E173_INIT 0x1c0b 3G modem initial /* HUAWEI 3com products */ product HUAWEI3COM WUB320G 0x0009 Aolynk WUB320g @@ -2110,6 +2112,7 @@ product LOGITEC RT2870_3 0x0164 RT2870 product LONGCHEER WM66 0x6061 Longcheer WM66 HSDPA product LONGCHEER W14 0x9603 Mobilcom W14 product LONGCHEER DISK 0xf000 Driver disk +product LONGCHEER XSSTICK 0x9605 4G Systems XSStick P14 /* Lucent products */ @@ -2447,6 +2450,7 @@ product OPTION GT3GQUAD 0x6300 GlobeTrotter 3G QUAD datacard product OPTION GT3GPLUS 0x6600 GlobeTrotter 3G+ datacard product OPTION GTICON322 0xd033 GlobeTrotter Icon322 storage product OPTION GTMAX36 0x6701 GlobeTrotter Max 3.6 Modem +product OPTION GTMAX72 0x6711 GlobeTrotter Max 7.2 HSDPA product OPTION GTHSDPA 0x6971 GlobeTrotter HSDPA product OPTION GTMAXHSUPA 0x7001 GlobeTrotter HSUPA product OPTION GTMAXHSUPAE 0x6901 GlobeTrotter HSUPA PCIe diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index d832c327db13b..6446720e86110 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -37,6 +37,7 @@ struct usb_page_search; struct usb_process; struct usb_proc_msg; struct usb_mbuf; +struct usb_fs_privdata; struct mbuf; typedef enum { /* keep in sync with usb_errstr_table */ @@ -449,7 +450,7 @@ struct usb_fifo_methods { struct usb_fifo_sc { struct usb_fifo *fp[2]; - struct cdev* dev; + struct usb_fs_privdata *dev; }; const char *usbd_errstr(usb_error_t error); @@ -474,6 +475,8 @@ void device_set_usb_desc(device_t dev); void usb_pause_mtx(struct mtx *mtx, int _ticks); usb_error_t usbd_set_pnpinfo(struct usb_device *udev, uint8_t iface_index, const char *pnpinfo); +usb_error_t usbd_add_dynamic_quirk(struct usb_device *udev, + uint16_t quirk); const struct usb_device_id *usbd_lookup_id_by_info( const struct usb_device_id *id, usb_size_t sizeof_id, diff --git a/sys/dev/vge/if_vge.c b/sys/dev/vge/if_vge.c index d9a58cce5b820..952970219603e 100644 --- a/sys/dev/vge/if_vge.c +++ b/sys/dev/vge/if_vge.c @@ -1752,6 +1752,10 @@ vge_intr(void *arg) #ifdef DEVICE_POLLING if (ifp->if_capenable & IFCAP_POLLING) { + status = CSR_READ_4(sc, VGE_ISR); + CSR_WRITE_4(sc, VGE_ISR, status); + if (status != 0xFFFFFFFF && (status & VGE_ISR_LINKSTS) != 0) + vge_link_statchg(sc); VGE_UNLOCK(sc); return; } @@ -2109,11 +2113,10 @@ vge_init_locked(struct vge_softc *sc) #ifdef DEVICE_POLLING /* - * Disable interrupts if we are polling. + * Disable interrupts except link state change if we are polling. */ if (ifp->if_capenable & IFCAP_POLLING) { - CSR_WRITE_4(sc, VGE_IMR, 0); - CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK); + CSR_WRITE_4(sc, VGE_IMR, VGE_INTRS_POLLING); } else /* otherwise ... */ #endif { @@ -2121,9 +2124,9 @@ vge_init_locked(struct vge_softc *sc) * Enable interrupts. */ CSR_WRITE_4(sc, VGE_IMR, VGE_INTRS); - CSR_WRITE_4(sc, VGE_ISR, 0xFFFFFFFF); - CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK); } + CSR_WRITE_4(sc, VGE_ISR, 0xFFFFFFFF); + CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK); sc->vge_flags &= ~VGE_FLAG_LINK; mii_mediachg(mii); @@ -2280,8 +2283,9 @@ vge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) return (error); VGE_LOCK(sc); /* Disable interrupts */ - CSR_WRITE_4(sc, VGE_IMR, 0); - CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK); + CSR_WRITE_4(sc, VGE_IMR, VGE_INTRS_POLLING); + CSR_WRITE_4(sc, VGE_ISR, 0xFFFFFFFF); + CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK); ifp->if_capenable |= IFCAP_POLLING; VGE_UNLOCK(sc); } else { diff --git a/sys/dev/vge/if_vgereg.h b/sys/dev/vge/if_vgereg.h index 77cd61eb6baf0..c8b3f1bb459b3 100644 --- a/sys/dev/vge/if_vgereg.h +++ b/sys/dev/vge/if_vgereg.h @@ -302,6 +302,8 @@ VGE_ISR_LINKSTS|VGE_ISR_RXNODESC| \ VGE_ISR_RXDMA_STALL|VGE_ISR_TXDMA_STALL) +#define VGE_INTRS_POLLING (VGE_ISR_PHYINT|VGE_ISR_LINKSTS) + /* Interrupt mask register */ #define VGE_IMR_RXOK_HIPRIO 0x00000001 /* hi prio RX int */ diff --git a/sys/dev/xen/console/console.c b/sys/dev/xen/console/console.c index d614082848005..5a14623d1c306 100644 --- a/sys/dev/xen/console/console.c +++ b/sys/dev/xen/console/console.c @@ -70,6 +70,10 @@ static int rc, rp; static unsigned int cnsl_evt_reg; static unsigned int wc, wp; /* write_cons, write_prod */ +#ifdef KDB +static int xc_altbrk; +#endif + #define CDEV_MAJOR 12 #define XCUNIT(x) (dev2unit(x)) #define ISTTYOPEN(tp) ((tp) && ((tp)->t_state & TS_ISOPEN)) @@ -268,8 +272,12 @@ xencons_rx(char *buf, unsigned len) #endif ) { tty_lock(tp); - for (i = 0; i < len; i++) + for (i = 0; i < len; i++) { +#ifdef KDB + kdb_alt_break(buf[i], &xc_altbrk); +#endif ttydisc_rint(tp, buf[i], 0); + } ttydisc_rint_done(tp); tty_unlock(tp); } else { diff --git a/sys/fs/cd9660/iso.h b/sys/fs/cd9660/iso.h index 0988bf6b4066f..89322e74dab69 100644 --- a/sys/fs/cd9660/iso.h +++ b/sys/fs/cd9660/iso.h @@ -220,7 +220,7 @@ enum ISO_FTYPE { ISO_FTYPE_DEFAULT, ISO_FTYPE_9660, ISO_FTYPE_RRIP, #endif struct iso_mnt { - int im_flags; + uint64_t im_flags; struct mount *im_mountp; struct cdev *im_dev; diff --git a/sys/fs/coda/coda_psdev.c b/sys/fs/coda/coda_psdev.c index 494f30bff513a..e982a2c467e76 100644 --- a/sys/fs/coda/coda_psdev.c +++ b/sys/fs/coda/coda_psdev.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/ioccom.h> #include <sys/kernel.h> @@ -371,7 +372,7 @@ vc_write(struct cdev *dev, struct uio *uiop, int flag) struct vnode *vp = NULL; if (tmp->oh.result == 0) { - error = getvnode(uiop->uio_td->td_proc->p_fd, + error = getvnode(uiop->uio_td->td_proc->p_fd, CAP_WRITE, tmp->fd, &fp); if (!error) { /* diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c index d72ada03672d3..a2d3222dda933 100644 --- a/sys/fs/devfs/devfs_devs.c +++ b/sys/fs/devfs/devfs_devs.c @@ -630,13 +630,15 @@ devfs_populate_loop(struct devfs_mount *dm, int cleanup) void devfs_populate(struct devfs_mount *dm) { + unsigned gen; sx_assert(&dm->dm_lock, SX_XLOCKED); - if (dm->dm_generation == devfs_generation) + gen = devfs_generation; + if (dm->dm_generation == gen) return; while (devfs_populate_loop(dm, 0)) continue; - dm->dm_generation = devfs_generation; + dm->dm_generation = gen; } /* diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c index 955bd8b0f22f8..68ab7ce9d94b8 100644 --- a/sys/fs/devfs/devfs_vnops.c +++ b/sys/fs/devfs/devfs_vnops.c @@ -1665,6 +1665,8 @@ static struct fileops devfs_ops_f = { .fo_kqfilter = devfs_kqfilter_f, .fo_stat = devfs_stat_f, .fo_close = devfs_close_f, + .fo_chmod = vn_chmod, + .fo_chown = vn_chown, .fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE }; diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c index e11b59ca67169..3c4f44d17c969 100644 --- a/sys/fs/fdescfs/fdesc_vnops.c +++ b/sys/fs/fdescfs/fdesc_vnops.c @@ -40,6 +40,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/dirent.h> #include <sys/filedesc.h> @@ -305,7 +306,10 @@ fdesc_lookup(ap) fd = fd1; } - if ((error = fget(td, fd, &fp)) != 0) + /* + * No rights to check since 'fp' isn't actually used. + */ + if ((error = fget(td, fd, 0, &fp)) != 0) goto bad; /* Check if we're looking up ourselves. */ @@ -455,7 +459,7 @@ fdesc_setattr(ap) /* * Allow setattr where there is an underlying vnode. */ - error = getvnode(td->td_proc->p_fd, fd, &fp); + error = getvnode(td->td_proc->p_fd, fd, CAP_EXTATTR_SET, &fp); if (error) { /* * getvnode() returns EINVAL if the file descriptor is not diff --git a/sys/fs/fifofs/fifo_vnops.c b/sys/fs/fifofs/fifo_vnops.c index e339a8ac8535f..b8d4a400660e0 100644 --- a/sys/fs/fifofs/fifo_vnops.c +++ b/sys/fs/fifofs/fifo_vnops.c @@ -72,6 +72,8 @@ struct fileops fifo_ops_f = { .fo_kqfilter = fifo_kqfilter_f, .fo_stat = fifo_stat_f, .fo_close = fifo_close_f, + .fo_chmod = vn_chmod, + .fo_chown = vn_chown, .fo_flags = DFLAG_PASSABLE }; diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h index 417923fa80597..673095ed69f5d 100644 --- a/sys/fs/msdosfs/msdosfsmount.h +++ b/sys/fs/msdosfs/msdosfsmount.h @@ -103,7 +103,7 @@ struct msdosfsmount { u_int pm_fatdiv; /* offset computation */ u_int pm_curfat; /* current fat for FAT32 (0 otherwise) */ u_int *pm_inusemap; /* ptr to bitmap of in-use clusters */ - u_int pm_flags; /* see below */ + uint64_t pm_flags; /* see below */ void *pm_u2w; /* Local->Unicode iconv handle */ void *pm_w2u; /* Unicode->Local iconv handle */ void *pm_u2d; /* Unicode->DOS iconv handle */ diff --git a/sys/fs/nfsclient/nfs_clnode.c b/sys/fs/nfsclient/nfs_clnode.c index d15de6e9c7b0c..5e7185df2125b 100644 --- a/sys/fs/nfsclient/nfs_clnode.c +++ b/sys/fs/nfsclient/nfs_clnode.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/proc.h> #include <sys/socket.h> #include <sys/sysctl.h> +#include <sys/taskqueue.h> #include <sys/vnode.h> #include <vm/uma.h> @@ -65,6 +66,8 @@ MALLOC_DECLARE(M_NEWNFSREQ); uma_zone_t newnfsnode_zone; +static void nfs_freesillyrename(void *arg, __unused int pending); + void ncl_nhinit(void) { @@ -186,6 +189,20 @@ ncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, struct nfsnode **npp, return (0); } +/* + * Do the vrele(sp->s_dvp) as a separate task in order to avoid a + * deadlock because of a LOR when vrele() locks the directory vnode. + */ +static void +nfs_freesillyrename(void *arg, __unused int pending) +{ + struct sillyrename *sp; + + sp = arg; + vrele(sp->s_dvp); + free(sp, M_NEWNFSREQ); +} + int ncl_inactive(struct vop_inactive_args *ap) { @@ -220,8 +237,8 @@ ncl_inactive(struct vop_inactive_args *ap) */ ncl_removeit(sp, vp); crfree(sp->s_cred); - vrele(sp->s_dvp); - FREE((caddr_t)sp, M_NEWNFSREQ); + TASK_INIT(&sp->s_task, 0, nfs_freesillyrename, sp); + taskqueue_enqueue(taskqueue_thread, &sp->s_task); mtx_lock(&np->n_mtx); } np->n_flag &= NMODIFIED; diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c index 44d3c7421c482..acbfa6ceda8f3 100644 --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$"); #include "opt_kdtrace.h" +#include <sys/capability.h> + /* * generally, I don't like #includes inside .h files, but it seems to * be the easiest way to handle the port. @@ -1231,7 +1233,13 @@ nfssvc_nfscl(struct thread *td, struct nfssvc_args *uap) error = copyin(uap->argp, (caddr_t)&nfscbdarg, sizeof(nfscbdarg)); if (error) return (error); - if ((error = fget(td, nfscbdarg.sock, &fp)) != 0) { + /* + * Since we don't know what rights might be required, + * pretend that we need them all. It is better to be too + * careful than too reckless. + */ + if ((error = fget(td, nfscbdarg.sock, CAP_SOCK_ALL, &fp)) + != 0) { return (error); } if (fp->f_type != DTYPE_SOCKET) { diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index a69c76e8e30f8..7e87b6e71a101 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -1596,6 +1596,8 @@ again: if (attrflag) (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 0, 1); + if (error != 0) + vput(newvp); } } if (!error) { diff --git a/sys/fs/nfsclient/nfsnode.h b/sys/fs/nfsclient/nfsnode.h index 1d1c89c7d4b7b..c29805d5efea6 100644 --- a/sys/fs/nfsclient/nfsnode.h +++ b/sys/fs/nfsclient/nfsnode.h @@ -35,11 +35,14 @@ #ifndef _NFSCLIENT_NFSNODE_H_ #define _NFSCLIENT_NFSNODE_H_ +#include <sys/_task.h> + /* * Silly rename structure that hangs off the nfsnode until the name * can be removed by nfs_inactive() */ struct sillyrename { + struct task s_task; struct ucred *s_cred; struct vnode *s_dvp; long s_namlen; diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 56c563ae1f33a..42ace8204f22f 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -34,6 +34,8 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include <sys/capability.h> + /* * Functions that perform the vfs operations required by the routines in * nfsd_serv.c. It is hoped that this change will make the server more @@ -280,6 +282,7 @@ nfsvno_namei(struct nfsrv_descript *nd, struct nameidata *ndp, *retdirp = NULL; cnp->cn_nameptr = cnp->cn_pnbuf; + ndp->ni_strictrelative = 0; /* * Extract and set starting directory. */ @@ -3027,7 +3030,12 @@ nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap) error = copyin(uap->argp, (caddr_t)&sockarg, sizeof (sockarg)); if (error) goto out; - if ((error = fget(td, sockarg.sock, &fp)) != 0) + /* + * Since we don't know what rights might be required, + * pretend that we need them all. It is better to be too + * careful than too reckless. + */ + if ((error = fget(td, sockarg.sock, CAP_SOCK_ALL, &fp)) != 0) goto out; if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, td); diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c index b6a365d612780..85fbbd24dcd76 100644 --- a/sys/fs/nfsserver/nfs_nfsdserv.c +++ b/sys/fs/nfsserver/nfs_nfsdserv.c @@ -620,7 +620,7 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) { u_int32_t *tl; - int error = 0, cnt, len, getret = 1, reqlen, eof = 0; + int error = 0, cnt, getret = 1, reqlen, eof = 0; mbuf_t m2, m3; struct nfsvattr nva; off_t off = 0x0; @@ -714,11 +714,11 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, eof = 1; } else if (reqlen == 0) cnt = 0; - else if ((off + reqlen) > nva.na_size) + else if ((off + reqlen) >= nva.na_size) { cnt = nva.na_size - off; - else + eof = 1; + } else cnt = reqlen; - len = NFSM_RNDUP(cnt); m3 = NULL; if (cnt > 0) { nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p, @@ -748,7 +748,7 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, *tl++ = txdr_unsigned(cnt); } else NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - if (len < reqlen || eof) + if (eof) *tl++ = newnfs_true; else *tl++ = newnfs_false; @@ -1425,6 +1425,7 @@ nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, struct nfsrvfh tfh; char *bufp, *tbufp = NULL; u_long *hashp; + fhandle_t fh; if (nd->nd_repstat) { nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); @@ -1450,19 +1451,34 @@ nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, tnes = *toexp; tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0); } else { + tfh.nfsrvfh_len = 0; error = nfsrv_mtofh(nd, &tfh); + if (error == 0) + error = nfsvno_getfh(dp, &fh, p); if (error) { vput(dp); /* todp is always NULL except NFSv4 */ nfsvno_relpathbuf(&fromnd); goto out; } - nd->nd_cred->cr_uid = nd->nd_saveduid; - nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 0, p); - if (tdp) { + + /* If this is the same file handle, just VREF() the vnode. */ + if (tfh.nfsrvfh_len == NFSX_MYFH && + !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) { + VREF(dp); + tdp = dp; + tnes = *exp; tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 1); - NFSVOPUNLOCK(tdp, 0); + } else { + nd->nd_cred->cr_uid = nd->nd_saveduid; + nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, + 0, p); + if (tdp) { + tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, + nd->nd_cred, p, 1); + NFSVOPUNLOCK(tdp, 0); + } } } NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART); @@ -2725,12 +2741,11 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, * Do basic access checking. */ if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { - if (vnode_vtype(vp) == VDIR) - nd->nd_repstat = NFSERR_ISDIR; - else if (vnode_vtype(vp) == VLNK) + /* + * The IETF working group decided that this is the correct + * error return for all non-regular files. + */ nd->nd_repstat = NFSERR_SYMLINK; - else - nd->nd_repstat = NFSERR_INVAL; } if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, diff --git a/sys/fs/ntfs/ntfs.h b/sys/fs/ntfs/ntfs.h index 4f6431f371526..8415222297be5 100644 --- a/sys/fs/ntfs/ntfs.h +++ b/sys/fs/ntfs/ntfs.h @@ -250,7 +250,7 @@ struct ntfsmount { uid_t ntm_uid; gid_t ntm_gid; mode_t ntm_mode; - u_int ntm_flag; + uint64_t ntm_flag; cn_t ntm_cfree; struct ntvattrdef *ntm_ad; int ntm_adnum; diff --git a/sys/fs/portalfs/portal_vfsops.c b/sys/fs/portalfs/portal_vfsops.c index a8c16c4b17fa4..04e7a3d225003 100644 --- a/sys/fs/portalfs/portal_vfsops.c +++ b/sys/fs/portalfs/portal_vfsops.c @@ -40,6 +40,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/domain.h> #include <sys/filedesc.h> #include <sys/kernel.h> @@ -112,7 +113,12 @@ portal_mount(struct mount *mp) if (error) return (error); - if ((error = fget(td, v, &fp)) != 0) + /* + * Capsicum is not incompatible with portalfs, but we don't really + * know what rights are required. In the spirit of "better safe than + * sorry", pretend that all rights are required for now. + */ + if ((error = fget(td, v, CAP_MASK_VALID, &fp)) != 0) return (error); if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, td); diff --git a/sys/fs/portalfs/portal_vnops.c b/sys/fs/portalfs/portal_vnops.c index 6fcc1ce642193..7cd5267698b74 100644 --- a/sys/fs/portalfs/portal_vnops.c +++ b/sys/fs/portalfs/portal_vnops.c @@ -38,7 +38,10 @@ * Portal Filesystem */ +#include "opt_capsicum.h" + #include <sys/param.h> +#include <sys/capability.h> #include <sys/fcntl.h> #include <sys/file.h> #include <sys/kernel.h> @@ -232,6 +235,15 @@ portal_open(ap) struct file *fp; struct portal_cred pcred; +#ifdef CAPABILITY_MODE + /* + * This may require access to a global namespace (e.g. an IP address); + * disallow it entirely, as we do open(2). + */ + if (IN_CAPABILITY_MODE(td)) + return (ECAPMODE); +#endif + /* * Nothing to do when opening the root node. */ @@ -414,7 +426,7 @@ portal_open(ap) * Check that the mode the file is being opened for is a subset * of the mode of the existing descriptor. */ - if ((error = fget(td, fd, &fp)) != 0) + if ((error = fget(td, fd, 0, &fp)) != 0) goto bad; if (((ap->a_mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) { fdrop(fp, td); diff --git a/sys/fs/procfs/procfs.c b/sys/fs/procfs/procfs.c index 8b69eb1a0b3c7..514e279396fec 100644 --- a/sys/fs/procfs/procfs.c +++ b/sys/fs/procfs/procfs.c @@ -67,20 +67,23 @@ int procfs_doprocfile(PFS_FILL_ARGS) { - char *fullpath = "unknown"; - char *freepath = NULL; + char *fullpath; + char *freepath; struct vnode *textvp; + int error; + freepath = NULL; PROC_LOCK(p); textvp = p->p_textvp; vhold(textvp); PROC_UNLOCK(p); - vn_fullpath(td, textvp, &fullpath, &freepath); + error = vn_fullpath(td, textvp, &fullpath, &freepath); vdrop(textvp); - sbuf_printf(sb, "%s", fullpath); - if (freepath) + if (error == 0) + sbuf_printf(sb, "%s", fullpath); + if (freepath != NULL) free(freepath, M_TEMP); - return (0); + return (error); } /* diff --git a/sys/fs/smbfs/smbfs.h b/sys/fs/smbfs/smbfs.h index 4be0a55c76b38..84c79a12f8925 100644 --- a/sys/fs/smbfs/smbfs.h +++ b/sys/fs/smbfs/smbfs.h @@ -80,7 +80,7 @@ struct smbmount { struct mount * sm_mp; struct smbnode * sm_root; struct ucred * sm_owner; - u_int sm_flags; + uint64_t sm_flags; long sm_nextino; struct smb_share * sm_share; /* struct simplelock sm_npslock;*/ diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index 0568e93cd4144..74aba047edcd4 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -518,8 +518,7 @@ lookupvpg: * Reference the page before unlocking and sleeping so * that the page daemon is less likely to reclaim it. */ - vm_page_lock_queues(); - vm_page_flag_set(m, PG_REFERENCED); + vm_page_reference(m); vm_page_sleep(m, "tmfsmr"); goto lookupvpg; } @@ -538,8 +537,7 @@ lookupvpg: * Reference the page before unlocking and sleeping so * that the page daemon is less likely to reclaim it. */ - vm_page_lock_queues(); - vm_page_flag_set(m, PG_REFERENCED); + vm_page_reference(m); vm_page_sleep(m, "tmfsmr"); goto lookupvpg; } @@ -650,8 +648,7 @@ lookupvpg: * Reference the page before unlocking and sleeping so * that the page daemon is less likely to reclaim it. */ - vm_page_lock_queues(); - vm_page_flag_set(vpg, PG_REFERENCED); + vm_page_reference(vpg); vm_page_sleep(vpg, "tmfsmw"); goto lookupvpg; } diff --git a/sys/gnu/fs/xfs/xfs_dfrag.c b/sys/gnu/fs/xfs/xfs_dfrag.c index 77a71dfe143c5..7b6b04ebcda70 100644 --- a/sys/gnu/fs/xfs/xfs_dfrag.c +++ b/sys/gnu/fs/xfs/xfs_dfrag.c @@ -46,6 +46,7 @@ #include "xfs_mac.h" #include "xfs_rw.h" +#include <sys/capability.h> #include <sys/file.h> /* @@ -79,7 +80,8 @@ xfs_swapext( } /* Pull information for the target fd */ - if (fgetvp(td, (int)sxp->sx_fdtarget, &bvp) != 0) { + if (fgetvp(td, (int)sxp->sx_fdtarget, CAP_READ | CAP_WRITE, &bvp) + != 0) { error = XFS_ERROR(EINVAL); goto error0; } @@ -91,7 +93,7 @@ xfs_swapext( goto error0; } - if (fgetvp(td, (int)sxp->sx_fdtmp, &btvp) != 0) { + if (fgetvp(td, (int)sxp->sx_fdtmp, CAP_READ | CAP_WRITE, &btvp) != 0) { error = XFS_ERROR(EINVAL); goto error0; } diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index c4548c6bce1ce..69e8d9b042921 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -39,7 +39,7 @@ options MD_ROOT # MD is a potential root device options NFSCL # New Network Filesystem Client options NFSD # New Network Filesystem Server options NFSLOCKD # Network Lock Manager -options NFS_ROOT # NFS usable as /, requires NFSCLIENT +options NFS_ROOT # NFS usable as /, requires NFSCL options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) @@ -196,10 +196,7 @@ device plip # TCP/IP over parallel device ppi # Parallel port interface device #device vpo # Requires scbus and da -# If you've got a "dumb" serial or parallel PCI card that is -# supported by the puc(4) glue driver, uncomment the following -# line to enable it (connects to sio, uart and/or ppc drivers): -#device puc +device puc # Multi I/O cards and multi-channel UARTs # PCI Ethernet NICs. device bxe # Broadcom BCM57710/BCM57711/BCM57711E 10Gb Ethernet @@ -342,7 +339,7 @@ device uath # Atheros AR5523 wireless NICs device upgt # Conexant/Intersil PrismGT wireless NICs. device ural # Ralink Technology RT2500USB wireless NICs device urtw # Realtek RTL8187B/L wireless NICs -device zyd # ZyDAS zb1211/zb1211b wireless NICs +device zyd # ZyDAS zd1211/zd1211b wireless NICs # FireWire support device firewire # FireWire bus code diff --git a/sys/i386/conf/XBOX b/sys/i386/conf/XBOX index a3e8a6bbbc2f4..9ee270b8ae4ee 100644 --- a/sys/i386/conf/XBOX +++ b/sys/i386/conf/XBOX @@ -27,10 +27,10 @@ options SOFTUPDATES # Enable FFS soft updates support #options UFS_ACL # Support for access control lists #options UFS_DIRHASH # Improve performance on big directories #options MD_ROOT # MD is a potential root device -options NFSCLIENT # Network Filesystem Client -#options NFSSERVER # Network Filesystem Server +options NFSCL # New Network Filesystem Client +#options NFSD # New Network Filesystem Server #options NFSLOCKD # Network Lock Manager -#options NFS_ROOT # NFS usable as /, requires NFSCLIENT +#options NFS_ROOT # NFS usable as /, requires NFSCL #options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem #options PROCFS # Process filesystem (requires PSEUDOFS) diff --git a/sys/i386/conf/XEN b/sys/i386/conf/XEN index f1fb99bab82ae..ad453bf80a1a4 100644 --- a/sys/i386/conf/XEN +++ b/sys/i386/conf/XEN @@ -21,10 +21,10 @@ options SOFTUPDATES # Enable FFS soft updates support options UFS_ACL # Support for access control lists options UFS_DIRHASH # Improve performance on big directories options UFS_GJOURNAL # Enable gjournal-based UFS journaling -options NFSCLIENT # Network Filesystem Client -options NFSSERVER # Network Filesystem Server +options NFSCL # New Network Filesystem Client +options NFSD # New Network Filesystem Server options NFSLOCKD # Network Lock Manager -options NFS_ROOT # NFS usable as /, requires NFSCLIENT +options NFS_ROOT # NFS usable as /, requires NFSCL options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 91050c43bee3d..e596b964d992b 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -2132,7 +2132,7 @@ static void getmemsize(int first) { int has_smap, off, physmap_idx, pa_indx, da_indx; - u_long physmem_tunable; + u_long physmem_tunable, memtest; vm_paddr_t physmap[PHYSMAP_SIZE]; pt_entry_t *pte; quad_t dcons_addr, dcons_size; @@ -2339,6 +2339,13 @@ physmap_done: if (has_smap && Maxmem > atop(physmap[physmap_idx + 1])) Maxmem = atop(physmap[physmap_idx + 1]); + /* + * By default keep the memtest enabled. Use a general name so that + * one could eventually do more with the code than just disable it. + */ + memtest = 1; + TUNABLE_ULONG_FETCH("hw.memtest.tests", &memtest); + if (atop(physmap[physmap_idx + 1]) != Maxmem && (boothowto & RB_VERBOSE)) printf("Physical memory use set to %ldK\n", Maxmem * 4); @@ -2402,6 +2409,8 @@ physmap_done: goto do_dump_avail; page_bad = FALSE; + if (memtest == 0) + goto skip_memtest; /* * map page into kernel: valid, read/write,non-cacheable @@ -2439,6 +2448,7 @@ physmap_done: */ *(int *)ptr = tmp; +skip_memtest: /* * Adjust array of valid/good pages. */ diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index 002e52948eb0c..db5f99566f79b 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -2207,7 +2207,7 @@ pmap_collect(pmap_t locked_pmap, struct vpgqueues *vpq) KASSERT((tpte & PG_W) == 0, ("pmap_collect: wired pte %#jx", (uintmax_t)tpte)); if (tpte & PG_A) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); if ((tpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); free = NULL; @@ -2221,7 +2221,7 @@ pmap_collect(pmap_t locked_pmap, struct vpgqueues *vpq) } if (TAILQ_EMPTY(&m->md.pv_list) && TAILQ_EMPTY(&pa_to_pvh(VM_PAGE_TO_PHYS(m))->pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } sched_unpin(); } @@ -2400,7 +2400,7 @@ pmap_pv_demote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa) va_last = va + NBPDR - PAGE_SIZE; do { m++; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_pv_demote_pde: page %p is not managed", m)); va += PAGE_SIZE; pmap_insert_entry(pmap, va, m); @@ -2461,7 +2461,7 @@ pmap_remove_entry(pmap_t pmap, vm_page_t m, vm_offset_t va) if (TAILQ_EMPTY(&m->md.pv_list)) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); if (TAILQ_EMPTY(&pvh->pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } } @@ -2714,10 +2714,10 @@ pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva, if ((oldpde & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); if (oldpde & PG_A) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); if (TAILQ_EMPTY(&m->md.pv_list) && TAILQ_EMPTY(&pvh->pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } } if (pmap == kernel_pmap) { @@ -2763,7 +2763,7 @@ pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t va, vm_page_t *free) if ((oldpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); if (oldpte & PG_A) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); pmap_remove_entry(pmap, m, va); } return (pmap_unuse_pt(pmap, va, free)); @@ -2927,7 +2927,7 @@ pmap_remove_all(vm_page_t m) vm_offset_t va; vm_page_t free; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_all: page %p is not managed", m)); free = NULL; vm_page_lock_queues(); @@ -2953,7 +2953,7 @@ pmap_remove_all(vm_page_t m) if (tpte & PG_W) pmap->pm_stats.wired_count--; if (tpte & PG_A) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); /* * Update the vm_page_t clean and reference bits. @@ -2966,7 +2966,7 @@ pmap_remove_all(vm_page_t m) free_pv_entry(pmap, pv); PMAP_UNLOCK(pmap); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); sched_unpin(); vm_page_unlock_queues(); pmap_free_zero_pages(free); @@ -3299,8 +3299,8 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, KASSERT(va < UPT_MIN_ADDRESS || va >= UPT_MAX_ADDRESS, ("pmap_enter: invalid to pmap_enter page table pages (va: 0x%x)", va)); - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0 || - (m->oflags & VPO_BUSY) != 0, + KASSERT((m->oflags & (VPO_UNMANAGED | VPO_BUSY)) != 0 || + VM_OBJECT_LOCKED(m->object), ("pmap_enter: page %p is not busy", m)); mpte = NULL; @@ -3388,7 +3388,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, /* * Enter on the PV list if part of our managed memory. */ - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) { + if ((m->oflags & VPO_UNMANAGED) == 0) { KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva, ("pmap_enter: managed mapping within the clean submap")); if (pv == NULL) @@ -3413,7 +3413,7 @@ validate: if ((prot & VM_PROT_WRITE) != 0) { newpte |= PG_RW; if ((newpte & PG_MANAGED) != 0) - vm_page_flag_set(m, PG_WRITEABLE); + vm_page_aflag_set(m, PGA_WRITEABLE); } #ifdef PAE if ((prot & VM_PROT_EXECUTE) == 0) @@ -3439,7 +3439,7 @@ validate: origpte = pte_load_store(pte, newpte); if (origpte & PG_A) { if (origpte & PG_MANAGED) - vm_page_flag_set(om, PG_REFERENCED); + vm_page_aflag_set(om, PGA_REFERENCED); if (opa != VM_PAGE_TO_PHYS(m)) invlva = TRUE; #ifdef PAE @@ -3457,7 +3457,7 @@ validate: if ((origpte & PG_MANAGED) != 0 && TAILQ_EMPTY(&om->md.pv_list) && TAILQ_EMPTY(&pa_to_pvh(opa)->pv_list)) - vm_page_flag_clear(om, PG_WRITEABLE); + vm_page_aflag_clear(om, PGA_WRITEABLE); if (invlva) pmap_invalidate_page(pmap, va); } else @@ -3498,7 +3498,7 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot) } newpde = VM_PAGE_TO_PHYS(m) | pmap_cache_bits(m->md.pat_mode, 1) | PG_PS | PG_V; - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) { + if ((m->oflags & VPO_UNMANAGED) == 0) { newpde |= PG_MANAGED; /* @@ -3604,7 +3604,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_page_t free; KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva || - (m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0, + (m->oflags & VPO_UNMANAGED) != 0, ("pmap_enter_quick_locked: managed mapping within the clean submap")); mtx_assert(&vm_page_queue_mtx, MA_OWNED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); @@ -3667,7 +3667,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, /* * Enter on the PV list if part of our managed memory. */ - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0 && + if ((m->oflags & VPO_UNMANAGED) == 0 && !pmap_try_insert_pv_entry(pmap, va, m)) { if (mpte != NULL) { free = NULL; @@ -3695,7 +3695,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, /* * Now validate mapping with RO protection */ - if (m->flags & (PG_FICTITIOUS|PG_UNMANAGED)) + if ((m->oflags & VPO_UNMANAGED) != 0) pte_store(pte, pa | PG_V | PG_U); else pte_store(pte, pa | PG_V | PG_U | PG_MANAGED); @@ -4096,7 +4096,7 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m) int loops = 0; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_page_exists_quick: page %p is not managed", m)); rv = FALSE; vm_page_lock_queues(); @@ -4137,7 +4137,7 @@ pmap_page_wired_mappings(vm_page_t m) int count; count = 0; - if ((m->flags & PG_FICTITIOUS) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (count); vm_page_lock_queues(); count = pmap_pvh_wired_mappings(&m->md, count); @@ -4181,7 +4181,7 @@ pmap_page_is_mapped(vm_page_t m) { boolean_t rv; - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (FALSE); vm_page_lock_queues(); rv = !TAILQ_EMPTY(&m->md.pv_list) || @@ -4287,7 +4287,7 @@ pmap_remove_pages(pmap_t pmap) if (TAILQ_EMPTY(&pvh->pv_list)) { for (mt = m; mt < &m[NBPDR / PAGE_SIZE]; mt++) if (TAILQ_EMPTY(&mt->md.pv_list)) - vm_page_flag_clear(mt, PG_WRITEABLE); + vm_page_aflag_clear(mt, PGA_WRITEABLE); } mpte = pmap_lookup_pt_page(pmap, pv->pv_va); if (mpte != NULL) { @@ -4305,7 +4305,7 @@ pmap_remove_pages(pmap_t pmap) if (TAILQ_EMPTY(&m->md.pv_list)) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); if (TAILQ_EMPTY(&pvh->pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } pmap_unuse_pt(pmap, pv->pv_va, &free); } @@ -4341,17 +4341,17 @@ pmap_is_modified(vm_page_t m) { boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_modified: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be - * concurrently set while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be + * concurrently set while the object is locked. Thus, if PGA_WRITEABLE * is clear, no PTEs can have PG_M set. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return (FALSE); vm_page_lock_queues(); rv = pmap_is_modified_pvh(&m->md) || @@ -4424,7 +4424,7 @@ pmap_is_referenced(vm_page_t m) { boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_referenced: page %p is not managed", m)); vm_page_lock_queues(); rv = pmap_is_referenced_pvh(&m->md) || @@ -4474,17 +4474,17 @@ pmap_remove_write(vm_page_t m) pt_entry_t oldpte, *pte; vm_offset_t va; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_write: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be set by - * another thread while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be set by + * another thread while the object is locked. Thus, if PGA_WRITEABLE * is clear, no page table entries need updating. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); sched_pin(); @@ -4522,7 +4522,7 @@ retry: } PMAP_UNLOCK(pmap); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); sched_unpin(); vm_page_unlock_queues(); } @@ -4550,7 +4550,7 @@ pmap_ts_referenced(vm_page_t m) vm_offset_t va; int rtval = 0; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_ts_referenced: page %p is not managed", m)); pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); vm_page_lock_queues(); @@ -4626,18 +4626,18 @@ pmap_clear_modify(vm_page_t m) pt_entry_t oldpte, *pte; vm_offset_t va; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_modify: page %p is not managed", m)); VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); KASSERT((m->oflags & VPO_BUSY) == 0, ("pmap_clear_modify: page %p is busy", m)); /* - * If the page is not PG_WRITEABLE, then no PTEs can have PG_M set. + * If the page is not PGA_WRITEABLE, then no PTEs can have PG_M set. * If the object containing the page is locked and the page is not - * VPO_BUSY, then PG_WRITEABLE cannot be concurrently set. + * VPO_BUSY, then PGA_WRITEABLE cannot be concurrently set. */ - if ((m->flags & PG_WRITEABLE) == 0) + if ((m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); sched_pin(); @@ -4715,7 +4715,7 @@ pmap_clear_reference(vm_page_t m) pt_entry_t *pte; vm_offset_t va; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_reference: page %p is not managed", m)); vm_page_lock_queues(); sched_pin(); diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index 5a8016c9c69da..dddecaa807ff1 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -1054,6 +1054,8 @@ cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) return (error); } +#include "../../kern/subr_syscall.c" + /* * syscall - system call request C handler * diff --git a/sys/i386/ibcs2/ibcs2_fcntl.c b/sys/i386/ibcs2/ibcs2_fcntl.c index 6875aef71fdcd..fddfcb59321b6 100644 --- a/sys/i386/ibcs2/ibcs2_fcntl.c +++ b/sys/i386/ibcs2/ibcs2_fcntl.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/fcntl.h> #include <sys/file.h> #include <sys/filedesc.h> @@ -203,7 +204,7 @@ ibcs2_open(td, uap) struct file *fp; int error; - error = fget(td, td->td_retval[0], &fp); + error = fget(td, td->td_retval[0], CAP_IOCTL, &fp); PROC_UNLOCK(p); if (error) return (EBADF); diff --git a/sys/i386/ibcs2/ibcs2_ioctl.c b/sys/i386/ibcs2/ibcs2_ioctl.c index 90184e3cb6286..3a582ce2f3376 100644 --- a/sys/i386/ibcs2/ibcs2_ioctl.c +++ b/sys/i386/ibcs2/ibcs2_ioctl.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/consio.h> #include <sys/fcntl.h> #include <sys/file.h> @@ -333,7 +334,7 @@ ibcs2_ioctl(td, uap) struct file *fp; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) { + if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) { DPRINTF(("ibcs2_ioctl(%d): bad fd %d ", p->p_pid, uap->fd)); return EBADF; diff --git a/sys/i386/ibcs2/ibcs2_misc.c b/sys/i386/ibcs2/ibcs2_misc.c index c537100ba177d..a08fdf3914d1a 100644 --- a/sys/i386/ibcs2/ibcs2_misc.c +++ b/sys/i386/ibcs2/ibcs2_misc.c @@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$"); */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/dirent.h> #include <sys/fcntl.h> #include <sys/filedesc.h> @@ -336,7 +337,8 @@ ibcs2_getdents(td, uap) #define BSD_DIRENT(cp) ((struct dirent *)(cp)) #define IBCS2_RECLEN(reclen) (reclen + sizeof(u_short)) - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, uap->fd, + CAP_READ | CAP_SEEK, &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); @@ -492,7 +494,8 @@ ibcs2_read(td, uap) u_long *cookies = NULL, *cookiep; int ncookies; - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) { + if ((error = getvnode(td->td_proc->p_fd, uap->fd, + CAP_READ | CAP_SEEK, &fp)) != 0) { if (error == EINVAL) return read(td, (struct read_args *)uap); else diff --git a/sys/i386/ibcs2/imgact_coff.c b/sys/i386/ibcs2/imgact_coff.c index 4a3cb95f8d4ba..44a243cac8354 100644 --- a/sys/i386/ibcs2/imgact_coff.c +++ b/sys/i386/ibcs2/imgact_coff.c @@ -91,9 +91,10 @@ load_coff_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, map_len = round_page(offset + filsz) - trunc_page(map_offset); } - DPRINTF(("%s(%d): vm_mmap(&vmspace->vm_map, &0x%08lx, 0x%x, 0x%x, " + DPRINTF(("%s(%d): vm_mmap(&vmspace->vm_map, &0x%08jx, 0x%x, 0x%x, " "VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, 0x%x)\n", - __FILE__, __LINE__, map_addr, map_len, prot, map_offset)); + __FILE__, __LINE__, (uintmax_t)map_addr, map_len, prot, + map_offset)); if ((error = vm_mmap(&vmspace->vm_map, &map_addr, @@ -123,16 +124,16 @@ load_coff_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, map_addr = trunc_page((vm_offset_t)vmaddr + filsz); map_len = round_page((vm_offset_t)vmaddr + memsz) - map_addr; - DPRINTF(("%s(%d): vm_map_find(&vmspace->vm_map, NULL, 0, &0x%08lx,0x%x, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0)\n", __FILE__, __LINE__, map_addr, map_len)); + DPRINTF(("%s(%d): vm_map_find(&vmspace->vm_map, NULL, 0, &0x%08jx,0x%x, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0)\n", __FILE__, __LINE__, (uintmax_t)map_addr, map_len)); if (map_len != 0) { error = vm_map_find(&vmspace->vm_map, NULL, 0, &map_addr, - map_len, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0); + map_len, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0); if (error) - return error; + return (vm_mmap_to_errno(error)); } - if ((error = vm_mmap(kernel_map, + if ((error = vm_mmap(exec_map, (vm_offset_t *) &data_buf, PAGE_SIZE, VM_PROT_READ, @@ -145,7 +146,7 @@ load_coff_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, error = copyout(data_buf, (caddr_t) map_addr, copy_len); - if (vm_map_remove(kernel_map, + if (vm_map_remove(exec_map, (vm_offset_t) data_buf, (vm_offset_t) data_buf + PAGE_SIZE)) panic("load_coff_section vm_map_remove failed"); @@ -213,7 +214,7 @@ coff_load_file(struct thread *td, char *name) */ VOP_UNLOCK(vp, 0); - if ((error = vm_mmap(kernel_map, + if ((error = vm_mmap(exec_map, (vm_offset_t *) &ptr, PAGE_SIZE, VM_PROT_READ, @@ -279,7 +280,7 @@ coff_load_file(struct thread *td, char *name) error = 0; dealloc_and_fail: - if (vm_map_remove(kernel_map, + if (vm_map_remove(exec_map, (vm_offset_t) ptr, (vm_offset_t) ptr + PAGE_SIZE)) panic("%s vm_map_remove failed", __func__); @@ -306,7 +307,7 @@ exec_coff_imgact(imgp) unsigned long text_offset = 0, text_address = 0, text_size = 0; unsigned long data_offset = 0, data_address = 0, data_size = 0; unsigned long bss_size = 0; - caddr_t hole; + vm_offset_t hole; if (fhdr->f_magic != I386_COFF || !(fhdr->f_flags & F_EXEC)) { @@ -343,9 +344,9 @@ exec_coff_imgact(imgp) for (i = 0; i < nscns; i++) { - DPRINTF(("i = %d, scns[i].s_name = %s, scns[i].s_vaddr = %08lx, " - "scns[i].s_scnptr = %d\n", i, scns[i].s_name, - scns[i].s_vaddr, scns[i].s_scnptr)); + DPRINTF(("i = %d, s_name = %s, s_vaddr = %08lx, " + "s_scnptr = %ld s_size = %lx\n", i, scns[i].s_name, + scns[i].s_vaddr, scns[i].s_scnptr, scns[i].s_size)); if (scns[i].s_flags & STYP_NOLOAD) { /* * A section that is not loaded, for whatever @@ -372,12 +373,12 @@ exec_coff_imgact(imgp) int len = round_page(scns[i].s_size + PAGE_SIZE); int j; - if ((error = vm_mmap(kernel_map, + if ((error = vm_mmap(exec_map, (vm_offset_t *) &buf, len, VM_PROT_READ, VM_PROT_READ, - 0, + MAP_SHARED, OBJT_VNODE, imgp->vp, foff)) != 0) { @@ -411,12 +412,16 @@ exec_coff_imgact(imgp) error = coff_load_file( FIRST_THREAD_IN_PROC(imgp->proc), libname); - if (error) + if (error) { + printf( + "error %d loading coff shared library %s\n", + error, libname); break; + } } free(libbuf, M_TEMP); } - if (vm_map_remove(kernel_map, + if (vm_map_remove(exec_map, (vm_offset_t) buf, (vm_offset_t) buf + len)) panic("exec_coff_imgact vm_map_remove failed"); @@ -429,7 +434,7 @@ exec_coff_imgact(imgp) */ DPRINTF(("%s(%d): load_coff_section(vmspace, " - "imgp->vp, %08lx, %08lx, 0x%x, 0x%x, 0x%x)\n", + "imgp->vp, %08lx, %08lx, 0x%lx, 0x%lx, 0x%x)\n", __FILE__, __LINE__, text_offset, text_address, text_size, text_size, VM_PROT_READ | VM_PROT_EXECUTE)); if ((error = load_coff_section(vmspace, imgp->vp, @@ -446,7 +451,7 @@ exec_coff_imgact(imgp) DPRINTF(("%s(%d): load_coff_section(vmspace, " - "imgp->vp, 0x%08lx, 0x%08lx, 0x%x, 0x%x, 0x%x)\n", + "imgp->vp, 0x%08lx, 0x%08lx, 0x%lx, 0x%lx, 0x%x)\n", __FILE__, __LINE__, data_offset, data_address, data_size + bss_size, data_size, VM_PROT_ALL)); if ((error = load_coff_section(vmspace, imgp->vp, @@ -467,26 +472,25 @@ exec_coff_imgact(imgp) vmspace->vm_taddr = (caddr_t)(void *)(uintptr_t)text_address; vmspace->vm_daddr = (caddr_t)(void *)(uintptr_t)data_address; - hole = (caddr_t)trunc_page((vm_offset_t)vmspace->vm_daddr) + ctob(vmspace->vm_dsize); - + hole = trunc_page((vm_offset_t)vmspace->vm_daddr + + ctob(vmspace->vm_dsize)); - DPRINTF(("%s(%d): vm_map_find(&vmspace->vm_map, NULL, 0, &0x%08lx, PAGE_SIZE, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0)\n", - __FILE__, __LINE__, hole)); + DPRINTF(("%s(%d): vm_map_find(&vmspace->vm_map, NULL, 0, &0x%jx, PAGE_SIZE, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0)\n", + __FILE__, __LINE__, (uintmax_t)hole)); DPRINTF(("imgact: error = %d\n", error)); - error = vm_map_find(&vmspace->vm_map, NULL, 0, - (vm_offset_t *) &hole, PAGE_SIZE, FALSE, - VM_PROT_ALL, VM_PROT_ALL, 0); - - DPRINTF(("IBCS2: start vm_dsize = 0x%x, vm_daddr = 0x%x end = 0x%x\n", + vm_map_find(&vmspace->vm_map, NULL, 0, + (vm_offset_t *)&hole, PAGE_SIZE, VMFS_NO_SPACE, + VM_PROT_ALL, VM_PROT_ALL, 0); + DPRINTF(("IBCS2: start vm_dsize = 0x%x, vm_daddr = 0x%p end = 0x%p\n", ctob(vmspace->vm_dsize), vmspace->vm_daddr, ctob(vmspace->vm_dsize) + vmspace->vm_daddr )); - DPRINTF(("%s(%d): returning successfully!\n", __FILE__, __LINE__)); + DPRINTF(("%s(%d): returning %d!\n", __FILE__, __LINE__, error)); fail: vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); - return error; + return (error); } /* diff --git a/sys/i386/include/param.h b/sys/i386/include/param.h index d95fcf3fd087d..6a0495c4c9529 100644 --- a/sys/i386/include/param.h +++ b/sys/i386/include/param.h @@ -68,7 +68,9 @@ #define MID_MACHINE MID_I386 #if defined(SMP) || defined(KLD_MODULE) +#ifndef MAXCPU #define MAXCPU 32 +#endif #else #define MAXCPU 1 #endif /* SMP || KLD_MODULE */ diff --git a/sys/i386/linux/linux_machdep.c b/sys/i386/linux/linux_machdep.c index d1f6ab99780c3..57756c4d3e83d 100644 --- a/sys/i386/linux/linux_machdep.c +++ b/sys/i386/linux/linux_machdep.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/file.h> #include <sys/fcntl.h> #include <sys/imgact.h> @@ -467,9 +468,12 @@ linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot, * The file descriptor fildes is opened with * read permission, regardless of the * protection options specified. + * + * Checking just CAP_MMAP is fine here, since the real work + * is done in the FreeBSD mmap(). */ - if ((error = fget(td, bsd_args.fd, &fp)) != 0) + if ((error = fget(td, bsd_args.fd, CAP_MMAP, &fp)) != 0) return (error); if (fp->f_type != DTYPE_VNODE) { fdrop(fp, td); diff --git a/sys/i386/xen/pmap.c b/sys/i386/xen/pmap.c index b5e71da2cd818..b19f75c61b8ef 100644 --- a/sys/i386/xen/pmap.c +++ b/sys/i386/xen/pmap.c @@ -2037,7 +2037,7 @@ pmap_collect(pmap_t locked_pmap, struct vpgqueues *vpq) KASSERT((tpte & PG_W) == 0, ("pmap_collect: wired pte %#jx", (uintmax_t)tpte)); if (tpte & PG_A) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); if ((tpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); free = NULL; @@ -2050,7 +2050,7 @@ pmap_collect(pmap_t locked_pmap, struct vpgqueues *vpq) PMAP_UNLOCK(pmap); } if (TAILQ_EMPTY(&m->md.pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } sched_unpin(); } @@ -2222,7 +2222,7 @@ pmap_remove_entry(pmap_t pmap, vm_page_t m, vm_offset_t va) mtx_assert(&vm_page_queue_mtx, MA_OWNED); pmap_pvh_free(&m->md, pmap, va); if (TAILQ_EMPTY(&m->md.pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } /* @@ -2274,7 +2274,7 @@ pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t va, vm_page_t *free) if ((oldpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); if (oldpte & PG_A) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); pmap_remove_entry(pmap, m, va); } return (pmap_unuse_pt(pmap, va, free)); @@ -2430,7 +2430,7 @@ pmap_remove_all(vm_page_t m) pt_entry_t *pte, tpte; vm_page_t free; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_all: page %p is not managed", m)); free = NULL; vm_page_lock_queues(); @@ -2446,7 +2446,7 @@ pmap_remove_all(vm_page_t m) if (tpte & PG_W) pmap->pm_stats.wired_count--; if (tpte & PG_A) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); /* * Update the vm_page_t clean and reference bits. @@ -2459,7 +2459,7 @@ pmap_remove_all(vm_page_t m) free_pv_entry(pmap, pv); PMAP_UNLOCK(pmap); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); PT_UPDATES_FLUSH(); if (*PMAP1) PT_SET_MA(PADDR1, 0); @@ -2616,8 +2616,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, KASSERT(va < UPT_MIN_ADDRESS || va >= UPT_MAX_ADDRESS, ("pmap_enter: invalid to pmap_enter page table pages (va: 0x%x)", va)); - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0 || - (m->oflags & VPO_BUSY) != 0, + KASSERT((m->oflags & (VPO_UNMANAGED | VPO_BUSY)) != 0, ("pmap_enter: page %p is not busy", m)); mpte = NULL; @@ -2715,7 +2714,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, /* * Enter on the PV list if part of our managed memory. */ - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) { + if ((m->oflags & VPO_UNMANAGED) == 0) { KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva, ("pmap_enter: managed mapping within the clean submap")); if (pv == NULL) @@ -2740,7 +2739,7 @@ validate: if ((prot & VM_PROT_WRITE) != 0) { newpte |= PG_RW; if ((newpte & PG_MANAGED) != 0) - vm_page_flag_set(m, PG_WRITEABLE); + vm_page_aflag_set(m, PGA_WRITEABLE); } #ifdef PAE if ((prot & VM_PROT_EXECUTE) == 0) @@ -2765,7 +2764,7 @@ validate: PT_SET_VA(pte, newpte | PG_A, FALSE); if (origpte & PG_A) { if (origpte & PG_MANAGED) - vm_page_flag_set(om, PG_REFERENCED); + vm_page_aflag_set(om, PGA_REFERENCED); if (opa != VM_PAGE_TO_PHYS(m)) invlva = TRUE; #ifdef PAE @@ -2782,7 +2781,7 @@ validate: } if ((origpte & PG_MANAGED) != 0 && TAILQ_EMPTY(&om->md.pv_list)) - vm_page_flag_clear(om, PG_WRITEABLE); + vm_page_aflag_clear(om, PGA_WRITEABLE); if (invlva) pmap_invalidate_page(pmap, va); } else{ @@ -2915,7 +2914,7 @@ pmap_enter_quick_locked(multicall_entry_t **mclpp, int *count, pmap_t pmap, vm_o multicall_entry_t *mcl = *mclpp; KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva || - (m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0, + (m->oflags & VPO_UNMANAGED) != 0, ("pmap_enter_quick_locked: managed mapping within the clean submap")); mtx_assert(&vm_page_queue_mtx, MA_OWNED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); @@ -2979,7 +2978,7 @@ pmap_enter_quick_locked(multicall_entry_t **mclpp, int *count, pmap_t pmap, vm_o /* * Enter on the PV list if part of our managed memory. */ - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0 && + if ((m->oflags & VPO_UNMANAGED) == 0 && !pmap_try_insert_pv_entry(pmap, va, m)) { if (mpte != NULL) { free = NULL; @@ -3008,7 +3007,7 @@ pmap_enter_quick_locked(multicall_entry_t **mclpp, int *count, pmap_t pmap, vm_o /* * Now validate mapping with RO protection */ - if (m->flags & (PG_FICTITIOUS|PG_UNMANAGED)) + if ((m->oflags & VPO_UNMANAGED) != 0) pte_store(pte, pa | PG_V | PG_U); else pte_store(pte, pa | PG_V | PG_U | PG_MANAGED); @@ -3016,7 +3015,7 @@ pmap_enter_quick_locked(multicall_entry_t **mclpp, int *count, pmap_t pmap, vm_o /* * Now validate mapping with RO protection */ - if (m->flags & (PG_FICTITIOUS|PG_UNMANAGED)) + if ((m->oflags & VPO_UNMANAGED) != 0) pa = xpmap_ptom(pa | PG_V | PG_U); else pa = xpmap_ptom(pa | PG_V | PG_U | PG_MANAGED); @@ -3403,7 +3402,7 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m) int loops = 0; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_page_exists_quick: page %p is not managed", m)); rv = FALSE; vm_page_lock_queues(); @@ -3435,7 +3434,7 @@ pmap_page_wired_mappings(vm_page_t m) int count; count = 0; - if ((m->flags & PG_FICTITIOUS) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (count); vm_page_lock_queues(); sched_pin(); @@ -3461,7 +3460,7 @@ pmap_page_is_mapped(vm_page_t m) { boolean_t rv; - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (FALSE); vm_page_lock_queues(); rv = !TAILQ_EMPTY(&m->md.pv_list) || @@ -3550,7 +3549,7 @@ pmap_remove_pages(pmap_t pmap) TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); if (TAILQ_EMPTY(&m->md.pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); pmap_unuse_pt(pmap, pv->pv_va, &free); @@ -3600,18 +3599,18 @@ pmap_is_modified(vm_page_t m) pmap_t pmap; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_modified: page %p is not managed", m)); rv = FALSE; /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be - * concurrently set while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be + * concurrently set while the object is locked. Thus, if PGA_WRITEABLE * is clear, no PTEs can have PG_M set. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return (rv); vm_page_lock_queues(); sched_pin(); @@ -3671,7 +3670,7 @@ pmap_is_referenced(vm_page_t m) pmap_t pmap; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_referenced: page %p is not managed", m)); rv = FALSE; vm_page_lock_queues(); @@ -3732,17 +3731,17 @@ pmap_remove_write(vm_page_t m) pmap_t pmap; pt_entry_t oldpte, *pte; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_write: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be set by - * another thread while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be set by + * another thread while the object is locked. Thus, if PGA_WRITEABLE * is clear, no page table entries need updating. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); sched_pin(); @@ -3770,7 +3769,7 @@ retry: } PMAP_UNLOCK(pmap); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); PT_UPDATES_FLUSH(); if (*PMAP1) PT_SET_MA(PADDR1, 0); @@ -3798,7 +3797,7 @@ pmap_ts_referenced(vm_page_t m) pt_entry_t *pte; int rtval = 0; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_ts_referenced: page %p is not managed", m)); vm_page_lock_queues(); sched_pin(); @@ -3840,18 +3839,18 @@ pmap_clear_modify(vm_page_t m) pmap_t pmap; pt_entry_t *pte; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_modify: page %p is not managed", m)); VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); KASSERT((m->oflags & VPO_BUSY) == 0, ("pmap_clear_modify: page %p is busy", m)); /* - * If the page is not PG_WRITEABLE, then no PTEs can have PG_M set. + * If the page is not PGA_WRITEABLE, then no PTEs can have PG_M set. * If the object containing the page is locked and the page is not - * VPO_BUSY, then PG_WRITEABLE cannot be concurrently set. + * VPO_BUSY, then PGA_WRITEABLE cannot be concurrently set. */ - if ((m->flags & PG_WRITEABLE) == 0) + if ((m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); sched_pin(); @@ -3886,7 +3885,7 @@ pmap_clear_reference(vm_page_t m) pmap_t pmap; pt_entry_t *pte; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_reference: page %p is not managed", m)); vm_page_lock_queues(); sched_pin(); diff --git a/sys/ia64/ia32/ia32_trap.c b/sys/ia64/ia32/ia32_trap.c index 57f4791695609..6755358189a16 100644 --- a/sys/ia64/ia32/ia32_trap.c +++ b/sys/ia64/ia32/ia32_trap.c @@ -144,6 +144,8 @@ ia32_fetch_syscall_args(struct thread *td, struct syscall_args *sa) return (error); } +#include "../../kern/subr_syscall.c" + static void ia32_syscall(struct trapframe *tf) { diff --git a/sys/ia64/ia64/dump_machdep.c b/sys/ia64/ia64/dump_machdep.c index ae82c360c582c..734acc76e43be 100644 --- a/sys/ia64/ia64/dump_machdep.c +++ b/sys/ia64/ia64/dump_machdep.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #endif #include <vm/vm.h> #include <vm/pmap.h> +#include <machine/bootinfo.h> #include <machine/efi.h> #include <machine/elf.h> #include <machine/md_var.h> @@ -191,7 +192,8 @@ foreach_chunk(callback_t cb, void *arg) seqnr = 0; mdp = efi_md_first(); while (mdp != NULL) { - if (mdp->md_type == EFI_MD_TYPE_FREE) { + if (mdp->md_type == EFI_MD_TYPE_FREE || + mdp->md_type == EFI_MD_TYPE_DATA) { error = (*cb)(mdp, seqnr++, arg); if (error) return (-error); @@ -225,6 +227,7 @@ dumpsys(struct dumperinfo *di) ehdr.e_ident[EI_OSABI] = ELFOSABI_STANDALONE; /* XXX big picture? */ ehdr.e_type = ET_CORE; ehdr.e_machine = EM_IA_64; + ehdr.e_entry = ia64_tpa((uintptr_t)bootinfo); ehdr.e_phoff = sizeof(ehdr); ehdr.e_flags = EF_IA_64_ABSOLUTE; /* XXX misuse? */ ehdr.e_ehsize = sizeof(ehdr); diff --git a/sys/ia64/ia64/locore.S b/sys/ia64/ia64/locore.S index d4c1190f5d837..f79ca68f37ca1 100644 --- a/sys/ia64/ia64/locore.S +++ b/sys/ia64/ia64/locore.S @@ -207,13 +207,13 @@ intr_n = 1 intr_n = intr_n + 1 .endr EXPORT(sintrnames) - .word INTRCNT_COUNT * INTRNAME_LEN + data8 INTRCNT_COUNT * INTRNAME_LEN .align 8 EXPORT(intrcnt) .fill INTRCNT_COUNT, 8, 0 EXPORT(sintrcnt) - .word INTRCNT_COUNT + data8 INTRCNT_COUNT * 8 .text // in0: image base diff --git a/sys/ia64/ia64/pmap.c b/sys/ia64/ia64/pmap.c index 0e34f36ccaca3..37116f5af198f 100644 --- a/sys/ia64/ia64/pmap.c +++ b/sys/ia64/ia64/pmap.c @@ -804,7 +804,7 @@ retry: pmap_invalidate_page(va); pmap_switch(oldpmap); if (pmap_accessed(pte)) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); if (pmap_dirty(pte)) vm_page_dirty(m); pmap_free_pte(pte, va); @@ -819,7 +819,7 @@ retry: free_pv_entry(pv); } if (TAILQ_EMPTY(&m->md.pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } if (allocated_pv == NULL) { if (vpq == &vm_page_queues[PQ_INACTIVE]) { @@ -972,7 +972,7 @@ pmap_remove_entry(pmap_t pmap, vm_page_t m, vm_offset_t va, pv_entry_t pv) TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); m->md.pv_list_count--; if (TAILQ_FIRST(&m->md.pv_list) == NULL) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); TAILQ_REMOVE(&pmap->pm_pvlist, pv, pv_plist); free_pv_entry(pv); @@ -1198,7 +1198,7 @@ pmap_remove_pte(pmap_t pmap, struct ia64_lpte *pte, vm_offset_t va, if (pmap_dirty(pte)) vm_page_dirty(m); if (pmap_accessed(pte)) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); error = pmap_remove_entry(pmap, m, va, pv); } @@ -1217,43 +1217,54 @@ pmap_kextract(vm_offset_t va) { struct ia64_lpte *pte; uint64_t *pbvm_pgtbl; + vm_paddr_t pa; u_int idx; KASSERT(va >= VM_MAXUSER_ADDRESS, ("Must be kernel VA")); /* Regions 6 and 7 are direct mapped. */ - if (va >= IA64_RR_BASE(6)) - return (IA64_RR_MASK(va)); + if (va >= IA64_RR_BASE(6)) { + pa = IA64_RR_MASK(va); + goto out; + } - /* Bail out if the virtual address is beyond our limits. */ + /* Region 5 is our KVA. Bail out if the VA is beyond our limits. */ if (va >= kernel_vm_end) - return (0); - + goto err_out; if (va >= VM_MIN_KERNEL_ADDRESS) { pte = pmap_find_kpte(va); - return (pmap_present(pte) ? pmap_ppn(pte)|(va&PAGE_MASK) : 0); + pa = pmap_present(pte) ? pmap_ppn(pte) | (va & PAGE_MASK) : 0; + goto out; } - /* PBVM page table. */ - if (va >= IA64_PBVM_PGTBL + bootinfo->bi_pbvm_pgtblsz); - return (0); - if (va >= IA64_PBVM_PGTBL) - return (va - IA64_PBVM_PGTBL) + bootinfo->bi_pbvm_pgtbl; + /* The PBVM page table. */ + if (va >= IA64_PBVM_PGTBL + bootinfo->bi_pbvm_pgtblsz) + goto err_out; + if (va >= IA64_PBVM_PGTBL) { + pa = (va - IA64_PBVM_PGTBL) + bootinfo->bi_pbvm_pgtbl; + goto out; + } - /* PBVM. */ + /* The PBVM itself. */ if (va >= IA64_PBVM_BASE) { pbvm_pgtbl = (void *)IA64_PBVM_PGTBL; idx = (va - IA64_PBVM_BASE) >> IA64_PBVM_PAGE_SHIFT; if (idx >= (bootinfo->bi_pbvm_pgtblsz >> 3)) - return (0); + goto err_out; if ((pbvm_pgtbl[idx] & PTE_PRESENT) == 0) - return (0); - return ((pbvm_pgtbl[idx] & PTE_PPN_MASK) + - (va & IA64_PBVM_PAGE_MASK)); + goto err_out; + pa = (pbvm_pgtbl[idx] & PTE_PPN_MASK) + + (va & IA64_PBVM_PAGE_MASK); + goto out; } - printf("XXX: %s: va=%#lx\n", __func__, va); - return (0); + err_out: + printf("XXX: %s: va=%#lx is invalid\n", __func__, va); + pa = 0; + /* FALLTHROUGH */ + + out: + return (pa); } /* @@ -1431,7 +1442,7 @@ pmap_remove_all(vm_page_t m) pmap_t oldpmap; pv_entry_t pv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_all: page %p is not managed", m)); vm_page_lock_queues(); while ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) { @@ -1449,7 +1460,7 @@ pmap_remove_all(vm_page_t m) pmap_switch(oldpmap); PMAP_UNLOCK(pmap); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } @@ -1537,8 +1548,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, va &= ~PAGE_MASK; KASSERT(va <= VM_MAX_KERNEL_ADDRESS, ("pmap_enter: toobig")); - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0 || - (m->oflags & VPO_BUSY) != 0, + KASSERT((m->oflags & (VPO_UNMANAGED | VPO_BUSY)) != 0, ("pmap_enter: page %p is not busy", m)); /* @@ -1608,7 +1618,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, /* * Enter on the PV list if part of our managed memory. */ - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) { + if ((m->oflags & VPO_UNMANAGED) == 0) { KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva, ("pmap_enter: managed mapping within the clean submap")); pmap_insert_entry(pmap, va, m); @@ -1637,7 +1647,7 @@ validate: ia64_sync_icache(va, PAGE_SIZE); if ((prot & VM_PROT_WRITE) != 0 && managed) - vm_page_flag_set(m, PG_WRITEABLE); + vm_page_aflag_set(m, PGA_WRITEABLE); vm_page_unlock_queues(); pmap_switch(oldpmap); PMAP_UNLOCK(pmap); @@ -1709,7 +1719,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, boolean_t managed; KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva || - (m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0, + (m->oflags & VPO_UNMANAGED) != 0, ("pmap_enter_quick_locked: managed mapping within the clean submap")); mtx_assert(&vm_page_queue_mtx, MA_OWNED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); @@ -1719,7 +1729,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, if (!pmap_present(pte)) { /* Enter on the PV list if the page is managed. */ - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) { + if ((m->oflags & VPO_UNMANAGED) == 0) { if (!pmap_try_insert_pv_entry(pmap, va, m)) { pmap_free_pte(pte, va); return; @@ -1889,7 +1899,7 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m) int loops = 0; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_page_exists_quick: page %p is not managed", m)); rv = FALSE; vm_page_lock_queues(); @@ -1921,7 +1931,7 @@ pmap_page_wired_mappings(vm_page_t m) int count; count = 0; - if ((m->flags & PG_FICTITIOUS) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (count); vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { @@ -1999,7 +2009,7 @@ pmap_ts_referenced(vm_page_t m) pv_entry_t pv; int count = 0; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_ts_referenced: page %p is not managed", m)); vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { @@ -2033,18 +2043,18 @@ pmap_is_modified(vm_page_t m) pv_entry_t pv; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_modified: page %p is not managed", m)); rv = FALSE; /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be - * concurrently set while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be + * concurrently set while the object is locked. Thus, if PGA_WRITEABLE * is clear, no PTEs can be dirty. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return (rv); vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { @@ -2093,7 +2103,7 @@ pmap_is_referenced(vm_page_t m) pv_entry_t pv; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_referenced: page %p is not managed", m)); rv = FALSE; vm_page_lock_queues(); @@ -2122,18 +2132,18 @@ pmap_clear_modify(vm_page_t m) pmap_t oldpmap; pv_entry_t pv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_modify: page %p is not managed", m)); VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); KASSERT((m->oflags & VPO_BUSY) == 0, ("pmap_clear_modify: page %p is busy", m)); /* - * If the page is not PG_WRITEABLE, then no PTEs can be modified. + * If the page is not PGA_WRITEABLE, then no PTEs can be modified. * If the object containing the page is locked and the page is not - * VPO_BUSY, then PG_WRITEABLE cannot be concurrently set. + * VPO_BUSY, then PGA_WRITEABLE cannot be concurrently set. */ - if ((m->flags & PG_WRITEABLE) == 0) + if ((m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { @@ -2163,7 +2173,7 @@ pmap_clear_reference(vm_page_t m) pmap_t oldpmap; pv_entry_t pv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_reference: page %p is not managed", m)); vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { @@ -2192,17 +2202,17 @@ pmap_remove_write(vm_page_t m) pv_entry_t pv; vm_prot_t prot; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_write: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be set by - * another thread while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be set by + * another thread while the object is locked. Thus, if PGA_WRITEABLE * is clear, no page table entries need updating. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { @@ -2225,7 +2235,7 @@ pmap_remove_write(vm_page_t m) pmap_switch(oldpmap); PMAP_UNLOCK(pmap); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } diff --git a/sys/ia64/ia64/trap.c b/sys/ia64/ia64/trap.c index 4b84f769340e0..d587b05868fd6 100644 --- a/sys/ia64/ia64/trap.c +++ b/sys/ia64/ia64/trap.c @@ -929,6 +929,8 @@ cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) return (0); } +#include "../../kern/subr_syscall.c" + /* * Process a system call. * diff --git a/sys/ia64/include/param.h b/sys/ia64/include/param.h index 36b27e048903d..d996441f6246f 100644 --- a/sys/ia64/include/param.h +++ b/sys/ia64/include/param.h @@ -62,7 +62,9 @@ #endif #if defined(SMP) || defined(KLD_MODULE) -#define MAXCPU 32 +#ifndef MAXCPU +#define MAXCPU 64 +#endif #else #define MAXCPU 1 #endif diff --git a/sys/kern/capabilities.conf b/sys/kern/capabilities.conf index f9a6b242d99b0..4a62643623eb7 100644 --- a/sys/kern/capabilities.conf +++ b/sys/kern/capabilities.conf @@ -196,7 +196,7 @@ fpathconf ## ## Allow various file descriptor-based I/O operations, subject to capability -## rights. mmap(2) requires further attention. +## rights. ## freebsd6_ftruncate freebsd6_lseek @@ -239,9 +239,7 @@ getcontext ## Allow directory I/O on a file descriptor, subject to capability rights. ## Originally we had separate capabilities for directory-specific read ## operations, but on BSD we allow reading the raw directory data, so we just -## rely on CAP_READ (etc) now. -## -## XXXRW: Possibly these should also use CAP_SEEK. +## rely on CAP_READ and CAP_SEEK now. ## getdents getdirentries @@ -336,8 +334,6 @@ issetugid ## Allow kevent(2), as we will authorize based on capability rights on the ## target descriptor. ## -## XXXRW: Do we do this? -## kevent ## @@ -406,9 +402,6 @@ mlockall ## Allow memory mapping a file descriptor, and updating protections, subject ## to capability rights. ## -## XXXRW: We currently don't properly mask VM protections using capability -## rights. -## mmap mprotect @@ -447,28 +440,26 @@ obreak olio_listio ## -## Once Capsicum is fully merged, some of the *at(2) calls which can be -## semantically constrained will be permitted in capability mode. For now, -## we will simply not allow them to be called. +## Operations relative to directory capabilities. ## -#faccessat -#fstatat -#fchmodat -#futimesat -#mkdirat -#rmdirat -#mkfifoat -#mknodat -#openat -#renameat +faccessat +fstatat +fchmodat +futimesat +mkdirat +rmdirat +mkfifoat +mknodat +openat +renameat ## -## ONCE CAPSICUM IS FULLY MERGED: -## Allow entry into open(2). This system call will fail, since access to the global -## file namespace has been disallowed, but allowing entry into the syscall means -## that an audit trail will be generated (which is also very useful for debugging), +## Allow entry into open(2). This system call will fail, since access to the +## global file namespace has been disallowed, but allowing entry into the +## syscall means that an audit trail will be generated (which is also very +## useful for debugging). ## -#open +open ## ## Allow poll(2), which will be scoped by capability rights. @@ -484,7 +475,7 @@ openbsd_poll pdfork pdgetpid pdkill -pdwait4 +#pdwait4 # not yet implemented ## ## Allow pipe(2). @@ -648,11 +639,9 @@ setsockopt setuid ## -## ONCE CAPSICUM IS FULLY MERGED: -## Allow shm_open(2), which is scoped so as to allow only access to new -## anonymous objects. +## shm_open(2) is scoped so as to allow only access to new anonymous objects. ## -#shm_open +shm_open ## ## Allow I/O-related file descriptors, subject to capability rights. diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index be5c26fec029b..fc072457c1916 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -790,7 +790,8 @@ create_init(const void *udata __unused) struct ucred *newcred, *oldcred; int error; - error = fork1(&thread0, RFFDG | RFPROC | RFSTOPPED, 0, &initproc); + error = fork1(&thread0, RFFDG | RFPROC | RFSTOPPED, 0, &initproc, + NULL, 0); if (error) panic("cannot fork init: %d\n", error); KASSERT(initproc->p_pid == 1, ("create_init: initproc->p_pid != 1")); diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 004516b6e8ded..d1063f4e83e15 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD + * created from FreeBSD: head/sys/kern/syscalls.master 224987 2011-08-18 22:51:30Z jonathan */ #include "opt_compat.h" @@ -39,7 +39,7 @@ struct sysent sysent[] = { { 0, (sy_call_t *)fork, AUE_FORK, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 2 = fork */ { AS(read_args), (sy_call_t *)read, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 3 = read */ { AS(write_args), (sy_call_t *)write, AUE_NULL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 4 = write */ - { AS(open_args), (sy_call_t *)open, AUE_OPEN_RWTC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 5 = open */ + { AS(open_args), (sy_call_t *)open, AUE_OPEN_RWTC, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 5 = open */ { AS(close_args), (sy_call_t *)close, AUE_CLOSE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 6 = close */ { AS(wait_args), (sy_call_t *)wait4, AUE_WAIT4, NULL, 0, 0, 0, SY_THR_STATIC }, /* 7 = wait4 */ { compat(AS(ocreat_args),creat), AUE_CREAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 8 = old creat */ @@ -516,26 +516,26 @@ struct sysent sysent[] = { { AS(truncate_args), (sy_call_t *)truncate, AUE_TRUNCATE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 479 = truncate */ { AS(ftruncate_args), (sy_call_t *)ftruncate, AUE_FTRUNCATE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 480 = ftruncate */ { AS(thr_kill2_args), (sy_call_t *)thr_kill2, AUE_KILL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 481 = thr_kill2 */ - { AS(shm_open_args), (sy_call_t *)shm_open, AUE_SHMOPEN, NULL, 0, 0, 0, SY_THR_STATIC }, /* 482 = shm_open */ + { AS(shm_open_args), (sy_call_t *)shm_open, AUE_SHMOPEN, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 482 = shm_open */ { AS(shm_unlink_args), (sy_call_t *)shm_unlink, AUE_SHMUNLINK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 483 = shm_unlink */ { AS(cpuset_args), (sy_call_t *)cpuset, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 484 = cpuset */ { AS(cpuset_setid_args), (sy_call_t *)cpuset_setid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 485 = cpuset_setid */ { AS(cpuset_getid_args), (sy_call_t *)cpuset_getid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 486 = cpuset_getid */ { AS(cpuset_getaffinity_args), (sy_call_t *)cpuset_getaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 487 = cpuset_getaffinity */ { AS(cpuset_setaffinity_args), (sy_call_t *)cpuset_setaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 488 = cpuset_setaffinity */ - { AS(faccessat_args), (sy_call_t *)faccessat, AUE_FACCESSAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 489 = faccessat */ - { AS(fchmodat_args), (sy_call_t *)fchmodat, AUE_FCHMODAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 490 = fchmodat */ + { AS(faccessat_args), (sy_call_t *)faccessat, AUE_FACCESSAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 489 = faccessat */ + { AS(fchmodat_args), (sy_call_t *)fchmodat, AUE_FCHMODAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 490 = fchmodat */ { AS(fchownat_args), (sy_call_t *)fchownat, AUE_FCHOWNAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 491 = fchownat */ { AS(fexecve_args), (sy_call_t *)fexecve, AUE_FEXECVE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 492 = fexecve */ - { AS(fstatat_args), (sy_call_t *)fstatat, AUE_FSTATAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 493 = fstatat */ - { AS(futimesat_args), (sy_call_t *)futimesat, AUE_FUTIMESAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 494 = futimesat */ + { AS(fstatat_args), (sy_call_t *)fstatat, AUE_FSTATAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 493 = fstatat */ + { AS(futimesat_args), (sy_call_t *)futimesat, AUE_FUTIMESAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 494 = futimesat */ { AS(linkat_args), (sy_call_t *)linkat, AUE_LINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 495 = linkat */ - { AS(mkdirat_args), (sy_call_t *)mkdirat, AUE_MKDIRAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 496 = mkdirat */ - { AS(mkfifoat_args), (sy_call_t *)mkfifoat, AUE_MKFIFOAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 497 = mkfifoat */ - { AS(mknodat_args), (sy_call_t *)mknodat, AUE_MKNODAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 498 = mknodat */ - { AS(openat_args), (sy_call_t *)openat, AUE_OPENAT_RWTC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 499 = openat */ + { AS(mkdirat_args), (sy_call_t *)mkdirat, AUE_MKDIRAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 496 = mkdirat */ + { AS(mkfifoat_args), (sy_call_t *)mkfifoat, AUE_MKFIFOAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 497 = mkfifoat */ + { AS(mknodat_args), (sy_call_t *)mknodat, AUE_MKNODAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 498 = mknodat */ + { AS(openat_args), (sy_call_t *)openat, AUE_OPENAT_RWTC, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 499 = openat */ { AS(readlinkat_args), (sy_call_t *)readlinkat, AUE_READLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 500 = readlinkat */ - { AS(renameat_args), (sy_call_t *)renameat, AUE_RENAMEAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 501 = renameat */ + { AS(renameat_args), (sy_call_t *)renameat, AUE_RENAMEAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 501 = renameat */ { AS(symlinkat_args), (sy_call_t *)symlinkat, AUE_SYMLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 502 = symlinkat */ { AS(unlinkat_args), (sy_call_t *)unlinkat, AUE_UNLINKAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 503 = unlinkat */ { AS(posix_openpt_args), (sy_call_t *)posix_openpt, AUE_POSIX_OPENPT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 504 = posix_openpt */ @@ -552,10 +552,10 @@ struct sysent sysent[] = { { AS(cap_getrights_args), (sy_call_t *)cap_getrights, AUE_CAP_GETRIGHTS, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 515 = cap_getrights */ { 0, (sy_call_t *)cap_enter, AUE_CAP_ENTER, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 516 = cap_enter */ { AS(cap_getmode_args), (sy_call_t *)cap_getmode, AUE_CAP_GETMODE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 517 = cap_getmode */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 518 = pdfork */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 519 = pdkill */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 520 = pdgetpid */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 521 = pdwait */ + { AS(pdfork_args), (sy_call_t *)pdfork, AUE_PDFORK, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 518 = pdfork */ + { AS(pdkill_args), (sy_call_t *)pdkill, AUE_PDKILL, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 519 = pdkill */ + { AS(pdgetpid_args), (sy_call_t *)pdgetpid, AUE_PDGETPID, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 520 = pdgetpid */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 521 = pdwait4 */ { AS(pselect_args), (sy_call_t *)pselect, AUE_SELECT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 522 = pselect */ { AS(getloginclass_args), (sy_call_t *)getloginclass, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 523 = getloginclass */ { AS(setloginclass_args), (sy_call_t *)setloginclass, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 524 = setloginclass */ diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c index a4d90c78218e4..8da16d288b3eb 100644 --- a/sys/kern/kern_conf.c +++ b/sys/kern/kern_conf.c @@ -764,7 +764,8 @@ make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit, LIST_REMOVE(dev, si_list); dev_unlock(); devfs_free(dev); - } + } else + dev_unlock(); return (res); } } diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 829ece218b099..4aaed1f040e8d 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include "opt_ddb.h" #include "opt_ktrace.h" +#include "opt_procdesc.h" #include <sys/param.h> #include <sys/systm.h> @@ -65,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include <sys/pipe.h> #include <sys/priv.h> #include <sys/proc.h> +#include <sys/procdesc.h> #include <sys/protosw.h> #include <sys/racct.h> #include <sys/resourcevar.h> @@ -120,6 +122,8 @@ static int fill_vnode_info(struct vnode *vp, struct kinfo_file *kif); static int fill_socket_info(struct socket *so, struct kinfo_file *kif); static int fill_pts_info(struct tty *tp, struct kinfo_file *kif); static int fill_pipe_info(struct pipe *pi, struct kinfo_file *kif); +static int fill_procdesc_info(struct procdesc *pdp, + struct kinfo_file *kif); /* * A process is initially started out with NDFILE descriptors stored within @@ -431,6 +435,26 @@ fdtofp(int fd, struct filedesc *fdp) return (fp); } +static inline int +fdunwrap(int fd, cap_rights_t rights, struct filedesc *fdp, struct file **fpp) +{ + + *fpp = fdtofp(fd, fdp); + if (*fpp == NULL) + return (EBADF); + +#ifdef CAPABILITIES + if ((*fpp)->f_type == DTYPE_CAPABILITY) { + int err = cap_funwrap(*fpp, rights, fpp); + if (err != 0) { + *fpp = NULL; + return (err); + } + } +#endif /* CAPABILITIES */ + return (0); +} + int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) { @@ -489,9 +513,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_GETFL: FILEDESC_SLOCK(fdp); - if ((fp = fdtofp(fd, fdp)) == NULL) { + error = fdunwrap(fd, CAP_FCNTL, fdp, &fp); + if (error != 0) { FILEDESC_SUNLOCK(fdp); - error = EBADF; break; } td->td_retval[0] = OFLAGS(fp->f_flag); @@ -500,9 +524,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_SETFL: FILEDESC_SLOCK(fdp); - if ((fp = fdtofp(fd, fdp)) == NULL) { + error = fdunwrap(fd, CAP_FCNTL, fdp, &fp); + if (error != 0) { FILEDESC_SUNLOCK(fdp); - error = EBADF; break; } fhold(fp); @@ -532,9 +556,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_GETOWN: FILEDESC_SLOCK(fdp); - if ((fp = fdtofp(fd, fdp)) == NULL) { + error = fdunwrap(fd, CAP_FCNTL, fdp, &fp); + if (error != 0) { FILEDESC_SUNLOCK(fdp); - error = EBADF; break; } fhold(fp); @@ -547,9 +571,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_SETOWN: FILEDESC_SLOCK(fdp); - if ((fp = fdtofp(fd, fdp)) == NULL) { + error = fdunwrap(fd, CAP_FCNTL, fdp, &fp); + if (error != 0) { FILEDESC_SUNLOCK(fdp); - error = EBADF; break; } fhold(fp); @@ -573,9 +597,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_SETLK: do_setlk: FILEDESC_SLOCK(fdp); - if ((fp = fdtofp(fd, fdp)) == NULL) { + error = fdunwrap(fd, CAP_FLOCK, fdp, &fp); + if (error != 0) { FILEDESC_SUNLOCK(fdp); - error = EBADF; break; } if (fp->f_type != DTYPE_VNODE) { @@ -668,9 +692,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) case F_GETLK: FILEDESC_SLOCK(fdp); - if ((fp = fdtofp(fd, fdp)) == NULL) { + error = fdunwrap(fd, CAP_FLOCK, fdp, &fp); + if (error != 0) { FILEDESC_SUNLOCK(fdp); - error = EBADF; break; } if (fp->f_type != DTYPE_VNODE) { @@ -1312,7 +1336,7 @@ kern_fstat(struct thread *td, int fd, struct stat *sbp) AUDIT_ARG_FD(fd); - if ((error = fget(td, fd, &fp)) != 0) + if ((error = fget(td, fd, CAP_FSTAT, &fp)) != 0) return (error); AUDIT_ARG_FILE(td->td_proc, fp); @@ -1368,7 +1392,7 @@ fpathconf(struct thread *td, struct fpathconf_args *uap) struct vnode *vp; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) + if ((error = fget(td, uap->fd, CAP_FPATHCONF, &fp)) != 0) return (error); /* If asynchronous I/O is available, it works for all descriptors. */ @@ -2294,7 +2318,7 @@ fget_unlocked(struct filedesc *fdp, int fd) #define FGET_GETCAP 0x00000001 static __inline int _fget(struct thread *td, int fd, struct file **fpp, int flags, - cap_rights_t needrights, cap_rights_t *haverights, u_char *maxprotp, + cap_rights_t needrights, cap_rights_t *haverightsp, u_char *maxprotp, int fget_flags) { struct filedesc *fdp; @@ -2316,6 +2340,16 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags, #ifdef CAPABILITIES /* + * If this is a capability, what rights does it have? + */ + if (haverightsp != NULL) { + if (fp->f_type == DTYPE_CAPABILITY) + *haverightsp = cap_rights(fp); + else + *haverightsp = CAP_MASK_VALID; + } + + /* * If a capability has been requested, return the capability directly. * Otherwise, check capability rights, extract the underlying object, * and check its access flags. @@ -2369,28 +2403,36 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags, } int -fget(struct thread *td, int fd, struct file **fpp) +fget(struct thread *td, int fd, cap_rights_t rights, struct file **fpp) +{ + + return(_fget(td, fd, fpp, 0, rights, NULL, NULL, 0)); +} + +int +fget_mmap(struct thread *td, int fd, cap_rights_t rights, u_char *maxprotp, + struct file **fpp) { - return(_fget(td, fd, fpp, 0, 0, NULL, NULL, 0)); + return (_fget(td, fd, fpp, 0, rights, NULL, maxprotp, 0)); } int -fget_read(struct thread *td, int fd, struct file **fpp) +fget_read(struct thread *td, int fd, cap_rights_t rights, struct file **fpp) { - return(_fget(td, fd, fpp, FREAD, 0, NULL, NULL, 0)); + return(_fget(td, fd, fpp, FREAD, rights, NULL, NULL, 0)); } int -fget_write(struct thread *td, int fd, struct file **fpp) +fget_write(struct thread *td, int fd, cap_rights_t rights, struct file **fpp) { - return(_fget(td, fd, fpp, FWRITE, 0, NULL, NULL, 0)); + return (_fget(td, fd, fpp, FWRITE, rights, NULL, NULL, 0)); } /* - * Unlike the other fget() calls, which will accept and check capability rights + * Unlike the other fget() calls, which accept and check capability rights * but never return capabilities, fgetcap() returns the capability but doesn't * check capability rights. */ @@ -2410,13 +2452,15 @@ fgetcap(struct thread *td, int fd, struct file **fpp) * XXX: what about the unused flags ? */ static __inline int -_fgetvp(struct thread *td, int fd, struct vnode **vpp, int flags) +_fgetvp(struct thread *td, int fd, int flags, cap_rights_t needrights, + cap_rights_t *haverightsp, struct vnode **vpp) { struct file *fp; int error; *vpp = NULL; - if ((error = _fget(td, fd, &fp, flags, 0, NULL, NULL, 0)) != 0) + if ((error = _fget(td, fd, &fp, flags, needrights, haverightsp, + NULL, 0)) != 0) return (error); if (fp->f_vnode == NULL) { error = EINVAL; @@ -2430,25 +2474,33 @@ _fgetvp(struct thread *td, int fd, struct vnode **vpp, int flags) } int -fgetvp(struct thread *td, int fd, struct vnode **vpp) +fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp) { - return (_fgetvp(td, fd, vpp, 0)); + return (_fgetvp(td, fd, 0, rights, NULL, vpp)); } int -fgetvp_read(struct thread *td, int fd, struct vnode **vpp) +fgetvp_rights(struct thread *td, int fd, cap_rights_t need, cap_rights_t *have, + struct vnode **vpp) +{ + return (_fgetvp(td, fd, 0, need, have, vpp)); +} + +int +fgetvp_read(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp) { - return (_fgetvp(td, fd, vpp, FREAD)); + return (_fgetvp(td, fd, FREAD, rights, NULL, vpp)); } #ifdef notyet int -fgetvp_write(struct thread *td, int fd, struct vnode **vpp) +fgetvp_write(struct thread *td, int fd, cap_rights_t rights, + struct vnode **vpp) { - return (_fgetvp(td, fd, vpp, FWRITE)); + return (_fgetvp(td, fd, FWRITE, rights, NULL, vpp)); } #endif @@ -2464,7 +2516,8 @@ fgetvp_write(struct thread *td, int fd, struct vnode **vpp) * during use. */ int -fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp) +fgetsock(struct thread *td, int fd, cap_rights_t rights, struct socket **spp, + u_int *fflagp) { struct file *fp; int error; @@ -2472,7 +2525,7 @@ fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp) *spp = NULL; if (fflagp != NULL) *fflagp = 0; - if ((error = _fget(td, fd, &fp, 0, 0, NULL, NULL, 0)) != 0) + if ((error = _fget(td, fd, &fp, 0, rights, NULL, NULL, 0)) != 0) return (error); if (fp->f_type != DTYPE_SOCKET) { error = ENOTSOCK; @@ -2557,7 +2610,7 @@ flock(struct thread *td, struct flock_args *uap) int vfslocked; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) + if ((error = fget(td, uap->fd, CAP_FLOCK, &fp)) != 0) return (error); if (fp->f_type != DTYPE_VNODE) { fdrop(fp, td); @@ -2946,6 +2999,22 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) so = NULL; tp = NULL; kif->kf_fd = i; + +#ifdef CAPABILITIES + /* + * When reporting a capability, most fields will be from the + * underlying object, but do mark as a capability. With + * ofiledesc, we don't have a field to export the cap_rights_t, + * but we do with the new filedesc. + */ + if (fp->f_type == DTYPE_CAPABILITY) { + kif->kf_flags |= KF_FLAG_CAPABILITY; + (void)cap_funwrap(fp, 0, &fp); + } +#else + KASSERT(fp->f_type != DTYPE_CAPABILITY, + ("sysctl_kern_proc_ofiledesc: saw capability")); +#endif switch (fp->f_type) { case DTYPE_VNODE: kif->kf_type = KF_TYPE_VNODE; @@ -2991,6 +3060,12 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) tp = fp->f_data; break; +#ifdef PROCDESC + case DTYPE_PROCDESC: + kif->kf_type = KF_TYPE_PROCDESC; + break; +#endif + default: kif->kf_type = KF_TYPE_UNKNOWN; break; @@ -3153,6 +3228,9 @@ export_fd_for_sysctl(void *data, int type, int fd, int fflags, int refcnt, case KF_TYPE_PTS: error = fill_pts_info((struct tty *)data, kif); break; + case KF_TYPE_PROCDESC: + error = fill_procdesc_info((struct procdesc *)data, kif); + break; default: error = 0; } @@ -3262,6 +3340,22 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) if ((fp = fdp->fd_ofiles[i]) == NULL) continue; data = NULL; + +#ifdef CAPABILITIES + /* + * When reporting a capability, most fields will be from the + * underlying object, but do mark as a capability and export + * the capability rights mask. + */ + if (fp->f_type == DTYPE_CAPABILITY) { + kif->kf_flags |= KF_FLAG_CAPABILITY; + kif->kf_cap_rights = cap_rights(fp); + (void)cap_funwrap(fp, 0, &fp); + } +#else /* !CAPABILITIES */ + KASSERT(fp->f_type != DTYPE_CAPABILITY, + ("sysctl_kern_proc_filedesc: saw capability")); +#endif switch (fp->f_type) { case DTYPE_VNODE: type = KF_TYPE_VNODE; @@ -3310,6 +3404,13 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) data = fp->f_data; break; +#ifdef PROCDESC + case DTYPE_PROCDESC: + type = KF_TYPE_PROCDESC; + data = fp->f_data; + break; +#endif + default: type = KF_TYPE_UNKNOWN; break; @@ -3505,6 +3606,16 @@ fill_pipe_info(struct pipe *pi, struct kinfo_file *kif) return (0); } +static int +fill_procdesc_info(struct procdesc *pdp, struct kinfo_file *kif) +{ + + if (pdp == NULL) + return (1); + kif->kf_un.kf_proc.kf_pid = pdp->pd_pid; + return (0); +} + static SYSCTL_NODE(_kern_proc, KERN_PROC_FILEDESC, filedesc, CTLFLAG_RD, sysctl_kern_proc_filedesc, "Process filedesc entries"); @@ -3693,6 +3804,22 @@ badfo_close(struct file *fp, struct thread *td) return (EBADF); } +static int +badfo_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, + struct thread *td) +{ + + return (EBADF); +} + +static int +badfo_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, + struct thread *td) +{ + + return (EBADF); +} + struct fileops badfileops = { .fo_read = badfo_readwrite, .fo_write = badfo_readwrite, @@ -3702,8 +3829,25 @@ struct fileops badfileops = { .fo_kqfilter = badfo_kqfilter, .fo_stat = badfo_stat, .fo_close = badfo_close, + .fo_chmod = badfo_chmod, + .fo_chown = badfo_chown, }; +int +invfo_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, + struct thread *td) +{ + + return (EINVAL); +} + +int +invfo_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, + struct thread *td) +{ + + return (EINVAL); +} /*-------------------------------------------------------------------*/ diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index e14ae0211bc6c..dc11411fd5df2 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -122,6 +123,8 @@ static struct fileops kqueueops = { .fo_kqfilter = kqueue_kqfilter, .fo_stat = kqueue_stat, .fo_close = kqueue_close, + .fo_chmod = invfo_chmod, + .fo_chown = invfo_chown, }; static int knote_attach(struct knote *kn, struct kqueue *kq); @@ -816,7 +819,7 @@ kern_kevent(struct thread *td, int fd, int nchanges, int nevents, struct file *fp; int i, n, nerrors, error; - if ((error = fget(td, fd, &fp)) != 0) + if ((error = fget(td, fd, CAP_POST_EVENT, &fp)) != 0) return (error); if ((error = kqueue_acquire(fp, &kq)) != 0) goto done_norel; @@ -972,7 +975,7 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int wa findkn: if (fops->f_isfd) { KASSERT(td != NULL, ("td is NULL")); - error = fget(td, kev->ident, &fp); + error = fget(td, kev->ident, CAP_POLL_EVENT, &fp); if (error) goto done; @@ -1701,6 +1704,7 @@ kqueue_close(struct file *fp, struct thread *td) SLIST_REMOVE(&fdp->fd_kqlist, kq, kqueue, kq_list); FILEDESC_XUNLOCK(fdp); + seldrain(&kq->kq_sel); knlist_destroy(&kq->kq_sel.si_note); mtx_destroy(&kq->kq_lock); kq->kq_fdp = NULL; @@ -2181,7 +2185,7 @@ kqfd_register(int fd, struct kevent *kev, struct thread *td, int waitok) struct file *fp; int error; - if ((error = fget(td, fd, &fp)) != 0) + if ((error = fget(td, fd, CAP_POST_EVENT, &fp)) != 0) return (error); if ((error = kqueue_acquire(fp, &kq)) != 0) goto noacquire; diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index f7f80af68c25a..1c424204800f2 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -439,7 +439,11 @@ interpret: imgp->vp = binvp; } else { AUDIT_ARG_FD(args->fd); - error = fgetvp(td, args->fd, &binvp); + /* + * Some might argue that CAP_READ and/or CAP_MMAP should also + * be required here; such arguments will be entertained. + */ + error = fgetvp_read(td, args->fd, CAP_FEXECVE, &binvp); if (error) goto exec_fail; vfslocked = VFS_LOCK_GIANT(binvp->v_mount); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 30b94b6a28a40..e5d60942f7c07 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -40,16 +40,19 @@ __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include "opt_kdtrace.h" #include "opt_ktrace.h" +#include "opt_procdesc.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/sysproto.h> +#include <sys/capability.h> #include <sys/eventhandler.h> #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/proc.h> +#include <sys/procdesc.h> #include <sys/pioctl.h> #include <sys/jail.h> #include <sys/tty.h> @@ -461,39 +464,54 @@ exit1(struct thread *td, int rv) knlist_clear(&p->p_klist, 1); /* - * Notify parent that we're gone. If parent has the PS_NOCLDWAIT - * flag set, or if the handler is set to SIG_IGN, notify process - * 1 instead (and hope it will handle this situation). + * If this is a process with a descriptor, we may not need to deliver + * a signal to the parent. proctree_lock is held over + * procdesc_exit() to serialize concurrent calls to close() and + * exit(). */ - PROC_LOCK(p->p_pptr); - mtx_lock(&p->p_pptr->p_sigacts->ps_mtx); - if (p->p_pptr->p_sigacts->ps_flag & (PS_NOCLDWAIT | PS_CLDSIGIGN)) { - struct proc *pp; - - mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx); - pp = p->p_pptr; - PROC_UNLOCK(pp); - proc_reparent(p, initproc); - p->p_sigparent = SIGCHLD; - PROC_LOCK(p->p_pptr); - +#ifdef PROCDESC + if (p->p_procdesc == NULL || procdesc_exit(p)) { +#endif /* - * Notify parent, so in case he was wait(2)ing or - * executing waitpid(2) with our pid, he will - * continue. + * Notify parent that we're gone. If parent has the + * PS_NOCLDWAIT flag set, or if the handler is set to SIG_IGN, + * notify process 1 instead (and hope it will handle this + * situation). */ - wakeup(pp); - } else - mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx); + PROC_LOCK(p->p_pptr); + mtx_lock(&p->p_pptr->p_sigacts->ps_mtx); + if (p->p_pptr->p_sigacts->ps_flag & + (PS_NOCLDWAIT | PS_CLDSIGIGN)) { + struct proc *pp; - if (p->p_pptr == initproc) - psignal(p->p_pptr, SIGCHLD); - else if (p->p_sigparent != 0) { - if (p->p_sigparent == SIGCHLD) - childproc_exited(p); - else /* LINUX thread */ - psignal(p->p_pptr, p->p_sigparent); - } + mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx); + pp = p->p_pptr; + PROC_UNLOCK(pp); + proc_reparent(p, initproc); + p->p_sigparent = SIGCHLD; + PROC_LOCK(p->p_pptr); + + /* + * Notify parent, so in case he was wait(2)ing or + * executing waitpid(2) with our pid, he will + * continue. + */ + wakeup(pp); + } else + mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx); + + if (p->p_pptr == initproc) + psignal(p->p_pptr, SIGCHLD); + else if (p->p_sigparent != 0) { + if (p->p_sigparent == SIGCHLD) + childproc_exited(p); + else /* LINUX thread */ + psignal(p->p_pptr, p->p_sigparent); + } +#ifdef PROCDESC + } else + PROC_LOCK(p->p_pptr); +#endif sx_xunlock(&proctree_lock); /* @@ -660,7 +678,7 @@ wait4(struct thread *td, struct wait_args *uap) * rusage. Asserts and will release both the proctree_lock and the process * lock as part of its work. */ -static void +void proc_reap(struct thread *td, struct proc *p, int *status, int options, struct rusage *rusage) { @@ -722,6 +740,10 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options, sx_xunlock(&allproc_lock); LIST_REMOVE(p, p_sibling); leavepgrp(p); +#ifdef PROCDESC + if (p->p_procdesc != NULL) + procdesc_reap(p); +#endif sx_xunlock(&proctree_lock); /* diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 9d3e22d224cf7..32d00550a8157 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -40,11 +40,13 @@ __FBSDID("$FreeBSD$"); #include "opt_kdtrace.h" #include "opt_ktrace.h" #include "opt_kstack_pages.h" +#include "opt_procdesc.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/sysproto.h> #include <sys/eventhandler.h> +#include <sys/fcntl.h> #include <sys/filedesc.h> #include <sys/jail.h> #include <sys/kernel.h> @@ -55,6 +57,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mutex.h> #include <sys/priv.h> #include <sys/proc.h> +#include <sys/procdesc.h> #include <sys/pioctl.h> #include <sys/racct.h> #include <sys/resourcevar.h> @@ -104,7 +107,7 @@ fork(struct thread *td, struct fork_args *uap) int error; struct proc *p2; - error = fork1(td, RFFDG | RFPROC, 0, &p2); + error = fork1(td, RFFDG | RFPROC, 0, &p2, NULL, 0); if (error == 0) { td->td_retval[0] = p2->p_pid; td->td_retval[1] = 0; @@ -112,6 +115,34 @@ fork(struct thread *td, struct fork_args *uap) return (error); } +/* ARGUSED */ +int +pdfork(td, uap) + struct thread *td; + struct pdfork_args *uap; +{ +#ifdef PROCDESC + int error, fd; + struct proc *p2; + + /* + * It is necessary to return fd by reference because 0 is a valid file + * descriptor number, and the child needs to be able to distinguish + * itself from the parent using the return value. + */ + error = fork1(td, RFFDG | RFPROC | RFPROCDESC, 0, &p2, + &fd, uap->flags); + if (error == 0) { + td->td_retval[0] = p2->p_pid; + td->td_retval[1] = 0; + error = copyout(&fd, uap->fdp, sizeof(fd)); + } + return (error); +#else + return (ENOSYS); +#endif +} + /* ARGSUSED */ int vfork(struct thread *td, struct vfork_args *uap) @@ -124,7 +155,7 @@ vfork(struct thread *td, struct vfork_args *uap) #else flags = RFFDG | RFPROC | RFPPWAIT | RFMEM; #endif - error = fork1(td, flags, 0, &p2); + error = fork1(td, flags, 0, &p2, NULL, 0); if (error == 0) { td->td_retval[0] = p2->p_pid; td->td_retval[1] = 0; @@ -143,7 +174,7 @@ rfork(struct thread *td, struct rfork_args *uap) return (EINVAL); AUDIT_ARG_FFLAGS(uap->flags); - error = fork1(td, uap->flags, 0, &p2); + error = fork1(td, uap->flags, 0, &p2, NULL, 0); if (error == 0) { td->td_retval[0] = p2 ? p2->p_pid : 0; td->td_retval[1] = 0; @@ -337,7 +368,7 @@ fail: static void do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2, - struct vmspace *vm2) + struct vmspace *vm2, int pdflags) { struct proc *p1, *pptr; int p2_held, trypid; @@ -625,6 +656,16 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2, p2->p_vmspace->vm_ssize); } +#ifdef PROCDESC + /* + * Associate the process descriptor with the process before anything + * can happen that might cause that process to need the descriptor. + * However, don't do this until after fork(2) can no longer fail. + */ + if (flags & RFPROCDESC) + procdesc_new(p2, pdflags); +#endif + /* * Both processes are set up, now check if any loadable modules want * to adjust anything. @@ -710,7 +751,8 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2, } int -fork1(struct thread *td, int flags, int pages, struct proc **procp) +fork1(struct thread *td, int flags, int pages, struct proc **procp, + int *procdescp, int pdflags) { struct proc *p1; struct proc *newproc; @@ -721,6 +763,9 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp) int error; static int curfail; static struct timeval lastfail; +#ifdef PROCDESC + struct file *fp_procdesc = NULL; +#endif /* Check for the undefined or unimplemented flags. */ if ((flags & ~(RFFLAGS | RFTSIGFLAGS(RFTSIGMASK))) != 0) @@ -738,6 +783,18 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp) if ((flags & RFTSIGZMB) != 0 && (u_int)RFTSIGNUM(flags) > _SIG_MAXSIG) return (EINVAL); +#ifdef PROCDESC + if ((flags & RFPROCDESC) != 0) { + /* Can't not create a process yet get a process descriptor. */ + if ((flags & RFPROC) == 0) + return (EINVAL); + + /* Must provide a place to put a procdesc if creating one. */ + if (procdescp == NULL) + return (EINVAL); + } +#endif + p1 = td->td_proc; /* @@ -757,6 +814,25 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp) return (EAGAIN); #endif +#ifdef PROCDESC + /* + * If required, create a process descriptor in the parent first; we + * will abandon it if something goes wrong. We don't finit() until + * later. + */ + if (flags & RFPROCDESC) { + error = falloc(td, &fp_procdesc, procdescp, 0); + if (error != 0) { +#ifdef RACCT + PROC_LOCK(p1); + racct_sub(p1, RACCT_NPROC, 1); + PROC_UNLOCK(p1); +#endif + return (error); + } + } +#endif + mem_charged = 0; vm2 = NULL; if (pages == 0) @@ -868,12 +944,16 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp) PROC_UNLOCK(p1); } if (ok) { - do_fork(td, flags, newproc, td2, vm2); + do_fork(td, flags, newproc, td2, vm2, pdflags); /* * Return child proc pointer to parent. */ *procp = newproc; +#ifdef PROCDESC + if (flags & RFPROCDESC) + procdesc_finit(newproc->p_procdesc, fp_procdesc); +#endif return (0); } @@ -892,6 +972,10 @@ fail1: if (vm2 != NULL) vmspace_free(vm2); uma_zfree(proc_zone, newproc); +#ifdef PROCDESC + if (((flags & RFPROCDESC) != 0) && (fp_procdesc != NULL)) + fdrop(fp_procdesc, td); +#endif pause("fork", hz / 2); #ifdef RACCT PROC_LOCK(p1); diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index 358d67394e4e9..8ce8327bde154 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -540,8 +540,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) #ifdef INET6 int ip6s, redo_ip6; #endif - unsigned pr_flags, ch_flags; - unsigned pr_allow, ch_allow, tallow; + uint64_t pr_allow, ch_allow, pr_flags, ch_flags; + unsigned tallow; char numbuf[12]; error = priv_check(td, PRIV_JAIL_SET); @@ -2470,32 +2470,11 @@ prison_deref(struct prison *pr, int flags) if (!(flags & PD_LOCKED)) mtx_lock(&pr->pr_mtx); - /* Decrement the user references in a separate loop. */ - if (flags & PD_DEUREF) { - for (tpr = pr;; tpr = tpr->pr_parent) { - if (tpr != pr) - mtx_lock(&tpr->pr_mtx); - if (--tpr->pr_uref > 0) - break; - KASSERT(tpr != &prison0, ("prison0 pr_uref=0")); - mtx_unlock(&tpr->pr_mtx); - } - /* Done if there were only user references to remove. */ - if (!(flags & PD_DEREF)) { - mtx_unlock(&tpr->pr_mtx); - if (flags & PD_LIST_SLOCKED) - sx_sunlock(&allprison_lock); - else if (flags & PD_LIST_XLOCKED) - sx_xunlock(&allprison_lock); - return; - } - if (tpr != pr) { - mtx_unlock(&tpr->pr_mtx); - mtx_lock(&pr->pr_mtx); - } - } - for (;;) { + if (flags & PD_DEUREF) { + pr->pr_uref--; + KASSERT(prison0.pr_uref != 0, ("prison0 pr_uref=0")); + } if (flags & PD_DEREF) pr->pr_ref--; /* If the prison still has references, nothing else to do. */ @@ -2551,7 +2530,7 @@ prison_deref(struct prison *pr, int flags) /* Removing a prison frees a reference on its parent. */ pr = ppr; mtx_lock(&pr->pr_mtx); - flags = PD_DEREF; + flags = PD_DEREF | PD_DEUREF; } } @@ -3858,7 +3837,8 @@ prison_priv_check(struct ucred *cred, int priv) case PRIV_VFS_UNMOUNT: case PRIV_VFS_MOUNT_NONUSER: case PRIV_VFS_MOUNT_OWNER: - if (cred->cr_prison->pr_allow & PR_ALLOW_MOUNT) + if (cred->cr_prison->pr_allow & PR_ALLOW_MOUNT && + cred->cr_prison->pr_enforce_statfs < 2) return (0); else return (EPERM); diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c index 95f896fa5aa68..bb1246980d5b3 100644 --- a/sys/kern/kern_kthread.c +++ b/sys/kern/kern_kthread.c @@ -88,7 +88,7 @@ kproc_create(void (*func)(void *), void *arg, panic("kproc_create called too soon"); error = fork1(&thread0, RFMEM | RFFDG | RFPROC | RFSTOPPED | flags, - pages, &p2); + pages, &p2, NULL, 0); if (error) return error; diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index f91925475b295..4337c953713e9 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -1116,8 +1116,9 @@ kern_kldunload(struct thread *td, int fileid, int flags) PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm); KLD_UNLOCK_READ(); } else -#else KLD_UNLOCK(); +#else + KLD_UNLOCK(); #endif CURVNET_RESTORE(); return (error); diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index 8e5546ee30717..73118726e3ab8 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -477,8 +477,18 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk, return (0); } - if (op == LK_SHARED && (lk->lock_object.lo_flags & LK_NOSHARE)) - op = LK_EXCLUSIVE; + if (lk->lock_object.lo_flags & LK_NOSHARE) { + switch (op) { + case LK_SHARED: + op = LK_EXCLUSIVE; + break; + case LK_UPGRADE: + case LK_DOWNGRADE: + _lockmgr_assert(lk, KA_XLOCKED | KA_NOTRECURSED, + file, line); + return (0); + } + } wakeup_swapper = 0; switch (op) { diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 4f1dc4567f181..c84c5ae776dbf 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -848,12 +848,14 @@ fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp, int preferthread) kp->ki_tdaddr = td; PROC_LOCK_ASSERT(p, MA_OWNED); + if (preferthread) + PROC_SLOCK(p); thread_lock(td); if (td->td_wmesg != NULL) strlcpy(kp->ki_wmesg, td->td_wmesg, sizeof(kp->ki_wmesg)); else bzero(kp->ki_wmesg, sizeof(kp->ki_wmesg)); - strlcpy(kp->ki_ocomm, td->td_name, sizeof(kp->ki_ocomm)); + strlcpy(kp->ki_tdname, td->td_name, sizeof(kp->ki_tdname)); if (TD_ON_LOCK(td)) { kp->ki_kiflag |= KI_LOCKBLOCK; strlcpy(kp->ki_lockname, td->td_lockname, @@ -899,6 +901,7 @@ fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp, int preferthread) kp->ki_pri.pri_user = td->td_user_pri; if (preferthread) { + rufetchtd(td, &kp->ki_rusage); kp->ki_runtime = cputick2usec(td->td_rux.rux_runtime); kp->ki_pctcpu = sched_pctcpu(td); kp->ki_estcpu = td->td_estcpu; @@ -911,6 +914,8 @@ fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp, int preferthread) kp->ki_siglist = td->td_siglist; kp->ki_sigmask = td->td_sigmask; thread_unlock(td); + if (preferthread) + PROC_SUNLOCK(p); } /* @@ -1054,7 +1059,7 @@ freebsd32_kinfo_proc_out(const struct kinfo_proc *ki, struct kinfo_proc32 *ki32) CP(*ki, *ki32, ki_rqindex); CP(*ki, *ki32, ki_oncpu); CP(*ki, *ki32, ki_lastcpu); - bcopy(ki->ki_ocomm, ki32->ki_ocomm, OCOMMLEN + 1); + bcopy(ki->ki_tdname, ki32->ki_tdname, TDNAMLEN + 1); bcopy(ki->ki_wmesg, ki32->ki_wmesg, WMESGLEN + 1); bcopy(ki->ki_login, ki32->ki_login, LOGNAMELEN + 1); bcopy(ki->ki_lockname, ki32->ki_lockname, LOCKNAMELEN + 1); @@ -1386,7 +1391,7 @@ sysctl_kern_proc_args(SYSCTL_HANDLER_ARGS) pa = p->p_args; pargs_hold(pa); PROC_UNLOCK(p); - if (req->oldptr != NULL && pa != NULL) + if (pa != NULL) error = SYSCTL_OUT(req, pa->ar_args, pa->ar_length); pargs_drop(pa); if (error != 0 || req->newptr == NULL) diff --git a/sys/kern/kern_racct.c b/sys/kern/kern_racct.c index 401ce1dce9d5f..b12b7c776ab88 100644 --- a/sys/kern/kern_racct.c +++ b/sys/kern/kern_racct.c @@ -605,6 +605,7 @@ out: void racct_proc_exit(struct proc *p) { + int i; uint64_t runtime; PROC_LOCK(p); @@ -618,14 +619,18 @@ racct_proc_exit(struct proc *p) if (runtime < p->p_prev_runtime) runtime = p->p_prev_runtime; #endif - racct_set(p, RACCT_CPU, runtime); + mtx_lock(&racct_lock); + racct_set_locked(p, RACCT_CPU, runtime); - /* - * XXX: Free this some other way. - */ - racct_set(p, RACCT_NPTS, 0); - racct_set(p, RACCT_NTHR, 0); - racct_set(p, RACCT_RSS, 0); + for (i = 0; i <= RACCT_MAX; i++) { + if (p->p_racct->r_resources[i] == 0) + continue; + if (!RACCT_IS_RECLAIMABLE(i)) + continue; + racct_set_locked(p, i, 0); + } + + mtx_unlock(&racct_lock); PROC_UNLOCK(p); #ifdef RCTL diff --git a/sys/kern/kern_rctl.c b/sys/kern/kern_rctl.c index a939758bc18d4..d60cae44205d5 100644 --- a/sys/kern/kern_rctl.c +++ b/sys/kern/kern_rctl.c @@ -363,6 +363,17 @@ rctl_enforce(struct proc *p, int resource, uint64_t amount) rule->rr_action)); /* + * We're supposed to send a signal, but the process + * is not fully initialized yet, probably because we + * got called from fork1(). For now just deny the + * allocation instead. + */ + if (p->p_state != PRS_NORMAL) { + should_deny = 1; + continue; + } + + /* * We're using the fact that RCTL_ACTION_SIG* values * are equal to their counterparts from sys/signal.h. */ @@ -908,7 +919,7 @@ rctl_string_to_rule(char *rulestr, struct rctl_rule **rulep) if (error != 0) goto out; if (RACCT_IS_IN_MILLIONS(rule->rr_resource)) - rule->rr_amount *= 1000; + rule->rr_amount *= 1000000; } if (perstr == NULL || perstr[0] == '\0') @@ -1223,7 +1234,7 @@ rctl_racct_to_sbuf(struct racct *racct, int sloppy) continue; amount = racct->r_resources[i]; if (RACCT_IS_IN_MILLIONS(i)) - amount /= 1000; + amount /= 1000000; sbuf_printf(sb, "%s=%jd,", rctl_resource_name(i), amount); } sbuf_setpos(sb, sbuf_len(sb) - 1); diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index 1062703b682b2..78a25ebaad99d 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -813,7 +813,7 @@ void calcru(struct proc *p, struct timeval *up, struct timeval *sp) { struct thread *td; - uint64_t u; + uint64_t runtime, u; PROC_LOCK_ASSERT(p, MA_OWNED); PROC_SLOCK_ASSERT(p, MA_OWNED); @@ -826,7 +826,9 @@ calcru(struct proc *p, struct timeval *up, struct timeval *sp) td = curthread; if (td->td_proc == p) { u = cpu_ticks(); - p->p_rux.rux_runtime += u - PCPU_GET(switchtime); + runtime = u - PCPU_GET(switchtime); + td->td_runtime += runtime; + td->td_incruntime += runtime; PCPU_SET(switchtime, u); } /* Make sure the per-thread stats are current. */ @@ -838,6 +840,34 @@ calcru(struct proc *p, struct timeval *up, struct timeval *sp) calcru1(p, &p->p_rux, up, sp); } +/* Collect resource usage for a single thread. */ +void +rufetchtd(struct thread *td, struct rusage *ru) +{ + struct proc *p; + uint64_t runtime, u; + + p = td->td_proc; + PROC_SLOCK_ASSERT(p, MA_OWNED); + THREAD_LOCK_ASSERT(td, MA_OWNED); + /* + * If we are getting stats for the current thread, then add in the + * stats that this thread has accumulated in its current time slice. + * We reset the thread and CPU state as if we had performed a context + * switch right here. + */ + if (td == curthread) { + u = cpu_ticks(); + runtime = u - PCPU_GET(switchtime); + td->td_runtime += runtime; + td->td_incruntime += runtime; + PCPU_SET(switchtime, u); + } + ruxagg(p, td); + *ru = td->td_ru; + calcru1(p, &td->td_rux, &ru->ru_utime, &ru->ru_stime); +} + static void calcru1(struct proc *p, struct rusage_ext *ruxp, struct timeval *up, struct timeval *sp) @@ -955,12 +985,10 @@ kern_getrusage(struct thread *td, int who, struct rusage *rup) case RUSAGE_THREAD: PROC_SLOCK(p); - ruxagg(p, td); - PROC_SUNLOCK(p); thread_lock(td); - *rup = td->td_ru; - calcru1(p, &td->td_rux, &rup->ru_utime, &rup->ru_stime); + rufetchtd(td, rup); thread_unlock(td); + PROC_SUNLOCK(p); break; default: diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c index 60e854fe340c0..c1e3dda4fb19c 100644 --- a/sys/kern/kern_shutdown.c +++ b/sys/kern/kern_shutdown.c @@ -40,7 +40,6 @@ __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include "opt_kdb.h" #include "opt_panic.h" -#include "opt_show_busybufs.h" #include "opt_sched.h" #include "opt_watchdog.h" @@ -66,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include <sys/smp.h> #include <sys/sysctl.h> #include <sys/sysproto.h> +#include <sys/vnode.h> #ifdef SW_WATCHDOG #include <sys/watchdog.h> #endif @@ -123,6 +123,14 @@ TUNABLE_INT("kern.sync_on_panic", &sync_on_panic); SYSCTL_NODE(_kern, OID_AUTO, shutdown, CTLFLAG_RW, 0, "Shutdown environment"); +#ifndef DIAGNOSTIC +static int show_busybufs; +#else +static int show_busybufs = 1; +#endif +SYSCTL_INT(_kern_shutdown, OID_AUTO, show_busybufs, CTLFLAG_RW, + &show_busybufs, 0, ""); + /* * Variable panicstr contains argument to first call to panic; used as flag * to indicate that the kernel has already called panic. @@ -389,13 +397,17 @@ kern_reboot(int howto) } #endif nbusy++; -#if defined(SHOW_BUSYBUFS) || defined(DIAGNOSTIC) - printf( - "%d: bufobj:%p, flags:%0x, blkno:%ld, lblkno:%ld\n", - nbusy, bp->b_bufobj, - bp->b_flags, (long)bp->b_blkno, - (long)bp->b_lblkno); -#endif + if (show_busybufs > 0) { + printf( + "%d: buf:%p, vnode:%p, flags:%0x, blkno:%jd, lblkno:%jd, buflock:", + nbusy, bp, bp->b_vp, bp->b_flags, + (intmax_t)bp->b_blkno, + (intmax_t)bp->b_lblkno); + BUF_LOCKPRINTINFO(bp); + if (show_busybufs > 1) + vn_printf(bp->b_vp, + "vnode content: "); + } } } if (nbusy) { @@ -585,15 +597,6 @@ panic(const char *fmt, ...) kdb_backtrace(); if (debugger_on_panic) kdb_enter(KDB_WHY_PANIC, "panic"); -#ifdef RESTARTABLE_PANICS - /* See if the user aborted the panic, in which case we continue. */ - if (panicstr == NULL) { -#ifdef SMP - atomic_store_rel_int(&panic_cpu, NOCPU); -#endif - return; - } -#endif #endif /*thread_lock(td); */ td->td_flags |= TDF_INPANIC; @@ -702,8 +705,11 @@ dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, if (length != 0 && (offset < di->mediaoffset || offset - di->mediaoffset + length > di->mediasize)) { - printf("Attempt to write outside dump device boundaries.\n"); - return (ENXIO); + printf("Attempt to write outside dump device boundaries.\n" + "offset(%jd), mediaoffset(%jd), length(%ju), mediasize(%jd).\n", + (intmax_t)offset, (intmax_t)di->mediaoffset, + (uintmax_t)length, (intmax_t)di->mediasize); + return (ENOSPC); } return (di->dumper(di->priv, virtual, physical, offset, length)); } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index e1861eb1e81d4..26ef0d7f31d47 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -41,12 +41,14 @@ __FBSDID("$FreeBSD$"); #include "opt_kdtrace.h" #include "opt_ktrace.h" #include "opt_core.h" +#include "opt_procdesc.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/signalvar.h> #include <sys/vnode.h> #include <sys/acct.h> +#include <sys/capability.h> #include <sys/condvar.h> #include <sys/event.h> #include <sys/fcntl.h> @@ -59,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mutex.h> #include <sys/namei.h> #include <sys/proc.h> +#include <sys/procdesc.h> #include <sys/posix4.h> #include <sys/pioctl.h> #include <sys/racct.h> @@ -1698,6 +1701,34 @@ kill(struct thread *td, struct kill_args *uap) /* NOTREACHED */ } +int +pdkill(td, uap) + struct thread *td; + struct pdkill_args *uap; +{ +#ifdef PROCDESC + struct proc *p; + int error; + + AUDIT_ARG_SIGNUM(uap->signum); + AUDIT_ARG_FD(uap->fd); + if ((u_int)uap->signum > _SIG_MAXSIG) + return (EINVAL); + + error = procdesc_find(td, uap->fd, CAP_PDKILL, &p); + if (error) + return (error); + AUDIT_ARG_PROCESS(p); + error = p_cansignal(td, p, uap->signum); + if (error == 0 && uap->signum) + psignal(p, uap->signum); + PROC_UNLOCK(p); + return (error); +#else + return (ENOSYS); +#endif +} + #if defined(COMPAT_43) #ifndef _SYS_SYSPROTO_H_ struct okillpg_args { diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c index 6a6f46b2c72bc..b820bd913ead1 100644 --- a/sys/kern/kern_timeout.c +++ b/sys/kern/kern_timeout.c @@ -269,10 +269,17 @@ callout_cpu_switch(struct callout *c, struct callout_cpu *cc, int new_cpu) MPASS(c != NULL && cc != NULL); CC_LOCK_ASSERT(cc); + /* + * Avoid interrupts and preemption firing after the callout cpu + * is blocked in order to avoid deadlocks as the new thread + * may be willing to acquire the callout cpu lock. + */ c->c_cpu = CPUBLOCK; + spinlock_enter(); CC_UNLOCK(cc); new_cc = CC_CPU(new_cpu); CC_LOCK(new_cc); + spinlock_exit(); c->c_cpu = new_cpu; return (new_cc); } diff --git a/sys/kern/sched_4bsd.c b/sys/kern/sched_4bsd.c index 574755f02ee24..136080caf55a5 100644 --- a/sys/kern/sched_4bsd.c +++ b/sys/kern/sched_4bsd.c @@ -720,7 +720,7 @@ sched_exit(struct proc *p, struct thread *td) { KTR_STATE1(KTR_SCHED, "thread", sched_tdname(td), "proc exit", - "prio:td", td->td_priority); + "prio:%d", td->td_priority); PROC_LOCK_ASSERT(p, MA_OWNED); sched_exit_thread(FIRST_THREAD_IN_PROC(p), td); @@ -731,7 +731,7 @@ sched_exit_thread(struct thread *td, struct thread *child) { KTR_STATE1(KTR_SCHED, "thread", sched_tdname(child), "exit", - "prio:td", child->td_priority); + "prio:%d", child->td_priority); thread_lock(td); td->td_estcpu = ESTCPULIM(td->td_estcpu + child->td_estcpu); thread_unlock(td); diff --git a/sys/kern/sched_ule.c b/sys/kern/sched_ule.c index 05267f3d6adb3..f505676933aac 100644 --- a/sys/kern/sched_ule.c +++ b/sys/kern/sched_ule.c @@ -84,7 +84,7 @@ dtrace_vtime_switch_func_t dtrace_vtime_switch_func; #define TS_NAME_LEN (MAXCOMLEN + sizeof(" td ") + sizeof(__XSTRING(UINT_MAX))) #define TDQ_NAME_LEN (sizeof("sched lock ") + sizeof(__XSTRING(MAXCPU))) -#define TDQ_LOADNAME_LEN (PCPU_NAME_LEN + sizeof(" load")) +#define TDQ_LOADNAME_LEN (sizeof("CPU ") + sizeof(__XSTRING(MAXCPU)) - 1 + sizeof(" load")) /* * Thread scheduler specific section. All fields are protected @@ -2022,7 +2022,7 @@ sched_exit(struct proc *p, struct thread *child) struct thread *td; KTR_STATE1(KTR_SCHED, "thread", sched_tdname(child), "proc exit", - "prio:td", child->td_priority); + "prio:%d", child->td_priority); PROC_LOCK_ASSERT(p, MA_OWNED); td = FIRST_THREAD_IN_PROC(p); sched_exit_thread(td, child); @@ -2039,7 +2039,7 @@ sched_exit_thread(struct thread *td, struct thread *child) { KTR_STATE1(KTR_SCHED, "thread", sched_tdname(child), "thread exit", - "prio:td", child->td_priority); + "prio:%d", child->td_priority); /* * Give the child's runtime to the parent without returning the * sleep time as a penalty to the parent. This causes shells that diff --git a/sys/kern/subr_kdb.c b/sys/kern/subr_kdb.c index f5cb31e71dd6c..2ee7dc674dfa4 100644 --- a/sys/kern/subr_kdb.c +++ b/sys/kern/subr_kdb.c @@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$"); #include "opt_kdb.h" #include "opt_stack.h" +#include "opt_watchdog.h" #include <sys/param.h> #include <sys/systm.h> @@ -41,6 +42,9 @@ __FBSDID("$FreeBSD$"); #include <sys/smp.h> #include <sys/stack.h> #include <sys/sysctl.h> +#ifdef SW_WATCHDOG +#include <sys/watchdog.h> +#endif #include <machine/kdb.h> #include <machine/pcb.h> @@ -57,6 +61,21 @@ struct pcb *kdb_thrctx = NULL; struct thread *kdb_thread = NULL; struct trapframe *kdb_frame = NULL; +#ifdef BREAK_TO_DEBUGGER +#define KDB_BREAK_TO_DEBUGGER 1 +#else +#define KDB_BREAK_TO_DEBUGGER 0 +#endif + +#ifdef ALT_BREAK_TO_DEBUGGER +#define KDB_ALT_BREAK_TO_DEBUGGER 1 +#else +#define KDB_ALT_BREAK_TO_DEBUGGER 0 +#endif + +static int kdb_break_to_debugger = KDB_BREAK_TO_DEBUGGER; +static int kdb_alt_break_to_debugger = KDB_ALT_BREAK_TO_DEBUGGER; + KDB_BACKEND(null, NULL, NULL, NULL); SET_DECLARE(kdb_dbbe_set, struct kdb_dbbe); @@ -87,6 +106,15 @@ SYSCTL_PROC(_debug_kdb, OID_AUTO, trap, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, SYSCTL_PROC(_debug_kdb, OID_AUTO, trap_code, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, kdb_sysctl_trap_code, "I", "set to cause a page fault via code access"); +SYSCTL_INT(_debug_kdb, OID_AUTO, break_to_debugger, CTLTYPE_INT | CTLFLAG_RW | + CTLFLAG_TUN, &kdb_break_to_debugger, 0, "Enable break to debugger"); +TUNABLE_INT("debug.kdb.break_to_debugger", &kdb_break_to_debugger); + +SYSCTL_INT(_debug_kdb, OID_AUTO, alt_break_to_debugger, CTLTYPE_INT | + CTLFLAG_RW | CTLFLAG_TUN, &kdb_alt_break_to_debugger, 0, + "Enable alternative break to debugger"); +TUNABLE_INT("debug.kdb.alt_break_to_debugger", &kdb_alt_break_to_debugger); + /* * Flag to indicate to debuggers why the debugger was entered. */ @@ -241,7 +269,17 @@ enum { }; int -kdb_alt_break(int key, int *state) +kdb_break(void) +{ + + if (!kdb_break_to_debugger) + return (0); + kdb_enter(KDB_WHY_BREAK, "Break to debugger"); + return (KDB_REQ_DEBUGGER); +} + +static int +kdb_alt_break_state(int key, int *state) { int brk; @@ -275,6 +313,53 @@ kdb_alt_break(int key, int *state) return (brk); } +static int +kdb_alt_break_internal(int key, int *state, int force_gdb) +{ + int brk; + + if (!kdb_alt_break_to_debugger) + return (0); + brk = kdb_alt_break_state(key, state); + switch (brk) { + case KDB_REQ_DEBUGGER: + if (force_gdb) + kdb_dbbe_select("gdb"); + kdb_enter(KDB_WHY_BREAK, "Break to debugger"); + break; + + case KDB_REQ_PANIC: + if (force_gdb) + kdb_dbbe_select("gdb"); + kdb_panic("Panic sequence on console"); + break; + + case KDB_REQ_REBOOT: + kdb_reboot(); + break; + } + return (0); +} + +int +kdb_alt_break(int key, int *state) +{ + + return (kdb_alt_break_internal(key, state, 0)); +} + +/* + * This variation on kdb_alt_break() is used only by dcons, which has its own + * configuration flag to force GDB use regardless of the global KDB + * configuration. + */ +int +kdb_alt_break_gdb(int key, int *state) +{ + + return (kdb_alt_break_internal(key, state, 1)); +} + /* * Print a backtrace of the calling thread. The backtrace is generated by * the selected debugger, provided it supports backtraces. If no debugger @@ -506,6 +591,9 @@ kdb_trap(int type, int code, struct trapframe *tf) cpuset_t other_cpus; #endif struct kdb_dbbe *be; +#ifdef SW_WATCHDOG + u_int wdoglvt; +#endif register_t intr; int handled; @@ -519,6 +607,10 @@ kdb_trap(int type, int code, struct trapframe *tf) intr = intr_disable(); +#ifdef SW_WATCHDOG + wdoglvt = wdog_kern_last_timeout(); + wdog_kern_pat(WD_TO_NEVER); +#endif #ifdef SMP other_cpus = all_cpus; CPU_CLR(PCPU_GET(cpuid), &other_cpus); @@ -550,6 +642,9 @@ kdb_trap(int type, int code, struct trapframe *tf) #ifdef SMP restart_cpus(stopped_cpus); #endif +#ifdef SW_WATCHDOG + wdog_kern_pat(wdoglvt); +#endif intr_restore(intr); diff --git a/sys/kern/subr_pcpu.c b/sys/kern/subr_pcpu.c index ec6b590d25d8f..ba76bb249ecb5 100644 --- a/sys/kern/subr_pcpu.c +++ b/sys/kern/subr_pcpu.c @@ -92,9 +92,6 @@ pcpu_init(struct pcpu *pcpu, int cpuid, size_t size) cpu_pcpu_init(pcpu, cpuid, size); pcpu->pc_rm_queue.rmq_next = &pcpu->pc_rm_queue; pcpu->pc_rm_queue.rmq_prev = &pcpu->pc_rm_queue; -#ifdef KTR - snprintf(pcpu->pc_name, sizeof(pcpu->pc_name), "CPU %d", cpuid); -#endif } void diff --git a/sys/kern/subr_sbuf.c b/sys/kern/subr_sbuf.c index e931e65503300..c0d7ea0a1ba99 100644 --- a/sys/kern/subr_sbuf.c +++ b/sys/kern/subr_sbuf.c @@ -184,7 +184,7 @@ sbuf_newbuf(struct sbuf *s, char *buf, int length, int flags) s->s_buf = buf; if ((s->s_flags & SBUF_AUTOEXTEND) == 0) { - KASSERT(s->s_size > 1, + KASSERT(s->s_size >= 0, ("attempt to create a too small sbuf")); } diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c index d0c5deff04ec8..87d536c4e56d9 100644 --- a/sys/kern/subr_smp.c +++ b/sys/kern/subr_smp.c @@ -109,8 +109,7 @@ static void (*volatile smp_rv_setup_func)(void *arg); static void (*volatile smp_rv_action_func)(void *arg); static void (*volatile smp_rv_teardown_func)(void *arg); static void *volatile smp_rv_func_arg; -static volatile int smp_rv_waiters[3]; -static volatile int smp_rv_generation; +static volatile int smp_rv_waiters[4]; /* * Shared mutex to restrict busywaits between smp_rendezvous() and @@ -321,7 +320,6 @@ smp_rendezvous_action(void) void (*local_setup_func)(void*); void (*local_action_func)(void*); void (*local_teardown_func)(void*); - int generation; #ifdef INVARIANTS int owepreempt; #endif @@ -336,7 +334,6 @@ smp_rendezvous_action(void) local_setup_func = smp_rv_setup_func; local_action_func = smp_rv_action_func; local_teardown_func = smp_rv_teardown_func; - generation = smp_rv_generation; /* * Use a nested critical section to prevent any preemptions @@ -382,32 +379,28 @@ smp_rendezvous_action(void) if (local_action_func != NULL) local_action_func(local_func_arg); - /* - * Signal that the main action has been completed. If a - * full exit rendezvous is requested, then all CPUs will - * wait here until all CPUs have finished the main action. - * - * Note that the write by the last CPU to finish the action - * may become visible to different CPUs at different times. - * As a result, the CPU that initiated the rendezvous may - * exit the rendezvous and drop the lock allowing another - * rendezvous to be initiated on the same CPU or a different - * CPU. In that case the exit sentinel may be cleared before - * all CPUs have noticed causing those CPUs to hang forever. - * Workaround this by using a generation count to notice when - * this race occurs and to exit the rendezvous in that case. - */ - MPASS(generation == smp_rv_generation); - atomic_add_int(&smp_rv_waiters[2], 1); if (local_teardown_func != smp_no_rendevous_barrier) { - while (smp_rv_waiters[2] < smp_rv_ncpus && - generation == smp_rv_generation) + /* + * Signal that the main action has been completed. If a + * full exit rendezvous is requested, then all CPUs will + * wait here until all CPUs have finished the main action. + */ + atomic_add_int(&smp_rv_waiters[2], 1); + while (smp_rv_waiters[2] < smp_rv_ncpus) cpu_spinwait(); if (local_teardown_func != NULL) local_teardown_func(local_func_arg); } + /* + * Signal that the rendezvous is fully completed by this CPU. + * This means that no member of smp_rv_* pseudo-structure will be + * accessed by this target CPU after this point; in particular, + * memory pointed by smp_rv_func_arg. + */ + atomic_add_int(&smp_rv_waiters[3], 1); + td->td_critnest--; KASSERT(owepreempt == td->td_owepreempt, ("rendezvous action changed td_owepreempt")); @@ -441,8 +434,6 @@ smp_rendezvous_cpus(cpuset_t map, mtx_lock_spin(&smp_ipi_mtx); - atomic_add_acq_int(&smp_rv_generation, 1); - /* Pass rendezvous parameters via global variables. */ smp_rv_ncpus = ncpus; smp_rv_setup_func = setup_func; @@ -451,6 +442,7 @@ smp_rendezvous_cpus(cpuset_t map, smp_rv_func_arg = arg; smp_rv_waiters[1] = 0; smp_rv_waiters[2] = 0; + smp_rv_waiters[3] = 0; atomic_store_rel_int(&smp_rv_waiters[0], 0); /* @@ -466,13 +458,13 @@ smp_rendezvous_cpus(cpuset_t map, smp_rendezvous_action(); /* - * If the caller did not request an exit barrier to be enforced - * on each CPU, ensure that this CPU waits for all the other - * CPUs to finish the rendezvous. + * Ensure that the master CPU waits for all the other + * CPUs to finish the rendezvous, so that smp_rv_* + * pseudo-structure and the arg are guaranteed to not + * be in use. */ - if (teardown_func == smp_no_rendevous_barrier) - while (atomic_load_acq_int(&smp_rv_waiters[2]) < ncpus) - cpu_spinwait(); + while (atomic_load_acq_int(&smp_rv_waiters[3]) < ncpus) + cpu_spinwait(); mtx_unlock_spin(&smp_ipi_mtx); } diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c new file mode 100644 index 0000000000000..cb0d9295ed2bd --- /dev/null +++ b/sys/kern/subr_syscall.c @@ -0,0 +1,213 @@ +/*- + * Copyright (C) 1994, David Greenman + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org> + * + * This code is derived from software contributed to Berkeley by + * the University of Utah, and William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 + */ + +#include "opt_capsicum.h" +#include "opt_ktrace.h" +#include "opt_kdtrace.h" + +__FBSDID("$FreeBSD$"); + +#include <sys/capability.h> +#include <sys/ktr.h> +#ifdef KTRACE +#include <sys/uio.h> +#include <sys/ktrace.h> +#endif +#include <security/audit/audit.h> + +static inline int +syscallenter(struct thread *td, struct syscall_args *sa) +{ + struct proc *p; + int error, traced; + + PCPU_INC(cnt.v_syscall); + p = td->td_proc; + + td->td_pticks = 0; + if (td->td_ucred != p->p_ucred) + cred_update_thread(td); + if (p->p_flag & P_TRACED) { + traced = 1; + PROC_LOCK(p); + td->td_dbgflags &= ~TDB_USERWR; + td->td_dbgflags |= TDB_SCE; + PROC_UNLOCK(p); + } else + traced = 0; + error = (p->p_sysent->sv_fetch_syscall_args)(td, sa); +#ifdef KTRACE + if (KTRPOINT(td, KTR_SYSCALL)) + ktrsyscall(sa->code, sa->narg, sa->args); +#endif + + CTR6(KTR_SYSC, +"syscall: td=%p pid %d %s (%#lx, %#lx, %#lx)", + td, td->td_proc->p_pid, syscallname(p, sa->code), + sa->args[0], sa->args[1], sa->args[2]); + + if (error == 0) { + STOPEVENT(p, S_SCE, sa->narg); + PTRACESTOP_SC(p, td, S_PT_SCE); + if (td->td_dbgflags & TDB_USERWR) { + /* + * Reread syscall number and arguments if + * debugger modified registers or memory. + */ + error = (p->p_sysent->sv_fetch_syscall_args)(td, sa); +#ifdef KTRACE + if (KTRPOINT(td, KTR_SYSCALL)) + ktrsyscall(sa->code, sa->narg, sa->args); +#endif + if (error != 0) + goto retval; + } + +#ifdef CAPABILITY_MODE + /* + * In capability mode, we only allow access to system calls + * flagged with SYF_CAPENABLED. + */ + if (IN_CAPABILITY_MODE(td) && + !(sa->callp->sy_flags & SYF_CAPENABLED)) { + error = ECAPMODE; + goto retval; + } +#endif + + error = syscall_thread_enter(td, sa->callp); + if (error != 0) + goto retval; + +#ifdef KDTRACE_HOOKS + /* + * If the systrace module has registered it's probe + * callback and if there is a probe active for the + * syscall 'entry', process the probe. + */ + if (systrace_probe_func != NULL && sa->callp->sy_entry != 0) + (*systrace_probe_func)(sa->callp->sy_entry, sa->code, + sa->callp, sa->args, 0); +#endif + + AUDIT_SYSCALL_ENTER(sa->code, td); + error = (sa->callp->sy_call)(td, sa->args); + AUDIT_SYSCALL_EXIT(error, td); + + /* Save the latest error return value. */ + td->td_errno = error; + +#ifdef KDTRACE_HOOKS + /* + * If the systrace module has registered it's probe + * callback and if there is a probe active for the + * syscall 'return', process the probe. + */ + if (systrace_probe_func != NULL && sa->callp->sy_return != 0) + (*systrace_probe_func)(sa->callp->sy_return, sa->code, + sa->callp, NULL, (error) ? -1 : td->td_retval[0]); +#endif + syscall_thread_exit(td, sa->callp); + CTR4(KTR_SYSC, "syscall: p=%p error=%d return %#lx %#lx", + p, error, td->td_retval[0], td->td_retval[1]); + } + retval: + if (traced) { + PROC_LOCK(p); + td->td_dbgflags &= ~TDB_SCE; + PROC_UNLOCK(p); + } + (p->p_sysent->sv_set_syscall_retval)(td, error); + return (error); +} + +static inline void +syscallret(struct thread *td, int error, struct syscall_args *sa __unused) +{ + struct proc *p; + int traced; + + p = td->td_proc; + + /* + * Check for misbehavior. + */ + WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning", + syscallname(p, sa->code)); + KASSERT(td->td_critnest == 0, + ("System call %s returning in a critical section", + syscallname(p, sa->code))); + KASSERT(td->td_locks == 0, + ("System call %s returning with %d locks held", + syscallname(p, sa->code), td->td_locks)); + + /* + * Handle reschedule and other end-of-syscall issues + */ + userret(td, td->td_frame); + + CTR4(KTR_SYSC, "syscall %s exit thread %p pid %d proc %s", + syscallname(p, sa->code), td, td->td_proc->p_pid, td->td_name); + +#ifdef KTRACE + if (KTRPOINT(td, KTR_SYSRET)) + ktrsysret(sa->code, error, td->td_retval[0]); +#endif + + if (p->p_flag & P_TRACED) { + traced = 1; + PROC_LOCK(p); + td->td_dbgflags |= TDB_SCX; + PROC_UNLOCK(p); + } else + traced = 0; + /* + * This works because errno is findable through the + * register set. If we ever support an emulation where this + * is not the case, this code will need to be revisited. + */ + STOPEVENT(p, S_SCX, sa->code); + PTRACESTOP_SC(p, td, S_PT_SCX); + if (traced || (td->td_dbgflags & (TDB_EXEC | TDB_FORK)) != 0) { + PROC_LOCK(p); + td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC | TDB_FORK); + PROC_UNLOCK(p); + } +} diff --git a/sys/kern/subr_taskqueue.c b/sys/kern/subr_taskqueue.c index 4c4589901557d..31ea52d1d8761 100644 --- a/sys/kern/subr_taskqueue.c +++ b/sys/kern/subr_taskqueue.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <sys/interrupt.h> #include <sys/kernel.h> #include <sys/kthread.h> +#include <sys/limits.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mutex.h> @@ -173,7 +174,8 @@ taskqueue_enqueue_locked(struct taskqueue *queue, struct task *task) * Count multiple enqueues. */ if (task->ta_pending) { - task->ta_pending++; + if (task->ta_pending < USHRT_MAX) + task->ta_pending++; return (0); } diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 3527ed1fbedfc..42adf80f04fee 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -252,7 +252,6 @@ ast(struct trapframe *framep) mtx_assert(&Giant, MA_NOTOWNED); } -#ifdef HAVE_SYSCALL_ARGS_DEF const char * syscallname(struct proc *p, u_int code) { @@ -264,164 +263,3 @@ syscallname(struct proc *p, u_int code) return (unknown); return (sv->sv_syscallnames[code]); } - -int -syscallenter(struct thread *td, struct syscall_args *sa) -{ - struct proc *p; - int error, traced; - - PCPU_INC(cnt.v_syscall); - p = td->td_proc; - - td->td_pticks = 0; - if (td->td_ucred != p->p_ucred) - cred_update_thread(td); - if (p->p_flag & P_TRACED) { - traced = 1; - PROC_LOCK(p); - td->td_dbgflags &= ~TDB_USERWR; - td->td_dbgflags |= TDB_SCE; - PROC_UNLOCK(p); - } else - traced = 0; - error = (p->p_sysent->sv_fetch_syscall_args)(td, sa); -#ifdef KTRACE - if (KTRPOINT(td, KTR_SYSCALL)) - ktrsyscall(sa->code, sa->narg, sa->args); -#endif - - CTR6(KTR_SYSC, -"syscall: td=%p pid %d %s (%#lx, %#lx, %#lx)", - td, td->td_proc->p_pid, syscallname(p, sa->code), - sa->args[0], sa->args[1], sa->args[2]); - - if (error == 0) { - STOPEVENT(p, S_SCE, sa->narg); - PTRACESTOP_SC(p, td, S_PT_SCE); - if (td->td_dbgflags & TDB_USERWR) { - /* - * Reread syscall number and arguments if - * debugger modified registers or memory. - */ - error = (p->p_sysent->sv_fetch_syscall_args)(td, sa); -#ifdef KTRACE - if (KTRPOINT(td, KTR_SYSCALL)) - ktrsyscall(sa->code, sa->narg, sa->args); -#endif - if (error != 0) - goto retval; - } - -#ifdef CAPABILITY_MODE - /* - * In capability mode, we only allow access to system calls - * flagged with SYF_CAPENABLED. - */ - if (IN_CAPABILITY_MODE(td) && - !(sa->callp->sy_flags & SYF_CAPENABLED)) { - error = ECAPMODE; - goto retval; - } -#endif - - error = syscall_thread_enter(td, sa->callp); - if (error != 0) - goto retval; - -#ifdef KDTRACE_HOOKS - /* - * If the systrace module has registered it's probe - * callback and if there is a probe active for the - * syscall 'entry', process the probe. - */ - if (systrace_probe_func != NULL && sa->callp->sy_entry != 0) - (*systrace_probe_func)(sa->callp->sy_entry, sa->code, - sa->callp, sa->args, 0); -#endif - - AUDIT_SYSCALL_ENTER(sa->code, td); - error = (sa->callp->sy_call)(td, sa->args); - AUDIT_SYSCALL_EXIT(error, td); - - /* Save the latest error return value. */ - td->td_errno = error; - -#ifdef KDTRACE_HOOKS - /* - * If the systrace module has registered it's probe - * callback and if there is a probe active for the - * syscall 'return', process the probe. - */ - if (systrace_probe_func != NULL && sa->callp->sy_return != 0) - (*systrace_probe_func)(sa->callp->sy_return, sa->code, - sa->callp, NULL, (error) ? -1 : td->td_retval[0]); -#endif - syscall_thread_exit(td, sa->callp); - CTR4(KTR_SYSC, "syscall: p=%p error=%d return %#lx %#lx", - p, error, td->td_retval[0], td->td_retval[1]); - } - retval: - if (traced) { - PROC_LOCK(p); - td->td_dbgflags &= ~TDB_SCE; - PROC_UNLOCK(p); - } - (p->p_sysent->sv_set_syscall_retval)(td, error); - return (error); -} - -void -syscallret(struct thread *td, int error, struct syscall_args *sa __unused) -{ - struct proc *p; - int traced; - - p = td->td_proc; - - /* - * Check for misbehavior. - */ - WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning", - syscallname(p, sa->code)); - KASSERT(td->td_critnest == 0, - ("System call %s returning in a critical section", - syscallname(p, sa->code))); - KASSERT(td->td_locks == 0, - ("System call %s returning with %d locks held", - syscallname(p, sa->code), td->td_locks)); - - /* - * Handle reschedule and other end-of-syscall issues - */ - userret(td, td->td_frame); - - CTR4(KTR_SYSC, "syscall %s exit thread %p pid %d proc %s", - syscallname(p, sa->code), td, td->td_proc->p_pid, td->td_name); - -#ifdef KTRACE - if (KTRPOINT(td, KTR_SYSRET)) - ktrsysret(sa->code, error, td->td_retval[0]); -#endif - - if (p->p_flag & P_TRACED) { - traced = 1; - PROC_LOCK(p); - td->td_dbgflags |= TDB_SCX; - PROC_UNLOCK(p); - } else - traced = 0; - /* - * This works because errno is findable through the - * register set. If we ever support an emulation where this - * is not the case, this code will need to be revisited. - */ - STOPEVENT(p, S_SCX, sa->code); - PTRACESTOP_SC(p, td, S_PT_SCX); - if (traced || (td->td_dbgflags & (TDB_EXEC | TDB_FORK)) != 0) { - PROC_LOCK(p); - td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC | TDB_FORK); - PROC_UNLOCK(p); - } -} -#endif /* HAVE_SYSCALL_ARGS_DEF */ diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index 04f98d8290c7a..318ffe4e04d2f 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -31,9 +31,24 @@ /* * FreeBSD kernel capability facility. * - * Currently, this file implements only capability mode; capabilities - * (rights-refined file descriptors) will follow. + * Two kernel features are implemented here: capability mode, a sandboxed mode + * of execution for processes, and capabilities, a refinement on file + * descriptors that allows fine-grained control over operations on the file + * descriptor. Collectively, these allow processes to run in the style of a + * historic "capability system" in which they can use only resources + * explicitly delegated to them. This model is enforced by restricting access + * to global namespaces in capability mode. * + * Capabilities wrap other file descriptor types, binding them to a constant + * rights mask set when the capability is created. New capabilities may be + * derived from existing capabilities, but only if they have the same or a + * strict subset of the rights on the original capability. + * + * System calls permitted in capability mode are defined in capabilities.conf; + * calls must be carefully audited for safety to ensure that they don't allow + * escape from a sandbox. Some calls permit only a subset of operations in + * capability mode -- for example, shm_open(2) is limited to creating + * anonymous, rather than named, POSIX shared memory objects. */ #include "opt_capsicum.h" @@ -61,7 +76,7 @@ __FBSDID("$FreeBSD$"); #ifdef CAPABILITY_MODE -FEATURE(security_capabilities, "Capsicum Capability Mode"); +FEATURE(security_capability_mode, "Capsicum Capability Mode"); /* * System call to enter capability mode for the process. @@ -119,6 +134,8 @@ cap_getmode(struct thread *td, struct cap_getmode_args *uap) #ifdef CAPABILITIES +FEATURE(security_capabilities, "Capsicum Capabilities"); + /* * struct capability describes a capability, and is hung off of its struct * file f_data field. cap_file and cap_rightss are static once hooked up, as @@ -144,6 +161,8 @@ static fo_poll_t capability_poll; static fo_kqfilter_t capability_kqfilter; static fo_stat_t capability_stat; static fo_close_t capability_close; +static fo_chmod_t capability_chmod; +static fo_chown_t capability_chown; static struct fileops capability_ops = { .fo_read = capability_read, @@ -154,6 +173,8 @@ static struct fileops capability_ops = { .fo_kqfilter = capability_kqfilter, .fo_stat = capability_stat, .fo_close = capability_close, + .fo_chmod = capability_chmod, + .fo_chown = capability_chown, .fo_flags = DFLAG_PASSABLE, }; @@ -166,6 +187,8 @@ static struct fileops capability_ops_unpassable = { .fo_kqfilter = capability_kqfilter, .fo_stat = capability_stat, .fo_close = capability_close, + .fo_chmod = capability_chmod, + .fo_chown = capability_chown, .fo_flags = 0, }; @@ -220,18 +243,16 @@ cap_new(struct thread *td, struct cap_new_args *uap) { int error, capfd; int fd = uap->fd; - struct file *fp, *fcapp; + struct file *fp; cap_rights_t rights = uap->rights; AUDIT_ARG_FD(fd); -#ifdef notyet /* capability auditing will follow in a few commits */ AUDIT_ARG_RIGHTS(rights); -#endif - error = fget(td, fd, &fp); + error = fget(td, fd, rights, &fp); if (error) return (error); AUDIT_ARG_FILE(td->td_proc, fp); - error = kern_capwrap(td, fp, rights, &fcapp, &capfd); + error = kern_capwrap(td, fp, rights, &capfd); if (error) return (error); @@ -269,10 +290,10 @@ cap_getrights(struct thread *td, struct cap_getrights_args *uap) */ int kern_capwrap(struct thread *td, struct file *fp, cap_rights_t rights, - struct file **fcappp, int *capfdp) + int *capfdp) { struct capability *cp, *cp_old; - struct file *fp_object; + struct file *fp_object, *fcapp; int error; if ((rights | CAP_MASK_VALID) != CAP_MASK_VALID) @@ -292,7 +313,7 @@ kern_capwrap(struct thread *td, struct file *fp, cap_rights_t rights, /* * Allocate a new file descriptor to hang the capability off of. */ - error = falloc(td, fcappp, capfdp, fp->f_flag); + error = falloc(td, &fcapp, capfdp, fp->f_flag); if (error) return (error); @@ -311,18 +332,18 @@ kern_capwrap(struct thread *td, struct file *fp, cap_rights_t rights, cp = uma_zalloc(capability_zone, M_WAITOK | M_ZERO); cp->cap_rights = rights; cp->cap_object = fp_object; - cp->cap_file = *fcappp; + cp->cap_file = fcapp; if (fp->f_flag & DFLAG_PASSABLE) - finit(*fcappp, fp->f_flag, DTYPE_CAPABILITY, cp, + finit(fcapp, fp->f_flag, DTYPE_CAPABILITY, cp, &capability_ops); else - finit(*fcappp, fp->f_flag, DTYPE_CAPABILITY, cp, + finit(fcapp, fp->f_flag, DTYPE_CAPABILITY, cp, &capability_ops_unpassable); /* * Release our private reference (the proc filedesc still has one). */ - fdrop(*fcappp, td); + fdrop(fcapp, td); return (0); } @@ -469,6 +490,22 @@ capability_stat(struct file *fp, struct stat *sb, struct ucred *active_cred, panic("capability_stat"); } +int +capability_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, + struct thread *td) +{ + + panic("capability_chmod"); +} + +int +capability_chown(struct file *fp, uid_t uid, gid_t gid, + struct ucred *active_cred, struct thread *td) +{ + + panic("capability_chown"); +} + #else /* !CAPABILITIES */ /* @@ -514,4 +551,3 @@ cap_funwrap_mmap(struct file *fp_cap, cap_rights_t rights, u_char *maxprotp, } #endif /* CAPABILITIES */ - diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 1a2685cc1f012..7b45efa2ff51d 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -37,12 +37,14 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_capsicum.h" #include "opt_compat.h" #include "opt_ktrace.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/sysproto.h> +#include <sys/capability.h> #include <sys/filedesc.h> #include <sys/filio.h> #include <sys/fcntl.h> @@ -232,7 +234,7 @@ kern_readv(struct thread *td, int fd, struct uio *auio) struct file *fp; int error; - error = fget_read(td, fd, &fp); + error = fget_read(td, fd, CAP_READ | CAP_SEEK, &fp); if (error) return (error); error = dofileread(td, fd, fp, auio, (off_t)-1, 0); @@ -275,7 +277,7 @@ kern_preadv(td, fd, auio, offset) struct file *fp; int error; - error = fget_read(td, fd, &fp); + error = fget_read(td, fd, CAP_READ, &fp); if (error) return (error); if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) @@ -441,7 +443,7 @@ kern_writev(struct thread *td, int fd, struct uio *auio) struct file *fp; int error; - error = fget_write(td, fd, &fp); + error = fget_write(td, fd, CAP_WRITE | CAP_SEEK, &fp); if (error) return (error); error = dofilewrite(td, fd, fp, auio, (off_t)-1, 0); @@ -484,7 +486,7 @@ kern_pwritev(td, fd, auio, offset) struct file *fp; int error; - error = fget_write(td, fd, &fp); + error = fget_write(td, fd, CAP_WRITE, &fp); if (error) return (error); if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) @@ -566,7 +568,7 @@ kern_ftruncate(td, fd, length) AUDIT_ARG_FD(fd); if (length < 0) return (EINVAL); - error = fget(td, fd, &fp); + error = fget(td, fd, CAP_FTRUNCATE, &fp); if (error) return (error); AUDIT_ARG_FILE(td->td_proc, fp); @@ -696,7 +698,7 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data) AUDIT_ARG_FD(fd); AUDIT_ARG_CMD(com); - if ((error = fget(td, fd, &fp)) != 0) + if ((error = fget(td, fd, CAP_IOCTL, &fp)) != 0) return (error); if ((fp->f_flag & (FREAD | FWRITE)) == 0) { fdrop(fp, td); @@ -1054,6 +1056,37 @@ selsetbits(fd_mask **ibits, fd_mask **obits, int idx, fd_mask bit, int events) return (n); } +static __inline int +getselfd_cap(struct filedesc *fdp, int fd, struct file **fpp) +{ + struct file *fp; +#ifdef CAPABILITIES + struct file *fp_fromcap; + int error; +#endif + + if ((fp = fget_unlocked(fdp, fd)) == NULL) + return (EBADF); +#ifdef CAPABILITIES + /* + * If the file descriptor is for a capability, test rights and use + * the file descriptor references by the capability. + */ + error = cap_funwrap(fp, CAP_POLL_EVENT, &fp_fromcap); + if (error) { + fdrop(fp, curthread); + return (error); + } + if (fp != fp_fromcap) { + fhold(fp_fromcap); + fdrop(fp, curthread); + fp = fp_fromcap; + } +#endif /* CAPABILITIES */ + *fpp = fp; + return (0); +} + /* * Traverse the list of fds attached to this thread's seltd and check for * completion. @@ -1069,6 +1102,7 @@ selrescan(struct thread *td, fd_mask **ibits, fd_mask **obits) struct file *fp; fd_mask bit; int fd, ev, n, idx; + int error; fdp = td->td_proc->p_fd; stp = td->td_sel; @@ -1080,8 +1114,9 @@ selrescan(struct thread *td, fd_mask **ibits, fd_mask **obits) /* If the selinfo wasn't cleared the event didn't fire. */ if (si != NULL) continue; - if ((fp = fget_unlocked(fdp, fd)) == NULL) - return (EBADF); + error = getselfd_cap(fdp, fd, &fp); + if (error) + return (error); idx = fd / NFDBITS; bit = (fd_mask)1 << (fd % NFDBITS); ev = fo_poll(fp, selflags(ibits, idx, bit), td->td_ucred, td); @@ -1109,6 +1144,7 @@ selscan(td, ibits, obits, nfd) fd_mask bit; int ev, flags, end, fd; int n, idx; + int error; fdp = td->td_proc->p_fd; n = 0; @@ -1119,8 +1155,9 @@ selscan(td, ibits, obits, nfd) flags = selflags(ibits, idx, bit); if (flags == 0) continue; - if ((fp = fget_unlocked(fdp, fd)) == NULL) - return (EBADF); + error = getselfd_cap(fdp, fd, &fp); + if (error) + return (error); selfdalloc(td, (void *)(uintptr_t)fd); ev = fo_poll(fp, flags, td->td_ucred, td); fdrop(fp, td); @@ -1242,11 +1279,17 @@ pollrescan(struct thread *td) if (si != NULL) continue; fp = fdp->fd_ofiles[fd->fd]; +#ifdef CAPABILITIES + if ((fp == NULL) + || (cap_funwrap(fp, CAP_POLL_EVENT, &fp) != 0)) { +#else if (fp == NULL) { +#endif fd->revents = POLLNVAL; n++; continue; } + /* * Note: backend also returns POLLHUP and * POLLERR if appropriate. @@ -1307,7 +1350,12 @@ pollscan(td, fds, nfd) fds->revents = 0; } else { fp = fdp->fd_ofiles[fds->fd]; +#ifdef CAPABILITIES + if ((fp == NULL) + || (cap_funwrap(fp, CAP_POLL_EVENT, &fp) != 0)) { +#else if (fp == NULL) { +#endif fds->revents = POLLNVAL; n++; } else { @@ -1442,6 +1490,23 @@ selfdfree(struct seltd *stp, struct selfd *sfp) uma_zfree(selfd_zone, sfp); } +/* Drain the waiters tied to all the selfd belonging the specified selinfo. */ +void +seldrain(sip) + struct selinfo *sip; +{ + + /* + * This feature is already provided by doselwakeup(), thus it is + * enough to go for it. + * Eventually, the context, should take care to avoid races + * between thread calling select()/poll() and file descriptor + * detaching, but, again, the races are just the same as + * selwakeup(). + */ + doselwakeup(sip, -1); +} + /* * Record a select request. */ diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 50b03897e2773..c44a2c964e499 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -155,6 +155,8 @@ static struct fileops pipeops = { .fo_kqfilter = pipe_kqfilter, .fo_stat = pipe_stat, .fo_close = pipe_close, + .fo_chmod = invfo_chmod, + .fo_chown = invfo_chown, .fo_flags = DFLAG_PASSABLE }; @@ -1515,6 +1517,7 @@ pipeclose(cpipe) */ knlist_clear(&cpipe->pipe_sel.si_note, 1); cpipe->pipe_present = PIPE_FINALIZED; + seldrain(&cpipe->pipe_sel); knlist_destroy(&cpipe->pipe_sel.si_note); /* diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c new file mode 100644 index 0000000000000..9993732527cdb --- /dev/null +++ b/sys/kern/sys_procdesc.c @@ -0,0 +1,524 @@ +/*- + * Copyright (c) 2009 Robert N. M. Watson + * All rights reserved. + * + * This software was developed at the University of Cambridge Computer + * Laboratory with support from a grant from Google, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*- + * FreeBSD process descriptor facility. + * + * Some processes are represented by a file descriptor, which will be used in + * preference to signaling and pids for the purposes of process management, + * and is, in effect, a form of capability. When a process descriptor is + * used with a process, it ceases to be visible to certain traditional UNIX + * process facilities, such as waitpid(2). + * + * Some semantics: + * + * - At most one process descriptor will exist for any process, although + * references to that descriptor may be held from many processes (or even + * be in flight between processes over a local domain socket). + * - Last close on the process descriptor will terminate the process using + * SIGKILL and reparent it to init so that there's a process to reap it + * when it's done exiting. + * - If the process exits before the descriptor is closed, it will not + * generate SIGCHLD on termination, or be picked up by waitpid(). + * - The pdkill(2) system call may be used to deliver a signal to the process + * using its process descriptor. + * - The pdwait4(2) system call may be used to block (or not) on a process + * descriptor to collect termination information. + * + * Open questions: + * + * - How to handle ptrace(2)? + * - Will we want to add a pidtoprocdesc(2) system call to allow process + * descriptors to be created for processes without pfork(2)? + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_procdesc.h" + +#include <sys/param.h> +#include <sys/capability.h> +#include <sys/fcntl.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/poll.h> +#include <sys/proc.h> +#include <sys/procdesc.h> +#include <sys/resourcevar.h> +#include <sys/stat.h> +#include <sys/sysproto.h> +#include <sys/sysctl.h> +#include <sys/systm.h> +#include <sys/ucred.h> + +#include <security/audit/audit.h> + +#include <vm/uma.h> + +#ifdef PROCDESC + +FEATURE(process_descriptors, "Process Descriptors"); + +static uma_zone_t procdesc_zone; + +static fo_rdwr_t procdesc_read; +static fo_rdwr_t procdesc_write; +static fo_truncate_t procdesc_truncate; +static fo_ioctl_t procdesc_ioctl; +static fo_poll_t procdesc_poll; +static fo_kqfilter_t procdesc_kqfilter; +static fo_stat_t procdesc_stat; +static fo_close_t procdesc_close; +static fo_chmod_t procdesc_chmod; +static fo_chown_t procdesc_chown; + +static struct fileops procdesc_ops = { + .fo_read = procdesc_read, + .fo_write = procdesc_write, + .fo_truncate = procdesc_truncate, + .fo_ioctl = procdesc_ioctl, + .fo_poll = procdesc_poll, + .fo_kqfilter = procdesc_kqfilter, + .fo_stat = procdesc_stat, + .fo_close = procdesc_close, + .fo_chmod = procdesc_chmod, + .fo_chown = procdesc_chown, + .fo_flags = DFLAG_PASSABLE, +}; + +/* + * Initialize with VFS so that process descriptors are available along with + * other file descriptor types. As long as it runs before init(8) starts, + * there shouldn't be a problem. + */ +static void +procdesc_init(void *dummy __unused) +{ + + procdesc_zone = uma_zcreate("procdesc", sizeof(struct procdesc), + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + if (procdesc_zone == NULL) + panic("procdesc_init: procdesc_zone not initialized"); +} +SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_ANY, procdesc_init, NULL); + +/* + * Return a locked process given a process descriptor, or ESRCH if it has + * died. + */ +int +procdesc_find(struct thread *td, int fd, cap_rights_t rights, + struct proc **p) +{ + struct procdesc *pd; + struct file *fp; + int error; + + error = fget(td, fd, rights, &fp); + if (error) + return (error); + if (fp->f_type != DTYPE_PROCDESC) { + error = EBADF; + goto out; + } + pd = fp->f_data; + sx_slock(&proctree_lock); + if (pd->pd_proc != NULL) { + *p = pd->pd_proc; + PROC_LOCK(*p); + } else + error = ESRCH; + sx_sunlock(&proctree_lock); +out: + fdrop(fp, td); + return (error); +} + +/* + * Function to be used by procstat(1) sysctls when returning procdesc + * information. + */ +pid_t +procdesc_pid(struct file *fp_procdesc) +{ + struct procdesc *pd; + + KASSERT(fp_procdesc->f_type == DTYPE_PROCDESC, + ("procdesc_pid: !procdesc")); + + pd = fp_procdesc->f_data; + return (pd->pd_pid); +} + +/* + * Retrieve the PID associated with a process descriptor. + */ +int +kern_pdgetpid(struct thread *td, int fd, cap_rights_t rights, pid_t *pidp) +{ + struct file *fp; + int error; + + error = fget(td, fd, rights, &fp); + if (error) + return (error); + if (fp->f_type != DTYPE_PROCDESC) { + error = EBADF; + goto out; + } + *pidp = procdesc_pid(fp); +out: + fdrop(fp, td); + return (error); +} + +/* + * System call to return the pid of a process given its process descriptor. + */ +int +pdgetpid(struct thread *td, struct pdgetpid_args *uap) +{ + pid_t pid; + int error; + + AUDIT_ARG_FD(uap->fd); + error = kern_pdgetpid(td, uap->fd, CAP_PDGETPID, &pid); + if (error == 0) + error = copyout(&pid, uap->pidp, sizeof(pid)); + return (error); +} + +/* + * When a new process is forked by pdfork(), a file descriptor is allocated + * by the fork code first, then the process is forked, and then we get a + * chance to set up the process descriptor. Failure is not permitted at this + * point, so procdesc_new() must succeed. + */ +void +procdesc_new(struct proc *p, int flags) +{ + struct procdesc *pd; + + pd = uma_zalloc(procdesc_zone, M_WAITOK | M_ZERO); + pd->pd_proc = p; + pd->pd_pid = p->p_pid; + p->p_procdesc = pd; + pd->pd_flags = 0; + if (flags & PD_DAEMON) + pd->pd_flags |= PDF_DAEMON; + PROCDESC_LOCK_INIT(pd); + + /* + * Process descriptors start out with two references: one from their + * struct file, and the other from their struct proc. + */ + refcount_init(&pd->pd_refcount, 2); +} + +/* + * Initialize a file with a process descriptor. + */ +void +procdesc_finit(struct procdesc *pdp, struct file *fp) +{ + + finit(fp, FREAD | FWRITE, DTYPE_PROCDESC, pdp, &procdesc_ops); +} + +static void +procdesc_free(struct procdesc *pd) +{ + + /* + * When the last reference is released, we assert that the descriptor + * has been closed, but not that the process has exited, as we will + * detach the descriptor before the process dies if the descript is + * closed, as we can't wait synchronously. + */ + if (refcount_release(&pd->pd_refcount)) { + KASSERT(pd->pd_proc == NULL, + ("procdesc_free: pd_proc != NULL")); + KASSERT((pd->pd_flags & PDF_CLOSED), + ("procdesc_free: !PDF_CLOSED")); + + PROCDESC_LOCK_DESTROY(pd); + uma_zfree(procdesc_zone, pd); + } +} + +/* + * procdesc_exit() - notify a process descriptor that its process is exiting. + * We use the proctree_lock to ensure that process exit either happens + * strictly before or strictly after a concurrent call to procdesc_close(). + */ +int +procdesc_exit(struct proc *p) +{ + struct procdesc *pd; + + sx_assert(&proctree_lock, SA_XLOCKED); + PROC_LOCK_ASSERT(p, MA_OWNED); + KASSERT(p->p_procdesc != NULL, ("procdesc_exit: p_procdesc NULL")); + + pd = p->p_procdesc; + + PROCDESC_LOCK(pd); + KASSERT((pd->pd_flags & PDF_CLOSED) == 0 || p->p_pptr == initproc, + ("procdesc_exit: closed && parent not init")); + + pd->pd_flags |= PDF_EXITED; + + /* + * If the process descriptor has been closed, then we have nothing + * to do; return 1 so that init will get SIGCHLD and do the reaping. + * Clean up the procdesc now rather than letting it happen during + * that reap. + */ + if (pd->pd_flags & PDF_CLOSED) { + PROCDESC_UNLOCK(pd); + pd->pd_proc = NULL; + p->p_procdesc = NULL; + procdesc_free(pd); + return (1); + } + if (pd->pd_flags & PDF_SELECTED) { + pd->pd_flags &= ~PDF_SELECTED; + selwakeup(&pd->pd_selinfo); + } + PROCDESC_UNLOCK(pd); + return (0); +} + +/* + * When a process descriptor is reaped, perhaps as a result of close() or + * pdwait4(), release the process's reference on the process descriptor. + */ +void +procdesc_reap(struct proc *p) +{ + struct procdesc *pd; + + sx_assert(&proctree_lock, SA_XLOCKED); + KASSERT(p->p_procdesc != NULL, ("procdesc_reap: p_procdesc == NULL")); + + pd = p->p_procdesc; + pd->pd_proc = NULL; + procdesc_free(pd); +} + +/* + * procdesc_close() - last close on a process descriptor. If the process is + * still running, terminate with SIGKILL (unless PD_DAEMON is set) and let + * init(8) clean up the mess; if not, we have to clean up the zombie ourselves. + */ +static int +procdesc_close(struct file *fp, struct thread *td) +{ + struct procdesc *pd; + struct proc *p; + + KASSERT(fp->f_type == DTYPE_PROCDESC, ("procdesc_close: !procdesc")); + + pd = fp->f_data; + fp->f_ops = &badfileops; + fp->f_data = NULL; + + sx_xlock(&proctree_lock); + PROCDESC_LOCK(pd); + pd->pd_flags |= PDF_CLOSED; + PROCDESC_UNLOCK(pd); + p = pd->pd_proc; + PROC_LOCK(p); + if (p->p_state == PRS_ZOMBIE) { + /* + * If the process is already dead and just awaiting reaping, + * do that now. This will release the process's reference to + * the process descriptor when it calls back into + * procdesc_reap(). + */ + PROC_SLOCK(p); + proc_reap(curthread, p, NULL, 0, NULL); + } else { + /* + * If the process is not yet dead, we need to kill it, but we + * can't wait around synchronously for it to go away, as that + * path leads to madness (and deadlocks). First, detach the + * process from its descriptor so that its exit status will + * be reported normally. + */ + pd->pd_proc = NULL; + p->p_procdesc = NULL; + procdesc_free(pd); + + /* + * Next, reparent it to init(8) so that there's someone to + * pick up the pieces; finally, terminate with prejudice. + */ + p->p_sigparent = SIGCHLD; + proc_reparent(p, initproc); + if ((pd->pd_flags & PD_DAEMON) == 0) + psignal(p, SIGKILL); + PROC_UNLOCK(p); + sx_xunlock(&proctree_lock); + } + + /* + * Release the file descriptor's reference on the process descriptor. + */ + procdesc_free(pd); + return (0); +} + +static int +procdesc_read(struct file *fp, struct uio *uio, struct ucred *active_cred, + int flags, struct thread *td) +{ + + return (EOPNOTSUPP); +} + +static int +procdesc_write(struct file *fp, struct uio *uio, struct ucred *active_cred, + int flags, struct thread *td) +{ + + return (EOPNOTSUPP); +} + +static int +procdesc_truncate(struct file *fp, off_t length, struct ucred *active_cred, + struct thread *td) +{ + + return (EOPNOTSUPP); +} + +static int +procdesc_ioctl(struct file *fp, u_long com, void *data, + struct ucred *active_cred, struct thread *td) +{ + + return (EOPNOTSUPP); +} + +static int +procdesc_poll(struct file *fp, int events, struct ucred *active_cred, + struct thread *td) +{ + struct procdesc *pd; + int revents; + + revents = 0; + pd = fp->f_data; + PROCDESC_LOCK(pd); + if (pd->pd_flags & PDF_EXITED) + revents |= POLLHUP; + if (revents == 0) { + selrecord(td, &pd->pd_selinfo); + pd->pd_flags |= PDF_SELECTED; + } + PROCDESC_UNLOCK(pd); + return (revents); +} + +static int +procdesc_kqfilter(struct file *fp, struct knote *kn) +{ + + return (EOPNOTSUPP); +} + +static int +procdesc_stat(struct file *fp, struct stat *sb, struct ucred *active_cred, + struct thread *td) +{ + struct procdesc *pd; + struct timeval pstart; + + /* + * XXXRW: Perhaps we should cache some more information from the + * process so that we can return it reliably here even after it has + * died. For example, caching its credential data. + */ + bzero(sb, sizeof(*sb)); + pd = fp->f_data; + sx_slock(&proctree_lock); + if (pd->pd_proc != NULL) { + PROC_LOCK(pd->pd_proc); + + /* Set birth and [acm] times to process start time. */ + pstart = pd->pd_proc->p_stats->p_start; + timevaladd(&pstart, &boottime); + TIMEVAL_TO_TIMESPEC(&pstart, &sb->st_birthtim); + sb->st_atim = sb->st_birthtim; + sb->st_ctim = sb->st_birthtim; + sb->st_mtim = sb->st_birthtim; + if (pd->pd_proc->p_state != PRS_ZOMBIE) + sb->st_mode = S_IFREG | S_IRWXU; + else + sb->st_mode = S_IFREG; + sb->st_uid = pd->pd_proc->p_ucred->cr_ruid; + sb->st_gid = pd->pd_proc->p_ucred->cr_rgid; + PROC_UNLOCK(pd->pd_proc); + } else + sb->st_mode = S_IFREG; + sx_sunlock(&proctree_lock); + return (0); +} + +static int +procdesc_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, + struct thread *td) +{ + + return (EOPNOTSUPP); +} + +static int +procdesc_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, + struct thread *td) +{ + + return (EOPNOTSUPP); +} + +#else /* !PROCDESC */ + +int +pdgetpid(struct thread *td, struct pdgetpid_args *uap) +{ + + return (ENOSYS); +} + +#endif /* PROCDESC */ diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c index c9b053443f454..cd6f655cc65cb 100644 --- a/sys/kern/sys_socket.c +++ b/sys/kern/sys_socket.c @@ -64,6 +64,8 @@ struct fileops socketops = { .fo_kqfilter = soo_kqfilter, .fo_stat = soo_stat, .fo_close = soo_close, + .fo_chmod = invfo_chmod, + .fo_chown = invfo_chown, .fo_flags = DFLAG_PASSABLE }; diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index abd94842c184c..e3531880cba6b 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD + * created from FreeBSD: head/sys/kern/syscalls.master 224987 2011-08-18 22:51:30Z jonathan */ const char *syscallnames[] = { @@ -525,10 +525,10 @@ const char *syscallnames[] = { "cap_getrights", /* 515 = cap_getrights */ "cap_enter", /* 516 = cap_enter */ "cap_getmode", /* 517 = cap_getmode */ - "#518", /* 518 = pdfork */ - "#519", /* 519 = pdkill */ - "#520", /* 520 = pdgetpid */ - "#521", /* 521 = pdwait */ + "pdfork", /* 518 = pdfork */ + "pdkill", /* 519 = pdkill */ + "pdgetpid", /* 520 = pdgetpid */ + "#521", /* 521 = pdwait4 */ "pselect", /* 522 = pselect */ "getloginclass", /* 523 = getloginclass */ "setloginclass", /* 524 = setloginclass */ diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 0b249a5b55ad7..b79c6c7109cc2 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -919,10 +919,10 @@ u_int64_t *rightsp); } 516 AUE_CAP_ENTER STD { int cap_enter(void); } 517 AUE_CAP_GETMODE STD { int cap_getmode(u_int *modep); } -518 AUE_PDFORK UNIMPL pdfork -519 AUE_PDKILL UNIMPL pdkill -520 AUE_PDGETPID UNIMPL pdgetpid -521 AUE_PDWAIT UNIMPL pdwait +518 AUE_PDFORK STD { int pdfork(int *fdp, int flags); } +519 AUE_PDKILL STD { int pdkill(int fd, int signum); } +520 AUE_PDGETPID STD { int pdgetpid(int fd, pid_t *pidp); } +521 AUE_PDWAIT UNIMPL pdwait4 522 AUE_SELECT STD { int pselect(int nd, fd_set *in, \ fd_set *ou, fd_set *ex, \ const struct timespec *ts, \ diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c index f57777f8c898b..9343613d9be61 100644 --- a/sys/kern/systrace_args.c +++ b/sys/kern/systrace_args.c @@ -3124,6 +3124,30 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 1; break; } + /* pdfork */ + case 518: { + struct pdfork_args *p = params; + uarg[0] = (intptr_t) p->fdp; /* int * */ + iarg[1] = p->flags; /* int */ + *n_args = 2; + break; + } + /* pdkill */ + case 519: { + struct pdkill_args *p = params; + iarg[0] = p->fd; /* int */ + iarg[1] = p->signum; /* int */ + *n_args = 2; + break; + } + /* pdgetpid */ + case 520: { + struct pdgetpid_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->pidp; /* pid_t * */ + *n_args = 2; + break; + } /* pselect */ case 522: { struct pselect_args *p = params; @@ -8381,6 +8405,45 @@ systrace_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* pdfork */ + case 518: + switch(ndx) { + case 0: + p = "int *"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* pdkill */ + case 519: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "int"; + break; + default: + break; + }; + break; + /* pdgetpid */ + case 520: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "pid_t *"; + break; + default: + break; + }; + break; /* pselect */ case 522: switch(ndx) { diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 187e6358f7514..b5fcba91b4a50 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -30,9 +30,11 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_capsicum.h" #include "opt_compat.h" #include <sys/param.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/cons.h> #include <sys/fcntl.h> @@ -764,7 +766,7 @@ ttyil_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { struct tty *tp = dev->si_drv1; - int error = 0; + int error; tty_lock(tp); if (tty_gone(tp)) { @@ -775,6 +777,7 @@ ttyil_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, error = ttydevsw_cioctl(tp, dev2unit(dev), cmd, data, td); if (error != ENOIOCTL) goto done; + error = 0; switch (cmd) { case TIOCGETA: @@ -1020,6 +1023,8 @@ tty_dealloc(void *arg) MPASS(ttyinq_getsize(&tp->t_inq) == 0); MPASS(ttyoutq_getsize(&tp->t_outq) == 0); + seldrain(&tp->t_inpoll); + seldrain(&tp->t_outpoll); knlist_destroy(&tp->t_inpoll.si_note); knlist_destroy(&tp->t_outpoll.si_note); @@ -1810,6 +1815,9 @@ ttyhook_register(struct tty **rtp, struct proc *p, int fd, { struct tty *tp; struct file *fp; +#ifdef CAPABILITIES + struct file *fp_cap; +#endif struct cdev *dev; struct cdevsw *cdp; struct filedesc *fdp; @@ -1827,6 +1835,13 @@ ttyhook_register(struct tty **rtp, struct proc *p, int fd, goto done1; } +#ifdef CAPABILITIES + fp_cap = fp; + error = cap_funwrap(fp_cap, CAP_TTYHOOK, &fp); + if (error) + return (error); +#endif + /* * Make sure the vnode is bound to a character device. * Unlocked check for the vnode type is ok there, because we diff --git a/sys/kern/tty_pts.c b/sys/kern/tty_pts.c index a3db59bfc5a43..f2f5c4e71bd8f 100644 --- a/sys/kern/tty_pts.c +++ b/sys/kern/tty_pts.c @@ -597,6 +597,8 @@ static struct fileops ptsdev_ops = { .fo_kqfilter = ptsdev_kqfilter, .fo_stat = ptsdev_stat, .fo_close = ptsdev_close, + .fo_chmod = invfo_chmod, + .fo_chown = invfo_chown, .fo_flags = DFLAG_PASSABLE, }; @@ -686,6 +688,8 @@ ptsdrv_free(void *softc) racct_sub_cred(psc->pts_cred, RACCT_NPTS, 1); crfree(psc->pts_cred); + seldrain(&psc->pts_inpoll); + seldrain(&psc->pts_outpoll); knlist_destroy(&psc->pts_inpoll.si_note); knlist_destroy(&psc->pts_outpoll.si_note); diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c index 9b334acb3fe3d..b91b890e8a273 100644 --- a/sys/kern/uipc_mqueue.c +++ b/sys/kern/uipc_mqueue.c @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/limits.h> #include <sys/buf.h> +#include <sys/capability.h> #include <sys/dirent.h> #include <sys/event.h> #include <sys/eventhandler.h> @@ -1561,6 +1562,8 @@ mqueue_free(struct mqueue *mq) } mtx_destroy(&mq->mq_mutex); + seldrain(&mq->mq_rsel); + seldrain(&mq->mq_wsel); knlist_destroy(&mq->mq_rsel.si_note); knlist_destroy(&mq->mq_wsel.si_note); uma_zfree(mqueue_zone, mq); @@ -2087,19 +2090,19 @@ kmq_unlink(struct thread *td, struct kmq_unlink_args *uap) return (error); } -typedef int (*_fgetf)(struct thread *, int, struct file **); +typedef int (*_fgetf)(struct thread *, int, cap_rights_t, struct file **); /* * Get message queue by giving file slot */ static int -_getmq(struct thread *td, int fd, _fgetf func, +_getmq(struct thread *td, int fd, cap_rights_t rights, _fgetf func, struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) { struct mqfs_node *pn; int error; - error = func(td, fd, fpp); + error = func(td, fd, rights, fpp); if (error) return (error); if (&mqueueops != (*fpp)->f_ops) { @@ -2118,21 +2121,21 @@ static __inline int getmq(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) { - return _getmq(td, fd, fget, fpp, ppn, pmq); + return _getmq(td, fd, CAP_POLL_EVENT, fget, fpp, ppn, pmq); } static __inline int getmq_read(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) { - return _getmq(td, fd, fget_read, fpp, ppn, pmq); + return _getmq(td, fd, CAP_READ, fget_read, fpp, ppn, pmq); } static __inline int getmq_write(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) { - return _getmq(td, fd, fget_write, fpp, ppn, pmq); + return _getmq(td, fd, CAP_WRITE, fget_write, fpp, ppn, pmq); } static int @@ -2243,7 +2246,7 @@ kmq_notify(struct thread *td, struct kmq_notify_args *uap) struct filedesc *fdp; struct proc *p; struct mqueue *mq; - struct file *fp; + struct file *fp, *fp2; struct mqueue_notifier *nt, *newnt = NULL; int error; @@ -2267,7 +2270,18 @@ kmq_notify(struct thread *td, struct kmq_notify_args *uap) return (error); again: FILEDESC_SLOCK(fdp); - if (fget_locked(fdp, uap->mqd) != fp) { + fp2 = fget_locked(fdp, uap->mqd); + if (fp2 == NULL) { + FILEDESC_SUNLOCK(fdp); + error = EBADF; + goto out; + } + error = cap_funwrap(fp2, CAP_POLL_EVENT, &fp2); + if (error) { + FILEDESC_SUNLOCK(fdp); + goto out; + } + if (fp2 != fp) { FILEDESC_SUNLOCK(fdp); error = EBADF; goto out; @@ -2457,6 +2471,7 @@ mqf_stat(struct file *fp, struct stat *st, struct ucred *active_cred, struct mqfs_node *pn = fp->f_data; bzero(st, sizeof *st); + sx_xlock(&mqfs_data.mi_lock); st->st_atim = pn->mn_atime; st->st_mtim = pn->mn_mtime; st->st_ctim = pn->mn_ctime; @@ -2464,10 +2479,56 @@ mqf_stat(struct file *fp, struct stat *st, struct ucred *active_cred, st->st_uid = pn->mn_uid; st->st_gid = pn->mn_gid; st->st_mode = S_IFIFO | pn->mn_mode; + sx_xunlock(&mqfs_data.mi_lock); return (0); } static int +mqf_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, + struct thread *td) +{ + struct mqfs_node *pn; + int error; + + error = 0; + pn = fp->f_data; + sx_xlock(&mqfs_data.mi_lock); + error = vaccess(VREG, pn->mn_mode, pn->mn_uid, pn->mn_gid, VADMIN, + active_cred, NULL); + if (error != 0) + goto out; + pn->mn_mode = mode & ACCESSPERMS; +out: + sx_xunlock(&mqfs_data.mi_lock); + return (error); +} + +static int +mqf_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, + struct thread *td) +{ + struct mqfs_node *pn; + int error; + + error = 0; + pn = fp->f_data; + sx_xlock(&mqfs_data.mi_lock); + if (uid == (uid_t)-1) + uid = pn->mn_uid; + if (gid == (gid_t)-1) + gid = pn->mn_gid; + if (((uid != pn->mn_uid && uid != active_cred->cr_uid) || + (gid != pn->mn_gid && !groupmember(gid, active_cred))) && + (error = priv_check_cred(active_cred, PRIV_VFS_CHOWN, 0))) + goto out; + pn->mn_uid = uid; + pn->mn_gid = gid; +out: + sx_xunlock(&mqfs_data.mi_lock); + return (error); +} + +static int mqf_kqfilter(struct file *fp, struct knote *kn) { struct mqueue *mq = FPTOMQ(fp); @@ -2523,6 +2584,8 @@ static struct fileops mqueueops = { .fo_poll = mqf_poll, .fo_kqfilter = mqf_kqfilter, .fo_stat = mqf_stat, + .fo_chmod = mqf_chmod, + .fo_chown = mqf_chown, .fo_close = mqf_close }; diff --git a/sys/kern/uipc_sem.c b/sys/kern/uipc_sem.c index 917c343ed3a42..f77bf3b9d5a33 100644 --- a/sys/kern/uipc_sem.c +++ b/sys/kern/uipc_sem.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include "opt_posix.h" #include <sys/param.h> +#include <sys/capability.h> #include <sys/condvar.h> #include <sys/fcntl.h> #include <sys/file.h> @@ -116,7 +117,8 @@ static int ksem_create(struct thread *td, const char *path, semid_t *semidp, mode_t mode, unsigned int value, int flags, int compat32); static void ksem_drop(struct ksem *ks); -static int ksem_get(struct thread *td, semid_t id, struct file **fpp); +static int ksem_get(struct thread *td, semid_t id, cap_rights_t rights, + struct file **fpp); static struct ksem *ksem_hold(struct ksem *ks); static void ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks); static struct ksem *ksem_lookup(char *path, Fnv32_t fnv); @@ -133,6 +135,8 @@ static fo_poll_t ksem_poll; static fo_kqfilter_t ksem_kqfilter; static fo_stat_t ksem_stat; static fo_close_t ksem_closef; +static fo_chmod_t ksem_chmod; +static fo_chown_t ksem_chown; /* File descriptor operations. */ static struct fileops ksem_ops = { @@ -144,6 +148,8 @@ static struct fileops ksem_ops = { .fo_kqfilter = ksem_kqfilter, .fo_stat = ksem_stat, .fo_close = ksem_closef, + .fo_chmod = ksem_chmod, + .fo_chown = ksem_chown, .fo_flags = DFLAG_PASSABLE }; @@ -218,19 +224,76 @@ ksem_stat(struct file *fp, struct stat *sb, struct ucred *active_cred, * file descriptor. */ bzero(sb, sizeof(*sb)); - sb->st_mode = S_IFREG | ks->ks_mode; /* XXX */ + mtx_lock(&sem_lock); sb->st_atim = ks->ks_atime; sb->st_ctim = ks->ks_ctime; sb->st_mtim = ks->ks_mtime; - sb->st_birthtim = ks->ks_birthtime; + sb->st_birthtim = ks->ks_birthtime; sb->st_uid = ks->ks_uid; sb->st_gid = ks->ks_gid; + sb->st_mode = S_IFREG | ks->ks_mode; /* XXX */ + mtx_unlock(&sem_lock); return (0); } static int +ksem_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, + struct thread *td) +{ + struct ksem *ks; + int error; + + error = 0; + ks = fp->f_data; + mtx_lock(&sem_lock); +#ifdef MAC + error = mac_posixsem_check_setmode(active_cred, ks, mode); + if (error != 0) + goto out; +#endif + error = vaccess(VREG, ks->ks_mode, ks->ks_uid, ks->ks_gid, VADMIN, + active_cred, NULL); + if (error != 0) + goto out; + ks->ks_mode = mode & ACCESSPERMS; +out: + mtx_unlock(&sem_lock); + return (error); +} + +static int +ksem_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, + struct thread *td) +{ + struct ksem *ks; + int error; + + error = 0; + ks = fp->f_data; + mtx_lock(&sem_lock); +#ifdef MAC + error = mac_posixsem_check_setowner(active_cred, ks, uid, gid); + if (error != 0) + goto out; +#endif + if (uid == (uid_t)-1) + uid = ks->ks_uid; + if (gid == (gid_t)-1) + gid = ks->ks_gid; + if (((uid != ks->ks_uid && uid != active_cred->cr_uid) || + (gid != ks->ks_gid && !groupmember(gid, active_cred))) && + (error = priv_check_cred(active_cred, PRIV_VFS_CHOWN, 0))) + goto out; + ks->ks_uid = uid; + ks->ks_gid = gid; +out: + mtx_unlock(&sem_lock); + return (error); +} + +static int ksem_closef(struct file *fp, struct thread *td) { struct ksem *ks; @@ -525,13 +588,13 @@ ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode, } static int -ksem_get(struct thread *td, semid_t id, struct file **fpp) +ksem_get(struct thread *td, semid_t id, cap_rights_t rights, struct file **fpp) { struct ksem *ks; struct file *fp; int error; - error = fget(td, id, &fp); + error = fget(td, id, rights, &fp); if (error) return (EINVAL); if (fp->f_type != DTYPE_SEM) { @@ -623,7 +686,8 @@ ksem_close(struct thread *td, struct ksem_close_args *uap) struct file *fp; int error; - error = ksem_get(td, uap->id, &fp); + /* No capability rights required to close a semaphore. */ + error = ksem_get(td, uap->id, 0, &fp); if (error) return (error); ks = fp->f_data; @@ -648,7 +712,7 @@ ksem_post(struct thread *td, struct ksem_post_args *uap) struct ksem *ks; int error; - error = ksem_get(td, uap->id, &fp); + error = ksem_get(td, uap->id, CAP_SEM_POST, &fp); if (error) return (error); ks = fp->f_data; @@ -738,7 +802,7 @@ kern_sem_wait(struct thread *td, semid_t id, int tryflag, int error; DP((">>> kern_sem_wait entered! pid=%d\n", (int)td->td_proc->p_pid)); - error = ksem_get(td, id, &fp); + error = ksem_get(td, id, CAP_SEM_WAIT, &fp); if (error) return (error); ks = fp->f_data; @@ -804,7 +868,7 @@ ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap) struct ksem *ks; int error, val; - error = ksem_get(td, uap->id, &fp); + error = ksem_get(td, uap->id, CAP_SEM_GETVALUE, &fp); if (error) return (error); ks = fp->f_data; @@ -838,7 +902,8 @@ ksem_destroy(struct thread *td, struct ksem_destroy_args *uap) struct ksem *ks; int error; - error = ksem_get(td, uap->id, &fp); + /* No capability rights required to close a semaphore. */ + error = ksem_get(td, uap->id, 0, &fp); if (error) return (error); ks = fp->f_data; diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c index 0414f1283e769..f9fc3ca8bf30e 100644 --- a/sys/kern/uipc_shm.c +++ b/sys/kern/uipc_shm.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2006 Robert N. M. Watson + * Copyright (c) 2006, 2011 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,25 +31,21 @@ * * TODO: * - * (2) Need to export data to a userland tool via a sysctl. Should ipcs(1) + * (1) Need to export data to a userland tool via a sysctl. Should ipcs(1) * and ipcrm(1) be expanded or should new tools to manage both POSIX * kernel semaphores and POSIX shared memory be written? * - * (3) Add support for this file type to fstat(1). + * (2) Add support for this file type to fstat(1). * - * (4) Resource limits? Does this need its own resource limits or are the + * (3) Resource limits? Does this need its own resource limits or are the * existing limits in mmap(2) sufficient? * - * (5) Partial page truncation. vnode_pager_setsize() will zero any parts + * (4) Partial page truncation. vnode_pager_setsize() will zero any parts * of a partially mapped page as a result of ftruncate(2)/truncate(2). * We can do the same (with the same pmap evil), but do we need to * worry about the bits on disk if the page is swapped out or will the * swapper zero the parts of a page that are invalid if the page is * swapped back in for us? - * - * (6) Add MAC support in mac_biba(4) and mac_mls(4). - * - * (7) Add a MAC check_create() hook for creating new named objects. */ #include <sys/cdefs.h> @@ -68,6 +64,7 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/mman.h> #include <sys/mutex.h> +#include <sys/priv.h> #include <sys/proc.h> #include <sys/refcount.h> #include <sys/resourcevar.h> @@ -123,6 +120,8 @@ static fo_poll_t shm_poll; static fo_kqfilter_t shm_kqfilter; static fo_stat_t shm_stat; static fo_close_t shm_close; +static fo_chmod_t shm_chmod; +static fo_chown_t shm_chown; /* File descriptor operations. */ static struct fileops shm_ops = { @@ -134,6 +133,8 @@ static struct fileops shm_ops = { .fo_kqfilter = shm_kqfilter, .fo_stat = shm_stat, .fo_close = shm_close, + .fo_chmod = shm_chmod, + .fo_chown = shm_chown, .fo_flags = DFLAG_PASSABLE }; @@ -218,16 +219,18 @@ shm_stat(struct file *fp, struct stat *sb, struct ucred *active_cred, * descriptor. */ bzero(sb, sizeof(*sb)); - sb->st_mode = S_IFREG | shmfd->shm_mode; /* XXX */ sb->st_blksize = PAGE_SIZE; sb->st_size = shmfd->shm_size; sb->st_blocks = (sb->st_size + sb->st_blksize - 1) / sb->st_blksize; + mtx_lock(&shm_timestamp_lock); sb->st_atim = shmfd->shm_atime; sb->st_ctim = shmfd->shm_ctime; sb->st_mtim = shmfd->shm_mtime; - sb->st_birthtim = shmfd->shm_birthtime; + sb->st_birthtim = shmfd->shm_birthtime; + sb->st_mode = S_IFREG | shmfd->shm_mode; /* XXX */ sb->st_uid = shmfd->shm_uid; sb->st_gid = shmfd->shm_gid; + mtx_unlock(&shm_timestamp_lock); return (0); } @@ -395,14 +398,18 @@ static int shm_access(struct shmfd *shmfd, struct ucred *ucred, int flags) { accmode_t accmode; + int error; accmode = 0; if (flags & FREAD) accmode |= VREAD; if (flags & FWRITE) accmode |= VWRITE; - return (vaccess(VREG, shmfd->shm_mode, shmfd->shm_uid, shmfd->shm_gid, - accmode, ucred, NULL)); + mtx_lock(&shm_timestamp_lock); + error = vaccess(VREG, shmfd->shm_mode, shmfd->shm_uid, shmfd->shm_gid, + accmode, ucred, NULL); + mtx_unlock(&shm_timestamp_lock); + return (error); } /* @@ -540,8 +547,16 @@ shm_open(struct thread *td, struct shm_open_args *uap) if (shmfd == NULL) { /* Object does not yet exist, create it if requested. */ if (uap->flags & O_CREAT) { - shmfd = shm_alloc(td->td_ucred, cmode); - shm_insert(path, fnv, shmfd); +#ifdef MAC + error = mac_posixshm_check_create(td->td_ucred, + path); + if (error == 0) { +#endif + shmfd = shm_alloc(td->td_ucred, cmode); + shm_insert(path, fnv, shmfd); +#ifdef MAC + } +#endif } else { free(path, M_SHMFD); error = ENOENT; @@ -558,7 +573,7 @@ shm_open(struct thread *td, struct shm_open_args *uap) else { #ifdef MAC error = mac_posixshm_check_open(td->td_ucred, - shmfd); + shmfd, FFLAGS(uap->flags & O_ACCMODE)); if (error == 0) #endif error = shm_access(shmfd, td->td_ucred, @@ -651,3 +666,62 @@ shm_mmap(struct shmfd *shmfd, vm_size_t objsize, vm_ooffset_t foff, *obj = shmfd->shm_object; return (0); } + +static int +shm_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, + struct thread *td) +{ + struct shmfd *shmfd; + int error; + + error = 0; + shmfd = fp->f_data; + mtx_lock(&shm_timestamp_lock); + /* + * SUSv4 says that x bits of permission need not be affected. + * Be consistent with our shm_open there. + */ +#ifdef MAC + error = mac_posixshm_check_setmode(active_cred, shmfd, mode); + if (error != 0) + goto out; +#endif + error = vaccess(VREG, shmfd->shm_mode, shmfd->shm_uid, + shmfd->shm_gid, VADMIN, active_cred, NULL); + if (error != 0) + goto out; + shmfd->shm_mode = mode & ACCESSPERMS; +out: + mtx_unlock(&shm_timestamp_lock); + return (error); +} + +static int +shm_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, + struct thread *td) +{ + struct shmfd *shmfd; + int error; + + error = 0; + shmfd = fp->f_data; + mtx_lock(&shm_timestamp_lock); +#ifdef MAC + error = mac_posixshm_check_setowner(active_cred, shmfd, uid, gid); + if (error != 0) + goto out; +#endif + if (uid == (uid_t)-1) + uid = shmfd->shm_uid; + if (gid == (gid_t)-1) + gid = shmfd->shm_gid; + if (((uid != shmfd->shm_uid && uid != active_cred->cr_uid) || + (gid != shmfd->shm_gid && !groupmember(gid, active_cred))) && + (error = priv_check_cred(active_cred, PRIV_VFS_CHOWN, 0))) + goto out; + shmfd->shm_uid = uid; + shmfd->shm_gid = gid; +out: + mtx_unlock(&shm_timestamp_lock); + return (error); +} diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c index 2d86d740996c0..551afac00138e 100644 --- a/sys/kern/uipc_sockbuf.c +++ b/sys/kern/uipc_sockbuf.c @@ -61,7 +61,7 @@ void (*aio_swake)(struct socket *, struct sockbuf *); u_long sb_max = SB_MAX; u_long sb_max_adj = - SB_MAX * MCLBYTES / (MSIZE + MCLBYTES); /* adjusted sb_max */ + (quad_t)SB_MAX * MCLBYTES / (MSIZE + MCLBYTES); /* adjusted sb_max */ static u_long sb_efficiency = 8; /* parameter for sbreserve() */ diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 990c6bad11f89..bbd4fad38749b 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -661,6 +661,8 @@ sofree(struct socket *so) */ sbdestroy(&so->so_snd, so); sbdestroy(&so->so_rcv, so); + seldrain(&so->so_snd.sb_sel); + seldrain(&so->so_rcv.sb_sel); knlist_destroy(&so->so_rcv.sb_sel.si_note); knlist_destroy(&so->so_snd.sb_sel.si_note); sodealloc(so); diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index c434973a1b675..0e5efe6f3a9be 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -120,33 +120,47 @@ SYSCTL_INT(_kern_ipc, OID_AUTO, nsfbufsused, CTLFLAG_RD, &nsfbufsused, 0, "Number of sendfile(2) sf_bufs in use"); /* - * Convert a user file descriptor to a kernel file entry. A reference on the - * file entry is held upon returning. This is lighter weight than - * fgetsock(), which bumps the socket reference drops the file reference - * count instead, as this approach avoids several additional mutex operations - * associated with the additional reference count. If requested, return the - * open file flags. + * Convert a user file descriptor to a kernel file entry and check that, if + * it is a capability, the right rights are present. A reference on the file + * entry is held upon returning. */ static int -getsock(struct filedesc *fdp, int fd, struct file **fpp, u_int *fflagp) +getsock_cap(struct filedesc *fdp, int fd, cap_rights_t rights, + struct file **fpp, u_int *fflagp) { struct file *fp; +#ifdef CAPABILITIES + struct file *fp_fromcap; int error; +#endif fp = NULL; - if (fdp == NULL || (fp = fget_unlocked(fdp, fd)) == NULL) { - error = EBADF; - } else if (fp->f_type != DTYPE_SOCKET) { + if ((fdp == NULL) || ((fp = fget_unlocked(fdp, fd)) == NULL)) + return (EBADF); +#ifdef CAPABILITIES + /* + * If the file descriptor is for a capability, test rights and use + * the file descriptor referenced by the capability. + */ + error = cap_funwrap(fp, rights, &fp_fromcap); + if (error) { fdrop(fp, curthread); - fp = NULL; - error = ENOTSOCK; - } else { - if (fflagp != NULL) - *fflagp = fp->f_flag; - error = 0; + return (error); } + if (fp != fp_fromcap) { + fhold(fp_fromcap); + fdrop(fp, curthread); + fp = fp_fromcap; + } +#endif /* CAPABILITIES */ + if (fp->f_type != DTYPE_SOCKET) { + fdrop(fp, curthread); + return (ENOTSOCK); + } + if (fflagp != NULL) + *fflagp = fp->f_flag; *fpp = fp; - return (error); + return (0); } /* @@ -226,7 +240,7 @@ kern_bind(td, fd, sa) int error; AUDIT_ARG_FD(fd); - error = getsock(td->td_proc->p_fd, fd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, fd, CAP_BIND, &fp, NULL); if (error) return (error); so = fp->f_data; @@ -257,7 +271,7 @@ listen(td, uap) int error; AUDIT_ARG_FD(uap->s); - error = getsock(td->td_proc->p_fd, uap->s, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_LISTEN, &fp, NULL); if (error == 0) { so = fp->f_data; #ifdef MAC @@ -347,7 +361,7 @@ kern_accept(struct thread *td, int s, struct sockaddr **name, AUDIT_ARG_FD(s); fdp = td->td_proc->p_fd; - error = getsock(fdp, s, &headfp, &fflag); + error = getsock_cap(fdp, s, CAP_ACCEPT, &headfp, &fflag); if (error) return (error); head = headfp->f_data; @@ -535,7 +549,7 @@ kern_connect(td, fd, sa) int interrupted = 0; AUDIT_ARG_FD(fd); - error = getsock(td->td_proc->p_fd, fd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, fd, CAP_CONNECT, &fp, NULL); if (error) return (error); so = fp->f_data; @@ -744,12 +758,16 @@ kern_sendit(td, s, mp, flags, control, segflg) struct socket *so; int i; int len, error; + cap_rights_t rights; #ifdef KTRACE struct uio *ktruio = NULL; #endif AUDIT_ARG_FD(s); - error = getsock(td->td_proc->p_fd, s, &fp, NULL); + rights = CAP_WRITE; + if (mp->msg_name != NULL) + rights |= CAP_CONNECT; + error = getsock_cap(td->td_proc->p_fd, s, rights, &fp, NULL); if (error) return (error); so = (struct socket *)fp->f_data; @@ -953,7 +971,7 @@ kern_recvit(td, s, mp, fromseg, controlp) *controlp = NULL; AUDIT_ARG_FD(s); - error = getsock(td->td_proc->p_fd, s, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, s, CAP_READ, &fp, NULL); if (error) return (error); so = fp->f_data; @@ -1267,7 +1285,8 @@ shutdown(td, uap) int error; AUDIT_ARG_FD(uap->s); - error = getsock(td->td_proc->p_fd, uap->s, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_SHUTDOWN, &fp, + NULL); if (error == 0) { so = fp->f_data; error = soshutdown(so, uap->how); @@ -1330,7 +1349,7 @@ kern_setsockopt(td, s, level, name, val, valseg, valsize) } AUDIT_ARG_FD(s); - error = getsock(td->td_proc->p_fd, s, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, s, CAP_SETSOCKOPT, &fp, NULL); if (error == 0) { so = fp->f_data; error = sosetopt(so, &sopt); @@ -1409,7 +1428,7 @@ kern_getsockopt(td, s, level, name, val, valseg, valsize) } AUDIT_ARG_FD(s); - error = getsock(td->td_proc->p_fd, s, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, s, CAP_GETSOCKOPT, &fp, NULL); if (error == 0) { so = fp->f_data; error = sogetopt(so, &sopt); @@ -1471,7 +1490,7 @@ kern_getsockname(struct thread *td, int fd, struct sockaddr **sa, return (EINVAL); AUDIT_ARG_FD(fd); - error = getsock(td->td_proc->p_fd, fd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, fd, CAP_GETSOCKNAME, &fp, NULL); if (error) return (error); so = fp->f_data; @@ -1571,7 +1590,7 @@ kern_getpeername(struct thread *td, int fd, struct sockaddr **sa, return (EINVAL); AUDIT_ARG_FD(fd); - error = getsock(td->td_proc->p_fd, fd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, fd, CAP_GETPEERNAME, &fp, NULL); if (error) return (error); so = fp->f_data; @@ -1827,7 +1846,7 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap, * we send only the header/trailer and no payload data. */ AUDIT_ARG_FD(uap->fd); - if ((error = fgetvp_read(td, uap->fd, &vp)) != 0) + if ((error = fgetvp_read(td, uap->fd, CAP_READ, &vp)) != 0) goto out; vfslocked = VFS_LOCK_GIANT(vp->v_mount); vn_lock(vp, LK_SHARED | LK_RETRY); @@ -1865,8 +1884,8 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap, * The socket must be a stream socket and connected. * Remember if it a blocking or non-blocking socket. */ - if ((error = getsock(td->td_proc->p_fd, uap->s, &sock_fp, - NULL)) != 0) + if ((error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_WRITE, + &sock_fp, NULL)) != 0) goto out; so = sock_fp->f_data; if (so->so_type != SOCK_STREAM) { @@ -2298,7 +2317,7 @@ sctp_peeloff(td, uap) fdp = td->td_proc->p_fd; AUDIT_ARG_FD(uap->sd); - error = fgetsock(td, uap->sd, &head, &fflag); + error = fgetsock(td, uap->sd, CAP_PEELOFF, &head, &fflag); if (error) goto done2; error = sctp_can_peel_off(head, (sctp_assoc_t)uap->name); @@ -2391,6 +2410,7 @@ sctp_generic_sendmsg (td, uap) #endif struct uio auio; struct iovec iov[1]; + cap_rights_t rights; if (uap->sinfo) { error = copyin(uap->sinfo, &sinfo, sizeof (sinfo)); @@ -2398,16 +2418,19 @@ sctp_generic_sendmsg (td, uap) return (error); u_sinfo = &sinfo; } + + rights = CAP_WRITE; if (uap->tolen) { error = getsockaddr(&to, uap->to, uap->tolen); if (error) { to = NULL; goto sctp_bad2; } + rights |= CAP_CONNECT; } AUDIT_ARG_FD(uap->sd); - error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->sd, rights, &fp, NULL); if (error) goto sctp_bad; #ifdef KTRACE @@ -2494,6 +2517,7 @@ sctp_generic_sendmsg_iov(td, uap) #endif struct uio auio; struct iovec *iov, *tiov; + cap_rights_t rights; if (uap->sinfo) { error = copyin(uap->sinfo, &sinfo, sizeof (sinfo)); @@ -2501,16 +2525,18 @@ sctp_generic_sendmsg_iov(td, uap) return (error); u_sinfo = &sinfo; } + rights = CAP_WRITE; if (uap->tolen) { error = getsockaddr(&to, uap->to, uap->tolen); if (error) { to = NULL; goto sctp_bad2; } + rights |= CAP_CONNECT; } AUDIT_ARG_FD(uap->sd); - error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->sd, rights, &fp, NULL); if (error) goto sctp_bad1; @@ -2618,7 +2644,7 @@ sctp_generic_recvmsg(td, uap) #endif AUDIT_ARG_FD(uap->sd); - error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL); + error = getsock_cap(td->td_proc->p_fd, uap->sd, CAP_READ, &fp, NULL); if (error) { return (error); } diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 4bad3869fe852..3a34f58605b5e 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -816,7 +816,7 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct unpcb *unp, *unp2; struct socket *so2; u_int mbcnt_delta, sbcc; - u_long newhiwat; + u_int newhiwat; int error = 0; unp = sotounpcb(so); @@ -974,7 +974,10 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, sorwakeup_locked(so2); SOCKBUF_LOCK(&so->so_snd); - newhiwat = so->so_snd.sb_hiwat - (sbcc - unp2->unp_cc); + if ((int)so->so_snd.sb_hiwat >= (int)(sbcc - unp2->unp_cc)) + newhiwat = so->so_snd.sb_hiwat - (sbcc - unp2->unp_cc); + else + newhiwat = 0; (void)chgsbsize(so->so_cred->cr_uidinfo, &so->so_snd.sb_hiwat, newhiwat, RLIM_INFINITY); so->so_snd.sb_mbmax -= mbcnt_delta; diff --git a/sys/kern/vfs_acl.c b/sys/kern/vfs_acl.c index b1cda38419e51..9010a5068bfb9 100644 --- a/sys/kern/vfs_acl.c +++ b/sys/kern/vfs_acl.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/sysproto.h> +#include <sys/capability.h> #include <sys/fcntl.h> #include <sys/kernel.h> #include <sys/malloc.h> @@ -408,7 +409,7 @@ __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap) struct file *fp; int vfslocked, error; - error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); + error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_GET, &fp); if (error == 0) { vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp); @@ -427,7 +428,7 @@ __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap) struct file *fp; int vfslocked, error; - error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); + error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_SET, &fp); if (error == 0) { vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp); @@ -486,7 +487,8 @@ __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap) struct file *fp; int vfslocked, error; - error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); + error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_DELETE, + &fp); if (error == 0) { vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); error = vacl_delete(td, fp->f_vnode, uap->type); @@ -545,7 +547,8 @@ __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap) struct file *fp; int vfslocked, error; - error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); + error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_CHECK, + &fp); if (error == 0) { vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp); diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c index 69b4e0a00c70e..aedbdd05385aa 100644 --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -28,6 +28,7 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/bio.h> #include <sys/buf.h> +#include <sys/capability.h> #include <sys/eventhandler.h> #include <sys/sysproto.h> #include <sys/filedesc.h> @@ -1577,17 +1578,30 @@ aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj, aiocbe->uaiocb.aio_lio_opcode = type; opcode = aiocbe->uaiocb.aio_lio_opcode; - /* Fetch the file object for the specified file descriptor. */ + /* + * Validate the opcode and fetch the file object for the specified + * file descriptor. + * + * XXXRW: Moved the opcode validation up here so that we don't + * retrieve a file descriptor without knowing what the capabiltity + * should be. + */ fd = aiocbe->uaiocb.aio_fildes; switch (opcode) { case LIO_WRITE: - error = fget_write(td, fd, &fp); + error = fget_write(td, fd, CAP_WRITE | CAP_SEEK, &fp); break; case LIO_READ: - error = fget_read(td, fd, &fp); + error = fget_read(td, fd, CAP_READ | CAP_SEEK, &fp); + break; + case LIO_SYNC: + error = fget(td, fd, CAP_FSYNC, &fp); + break; + case LIO_NOP: + error = fget(td, fd, 0, &fp); break; default: - error = fget(td, fd, &fp); + error = EINVAL; } if (error) { uma_zfree(aiocb_zone, aiocbe); @@ -1623,11 +1637,6 @@ aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj, uma_zfree(aiocb_zone, aiocbe); return (0); } - if ((opcode != LIO_READ) && (opcode != LIO_WRITE) && - (opcode != LIO_SYNC)) { - error = EINVAL; - goto aqueue_fail; - } if (aiocbe->uaiocb.aio_sigevent.sigev_notify != SIGEV_KEVENT) goto no_kqueue; @@ -1971,7 +1980,7 @@ aio_cancel(struct thread *td, struct aio_cancel_args *uap) struct vnode *vp; /* Lookup file object. */ - error = fget(td, uap->fd, &fp); + error = fget(td, uap->fd, 0, &fp); if (error) return (error); diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index a6ad81e9e03bc..7b5b0154c6b69 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -4020,7 +4020,7 @@ DB_SHOW_COMMAND(buffer, db_show_buffer) db_printf("\n"); } db_printf(" "); - lockmgr_printinfo(&bp->b_lock); + BUF_LOCKPRINTINFO(bp); } DB_SHOW_COMMAND(lockedbufs, lockedbufs) diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index e7bf2d19d7d39..b8b9cdf058bdf 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/lock.h> #include <sys/mount.h> #include <sys/mutex.h> @@ -230,7 +231,7 @@ extattr_set_fd(td, uap) return (error); AUDIT_ARG_TEXT(attrname); - error = getvnode(td->td_proc->p_fd, uap->fd, &fp); + error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_SET, &fp); if (error) return (error); @@ -410,7 +411,7 @@ extattr_get_fd(td, uap) return (error); AUDIT_ARG_TEXT(attrname); - error = getvnode(td->td_proc->p_fd, uap->fd, &fp); + error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_GET, &fp); if (error) return (error); @@ -560,7 +561,8 @@ extattr_delete_fd(td, uap) return (error); AUDIT_ARG_TEXT(attrname); - error = getvnode(td->td_proc->p_fd, uap->fd, &fp); + error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_DELETE, + &fp); if (error) return (error); @@ -719,7 +721,7 @@ extattr_list_fd(td, uap) AUDIT_ARG_FD(uap->fd); AUDIT_ARG_VALUE(uap->attrnamespace); - error = getvnode(td->td_proc->p_fd, uap->fd, &fp); + error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_LIST, &fp); if (error) return (error); diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c index 4367b8c8096ba..0165b38c3cd55 100644 --- a/sys/kern/vfs_init.c +++ b/sys/kern/vfs_init.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/fnv_hash.h> #include <sys/kernel.h> #include <sys/linker.h> #include <sys/mount.h> @@ -65,6 +66,18 @@ int maxvfsconf = VFS_GENERIC + 1; struct vfsconfhead vfsconf = TAILQ_HEAD_INITIALIZER(vfsconf); /* + * Loader.conf variable vfs.typenumhash enables setting vfc_typenum using a hash + * calculation on vfc_name, so that it doesn't change when file systems are + * loaded in a different order. This will avoid the NFS server file handles from + * changing for file systems that use vfc_typenum in their fsid. + */ +static int vfs_typenumhash = 1; +TUNABLE_INT("vfs.typenumhash", &vfs_typenumhash); +SYSCTL_INT(_vfs, OID_AUTO, typenumhash, CTLFLAG_RDTUN, &vfs_typenumhash, 0, + "Set vfc_typenum using a hash calculation on vfc_name, so that it does not" + "change when file systems are loaded in a different order."); + +/* * A Zen vnode attribute structure. * * Initialized when the first filesystem registers by vfs_register(). @@ -138,6 +151,9 @@ vfs_register(struct vfsconf *vfc) struct sysctl_oid *oidp; struct vfsops *vfsops; static int once; + struct vfsconf *tvfc; + uint32_t hashval; + int secondpass; if (!once) { vattr_null(&va_null); @@ -152,7 +168,34 @@ vfs_register(struct vfsconf *vfc) if (vfs_byname(vfc->vfc_name) != NULL) return EEXIST; - vfc->vfc_typenum = maxvfsconf++; + if (vfs_typenumhash != 0) { + /* + * Calculate a hash on vfc_name to use for vfc_typenum. Unless + * all of 1<->255 are assigned, it is limited to 8bits since + * that is what ZFS uses from vfc_typenum and is also the + * preferred range for vfs_getnewfsid(). + */ + hashval = fnv_32_str(vfc->vfc_name, FNV1_32_INIT); + hashval &= 0xff; + secondpass = 0; + do { + /* Look for and fix any collision. */ + TAILQ_FOREACH(tvfc, &vfsconf, vfc_list) { + if (hashval == tvfc->vfc_typenum) { + if (hashval == 255 && secondpass == 0) { + hashval = 1; + secondpass = 1; + } else + hashval++; + break; + } + } + } while (tvfc != NULL); + vfc->vfc_typenum = hashval; + if (vfc->vfc_typenum >= maxvfsconf) + maxvfsconf = vfc->vfc_typenum + 1; + } else + vfc->vfc_typenum = maxvfsconf++; TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list); /* diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 50a2570254f46..a14501704fa97 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -37,12 +37,14 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_capsicum.h" #include "opt_kdtrace.h" #include "opt_ktrace.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/capability.h> #include <sys/fcntl.h> #include <sys/jail.h> #include <sys/lock.h> @@ -178,6 +180,18 @@ namei(struct nameidata *ndp) if (!error && *cnp->cn_pnbuf == '\0') error = ENOENT; +#ifdef CAPABILITY_MODE + /* + * In capability mode, lookups must be "strictly relative" (i.e. + * not an absolute path, and not containing '..' components) to + * a real file descriptor, not the pseudo-descriptor AT_FDCWD. + */ + if (IN_CAPABILITY_MODE(td)) { + ndp->ni_strictrelative = 1; + if (ndp->ni_dirfd == AT_FDCWD) + error = ECAPMODE; + } +#endif if (error) { uma_zfree(namei_zone, cnp->cn_pnbuf); #ifdef DIAGNOSTIC @@ -212,7 +226,20 @@ namei(struct nameidata *ndp) AUDIT_ARG_ATFD1(ndp->ni_dirfd); if (cnp->cn_flags & AUDITVNODE2) AUDIT_ARG_ATFD2(ndp->ni_dirfd); - error = fgetvp(td, ndp->ni_dirfd, &dp); + error = fgetvp_rights(td, ndp->ni_dirfd, + ndp->ni_rightsneeded | CAP_LOOKUP, + &(ndp->ni_baserights), &dp); +#ifdef CAPABILITIES + /* + * Lookups relative to a capability must also be + * strictly relative. + * + * Note that a capability with rights CAP_MASK_VALID + * is treated exactly like a regular file descriptor. + */ + if (ndp->ni_baserights != CAP_MASK_VALID) + ndp->ni_strictrelative = 1; +#endif } if (error != 0 || dp != NULL) { FILEDESC_SUNLOCK(fdp); @@ -254,6 +281,8 @@ namei(struct nameidata *ndp) if (*(cnp->cn_nameptr) == '/') { vrele(dp); VFS_UNLOCK_GIANT(vfslocked); + if (ndp->ni_strictrelative != 0) + return (ENOTCAPABLE); while (*(cnp->cn_nameptr) == '/') { cnp->cn_nameptr++; ndp->ni_pathlen--; @@ -597,7 +626,10 @@ dirloop: } /* - * Handle "..": four special cases. + * Handle "..": five special cases. + * 0. If doing a capability lookup, return ENOTCAPABLE (this is a + * fairly conservative design choice, but it's the only one that we + * are satisfied guarantees the property we're looking for). * 1. Return an error if this is the last component of * the name and the operation is DELETE or RENAME. * 2. If at root directory (e.g. after chroot) @@ -611,6 +643,10 @@ dirloop: * the jail or chroot, don't let them out. */ if (cnp->cn_flags & ISDOTDOT) { + if (ndp->ni_strictrelative != 0) { + error = ENOTCAPABLE; + goto bad; + } if ((cnp->cn_flags & ISLASTCN) != 0 && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { error = EINVAL; diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 5edf0f52acbb7..5d6892c5e9b73 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -1496,7 +1496,8 @@ vfs_getopts(struct vfsoptlist *opts, const char *name, int *error) } int -vfs_flagopt(struct vfsoptlist *opts, const char *name, u_int *w, u_int val) +vfs_flagopt(struct vfsoptlist *opts, const char *name, uint64_t *w, + uint64_t val) { struct vfsopt *opt; diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 934745b433b64..325ca99deb32a 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -2841,6 +2841,7 @@ DB_SHOW_COMMAND(mount, db_show_mount) MNT_FLAG(MNT_ASYNC); MNT_FLAG(MNT_SUIDDIR); MNT_FLAG(MNT_SOFTDEP); + MNT_FLAG(MNT_SUJ); MNT_FLAG(MNT_NOSYMFOLLOW); MNT_FLAG(MNT_GJOURNAL); MNT_FLAG(MNT_MULTILABEL); @@ -2866,7 +2867,6 @@ DB_SHOW_COMMAND(mount, db_show_mount) MNT_FLAG(MNT_FORCE); MNT_FLAG(MNT_SNAPSHOT); MNT_FLAG(MNT_BYFSID); - MNT_FLAG(MNT_SOFTDEP); #undef MNT_FLAG if (flags != 0) { if (buf[0] != '\0') @@ -2894,7 +2894,6 @@ DB_SHOW_COMMAND(mount, db_show_mount) MNT_KERN_FLAG(MNTK_REFEXPIRE); MNT_KERN_FLAG(MNTK_EXTENDED_SHARED); MNT_KERN_FLAG(MNTK_SHARED_WRITES); - MNT_KERN_FLAG(MNTK_SUJ); MNT_KERN_FLAG(MNTK_UNMOUNT); MNT_KERN_FLAG(MNTK_MWAIT); MNT_KERN_FLAG(MNTK_SUSPEND); @@ -3313,6 +3312,7 @@ vbusy(struct vnode *vp) static void destroy_vpollinfo(struct vpollinfo *vi) { + seldrain(&vi->vpi_selinfo); knlist_destroy(&vi->vpi_selinfo.si_note); mtx_destroy(&vi->vpi_lock); uma_zfree(vnodepoll_zone, vi); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index b48c6e7969585..c0ae0a7476495 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -37,6 +37,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_capsicum.h" #include "opt_compat.h" #include "opt_kdtrace.h" #include "opt_ktrace.h" @@ -45,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/bio.h> #include <sys/buf.h> +#include <sys/capability.h> #include <sys/disk.h> #include <sys/sysent.h> #include <sys/malloc.h> @@ -94,8 +96,6 @@ SDT_PROBE_ARGTYPE(vfs, , stat, reg, 1, "int"); static int chroot_refuse_vdir_fds(struct filedesc *fdp); static int getutimes(const struct timeval *, enum uio_seg, struct timespec *); -static int setfown(struct thread *td, struct vnode *, uid_t, gid_t); -static int setfmode(struct thread *td, struct vnode *, int); static int setfflags(struct thread *td, struct vnode *, int); static int setutimes(struct thread *td, struct vnode *, const struct timespec *, int, int); @@ -373,7 +373,7 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf) int error; AUDIT_ARG_FD(fd); - error = getvnode(td->td_proc->p_fd, fd, &fp); + error = getvnode(td->td_proc->p_fd, fd, CAP_FSTATFS, &fp); if (error) return (error); vp = fp->f_vnode; @@ -746,7 +746,7 @@ fchdir(td, uap) int error; AUDIT_ARG_FD(uap->fd); - if ((error = getvnode(fdp, uap->fd, &fp)) != 0) + if ((error = getvnode(fdp, uap->fd, CAP_FCHDIR, &fp)) != 0) return (error); vp = fp->f_vnode; VREF(vp); @@ -991,6 +991,41 @@ change_root(vp, td) return (0); } +static __inline cap_rights_t +flags_to_rights(int flags) +{ + cap_rights_t rights = 0; + + switch ((flags & O_ACCMODE)) { + case O_RDONLY: + rights |= CAP_READ; + break; + + case O_RDWR: + rights |= CAP_READ; + /* fall through */ + + case O_WRONLY: + rights |= CAP_WRITE; + break; + + case O_EXEC: + rights |= CAP_FEXECVE; + break; + } + + if (flags & O_CREAT) + rights |= CAP_CREATE; + + if (flags & O_TRUNC) + rights |= CAP_FTRUNCATE; + + if ((flags & O_EXLOCK) || (flags & O_SHLOCK)) + rights |= CAP_FLOCK; + + return (rights); +} + /* * Check permissions, allocate an open file structure, and call the device * open routine if any. @@ -1049,14 +1084,16 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg, struct vnode *vp; int cmode; struct file *nfp; - int type, indx, error; + int type, indx = -1, error, error_open; struct flock lf; struct nameidata nd; int vfslocked; + cap_rights_t rights_needed = CAP_LOOKUP; AUDIT_ARG_FFLAGS(flags); AUDIT_ARG_MODE(mode); /* XXX: audit dirfd */ + rights_needed |= flags_to_rights(flags); /* * Only one of the O_EXEC, O_RDONLY, O_WRONLY and O_RDWR flags * may be specified. @@ -1069,16 +1106,19 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg, else flags = FFLAGS(flags); - error = falloc(td, &nfp, &indx, flags); + /* + * allocate the file descriptor, but don't install a descriptor yet + */ + error = falloc_noinstall(td, &nfp); if (error) return (error); - /* An extra reference on `nfp' has been held for us by falloc(). */ + /* An extra reference on `nfp' has been held for us by falloc_noinstall(). */ fp = nfp; /* Set the flags early so the finit in devfs can pick them up. */ fp->f_flag = flags & FMASK; cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; - NDINIT_AT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, fd, - td); + NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, + path, fd, rights_needed, td); td->td_dupfd = -1; /* XXX check for fdopen */ error = vn_open(&nd, &flags, cmode, fp); if (error) { @@ -1087,30 +1127,35 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg, * wonderous happened deep below and we just pass it up * pretending we know what we do. */ - if (error == ENXIO && fp->f_ops != &badfileops) { - fdrop(fp, td); - td->td_retval[0] = indx; - return (0); - } + if (error == ENXIO && fp->f_ops != &badfileops) + goto success; /* * handle special fdopen() case. bleh. dupfdopen() is * responsible for dropping the old contents of ofiles[indx] * if it succeeds. + * + * Don't do this for relative (capability) lookups; we don't + * understand exactly what would happen, and we don't think + * that it ever should. */ - if ((error == ENODEV || error == ENXIO) && - td->td_dupfd >= 0 && /* XXX from fdopen */ - (error = - dupfdopen(td, fdp, indx, td->td_dupfd, flags, error)) == 0) { - td->td_retval[0] = indx; - fdrop(fp, td); - return (0); + if ((nd.ni_strictrelative == 0) && + (error == ENODEV || error == ENXIO) && + (td->td_dupfd >= 0)) { + /* XXX from fdopen */ + error_open = error; + if ((error = finstall(td, fp, &indx, flags)) != 0) + goto bad_unlocked; + if ((error = dupfdopen(td, fdp, indx, td->td_dupfd, + flags, error_open)) == 0) + goto success; } /* * Clean up the descriptor, but only if another thread hadn't * replaced or closed it. */ - fdclose(fdp, fp, indx, td); + if (indx != -1) + fdclose(fdp, fp, indx, td); fdrop(fp, td); if (error == ERESTART) @@ -1161,6 +1206,27 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg, goto bad; } VFS_UNLOCK_GIANT(vfslocked); +success: + /* + * If we haven't already installed the FD (for dupfdopen), do so now. + */ + if (indx == -1) { +#ifdef CAPABILITIES + if (nd.ni_strictrelative == 1) { + /* + * We are doing a strict relative lookup; wrap the + * result in a capability. + */ + if ((error = kern_capwrap(td, fp, nd.ni_baserights, + &indx)) != 0) + goto bad_unlocked; + } else +#endif + if ((error = finstall(td, fp, &indx, flags)) != 0) + goto bad_unlocked; + + } + /* * Release our private reference, leaving the one associated with * the descriptor table intact. @@ -1170,8 +1236,11 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg, return (0); bad: VFS_UNLOCK_GIANT(vfslocked); - fdclose(fdp, fp, indx, td); +bad_unlocked: + if (indx != -1) + fdclose(fdp, fp, indx, td); fdrop(fp, td); + td->td_retval[0] = -1; return (error); } @@ -1283,8 +1352,9 @@ kern_mknodat(struct thread *td, int fd, char *path, enum uio_seg pathseg, return (error); restart: bwillwrite(); - NDINIT_AT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1, - pathseg, path, fd, td); + NDINIT_ATRIGHTS(&nd, CREATE, + LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1, pathseg, path, fd, + CAP_MKFIFO, td); if ((error = namei(&nd)) != 0) return (error); vfslocked = NDHASGIANT(&nd); @@ -1918,7 +1988,7 @@ lseek(td, uap) int vfslocked; AUDIT_ARG_FD(uap->fd); - if ((error = fget(td, uap->fd, &fp)) != 0) + if ((error = fget(td, uap->fd, CAP_SEEK, &fp)) != 0) return (error); if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) { fdrop(fp, td); @@ -2135,8 +2205,8 @@ kern_accessat(struct thread *td, int fd, char *path, enum uio_seg pathseg, } else cred = tmpcred = td->td_ucred; AUDIT_ARG_VALUE(mode); - NDINIT_AT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | MPSAFE | - AUDITVNODE1, pathseg, path, fd, td); + NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | MPSAFE | + AUDITVNODE1, pathseg, path, fd, CAP_FSTAT, td); if ((error = namei(&nd)) != 0) goto out1; vfslocked = NDHASGIANT(&nd); @@ -2345,9 +2415,9 @@ kern_statat_vnhook(struct thread *td, int flag, int fd, char *path, if (flag & ~AT_SYMLINK_NOFOLLOW) return (EINVAL); - NDINIT_AT(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : + NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW) | LOCKSHARED | LOCKLEAF | AUDITVNODE1 | MPSAFE, pathseg, - path, fd, td); + path, fd, CAP_FSTAT, td); if ((error = namei(&nd)) != 0) return (error); @@ -2775,7 +2845,8 @@ fchflags(td, uap) AUDIT_ARG_FD(uap->fd); AUDIT_ARG_FFLAGS(uap->flags); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_FCHFLAGS, + &fp)) != 0) return (error); vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); #ifdef AUDIT @@ -2792,9 +2863,10 @@ fchflags(td, uap) /* * Common implementation code for chmod(), lchmod() and fchmod(). */ -static int -setfmode(td, vp, mode) +int +setfmode(td, cred, vp, mode) struct thread *td; + struct ucred *cred; struct vnode *vp; int mode; { @@ -2808,10 +2880,10 @@ setfmode(td, vp, mode) VATTR_NULL(&vattr); vattr.va_mode = mode & ALLPERMS; #ifdef MAC - error = mac_vnode_check_setmode(td->td_ucred, vp, vattr.va_mode); + error = mac_vnode_check_setmode(cred, vp, vattr.va_mode); if (error == 0) #endif - error = VOP_SETATTR(vp, &vattr, td->td_ucred); + error = VOP_SETATTR(vp, &vattr, cred); VOP_UNLOCK(vp, 0); vn_finished_write(mp); return (error); @@ -2901,13 +2973,13 @@ kern_fchmodat(struct thread *td, int fd, char *path, enum uio_seg pathseg, AUDIT_ARG_MODE(mode); follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; - NDINIT_AT(&nd, LOOKUP, follow | MPSAFE | AUDITVNODE1, pathseg, path, - fd, td); + NDINIT_ATRIGHTS(&nd, LOOKUP, follow | MPSAFE | AUDITVNODE1, pathseg, + path, fd, CAP_FCHMOD, td); if ((error = namei(&nd)) != 0) return (error); vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); - error = setfmode(td, nd.ni_vp, mode); + error = setfmode(td, td->td_ucred, nd.ni_vp, mode); vrele(nd.ni_vp); VFS_UNLOCK_GIANT(vfslocked); return (error); @@ -2923,29 +2995,18 @@ struct fchmod_args { }; #endif int -fchmod(td, uap) - struct thread *td; - register struct fchmod_args /* { - int fd; - int mode; - } */ *uap; +fchmod(struct thread *td, struct fchmod_args *uap) { struct file *fp; - int vfslocked; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_MODE(uap->mode); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + + error = fget(td, uap->fd, CAP_FCHMOD, &fp); + if (error != 0) return (error); - vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); -#ifdef AUDIT - vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); - AUDIT_ARG_VNODE1(fp->f_vnode); - VOP_UNLOCK(fp->f_vnode, 0); -#endif - error = setfmode(td, fp->f_vnode, uap->mode); - VFS_UNLOCK_GIANT(vfslocked); + error = fo_chmod(fp, uap->mode, td->td_ucred, td); fdrop(fp, td); return (error); } @@ -2953,9 +3014,10 @@ fchmod(td, uap) /* * Common implementation for chown(), lchown(), and fchown() */ -static int -setfown(td, vp, uid, gid) +int +setfown(td, cred, vp, uid, gid) struct thread *td; + struct ucred *cred; struct vnode *vp; uid_t uid; gid_t gid; @@ -2971,11 +3033,11 @@ setfown(td, vp, uid, gid) vattr.va_uid = uid; vattr.va_gid = gid; #ifdef MAC - error = mac_vnode_check_setowner(td->td_ucred, vp, vattr.va_uid, + error = mac_vnode_check_setowner(cred, vp, vattr.va_uid, vattr.va_gid); if (error == 0) #endif - error = VOP_SETATTR(vp, &vattr, td->td_ucred); + error = VOP_SETATTR(vp, &vattr, cred); VOP_UNLOCK(vp, 0); vn_finished_write(mp); return (error); @@ -3043,14 +3105,14 @@ kern_fchownat(struct thread *td, int fd, char *path, enum uio_seg pathseg, AUDIT_ARG_OWNER(uid, gid); follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; - NDINIT_AT(&nd, LOOKUP, follow | MPSAFE | AUDITVNODE1, pathseg, path, - fd, td); + NDINIT_ATRIGHTS(&nd, LOOKUP, follow | MPSAFE | AUDITVNODE1, pathseg, + path, fd, CAP_FCHOWN, td); if ((error = namei(&nd)) != 0) return (error); vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); - error = setfown(td, nd.ni_vp, uid, gid); + error = setfown(td, td->td_ucred, nd.ni_vp, uid, gid); vrele(nd.ni_vp); VFS_UNLOCK_GIANT(vfslocked); return (error); @@ -3108,21 +3170,14 @@ fchown(td, uap) } */ *uap; { struct file *fp; - int vfslocked; int error; AUDIT_ARG_FD(uap->fd); AUDIT_ARG_OWNER(uap->uid, uap->gid); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + error = fget(td, uap->fd, CAP_FCHOWN, &fp); + if (error != 0) return (error); - vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); -#ifdef AUDIT - vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); - AUDIT_ARG_VNODE1(fp->f_vnode); - VOP_UNLOCK(fp->f_vnode, 0); -#endif - error = setfown(td, fp->f_vnode, uap->uid, uap->gid); - VFS_UNLOCK_GIANT(vfslocked); + error = fo_chown(fp, uap->uid, uap->gid, td->td_ucred, td); fdrop(fp, td); return (error); } @@ -3258,8 +3313,8 @@ kern_utimesat(struct thread *td, int fd, char *path, enum uio_seg pathseg, if ((error = getutimes(tptr, tptrseg, ts)) != 0) return (error); - NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, - fd, td); + NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, + path, fd, CAP_FUTIMES, td); if ((error = namei(&nd)) != 0) return (error); @@ -3348,7 +3403,8 @@ kern_futimes(struct thread *td, int fd, struct timeval *tptr, AUDIT_ARG_FD(fd); if ((error = getutimes(tptr, tptrseg, ts)) != 0) return (error); - if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, fd, CAP_FUTIMES, &fp)) + != 0) return (error); vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); #ifdef AUDIT @@ -3500,7 +3556,8 @@ fsync(td, uap) int error, lock_flags; AUDIT_ARG_FD(uap->fd); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_FSYNC, + &fp)) != 0) return (error); vp = fp->f_vnode; vfslocked = VFS_LOCK_GIANT(vp->v_mount); @@ -3587,11 +3644,11 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new, bwillwrite(); #ifdef MAC - NDINIT_AT(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART | MPSAFE | - AUDITVNODE1, pathseg, old, oldfd, td); + NDINIT_ATRIGHTS(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART | + MPSAFE | AUDITVNODE1, pathseg, old, oldfd, CAP_DELETE, td); #else - NDINIT_AT(&fromnd, DELETE, WANTPARENT | SAVESTART | MPSAFE | - AUDITVNODE1, pathseg, old, oldfd, td); + NDINIT_ATRIGHTS(&fromnd, DELETE, WANTPARENT | SAVESTART | MPSAFE | + AUDITVNODE1, pathseg, old, oldfd, CAP_DELETE, td); #endif if ((error = namei(&fromnd)) != 0) @@ -3614,8 +3671,9 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new, vrele(fvp); goto out1; } - NDINIT_AT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | - MPSAFE | AUDITVNODE2, pathseg, new, newfd, td); + NDINIT_ATRIGHTS(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | + SAVESTART | MPSAFE | AUDITVNODE2, pathseg, new, newfd, CAP_CREATE, + td); if (fromnd.ni_vp->v_type == VDIR) tond.ni_cnd.cn_flags |= WILLBEDIR; if ((error = namei(&tond)) != 0) { @@ -3741,8 +3799,8 @@ kern_mkdirat(struct thread *td, int fd, char *path, enum uio_seg segflg, AUDIT_ARG_MODE(mode); restart: bwillwrite(); - NDINIT_AT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1, - segflg, path, fd, td); + NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | + AUDITVNODE1, segflg, path, fd, CAP_MKDIR, td); nd.ni_cnd.cn_flags |= WILLBEDIR; if ((error = namei(&nd)) != 0) return (error); @@ -3830,8 +3888,8 @@ kern_rmdirat(struct thread *td, int fd, char *path, enum uio_seg pathseg) restart: bwillwrite(); - NDINIT_AT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1, - pathseg, path, fd, td); + NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | + AUDITVNODE1, pathseg, path, fd, CAP_RMDIR, td); if ((error = namei(&nd)) != 0) return (error); vfslocked = NDHASGIANT(&nd); @@ -3925,7 +3983,8 @@ kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap, /* XXX arbitrary sanity limit on `count'. */ if (uap->count > 64 * 1024) return (EINVAL); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, + &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); @@ -4085,7 +4144,8 @@ kern_getdirentries(struct thread *td, int fd, char *buf, u_int count, AUDIT_ARG_FD(fd); if (count > INT_MAX) return (EINVAL); - if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, fd, CAP_READ | CAP_SEEK, + &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); @@ -4248,30 +4308,49 @@ out: } /* - * Convert a user file descriptor to a kernel file entry. - * A reference on the file entry is held upon returning. + * Convert a user file descriptor to a kernel file entry and check that, if it + * is a capability, the correct rights are present. A reference on the file + * entry is held upon returning. */ int -getvnode(fdp, fd, fpp) - struct filedesc *fdp; - int fd; - struct file **fpp; +getvnode(struct filedesc *fdp, int fd, cap_rights_t rights, + struct file **fpp) { - int error; struct file *fp; +#ifdef CAPABILITIES + struct file *fp_fromcap; +#endif + int error; error = 0; fp = NULL; - if (fdp == NULL || (fp = fget_unlocked(fdp, fd)) == NULL) - error = EBADF; - else if (fp->f_vnode == NULL) { - error = EINVAL; + if ((fdp == NULL) || (fp = fget_unlocked(fdp, fd)) == NULL) + return (EBADF); +#ifdef CAPABILITIES + /* + * If the file descriptor is for a capability, test rights and use the + * file descriptor referenced by the capability. + */ + error = cap_funwrap(fp, rights, &fp_fromcap); + if (error) { + fdrop(fp, curthread); + return (error); + } + if (fp != fp_fromcap) { + fhold(fp_fromcap); fdrop(fp, curthread); + fp = fp_fromcap; + } +#endif /* CAPABILITIES */ + if (fp->f_vnode == NULL) { + fdrop(fp, curthread); + return (EINVAL); } *fpp = fp; - return (error); + return (0); } + /* * Get an (NFS) file handle. */ @@ -4683,7 +4762,7 @@ kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len) fp = NULL; vfslocked = 0; - error = fget(td, fd, &fp); + error = fget(td, fd, CAP_WRITE, &fp); if (error != 0) goto out; diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index e8bcc91cb9696..92fb0d9335f7e 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -61,8 +61,12 @@ __FBSDID("$FreeBSD$"); #include <sys/syslog.h> #include <sys/unistd.h> +#include <security/audit/audit.h> #include <security/mac/mac_framework.h> +#include <vm/vm.h> +#include <vm/vm_object.h> + static fo_rdwr_t vn_read; static fo_rdwr_t vn_write; static fo_truncate_t vn_truncate; @@ -81,6 +85,8 @@ struct fileops vnops = { .fo_kqfilter = vn_kqfilter, .fo_stat = vn_statfile, .fo_close = vn_closefile, + .fo_chmod = vn_chmod, + .fo_chown = vn_chown, .fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE }; @@ -1357,3 +1363,53 @@ vn_rlimit_fsize(const struct vnode *vp, const struct uio *uio, PROC_UNLOCK(td->td_proc); return (0); } + +int +vn_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, + struct thread *td) +{ + struct vnode *vp; + int error, vfslocked; + + vp = fp->f_vnode; + vfslocked = VFS_LOCK_GIANT(vp->v_mount); +#ifdef AUDIT + vn_lock(vp, LK_SHARED | LK_RETRY); + AUDIT_ARG_VNODE1(vp); + VOP_UNLOCK(vp, 0); +#endif + error = setfmode(td, active_cred, vp, mode); + VFS_UNLOCK_GIANT(vfslocked); + return (error); +} + +int +vn_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, + struct thread *td) +{ + struct vnode *vp; + int error, vfslocked; + + vp = fp->f_vnode; + vfslocked = VFS_LOCK_GIANT(vp->v_mount); +#ifdef AUDIT + vn_lock(vp, LK_SHARED | LK_RETRY); + AUDIT_ARG_VNODE1(vp); + VOP_UNLOCK(vp, 0); +#endif + error = setfown(td, active_cred, vp, uid, gid); + VFS_UNLOCK_GIANT(vfslocked); + return (error); +} + +void +vn_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end) +{ + vm_object_t object; + + if ((object = vp->v_object) == NULL) + return; + VM_OBJECT_LOCK(object); + vm_object_page_remove(object, start, end, 0); + VM_OBJECT_UNLOCK(object); +} diff --git a/sys/mips/cavium/asm_octeon.S b/sys/mips/cavium/asm_octeon.S index 94ac875a19962..1ef5083348979 100644 --- a/sys/mips/cavium/asm_octeon.S +++ b/sys/mips/cavium/asm_octeon.S @@ -50,12 +50,12 @@ LEAF(octeon_ap_wait) jal platform_processor_id nop -1: ll t0, octeon_ap_boot +1: lld t0, octeon_ap_boot bne v0, t0, 1b nop move t0, zero - sc t0, octeon_ap_boot + scd t0, octeon_ap_boot beqz t0, 1b nop diff --git a/sys/mips/cavium/octeon_mp.c b/sys/mips/cavium/octeon_mp.c index efddee86ae0fd..2bc268e95064b 100644 --- a/sys/mips/cavium/octeon_mp.c +++ b/sys/mips/cavium/octeon_mp.c @@ -46,7 +46,8 @@ __FBSDID("$FreeBSD$"); /* XXX */ extern cvmx_bootinfo_t *octeon_bootinfo; -unsigned octeon_ap_boot = ~0; +/* NOTE: this 64-bit mask (and many others) limits MAXCPU to 64 */ +uint64_t octeon_ap_boot = ~0ULL; void platform_ipi_send(int cpuid) @@ -105,15 +106,13 @@ platform_init_ap(int cpuid) void platform_cpu_mask(cpuset_t *mask) { + uint64_t core_mask = octeon_bootinfo->core_mask; + uint64_t i, m; CPU_ZERO(mask); - - /* - * XXX: hack in order to simplify CPU set building, assuming that - * core_mask is 32-bits. - */ - memcpy(mask, &octeon_bootinfo->core_mask, - sizeof(octeon_bootinfo->core_mask)); + for (i = 0, m = 1 ; i < MAXCPU; i++, m <<= 1) + if (core_mask & m) + CPU_SET(i, mask); } struct cpu_group * @@ -125,11 +124,26 @@ platform_smp_topo(void) int platform_start_ap(int cpuid) { - if (atomic_cmpset_32(&octeon_ap_boot, ~0, cpuid) == 0) + uint64_t cores_in_reset; + + /* + * Release the core if it is in reset, and let it rev up a bit. + * The real synchronization happens below via octeon_ap_boot. + */ + cores_in_reset = cvmx_read_csr(CVMX_CIU_PP_RST); + if (cores_in_reset & (1ULL << cpuid)) { + if (bootverbose) + printf ("AP #%d still in reset\n", cpuid); + cores_in_reset &= ~(1ULL << cpuid); + cvmx_write_csr(CVMX_CIU_PP_RST, (uint64_t)(cores_in_reset)); + DELAY(2000); /* Give it a moment to start */ + } + + if (atomic_cmpset_64(&octeon_ap_boot, ~0, cpuid) == 0) return (-1); for (;;) { DELAY(1000); - if (atomic_cmpset_32(&octeon_ap_boot, 0, ~0) != 0) + if (atomic_cmpset_64(&octeon_ap_boot, 0, ~0) != 0) return (0); printf("Waiting for cpu%d to start\n", cpuid); } diff --git a/sys/mips/conf/OCTEON1 b/sys/mips/conf/OCTEON1 index 2a0abcf42249d..60b2b01f77e50 100644 --- a/sys/mips/conf/OCTEON1 +++ b/sys/mips/conf/OCTEON1 @@ -295,4 +295,4 @@ device udav # Davicom DM9601E USB device rum # Ralink Technology RT2501USB wireless NICs device uath # Atheros AR5523 wireless NICs device ural # Ralink Technology RT2500USB wireless NICs -device zyd # ZyDAS zb1211/zb1211b wireless NICs +device zyd # ZyDAS zd1211/zd1211b wireless NICs diff --git a/sys/mips/conf/XLP b/sys/mips/conf/XLP index 6843534b72fe8..ff40239a30415 100644 --- a/sys/mips/conf/XLP +++ b/sys/mips/conf/XLP @@ -36,6 +36,7 @@ options SCHED_ULE # ULE scheduler options SMP options PREEMPTION # Enable kernel thread preemption #options FULL_PREEMPTION # Enable kernel thread preemption +#options MAXCPU=128 # XLP can probe 128 CPUs options INET # InterNETworking options INET6 # IPv6 communications protocols options FFS # Berkeley Fast Filesystem @@ -88,6 +89,7 @@ device bpf # UART device uart +device pci # Network device ether diff --git a/sys/mips/conf/XLP64 b/sys/mips/conf/XLP64 index 997a1f61c7fcd..1d4b575f3a45d 100644 --- a/sys/mips/conf/XLP64 +++ b/sys/mips/conf/XLP64 @@ -21,7 +21,7 @@ machine mips mips64eb ident XLP64 options ISA_MIPS64 -makeoptions ARCH_FLAGS="-march=mips64 -mabi=64" +makeoptions ARCH_FLAGS="-march=mips64r2 -mabi=64" makeoptions KERNLOADADDR=0xffffffff80100000 include "../nlm/std.xlp" @@ -38,6 +38,7 @@ options SCHED_ULE # ULE scheduler options SMP options PREEMPTION # Enable kernel thread preemption #options FULL_PREEMPTION # Enable kernel thread preemption +#options MAXCPU=128 # XLP can probe 128 CPUs options INET # InterNETworking options INET6 # IPv6 communications protocols options FFS # Berkeley Fast Filesystem @@ -90,6 +91,7 @@ device bpf # UART device uart +device pci # Network device ether diff --git a/sys/mips/conf/XLPN32 b/sys/mips/conf/XLPN32 index 97c73a80d6952..02119a85435ce 100644 --- a/sys/mips/conf/XLPN32 +++ b/sys/mips/conf/XLPN32 @@ -37,6 +37,7 @@ options SCHED_ULE # ULE scheduler options SMP options PREEMPTION # Enable kernel thread preemption #options FULL_PREEMPTION # Enable kernel thread preemption +#options MAXCPU=128 # XLP can probe 128 CPUs options INET # InterNETworking options INET6 # IPv6 communications protocols options FFS # Berkeley Fast Filesystem @@ -89,6 +90,7 @@ device bpf # UART device uart +device pci # Network device ether diff --git a/sys/mips/include/param.h b/sys/mips/include/param.h index 0b1ea9837afa8..5f25c81c98f95 100644 --- a/sys/mips/include/param.h +++ b/sys/mips/include/param.h @@ -87,7 +87,9 @@ #ifdef SMP #define MAXSMPCPU 32 +#ifndef MAXCPU #define MAXCPU MAXSMPCPU +#endif #else #define MAXSMPCPU 1 #define MAXCPU 1 diff --git a/sys/mips/mips/dump_machdep.c b/sys/mips/mips/dump_machdep.c index 1dd69f759c253..bf8c4a3152f3d 100644 --- a/sys/mips/mips/dump_machdep.c +++ b/sys/mips/mips/dump_machdep.c @@ -188,7 +188,7 @@ cb_dumpdata(struct md_pa *mdp, int seqnr, void *arg) } #ifdef SW_WATCHDOG - wdog_kern_path(WD_LASTVAL); + wdog_kern_pat(WD_LASTVAL); #endif error = dump_write(di, (void *)(intptr_t)(pa),0, dumplo, sz); /* XXX fix PA */ if (error) diff --git a/sys/mips/mips/exception.S b/sys/mips/mips/exception.S index ed7554bc7c03f..729391e1efcf0 100644 --- a/sys/mips/mips/exception.S +++ b/sys/mips/mips/exception.S @@ -1140,13 +1140,21 @@ END(MipsFPTrap) intrnames: .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 sintrnames: - .word INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 +#ifdef __mips_n64 + .quad INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 +#else + .int INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 +#endif .align 4 intrcnt: .space INTRCNT_COUNT * 4 * 2 sintrcnt: - .word INTRCNT_COUNT * 4 * 2 +#ifdef __mips_n64 + .quad INTRCNT_COUNT * 4 * 2 +#else + .int INTRCNT_COUNT * 4 * 2 +#endif /* diff --git a/sys/mips/mips/pmap.c b/sys/mips/mips/pmap.c index 4d4609907169d..7da76be6236d4 100644 --- a/sys/mips/mips/pmap.c +++ b/sys/mips/mips/pmap.c @@ -1432,7 +1432,7 @@ retry: KASSERT(!pte_test(&oldpte, PTE_W), ("wired pte for unwired page")); if (m->md.pv_flags & PV_TABLE_REF) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); if (pte_test(&oldpte, PTE_D)) vm_page_dirty(m); pmap_invalidate_page(pmap, va); @@ -1448,7 +1448,7 @@ retry: free_pv_entry(pv); } if (TAILQ_EMPTY(&m->md.pv_list)) { - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); m->md.pv_flags &= ~(PV_TABLE_REF | PV_TABLE_MOD); } } @@ -1527,7 +1527,7 @@ pmap_remove_entry(pmap_t pmap, vm_page_t m, vm_offset_t va) mtx_assert(&vm_page_queue_mtx, MA_OWNED); pmap_pvh_free(&m->md, pmap, va); if (TAILQ_EMPTY(&m->md.pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } /* @@ -1589,7 +1589,7 @@ pmap_remove_pte(struct pmap *pmap, pt_entry_t *ptq, vm_offset_t va) vm_page_dirty(m); } if (m->md.pv_flags & PV_TABLE_REF) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); m->md.pv_flags &= ~(PV_TABLE_REF | PV_TABLE_MOD); pmap_remove_entry(pmap, m, va); @@ -1708,12 +1708,12 @@ pmap_remove_all(vm_page_t m) pv_entry_t pv; pt_entry_t *pte, tpte; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_all: page %p is not managed", m)); vm_page_lock_queues(); if (m->md.pv_flags & PV_TABLE_REF) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); while ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) { PMAP_LOCK(pv->pv_pmap); @@ -1757,7 +1757,7 @@ pmap_remove_all(vm_page_t m) free_pv_entry(pv); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); m->md.pv_flags &= ~(PV_TABLE_REF | PV_TABLE_MOD); vm_page_unlock_queues(); } @@ -1863,8 +1863,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, va &= ~PAGE_MASK; KASSERT(va <= VM_MAX_KERNEL_ADDRESS, ("pmap_enter: toobig")); - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0 || - (m->oflags & VPO_BUSY) != 0, + KASSERT((m->oflags & (VPO_UNMANAGED | VPO_BUSY)) != 0, ("pmap_enter: page %p is not busy", m)); mpte = NULL; @@ -1952,7 +1951,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, * raise IPL while manipulating pv_table since pmap_enter can be * called at interrupt time. */ - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) { + if ((m->oflags & VPO_UNMANAGED) == 0) { KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva, ("pmap_enter: managed mapping within the clean submap")); if (pv == NULL) @@ -2005,7 +2004,7 @@ validate: *pte = newpte; if (page_is_managed(opa) && (opa != pa)) { if (om->md.pv_flags & PV_TABLE_REF) - vm_page_flag_set(om, PG_REFERENCED); + vm_page_aflag_set(om, PGA_REFERENCED); om->md.pv_flags &= ~(PV_TABLE_REF | PV_TABLE_MOD); } @@ -2018,7 +2017,7 @@ validate: } if (page_is_managed(opa) && TAILQ_EMPTY(&om->md.pv_list)) - vm_page_flag_clear(om, PG_WRITEABLE); + vm_page_aflag_clear(om, PGA_WRITEABLE); } else { *pte = newpte; } @@ -2067,7 +2066,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_paddr_t pa; KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva || - (m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0, + (m->oflags & VPO_UNMANAGED) != 0, ("pmap_enter_quick_locked: managed mapping within the clean submap")); mtx_assert(&vm_page_queue_mtx, MA_OWNED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); @@ -2129,7 +2128,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, /* * Enter on the PV list if part of our managed memory. */ - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0 && + if ((m->oflags & VPO_UNMANAGED) == 0 && !pmap_try_insert_pv_entry(pmap, mpte, va, m)) { if (mpte != NULL) { pmap_unwire_pte_hold(pmap, va, mpte); @@ -2464,7 +2463,7 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m) int loops = 0; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_page_exists_quick: page %p is not managed", m)); rv = FALSE; vm_page_lock_queues(); @@ -2536,7 +2535,7 @@ pmap_remove_pages(pmap_t pmap) m->md.pv_list_count--; TAILQ_REMOVE(&m->md.pv_list, pv, pv_list); if (TAILQ_FIRST(&m->md.pv_list) == NULL) { - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } pmap_unuse_pt(pv->pv_pmap, pv->pv_va, pv->pv_ptem); free_pv_entry(pv); @@ -2558,7 +2557,7 @@ pmap_testbit(vm_page_t m, int bit) pt_entry_t *pte; boolean_t rv = FALSE; - if (m->flags & PG_FICTITIOUS) + if (m->oflags & VPO_UNMANAGED) return (rv); if (TAILQ_FIRST(&m->md.pv_list) == NULL) @@ -2585,7 +2584,7 @@ pmap_changebit(vm_page_t m, int bit, boolean_t setem) pv_entry_t pv; pt_entry_t *pte; - if (m->flags & PG_FICTITIOUS) + if (m->oflags & VPO_UNMANAGED) return; mtx_assert(&vm_page_queue_mtx, MA_OWNED); @@ -2616,7 +2615,7 @@ pmap_changebit(vm_page_t m, int bit, boolean_t setem) PMAP_UNLOCK(pv->pv_pmap); } if (!setem && bit == PTE_D) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); } /* @@ -2634,7 +2633,7 @@ pmap_page_wired_mappings(vm_page_t m) int count; count = 0; - if ((m->flags & PG_FICTITIOUS) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (count); vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { @@ -2659,17 +2658,17 @@ pmap_remove_write(vm_page_t m) vm_offset_t va; pt_entry_t *pte; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_write: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be set by - * another thread while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be set by + * another thread while the object is locked. Thus, if PGA_WRITEABLE * is clear, no page table entries need updating. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return; /* @@ -2686,7 +2685,7 @@ pmap_remove_write(vm_page_t m) pmap_protect(pv->pv_pmap, va, va + PAGE_SIZE, VM_PROT_READ | VM_PROT_EXECUTE); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } @@ -2699,7 +2698,7 @@ int pmap_ts_referenced(vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_ts_referenced: page %p is not managed", m)); if (m->md.pv_flags & PV_TABLE_REF) { vm_page_lock_queues(); @@ -2721,17 +2720,17 @@ pmap_is_modified(vm_page_t m) { boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_modified: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be - * concurrently set while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be + * concurrently set while the object is locked. Thus, if PGA_WRITEABLE * is clear, no PTEs can have PTE_D set. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return (FALSE); vm_page_lock_queues(); if (m->md.pv_flags & PV_TABLE_MOD) @@ -2775,18 +2774,18 @@ void pmap_clear_modify(vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_modify: page %p is not managed", m)); VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); KASSERT((m->oflags & VPO_BUSY) == 0, ("pmap_clear_modify: page %p is busy", m)); /* - * If the page is not PG_WRITEABLE, then no PTEs can have PTE_D set. + * If the page is not PGA_WRITEABLE, then no PTEs can have PTE_D set. * If the object containing the page is locked and the page is not - * VPO_BUSY, then PG_WRITEABLE cannot be concurrently set. + * VPO_BUSY, then PGA_WRITEABLE cannot be concurrently set. */ - if ((m->flags & PG_WRITEABLE) == 0) + if ((m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); if (m->md.pv_flags & PV_TABLE_MOD) { @@ -2806,7 +2805,7 @@ boolean_t pmap_is_referenced(vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_referenced: page %p is not managed", m)); return ((m->md.pv_flags & PV_TABLE_REF) != 0); } @@ -2820,7 +2819,7 @@ void pmap_clear_reference(vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_reference: page %p is not managed", m)); vm_page_lock_queues(); if (m->md.pv_flags & PV_TABLE_REF) { @@ -2930,7 +2929,7 @@ retry: * determine if the address is MINCORE_REFERENCED. */ m = PHYS_TO_VM_PAGE(pa); - if ((m->flags & PG_REFERENCED) != 0) + if ((m->aflags & PGA_REFERENCED) != 0) val |= MINCORE_REFERENCED | MINCORE_REFERENCED_OTHER; } if ((val & (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER)) != @@ -3168,7 +3167,7 @@ page_is_managed(vm_paddr_t pa) m = PHYS_TO_VM_PAGE(pa); if (m == NULL) return (0); - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) + if ((m->oflags & VPO_UNMANAGED) == 0) return (1); } return (0); @@ -3181,12 +3180,12 @@ init_pte_prot(vm_offset_t va, vm_page_t m, vm_prot_t prot) if (!(prot & VM_PROT_WRITE)) rw = PTE_V | PTE_RO | PTE_C_CACHE; - else if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) { + else if ((m->oflags & VPO_UNMANAGED) == 0) { if ((m->md.pv_flags & PV_TABLE_MOD) != 0) rw = PTE_V | PTE_D | PTE_C_CACHE; else rw = PTE_V | PTE_C_CACHE; - vm_page_flag_set(m, PG_WRITEABLE); + vm_page_aflag_set(m, PGA_WRITEABLE); } else /* Needn't emulate a modified bit for unmanaged pages. */ rw = PTE_V | PTE_D | PTE_C_CACHE; diff --git a/sys/mips/nlm/board.c b/sys/mips/nlm/board.c index d75059e21caec..5fd771d8d2cb4 100644 --- a/sys/mips/nlm/board.c +++ b/sys/mips/nlm/board.c @@ -29,7 +29,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/systm.h> #include <sys/bus.h> @@ -38,7 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mutex.h> #include <mips/nlm/hal/mips-extns.h> -#include <mips/nlm/hal/mmio.h> +#include <mips/nlm/hal/haldefs.h> #include <mips/nlm/hal/iomap.h> #include <mips/nlm/hal/fmn.h> #include <mips/nlm/hal/pic.h> diff --git a/sys/mips/nlm/board.h b/sys/mips/nlm/board.h index 742ebbab2a4ba..5a0c868c5105a 100644 --- a/sys/mips/nlm/board.h +++ b/sys/mips/nlm/board.h @@ -25,8 +25,9 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ #ifndef __NLM_BOARD_H__ #define __NLM_BOARD_H__ diff --git a/sys/mips/nlm/bus_space_rmi.c b/sys/mips/nlm/bus_space_rmi.c index 8653cdfaaf421..6bb3fff7f8fb6 100644 --- a/sys/mips/nlm/bus_space_rmi.c +++ b/sys/mips/nlm/bus_space_rmi.c @@ -401,14 +401,14 @@ static u_int8_t rmi_bus_space_read_1(void *tag, bus_space_handle_t handle, bus_size_t offset) { - return (u_int8_t) (*(volatile u_int32_t *)(handle + offset)); + return (u_int8_t) (*(volatile u_int8_t *)(handle + offset)); } static u_int16_t rmi_bus_space_read_2(void *tag, bus_space_handle_t handle, bus_size_t offset) { - return (u_int16_t)(*(volatile u_int32_t *)(handle + offset)); + return (u_int16_t)(*(volatile u_int16_t *)(handle + offset)); } static u_int32_t @@ -453,14 +453,14 @@ static void rmi_bus_space_write_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t value) { - *(volatile u_int32_t *)(handle + offset) = (u_int32_t)value; + *(volatile u_int8_t *)(handle + offset) = value; } static void rmi_bus_space_write_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t value) { - *(volatile u_int32_t *)(handle + offset) = (u_int32_t)value; + *(volatile u_int16_t *)(handle + offset) = value; } static void diff --git a/sys/mips/nlm/bus_space_rmi_pci.c b/sys/mips/nlm/bus_space_rmi_pci.c new file mode 100644 index 0000000000000..8e757ef02070a --- /dev/null +++ b/sys/mips/nlm/bus_space_rmi_pci.c @@ -0,0 +1,768 @@ +/*- + * Copyright 2003-2011 Netlogic Microsystems (Netlogic). 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 Netlogic Microsystems ``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 NETLOGIC 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. + * + * NETLOGIC_BSD */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/endian.h> +#include <sys/malloc.h> +#include <sys/ktr.h> + +#include <vm/vm.h> +#include <vm/pmap.h> +#include <vm/vm_kern.h> +#include <vm/vm_extern.h> + +#include <machine/bus.h> +#include <machine/cache.h> + +static int +rmi_pci_bus_space_map(void *t, bus_addr_t addr, + bus_size_t size, int flags, + bus_space_handle_t * bshp); + +static void +rmi_pci_bus_space_unmap(void *t, bus_space_handle_t bsh, + bus_size_t size); + +static int +rmi_pci_bus_space_subregion(void *t, + bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size, + bus_space_handle_t * nbshp); + +static u_int8_t +rmi_pci_bus_space_read_1(void *t, + bus_space_handle_t handle, + bus_size_t offset); + +static u_int16_t +rmi_pci_bus_space_read_2(void *t, + bus_space_handle_t handle, + bus_size_t offset); + +static u_int32_t +rmi_pci_bus_space_read_4(void *t, + bus_space_handle_t handle, + bus_size_t offset); + +static void +rmi_pci_bus_space_read_multi_1(void *t, + bus_space_handle_t handle, + bus_size_t offset, u_int8_t * addr, + size_t count); + +static void +rmi_pci_bus_space_read_multi_2(void *t, + bus_space_handle_t handle, + bus_size_t offset, u_int16_t * addr, + size_t count); + +static void +rmi_pci_bus_space_read_multi_4(void *t, + bus_space_handle_t handle, + bus_size_t offset, u_int32_t * addr, + size_t count); + +static void +rmi_pci_bus_space_read_region_1(void *t, + bus_space_handle_t bsh, + bus_size_t offset, u_int8_t * addr, + size_t count); + +static void +rmi_pci_bus_space_read_region_2(void *t, + bus_space_handle_t bsh, + bus_size_t offset, u_int16_t * addr, + size_t count); + +static void +rmi_pci_bus_space_read_region_4(void *t, + bus_space_handle_t bsh, + bus_size_t offset, u_int32_t * addr, + size_t count); + +static void +rmi_pci_bus_space_write_1(void *t, + bus_space_handle_t handle, + bus_size_t offset, u_int8_t value); + +static void +rmi_pci_bus_space_write_2(void *t, + bus_space_handle_t handle, + bus_size_t offset, u_int16_t value); + +static void +rmi_pci_bus_space_write_4(void *t, + bus_space_handle_t handle, + bus_size_t offset, u_int32_t value); + +static void +rmi_pci_bus_space_write_multi_1(void *t, + bus_space_handle_t handle, + bus_size_t offset, + const u_int8_t * addr, + size_t count); + +static void +rmi_pci_bus_space_write_multi_2(void *t, + bus_space_handle_t handle, + bus_size_t offset, + const u_int16_t * addr, + size_t count); + +static void +rmi_pci_bus_space_write_multi_4(void *t, + bus_space_handle_t handle, + bus_size_t offset, + const u_int32_t * addr, + size_t count); + +static void +rmi_pci_bus_space_write_region_2(void *t, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int16_t * addr, + size_t count); + +static void +rmi_pci_bus_space_write_region_4(void *t, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int32_t * addr, + size_t count); + + +static void +rmi_pci_bus_space_set_region_2(void *t, + bus_space_handle_t bsh, + bus_size_t offset, u_int16_t value, + size_t count); +static void +rmi_pci_bus_space_set_region_4(void *t, + bus_space_handle_t bsh, + bus_size_t offset, u_int32_t value, + size_t count); + +static void +rmi_pci_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused, + bus_size_t offset __unused, bus_size_t len __unused, int flags); + +static void +rmi_pci_bus_space_copy_region_2(void *t, + bus_space_handle_t bsh1, + bus_size_t off1, + bus_space_handle_t bsh2, + bus_size_t off2, size_t count); + +u_int8_t +rmi_pci_bus_space_read_stream_1(void *t, bus_space_handle_t handle, + bus_size_t offset); + +static u_int16_t +rmi_pci_bus_space_read_stream_2(void *t, bus_space_handle_t handle, + bus_size_t offset); + +static u_int32_t +rmi_pci_bus_space_read_stream_4(void *t, bus_space_handle_t handle, + bus_size_t offset); +static void +rmi_pci_bus_space_read_multi_stream_1(void *t, + bus_space_handle_t handle, + bus_size_t offset, u_int8_t * addr, + size_t count); + +static void +rmi_pci_bus_space_read_multi_stream_2(void *t, + bus_space_handle_t handle, + bus_size_t offset, u_int16_t * addr, + size_t count); + +static void +rmi_pci_bus_space_read_multi_stream_4(void *t, + bus_space_handle_t handle, + bus_size_t offset, u_int32_t * addr, + size_t count); + +void +rmi_pci_bus_space_write_stream_1(void *t, bus_space_handle_t bsh, + bus_size_t offset, u_int8_t value); +static void +rmi_pci_bus_space_write_stream_2(void *t, bus_space_handle_t handle, + bus_size_t offset, u_int16_t value); + +static void +rmi_pci_bus_space_write_stream_4(void *t, bus_space_handle_t handle, + bus_size_t offset, u_int32_t value); + +static void +rmi_pci_bus_space_write_multi_stream_1(void *t, + bus_space_handle_t handle, + bus_size_t offset, + const u_int8_t * addr, + size_t count); +static void +rmi_pci_bus_space_write_multi_stream_2(void *t, + bus_space_handle_t handle, + bus_size_t offset, + const u_int16_t * addr, + size_t count); + +static void +rmi_pci_bus_space_write_multi_stream_4(void *t, + bus_space_handle_t handle, + bus_size_t offset, + const u_int32_t * addr, + size_t count); + +#define TODO() printf("XLR memory bus space function '%s' unimplemented\n", __func__) + +static struct bus_space local_rmi_pci_bus_space = { + /* cookie */ + (void *)0, + + /* mapping/unmapping */ + rmi_pci_bus_space_map, + rmi_pci_bus_space_unmap, + rmi_pci_bus_space_subregion, + + /* allocation/deallocation */ + NULL, + NULL, + + /* barrier */ + rmi_pci_bus_space_barrier, + + /* read (single) */ + rmi_pci_bus_space_read_1, + rmi_pci_bus_space_read_2, + rmi_pci_bus_space_read_4, + NULL, + + /* read multiple */ + rmi_pci_bus_space_read_multi_1, + rmi_pci_bus_space_read_multi_2, + rmi_pci_bus_space_read_multi_4, + NULL, + + /* read region */ + rmi_pci_bus_space_read_region_1, + rmi_pci_bus_space_read_region_2, + rmi_pci_bus_space_read_region_4, + NULL, + + /* write (single) */ + rmi_pci_bus_space_write_1, + rmi_pci_bus_space_write_2, + rmi_pci_bus_space_write_4, + NULL, + + /* write multiple */ + rmi_pci_bus_space_write_multi_1, + rmi_pci_bus_space_write_multi_2, + rmi_pci_bus_space_write_multi_4, + NULL, + + /* write region */ + NULL, + rmi_pci_bus_space_write_region_2, + rmi_pci_bus_space_write_region_4, + NULL, + + /* set multiple */ + NULL, + NULL, + NULL, + NULL, + + /* set region */ + NULL, + rmi_pci_bus_space_set_region_2, + rmi_pci_bus_space_set_region_4, + NULL, + + /* copy */ + NULL, + rmi_pci_bus_space_copy_region_2, + NULL, + NULL, + + /* read (single) stream */ + rmi_pci_bus_space_read_stream_1, + rmi_pci_bus_space_read_stream_2, + rmi_pci_bus_space_read_stream_4, + NULL, + + /* read multiple stream */ + rmi_pci_bus_space_read_multi_stream_1, + rmi_pci_bus_space_read_multi_stream_2, + rmi_pci_bus_space_read_multi_stream_4, + NULL, + + /* read region stream */ + rmi_pci_bus_space_read_region_1, + rmi_pci_bus_space_read_region_2, + rmi_pci_bus_space_read_region_4, + NULL, + + /* write (single) stream */ + rmi_pci_bus_space_write_stream_1, + rmi_pci_bus_space_write_stream_2, + rmi_pci_bus_space_write_stream_4, + NULL, + + /* write multiple stream */ + rmi_pci_bus_space_write_multi_stream_1, + rmi_pci_bus_space_write_multi_stream_2, + rmi_pci_bus_space_write_multi_stream_4, + NULL, + + /* write region stream */ + NULL, + rmi_pci_bus_space_write_region_2, + rmi_pci_bus_space_write_region_4, + NULL, +}; + +/* generic bus_space tag */ +bus_space_tag_t rmi_pci_bus_space = &local_rmi_pci_bus_space; + +/* + * Map a region of device bus space into CPU virtual address space. + */ +static int +rmi_pci_bus_space_map(void *t __unused, bus_addr_t addr, + bus_size_t size __unused, int flags __unused, + bus_space_handle_t * bshp) +{ + *bshp = addr; + return (0); +} + +/* + * Unmap a region of device bus space. + */ +static void +rmi_pci_bus_space_unmap(void *t __unused, bus_space_handle_t bsh __unused, + bus_size_t size __unused) +{ +} + +/* + * Get a new handle for a subregion of an already-mapped area of bus space. + */ + +static int +rmi_pci_bus_space_subregion(void *t __unused, bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size __unused, + bus_space_handle_t * nbshp) +{ + *nbshp = bsh + offset; + return (0); +} + +/* + * Read a 1, 2, 4, or 8 byte quantity from bus space + * described by tag/handle/offset. + */ + +static u_int8_t +rmi_pci_bus_space_read_1(void *tag, bus_space_handle_t handle, + bus_size_t offset) +{ + return (u_int8_t) (*(volatile u_int8_t *)(handle + offset)); +} + +static u_int16_t +rmi_pci_bus_space_read_2(void *tag, bus_space_handle_t handle, + bus_size_t offset) +{ + u_int16_t value; + + value = *(volatile u_int16_t *)(handle + offset); + return bswap16(value); +} + +static u_int32_t +rmi_pci_bus_space_read_4(void *tag, bus_space_handle_t handle, + bus_size_t offset) +{ + uint32_t value; + + value = *(volatile u_int32_t *)(handle + offset); + return bswap32(value); +} + +/* + * Read `count' 1, 2, 4, or 8 byte quantities from bus space + * described by tag/handle/offset and copy into buffer provided. + */ +static void +rmi_pci_bus_space_read_multi_1(void *tag, bus_space_handle_t handle, + bus_size_t offset, u_int8_t * addr, size_t count) +{ + while (count--) { + *addr = *(volatile u_int8_t *)(handle + offset); + addr++; + } +} + +static void +rmi_pci_bus_space_read_multi_2(void *tag, bus_space_handle_t handle, + bus_size_t offset, u_int16_t * addr, size_t count) +{ + + while (count--) { + *addr = *(volatile u_int16_t *)(handle + offset); + *addr = bswap16(*addr); + addr++; + } +} + +static void +rmi_pci_bus_space_read_multi_4(void *tag, bus_space_handle_t handle, + bus_size_t offset, u_int32_t * addr, size_t count) +{ + + while (count--) { + *addr = *(volatile u_int32_t *)(handle + offset); + *addr = bswap32(*addr); + addr++; + } +} + +/* + * Write the 1, 2, 4, or 8 byte value `value' to bus space + * described by tag/handle/offset. + */ + +static void +rmi_pci_bus_space_write_1(void *tag, bus_space_handle_t handle, + bus_size_t offset, u_int8_t value) +{ + mips_sync(); + *(volatile u_int8_t *)(handle + offset) = value; +} + +static void +rmi_pci_bus_space_write_2(void *tag, bus_space_handle_t handle, + bus_size_t offset, u_int16_t value) +{ + mips_sync(); + *(volatile u_int16_t *)(handle + offset) = bswap16(value); +} + + +static void +rmi_pci_bus_space_write_4(void *tag, bus_space_handle_t handle, + bus_size_t offset, u_int32_t value) +{ + mips_sync(); + *(volatile u_int32_t *)(handle + offset) = bswap32(value); +} + +/* + * Write `count' 1, 2, 4, or 8 byte quantities from the buffer + * provided to bus space described by tag/handle/offset. + */ + + +static void +rmi_pci_bus_space_write_multi_1(void *tag, bus_space_handle_t handle, + bus_size_t offset, const u_int8_t * addr, size_t count) +{ + mips_sync(); + while (count--) { + (*(volatile u_int8_t *)(handle + offset)) = *addr; + addr++; + } +} + +static void +rmi_pci_bus_space_write_multi_2(void *tag, bus_space_handle_t handle, + bus_size_t offset, const u_int16_t * addr, size_t count) +{ + mips_sync(); + while (count--) { + (*(volatile u_int16_t *)(handle + offset)) = bswap16(*addr); + addr++; + } +} + +static void +rmi_pci_bus_space_write_multi_4(void *tag, bus_space_handle_t handle, + bus_size_t offset, const u_int32_t * addr, size_t count) +{ + mips_sync(); + while (count--) { + (*(volatile u_int32_t *)(handle + offset)) = bswap32(*addr); + addr++; + } +} + +/* + * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described + * by tag/handle starting at `offset'. + */ + +static void +rmi_pci_bus_space_set_region_2(void *t, bus_space_handle_t bsh, + bus_size_t offset, u_int16_t value, size_t count) +{ + bus_addr_t addr = bsh + offset; + + for (; count != 0; count--, addr += 2) + (*(volatile u_int16_t *)(addr)) = value; +} + +static void +rmi_pci_bus_space_set_region_4(void *t, bus_space_handle_t bsh, + bus_size_t offset, u_int32_t value, size_t count) +{ + bus_addr_t addr = bsh + offset; + + for (; count != 0; count--, addr += 4) + (*(volatile u_int32_t *)(addr)) = value; +} + + +/* + * Copy `count' 1, 2, 4, or 8 byte values from bus space starting + * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. + */ +static void +rmi_pci_bus_space_copy_region_2(void *t, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, + bus_size_t off2, size_t count) +{ + TODO(); +} + +/* + * Read `count' 1, 2, 4, or 8 byte quantities from bus space + * described by tag/handle/offset and copy into buffer provided. + */ + +u_int8_t +rmi_pci_bus_space_read_stream_1(void *t, bus_space_handle_t handle, + bus_size_t offset) +{ + + return *((volatile u_int8_t *)(handle + offset)); +} + + +static u_int16_t +rmi_pci_bus_space_read_stream_2(void *t, bus_space_handle_t handle, + bus_size_t offset) +{ + return *(volatile u_int16_t *)(handle + offset); +} + + +static u_int32_t +rmi_pci_bus_space_read_stream_4(void *t, bus_space_handle_t handle, + bus_size_t offset) +{ + return (*(volatile u_int32_t *)(handle + offset)); +} + + +static void +rmi_pci_bus_space_read_multi_stream_1(void *tag, bus_space_handle_t handle, + bus_size_t offset, u_int8_t * addr, size_t count) +{ + while (count--) { + *addr = (*(volatile u_int8_t *)(handle + offset)); + addr++; + } +} + +static void +rmi_pci_bus_space_read_multi_stream_2(void *tag, bus_space_handle_t handle, + bus_size_t offset, u_int16_t * addr, size_t count) +{ + while (count--) { + *addr = (*(volatile u_int16_t *)(handle + offset)); + addr++; + } +} + +static void +rmi_pci_bus_space_read_multi_stream_4(void *tag, bus_space_handle_t handle, + bus_size_t offset, u_int32_t * addr, size_t count) +{ + while (count--) { + *addr = (*(volatile u_int32_t *)(handle + offset)); + addr++; + } +} + + + +/* + * Read `count' 1, 2, 4, or 8 byte quantities from bus space + * described by tag/handle and starting at `offset' and copy into + * buffer provided. + */ +void +rmi_pci_bus_space_read_region_1(void *t, bus_space_handle_t bsh, + bus_size_t offset, u_int8_t * addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + while (count--) { + *addr++ = (*(volatile u_int8_t *)(baddr)); + baddr += 1; + } +} + +void +rmi_pci_bus_space_read_region_2(void *t, bus_space_handle_t bsh, + bus_size_t offset, u_int16_t * addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + while (count--) { + *addr++ = (*(volatile u_int16_t *)(baddr)); + baddr += 2; + } +} + +void +rmi_pci_bus_space_read_region_4(void *t, bus_space_handle_t bsh, + bus_size_t offset, u_int32_t * addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + while (count--) { + *addr++ = (*(volatile u_int32_t *)(baddr)); + baddr += 4; + } +} + + +void +rmi_pci_bus_space_write_stream_1(void *t, bus_space_handle_t handle, + bus_size_t offset, u_int8_t value) +{ + mips_sync(); + *(volatile u_int8_t *)(handle + offset) = value; +} + +static void +rmi_pci_bus_space_write_stream_2(void *t, bus_space_handle_t handle, + bus_size_t offset, u_int16_t value) +{ + mips_sync(); + *(volatile u_int16_t *)(handle + offset) = value; +} + + +static void +rmi_pci_bus_space_write_stream_4(void *t, bus_space_handle_t handle, + bus_size_t offset, u_int32_t value) +{ + mips_sync(); + *(volatile u_int32_t *)(handle + offset) = value; +} + + +static void +rmi_pci_bus_space_write_multi_stream_1(void *tag, bus_space_handle_t handle, + bus_size_t offset, const u_int8_t * addr, size_t count) +{ + mips_sync(); + while (count--) { + (*(volatile u_int8_t *)(handle + offset)) = *addr; + addr++; + } +} + +static void +rmi_pci_bus_space_write_multi_stream_2(void *tag, bus_space_handle_t handle, + bus_size_t offset, const u_int16_t * addr, size_t count) +{ + mips_sync(); + while (count--) { + (*(volatile u_int16_t *)(handle + offset)) = *addr; + addr++; + } +} + +static void +rmi_pci_bus_space_write_multi_stream_4(void *tag, bus_space_handle_t handle, + bus_size_t offset, const u_int32_t * addr, size_t count) +{ + mips_sync(); + while (count--) { + (*(volatile u_int32_t *)(handle + offset)) = *addr; + addr++; + } +} + +void +rmi_pci_bus_space_write_region_2(void *t, + bus_space_handle_t bsh, + bus_size_t offset, + const u_int16_t * addr, + size_t count) +{ + bus_addr_t baddr = (bus_addr_t) bsh + offset; + + while (count--) { + (*(volatile u_int16_t *)(baddr)) = *addr; + addr++; + baddr += 2; + } +} + +void +rmi_pci_bus_space_write_region_4(void *t, bus_space_handle_t bsh, + bus_size_t offset, const u_int32_t * addr, size_t count) +{ + bus_addr_t baddr = bsh + offset; + + while (count--) { + (*(volatile u_int32_t *)(baddr)) = *addr; + addr++; + baddr += 4; + } +} + +static void +rmi_pci_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused, + bus_size_t offset __unused, bus_size_t len __unused, int flags) +{ + +} diff --git a/sys/mips/nlm/clock.h b/sys/mips/nlm/clock.h index 2135dbf5ee0d3..7a2be07004527 100644 --- a/sys/mips/nlm/clock.h +++ b/sys/mips/nlm/clock.h @@ -25,8 +25,9 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ #ifndef _RMI_CLOCK_H_ #define _RMI_CLOCK_H_ diff --git a/sys/mips/nlm/cms.c b/sys/mips/nlm/cms.c index fb03d8030f0eb..043d5884e0720 100644 --- a/sys/mips/nlm/cms.c +++ b/sys/mips/nlm/cms.c @@ -56,9 +56,8 @@ __FBSDID("$FreeBSD$"); #include <machine/intr_machdep.h> #include <mips/nlm/hal/mips-extns.h> -#include <mips/nlm/hal/mmio.h> +#include <mips/nlm/hal/haldefs.h> #include <mips/nlm/hal/iomap.h> -#include <mips/nlm/hal/cop0.h> #include <mips/nlm/hal/cop2.h> #include <mips/nlm/hal/fmn.h> #include <mips/nlm/hal/pic.h> @@ -108,7 +107,7 @@ xlp_msgring_config(void) int i; /* TODO: Add other nodes */ - xlp_cms_base = nlm_regbase_cms(0); + xlp_cms_base = nlm_get_cms_regbase(0); mtx_init(&msgmap_lock, "msgring", NULL, MTX_SPIN); if (xlp_threads_per_core < xlp_msg_threads_per_core) @@ -147,62 +146,58 @@ xlp_msgring_iodi_config(void) void nlm_cms_credit_setup(int credit) { - int src, qid, i; + int src, qid, i; #if 0 - /* there are a total of 18 src stations on XLP. */ + /* there are a total of 18 src stations on XLP. */ printf("Setting up CMS credits!\n"); - for(src=0; src<18; src++) { - for(qid=0; qid<1024; qid++) { - nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); - } - } + for (src=0; src<18; src++) { + for(qid=0; qid<1024; qid++) { + nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); + } + } #endif printf("Setting up CMS credits!\n"); /* CPU Credits */ - for(i = 1; i < 8; i++) { + for (i = 1; i < 8; i++) { src = (i << 4); - for(qid = 0; qid < 1024; qid++) { - nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); - } - } + for (qid = 0; qid < 1024; qid++) + nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); + } /* PCIE Credits */ - for(i = 0; i < 4; i++) { + for(i = 0; i < 4; i++) { src = (256 + (i * 2)); - for(qid = 0; qid < 1024; qid++) { - nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); - } - } + for(qid = 0; qid < 1024; qid++) + nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); + } /* DTE Credits */ src = 264; - for(qid = 0; qid < 1024; qid++) { - nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); - } + for (qid = 0; qid < 1024; qid++) + nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); /* RSA Credits */ src = 272; - for(qid = 0; qid < 1024; qid++) { - nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); - } + for (qid = 0; qid < 1024; qid++) + nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); + /* Crypto Credits */ src = 281; - for(qid = 0; qid < 1024; qid++) { - nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); - } + for (qid = 0; qid < 1024; qid++) + nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); + /* CMP Credits */ src = 298; - for(qid = 0; qid < 1024; qid++) { - nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); - } + for (qid = 0; qid < 1024; qid++) + nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); + /* POE Credits */ src = 384; - for(qid = 0; qid < 1024; qid++) { - nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); - } + for(qid = 0; qid < 1024; qid++) + nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); + /* NAE Credits */ src = 476; - for(qid = 0; qid < 1024; qid++) { - nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); - } + for(qid = 0; qid < 1024; qid++) + nlm_cms_setup_credits(xlp_cms_base, qid, src, credit); } void @@ -210,7 +205,7 @@ xlp_msgring_cpu_init(uint32_t cpuid) { int queue,i; - queue = XLP_CMS_CPU_PUSHQ(0, ((cpuid >> 2) & 0x7), (cpuid & 0x3), 0); + queue = CMS_CPU_PUSHQ(0, ((cpuid >> 2) & 0x7), (cpuid & 0x3), 0); /* temp allocate 4 segments to each output queue */ nlm_cms_alloc_onchip_q(xlp_cms_base, queue, 4); /* Enable high watermark and non empty interrupt */ @@ -247,9 +242,9 @@ xlp_handle_msg_vc(int vc, int max_msgs) uint32_t mflags, status; for (i = 0; i < max_msgs; i++) { - mflags = nlm_fmn_saveflags(); + mflags = nlm_save_flags_cop2(); status = nlm_fmn_msgrcv(vc, &srcid, &size, &code, &msg); - nlm_fmn_restoreflags(mflags); + nlm_restore_flags(mflags); if (status != 0) /* If there is no msg or error */ break; if (srcid < 0 && srcid >= 1024) { @@ -273,27 +268,27 @@ xlp_handle_msg_vc(int vc, int max_msgs) static int msgring_process_fast_intr(void *arg) { - struct msgring_thread *mthd; - struct thread *td; - int cpu; + struct msgring_thread *mthd; + struct thread *td; + int cpu; cpu = nlm_cpuid(); - mthd = &msgring_threads[cpu]; - td = mthd->thread; + mthd = &msgring_threads[cpu]; + td = mthd->thread; - /* clear pending interrupts */ - nlm_write_c0_eirr(1ULL << IRQ_MSGRING); + /* clear pending interrupts */ + nlm_write_c0_eirr(1ULL << IRQ_MSGRING); - /* wake up the target thread */ - mthd->needed = 1; - thread_lock(td); - if (TD_AWAITING_INTR(td)) { - TD_CLR_IWAIT(td); - sched_add(td, SRQ_INTR); - } + /* wake up the target thread */ + mthd->needed = 1; + thread_lock(td); + if (TD_AWAITING_INTR(td)) { + TD_CLR_IWAIT(td); + sched_add(td, SRQ_INTR); + } - thread_unlock(td); - return (FILTER_HANDLED); + thread_unlock(td); + return (FILTER_HANDLED); } u_int fmn_msgcount[32][4]; @@ -302,31 +297,31 @@ u_int fmn_loops[32]; static void msgring_process(void * arg) { - volatile struct msgring_thread *mthd; - struct thread *td; - uint32_t mflags; + volatile struct msgring_thread *mthd; + struct thread *td; + uint32_t mflags; int hwtid, vc, handled, nmsgs; hwtid = (intptr_t)arg; - mthd = &msgring_threads[hwtid]; - td = mthd->thread; - KASSERT(curthread == td, - ("%s:msg_ithread and proc linkage out of sync", __func__)); + mthd = &msgring_threads[hwtid]; + td = mthd->thread; + KASSERT(curthread == td, + ("%s:msg_ithread and proc linkage out of sync", __func__)); - /* First bind this thread to the right CPU */ - thread_lock(td); - sched_bind(td, xlp_hwtid_to_cpuid[hwtid]); - thread_unlock(td); + /* First bind this thread to the right CPU */ + thread_lock(td); + sched_bind(td, xlp_hwtid_to_cpuid[hwtid]); + thread_unlock(td); if (hwtid != nlm_cpuid()) printf("Misscheduled hwtid %d != cpuid %d\n", hwtid, nlm_cpuid()); - mflags = nlm_fmn_saveflags(); - nlm_fmn_cpu_init(IRQ_MSGRING, 0, 0, 0, 0, 0); - nlm_fmn_restoreflags(mflags); + mflags = nlm_save_flags_cop2(); + nlm_fmn_cpu_init(IRQ_MSGRING, 0, 0, 0, 0, 0); + nlm_restore_flags(mflags); - /* start processing messages */ - for( ; ; ) { - /*atomic_store_rel_int(&mthd->needed, 0);*/ + /* start processing messages */ + for( ; ; ) { + /*atomic_store_rel_int(&mthd->needed, 0);*/ /* enable cop2 access */ do { @@ -338,22 +333,22 @@ msgring_process(void * arg) } } while (handled); - /* sleep */ + /* sleep */ #if 0 - thread_lock(td); - if (mthd->needed) { - thread_unlock(td); - continue; - } - sched_class(td, PRI_ITHD); - TD_SET_IWAIT(td); - mi_switch(SW_VOL, NULL); - thread_unlock(td); + thread_lock(td); + if (mthd->needed) { + thread_unlock(td); + continue; + } + sched_class(td, PRI_ITHD); + TD_SET_IWAIT(td); + mi_switch(SW_VOL, NULL); + thread_unlock(td); #else pause("wmsg", 1); #endif fmn_loops[hwtid]++; - } + } } static void @@ -396,7 +391,6 @@ register_msgring_handler(int startb, int endb, msgring_handler action, msgmap[i].arg = arg; } mtx_unlock_spin(&msgmap_lock); - return (0); } diff --git a/sys/mips/nlm/files.xlp b/sys/mips/nlm/files.xlp index ac138454896f1..f9b2b719d3a5a 100644 --- a/sys/mips/nlm/files.xlp +++ b/sys/mips/nlm/files.xlp @@ -3,10 +3,13 @@ mips/nlm/hal/fmn.c standard mips/nlm/xlp_machdep.c standard mips/nlm/intr_machdep.c standard mips/nlm/tick.c standard -mips/nlm/iodi.c standard mips/nlm/board.c standard mips/nlm/cms.c standard -mips/nlm/bus_space_rmi.c standard +mips/nlm/bus_space_rmi.c standard +mips/nlm/bus_space_rmi_pci.c standard mips/nlm/mpreset.S standard -mips/nlm/uart_bus_xlp_iodi.c optional uart -mips/nlm/uart_cpu_mips_xlp.c optional uart +mips/nlm/xlp_pci.c optional pci +mips/nlm/intern_dev.c optional pci +mips/nlm/uart_pci_xlp.c optional uart +mips/nlm/uart_cpu_xlp.c optional uart +mips/nlm/usb_init.c optional usb diff --git a/sys/mips/nlm/hal/bridge.h b/sys/mips/nlm/hal/bridge.h index d91ccd6488624..543c3659421db 100644 --- a/sys/mips/nlm/hal/bridge.h +++ b/sys/mips/nlm/hal/bridge.h @@ -25,11 +25,12 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ -#ifndef __NLM_BRIDGE_H__ -#define __NLM_BRIDGE_H__ +#ifndef __NLM_HAL_BRIDGE_H__ +#define __NLM_HAL_BRIDGE_H__ /** * @file_name mio.h @@ -37,141 +38,147 @@ * @brief Basic definitions of XLP memory and io subsystem */ -/* BRIDGE specific registers */ -#define XLP_BRIDGE_MODE_REG 0x40 -#define XLP_BRIDGE_PCI_CFG_BASE_REG 0x41 -#define XLP_BRIDGE_PCI_CFG_LIMIT_REG 0x42 -#define XLP_BRIDGE_PCIE_CFG_BASE_REG 0x43 -#define XLP_BRIDGE_PCIE_CFG_LIMIT_REG 0x44 -#define XLP_BRIDGE_BUSNUM_BAR0_REG 0x45 -#define XLP_BRIDGE_BUSNUM_BAR1_REG 0x46 -#define XLP_BRIDGE_BUSNUM_BAR2_REG 0x47 -#define XLP_BRIDGE_BUSNUM_BAR3_REG 0x48 -#define XLP_BRIDGE_BUSNUM_BAR4_REG 0x49 -#define XLP_BRIDGE_BUSNUM_BAR5_REG 0x4a -#define XLP_BRIDGE_BUSNUM_BAR6_REG 0x4b -#define XLP_BRIDGE_FLASH_BAR0_REG 0x4c -#define XLP_BRIDGE_FLASH_BAR1_REG 0x4d -#define XLP_BRIDGE_FLASH_BAR2_REG 0x4e -#define XLP_BRIDGE_FLASH_BAR3_REG 0x4f -#define XLP_BRIDGE_FLASH_LIMIT0_REG 0x50 -#define XLP_BRIDGE_FLASH_LIMIT1_REG 0x51 -#define XLP_BRIDGE_FLASH_LIMIT2_REG 0x52 -#define XLP_BRIDGE_FLASH_LIMIT3_REG 0x53 +/* + * BRIDGE specific registers + * + * These registers start after the PCIe header, which has 0x40 + * standard entries + */ +#define BRIDGE_MODE 0x00 +#define BRIDGE_PCI_CFG_BASE 0x01 +#define BRIDGE_PCI_CFG_LIMIT 0x02 +#define BRIDGE_PCIE_CFG_BASE 0x03 +#define BRIDGE_PCIE_CFG_LIMIT 0x04 +#define BRIDGE_BUSNUM_BAR0 0x05 +#define BRIDGE_BUSNUM_BAR1 0x06 +#define BRIDGE_BUSNUM_BAR2 0x07 +#define BRIDGE_BUSNUM_BAR3 0x08 +#define BRIDGE_BUSNUM_BAR4 0x09 +#define BRIDGE_BUSNUM_BAR5 0x0a +#define BRIDGE_BUSNUM_BAR6 0x0b +#define BRIDGE_FLASH_BAR0 0x0c +#define BRIDGE_FLASH_BAR1 0x0d +#define BRIDGE_FLASH_BAR2 0x0e +#define BRIDGE_FLASH_BAR3 0x0f +#define BRIDGE_FLASH_LIMIT0 0x10 +#define BRIDGE_FLASH_LIMIT1 0x11 +#define BRIDGE_FLASH_LIMIT2 0x12 +#define BRIDGE_FLASH_LIMIT3 0x13 -#define XLP_BRIDGE_DRAM_BAR_REG(i) (0x54 + (i)) -#define XLP_BRIDGE_DRAM_BAR0_REG 0x54 -#define XLP_BRIDGE_DRAM_BAR1_REG 0x55 -#define XLP_BRIDGE_DRAM_BAR2_REG 0x56 -#define XLP_BRIDGE_DRAM_BAR3_REG 0x57 -#define XLP_BRIDGE_DRAM_BAR4_REG 0x58 -#define XLP_BRIDGE_DRAM_BAR5_REG 0x59 -#define XLP_BRIDGE_DRAM_BAR6_REG 0x5a -#define XLP_BRIDGE_DRAM_BAR7_REG 0x5b +#define BRIDGE_DRAM_BAR(i) (0x14 + (i)) +#define BRIDGE_DRAM_BAR0 0x14 +#define BRIDGE_DRAM_BAR1 0x15 +#define BRIDGE_DRAM_BAR2 0x16 +#define BRIDGE_DRAM_BAR3 0x17 +#define BRIDGE_DRAM_BAR4 0x18 +#define BRIDGE_DRAM_BAR5 0x19 +#define BRIDGE_DRAM_BAR6 0x1a +#define BRIDGE_DRAM_BAR7 0x1b -#define XLP_BRIDGE_DRAM_LIMIT_REG(i) (0x5c + (i)) -#define XLP_BRIDGE_DRAM_LIMIT0_REG 0x5c -#define XLP_BRIDGE_DRAM_LIMIT1_REG 0x5d -#define XLP_BRIDGE_DRAM_LIMIT2_REG 0x5e -#define XLP_BRIDGE_DRAM_LIMIT3_REG 0x5f -#define XLP_BRIDGE_DRAM_LIMIT4_REG 0x60 -#define XLP_BRIDGE_DRAM_LIMIT5_REG 0x61 -#define XLP_BRIDGE_DRAM_LIMIT6_REG 0x62 -#define XLP_BRIDGE_DRAM_LIMIT7_REG 0x63 +#define BRIDGE_DRAM_LIMIT(i) (0x1c + (i)) +#define BRIDGE_DRAM_LIMIT0 0x1c +#define BRIDGE_DRAM_LIMIT1 0x1d +#define BRIDGE_DRAM_LIMIT2 0x1e +#define BRIDGE_DRAM_LIMIT3 0x1f +#define BRIDGE_DRAM_LIMIT4 0x20 +#define BRIDGE_DRAM_LIMIT5 0x21 +#define BRIDGE_DRAM_LIMIT6 0x22 +#define BRIDGE_DRAM_LIMIT7 0x23 -#define XLP_BRIDGE_DRAM_NODE_TRANSLN0_REG 0x64 -#define XLP_BRIDGE_DRAM_NODE_TRANSLN1_REG 0x65 -#define XLP_BRIDGE_DRAM_NODE_TRANSLN2_REG 0x66 -#define XLP_BRIDGE_DRAM_NODE_TRANSLN3_REG 0x67 -#define XLP_BRIDGE_DRAM_NODE_TRANSLN4_REG 0x68 -#define XLP_BRIDGE_DRAM_NODE_TRANSLN5_REG 0x69 -#define XLP_BRIDGE_DRAM_NODE_TRANSLN6_REG 0x6a -#define XLP_BRIDGE_DRAM_NODE_TRANSLN7_REG 0x6b -#define XLP_BRIDGE_DRAM_CHNL_TRANSLN0_REG 0x6c -#define XLP_BRIDGE_DRAM_CHNL_TRANSLN1_REG 0x6d -#define XLP_BRIDGE_DRAM_CHNL_TRANSLN2_REG 0x6e -#define XLP_BRIDGE_DRAM_CHNL_TRANSLN3_REG 0x6f -#define XLP_BRIDGE_DRAM_CHNL_TRANSLN4_REG 0x70 -#define XLP_BRIDGE_DRAM_CHNL_TRANSLN5_REG 0x71 -#define XLP_BRIDGE_DRAM_CHNL_TRANSLN6_REG 0x72 -#define XLP_BRIDGE_DRAM_CHNL_TRANSLN7_REG 0x73 -#define XLP_BRIDGE_PCIEMEM_BASE0_REG 0x74 -#define XLP_BRIDGE_PCIEMEM_BASE1_REG 0x75 -#define XLP_BRIDGE_PCIEMEM_BASE2_REG 0x76 -#define XLP_BRIDGE_PCIEMEM_BASE3_REG 0x77 -#define XLP_BRIDGE_PCIEMEM_LIMIT0_REG 0x78 -#define XLP_BRIDGE_PCIEMEM_LIMIT1_REG 0x79 -#define XLP_BRIDGE_PCIEMEM_LIMIT2_REG 0x7a -#define XLP_BRIDGE_PCIEMEM_LIMIT3_REG 0x7b -#define XLP_BRIDGE_PCIEIO_BASE0_REG 0x7c -#define XLP_BRIDGE_PCIEIO_BASE1_REG 0x7d -#define XLP_BRIDGE_PCIEIO_BASE2_REG 0x7e -#define XLP_BRIDGE_PCIEIO_BASE3_REG 0x7f -#define XLP_BRIDGE_PCIEIO_LIMIT0_REG 0x80 -#define XLP_BRIDGE_PCIEIO_LIMIT1_REG 0x81 -#define XLP_BRIDGE_PCIEIO_LIMIT2_REG 0x82 -#define XLP_BRIDGE_PCIEIO_LIMIT3_REG 0x83 -#define XLP_BRIDGE_PCIEMEM_BASE4_REG 0x84 -#define XLP_BRIDGE_PCIEMEM_BASE5_REG 0x85 -#define XLP_BRIDGE_PCIEMEM_BASE6_REG 0x86 -#define XLP_BRIDGE_PCIEMEM_LIMIT4_REG 0x87 -#define XLP_BRIDGE_PCIEMEM_LIMIT5_REG 0x88 -#define XLP_BRIDGE_PCIEMEM_LIMIT6_REG 0x89 -#define XLP_BRIDGE_PCIEIO_BASE4_REG 0x8a -#define XLP_BRIDGE_PCIEIO_BASE5_REG 0x8b -#define XLP_BRIDGE_PCIEIO_BASE6_REG 0x8c -#define XLP_BRIDGE_PCIEIO_LIMIT4_REG 0x8d -#define XLP_BRIDGE_PCIEIO_LIMIT5_REG 0x8e -#define XLP_BRIDGE_PCIEIO_LIMIT6_REG 0x8f -#define XLP_BRIDGE_NBU_EVENT_CNT_CTL_REG 0x90 -#define XLP_BRIDGE_EVNTCTR1_LOW_REG 0x91 -#define XLP_BRIDGE_EVNTCTR1_HI_REG 0x92 -#define XLP_BRIDGE_EVNT_CNT_CTL2_REG 0x93 -#define XLP_BRIDGE_EVNTCTR2_LOW_REG 0x94 -#define XLP_BRIDGE_EVNTCTR2_HI_REG 0x95 -#define XLP_BRIDGE_TRACEBUF_MATCH_REG0 0x96 -#define XLP_BRIDGE_TRACEBUF_MATCH_REG1 0x97 -#define XLP_BRIDGE_TRACEBUF_MATCH_LOW_REG 0x98 -#define XLP_BRIDGE_TRACEBUF_MATCH_HI_REG 0x99 -#define XLP_BRIDGE_TRACEBUF_CTRL_REG 0x9a -#define XLP_BRIDGE_TRACEBUF_INIT_REG 0x9b -#define XLP_BRIDGE_TRACEBUF_ACCESS_REG 0x9c -#define XLP_BRIDGE_TRACEBUF_READ_DATA_REG0 0x9d -#define XLP_BRIDGE_TRACEBUF_READ_DATA_REG1 0x9d -#define XLP_BRIDGE_TRACEBUF_READ_DATA_REG2 0x9f -#define XLP_BRIDGE_TRACEBUF_READ_DATA_REG3 0xa0 -#define XLP_BRIDGE_TRACEBUF_STATUS_REG 0xa1 -#define XLP_BRIDGE_ADDRESS_ERROR0_REG 0xa2 -#define XLP_BRIDGE_ADDRESS_ERROR1_REG 0xa3 -#define XLP_BRIDGE_ADDRESS_ERROR2_REG 0xa4 -#define XLP_BRIDGE_TAG_ECC_ADDR_ERROR0_REG 0xa5 -#define XLP_BRIDGE_TAG_ECC_ADDR_ERROR1_REG 0xa6 -#define XLP_BRIDGE_TAG_ECC_ADDR_ERROR2_REG 0xa7 -#define XLP_BRIDGE_LINE_FLUSH_REG0 0xa8 -#define XLP_BRIDGE_LINE_FLUSH_REG1 0xa9 -#define XLP_BRIDGE_NODE_ID_REG 0xaa -#define XLP_BRIDGE_ERROR_INTERRUPT_EN_REG 0xab -#define XLP_BRIDGE_PCIE0_WEIGHT_REG 0x300 -#define XLP_BRIDGE_PCIE1_WEIGHT_REG 0x301 -#define XLP_BRIDGE_PCIE2_WEIGHT_REG 0x302 -#define XLP_BRIDGE_PCIE3_WEIGHT_REG 0x303 -#define XLP_BRIDGE_USB_WEIGHT_REG 0x304 -#define XLP_BRIDGE_NET_WEIGHT_REG 0x305 -#define XLP_BRIDGE_POE_WEIGHT_REG 0x306 -#define XLP_BRIDGE_CMS_WEIGHT_REG 0x307 -#define XLP_BRIDGE_DMAENG_WEIGHT_REG 0x308 -#define XLP_BRIDGE_SEC_WEIGHT_REG 0x309 -#define XLP_BRIDGE_COMP_WEIGHT_REG 0x30a -#define XLP_BRIDGE_GIO_WEIGHT_REG 0x30b -#define XLP_BRIDGE_FLASH_WEIGHT_REG 0x30c +#define BRIDGE_DRAM_NODE_TRANSLN0 0x24 +#define BRIDGE_DRAM_NODE_TRANSLN1 0x25 +#define BRIDGE_DRAM_NODE_TRANSLN2 0x26 +#define BRIDGE_DRAM_NODE_TRANSLN3 0x27 +#define BRIDGE_DRAM_NODE_TRANSLN4 0x28 +#define BRIDGE_DRAM_NODE_TRANSLN5 0x29 +#define BRIDGE_DRAM_NODE_TRANSLN6 0x2a +#define BRIDGE_DRAM_NODE_TRANSLN7 0x2b +#define BRIDGE_DRAM_CHNL_TRANSLN0 0x2c +#define BRIDGE_DRAM_CHNL_TRANSLN1 0x2d +#define BRIDGE_DRAM_CHNL_TRANSLN2 0x2e +#define BRIDGE_DRAM_CHNL_TRANSLN3 0x2f +#define BRIDGE_DRAM_CHNL_TRANSLN4 0x30 +#define BRIDGE_DRAM_CHNL_TRANSLN5 0x31 +#define BRIDGE_DRAM_CHNL_TRANSLN6 0x32 +#define BRIDGE_DRAM_CHNL_TRANSLN7 0x33 +#define BRIDGE_PCIEMEM_BASE0 0x34 +#define BRIDGE_PCIEMEM_BASE1 0x35 +#define BRIDGE_PCIEMEM_BASE2 0x36 +#define BRIDGE_PCIEMEM_BASE3 0x37 +#define BRIDGE_PCIEMEM_LIMIT0 0x38 +#define BRIDGE_PCIEMEM_LIMIT1 0x39 +#define BRIDGE_PCIEMEM_LIMIT2 0x3a +#define BRIDGE_PCIEMEM_LIMIT3 0x3b +#define BRIDGE_PCIEIO_BASE0 0x3c +#define BRIDGE_PCIEIO_BASE1 0x3d +#define BRIDGE_PCIEIO_BASE2 0x3e +#define BRIDGE_PCIEIO_BASE3 0x3f +#define BRIDGE_PCIEIO_LIMIT0 0x40 +#define BRIDGE_PCIEIO_LIMIT1 0x41 +#define BRIDGE_PCIEIO_LIMIT2 0x42 +#define BRIDGE_PCIEIO_LIMIT3 0x43 +#define BRIDGE_PCIEMEM_BASE4 0x44 +#define BRIDGE_PCIEMEM_BASE5 0x45 +#define BRIDGE_PCIEMEM_BASE6 0x46 +#define BRIDGE_PCIEMEM_LIMIT4 0x47 +#define BRIDGE_PCIEMEM_LIMIT5 0x48 +#define BRIDGE_PCIEMEM_LIMIT6 0x49 +#define BRIDGE_PCIEIO_BASE4 0x4a +#define BRIDGE_PCIEIO_BASE5 0x4b +#define BRIDGE_PCIEIO_BASE6 0x4c +#define BRIDGE_PCIEIO_LIMIT4 0x4d +#define BRIDGE_PCIEIO_LIMIT5 0x4e +#define BRIDGE_PCIEIO_LIMIT6 0x4f +#define BRIDGE_NBU_EVENT_CNT_CTL 0x50 +#define BRIDGE_EVNTCTR1_LOW 0x51 +#define BRIDGE_EVNTCTR1_HI 0x52 +#define BRIDGE_EVNT_CNT_CTL2 0x53 +#define BRIDGE_EVNTCTR2_LOW 0x54 +#define BRIDGE_EVNTCTR2_HI 0x55 +#define BRIDGE_TRACEBUF_MATCH0 0x56 +#define BRIDGE_TRACEBUF_MATCH1 0x57 +#define BRIDGE_TRACEBUF_MATCH_LOW 0x58 +#define BRIDGE_TRACEBUF_MATCH_HI 0x59 +#define BRIDGE_TRACEBUF_CTRL 0x5a +#define BRIDGE_TRACEBUF_INIT 0x5b +#define BRIDGE_TRACEBUF_ACCESS 0x5c +#define BRIDGE_TRACEBUF_READ_DATA0 0x5d +#define BRIDGE_TRACEBUF_READ_DATA1 0x5d +#define BRIDGE_TRACEBUF_READ_DATA2 0x5f +#define BRIDGE_TRACEBUF_READ_DATA3 0x60 +#define BRIDGE_TRACEBUF_STATUS 0x61 +#define BRIDGE_ADDRESS_ERROR0 0x62 +#define BRIDGE_ADDRESS_ERROR1 0x63 +#define BRIDGE_ADDRESS_ERROR2 0x64 +#define BRIDGE_TAG_ECC_ADDR_ERROR0 0x65 +#define BRIDGE_TAG_ECC_ADDR_ERROR1 0x66 +#define BRIDGE_TAG_ECC_ADDR_ERROR2 0x67 +#define BRIDGE_LINE_FLUSH0 0x68 +#define BRIDGE_LINE_FLUSH1 0x69 +#define BRIDGE_NODE_ID 0x6a +#define BRIDGE_ERROR_INTERRUPT_EN 0x6b +#define BRIDGE_PCIE0_WEIGHT 0x2c0 +#define BRIDGE_PCIE1_WEIGHT 0x2c1 +#define BRIDGE_PCIE2_WEIGHT 0x2c2 +#define BRIDGE_PCIE3_WEIGHT 0x2c3 +#define BRIDGE_USB_WEIGHT 0x2c4 +#define BRIDGE_NET_WEIGHT 0x2c5 +#define BRIDGE_POE_WEIGHT 0x2c6 +#define BRIDGE_CMS_WEIGHT 0x2c7 +#define BRIDGE_DMAENG_WEIGHT 0x2c8 +#define BRIDGE_SEC_WEIGHT 0x2c9 +#define BRIDGE_COMP_WEIGHT 0x2ca +#define BRIDGE_GIO_WEIGHT 0x2cb +#define BRIDGE_FLASH_WEIGHT 0x2cc #if !defined(LOCORE) && !defined(__ASSEMBLY__) -#define nlm_rdreg_bridge(b, r) nlm_read_reg_kseg(b, r) -#define nlm_wreg_bridge(b, r, v) nlm_write_reg_kseg(b, r, v) -#define nlm_pcibase_bridge(node) nlm_pcicfg_base(XLP_IO_BRIDGE_OFFSET(node)) -#define nlm_regbase_bridge(node) nlm_pcibase_bridge(node) +#define nlm_read_bridge_reg(b, r) nlm_read_reg(b, r) +#define nlm_write_bridge_reg(b, r, v) nlm_write_reg(b, r, v) +#define nlm_get_bridge_pcibase(node) \ + nlm_pcicfg_base(XLP_IO_BRIDGE_OFFSET(node)) +#define nlm_get_bridge_regbase(node) \ + (nlm_get_bridge_pcibase(node) + XLP_IO_PCI_HDRSZ) #endif - #endif diff --git a/sys/mips/nlm/hal/cop0.h b/sys/mips/nlm/hal/cop0.h deleted file mode 100644 index 18ecc97dfe90b..0000000000000 --- a/sys/mips/nlm/hal/cop0.h +++ /dev/null @@ -1,280 +0,0 @@ -/*- - * Copyright 2003-2011 Netlogic Microsystems (Netlogic). 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 Netlogic Microsystems ``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 NETLOGIC 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$ - * NETLOGIC_BSD */ - -#ifndef __NLM_COP0_H__ -#define __NLM_COP0_H__ - -#define NLM_C0_INDEX 0 -#define NLM_C0_RANDOM 1 -#define NLM_C0_ENTRYLO0 2 -#define NLM_C0_ENTRYLO1 3 -#define NLM_C0_CONTEXT 4 -#define NLM_C0_USERLOCAL 4 -#define NLM_C0_PAGEMASK 5 -#define NLM_C0_WIRED 6 -#define NLM_C0_BADVADDR 8 -#define NLM_C0_COUNT 9 -#define NLM_C0_EIRR 9 -#define NLM_C0_EIMR 9 -#define NLM_C0_ENTRYHI 10 -#define NLM_C0_COMPARE 11 -#define NLM_C0_STATUS 12 -#define NLM_C0_INTCTL 12 -#define NLM_C0_SRSCTL 12 -#define NLM_C0_CAUSE 13 -#define NLM_C0_EPC 14 -#define NLM_C0_PRID 15 -#define NLM_C0_EBASE 15 -#define NLM_C0_CONFIG 16 -#define NLM_C0_CONFIG0 16 -#define NLM_C0_CONFIG1 16 -#define NLM_C0_CONFIG2 16 -#define NLM_C0_CONFIG3 16 -#define NLM_C0_CONFIG4 16 -#define NLM_C0_CONFIG5 16 -#define NLM_C0_CONFIG6 16 -#define NLM_C0_CONFIG7 16 -#define NLM_C0_WATCHLO 18 -#define NLM_C0_WATCHHI 19 -#define NLM_C0_XCONTEXT 20 -#define NLM_C0_SCRATCH 22 -#define NLM_C0_SCRATCH0 22 -#define NLM_C0_SCRATCH1 22 -#define NLM_C0_SCRATCH2 22 -#define NLM_C0_SCRATCH3 22 -#define NLM_C0_SCRATCH4 22 -#define NLM_C0_SCRATCH5 22 -#define NLM_C0_SCRATCH6 22 -#define NLM_C0_SCRATCH7 22 -#define NLM_C0_DEBUG 23 -#define NLM_C0_DEPC 24 -#define NLM_C0_PERFCNT 25 -#define NLM_C0_PERFCNT0 25 -#define NLM_C0_PERFCNT1 25 -#define NLM_C0_TAGLO 28 -#define NLM_C0_DATALO 28 -#define NLM_C0_TAGHI 29 -#define NLM_C0_DATAHI 29 -#define NLM_C0_ERROREPC 30 -#define NLM_C0_DESAVE 31 - -/* cop0 status bits */ -#define NLM_STATUS_CP0_EN (1<<28) -#define NLM_STATUS_CP1_EN (1<<29) -#define NLM_STATUS_CP2_EN (1<<30) -#define NLM_STATUS_KX_EN (1<<7) -#define NLM_STATUS_UX_EN (1<<5) - -#ifndef LOCORE - -#define nlm_memory_barrier() \ - __asm__ __volatile__( \ - ".set push\n\t" \ - ".set noreorder\n\t" \ - " sync\n\t" \ - ".set pop" \ - ::: "memory") - -#define NLM_DEFINE_ACCESSORS32(name, reg, sel) \ -static __inline__ uint32_t nlm_read_c0_##name(void) \ -{ \ - uint32_t __rv; \ - __asm__ __volatile__ ( \ - ".set push\n" \ - ".set noreorder\n" \ - ".set mips64\n" \ - "mfc0 %0, $%1, %2\n" \ - ".set pop\n" \ - : "=r" (__rv) \ - : "i" (reg), "i" (sel) \ - ); \ - return __rv; \ -} \ - \ -static __inline__ void nlm_write_c0_##name(uint32_t val) \ -{ \ - __asm__ __volatile__( \ - ".set push\n" \ - ".set noreorder\n" \ - ".set mips64\n" \ - "mtc0 %0, $%1, %2\n" \ - ".set pop\n" \ - :: "r" (val), "i" (reg), "i" (sel) \ - ); \ -} struct __hack - -/* struct __hack above swallows a semicolon - otherwise the macro - * usage below cannot have the terminating semicolon */ -#if (__mips == 64) -#define NLM_DEFINE_ACCESSORS64(name, reg, sel) \ -static __inline__ uint64_t nlm_read_c0_##name(void) \ -{ \ - uint64_t __rv; \ - __asm__ __volatile__ ( \ - ".set push\n" \ - ".set noreorder\n" \ - ".set mips64\n" \ - "dmfc0 %0,$%1,%2\n" \ - ".set pop\n" \ - : "=r" (__rv) \ - : "i" (reg), "i" (sel) ); \ - return __rv; \ -} \ - \ -static __inline__ void nlm_write_c0_##name(uint64_t val) \ -{ \ - __asm__ __volatile__ ( \ - ".set push\n" \ - ".set noreorder\n" \ - ".set mips64\n" \ - "dmtc0 %0,$%1,%2\n" \ - ".set pop\n" \ - :: "r" (val), "i" (reg), "i" (sel) ); \ -} struct __hack - -#else - -#define NLM_DEFINE_ACCESSORS64(name, reg, sel) \ -static __inline__ uint64_t nlm_read_c0_##name(void) \ -{ \ - uint32_t __high, __low; \ - __asm__ __volatile__ ( \ - ".set push\n" \ - ".set noreorder\n" \ - ".set mips64\n" \ - "dmfc0 $8, $%2, %3\n" \ - "dsra32 %0, $8, 0\n" \ - "sll %1, $8, 0\n" \ - ".set pop\n" \ - : "=r"(__high), "=r"(__low) \ - : "i"(reg), "i"(sel) \ - : "$8" ); \ - \ - return (((uint64_t)__high << 32) | __low); \ -} \ - \ -static __inline__ void nlm_write_c0_##name(uint64_t val) \ -{ \ - uint32_t __high = val >> 32; \ - uint32_t __low = val & 0xffffffff; \ - __asm__ __volatile__ ( \ - ".set push\n" \ - ".set noreorder\n" \ - ".set mips64\n" \ - "dsll32 $8, %1, 0\n" \ - "dsll32 $9, %0, 0\n" \ - "dsrl32 $8, $8, 0\n" \ - "or $8, $8, $9\n" \ - "dmtc0 $8, $%2, %3\n" \ - ".set pop\n" \ - :: "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ - : "$8", "$9"); \ -} struct __hack - -#endif - -NLM_DEFINE_ACCESSORS32(index, 0, 0); -NLM_DEFINE_ACCESSORS32(random, 1, 0); -NLM_DEFINE_ACCESSORS64(entrylo0, 2, 0); -NLM_DEFINE_ACCESSORS64(entrylo1, 3, 0); -NLM_DEFINE_ACCESSORS64(context, 4, 0); -NLM_DEFINE_ACCESSORS64(userlocal, 4, 0); -NLM_DEFINE_ACCESSORS32(pagemask, 5, 0); -NLM_DEFINE_ACCESSORS32(wired, 6, 0); -NLM_DEFINE_ACCESSORS64(badvaddr, 8, 0); -NLM_DEFINE_ACCESSORS32(count, 9, 0); -NLM_DEFINE_ACCESSORS64(eirr, 9, 6); -NLM_DEFINE_ACCESSORS64(eimr, 9, 7); -NLM_DEFINE_ACCESSORS64(entryhi, 10, 0); -NLM_DEFINE_ACCESSORS32(compare, 11, 0); -NLM_DEFINE_ACCESSORS32(status, 12, 0); -NLM_DEFINE_ACCESSORS32(intctl, 12, 1); -NLM_DEFINE_ACCESSORS32(srsctl, 12, 2); -NLM_DEFINE_ACCESSORS32(cause, 13, 0); -NLM_DEFINE_ACCESSORS64(epc, 14, 0); -NLM_DEFINE_ACCESSORS32(prid, 15, 0); -NLM_DEFINE_ACCESSORS32(ebase, 15, 1); -NLM_DEFINE_ACCESSORS32(config0, 16, 0); -NLM_DEFINE_ACCESSORS32(config1, 16, 1); -NLM_DEFINE_ACCESSORS32(config2, 16, 2); -NLM_DEFINE_ACCESSORS32(config3, 16, 3); -NLM_DEFINE_ACCESSORS32(config6, 16, 6); -NLM_DEFINE_ACCESSORS32(config7, 16, 7); -NLM_DEFINE_ACCESSORS64(watchlo0, 18, 0); -NLM_DEFINE_ACCESSORS32(watchhi0, 19, 0); -NLM_DEFINE_ACCESSORS64(xcontext, 20, 0); -NLM_DEFINE_ACCESSORS64(scratch0, 22, 0); -NLM_DEFINE_ACCESSORS64(scratch1, 22, 1); -NLM_DEFINE_ACCESSORS64(scratch2, 22, 2); -NLM_DEFINE_ACCESSORS64(scratch3, 22, 3); -NLM_DEFINE_ACCESSORS64(scratch4, 22, 4); -NLM_DEFINE_ACCESSORS64(scratch5, 22, 5); -NLM_DEFINE_ACCESSORS64(scratch6, 22, 6); -NLM_DEFINE_ACCESSORS64(scratch7, 22, 7); -NLM_DEFINE_ACCESSORS32(debug, 23, 0); -NLM_DEFINE_ACCESSORS32(depc, 24, 0); -NLM_DEFINE_ACCESSORS32(perfctrl0, 25, 0); -NLM_DEFINE_ACCESSORS64(perfcntr0, 25, 1); -NLM_DEFINE_ACCESSORS32(perfctrl1, 25, 2); -NLM_DEFINE_ACCESSORS64(perfcntr1, 25, 3); -NLM_DEFINE_ACCESSORS32(perfctrl2, 25, 4); -NLM_DEFINE_ACCESSORS64(perfcntr2, 25, 5); -NLM_DEFINE_ACCESSORS32(perfctrl3, 25, 6); -NLM_DEFINE_ACCESSORS64(perfcntr3, 25, 7); -NLM_DEFINE_ACCESSORS64(taglo0, 28, 0); -NLM_DEFINE_ACCESSORS64(taglo2, 28, 2); -NLM_DEFINE_ACCESSORS64(taghi0, 29, 0); -NLM_DEFINE_ACCESSORS64(taghi2, 29, 2); -NLM_DEFINE_ACCESSORS64(errorepc, 30, 0); -NLM_DEFINE_ACCESSORS64(desave, 31, 0); - -static __inline__ int nlm_nodeid(void) -{ - return (nlm_read_c0_ebase() >> 5) & 0x3; -} - -static __inline__ int nlm_cpuid(void) -{ - return nlm_read_c0_ebase() & 0x1f; -} - -static __inline__ int nlm_threadid(void) -{ - return nlm_read_c0_ebase() & 0x3; -} - -static __inline__ int nlm_coreid(void) -{ - return (nlm_read_c0_ebase() >> 2) & 0x7; -} - -#endif - -#endif diff --git a/sys/mips/nlm/hal/cop2.h b/sys/mips/nlm/hal/cop2.h index 062cd9df44ab5..6b79d3fd68f5c 100644 --- a/sys/mips/nlm/hal/cop2.h +++ b/sys/mips/nlm/hal/cop2.h @@ -25,27 +25,28 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ -#ifndef __NLM_COP2_H__ -#define __NLM_COP2_H__ +#ifndef __NLM_HAL_COP2_H__ +#define __NLM_HAL_COP2_H__ -#define XLP_COP2_TX_BUF_REG 0 -#define XLP_COP2_RX_BUF_REG 1 -#define XLP_COP2_TXMSGSTATUS_REG 2 -#define XLP_COP2_RXMSGSTATUS_REG 3 -#define XLP_COP2_MSGSTATUS1_REG 4 -#define XLP_COP2_MSGCONFIG_REG 5 -#define XLP_COP2_MSGCONFIG1_REG 6 +#define COP2_TX_BUF 0 +#define COP2_RX_BUF 1 +#define COP2_TXMSGSTATUS 2 +#define COP2_RXMSGSTATUS 3 +#define COP2_MSGSTATUS1 4 +#define COP2_MSGCONFIG 5 +#define COP2_MSGCONFIG1 6 -#define CROSSTHR_POPQ_EN 0x01 -#define VC0_POPQ_EN 0x02 -#define VC1_POPQ_EN 0x04 -#define VC2_POPQ_EN 0x08 -#define VC3_POPQ_EN 0x10 -#define ALL_VC_POPQ_EN 0x1E -#define ALL_VC_CT_POPQ_EN 0x1F +#define CROSSTHR_POPQ_EN 0x01 +#define VC0_POPQ_EN 0x02 +#define VC1_POPQ_EN 0x04 +#define VC2_POPQ_EN 0x08 +#define VC3_POPQ_EN 0x10 +#define ALL_VC_POPQ_EN 0x1E +#define ALL_VC_CT_POPQ_EN 0x1F struct nlm_fmn_msg { uint64_t msg[4]; @@ -62,8 +63,7 @@ static inline uint32_t nlm_read_c2_##name(void) \ "mfc2 %0, $%1, %2\n" \ ".set pop\n" \ : "=r" (__rv) \ - : "i" (reg), "i" (sel) \ - ); \ + : "i" (reg), "i" (sel)); \ return __rv; \ } \ \ @@ -75,8 +75,7 @@ static inline void nlm_write_c2_##name(uint32_t val) \ ".set mips64\n" \ "mtc2 %0, $%1, %2\n" \ ".set pop\n" \ - :: "r" (val), "i" (reg), "i" (sel) \ - ); \ + : : "r" (val), "i" (reg), "i" (sel)); \ } struct __hack #if (__mips == 64) @@ -91,7 +90,7 @@ static inline uint64_t nlm_read_c2_##name(void) \ "dmfc2 %0, $%1, %2\n" \ ".set pop\n" \ : "=r" (__rv) \ - : "i" (reg), "i" (sel) ); \ + : "i" (reg), "i" (sel)); \ return __rv; \ } \ \ @@ -103,7 +102,7 @@ static inline void nlm_write_c2_##name(uint64_t val) \ ".set mips64\n" \ "dmtc2 %0, $%1, %2\n" \ ".set pop\n" \ - :: "r" (val), "i" (reg), "i" (sel) ); \ + : : "r" (val), "i" (reg), "i" (sel)); \ } struct __hack #else @@ -122,15 +121,15 @@ static inline uint64_t nlm_read_c2_##name(void) \ ".set pop\n" \ : "=r"(__high), "=r"(__low) \ : "i"(reg), "i"(sel) \ - : "$8" ); \ + : "$8"); \ \ - return (((uint64_t)__high << 32) | __low); \ + return ((uint64_t)__high << 32) | __low; \ } \ \ static inline void nlm_write_c2_##name(uint64_t val) \ { \ - uint32_t __high = val >> 32; \ - uint32_t __low = val & 0xffffffff; \ + uint32_t __high = val >> 32; \ + uint32_t __low = val & 0xffffffff; \ __asm__ __volatile__ ( \ ".set push\n" \ ".set noreorder\n" \ @@ -141,113 +140,100 @@ static inline void nlm_write_c2_##name(uint64_t val) \ "or $8, $8, $9\n" \ "dmtc2 $8, $%2, %3\n" \ ".set pop\n" \ - :: "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ - :"$8", "$9"); \ + : : "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ + : "$8", "$9"); \ } struct __hack #endif -NLM_DEFINE_COP2_ACCESSORS64(txbuf0, XLP_COP2_TX_BUF_REG, 0); -NLM_DEFINE_COP2_ACCESSORS64(txbuf1, XLP_COP2_TX_BUF_REG, 1); -NLM_DEFINE_COP2_ACCESSORS64(txbuf2, XLP_COP2_TX_BUF_REG, 2); -NLM_DEFINE_COP2_ACCESSORS64(txbuf3, XLP_COP2_TX_BUF_REG, 3); +NLM_DEFINE_COP2_ACCESSORS64(txbuf0, COP2_TX_BUF, 0); +NLM_DEFINE_COP2_ACCESSORS64(txbuf1, COP2_TX_BUF, 1); +NLM_DEFINE_COP2_ACCESSORS64(txbuf2, COP2_TX_BUF, 2); +NLM_DEFINE_COP2_ACCESSORS64(txbuf3, COP2_TX_BUF, 3); -NLM_DEFINE_COP2_ACCESSORS64(rxbuf0, XLP_COP2_RX_BUF_REG, 0); -NLM_DEFINE_COP2_ACCESSORS64(rxbuf1, XLP_COP2_RX_BUF_REG, 1); -NLM_DEFINE_COP2_ACCESSORS64(rxbuf2, XLP_COP2_RX_BUF_REG, 2); -NLM_DEFINE_COP2_ACCESSORS64(rxbuf3, XLP_COP2_RX_BUF_REG, 3); +NLM_DEFINE_COP2_ACCESSORS64(rxbuf0, COP2_RX_BUF, 0); +NLM_DEFINE_COP2_ACCESSORS64(rxbuf1, COP2_RX_BUF, 1); +NLM_DEFINE_COP2_ACCESSORS64(rxbuf2, COP2_RX_BUF, 2); +NLM_DEFINE_COP2_ACCESSORS64(rxbuf3, COP2_RX_BUF, 3); -NLM_DEFINE_COP2_ACCESSORS32(txmsgstatus, XLP_COP2_TXMSGSTATUS_REG, 0); -NLM_DEFINE_COP2_ACCESSORS32(rxmsgstatus, XLP_COP2_RXMSGSTATUS_REG, 0); -NLM_DEFINE_COP2_ACCESSORS32(msgstatus1, XLP_COP2_MSGSTATUS1_REG, 0); -NLM_DEFINE_COP2_ACCESSORS32(msgconfig, XLP_COP2_MSGCONFIG_REG, 0); -NLM_DEFINE_COP2_ACCESSORS32(msgconfig1, XLP_COP2_MSGCONFIG1_REG, 0); +NLM_DEFINE_COP2_ACCESSORS32(txmsgstatus, COP2_TXMSGSTATUS, 0); +NLM_DEFINE_COP2_ACCESSORS32(rxmsgstatus, COP2_RXMSGSTATUS, 0); +NLM_DEFINE_COP2_ACCESSORS32(msgstatus1, COP2_MSGSTATUS1, 0); +NLM_DEFINE_COP2_ACCESSORS32(msgconfig, COP2_MSGCONFIG, 0); +NLM_DEFINE_COP2_ACCESSORS32(msgconfig1, COP2_MSGCONFIG1, 0); /* successful completion returns 1, else 0 */ -static __inline__ int nlm_msgsend(int val) +static inline int +nlm_msgsend(int val) { int result; __asm__ volatile ( - ".set push \n" - ".set noreorder \n" - ".set mips64 \n" - "move $8, %1 \n" - "sync \n" - "/* msgsnds $9, $8 */ \n" - ".word 0x4a084801 \n" - "move %0, $9 \n" - ".set pop \n" + ".set push\n" + ".set noreorder\n" + ".set mips64\n" + "move $8, %1\n" + "sync\n" + "/* msgsnds $9, $8 */\n" + ".word 0x4a084801\n" + "move %0, $9\n" + ".set pop\n" : "=r" (result) : "r" (val) - : "$8", "$9" - ); + : "$8", "$9"); return result; } -static __inline__ int nlm_msgld(int vc) +static inline int +nlm_msgld(int vc) { int val; __asm__ volatile ( - ".set push \n" - ".set noreorder \n" - ".set mips64 \n" - "move $8, %1 \n" - "/* msgld $9, $8 */ \n" - ".word 0x4a084802 \n" - "move %0, $9 \n" - ".set pop \n" + ".set push\n" + ".set noreorder\n" + ".set mips64\n" + "move $8, %1\n" + "/* msgld $9, $8 */\n" + ".word 0x4a084802\n" + "move %0, $9\n" + ".set pop\n" : "=r" (val) : "r" (vc) - : "$8", "$9" - ); + : "$8", "$9"); return val; } -static __inline__ void nlm_msgwait(int vc) +static inline void +nlm_msgwait(int vc) { __asm__ volatile ( - ".set push \n" - ".set noreorder \n" - ".set mips64 \n" - "move $8, %0 \n" - "/* msgwait $8 */ \n" - ".word 0x4a080003 \n" - ".set pop \n" - :: "r" (vc) - : "$8" - ); -} - -/* TODO this is not needed in n32 and n64 */ -static __inline uint32_t -nlm_fmn_saveflags(void) -{ - uint32_t sr = mips_rd_status(); - - mips_wr_status((sr & ~MIPS_SR_INT_IE) | MIPS_SR_COP_2_BIT); - return (sr); -} - -static __inline void -nlm_fmn_restoreflags(uint32_t sr) -{ - - mips_wr_status(sr); + ".set push\n" + ".set noreorder\n" + ".set mips64\n" + "move $8, %0\n" + "/* msgwait $8 */\n" + ".word 0x4a080003\n" + ".set pop\n" + : : "r" (vc) + : "$8"); } -static __inline__ int nlm_fmn_msgsend(int dstid, int size, int swcode, - struct nlm_fmn_msg *m) +static inline int +nlm_fmn_msgsend(int dstid, int size, int swcode, struct nlm_fmn_msg *m) { uint32_t flags, status; int rv; size -= 1; - flags = nlm_fmn_saveflags(); - switch(size) { - case 3: nlm_write_c2_txbuf3(m->msg[3]); - case 2: nlm_write_c2_txbuf2(m->msg[2]); - case 1: nlm_write_c2_txbuf1(m->msg[1]); - case 0: nlm_write_c2_txbuf0(m->msg[0]); + flags = nlm_save_flags_cop2(); + switch (size) { + case 3: + nlm_write_c2_txbuf3(m->msg[3]); + case 2: + nlm_write_c2_txbuf2(m->msg[2]); + case 1: + nlm_write_c2_txbuf1(m->msg[1]); + case 0: + nlm_write_c2_txbuf0(m->msg[0]); } dstid |= ((swcode << 24) | (size << 16)); @@ -255,19 +241,19 @@ static __inline__ int nlm_fmn_msgsend(int dstid, int size, int swcode, rv = !status; if (rv != 0) rv = nlm_read_c2_txmsgstatus(); - nlm_fmn_restoreflags(flags); + nlm_restore_flags(flags); - return (rv); + return rv; } -static __inline__ int nlm_fmn_msgrcv(int vc, int *srcid, int *size, int *code, - struct nlm_fmn_msg *m) +static inline int +nlm_fmn_msgrcv(int vc, int *srcid, int *size, int *code, struct nlm_fmn_msg *m) { uint32_t status; uint32_t msg_status, flags; int tmp_sz, rv; - flags = nlm_fmn_saveflags(); + flags = nlm_save_flags_cop2(); status = nlm_msgld(vc); /* will return 0, if error */ rv = !status; if (rv == 0) { @@ -276,38 +262,24 @@ static __inline__ int nlm_fmn_msgrcv(int vc, int *srcid, int *size, int *code, *code = (msg_status >> 18) & 0xff; *srcid = (msg_status >> 4) & 0xfff; tmp_sz = *size - 1; - switch(tmp_sz) { - case 3: m->msg[3] = nlm_read_c2_rxbuf3(); - case 2: m->msg[2] = nlm_read_c2_rxbuf2(); - case 1: m->msg[1] = nlm_read_c2_rxbuf1(); - case 0: m->msg[0] = nlm_read_c2_rxbuf0(); + switch (tmp_sz) { + case 3: + m->msg[3] = nlm_read_c2_rxbuf3(); + case 2: + m->msg[2] = nlm_read_c2_rxbuf2(); + case 1: + m->msg[1] = nlm_read_c2_rxbuf1(); + case 0: + m->msg[0] = nlm_read_c2_rxbuf0(); } } - nlm_fmn_restoreflags(flags); + nlm_restore_flags(flags); return rv; } -/** - * nlm_fmn_cpu_init() initializes the per-h/w thread cop2 w.r.t the following - * configuration parameters. It needs to be individually setup on each - * hardware thread. - * - * int_vec - interrupt vector getting placed into msgconfig reg - * ctpe - cross thread message pop enable. When set to 1, the thread (h/w cpu) - * associated where this cop2 register is setup, can pop messages - * intended for any other thread in the same core. - * v0pe - VC0 pop message request mode enable. When set to 1, the thread - * can send pop requests to vc0. - * v1pe - VC1 pop message request mode enable. When set to 1, the thread - * can send pop requests to vc1. - * v2pe - VC2 pop message request mode enable. When set to 1, the thread - * can send pop requests to vc2. - * v3pe - VC3 pop message request mode enable. When set to 1, the thread - * can send pop requests to vc3. - */ -static __inline__ void nlm_fmn_cpu_init(int int_vec, int ctpe, int v0pe, - int v1pe, int v2pe, int v3pe) +static inline void +nlm_fmn_cpu_init(int int_vec, int ctpe, int v0pe, int v1pe, int v2pe, int v3pe) { uint32_t val = nlm_read_c2_msgconfig(); diff --git a/sys/mips/nlm/hal/cpucontrol.h b/sys/mips/nlm/hal/cpucontrol.h index 0bc0f5be7bbb2..715cd535f5d6e 100644 --- a/sys/mips/nlm/hal/cpucontrol.h +++ b/sys/mips/nlm/hal/cpucontrol.h @@ -25,46 +25,168 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ -#ifndef __NLM_CPUCONTROL_H__ -#define __NLM_CPUCONTROL_H__ +#ifndef __NLM_HAL_CPUCONTROL_H__ +#define __NLM_HAL_CPUCONTROL_H__ -#define XLP_CPU_BLOCKID_IFU 0 -#define XLP_CPU_BLOCKID_ICU 1 +#define CPU_BLOCKID_IFU 0 +#define CPU_BLOCKID_ICU 1 +#define CPU_BLOCKID_IEU 2 +#define CPU_BLOCKID_LSU 3 +#define CPU_BLOCKID_MMU 4 +#define CPU_BLOCKID_PRF 5 +#define CPU_BLOCKID_SCH 7 +#define CPU_BLOCKID_SCU 8 +#define CPU_BLOCKID_FPU 9 +#define CPU_BLOCKID_MAP 10 -#define XLP_CPU_BLOCKID_IEU 2 -#define XLP_CPU_BLOCKID_LSU 3 -#define XLP_LSU_DEFEATURE 0x304 -#define XLP_LSU_CERRLOG_REGID 0x09 +#define LSU_DEFEATURE 0x304 +#define LSU_CERRLOG_REGID 0x09 +#define SCHED_DEFEATURE 0x700 -#define XLP_CPU_BLOCKID_MMU 4 -#define XLP_CPU_BLOCKID_PRF 5 +/* Offsets of interest from the 'MAP' Block */ +#define MAP_THREADMODE 0x00 +#define MAP_EXT_EBASE_ENABLE 0x04 +#define MAP_CCDI_CONFIG 0x08 +#define MAP_THRD0_CCDI_STATUS 0x0c +#define MAP_THRD1_CCDI_STATUS 0x10 +#define MAP_THRD2_CCDI_STATUS 0x14 +#define MAP_THRD3_CCDI_STATUS 0x18 +#define MAP_THRD0_DEBUG_MODE 0x1c +#define MAP_THRD1_DEBUG_MODE 0x20 +#define MAP_THRD2_DEBUG_MODE 0x24 +#define MAP_THRD3_DEBUG_MODE 0x28 +#define MAP_MISC_STATE 0x60 +#define MAP_DEBUG_READ_CTL 0x64 +#define MAP_DEBUG_READ_REG0 0x68 +#define MAP_DEBUG_READ_REG1 0x6c -#define XLP_CPU_BLOCKID_SCH 7 -#define XLP_SCHED_DEFEATURE 0x700 +#define MMU_SETUP 0x400 +#define MMU_LFSRSEED 0x401 +#define MMU_HPW_NUM_PAGE_LVL 0x410 +#define MMU_PGWKR_PGDBASE 0x411 +#define MMU_PGWKR_PGDSHFT 0x412 +#define MMU_PGWKR_PGDMASK 0x413 +#define MMU_PGWKR_PUDSHFT 0x414 +#define MMU_PGWKR_PUDMASK 0x415 +#define MMU_PGWKR_PMDSHFT 0x416 +#define MMU_PGWKR_PMDMASK 0x417 +#define MMU_PGWKR_PTESHFT 0x418 +#define MMU_PGWKR_PTEMASK 0x419 -#define XLP_CPU_BLOCKID_SCU 8 -#define XLP_CPU_BLOCKID_FPU 9 -#define XLP_CPU_BLOCKID_MAP 10 +#if !defined(LOCORE) && !defined(__ASSEMBLY__) +#if defined(__mips_n64) || defined(__mips_n32) +static __inline uint64_t +nlm_mfcr(uint32_t reg) +{ + uint64_t res; -/* Offsets of interest from the 'MAP' Block */ -#define XLP_BLKID_MAP_THREADMODE 0x00 -#define XLP_BLKID_MAP_EXT_EBASE_ENABLE 0x04 -#define XLP_BLKID_MAP_CCDI_CONFIG 0x08 -#define XLP_BLKID_MAP_THRD0_CCDI_STATUS 0x0c -#define XLP_BLKID_MAP_THRD1_CCDI_STATUS 0x10 -#define XLP_BLKID_MAP_THRD2_CCDI_STATUS 0x14 -#define XLP_BLKID_MAP_THRD3_CCDI_STATUS 0x18 -#define XLP_BLKID_MAP_THRD0_DEBUG_MODE 0x1c -#define XLP_BLKID_MAP_THRD1_DEBUG_MODE 0x20 -#define XLP_BLKID_MAP_THRD2_DEBUG_MODE 0x24 -#define XLP_BLKID_MAP_THRD3_DEBUG_MODE 0x28 -#define XLP_BLKID_MAP_MISC_STATE 0x60 -#define XLP_BLKID_MAP_DEBUG_READ_CTL 0x64 -#define XLP_BLKID_MAP_DEBUG_READ_REG0 0x68 -#define XLP_BLKID_MAP_DEBUG_READ_REG1 0x6c + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + "move $9, %1\n\t" + ".word 0x71280018\n\t" /* mfcr $8, $9 */ + "move %0, $8\n\t" + ".set pop\n" + : "=r" (res) : "r"(reg) + : "$8", "$9" + ); + return (res); +} + +static __inline void +nlm_mtcr(uint32_t reg, uint64_t value) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + "move $8, %0\n" + "move $9, %1\n" + ".word 0x71280019\n" /* mtcr $8, $9 */ + ".set pop\n" + : + : "r" (value), "r" (reg) + : "$8", "$9" + ); +} + +#else /* !(defined(__mips_n64) || defined(__mips_n32)) */ + +static __inline__ uint64_t +nlm_mfcr(uint32_t reg) +{ + uint32_t hi, lo; + + __asm__ __volatile__ ( + ".set push\n" + ".set mips64\n" + "move $8, %2\n" + ".word 0x71090018\n" + "nop \n" + "dsra32 %0, $9, 0\n" + "sll %1, $9, 0\n" + ".set pop\n" + : "=r"(hi), "=r"(lo) + : "r"(reg) : "$8", "$9"); + + return (((uint64_t)hi) << 32) | lo; +} + +static __inline__ void +nlm_mtcr(uint32_t reg, uint64_t val) +{ + uint32_t hi, lo; + + hi = val >> 32; + lo = val & 0xffffffff; + + __asm__ __volatile__ ( + ".set push\n" + ".set mips64\n" + "move $9, %0\n" + "dsll32 $9, %1, 0\n" + "dsll32 $8, %0, 0\n" + "dsrl32 $9, $9, 0\n" + "or $9, $9, $8\n" + "move $8, %2\n" + ".word 0x71090019\n" + "nop \n" + ".set pop\n" + : :"r"(hi), "r"(lo), "r"(reg) + : "$8", "$9"); +} +#endif /* (defined(__mips_n64) || defined(__mips_n32)) */ + +/* hashindex_en = 1 to enable hash mode, hashindex_en=0 to disable + * global_mode = 1 to enable global mode, global_mode=0 to disable + * clk_gating = 0 to enable clock gating, clk_gating=1 to disable + */ +static __inline__ void nlm_mmu_setup(int hashindex_en, int global_mode, + int clk_gating) +{ + uint32_t mmusetup = 0; + + mmusetup |= (hashindex_en << 13); + mmusetup |= (clk_gating << 3); + mmusetup |= (global_mode << 0); + nlm_mtcr(MMU_SETUP, mmusetup); +} + +static __inline__ void nlm_mmu_lfsr_seed (int thr0_seed, int thr1_seed, + int thr2_seed, int thr3_seed) +{ + uint32_t seed = nlm_mfcr(MMU_LFSRSEED); + + seed |= ((thr3_seed & 0x7f) << 23); + seed |= ((thr2_seed & 0x7f) << 16); + seed |= ((thr1_seed & 0x7f) << 7); + seed |= ((thr0_seed & 0x7f) << 0); + nlm_mtcr(MMU_LFSRSEED, seed); +} +#endif /* __ASSEMBLY__ */ #endif /* __NLM_CPUCONTROL_H__ */ diff --git a/sys/mips/nlm/hal/fmn.c b/sys/mips/nlm/hal/fmn.c index fd4f7c80a7df8..e58a2a5590361 100644 --- a/sys/mips/nlm/hal/fmn.c +++ b/sys/mips/nlm/hal/fmn.c @@ -25,20 +25,19 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD$ * NETLOGIC_BSD */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); - #include <sys/types.h> +#include <sys/systm.h> + +#include <machine/cpufunc.h> #include <mips/nlm/hal/mips-extns.h> -#include <mips/nlm/hal/mmio.h> +#include <mips/nlm/hal/haldefs.h> #include <mips/nlm/hal/iomap.h> #include <mips/nlm/hal/fmn.h> -#include <sys/systm.h> -uint32_t bad_xlp_num_nodes = 4; /* XLP can take upto 16K of FMN messages per hardware queue, as spill. * But, configuring all 16K causes the total spill memory to required * to blow upto 192MB for single chip configuration, and 768MB in four @@ -68,27 +67,7 @@ uint64_t nlm_cms_spill_total_messages = 1 * 1024; * For all 4 nodes, there are 18*4 = 72 FMN stations */ uint32_t nlm_cms_total_stations = 18 * 4 /*xlp_num_nodes*/; -uint32_t cms_onchip_seg_availability[XLP_CMS_ON_CHIP_PER_QUEUE_SPACE]; - -int nlm_cms_verify_credit_config (int spill_en, int tot_credit) -{ - /* Note: In XLP there seem to be no mechanism to read back - * the credit count that has been programmed into a sid / did pair; - * since we have only one register 0x2000 to read. - * Hence it looks like all credit mgmt/verification needs to - * be done by software. Software could keep track of total credits - * getting programmed and verify it from this function. - */ - - if (spill_en) { - /* TODO */ - } - - if (tot_credit > (XLP_CMS_ON_CHIP_MESG_SPACE*bad_xlp_num_nodes)) - return 1; /* credits overflowed - should not happen */ - - return 0; -} +uint32_t cms_onchip_seg_availability[CMS_ON_CHIP_PER_QUEUE_SPACE]; /** * Takes inputs as node, queue_size and maximum number of queues. @@ -163,7 +142,7 @@ void nlm_cms_setup_credits(uint64_t base, int destid, int srcid, int credit) uint32_t val; val = ((credit << 24) | (destid << 12) | (srcid << 0)); - nlm_wreg_cms(base, XLP_CMS_OUTPUTQ_CREDIT_CFG_REG, val); + nlm_write_cms_reg(base, CMS_OUTPUTQ_CREDIT_CFG, val); } @@ -182,93 +161,93 @@ int nlm_cms_config_onchip_queue (uint64_t base, uint64_t spill_base, #if 0 /* configure credits for src cpu0, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_CPU0_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_CPU0_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src cpu1, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_CPU1_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_CPU1_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src cpu2, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_CPU2_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_CPU2_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src cpu3, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_CPU3_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_CPU3_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src cpu4, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_CPU4_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_CPU4_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src cpu5, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_CPU5_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_CPU5_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src cpu6, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_CPU6_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_CPU6_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src cpu7, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_CPU7_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_CPU7_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src pcie0, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_PCIE0_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_PCIE0_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src pcie1, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_PCIE1_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_PCIE1_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src pcie2, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_PCIE2_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_PCIE2_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src pcie3, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_PCIE3_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_PCIE3_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src dte, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_DTE_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_DTE_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src rsa_ecc, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_RSA_ECC_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_RSA_ECC_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src crypto, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_CRYPTO_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_CRYPTO_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src cmp, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_CMP_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_CMP_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src poe, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_POE_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_POE_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); /* configure credits for src nae, on this queue */ - nlm_cms_setup_credits(base, qid, XLP_CMS_NAE_SRC_STID, - XLP_CMS_DEFAULT_CREDIT(nlm_cms_total_stations, + nlm_cms_setup_credits(base, qid, CMS_NAE_SRC_STID, + CMS_DEFAULT_CREDIT(nlm_cms_total_stations, nlm_cms_spill_total_messages)); #endif @@ -289,20 +268,20 @@ int nlm_cms_alloc_spill_q(uint64_t base, int qid, uint64_t spill_base, uint64_t queue_config; uint32_t spill_start; - if(nsegs > XLP_CMS_MAX_SPILL_SEGMENTS_PER_QUEUE) { + if(nsegs > CMS_MAX_SPILL_SEGMENTS_PER_QUEUE) { return 1; } - queue_config = nlm_rdreg_cms(base,(XLP_CMS_OUTPUTQ_CONFIG_REG(qid))); + queue_config = nlm_read_cms_reg(base,(CMS_OUTPUTQ_CONFIG(qid))); spill_start = ((spill_base >> 12) & 0x3F); /* Spill configuration */ - queue_config = (((uint64_t)XLP_CMS_SPILL_ENA << 62) | + queue_config = (((uint64_t)CMS_SPILL_ENA << 62) | (((spill_base >> 18) & 0x3FFFFF) << 27) | (spill_start + nsegs - 1) << 21 | (spill_start << 15)); - nlm_wreg_cms(base,(XLP_CMS_OUTPUTQ_CONFIG_REG(qid)),queue_config); + nlm_write_cms_reg(base,(CMS_OUTPUTQ_CONFIG(qid)),queue_config); return 0; } @@ -320,8 +299,8 @@ int nlm_cms_alloc_onchip_q(uint64_t base, int qid, int nsegs) int onchipbase, start, last; uint8_t i; - if( ((curr_end + nsegs) > XLP_CMS_MAX_ONCHIP_SEGMENTS) || - (nsegs > XLP_CMS_ON_CHIP_PER_QUEUE_SPACE) ) { + if( ((curr_end + nsegs) > CMS_MAX_ONCHIP_SEGMENTS) || + (nsegs > CMS_ON_CHIP_PER_QUEUE_SPACE) ) { /* Invalid configuration */ return 1; } @@ -347,15 +326,15 @@ int nlm_cms_alloc_onchip_q(uint64_t base, int qid, int nsegs) cms_onchip_seg_availability[onchipbase] |= (1 << i); } - queue_config = nlm_rdreg_cms(base,(XLP_CMS_OUTPUTQ_CONFIG_REG(qid))); + queue_config = nlm_read_cms_reg(base,(CMS_OUTPUTQ_CONFIG(qid))); /* On chip configuration */ - queue_config = (((uint64_t)XLP_CMS_QUEUE_ENA << 63) | + queue_config = (((uint64_t)CMS_QUEUE_ENA << 63) | ((onchipbase & 0x1f) << 10) | ((last & 0x1f) << 5) | (start & 0x1f)); - nlm_wreg_cms(base,(XLP_CMS_OUTPUTQ_CONFIG_REG(qid)),queue_config); + nlm_write_cms_reg(base,(CMS_OUTPUTQ_CONFIG(qid)),queue_config); return 0; } @@ -367,85 +346,86 @@ void nlm_cms_default_setup(int node, uint64_t spill_base, int spill_en, int queue; uint64_t base; - base = nlm_regbase_cms(node); + base = nlm_get_cms_regbase(node); for(j=0; j<1024; j++) { - printf("Qid:0x%04d Val:0x%016jx\n",j, (uintmax_t)nlm_cms_get_onchip_queue (base, j)); + printf("Qid:0x%04d Val:0x%016jx\n",j, + (uintmax_t)nlm_cms_get_onchip_queue (base, j)); } /* Enable all cpu push queues */ for (j=0; j<XLP_MAX_CORES; j++) for (k=0; k<XLP_MAX_THREADS; k++) - for (vc=0; vc<XLP_CMS_MAX_VCPU_VC; vc++) { + for (vc=0; vc<CMS_MAX_VCPU_VC; vc++) { /* TODO : remove this once SMP works */ if( (j == 0) && (k == 0) ) continue; - queue = XLP_CMS_CPU_PUSHQ(node, j, k, vc); + queue = CMS_CPU_PUSHQ(node, j, k, vc); nlm_cms_config_onchip_queue(base, spill_base, queue, spill_en); } /* Enable pcie 0 push queue */ - for (j=XLP_CMS_PCIE0_QID(0); j<XLP_CMS_PCIE0_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_PCIE0_QID(0); j<CMS_PCIE0_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_config_onchip_queue(base, spill_base, queue, spill_en); } /* Enable pcie 1 push queue */ - for (j=XLP_CMS_PCIE1_QID(0); j<XLP_CMS_PCIE1_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_PCIE1_QID(0); j<CMS_PCIE1_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_config_onchip_queue(base, spill_base, queue, spill_en); } /* Enable pcie 2 push queue */ - for (j=XLP_CMS_PCIE2_QID(0); j<XLP_CMS_PCIE2_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_PCIE2_QID(0); j<CMS_PCIE2_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_config_onchip_queue(base, spill_base, queue, spill_en); } /* Enable pcie 3 push queue */ - for (j=XLP_CMS_PCIE3_QID(0); j<XLP_CMS_PCIE3_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_PCIE3_QID(0); j<CMS_PCIE3_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_config_onchip_queue(base, spill_base, queue, spill_en); } /* Enable DTE push queue */ - for (j=XLP_CMS_DTE_QID(0); j<XLP_CMS_DTE_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_DTE_QID(0); j<CMS_DTE_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_config_onchip_queue(base, spill_base, queue, spill_en); } /* Enable RSA/ECC push queue */ - for (j=XLP_CMS_RSA_ECC_QID(0); j<XLP_CMS_RSA_ECC_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_RSA_ECC_QID(0); j<CMS_RSA_ECC_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_config_onchip_queue(base, spill_base, queue, spill_en); } /* Enable crypto push queue */ - for (j=XLP_CMS_CRYPTO_QID(0); j<XLP_CMS_CRYPTO_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_CRYPTO_QID(0); j<CMS_CRYPTO_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_config_onchip_queue(base, spill_base, queue, spill_en); } /* Enable CMP push queue */ - for (j=XLP_CMS_CMP_QID(0); j<XLP_CMS_CMP_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_CMP_QID(0); j<CMS_CMP_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_config_onchip_queue(base, spill_base, queue, spill_en); } /* Enable POE push queue */ - for (j=XLP_CMS_POE_QID(0); j<XLP_CMS_POE_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_POE_QID(0); j<CMS_POE_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_config_onchip_queue(base, spill_base, queue, spill_en); } /* Enable NAE push queue */ - for (j=XLP_CMS_NAE_QID(0); j<XLP_CMS_NAE_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_NAE_QID(0); j<CMS_NAE_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_config_onchip_queue(base, spill_base, queue, spill_en); } /* Enable all pop queues */ if (popq_en) { - for (j=XLP_CMS_POPQ_QID(0); j<XLP_CMS_POPQ_MAXQID; j++) { - queue = XLP_CMS_POPQ(node, j); + for (j=CMS_POPQ_QID(0); j<CMS_POPQ_MAXQID; j++) { + queue = CMS_POPQ(node, j); nlm_cms_config_onchip_queue(base, spill_base, queue, spill_en); } @@ -454,16 +434,16 @@ void nlm_cms_default_setup(int node, uint64_t spill_base, int spill_en, uint64_t nlm_cms_get_onchip_queue (uint64_t base, int qid) { - return nlm_rdreg_cms(base, XLP_CMS_OUTPUTQ_CONFIG_REG(qid)); + return nlm_read_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid)); } void nlm_cms_set_onchip_queue (uint64_t base, int qid, uint64_t val) { uint64_t rdval; - rdval = nlm_rdreg_cms(base, XLP_CMS_OUTPUTQ_CONFIG_REG(qid)); + rdval = nlm_read_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid)); rdval |= val; - nlm_wreg_cms(base, XLP_CMS_OUTPUTQ_CONFIG_REG(qid), rdval); + nlm_write_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid), rdval); } void nlm_cms_per_queue_level_intr(uint64_t base, int qid, int sub_type, @@ -471,12 +451,12 @@ void nlm_cms_per_queue_level_intr(uint64_t base, int qid, int sub_type, { uint64_t val; - val = nlm_rdreg_cms(base, XLP_CMS_OUTPUTQ_CONFIG_REG(qid)); + val = nlm_read_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid)); val |= (((uint64_t)sub_type<<54) | ((uint64_t)intr_val<<56)); - nlm_wreg_cms(base, XLP_CMS_OUTPUTQ_CONFIG_REG(qid), val); + nlm_write_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid), val); } void nlm_cms_level_intr(int node, int sub_type, int intr_val) @@ -485,78 +465,78 @@ void nlm_cms_level_intr(int node, int sub_type, int intr_val) int queue; uint64_t base; - base = nlm_regbase_cms(node); + base = nlm_get_cms_regbase(node); /* setup level intr config on all cpu push queues */ for (j=0; j<XLP_MAX_CORES; j++) for (k=0; k<XLP_MAX_THREADS; k++) - for (vc=0; vc<XLP_CMS_MAX_VCPU_VC; vc++) { - queue = XLP_CMS_CPU_PUSHQ(node, j, k, vc); + for (vc=0; vc<CMS_MAX_VCPU_VC; vc++) { + queue = CMS_CPU_PUSHQ(node, j, k, vc); nlm_cms_per_queue_level_intr(base, queue, sub_type, intr_val); } /* setup level intr config on all pcie 0 push queue */ - for (j=XLP_CMS_PCIE0_QID(0); j<XLP_CMS_PCIE0_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_PCIE0_QID(0); j<CMS_PCIE0_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_level_intr(base, queue, sub_type, intr_val); } /* setup level intr config on all pcie 1 push queue */ - for (j=XLP_CMS_PCIE1_QID(0); j<XLP_CMS_PCIE1_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_PCIE1_QID(0); j<CMS_PCIE1_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_level_intr(base, queue, sub_type, intr_val); } /* setup level intr config on all pcie 2 push queue */ - for (j=XLP_CMS_PCIE2_QID(0); j<XLP_CMS_PCIE2_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_PCIE2_QID(0); j<CMS_PCIE2_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_level_intr(base, queue, sub_type, intr_val); } /* setup level intr config on all pcie 3 push queue */ - for (j=XLP_CMS_PCIE3_QID(0); j<XLP_CMS_PCIE3_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_PCIE3_QID(0); j<CMS_PCIE3_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_level_intr(base, queue, sub_type, intr_val); } /* setup level intr config on all DTE push queue */ - for (j=XLP_CMS_DTE_QID(0); j<XLP_CMS_DTE_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_DTE_QID(0); j<CMS_DTE_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_level_intr(base, queue, sub_type, intr_val); } /* setup level intr config on all RSA/ECC push queue */ - for (j=XLP_CMS_RSA_ECC_QID(0); j<XLP_CMS_RSA_ECC_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_RSA_ECC_QID(0); j<CMS_RSA_ECC_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_level_intr(base, queue, sub_type, intr_val); } /* setup level intr config on all crypto push queue */ - for (j=XLP_CMS_CRYPTO_QID(0); j<XLP_CMS_CRYPTO_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_CRYPTO_QID(0); j<CMS_CRYPTO_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_level_intr(base, queue, sub_type, intr_val); } /* setup level intr config on all CMP push queue */ - for (j=XLP_CMS_CMP_QID(0); j<XLP_CMS_CMP_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_CMP_QID(0); j<CMS_CMP_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_level_intr(base, queue, sub_type, intr_val); } /* setup level intr config on all POE push queue */ - for (j=XLP_CMS_POE_QID(0); j<XLP_CMS_POE_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_POE_QID(0); j<CMS_POE_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_level_intr(base, queue, sub_type, intr_val); } /* setup level intr config on all NAE push queue */ - for (j=XLP_CMS_NAE_QID(0); j<XLP_CMS_NAE_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_NAE_QID(0); j<CMS_NAE_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_level_intr(base, queue, sub_type, intr_val); } /* setup level intr config on all pop queues */ - for (j=XLP_CMS_POPQ_QID(0); j<XLP_CMS_POPQ_MAXQID; j++) { - queue = XLP_CMS_POPQ(node, j); + for (j=CMS_POPQ_QID(0); j<CMS_POPQ_MAXQID; j++) { + queue = CMS_POPQ(node, j); nlm_cms_per_queue_level_intr(base, queue, sub_type, intr_val); } } @@ -566,12 +546,12 @@ void nlm_cms_per_queue_timer_intr(uint64_t base, int qid, int sub_type, { uint64_t val; - val = nlm_rdreg_cms(base, XLP_CMS_OUTPUTQ_CONFIG_REG(qid)); + val = nlm_read_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid)); val |= (((uint64_t)sub_type<<49) | ((uint64_t)intr_val<<51)); - nlm_wreg_cms(base, XLP_CMS_OUTPUTQ_CONFIG_REG(qid), val); + nlm_write_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid), val); } void nlm_cms_timer_intr(int node, int en, int sub_type, int intr_val) @@ -580,78 +560,78 @@ void nlm_cms_timer_intr(int node, int en, int sub_type, int intr_val) int queue; uint64_t base; - base = nlm_regbase_cms(node); + base = nlm_get_cms_regbase(node); /* setup timer intr config on all cpu push queues */ for (j=0; j<XLP_MAX_CORES; j++) for (k=0; k<XLP_MAX_THREADS; k++) - for (vc=0; vc<XLP_CMS_MAX_VCPU_VC; vc++) { - queue = XLP_CMS_CPU_PUSHQ(node, j, k, vc); + for (vc=0; vc<CMS_MAX_VCPU_VC; vc++) { + queue = CMS_CPU_PUSHQ(node, j, k, vc); nlm_cms_per_queue_timer_intr(base, queue, sub_type, intr_val); } /* setup timer intr config on all pcie 0 push queue */ - for (j=XLP_CMS_PCIE0_QID(0); j<XLP_CMS_PCIE0_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_PCIE0_QID(0); j<CMS_PCIE0_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_timer_intr(base, queue, sub_type, intr_val); } /* setup timer intr config on all pcie 1 push queue */ - for (j=XLP_CMS_PCIE1_QID(0); j<XLP_CMS_PCIE1_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_PCIE1_QID(0); j<CMS_PCIE1_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_timer_intr(base, queue, sub_type, intr_val); } /* setup timer intr config on all pcie 2 push queue */ - for (j=XLP_CMS_PCIE2_QID(0); j<XLP_CMS_PCIE2_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_PCIE2_QID(0); j<CMS_PCIE2_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_timer_intr(base, queue, sub_type, intr_val); } /* setup timer intr config on all pcie 3 push queue */ - for (j=XLP_CMS_PCIE3_QID(0); j<XLP_CMS_PCIE3_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_PCIE3_QID(0); j<CMS_PCIE3_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_timer_intr(base, queue, sub_type, intr_val); } /* setup timer intr config on all DTE push queue */ - for (j=XLP_CMS_DTE_QID(0); j<XLP_CMS_DTE_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_DTE_QID(0); j<CMS_DTE_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_timer_intr(base, queue, sub_type, intr_val); } /* setup timer intr config on all RSA/ECC push queue */ - for (j=XLP_CMS_RSA_ECC_QID(0); j<XLP_CMS_RSA_ECC_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_RSA_ECC_QID(0); j<CMS_RSA_ECC_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_timer_intr(base, queue, sub_type, intr_val); } /* setup timer intr config on all crypto push queue */ - for (j=XLP_CMS_CRYPTO_QID(0); j<XLP_CMS_CRYPTO_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_CRYPTO_QID(0); j<CMS_CRYPTO_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_timer_intr(base, queue, sub_type, intr_val); } /* setup timer intr config on all CMP push queue */ - for (j=XLP_CMS_CMP_QID(0); j<XLP_CMS_CMP_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_CMP_QID(0); j<CMS_CMP_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_timer_intr(base, queue, sub_type, intr_val); } /* setup timer intr config on all POE push queue */ - for (j=XLP_CMS_POE_QID(0); j<XLP_CMS_POE_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_POE_QID(0); j<CMS_POE_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_timer_intr(base, queue, sub_type, intr_val); } /* setup timer intr config on all NAE push queue */ - for (j=XLP_CMS_NAE_QID(0); j<XLP_CMS_NAE_MAXQID; j++) { - queue = XLP_CMS_IO_PUSHQ(node, j); + for (j=CMS_NAE_QID(0); j<CMS_NAE_MAXQID; j++) { + queue = CMS_IO_PUSHQ(node, j); nlm_cms_per_queue_timer_intr(base, queue, sub_type, intr_val); } /* setup timer intr config on all pop queues */ - for (j=XLP_CMS_POPQ_QID(0); j<XLP_CMS_POPQ_MAXQID; j++) { - queue = XLP_CMS_POPQ(node, j); + for (j=CMS_POPQ_QID(0); j<CMS_POPQ_MAXQID; j++) { + queue = CMS_POPQ(node, j); nlm_cms_per_queue_timer_intr(base, queue, sub_type, intr_val); } } @@ -660,7 +640,7 @@ void nlm_cms_timer_intr(int node, int en, int sub_type, int intr_val) int nlm_cms_outputq_intr_check(uint64_t base, int qid) { uint64_t val; - val = nlm_rdreg_cms(base, XLP_CMS_OUTPUTQ_CONFIG_REG(qid)); + val = nlm_read_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid)); return ((val >> 59) & 0x1); } @@ -668,77 +648,77 @@ int nlm_cms_outputq_intr_check(uint64_t base, int qid) void nlm_cms_outputq_clr_intr(uint64_t base, int qid) { uint64_t val; - val = nlm_rdreg_cms(base, XLP_CMS_OUTPUTQ_CONFIG_REG(qid)); + val = nlm_read_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid)); val |= (1ULL<<59); - nlm_wreg_cms(base, XLP_CMS_OUTPUTQ_CONFIG_REG(qid), val); + nlm_write_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid), val); } void nlm_cms_illegal_dst_error_intr(uint64_t base, int en) { uint64_t val; - val = nlm_rdreg_cms(base, XLP_CMS_MSG_CONFIG_REG); + val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<8); - nlm_wreg_cms(base, XLP_CMS_MSG_CONFIG_REG, val); + nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_timeout_error_intr(uint64_t base, int en) { uint64_t val; - val = nlm_rdreg_cms(base, XLP_CMS_MSG_CONFIG_REG); + val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<7); - nlm_wreg_cms(base, XLP_CMS_MSG_CONFIG_REG, val); + nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_biu_error_resp_intr(uint64_t base, int en) { uint64_t val; - val = nlm_rdreg_cms(base, XLP_CMS_MSG_CONFIG_REG); + val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<6); - nlm_wreg_cms(base, XLP_CMS_MSG_CONFIG_REG, val); + nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_spill_uncorrectable_ecc_error_intr(uint64_t base, int en) { uint64_t val; - val = nlm_rdreg_cms(base, XLP_CMS_MSG_CONFIG_REG); + val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<5) | (en<<3); - nlm_wreg_cms(base, XLP_CMS_MSG_CONFIG_REG, val); + nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_spill_correctable_ecc_error_intr(uint64_t base, int en) { uint64_t val; - val = nlm_rdreg_cms(base, XLP_CMS_MSG_CONFIG_REG); + val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<4) | (en<<2); - nlm_wreg_cms(base, XLP_CMS_MSG_CONFIG_REG, val); + nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_outputq_uncorrectable_ecc_error_intr(uint64_t base, int en) { uint64_t val; - val = nlm_rdreg_cms(base, XLP_CMS_MSG_CONFIG_REG); + val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<1); - nlm_wreg_cms(base, XLP_CMS_MSG_CONFIG_REG, val); + nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_outputq_correctable_ecc_error_intr(uint64_t base, int en) { uint64_t val; - val = nlm_rdreg_cms(base, XLP_CMS_MSG_CONFIG_REG); + val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<0); - nlm_wreg_cms(base, XLP_CMS_MSG_CONFIG_REG, val); + nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } uint64_t nlm_cms_network_error_status(uint64_t base) { - return nlm_rdreg_cms(base, XLP_CMS_MSG_ERR_REG); + return nlm_read_cms_reg(base, CMS_MSG_ERR); } int nlm_cms_get_net_error_code(uint64_t err) @@ -770,20 +750,20 @@ void nlm_cms_trace_setup(uint64_t base, int en, uint64_t trace_base, { uint64_t val; - nlm_wreg_cms(base, XLP_CMS_TRACE_BASE_ADDR_REG, trace_base); - nlm_wreg_cms(base, XLP_CMS_TRACE_LIMIT_ADDR_REG, trace_limit); + nlm_write_cms_reg(base, CMS_TRACE_BASE_ADDR, trace_base); + nlm_write_cms_reg(base, CMS_TRACE_LIMIT_ADDR, trace_limit); - val = nlm_rdreg_cms(base, XLP_CMS_TRACE_CONFIG_REG); + val = nlm_read_cms_reg(base, CMS_TRACE_CONFIG); val |= (((uint64_t)match_dstid_en << 39) | ((dst_id & 0xfff) << 24) | (match_srcid_en << 23) | ((src_id & 0xfff) << 8) | (wrap << 1) | (en << 0)); - nlm_wreg_cms(base, XLP_CMS_MSG_CONFIG_REG, val); + nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_endian_byte_swap (uint64_t base, int en) { - nlm_wreg_cms(base, XLP_CMS_MSG_ENDIAN_SWAP_REG, en); + nlm_write_cms_reg(base, CMS_MSG_ENDIAN_SWAP, en); } diff --git a/sys/mips/nlm/hal/fmn.h b/sys/mips/nlm/hal/fmn.h index 75fc77403166c..88ba113ec473d 100644 --- a/sys/mips/nlm/hal/fmn.h +++ b/sys/mips/nlm/hal/fmn.h @@ -25,8 +25,9 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ #ifndef __NLM_FMNV2_H__ #define __NLM_FMNV2_H__ @@ -38,156 +39,156 @@ */ /* FMN configuration registers */ -#define XLP_CMS_OUTPUTQ_CONFIG_REG(i) ((i)*2) -#define XLP_CMS_MAX_OUTPUTQ 1024 -#define XLP_CMS_OUTPUTQ_CREDIT_CFG_REG (0x2000/4) -#define XLP_CMS_MSG_CONFIG_REG (0x2008/4) -#define XLP_CMS_MSG_ERR_REG (0x2010/4) -#define XLP_CMS_TRACE_CONFIG_REG (0x2018/4) -#define XLP_CMS_TRACE_BASE_ADDR_REG (0x2020/4) -#define XLP_CMS_TRACE_LIMIT_ADDR_REG (0x2028/4) -#define XLP_CMS_TRACE_CURRENT_ADDR_REG (0x2030/4) -#define XLP_CMS_MSG_ENDIAN_SWAP_REG (0x2038/4) +#define CMS_OUTPUTQ_CONFIG(i) ((i)*2) +#define CMS_MAX_OUTPUTQ 1024 +#define CMS_OUTPUTQ_CREDIT_CFG (0x2000/4) +#define CMS_MSG_CONFIG (0x2008/4) +#define CMS_MSG_ERR (0x2010/4) +#define CMS_TRACE_CONFIG (0x2018/4) +#define CMS_TRACE_BASE_ADDR (0x2020/4) +#define CMS_TRACE_LIMIT_ADDR (0x2028/4) +#define CMS_TRACE_CURRENT_ADDR (0x2030/4) +#define CMS_MSG_ENDIAN_SWAP (0x2038/4) -#define XLP_CMS_CPU_PUSHQ(node, core, thread, vc) \ +#define CMS_CPU_PUSHQ(node, core, thread, vc) \ (((node)<<10) | ((core)<<4) | ((thread)<<2) | ((vc)<<0)) -#define XLP_CMS_POPQ(node, queue) (((node)<<10) | (queue)) -#define XLP_CMS_IO_PUSHQ(node, queue) (((node)<<10) | (queue)) +#define CMS_POPQ(node, queue) (((node)<<10) | (queue)) +#define CMS_IO_PUSHQ(node, queue) (((node)<<10) | (queue)) -#define XLP_CMS_POPQ_QID(i) (128+(i)) -#define XLP_CMS_POPQ_MAXQID 255 -#define XLP_CMS_PCIE0_QID(i) (256+(i)) -#define XLP_CMS_PCIE0_MAXQID 257 -#define XLP_CMS_PCIE1_QID(i) (258+(i)) -#define XLP_CMS_PCIE1_MAXQID 259 -#define XLP_CMS_PCIE2_QID(i) (260+(i)) -#define XLP_CMS_PCIE2_MAXQID 261 -#define XLP_CMS_PCIE3_QID(i) (262+(i)) -#define XLP_CMS_PCIE3_MAXQID 263 -#define XLP_CMS_DTE_QID(i) (264+(i)) -#define XLP_CMS_DTE_MAXQID 267 -#define XLP_CMS_RSA_ECC_QID(i) (272+(i)) -#define XLP_CMS_RSA_ECC_MAXQID 280 -#define XLP_CMS_CRYPTO_QID(i) (281+(i)) -#define XLP_CMS_CRYPTO_MAXQID 296 +#define CMS_POPQ_QID(i) (128+(i)) +#define CMS_POPQ_MAXQID 255 +#define CMS_PCIE0_QID(i) (256+(i)) +#define CMS_PCIE0_MAXQID 257 +#define CMS_PCIE1_QID(i) (258+(i)) +#define CMS_PCIE1_MAXQID 259 +#define CMS_PCIE2_QID(i) (260+(i)) +#define CMS_PCIE2_MAXQID 261 +#define CMS_PCIE3_QID(i) (262+(i)) +#define CMS_PCIE3_MAXQID 263 +#define CMS_DTE_QID(i) (264+(i)) +#define CMS_DTE_MAXQID 267 +#define CMS_RSA_ECC_QID(i) (272+(i)) +#define CMS_RSA_ECC_MAXQID 280 +#define CMS_CRYPTO_QID(i) (281+(i)) +#define CMS_CRYPTO_MAXQID 296 /* TODO PCI header register 0x3C says CMP starts at 297(0x129) VERIFY */ -#define XLP_CMS_CMP_QID(i) (298+(i)) -#define XLP_CMS_CMP_MAXQID 305 -#define XLP_CMS_POE_QID(i) (384+(i)) -#define XLP_CMS_POE_MAXQID 391 -#define XLP_CMS_NAE_QID(i) (476+(i)) -#define XLP_CMS_NAE_MAXQID 1023 +#define CMS_CMP_QID(i) (298+(i)) +#define CMS_CMP_MAXQID 305 +#define CMS_POE_QID(i) (384+(i)) +#define CMS_POE_MAXQID 391 +#define CMS_NAE_QID(i) (476+(i)) +#define CMS_NAE_MAXQID 1023 -#define XLP_CMS_NAE_TX_VC_BASE 476 -#define XLP_CMS_NAE_TX_VC_LIMIT 999 -#define XLP_CMS_NAE_RX_VC_BASE 1000 -#define XLP_CMS_NAE_RX_VC_LIMIT 1019 +#define CMS_NAE_TX_VC_BASE 476 +#define CMS_NAE_TX_VC_LIMIT 999 +#define CMS_NAE_RX_VC_BASE 1000 +#define CMS_NAE_RX_VC_LIMIT 1019 -#define XLP_MAX_CMS_QUEUES 1024 +#define MAX_CMS_QUEUES 1024 /* FMN Level Interrupt Type */ -#define XLP_CMS_LVL_INTR_DISABLE 0 -#define XLP_CMS_LVL_LOW_WATERMARK 1 -#define XLP_CMS_LVL_HI_WATERMARK 2 +#define CMS_LVL_INTR_DISABLE 0 +#define CMS_LVL_LOW_WATERMARK 1 +#define CMS_LVL_HI_WATERMARK 2 /* FMN Level interrupt trigger values */ -#define XLP_CMS_QUEUE_NON_EMPTY 0 -#define XLP_CMS_QUEUE_QUARTER_FULL 1 -#define XLP_CMS_QUEUE_HALF_FULL 2 -#define XLP_CMS_QUEUE_THREE_QUARTER_FULL 3 -#define XLP_CMS_QUEUE_FULL 4 +#define CMS_QUEUE_NON_EMPTY 0 +#define CMS_QUEUE_QUARTER_FULL 1 +#define CMS_QUEUE_HALF_FULL 2 +#define CMS_QUEUE_THREE_QUARTER_FULL 3 +#define CMS_QUEUE_FULL 4 /* FMN Timer Interrupt Type */ -#define XLP_CMS_TIMER_INTR_DISABLE 0 -#define XLP_CMS_TIMER_CONSUMER 1 -#define XLP_CMS_TIMER_PRODUCER 1 +#define CMS_TIMER_INTR_DISABLE 0 +#define CMS_TIMER_CONSUMER 1 +#define CMS_TIMER_PRODUCER 1 /* FMN timer interrupt trigger values */ -#define XLP_CMS_TWO_POW_EIGHT_CYCLES 0 -#define XLP_CMS_TWO_POW_TEN_CYCLES 1 -#define XLP_CMS_TWO_POW_TWELVE_CYCLES 2 -#define XLP_CMS_TWO_POW_FOURTEEN_CYCLES 3 -#define XLP_CMS_TWO_POW_SIXTEEN_CYCLES 4 -#define XLP_CMS_TWO_POW_EIGHTTEEN_CYCLES 5 -#define XLP_CMS_TWO_POW_TWENTY_CYCLES 6 -#define XLP_CMS_TWO_POW_TWENTYTWO_CYCLES 7 +#define CMS_TWO_POW_EIGHT_CYCLES 0 +#define CMS_TWO_POW_TEN_CYCLES 1 +#define CMS_TWO_POW_TWELVE_CYCLES 2 +#define CMS_TWO_POW_FOURTEEN_CYCLES 3 +#define CMS_TWO_POW_SIXTEEN_CYCLES 4 +#define CMS_TWO_POW_EIGHTTEEN_CYCLES 5 +#define CMS_TWO_POW_TWENTY_CYCLES 6 +#define CMS_TWO_POW_TWENTYTWO_CYCLES 7 -#define XLP_CMS_QUEUE_ENA 1ULL -#define XLP_CMS_QUEUE_DIS 0 -#define XLP_CMS_SPILL_ENA 1ULL -#define XLP_CMS_SPILL_DIS 0 +#define CMS_QUEUE_ENA 1ULL +#define CMS_QUEUE_DIS 0 +#define CMS_SPILL_ENA 1ULL +#define CMS_SPILL_DIS 0 -#define XLP_CMS_MAX_VCPU_VC 4 +#define CMS_MAX_VCPU_VC 4 /* Each XLP chip can hold upto 32K messages on the chip itself */ -#define XLP_CMS_ON_CHIP_MESG_SPACE (32*1024) -#define XLP_CMS_ON_CHIP_PER_QUEUE_SPACE \ - ((XLP_CMS_ON_CHIP_MESG_SPACE)/(XLP_MAX_CMS_QUEUES)) -#define XLP_CMS_MAX_ONCHIP_SEGMENTS 1024 -#define XLP_CMS_MAX_SPILL_SEGMENTS_PER_QUEUE 64 +#define CMS_ON_CHIP_MESG_SPACE (32*1024) +#define CMS_ON_CHIP_PER_QUEUE_SPACE \ + ((CMS_ON_CHIP_MESG_SPACE)/(MAX_CMS_QUEUES)) +#define CMS_MAX_ONCHIP_SEGMENTS 1024 +#define CMS_MAX_SPILL_SEGMENTS_PER_QUEUE 64 /* FMN Network error */ -#define XLP_CMS_ILLEGAL_DST_ERROR 0x100 -#define XLP_CMS_BIU_TIMEOUT_ERROR 0x080 -#define XLP_CMS_BIU_ERROR 0x040 -#define XLP_CMS_SPILL_FILL_UNCORRECT_ECC_ERROR 0x020 -#define XLP_CMS_SPILL_FILL_CORRECT_ECC_ERROR 0x010 -#define XLP_CMS_SPILL_UNCORRECT_ECC_ERROR 0x008 -#define XLP_CMS_SPILL_CORRECT_ECC_ERROR 0x004 -#define XLP_CMS_OUTPUTQ_UNCORRECT_ECC_ERROR 0x002 -#define XLP_CMS_OUTPUTQ_CORRECT_ECC_ERROR 0x001 +#define CMS_ILLEGAL_DST_ERROR 0x100 +#define CMS_BIU_TIMEOUT_ERROR 0x080 +#define CMS_BIU_ERROR 0x040 +#define CMS_SPILL_FILL_UNCORRECT_ECC_ERROR 0x020 +#define CMS_SPILL_FILL_CORRECT_ECC_ERROR 0x010 +#define CMS_SPILL_UNCORRECT_ECC_ERROR 0x008 +#define CMS_SPILL_CORRECT_ECC_ERROR 0x004 +#define CMS_OUTPUTQ_UNCORRECT_ECC_ERROR 0x002 +#define CMS_OUTPUTQ_CORRECT_ECC_ERROR 0x001 /* worst case, a single entry message consists of a 4 byte header * and an 8-byte entry = 12 bytes in total */ -#define XLP_CMS_SINGLE_ENTRY_MSG_SIZE 12 +#define CMS_SINGLE_ENTRY_MSG_SIZE 12 /* total spill memory needed for one FMN queue */ -#define XLP_CMS_PER_QUEUE_SPILL_MEM(spilltotmsgs) \ - ((spilltotmsgs) * (XLP_CMS_SINGLE_ENTRY_MSG_SIZE)) +#define CMS_PER_QUEUE_SPILL_MEM(spilltotmsgs) \ + ((spilltotmsgs) * (CMS_SINGLE_ENTRY_MSG_SIZE)) /* total spill memory needed */ -#define XLP_CMS_TOTAL_SPILL_MEM(spilltotmsgs) \ - ((XLP_CMS_PER_QUEUE_SPILL_MEM(spilltotmsgs)) * \ - (XLP_MAX_CMS_QUEUES)) +#define CMS_TOTAL_SPILL_MEM(spilltotmsgs) \ + ((CMS_PER_QUEUE_SPILL_MEM(spilltotmsgs)) * \ + (MAX_CMS_QUEUES)) /* total number of FMN messages possible in a queue */ -#define XLP_CMS_TOTAL_QUEUE_SIZE(spilltotmsgs) \ - ((spilltotmsgs) + (XLP_CMS_ON_CHIP_PER_QUEUE_SPACE)) +#define CMS_TOTAL_QUEUE_SIZE(spilltotmsgs) \ + ((spilltotmsgs) + (CMS_ON_CHIP_PER_QUEUE_SPACE)) /* FMN Src station id's */ -#define XLP_CMS_CPU0_SRC_STID (0 << 4) -#define XLP_CMS_CPU1_SRC_STID (1 << 4) -#define XLP_CMS_CPU2_SRC_STID (2 << 4) -#define XLP_CMS_CPU3_SRC_STID (3 << 4) -#define XLP_CMS_CPU4_SRC_STID (4 << 4) -#define XLP_CMS_CPU5_SRC_STID (5 << 4) -#define XLP_CMS_CPU6_SRC_STID (6 << 4) -#define XLP_CMS_CPU7_SRC_STID (7 << 4) -#define XLP_CMS_PCIE0_SRC_STID 256 -#define XLP_CMS_PCIE1_SRC_STID 258 -#define XLP_CMS_PCIE2_SRC_STID 260 -#define XLP_CMS_PCIE3_SRC_STID 262 -#define XLP_CMS_DTE_SRC_STID 264 -#define XLP_CMS_RSA_ECC_SRC_STID 272 -#define XLP_CMS_CRYPTO_SRC_STID 281 -#define XLP_CMS_CMP_SRC_STID 298 -#define XLP_CMS_POE_SRC_STID 384 -#define XLP_CMS_NAE_SRC_STID 476 +#define CMS_CPU0_SRC_STID (0 << 4) +#define CMS_CPU1_SRC_STID (1 << 4) +#define CMS_CPU2_SRC_STID (2 << 4) +#define CMS_CPU3_SRC_STID (3 << 4) +#define CMS_CPU4_SRC_STID (4 << 4) +#define CMS_CPU5_SRC_STID (5 << 4) +#define CMS_CPU6_SRC_STID (6 << 4) +#define CMS_CPU7_SRC_STID (7 << 4) +#define CMS_PCIE0_SRC_STID 256 +#define CMS_PCIE1_SRC_STID 258 +#define CMS_PCIE2_SRC_STID 260 +#define CMS_PCIE3_SRC_STID 262 +#define CMS_DTE_SRC_STID 264 +#define CMS_RSA_ECC_SRC_STID 272 +#define CMS_CRYPTO_SRC_STID 281 +#define CMS_CMP_SRC_STID 298 +#define CMS_POE_SRC_STID 384 +#define CMS_NAE_SRC_STID 476 #if 0 -#define XLP_CMS_DEFAULT_CREDIT(cmstotstns,spilltotmsgs) \ - ((XLP_CMS_TOTAL_QUEUE_SIZE(spilltotmsgs)) / \ +#define CMS_DEFAULT_CREDIT(cmstotstns,spilltotmsgs) \ + ((CMS_TOTAL_QUEUE_SIZE(spilltotmsgs)) / \ (cmstotstns)) #endif -#define XLP_CMS_DEFAULT_CREDIT(cmstotstns,spilltotmsgs) 8 +#define CMS_DEFAULT_CREDIT(cmstotstns,spilltotmsgs) 8 /* POPQ related defines */ -#define XLP_CMS_POPQID_START 128 -#define XLP_CMS_POPQID_END 255 +#define CMS_POPQID_START 128 +#define CMS_POPQID_END 255 -#define XLP_CMS_INT_RCVD 0x800000000000000ULL +#define CMS_INT_RCVD 0x800000000000000ULL -#define nlm_rdreg_cms(b, r) nlm_read_reg64_xkseg(b,r) -#define nlm_wreg_cms(b, r, v) nlm_write_reg64_xkseg(b,r,v) -#define nlm_pcibase_cms(node) nlm_pcicfg_base(XLP_IO_CMS_OFFSET(node)) -#define nlm_regbase_cms(node) nlm_pcibar0_base_xkphys(nlm_pcibase_cms(node)) +#define nlm_read_cms_reg(b, r) nlm_read_reg64_xkphys(b,r) +#define nlm_write_cms_reg(b, r, v) nlm_write_reg64_xkphys(b,r,v) +#define nlm_get_cms_pcibase(node) nlm_pcicfg_base(XLP_IO_CMS_OFFSET(node)) +#define nlm_get_cms_regbase(node) nlm_xkphys_map_pcibar0(nlm_get_cms_pcibase(node)) enum fmn_swcode { FMN_SWCODE_CPU0=1, @@ -237,7 +238,7 @@ enum fmn_swcode { extern uint64_t nlm_cms_spill_total_messages; extern uint32_t nlm_cms_total_stations; -extern uint32_t cms_onchip_seg_availability[XLP_CMS_ON_CHIP_PER_QUEUE_SPACE]; +extern uint32_t cms_onchip_seg_availability[CMS_ON_CHIP_PER_QUEUE_SPACE]; extern uint64_t cms_base_addr(int node); extern int nlm_cms_verify_credit_config (int spill_en, int tot_credit); diff --git a/sys/mips/nlm/hal/haldefs.h b/sys/mips/nlm/hal/haldefs.h new file mode 100644 index 0000000000000..a8e13420dfcf6 --- /dev/null +++ b/sys/mips/nlm/hal/haldefs.h @@ -0,0 +1,437 @@ +/*- + * Copyright 2003-2011 Netlogic Microsystems (Netlogic). 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 Netlogic Microsystems ``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 NETLOGIC 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. + * + * NETLOGIC_BSD + * $FreeBSD$ + */ + +#ifndef __NLM_HAL_MMIO_H__ +#define __NLM_HAL_MMIO_H__ + +/* + * This file contains platform specific memory mapped IO implementation + * and will provide a way to read 32/64 bit memory mapped registers in + * all ABIs + */ + +/* + * For o32 compilation, we have to disable interrupts and enable KX bit to + * access 64 bit addresses or data. + * + * We need to disable interrupts because we save just the lower 32 bits of + * registers in interrupt handling. So if we get hit by an interrupt while + * using the upper 32 bits of a register, we lose. + */ +static inline uint32_t nlm_save_flags_kx(void) +{ + uint32_t sr = mips_rd_status(); + + mips_wr_status((sr & ~MIPS_SR_INT_IE) | MIPS_SR_KX); + return (sr); +} + +static inline uint32_t nlm_save_flags_cop2(void) +{ + uint32_t sr = mips_rd_status(); + + mips_wr_status((sr & ~MIPS_SR_INT_IE) | MIPS_SR_COP_2_BIT); + return (sr); +} + +static inline void nlm_restore_flags(uint32_t sr) +{ + mips_wr_status(sr); +} + +static inline uint32_t +nlm_load_word(uint64_t addr) +{ + volatile uint32_t *p = (volatile uint32_t *)(long)addr; + + return *p; +} + +static inline void +nlm_store_word(uint64_t addr, uint32_t val) +{ + volatile uint32_t *p = (volatile uint32_t *)(long)addr; + + *p = val; +} + +#if defined(__mips_n64) || defined(__mips_n32) +static inline uint64_t +nlm_load_dword(volatile uint64_t addr) +{ + volatile uint64_t *p = (volatile uint64_t *)(long)addr; + + return *p; +} + +static inline void +nlm_store_dword(volatile uint64_t addr, uint64_t val) +{ + volatile uint64_t *p = (volatile uint64_t *)(long)addr; + + *p = val; +} + +#else /* o32 */ +static inline uint64_t +nlm_load_dword(uint64_t addr) +{ + volatile uint64_t *p = (volatile uint64_t *)(long)addr; + uint32_t valhi, vallo, sr; + + sr = nlm_save_flags_kx(); + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + "ld $8, 0(%2)\n\t" + "dsra32 %0, $8, 0\n\t" + "sll %1, $8, 0\n\t" + ".set pop\n" + : "=r"(valhi), "=r"(vallo) + : "r"(p) + : "$8"); + nlm_restore_flags(sr); + + return ((uint64_t)valhi << 32) | vallo; +} + +static inline void +nlm_store_dword(uint64_t addr, uint64_t val) +{ + volatile uint64_t *p = (volatile uint64_t *)(long)addr; + uint32_t valhi, vallo, sr; + + valhi = val >> 32; + vallo = val & 0xffffffff; + + sr = nlm_save_flags_kx(); + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + "dsll32 $8, %1, 0\n\t" + "dsll32 $9, %2, 0\n\t" /* get rid of the */ + "dsrl32 $9, $9, 0\n\t" /* sign extend */ + "or $9, $9, $8\n\t" + "sd $9, 0(%0)\n\t" + ".set pop\n" + : : "r"(p), "r"(valhi), "r"(vallo) + : "$8", "$9", "memory"); + nlm_restore_flags(sr); +} +#endif + +#if defined(__mips_n64) +static inline uint64_t +nlm_load_word_daddr(uint64_t addr) +{ + volatile uint32_t *p = (volatile uint32_t *)(long)addr; + + return *p; +} + +static inline void +nlm_store_word_daddr(uint64_t addr, uint32_t val) +{ + volatile uint32_t *p = (volatile uint32_t *)(long)addr; + + *p = val; +} + +static inline uint64_t +nlm_load_dword_daddr(uint64_t addr) +{ + volatile uint64_t *p = (volatile uint64_t *)(long)addr; + + return *p; +} + +static inline void +nlm_store_dword_daddr(uint64_t addr, uint64_t val) +{ + volatile uint64_t *p = (volatile uint64_t *)(long)addr; + + *p = val; +} + +#elif defined(__mips_n32) + +static inline uint64_t +nlm_load_word_daddr(uint64_t addr) +{ + uint32_t val; + + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + "lw %0, 0(%1)\n\t" + ".set pop\n" + : "=r"(val) + : "r"(addr)); + + return val; +} + +static inline void +nlm_store_word_daddr(uint64_t addr, uint32_t val) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + "sw %0, 0(%1)\n\t" + ".set pop\n" + : : "r"(val), "r"(addr) + : "memory"); +} + +static inline uint64_t +nlm_load_dword_daddr(uint64_t addr) +{ + uint64_t val; + + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + "ld %0, 0(%1)\n\t" + ".set pop\n" + : "=r"(val) + : "r"(addr)); + return val; +} + +static inline void +nlm_store_dword_daddr(uint64_t addr, uint64_t val) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + "sd %0, 0(%1)\n\t" + ".set pop\n" + : : "r"(val), "r"(addr) + : "memory"); +} + +#else /* o32 */ +static inline uint64_t +nlm_load_word_daddr(uint64_t addr) +{ + uint32_t val, addrhi, addrlo, sr; + + addrhi = addr >> 32; + addrlo = addr & 0xffffffff; + + sr = nlm_save_flags_kx(); + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + "dsll32 $8, %1, 0\n\t" + "dsll32 $9, %2, 0\n\t" + "dsrl32 $9, $9, 0\n\t" + "or $9, $9, $8\n\t" + "lw %0, 0($9)\n\t" + ".set pop\n" + : "=r"(val) + : "r"(addrhi), "r"(addrlo) + : "$8", "$9"); + nlm_restore_flags(sr); + + return val; + +} + +static inline void +nlm_store_word_daddr(uint64_t addr, uint32_t val) +{ + uint32_t addrhi, addrlo, sr; + + addrhi = addr >> 32; + addrlo = addr & 0xffffffff; + + sr = nlm_save_flags_kx(); + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + "dsll32 $8, %1, 0\n\t" + "dsll32 $9, %2, 0\n\t" + "dsrl32 $9, $9, 0\n\t" + "or $9, $9, $8\n\t" + "sw %0, 0($9)\n\t" + ".set pop\n" + : : "r"(val), "r"(addrhi), "r"(addrlo) + : "$8", "$9", "memory"); + nlm_restore_flags(sr); +} + +static inline uint64_t +nlm_load_dword_daddr(uint64_t addr) +{ + uint32_t addrh, addrl, sr; + uint32_t valh, vall; + + addrh = addr >> 32; + addrl = addr & 0xffffffff; + + sr = nlm_save_flags_kx(); + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + "dsll32 $8, %2, 0\n\t" + "dsll32 $9, %3, 0\n\t" + "dsrl32 $9, $9, 0\n\t" + "or $9, $9, $8\n\t" + "ld $8, 0($9)\n\t" + "dsra32 %0, $8, 0\n\t" + "sll %1, $8, 0\n\t" + ".set pop\n" + : "=r"(valh), "=r"(vall) + : "r"(addrh), "r"(addrl) + : "$8", "$9"); + nlm_restore_flags(sr); + + return ((uint64_t)valh << 32) | vall; +} + +static inline void +nlm_store_dword_daddr(uint64_t addr, uint64_t val) +{ + uint32_t addrh, addrl, sr; + uint32_t valh, vall; + + addrh = addr >> 32; + addrl = addr & 0xffffffff; + valh = val >> 32; + vall = val & 0xffffffff; + + sr = nlm_save_flags_kx(); + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + "dsll32 $8, %2, 0\n\t" + "dsll32 $9, %3, 0\n\t" + "dsrl32 $9, $9, 0\n\t" + "or $9, $9, $8\n\t" + "dsll32 $8, %0, 0\n\t" + "dsll32 $10, %1, 0\n\t" + "dsrl32 $10, $10, 0\n\t" + "or $8, $8, $10\n\t" + "sd $8, 0($9)\n\t" + ".set pop\n" + : : "r"(valh), "r"(vall), "r"(addrh), "r"(addrl) + : "$8", "$9", "memory"); + nlm_restore_flags(sr); +} +#endif /* __mips_n64 */ + +static inline uint32_t +nlm_read_reg(uint64_t base, uint32_t reg) +{ + volatile uint32_t *addr = (volatile uint32_t *)(long)base + reg; + + return *addr; +} + +static inline void +nlm_write_reg(uint64_t base, uint32_t reg, uint32_t val) +{ + volatile uint32_t *addr = (volatile uint32_t *)(long)base + reg; + + *addr = val; +} + +static inline uint64_t +nlm_read_reg64(uint64_t base, uint32_t reg) +{ + uint64_t addr = base + (reg >> 1) * sizeof(uint64_t); + + return nlm_load_dword(addr); +} + +static inline void +nlm_write_reg64(uint64_t base, uint32_t reg, uint64_t val) +{ + uint64_t addr = base + (reg >> 1) * sizeof(uint64_t); + + return nlm_store_dword(addr, val); +} + +/* + * Routines to store 32/64 bit values to 64 bit addresses, + * used when going thru XKPHYS to access registers + */ +static inline uint32_t +nlm_read_reg_xkphys(uint64_t base, uint32_t reg) +{ + uint64_t addr = base + reg * sizeof(uint32_t); + + return nlm_load_word_daddr(addr); +} + +static inline void +nlm_write_reg_xkphys(uint64_t base, uint32_t reg, uint32_t val) +{ + uint64_t addr = base + reg * sizeof(uint32_t); + return nlm_store_word_daddr(addr, val); +} + +static inline uint64_t +nlm_read_reg64_xkphys(uint64_t base, uint32_t reg) +{ + uint64_t addr = base + (reg >> 1) * sizeof(uint64_t); + + return nlm_load_dword_daddr(addr); +} + +static inline void +nlm_write_reg64_xkphys(uint64_t base, uint32_t reg, uint64_t val) +{ + uint64_t addr = base + (reg >> 1) * sizeof(uint64_t); + + return nlm_store_dword_daddr(addr, val); +} + +/* Location where IO base is mapped */ +extern uint64_t xlp_io_base; + +static inline uint64_t +nlm_pcicfg_base(uint32_t devoffset) +{ + return xlp_io_base + devoffset; +} + +static inline uint64_t +nlm_xkphys_map_pcibar0(uint64_t pcibase) +{ + uint64_t paddr; + + paddr = nlm_read_reg(pcibase, 0x4) & ~0xfu; + return (uint64_t)0x9000000000000000 | paddr; +} + +#endif diff --git a/sys/mips/nlm/hal/iomap.h b/sys/mips/nlm/hal/iomap.h index e11dcdde0fb57..9f4a52c0a5161 100644 --- a/sys/mips/nlm/hal/iomap.h +++ b/sys/mips/nlm/hal/iomap.h @@ -25,82 +25,75 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ - -#ifndef __NLM_IOMAP_H__ -#define __NLM_IOMAP_H__ - -/** -* @file_name xlpiomap.h -* @author Netlogic Microsystems -* @brief Basic definitions Netlogic XLP IO BASEs -*/ - -/* ---------------------------------- - * XLP RESET Physical Address Map - * ---------------------------------- - * PCI ECFG : 0x18000000 - 0x1bffffff - * PCI CFG : 0x1c000000 - 0x1cffffff - * FLASH : 0x1fc00000 - 0x1fffffff - * ---------------------------------- */ +#ifndef __NLM_HAL_IOMAP_H__ +#define __NLM_HAL_IOMAP_H__ + #define XLP_DEFAULT_IO_BASE 0x18000000 -#define XLP_DEFAULT_IO_BASE_KSEG1 0xb8000000 -#define XLP_IO_SIZE (64 << 20) /* Size of the ECFG Space */ +#define NMI_BASE 0xbfc00000 +#define XLP_IO_CLK 133333333 + +#define XLP_PCIE_CFG_SIZE 0x1000 /* 4K */ +#define XLP_PCIE_DEV_BLK_SIZE (8 * XLP_PCIE_CFG_SIZE) +#define XLP_PCIE_BUS_BLK_SIZE (256 * XLP_PCIE_DEV_BLK_SIZE) +#define XLP_IO_SIZE (64 << 20) /* ECFG space size */ #define XLP_IO_PCI_HDRSZ 0x100 #define XLP_IO_DEV(node, dev) ((dev) + (node) * 8) #define XLP_HDR_OFFSET(node, bus, dev, fn) (((bus) << 20) | \ ((XLP_IO_DEV(node, dev)) << 15) | ((fn) << 12)) -#define XLP_IO_BRIDGE_OFFSET(node) XLP_HDR_OFFSET(node,0,0,0) +#define XLP_IO_BRIDGE_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 0) /* coherent inter chip */ -#define XLP_IO_CIC0_OFFSET(node) XLP_HDR_OFFSET(node,0,0,1) -#define XLP_IO_CIC1_OFFSET(node) XLP_HDR_OFFSET(node,0,0,2) -#define XLP_IO_CIC2_OFFSET(node) XLP_HDR_OFFSET(node,0,0,3) -#define XLP_IO_PIC_OFFSET(node) XLP_HDR_OFFSET(node,0,0,4) +#define XLP_IO_CIC0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 1) +#define XLP_IO_CIC1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 2) +#define XLP_IO_CIC2_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 3) +#define XLP_IO_PIC_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 4) -#define XLP_IO_PCIE_OFFSET(node,i) XLP_HDR_OFFSET(node,0,1,i) -#define XLP_IO_PCIE0_OFFSET(node) XLP_HDR_OFFSET(node,0,1,0) -#define XLP_IO_PCIE1_OFFSET(node) XLP_HDR_OFFSET(node,0,1,1) -#define XLP_IO_PCIE2_OFFSET(node) XLP_HDR_OFFSET(node,0,1,2) -#define XLP_IO_PCIE3_OFFSET(node) XLP_HDR_OFFSET(node,0,1,3) +#define XLP_IO_PCIE_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 1, i) +#define XLP_IO_PCIE0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 1, 0) +#define XLP_IO_PCIE1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 1, 1) +#define XLP_IO_PCIE2_OFFSET(node) XLP_HDR_OFFSET(node, 0, 1, 2) +#define XLP_IO_PCIE3_OFFSET(node) XLP_HDR_OFFSET(node, 0, 1, 3) -#define XLP_IO_USB_OFFSET(node, i) XLP_HDR_OFFSET(node,0,2,i) -#define XLP_IO_USB_EHCI0_OFFSET(node) XLP_HDR_OFFSET(node,0,2,0) -#define XLP_IO_USB_OHCI0_OFFSET(node) XLP_HDR_OFFSET(node,0,2,1) -#define XLP_IO_USB_OHCI1_OFFSET(node) XLP_HDR_OFFSET(node,0,2,2) -#define XLP_IO_USB_EHCI1_OFFSET(node) XLP_HDR_OFFSET(node,0,2,3) -#define XLP_IO_USB_OHCI2_OFFSET(node) XLP_HDR_OFFSET(node,0,2,4) -#define XLP_IO_USB_OHCI3_OFFSET(node) XLP_HDR_OFFSET(node,0,2,5) +#define XLP_IO_USB_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 2, i) +#define XLP_IO_USB_EHCI0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 0) +#define XLP_IO_USB_OHCI0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 1) +#define XLP_IO_USB_OHCI1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 2) +#define XLP_IO_USB_EHCI1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 3) +#define XLP_IO_USB_OHCI2_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 4) +#define XLP_IO_USB_OHCI3_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 5) -#define XLP_IO_NAE_OFFSET(node) XLP_HDR_OFFSET(node,0,3,0) -#define XLP_IO_POE_OFFSET(node) XLP_HDR_OFFSET(node,0,3,1) +#define XLP_IO_NAE_OFFSET(node) XLP_HDR_OFFSET(node, 0, 3, 0) +#define XLP_IO_POE_OFFSET(node) XLP_HDR_OFFSET(node, 0, 3, 1) -#define XLP_IO_CMS_OFFSET(node) XLP_HDR_OFFSET(node,0,4,0) +#define XLP_IO_CMS_OFFSET(node) XLP_HDR_OFFSET(node, 0, 4, 0) -#define XLP_IO_DMA_OFFSET(node) XLP_HDR_OFFSET(node,0,5,1) -#define XLP_IO_SEC_OFFSET(node) XLP_HDR_OFFSET(node,0,5,2) -#define XLP_IO_CMP_OFFSET(node) XLP_HDR_OFFSET(node,0,5,3) +#define XLP_IO_DMA_OFFSET(node) XLP_HDR_OFFSET(node, 0, 5, 1) +#define XLP_IO_SEC_OFFSET(node) XLP_HDR_OFFSET(node, 0, 5, 2) +#define XLP_IO_CMP_OFFSET(node) XLP_HDR_OFFSET(node, 0, 5, 3) -#define XLP_IO_UART_OFFSET(node, i) XLP_HDR_OFFSET(node,0,6,i) -#define XLP_IO_UART0_OFFSET(node) XLP_HDR_OFFSET(node,0,6,0) -#define XLP_IO_UART1_OFFSET(node) XLP_HDR_OFFSET(node,0,6,1) -#define XLP_IO_I2C_OFFSET(node, i) XLP_HDR_OFFSET(node,0,6,2+i) -#define XLP_IO_I2C0_OFFSET(node) XLP_HDR_OFFSET(node,0,6,2) -#define XLP_IO_I2C1_OFFSET(node) XLP_HDR_OFFSET(node,0,6,3) -#define XLP_IO_GPIO_OFFSET(node) XLP_HDR_OFFSET(node,0,6,4) +#define XLP_IO_UART_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 6, i) +#define XLP_IO_UART0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 0) +#define XLP_IO_UART1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 1) +#define XLP_IO_I2C_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 6, 2 + i) +#define XLP_IO_I2C0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 2) +#define XLP_IO_I2C1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 3) +#define XLP_IO_GPIO_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 4) /* system management */ -#define XLP_IO_SYS_OFFSET(node) XLP_HDR_OFFSET(node,0,6,5) -#define XLP_IO_JTAG_OFFSET(node) XLP_HDR_OFFSET(node,0,6,6) +#define XLP_IO_SYS_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 5) +#define XLP_IO_JTAG_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 6) -#define XLP_IO_NOR_OFFSET(node) XLP_HDR_OFFSET(node,0,7,0) -#define XLP_IO_NAND_OFFSET(node) XLP_HDR_OFFSET(node,0,7,1) -#define XLP_IO_SPI_OFFSET(node) XLP_HDR_OFFSET(node,0,7,2) +#define XLP_IO_NOR_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 0) +#define XLP_IO_NAND_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 1) +#define XLP_IO_SPI_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 2) /* SD flash */ -#define XLP_IO_SD_OFFSET(node) XLP_HDR_OFFSET(node,0,7,3) -#define XLP_IO_MMC_OFFSET(node, slot) ((XLP_IO_SD_OFFSET(node))+(slot*0x100)+XLP_IO_PCI_HDRSZ) +#define XLP_IO_SD_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 3) +#define XLP_IO_MMC_OFFSET(node, slot) \ + ((XLP_IO_SD_OFFSET(node))+(slot*0x100)+XLP_IO_PCI_HDRSZ) + /* PCI config header register id's */ #define XLP_PCI_CFGREG0 0x00 #define XLP_PCI_CFGREG1 0x01 @@ -125,113 +118,35 @@ #define XLP_PCI_UCODEINFO_REG 0x3e #define XLP_PCI_SBB_WT_REG 0x3f -#if !defined(LOCORE) && !defined(__ASSEMBLY__) - -#ifndef __NLM_NLMIO_H__ -#error iomap.h needs mmio.h to be included -#endif - -static __inline__ uint32_t -nlm_read_reg_kseg(uint64_t base, uint32_t reg) -{ - volatile uint32_t *addr = (volatile uint32_t *)(intptr_t)base + reg; - - return (*addr); -} - -static __inline__ void -nlm_write_reg_kseg(uint64_t base, uint32_t reg, uint32_t val) -{ - volatile uint32_t *addr = (volatile uint32_t *)(intptr_t)base + reg; - - *addr = val; -} - -static __inline__ uint64_t -nlm_read_reg64_kseg(uint64_t base, uint32_t reg) -{ - volatile uint64_t *addr = (volatile uint64_t *)(intptr_t)base + (reg >> 1); - - return (nlm_load_dword(addr)); -} - -static __inline__ void -nlm_write_reg64_kseg(uint64_t base, uint32_t reg, uint64_t val) -{ - volatile uint64_t *addr = (volatile uint64_t *)(intptr_t)base + (reg >> 1); +/* PCI IDs for SoC device */ +#define PCI_VENDOR_NETLOGIC 0x184e - return (nlm_store_dword(addr, val)); -} - -/* - * Routines to store 32/64 bit values to 64 bit addresses, - * used when going thru XKPHYS to access registers - */ -static __inline__ uint32_t -nlm_read_reg_xkseg(uint64_t base, uint32_t reg) -{ - uint64_t addr = base + reg * sizeof(uint32_t); - - return (nlm_load_word_daddr(addr)); -} - -static __inline__ void -nlm_write_reg_xkseg(uint64_t base, uint32_t reg, uint32_t val) -{ - uint64_t addr = base + reg * sizeof(uint32_t); - - return (nlm_store_word_daddr(addr, val)); -} - -static __inline__ uint64_t -nlm_read_reg64_xkseg(uint64_t base, uint32_t reg) -{ - uint64_t addr = base + (reg >> 1) * sizeof(uint64_t); - - return (nlm_load_dword_daddr(addr)); -} - -static __inline__ void -nlm_write_reg64_xkseg(uint64_t base, uint32_t reg, uint64_t val) -{ - uint64_t addr = base + (reg >> 1) * sizeof(uint64_t); - - return (nlm_store_dword_daddr(addr, val)); -} - -/* Location where IO base is mapped */ -extern uint64_t nlm_pcicfg_baseaddr; - -static __inline__ uint64_t -nlm_pcicfg_base(uint32_t devoffset) -{ - return (nlm_pcicfg_baseaddr + devoffset); -} - -static __inline__ uint64_t -nlm_pcibar0_base_xkphys(uint64_t pcibase) -{ - uint64_t paddr; - - paddr = nlm_read_reg_kseg(pcibase, XLP_PCI_CFGREG4) & ~0xfu; - return (0x9000000000000000 | paddr); -} -#define nlm_pci_rdreg(b, r) nlm_read_reg_kseg(b, r) -#define nlm_pci_wreg(b, r, v) nlm_write_reg_kseg(b, r, v) - -#endif /* !LOCORE && !__ASSEMBLY__*/ +#define PCI_DEVICE_ID_NLM_ROOT 0x1001 +#define PCI_DEVICE_ID_NLM_ICI 0x1002 +#define PCI_DEVICE_ID_NLM_PIC 0x1003 +#define PCI_DEVICE_ID_NLM_PCIE 0x1004 +#define PCI_DEVICE_ID_NLM_EHCI 0x1007 +#define PCI_DEVICE_ID_NLM_ILK 0x1008 +#define PCI_DEVICE_ID_NLM_NAE 0x1009 +#define PCI_DEVICE_ID_NLM_POE 0x100A +#define PCI_DEVICE_ID_NLM_FMN 0x100B +#define PCI_DEVICE_ID_NLM_RAID 0x100D +#define PCI_DEVICE_ID_NLM_SAE 0x100D +#define PCI_DEVICE_ID_NLM_RSA 0x100E +#define PCI_DEVICE_ID_NLM_CMP 0x100F +#define PCI_DEVICE_ID_NLM_UART 0x1010 +#define PCI_DEVICE_ID_NLM_I2C 0x1011 +#define PCI_DEVICE_ID_NLM_NOR 0x1015 +#define PCI_DEVICE_ID_NLM_NAND 0x1016 +#define PCI_DEVICE_ID_NLM_MMC 0x1018 +#if !defined(LOCORE) && !defined(__ASSEMBLY__) -/* COMPAT stuff - TODO remove */ -#define bit_set(p, m) ((p) |= (m)) -#define bit_clear(p, m) ((p) &= ~(m)) -#define bit_get(p,m) ((p) & (m)) -#define BIT(x) (0x01 << (x)) +#define nlm_read_pci_reg(b, r) nlm_read_reg(b, r) +#define nlm_write_pci_reg(b, r, v) nlm_write_reg(b, r, v) -#define XLP_MAX_NODES 4 -#define XLP_MAX_CORES 8 -#define XLP_MAX_THREADS 4 -#define XLP_CACHELINE_SIZE 64 -#define XLP_NUM_NODES 1 /* we support only one now */ +extern uint64_t xlp_sys_base; +extern uint64_t xlp_pic_base; +#endif /* !LOCORE or !__ASSEMBLY */ -#endif +#endif /* __NLM_HAL_IOMAP_H__ */ diff --git a/sys/mips/nlm/hal/mips-extns.h b/sys/mips/nlm/hal/mips-extns.h index 7851b1b18632a..839aa7313b08a 100644 --- a/sys/mips/nlm/hal/mips-extns.h +++ b/sys/mips/nlm/hal/mips-extns.h @@ -25,8 +25,9 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ #ifndef __NLM_MIPS_EXTNS_H__ #define __NLM_MIPS_EXTNS_H__ @@ -91,110 +92,183 @@ static __inline__ uint64_t nlm_swapd(int32_t *loc, uint64_t val) } #endif +/* + * Atomic increment a unsigned int + */ +static __inline unsigned int +nlm_ldaddwu(unsigned int value, unsigned int *addr) +{ + __asm__ __volatile__( + ".set push\n" + ".set noreorder\n" + "move $8, %2\n" + "move $9, %3\n" + ".word 0x71280011\n" /* ldaddwu $8, $9 */ + "move %0, $8\n" + ".set pop\n" + : "=&r"(value), "+m"(*addr) + : "0"(value), "r" ((unsigned long)addr) + : "$8", "$9"); + + return (value); +} +/* + * 32 bit read write for c0 + */ +#define read_c0_register32(reg, sel) \ +({ \ + uint32_t __rv; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips32\n\t" \ + "mfc0 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : "=r" (__rv) : "i" (reg), "i" (sel) ); \ + __rv; \ + }) + +#define write_c0_register32(reg, sel, value) \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips32\n\t" \ + "mtc0 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : : "r" (value), "i" (reg), "i" (sel) ); + #if defined(__mips_n64) || defined(__mips_n32) -static __inline uint64_t -nlm_mfcr(uint32_t reg) +/* + * On 64 bit compilation, the operations are simple + */ +#define read_c0_register64(reg, sel) \ +({ \ + uint64_t __rv; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips64\n\t" \ + "dmfc0 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : "=r" (__rv) : "i" (reg), "i" (sel) ); \ + __rv; \ + }) + +#define write_c0_register64(reg, sel, value) \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips64\n\t" \ + "dmtc0 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : : "r" (value), "i" (reg), "i" (sel) ); +#else /* ! (defined(__mips_n64) || defined(__mips_n32)) */ + +/* + * 32 bit compilation, 64 bit values has to split + */ +#define read_c0_register64(reg, sel) \ +({ \ + uint32_t __high, __low; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + ".set mips64\n\t" \ + "dmfc0 $8, $%2, %3\n\t" \ + "dsra32 %0, $8, 0\n\t" \ + "sll %1, $8, 0\n\t" \ + ".set pop\n" \ + : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel) \ + : "$8"); \ + ((uint64_t)__high << 32) | __low; \ +}) + +#define write_c0_register64(reg, sel, value) \ +do { \ + uint32_t __high = value >> 32; \ + uint32_t __low = value & 0xffffffff; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + ".set mips64\n\t" \ + "dsll32 $8, %1, 0\n\t" \ + "dsll32 $9, %0, 0\n\t" \ + "dsrl32 $8, $8, 0\n\t" \ + "or $8, $8, $9\n\t" \ + "dmtc0 $8, $%2, %3\n\t" \ + ".set pop" \ + :: "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ + :"$8", "$9"); \ +} while(0) + +#endif +/* functions to write to and read from the extended + * cp0 registers. + * EIRR : Extended Interrupt Request Register + * cp0 register 9 sel 6 + * bits 0...7 are same as cause register 8...15 + * EIMR : Extended Interrupt Mask Register + * cp0 register 9 sel 7 + * bits 0...7 are same as status register 8...15 + */ +static __inline uint64_t +nlm_read_c0_eirr(void) { - uint64_t res; - __asm__ __volatile__( - ".set push\n\t" - ".set noreorder\n\t" - "move $9, %1\n\t" - ".word 0x71280018\n\t" /* mfcr $8, $9 */ - "move %0, $8\n\t" - ".set pop\n" - : "=r" (res) : "r"(reg) - : "$8", "$9" - ); - return (res); + return (read_c0_register64(9, 6)); } static __inline void -nlm_mtcr(uint32_t reg, uint64_t value) +nlm_write_c0_eirr(uint64_t val) { - __asm__ __volatile__( - ".set push\n\t" - ".set noreorder\n\t" - "move $8, %0\n" - "move $9, %1\n" - ".word 0x71280019\n" /* mtcr $8, $9 */ - ".set pop\n" - : - : "r" (value), "r" (reg) - : "$8", "$9" - ); -} -#else /* !(defined(__mips_n64) || defined(__mips_n32)) */ + write_c0_register64(9, 6, val); +} -static __inline__ uint64_t -nlm_mfcr(uint32_t reg) +static __inline uint64_t +nlm_read_c0_eimr(void) { - uint64_t hi; - uint64_t lo; - __asm__ __volatile__ ( - ".set push\n" - ".set mips64\n" - "move $8, %2\n" - ".word 0x71090018\n" - "nop \n" - "dsra32 %0, $9, 0\n" - "sll %1, $9, 0\n" - ".set pop\n" - : "=r"(hi), "=r"(lo) - : "r"(reg) : "$8", "$9"); + return (read_c0_register64(9, 7)); +} - return (((uint64_t)hi) << 32) | lo; +static __inline void +nlm_write_c0_eimr(uint64_t val) +{ + + write_c0_register64(9, 7, val); } -static __inline__ void -nlm_mtcr(uint32_t reg, uint64_t val) +static __inline__ uint32_t +nlm_read_c0_ebase(void) { - uint32_t hi, lo; - hi = val >> 32; - lo = val & 0xffffffff; - __asm__ __volatile__ ( - ".set push\n" - ".set mips64\n" - "move $9, %0\n" - "dsll32 $9, %1, 0\n" - "dsll32 $8, %0, 0\n" - "dsrl32 $9, $9, 0\n" - "or $9, $9, $8\n" - "move $8, %2\n" - ".word 0x71090019\n" - "nop \n" - ".set pop\n" - ::"r"(hi), "r"(lo), "r"(reg) - : "$8", "$9"); + return (read_c0_register32(15, 1)); } -#endif /* (defined(__mips_n64) || defined(__mips_n32)) */ -/* dcrc2 */ -/* XLP additional instructions */ +static __inline__ int +nlm_nodeid(void) +{ + return (nlm_read_c0_ebase() >> 5) & 0x3; +} -/* - * Atomic increment a unsigned int - */ -static __inline unsigned int -nlm_ldaddwu(unsigned int value, unsigned int *addr) +static __inline__ int +nlm_cpuid(void) { - __asm__ __volatile__( - ".set push\n" - ".set noreorder\n" - "move $8, %2\n" - "move $9, %3\n" - ".word 0x71280011\n" /* ldaddwu $8, $9 */ - "move %0, $8\n" - ".set pop\n" - : "=&r"(value), "+m"(*addr) - : "0"(value), "r" ((unsigned long)addr) - : "$8", "$9"); + return nlm_read_c0_ebase() & 0x1f; +} - return (value); +static __inline__ int +nlm_threadid(void) +{ + return nlm_read_c0_ebase() & 0x3; +} + +static __inline__ int +nlm_coreid(void) +{ + return (nlm_read_c0_ebase() >> 2) & 0x7; } #endif + +#define XLP_MAX_NODES 4 +#define XLP_MAX_CORES 8 +#define XLP_MAX_THREADS 4 + #endif diff --git a/sys/mips/nlm/hal/mmio.h b/sys/mips/nlm/hal/mmio.h deleted file mode 100644 index a19a8673e9e69..0000000000000 --- a/sys/mips/nlm/hal/mmio.h +++ /dev/null @@ -1,338 +0,0 @@ -/*- - * Copyright 2003-2011 Netlogic Microsystems (Netlogic). 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 Netlogic Microsystems ``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 NETLOGIC 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$ - * NETLOGIC_BSD */ - -#ifndef __NLM_NLMIO_H__ -#define __NLM_NLMIO_H__ - -#if !defined(__mips_n32) && !defined(__mips_n64) -/* - * For o32 compilation, we have to disable interrupts and enable KX bit to - * access 64 bit addresses or data. - * - * We need to disable interrupts because we save just the lower 32 bits of - * registers in interrupt handling. So if we get hit by an interrupt while - * using the upper 32 bits of a register, we lose. - */ -static __inline__ uint32_t nlm_enable_kx(void) -{ - uint32_t sr; - - __asm__ __volatile__( - "mfc0 %0, $12 \n\t" /* read status reg */ - "move $8, %0 \n\t" - "ori $8, $8, 0x81 \n\t" /* set KX, and IE */ - "xori $8, $8, 0x1 \n\t" /* flip IE */ - "mtc0 $8, $12 \n\t" /* update status reg */ - : "=r"(sr) - : : "$8"); - - return (sr); -} - -static __inline__ void nlm_restore_kx(uint32_t sr) -{ - __asm__ __volatile__("mtc0 %0, $12" : : "r"(sr)); -} -#endif - -static __inline__ uint32_t -nlm_load_word(volatile uint32_t *addr) -{ - return (*addr); -} - -static __inline__ void -nlm_store_word(volatile uint32_t *addr, uint32_t val) -{ - *addr = val; -} - -#if defined(__mips_n64) || defined(__mips_n32) -static __inline__ uint64_t -nlm_load_dword(volatile uint64_t *addr) -{ - return (*addr); -} - -static __inline__ void -nlm_store_dword(volatile uint64_t *addr, uint64_t val) -{ - *addr = val; -} - -#else /* o32 */ -static __inline__ uint64_t -nlm_load_dword(volatile uint64_t *addr) -{ - uint32_t valhi, vallo, sr; - - sr = nlm_enable_kx(); - __asm__ __volatile__( - ".set push \n\t" - ".set mips64 \n\t" - "ld $8, 0(%2) \n\t" - "dsra32 %0, $8, 0 \n\t" - "sll %1, $8, 0 \n\t" - ".set pop \n" - : "=r"(valhi), "=r"(vallo) - : "r"(addr) - : "$8" ); - nlm_restore_kx(sr); - - return (((uint64_t)valhi << 32) | vallo); -} - -static __inline__ void -nlm_store_dword(volatile uint64_t *addr, uint64_t val) -{ - uint32_t valhi, vallo, sr; - - valhi = val >> 32; - vallo = val & 0xffffffff; - - sr = nlm_enable_kx(); - __asm__ __volatile__( - ".set push \n\t" - ".set mips64 \n\t" - "dsll32 $8, %1, 0 \n\t" - "dsll32 $9, %2, 0 \n\t" /* get rid of the */ - "dsrl32 $9, $9, 0 \n\t" /* sign extend */ - "or $9, $9, $8 \n\t" - "sd $9, 0(%0) \n\t" - ".set pop \n" - : : "r"(addr), "r"(valhi), "r"(vallo) - : "$8", "$9", "memory"); - nlm_restore_kx(sr); -} -#endif - -#if defined(__mips_n64) -static __inline__ uint64_t -nlm_load_word_daddr(uint64_t addr) -{ - volatile uint32_t *p = (volatile uint32_t *)(intptr_t)addr; - - return (*p); -} - -static __inline__ void -nlm_store_word_daddr(uint64_t addr, uint32_t val) -{ - volatile uint32_t *p = (volatile uint32_t *)(intptr_t)addr; - - *p = val; -} - -static __inline__ uint64_t -nlm_load_dword_daddr(uint64_t addr) -{ - volatile uint64_t *p = (volatile uint64_t *)(intptr_t)addr; - - return (*p); -} - -static __inline__ void -nlm_store_dword_daddr(uint64_t addr, uint64_t val) -{ - volatile uint64_t *p = (volatile uint64_t *)(intptr_t)addr; - - *p = val; -} - -#elif defined(__mips_n32) - -static __inline__ uint64_t -nlm_load_word_daddr(uint64_t addr) -{ - uint32_t val; - - __asm__ __volatile__( - ".set push \n\t" - ".set mips64 \n\t" - "lw %0, 0(%1) \n\t" - ".set pop \n" - : "=r"(val) - : "r"(addr)); - - return (val); -} - -static __inline__ void -nlm_store_word_daddr(uint64_t addr, uint32_t val) -{ - __asm__ __volatile__( - ".set push \n\t" - ".set mips64 \n\t" - "sw %0, 0(%1) \n\t" - ".set pop \n" - : : "r"(val), "r"(addr) - : "memory"); -} - -static __inline__ uint64_t -nlm_load_dword_daddr(uint64_t addr) -{ - uint64_t val; - - __asm__ __volatile__( - ".set push \n\t" - ".set mips64 \n\t" - "ld %0, 0(%1) \n\t" - ".set pop \n" - : "=r"(val) - : "r"(addr)); - return (val); -} - -static __inline__ void -nlm_store_dword_daddr(uint64_t addr, uint64_t val) -{ - __asm__ __volatile__( - ".set push \n\t" - ".set mips64 \n\t" - "sd %0, 0(%1) \n\t" - ".set pop \n" - : : "r"(val), "r"(addr) - : "memory"); -} - -#else /* o32 */ -static __inline__ uint64_t -nlm_load_word_daddr(uint64_t addr) -{ - uint32_t val, addrhi, addrlo, sr; - - addrhi = addr >> 32; - addrlo = addr & 0xffffffff; - - sr = nlm_enable_kx(); - __asm__ __volatile__( - ".set push \n\t" - ".set mips64 \n\t" - "dsll32 $8, %1, 0 \n\t" - "dsll32 $9, %2, 0 \n\t" /* get rid of the */ - "dsrl32 $9, $9, 0 \n\t" /* sign extend */ - "or $9, $9, $8 \n\t" - "lw %0, 0($9) \n\t" - ".set pop \n" - : "=r"(val) - : "r"(addrhi), "r"(addrlo) - : "$8", "$9"); - nlm_restore_kx(sr); - - return (val); - -} - -static __inline__ void -nlm_store_word_daddr(uint64_t addr, uint32_t val) -{ - uint32_t addrhi, addrlo, sr; - - addrhi = addr >> 32; - addrlo = addr & 0xffffffff; - - sr = nlm_enable_kx(); - __asm__ __volatile__( - ".set push \n\t" - ".set mips64 \n\t" - "dsll32 $8, %1, 0 \n\t" - "dsll32 $9, %2, 0 \n\t" /* get rid of the */ - "dsrl32 $9, $9, 0 \n\t" /* sign extend */ - "or $9, $9, $8 \n\t" - "sw %0, 0($9) \n\t" - ".set pop \n" - :: "r"(val), "r"(addrhi), "r"(addrlo) - : "$8", "$9", "memory"); - nlm_restore_kx(sr); -} - -static __inline__ uint64_t -nlm_load_dword_daddr(uint64_t addr) -{ - uint32_t addrh, addrl, sr; - uint32_t valh, vall; - - addrh = addr >> 32; - addrl = addr & 0xffffffff; - - sr = nlm_enable_kx(); - __asm__ __volatile__( - ".set push \n\t" - ".set mips64 \n\t" - "dsll32 $8, %2, 0 \n\t" - "dsll32 $9, %3, 0 \n\t" /* get rid of the */ - "dsrl32 $9, $9, 0 \n\t" /* sign extend */ - "or $9, $9, $8 \n\t" - "ld $8, 0($9) \n\t" - "dsra32 %0, $8, 0 \n\t" - "sll %1, $8, 0 \n\t" - ".set pop \n" - : "=r"(valh), "=r"(vall) - : "r"(addrh), "r"(addrl) - : "$8", "$9"); - nlm_restore_kx(sr); - - return (((uint64_t)valh << 32) | vall); -} - -static __inline__ void -nlm_store_dword_daddr(uint64_t addr, uint64_t val) -{ - uint32_t addrh, addrl, sr; - uint32_t valh, vall; - - addrh = addr >> 32; - addrl = addr & 0xffffffff; - valh = val >> 32; - vall = val & 0xffffffff; - - sr = nlm_enable_kx(); - __asm__ __volatile__( - ".set push \n\t" - ".set mips64 \n\t" - "dsll32 $8, %2, 0 \n\t" - "dsll32 $9, %3, 0 \n\t" /* get rid of the */ - "dsrl32 $9, $9, 0 \n\t" /* sign extend */ - "or $9, $9, $8 \n\t" - "dsll32 $8, %0, 0 \n\t" - "dsll32 $10, %1, 0 \n\t" /* get rid of the */ - "dsrl32 $10, $10, 0 \n\t" /* sign extend */ - "or $8, $8, $10 \n\t" - "sd $8, 0($9) \n\t" - ".set pop \n" - : : "r"(valh), "r"(vall), "r"(addrh), "r"(addrl) - : "$8", "$9", "memory"); - nlm_restore_kx(sr); -} - -#endif /* __mips_n64 */ - -#endif diff --git a/sys/mips/nlm/hal/mmu.h b/sys/mips/nlm/hal/mmu.h index a620727531987..ebb4b5d67033e 100644 --- a/sys/mips/nlm/hal/mmu.h +++ b/sys/mips/nlm/hal/mmu.h @@ -25,44 +25,66 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ #ifndef __XLP_MMU_H__ #define __XLP_MMU_H__ -#include <mips/nlm/hal/cop0.h> #include <mips/nlm/hal/mips-extns.h> -#define XLP_MMU_SETUP_REG 0x400 -#define XLP_MMU_LFSRSEED_REG 0x401 -#define XLP_MMU_HPW_NUM_PAGE_LVL_REG 0x410 -#define XLP_MMU_PGWKR_PGDBASE_REG 0x411 -#define XLP_MMU_PGWKR_PGDSHFT_REG 0x412 -#define XLP_MMU_PGWKR_PGDMASK_REG 0x413 -#define XLP_MMU_PGWKR_PUDSHFT_REG 0x414 -#define XLP_MMU_PGWKR_PUDMASK_REG 0x415 -#define XLP_MMU_PGWKR_PMDSHFT_REG 0x416 -#define XLP_MMU_PGWKR_PMDMASK_REG 0x417 -#define XLP_MMU_PGWKR_PTESHFT_REG 0x418 -#define XLP_MMU_PGWKR_PTEMASK_REG 0x419 +static __inline__ uint32_t +nlm_read_c0_config6(void) +{ + uint32_t rv; + + __asm__ __volatile__ ( + ".set push\n" + ".set mips64\n" + "mfc0 %0, $16, 6\n" + ".set pop\n" + : "=r" (rv)); + + return rv; +} -typedef struct hw_pagewalker { - int pgd_present; - int pud_present; - int pmd_present; - int pte_present; - uint64_t pgd_baseaddr; - uint32_t pgd_shift; - uint32_t pgd_mask; - uint32_t pud_shift; - uint32_t pud_mask; - uint32_t pmd_shift; - uint32_t pmd_mask; - uint32_t pte_shift; - uint32_t pte_mask; -} nlm_pagewalker; +static __inline__ void +nlm_write_c0_config6(uint32_t value) +{ + __asm__ __volatile__ ( + ".set push\n" + ".set mips64\n" + "mtc0 %0, $16, 6\n" + ".set pop\n" + : : "r" (value)); +} + +static __inline__ uint32_t +nlm_read_c0_config7(void) +{ + uint32_t rv; + __asm__ __volatile__ ( + ".set push\n" + ".set mips64\n" + "mfc0 %0, $16, 7\n" + ".set pop\n" + : "=r" (rv)); + + return rv; +} + +static __inline__ void +nlm_write_c0_config7(uint32_t value) +{ + __asm__ __volatile__ ( + ".set push\n" + ".set mips64\n" + "mtc0 %0, $16, 7\n" + ".set pop\n" + : : "r" (value)); +} /** * On power on reset, XLP comes up with 64 TLBs. * Large-variable-tlb's (ELVT) and extended TLB is disabled. @@ -101,7 +123,7 @@ static __inline__ void nlm_large_variable_tlb_en (int en) /* en = 1 to enable * en = 0 to disable */ -static __inline__ void nlm_pagewalker_en (int en) +static __inline__ void nlm_pagewalker_en(int en) { unsigned int val; @@ -114,7 +136,7 @@ static __inline__ void nlm_pagewalker_en (int en) /* en = 1 to enable * en = 0 to disable */ -static __inline__ void nlm_extended_tlb_en (int en) +static __inline__ void nlm_extended_tlb_en(int en) { unsigned int val; @@ -135,70 +157,9 @@ static __inline__ int nlm_get_num_vtlbs(void) return (((nlm_read_c0_config6() >> 6) & 0x3ff) + 1); } -static __inline__ void nlm_setup_extended_pagemask (int mask) +static __inline__ void nlm_setup_extended_pagemask(int mask) { nlm_write_c0_config7(mask); } -/* hashindex_en = 1 to enable hash mode, hashindex_en=0 to disable - * global_mode = 1 to enable global mode, global_mode=0 to disable - * clk_gating = 0 to enable clock gating, clk_gating=1 to disable - */ -static __inline__ void nlm_mmu_setup(int hashindex_en, int global_mode, - int clk_gating) -{ - /*uint32_t mmusetup = nlm_mfcr(XLP_MMU_SETUP_REG);*/ - - uint32_t mmusetup = 0; - mmusetup |= (hashindex_en << 13); - mmusetup |= (clk_gating << 3); - mmusetup |= (global_mode << 0); - nlm_mtcr(XLP_MMU_SETUP_REG, mmusetup); -} - -static __inline__ void nlm_mmu_lfsr_seed (int thr0_seed, int thr1_seed, - int thr2_seed, int thr3_seed) -{ - uint32_t seed = nlm_mfcr(XLP_MMU_LFSRSEED_REG); - seed |= ((thr3_seed & 0x7f) << 23); - seed |= ((thr2_seed & 0x7f) << 16); - seed |= ((thr1_seed & 0x7f) << 7); - seed |= ((thr0_seed & 0x7f) << 0); - nlm_mtcr(XLP_MMU_LFSRSEED_REG, seed); -} - -static __inline__ void nlm_pagewalker_setup (nlm_pagewalker *walker) -{ - uint64_t val; - - if (!walker->pgd_present) - return; - - val = nlm_mfcr(XLP_MMU_HPW_NUM_PAGE_LVL_REG); - - if (walker->pgd_present) - val |= (1 << 3); - - if (walker->pud_present) - val |= (1 << 2); - - if (walker->pmd_present) - val |= (1 << 1); - - if (walker->pte_present) - val |= (1 << 0); - - nlm_mtcr(XLP_MMU_HPW_NUM_PAGE_LVL_REG, val); - - nlm_mtcr(XLP_MMU_PGWKR_PGDBASE_REG, walker->pgd_baseaddr); - nlm_mtcr(XLP_MMU_PGWKR_PGDSHFT_REG, walker->pgd_shift); - nlm_mtcr(XLP_MMU_PGWKR_PGDMASK_REG, walker->pgd_mask); - nlm_mtcr(XLP_MMU_PGWKR_PUDSHFT_REG, walker->pud_shift); - nlm_mtcr(XLP_MMU_PGWKR_PUDMASK_REG, walker->pud_mask); - nlm_mtcr(XLP_MMU_PGWKR_PMDSHFT_REG, walker->pmd_shift); - nlm_mtcr(XLP_MMU_PGWKR_PMDMASK_REG, walker->pmd_mask); - nlm_mtcr(XLP_MMU_PGWKR_PTESHFT_REG, walker->pte_shift); - nlm_mtcr(XLP_MMU_PGWKR_PTEMASK_REG, walker->pte_mask); -} - #endif diff --git a/sys/mips/nlm/hal/pcibus.h b/sys/mips/nlm/hal/pcibus.h new file mode 100644 index 0000000000000..6275ff19faad5 --- /dev/null +++ b/sys/mips/nlm/hal/pcibus.h @@ -0,0 +1,89 @@ +/*- + * Copyright 2003-2011 Netlogic Microsystems (Netlogic). 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 Netlogic Microsystems ``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 NETLOGIC 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. + * + * NETLOGIC_BSD + * $FreeBSD$ + */ + +#ifndef __XLP_PCIBUS_H__ +#define __XLP_PCIBUS_H__ + +#define MSI_MIPS_ADDR_BASE 0xfee00000 +/* MSI support */ +#define MSI_MIPS_ADDR_DEST 0x000ff000 +#define MSI_MIPS_ADDR_RH 0x00000008 +#define MSI_MIPS_ADDR_RH_OFF 0x00000000 +#define MSI_MIPS_ADDR_RH_ON 0x00000008 +#define MSI_MIPS_ADDR_DM 0x00000004 +#define MSI_MIPS_ADDR_DM_PHYSICAL 0x00000000 +#define MSI_MIPS_ADDR_DM_LOGICAL 0x00000004 + +/* Fields in data for Intel MSI messages. */ +#define MSI_MIPS_DATA_TRGRMOD 0x00008000 /* Trigger mode */ +#define MSI_MIPS_DATA_TRGREDG 0x00000000 /* edge */ +#define MSI_MIPS_DATA_TRGRLVL 0x00008000 /* level */ + +#define MSI_MIPS_DATA_LEVEL 0x00004000 /* Polarity. */ +#define MSI_MIPS_DATA_DEASSERT 0x00000000 +#define MSI_MIPS_DATA_ASSERT 0x00004000 + +#define MSI_MIPS_DATA_DELMOD 0x00000700 /* Delivery Mode */ +#define MSI_MIPS_DATA_DELFIXED 0x00000000 /* fixed */ +#define MSI_MIPS_DATA_DELLOPRI 0x00000100 /* lowest priority */ + +#define MSI_MIPS_DATA_INTVEC 0x000000ff + +/* + * Build Intel MSI message and data values from a source. AMD64 systems + * seem to be compatible, so we use the same function for both. + */ +#define MIPS_MSI_ADDR(cpu) \ + (MSI_MIPS_ADDR_BASE | (cpu) << 12 | \ + MSI_MIPS_ADDR_RH_OFF | MSI_MIPS_ADDR_DM_PHYSICAL) + +#define MIPS_MSI_DATA(irq) \ + (MSI_MIPS_DATA_TRGRLVL | MSI_MIPS_DATA_DELFIXED | \ + MSI_MIPS_DATA_ASSERT | (irq)) + +#define PCIE_BRIDGE_CMD 0x1 +#define PCIE_BRIDGE_MSI_CAP 0x14 +#define PCIE_BRIDGE_MSI_ADDRL 0x15 +#define PCIE_BRIDGE_MSI_ADDRH 0x16 +#define PCIE_BRIDGE_MSI_DATA 0x17 + +/* XLP Global PCIE configuration space registers */ +#define PCIE_MSI_STATUS 0x25A +#define PCIE_MSI_EN 0x25B +#define PCIE_INT_EN0 0x261 + +/* PCIE_MSI_EN */ +#define PCIE_MSI_VECTOR_INT_EN 0xFFFFFFFF + +/* PCIE_INT_EN0 */ +#define PCIE_MSI_INT_EN (1 << 9) + +#endif /* __XLP_PCIBUS_H__ */ diff --git a/sys/mips/nlm/hal/pic.h b/sys/mips/nlm/hal/pic.h index 842a367babfd5..efc676e069c79 100644 --- a/sys/mips/nlm/hal/pic.h +++ b/sys/mips/nlm/hal/pic.h @@ -25,403 +25,356 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ -#ifndef __XLP_PIC_H__ -#define __XLP_PIC_H__ +#ifndef _NLM_HAL_PIC_H +#define _NLM_HAL_PIC_H /* PIC Specific registers */ -#define XLP_PIC_CTRL_REG 0x40 -#define XLP_PIC_BYTESWAP_REG 0x42 -#define XLP_PIC_STATUS_REG 0x44 -#define XLP_PIC_INTR_TIMEOUT 0x46 -#define XLP_PIC_ICI0_INTR_TIMEOUT 0x48 -#define XLP_PIC_ICI1_INTR_TIMEOUT 0x4a -#define XLP_PIC_ICI2_INTR_TIMEOUT 0x4c -#define XLP_PIC_IPI_CTRL_REG 0x4e -#define XLP_PIC_INT_ACK_REG 0x50 -#define XLP_PIC_INT_PENDING0_REG 0x52 -#define XLP_PIC_INT_PENDING1_REG 0x54 -#define XLP_PIC_INT_PENDING2_REG 0x56 +#define PIC_CTRL 0x00 -#define XLP_PIC_WDOG0_MAXVAL_REG 0x58 -#define XLP_PIC_WDOG0_COUNT_REG 0x5a -#define XLP_PIC_WDOG0_ENABLE0_REG 0x5c -#define XLP_PIC_WDOG0_ENABLE1_REG 0x5e -#define XLP_PIC_WDOG0_BEATCMD_REG 0x60 -#define XLP_PIC_WDOG0_BEAT0_REG 0x62 -#define XLP_PIC_WDOG0_BEAT1_REG 0x64 +/* PIC control register defines */ +#define PIC_CTRL_ITV 32 /* interrupt timeout value */ +#define PIC_CTRL_ICI 19 /* ICI interrupt timeout enable */ +#define PIC_CTRL_ITE 18 /* interrupt timeout enable */ +#define PIC_CTRL_STE 10 /* system timer interrupt enable */ +#define PIC_CTRL_WWR1 8 /* watchdog 1 wraparound count for reset */ +#define PIC_CTRL_WWR0 6 /* watchdog 0 wraparound count for reset */ +#define PIC_CTRL_WWN1 4 /* watchdog 1 wraparound count for NMI */ +#define PIC_CTRL_WWN0 2 /* watchdog 0 wraparound count for NMI */ +#define PIC_CTRL_WTE 0 /* watchdog timer enable */ -#define XLP_PIC_WDOG1_MAXVAL_REG 0x66 -#define XLP_PIC_WDOG1_COUNT_REG 0x68 -#define XLP_PIC_WDOG1_ENABLE0_REG 0x6a -#define XLP_PIC_WDOG1_ENABLE1_REG 0x6c -#define XLP_PIC_WDOG1_BEATCMD_REG 0x6e -#define XLP_PIC_WDOG1_BEAT0_REG 0x70 -#define XLP_PIC_WDOG1_BEAT1_REG 0x72 +/* PIC Status register defines */ +#define PIC_ICI_STATUS 33 /* ICI interrupt timeout status */ +#define PIC_ITE_STATUS 32 /* interrupt timeout status */ +#define PIC_STS_STATUS 4 /* System timer interrupt status */ +#define PIC_WNS_STATUS 2 /* NMI status for watchdog timers */ +#define PIC_WIS_STATUS 0 /* Interrupt status for watchdog timers */ -#define XLP_PIC_WDOG_MAXVAL_REG(i) (XLP_PIC_WDOG0_MAXVAL_REG + ((i) ? 7 : 0)) -#define XLP_PIC_WDOG_COUNT_REG(i) (XLP_PIC_WDOG0_COUNT_REG + ((i) ? 7 : 0)) -#define XLP_PIC_WDOG_ENABLE0_REG(i) (XLP_PIC_WDOG0_ENABLE0_REG + ((i) ? 7 : 0)) -#define XLP_PIC_WDOG_ENABLE1_REG(i) (XLP_PIC_WDOG0_ENABLE1_REG + ((i) ? 7 : 0)) -#define XLP_PIC_WDOG_BEATCMD_REG(i) (XLP_PIC_WDOG0_BEATCMD_REG + ((i) ? 7 : 0)) -#define XLP_PIC_WDOG_BEAT0_REG(i) (XLP_PIC_WDOG0_BEAT0_REG + ((i) ? 7 : 0)) -#define XLP_PIC_WDOG_BEAT1_REG(i) (XLP_PIC_WDOG0_BEAT1_REG + ((i) ? 7 : 0)) +/* PIC IPI control register offsets */ +#define PIC_IPICTRL_NMI 32 +#define PIC_IPICTRL_RIV 20 /* received interrupt vector */ +#define PIC_IPICTRL_IDB 16 /* interrupt destination base */ +#define PIC_IPICTRL_DTE 0 /* interrupt destination thread enables */ -#define XLP_PIC_SYSTIMER0_MAXVAL_REG 0x74 -#define XLP_PIC_SYSTIMER1_MAXVAL_REG 0x76 -#define XLP_PIC_SYSTIMER2_MAXVAL_REG 0x78 -#define XLP_PIC_SYSTIMER3_MAXVAL_REG 0x7a -#define XLP_PIC_SYSTIMER4_MAXVAL_REG 0x7c -#define XLP_PIC_SYSTIMER5_MAXVAL_REG 0x7e -#define XLP_PIC_SYSTIMER6_MAXVAL_REG 0x80 -#define XLP_PIC_SYSTIMER7_MAXVAL_REG 0x82 -#define XLP_PIC_SYSTIMER_MAXVAL_REG(i) (XLP_PIC_SYSTIMER0_MAXVAL_REG + ((i)*2)) +/* PIC IRT register offsets */ +#define PIC_IRT_ENABLE 31 +#define PIC_IRT_NMI 29 +#define PIC_IRT_SCH 28 /* Scheduling scheme */ +#define PIC_IRT_RVEC 20 /* Interrupt receive vectors */ +#define PIC_IRT_DT 19 /* Destination type */ +#define PIC_IRT_DB 16 /* Destination base */ +#define PIC_IRT_DTE 0 /* Destination thread enables */ -#define XLP_PIC_SYSTIMER0_COUNT_REG 0x84 -#define XLP_PIC_SYSTIMER1_COUNT_REG 0x86 -#define XLP_PIC_SYSTIMER2_COUNT_REG 0x88 -#define XLP_PIC_SYSTIMER3_COUNT_REG 0x8a -#define XLP_PIC_SYSTIMER4_COUNT_REG 0x8c -#define XLP_PIC_SYSTIMER5_COUNT_REG 0x8e -#define XLP_PIC_SYSTIMER6_COUNT_REG 0x90 -#define XLP_PIC_SYSTIMER7_COUNT_REG 0x92 -#define XLP_PIC_SYSTIMER_COUNT_REG(i) (XLP_PIC_SYSTIMER0_COUNT_REG + ((i)*2)) +#define PIC_BYTESWAP 0x02 +#define PIC_STATUS 0x04 +#define PIC_INTR_TIMEOUT 0x06 +#define PIC_ICI0_INTR_TIMEOUT 0x08 +#define PIC_ICI1_INTR_TIMEOUT 0x0a +#define PIC_ICI2_INTR_TIMEOUT 0x0c +#define PIC_IPI_CTL 0x0e +#define PIC_INT_ACK 0x10 +#define PIC_INT_PENDING0 0x12 +#define PIC_INT_PENDING1 0x14 +#define PIC_INT_PENDING2 0x16 -#define XLP_PIC_ITE0_N0_N1_REG 0x94 -#define XLP_PIC_ITE1_N0_N1_REG 0x98 -#define XLP_PIC_ITE2_N0_N1_REG 0x9c -#define XLP_PIC_ITE3_N0_N1_REG 0xa0 -#define XLP_PIC_ITE4_N0_N1_REG 0xa4 -#define XLP_PIC_ITE5_N0_N1_REG 0xa8 -#define XLP_PIC_ITE6_N0_N1_REG 0xac -#define XLP_PIC_ITE7_N0_N1_REG 0xb0 -#define XLP_PIC_ITE_N0_N1_REG(i) (XLP_PIC_ITE0_N0_N1_REG + ((i)*4)) +#define PIC_WDOG0_MAXVAL 0x18 +#define PIC_WDOG0_COUNT 0x1a +#define PIC_WDOG0_ENABLE0 0x1c +#define PIC_WDOG0_ENABLE1 0x1e +#define PIC_WDOG0_BEATCMD 0x20 +#define PIC_WDOG0_BEAT0 0x22 +#define PIC_WDOG0_BEAT1 0x24 -#define XLP_PIC_ITE0_N2_N3_REG 0x96 -#define XLP_PIC_ITE1_N2_N3_REG 0x9a -#define XLP_PIC_ITE2_N2_N3_REG 0x9e -#define XLP_PIC_ITE3_N2_N3_REG 0xa2 -#define XLP_PIC_ITE4_N2_N3_REG 0xa6 -#define XLP_PIC_ITE5_N2_N3_REG 0xaa -#define XLP_PIC_ITE6_N2_N3_REG 0xae -#define XLP_PIC_ITE7_N2_N3_REG 0xb2 -#define XLP_PIC_ITE_N2_N3_REG(i) (XLP_PIC_ITE0_N2_N3_REG + ((i)*4)) +#define PIC_WDOG1_MAXVAL 0x26 +#define PIC_WDOG1_COUNT 0x28 +#define PIC_WDOG1_ENABLE0 0x2a +#define PIC_WDOG1_ENABLE1 0x2c +#define PIC_WDOG1_BEATCMD 0x2e +#define PIC_WDOG1_BEAT0 0x30 +#define PIC_WDOG1_BEAT1 0x32 -#define XLP_PIC_IRT0_REG 0xb4 -#define XLP_PIC_IRT_REG(i) (XLP_PIC_IRT0_REG + ((i)*2)) +#define PIC_WDOG_MAXVAL(i) (PIC_WDOG0_MAXVAL + ((i) ? 7 : 0)) +#define PIC_WDOG_COUNT(i) (PIC_WDOG0_COUNT + ((i) ? 7 : 0)) +#define PIC_WDOG_ENABLE0(i) (PIC_WDOG0_ENABLE0 + ((i) ? 7 : 0)) +#define PIC_WDOG_ENABLE1(i) (PIC_WDOG0_ENABLE1 + ((i) ? 7 : 0)) +#define PIC_WDOG_BEATCMD(i) (PIC_WDOG0_BEATCMD + ((i) ? 7 : 0)) +#define PIC_WDOG_BEAT0(i) (PIC_WDOG0_BEAT0 + ((i) ? 7 : 0)) +#define PIC_WDOG_BEAT1(i) (PIC_WDOG0_BEAT1 + ((i) ? 7 : 0)) -/* PIC IRT indices */ +#define PIC_TIMER0_MAXVAL 0x34 +#define PIC_TIMER1_MAXVAL 0x36 +#define PIC_TIMER2_MAXVAL 0x38 +#define PIC_TIMER3_MAXVAL 0x3a +#define PIC_TIMER4_MAXVAL 0x3c +#define PIC_TIMER5_MAXVAL 0x3e +#define PIC_TIMER6_MAXVAL 0x40 +#define PIC_TIMER7_MAXVAL 0x42 +#define PIC_TIMER_MAXVAL(i) (PIC_TIMER0_MAXVAL + ((i) * 2)) -#define XLP_PIC_IRT_WD0_INDEX 0 -#define XLP_PIC_IRT_WD1_INDEX 1 -#define XLP_PIC_IRT_WD_NMI0_INDEX 2 -#define XLP_PIC_IRT_WD_NMI1_INDEX 3 -#define XLP_PIC_IRT_TIMER0_INDEX 4 -#define XLP_PIC_IRT_TIMER1_INDEX 5 -#define XLP_PIC_IRT_TIMER2_INDEX 6 -#define XLP_PIC_IRT_TIMER3_INDEX 7 -#define XLP_PIC_IRT_TIMER4_INDEX 8 -#define XLP_PIC_IRT_TIMER5_INDEX 9 -#define XLP_PIC_IRT_TIMER6_INDEX 10 -#define XLP_PIC_IRT_TIMER7_INDEX 11 -#define XLP_PIC_IRT_TIMER_INDEX(i) (XLP_PIC_IRT_TIMER0_INDEX + (i)) +#define PIC_TIMER0_COUNT 0x44 +#define PIC_TIMER1_COUNT 0x46 +#define PIC_TIMER2_COUNT 0x48 +#define PIC_TIMER3_COUNT 0x4a +#define PIC_TIMER4_COUNT 0x4c +#define PIC_TIMER5_COUNT 0x4e +#define PIC_TIMER6_COUNT 0x50 +#define PIC_TIMER7_COUNT 0x52 +#define PIC_TIMER_COUNT(i) (PIC_TIMER0_COUNT + ((i) * 2)) -#define XLP_PIC_IRT_MSGQ0_INDEX 12 -#define XLP_PIC_IRT_MSGQ_INDEX(i) (XLP_PIC_IRT_MSGQ0_INDEX + (i)) -/* 12 to 43 */ -#define XLP_PIC_IRT_MSG0_INDEX 44 -#define XLP_PIC_IRT_MSG1_INDEX 45 +#define PIC_ITE0_N0_N1 0x54 +#define PIC_ITE1_N0_N1 0x58 +#define PIC_ITE2_N0_N1 0x5c +#define PIC_ITE3_N0_N1 0x60 +#define PIC_ITE4_N0_N1 0x64 +#define PIC_ITE5_N0_N1 0x68 +#define PIC_ITE6_N0_N1 0x6c +#define PIC_ITE7_N0_N1 0x70 +#define PIC_ITE_N0_N1(i) (PIC_ITE0_N0_N1 + ((i) * 4)) + +#define PIC_ITE0_N2_N3 0x56 +#define PIC_ITE1_N2_N3 0x5a +#define PIC_ITE2_N2_N3 0x5e +#define PIC_ITE3_N2_N3 0x62 +#define PIC_ITE4_N2_N3 0x66 +#define PIC_ITE5_N2_N3 0x6a +#define PIC_ITE6_N2_N3 0x6e +#define PIC_ITE7_N2_N3 0x72 +#define PIC_ITE_N2_N3(i) (PIC_ITE0_N2_N3 + ((i) * 4)) -#define XLP_PIC_IRT_PCIE_MSIX0_INDEX 46 -#define XLP_PIC_IRT_PCIE_MSIX_INDEX(i) (XLP_PIC_IRT_PCIE_MSIX0_INDEX + (i)) +#define PIC_IRT0 0x74 +#define PIC_IRT(i) (PIC_IRT0 + ((i) * 2)) + +#define TIMER_CYCLES_MAXVAL 0xffffffffffffffffULL + +/* + * IRT Map + */ +#define PIC_NUM_IRTS 160 + +#define PIC_IRT_WD_0_INDEX 0 +#define PIC_IRT_WD_1_INDEX 1 +#define PIC_IRT_WD_NMI_0_INDEX 2 +#define PIC_IRT_WD_NMI_1_INDEX 3 +#define PIC_IRT_TIMER_0_INDEX 4 +#define PIC_IRT_TIMER_1_INDEX 5 +#define PIC_IRT_TIMER_2_INDEX 6 +#define PIC_IRT_TIMER_3_INDEX 7 +#define PIC_IRT_TIMER_4_INDEX 8 +#define PIC_IRT_TIMER_5_INDEX 9 +#define PIC_IRT_TIMER_6_INDEX 10 +#define PIC_IRT_TIMER_7_INDEX 11 +#define PIC_IRT_CLOCK_INDEX PIC_IRT_TIMER_7_INDEX +#define PIC_IRT_TIMER_INDEX(num) ((num) + PIC_IRT_TIMER_0_INDEX) + + +/* 11 and 12 */ +#define PIC_NUM_MSG_Q_IRTS 32 +#define PIC_IRT_MSG_Q0_INDEX 12 +#define PIC_IRT_MSG_Q_INDEX(qid) ((qid) + PIC_IRT_MSG_Q0_INDEX) +/* 12 to 43 */ +#define PIC_IRT_MSG_0_INDEX 44 +#define PIC_IRT_MSG_1_INDEX 45 +/* 44 and 45 */ +#define PIC_NUM_PCIE_MSIX_IRTS 32 +#define PIC_IRT_PCIE_MSIX_0_INDEX 46 +#define PIC_IRT_PCIE_MSIX_INDEX(num) ((num) + PIC_IRT_PCIE_MSIX_0_INDEX) /* 46 to 77 */ -#define XLP_PIC_IRT_PCIE_LINK0_INDEX 78 -#define XLP_PIC_IRT_PCIE_LINK1_INDEX 79 -#define XLP_PIC_IRT_PCIE_LINK2_INDEX 80 -#define XLP_PIC_IRT_PCIE_LINK3_INDEX 81 -#define XLP_PIC_IRT_PCIE_LINK_INDEX(i) (XLP_PIC_IRT_PCIE_LINK0_INDEX + (i)) +#define PIC_NUM_PCIE_LINK_IRTS 4 +#define PIC_IRT_PCIE_LINK_0_INDEX 78 +#define PIC_IRT_PCIE_LINK_1_INDEX 79 +#define PIC_IRT_PCIE_LINK_2_INDEX 80 +#define PIC_IRT_PCIE_LINK_3_INDEX 81 +#define PIC_IRT_PCIE_LINK_INDEX(num) ((num) + PIC_IRT_PCIE_LINK_0_INDEX) /* 78 to 81 */ -#define XLP_PIC_IRT_NA0_INDEX 82 -#define XLP_PIC_IRT_NA_INDEX(i) (XLP_PIC_IRT_NA0_INDEX + (i)) +#define PIC_NUM_NA_IRTS 32 /* 82 to 113 */ -#define XLP_PIC_IRT_POE_INDEX 114 -#define XLP_PIC_IRT_USB0_INDEX 115 -#define XLP_PIC_IRT_EHCI0_INDEX 115 -#define XLP_PIC_IRT_EHCI1_INDEX 118 -#define XLP_PIC_IRT_USB_INDEX(i) (XLP_PIC_IRT_USB0_INDEX + (i)) +#define PIC_IRT_NA_0_INDEX 82 +#define PIC_IRT_NA_INDEX(num) ((num) + PIC_IRT_NA_0_INDEX) +#define PIC_IRT_POE_INDEX 114 + +#define PIC_NUM_USB_IRTS 6 +#define PIC_IRT_USB_0_INDEX 115 +#define PIC_IRT_EHCI_0_INDEX 115 +#define PIC_IRT_EHCI_1_INDEX 118 +#define PIC_IRT_USB_INDEX(num) ((num) + PIC_IRT_USB_0_INDEX) /* 115 to 120 */ -#define XLP_PIC_IRT_GDX_INDEX 121 -#define XLP_PIC_IRT_SEC_INDEX 122 -#define XLP_PIC_IRT_RSA_INDEX 123 -#define XLP_PIC_IRT_COMP0_INDEX 124 -#define XLP_PIC_IRT_COMP_INDEX(i) (XLP_PIC_IRT_COMP0_INDEX + (i)) +#define PIC_IRT_GDX_INDEX 121 +#define PIC_IRT_SEC_INDEX 122 +#define PIC_IRT_RSA_INDEX 123 + +#define PIC_NUM_COMP_IRTS 4 +#define PIC_IRT_COMP_0_INDEX 124 +#define PIC_IRT_COMP_INDEX(num) ((num) + PIC_IRT_COMP_0_INDEX) /* 124 to 127 */ -#define XLP_PIC_IRT_GBU_INDEX 128 -/* coherent inter chip */ -#define XLP_PIC_IRT_CIC0_INDEX 129 -#define XLP_PIC_IRT_CIC1_INDEX 130 -#define XLP_PIC_IRT_CIC2_INDEX 131 -#define XLP_PIC_IRT_CAM_INDEX 132 -#define XLP_PIC_IRT_UART0_INDEX 133 -#define XLP_PIC_IRT_UART1_INDEX 134 -#define XLP_PIC_IRT_I2C0_INDEX 135 -#define XLP_PIC_IRT_I2C1_INDEX 136 -#define XLP_PIC_IRT_SYS0_INDEX 137 -#define XLP_PIC_IRT_SYS1_INDEX 138 -#define XLP_PIC_IRT_JTAG_INDEX 139 -#define XLP_PIC_IRT_PIC_INDEX 140 -#define XLP_PIC_IRT_NBU_INDEX 141 -#define XLP_PIC_IRT_TCU_INDEX 142 -/* global coherency */ -#define XLP_PIC_IRT_GCU_INDEX 143 -#define XLP_PIC_IRT_DMC0_INDEX 144 -#define XLP_PIC_IRT_DMC1_INDEX 145 -#define XLP_PIC_IRT_GPIO0_INDEX 146 -#define XLP_PIC_IRT_GPIO_INDEX(i) (XLP_PIC_IRT_GPIO0_INDEX + (i)) -/* 146 to 149 */ -#define XLP_PIC_IRT_NOR_INDEX 150 -#define XLP_PIC_IRT_NAND_INDEX 151 -#define XLP_PIC_IRT_SPI_INDEX 152 -#define XLP_PIC_IRT_MMC_INDEX 153 +#define PIC_IRT_GBU_INDEX 128 +#define PIC_IRT_ICC_0_INDEX 129 /* ICC - Inter Chip Coherency */ +#define PIC_IRT_ICC_1_INDEX 130 +#define PIC_IRT_ICC_2_INDEX 131 +#define PIC_IRT_CAM_INDEX 132 +#define PIC_IRT_UART_0_INDEX 133 +#define PIC_IRT_UART_1_INDEX 134 +#define PIC_IRT_I2C_0_INDEX 135 +#define PIC_IRT_I2C_1_INDEX 136 +#define PIC_IRT_SYS_0_INDEX 137 +#define PIC_IRT_SYS_1_INDEX 138 +#define PIC_IRT_JTAG_INDEX 139 +#define PIC_IRT_PIC_INDEX 140 +#define PIC_IRT_NBU_INDEX 141 +#define PIC_IRT_TCU_INDEX 142 +#define PIC_IRT_GCU_INDEX 143 /* GBC - Global Coherency */ +#define PIC_IRT_DMC_0_INDEX 144 +#define PIC_IRT_DMC_1_INDEX 145 -/* PIC control register defines */ -#define XLP_PIC_ITV_OFFSET 32 /* interrupt timeout value */ -#define XLP_PIC_ICI_OFFSET 19 /* ICI interrupt timeout enable */ -#define XLP_PIC_ITE_OFFSET 18 /* interrupt timeout enable */ -#define XLP_PIC_STE_OFFSET 10 /* system timer interrupt enable */ -#define XLP_PIC_WWR1_OFFSET 8 /* watchdog timer 1 wraparound count for reset */ -#define XLP_PIC_WWR0_OFFSET 6 /* watchdog timer 0 wraparound count for reset */ -#define XLP_PIC_WWN1_OFFSET 4 /* watchdog timer 1 wraparound count for NMI */ -#define XLP_PIC_WWN0_OFFSET 2 /* watchdog timer 0 wraparound count for NMI */ -#define XLP_PIC_WTE_OFFSET 0 /* watchdog timer enable */ +#define PIC_NUM_GPIO_IRTS 4 +#define PIC_IRT_GPIO_0_INDEX 146 +#define PIC_IRT_GPIO_INDEX(num) ((num) + PIC_IRT_GPIO_0_INDEX) -/* PIC Status register defines */ -#define XLP_PIC_ICI_STATUS_OFFSET 33 /* ICI interrupt timeout interrupt status */ -#define XLP_PIC_ITE_STATUS_OFFSET 32 /* interrupt timeout interrupt status */ -#define XLP_PIC_STS_STATUS_OFFSET 4 /* System timer interrupt status */ -#define XLP_PIC_WNS_STATUS_OFFSET 2 /* NMI interrupt status for watchdog timers */ -#define XLP_PIC_WIS_STATUS_OFFSET 0 /* Interrupt status for watchdog timers */ +/* 146 to 149 */ +#define PIC_IRT_NOR_INDEX 150 +#define PIC_IRT_NAND_INDEX 151 +#define PIC_IRT_SPI_INDEX 152 +#define PIC_IRT_MMC_INDEX 153 -/* PIC IPI control register offsets */ -#define XLP_PIC_IPICTRL_NMI_OFFSET 32 -#define XLP_PIC_IPICTRL_RIV_OFFSET 20 /* received interrupt vector */ -#define XLP_PIC_IPICTRL_IDB_OFFSET 16 /* interrupt destination base */ -#define XLP_PIC_IPICTRL_DTE_OFFSET 16 /* interrupt destination thread enables */ +#define PIC_CLOCK_TIMER 7 +#define PIC_IRQ_BASE 8 -/* PIC IRT register offsets */ -#define XLP_PIC_IRT_ENABLE_OFFSET 31 -#define XLP_PIC_IRT_NMI_OFFSET 29 -#define XLP_PIC_IRT_SCH_OFFSET 28 /* Scheduling scheme */ -#define XLP_PIC_IRT_RVEC_OFFSET 20 /* Interrupt receive vectors */ -#define XLP_PIC_IRT_DT_OFFSET 19 /* Destination type */ -#define XLP_PIC_IRT_DB_OFFSET 16 /* Destination base */ -#define XLP_PIC_IRT_DTE_OFFSET 0 /* Destination thread enables */ +#if !defined(LOCORE) && !defined(__ASSEMBLY__) -#define XLP_PIC_MAX_IRQ 64 -#define XLP_PIC_MAX_IRT 160 -#define XLP_PIC_TIMER_FREQ 133000000 +#define PIC_IRT_FIRST_IRQ (PIC_IRQ_BASE) +#define PIC_IRT_LAST_IRQ 63 +#define PIC_IRQ_IS_IRT(irq) ((irq) >= PIC_IRT_FIRST_IRQ) -#if !defined(LOCORE) && !defined(__ASSEMBLY__) +/* + * Misc + */ +#define PIC_IRT_VALID 1 +#define PIC_LOCAL_SCHEDULING 1 +#define PIC_GLOBAL_SCHEDULING 0 -#define nlm_rdreg_pic(b, r) nlm_read_reg64_kseg(b,r) -#define nlm_wreg_pic(b, r, v) nlm_write_reg64_kseg(b,r,v) -#define nlm_pcibase_pic(node) nlm_pcicfg_base(XLP_IO_PIC_OFFSET(node)) -#define nlm_regbase_pic(node) nlm_pcibase_pic(node) +#define nlm_read_pic_reg(b, r) nlm_read_reg64(b, r) +#define nlm_write_pic_reg(b, r, v) nlm_write_reg64(b, r, v) +#define nlm_get_pic_pcibase(node) nlm_pcicfg_base(XLP_IO_PIC_OFFSET(node)) +#define nlm_get_pic_regbase(node) (nlm_get_pic_pcibase(node) + XLP_IO_PCI_HDRSZ) /* IRT and h/w interrupt routines */ -static __inline__ int -nlm_pic_get_numirts(uint64_t pcibase) +static inline int +nlm_pic_read_irt(uint64_t base, int irt_index) { - return (nlm_pci_rdreg(pcibase, XLP_PCI_IRTINFO_REG) >> 16); + return nlm_read_pic_reg(base, PIC_IRT(irt_index)); } -static __inline__ int -nlm_pic_get_startirt(uint64_t base) +static inline void +nlm_pic_send_ipi(uint64_t base, int cpu, int vec, int nmi) { - return (nlm_pci_rdreg(base, XLP_PCI_IRTINFO_REG) & 0xff); -} + uint64_t ipi; + int node, ncpu; + node = cpu / 32; + ncpu = cpu & 0x1f; + ipi = ((uint64_t)nmi << 31) | (vec << 20) | (node << 17) | + (1 << (cpu & 0xf)); + if (ncpu > 15) + ipi |= 0x10000; /* Setting bit 16 to select cpus 16-31 */ -static __inline__ int -nlm_pic_read_irt(uint64_t base, int irt_index) -{ - return nlm_rdreg_pic(base, XLP_PIC_IRT_REG(irt_index)); + nlm_write_pic_reg(base, PIC_IPI_CTL, ipi); } -/* IRT's can be written into in two modes - * ITE mode - Here the destination of the interrupt is one of the - * eight interrupt-thread-enable groups, allowing the interrupt - * to be distributed to any thread on any node - * ID mode - In ID mode, the IRT has the DB and DTE fields. - * DB[18:17] hold the node select and DB[16], if set to 0 selects - * cpu-cores 0-3, and if set to 1 selects cpu-cores 4-7. - * The DTE[15:0] field is a thread mask, allowing the PIC to broadcast - * the interrupt to 1-16 threads selectable from that mask - */ - -static __inline__ void -nlm_pic_write_irt_raw(uint64_t base, int irt_index, int en, int nmi, int sch, - int vec, int dt, int db, int dte) +static inline uint64_t +nlm_pic_read_control(uint64_t base) { - uint64_t val = - (((en & 0x1) << XLP_PIC_IRT_ENABLE_OFFSET) | - ((nmi & 0x1) << XLP_PIC_IRT_NMI_OFFSET) | - ((sch & 0x1) << XLP_PIC_IRT_SCH_OFFSET) | - ((vec & 0x3f) << XLP_PIC_IRT_RVEC_OFFSET) | - ((dt & 0x1 ) << XLP_PIC_IRT_DT_OFFSET) | - ((db & 0x7) << XLP_PIC_IRT_DB_OFFSET) | - (dte & 0xffff)); - nlm_wreg_pic(base, XLP_PIC_IRT_REG(irt_index), val); + return nlm_read_pic_reg(base, PIC_CTRL); } -/* write IRT in ID mode */ -static __inline__ void -nlm_pic_write_irt_id(uint64_t base, int irt_index, int en, int nmi, int vec, - int node, int cpugroup, uint32_t cpu_mask) +static inline void +nlm_pic_write_control(uint64_t base, uint64_t control) { - nlm_pic_write_irt_raw(base, irt_index, en, nmi, 1, vec, 1, - (node << 1) | cpugroup , cpu_mask); + nlm_write_pic_reg(base, PIC_CTRL, control); } -/* write IRT in ITE mode */ -static __inline__ void -nlm_pic_write_ite(uint64_t base, int ite, uint32_t node0_thrmask, - uint32_t node1_thrmask, uint32_t node2_thrmask, uint32_t node3_thrmask) +static inline void +nlm_pic_update_control(uint64_t base, uint64_t control) { - uint64_t tm10 = ((uint64_t)node1_thrmask << 32) | node0_thrmask; - uint64_t tm32 = ((uint64_t)node1_thrmask << 32) | node0_thrmask; + uint64_t val; - /* Enable the ITE register for all nodes */ - nlm_wreg_pic(base, XLP_PIC_ITE_N0_N1_REG(ite), tm10); - nlm_wreg_pic(base, XLP_PIC_ITE_N2_N3_REG(ite), tm32); + val = nlm_read_pic_reg(base, PIC_CTRL); + nlm_write_pic_reg(base, PIC_CTRL, control | val); } -static __inline__ void -nlm_pic_write_irt_ite(uint64_t base, int irt_index, int ite, int en, int nmi, - int sch, int vec) +static inline void +nlm_pic_ack(uint64_t base, int irt_num) { - nlm_pic_write_irt_raw(base, irt_index, en, nmi, sch, vec, 0, ite, 0); -} + nlm_write_pic_reg(base, PIC_INT_ACK, irt_num); -/* Goto PIC on that node, and ack the interrupt */ -static __inline__ void nlm_pic_ack(uint64_t src_base, int irt) -{ - nlm_wreg_pic(src_base, XLP_PIC_INT_ACK_REG, irt); - /* ack in the status registers for watchdog and system timers */ - if (irt < 12) - nlm_wreg_pic(src_base, XLP_PIC_STATUS_REG, (1 << irt)); + /* Ack the Status register for Watchdog & System timers */ + if (irt_num < 12) + nlm_write_pic_reg(base, PIC_STATUS, (1 << irt_num)); } -/* IPI routines */ - -static __inline__ void -nlm_pic_send_ipi(uint64_t local_base, int target_node, int vcpu, int vec, int nmi) +static inline void +nlm_set_irt_to_cpu(uint64_t base, int irt, int cpu) { - uint64_t ipi = - (((uint64_t)nmi << XLP_PIC_IPICTRL_NMI_OFFSET) | - (vec << XLP_PIC_IPICTRL_RIV_OFFSET) | - (target_node << 17) | - (1 << (vcpu & 0xf))); - if (vcpu > 15) - ipi |= 0x10000; /* set bit 16 to select cpus 16-31 */ + uint64_t val; - nlm_wreg_pic(local_base, XLP_PIC_IPI_CTRL_REG, ipi); + val = nlm_read_pic_reg(base, PIC_IRT(irt)); + val |= cpu & 0xf; + if (cpu > 15) + val |= 1 << 16; + nlm_write_pic_reg(base, PIC_IRT(irt), val); } -/* System Timer routines -- broadcasts systemtimer to 16 vcpus defined in cpu_mask */ - -static __inline__ void -nlm_pic_set_systimer(uint64_t base, int timer, uint64_t value, int irq, int node, - int cpugroup, uint32_t cpumask) +static inline void +nlm_pic_write_irt(uint64_t base, int irt_num, int en, int nmi, + int sch, int vec, int dt, int db, int dte) { - uint64_t pic_ctrl = nlm_rdreg_pic(base, XLP_PIC_CTRL_REG); - int en; + uint64_t val; - en = (cpumask != 0); - nlm_wreg_pic(base, XLP_PIC_SYSTIMER_MAXVAL_REG(timer), value); - nlm_pic_write_irt_id(base, XLP_PIC_IRT_TIMER_INDEX(timer), - en, 0, irq, node, cpugroup, cpumask); + val = (((uint64_t)en & 0x1) << 31) | ((nmi & 0x1) << 29) | + ((sch & 0x1) << 28) | ((vec & 0x3f) << 20) | + ((dt & 0x1) << 19) | ((db & 0x7) << 16) | + (dte & 0xffff); - /* enable the timer */ - pic_ctrl |= (1 << (XLP_PIC_STE_OFFSET+timer)); - nlm_wreg_pic(base, XLP_PIC_CTRL_REG, pic_ctrl); + nlm_write_pic_reg(base, PIC_IRT(irt_num), val); } -static __inline__ uint64_t -nlm_pic_read_systimer(uint64_t base, int timer) +static inline void +nlm_pic_write_irt_direct(uint64_t base, int irt_num, int en, int nmi, + int sch, int vec, int cpu) { - return nlm_rdreg_pic(base, XLP_PIC_SYSTIMER_COUNT_REG(timer)); + nlm_pic_write_irt(base, irt_num, en, nmi, sch, vec, 1, + (cpu >> 4), /* thread group */ + 1 << (cpu & 0xf)); /* thread mask */ } -/* Watchdog timer routines */ - -/* node - XLP node - * timer - watchdog timer. valid values are 0 and 1 - * wrap_around_count - defines the number of times the watchdog timer can wrap-around - * after which the reset / NMI gets generated to the threads defined in thread-enable-masks. - * value - the vatchdog timer max value, upto which the timer will count down - */ - -static __inline__ void -nlm_pic_set_wdogtimer(uint64_t base, int timer, int wrap_around_count, int nmi, - uint32_t node0_thrmask, uint32_t node1_thrmask, - uint32_t node2_thrmask, uint32_t node3_thrmask, uint64_t value) +static inline uint64_t +nlm_pic_read_timer(uint64_t base, int timer) { - uint64_t pic_ctrl = nlm_rdreg_pic(base, XLP_PIC_CTRL_REG); - uint64_t mask0, mask1; - - if (timer > 1 || wrap_around_count > 3) - return; - - /* enable watchdog timer interrupt */ - pic_ctrl |= (((1 << timer) & 0xf)); - - if (timer) { - if (nmi) - pic_ctrl |= (wrap_around_count << XLP_PIC_WWN1_OFFSET); - else - pic_ctrl |= (wrap_around_count << XLP_PIC_WWN0_OFFSET); - } else { - if (nmi) - pic_ctrl |= (wrap_around_count << XLP_PIC_WWR1_OFFSET); - else - pic_ctrl |= (wrap_around_count << XLP_PIC_WWR0_OFFSET); - } - - mask0 = ((unsigned long long)node1_thrmask << 32) | node0_thrmask; - mask1 = ((unsigned long long)node3_thrmask << 32) | node2_thrmask; - - nlm_wreg_pic(base, XLP_PIC_WDOG_MAXVAL_REG(timer), value); - - nlm_wreg_pic(base, XLP_PIC_WDOG_ENABLE0_REG(timer), mask0); - nlm_wreg_pic(base, XLP_PIC_WDOG_ENABLE1_REG(timer), mask1); + return nlm_read_pic_reg(base, PIC_TIMER_COUNT(timer)); +} - nlm_wreg_pic(base, XLP_PIC_CTRL_REG, pic_ctrl); +static inline void +nlm_pic_write_timer(uint64_t base, int timer, uint64_t value) +{ + nlm_write_pic_reg(base, PIC_TIMER_COUNT(timer), value); } -/* watchdog's need to be "stroked" by heartbeats from vcpus. - * On XLP, the heartbeat bit for a specific cpu thread on a specific - * node is set according to the following formula: - * 32N + 4C + T - * where N = node, C=cpu-core number, T=thread number - * - * src_node = source node of watchdog timer interrupts. These interrupts - * get generated from the PIC on src_node. - * timer = watchdog timer 0 or 1 - * node = node for which the hearbeat is being done - * cpu = cpu-core for which the hearbeat is being done - * thread = h/w thread for which the hearbeat is being done - */ -static __inline__ void -nlm_pic_set_wdog_heartbeat(uint64_t base, int timer, int node, int cpu, - int thread) +static inline void +nlm_pic_set_timer(uint64_t base, int timer, uint64_t value, int irq, int cpu) { - int val = 32 * node + 4 * cpu + thread; + uint64_t pic_ctrl = nlm_read_pic_reg(base, PIC_CTRL); + int en; + + en = (irq > 0); + nlm_write_pic_reg(base, PIC_TIMER_MAXVAL(timer), value); + nlm_pic_write_irt_direct(base, PIC_IRT_TIMER_INDEX(timer), + en, 0, 0, irq, cpu); - nlm_wreg_pic(base, XLP_PIC_WDOG_BEATCMD_REG(timer), val); + /* enable the timer */ + pic_ctrl |= (1 << (PIC_CTRL_STE + timer)); + nlm_write_pic_reg(base, PIC_CTRL, pic_ctrl); } -#endif /* !LOCORE && !__ASSEMBLY__ */ -#endif +#endif /* __ASSEMBLY__ */ +#endif /* _NLM_HAL_PIC_H */ diff --git a/sys/mips/nlm/hal/sys.h b/sys/mips/nlm/hal/sys.h index 89e4c52d15bec..89b27fd7bdf36 100644 --- a/sys/mips/nlm/hal/sys.h +++ b/sys/mips/nlm/hal/sys.h @@ -25,101 +25,101 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ -#ifndef __NLM_SYS_H__ -#define __NLM_SYS_H__ +#ifndef __NLM_HAL_SYS_H__ +#define __NLM_HAL_SYS_H__ /** * @file_name sys.h * @author Netlogic Microsystems * @brief HAL for System configuration registers */ -#define XLP_SYS_CHIP_RESET_REG 0x40 -#define XLP_SYS_POWER_ON_RESET_REG 0x41 -#define XLP_SYS_EFUSE_DEVICE_CFG_STATUS0_REG 0x42 -#define XLP_SYS_EFUSE_DEVICE_CFG_STATUS1_REG 0x43 -#define XLP_SYS_EFUSE_DEVICE_CFG_STATUS2_REG 0x44 -#define XLP_SYS_EFUSE_DEVICE_CFG3_REG 0x45 -#define XLP_SYS_EFUSE_DEVICE_CFG4_REG 0x46 -#define XLP_SYS_EFUSE_DEVICE_CFG5_REG 0x47 -#define XLP_SYS_EFUSE_DEVICE_CFG6_REG 0x48 -#define XLP_SYS_EFUSE_DEVICE_CFG7_REG 0x49 -#define XLP_SYS_PLL_CTRL_REG 0x4a -#define XLP_SYS_CPU_RESET_REG 0x4b -#define XLP_SYS_CPU_NONCOHERENT_MODE_REG 0x4d -#define XLP_SYS_CORE_DFS_DIS_CTRL_REG 0x4e -#define XLP_SYS_CORE_DFS_RST_CTRL_REG 0x4f -#define XLP_SYS_CORE_DFS_BYP_CTRL_REG 0x50 -#define XLP_SYS_CORE_DFS_PHA_CTRL_REG 0x51 -#define XLP_SYS_CORE_DFS_DIV_INC_CTRL_REG 0x52 -#define XLP_SYS_CORE_DFS_DIV_DEC_CTRL_REG 0x53 -#define XLP_SYS_CORE_DFS_DIV_VALUE_REG 0x54 -#define XLP_SYS_RESET_REG 0x55 -#define XLP_SYS_DFS_DIS_CTRL_REG 0x56 -#define XLP_SYS_DFS_RST_CTRL_REG 0x57 -#define XLP_SYS_DFS_BYP_CTRL_REG 0x58 -#define XLP_SYS_DFS_DIV_INC_CTRL_REG 0x59 -#define XLP_SYS_DFS_DIV_DEC_CTRL_REG 0x5a -#define XLP_SYS_DFS_DIV_VALUE0_REG 0x5b -#define XLP_SYS_DFS_DIV_VALUE1_REG 0x5c -#define XLP_SYS_SENSE_AMP_DLY_REG 0x5d -#define XLP_SYS_SOC_SENSE_AMP_DLY_REG 0x5e -#define XLP_SYS_CTRL0_REG 0x5f -#define XLP_SYS_CTRL1_REG 0x60 -#define XLP_SYS_TIMEOUT_BS1_REG 0x61 -#define XLP_SYS_BYTE_SWAP_REG 0x62 -#define XLP_SYS_VRM_VID_REG 0x63 -#define XLP_SYS_PWR_RAM_CMD_REG 0x64 -#define XLP_SYS_PWR_RAM_ADDR_REG 0x65 -#define XLP_SYS_PWR_RAM_DATA0_REG 0x66 -#define XLP_SYS_PWR_RAM_DATA1_REG 0x67 -#define XLP_SYS_PWR_RAM_DATA2_REG 0x68 -#define XLP_SYS_PWR_UCODE_REG 0x69 -#define XLP_SYS_CPU0_PWR_STATUS_REG 0x6a -#define XLP_SYS_CPU1_PWR_STATUS_REG 0x6b -#define XLP_SYS_CPU2_PWR_STATUS_REG 0x6c -#define XLP_SYS_CPU3_PWR_STATUS_REG 0x6d -#define XLP_SYS_CPU4_PWR_STATUS_REG 0x6e -#define XLP_SYS_CPU5_PWR_STATUS_REG 0x6f -#define XLP_SYS_CPU6_PWR_STATUS_REG 0x70 -#define XLP_SYS_CPU7_PWR_STATUS_REG 0x71 -#define XLP_SYS_STATUS_REG 0x72 -#define XLP_SYS_INT_POL_REG 0x73 -#define XLP_SYS_INT_TYPE_REG 0x74 -#define XLP_SYS_INT_STATUS_REG 0x75 -#define XLP_SYS_INT_MASK0_REG 0x76 -#define XLP_SYS_INT_MASK1_REG 0x77 -#define XLP_SYS_UCO_S_ECC_REG 0x78 -#define XLP_SYS_UCO_M_ECC_REG 0x79 -#define XLP_SYS_UCO_ADDR_REG 0x7a -#define XLP_SYS_UCO_INSTR_REG 0x7b -#define XLP_SYS_MEM_BIST0_REG 0x7c -#define XLP_SYS_MEM_BIST1_REG 0x7d -#define XLP_SYS_MEM_BIST2_REG 0x7e -#define XLP_SYS_MEM_BIST3_REG 0x7f -#define XLP_SYS_MEM_BIST4_REG 0x80 -#define XLP_SYS_MEM_BIST5_REG 0x81 -#define XLP_SYS_MEM_BIST6_REG 0x82 -#define XLP_SYS_MEM_BIST7_REG 0x83 -#define XLP_SYS_MEM_BIST8_REG 0x84 -#define XLP_SYS_MEM_BIST9_REG 0x85 -#define XLP_SYS_MEM_BIST10_REG 0x86 -#define XLP_SYS_MEM_BIST11_REG 0x87 -#define XLP_SYS_MEM_BIST12_REG 0x88 -#define XLP_SYS_SCRTCH0_REG 0x89 -#define XLP_SYS_SCRTCH1_REG 0x8a -#define XLP_SYS_SCRTCH2_REG 0x8b -#define XLP_SYS_SCRTCH3_REG 0x8c +#define SYS_CHIP_RESET 0x00 +#define SYS_POWER_ON_RESET_CFG 0x01 +#define SYS_EFUSE_DEVICE_CFG_STATUS0 0x02 +#define SYS_EFUSE_DEVICE_CFG_STATUS1 0x03 +#define SYS_EFUSE_DEVICE_CFG_STATUS2 0x04 +#define SYS_EFUSE_DEVICE_CFG3 0x05 +#define SYS_EFUSE_DEVICE_CFG4 0x06 +#define SYS_EFUSE_DEVICE_CFG5 0x07 +#define SYS_EFUSE_DEVICE_CFG6 0x08 +#define SYS_EFUSE_DEVICE_CFG7 0x09 +#define SYS_PLL_CTRL 0x0a +#define SYS_CPU_RESET 0x0b +#define SYS_CPU_NONCOHERENT_MODE 0x0d +#define SYS_CORE_DFS_DIS_CTRL 0x0e +#define SYS_CORE_DFS_RST_CTRL 0x0f +#define SYS_CORE_DFS_BYP_CTRL 0x10 +#define SYS_CORE_DFS_PHA_CTRL 0x11 +#define SYS_CORE_DFS_DIV_INC_CTRL 0x12 +#define SYS_CORE_DFS_DIV_DEC_CTRL 0x13 +#define SYS_CORE_DFS_DIV_VALUE 0x14 +#define SYS_RESET 0x15 +#define SYS_DFS_DIS_CTRL 0x16 +#define SYS_DFS_RST_CTRL 0x17 +#define SYS_DFS_BYP_CTRL 0x18 +#define SYS_DFS_DIV_INC_CTRL 0x19 +#define SYS_DFS_DIV_DEC_CTRL 0x1a +#define SYS_DFS_DIV_VALUE0 0x1b +#define SYS_DFS_DIV_VALUE1 0x1c +#define SYS_SENSE_AMP_DLY 0x1d +#define SYS_SOC_SENSE_AMP_DLY 0x1e +#define SYS_CTRL0 0x1f +#define SYS_CTRL1 0x20 +#define SYS_TIMEOUT_BS1 0x21 +#define SYS_BYTE_SWAP 0x22 +#define SYS_VRM_VID 0x23 +#define SYS_PWR_RAM_CMD 0x24 +#define SYS_PWR_RAM_ADDR 0x25 +#define SYS_PWR_RAM_DATA0 0x26 +#define SYS_PWR_RAM_DATA1 0x27 +#define SYS_PWR_RAM_DATA2 0x28 +#define SYS_PWR_UCODE 0x29 +#define SYS_CPU0_PWR_STATUS 0x2a +#define SYS_CPU1_PWR_STATUS 0x2b +#define SYS_CPU2_PWR_STATUS 0x2c +#define SYS_CPU3_PWR_STATUS 0x2d +#define SYS_CPU4_PWR_STATUS 0x2e +#define SYS_CPU5_PWR_STATUS 0x2f +#define SYS_CPU6_PWR_STATUS 0x30 +#define SYS_CPU7_PWR_STATUS 0x31 +#define SYS_STATUS 0x32 +#define SYS_INT_POL 0x33 +#define SYS_INT_TYPE 0x34 +#define SYS_INT_STATUS 0x35 +#define SYS_INT_MASK0 0x36 +#define SYS_INT_MASK1 0x37 +#define SYS_UCO_S_ECC 0x38 +#define SYS_UCO_M_ECC 0x39 +#define SYS_UCO_ADDR 0x3a +#define SYS_UCO_INSTR 0x3b +#define SYS_MEM_BIST0 0x3c +#define SYS_MEM_BIST1 0x3d +#define SYS_MEM_BIST2 0x3e +#define SYS_MEM_BIST3 0x3f +#define SYS_MEM_BIST4 0x40 +#define SYS_MEM_BIST5 0x41 +#define SYS_MEM_BIST6 0x42 +#define SYS_MEM_BIST7 0x43 +#define SYS_MEM_BIST8 0x44 +#define SYS_MEM_BIST9 0x45 +#define SYS_MEM_BIST10 0x46 +#define SYS_MEM_BIST11 0x47 +#define SYS_MEM_BIST12 0x48 +#define SYS_SCRTCH0 0x49 +#define SYS_SCRTCH1 0x4a +#define SYS_SCRTCH2 0x4b +#define SYS_SCRTCH3 0x4c #if !defined(LOCORE) && !defined(__ASSEMBLY__) -#define nlm_rdreg_sys(b, r) nlm_read_reg_kseg(b,r) -#define nlm_wreg_sys(b, r, v) nlm_write_reg_kseg(b,r,v) -#define nlm_pcibase_sys(node) nlm_pcicfg_base(XLP_IO_SYS_OFFSET(node)) -#define nlm_regbase_sys(node) nlm_pcibase_sys(node) +#define nlm_read_sys_reg(b, r) nlm_read_reg(b, r) +#define nlm_write_sys_reg(b, r, v) nlm_write_reg(b, r, v) +#define nlm_get_sys_pcibase(node) nlm_pcicfg_base(XLP_IO_SYS_OFFSET(node)) +#define nlm_get_sys_regbase(node) (nlm_get_sys_pcibase(node) + XLP_IO_PCI_HDRSZ) #endif - #endif diff --git a/sys/mips/nlm/hal/uart.h b/sys/mips/nlm/hal/uart.h index 9eebb49ba671e..ce11c849428c3 100644 --- a/sys/mips/nlm/hal/uart.h +++ b/sys/mips/nlm/hal/uart.h @@ -25,127 +25,121 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ -#ifndef __XLP_UART_H__ -#define __XLP_UART_H__ +#ifndef __XLP_HAL_UART_H__ +#define __XLP_HAL_UART_H__ /* UART Specific registers */ -#define XLP_UART_RX_DATA_REG 0x40 -#define XLP_UART_TX_DATA_REG 0x40 +#define UART_RX_DATA 0x00 +#define UART_TX_DATA 0x00 -#define XLP_UART_INT_EN_REG 0x41 -#define XLP_UART_INT_ID_REG 0x42 -#define XLP_UART_FIFO_CTL_REG 0x42 -#define XLP_UART_LINE_CTL_REG 0x43 -#define XLP_UART_MODEM_CTL_REG 0x44 -#define XLP_UART_LINE_STS_REG 0x45 -#define XLP_UART_MODEM_STS_REG 0x46 +#define UART_INT_EN 0x01 +#define UART_INT_ID 0x02 +#define UART_FIFO_CTL 0x02 +#define UART_LINE_CTL 0x03 +#define UART_MODEM_CTL 0x04 +#define UART_LINE_STS 0x05 +#define UART_MODEM_STS 0x06 -#define XLP_UART_DIVISOR0_REG 0x40 -#define XLP_UART_DIVISOR1_REG 0x41 +#define UART_DIVISOR0 0x00 +#define UART_DIVISOR1 0x01 -#define XLP_UART_BASE_BAUD (133000000/16) -#define XLP_UART_BAUD_DIVISOR(baud) (XLP_UART_BASE_BAUD / baud) +#define BASE_BAUD (XLP_IO_CLK/16) +#define BAUD_DIVISOR(baud) (BASE_BAUD / baud) /* LCR mask values */ -#define LCR_5BITS 0x00 -#define LCR_6BITS 0x01 -#define LCR_7BITS 0x02 -#define LCR_8BITS 0x03 -#define LCR_STOPB 0x04 -#define LCR_PENAB 0x08 -#define LCR_PODD 0x00 -#define LCR_PEVEN 0x10 -#define LCR_PONE 0x20 -#define LCR_PZERO 0x30 -#define LCR_SBREAK 0x40 -#define LCR_EFR_ENABLE 0xbf -#define LCR_DLAB 0x80 +#define LCR_5BITS 0x00 +#define LCR_6BITS 0x01 +#define LCR_7BITS 0x02 +#define LCR_8BITS 0x03 +#define LCR_STOPB 0x04 +#define LCR_PENAB 0x08 +#define LCR_PODD 0x00 +#define LCR_PEVEN 0x10 +#define LCR_PONE 0x20 +#define LCR_PZERO 0x30 +#define LCR_SBREAK 0x40 +#define LCR_EFR_ENABLE 0xbf +#define LCR_DLAB 0x80 /* MCR mask values */ -#define MCR_DTR 0x01 -#define MCR_RTS 0x02 -#define MCR_DRS 0x04 -#define MCR_IE 0x08 -#define MCR_LOOPBACK 0x10 +#define MCR_DTR 0x01 +#define MCR_RTS 0x02 +#define MCR_DRS 0x04 +#define MCR_IE 0x08 +#define MCR_LOOPBACK 0x10 /* FCR mask values */ -#define FCR_RCV_RST 0x02 -#define FCR_XMT_RST 0x04 -#define FCR_RX_LOW 0x00 -#define FCR_RX_MEDL 0x40 -#define FCR_RX_MEDH 0x80 -#define FCR_RX_HIGH 0xc0 +#define FCR_RCV_RST 0x02 +#define FCR_XMT_RST 0x04 +#define FCR_RX_LOW 0x00 +#define FCR_RX_MEDL 0x40 +#define FCR_RX_MEDH 0x80 +#define FCR_RX_HIGH 0xc0 /* IER mask values */ -#define IER_ERXRDY 0x1 -#define IER_ETXRDY 0x2 -#define IER_ERLS 0x4 -#define IER_EMSC 0x8 - -/* uart IRQ info */ -#define XLP_NODE0_UART0_IRQ 17 -#define XLP_NODE1_UART0_IRQ 18 -#define XLP_NODE2_UART0_IRQ 19 -#define XLP_NODE3_UART0_IRQ 20 -#define XLP_NODE0_UART1_IRQ 21 -#define XLP_NODE1_UART1_IRQ 22 -#define XLP_NODE2_UART1_IRQ 23 -#define XLP_NODE3_UART1_IRQ 24 +#define IER_ERXRDY 0x1 +#define IER_ETXRDY 0x2 +#define IER_ERLS 0x4 +#define IER_EMSC 0x8 #if !defined(LOCORE) && !defined(__ASSEMBLY__) -#define nlm_rdreg_uart(b, r) nlm_read_reg_kseg(b,r) -#define nlm_wreg_uart(b, r, v) nlm_write_reg_kseg(b,r,v) -#define nlm_pcibase_uart(node, inst) nlm_pcicfg_base(XLP_IO_UART_OFFSET(node, inst)) -#define nlm_regbase_uart(node, inst) nlm_pcibase_uart(node, inst) +#define nlm_read_uart_reg(b, r) nlm_read_reg(b, r) +#define nlm_write_uart_reg(b, r, v) nlm_write_reg(b, r, v) +#define nlm_get_uart_pcibase(node, inst) \ + nlm_pcicfg_base(XLP_IO_UART_OFFSET(node, inst)) +#define nlm_get_uart_regbase(node, inst) \ + (nlm_get_uart_pcibase(node, inst) + XLP_IO_PCI_HDRSZ) -static __inline__ void +static inline void nlm_uart_set_baudrate(uint64_t base, int baud) { uint32_t lcr; - lcr = nlm_rdreg_uart(base, XLP_UART_LINE_CTL_REG); + lcr = nlm_read_uart_reg(base, UART_LINE_CTL); /* enable divisor register, and write baud values */ - nlm_wreg_uart(base, XLP_UART_LINE_CTL_REG, lcr | (1 << 7)); - nlm_wreg_uart(base, XLP_UART_DIVISOR0_REG, - (XLP_UART_BAUD_DIVISOR(baud) & 0xff)); - nlm_wreg_uart(base, XLP_UART_DIVISOR1_REG, - ((XLP_UART_BAUD_DIVISOR(baud) >> 8) & 0xff)); + nlm_write_uart_reg(base, UART_LINE_CTL, lcr | (1 << 7)); + nlm_write_uart_reg(base, UART_DIVISOR0, + (BAUD_DIVISOR(baud) & 0xff)); + nlm_write_uart_reg(base, UART_DIVISOR1, + ((BAUD_DIVISOR(baud) >> 8) & 0xff)); /* restore default lcr */ - nlm_wreg_uart(base, XLP_UART_LINE_CTL_REG, lcr); + nlm_write_uart_reg(base, UART_LINE_CTL, lcr); } -static __inline__ void -nlm_outbyte (uint64_t base, char c) +static inline void +nlm_uart_outbyte(uint64_t base, char c) { uint32_t lsr; for (;;) { - lsr = nlm_rdreg_uart(base, XLP_UART_LINE_STS_REG); - if (lsr & 0x20) break; + lsr = nlm_read_uart_reg(base, UART_LINE_STS); + if (lsr & 0x20) + break; } - nlm_wreg_uart(base, XLP_UART_TX_DATA_REG, (int)c); + nlm_write_uart_reg(base, UART_TX_DATA, (int)c); } -static __inline__ char -nlm_inbyte (uint64_t base) +static inline char +nlm_uart_inbyte(uint64_t base) { int data, lsr; - for(;;) { - lsr = nlm_rdreg_uart(base, XLP_UART_LINE_STS_REG); - if (lsr & 0x80) { /* parity/frame/break-error - push a zero */ + for (;;) { + lsr = nlm_read_uart_reg(base, UART_LINE_STS); + if (lsr & 0x80) { /* parity/frame/break-error - push a zero */ data = 0; break; } - if (lsr & 0x01) { /* Rx data */ - data = nlm_rdreg_uart(base, XLP_UART_RX_DATA_REG); + if (lsr & 0x01) { /* Rx data */ + data = nlm_read_uart_reg(base, UART_RX_DATA); break; } } @@ -153,9 +147,9 @@ nlm_inbyte (uint64_t base) return (char)data; } -static __inline__ int +static inline int nlm_uart_init(uint64_t base, int baud, int databits, int stopbits, - int parity, int int_en, int loopback) + int parity, int int_en, int loopback) { uint32_t lcr; @@ -175,22 +169,20 @@ nlm_uart_init(uint64_t base, int baud, int databits, int stopbits, lcr |= parity << 3; /* setup default lcr */ - nlm_wreg_uart(base, XLP_UART_LINE_CTL_REG, lcr); + nlm_write_uart_reg(base, UART_LINE_CTL, lcr); /* Reset the FIFOs */ - nlm_wreg_uart(base, XLP_UART_LINE_CTL_REG, FCR_RCV_RST | FCR_XMT_RST); + nlm_write_uart_reg(base, UART_LINE_CTL, FCR_RCV_RST | FCR_XMT_RST); nlm_uart_set_baudrate(base, baud); if (loopback) - nlm_wreg_uart(base, XLP_UART_MODEM_CTL_REG, 0x1f); + nlm_write_uart_reg(base, UART_MODEM_CTL, 0x1f); if (int_en) - nlm_wreg_uart(base, XLP_UART_INT_EN_REG, IER_ERXRDY | IER_ETXRDY); + nlm_write_uart_reg(base, UART_INT_EN, IER_ERXRDY | IER_ETXRDY); return 0; } - #endif /* !LOCORE && !__ASSEMBLY__ */ -#endif /* __XLP_UART_H__ */ - +#endif /* __XLP_HAL_UART_H__ */ diff --git a/sys/mips/nlm/hal/usb.h b/sys/mips/nlm/hal/usb.h new file mode 100644 index 0000000000000..ba8515a9646a1 --- /dev/null +++ b/sys/mips/nlm/hal/usb.h @@ -0,0 +1,59 @@ +/*- + * Copyright 2003-2011 Netlogic Microsystems (Netlogic). 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 Netlogic Microsystems ``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 NETLOGIC 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. + * + * NETLOGIC_BSD + * $FreeBSD$ + */ + +#ifndef __NLM_USB_H__ +#define __NLM_USB_H__ + +#define USB_CTL_0 0x01 +#define USB_PHY_0 0x0A +#define USB_PHY_RESET 0x01 +#define USB_PHY_PORT_RESET_0 0x10 +#define USB_PHY_PORT_RESET_1 0x20 +#define USB_CONTROLLER_RESET 0x01 +#define USB_INT_STATUS 0x0E +#define USB_INT_EN 0x0F +#define USB_PHY_INTERRUPT_EN 0x01 +#define USB_OHCI_INTERRUPT_EN 0x02 +#define USB_OHCI_INTERRUPT1_EN 0x04 +#define USB_OHCI_INTERRUPT2_EN 0x08 +#define USB_CTRL_INTERRUPT_EN 0x10 + + +#if !defined(LOCORE) && !defined(__ASSEMBLY__) + +#define nlm_read_usb_reg(b, r) nlm_read_reg(b,r) +#define nlm_write_usb_reg(b, r, v) nlm_write_reg(b,r,v) +#define nlm_get_usb_pcibase(node, inst) nlm_pcicfg_base(XLP_IO_USB_OFFSET(node, inst)) +#define nlm_get_usb_hcd_base(node, inst) nlm_xkphys_map_pcibar0(nlm_get_usb_pcibase(node, inst)) +#define nlm_get_usb_regbase(node, inst) (nlm_get_usb_pcibase(node, inst) + XLP_IO_PCI_HDRSZ) + +#endif +#endif diff --git a/sys/mips/nlm/intern_dev.c b/sys/mips/nlm/intern_dev.c new file mode 100644 index 0000000000000..ec237e41df6db --- /dev/null +++ b/sys/mips/nlm/intern_dev.c @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2011 Netlogic Microsystems Inc. + * + * (based on pci/ignore_pci.c) + * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> + * Copyright (c) 2000 BSDi + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * 'Ignore' driver - eats devices that show up errnoeously on PCI + * but shouldn't ever be listed or handled by a driver. + */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <dev/pci/pcivar.h> + +#include <mips/nlm/hal/haldefs.h> +#include <mips/nlm/hal/iomap.h> + +static int nlm_soc_pci_probe(device_t dev); + +static device_method_t nlm_soc_pci_methods[] = { + DEVMETHOD(device_probe, nlm_soc_pci_probe), + DEVMETHOD(device_attach, bus_generic_attach), + { 0, 0 } +}; + +static driver_t nlm_soc_pci_driver = { + "nlm_soc_pci", + nlm_soc_pci_methods, + 0, +}; + +static devclass_t nlm_soc_pci_devclass; +DRIVER_MODULE(nlm_soc_pci, pci, nlm_soc_pci_driver, nlm_soc_pci_devclass, 0, 0); + +static int +nlm_soc_pci_probe(device_t dev) +{ + if (pci_get_vendor(dev) != PCI_VENDOR_NETLOGIC) + return(ENXIO); + + /* Ignore SoC internal devices */ + switch (pci_get_device(dev)) { + case PCI_DEVICE_ID_NLM_ICI: + case PCI_DEVICE_ID_NLM_PIC: + case PCI_DEVICE_ID_NLM_FMN: + device_set_desc(dev, "Netlogic Internal"); + device_quiet(dev); + return(-10000); + + default: + return(ENXIO); + } +} diff --git a/sys/mips/nlm/interrupt.h b/sys/mips/nlm/interrupt.h index 41904ebd13d0c..342f1d3f0e05b 100644 --- a/sys/mips/nlm/interrupt.h +++ b/sys/mips/nlm/interrupt.h @@ -25,8 +25,9 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ #ifndef _RMI_INTERRUPT_H_ #define _RMI_INTERRUPT_H_ diff --git a/sys/mips/nlm/intr_machdep.c b/sys/mips/nlm/intr_machdep.c index 4862356443630..782043e2366fb 100644 --- a/sys/mips/nlm/intr_machdep.c +++ b/sys/mips/nlm/intr_machdep.c @@ -46,9 +46,9 @@ __FBSDID("$FreeBSD$"); #include <machine/trap.h> #include <machine/hwfunc.h> -#include <mips/nlm/hal/mmio.h> +#include <mips/nlm/hal/haldefs.h> #include <mips/nlm/hal/iomap.h> -#include <mips/nlm/hal/cop0.h> +#include <mips/nlm/hal/mips-extns.h> #include <mips/nlm/interrupt.h> #include <mips/nlm/hal/pic.h> #include <mips/nlm/xlp.h> diff --git a/sys/mips/nlm/iodi.c b/sys/mips/nlm/iodi.c deleted file mode 100644 index 3b372bb916b31..0000000000000 --- a/sys/mips/nlm/iodi.c +++ /dev/null @@ -1,233 +0,0 @@ -/*- - * Copyright 2003-2011 Netlogic Microsystems (Netlogic). 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 Netlogic Microsystems ``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 NETLOGIC 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. - * - * NETLOGIC_BSD */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#define __RMAN_RESOURCE_VISIBLE -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/bus.h> -#include <sys/interrupt.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/mutex.h> -#include <sys/reboot.h> -#include <sys/rman.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/pmap.h> - -#include <machine/cpu.h> -#include <machine/bus.h> -#include <machine/intr_machdep.h> - -#include <mips/nlm/hal/mmio.h> -#include <mips/nlm/hal/iomap.h> -#include <mips/nlm/hal/pic.h> -#include <mips/nlm/hal/uart.h> -#include <mips/nlm/hal/cop2.h> -#include <mips/nlm/hal/fmn.h> - -#include <mips/nlm/msgring.h> -#include <mips/nlm/xlp.h> -#include <mips/nlm/board.h> - -extern void iodi_activateirqs(void); - -extern bus_space_tag_t uart_bus_space_mem; - -static struct resource *iodi_alloc_resource(device_t, device_t, int, int *, - u_long, u_long, u_long, u_int); - -static int iodi_activate_resource(device_t, device_t, int, int, - struct resource *); -struct iodi_softc *iodi_softc; /* There can be only one. */ - -static int -iodi_setup_intr(device_t dev, device_t child, - struct resource *ires, int flags, driver_filter_t *filt, - driver_intr_t *intr, void *arg, void **cookiep) -{ - const char *name = device_get_name(child); - int unit = device_get_unit(child); - - if (strcmp(name, "uart") == 0) { - /* Note: in xlp, all pic interrupts are level triggered */ - nlm_pic_write_irt_id(xlp_pic_base, XLP_PIC_IRT_UART0_INDEX, 1, 0, - xlp_irt_to_irq(XLP_PIC_IRT_UART0_INDEX), 0, 0, 0x1); - - cpu_establish_hardintr("uart", filt, intr, arg, - xlp_irt_to_irq(XLP_PIC_IRT_UART0_INDEX), flags, cookiep); - } else if (strcmp(name, "ehci") == 0) { - if (unit == 0) { - nlm_pic_write_irt_id(xlp_pic_base, XLP_PIC_IRT_EHCI0_INDEX, 1, 0, - xlp_irt_to_irq(XLP_PIC_IRT_EHCI0_INDEX), 0, 0, 0x1); - - cpu_establish_hardintr("ehci0", filt, intr, arg, - xlp_irt_to_irq(XLP_PIC_IRT_EHCI0_INDEX), flags, cookiep); - } else if (unit == 1) { - nlm_pic_write_irt_id(xlp_pic_base, XLP_PIC_IRT_EHCI1_INDEX, 1, 0, - xlp_irt_to_irq(XLP_PIC_IRT_EHCI1_INDEX), 0, 0, 0x1); - - cpu_establish_hardintr("ehci1", filt, intr, arg, - xlp_irt_to_irq(XLP_PIC_IRT_EHCI1_INDEX), flags, cookiep); - - } - } else if (strcmp(name, "xlp_sdhci") == 0) { - nlm_pic_write_irt_id(xlp_pic_base, XLP_PIC_IRT_MMC_INDEX, 1, 0, - xlp_irt_to_irq(XLP_PIC_IRT_MMC_INDEX), 0, 0, 0x1); - - cpu_establish_hardintr("xlp_sdhci", filt, intr, arg, - xlp_irt_to_irq(XLP_PIC_IRT_MMC_INDEX), flags, cookiep); - - } - - return (0); -} - -static struct resource * -iodi_alloc_resource(device_t bus, device_t child, int type, int *rid, - u_long start, u_long end, u_long count, u_int flags) -{ - struct resource *res = malloc(sizeof(*res), M_DEVBUF, M_WAITOK); - const char *name = device_get_name(child); - int unit; - - switch (type) { - case SYS_RES_IRQ: - device_printf(bus, "IRQ resource - for %s %lx-%lx\n", - device_get_nameunit(child), start, end); - break; - - case SYS_RES_IOPORT: - device_printf(bus, "IOPORT resource - for %s %lx-%lx\n", - device_get_nameunit(child), start, end); - break; - - case SYS_RES_MEMORY: - device_printf(bus, "MEMORY resource - for %s %lx-%lx\n", - device_get_nameunit(child), start, end); - break; - } - - unit = device_get_unit(child); - if (strcmp(name, "uart") == 0) { - if (unit == 0) { - res->r_bushandle = nlm_regbase_uart(0, 0) + XLP_IO_PCI_HDRSZ; - } else if ( unit == 1) { - res->r_bushandle = nlm_regbase_uart(0, 1) + XLP_IO_PCI_HDRSZ; - } else - printf("%s: Unknown uart unit\n", __FUNCTION__); - - res->r_bustag = uart_bus_space_mem; - } - - return (res); -} - -static int -iodi_activate_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) -{ - return (0); -} -/* prototypes */ -static int iodi_probe(device_t); -static int iodi_attach(device_t); -static void iodi_identify(driver_t *, device_t); - -int -iodi_probe(device_t dev) -{ - return 0; -} - -void -iodi_identify(driver_t *driver, device_t parent) -{ - - BUS_ADD_CHILD(parent, 0, "iodi", 0); -} - - -int -iodi_attach(device_t dev) -{ - device_t tmpd; - char desc[32]; - int i; - - device_printf(dev, "IODI - Initialize message ring.\n"); - xlp_msgring_iodi_config(); - - /* - * Attach each devices - */ - device_add_child(dev, "uart", 0); - device_add_child(dev, "xlp_i2c", 0); - device_add_child(dev, "xlp_i2c", 1); - device_add_child(dev, "ehci", 0); - device_add_child(dev, "ehci", 1); - device_add_child(dev, "xlp_sdhci", 0); - - for (i=0; i < XLP_NUM_NODES; i++) { - tmpd = device_add_child(dev, "xlpnae", i); - device_set_ivars(tmpd, &xlp_board_info.nodes[i].nae_ivars); - snprintf(desc, sizeof(desc), "XLP NAE %d", i); - device_set_desc_copy(tmpd, desc); - } - - bus_generic_probe(dev); - bus_generic_attach(dev); - return 0; -} - -static device_method_t iodi_methods[] = { - DEVMETHOD(device_probe, iodi_probe), - DEVMETHOD(device_attach, iodi_attach), - DEVMETHOD(device_identify, iodi_identify), - DEVMETHOD(bus_alloc_resource, iodi_alloc_resource), - DEVMETHOD(bus_activate_resource, iodi_activate_resource), - DEVMETHOD(bus_add_child, bus_generic_add_child), - DEVMETHOD(bus_setup_intr, iodi_setup_intr), - {0, 0}, -}; - -static driver_t iodi_driver = { - "iodi", - iodi_methods, - 1 /* no softc */ -}; -static devclass_t iodi_devclass; - -DRIVER_MODULE(iodi, nexus, iodi_driver, iodi_devclass, 0, 0); diff --git a/sys/mips/nlm/mpreset.S b/sys/mips/nlm/mpreset.S index c56bd9f053d32..95b2440b10eae 100644 --- a/sys/mips/nlm/mpreset.S +++ b/sys/mips/nlm/mpreset.S @@ -25,8 +25,9 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ #include <machine/asm.h> #include <machine/cpu.h> @@ -35,6 +36,8 @@ #include <mips/nlm/hal/sys.h> #include <mips/nlm/hal/cpucontrol.h> +#define SYS_REG_KSEG1(node, reg) (0xa0000000 + XLP_DEFAULT_IO_BASE + \ + XLP_IO_SYS_OFFSET(node) + XLP_IO_PCI_HDRSZ + (reg) * 4) #include "assym.s" .text @@ -59,7 +62,7 @@ VECTOR(XLPResetEntry, unknown) nor t0, t0, zero /* mask with core id bit clear */ /* clear CPU non-coherent bit */ - li t2, XLP_DEFAULT_IO_BASE_KSEG1 + XLP_IO_SYS_OFFSET(0) + XLP_SYS_CPU_NONCOHERENT_MODE_REG * 4 + li t2, SYS_REG_KSEG1(0, SYS_CPU_NONCOHERENT_MODE) lw t1, 0(t2) and t1, t1, t0 sw t1, 0(t2) @@ -109,7 +112,7 @@ LEAF(xlp_enable_threads) sd gp, 80(sp) sd ra, 88(sp) /* Use register number to work in o32 and n32 */ - li $9, ((XLP_CPU_BLOCKID_MAP << 8) | XLP_BLKID_MAP_THREADMODE) + li $9, ((CPU_BLOCKID_MAP << 8) | MAP_THREADMODE) move $8, a0 sync .word 0x71280019 /* mtcr t0, t1*/ diff --git a/sys/mips/nlm/msgring.h b/sys/mips/nlm/msgring.h index b951569cf3833..e57a0fe216509 100644 --- a/sys/mips/nlm/msgring.h +++ b/sys/mips/nlm/msgring.h @@ -25,10 +25,10 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ -/** FIXME **/ extern uint32_t xlp_msg_thread_mask; typedef void (*msgring_handler)(int, int, int, int, struct nlm_fmn_msg *, void *); int register_msgring_handler(int startb, int endb, msgring_handler action, @@ -41,4 +41,3 @@ void xlp_cpu_msgring_handler(int bucket, int size, int code, int stid, void nlm_cms_credit_setup(int credit); void xlp_msgring_iodi_config(void); - diff --git a/sys/mips/nlm/uart_bus_xlp_iodi.c b/sys/mips/nlm/uart_bus_xlp_iodi.c index 236900abf3846..ca68d68f64767 100644 --- a/sys/mips/nlm/uart_bus_xlp_iodi.c +++ b/sys/mips/nlm/uart_bus_xlp_iodi.c @@ -42,7 +42,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <machine/resource.h> -#include <mips/nlm/hal/mmio.h> +#include <mips/nlm/hal/haldefs.h> #include <mips/nlm/hal/iomap.h> #include <mips/nlm/hal/uart.h> @@ -78,9 +78,9 @@ uart_iodi_probe(device_t dev) sc->sc_class = &uart_ns8250_class; bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); sc->sc_sysdev->bas.bst = rmi_bus_space; - sc->sc_sysdev->bas.bsh = nlm_regbase_uart(0, 0) + XLP_IO_PCI_HDRSZ; + sc->sc_sysdev->bas.bsh = nlm_get_uart_regbase(0, 0); sc->sc_bas.bst = rmi_bus_space; - sc->sc_bas.bsh = nlm_regbase_uart(0, 0) + XLP_IO_PCI_HDRSZ; + sc->sc_bas.bsh = nlm_get_uart_regbase(0, 0); /* regshft = 2, rclk = 66000000, rid = 0, chan = 0 */ return (uart_bus_probe(dev, 2, 133000000, 0, 0)); } diff --git a/sys/mips/nlm/uart_cpu_mips_xlp.c b/sys/mips/nlm/uart_cpu_xlp.c index 07bdd6adbc04d..0e476d58c06ee 100644 --- a/sys/mips/nlm/uart_cpu_mips_xlp.c +++ b/sys/mips/nlm/uart_cpu_xlp.c @@ -53,27 +53,51 @@ __FBSDID("$FreeBSD$"); #include <dev/uart/uart.h> #include <dev/uart/uart_cpu.h> -#include <mips/nlm/hal/mmio.h> +#include <mips/nlm/hal/haldefs.h> #include <mips/nlm/hal/iomap.h> #include <mips/nlm/hal/uart.h> bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; +/* + * need a special bus space for this, because the Netlogic SoC + * UART allows only 32 bit access to its registers + */ +static struct bus_space nlm_uart_bussp; + +static u_int8_t +nlm_uart_bussp_read_1(void *tag, bus_space_handle_t handle, + bus_size_t offset) +{ + return (u_int8_t)(*(volatile u_int32_t *)(handle + offset)); +} + +static void +nlm_uart_bussp_write_1(void *tag, bus_space_handle_t handle, + bus_size_t offset, u_int8_t value) +{ + *(volatile u_int32_t *)(handle + offset) = value; +} + int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); } - int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { + /* Create custom bus space */ + memcpy(&nlm_uart_bussp, rmi_bus_space, sizeof(nlm_uart_bussp)); + nlm_uart_bussp.bs_r_1 = nlm_uart_bussp_read_1; + nlm_uart_bussp.bs_w_1 = nlm_uart_bussp_write_1; + di->ops = uart_getops(&uart_ns8250_class); di->bas.chan = 0; - di->bas.bst = rmi_bus_space; - di->bas.bsh = nlm_regbase_uart(0, 0) + XLP_IO_PCI_HDRSZ; + di->bas.bst = &nlm_uart_bussp; + di->bas.bsh = nlm_get_uart_regbase(0, 0); di->bas.regshft = 2; /* divisor = rclk / (baudrate * 16); */ @@ -84,6 +108,6 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) di->parity = UART_PARITY_NONE; uart_bus_space_io = NULL; - uart_bus_space_mem = rmi_bus_space; + uart_bus_space_mem = &nlm_uart_bussp; return (0); } diff --git a/sys/mips/nlm/uart_pci_xlp.c b/sys/mips/nlm/uart_pci_xlp.c new file mode 100644 index 0000000000000..16c795c158278 --- /dev/null +++ b/sys/mips/nlm/uart_pci_xlp.c @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 2011 Netlogic Microsystems Inc. + * + * (based on dev/uart/uart_bus_pci.c) + * Copyright (c) 2006 Marcel Moolenaar + * Copyright (c) 2001 M. Warner Losh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <dev/pci/pcivar.h> + +#include <mips/nlm/hal/haldefs.h> +#include <mips/nlm/hal/iomap.h> +#include <mips/nlm/hal/uart.h> + +#include <dev/uart/uart.h> +#include <dev/uart/uart_bus.h> + +static int uart_soc_probe(device_t dev); + +static device_method_t uart_soc_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, uart_soc_probe), + DEVMETHOD(device_attach, uart_bus_attach), + DEVMETHOD(device_detach, uart_bus_detach), + { 0, 0 } +}; + +static driver_t uart_soc_driver = { + uart_driver_name, + uart_soc_methods, + sizeof(struct uart_softc), +}; + +static int +uart_soc_probe(device_t dev) +{ + struct uart_softc *sc; + uint64_t ubase; + + if (pci_get_vendor(dev) != PCI_VENDOR_NETLOGIC || + pci_get_device(dev) != PCI_DEVICE_ID_NLM_UART) + return (ENXIO); + + ubase = nlm_get_uart_regbase(0, 0); + sc = device_get_softc(dev); + sc->sc_class = &uart_ns8250_class; + device_set_desc(dev, "Netlogic SoC UART"); + return (uart_bus_probe(dev, 2, 133000000, 0, 0)); +} + +DRIVER_MODULE(uart_soc, pci, uart_soc_driver, uart_devclass, 0, 0); diff --git a/sys/mips/nlm/usb_init.c b/sys/mips/nlm/usb_init.c new file mode 100644 index 0000000000000..32a6165c60ded --- /dev/null +++ b/sys/mips/nlm/usb_init.c @@ -0,0 +1,92 @@ +/*- + * Copyright 2003-2011 Netlogic Microsystems (Netlogic). 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 Netlogic Microsystems ``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 NETLOGIC 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. + * + * NETLOGIC_BSD */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/param.h> +#include <sys/kernel.h> + +#include <mips/nlm/hal/haldefs.h> +#include <mips/nlm/hal/iomap.h> +#include <mips/nlm/hal/cpuinfo.h> +#include <mips/nlm/hal/usb.h> + +#include <mips/nlm/xlp.h> + + +static void +nlm_usb_intr_en(int node, int port) +{ + uint32_t val; + uint64_t port_addr; + + port_addr = nlm_get_usb_regbase(node, port); + val = nlm_read_usb_reg(port_addr, USB_INT_EN); + val = USB_CTRL_INTERRUPT_EN | USB_OHCI_INTERRUPT_EN | + USB_OHCI_INTERRUPT1_EN | USB_CTRL_INTERRUPT_EN | + USB_OHCI_INTERRUPT_EN | USB_OHCI_INTERRUPT2_EN; + nlm_write_usb_reg(port_addr, USB_INT_EN, val); +} + +static void +nlm_usb_hw_reset(int node, int port) +{ + uint64_t port_addr; + uint32_t val; + + /* reset USB phy */ + port_addr = nlm_get_usb_regbase(node, port); + val = nlm_read_usb_reg(port_addr, USB_PHY_0); + val &= ~(USB_PHY_RESET | USB_PHY_PORT_RESET_0 | USB_PHY_PORT_RESET_1); + nlm_write_usb_reg(port_addr, USB_PHY_0, val); + + DELAY(100); + val = nlm_read_usb_reg(port_addr, USB_CTL_0); + val &= ~(USB_CONTROLLER_RESET); + val |= 0x4; + nlm_write_usb_reg(port_addr, USB_CTL_0, val); +} + +static void +nlm_usb_init(void) +{ + /* XXX: should be checking if these are in Device mode here */ + printf("Initialize USB Interface\n"); + nlm_usb_hw_reset(0, 0); + nlm_usb_hw_reset(0, 3); + + /* Enable PHY interrupts */ + nlm_usb_intr_en(0, 0); + nlm_usb_intr_en(0, 3); +} + +SYSINIT(nlm_usb_init, SI_SUB_CPU, SI_ORDER_MIDDLE, + nlm_usb_init, NULL); diff --git a/sys/mips/nlm/xlp.h b/sys/mips/nlm/xlp.h index 5c79aaf992d29..b4008919593fe 100644 --- a/sys/mips/nlm/xlp.h +++ b/sys/mips/nlm/xlp.h @@ -25,25 +25,25 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * + * NETLOGIC_BSD * $FreeBSD$ - * NETLOGIC_BSD */ + */ #ifndef __NLM_XLP_H__ #define __NLM_XLP_H__ #include <mips/nlm/hal/pic.h> -#define XLP_PIC_IRT_UART0_IRQ 9 -#define XLP_PIC_IRT_UART1_IRQ 10 - -#define XLP_PIC_IRT_PCIE0_IRQ 11 -#define XLP_PIC_IRT_PCIE1_IRQ 12 -#define XLP_PIC_IRT_PCIE2_IRQ 13 -#define XLP_PIC_IRT_PCIE3_IRQ 14 +#define PIC_UART_0_IRQ 9 +#define PIC_UART_1_IRQ 10 -#define XLP_PIC_IRT_EHCI0_IRQ 39 -#define XLP_PIC_IRT_EHCI1_IRQ 42 -#define XLP_PIC_IRT_MMC_IRQ 43 +#define PIC_PCIE_0_IRQ 11 +#define PIC_PCIE_1_IRQ 12 +#define PIC_PCIE_2_IRQ 13 +#define PIC_PCIE_3_IRQ 14 +#define PIC_EHCI_0_IRQ 39 +#define PIC_EHCI_1_IRQ 42 +#define PIC_MMC_IRQ 43 #ifndef LOCORE /* @@ -59,30 +59,28 @@ extern int xlp_hwtid_to_cpuid[]; extern void xlp_enable_threads(int code); #endif -extern uint64_t xlp_pic_base; /* TODO just for node 0 now */ - static __inline__ int xlp_irt_to_irq(int irt) { switch (irt) { - case XLP_PIC_IRT_MMC_INDEX : - return XLP_PIC_IRT_MMC_IRQ; - case XLP_PIC_IRT_EHCI0_INDEX : - return XLP_PIC_IRT_EHCI0_IRQ; - case XLP_PIC_IRT_EHCI1_INDEX : - return XLP_PIC_IRT_EHCI1_IRQ; - case XLP_PIC_IRT_UART0_INDEX : - return XLP_PIC_IRT_UART0_IRQ; - case XLP_PIC_IRT_UART1_INDEX : - return XLP_PIC_IRT_UART1_IRQ; - case XLP_PIC_IRT_PCIE_LINK0_INDEX : - return XLP_PIC_IRT_PCIE0_IRQ; - case XLP_PIC_IRT_PCIE_LINK1_INDEX : - return XLP_PIC_IRT_PCIE1_IRQ; - case XLP_PIC_IRT_PCIE_LINK2_INDEX : - return XLP_PIC_IRT_PCIE2_IRQ; - case XLP_PIC_IRT_PCIE_LINK3_INDEX : - return XLP_PIC_IRT_PCIE3_IRQ; + case PIC_IRT_MMC_INDEX : + return PIC_MMC_IRQ; + case PIC_IRT_EHCI_0_INDEX : + return PIC_EHCI_0_IRQ; + case PIC_IRT_EHCI_1_INDEX : + return PIC_EHCI_1_IRQ; + case PIC_IRT_UART_0_INDEX : + return PIC_UART_0_IRQ; + case PIC_IRT_UART_1_INDEX : + return PIC_UART_1_IRQ; + case PIC_IRT_PCIE_LINK_0_INDEX : + return PIC_PCIE_0_IRQ; + case PIC_IRT_PCIE_LINK_1_INDEX : + return PIC_PCIE_1_IRQ; + case PIC_IRT_PCIE_LINK_2_INDEX : + return PIC_PCIE_2_IRQ; + case PIC_IRT_PCIE_LINK_3_INDEX : + return PIC_PCIE_3_IRQ; default: panic("Bad IRT %d\n", irt); } } @@ -91,24 +89,24 @@ static __inline__ int xlp_irq_to_irt(int irq) { switch (irq) { - case XLP_PIC_IRT_MMC_IRQ : - return XLP_PIC_IRT_MMC_INDEX; - case XLP_PIC_IRT_EHCI0_IRQ : - return XLP_PIC_IRT_EHCI0_INDEX; - case XLP_PIC_IRT_EHCI1_IRQ : - return XLP_PIC_IRT_EHCI1_INDEX; - case XLP_PIC_IRT_UART0_IRQ : - return XLP_PIC_IRT_UART0_INDEX; - case XLP_PIC_IRT_UART1_IRQ : - return XLP_PIC_IRT_UART1_INDEX; - case XLP_PIC_IRT_PCIE0_IRQ : - return XLP_PIC_IRT_PCIE_LINK0_INDEX; - case XLP_PIC_IRT_PCIE1_IRQ : - return XLP_PIC_IRT_PCIE_LINK1_INDEX; - case XLP_PIC_IRT_PCIE2_IRQ : - return XLP_PIC_IRT_PCIE_LINK2_INDEX; - case XLP_PIC_IRT_PCIE3_IRQ : - return XLP_PIC_IRT_PCIE_LINK3_INDEX; + case PIC_MMC_IRQ : + return PIC_IRT_MMC_INDEX; + case PIC_EHCI_0_IRQ : + return PIC_IRT_EHCI_0_INDEX; + case PIC_EHCI_1_IRQ : + return PIC_IRT_EHCI_1_INDEX; + case PIC_UART_0_IRQ : + return PIC_IRT_UART_0_INDEX; + case PIC_UART_1_IRQ : + return PIC_IRT_UART_1_INDEX; + case PIC_PCIE_0_IRQ : + return PIC_IRT_PCIE_LINK_0_INDEX; + case PIC_PCIE_1_IRQ : + return PIC_IRT_PCIE_LINK_1_INDEX; + case PIC_PCIE_2_IRQ : + return PIC_IRT_PCIE_LINK_2_INDEX; + case PIC_PCIE_3_IRQ : + return PIC_IRT_PCIE_LINK_3_INDEX; default: panic("Bad IRQ %d\n", irq); } } @@ -117,15 +115,15 @@ static __inline__ int xlp_irq_is_picintr(int irq) { switch (irq) { - case XLP_PIC_IRT_MMC_IRQ : return 1; - case XLP_PIC_IRT_EHCI0_IRQ : return 1; - case XLP_PIC_IRT_EHCI1_IRQ : return 1; - case XLP_PIC_IRT_UART0_IRQ : return 1; - case XLP_PIC_IRT_UART1_IRQ : return 1; - case XLP_PIC_IRT_PCIE0_IRQ : return 1; - case XLP_PIC_IRT_PCIE1_IRQ : return 1; - case XLP_PIC_IRT_PCIE2_IRQ : return 1; - case XLP_PIC_IRT_PCIE3_IRQ : return 1; + case PIC_MMC_IRQ : return 1; + case PIC_EHCI_0_IRQ : return 1; + case PIC_EHCI_1_IRQ : return 1; + case PIC_UART_0_IRQ : return 1; + case PIC_UART_1_IRQ : return 1; + case PIC_PCIE_0_IRQ : return 1; + case PIC_PCIE_1_IRQ : return 1; + case PIC_PCIE_2_IRQ : return 1; + case PIC_PCIE_3_IRQ : return 1; default: return 0; } } diff --git a/sys/mips/nlm/xlp_machdep.c b/sys/mips/nlm/xlp_machdep.c index 6b4bde4c730f3..30430fad53cac 100644 --- a/sys/mips/nlm/xlp_machdep.c +++ b/sys/mips/nlm/xlp_machdep.c @@ -71,9 +71,8 @@ __FBSDID("$FreeBSD$"); #include <machine/smp.h> #include <mips/nlm/hal/mips-extns.h> -#include <mips/nlm/hal/mmio.h> +#include <mips/nlm/hal/haldefs.h> #include <mips/nlm/hal/iomap.h> -#include <mips/nlm/hal/cop0.h> #include <mips/nlm/hal/sys.h> #include <mips/nlm/hal/pic.h> #include <mips/nlm/hal/uart.h> @@ -93,7 +92,7 @@ int xlp_argc; char **xlp_argv, **xlp_envp; uint64_t xlp_cpu_frequency; -uint64_t nlm_pcicfg_baseaddr = MIPS_PHYS_TO_KSEG1(XLP_DEFAULT_IO_BASE); +uint64_t xlp_io_base = MIPS_PHYS_TO_KSEG1(XLP_DEFAULT_IO_BASE); int xlp_ncores; int xlp_threads_per_core; @@ -112,7 +111,7 @@ xlp_setup_core(void) { uint64_t reg; - reg = nlm_mfcr(XLP_LSU_DEFEATURE); + reg = nlm_mfcr(LSU_DEFEATURE); /* Enable Unaligned and L2HPE */ reg |= (1 << 30) | (1 << 23); /* @@ -123,12 +122,12 @@ xlp_setup_core(void) reg |= (1ull << 31); /* Clear S1RCM - A0 errata */ reg &= ~0xeull; - nlm_mtcr(XLP_LSU_DEFEATURE, reg); + nlm_mtcr(LSU_DEFEATURE, reg); - reg = nlm_mfcr(XLP_SCHED_DEFEATURE); + reg = nlm_mfcr(SCHED_DEFEATURE); /* Experimental: Disable BRU accepting ALU ops - A0 errata */ reg |= (1 << 24); - nlm_mtcr(XLP_SCHED_DEFEATURE, reg); + nlm_mtcr(SCHED_DEFEATURE, reg); } static void @@ -281,8 +280,9 @@ mips_init(void) unsigned int platform_get_timecount(struct timecounter *tc __unused) { + uint64_t count = nlm_pic_read_timer(xlp_pic_base, PIC_CLOCK_TIMER); - return ((unsigned int)~nlm_pic_read_systimer(xlp_pic_base, 7)); + return (unsigned int)~count; } static void @@ -292,21 +292,21 @@ xlp_pic_init(void) platform_get_timecount, /* get_timecount */ 0, /* no poll_pps */ ~0U, /* counter_mask */ - XLP_PIC_TIMER_FREQ, /* frequency */ + XLP_IO_CLK, /* frequency */ "XLRPIC", /* name */ 2000, /* quality (adjusted in code) */ }; int i; - xlp_pic_base = nlm_regbase_pic(0); /* TOOD: Add other nodes */ + xlp_pic_base = nlm_get_pic_regbase(0); /* TOOD: Add other nodes */ printf("Initializing PIC...@%jx\n", (uintmax_t)xlp_pic_base); /* Bind all PIC irqs to cpu 0 */ - for(i = 0; i < XLP_PIC_MAX_IRT; i++) { - nlm_pic_write_irt_raw(xlp_pic_base, i, 0, 0, 1, 0, + for(i = 0; i < PIC_NUM_IRTS; i++) { + nlm_pic_write_irt(xlp_pic_base, i, 0, 0, 1, 0, 1, 0, 0x1); } - nlm_pic_set_systimer(xlp_pic_base, 7, ~0ULL, 0, 0, 0, 0); + nlm_pic_set_timer(xlp_pic_base, PIC_CLOCK_TIMER, ~0ULL, 0, 0); platform_timecounter = &pic_timecounter; } @@ -322,15 +322,15 @@ xlp_pic_init(void) static void xlp_mem_init(void) { - uint64_t bridgebase = nlm_regbase_bridge(0); /* TOOD: Add other nodes */ + uint64_t bridgebase = nlm_get_bridge_regbase(0); /* TOOD: Add other nodes */ vm_size_t physsz = 0; uint64_t base, lim, val; int i, j; for (i = 0, j = 0; i < 8; i++) { - val = nlm_rdreg_bridge(bridgebase, XLP_BRIDGE_DRAM_BAR_REG(i)); + val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_BAR(i)); base = ((val >> 12) & 0xfffff) << 20; - val = nlm_rdreg_bridge(bridgebase, XLP_BRIDGE_DRAM_LIMIT_REG(i)); + val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_LIMIT(i)); lim = ((val >> 12) & 0xfffff) << 20; /* BAR not enabled */ @@ -396,17 +396,22 @@ xlp_mem_init(void) /* setup final entry with 0 */ phys_avail[j] = phys_avail[j + 1] = 0; + + /* copy phys_avail to dump_avail */ + for(i = 0; i <= j + 1; i++) + dump_avail[i] = phys_avail[i]; + realmem = physmem = btoc(physsz); } static uint32_t xlp_get_cpu_frequency(void) { - uint64_t sysbase = nlm_regbase_sys(0); + uint64_t sysbase = nlm_get_sys_regbase(0); unsigned int pll_divf, pll_divr, dfs_div, num, denom; uint32_t val; - val = nlm_rdreg_sys(sysbase, XLP_SYS_POWER_ON_RESET_REG); + val = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG); pll_divf = (val >> 10) & 0x7f; pll_divr = (val >> 8) & 0x3; dfs_div = (val >> 17) & 0x3; @@ -520,9 +525,9 @@ platform_trap_enter(void) void platform_reset(void) { - uint64_t sysbase = nlm_regbase_sys(0); + uint64_t sysbase = nlm_get_sys_regbase(0); - nlm_wreg_sys(sysbase, XLP_SYS_CHIP_RESET_REG, 1); + nlm_write_sys_reg(sysbase, SYS_CHIP_RESET, 1); for(;;) __asm __volatile("wait"); } @@ -544,7 +549,7 @@ int platform_start_ap(int cpuid) { uint32_t coremask, val; - uint64_t sysbase = nlm_regbase_sys(0); + uint64_t sysbase = nlm_get_sys_regbase(0); int hwtid = xlp_cpuid_to_hwtid[cpuid]; int core, thr; @@ -555,21 +560,21 @@ platform_start_ap(int cpuid) coremask = 1u << core; /* Enable core clock */ - val = nlm_rdreg_sys(sysbase, XLP_SYS_CORE_DFS_DIS_CTRL_REG); + val = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL); val &= ~coremask; - nlm_wreg_sys(sysbase, XLP_SYS_CORE_DFS_DIS_CTRL_REG, val); + nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, val); /* Remove CPU Reset */ - val = nlm_rdreg_sys(sysbase, XLP_SYS_CPU_RESET_REG); + val = nlm_read_sys_reg(sysbase, SYS_CPU_RESET); val &= ~coremask & 0xff; - nlm_wreg_sys(sysbase, XLP_SYS_CPU_RESET_REG, val); + nlm_write_sys_reg(sysbase, SYS_CPU_RESET, val); if (bootverbose) printf("Waking up core %d ...", core); /* Poll for CPU to mark itself coherent */ do { - val = nlm_rdreg_sys(sysbase, XLP_SYS_CPU_NONCOHERENT_MODE_REG); + val = nlm_read_sys_reg(sysbase, SYS_CPU_NONCOHERENT_MODE); } while ((val & coremask) != 0); if (bootverbose) printf("Done\n"); @@ -628,7 +633,7 @@ void platform_ipi_send(int cpuid) { - nlm_pic_send_ipi(xlp_pic_base, 0, xlp_cpuid_to_hwtid[cpuid], + nlm_pic_send_ipi(xlp_pic_base, xlp_cpuid_to_hwtid[cpuid], platform_ipi_intrnum(), 0); } diff --git a/sys/mips/nlm/xlp_pci.c b/sys/mips/nlm/xlp_pci.c new file mode 100644 index 0000000000000..09e214ebab934 --- /dev/null +++ b/sys/mips/nlm/xlp_pci.c @@ -0,0 +1,666 @@ +/*- + * Copyright (c) 2003-2009 RMI Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of RMI Corporation, nor the names of its contributors, + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * NETLOGIC_BSD */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/types.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/malloc.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/rman.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/pmap.h> + +#include <sys/pciio.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/uart/uart.h> +#include <dev/uart/uart_bus.h> +#include <dev/uart/uart_cpu.h> + +#include <machine/bus.h> +#include <machine/md_var.h> +#include <machine/intr_machdep.h> +#include <machine/cpuregs.h> + +#include <mips/nlm/hal/haldefs.h> +#include <mips/nlm/interrupt.h> +#include <mips/nlm/hal/iomap.h> +#include <mips/nlm/hal/mips-extns.h> +#include <mips/nlm/hal/pic.h> +#include <mips/nlm/hal/pcibus.h> +#include <mips/nlm/hal/uart.h> +#include <mips/nlm/xlp.h> + +#include "pcib_if.h" + +struct xlp_pcib_softc { + bus_dma_tag_t sc_pci_dmat; /* PCI DMA tag pointer */ +}; + +static devclass_t pcib_devclass; +static struct rman irq_rman, port_rman, mem_rman, emul_rman; + +static void +xlp_pci_init_resources(void) +{ + + irq_rman.rm_start = 0; + irq_rman.rm_end = 255; + irq_rman.rm_type = RMAN_ARRAY; + irq_rman.rm_descr = "PCI Mapped Interrupts"; + if (rman_init(&irq_rman) + || rman_manage_region(&irq_rman, 0, 255)) + panic("pci_init_resources irq_rman"); + + port_rman.rm_start = 0; + port_rman.rm_end = ~0ul; + port_rman.rm_type = RMAN_ARRAY; + port_rman.rm_descr = "I/O ports"; + if (rman_init(&port_rman) + || rman_manage_region(&port_rman, 0x14000000UL, 0x15ffffffUL)) + panic("pci_init_resources port_rman"); + + mem_rman.rm_start = 0; + mem_rman.rm_end = ~0ul; + mem_rman.rm_type = RMAN_ARRAY; + mem_rman.rm_descr = "I/O memory"; + if (rman_init(&mem_rman) + || rman_manage_region(&mem_rman, 0xd0000000ULL, 0xdfffffffULL)) + panic("pci_init_resources mem_rman"); + + emul_rman.rm_start = 0; + emul_rman.rm_end = ~0ul; + emul_rman.rm_type = RMAN_ARRAY; + emul_rman.rm_descr = "Emulated MEMIO"; + if (rman_init(&emul_rman) + || rman_manage_region(&emul_rman, 0x18000000ULL, 0x18ffffffULL)) + panic("pci_init_resources emul_rman"); + +} + +static int +xlp_pcib_probe(device_t dev) +{ + + device_set_desc(dev, "XLP PCI bus"); + + xlp_pci_init_resources(); + return (0); +} + +static int +xlp_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + + switch (which) { + case PCIB_IVAR_DOMAIN: + *result = 0; + return (0); + case PCIB_IVAR_BUS: + *result = 0; + return (0); + } + return (ENOENT); +} + +static int +xlp_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t result) +{ + switch (which) { + case PCIB_IVAR_DOMAIN: + return (EINVAL); + case PCIB_IVAR_BUS: + return (EINVAL); + } + return (ENOENT); +} + +static int +xlp_pcib_maxslots(device_t dev) +{ + + return (PCI_SLOTMAX); +} + +static u_int32_t +xlp_pcib_read_config(device_t dev, u_int b, u_int s, u_int f, + u_int reg, int width) +{ + uint32_t data = 0; + uint64_t cfgaddr; + int regindex = reg/sizeof(uint32_t); + + cfgaddr = nlm_pcicfg_base(XLP_HDR_OFFSET(0, b, s, f)); + if ((width == 2) && (reg & 1)) + return 0xFFFFFFFF; + else if ((width == 4) && (reg & 3)) + return 0xFFFFFFFF; + + data = nlm_read_pci_reg(cfgaddr, regindex); + + /* + * Fix up read data in some SoC devices + * to emulate complete PCIe header + */ + if (b == 0) { + int dev = s % 8; + + /* Fake intpin on config read for UART/I2C, USB, SD/Flash */ + if (regindex == 0xf && + (dev == 6 || dev == 2 || dev == 7)) + data |= 0x1 << 8; /* Fake int pin */ + } + + if (width == 1) + return ((data >> ((reg & 3) << 3)) & 0xff); + else if (width == 2) + return ((data >> ((reg & 3) << 3)) & 0xffff); + else + return (data); +} + +static void +xlp_pcib_write_config(device_t dev, u_int b, u_int s, u_int f, + u_int reg, u_int32_t val, int width) +{ + uint64_t cfgaddr; + uint32_t data = 0; + int regindex = reg / sizeof(uint32_t); + + cfgaddr = nlm_pcicfg_base(XLP_HDR_OFFSET(0, b, s, f)); + if ((width == 2) && (reg & 1)) + return; + else if ((width == 4) && (reg & 3)) + return; + + if (width == 1) { + data = nlm_read_pci_reg(cfgaddr, regindex); + data = (data & ~(0xff << ((reg & 3) << 3))) | + (val << ((reg & 3) << 3)); + } else if (width == 2) { + data = nlm_read_pci_reg(cfgaddr, regindex); + data = (data & ~(0xffff << ((reg & 3) << 3))) | + (val << ((reg & 3) << 3)); + } else { + data = val; + } + + nlm_write_pci_reg(cfgaddr, regindex, data); + + return; +} + +static int +xlp_pcib_attach(device_t dev) +{ + struct xlp_pcib_softc *sc; + sc = device_get_softc(dev); + + device_add_child(dev, "pci", 0); + bus_generic_attach(dev); + + return (0); +} + +static void +xlp_pcib_identify(driver_t * driver, device_t parent) +{ + + BUS_ADD_CHILD(parent, 0, "pcib", 0); +} + +/* + * XLS PCIe can have upto 4 links, and each link has its on IRQ + * Find the link on which the device is on + */ +static int +xlp_pcie_link(device_t pcib, device_t dev) +{ + device_t parent, tmp; + + /* find the lane on which the slot is connected to */ + printf("xlp_pcie_link : bus %s dev %s\n", device_get_nameunit(pcib), + device_get_nameunit(dev)); + tmp = dev; + while (1) { + parent = device_get_parent(tmp); + if (parent == NULL || parent == pcib) { + device_printf(dev, "Cannot find parent bus\n"); + return (-1); + } + if (strcmp(device_get_nameunit(parent), "pci0") == 0) + break; + tmp = parent; + } + return (pci_get_function(tmp)); +} + +/* + * Find the IRQ for the link, each link has a different interrupt + * at the XLP pic + */ +static int +xlp_pcie_link_irt(int link) +{ + + if( (link < 0) || (link > 3)) + return (-1); + + return PIC_IRT_PCIE_LINK_INDEX(link); +} + +static int +xlp_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) +{ + int i, link; + + /* + * Each link has 32 MSIs that can be allocated, but for now + * we only support one device per link. + * msi_alloc() equivalent is needed when we start supporting + * bridges on the PCIe link. + */ + link = xlp_pcie_link(pcib, dev); + if (link == -1) + return (ENXIO); + + /* + * encode the irq so that we know it is a MSI interrupt when we + * setup interrupts + */ + for (i = 0; i < count; i++) + irqs[i] = 64 + link * 32 + i; + + return (0); +} + +static int +xlp_release_msi(device_t pcib, device_t dev, int count, int *irqs) +{ + device_printf(dev, "%s: msi release %d\n", device_get_nameunit(pcib), + count); + return (0); +} + +static int +xlp_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, + uint32_t *data) +{ + int msi, irt; + + if (irq >= 64) { + msi = irq - 64; + *addr = MIPS_MSI_ADDR(0); + + irt = xlp_pcie_link_irt(msi/32); + if (irt != -1) + *data = MIPS_MSI_DATA(xlp_irt_to_irq(irt)); + return (0); + } else { + device_printf(dev, "%s: map_msi for irq %d - ignored", + device_get_nameunit(pcib), irq); + return (ENXIO); + } +} + +static void +bridge_pcie_ack(int irq) +{ + uint32_t node,reg; + uint64_t base; + + node = nlm_nodeid(); + reg = PCIE_MSI_STATUS; + + switch(irq) { + case PIC_PCIE_0_IRQ: + base = nlm_pcicfg_base(XLP_IO_PCIE0_OFFSET(node)); + break; + case PIC_PCIE_1_IRQ: + base = nlm_pcicfg_base(XLP_IO_PCIE1_OFFSET(node)); + break; + case PIC_PCIE_2_IRQ: + base = nlm_pcicfg_base(XLP_IO_PCIE2_OFFSET(node)); + break; + case PIC_PCIE_3_IRQ: + base = nlm_pcicfg_base(XLP_IO_PCIE3_OFFSET(node)); + break; + default: + return; + } + + nlm_write_pci_reg(base, reg, 0xFFFFFFFF); + + return; +} + +static int +mips_platform_pci_setup_intr(device_t dev, device_t child, + struct resource *irq, int flags, driver_filter_t *filt, + driver_intr_t *intr, void *arg, void **cookiep) +{ + int error = 0; + int xlpirq; + int node,base,val,link; + void *extra_ack; + + error = rman_activate_resource(irq); + if (error) + return error; + if (rman_get_start(irq) != rman_get_end(irq)) { + device_printf(dev, "Interrupt allocation %lu != %lu\n", + rman_get_start(irq), rman_get_end(irq)); + return (EINVAL); + } + xlpirq = rman_get_start(irq); + device_printf(dev, "setup intr %d\n", xlpirq); + + if (strcmp(device_get_name(dev), "pcib") != 0) { + device_printf(dev, "ret 0 on dev\n"); + return (0); + } + + /* + * temporary hack for MSI, we support just one device per + * link, and assign the link interrupt to the device interrupt + */ + if (xlpirq >= 64) { + xlpirq -= 64; + if (xlpirq % 32 != 0) + return (0); + + node = nlm_nodeid(); + link = (xlpirq / 32); + base = nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node,link)); + + /* MSI Interrupt Vector enable at bridge's configuration */ + nlm_write_pci_reg(base, PCIE_MSI_EN, PCIE_MSI_VECTOR_INT_EN); + + val = nlm_read_pci_reg(base, PCIE_INT_EN0); + /* MSI Interrupt enable at bridge's configuration */ + nlm_write_pci_reg(base, PCIE_INT_EN0, + (val | PCIE_MSI_INT_EN)); + + /* legacy interrupt disable at bridge */ + val = nlm_read_pci_reg(base, PCIE_BRIDGE_CMD); + nlm_write_pci_reg(base, PCIE_BRIDGE_CMD, + (val | PCIM_CMD_INTxDIS)); + + /* MSI address update at bridge */ + val = nlm_read_pci_reg(base, PCIE_BRIDGE_MSI_ADDRL); + nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_ADDRL, + (val | MSI_MIPS_ADDR_BASE)); + + val = nlm_read_pci_reg(base, PCIE_BRIDGE_MSI_CAP); + /* MSI capability enable at bridge */ + nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_CAP, + (val | + (PCIM_MSICTRL_MSI_ENABLE << 16) | + (PCIM_MSICTRL_MMC_32 << 16))); + + xlpirq = xlp_pcie_link_irt(xlpirq / 32); + if (xlpirq == -1) + return (EINVAL); + xlpirq = xlp_irt_to_irq(xlpirq); + } + /* Set all irqs to CPU 0 for now */ + nlm_pic_write_irt_direct(xlp_pic_base, xlp_irq_to_irt(xlpirq), 1, 0, + PIC_LOCAL_SCHEDULING, xlpirq, 0); + extra_ack = NULL; + if (xlpirq >= PIC_PCIE_0_IRQ && + xlpirq <= PIC_PCIE_3_IRQ) + extra_ack = bridge_pcie_ack; + xlp_establish_intr(device_get_name(child), filt, + intr, arg, xlpirq, flags, cookiep, extra_ack); + + return (0); +} + +static int +mips_platform_pci_teardown_intr(device_t dev, device_t child, + struct resource *irq, void *cookie) +{ + if (strcmp(device_get_name(child), "pci") == 0) { + /* if needed reprogram the pic to clear pcix related entry */ + device_printf(dev, "teardown intr\n"); + } + return (bus_generic_teardown_intr(dev, child, irq, cookie)); +} + +static void +assign_soc_resource(device_t child, int type, u_long *startp, u_long *endp, + u_long *countp, struct rman **rm, bus_space_tag_t *bst, vm_offset_t *va) +{ + int devid = pci_get_device(child); + int inst = pci_get_function(child); + int node = pci_get_slot(child) / 8; + + *rm = NULL; + *va = 0; + *bst = 0; + switch (devid) { + case PCI_DEVICE_ID_NLM_UART: + switch (type) { + case SYS_RES_IRQ: + *startp = *endp = PIC_UART_0_IRQ + inst; + *countp = 1; + break; + case SYS_RES_MEMORY: + *va = nlm_get_uart_regbase(node, inst); + *startp = MIPS_KSEG1_TO_PHYS(va); + *countp = 0x100; + *rm = &emul_rman; + *bst = uart_bus_space_mem; + break; + }; + break; + + case PCI_DEVICE_ID_NLM_EHCI: + if (type == SYS_RES_IRQ) { + if (inst == 0) + *startp = *endp = PIC_EHCI_0_IRQ; + else if (inst == 3) + *startp = *endp = PIC_EHCI_1_IRQ; + else + device_printf(child, "bad instance %d\n", inst); + + *countp = 1; + } + break; + } + + /* default to rmi_bus_space for SoC resources */ + if (type == SYS_RES_MEMORY && *bst == 0) + *bst = rmi_bus_space; +} + +static struct resource * +xlp_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct rman *rm = NULL; + struct resource *rv; + vm_offset_t va = 0; + int needactivate = flags & RF_ACTIVE; + bus_space_tag_t bst = 0; + + /* + * For SoC PCI devices, we have to assign resources correctly + * since the IRQ and MEM resources depend on the block. + * If the address is not from BAR0, then we use emul_rman + */ + if (pci_get_bus(child) == 0 && + pci_get_vendor(child) == PCI_VENDOR_NETLOGIC) + assign_soc_resource(child, type, &start, &end, + &count, &rm, &bst, &va); + if (rm == NULL) { + switch (type) { + case SYS_RES_IRQ: + rm = &irq_rman; + break; + + case SYS_RES_IOPORT: + rm = &port_rman; + break; + + case SYS_RES_MEMORY: + rm = &mem_rman; + break; + + default: + return (0); + } + } + + rv = rman_reserve_resource(rm, start, end, count, flags, child); + if (rv == 0) + return (0); + + rman_set_rid(rv, *rid); + + if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { + if (va == 0) + va = (vm_offset_t)pmap_mapdev(start, count); + if (bst == 0) + bst = rmi_pci_bus_space; + + rman_set_bushandle(rv, va); + rman_set_virtual(rv, (void *)va); + rman_set_bustag(rv, bst); + } + + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv)) { + rman_release_resource(rv); + return (NULL); + } + } + + return (rv); +} + +static int +xlp_pci_release_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + + return (rman_release_resource(r)); +} + +static bus_dma_tag_t +xlp_pci_get_dma_tag(device_t bus, device_t child) +{ + struct xlp_pcib_softc *sc; + + sc = device_get_softc(bus); + return (sc->sc_pci_dmat); +} + +static int +xlp_pci_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + + return (rman_activate_resource(r)); +} + +static int +xlp_pci_deactivate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + + return (rman_deactivate_resource(r)); +} + +static int +mips_pci_route_interrupt(device_t bus, device_t dev, int pin) +{ + int irt, link; + + /* + * Validate requested pin number. + */ + device_printf(bus, "route %s %d", device_get_nameunit(dev), pin); + if ((pin < 1) || (pin > 4)) + return (255); + + link = xlp_pcie_link(bus, dev); + irt = xlp_pcie_link_irt(link); + if (irt != -1) + return (xlp_irt_to_irq(irt)); + + return (255); +} + +static device_method_t xlp_pcib_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, xlp_pcib_identify), + DEVMETHOD(device_probe, xlp_pcib_probe), + DEVMETHOD(device_attach, xlp_pcib_attach), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_read_ivar, xlp_pcib_read_ivar), + DEVMETHOD(bus_write_ivar, xlp_pcib_write_ivar), + DEVMETHOD(bus_alloc_resource, xlp_pci_alloc_resource), + DEVMETHOD(bus_release_resource, xlp_pci_release_resource), + DEVMETHOD(bus_get_dma_tag, xlp_pci_get_dma_tag), + DEVMETHOD(bus_activate_resource, xlp_pci_activate_resource), + DEVMETHOD(bus_deactivate_resource, xlp_pci_deactivate_resource), + DEVMETHOD(bus_setup_intr, mips_platform_pci_setup_intr), + DEVMETHOD(bus_teardown_intr, mips_platform_pci_teardown_intr), + + /* pcib interface */ + DEVMETHOD(pcib_maxslots, xlp_pcib_maxslots), + DEVMETHOD(pcib_read_config, xlp_pcib_read_config), + DEVMETHOD(pcib_write_config, xlp_pcib_write_config), + DEVMETHOD(pcib_route_interrupt, mips_pci_route_interrupt), + + DEVMETHOD(pcib_alloc_msi, xlp_alloc_msi), + DEVMETHOD(pcib_release_msi, xlp_release_msi), + DEVMETHOD(pcib_map_msi, xlp_map_msi), + + {0, 0} +}; + +static driver_t xlp_pcib_driver = { + "pcib", + xlp_pcib_methods, + sizeof(struct xlp_pcib_softc), +}; + +DRIVER_MODULE(pcib, nexus, xlp_pcib_driver, pcib_devclass, 0, 0); diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 2777e22c9d25e..ca8586c5c12fc 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -321,6 +321,7 @@ SUBDIR= ${_3dfx} \ vr \ vte \ vx \ + ${_vxge} \ wb \ ${_wi} \ wlan \ @@ -474,6 +475,7 @@ _sppp= sppp _stg= stg _streams= streams _svr4= svr4 +_vxge= vxge _wi= wi _xe= xe .if ${MK_ZFS} != "no" || defined(ALL_MODULES) @@ -629,6 +631,7 @@ _tpm= tpm _twa= twa _vesa= vesa _vmm= vmm +_vxge= vxge _x86bios= x86bios _wi= wi _wpi= wpi diff --git a/sys/modules/dcons/Makefile b/sys/modules/dcons/Makefile index 604242503971c..4a08b65923818 100644 --- a/sys/modules/dcons/Makefile +++ b/sys/modules/dcons/Makefile @@ -5,7 +5,7 @@ KMOD = dcons SRCS = dcons.c dcons.h dcons_os.c dcons_os.h \ - opt_dcons.h opt_kdb.h opt_ddb.h opt_gdb.h opt_comconsole.h + opt_dcons.h opt_kdb.h opt_ddb.h opt_gdb.h .if !defined(KERNBUILDDIR) opt_kdb.h: @@ -13,9 +13,6 @@ opt_kdb.h: opt_ddb.h: echo "#define DDB 1" > $@ - -opt_comconsole.h: - echo "#define ALT_BREAK_TO_DEBUGGER 1" > $@ .endif CFLAGS+= -I${.CURDIR}/../.. diff --git a/sys/modules/ipfw/Makefile b/sys/modules/ipfw/Makefile index 81ce838085d9d..ec9b3cc49c1af 100644 --- a/sys/modules/ipfw/Makefile +++ b/sys/modules/ipfw/Makefile @@ -8,7 +8,7 @@ KMOD= ipfw SRCS= ip_fw2.c ip_fw_pfil.c SRCS+= ip_fw_dynamic.c ip_fw_log.c SRCS+= ip_fw_sockopt.c ip_fw_table.c -SRCS+= opt_inet6.h opt_ipsec.h +SRCS+= opt_inet6.h opt_ipfw.h opt_ipsec.h CFLAGS+= -DIPFIREWALL CFLAGS+= -I${.CURDIR}/../../contrib/pf diff --git a/sys/modules/netgraph/ipfw/Makefile b/sys/modules/netgraph/ipfw/Makefile index b40abcfbf57c2..cc3f0f24e2a0a 100644 --- a/sys/modules/netgraph/ipfw/Makefile +++ b/sys/modules/netgraph/ipfw/Makefile @@ -1,6 +1,20 @@ # $FreeBSD$ +.include <bsd.own.mk> + KMOD= ng_ipfw -SRCS= ng_ipfw.c +SRCS= ng_ipfw.c opt_inet.h opt_inet6.h + +.if !defined(KERNBUILDDIR) + +.if ${MK_INET_SUPPORT} != "no" +opt_inet.h: + echo "#define INET 1" > ${.TARGET} +.endif +.if ${MK_INET6_SUPPORT} != "no" +opt_inet6.h: + echo "#define INET6 1" > ${.TARGET} +.endif +.endif .include <bsd.kmod.mk> diff --git a/sys/modules/portalfs/Makefile b/sys/modules/portalfs/Makefile index ef6955b5d1416..dcd5966c26a85 100644 --- a/sys/modules/portalfs/Makefile +++ b/sys/modules/portalfs/Makefile @@ -4,6 +4,7 @@ KMOD= portalfs SRCS= vnode_if.h \ - portal_vfsops.c portal_vnops.c + portal_vfsops.c portal_vnops.c \ + opt_capsicum.h .include <bsd.kmod.mk> diff --git a/sys/modules/sio/Makefile b/sys/modules/sio/Makefile index dc683ba31f3f0..057e9c614d42e 100644 --- a/sys/modules/sio/Makefile +++ b/sys/modules/sio/Makefile @@ -7,7 +7,7 @@ KMOD= sio SRCS= bus_if.h card_if.h device_if.h isa_if.h pci_if.h serdev_if.h \ - opt_comconsole.h opt_compat.h opt_gdb.h opt_kdb.h opt_sio.h \ + opt_compat.h opt_gdb.h opt_kdb.h opt_sio.h \ sio.c sio_pccard.c sio_pci.c sio_puc.c pccarddevs.h .if ${MACHINE} == "pc98" SRCS+= sio_cbus.c diff --git a/sys/net/bpf.c b/sys/net/bpf.c index e5165731dae7b..79c77a93278c1 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -652,10 +652,10 @@ bpf_dtor(void *data) if (d->bd_bif) bpf_detachd(d); mtx_unlock(&bpf_mtx); - selwakeuppri(&d->bd_sel, PRINET); #ifdef MAC mac_bpfdesc_destroy(d); #endif /* MAC */ + seldrain(&d->bd_sel); knlist_destroy(&d->bd_sel.si_note); callout_drain(&d->bd_callout); bpf_freed(d); diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 5ac4ef002dc61..c251653841f1a 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -85,6 +85,7 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/protosw.h> #include <sys/systm.h> +#include <sys/jail.h> #include <sys/time.h> #include <sys/socket.h> /* for net/if.h */ #include <sys/sockio.h> @@ -560,7 +561,8 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) { struct bridge_softc *sc, *sc2; struct ifnet *bifp, *ifp; - int retry; + int fb, retry; + unsigned long hostid; sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); ifp = sc->sc_ifp = if_alloc(IFT_ETHER); @@ -593,17 +595,30 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) IFQ_SET_READY(&ifp->if_snd); /* - * Generate a random ethernet address with a locally administered - * address. + * Generate an ethernet address with a locally administered address. * * Since we are using random ethernet addresses for the bridge, it is * possible that we might have address collisions, so make sure that * this hardware address isn't already in use on another bridge. + * The first try uses the hostid and falls back to arc4rand(). */ + fb = 0; + getcredhostid(curthread->td_ucred, &hostid); for (retry = 1; retry != 0;) { - arc4rand(sc->sc_defaddr, ETHER_ADDR_LEN, 1); - sc->sc_defaddr[0] &= ~1; /* clear multicast bit */ - sc->sc_defaddr[0] |= 2; /* set the LAA bit */ + if (fb || hostid == 0) { + arc4rand(sc->sc_defaddr, ETHER_ADDR_LEN, 1); + sc->sc_defaddr[0] &= ~1;/* clear multicast bit */ + sc->sc_defaddr[0] |= 2; /* set the LAA bit */ + } else { + sc->sc_defaddr[0] = 0x2; + sc->sc_defaddr[1] = (hostid >> 24) & 0xff; + sc->sc_defaddr[2] = (hostid >> 16) & 0xff; + sc->sc_defaddr[3] = (hostid >> 8 ) & 0xff; + sc->sc_defaddr[4] = hostid & 0xff; + sc->sc_defaddr[5] = ifp->if_dunit & 0xff; + } + + fb = 1; retry = 0; mtx_lock(&bridge_list_mtx); LIST_FOREACH(sc2, &bridge_list, sc_list) { @@ -3083,6 +3098,7 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) args.m = *mp; args.oif = ifp; args.next_hop = NULL; + args.next_hop6 = NULL; args.eh = &eh2; args.inp = NULL; /* used by ipfw uid/gid/jail rules */ i = V_ip_fw_chk_ptr(&args); diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index aa8113bf550d5..1d16ae6c660e7 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -499,6 +499,7 @@ ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared) args.m = m; /* the packet we are looking at */ args.oif = dst; /* destination, if any */ args.next_hop = NULL; /* we do not support forward yet */ + args.next_hop6 = NULL; /* we do not support forward yet */ args.eh = &save_eh; /* MAC header for bridged/MAC packets */ args.inp = NULL; /* used by ipfw uid/gid/jail rules */ i = V_ip_fw_chk_ptr(&args); diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c index d540966ab4cf3..6a3eb93e5a579 100644 --- a/sys/net/if_lagg.c +++ b/sys/net/if_lagg.c @@ -208,6 +208,7 @@ static moduledata_t lagg_mod = { }; DECLARE_MODULE(if_lagg, lagg_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); +MODULE_VERSION(if_lagg, 1); #if __FreeBSD_version >= 800000 /* diff --git a/sys/net/if_tap.c b/sys/net/if_tap.c index ad29da044997e..08c669ab3b89d 100644 --- a/sys/net/if_tap.c +++ b/sys/net/if_tap.c @@ -214,6 +214,7 @@ tap_destroy(struct tap_softc *tp) KASSERT(!(tp->tap_flags & TAP_OPEN), ("%s flags is out of sync", ifp->if_xname)); + seldrain(&tp->tap_rsel); knlist_destroy(&tp->tap_rsel.si_note); destroy_dev(tp->tap_dev); ether_ifdetach(ifp); diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c index d74c9fec28520..c5328848c7b72 100644 --- a/sys/net/if_tun.c +++ b/sys/net/if_tun.c @@ -259,6 +259,7 @@ tun_destroy(struct tun_softc *tp) if_detach(TUN2IFP(tp)); if_free(TUN2IFP(tp)); destroy_dev(dev); + seldrain(&tp->tun_rsel); knlist_destroy(&tp->tun_rsel.si_note); mtx_destroy(&tp->tun_mtx); cv_destroy(&tp->tun_cv); diff --git a/sys/net/radix_mpath.c b/sys/net/radix_mpath.c index ea84e5ce2282e..ee7826f6e3e9a 100644 --- a/sys/net/radix_mpath.c +++ b/sys/net/radix_mpath.c @@ -96,10 +96,7 @@ rt_mpath_matchgate(struct rtentry *rt, struct sockaddr *gate) { struct radix_node *rn; - if (!rn_mpath_next((struct radix_node *)rt)) - return rt; - - if (!gate) + if (!gate || !rt->rt_gateway) return NULL; /* beyond here, we use rn as the master copy */ diff --git a/sys/net/route.c b/sys/net/route.c index 9c7dfac542fab..d42b4c73b40eb 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -1478,7 +1478,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) */ bzero((caddr_t)&info, sizeof(info)); info.rti_ifa = ifa; - info.rti_flags = flags | ifa->ifa_flags; + info.rti_flags = flags | (ifa->ifa_flags & ~IFA_RTSELF); info.rti_info[RTAX_DST] = dst; /* * doing this for compatibility reasons diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c index 61c84e936f388..c49a17803bb7d 100644 --- a/sys/net80211/ieee80211_ht.c +++ b/sys/net80211/ieee80211_ht.c @@ -2207,7 +2207,7 @@ bar_tx_complete(struct ieee80211_node *ni, void *arg, int status) callout_pending(&tap->txa_timer)) { struct ieee80211com *ic = ni->ni_ic; - if (status) /* ACK'd */ + if (status == 0) /* ACK'd */ bar_stop_timer(tap); ic->ic_bar_response(ni, tap, status); /* NB: just let timer expire so we pace requests */ @@ -2219,7 +2219,7 @@ ieee80211_bar_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int status) { - if (status != 0) { /* got ACK */ + if (status == 0) { /* got ACK */ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni, "BAR moves BA win <%u:%u> (%u frames) txseq %u tid %u", tap->txa_start, @@ -2309,11 +2309,15 @@ ieee80211_send_bar(struct ieee80211_node *ni, ni, "send BAR: tid %u ctl 0x%x start %u (attempt %d)", tid, barctl, seq, tap->txa_attempts); + /* + * ic_raw_xmit will free the node reference + * regardless of queue/TX success or failure. + */ ret = ic->ic_raw_xmit(ni, m, NULL); if (ret != 0) { /* xmit failed, clear state flag */ tap->txa_flags &= ~IEEE80211_AGGR_BARPEND; - goto bad; + return ret; } /* XXX hack against tx complete happening before timer is started */ if (tap->txa_flags & IEEE80211_AGGR_BARPEND) diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index 6020144ef7c19..bcd3c2bdac5fe 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -2792,6 +2792,8 @@ ieee80211_beacon_update(struct ieee80211_node *ni, struct ieee80211com *ic = ni->ni_ic; int len_changed = 0; uint16_t capinfo; + struct ieee80211_frame *wh; + ieee80211_seq seqno; IEEE80211_LOCK(ic); /* @@ -2823,6 +2825,12 @@ ieee80211_beacon_update(struct ieee80211_node *ni, return 1; /* just assume length changed */ } + wh = mtod(m, struct ieee80211_frame *); + seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; + *(uint16_t *)&wh->i_seq[0] = + htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); + M_SEQNO_SET(m, seqno); + /* XXX faster to recalculate entirely or just changes? */ capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); *bo->bo_caps = htole16(capinfo); diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index 8c8ee52981564..8dee3f7f32d46 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -1501,6 +1501,11 @@ ieee80211_csa_startswitch(struct ieee80211com *ic, ieee80211_notify_csa(ic, c, mode, count); } +/* + * Complete the channel switch by transitioning all CSA VAPs to RUN. + * This is called by both the completion and cancellation functions + * so each VAP is placed back in the RUN state and can thus transmit. + */ static void csa_completeswitch(struct ieee80211com *ic) { @@ -1518,15 +1523,27 @@ csa_completeswitch(struct ieee80211com *ic) * Complete an 802.11h channel switch started by ieee80211_csa_startswitch. * We clear state and move all vap's in CSA state to RUN state * so they can again transmit. + * + * Although this may not be completely correct, update the BSS channel + * for each VAP to the newly configured channel. The setcurchan sets + * the current operating channel for the interface (so the radio does + * switch over) but the VAP BSS isn't updated, leading to incorrectly + * reported information via ioctl. */ void ieee80211_csa_completeswitch(struct ieee80211com *ic) { + struct ieee80211vap *vap; + IEEE80211_LOCK_ASSERT(ic); KASSERT(ic->ic_flags & IEEE80211_F_CSAPENDING, ("csa not pending")); ieee80211_setcurchan(ic, ic->ic_csa_newchan); + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if (vap->iv_state == IEEE80211_S_CSA) + vap->iv_bss->ni_chan = ic->ic_curchan; + csa_completeswitch(ic); } diff --git a/sys/net80211/ieee80211_scan_sta.c b/sys/net80211/ieee80211_scan_sta.c index 987a26f19b2bd..6f5e9d256fc9a 100644 --- a/sys/net80211/ieee80211_scan_sta.c +++ b/sys/net80211/ieee80211_scan_sta.c @@ -238,6 +238,7 @@ sta_add(struct ieee80211_scan_state *ss, const uint8_t *macaddr = wh->i_addr2; struct ieee80211vap *vap = ss->ss_vap; struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_channel *c; struct sta_entry *se; struct ieee80211_scan_entry *ise; int hash; @@ -300,7 +301,6 @@ found: * association on the wrong channel. */ if (sp->status & IEEE80211_BPARSE_OFFCHAN) { - struct ieee80211_channel *c; /* * Off-channel, locate the home/bss channel for the sta * using the value broadcast in the DSPARMS ie. We know @@ -317,6 +317,14 @@ found: } } else ise->se_chan = ic->ic_curchan; + if (IEEE80211_IS_CHAN_HT(ise->se_chan) && sp->htcap == NULL) { + /* Demote legacy networks to a non-HT channel. */ + c = ieee80211_find_channel(ic, ise->se_chan->ic_freq, + ise->se_chan->ic_flags & ~IEEE80211_CHAN_HT); + KASSERT(c != NULL, + ("no legacy channel %u", ise->se_chan->ic_ieee)); + ise->se_chan = c; + } ise->se_fhdwell = sp->fhdwell; ise->se_fhindex = sp->fhindex; ise->se_erp = sp->erp; diff --git a/sys/netgraph/ng_ether.c b/sys/netgraph/ng_ether.c index afedaa37a8f78..15e8b2d3625c6 100644 --- a/sys/netgraph/ng_ether.c +++ b/sys/netgraph/ng_ether.c @@ -604,9 +604,6 @@ ng_ether_rcvdata(hook_p hook, item_p item) NG_FREE_ITEM(item); panic("%s: weird hook", __func__); -#ifdef RESTARTABLE_PANICS /* so we don't get an error msg in LINT */ - return (0); -#endif } /* diff --git a/sys/netgraph/ng_ipfw.c b/sys/netgraph/ng_ipfw.c index 68bd89c09e8bc..4f1bc0ee94d26 100644 --- a/sys/netgraph/ng_ipfw.c +++ b/sys/netgraph/ng_ipfw.c @@ -26,6 +26,9 @@ * $FreeBSD$ */ +#include "opt_inet.h" +#include "opt_inet6.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -47,6 +50,8 @@ #include <netinet/ip_fw.h> #include <netinet/ipfw/ip_fw_private.h> #include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> #include <netgraph/ng_message.h> #include <netgraph/ng_parse.h> @@ -224,6 +229,7 @@ ng_ipfw_rcvdata(hook_p hook, item_p item) struct m_tag *tag; struct ipfw_rule_ref *r; struct mbuf *m; + struct ip *ip; NGI_GET_M(item, m); NG_FREE_ITEM(item); @@ -234,23 +240,47 @@ ng_ipfw_rcvdata(hook_p hook, item_p item) return (EINVAL); /* XXX: find smth better */ }; + if (m->m_len < sizeof(struct ip) && + (m = m_pullup(m, sizeof(struct ip))) == NULL) + return (EINVAL); + + ip = mtod(m, struct ip *); + r = (struct ipfw_rule_ref *)(tag + 1); if (r->info & IPFW_INFO_IN) { - ip_input(m); + switch (ip->ip_v) { +#ifdef INET + case IPVERSION: + ip_input(m); + break; +#endif +#ifdef INET6 + case IPV6_VERSION >> 4: + ip6_input(m); + break; +#endif + default: + NG_FREE_M(m); + return (EINVAL); + } return (0); } else { - struct ip *ip; - - if (m->m_len < sizeof(struct ip) && - (m = m_pullup(m, sizeof(struct ip))) == NULL) + switch (ip->ip_v) { +#ifdef INET + case IPVERSION: + SET_HOST_IPLEN(ip); + return (ip_output(m, NULL, NULL, IP_FORWARDING, + NULL, NULL)); +#endif +#ifdef INET6 + case IPV6_VERSION >> 4: + return (ip6_output(m, NULL, NULL, 0, NULL, + NULL, NULL)); +#endif + default: return (EINVAL); - - ip = mtod(m, struct ip *); - - SET_HOST_IPLEN(ip); - - return ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); - } + } + } } static int diff --git a/sys/netgraph/ng_mppc.c b/sys/netgraph/ng_mppc.c index 75194e8df187d..cb6531619d314 100644 --- a/sys/netgraph/ng_mppc.c +++ b/sys/netgraph/ng_mppc.c @@ -404,9 +404,6 @@ ng_mppc_rcvdata(hook_p hook, item_p item) /* Oops */ panic("%s: unknown hook", __func__); -#ifdef RESTARTABLE_PANICS - return (EINVAL); -#endif } /* diff --git a/sys/netgraph/ng_parse.c b/sys/netgraph/ng_parse.c index 1215df124b5e9..fbbefc62d9898 100644 --- a/sys/netgraph/ng_parse.c +++ b/sys/netgraph/ng_parse.c @@ -374,9 +374,6 @@ ng_int8_unparse(const struct ng_parse_type *type, break; default: panic("%s: unknown type", __func__); -#ifdef RESTARTABLE_PANICS - return(0); -#endif } if ((error = ng_parse_append(&cbuf, &cbuflen, fmt, fval)) != 0) return (error); @@ -473,9 +470,6 @@ ng_int16_unparse(const struct ng_parse_type *type, break; default: panic("%s: unknown type", __func__); -#ifdef RESTARTABLE_PANICS - return(0); -#endif } if ((error = ng_parse_append(&cbuf, &cbuflen, fmt, fval)) != 0) return (error); @@ -575,9 +569,6 @@ ng_int32_unparse(const struct ng_parse_type *type, break; default: panic("%s: unknown type", __func__); -#ifdef RESTARTABLE_PANICS - return(0); -#endif } if ((error = ng_parse_append(&cbuf, &cbuflen, fmt, fval)) != 0) return (error); @@ -673,9 +664,6 @@ ng_int64_unparse(const struct ng_parse_type *type, break; default: panic("%s: unknown type", __func__); -#ifdef RESTARTABLE_PANICS - return(0); -#endif } if ((error = ng_parse_append(&cbuf, &cbuflen, fmt, fval)) != 0) return (error); diff --git a/sys/netgraph/ng_socket.c b/sys/netgraph/ng_socket.c index f72f8226c76e9..8c819c01429dc 100644 --- a/sys/netgraph/ng_socket.c +++ b/sys/netgraph/ng_socket.c @@ -694,7 +694,7 @@ ng_internalize(struct mbuf *control, struct thread *td) /* Check that the FD given is legit. and change it to a pointer to a * struct file. */ fd = CMSG_DATA(cm); - if ((error = fget(td, fd, &fp)) != 0) + if ((error = fget(td, fd, 0, &fp)) != 0) return (error); /* Depending on what kind of resource it is, act differently. For diff --git a/sys/netinet/in.c b/sys/netinet/in.c index c0901178d990f..4547e395eba9d 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -1037,7 +1037,7 @@ in_addprefix(struct in_ifaddr *target, int flags) IN_IFADDR_RLOCK(); TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if (rtinitflags(ia)) { - p = ia->ia_addr.sin_addr; + p = ia->ia_dstaddr.sin_addr; if (prefix.s_addr != p.s_addr) continue; @@ -1163,7 +1163,8 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags) p.s_addr &= ia->ia_sockmask.sin_addr.s_addr; } - if (prefix.s_addr != p.s_addr) + if ((prefix.s_addr != p.s_addr) || + !(ia->ia_ifp->if_flags & IFF_UP)) continue; /* diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index 29a5d424fddaa..234cae2757949 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -410,6 +410,7 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin, } ip6->ip6_plen = ntohs(ip6->ip6_plen); + break; } #endif default: diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index ff3a67fe61ce5..f6f8fcd876f7d 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -203,6 +203,8 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_CALLRETURN, /* arg1=called rule number */ + O_FORWARD_IP6, /* fwd sockaddr_in6 */ + O_LAST_OPCODE /* not an opcode! */ }; @@ -299,6 +301,14 @@ typedef struct _ipfw_insn_sa { } ipfw_insn_sa; /* + * This is used to forward to a given address (ipv6). + */ +typedef struct _ipfw_insn_sa6 { + ipfw_insn o; + struct sockaddr_in6 sa; +} ipfw_insn_sa6; + +/* * This is used for MAC addr-mask pairs. */ typedef struct _ipfw_insn_mac { diff --git a/sys/netinet/ipfw/ip_fw2.c b/sys/netinet/ipfw/ip_fw2.c index 4e25f9a086d8a..619ce6b91e5bf 100644 --- a/sys/netinet/ipfw/ip_fw2.c +++ b/sys/netinet/ipfw/ip_fw2.c @@ -30,8 +30,8 @@ __FBSDID("$FreeBSD$"); * The FreeBSD IP packet firewall, main file */ -#if !defined(KLD_MODULE) #include "opt_ipfw.h" +#if !defined(KLD_MODULE) #include "opt_ipdivert.h" #include "opt_ipdn.h" #include "opt_inet.h" @@ -107,6 +107,9 @@ static VNET_DEFINE(int, ipfw_vnet_ready) = 0; static VNET_DEFINE(int, fw_deny_unknown_exthdrs); #define V_fw_deny_unknown_exthdrs VNET(fw_deny_unknown_exthdrs) +static VNET_DEFINE(int, fw_permit_single_frag6) = 1; +#define V_fw_permit_single_frag6 VNET(fw_permit_single_frag6) + #ifdef IPFIREWALL_DEFAULT_TO_ACCEPT static int default_to_accept = 1; #else @@ -182,6 +185,9 @@ SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs, CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_deny_unknown_exthdrs), 0, "Deny packets with unknown IPv6 Extension Headers"); +SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, permit_single_frag6, + CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_permit_single_frag6), 0, + "Permit single packet IPv6 fragments"); #endif /* INET6 */ SYSEND @@ -790,6 +796,7 @@ set_match(struct ip_fw_args *args, int slot, * * args->rule Pointer to the last matching rule (in/out) * args->next_hop Socket we are forwarding to (out). + * args->next_hop6 IPv6 next hop we are forwarding to (out). * args->f_id Addresses grabbed from the packet (out) * args->rule.info a cookie depending on rule action * @@ -871,13 +878,14 @@ ipfw_chk(struct ip_fw_args *args) * we have a fragment at this offset of an IPv4 packet. * offset == 0 means that (if this is an IPv4 packet) * this is the first or only fragment. - * For IPv6 offset == 0 means there is no Fragment Header. - * If offset != 0 for IPv6 always use correct mask to - * get the correct offset because we add IP6F_MORE_FRAG - * to be able to dectect the first fragment which would - * otherwise have offset = 0. + * For IPv6 offset|ip6f_mf == 0 means there is no Fragment Header + * or there is a single packet fragement (fragement header added + * without needed). We will treat a single packet fragment as if + * there was no fragment header (or log/block depending on the + * V_fw_permit_single_frag6 sysctl setting). */ u_short offset = 0; + u_short ip6f_mf = 0; /* * Local copies of addresses. They are only valid if we have @@ -971,7 +979,7 @@ do { \ proto = ip6->ip6_nxt; /* Search extension headers to find upper layer protocols */ - while (ulp == NULL) { + while (ulp == NULL && offset == 0) { switch (proto) { case IPPROTO_ICMPV6: PULLUP_TO(hlen, ulp, struct icmp6_hdr); @@ -1016,9 +1024,11 @@ do { \ ext_hd |= EXT_RTHDR2; break; default: - printf("IPFW2: IPV6 - Unknown Routing " - "Header type(%d)\n", - ((struct ip6_rthdr *)ulp)->ip6r_type); + if (V_fw_verbose) + printf("IPFW2: IPV6 - Unknown " + "Routing Header type(%d)\n", + ((struct ip6_rthdr *) + ulp)->ip6r_type); if (V_fw_deny_unknown_exthdrs) return (IP_FW_DENY); break; @@ -1036,13 +1046,13 @@ do { \ proto = ((struct ip6_frag *)ulp)->ip6f_nxt; offset = ((struct ip6_frag *)ulp)->ip6f_offlg & IP6F_OFF_MASK; - /* Add IP6F_MORE_FRAG for offset of first - * fragment to be != 0. */ - offset |= ((struct ip6_frag *)ulp)->ip6f_offlg & + ip6f_mf = ((struct ip6_frag *)ulp)->ip6f_offlg & IP6F_MORE_FRAG; - if (offset == 0) { - printf("IPFW2: IPV6 - Invalid Fragment " - "Header\n"); + if (V_fw_permit_single_frag6 == 0 && + offset == 0 && ip6f_mf == 0) { + if (V_fw_verbose) + printf("IPFW2: IPV6 - Invalid " + "Fragment Header\n"); if (V_fw_deny_unknown_exthdrs) return (IP_FW_DENY); break; @@ -1113,8 +1123,10 @@ do { \ break; default: - printf("IPFW2: IPV6 - Unknown Extension " - "Header(%d), ext_hd=%x\n", proto, ext_hd); + if (V_fw_verbose) + printf("IPFW2: IPV6 - Unknown " + "Extension Header(%d), ext_hd=%x\n", + proto, ext_hd); if (V_fw_deny_unknown_exthdrs) return (IP_FW_DENY); PULLUP_TO(hlen, ulp, struct ip6_ext); @@ -1676,7 +1688,7 @@ do { \ case O_LOG: ipfw_log(f, hlen, args, m, - oif, offset, tablearg, ip); + oif, offset | ip6f_mf, tablearg, ip); match = 1; break; @@ -2270,6 +2282,23 @@ do { \ done = 1; /* exit outer loop */ break; +#ifdef INET6 + case O_FORWARD_IP6: + if (args->eh) /* not valid on layer2 pkts */ + break; + if (q == NULL || q->rule != f || + dyn_dir == MATCH_FORWARD) { + struct sockaddr_in6 *sin6; + + sin6 = &(((ipfw_insn_sa6 *)cmd)->sa); + args->next_hop6 = sin6; + } + retval = IP_FW_PASS; + l = 0; /* exit inner loop */ + done = 1; /* exit outer loop */ + break; +#endif + case O_NETGRAPH: case O_NGTEE: set_match(args, f_pos, chain); diff --git a/sys/netinet/ipfw/ip_fw_dynamic.c b/sys/netinet/ipfw/ip_fw_dynamic.c index 0bc4cc112ce26..d1eec89eed4f3 100644 --- a/sys/netinet/ipfw/ip_fw_dynamic.c +++ b/sys/netinet/ipfw/ip_fw_dynamic.c @@ -33,8 +33,8 @@ __FBSDID("$FreeBSD$"); * Dynamic rule support for ipfw */ -#if !defined(KLD_MODULE) #include "opt_ipfw.h" +#if !defined(KLD_MODULE) #include "opt_ipdivert.h" #include "opt_ipdn.h" #include "opt_inet.h" diff --git a/sys/netinet/ipfw/ip_fw_log.c b/sys/netinet/ipfw/ip_fw_log.c index 2b55a382d70d1..2f6e8b61fee88 100644 --- a/sys/netinet/ipfw/ip_fw_log.c +++ b/sys/netinet/ipfw/ip_fw_log.c @@ -30,8 +30,8 @@ __FBSDID("$FreeBSD$"); * Logging support for ipfw */ -#if !defined(KLD_MODULE) #include "opt_ipfw.h" +#if !defined(KLD_MODULE) #include "opt_ipdivert.h" #include "opt_ipdn.h" #include "opt_inet.h" @@ -167,7 +167,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args, { char *action; int limit_reached = 0; - char action2[40], proto[128], fragment[32]; + char action2[92], proto[128], fragment[32]; if (V_fw_verbose == 0) { #ifndef WITHOUT_BPF @@ -290,6 +290,21 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args, sa->sa.sin_port); } break; +#ifdef INET6 + case O_FORWARD_IP6: { + char buf[INET6_ADDRSTRLEN]; + ipfw_insn_sa6 *sa = (ipfw_insn_sa6 *)cmd; + int len; + + len = snprintf(SNPARGS(action2, 0), "Forward to [%s]", + ip6_sprintf(buf, &sa->sa.sin6_addr)); + + if (sa->sa.sin6_port) + snprintf(SNPARGS(action2, len), ":%u", + sa->sa.sin6_port); + } + break; +#endif case O_NETGRAPH: snprintf(SNPARGS(action2, 0), "Netgraph %d", cmd->arg1); @@ -333,10 +348,14 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args, #ifdef INET6 struct ip6_hdr *ip6 = NULL; struct icmp6_hdr *icmp6; + u_short ip6f_mf; #endif src[0] = '\0'; dst[0] = '\0'; #ifdef INET6 + ip6f_mf = offset & IP6F_MORE_FRAG; + offset &= IP6F_OFF_MASK; + if (IS_IP6_FLOW_ID(&(args->f_id))) { char ip6buf[INET6_ADDRSTRLEN]; snprintf(src, sizeof(src), "[%s]", @@ -418,8 +437,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args, " (frag %08x:%d@%d%s)", args->f_id.extra, ntohs(ip6->ip6_plen) - hlen, - ntohs(offset & IP6F_OFF_MASK) << 3, - (offset & IP6F_MORE_FRAG) ? "+" : ""); + ntohs(offset) << 3, ip6f_mf ? "+" : ""); } else #endif { diff --git a/sys/netinet/ipfw/ip_fw_pfil.c b/sys/netinet/ipfw/ip_fw_pfil.c index 736615b947a21..c470b1f2092d6 100644 --- a/sys/netinet/ipfw/ip_fw_pfil.c +++ b/sys/netinet/ipfw/ip_fw_pfil.c @@ -27,8 +27,8 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#if !defined(KLD_MODULE) #include "opt_ipfw.h" +#if !defined(KLD_MODULE) #include "opt_ipdn.h" #include "opt_inet.h" #ifndef INET @@ -152,13 +152,26 @@ again: switch (ipfw) { case IP_FW_PASS: /* next_hop may be set by ipfw_chk */ - if (args.next_hop == NULL) + if (args.next_hop == NULL && args.next_hop6 == NULL) break; /* pass */ #ifndef IPFIREWALL_FORWARD ret = EACCES; #else { struct m_tag *fwd_tag; + size_t len; + + KASSERT(args.next_hop == NULL || args.next_hop6 == NULL, + ("%s: both next_hop=%p and next_hop6=%p not NULL", __func__, + args.next_hop, args.next_hop6)); +#ifdef INET6 + if (args.next_hop6 != NULL) + len = sizeof(struct sockaddr_in6); +#endif +#ifdef INET + if (args.next_hop != NULL) + len = sizeof(struct sockaddr_in); +#endif /* Incoming packets should not be tagged so we do not * m_tag_find. Outgoing packets may be tagged, so we @@ -169,18 +182,28 @@ again: if (fwd_tag != NULL) { m_tag_unlink(*m0, fwd_tag); } else { - fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, - sizeof(struct sockaddr_in), M_NOWAIT); + fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, len, + M_NOWAIT); if (fwd_tag == NULL) { ret = EACCES; break; /* i.e. drop */ } } - bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in)); +#ifdef INET6 + if (args.next_hop6 != NULL) { + bcopy(args.next_hop6, (fwd_tag+1), len); + if (in6_localip(&args.next_hop6->sin6_addr)) + (*m0)->m_flags |= M_FASTFWD_OURS; + } +#endif +#ifdef INET + if (args.next_hop != NULL) { + bcopy(args.next_hop, (fwd_tag+1), len); + if (in_localip(args.next_hop->sin_addr)) + (*m0)->m_flags |= M_FASTFWD_OURS; + } +#endif m_tag_prepend(*m0, fwd_tag); - - if (in_localip(args.next_hop->sin_addr)) - (*m0)->m_flags |= M_FASTFWD_OURS; } #endif break; diff --git a/sys/netinet/ipfw/ip_fw_private.h b/sys/netinet/ipfw/ip_fw_private.h index 16ef46d574e13..fdb2b77f88b05 100644 --- a/sys/netinet/ipfw/ip_fw_private.h +++ b/sys/netinet/ipfw/ip_fw_private.h @@ -86,6 +86,7 @@ struct ip_fw_args { struct mbuf *m; /* the mbuf chain */ struct ifnet *oif; /* output interface */ struct sockaddr_in *next_hop; /* forward address */ + struct sockaddr_in6 *next_hop6; /* ipv6 forward address */ /* * On return, it points to the matching rule. diff --git a/sys/netinet/ipfw/ip_fw_sockopt.c b/sys/netinet/ipfw/ip_fw_sockopt.c index 143285850113d..610570ba9a785 100644 --- a/sys/netinet/ipfw/ip_fw_sockopt.c +++ b/sys/netinet/ipfw/ip_fw_sockopt.c @@ -33,8 +33,8 @@ __FBSDID("$FreeBSD$"); * the upper half of the ipfw code. */ -#if !defined(KLD_MODULE) #include "opt_ipfw.h" +#if !defined(KLD_MODULE) #include "opt_ipdivert.h" #include "opt_ipdn.h" #include "opt_inet.h" @@ -723,6 +723,17 @@ check_ipfw_struct(struct ip_fw *rule, int size) return EINVAL; #endif +#ifdef INET6 + case O_FORWARD_IP6: +#ifdef IPFIREWALL_FORWARD + if (cmdlen != F_INSN_SIZE(ipfw_insn_sa6)) + goto bad_size; + goto check_action; +#else + return (EINVAL); +#endif +#endif /* INET6 */ + case O_DIVERT: case O_TEE: if (ip_divert_ptr == NULL) diff --git a/sys/netinet/ipfw/ip_fw_table.c b/sys/netinet/ipfw/ip_fw_table.c index 517622f021715..f72401765a193 100644 --- a/sys/netinet/ipfw/ip_fw_table.c +++ b/sys/netinet/ipfw/ip_fw_table.c @@ -39,8 +39,8 @@ __FBSDID("$FreeBSD$"); * from userland, because operations are typically fast. */ -#if !defined(KLD_MODULE) #include "opt_ipfw.h" +#if !defined(KLD_MODULE) #include "opt_ipdivert.h" #include "opt_ipdn.h" #include "opt_inet.h" diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h index 3c8cf364ca6cb..11aa02a0a5684 100644 --- a/sys/netinet/sctp.h +++ b/sys/netinet/sctp.h @@ -119,6 +119,7 @@ struct sctp_paramhdr { #define SCTP_RECVNXTINFO 0x00000020 #define SCTP_DEFAULT_SNDINFO 0x00000021 #define SCTP_DEFAULT_PRINFO 0x00000022 +#define SCTP_PEER_ADDR_THLDS 0x00000023 /* * read-only options @@ -564,7 +565,6 @@ struct sctp_error_unrecognized_chunk { #define SCTP_BLK_LOGGING_ENABLE 0x00000001 #define SCTP_CWND_MONITOR_ENABLE 0x00000002 #define SCTP_CWND_LOGGING_ENABLE 0x00000004 -#define SCTP_EARLYFR_LOGGING_ENABLE 0x00000010 #define SCTP_FLIGHT_LOGGING_ENABLE 0x00000020 #define SCTP_FR_LOGGING_ENABLE 0x00000040 #define SCTP_LOCK_LOGGING_ENABLE 0x00000080 @@ -572,23 +572,23 @@ struct sctp_error_unrecognized_chunk { #define SCTP_MBCNT_LOGGING_ENABLE 0x00000200 #define SCTP_MBUF_LOGGING_ENABLE 0x00000400 #define SCTP_NAGLE_LOGGING_ENABLE 0x00000800 -#define SCTP_RECV_RWND_LOGGING_ENABLE 0x00001000 +#define SCTP_RECV_RWND_LOGGING_ENABLE 0x00001000 #define SCTP_RTTVAR_LOGGING_ENABLE 0x00002000 #define SCTP_SACK_LOGGING_ENABLE 0x00004000 -#define SCTP_SACK_RWND_LOGGING_ENABLE 0x00008000 +#define SCTP_SACK_RWND_LOGGING_ENABLE 0x00008000 #define SCTP_SB_LOGGING_ENABLE 0x00010000 #define SCTP_STR_LOGGING_ENABLE 0x00020000 #define SCTP_WAKE_LOGGING_ENABLE 0x00040000 #define SCTP_LOG_MAXBURST_ENABLE 0x00080000 #define SCTP_LOG_RWND_ENABLE 0x00100000 -#define SCTP_LOG_SACK_ARRIVALS_ENABLE 0x00200000 -#define SCTP_LTRACE_CHUNK_ENABLE 0x00400000 -#define SCTP_LTRACE_ERROR_ENABLE 0x00800000 -#define SCTP_LAST_PACKET_TRACING 0x01000000 -#define SCTP_THRESHOLD_LOGGING 0x02000000 -#define SCTP_LOG_AT_SEND_2_SCTP 0x04000000 -#define SCTP_LOG_AT_SEND_2_OUTQ 0x08000000 -#define SCTP_LOG_TRY_ADVANCE 0x10000000 +#define SCTP_LOG_SACK_ARRIVALS_ENABLE 0x00200000 +#define SCTP_LTRACE_CHUNK_ENABLE 0x00400000 +#define SCTP_LTRACE_ERROR_ENABLE 0x00800000 +#define SCTP_LAST_PACKET_TRACING 0x01000000 +#define SCTP_THRESHOLD_LOGGING 0x02000000 +#define SCTP_LOG_AT_SEND_2_SCTP 0x04000000 +#define SCTP_LOG_AT_SEND_2_OUTQ 0x08000000 +#define SCTP_LOG_TRY_ADVANCE 0x10000000 #undef SCTP_PACKED diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c index a6db580f6abe6..b4985aa66aec5 100644 --- a/sys/netinet/sctp_asconf.c +++ b/sys/netinet/sctp_asconf.c @@ -198,14 +198,16 @@ sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t * error_tlv, static struct mbuf * sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, - struct sctp_tcb *stcb, int response_required) + struct sctp_tcb *stcb, int send_hb, int response_required) { + struct sctp_nets *net; struct mbuf *m_reply = NULL; struct sockaddr_storage sa_source, sa_store; struct sctp_paramhdr *ph; uint16_t param_type, param_length, aparam_length; struct sockaddr *sa; int zero_address = 0; + int bad_address = 0; #ifdef INET struct sockaddr_in *sin; @@ -238,6 +240,10 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, sin->sin_len = sizeof(struct sockaddr_in); sin->sin_port = stcb->rport; sin->sin_addr.s_addr = v4addr->addr; + if ((sin->sin_addr.s_addr == INADDR_BROADCAST) || + IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { + bad_address = 1; + } if (sin->sin_addr.s_addr == INADDR_ANY) zero_address = 1; SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding "); @@ -258,6 +264,9 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, sin6->sin6_port = stcb->rport; memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr, sizeof(struct in6_addr)); + if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { + bad_address = 1; + } if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) zero_address = 1; SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding "); @@ -265,12 +274,8 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, break; #endif default: - /* - * XXX: Is this the correct error cause? Maybe - * SCTP_CAUSE_INVALID_PARAM is a better choice. - */ m_reply = sctp_asconf_error_response(aph->correlation_id, - SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph, + SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph, aparam_length); return m_reply; } /* end switch */ @@ -284,7 +289,11 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); } /* add the address */ - if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, + if (bad_address) { + m_reply = sctp_asconf_error_response(aph->correlation_id, + SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph, + aparam_length); + } else if (sctp_add_remote_addr(stcb, sa, &net, SCTP_DONOT_SETSCOPE, SCTP_ADDR_DYNAMIC_ADDED) != 0) { SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: error adding address\n"); @@ -298,10 +307,12 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, m_reply = sctp_asconf_success_response(aph->correlation_id); } - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, - NULL, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1); + sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, - stcb, NULL); + stcb, net); + if (send_hb) { + sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); + } } return m_reply; } @@ -554,7 +565,12 @@ sctp_process_asconf_set_primary(struct mbuf *m, "process_asconf_set_primary: primary address set\n"); /* notify upper layer */ sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED); - + if ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_REACHABLE) && + (!(stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF)) && + (stcb->asoc.alternate)) { + sctp_free_remote_addr(stcb->asoc.alternate); + stcb->asoc.alternate = NULL; + } if (response_required) { m_reply = sctp_asconf_success_response(aph->correlation_id); } @@ -622,7 +638,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset, struct sctp_asconf_ack_chunk *ack_cp; struct sctp_asconf_paramhdr *aph, *ack_aph; struct sctp_ipv6addr_param *p_addr; - unsigned int asconf_limit; + unsigned int asconf_limit, cnt; int error = 0; /* did an error occur? */ /* asconf param buffer */ @@ -717,6 +733,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset, goto send_reply; } /* process through all parameters */ + cnt = 0; while (aph != NULL) { unsigned int param_length, param_type; @@ -749,7 +766,8 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset, case SCTP_ADD_IP_ADDRESS: asoc->peer_supports_asconf = 1; m_result = sctp_process_asconf_add_ip(m, aph, stcb, - error); + (cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error); + cnt++; break; case SCTP_DEL_IP_ADDRESS: asoc->peer_supports_asconf = 1; @@ -1959,7 +1977,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int status; - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 && + if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 || sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) { /* subset bound, no ASCONF allowed case, so ignore */ return; @@ -2075,8 +2093,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, stcb->asoc.primary_destination); #else - sctp_send_asconf(stcb, stcb->asoc.primary_destination, - addr_locked); + sctp_send_asconf(stcb, NULL, addr_locked); #endif } } @@ -2328,8 +2345,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, * If we have queued params in the open state, send out an ASCONF. */ if (num_queued > 0) { - sctp_send_asconf(stcb, stcb->asoc.primary_destination, - SCTP_ADDR_NOT_LOCKED); + sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); } } @@ -2384,8 +2400,7 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa) stcb->sctp_ep, stcb, stcb->asoc.primary_destination); #else - sctp_send_asconf(stcb, stcb->asoc.primary_destination, - SCTP_ADDR_NOT_LOCKED); + sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); #endif } } else { @@ -2421,8 +2436,7 @@ sctp_set_primary_ip_address(struct sctp_ifa *ifa) stcb->sctp_ep, stcb, stcb->asoc.primary_destination); #else - sctp_send_asconf(stcb, stcb->asoc.primary_destination, - SCTP_ADDR_NOT_LOCKED); + sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); #endif } } @@ -2965,8 +2979,7 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m, stcb->sctp_ep, stcb, stcb->asoc.primary_destination); #else - sctp_send_asconf(stcb, stcb->asoc.primary_destination, - SCTP_ADDR_NOT_LOCKED); + sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); #endif } } @@ -3540,5 +3553,5 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, } skip_rest: /* Now we must send the asconf into the queue */ - sctp_send_asconf(stcb, net, 0); + sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED); } diff --git a/sys/netinet/sctp_cc_functions.c b/sys/netinet/sctp_cc_functions.c index 85beb6adaaed4..b1596cccdbb06 100644 --- a/sys/netinet/sctp_cc_functions.c +++ b/sys/netinet/sctp_cc_functions.c @@ -728,40 +728,6 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, } } #endif - if (SCTP_BASE_SYSCTL(sctp_early_fr)) { - /* - * So, first of all do we need to have a Early FR - * timer running? - */ - if ((!TAILQ_EMPTY(&asoc->sent_queue) && - (net->ref_count > 1) && - (net->flight_size < net->cwnd)) || - (reneged_all)) { - /* - * yes, so in this case stop it if its - * running, and then restart it. Reneging - * all is a special case where we want to - * run the Early FR timer and then force the - * last few unacked to be sent, causing us - * to illicit a sack with gaps to force out - * the others. - */ - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - SCTP_STAT_INCR(sctps_earlyfrstpidsck2); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); - } - SCTP_STAT_INCR(sctps_earlyfrstrid); - sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); - } else { - /* No, stop it if its running */ - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - SCTP_STAT_INCR(sctps_earlyfrstpidsck3); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); - } - } - } /* if nothing was acked on this destination skip it */ if (net->net_ack == 0) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { @@ -769,51 +735,6 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, } continue; } - if (net->net_ack2 > 0) { - /* - * Karn's rule applies to clearing error count, this - * is optional. - */ - net->error_count = 0; - if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == - SCTP_ADDR_NOT_REACHABLE) { - /* addr came good */ - net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; - net->dest_state |= SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, - SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); - /* now was it the primary? if so restore */ - if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { - (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); - } - } - /* - * JRS 5/14/07 - If CMT PF is on and the destination - * is in PF state, set the destination to active - * state and set the cwnd to one or two MTU's based - * on whether PF1 or PF2 is being used. - * - * Should we stop any running T3 timer here? - */ - if ((asoc->sctp_cmt_on_off > 0) && - (asoc->sctp_cmt_pf > 0) && - ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { - net->dest_state &= ~SCTP_ADDR_PF; - old_cwnd = net->cwnd; - net->cwnd = net->mtu * asoc->sctp_cmt_pf; - SDT_PROBE(sctp, cwnd, net, ack, - stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, - old_cwnd, net->cwnd); - SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", - net, net->cwnd); - /* - * Since the cwnd value is explicitly set, - * skip the code that updates the cwnd - * value. - */ - goto skip_cwnd_update; - } - } #ifdef JANA_CMT_FAST_RECOVERY /* * CMT fast recovery code @@ -833,7 +754,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, * If we are in loss recovery we skip any cwnd * update */ - goto skip_cwnd_update; + return; } /* * Did any measurements go on for this network? @@ -856,7 +777,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, if (net->cc_mod.rtcc.lbw) { if (cc_bw_limit(stcb, net, nbw)) { /* Hold here, no update */ - goto skip_cwnd_update; + continue; } } else { uint64_t vtag, probepoint; @@ -1049,27 +970,25 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, SCTP_CWND_LOG_NO_CUMACK); } } -skip_cwnd_update: - /* - * NOW, according to Karn's rule do we need to restore the - * RTO timer back? Check our net_ack2. If not set then we - * have a ambiguity.. i.e. all data ack'd was sent to more - * than one place. - */ - if (net->net_ack2) { - /* restore any doubled timers */ - net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; - if (net->RTO < stcb->asoc.minrto) { - net->RTO = stcb->asoc.minrto; - } - if (net->RTO > stcb->asoc.maxrto) { - net->RTO = stcb->asoc.maxrto; - } - } } } static void +sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net) +{ + int old_cwnd; + + old_cwnd = net->cwnd; + net->cwnd = net->mtu; + SDT_PROBE(sctp, cwnd, net, ack, + stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, + old_cwnd, net->cwnd); + SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", + net, net->cwnd); +} + + +static void sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net) { int old_cwnd = net->cwnd; @@ -1344,32 +1263,6 @@ sctp_cwnd_update_after_output(struct sctp_tcb *stcb, } static void -sctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, struct sctp_nets *net) -{ - int old_cwnd = net->cwnd; - - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); - /* - * make a small adjustment to cwnd and force to CA. - */ - if (net->cwnd > net->mtu) - /* drop down one MTU after sending */ - net->cwnd -= net->mtu; - if (net->cwnd < net->ssthresh) - /* still in SS move to CA */ - net->ssthresh = net->cwnd - 1; - SDT_PROBE(sctp, cwnd, net, fr, - stcb->asoc.my_vtag, - ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), - net, - old_cwnd, net->cwnd); - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR); - } -} - -static void sctp_cwnd_update_after_sack(struct sctp_tcb *stcb, struct sctp_association *asoc, int accum_moved, int reneged_all, int will_exit) @@ -1858,40 +1751,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, } } #endif - if (SCTP_BASE_SYSCTL(sctp_early_fr)) { - /* - * So, first of all do we need to have a Early FR - * timer running? - */ - if ((!TAILQ_EMPTY(&asoc->sent_queue) && - (net->ref_count > 1) && - (net->flight_size < net->cwnd)) || - (reneged_all)) { - /* - * yes, so in this case stop it if its - * running, and then restart it. Reneging - * all is a special case where we want to - * run the Early FR timer and then force the - * last few unacked to be sent, causing us - * to illicit a sack with gaps to force out - * the others. - */ - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - SCTP_STAT_INCR(sctps_earlyfrstpidsck2); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); - } - SCTP_STAT_INCR(sctps_earlyfrstrid); - sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); - } else { - /* No, stop it if its running */ - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - SCTP_STAT_INCR(sctps_earlyfrstpidsck3); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); - } - } - } /* if nothing was acked on this destination skip it */ if (net->net_ack == 0) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { @@ -1899,47 +1758,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, } continue; } - if (net->net_ack2 > 0) { - /* - * Karn's rule applies to clearing error count, this - * is optional. - */ - net->error_count = 0; - if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == - SCTP_ADDR_NOT_REACHABLE) { - /* addr came good */ - net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; - net->dest_state |= SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, - SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); - /* now was it the primary? if so restore */ - if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { - (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); - } - } - /* - * JRS 5/14/07 - If CMT PF is on and the destination - * is in PF state, set the destination to active - * state and set the cwnd to one or two MTU's based - * on whether PF1 or PF2 is being used. - * - * Should we stop any running T3 timer here? - */ - if ((asoc->sctp_cmt_on_off > 0) && - (asoc->sctp_cmt_pf > 0) && - ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { - net->dest_state &= ~SCTP_ADDR_PF; - net->cwnd = net->mtu * asoc->sctp_cmt_pf; - SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", - net, net->cwnd); - /* - * Since the cwnd value is explicitly set, - * skip the code that updates the cwnd - * value. - */ - goto skip_cwnd_update; - } - } #ifdef JANA_CMT_FAST_RECOVERY /* * CMT fast recovery code @@ -1959,7 +1777,7 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, * If we are in loss recovery we skip any cwnd * update */ - goto skip_cwnd_update; + return; } /* * CMT: CUC algorithm. Update cwnd if pseudo-cumack has @@ -2004,23 +1822,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, SCTP_CWND_LOG_NO_CUMACK); } } -skip_cwnd_update: - /* - * NOW, according to Karn's rule do we need to restore the - * RTO timer back? Check our net_ack2. If not set then we - * have a ambiguity.. i.e. all data ack'd was sent to more - * than one place. - */ - if (net->net_ack2) { - /* restore any doubled timers */ - net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; - if (net->RTO < stcb->asoc.minrto) { - net->RTO = stcb->asoc.minrto; - } - if (net->RTO > stcb->asoc.maxrto) { - net->RTO = stcb->asoc.maxrto; - } - } } } @@ -2340,40 +2141,6 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, } } #endif - if (SCTP_BASE_SYSCTL(sctp_early_fr)) { - /* - * So, first of all do we need to have a Early FR - * timer running? - */ - if ((!TAILQ_EMPTY(&asoc->sent_queue) && - (net->ref_count > 1) && - (net->flight_size < net->cwnd)) || - (reneged_all)) { - /* - * yes, so in this case stop it if its - * running, and then restart it. Reneging - * all is a special case where we want to - * run the Early FR timer and then force the - * last few unacked to be sent, causing us - * to illicit a sack with gaps to force out - * the others. - */ - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - SCTP_STAT_INCR(sctps_earlyfrstpidsck2); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); - } - SCTP_STAT_INCR(sctps_earlyfrstrid); - sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); - } else { - /* No, stop it if its running */ - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - SCTP_STAT_INCR(sctps_earlyfrstpidsck3); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_21); - } - } - } /* if nothing was acked on this destination skip it */ if (net->net_ack == 0) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { @@ -2381,47 +2148,6 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, } continue; } - if (net->net_ack2 > 0) { - /* - * Karn's rule applies to clearing error count, this - * is optional. - */ - net->error_count = 0; - if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == - SCTP_ADDR_NOT_REACHABLE) { - /* addr came good */ - net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; - net->dest_state |= SCTP_ADDR_REACHABLE; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, - SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); - /* now was it the primary? if so restore */ - if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) { - (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net); - } - } - /* - * JRS 5/14/07 - If CMT PF is on and the destination - * is in PF state, set the destination to active - * state and set the cwnd to one or two MTU's based - * on whether PF1 or PF2 is being used. - * - * Should we stop any running T3 timer here? - */ - if ((asoc->sctp_cmt_on_off > 0) && - (asoc->sctp_cmt_pf > 0) && - ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { - net->dest_state &= ~SCTP_ADDR_PF; - net->cwnd = net->mtu * asoc->sctp_cmt_pf; - SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", - net, net->cwnd); - /* - * Since the cwnd value is explicitly set, - * skip the code that updates the cwnd - * value. - */ - goto skip_cwnd_update; - } - } #ifdef JANA_CMT_FAST_RECOVERY /* * CMT fast recovery code @@ -2441,7 +2167,7 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, * If we are in loss recovery we skip any cwnd * update */ - goto skip_cwnd_update; + return; } /* * CMT: CUC algorithm. Update cwnd if pseudo-cumack has @@ -2457,23 +2183,6 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, SCTP_CWND_LOG_NO_CUMACK); } } -skip_cwnd_update: - /* - * NOW, according to Karn's rule do we need to restore the - * RTO timer back? Check our net_ack2. If not set then we - * have a ambiguity.. i.e. all data ack'd was sent to more - * than one place. - */ - if (net->net_ack2) { - /* restore any doubled timers */ - net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; - if (net->RTO < stcb->asoc.minrto) { - net->RTO = stcb->asoc.minrto; - } - if (net->RTO > stcb->asoc.maxrto) { - net->RTO = stcb->asoc.maxrto; - } - } } } @@ -2566,30 +2275,6 @@ sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb, } static void -sctp_htcp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, struct sctp_nets *net) -{ - int old_cwnd; - - old_cwnd = net->cwnd; - - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); - net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count(); - /* - * make a small adjustment to cwnd and force to CA. - */ - if (net->cwnd > net->mtu) - /* drop down one MTU after sending */ - net->cwnd -= net->mtu; - if (net->cwnd < net->ssthresh) - /* still in SS move to CA */ - net->ssthresh = net->cwnd - 1; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { - sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR); - } -} - -static void sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, int in_window, int num_pkt_lost) { @@ -2618,42 +2303,42 @@ struct sctp_cc_functions sctp_cc_functions[] = { { .sctp_set_initial_cc_param = sctp_set_initial_cc_param, .sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack, + .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr, .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo, .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, - .sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer }, { .sctp_set_initial_cc_param = sctp_set_initial_cc_param, .sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack, + .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, .sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr, .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo, .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, - .sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer }, { .sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param, .sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack, + .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, .sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr, .sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout, .sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo, .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, - .sctp_cwnd_update_after_fr_timer = sctp_htcp_cwnd_update_after_fr_timer }, { .sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param, .sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack, + .sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common, .sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr, .sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout, .sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo, .sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped, .sctp_cwnd_update_after_output = sctp_cwnd_update_after_output, - .sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer, .sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted, .sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged, .sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins, diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index 6c2df1693fb1b..4087c8d266d18 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -416,7 +416,7 @@ __FBSDID("$FreeBSD$"); #define SCTP_STR_RESET_IN_REQUEST 0x000e #define SCTP_STR_RESET_TSN_REQUEST 0x000f #define SCTP_STR_RESET_RESPONSE 0x0010 -#define SCTP_STR_RESET_ADD_STREAMS 0x0011 +#define SCTP_STR_RESET_ADD_STREAMS 0x0011 #define SCTP_MAX_RESET_PARAMS 2 #define SCTP_STREAM_RESET_TSN_DELTA 0x1000 @@ -508,14 +508,10 @@ __FBSDID("$FreeBSD$"); /* SCTP reachability state for each address */ #define SCTP_ADDR_REACHABLE 0x001 -#define SCTP_ADDR_NOT_REACHABLE 0x002 #define SCTP_ADDR_NOHB 0x004 #define SCTP_ADDR_BEING_DELETED 0x008 #define SCTP_ADDR_NOT_IN_ASSOC 0x010 -#define SCTP_ADDR_WAS_PRIMARY 0x020 -#define SCTP_ADDR_SWITCH_PRIMARY 0x040 #define SCTP_ADDR_OUT_OF_SCOPE 0x080 -#define SCTP_ADDR_DOUBLE_SWITCH 0x100 #define SCTP_ADDR_UNCONFIRMED 0x200 #define SCTP_ADDR_REQ_PRIMARY 0x400 /* JRS 5/13/07 - Added potentially failed state for CMT PF */ @@ -579,14 +575,13 @@ __FBSDID("$FreeBSD$"); #define SCTP_TIMER_TYPE_EVENTWAKE 13 #define SCTP_TIMER_TYPE_STRRESET 14 #define SCTP_TIMER_TYPE_INPKILL 15 -#define SCTP_TIMER_TYPE_EARLYFR 17 -#define SCTP_TIMER_TYPE_ASOCKILL 18 -#define SCTP_TIMER_TYPE_ADDR_WQ 19 -#define SCTP_TIMER_TYPE_ZERO_COPY 20 -#define SCTP_TIMER_TYPE_ZCOPY_SENDQ 21 -#define SCTP_TIMER_TYPE_PRIM_DELETED 22 +#define SCTP_TIMER_TYPE_ASOCKILL 16 +#define SCTP_TIMER_TYPE_ADDR_WQ 17 +#define SCTP_TIMER_TYPE_ZERO_COPY 18 +#define SCTP_TIMER_TYPE_ZCOPY_SENDQ 19 +#define SCTP_TIMER_TYPE_PRIM_DELETED 20 /* add new timers here - and increment LAST */ -#define SCTP_TIMER_TYPE_LAST 23 +#define SCTP_TIMER_TYPE_LAST 21 #define SCTP_IS_TIMER_TYPE_VALID(t) (((t) > SCTP_TIMER_TYPE_NONE) && \ ((t) < SCTP_TIMER_TYPE_LAST)) @@ -655,16 +650,17 @@ __FBSDID("$FreeBSD$"); #define SCTP_DEFAULT_SECRET_LIFE_SEC 3600 #define SCTP_RTO_UPPER_BOUND (60000) /* 60 sec in ms */ -#define SCTP_RTO_LOWER_BOUND (300) /* 0.3 sec is ms */ +#define SCTP_RTO_LOWER_BOUND (1000) /* 1 sec is ms */ #define SCTP_RTO_INITIAL (3000) /* 3 sec in ms */ #define SCTP_INP_KILL_TIMEOUT 20/* number of ms to retry kill of inpcb */ #define SCTP_ASOC_KILL_TIMEOUT 10 /* number of ms to retry kill of inpcb */ -#define SCTP_DEF_MAX_INIT 8 -#define SCTP_DEF_MAX_SEND 10 -#define SCTP_DEF_MAX_PATH_RTX 5 +#define SCTP_DEF_MAX_INIT 8 +#define SCTP_DEF_MAX_SEND 10 +#define SCTP_DEF_MAX_PATH_RTX 5 +#define SCTP_DEF_PATH_PF_THRESHOLD SCTP_DEF_MAX_PATH_RTX #define SCTP_DEF_PMTU_RAISE_SEC 600 /* 10 min between raise attempts */ @@ -679,7 +675,7 @@ __FBSDID("$FreeBSD$"); /* Send window update (incr * this > hiwat). Should be a power of 2 */ #define SCTP_MINIMAL_RWND (4096) /* minimal rwnd */ -#define SCTP_ADDRMAX 24 +#define SCTP_ADDRMAX 16 /* SCTP DEBUG Switch parameters */ #define SCTP_DEBUG_TIMER1 0x00000001 diff --git a/sys/netinet/sctp_header.h b/sys/netinet/sctp_header.h index dc8d91785057d..1aff6a1485e91 100644 --- a/sys/netinet/sctp_header.h +++ b/sys/netinet/sctp_header.h @@ -98,9 +98,10 @@ struct sctp_heartbeat_info_param { uint32_t time_value_2; uint32_t random_value1; uint32_t random_value2; - uint16_t user_req; uint8_t addr_family; uint8_t addr_len; + /* make sure that this structure is 4 byte aligned */ + uint8_t padding[2]; char address[SCTP_ADDRMAX]; } SCTP_PACKED; diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index e142a3e5246ed..48b79fb89da01 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -2434,7 +2434,8 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap, int *abort_flag) sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_INDATA + SCTP_LOC_18); } - sctp_send_shutdown(stcb, stcb->asoc.primary_destination); + sctp_send_shutdown(stcb, + ((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination)); sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); } else { int is_a_gap; @@ -4054,9 +4055,50 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, } /* JRS - Use the congestion control given in the CC module */ - if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0)) + if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0)) { + TAILQ_FOREACH(net, &asoc->nets, sctp_next) { + if (net->net_ack2 > 0) { + /* + * Karn's rule applies to clearing error + * count, this is optional. + */ + net->error_count = 0; + if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { + /* addr came good */ + net->dest_state |= SCTP_ADDR_REACHABLE; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, + SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); + } + if (net == stcb->asoc.primary_destination) { + if (stcb->asoc.alternate) { + /* + * release the alternate, + * primary is good + */ + sctp_free_remote_addr(stcb->asoc.alternate); + stcb->asoc.alternate = NULL; + } + } + if (net->dest_state & SCTP_ADDR_PF) { + net->dest_state &= ~SCTP_ADDR_PF; + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); + asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net); + /* Done with this net */ + net->net_ack = 0; + } + /* restore any doubled timers */ + net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; + if (net->RTO < stcb->asoc.minrto) { + net->RTO = stcb->asoc.minrto; + } + if (net->RTO > stcb->asoc.maxrto) { + net->RTO = stcb->asoc.maxrto; + } + } + } asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, 1, 0, 0); - + } asoc->last_acked_seq = cumack; if (TAILQ_EMPTY(&asoc->sent_queue)) { @@ -4127,13 +4169,6 @@ again: stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_22); } - if (SCTP_BASE_SYSCTL(sctp_early_fr)) { - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - SCTP_STAT_INCR(sctps_earlyfrstpidsck4); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_23); - } - } } } if ((j == 0) && @@ -4222,6 +4257,8 @@ again: stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24; sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper, SCTP_SO_NOT_LOCKED); } else { + struct sctp_nets *netp; + if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); @@ -4229,26 +4266,36 @@ again: SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); sctp_stop_timers_for_shutdown(stcb); - sctp_send_shutdown(stcb, - stcb->asoc.primary_destination); + if (asoc->alternate) { + netp = asoc->alternate; + } else { + netp = asoc->primary_destination; + } + sctp_send_shutdown(stcb, netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, - stcb->sctp_ep, stcb, asoc->primary_destination); + stcb->sctp_ep, stcb, netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, - stcb->sctp_ep, stcb, asoc->primary_destination); + stcb->sctp_ep, stcb, netp); } } else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) && (asoc->stream_queue_cnt == 0)) { + struct sctp_nets *netp; + + if (asoc->alternate) { + netp = asoc->alternate; + } else { + netp = asoc->primary_destination; + } if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) { goto abort_out_now; } SCTP_STAT_DECR_GAUGE32(sctps_currestab); SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); - sctp_send_shutdown_ack(stcb, - stcb->asoc.primary_destination); + sctp_send_shutdown_ack(stcb, netp); sctp_stop_timers_for_shutdown(stcb); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, - stcb->sctp_ep, stcb, asoc->primary_destination); + stcb->sctp_ep, stcb, netp); } } /*********************************************/ @@ -4380,7 +4427,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, num_dup, SCTP_LOG_NEW_SACK); } - if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_FR_LOGGING_ENABLE | SCTP_EARLYFR_LOGGING_ENABLE))) { + if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE)) { uint16_t i; uint32_t *dupdata, dblock; @@ -4468,13 +4515,6 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, TAILQ_FOREACH(net, &asoc->nets, sctp_next) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_26); - if (SCTP_BASE_SYSCTL(sctp_early_fr)) { - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - SCTP_STAT_INCR(sctps_earlyfrstpidsck1); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_26); - } - } net->partial_bytes_acked = 0; net->flight_size = 0; } @@ -4830,20 +4870,54 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, asoc->saw_sack_with_nr_frags = 0; /* JRS - Use the congestion control given in the CC module */ - if (ecne_seen == 0) + if (ecne_seen == 0) { + TAILQ_FOREACH(net, &asoc->nets, sctp_next) { + if (net->net_ack2 > 0) { + /* + * Karn's rule applies to clearing error + * count, this is optional. + */ + net->error_count = 0; + if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { + /* addr came good */ + net->dest_state |= SCTP_ADDR_REACHABLE; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, + SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED); + } + if (net == stcb->asoc.primary_destination) { + if (stcb->asoc.alternate) { + /* + * release the alternate, + * primary is good + */ + sctp_free_remote_addr(stcb->asoc.alternate); + stcb->asoc.alternate = NULL; + } + } + if (net->dest_state & SCTP_ADDR_PF) { + net->dest_state &= ~SCTP_ADDR_PF; + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); + asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net); + /* Done with this net */ + net->net_ack = 0; + } + /* restore any doubled timers */ + net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; + if (net->RTO < stcb->asoc.minrto) { + net->RTO = stcb->asoc.minrto; + } + if (net->RTO > stcb->asoc.maxrto) { + net->RTO = stcb->asoc.maxrto; + } + } + } asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery); - + } if (TAILQ_EMPTY(&asoc->sent_queue)) { /* nothing left in-flight */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { /* stop all timers */ - if (SCTP_BASE_SYSCTL(sctp_early_fr)) { - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - SCTP_STAT_INCR(sctps_earlyfrstpidsck4); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_29); - } - } sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30); net->flight_size = 0; @@ -4918,6 +4992,13 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper, SCTP_SO_NOT_LOCKED); return; } else { + struct sctp_nets *netp; + + if (asoc->alternate) { + netp = asoc->alternate; + } else { + netp = asoc->primary_destination; + } if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); @@ -4925,27 +5006,32 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); sctp_stop_timers_for_shutdown(stcb); - sctp_send_shutdown(stcb, - stcb->asoc.primary_destination); + sctp_send_shutdown(stcb, netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, - stcb->sctp_ep, stcb, asoc->primary_destination); + stcb->sctp_ep, stcb, netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, - stcb->sctp_ep, stcb, asoc->primary_destination); + stcb->sctp_ep, stcb, netp); } return; } else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) && (asoc->stream_queue_cnt == 0)) { + struct sctp_nets *netp; + + if (asoc->alternate) { + netp = asoc->alternate; + } else { + netp = asoc->primary_destination; + } if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) { goto abort_out_now; } SCTP_STAT_DECR_GAUGE32(sctps_currestab); SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); - sctp_send_shutdown_ack(stcb, - stcb->asoc.primary_destination); + sctp_send_shutdown_ack(stcb, netp); sctp_stop_timers_for_shutdown(stcb); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, - stcb->sctp_ep, stcb, asoc->primary_destination); + stcb->sctp_ep, stcb, netp); return; } } @@ -5056,13 +5142,6 @@ again: stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_22); } - if (SCTP_BASE_SYSCTL(sctp_early_fr)) { - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - SCTP_STAT_INCR(sctps_earlyfrstpidsck4); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_23); - } - } } } if ((j == 0) && diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 4c4d779b39d0d..d8f0ae539707f 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -537,6 +537,7 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, struct sctp_nets *r_net, *f_net; struct timeval tv; int req_prim = 0; + uint16_t old_error_counter; #ifdef INET struct sockaddr_in *sin; @@ -599,7 +600,6 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, r_net->dest_state &= ~SCTP_ADDR_UNCONFIRMED; if (r_net->dest_state & SCTP_ADDR_REQ_PRIMARY) { stcb->asoc.primary_destination = r_net; - r_net->dest_state &= ~SCTP_ADDR_WAS_PRIMARY; r_net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY; f_net = TAILQ_FIRST(&stcb->asoc.nets); if (f_net != r_net) { @@ -616,44 +616,37 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, } sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net); } + old_error_counter = r_net->error_count; r_net->error_count = 0; r_net->hb_responded = 1; tv.tv_sec = cp->heartbeat.hb_info.time_value_1; tv.tv_usec = cp->heartbeat.hb_info.time_value_2; - if (r_net->dest_state & SCTP_ADDR_NOT_REACHABLE) { - r_net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE; + /* Now lets do a RTO with this */ + r_net->RTO = sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv, sctp_align_safe_nocopy, + SCTP_RTT_FROM_NON_DATA); + if (!(r_net->dest_state & SCTP_ADDR_REACHABLE)) { r_net->dest_state |= SCTP_ADDR_REACHABLE; sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_HEARTBEAT_SUCCESS, (void *)r_net, SCTP_SO_NOT_LOCKED); - /* now was it the primary? if so restore */ - if (r_net->dest_state & SCTP_ADDR_WAS_PRIMARY) { - (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, r_net); - } } - /* - * JRS 5/14/07 - If CMT PF is on and the destination is in PF state, - * set the destination to active state and set the cwnd to one or - * two MTU's based on whether PF1 or PF2 is being used. If a T3 - * timer is running, for the destination, stop the timer because a - * PF-heartbeat was received. - */ - if ((stcb->asoc.sctp_cmt_on_off > 0) && - (stcb->asoc.sctp_cmt_pf > 0) && - ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { - if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_5); + if (r_net->dest_state & SCTP_ADDR_PF) { + r_net->dest_state &= ~SCTP_ADDR_PF; + stcb->asoc.cc_functions.sctp_cwnd_update_exit_pf(stcb, net); + } + if (old_error_counter > 0) { + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net); + } + if (r_net == stcb->asoc.primary_destination) { + if (stcb->asoc.alternate) { + /* release the alternate, primary is good */ + sctp_free_remote_addr(stcb->asoc.alternate); + stcb->asoc.alternate = NULL; } - net->dest_state &= ~SCTP_ADDR_PF; - net->cwnd = net->mtu * stcb->asoc.sctp_cmt_pf; - SCTPDBG(SCTP_DEBUG_INPUT1, "Destination %p moved from PF to reachable with cwnd %d.\n", - net, net->cwnd); } - /* Now lets do a RTO with this */ - r_net->RTO = sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv, sctp_align_safe_nocopy, - SCTP_RTT_FROM_NON_DATA); /* Mobility adaptation */ if (req_prim) { if ((sctp_is_mobility_feature_on(stcb->sctp_ep, @@ -825,6 +818,35 @@ sctp_handle_abort(struct sctp_abort_chunk *cp, } static void +sctp_start_net_timers(struct sctp_tcb *stcb) +{ + uint32_t cnt_hb_sent; + struct sctp_nets *net; + + cnt_hb_sent = 0; + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + /* + * For each network start: 1) A pmtu timer. 2) A HB timer 3) + * If the dest in unconfirmed send a hb as well if under + * max_hb_burst have been sent. + */ + sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); + if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) && + (cnt_hb_sent < SCTP_BASE_SYSCTL(sctp_hb_maxburst))) { + sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); + cnt_hb_sent++; + } + } + if (cnt_hb_sent) { + sctp_chunk_output(stcb->sctp_ep, stcb, + SCTP_OUTPUT_FROM_COOKIE_ACK, + SCTP_SO_NOT_LOCKED); + } +} + + +static void sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, struct sctp_tcb *stcb, struct sctp_nets *net, int *abort_flag) { @@ -916,7 +938,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, } else { /* no outstanding data to send, so move on... */ /* send SHUTDOWN-ACK */ - sctp_send_shutdown_ack(stcb, stcb->asoc.primary_destination); + sctp_send_shutdown_ack(stcb, net); /* move to SHUTDOWN-ACK-SENT state */ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { @@ -2685,7 +2707,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, /* TSNH! Huh, why do I need to add this address here? */ int ret; - ret = sctp_add_remote_addr(*stcb, to, SCTP_DONOT_SETSCOPE, + ret = sctp_add_remote_addr(*stcb, to, NULL, SCTP_DONOT_SETSCOPE, SCTP_IN_COOKIE_PROC); netl = sctp_findnet(*stcb, to); } @@ -2697,10 +2719,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, send_int_conf = 1; } } - if (*stcb) { - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, *inp_p, - *stcb, NULL); - } + sctp_start_net_timers(*stcb); if ((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { if (!had_a_existing_tcb || (((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { @@ -2890,6 +2909,7 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp, /* state change only needed when I am in right state */ SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n"); SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); + sctp_start_net_timers(stcb); if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, asoc->primary_destination); @@ -3380,7 +3400,7 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc, * Only retransmit if we KNOW we wont destroy the * tcb */ - (void)sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED); + sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); } break; case SCTP_SHUTDOWN: @@ -3999,8 +4019,7 @@ strres_nochunk: /* setup chunk parameters */ chk->sent = SCTP_DATAGRAM_UNSENT; chk->snd_count = 0; - chk->whoTo = stcb->asoc.primary_destination; - atomic_add_int(&chk->whoTo->ref_count, 1); + chk->whoTo = NULL; ch = mtod(chk->data, struct sctp_chunkhdr *); ch->chunk_type = SCTP_STREAM_RESET; @@ -4630,8 +4649,7 @@ process_control_chunks: if ((stcb != NULL) && (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT)) { - sctp_send_shutdown_ack(stcb, - stcb->asoc.primary_destination); + sctp_send_shutdown_ack(stcb, NULL); *offset = length; sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED); if (locked_tcb) { diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 043b3b274c347..7fd5d4d22affd 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3541,9 +3541,10 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er (sin.sin_addr.s_addr == INADDR_BROADCAST) || IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { *error = EINVAL; - return (-1); + return (1); } - if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, + SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { *error = ENOBUFS; return (1); } @@ -3563,7 +3564,7 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr) || IN6_IS_ADDR_MULTICAST(&sin6.sin6_addr)) { *error = EINVAL; - return (-1); + return (1); } #ifdef INET if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) { @@ -3572,15 +3573,17 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er (sin.sin_addr.s_addr == INADDR_BROADCAST) || IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { *error = EINVAL; - return (-1); + return (1); } - if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, + SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { *error = ENOBUFS; return (1); } } else #endif - if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, NULL, + SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { *error = ENOBUFS; return (1); } @@ -3828,28 +3831,7 @@ sctp_handle_no_route(struct sctp_tcb *stcb, (void *)net, so_locked); net->dest_state &= ~SCTP_ADDR_REACHABLE; - net->dest_state |= SCTP_ADDR_NOT_REACHABLE; - /* - * JRS 5/14/07 - If a destination is - * unreachable, the PF bit is turned off. - * This allows an unambiguous use of the PF - * bit for destinations that are reachable - * but potentially failed. If the - * destination is set to the unreachable - * state, also set the destination to the PF - * state. - */ - /* - * Add debug message here if destination is - * not in PF state. - */ - /* Stop any running T3 timers here? */ - if ((stcb->asoc.sctp_cmt_on_off > 0) && - (stcb->asoc.sctp_cmt_pf > 0)) { - net->dest_state &= ~SCTP_ADDR_PF; - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Destination %p moved from PF to unreachable.\n", - net); - } + net->dest_state &= ~SCTP_ADDR_PF; } } if (stcb) { @@ -3859,14 +3841,16 @@ sctp_handle_no_route(struct sctp_tcb *stcb, alt = sctp_find_alternate_net(stcb, net, 0); if (alt != net) { - if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, alt) == 0) { - net->dest_state |= SCTP_ADDR_WAS_PRIMARY; - if (net->ro._s_addr) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - } - net->src_addr_selected = 0; + if (stcb->asoc.alternate) { + sctp_free_remote_addr(stcb->asoc.alternate); + } + stcb->asoc.alternate = alt; + atomic_add_int(&stcb->asoc.alternate->ref_count, 1); + if (net->ro._s_addr) { + sctp_free_ifa(net->ro._s_addr); + net->ro._s_addr = NULL; } + net->src_addr_selected = 0; } } } @@ -3920,6 +3904,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, uint32_t vrf_id; sctp_route_t *ro = NULL; struct udphdr *udp = NULL; + uint8_t tos_value; #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) struct socket *so = NULL; @@ -3941,13 +3926,20 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, if ((auth != NULL) && (stcb != NULL)) { sctp_fill_hmac_digest_m(m, auth_offset, auth, stcb, auth_keyid); } + if (net) { + tos_value = net->dscp; + } else if (stcb) { + tos_value = stcb->asoc.default_dscp; + } else { + tos_value = inp->sctp_ep.default_dscp; + } + switch (to->sa_family) { #ifdef INET case AF_INET: { struct ip *ip = NULL; sctp_route_t iproute; - uint8_t tos_value; int len; len = sizeof(struct ip) + sizeof(struct sctphdr); @@ -3982,11 +3974,18 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, ip = mtod(m, struct ip *); ip->ip_v = IPVERSION; ip->ip_hl = (sizeof(struct ip) >> 2); - if (net) { - tos_value = net->tos_flowlabel & 0x000000ff; - } else { + if (tos_value == 0) { + /* + * This means especially, that it is not set + * at the SCTP layer. So use the value from + * the IP layer. + */ tos_value = inp->ip_inp.inp.inp_ip_tos; } + tos_value &= 0xfc; + if (ecn_ok) { + tos_value |= sctp_get_ect(stcb, chk); + } if ((nofragment_flag) && (port == 0)) { ip->ip_off = IP_DF; } else @@ -3997,10 +3996,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, ip->ip_ttl = inp->ip_inp.inp.inp_ip_ttl; ip->ip_len = packet_length; - ip->ip_tos = tos_value & 0xfc; - if (ecn_ok) { - ip->ip_tos |= sctp_get_ect(stcb, chk); - } + ip->ip_tos = tos_value; if (port) { ip->ip_p = IPPROTO_UDP; } else { @@ -4205,13 +4201,10 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, #ifdef INET6 case AF_INET6: { - uint32_t flowlabel; + uint32_t flowlabel, flowinfo; struct ip6_hdr *ip6h; struct route_in6 ip6route; struct ifnet *ifp; - u_char flowTop; - uint16_t flowBottom; - u_char tosBottom, tosTop; struct sockaddr_in6 *sin6, tmp, *lsa6, lsa6_tmp; int prev_scope = 0; struct sockaddr_in6 lsa6_storage; @@ -4219,12 +4212,22 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, u_short prev_port = 0; int len; - if (net != NULL) { - flowlabel = net->tos_flowlabel; + if (net) { + flowlabel = net->flowlabel; + } else if (stcb) { + flowlabel = stcb->asoc.default_flowlabel; } else { - flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo; + flowlabel = inp->sctp_ep.default_flowlabel; } - + if (flowlabel == 0) { + /* + * This means especially, that it is not set + * at the SCTP layer. So use the value from + * the IP layer. + */ + flowlabel = ntohl(((struct in6pcb *)inp)->in6p_flowinfo); + } + flowlabel &= 0x000fffff; len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr); if (port) { len += sizeof(struct udphdr); @@ -4256,13 +4259,6 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, packet_length = sctp_calculate_len(m); ip6h = mtod(m, struct ip6_hdr *); - /* - * We assume here that inp_flow is in host byte - * order within the TCB! - */ - flowBottom = flowlabel & 0x0000ffff; - flowTop = ((flowlabel & 0x000f0000) >> 16); - tosTop = (((flowlabel & 0xf0) >> 4) | IPV6_VERSION); /* protect *sin6 from overwrite */ sin6 = (struct sockaddr_in6 *)to; tmp = *sin6; @@ -4280,12 +4276,28 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } else { ro = (sctp_route_t *) & net->ro; } - tosBottom = (((struct in6pcb *)inp)->in6p_flowinfo & 0x0c); + /* + * We assume here that inp_flow is in host byte + * order within the TCB! + */ + if (tos_value == 0) { + /* + * This means especially, that it is not set + * at the SCTP layer. So use the value from + * the IP layer. + */ + tos_value = (ntohl(((struct in6pcb *)inp)->in6p_flowinfo) >> 20) & 0xff; + } + tos_value &= 0xfc; if (ecn_ok) { - tosBottom |= sctp_get_ect(stcb, chk); + tos_value |= sctp_get_ect(stcb, chk); } - tosBottom <<= 4; - ip6h->ip6_flow = htonl(((tosTop << 24) | ((tosBottom | flowTop) << 16) | flowBottom)); + flowinfo = 0x06; + flowinfo <<= 8; + flowinfo |= tos_value; + flowinfo <<= 20; + flowinfo |= flowlabel; + ip6h->ip6_flow = htonl(flowinfo); if (port) { ip6h->ip6_nxt = IPPROTO_UDP; } else { @@ -6498,6 +6510,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, int added_control = 0; int un_sent, do_chunk_output = 1; struct sctp_association *asoc; + struct sctp_nets *net; ca = (struct sctp_copy_all *)ptr; if (ca->m == NULL) { @@ -6531,6 +6544,11 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, m = NULL; } SCTP_TCB_LOCK_ASSERT(stcb); + if (stcb->asoc.alternate) { + net = stcb->asoc.alternate; + } else { + net = stcb->asoc.primary_destination; + } if (ca->sndrcv.sinfo_flags & SCTP_ABORT) { /* Abort this assoc with m as the user defined reason */ if (m) { @@ -6569,7 +6587,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, } } else { if (m) { - ret = sctp_msg_append(stcb, stcb->asoc.primary_destination, m, + ret = sctp_msg_append(stcb, net, m, &ca->sndrcv, 1); } asoc = &stcb->asoc; @@ -6596,14 +6614,14 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, * only send SHUTDOWN the first time * through */ - sctp_send_shutdown(stcb, stcb->asoc.primary_destination); + sctp_send_shutdown(stcb, net); if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, - asoc->primary_destination); + net); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, asoc->primary_destination); added_control = 1; @@ -7733,13 +7751,13 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, struct sctp_auth_chunk *auth = NULL; uint16_t auth_keyid; int override_ok = 1; + int skip_fill_up = 0; int data_auth_reqd = 0; /* * JRS 5/14/07 - Add flag for whether a heartbeat is sent to the * destination. */ - int pf_hbflag = 0; int quit_now = 0; *num_out = 0; @@ -7806,7 +7824,22 @@ nothing_to_send: max_send_per_dest = SCTP_SB_LIMIT_SND(stcb->sctp_socket) / asoc->numnets; else max_send_per_dest = 0; + if (no_data_chunks == 0) { + /* How many non-directed chunks are there? */ + TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { + if (chk->whoTo == NULL) { + /* + * We already have non-directed chunks on + * the queue, no need to do a fill-up. + */ + skip_fill_up = 1; + break; + } + } + + } if ((no_data_chunks == 0) && + (skip_fill_up == 0) && (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc))) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) { /* @@ -7821,8 +7854,10 @@ nothing_to_send: * copy by reference (we hope). */ net->window_probe = 0; - if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) || - (net->dest_state & SCTP_ADDR_UNCONFIRMED)) { + if ((net != stcb->asoc.alternate) && + ((net->dest_state & SCTP_ADDR_PF) || + (!(net->dest_state & SCTP_ADDR_REACHABLE)) || + (net->dest_state & SCTP_ADDR_UNCONFIRMED))) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { sctp_log_cwnd(stcb, net, 1, SCTP_CWND_LOG_FILL_OUTQ_CALLED); @@ -7833,16 +7868,6 @@ nothing_to_send: (net->flight_size == 0)) { (*stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) (stcb, net); } - if ((asoc->sctp_cmt_on_off == 0) && - (asoc->primary_destination != net) && - (net->ref_count < 2)) { - /* nothing can be in queue for this guy */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, 2, - SCTP_CWND_LOG_FILL_OUTQ_CALLED); - } - continue; - } if (net->flight_size >= net->cwnd) { /* skip this network, no room - can't fill */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { @@ -7886,6 +7911,16 @@ nothing_to_send: } else { start_at = TAILQ_FIRST(&asoc->nets); } + TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { + if (chk->whoTo == NULL) { + if (asoc->alternate) { + chk->whoTo = asoc->alternate; + } else { + chk->whoTo = asoc->primary_destination; + } + atomic_add_int(&chk->whoTo->ref_count, 1); + } + } old_start_at = NULL; again_one_more_time: for (net = start_at; net != NULL; net = TAILQ_NEXT(net, sctp_next)) { @@ -7896,15 +7931,6 @@ again_one_more_time: break; } tsns_sent = 0xa; - if ((asoc->sctp_cmt_on_off == 0) && - (asoc->primary_destination != net) && - (net->ref_count < 2)) { - /* - * Ref-count of 1 so we cannot have data or control - * queued to this address. Skip it (non-CMT). - */ - continue; - } if (TAILQ_EMPTY(&asoc->control_send_queue) && TAILQ_EMPTY(&asoc->asconf_send_queue) && (net->flight_size >= net->cwnd)) { @@ -8266,15 +8292,8 @@ again_one_more_time: (chk->rec.chunk_id.id == SCTP_ECN_CWR) || (chk->rec.chunk_id.id == SCTP_PACKET_DROPPED) || (chk->rec.chunk_id.id == SCTP_ASCONF_ACK)) { - if (chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) { hbflag = 1; - /* - * JRS 5/14/07 - Set the - * flag to say a heartbeat - * is being sent. - */ - pf_hbflag = 1; } /* remove these chunks at the end */ if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) || @@ -8408,7 +8427,7 @@ again_one_more_time: } /* JRI: if dest is in PF state, do not send data to it */ if ((asoc->sctp_cmt_on_off > 0) && - (asoc->sctp_cmt_pf > 0) && + (net != stcb->asoc.alternate) && (net->dest_state & SCTP_ADDR_PF)) { goto no_data_fill; } @@ -8486,6 +8505,17 @@ again_one_more_time: /* Don't send the chunk on this net */ continue; } + if (asoc->sctp_cmt_on_off == 0) { + if ((asoc->alternate) && + (asoc->alternate != net) && + (chk->whoTo == NULL)) { + continue; + } else if ((net != asoc->primary_destination) && + (asoc->alternate == NULL) && + (chk->whoTo == NULL)) { + continue; + } + } if ((chk->send_size > omtu) && ((chk->flags & CHUNK_FLAGS_FRAGMENT_OK) == 0)) { /*- * strange, we have a chunk that is @@ -8646,18 +8676,6 @@ no_data_fill: * restart it. */ sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); - } else if ((asoc->sctp_cmt_on_off > 0) && - (asoc->sctp_cmt_pf > 0) && - pf_hbflag && - ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF) && - (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer))) { - /* - * JRS 5/14/07 - If a HB has been sent to a - * PF destination and no T3 timer is - * currently running, start the T3 timer to - * track the HBs that were sent. - */ - sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); } /* Now send it, if there is anything to send :> */ if ((error = sctp_lowlevel_chunk_output(inp, @@ -8747,24 +8765,6 @@ no_data_fill: } SCTP_STAT_INCR_BY(sctps_senddata, bundle_at); sctp_clean_up_datalist(stcb, asoc, data_list, bundle_at, net); - if (SCTP_BASE_SYSCTL(sctp_early_fr)) { - if (net->flight_size < net->cwnd) { - /* start or restart it */ - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net, - SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_2); - } - SCTP_STAT_INCR(sctps_earlyfrstrout); - sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net); - } else { - /* stop it if its running */ - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - SCTP_STAT_INCR(sctps_earlyfrstpout); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net, - SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_3); - } - } - } } if (one_chunk) { break; @@ -8833,8 +8833,7 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err) chk->flags = 0; chk->asoc = &stcb->asoc; chk->data = op_err; - chk->whoTo = chk->asoc->primary_destination; - atomic_add_int(&chk->whoTo->ref_count, 1); + chk->whoTo = NULL; hdr = mtod(op_err, struct sctp_chunkhdr *); hdr->chunk_type = SCTP_OPERATION_ERROR; hdr->chunk_flags = 0; @@ -8929,7 +8928,7 @@ sctp_send_cookie_echo(struct mbuf *m, chk->flags = CHUNK_FLAGS_FRAGMENT_OK; chk->asoc = &stcb->asoc; chk->data = cookie; - chk->whoTo = chk->asoc->primary_destination; + chk->whoTo = net; atomic_add_int(&chk->whoTo->ref_count, 1); TAILQ_INSERT_HEAD(&chk->asoc->control_send_queue, chk, sctp_next); chk->asoc->ctrl_queue_cnt++; @@ -9039,10 +9038,10 @@ sctp_send_cookie_ack(struct sctp_tcb *stcb) chk->data = cookie_ack; if (chk->asoc->last_control_chunk_from != NULL) { chk->whoTo = chk->asoc->last_control_chunk_from; + atomic_add_int(&chk->whoTo->ref_count, 1); } else { - chk->whoTo = chk->asoc->primary_destination; + chk->whoTo = NULL; } - atomic_add_int(&chk->whoTo->ref_count, 1); hdr = mtod(cookie_ack, struct sctp_chunkhdr *); hdr->chunk_type = SCTP_COOKIE_ACK; hdr->chunk_flags = 0; @@ -9084,8 +9083,9 @@ sctp_send_shutdown_ack(struct sctp_tcb *stcb, struct sctp_nets *net) chk->asoc = &stcb->asoc; chk->data = m_shutdown_ack; chk->whoTo = net; - atomic_add_int(&net->ref_count, 1); - + if (chk->whoTo) { + atomic_add_int(&chk->whoTo->ref_count, 1); + } ack_cp = mtod(m_shutdown_ack, struct sctp_shutdown_ack_chunk *); ack_cp->ch.chunk_type = SCTP_SHUTDOWN_ACK; ack_cp->ch.chunk_flags = 0; @@ -9126,8 +9126,9 @@ sctp_send_shutdown(struct sctp_tcb *stcb, struct sctp_nets *net) chk->asoc = &stcb->asoc; chk->data = m_shutdown; chk->whoTo = net; - atomic_add_int(&net->ref_count, 1); - + if (chk->whoTo) { + atomic_add_int(&chk->whoTo->ref_count, 1); + } shutdown_cp = mtod(m_shutdown, struct sctp_shutdown_chunk *); shutdown_cp->ch.chunk_type = SCTP_SHUTDOWN; shutdown_cp->ch.chunk_flags = 0; @@ -9178,7 +9179,9 @@ sctp_send_asconf(struct sctp_tcb *stcb, struct sctp_nets *net, int addr_locked) chk->flags = CHUNK_FLAGS_FRAGMENT_OK; chk->asoc = &stcb->asoc; chk->whoTo = net; - atomic_add_int(&chk->whoTo->ref_count, 1); + if (chk->whoTo) { + atomic_add_int(&chk->whoTo->ref_count, 1); + } TAILQ_INSERT_TAIL(&chk->asoc->asconf_send_queue, chk, sctp_next); chk->asoc->ctrl_queue_cnt++; return; @@ -9208,17 +9211,27 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb) net = sctp_find_alternate_net(stcb, stcb->asoc.last_control_chunk_from, 0); if (net == NULL) { /* no alternate */ - if (stcb->asoc.last_control_chunk_from == NULL) - net = stcb->asoc.primary_destination; - else + if (stcb->asoc.last_control_chunk_from == NULL) { + if (stcb->asoc.alternate) { + net = stcb->asoc.alternate; + } else { + net = stcb->asoc.primary_destination; + } + } else { net = stcb->asoc.last_control_chunk_from; + } } } else { /* normal case */ - if (stcb->asoc.last_control_chunk_from == NULL) - net = stcb->asoc.primary_destination; - else + if (stcb->asoc.last_control_chunk_from == NULL) { + if (stcb->asoc.alternate) { + net = stcb->asoc.alternate; + } else { + net = stcb->asoc.primary_destination; + } + } else { net = stcb->asoc.last_control_chunk_from; + } } latest_ack->last_sent_to = net; @@ -9256,6 +9269,9 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb) chk->copy_by_ref = 0; chk->whoTo = net; + if (chk->whoTo) { + atomic_add_int(&chk->whoTo->ref_count, 1); + } chk->data = m_ack; chk->send_size = 0; /* Get size */ @@ -9267,7 +9283,6 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb) chk->snd_count = 0; chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; /* XXX */ chk->asoc = &stcb->asoc; - atomic_add_int(&chk->whoTo->ref_count, 1); TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); chk->asoc->ctrl_queue_cnt++; @@ -9797,7 +9812,11 @@ sctp_timer_validation(struct sctp_inpcb *inp, SCTP_TCB_LOCK_ASSERT(stcb); /* Gak, we did not have a timer somewhere */ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Deadlock avoided starting timer on a dest at retran\n"); - sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->primary_destination); + if (asoc->alternate) { + sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->alternate); + } else { + sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->primary_destination); + } return (ret); } @@ -9830,19 +9849,22 @@ sctp_chunk_output(struct sctp_inpcb *inp, unsigned int burst_cnt = 0; struct timeval now; int now_filled = 0; - int nagle_on = 0; + int nagle_on; int frag_point = sctp_get_frag_point(stcb, &stcb->asoc); int un_sent = 0; int fr_done; unsigned int tot_frs = 0; asoc = &stcb->asoc; + /* The Nagle algorithm is only applied when handling a send call. */ if (from_where == SCTP_OUTPUT_FROM_USR_SEND) { if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY)) { nagle_on = 0; } else { nagle_on = 1; } + } else { + nagle_on = 0; } SCTP_TCB_LOCK_ASSERT(stcb); @@ -9945,8 +9967,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, #endif /* Check for bad destinations, if they exist move chunks around. */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == - SCTP_ADDR_NOT_REACHABLE) { + if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { /*- * if possible move things off of this address we * still may send below due to the dormant state but @@ -9956,16 +9977,6 @@ sctp_chunk_output(struct sctp_inpcb *inp, */ if (net->ref_count > 1) sctp_move_chunks_from_net(stcb, net); - } else if ((asoc->sctp_cmt_on_off > 0) && - (asoc->sctp_cmt_pf > 0) && - ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { - /* - * JRS 5/14/07 - If CMT PF is on and the current - * destination is in PF state, move all queued data - * to an alternate desination. - */ - if (net->ref_count > 1) - sctp_move_chunks_from_net(stcb, net); } else { /*- * if ((asoc->sat_network) || (net->addr_is_local)) @@ -10027,15 +10038,18 @@ sctp_chunk_output(struct sctp_inpcb *inp, } } if (nagle_on) { - /*- - * When nagle is on, we look at how much is un_sent, then - * if its smaller than an MTU and we have data in - * flight we stop. + /* + * When the Nagle algorithm is used, look at how + * much is unsent, then if its smaller than an MTU + * and we have data in flight we stop, except if we + * are handling a fragmented user message. */ un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) + (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk))); if ((un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD)) && - (stcb->asoc.total_flight > 0)) { + (stcb->asoc.total_flight > 0) && + ((stcb->asoc.locked_on_sending == NULL) || + sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) { break; } } @@ -10123,10 +10137,9 @@ send_forward_tsn(struct sctp_tcb *stcb, chk->sent = SCTP_DATAGRAM_UNSENT; chk->snd_count = 0; /* Do we correct its output location? */ - if (chk->whoTo != asoc->primary_destination) { + if (chk->whoTo) { sctp_free_remote_addr(chk->whoTo); - chk->whoTo = asoc->primary_destination; - atomic_add_int(&chk->whoTo->ref_count, 1); + chk->whoTo = NULL; } goto sctp_fill_in_rest; } @@ -10150,8 +10163,6 @@ send_forward_tsn(struct sctp_tcb *stcb, SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); chk->sent = SCTP_DATAGRAM_UNSENT; chk->snd_count = 0; - chk->whoTo = asoc->primary_destination; - atomic_add_int(&chk->whoTo->ref_count, 1); TAILQ_INSERT_TAIL(&asoc->control_send_queue, chk, sctp_next); asoc->ctrl_queue_cnt++; sctp_fill_in_rest: @@ -10346,8 +10357,10 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked sctp_m_freem(a_chk->data); a_chk->data = NULL; } - sctp_free_remote_addr(a_chk->whoTo); - a_chk->whoTo = NULL; + if (a_chk->whoTo) { + sctp_free_remote_addr(a_chk->whoTo); + a_chk->whoTo = NULL; + } break; } } @@ -10379,13 +10392,13 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked a_chk->whoTo = NULL; if ((asoc->numduptsns) || - (asoc->last_data_chunk_from->dest_state & SCTP_ADDR_NOT_REACHABLE)) { + (!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE))) { /*- * Ok, we have some duplicates or the destination for the * sack is unreachable, lets see if we can select an * alternate than asoc->last_data_chunk_from */ - if ((!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_NOT_REACHABLE)) && + if ((asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE) && (asoc->used_alt_onsack > asoc->numnets)) { /* We used an alt last time, don't this time */ a_chk->whoTo = NULL; @@ -10710,6 +10723,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked int sz; uint32_t auth_offset = 0; struct sctp_auth_chunk *auth = NULL; + struct sctp_nets *net; /*- * Add an AUTH chunk, if chunk requires it and save the offset into @@ -10750,16 +10764,19 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked /* Put AUTH chunk at the front of the chain */ SCTP_BUF_NEXT(m_end) = m_abort; } - + if (stcb->asoc.alternate) { + net = stcb->asoc.alternate; + } else { + net = stcb->asoc.primary_destination; + } /* fill in the ABORT chunk */ abort = mtod(m_abort, struct sctp_abort_chunk *); abort->ch.chunk_type = SCTP_ABORT_ASSOCIATION; abort->ch.chunk_flags = 0; abort->ch.chunk_length = htons(sizeof(*abort) + sz); - (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, - stcb->asoc.primary_destination, - (struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr, + (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net, + (struct sockaddr *)&net->ro._l_addr, m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, NULL, 0, stcb->sctp_ep->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag), stcb->asoc.primary_destination->port, so_locked, NULL, NULL); @@ -11030,120 +11047,22 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, } -static struct sctp_nets * -sctp_select_hb_destination(struct sctp_tcb *stcb, struct timeval *now) -{ - struct sctp_nets *net, *hnet; - int ms_goneby, highest_ms, state_overide = 0; - - (void)SCTP_GETTIME_TIMEVAL(now); - highest_ms = 0; - hnet = NULL; - SCTP_TCB_LOCK_ASSERT(stcb); - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if ( - ((net->dest_state & SCTP_ADDR_NOHB) && ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0)) || - (net->dest_state & SCTP_ADDR_OUT_OF_SCOPE) - ) { - /* - * Skip this guy from consideration if HB is off AND - * its confirmed - */ - continue; - } - if (sctp_destination_is_reachable(stcb, (struct sockaddr *)&net->ro._l_addr) == 0) { - /* skip this dest net from consideration */ - continue; - } - if (net->last_sent_time.tv_sec) { - /* Sent to so we subtract */ - ms_goneby = (now->tv_sec - net->last_sent_time.tv_sec) * 1000; - } else - /* Never been sent to */ - ms_goneby = 0x7fffffff; - /*- - * When the address state is unconfirmed but still - * considered reachable, we HB at a higher rate. Once it - * goes confirmed OR reaches the "unreachable" state, thenw - * we cut it back to HB at a more normal pace. - */ - if ((net->dest_state & (SCTP_ADDR_UNCONFIRMED | SCTP_ADDR_NOT_REACHABLE)) == SCTP_ADDR_UNCONFIRMED) { - state_overide = 1; - } else { - state_overide = 0; - } - - if ((((unsigned int)ms_goneby >= net->RTO) || (state_overide)) && - (ms_goneby > highest_ms)) { - highest_ms = ms_goneby; - hnet = net; - } - } - if (hnet && - ((hnet->dest_state & (SCTP_ADDR_UNCONFIRMED | SCTP_ADDR_NOT_REACHABLE)) == SCTP_ADDR_UNCONFIRMED)) { - state_overide = 1; - } else { - state_overide = 0; - } - - if (hnet && highest_ms && (((unsigned int)highest_ms >= hnet->RTO) || state_overide)) { - /*- - * Found the one with longest delay bounds OR it is - * unconfirmed and still not marked unreachable. - */ - SCTPDBG(SCTP_DEBUG_OUTPUT4, "net:%p is the hb winner -", hnet); -#ifdef SCTP_DEBUG - if (hnet) { - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT4, - (struct sockaddr *)&hnet->ro._l_addr); - } else { - SCTPDBG(SCTP_DEBUG_OUTPUT4, " none\n"); - } -#endif - /* update the timer now */ - hnet->last_sent_time = *now; - return (hnet); - } - /* Nothing to HB */ - return (NULL); -} - -int -sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int so_locked +void +sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net, int so_locked #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) SCTP_UNUSED #endif ) { struct sctp_tmit_chunk *chk; - struct sctp_nets *net; struct sctp_heartbeat_chunk *hb; struct timeval now; SCTP_TCB_LOCK_ASSERT(stcb); - if (user_req == 0) { - net = sctp_select_hb_destination(stcb, &now); - if (net == NULL) { - /*- - * All our busy none to send to, just start the - * timer again. - */ - if (stcb->asoc.state == 0) { - return (0); - } - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, - stcb->sctp_ep, - stcb, - net); - return (0); - } - } else { - net = u_net; - if (net == NULL) { - return (0); - } - (void)SCTP_GETTIME_TIMEVAL(&now); + if (net == NULL) { + return; } + (void)SCTP_GETTIME_TIMEVAL(&now); switch (net->ro._l_addr.sa.sa_family) { #ifdef INET case AF_INET: @@ -11154,12 +11073,12 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s break; #endif default: - return (0); + return; } sctp_alloc_a_chunk(stcb, chk); if (chk == NULL) { SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak, can't get a chunk for hb\n"); - return (0); + return; } chk->copy_by_ref = 0; chk->rec.chunk_id.id = SCTP_HEARTBEAT_REQUEST; @@ -11170,7 +11089,7 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_DONTWAIT, 1, MT_HEADER); if (chk->data == NULL) { sctp_free_a_chunk(stcb, chk, so_locked); - return (0); + return; } SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); SCTP_BUF_LEN(chk->data) = chk->send_size; @@ -11191,7 +11110,6 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s hb->heartbeat.hb_info.time_value_1 = now.tv_sec; hb->heartbeat.hb_info.time_value_2 = now.tv_usec; /* Did our user request this one, put it in */ - hb->heartbeat.hb_info.user_req = user_req; hb->heartbeat.hb_info.addr_family = net->ro._l_addr.sa.sa_family; hb->heartbeat.hb_info.addr_len = net->ro._l_addr.sa.sa_len; if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { @@ -11221,57 +11139,14 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s break; #endif default: - return (0); + return; break; } - - /* - * JRS 5/14/07 - In CMT PF, the T3 timer is used to track - * PF-heartbeats. Because of this, threshold management is done by - * the t3 timer handler, and does not need to be done upon the send - * of a PF-heartbeat. If CMT PF is on and the destination to which a - * heartbeat is being sent is in PF state, do NOT do threshold - * management. - */ - if ((stcb->asoc.sctp_cmt_pf == 0) || - ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF)) { - /* ok we have a destination that needs a beat */ - /* lets do the theshold management Qiaobing style */ - if (sctp_threshold_management(stcb->sctp_ep, stcb, net, - stcb->asoc.max_send_times)) { - /*- - * we have lost the association, in a way this is - * quite bad since we really are one less time since - * we really did not send yet. This is the down side - * to the Q's style as defined in the RFC and not my - * alternate style defined in the RFC. - */ - if (chk->data != NULL) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - /* - * Here we do NOT use the macro since the - * association is now gone. - */ - if (chk->whoTo) { - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = NULL; - } - sctp_free_a_chunk((struct sctp_tcb *)NULL, chk, so_locked); - return (-1); - } - } net->hb_responded = 0; TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next); stcb->asoc.ctrl_queue_cnt++; SCTP_STAT_INCR(sctps_sendheartbeat); - /*- - * Call directly med level routine to put out the chunk. It will - * always tumble out control chunks aka HB but it may even tumble - * out data too. - */ - return (1); + return; } void @@ -11282,6 +11157,9 @@ sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, struct sctp_ecne_chunk *ecne; struct sctp_tmit_chunk *chk; + if (net == NULL) { + return; + } asoc = &stcb->asoc; SCTP_TCB_LOCK_ASSERT(stcb); TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { @@ -11323,6 +11201,7 @@ sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, chk->snd_count = 0; chk->whoTo = net; atomic_add_int(&chk->whoTo->ref_count, 1); + stcb->asoc.ecn_echo_cnt_onq++; ecne = mtod(chk->data, struct sctp_ecne_chunk *); ecne->ch.chunk_type = SCTP_ECN_ECHO; @@ -11477,10 +11356,10 @@ jump_out: if (net) { /* we should hit here */ chk->whoTo = net; + atomic_add_int(&chk->whoTo->ref_count, 1); } else { - chk->whoTo = asoc->primary_destination; + chk->whoTo = NULL; } - atomic_add_int(&chk->whoTo->ref_count, 1); chk->rec.chunk_id.id = SCTP_PACKET_DROPPED; chk->rec.chunk_id.can_take_data = 1; drp->ch.chunk_type = SCTP_PACKET_DROPPED; @@ -11518,8 +11397,9 @@ sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn, u asoc = &stcb->asoc; SCTP_TCB_LOCK_ASSERT(stcb); - - + if (net == NULL) { + return; + } TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { if ((chk->rec.chunk_id.id == SCTP_ECN_CWR) && (net == chk->whoTo)) { /* @@ -11849,9 +11729,12 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, /* setup chunk parameters */ chk->sent = SCTP_DATAGRAM_UNSENT; chk->snd_count = 0; - chk->whoTo = asoc->primary_destination; + if (stcb->asoc.alternate) { + chk->whoTo = stcb->asoc.alternate; + } else { + chk->whoTo = stcb->asoc.primary_destination; + } atomic_add_int(&chk->whoTo->ref_count, 1); - ch = mtod(chk->data, struct sctp_chunkhdr *); ch->chunk_type = SCTP_STREAM_RESET; ch->chunk_flags = 0; @@ -12745,14 +12628,10 @@ sctp_lower_sosend(struct socket *so, (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { SCTP_INP_RLOCK(inp); stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb == NULL) { - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOTCONN); - error = ENOTCONN; - goto out_unlocked; + if (stcb) { + SCTP_TCB_LOCK(stcb); + hold_tcblock = 1; } - SCTP_TCB_LOCK(stcb); - hold_tcblock = 1; SCTP_INP_RUNLOCK(inp); } else if (sinfo_assoc_id) { stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 0); @@ -12817,21 +12696,12 @@ sctp_lower_sosend(struct socket *so, } } if (stcb == NULL) { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOTCONN); - error = ENOTCONN; - goto out_unlocked; - } if (addr == NULL) { SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOENT); error = ENOENT; goto out_unlocked; } else { - /* - * UDP style, we must go ahead and start the INIT - * process - */ + /* We must go ahead and start the INIT process */ uint32_t vrf_id; if ((sinfo_flags & SCTP_ABORT) || @@ -12858,6 +12728,14 @@ sctp_lower_sosend(struct socket *so, /* Error is setup for us in the call */ goto out_unlocked; } + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { + stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; + /* + * Set the connected flag so we can queue + * data + */ + soisconnecting(so); + } hold_tcblock = 1; if (create_lock_applied) { SCTP_ASOC_CREATE_UNLOCK(inp); @@ -12910,7 +12788,11 @@ sctp_lower_sosend(struct socket *so, goto out_unlocked; } } else { - net = stcb->asoc.primary_destination; + if (stcb->asoc.alternate) { + net = stcb->asoc.alternate; + } else { + net = stcb->asoc.primary_destination; + } } atomic_add_int(&stcb->total_sends, 1); /* Keep the stcb from being freed under our feet */ @@ -13579,15 +13461,22 @@ dataless_eof: if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) && (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { + struct sctp_nets *netp; + + if (stcb->asoc.alternate) { + netp = stcb->asoc.alternate; + } else { + netp = stcb->asoc.primary_destination; + } /* only send SHUTDOWN the first time through */ - sctp_send_shutdown(stcb, stcb->asoc.primary_destination); + sctp_send_shutdown(stcb, netp); if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, - asoc->primary_destination); + netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, asoc->primary_destination); } diff --git a/sys/netinet/sctp_output.h b/sys/netinet/sctp_output.h index 5cbadf34909d8..68a08c11c9591 100644 --- a/sys/netinet/sctp_output.h +++ b/sys/netinet/sctp_output.h @@ -155,7 +155,7 @@ void send_forward_tsn(struct sctp_tcb *, struct sctp_association *); void sctp_send_sack(struct sctp_tcb *, int); -int sctp_send_hb(struct sctp_tcb *, int, struct sctp_nets *, int); +void sctp_send_hb(struct sctp_tcb *, struct sctp_nets *, int); void sctp_send_ecn_echo(struct sctp_tcb *, struct sctp_nets *, uint32_t); diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 70593655fdc69..b0f2880754453 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -49,6 +49,9 @@ __FBSDID("$FreeBSD$"); #include <netinet/sctp_bsd_addr.h> #include <netinet/sctp_dtrace_define.h> #include <netinet/udp.h> +#ifdef INET6 +#include <netinet6/ip6_var.h> +#endif #include <sys/sched.h> #include <sys/smp.h> #include <sys/unistd.h> @@ -1096,8 +1099,15 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to) continue; } LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { - if (sctp_is_addr_restricted(stcb, sctp_ifa)) + if (sctp_is_addr_restricted(stcb, sctp_ifa) && + (!sctp_is_addr_pending(stcb, sctp_ifa))) { + /* + * We allow pending addresses, where + * we have sent an asconf-add to be + * considered valid. + */ continue; + } switch (sctp_ifa->address.sa.sa_family) { #ifdef INET case AF_INET: @@ -1155,7 +1165,13 @@ sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to) struct sctp_laddr *laddr; LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) { - if (sctp_is_addr_restricted(stcb, laddr->ifa)) { + if (sctp_is_addr_restricted(stcb, laddr->ifa) && + (!sctp_is_addr_pending(stcb, laddr->ifa))) { + /* + * We allow pending addresses, where we have + * sent an asconf-add to be considered + * valid. + */ continue; } if (laddr->ifa->address.sa.sa_family != to->sa_family) { @@ -2490,6 +2506,11 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) /* setup socket pointers */ inp->sctp_socket = so; inp->ip_inp.inp.inp_socket = so; +#ifdef INET6 + if (MODULE_GLOBAL(ip6_auto_flowlabel)) { + inp->ip_inp.inp.inp_flags |= IN6P_AUTOFLOWLABEL; + } +#endif inp->sctp_associd_counter = 1; inp->partial_delivery_point = SCTP_SB_LIMIT_RCV(so) >> SCTP_PARTIAL_DELIVERY_SHIFT; inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; @@ -2614,6 +2635,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) m->max_init_times = SCTP_BASE_SYSCTL(sctp_init_rtx_max_default); m->max_send_times = SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default); m->def_net_failure = SCTP_BASE_SYSCTL(sctp_path_rtx_max_default); + m->def_net_pf_threshold = SCTP_BASE_SYSCTL(sctp_path_pf_threshold); m->sctp_sws_sender = SCTP_SWS_SENDER_DEF; m->sctp_sws_receiver = SCTP_SWS_RECEIVER_DEF; m->max_burst = SCTP_BASE_SYSCTL(sctp_max_burst_default); @@ -2654,6 +2676,10 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) */ m->local_hmacs = sctp_default_supported_hmaclist(); m->local_auth_chunks = sctp_alloc_chunklist(); + m->default_dscp = 0; +#ifdef INET6 + m->default_flowlabel = 0; +#endif sctp_auth_set_default_chunks(m->local_auth_chunks); LIST_INIT(&m->shared_keys); /* add default NULL key as key id 0 */ @@ -2768,7 +2794,6 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, * all of them. */ - stcb->asoc.hb_timer.ep = (void *)new_inp; stcb->asoc.dack_timer.ep = (void *)new_inp; stcb->asoc.asconf_timer.ep = (void *)new_inp; stcb->asoc.strreset_timer.ep = (void *)new_inp; @@ -2780,7 +2805,6 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { net->pmtu_timer.ep = (void *)new_inp; net->rxt_timer.ep = (void *)new_inp; - net->fr_timer.ep = (void *)new_inp; } SCTP_INP_WUNLOCK(new_inp); SCTP_INP_WUNLOCK(old_inp); @@ -3452,11 +3476,18 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) } if ((SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_SENT) && (SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { + struct sctp_nets *netp; + + if (asoc->asoc.alternate) { + netp = asoc->asoc.alternate; + } else { + netp = asoc->asoc.primary_destination; + } /* * there is nothing queued to send, * so I send shutdown */ - sctp_send_shutdown(asoc, asoc->asoc.primary_destination); + sctp_send_shutdown(asoc, netp); if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) || (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); @@ -3464,7 +3495,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) SCTP_SET_STATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_CLEAR_SUBSTATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_PENDING); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, asoc->sctp_ep, asoc, - asoc->asoc.primary_destination); + netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc, asoc->asoc.primary_destination); sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_LOCKED); @@ -3808,7 +3839,7 @@ sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id) */ int sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, - int set_scope, int from) + struct sctp_nets **netp, int set_scope, int from) { /* * The following is redundant to the same lines in the @@ -3942,7 +3973,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, return (-1); } SCTP_INCR_RADDR_COUNT(); - bzero(net, sizeof(*net)); + bzero(net, sizeof(struct sctp_nets)); (void)SCTP_GETTIME_TIMEVAL(&net->start_time); memcpy(&net->ro._l_addr, newaddr, newaddr->sa_len); switch (newaddr->sa_family) { @@ -3968,6 +3999,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, addr_inscope = 1; } net->failure_threshold = stcb->asoc.def_net_failure; + net->pf_threshold = stcb->asoc.def_net_pf_threshold; if (addr_inscope == 0) { net->dest_state = (SCTP_ADDR_REACHABLE | SCTP_ADDR_OUT_OF_SCOPE); @@ -3989,24 +4021,25 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, stcb->asoc.numnets++; *(&net->ref_count) = 1; net->cwr_window_tsn = net->last_cwr_tsn = stcb->asoc.sending_seq - 1; - net->tos_flowlabel = 0; if (SCTP_BASE_SYSCTL(sctp_udp_tunneling_for_client_enable)) { net->port = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); } else { net->port = 0; } -#ifdef INET - if (newaddr->sa_family == AF_INET) - net->tos_flowlabel = stcb->asoc.default_tos; -#endif + net->dscp = stcb->asoc.default_dscp; #ifdef INET6 - if (newaddr->sa_family == AF_INET6) - net->tos_flowlabel = stcb->asoc.default_flowlabel; + net->flowlabel = stcb->asoc.default_flowlabel; #endif + if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { + net->dest_state |= SCTP_ADDR_NOHB; + } else { + net->dest_state &= ~SCTP_ADDR_NOHB; + } + net->heart_beat_delay = stcb->asoc.heart_beat_delay; /* Init the timer structure */ SCTP_OS_TIMER_INIT(&net->rxt_timer.timer); - SCTP_OS_TIMER_INIT(&net->fr_timer.timer); SCTP_OS_TIMER_INIT(&net->pmtu_timer.timer); + SCTP_OS_TIMER_INIT(&net->hb_timer.timer); /* Now generate a route for this guy */ #ifdef INET6 @@ -4153,8 +4186,6 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, /* No route to current primary adopt new primary */ stcb->asoc.primary_destination = net; } - sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, - net); /* Validate primary is first */ net = TAILQ_FIRST(&stcb->asoc.nets); if ((net != stcb->asoc.primary_destination) && @@ -4169,6 +4200,9 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, TAILQ_INSERT_HEAD(&stcb->asoc.nets, stcb->asoc.primary_destination, sctp_next); } + if (netp) { + *netp = net; + } return (0); } @@ -4257,6 +4291,16 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, *error = EINVAL; return (NULL); } + if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) || + (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED)) { + SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); + *error = EINVAL; + return (NULL); + } + } SCTPDBG(SCTP_DEBUG_PCB3, "Allocate an association for peer:"); #ifdef SCTP_DEBUG if (firstaddr) { @@ -4288,7 +4332,10 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, struct sockaddr_in *sin; sin = (struct sockaddr_in *)firstaddr; - if ((sin->sin_port == 0) || (sin->sin_addr.s_addr == 0)) { + if ((ntohs(sin->sin_port) == 0) || + (sin->sin_addr.s_addr == INADDR_ANY) || + (sin->sin_addr.s_addr == INADDR_BROADCAST) || + IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { /* Invalid address */ SCTP_INP_RUNLOCK(inp); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); @@ -4305,8 +4352,9 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, struct sockaddr_in6 *sin6; sin6 = (struct sockaddr_in6 *)firstaddr; - if ((sin6->sin6_port == 0) || - (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) { + if ((ntohs(sin6->sin6_port) == 0) || + IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || + IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { /* Invalid address */ SCTP_INP_RUNLOCK(inp); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); @@ -4393,7 +4441,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, LIST_INSERT_HEAD(head, stcb, sctp_asocs); SCTP_INP_INFO_WUNLOCK(); - if ((err = sctp_add_remote_addr(stcb, firstaddr, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) { + if ((err = sctp_add_remote_addr(stcb, firstaddr, NULL, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) { /* failure.. memory error? */ if (asoc->strmout) { SCTP_FREE(asoc->strmout, SCTP_M_STRMO); @@ -4418,7 +4466,6 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, return (NULL); } /* Init all the timers */ - SCTP_OS_TIMER_INIT(&asoc->hb_timer.timer); SCTP_OS_TIMER_INIT(&asoc->dack_timer.timer); SCTP_OS_TIMER_INIT(&asoc->strreset_timer.timer); SCTP_OS_TIMER_INIT(&asoc->asconf_timer.timer); @@ -4488,6 +4535,10 @@ out: /* Clear net */ asoc->last_control_chunk_from = NULL; } + if (net == stcb->asoc.alternate) { + sctp_free_remote_addr(stcb->asoc.alternate); + stcb->asoc.alternate = NULL; + } sctp_free_remote_addr(net); } @@ -4699,6 +4750,10 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre /* there is no asoc, really TSNH :-0 */ return (1); } + if (stcb->asoc.alternate) { + sctp_free_remote_addr(stcb->asoc.alternate); + stcb->asoc.alternate = NULL; + } /* TEMP CODE */ if (stcb->freed_from_where == 0) { /* Only record the first place free happened from */ @@ -4737,8 +4792,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } /* now clean up any other timers */ - (void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer); - asoc->hb_timer.self = NULL; (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer); asoc->dack_timer.self = NULL; (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer); @@ -4762,12 +4815,12 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre (void)SCTP_OS_TIMER_STOP(&asoc->delete_prim_timer.timer); asoc->delete_prim_timer.self = NULL; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - (void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer); - net->fr_timer.self = NULL; (void)SCTP_OS_TIMER_STOP(&net->rxt_timer.timer); net->rxt_timer.self = NULL; (void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer); net->pmtu_timer.self = NULL; + (void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer); + net->hb_timer.self = NULL; } /* Now the read queue needs to be cleaned up (only once) */ if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) { @@ -4935,7 +4988,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre * Now restop the timers to be sure this is paranoia at is finest! */ (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer); - (void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer); @@ -4943,9 +4995,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre (void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer); TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - (void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer); (void)SCTP_OS_TIMER_STOP(&net->rxt_timer.timer); (void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer); + (void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer); } asoc->strreset_timer.type = SCTP_TIMER_TYPE_NONE; @@ -6189,7 +6241,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, #ifdef INET case AF_INET: if (stcb->asoc.ipv4_addr_legal) { - if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) { + if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) { return (-1); } } @@ -6198,7 +6250,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, #ifdef INET6 case AF_INET6: if (stcb->asoc.ipv6_addr_legal) { - if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) { + if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) { return (-2); } } @@ -6289,7 +6341,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, /* the assoc was freed? */ return (-7); } - if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) { + if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) { return (-8); } } else if (stcb_tmp == stcb) { @@ -6376,7 +6428,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, * we must add the address, no scope * set */ - if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) { + if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) { return (-17); } } else if (stcb_tmp == stcb) { @@ -6748,7 +6800,10 @@ sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa, return (0); } stcb->asoc.primary_destination = net; - net->dest_state &= ~SCTP_ADDR_WAS_PRIMARY; + if (!(net->dest_state & SCTP_ADDR_PF) && (stcb->asoc.alternate)) { + sctp_free_remote_addr(stcb->asoc.alternate); + stcb->asoc.alternate = NULL; + } net = TAILQ_FIRST(&stcb->asoc.nets); if (net != stcb->asoc.primary_destination) { /* diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h index 783968191af84..e39055ca075f3 100644 --- a/sys/netinet/sctp_pcb.h +++ b/sys/netinet/sctp_pcb.h @@ -293,6 +293,8 @@ struct sctp_pcb { uint16_t def_net_failure; + uint16_t def_net_pf_threshold; + /* number of streams to pre-open on a association */ uint16_t pre_open_stream_count; uint16_t max_open_streams_intome; @@ -320,6 +322,10 @@ struct sctp_pcb { uint32_t store_at; uint32_t max_burst; uint32_t fr_max_burst; +#ifdef INET6 + uint32_t default_flowlabel; +#endif + uint8_t default_dscp; char current_secret_number; char last_secret_number; }; @@ -582,7 +588,7 @@ void sctp_remove_laddr(struct sctp_laddr *); void sctp_del_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *); -int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, int, int); +int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, struct sctp_nets **, int, int); void sctp_remove_net(struct sctp_tcb *, struct sctp_nets *); diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h index 0f9bcaf5268ba..c7dee69565780 100644 --- a/sys/netinet/sctp_structs.h +++ b/sys/netinet/sctp_structs.h @@ -251,6 +251,7 @@ struct sctp_nets { * structure shared by all. */ struct sctp_timer pmtu_timer; + struct sctp_timer hb_timer; /* * The following two in combination equate to a route entry for v6 @@ -273,7 +274,6 @@ struct sctp_nets { /* This is used for SHUTDOWN/SHUTDOWN-ACK/SEND or INIT timers */ struct sctp_timer rxt_timer; - struct sctp_timer fr_timer; /* for early fr */ /* last time in seconds I sent to it */ struct timeval last_sent_time; @@ -321,18 +321,24 @@ struct sctp_nets { uint32_t fast_recovery_tsn; uint32_t heartbeat_random1; uint32_t heartbeat_random2; - uint32_t tos_flowlabel; +#ifdef INET6 + uint32_t flowlabel; +#endif + uint8_t dscp; struct timeval start_time; /* time when this net was created */ uint32_t marked_retrans;/* number or DATA chunks marked for timer * based retransmissions */ uint32_t marked_fastretrans; + uint32_t heart_beat_delay; /* Heart Beat delay in ms */ /* if this guy is ok or not ... status */ uint16_t dest_state; - /* number of transmit failures to down this guy */ + /* number of timeouts to consider the destination unreachable */ uint16_t failure_threshold; - /* error stats on destination */ + /* number of timeouts to consider the destination potentially failed */ + uint16_t pf_threshold; + /* error stats on the destination */ uint16_t error_count; /* UDP port number in case of UDP tunneling */ uint16_t port; @@ -661,6 +667,7 @@ struct sctp_cc_functions { void (*sctp_cwnd_update_after_sack) (struct sctp_tcb *stcb, struct sctp_association *asoc, int accum_moved, int reneged_all, int will_exit); + void (*sctp_cwnd_update_exit_pf) (struct sctp_tcb *stcb, struct sctp_nets *net); void (*sctp_cwnd_update_after_fr) (struct sctp_tcb *stcb, struct sctp_association *asoc); void (*sctp_cwnd_update_after_timeout) (struct sctp_tcb *stcb, @@ -672,8 +679,6 @@ struct sctp_cc_functions { uint32_t * bottle_bw, uint32_t * on_queue); void (*sctp_cwnd_update_after_output) (struct sctp_tcb *stcb, struct sctp_nets *net, int burst_limit); - void (*sctp_cwnd_update_after_fr_timer) (struct sctp_inpcb *inp, - struct sctp_tcb *stcb, struct sctp_nets *net); void (*sctp_cwnd_update_packet_transmitted) (struct sctp_tcb *stcb, struct sctp_nets *net); void (*sctp_cwnd_update_tsn_acknowledged) (struct sctp_nets *net, @@ -753,7 +758,6 @@ struct sctp_association { struct sctp_nonpad_sndrcvinfo def_send; /* timers and such */ - struct sctp_timer hb_timer; /* hb timer */ struct sctp_timer dack_timer; /* Delayed ack timer */ struct sctp_timer asconf_timer; /* asconf */ struct sctp_timer strreset_timer; /* stream reset */ @@ -828,6 +832,7 @@ struct sctp_association { uint8_t *mapping_array; /* primary destination to use */ struct sctp_nets *primary_destination; + struct sctp_nets *alternate; /* If primary is down or PF */ /* For CMT */ struct sctp_nets *last_net_cmt_send_started; /* last place I got a data chunk from */ @@ -984,7 +989,9 @@ struct sctp_association { uint32_t sb_send_resv; /* amount reserved on a send */ uint32_t my_rwnd_control_len; /* shadow of sb_mbcnt used for rwnd * control */ +#ifdef INET6 uint32_t default_flowlabel; +#endif uint32_t pr_sctp_cnt; int ctrl_queue_cnt; /* could be removed REM - NO IT CAN'T!! RRS */ /* @@ -1023,8 +1030,8 @@ struct sctp_association { unsigned int size_on_all_streams; unsigned int cnt_on_all_streams; - /* Heart Beat delay in ticks */ - unsigned int heart_beat_delay; + /* Heart Beat delay in ms */ + uint32_t heart_beat_delay; /* autoclose */ unsigned int sctp_autoclose_ticks; @@ -1094,6 +1101,8 @@ struct sctp_association { uint16_t def_net_failure; + uint16_t def_net_pf_threshold; + /* * lock flag: 0 is ok to send, 1+ (duals as a retran count) is * awaiting ACK @@ -1133,8 +1142,7 @@ struct sctp_association { uint8_t last_flags_delivered; uint8_t hb_ect_randombit; uint8_t hb_random_idx; - uint8_t hb_is_disabled; /* is the hb disabled? */ - uint8_t default_tos; + uint8_t default_dscp; uint8_t asconf_del_pending; /* asconf delete last addr pending */ /* diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c index bb7b6e265d22f..25d75f88e084d 100644 --- a/sys/netinet/sctp_sysctl.c +++ b/sys/netinet/sctp_sysctl.c @@ -83,16 +83,14 @@ sctp_init_sysctls() SCTP_BASE_SYSCTL(sctp_init_rtx_max_default) = SCTPCTL_INIT_RTX_MAX_DEFAULT; SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default) = SCTPCTL_ASSOC_RTX_MAX_DEFAULT; SCTP_BASE_SYSCTL(sctp_path_rtx_max_default) = SCTPCTL_PATH_RTX_MAX_DEFAULT; + SCTP_BASE_SYSCTL(sctp_path_pf_threshold) = SCTPCTL_PATH_PF_THRESHOLD_DEFAULT; SCTP_BASE_SYSCTL(sctp_add_more_threshold) = SCTPCTL_ADD_MORE_ON_OUTPUT_DEFAULT; SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default) = SCTPCTL_OUTGOING_STREAMS_DEFAULT; SCTP_BASE_SYSCTL(sctp_cmt_on_off) = SCTPCTL_CMT_ON_OFF_DEFAULT; /* EY */ SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) = SCTPCTL_NR_SACK_ON_OFF_DEFAULT; SCTP_BASE_SYSCTL(sctp_cmt_use_dac) = SCTPCTL_CMT_USE_DAC_DEFAULT; - SCTP_BASE_SYSCTL(sctp_cmt_pf) = SCTPCTL_CMT_PF_DEFAULT; SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst) = SCTPCTL_CWND_MAXBURST_DEFAULT; - SCTP_BASE_SYSCTL(sctp_early_fr) = SCTPCTL_EARLY_FAST_RETRAN_DEFAULT; - SCTP_BASE_SYSCTL(sctp_early_fr_msec) = SCTPCTL_EARLY_FAST_RETRAN_MSEC_DEFAULT; SCTP_BASE_SYSCTL(sctp_asconf_auth_nochk) = SCTPCTL_ASCONF_AUTH_NOCHK_DEFAULT; SCTP_BASE_SYSCTL(sctp_auth_disable) = SCTPCTL_AUTH_DISABLE_DEFAULT; SCTP_BASE_SYSCTL(sctp_nat_friendly) = SCTPCTL_NAT_FRIENDLY_DEFAULT; @@ -494,6 +492,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) xraddr.active = ((net->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE); xraddr.confirmed = ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0); xraddr.heartbeat_enabled = ((net->dest_state & SCTP_ADDR_NOHB) == 0); + xraddr.potentially_failed = ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF); xraddr.rto = net->RTO; xraddr.max_path_rtx = net->failure_threshold; xraddr.rtx = net->marked_retrans; @@ -502,6 +501,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) xraddr.flight_size = net->flight_size; xraddr.mtu = net->mtu; xraddr.rtt = net->rtt / 1000; + xraddr.heartbeat_interval = net->heart_beat_delay; xraddr.start_time.tv_sec = (uint32_t) net->start_time.tv_sec; xraddr.start_time.tv_usec = (uint32_t) net->start_time.tv_usec; SCTP_INP_RUNLOCK(inp); @@ -633,16 +633,14 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS) RANGECHK(SCTP_BASE_SYSCTL(sctp_init_rtx_max_default), SCTPCTL_INIT_RTX_MAX_MIN, SCTPCTL_INIT_RTX_MAX_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default), SCTPCTL_ASSOC_RTX_MAX_MIN, SCTPCTL_ASSOC_RTX_MAX_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_path_rtx_max_default), SCTPCTL_PATH_RTX_MAX_MIN, SCTPCTL_PATH_RTX_MAX_MAX); + RANGECHK(SCTP_BASE_SYSCTL(sctp_path_pf_threshold), SCTPCTL_PATH_PF_THRESHOLD_MIN, SCTPCTL_PATH_PF_THRESHOLD_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTPCTL_ADD_MORE_ON_OUTPUT_MIN, SCTPCTL_ADD_MORE_ON_OUTPUT_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default), SCTPCTL_OUTGOING_STREAMS_MIN, SCTPCTL_OUTGOING_STREAMS_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_on_off), SCTPCTL_CMT_ON_OFF_MIN, SCTPCTL_CMT_ON_OFF_MAX); /* EY */ RANGECHK(SCTP_BASE_SYSCTL(sctp_nr_sack_on_off), SCTPCTL_NR_SACK_ON_OFF_MIN, SCTPCTL_NR_SACK_ON_OFF_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_use_dac), SCTPCTL_CMT_USE_DAC_MIN, SCTPCTL_CMT_USE_DAC_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_pf), SCTPCTL_CMT_PF_MIN, SCTPCTL_CMT_PF_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), SCTPCTL_CWND_MAXBURST_MIN, SCTPCTL_CWND_MAXBURST_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_early_fr), SCTPCTL_EARLY_FAST_RETRAN_MIN, SCTPCTL_EARLY_FAST_RETRAN_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_early_fr_msec), SCTPCTL_EARLY_FAST_RETRAN_MSEC_MIN, SCTPCTL_EARLY_FAST_RETRAN_MSEC_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_asconf_auth_nochk), SCTPCTL_ASCONF_AUTH_NOCHK_MIN, SCTPCTL_ASCONF_AUTH_NOCHK_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_auth_disable), SCTPCTL_AUTH_DISABLE_MIN, SCTPCTL_AUTH_DISABLE_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_nat_friendly), SCTPCTL_NAT_FRIENDLY_MIN, SCTPCTL_NAT_FRIENDLY_MAX); @@ -793,17 +791,6 @@ sysctl_stat_get(SYSCTL_HANDLER_ARGS) sb.sctps_timoautoclose += sarry->sctps_timoautoclose; sb.sctps_timoassockill += sarry->sctps_timoassockill; sb.sctps_timoinpkill += sarry->sctps_timoinpkill; - sb.sctps_earlyfrstart += sarry->sctps_earlyfrstart; - sb.sctps_earlyfrstop += sarry->sctps_earlyfrstop; - sb.sctps_earlyfrmrkretrans += sarry->sctps_earlyfrmrkretrans; - sb.sctps_earlyfrstpout += sarry->sctps_earlyfrstpout; - sb.sctps_earlyfrstpidsck1 += sarry->sctps_earlyfrstpidsck1; - sb.sctps_earlyfrstpidsck2 += sarry->sctps_earlyfrstpidsck2; - sb.sctps_earlyfrstpidsck3 += sarry->sctps_earlyfrstpidsck3; - sb.sctps_earlyfrstpidsck4 += sarry->sctps_earlyfrstpidsck4; - sb.sctps_earlyfrstrid += sarry->sctps_earlyfrstrid; - sb.sctps_earlyfrstrout += sarry->sctps_earlyfrstrout; - sb.sctps_earlyfrstrtmr += sarry->sctps_earlyfrstrtmr; sb.sctps_hdrops += sarry->sctps_hdrops; sb.sctps_badsum += sarry->sctps_badsum; sb.sctps_noport += sarry->sctps_noport; @@ -994,6 +981,10 @@ SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, path_rtx_max, CTLTYPE_UINT | CTLFLAG_ &SCTP_BASE_SYSCTL(sctp_path_rtx_max_default), 0, sysctl_sctp_check, "IU", SCTPCTL_PATH_RTX_MAX_DESC); +SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, path_pf_threshold, CTLTYPE_UINT | CTLFLAG_RW, + &SCTP_BASE_SYSCTL(sctp_path_pf_threshold), 0, sysctl_sctp_check, "IU", + SCTPCTL_PATH_PF_THRESHOLD_DESC); + SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, add_more_on_output, CTLTYPE_UINT | CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_add_more_threshold), 0, sysctl_sctp_check, "IU", SCTPCTL_ADD_MORE_ON_OUTPUT_DESC); @@ -1014,22 +1005,10 @@ SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, cmt_use_dac, CTLTYPE_UINT | CTLFLAG_R &SCTP_BASE_SYSCTL(sctp_cmt_use_dac), 0, sysctl_sctp_check, "IU", SCTPCTL_CMT_USE_DAC_DESC); -SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, cmt_pf, CTLTYPE_UINT | CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_cmt_pf), 0, sysctl_sctp_check, "IU", - SCTPCTL_CMT_PF_DESC); - SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, cwnd_maxburst, CTLTYPE_UINT | CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), 0, sysctl_sctp_check, "IU", SCTPCTL_CWND_MAXBURST_DESC); -SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, early_fast_retran, CTLTYPE_UINT | CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_early_fr), 0, sysctl_sctp_check, "IU", - SCTPCTL_EARLY_FAST_RETRAN_DESC); - -SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, early_fast_retran_msec, CTLTYPE_UINT | CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_early_fr_msec), 0, sysctl_sctp_check, "IU", - SCTPCTL_EARLY_FAST_RETRAN_MSEC_DESC); - SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, asconf_auth_nochk, CTLTYPE_UINT | CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_asconf_auth_nochk), 0, sysctl_sctp_check, "IU", SCTPCTL_ASCONF_AUTH_NOCHK_DESC); diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h index 6429d594fec8c..f62679f8e640a 100644 --- a/sys/netinet/sctp_sysctl.h +++ b/sys/netinet/sctp_sysctl.h @@ -74,16 +74,14 @@ struct sctp_sysctl { uint32_t sctp_init_rtx_max_default; uint32_t sctp_assoc_rtx_max_default; uint32_t sctp_path_rtx_max_default; + uint32_t sctp_path_pf_threshold; uint32_t sctp_add_more_threshold; uint32_t sctp_nr_outgoing_streams_default; uint32_t sctp_cmt_on_off; uint32_t sctp_cmt_use_dac; /* EY 5/5/08 - nr_sack flag variable */ uint32_t sctp_nr_sack_on_off; - uint32_t sctp_cmt_pf; uint32_t sctp_use_cwnd_based_maxburst; - uint32_t sctp_early_fr; - uint32_t sctp_early_fr_msec; uint32_t sctp_asconf_auth_nochk; uint32_t sctp_auth_disable; uint32_t sctp_nat_friendly; @@ -322,6 +320,12 @@ struct sctp_sysctl { #define SCTPCTL_PATH_RTX_MAX_MAX 0xFFFFFFFF #define SCTPCTL_PATH_RTX_MAX_DEFAULT SCTP_DEF_MAX_PATH_RTX +/* path_pf_threshold: threshold for considering the path potentially failed */ +#define SCTPCTL_PATH_PF_THRESHOLD_DESC "Default potentially failed threshold" +#define SCTPCTL_PATH_PF_THRESHOLD_MIN 0 +#define SCTPCTL_PATH_PF_THRESHOLD_MAX 0xFFFF +#define SCTPCTL_PATH_PF_THRESHOLD_DEFAULT SCTPCTL_PATH_PF_THRESHOLD_MAX + /* add_more_on_output: When space-wise is it worthwhile to try to add more to a socket send buffer */ #define SCTPCTL_ADD_MORE_ON_OUTPUT_DESC "When space-wise is it worthwhile to try to add more to a socket send buffer" #define SCTPCTL_ADD_MORE_ON_OUTPUT_MIN 0 @@ -352,30 +356,12 @@ struct sctp_sysctl { #define SCTPCTL_CMT_USE_DAC_MAX 1 #define SCTPCTL_CMT_USE_DAC_DEFAULT 0 -/* JRS 5/2107 - CMT PF type flag */ -#define SCTPCTL_CMT_PF_DESC "CMT PF type flag" -#define SCTPCTL_CMT_PF_MIN 0 -#define SCTPCTL_CMT_PF_MAX 2 -#define SCTPCTL_CMT_PF_DEFAULT 0 - /* cwnd_maxburst: Use a CWND adjusting maxburst */ #define SCTPCTL_CWND_MAXBURST_DESC "Use a CWND adjusting maxburst" #define SCTPCTL_CWND_MAXBURST_MIN 0 #define SCTPCTL_CWND_MAXBURST_MAX 1 #define SCTPCTL_CWND_MAXBURST_DEFAULT 1 -/* early_fast_retran: Early Fast Retransmit with timer */ -#define SCTPCTL_EARLY_FAST_RETRAN_DESC "Early Fast Retransmit with timer" -#define SCTPCTL_EARLY_FAST_RETRAN_MIN 0 -#define SCTPCTL_EARLY_FAST_RETRAN_MAX 0xFFFFFFFF -#define SCTPCTL_EARLY_FAST_RETRAN_DEFAULT 0 - -/* early_fast_retran_msec: Early Fast Retransmit minimum timer value */ -#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_DESC "Early Fast Retransmit minimum timer value" -#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_MIN 0 -#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_MAX 0xFFFFFFFF -#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_DEFAULT SCTP_MINFR_MSEC_TIMER - /* asconf_auth_nochk: Disable SCTP ASCONF AUTH requirement */ #define SCTPCTL_ASCONF_AUTH_NOCHK_DESC "Disable SCTP ASCONF AUTH requirement" #define SCTPCTL_ASCONF_AUTH_NOCHK_MIN 0 diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c index 133af4aed452d..a33e7924b2249 100644 --- a/sys/netinet/sctp_timer.c +++ b/sys/netinet/sctp_timer.c @@ -55,103 +55,6 @@ __FBSDID("$FreeBSD$"); void -sctp_early_fr_timer(struct sctp_inpcb *inp, - struct sctp_tcb *stcb, - struct sctp_nets *net) -{ - struct sctp_tmit_chunk *chk, *pchk; - struct timeval now, min_wait, tv; - unsigned int cur_rto, cnt = 0, cnt_resend = 0; - - /* an early FR is occuring. */ - (void)SCTP_GETTIME_TIMEVAL(&now); - /* get cur rto in micro-seconds */ - if (net->lastsa == 0) { - /* Hmm no rtt estimate yet? */ - cur_rto = stcb->asoc.initial_rto >> 2; - } else { - - cur_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; - } - if (cur_rto < SCTP_BASE_SYSCTL(sctp_early_fr_msec)) { - cur_rto = SCTP_BASE_SYSCTL(sctp_early_fr_msec); - } - cur_rto *= 1000; - tv.tv_sec = cur_rto / 1000000; - tv.tv_usec = cur_rto % 1000000; - min_wait = now; - timevalsub(&min_wait, &tv); - if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) { - /* - * if we hit here, we don't have enough seconds on the clock - * to account for the RTO. We just let the lower seconds be - * the bounds and don't worry about it. This may mean we - * will mark a lot more than we should. - */ - min_wait.tv_sec = min_wait.tv_usec = 0; - } - TAILQ_FOREACH_REVERSE_SAFE(chk, &stcb->asoc.sent_queue, sctpchunk_listhead, sctp_next, pchk) { - if (chk->whoTo != net) { - continue; - } - if (chk->sent == SCTP_DATAGRAM_RESEND) - cnt_resend++; - else if ((chk->sent > SCTP_DATAGRAM_UNSENT) && - (chk->sent < SCTP_DATAGRAM_RESEND)) { - /* pending, may need retran */ - if (chk->sent_rcv_time.tv_sec > min_wait.tv_sec) { - /* - * we have reached a chunk that was sent - * some seconds past our min.. forget it we - * will find no more to send. - */ - continue; - } else if (chk->sent_rcv_time.tv_sec == min_wait.tv_sec) { - /* - * we must look at the micro seconds to - * know. - */ - if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) { - /* - * ok it was sent after our boundary - * time. - */ - continue; - } - } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_EARLYFR_LOGGING_ENABLE) { - sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count, - 4, SCTP_FR_MARKED_EARLY); - } - SCTP_STAT_INCR(sctps_earlyfrmrkretrans); - chk->sent = SCTP_DATAGRAM_RESEND; - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - /* double book size since we are doing an early FR */ - chk->book_size_scale++; - cnt += chk->send_size; - if ((cnt + net->flight_size) > net->cwnd) { - /* Mark all we could possibly resend */ - break; - } - } - } - if (cnt) { - /* - * JRS - Use the congestion control given in the congestion - * control module - */ - stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer(inp, stcb, net); - } else if (cnt_resend) { - sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); - } - /* Restart it? */ - if (net->flight_size < net->cwnd) { - SCTP_STAT_INCR(sctps_earlyfrstrtmr); - sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); - } -} - -void sctp_audit_retranmission_queue(struct sctp_association *asoc) { struct sctp_tmit_chunk *chk; @@ -195,44 +98,23 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, /* We had a threshold failure */ if (net->dest_state & SCTP_ADDR_REACHABLE) { net->dest_state &= ~SCTP_ADDR_REACHABLE; - net->dest_state |= SCTP_ADDR_NOT_REACHABLE; net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY; - if (net == stcb->asoc.primary_destination) { - net->dest_state |= SCTP_ADDR_WAS_PRIMARY; - } - /* - * JRS 5/14/07 - If a destination is - * unreachable, the PF bit is turned off. - * This allows an unambiguous use of the PF - * bit for destinations that are reachable - * but potentially failed. If the - * destination is set to the unreachable - * state, also set the destination to the PF - * state. - */ - /* - * Add debug message here if destination is - * not in PF state. - */ - /* Stop any running T3 timers here? */ - if ((stcb->asoc.sctp_cmt_on_off > 0) && - (stcb->asoc.sctp_cmt_pf > 0)) { - net->dest_state &= ~SCTP_ADDR_PF; - SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", - net); - } + net->dest_state &= ~SCTP_ADDR_PF; sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_FAILED_THRESHOLD, (void *)net, SCTP_SO_NOT_LOCKED); } + } else if ((net->pf_threshold < net->failure_threshold) && + (net->error_count > net->pf_threshold)) { + if (!(net->dest_state & SCTP_ADDR_PF)) { + net->dest_state |= SCTP_ADDR_PF; + net->last_active = sctp_get_tick_count(); + sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); + } } - /*********HOLD THIS COMMENT FOR PATCH OF ALTERNATE - *********ROUTING CODE - */ - /*********HOLD THIS COMMENT FOR END OF PATCH OF ALTERNATE - *********ROUTING CODE - */ } if (stcb == NULL) return (0); @@ -407,31 +289,10 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, } } } - /* - * JRS 5/14/07 - After all destination have been considered - * as alternates, check to see if there was some active - * destination (not in PF state). If not, check to see if - * there was some PF destination with the minimum number of - * errors. If not, return the original destination. If - * there is a min_errors_net, remove the PF flag from that - * destination, set the cwnd to one or two MTUs, and return - * the destination as an alt. If there was some active - * destination with a highest cwnd, return the destination - * as an alt. - */ if (max_cwnd_net == NULL) { if (min_errors_net == NULL) { return (net); } - min_errors_net->dest_state &= ~SCTP_ADDR_PF; - min_errors_net->cwnd = min_errors_net->mtu * stcb->asoc.sctp_cmt_pf; - if (SCTP_OS_TIMER_PENDING(&min_errors_net->rxt_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, min_errors_net, - SCTP_FROM_SCTP_TIMER + SCTP_LOC_2); - } - SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to active with %d errors.\n", - min_errors_net, min_errors_net->error_count); return (min_errors_net); } else { return (max_cwnd_net); @@ -646,15 +507,12 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, /* get cur rto in micro-seconds */ cur_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; cur_rto *= 1000; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(cur_rto, stcb->asoc.peers_rwnd, window_probe, SCTP_FR_T3_MARK_TIME); - sctp_log_fr(net->flight_size, - SCTP_OS_TIMER_PENDING(&net->fr_timer.timer), - SCTP_OS_TIMER_ACTIVE(&net->fr_timer.timer), - SCTP_FR_CWND_REPORT); + sctp_log_fr(net->flight_size, 0, 0, SCTP_FR_CWND_REPORT); sctp_log_fr(net->flight_size, net->cwnd, stcb->asoc.total_flight, SCTP_FR_CWND_REPORT); } tv.tv_sec = cur_rto / 1000000; @@ -670,7 +528,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb, */ min_wait.tv_sec = min_wait.tv_usec = 0; } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(cur_rto, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME); sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME); } @@ -717,7 +575,7 @@ start_again: */ /* validate its been outstanding long enough */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(chk->rec.data.TSN_seq, chk->sent_rcv_time.tv_sec, chk->sent_rcv_time.tv_usec, @@ -729,7 +587,7 @@ start_again: * some seconds past our min.. forget it we * will find no more to send. */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(0, chk->sent_rcv_time.tv_sec, chk->sent_rcv_time.tv_usec, @@ -747,12 +605,6 @@ start_again: * ok it was sent after our boundary * time. */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { - sctp_log_fr(0, - chk->sent_rcv_time.tv_sec, - chk->sent_rcv_time.tv_usec, - SCTP_FR_T3_STOPPED); - } continue; } } @@ -791,7 +643,7 @@ start_again: tsnfirst = chk->rec.data.TSN_seq; } tsnlast = chk->rec.data.TSN_seq; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count, 0, SCTP_FR_T3_MARKED); } @@ -860,7 +712,7 @@ start_again: /* we did not subtract the same things? */ audit_tf = 1; } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT); } #ifdef SCTP_DEBUG @@ -978,61 +830,6 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, win_probe = 0; } - /* - * JRS 5/14/07 - If CMT PF is on and the destination if not already - * in PF state, set the destination to PF state and store the - * current time as the time that the destination was last active. In - * addition, find an alternate destination with PF-based - * find_alt_net(). - */ - if ((stcb->asoc.sctp_cmt_on_off > 0) && - (stcb->asoc.sctp_cmt_pf > 0)) { - if ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF) { - net->dest_state |= SCTP_ADDR_PF; - net->last_active = sctp_get_tick_count(); - SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from active to PF.\n", - net); - } - alt = sctp_find_alternate_net(stcb, net, 2); - } else if (stcb->asoc.sctp_cmt_on_off > 0) { - /* - * CMT: Using RTX_SSTHRESH policy for CMT. If CMT is being - * used, then pick dest with largest ssthresh for any - * retransmission. - */ - alt = sctp_find_alternate_net(stcb, net, 1); - /* - * CUCv2: If a different dest is picked for the - * retransmission, then new (rtx-)pseudo_cumack needs to be - * tracked for orig dest. Let CUCv2 track new (rtx-) - * pseudo-cumack always. - */ - net->find_pseudo_cumack = 1; - net->find_rtx_pseudo_cumack = 1; - } else { /* CMT is OFF */ - alt = sctp_find_alternate_net(stcb, net, 0); - } - num_mk = 0; - num_abandoned = 0; - (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, - &num_mk, &num_abandoned); - /* FR Loss recovery just ended with the T3. */ - stcb->asoc.fast_retran_loss_recovery = 0; - - /* CMT FR loss recovery ended with the T3 */ - net->fast_retran_loss_recovery = 0; - if ((stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) && - (net->flight_size == 0)) { - (*stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) (stcb, net); - } - /* - * setup the sat loss recovery that prevents satellite cwnd advance. - */ - stcb->asoc.sat_t3_loss_recovery = 1; - stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq; - - /* Backoff the timer and cwnd */ - sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned); if (win_probe == 0) { /* We don't do normal threshold management on window probes */ if (sctp_threshold_management(inp, stcb, net, @@ -1051,17 +848,15 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, } else { ms_goneby = 0; } - if ((ms_goneby > net->RTO) || (net->RTO == 0)) { - /* - * no recent feed back in an RTO or - * more, request a RTT update - */ - if (sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED) < 0) + if ((net->dest_state & SCTP_ADDR_PF) == 0) { + if ((ms_goneby > net->RTO) || (net->RTO == 0)) { /* - * Less than 0 means we lost - * the assoc + * no recent feed back in an + * RTO or more, request a + * RTT update */ - return (1); + sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); + } } } } @@ -1078,7 +873,52 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, return (1); } } - if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { + if (stcb->asoc.sctp_cmt_on_off > 0) { + if (net->pf_threshold < net->failure_threshold) { + alt = sctp_find_alternate_net(stcb, net, 2); + } else { + /* + * CMT: Using RTX_SSTHRESH policy for CMT. If CMT is + * being used, then pick dest with largest ssthresh + * for any retransmission. + */ + alt = sctp_find_alternate_net(stcb, net, 1); + /* + * CUCv2: If a different dest is picked for the + * retransmission, then new (rtx-)pseudo_cumack + * needs to be tracked for orig dest. Let CUCv2 + * track new (rtx-) pseudo-cumack always. + */ + net->find_pseudo_cumack = 1; + net->find_rtx_pseudo_cumack = 1; + } + } else { + alt = sctp_find_alternate_net(stcb, net, 0); + } + + num_mk = 0; + num_abandoned = 0; + (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, + &num_mk, &num_abandoned); + /* FR Loss recovery just ended with the T3. */ + stcb->asoc.fast_retran_loss_recovery = 0; + + /* CMT FR loss recovery ended with the T3 */ + net->fast_retran_loss_recovery = 0; + if ((stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) && + (net->flight_size == 0)) { + (*stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) (stcb, net); + } + /* + * setup the sat loss recovery that prevents satellite cwnd advance. + */ + stcb->asoc.sat_t3_loss_recovery = 1; + stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq; + + /* Backoff the timer and cwnd */ + sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned); + if ((!(net->dest_state & SCTP_ADDR_REACHABLE)) || + (net->dest_state & SCTP_ADDR_PF)) { /* Move all pending over too */ sctp_move_chunks_from_net(stcb, net); @@ -1106,23 +946,12 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, * change-primary then this flag must be cleared * from any net structures. */ - if (sctp_set_primary_addr(stcb, - (struct sockaddr *)NULL, - alt) == 0) { - net->dest_state |= SCTP_ADDR_WAS_PRIMARY; + if (stcb->asoc.alternate) { + sctp_free_remote_addr(stcb->asoc.alternate); } + stcb->asoc.alternate = alt; + atomic_add_int(&stcb->asoc.alternate->ref_count, 1); } - } else if ((stcb->asoc.sctp_cmt_on_off > 0) && - (stcb->asoc.sctp_cmt_pf > 0) && - ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { - /* - * JRS 5/14/07 - If the destination hasn't failed completely - * but is in PF state, a PF-heartbeat needs to be sent - * manually. - */ - if (sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED) < 0) - /* Return less than 0 means we lost the association */ - return (1); } /* * Special case for cookie-echo'ed case, we don't do output but must @@ -1324,7 +1153,7 @@ sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, atomic_add_int(&alt->ref_count, 1); } } - if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { + if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { /* * If the address went un-reachable, we need to move to * alternates for ALL chk's in queue @@ -1414,7 +1243,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); chk->sent = SCTP_DATAGRAM_RESEND; } - if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { + if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { /* * If the address went un-reachable, we need to move * to the alternate for ALL chunks in queue @@ -1569,11 +1398,15 @@ sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp, int sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *net, int cnt_of_unconf) + struct sctp_nets *net) { - int ret; + uint8_t net_was_pf; + net_was_pf = 0; if (net) { + if (net->dest_state & SCTP_ADDR_PF) { + net_was_pf = 1; + } if (net->hb_responded == 0) { if (net->ro._s_addr) { /* @@ -1585,6 +1418,10 @@ sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, net->src_addr_selected = 0; } sctp_backoff_on_timeout(stcb, net, 1, 0, 0); + if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { + /* Assoc is over */ + return (1); + } } /* Zero PBA, if it needs it */ if (net->partial_bytes_acked) { @@ -1596,41 +1433,13 @@ sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { sctp_audit_stream_queues_for_size(inp, stcb); } - /* Send a new HB, this will do threshold managment, pick a new dest */ - if (cnt_of_unconf == 0) { - if (sctp_send_hb(stcb, 0, NULL, SCTP_SO_NOT_LOCKED) < 0) { - return (1); - } - } else { + if (!(net->dest_state & SCTP_ADDR_NOHB) && + !((net_was_pf == 0) && (net->dest_state & SCTP_ADDR_PF))) { /* - * this will send out extra hb's up to maxburst if there are - * any unconfirmed addresses. + * when move to PF during threshold mangement, a HB has been + * queued in that routine */ - uint32_t cnt_sent = 0; - - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) && - (net->dest_state & SCTP_ADDR_REACHABLE)) { - cnt_sent++; - if (net->hb_responded == 0) { - /* Did we respond last time? */ - if (net->ro._s_addr) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - net->src_addr_selected = 0; - } - } - ret = sctp_send_hb(stcb, 1, net, SCTP_SO_NOT_LOCKED); - if (ret < 0) - return 1; - else if (ret == 0) { - break; - } - if (SCTP_BASE_SYSCTL(sctp_hb_maxburst) && - (cnt_sent >= SCTP_BASE_SYSCTL(sctp_hb_maxburst))) - break; - } - } + sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); } return (0); } @@ -1733,7 +1542,14 @@ sctp_autoclose_timer(struct sctp_inpcb *inp, */ if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { /* only send SHUTDOWN 1st time thru */ - sctp_send_shutdown(stcb, stcb->asoc.primary_destination); + struct sctp_nets *netp; + + if (stcb->asoc.alternate) { + netp = stcb->asoc.alternate; + } else { + netp = stcb->asoc.primary_destination; + } + sctp_send_shutdown(stcb, netp); if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); @@ -1742,10 +1558,10 @@ sctp_autoclose_timer(struct sctp_inpcb *inp, SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, - asoc->primary_destination); + netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, - asoc->primary_destination); + netp); } } } else { diff --git a/sys/netinet/sctp_timer.h b/sys/netinet/sctp_timer.h index 5857291da8900..7b1341a3cf481 100644 --- a/sys/netinet/sctp_timer.h +++ b/sys/netinet/sctp_timer.h @@ -42,10 +42,6 @@ __FBSDID("$FreeBSD$"); #define SCTP_RTT_SHIFT 3 #define SCTP_RTT_VAR_SHIFT 2 -void -sctp_early_fr_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct sctp_nets *net); - struct sctp_nets * sctp_find_alternate_net(struct sctp_tcb *, struct sctp_nets *, int mode); @@ -65,7 +61,7 @@ sctp_shutdown_timer(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *); int sctp_heartbeat_timer(struct sctp_inpcb *, struct sctp_tcb *, - struct sctp_nets *, int); + struct sctp_nets *); int sctp_cookie_timer(struct sctp_inpcb *, struct sctp_tcb *, diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h index 9b9acbfc6f64d..37e9b798a991b 100644 --- a/sys/netinet/sctp_uio.h +++ b/sys/netinet/sctp_uio.h @@ -329,7 +329,8 @@ struct sctp_paddr_change { #define SCTP_ADDR_CONFIRMED 0x0006 #define SCTP_ACTIVE 0x0001 /* SCTP_ADDR_REACHABLE */ -#define SCTP_INACTIVE 0x0002 /* SCTP_ADDR_NOT_REACHABLE */ +#define SCTP_INACTIVE 0x0002 /* neither SCTP_ADDR_REACHABLE nor + * SCTP_ADDR_UNCONFIRMED */ #define SCTP_UNCONFIRMED 0x0200 /* SCTP_ADDR_UNCONFIRMED */ /* remote error events */ @@ -504,9 +505,11 @@ struct sctp_paddrparams { uint32_t spp_flags; uint32_t spp_ipv6_flowlabel; uint16_t spp_pathmaxrxt; - uint8_t spp_ipv4_tos; + uint8_t spp_dscp; }; +#define spp_ipv4_tos spp_dscp + #define SPP_HB_ENABLE 0x00000001 #define SPP_HB_DISABLE 0x00000002 #define SPP_HB_DEMAND 0x00000004 @@ -514,7 +517,15 @@ struct sctp_paddrparams { #define SPP_PMTUD_DISABLE 0x00000010 #define SPP_HB_TIME_IS_ZERO 0x00000080 #define SPP_IPV6_FLOWLABEL 0x00000100 -#define SPP_IPV4_TOS 0x00000200 +#define SPP_DSCP 0x00000200 +#define SPP_IPV4_TOS SPP_DSCP + +struct sctp_paddrthlds { + sctp_assoc_t spt_assoc_id; + struct sockaddr_storage spt_address; + uint16_t spt_pathmaxrxt; + uint16_t spt_pathpfthld; +}; struct sctp_paddrinfo { struct sockaddr_storage spinfo_address; @@ -978,18 +989,8 @@ struct sctpstat { * fired */ uint32_t sctps_timoassockill; /* Number of asoc free timers expired */ uint32_t sctps_timoinpkill; /* Number of inp free timers expired */ - /* Early fast retransmission counters */ - uint32_t sctps_earlyfrstart; - uint32_t sctps_earlyfrstop; - uint32_t sctps_earlyfrmrkretrans; - uint32_t sctps_earlyfrstpout; - uint32_t sctps_earlyfrstpidsck1; - uint32_t sctps_earlyfrstpidsck2; - uint32_t sctps_earlyfrstpidsck3; - uint32_t sctps_earlyfrstpidsck4; - uint32_t sctps_earlyfrstrid; - uint32_t sctps_earlyfrstrout; - uint32_t sctps_earlyfrstrtmr; + /* former early FR counters */ + uint32_t sctps_spare[11]; /* others */ uint32_t sctps_hdrops; /* packet shorter than header */ uint32_t sctps_badsum; /* checksum error */ @@ -1162,9 +1163,11 @@ struct xsctp_raddr { uint8_t active; /* sctpAssocLocalRemEntry 3 */ uint8_t confirmed; /* */ uint8_t heartbeat_enabled; /* sctpAssocLocalRemEntry 4 */ + uint8_t potentially_failed; struct sctp_timeval start_time; /* sctpAssocLocalRemEntry 8 */ uint32_t rtt; - uint32_t extra_padding[32]; /* future */ + uint32_t heartbeat_interval; + uint32_t extra_padding[31]; /* future */ }; #define SCTP_MAX_LOGGING_SIZE 30000 diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index ab87772f0d475..82a8cba37fcbb 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -275,33 +275,8 @@ sctp_notify(struct sctp_inpcb *inp, */ if (net->dest_state & SCTP_ADDR_REACHABLE) { /* Ok that destination is NOT reachable */ - SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n", - net->error_count, - net->failure_threshold, - net); - net->dest_state &= ~SCTP_ADDR_REACHABLE; - net->dest_state |= SCTP_ADDR_NOT_REACHABLE; - /* - * JRS 5/14/07 - If a destination is unreachable, - * the PF bit is turned off. This allows an - * unambiguous use of the PF bit for destinations - * that are reachable but potentially failed. If the - * destination is set to the unreachable state, also - * set the destination to the PF state. - */ - /* - * Add debug message here if destination is not in - * PF state. - */ - /* Stop any running T3 timers here? */ - if ((stcb->asoc.sctp_cmt_on_off > 0) && - (stcb->asoc.sctp_cmt_pf > 0)) { - net->dest_state &= ~SCTP_ADDR_PF; - SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", - net); - } - net->error_count = net->failure_threshold + 1; + net->dest_state &= ~SCTP_ADDR_PF; sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_FAILED_THRESHOLD, (void *)net, SCTP_SO_NOT_LOCKED); @@ -585,7 +560,7 @@ sctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p) struct sctp_inpcb *inp = NULL; int error; -#ifdef INET6 +#ifdef INET if (addr && addr->sa_family != AF_INET) { /* must be a v4 address! */ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); @@ -837,9 +812,15 @@ sctp_disconnect(struct socket *so) if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { /* only send SHUTDOWN 1st time thru */ + struct sctp_nets *netp; + + if (stcb->asoc.alternate) { + netp = stcb->asoc.alternate; + } else { + netp = stcb->asoc.primary_destination; + } sctp_stop_timers_for_shutdown(stcb); - sctp_send_shutdown(stcb, - stcb->asoc.primary_destination); + sctp_send_shutdown(stcb, netp); sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { @@ -848,11 +829,10 @@ sctp_disconnect(struct socket *so) SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, - stcb->sctp_ep, stcb, - asoc->primary_destination); + stcb->sctp_ep, stcb, netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, - stcb->sctp_ep, stcb, - asoc->primary_destination); + stcb->sctp_ep, stcb, netp); + } } else { /* @@ -865,9 +845,17 @@ sctp_disconnect(struct socket *so) * we will allow user data to be sent first * and move to SHUTDOWN-PENDING */ + struct sctp_nets *netp; + + if (stcb->asoc.alternate) { + netp = stcb->asoc.alternate; + } else { + netp = stcb->asoc.primary_destination; + } + asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, - asoc->primary_destination); + netp); if (asoc->locked_on_sending) { /* Locked to send out the data */ struct sctp_stream_queue_pending *sp; @@ -1047,9 +1035,15 @@ sctp_shutdown(struct socket *so) /* there is nothing queued to send, so I'm done... */ if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { /* only send SHUTDOWN the first time through */ + struct sctp_nets *netp; + + if (stcb->asoc.alternate) { + netp = stcb->asoc.alternate; + } else { + netp = stcb->asoc.primary_destination; + } sctp_stop_timers_for_shutdown(stcb); - sctp_send_shutdown(stcb, - stcb->asoc.primary_destination); + sctp_send_shutdown(stcb, netp); sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { @@ -1058,20 +1052,26 @@ sctp_shutdown(struct socket *so) SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, - stcb->sctp_ep, stcb, - asoc->primary_destination); + stcb->sctp_ep, stcb, netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, - stcb->sctp_ep, stcb, - asoc->primary_destination); + stcb->sctp_ep, stcb, netp); } } else { /* * we still got (or just got) data to send, so set * SHUTDOWN_PENDING */ + struct sctp_nets *netp; + + if (stcb->asoc.alternate) { + netp = stcb->asoc.alternate; + } else { + netp = stcb->asoc.primary_destination; + } + asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, - asoc->primary_destination); + netp); if (asoc->locked_on_sending) { /* Locked to send out the data */ @@ -1541,6 +1541,11 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, /* Gak! no memory */ goto out_now; } + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { + stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; + /* Set the connected flag so we can queue data */ + soisconnecting(so); + } SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); /* move to second address */ switch (sa->sa_family) { @@ -1767,7 +1772,9 @@ flags_out: av->assoc_value = stcb->asoc.sctp_cmt_on_off; SCTP_TCB_UNLOCK(stcb); } else { - if (av->assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); av->assoc_value = inp->sctp_cmt_on_off; SCTP_INP_RUNLOCK(inp); @@ -1791,7 +1798,9 @@ flags_out: av->assoc_value = stcb->asoc.congestion_control_module; SCTP_TCB_UNLOCK(stcb); } else { - if (av->assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); av->assoc_value = inp->sctp_ep.sctp_default_cc_module; SCTP_INP_RUNLOCK(inp); @@ -1834,7 +1843,9 @@ flags_out: av->assoc_value = stcb->asoc.stream_scheduling_module; SCTP_TCB_UNLOCK(stcb); } else { - if (av->assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); av->assoc_value = inp->sctp_ep.sctp_default_ss_module; SCTP_INP_RUNLOCK(inp); @@ -1949,7 +1960,9 @@ flags_out: av->assoc_value = stcb->asoc.context; SCTP_TCB_UNLOCK(stcb); } else { - if (av->assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); av->assoc_value = inp->sctp_context; SCTP_INP_RUNLOCK(inp); @@ -2022,7 +2035,9 @@ flags_out: sack->sack_freq = stcb->asoc.sack_freq; SCTP_TCB_UNLOCK(stcb); } else { - if (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); sack->sack_freq = inp->sctp_ep.sctp_sack_freq; @@ -2067,7 +2082,9 @@ flags_out: av->assoc_value = stcb->asoc.max_burst; SCTP_TCB_UNLOCK(stcb); } else { - if (av->assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); av->assoc_value = inp->sctp_ep.max_burst; SCTP_INP_RUNLOCK(inp); @@ -2093,7 +2110,9 @@ flags_out: av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); SCTP_TCB_UNLOCK(stcb); } else { - if (av->assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { ovh = SCTP_MED_OVERHEAD; @@ -2389,7 +2408,7 @@ flags_out: } } if (stcb) { - /* Applys to the specific association */ + /* Applies to the specific association */ paddrp->spp_flags = 0; if (net) { int ovh; @@ -2400,7 +2419,7 @@ flags_out: ovh = SCTP_MED_V4_OVERHEAD; } - + paddrp->spp_hbinterval = net->heart_beat_delay; paddrp->spp_pathmaxrxt = net->failure_threshold; paddrp->spp_pathmtu = net->mtu - ovh; /* get flags for HB */ @@ -2414,15 +2433,14 @@ flags_out: } else { paddrp->spp_flags |= SPP_PMTUD_DISABLE; } -#ifdef INET - if (net->ro._l_addr.sin.sin_family == AF_INET) { - paddrp->spp_ipv4_tos = net->tos_flowlabel & 0x000000fc; - paddrp->spp_flags |= SPP_IPV4_TOS; + if (net->dscp & 0x01) { + paddrp->spp_dscp = net->dscp >> 2; + paddrp->spp_flags |= SPP_DSCP; } -#endif #ifdef INET6 - if (net->ro._l_addr.sin6.sin6_family == AF_INET6) { - paddrp->spp_ipv6_flowlabel = net->tos_flowlabel; + if ((net->ro._l_addr.sa.sa_family == AF_INET6) && + (net->flowlabel & 0x80000000)) { + paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff; paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; } #endif @@ -2435,20 +2453,23 @@ flags_out: paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc); -#ifdef INET - paddrp->spp_ipv4_tos = stcb->asoc.default_tos & 0x000000fc; - paddrp->spp_flags |= SPP_IPV4_TOS; -#endif + if (stcb->asoc.default_dscp & 0x01) { + paddrp->spp_dscp = stcb->asoc.default_dscp >> 2; + paddrp->spp_flags |= SPP_DSCP; + } #ifdef INET6 - paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel; - paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; + if (stcb->asoc.default_flowlabel & 0x80000000) { + paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff; + paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; + } #endif /* default settings should be these */ - if (stcb->asoc.hb_is_disabled == 0) { - paddrp->spp_flags |= SPP_HB_ENABLE; - } else { + if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { paddrp->spp_flags |= SPP_HB_DISABLE; + } else { + paddrp->spp_flags |= SPP_HB_ENABLE; } + paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { cnt++; @@ -2458,24 +2479,26 @@ flags_out: paddrp->spp_flags |= SPP_PMTUD_ENABLE; } } - paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; paddrp->spp_assoc_id = sctp_get_associd(stcb); SCTP_TCB_UNLOCK(stcb); } else { - if (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { /* Use endpoint defaults */ SCTP_INP_RLOCK(inp); paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC; /* get inp's default */ -#ifdef INET - paddrp->spp_ipv4_tos = inp->ip_inp.inp.inp_ip_tos; - paddrp->spp_flags |= SPP_IPV4_TOS; -#endif + if (inp->sctp_ep.default_dscp & 0x01) { + paddrp->spp_dscp = inp->sctp_ep.default_dscp >> 2; + paddrp->spp_flags |= SPP_DSCP; + } #ifdef INET6 - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - paddrp->spp_ipv6_flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo; + if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && + (inp->sctp_ep.default_flowlabel & 0x80000000)) { + paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff; paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; } #endif @@ -2637,7 +2660,9 @@ flags_out: srto->srto_min = stcb->asoc.minrto; SCTP_TCB_UNLOCK(stcb); } else { - if (srto->srto_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); srto->srto_initial = inp->sctp_ep.initial_rto; srto->srto_max = inp->sctp_ep.sctp_maxrto; @@ -2691,7 +2716,9 @@ flags_out: sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; SCTP_TCB_UNLOCK(stcb); } else { - if (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life); sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; @@ -2720,7 +2747,9 @@ flags_out: memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send)); SCTP_TCB_UNLOCK(stcb); } else { - if (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); memcpy(s_info, &inp->def_send, sizeof(inp->def_send)); SCTP_INP_RUNLOCK(inp); @@ -2822,7 +2851,9 @@ flags_out: scact->scact_keynumber = stcb->asoc.authinfo.active_keyid; SCTP_TCB_UNLOCK(stcb); } else { - if (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) { /* get the endpoint active key */ SCTP_INP_RLOCK(inp); scact->scact_keynumber = inp->sctp_ep.default_keyid; @@ -2861,7 +2892,9 @@ flags_out: } SCTP_TCB_UNLOCK(stcb); } else { - if (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) { /* get off the endpoint */ SCTP_INP_RLOCK(inp); chklist = inp->sctp_ep.local_auth_chunks; @@ -2967,7 +3000,9 @@ flags_out: event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type); SCTP_TCB_UNLOCK(stcb); } else { - if (event->se_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (event->se_assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); event->se_on = sctp_is_feature_on(inp, event_type); SCTP_INP_RUNLOCK(inp); @@ -3035,7 +3070,9 @@ flags_out: info->snd_context = stcb->asoc.def_send.sinfo_context; SCTP_TCB_UNLOCK(stcb); } else { - if (info->snd_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); info->snd_sid = inp->def_send.sinfo_stream; info->snd_flags = inp->def_send.sinfo_flags; @@ -3065,7 +3102,9 @@ flags_out: info->pr_value = stcb->asoc.def_send.sinfo_timetolive; SCTP_TCB_UNLOCK(stcb); } else { - if (info->pr_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_RLOCK(inp); info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); info->pr_value = inp->def_send.sinfo_timetolive; @@ -3080,6 +3119,97 @@ flags_out: } break; } + case SCTP_PEER_ADDR_THLDS: + { + struct sctp_paddrthlds *thlds; + struct sctp_nets *net; + + SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize); + SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); + + net = NULL; + if (stcb) { + net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address); + } else { + /* + * We increment here since + * sctp_findassociation_ep_addr() wil do a + * decrement if it finds the stcb as long as + * the locked tcb (last argument) is NOT a + * TCB.. aka NULL. + */ + SCTP_INP_INCR_REF(inp); + stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&thlds->spt_address, &net, NULL, NULL); + if (stcb == NULL) { + SCTP_INP_DECR_REF(inp); + } + } + if (stcb && (net == NULL)) { + struct sockaddr *sa; + + sa = (struct sockaddr *)&thlds->spt_address; +#ifdef INET + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)sa; + if (sin->sin_addr.s_addr) { + error = EINVAL; + SCTP_TCB_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + break; + } + } else +#endif +#ifdef INET6 + if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)sa; + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + error = EINVAL; + SCTP_TCB_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + break; + } + } else +#endif + { + error = EAFNOSUPPORT; + SCTP_TCB_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + break; + } + } + if (stcb) { + if (net) { + thlds->spt_pathmaxrxt = net->failure_threshold; + thlds->spt_pathpfthld = net->pf_threshold; + } else { + thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure; + thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold; + } + thlds->spt_assoc_id = sctp_get_associd(stcb); + SCTP_TCB_UNLOCK(stcb); + } else { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { + /* Use endpoint defaults */ + SCTP_INP_RLOCK(inp); + thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure; + thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold; + SCTP_INP_RUNLOCK(inp); + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + } + if (error == 0) { + *optsize = sizeof(struct sctp_paddrthlds); + } + break; + } default: SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); error = ENOPROTOOPT; @@ -3138,6 +3268,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, */ if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { /* only valid for bound all sockets */ + if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) && + (*mopt != 0)) { + /* forbidden by admin */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM); + return (EPERM); + } set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; } else { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); @@ -3252,7 +3388,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, stcb->asoc.sctp_cmt_on_off = av->assoc_value; SCTP_TCB_UNLOCK(stcb); } else { - if ((av->assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC) || (av->assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); inp->sctp_cmt_on_off = av->assoc_value; @@ -3265,8 +3403,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, SCTP_TCB_LOCK(stcb); stcb->asoc.sctp_cmt_on_off = av->assoc_value; SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); } + SCTP_INP_RUNLOCK(inp); } } } else { @@ -3299,7 +3437,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } SCTP_TCB_UNLOCK(stcb); } else { - if ((av->assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC) || (av->assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); inp->sctp_ep.sctp_default_cc_module = av->assoc_value; @@ -3379,7 +3519,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); SCTP_TCB_UNLOCK(stcb); } else { - if ((av->assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC) || (av->assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); inp->sctp_ep.sctp_default_ss_module = av->assoc_value; @@ -3453,7 +3595,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, stcb->asoc.context = av->assoc_value; SCTP_TCB_UNLOCK(stcb); } else { - if ((av->assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC) || (av->assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); inp->sctp_context = av->assoc_value; @@ -3519,7 +3663,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } SCTP_TCB_UNLOCK(stcb); } else { - if ((sack->sack_assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) || (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); if (sack->sack_delay) { @@ -3614,7 +3760,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, error = sctp_insert_sharedkey(shared_keys, shared_key); SCTP_TCB_UNLOCK(stcb); } else { - if ((sca->sca_assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) || (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); shared_keys = &inp->sctp_ep.shared_keys; @@ -3758,7 +3906,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } SCTP_TCB_UNLOCK(stcb); } else { - if ((scact->scact_assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) || (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) { @@ -3795,7 +3945,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } SCTP_TCB_UNLOCK(stcb); } else { - if ((scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) || (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) { @@ -3832,7 +3984,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } SCTP_TCB_UNLOCK(stcb); } else { - if ((keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) || (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) { @@ -4098,7 +4252,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, stcb->asoc.max_burst = av->assoc_value; SCTP_TCB_UNLOCK(stcb); } else { - if ((av->assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC) || (av->assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); inp->sctp_ep.max_burst = av->assoc_value; @@ -4138,7 +4294,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } SCTP_TCB_UNLOCK(stcb); } else { - if (av->assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_WLOCK(inp); /* * FIXME MT: I think this is not in @@ -4346,7 +4504,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } SCTP_TCB_UNLOCK(stcb); } else { - if ((s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) || (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send))); @@ -4368,7 +4528,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, break; } case SCTP_PEER_ADDR_PARAMS: - /* Applys to the specific association */ + /* Applies to the specific association */ { struct sctp_paddrparams *paddrp; struct sctp_nets *net; @@ -4459,29 +4619,33 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, ovh = SCTP_MED_V4_OVERHEAD; } - if (paddrp->spp_hbinterval) - stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; - else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) - stcb->asoc.heart_beat_delay = 0; - /* network sets ? */ if (net) { /************************NET SPECIFIC SET ******************/ - if (paddrp->spp_flags & SPP_HB_DEMAND) { - /* on demand HB */ - if (sctp_send_hb(stcb, 1, net, SCTP_SO_LOCKED) < 0) { - /* asoc destroyed */ - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - error = EINVAL; - break; - } - } if (paddrp->spp_flags & SPP_HB_DISABLE) { + if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && + !(net->dest_state & SCTP_ADDR_NOHB)) { + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); + } net->dest_state |= SCTP_ADDR_NOHB; } if (paddrp->spp_flags & SPP_HB_ENABLE) { + if (paddrp->spp_hbinterval) { + net->heart_beat_delay = paddrp->spp_hbinterval; + } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { + net->heart_beat_delay = 0; + } + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); net->dest_state &= ~SCTP_ADDR_NOHB; } + if (paddrp->spp_flags & SPP_HB_DEMAND) { + /* on demand HB */ + sctp_send_hb(stcb, net, SCTP_SO_LOCKED); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); + } if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, @@ -4499,31 +4663,108 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); } } - if (paddrp->spp_pathmaxrxt) - net->failure_threshold = paddrp->spp_pathmaxrxt; -#ifdef INET - if (paddrp->spp_flags & SPP_IPV4_TOS) { - if (net->ro._l_addr.sin.sin_family == AF_INET) { - net->tos_flowlabel = paddrp->spp_ipv4_tos & 0x000000fc; + if (paddrp->spp_pathmaxrxt) { + if (net->dest_state & SCTP_ADDR_PF) { + if (net->error_count > paddrp->spp_pathmaxrxt) { + net->dest_state &= ~SCTP_ADDR_PF; + } + } else { + if ((net->error_count <= paddrp->spp_pathmaxrxt) && + (net->error_count > net->pf_threshold)) { + net->dest_state |= SCTP_ADDR_PF; + sctp_send_hb(stcb, net, SCTP_SO_LOCKED); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); + } } + if (net->dest_state & SCTP_ADDR_REACHABLE) { + if (net->error_count > paddrp->spp_pathmaxrxt) { + net->dest_state &= ~SCTP_ADDR_REACHABLE; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); + } + } else { + if (net->error_count <= paddrp->spp_pathmaxrxt) { + net->dest_state |= SCTP_ADDR_REACHABLE; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); + } + } + net->failure_threshold = paddrp->spp_pathmaxrxt; + } + if (paddrp->spp_flags & SPP_DSCP) { + net->dscp = paddrp->spp_dscp << 2; + net->dscp |= 0x01; } -#endif #ifdef INET6 if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { - if (net->ro._l_addr.sin6.sin6_family == AF_INET6) { - net->tos_flowlabel = paddrp->spp_ipv6_flowlabel; + if (net->ro._l_addr.sa.sa_family == AF_INET6) { + net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; + net->flowlabel |= 0x80000000; } } #endif } else { /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ - if (paddrp->spp_pathmaxrxt) + if (paddrp->spp_pathmaxrxt) { stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; - + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + if (net->dest_state & SCTP_ADDR_PF) { + if (net->error_count > paddrp->spp_pathmaxrxt) { + net->dest_state &= ~SCTP_ADDR_PF; + } + } else { + if ((net->error_count <= paddrp->spp_pathmaxrxt) && + (net->error_count > net->pf_threshold)) { + net->dest_state |= SCTP_ADDR_PF; + sctp_send_hb(stcb, net, SCTP_SO_LOCKED); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); + } + } + if (net->dest_state & SCTP_ADDR_REACHABLE) { + if (net->error_count > paddrp->spp_pathmaxrxt) { + net->dest_state &= ~SCTP_ADDR_REACHABLE; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); + } + } else { + if (net->error_count <= paddrp->spp_pathmaxrxt) { + net->dest_state |= SCTP_ADDR_REACHABLE; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); + } + } + net->failure_threshold = paddrp->spp_pathmaxrxt; + } + } if (paddrp->spp_flags & SPP_HB_ENABLE) { + if (paddrp->spp_hbinterval) { + stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; + } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { + stcb->asoc.heart_beat_delay = 0; + } /* Turn back on the timer */ - stcb->asoc.hb_is_disabled = 0; - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + if (paddrp->spp_hbinterval) { + net->heart_beat_delay = paddrp->spp_hbinterval; + } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { + net->heart_beat_delay = 0; + } + if (net->dest_state & SCTP_ADDR_NOHB) { + net->dest_state &= ~SCTP_ADDR_NOHB; + } + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); + } + } + if (paddrp->spp_flags & SPP_HB_DISABLE) { + /* Turn back on the timer */ + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + if (!(net->dest_state & SCTP_ADDR_NOHB)) { + net->dest_state |= SCTP_ADDR_NOHB; + if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); + } + } + } } if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { @@ -4546,48 +4787,33 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } } } - if (paddrp->spp_flags & SPP_HB_DISABLE) { - int cnt_of_unconf = 0; - struct sctp_nets *lnet; - - stcb->asoc.hb_is_disabled = 1; - TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { - if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) { - cnt_of_unconf++; - } - } - /* - * stop the timer ONLY if we - * have no unconfirmed - * addresses - */ - if (cnt_of_unconf == 0) { - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11); - } + if (paddrp->spp_flags & SPP_DSCP) { + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + net->dscp = paddrp->spp_dscp << 2; + net->dscp |= 0x01; } + stcb->asoc.default_dscp = paddrp->spp_dscp << 2; + stcb->asoc.default_dscp |= 0x01; } - if (paddrp->spp_flags & SPP_HB_ENABLE) { - /* start up the timer. */ +#ifdef INET6 + if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); + if (net->ro._l_addr.sa.sa_family == AF_INET6) { + net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; + net->flowlabel |= 0x80000000; + } } + stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; + stcb->asoc.default_flowlabel |= 0x80000000; } -#ifdef INET - if (paddrp->spp_flags & SPP_IPV4_TOS) - stcb->asoc.default_tos = paddrp->spp_ipv4_tos & 0x000000fc; #endif -#ifdef INET6 - if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) - stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel; -#endif - } SCTP_TCB_UNLOCK(stcb); } else { /************************NO TCB, SET TO default stuff ******************/ - if (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_WLOCK(inp); /* * For the TOS/FLOWLABEL stuff you @@ -4605,11 +4831,27 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); } if (paddrp->spp_flags & SPP_HB_ENABLE) { + if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { + inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; + } else if (paddrp->spp_hbinterval) { + inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); + } sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); - } else if (paddrp->spp_flags & SPP_HB_DISABLE) { sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); } + if (paddrp->spp_flags & SPP_DSCP) { + inp->sctp_ep.default_dscp = paddrp->spp_dscp << 2; + inp->sctp_ep.default_dscp |= 0x01; + } +#ifdef INET6 + if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { + if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { + inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; + inp->sctp_ep.default_flowlabel |= 0x80000000; + } + } +#endif SCTP_INP_WUNLOCK(inp); } else { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); @@ -4649,7 +4891,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } SCTP_TCB_UNLOCK(stcb); } else { - if (srto->srto_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_WLOCK(inp); if (srto->srto_initial) new_init = srto->srto_initial; @@ -4701,7 +4945,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } SCTP_TCB_UNLOCK(stcb); } else { - if (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { SCTP_INP_WLOCK(inp); if (sasoc->sasoc_asocmaxrxt) inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; @@ -4769,10 +5015,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) { /* Ok we need to set it */ if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { - if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { - net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH; + if ((stcb->asoc.alternate) && + (!(net->dest_state & SCTP_ADDR_PF)) && + (net->dest_state & SCTP_ADDR_REACHABLE)) { + sctp_free_remote_addr(stcb->asoc.alternate); + stcb->asoc.alternate = NULL; } - net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY; } } } else { @@ -4930,7 +5178,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, error = EINVAL; break; } - if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), + if (td != NULL && + (error = prison_local_ip6(td->td_ucred, + &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); break; @@ -5017,13 +5267,17 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, * sender dry events */ if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) && + ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) && + ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) && ((event->se_assoc_id == SCTP_ALL_ASSOC) || (event->se_assoc_id == SCTP_CURRENT_ASSOC))) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); error = ENOTSUP; break; } - if ((event->se_assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (event->se_assoc_id == SCTP_FUTURE_ASSOC) || (event->se_assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); if (event->se_on) { @@ -5101,7 +5355,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } SCTP_TCB_UNLOCK(stcb); } else { - if ((info->snd_assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (info->snd_assoc_id == SCTP_FUTURE_ASSOC) || (info->snd_assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); inp->def_send.sinfo_stream = info->snd_sid; @@ -5147,13 +5403,17 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (stcb) { stcb->asoc.def_send.sinfo_flags &= 0xfff0; stcb->asoc.def_send.sinfo_flags |= info->pr_policy; + stcb->asoc.def_send.sinfo_timetolive = info->pr_value; SCTP_TCB_UNLOCK(stcb); } else { - if ((info->pr_assoc_id == SCTP_FUTURE_ASSOC) || + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (info->pr_assoc_id == SCTP_FUTURE_ASSOC) || (info->pr_assoc_id == SCTP_ALL_ASSOC)) { SCTP_INP_WLOCK(inp); inp->def_send.sinfo_flags &= 0xfff0; inp->def_send.sinfo_flags |= info->pr_policy; + inp->def_send.sinfo_timetolive = info->pr_value; SCTP_INP_WUNLOCK(inp); } if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) || @@ -5163,6 +5423,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, SCTP_TCB_LOCK(stcb); stcb->asoc.def_send.sinfo_flags &= 0xfff0; stcb->asoc.def_send.sinfo_flags |= info->pr_policy; + stcb->asoc.def_send.sinfo_timetolive = info->pr_value; SCTP_TCB_UNLOCK(stcb); } SCTP_INP_RUNLOCK(inp); @@ -5170,6 +5431,148 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } break; } + case SCTP_PEER_ADDR_THLDS: + /* Applies to the specific association */ + { + struct sctp_paddrthlds *thlds; + struct sctp_nets *net; + + SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize); + SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); + net = NULL; + if (stcb) { + net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_assoc_id); + } else { + /* + * We increment here since + * sctp_findassociation_ep_addr() wil do a + * decrement if it finds the stcb as long as + * the locked tcb (last argument) is NOT a + * TCB.. aka NULL. + */ + SCTP_INP_INCR_REF(inp); + stcb = sctp_findassociation_ep_addr(&inp, + (struct sockaddr *)&thlds->spt_assoc_id, + &net, NULL, NULL); + if (stcb == NULL) { + SCTP_INP_DECR_REF(inp); + } + } + if (stcb && (net == NULL)) { + struct sockaddr *sa; + + sa = (struct sockaddr *)&thlds->spt_assoc_id; +#ifdef INET + if (sa->sa_family == AF_INET) { + + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)sa; + if (sin->sin_addr.s_addr) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + SCTP_TCB_UNLOCK(stcb); + error = EINVAL; + break; + } + } else +#endif +#ifdef INET6 + if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)sa; + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + SCTP_TCB_UNLOCK(stcb); + error = EINVAL; + break; + } + } else +#endif + { + error = EAFNOSUPPORT; + SCTP_TCB_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + break; + } + } + if (stcb) { + if (net) { + if (net->dest_state & SCTP_ADDR_PF) { + if ((net->failure_threshold > thlds->spt_pathmaxrxt) || + (net->failure_threshold <= thlds->spt_pathpfthld)) { + net->dest_state &= ~SCTP_ADDR_PF; + } + } else { + if ((net->failure_threshold > thlds->spt_pathpfthld) && + (net->failure_threshold <= thlds->spt_pathmaxrxt)) { + net->dest_state |= SCTP_ADDR_PF; + sctp_send_hb(stcb, net, SCTP_SO_LOCKED); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); + } + } + if (net->dest_state & SCTP_ADDR_REACHABLE) { + if (net->failure_threshold > thlds->spt_pathmaxrxt) { + net->dest_state &= ~SCTP_ADDR_REACHABLE; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); + } + } else { + if (net->failure_threshold <= thlds->spt_pathmaxrxt) { + net->dest_state |= SCTP_ADDR_REACHABLE; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); + } + } + net->failure_threshold = thlds->spt_pathmaxrxt; + net->pf_threshold = thlds->spt_pathpfthld; + } else { + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + if (net->dest_state & SCTP_ADDR_PF) { + if ((net->failure_threshold > thlds->spt_pathmaxrxt) || + (net->failure_threshold <= thlds->spt_pathpfthld)) { + net->dest_state &= ~SCTP_ADDR_PF; + } + } else { + if ((net->failure_threshold > thlds->spt_pathpfthld) && + (net->failure_threshold <= thlds->spt_pathmaxrxt)) { + net->dest_state |= SCTP_ADDR_PF; + sctp_send_hb(stcb, net, SCTP_SO_LOCKED); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); + } + } + if (net->dest_state & SCTP_ADDR_REACHABLE) { + if (net->failure_threshold > thlds->spt_pathmaxrxt) { + net->dest_state &= ~SCTP_ADDR_REACHABLE; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); + } + } else { + if (net->failure_threshold <= thlds->spt_pathmaxrxt) { + net->dest_state |= SCTP_ADDR_REACHABLE; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); + } + } + net->failure_threshold = thlds->spt_pathmaxrxt; + net->pf_threshold = thlds->spt_pathpfthld; + } + stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt; + stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld; + } + } else { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { + SCTP_INP_WLOCK(inp); + inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt; + inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld; + SCTP_INP_WUNLOCK(inp); + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + } + break; + } default: SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); error = ENOPROTOOPT; @@ -5374,15 +5777,6 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; /* Set the connected flag so we can queue data */ - SOCKBUF_LOCK(&so->so_rcv); - so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; - SOCKBUF_UNLOCK(&so->so_rcv); - SOCKBUF_LOCK(&so->so_snd); - so->so_snd.sb_state &= ~SBS_CANTSENDMORE; - SOCKBUF_UNLOCK(&so->so_snd); - SOCK_LOCK(so); - so->so_state &= ~SS_ISDISCONNECTING; - SOCK_UNLOCK(so); soisconnecting(so); } SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h index e48dfe49da100..b41f5c8303de0 100644 --- a/sys/netinet/sctp_var.h +++ b/sys/netinet/sctp_var.h @@ -179,7 +179,6 @@ extern struct pr_usrreqs sctp_usrreqs; if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(&(__net)->ref_count)) { \ (void)SCTP_OS_TIMER_STOP(&(__net)->rxt_timer.timer); \ (void)SCTP_OS_TIMER_STOP(&(__net)->pmtu_timer.timer); \ - (void)SCTP_OS_TIMER_STOP(&(__net)->fr_timer.timer); \ if ((__net)->ro.ro_rt) { \ RTFREE((__net)->ro.ro_rt); \ (__net)->ro.ro_rt = NULL; \ @@ -189,7 +188,7 @@ extern struct pr_usrreqs sctp_usrreqs; (__net)->ro._s_addr = NULL; \ } \ (__net)->src_addr_selected = 0; \ - (__net)->dest_state = SCTP_ADDR_NOT_REACHABLE; \ + (__net)->dest_state &= ~SCTP_ADDR_REACHABLE; \ SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_net), (__net)); \ SCTP_DECR_RADDR_COUNT(); \ } \ @@ -312,6 +311,8 @@ extern struct pr_usrreqs sctp_usrreqs; #endif +#define SCTP_PF_ENABLED(_net) (_net->pf_threshold < _net->failure_threshold) +#define SCTP_NET_IS_PF(_net) (_net->pf_threshold < _net->error_count) struct sctp_nets; struct sctp_inpcb; diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 9a8bd2e9dd19b..62fa0d1f2325a 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -739,15 +739,14 @@ sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb) asoc = &stcb->asoc; - (void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer); TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - (void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer); (void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer); + (void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer); } } @@ -921,19 +920,22 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb, asoc->sctp_cmt_on_off = m->sctp_cmt_on_off; asoc->ecn_allowed = m->sctp_ecn_enable; asoc->sctp_nr_sack_on_off = (uint8_t) SCTP_BASE_SYSCTL(sctp_nr_sack_on_off); - asoc->sctp_cmt_pf = (uint8_t) SCTP_BASE_SYSCTL(sctp_cmt_pf); + asoc->sctp_cmt_pf = (uint8_t) 0; asoc->sctp_frag_point = m->sctp_frag_point; asoc->sctp_features = m->sctp_features; -#ifdef INET - asoc->default_tos = m->ip_inp.inp.inp_ip_tos; -#else - asoc->default_tos = 0; -#endif - + asoc->default_dscp = m->sctp_ep.default_dscp; #ifdef INET6 - asoc->default_flowlabel = ((struct in6pcb *)m)->in6p_flowinfo; -#else - asoc->default_flowlabel = 0; + if (m->sctp_ep.default_flowlabel) { + asoc->default_flowlabel = m->sctp_ep.default_flowlabel; + } else { + if (m->ip_inp.inp.inp_flags & IN6P_AUTOFLOWLABEL) { + asoc->default_flowlabel = sctp_select_initial_TSN(&m->sctp_ep); + asoc->default_flowlabel &= 0x000fffff; + asoc->default_flowlabel |= 0x80000000; + } else { + asoc->default_flowlabel = 0; + } + } #endif asoc->sb_send_resv = 0; if (override_tag) { @@ -946,11 +948,6 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb, asoc->peer_vtag_nonce = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 0); asoc->vrf_id = vrf_id; - if (sctp_is_feature_on(m, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) - asoc->hb_is_disabled = 1; - else - asoc->hb_is_disabled = 0; - #ifdef SCTP_ASOCLOG_OF_TSNS asoc->tsn_in_at = 0; asoc->tsn_out_at = 0; @@ -989,6 +986,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb, asoc->max_init_times = m->sctp_ep.max_init_times; asoc->max_send_times = m->sctp_ep.max_send_times; asoc->def_net_failure = m->sctp_ep.def_net_failure; + asoc->def_net_pf_threshold = m->sctp_ep.def_net_pf_threshold; asoc->free_chunk_cnt = 0; asoc->iam_blocking = 0; @@ -1632,11 +1630,10 @@ sctp_timeout_handler(void *t) case SCTP_TIMER_TYPE_RECV: if ((stcb == NULL) || (inp == NULL)) { break; - } { - SCTP_STAT_INCR(sctps_timosack); - stcb->asoc.timosack++; - sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); } + SCTP_STAT_INCR(sctps_timosack); + stcb->asoc.timosack++; + sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); #ifdef SCTP_AUDITING_ENABLED sctp_auditing(4, inp, stcb, net); #endif @@ -1658,33 +1655,20 @@ sctp_timeout_handler(void *t) sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED); break; case SCTP_TIMER_TYPE_HEARTBEAT: - { - struct sctp_nets *lnet; - int cnt_of_unconf = 0; - - if ((stcb == NULL) || (inp == NULL)) { - break; - } - SCTP_STAT_INCR(sctps_timoheartbeat); - stcb->asoc.timoheartbeat++; - TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { - if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) && - (lnet->dest_state & SCTP_ADDR_REACHABLE)) { - cnt_of_unconf++; - } - } - if (cnt_of_unconf == 0) { - if (sctp_heartbeat_timer(inp, stcb, lnet, - cnt_of_unconf)) { - /* no need to unlock on tcb its gone */ - goto out_decr; - } - } + if ((stcb == NULL) || (inp == NULL) || (net == NULL)) { + break; + } + SCTP_STAT_INCR(sctps_timoheartbeat); + stcb->asoc.timoheartbeat++; + if (sctp_heartbeat_timer(inp, stcb, net)) { + /* no need to unlock on tcb its gone */ + goto out_decr; + } #ifdef SCTP_AUDITING_ENABLED - sctp_auditing(4, inp, stcb, lnet); + sctp_auditing(4, inp, stcb, net); #endif - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, - stcb->sctp_ep, stcb, lnet); + if (!(net->dest_state & SCTP_ADDR_NOHB)) { + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED); } break; @@ -1780,14 +1764,6 @@ sctp_timeout_handler(void *t) SCTP_STAT_INCR(sctps_timostrmrst); sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED); break; - case SCTP_TIMER_TYPE_EARLYFR: - /* Need to do FR of things for net */ - if ((stcb == NULL) || (inp == NULL)) { - break; - } - SCTP_STAT_INCR(sctps_timoearlyfr); - sctp_early_fr_timer(inp, stcb, net); - break; case SCTP_TIMER_TYPE_ASCONF: if ((stcb == NULL) || (inp == NULL)) { break; @@ -1898,7 +1874,7 @@ void sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net) { - int to_ticks; + uint32_t to_ticks; struct sctp_timer *tmr; if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) @@ -1985,71 +1961,38 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, * though we use a different timer. We also add the HB timer * PLUS a random jitter. */ - if ((inp == NULL) || (stcb == NULL)) { + if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { return; } else { uint32_t rndval; - uint8_t this_random; - int cnt_of_unconf = 0; - struct sctp_nets *lnet; + uint32_t jitter; - TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { - if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) && - (lnet->dest_state & SCTP_ADDR_REACHABLE)) { - cnt_of_unconf++; - } - } - if (cnt_of_unconf) { - net = lnet = NULL; - (void)sctp_heartbeat_timer(inp, stcb, lnet, cnt_of_unconf); - } - if (stcb->asoc.hb_random_idx > 3) { - rndval = sctp_select_initial_TSN(&inp->sctp_ep); - memcpy(stcb->asoc.hb_random_values, &rndval, - sizeof(stcb->asoc.hb_random_values)); - stcb->asoc.hb_random_idx = 0; - } - this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx]; - stcb->asoc.hb_random_idx++; - stcb->asoc.hb_ect_randombit = 0; - /* - * this_random will be 0 - 256 ms RTO is in ms. - */ - if ((stcb->asoc.hb_is_disabled) && - (cnt_of_unconf == 0)) { + if ((net->dest_state & SCTP_ADDR_NOHB) && + !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { return; } - if (net) { - int delay; - - delay = stcb->asoc.heart_beat_delay; - TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { - if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) && - ((lnet->dest_state & SCTP_ADDR_OUT_OF_SCOPE) == 0) && - (lnet->dest_state & SCTP_ADDR_REACHABLE)) { - delay = 0; - } - } - if (net->RTO == 0) { - /* Never been checked */ - to_ticks = this_random + stcb->asoc.initial_rto + delay; - } else { - /* set rto_val to the ms */ - to_ticks = delay + net->RTO + this_random; - } + if (net->RTO == 0) { + to_ticks = stcb->asoc.initial_rto; } else { - if (cnt_of_unconf) { - to_ticks = this_random + stcb->asoc.initial_rto; - } else { - to_ticks = stcb->asoc.heart_beat_delay + this_random + stcb->asoc.initial_rto; - } + to_ticks = net->RTO; + } + rndval = sctp_select_initial_TSN(&inp->sctp_ep); + jitter = rndval % to_ticks; + if (jitter >= (to_ticks >> 1)) { + to_ticks = to_ticks + (jitter - (to_ticks >> 1)); + } else { + to_ticks = to_ticks - jitter; + } + if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && + !(net->dest_state & SCTP_ADDR_PF)) { + to_ticks += net->heart_beat_delay; } /* * Now we must convert the to_ticks that are now in * ms to ticks. */ to_ticks = MSEC_TO_TICKS(to_ticks); - tmr = &stcb->asoc.hb_timer; + tmr = &net->hb_timer; } break; case SCTP_TIMER_TYPE_COOKIE: @@ -2150,35 +2093,6 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, } tmr = &stcb->asoc.strreset_timer; break; - - case SCTP_TIMER_TYPE_EARLYFR: - { - unsigned int msec; - - if ((stcb == NULL) || (net == NULL)) { - return; - } - if (net->flight_size > net->cwnd) { - /* no need to start */ - return; - } - SCTP_STAT_INCR(sctps_earlyfrstart); - if (net->lastsa == 0) { - /* Hmm no rtt estimate yet? */ - msec = stcb->asoc.initial_rto >> 2; - } else { - msec = ((net->lastsa >> 2) + net->lastsv) >> 1; - } - if (msec < SCTP_BASE_SYSCTL(sctp_early_fr_msec)) { - msec = SCTP_BASE_SYSCTL(sctp_early_fr_msec); - if (msec < SCTP_MINFR_MSEC_FLOOR) { - msec = SCTP_MINFR_MSEC_FLOOR; - } - } - to_ticks = MSEC_TO_TICKS(msec); - tmr = &net->fr_timer; - } - break; case SCTP_TIMER_TYPE_ASCONF: /* * Here the timer comes from the stcb but its value is from @@ -2273,13 +2187,6 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, case SCTP_TIMER_TYPE_ADDR_WQ: tmr = &SCTP_BASE_INFO(addr_wq_timer); break; - case SCTP_TIMER_TYPE_EARLYFR: - if ((stcb == NULL) || (net == NULL)) { - return; - } - tmr = &net->fr_timer; - SCTP_STAT_INCR(sctps_earlyfrstop); - break; case SCTP_TIMER_TYPE_SEND: if ((stcb == NULL) || (net == NULL)) { return; @@ -2305,10 +2212,10 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, tmr = &net->rxt_timer; break; case SCTP_TIMER_TYPE_HEARTBEAT: - if (stcb == NULL) { + if ((stcb == NULL) || (net == NULL)) { return; } - tmr = &stcb->asoc.hb_timer; + tmr = &net->hb_timer; break; case SCTP_TIMER_TYPE_COOKIE: if ((stcb == NULL) || (net == NULL)) { @@ -3715,10 +3622,14 @@ sctp_abort_notification(struct sctp_tcb *stcb, int error, int so_locked #endif ) { - if (stcb == NULL) { return; } + if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && + (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { + stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED; + } if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { @@ -3726,11 +3637,6 @@ sctp_abort_notification(struct sctp_tcb *stcb, int error, int so_locked } /* Tell them we lost the asoc */ sctp_report_all_outbound(stcb, 1, so_locked); - if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || - ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && - (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { - stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED; - } sctp_ulp_notify(SCTP_NOTIFY_ASSOC_ABORTED, stcb, error, NULL, so_locked); } @@ -5191,17 +5097,6 @@ restart_nosblocks: */ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); error = ECONNRESET; - /* - * You get this once if you are - * active open side - */ - if (!(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - /* - * Remove flag if on the - * active open side - */ - inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAS_ABORTED; - } } so->so_state &= ~(SS_ISCONNECTING | SS_ISDISCONNECTING | @@ -5211,8 +5106,6 @@ restart_nosblocks: if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); error = ENOTCONN; - } else { - inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAS_CONNECTED; } } goto out; @@ -5245,18 +5138,6 @@ restart_nosblocks: */ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); error = ECONNRESET; - /* - * You get this once if you - * are active open side - */ - if (!(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - /* - * Remove flag if on - * the active open - * side - */ - inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAS_ABORTED; - } } so->so_state &= ~(SS_ISCONNECTING | SS_ISDISCONNECTING | @@ -5266,8 +5147,6 @@ restart_nosblocks: if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); error = ENOTCONN; - } else { - inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAS_CONNECTED; } } goto out; @@ -6201,6 +6080,15 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, struct sockaddr *sa; size_t incr = 0; +#ifdef INET + struct sockaddr_in *sin; + +#endif +#ifdef INET6 + struct sockaddr_in6 *sin6; + +#endif + sa = addr; inp = stcb->sctp_ep; *error = 0; @@ -6209,7 +6097,16 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, #ifdef INET case AF_INET: incr = sizeof(struct sockaddr_in); - if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + sin = (struct sockaddr_in *)sa; + if ((sin->sin_addr.s_addr == INADDR_ANY) || + (sin->sin_addr.s_addr == INADDR_BROADCAST) || + IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); + *error = EINVAL; + goto out_now; + } + if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); @@ -6222,7 +6119,15 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, #ifdef INET6 case AF_INET6: incr = sizeof(struct sockaddr_in6); - if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + sin6 = (struct sockaddr_in6 *)sa; + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || + IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); + *error = EINVAL; + goto out_now; + } + if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index e3e9aa6c745af..b1a8b335cabb1 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -195,7 +195,7 @@ SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, recvbuf_inc, CTLFLAG_RW, &VNET_NAME(tcp_autorcvbuf_inc), 0, "Incrementor step size of automatic receive buffer"); -VNET_DEFINE(int, tcp_autorcvbuf_max) = 256*1024; +VNET_DEFINE(int, tcp_autorcvbuf_max) = 2*1024*1024; #define V_tcp_autorcvbuf_max VNET(tcp_autorcvbuf_max) SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, recvbuf_max, CTLFLAG_RW, &VNET_NAME(tcp_autorcvbuf_max), 0, @@ -573,19 +573,14 @@ tcp_input(struct mbuf *m, int off0) uint8_t sig_checked = 0; #endif uint8_t iptos = 0; -#ifdef INET #ifdef IPFIREWALL_FORWARD struct m_tag *fwd_tag; #endif -#endif /* INET */ #ifdef INET6 struct ip6_hdr *ip6 = NULL; int isipv6; #else const void *ip6 = NULL; -#if (defined(INET) && defined(IPFIREWALL_FORWARD)) || defined(TCPDEBUG) - const int isipv6 = 0; -#endif #endif /* INET6 */ struct tcpopt to; /* options in this segment */ char *s = NULL; /* address and port logging */ @@ -776,14 +771,55 @@ findpcb: } #endif -#ifdef INET #ifdef IPFIREWALL_FORWARD /* * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */ fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); +#endif /* IPFIREWALL_FORWARD */ + +#ifdef INET6 +#ifdef IPFIREWALL_FORWARD + if (isipv6 && fwd_tag != NULL) { + struct sockaddr_in6 *next_hop6; - if (fwd_tag != NULL && isipv6 == 0) { /* IPv6 support is not yet */ + next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1); + /* + * Transparently forwarded. Pretend to be the destination. + * Already got one like this? + */ + inp = in6_pcblookup_mbuf(&V_tcbinfo, + &ip6->ip6_src, th->th_sport, &ip6->ip6_dst, th->th_dport, + INPLOOKUP_WLOCKPCB, m->m_pkthdr.rcvif, m); + if (!inp) { + /* + * It's new. Try to find the ambushing socket. + * Because we've rewritten the destination address, + * any hardware-generated hash is ignored. + */ + inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_src, + th->th_sport, &next_hop6->sin6_addr, + next_hop6->sin6_port ? ntohs(next_hop6->sin6_port) : + th->th_dport, INPLOOKUP_WILDCARD | + INPLOOKUP_WLOCKPCB, m->m_pkthdr.rcvif); + } + /* Remove the tag from the packet. We don't need it anymore. */ + m_tag_delete(m, fwd_tag); + } else +#endif /* IPFIREWALL_FORWARD */ + if (isipv6) { + inp = in6_pcblookup_mbuf(&V_tcbinfo, &ip6->ip6_src, + th->th_sport, &ip6->ip6_dst, th->th_dport, + INPLOOKUP_WILDCARD | INPLOOKUP_WLOCKPCB, + m->m_pkthdr.rcvif, m); + } +#endif /* INET6 */ +#if defined(INET6) && defined(INET) + else +#endif +#ifdef INET +#ifdef IPFIREWALL_FORWARD + if (fwd_tag != NULL) { struct sockaddr_in *next_hop; next_hop = (struct sockaddr_in *)(fwd_tag+1); @@ -810,25 +846,11 @@ findpcb: m_tag_delete(m, fwd_tag); } else #endif /* IPFIREWALL_FORWARD */ + inp = in_pcblookup_mbuf(&V_tcbinfo, ip->ip_src, + th->th_sport, ip->ip_dst, th->th_dport, + INPLOOKUP_WILDCARD | INPLOOKUP_WLOCKPCB, + m->m_pkthdr.rcvif, m); #endif /* INET */ - { -#ifdef INET6 - if (isipv6) - inp = in6_pcblookup_mbuf(&V_tcbinfo, &ip6->ip6_src, - th->th_sport, &ip6->ip6_dst, th->th_dport, - INPLOOKUP_WILDCARD | INPLOOKUP_WLOCKPCB, - m->m_pkthdr.rcvif, m); -#endif -#if defined(INET) && defined(INET6) - else -#endif -#ifdef INET - inp = in_pcblookup_mbuf(&V_tcbinfo, ip->ip_src, - th->th_sport, ip->ip_dst, th->th_dport, - INPLOOKUP_WILDCARD | INPLOOKUP_WLOCKPCB, - m->m_pkthdr.rcvif, m); -#endif - } /* * If the INPCB does not exist then all data in the incoming @@ -1003,11 +1025,11 @@ relocked: #ifdef TCPDEBUG if (so->so_options & SO_DEBUG) { ostate = tp->t_state; - if (isipv6) { #ifdef INET6 + if (isipv6) { bcopy((char *)ip6, (char *)tcp_saveipgen, sizeof(*ip6)); -#endif } else +#endif bcopy((char *)ip, (char *)tcp_saveipgen, sizeof(*ip)); tcp_savetcp = *th; } diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 572a491be0db1..702eed330f157 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -117,7 +117,7 @@ SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, sendbuf_inc, CTLFLAG_RW, &VNET_NAME(tcp_autosndbuf_inc), 0, "Incrementor step size of automatic send buffer"); -VNET_DEFINE(int, tcp_autosndbuf_max) = 256*1024; +VNET_DEFINE(int, tcp_autosndbuf_max) = 2*1024*1024; #define V_tcp_autosndbuf_max VNET(tcp_autosndbuf_max) SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, sendbuf_max, CTLFLAG_RW, &VNET_NAME(tcp_autosndbuf_max), 0, diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 28eb8fd19f88b..701bc358ab9e1 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -441,28 +441,6 @@ udp_input(struct mbuf *m, int off) } else UDPSTAT_INC(udps_nosum); -#ifdef IPFIREWALL_FORWARD - /* - * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. - */ - fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); - if (fwd_tag != NULL) { - struct sockaddr_in *next_hop; - - /* - * Do the hack. - */ - next_hop = (struct sockaddr_in *)(fwd_tag + 1); - ip->ip_dst = next_hop->sin_addr; - uh->uh_dport = ntohs(next_hop->sin_port); - - /* - * Remove the tag from the packet. We don't need it anymore. - */ - m_tag_delete(m, fwd_tag); - } -#endif - if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || in_broadcast(ip->ip_dst, ifp)) { struct inpcb *last; @@ -568,9 +546,41 @@ udp_input(struct mbuf *m, int off) /* * Locate pcb for datagram. */ - inp = in_pcblookup_mbuf(&V_udbinfo, ip->ip_src, uh->uh_sport, - ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, - ifp, m); +#ifdef IPFIREWALL_FORWARD + /* + * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. + */ + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + struct sockaddr_in *next_hop; + + next_hop = (struct sockaddr_in *)(fwd_tag + 1); + + /* + * Transparently forwarded. Pretend to be the destination. + * Already got one like this? + */ + inp = in_pcblookup_mbuf(&V_udbinfo, ip->ip_src, uh->uh_sport, + ip->ip_dst, uh->uh_dport, INPLOOKUP_RLOCKPCB, ifp, m); + if (!inp) { + /* + * It's new. Try to find the ambushing socket. + * Because we've rewritten the destination address, + * any hardware-generated hash is ignored. + */ + inp = in_pcblookup(&V_udbinfo, ip->ip_src, + uh->uh_sport, next_hop->sin_addr, + next_hop->sin_port ? htons(next_hop->sin_port) : + uh->uh_dport, INPLOOKUP_WILDCARD | + INPLOOKUP_RLOCKPCB, ifp); + } + /* Remove the tag from the packet. We don't need it anymore. */ + m_tag_delete(m, fwd_tag); + } else +#endif /* IPFIREWALL_FORWARD */ + inp = in_pcblookup_mbuf(&V_udbinfo, ip->ip_src, uh->uh_sport, + ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD | + INPLOOKUP_RLOCKPCB, ifp, m); if (inp == NULL) { if (udp_log_in_vain) { char buf[4*sizeof "123"]; diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 39e77e999b8f2..9bf7a8f44e5da 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -2017,6 +2017,27 @@ in6_localaddr(struct in6_addr *in6) return (0); } +/* + * Return 1 if an internet address is for the local host and configured + * on one of its interfaces. + */ +int +in6_localip(struct in6_addr *in6) +{ + struct in6_ifaddr *ia; + + IN6_IFADDR_RLOCK(); + TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { + if (IN6_ARE_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr)) { + IN6_IFADDR_RUNLOCK(); + return (1); + } + } + IN6_IFADDR_RUNLOCK(); + return (0); +} + + int in6_is_addr_deprecated(struct sockaddr_in6 *sa6) { diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index ae0da6aa0fffc..1040d90e94a02 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -614,7 +614,9 @@ struct ip6_mtuinfo { #define IPV6CTL_NO_RADR 48 /* No defroute from RA */ #define IPV6CTL_NORBIT_RAIF 49 /* Disable R-bit in NA on RA * receiving IF. */ -#define IPV6CTL_MAXID 50 +#define IPV6CTL_RFC6204W3 50 /* Accept defroute even when forwarding + enabled */ +#define IPV6CTL_MAXID 51 #endif /* __BSD_VISIBLE */ /* @@ -631,6 +633,7 @@ struct cmsghdr; int in6_cksum __P((struct mbuf *, u_int8_t, u_int32_t, u_int32_t)); int in6_localaddr __P((struct in6_addr *)); +int in6_localip(struct in6_addr *); int in6_addrscope __P((struct in6_addr *)); struct in6_ifaddr *in6_ifawithifp __P((struct ifnet *, struct in6_addr *)); extern void in6_if_up __P((struct ifnet *)); diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index e03e6405d5f23..254ec88523b16 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -399,6 +399,7 @@ VNET_DEFINE(int, ip6_defmcasthlim) = IPV6_DEFAULT_MULTICAST_HOPS; VNET_DEFINE(int, ip6_accept_rtadv) = 0; VNET_DEFINE(int, ip6_no_radr) = 0; VNET_DEFINE(int, ip6_norbit_raif) = 0; +VNET_DEFINE(int, ip6_rfc6204w3) = 0; VNET_DEFINE(int, ip6_maxfragpackets); /* initialized in frag6.c:frag6_init() */ VNET_DEFINE(int, ip6_maxfrags); /* initialized in frag6.c:frag6_init() */ VNET_DEFINE(int, ip6_log_interval) = 5; @@ -536,6 +537,10 @@ SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_NORBIT_RAIF, norbit_raif, CTLFLAG_RW, &VNET_NAME(ip6_norbit_raif), 0, "Always set 0 to R flag in ICMPv6 NA messages when accepting RA" " on the interface."); +SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_RFC6204W3, rfc6204w3, + CTLFLAG_RW, &VNET_NAME(ip6_rfc6204w3), 0, + "Accept the default router list from ICMPv6 RA messages even " + "when packet forwarding enabled."); SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_KEEPFAITH, keepfaith, CTLFLAG_RW, &VNET_NAME(ip6_keepfaith), 0, ""); SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_LOG_INTERVAL, log_interval, diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index cff29e19be521..77cb926630764 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" +#include "opt_ipfw.h" #include "opt_ipsec.h" #include "opt_ipstealth.h" @@ -50,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <sys/syslog.h> #include <net/if.h> +#include <net/netisr.h> #include <net/route.h> #include <net/pfil.h> @@ -98,11 +100,17 @@ ip6_forward(struct mbuf *m, int srcrt) struct mbuf *mcopy = NULL; struct ifnet *origifp; /* maybe unnecessary */ u_int32_t inzone, outzone; - struct in6_addr src_in6, dst_in6; + struct in6_addr src_in6, dst_in6, odst; #ifdef IPSEC struct secpolicy *sp = NULL; int ipsecrt = 0; #endif +#ifdef SCTP + int sw_csum; +#endif +#ifdef IPFIREWALL_FORWARD + struct m_tag *fwd_tag; +#endif char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; #ifdef IPSEC @@ -345,13 +353,15 @@ ip6_forward(struct mbuf *m, int srcrt) goto skip_routing; skip_ipsec: #endif - +again: bzero(&rin6, sizeof(struct route_in6)); dst = (struct sockaddr_in6 *)&rin6.ro_dst; dst->sin6_len = sizeof(struct sockaddr_in6); dst->sin6_family = AF_INET6; dst->sin6_addr = ip6->ip6_dst; - +#ifdef IPFIREWALL_FORWARD +again2: +#endif rin6.ro_rt = rtalloc1((struct sockaddr *)dst, 0, 0); if (rin6.ro_rt != NULL) RT_UNLOCK(rin6.ro_rt); @@ -554,6 +564,7 @@ skip_routing: if (!PFIL_HOOKED(&V_inet6_pfil_hook)) goto pass; + odst = ip6->ip6_dst; /* Run through list of hooks for output packets. */ error = pfil_run_hooks(&V_inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT, NULL); if (error != 0) @@ -562,6 +573,59 @@ skip_routing: goto freecopy; ip6 = mtod(m, struct ip6_hdr *); + /* See if destination IP address was changed by packet filter. */ + if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) { + m->m_flags |= M_SKIP_FIREWALL; + /* If destination is now ourself drop to ip6_input(). */ + if (in6_localip(&ip6->ip6_dst)) { + m->m_flags |= M_FASTFWD_OURS; + if (m->m_pkthdr.rcvif == NULL) + m->m_pkthdr.rcvif = V_loif; + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + m->m_pkthdr.csum_flags |= + CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xffff; + } + m->m_pkthdr.csum_flags |= + CSUM_IP_CHECKED | CSUM_IP_VALID; +#ifdef SCTP + if (m->m_pkthdr.csum_flags & CSUM_SCTP) + m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; +#endif + error = netisr_queue(NETISR_IPV6, m); + goto out; + } else + goto again; /* Redo the routing table lookup. */ + } + +#ifdef IPFIREWALL_FORWARD + /* See if local, if yes, send it to netisr. */ + if (m->m_flags & M_FASTFWD_OURS) { + if (m->m_pkthdr.rcvif == NULL) + m->m_pkthdr.rcvif = V_loif; + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + m->m_pkthdr.csum_flags |= + CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xffff; + } +#ifdef SCTP + if (m->m_pkthdr.csum_flags & CSUM_SCTP) + m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; +#endif + error = netisr_queue(NETISR_IPV6, m); + goto out; + } + /* Or forward to some other address? */ + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag) { + dst = (struct sockaddr_in6 *)&rin6.ro_dst; + bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in6)); + m->m_flags |= M_SKIP_FIREWALL; + m_tag_delete(m, fwd_tag); + goto again2; + } +#endif /* IPFIREWALL_FORWARD */ + pass: error = nd6_output(rt->rt_ifp, origifp, m, dst, rt); if (error) { diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index de3a622706b18..1fdde1662283f 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" +#include "opt_ipfw.h" #include "opt_ipsec.h" #include "opt_route.h" @@ -91,6 +92,7 @@ __FBSDID("$FreeBSD$"); #include <net/vnet.h> #include <netinet/in.h> +#include <netinet/ip_var.h> #include <netinet/in_systm.h> #include <net/if_llatbl.h> #ifdef INET @@ -357,6 +359,17 @@ ip6_input(struct mbuf *m) */ ip6_delaux(m); + if (m->m_flags & M_FASTFWD_OURS) { + /* + * Firewall changed destination to local. + */ + m->m_flags &= ~M_FASTFWD_OURS; + ours = 1; + deliverifp = m->m_pkthdr.rcvif; + ip6 = mtod(m, struct ip6_hdr *); + goto hbhcheck; + } + /* * mbuf statistics */ @@ -533,6 +546,24 @@ ip6_input(struct mbuf *m) ip6 = mtod(m, struct ip6_hdr *); srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst); +#ifdef IPFIREWALL_FORWARD + if (m->m_flags & M_FASTFWD_OURS) { + m->m_flags &= ~M_FASTFWD_OURS; + ours = 1; + deliverifp = m->m_pkthdr.rcvif; + goto hbhcheck; + } + if (m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL) { + /* + * Directly ship the packet on. This allows forwarding + * packets originally destined to us to some other directly + * connected host. + */ + ip6_forward(m, 1); + goto out; + } +#endif /* IPFIREWALL_FORWARD */ + passin: /* * Disambiguate address scope zones (if there is ambiguity). diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 973689c7aa9bf..85161247d7e62 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" +#include "opt_ipfw.h" #include "opt_ipsec.h" #include "opt_sctp.h" #include "opt_route.h" @@ -90,6 +91,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/in.h> #include <netinet/in_var.h> +#include <netinet/ip_var.h> #include <netinet6/in6_var.h> #include <netinet/ip6.h> #include <netinet/icmp6.h> @@ -229,6 +231,9 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, int segleft_org = 0; struct secpolicy *sp = NULL; #endif /* IPSEC */ +#ifdef IPFIREWALL_FORWARD + struct m_tag *fwd_tag; +#endif ip6 = mtod(m, struct ip6_hdr *); if (ip6 == NULL) { @@ -850,7 +855,8 @@ again: if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) { m->m_flags |= M_SKIP_FIREWALL; /* If destination is now ourself drop to ip6_input(). */ - if (in6_localaddr(&ip6->ip6_dst)) { + if (in6_localip(&ip6->ip6_dst)) { + m->m_flags |= M_FASTFWD_OURS; if (m->m_pkthdr.rcvif == NULL) m->m_pkthdr.rcvif = V_loif; if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { @@ -870,7 +876,33 @@ again: goto again; /* Redo the routing table lookup. */ } - /* XXX: IPFIREWALL_FORWARD */ +#ifdef IPFIREWALL_FORWARD + /* See if local, if yes, send it to netisr. */ + if (m->m_flags & M_FASTFWD_OURS) { + if (m->m_pkthdr.rcvif == NULL) + m->m_pkthdr.rcvif = V_loif; + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + m->m_pkthdr.csum_flags |= + CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xffff; + } +#ifdef SCTP + if (m->m_pkthdr.csum_flags & CSUM_SCTP) + m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; +#endif + error = netisr_queue(NETISR_IPV6, m); + goto done; + } + /* Or forward to some other address? */ + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag) { + dst = (struct sockaddr_in6 *)&ro->ro_dst; + bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in6)); + m->m_flags |= M_SKIP_FIREWALL; + m_tag_delete(m, fwd_tag); + goto again; + } +#endif /* IPFIREWALL_FORWARD */ passout: /* diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index dbfba9a0b9e79..c9d35e0b03d0c 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -319,6 +319,8 @@ VNET_DECLARE(int, ip6_accept_rtadv); /* Acts as a host not a router */ VNET_DECLARE(int, ip6_no_radr); /* No defroute from RA */ VNET_DECLARE(int, ip6_norbit_raif); /* Disable R-bit in NA on RA * receiving IF. */ +VNET_DECLARE(int, ip6_rfc6204w3); /* Accept defroute from RA even when + forwarding enabled */ VNET_DECLARE(int, ip6_keepfaith); /* Firewall Aided Internet Translator */ VNET_DECLARE(int, ip6_log_interval); VNET_DECLARE(time_t, ip6_log_time); @@ -332,6 +334,7 @@ VNET_DECLARE(int, ip6_dad_count); /* DupAddrDetectionTransmits */ #define V_ip6_accept_rtadv VNET(ip6_accept_rtadv) #define V_ip6_no_radr VNET(ip6_no_radr) #define V_ip6_norbit_raif VNET(ip6_norbit_raif) +#define V_ip6_rfc6204w3 VNET(ip6_rfc6204w3) #define V_ip6_keepfaith VNET(ip6_keepfaith) #define V_ip6_log_interval VNET(ip6_log_interval) #define V_ip6_log_time VNET(ip6_log_time) diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c index 21d9eabe363b6..a56f83d2f743a 100644 --- a/sys/netinet6/mld6.c +++ b/sys/netinet6/mld6.c @@ -680,7 +680,6 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, IN6_MULTI_LOCK(); MLD_LOCK(); - IF_ADDR_LOCK(ifp); /* * Switch to MLDv1 host compatibility mode. @@ -693,6 +692,7 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, if (timer == 0) timer = 1; + IF_ADDR_LOCK(ifp); if (is_general_query) { /* * For each reporting group joined on this @@ -888,7 +888,6 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, IN6_MULTI_LOCK(); MLD_LOCK(); - IF_ADDR_LOCK(ifp); mli = MLD_IFINFO(ifp); KASSERT(mli != NULL, ("%s: no mld_ifinfo for ifp %p", __func__, ifp)); @@ -936,14 +935,18 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, * Queries for groups we are not a member of on this * link are simply ignored. */ + IF_ADDR_LOCK(ifp); inm = in6m_lookup_locked(ifp, &mld->mld_addr); - if (inm == NULL) + if (inm == NULL) { + IF_ADDR_UNLOCK(ifp); goto out_locked; + } if (nsrc > 0) { if (!ratecheck(&inm->in6m_lastgsrtv, &V_mld_gsrdelay)) { CTR1(KTR_MLD, "%s: GS query throttled.", __func__); + IF_ADDR_UNLOCK(ifp); goto out_locked; } } @@ -961,10 +964,10 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, /* XXX Clear embedded scope ID as userland won't expect it. */ in6_clearscope(&mld->mld_addr); + IF_ADDR_UNLOCK(ifp); } out_locked: - IF_ADDR_UNLOCK(ifp); MLD_UNLOCK(); IN6_MULTI_UNLOCK(); diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index e791e2e3a7b96..5352dd5a2f645 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -269,11 +269,13 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len) dr0.rtaddr = saddr6; dr0.flags = nd_ra->nd_ra_flags_reserved; /* - * Effectively-disable the route in the RA packet - * when ND6_IFF_NO_RADR on the receiving interface or - * ip6.forwarding=1. + * Effectively-disable routes from RA messages when + * ND6_IFF_NO_RADR enabled on the receiving interface or + * (ip6.forwarding == 1 && ip6.rfc6204w3 != 1). */ - if (ndi->flags & ND6_IFF_NO_RADR || V_ip6_forwarding) + if (ndi->flags & ND6_IFF_NO_RADR) + dr0.rtlifetime = 0; + else if (V_ip6_forwarding && !V_ip6_rfc6204w3) dr0.rtlifetime = 0; else dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index 62efcd6bae9fb..7512f5b9f25c9 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -420,33 +420,8 @@ sctp6_notify(struct sctp_inpcb *inp, */ if (net->dest_state & SCTP_ADDR_REACHABLE) { /* Ok that destination is NOT reachable */ - SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n", - net->error_count, - net->failure_threshold, - net); - net->dest_state &= ~SCTP_ADDR_REACHABLE; - net->dest_state |= SCTP_ADDR_NOT_REACHABLE; - /* - * JRS 5/14/07 - If a destination is unreachable, - * the PF bit is turned off. This allows an - * unambiguous use of the PF bit for destinations - * that are reachable but potentially failed. If the - * destination is set to the unreachable state, also - * set the destination to the PF state. - */ - /* - * Add debug message here if destination is not in - * PF state. - */ - /* Stop any running T3 timers here? */ - if ((stcb->asoc.sctp_cmt_on_off > 0) && - (stcb->asoc.sctp_cmt_pf > 0)) { - net->dest_state &= ~SCTP_ADDR_PF; - SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", - net); - } - net->error_count = net->failure_threshold + 1; + net->dest_state &= ~SCTP_ADDR_PF; sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_FAILED_THRESHOLD, (void *)net, SCTP_SO_NOT_LOCKED); diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 6723007481868..2a4c0a55a4698 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" +#include "opt_ipfw.h" #include "opt_ipsec.h" #include <sys/param.h> @@ -181,6 +182,9 @@ udp6_input(struct mbuf **mp, int *offp, int proto) int off = *offp; int plen, ulen; struct sockaddr_in6 fromsa; +#ifdef IPFIREWALL_FORWARD + struct m_tag *fwd_tag; +#endif ifp = m->m_pkthdr.rcvif; ip6 = mtod(m, struct ip6_hdr *); @@ -377,9 +381,43 @@ udp6_input(struct mbuf **mp, int *offp, int proto) /* * Locate pcb for datagram. */ - inp = in6_pcblookup_mbuf(&V_udbinfo, &ip6->ip6_src, uh->uh_sport, - &ip6->ip6_dst, uh->uh_dport, INPLOOKUP_WILDCARD | - INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif, m); +#ifdef IPFIREWALL_FORWARD + /* + * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. + */ + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + struct sockaddr_in6 *next_hop6; + + next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1); + + /* + * Transparently forwarded. Pretend to be the destination. + * Already got one like this? + */ + inp = in6_pcblookup_mbuf(&V_udbinfo, + &ip6->ip6_src, uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, + INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif, m); + if (!inp) { + /* + * It's new. Try to find the ambushing socket. + * Because we've rewritten the destination address, + * any hardware-generated hash is ignored. + */ + inp = in6_pcblookup(&V_udbinfo, &ip6->ip6_src, + uh->uh_sport, &next_hop6->sin6_addr, + next_hop6->sin6_port ? htons(next_hop6->sin6_port) : + uh->uh_dport, INPLOOKUP_WILDCARD | + INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif); + } + /* Remove the tag from the packet. We don't need it anymore. */ + m_tag_delete(m, fwd_tag); + } else +#endif /* IPFIREWALL_FORWARD */ + inp = in6_pcblookup_mbuf(&V_udbinfo, &ip6->ip6_src, + uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, + INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, + m->m_pkthdr.rcvif, m); if (inp == NULL) { if (udp_log_in_vain) { char ip6bufs[INET6_ADDRSTRLEN]; diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c index da8a2ece335a9..305c189d73d88 100644 --- a/sys/nfsclient/nfs_bio.c +++ b/sys/nfsclient/nfs_bio.c @@ -445,6 +445,7 @@ nfs_bioread(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred) struct thread *td; struct nfsmount *nmp = VFSTONFS(vp->v_mount); daddr_t lbn, rabn; + off_t end; int bcount; int seqcount; int nra, error = 0, n = 0, on = 0; @@ -464,8 +465,9 @@ nfs_bioread(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred) } else mtx_unlock(&nmp->nm_mtx); + end = uio->uio_offset + uio->uio_resid; if (vp->v_type != VDIR && - (uio->uio_offset + uio->uio_resid) > nmp->nm_maxfilesize) + (end > nmp->nm_maxfilesize || end < uio->uio_offset)) return (EFBIG); if (nfs_directio_enable && (ioflag & IO_DIRECT) && (vp->v_type == VREG)) @@ -865,6 +867,7 @@ nfs_write(struct vop_write_args *ap) struct vattr vattr; struct nfsmount *nmp = VFSTONFS(vp->v_mount); daddr_t lbn; + off_t end; int bcount; int n, on, error = 0; @@ -932,7 +935,8 @@ flush_and_restart: if (uio->uio_offset < 0) return (EINVAL); - if ((uio->uio_offset + uio->uio_resid) > nmp->nm_maxfilesize) + end = uio->uio_offset + uio->uio_resid; + if (end > nmp->nm_maxfilesize || end < uio->uio_offset) return (EFBIG); if (uio->uio_resid == 0) return (0); diff --git a/sys/nfsclient/nfs_node.c b/sys/nfsclient/nfs_node.c index 5b43b3d653b19..afe3341ba6cd5 100644 --- a/sys/nfsclient/nfs_node.c +++ b/sys/nfsclient/nfs_node.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/proc.h> #include <sys/socket.h> #include <sys/sysctl.h> +#include <sys/taskqueue.h> #include <sys/vnode.h> #include <vm/uma.h> @@ -59,6 +60,8 @@ __FBSDID("$FreeBSD$"); static uma_zone_t nfsnode_zone; +static void nfs_freesillyrename(void *arg, __unused int pending); + #define TRUE 1 #define FALSE 0 @@ -185,6 +188,20 @@ nfs_nget(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp, int return (0); } +/* + * Do the vrele(sp->s_dvp) as a separate task in order to avoid a + * deadlock because of a LOR when vrele() locks the directory vnode. + */ +static void +nfs_freesillyrename(void *arg, __unused int pending) +{ + struct sillyrename *sp; + + sp = arg; + vrele(sp->s_dvp); + free(sp, M_NFSREQ); +} + int nfs_inactive(struct vop_inactive_args *ap) { @@ -207,8 +224,8 @@ nfs_inactive(struct vop_inactive_args *ap) */ (sp->s_removeit)(sp); crfree(sp->s_cred); - vrele(sp->s_dvp); - free((caddr_t)sp, M_NFSREQ); + TASK_INIT(&sp->s_task, 0, nfs_freesillyrename, sp); + taskqueue_enqueue(taskqueue_thread, &sp->s_task); mtx_lock(&np->n_mtx); } np->n_flag &= NMODIFIED; diff --git a/sys/nfsclient/nfs_vfsops.c b/sys/nfsclient/nfs_vfsops.c index 8498ee45526ca..6bcc9b58cb768 100644 --- a/sys/nfsclient/nfs_vfsops.c +++ b/sys/nfsclient/nfs_vfsops.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <sys/bio.h> #include <sys/buf.h> #include <sys/jail.h> +#include <sys/limits.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mbuf.h> @@ -1228,13 +1229,11 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, * * For V3, nfs_fsinfo will adjust this as necessary. Assume maximum * that we can handle until we find out otherwise. - * XXX Our "safe" limit on the client is what we can store in our - * buffer cache using signed(!) block numbers. */ if ((argp->flags & NFSMNT_NFSV3) == 0) nmp->nm_maxfilesize = 0xffffffffLL; else - nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1; + nmp->nm_maxfilesize = OFF_MAX; nmp->nm_timeo = NFS_TIMEO; nmp->nm_retry = NFS_RETRANS; diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c index bb81f6b24f3f6..a9f746df6196d 100644 --- a/sys/nfsclient/nfs_vnops.c +++ b/sys/nfsclient/nfs_vnops.c @@ -1276,6 +1276,7 @@ nfs_readrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred) caddr_t bpos, dpos; struct mbuf *mreq, *mrep, *md, *mb; struct nfsmount *nmp; + off_t end; int error = 0, len, retlen, tsiz, eof, attrflag; int v3 = NFS_ISV3(vp); int rsize; @@ -1286,7 +1287,8 @@ nfs_readrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred) nmp = VFSTONFS(vp->v_mount); tsiz = uiop->uio_resid; mtx_lock(&nmp->nm_mtx); - if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize) { + end = uiop->uio_offset + tsiz; + if (end > nmp->nm_maxfilesize || end < uiop->uio_offset) { mtx_unlock(&nmp->nm_mtx); return (EFBIG); } @@ -1348,6 +1350,7 @@ nfs_writerpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, caddr_t bpos, dpos; struct mbuf *mreq, *mrep, *md, *mb; struct nfsmount *nmp = VFSTONFS(vp->v_mount); + off_t end; int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit; int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC; int wsize; @@ -1356,7 +1359,8 @@ nfs_writerpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, *must_commit = 0; tsiz = uiop->uio_resid; mtx_lock(&nmp->nm_mtx); - if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize) { + end = uiop->uio_offset + tsiz; + if (end > nmp->nm_maxfilesize || end < uiop->uio_offset) { mtx_unlock(&nmp->nm_mtx); return (EFBIG); } diff --git a/sys/nfsclient/nfsnode.h b/sys/nfsclient/nfsnode.h index 19c1c474ecc4c..8e35fdd34567d 100644 --- a/sys/nfsclient/nfsnode.h +++ b/sys/nfsclient/nfsnode.h @@ -36,6 +36,7 @@ #ifndef _NFSCLIENT_NFSNODE_H_ #define _NFSCLIENT_NFSNODE_H_ +#include <sys/_task.h> #if !defined(_NFSCLIENT_NFS_H_) && !defined(_KERNEL) #include <nfs/nfs.h> #endif @@ -45,6 +46,7 @@ * can be removed by nfs_inactive() */ struct sillyrename { + struct task s_task; struct ucred *s_cred; struct vnode *s_dvp; int (*s_removeit)(struct sillyrename *sp); diff --git a/sys/nfsserver/nfs_serv.c b/sys/nfsserver/nfs_serv.c index 1b9dd987bab9c..fd3a1b553e11d 100644 --- a/sys/nfsserver/nfs_serv.c +++ b/sys/nfsserver/nfs_serv.c @@ -157,6 +157,7 @@ ndclear(struct nameidata *nd) nd->ni_vp = NULL; nd->ni_dvp = NULL; nd->ni_startdir = NULL; + nd->ni_strictrelative = 0; } /* diff --git a/sys/nfsserver/nfs_srvkrpc.c b/sys/nfsserver/nfs_srvkrpc.c index 3c60825f2087e..2581092eafe06 100644 --- a/sys/nfsserver/nfs_srvkrpc.c +++ b/sys/nfsserver/nfs_srvkrpc.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include "opt_kgssapi.h" #include <sys/param.h> +#include <sys/capability.h> #include <sys/systm.h> #include <sys/sysproto.h> #include <sys/kernel.h> @@ -173,7 +174,7 @@ nfssvc_nfsserver(struct thread *td, struct nfssvc_args *uap) sizeof(addsockarg)); if (error) return (error); - if ((error = fget(td, addsockarg.sock, &fp)) != 0) + if ((error = fget(td, addsockarg.sock, CAP_SOCK_ALL, &fp)) != 0) return (error); if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, td); diff --git a/sys/ofed/include/linux/linux_compat.c b/sys/ofed/include/linux/linux_compat.c index 98ad807d2aa75..90737f2eaf154 100644 --- a/sys/ofed/include/linux/linux_compat.c +++ b/sys/ofed/include/linux/linux_compat.c @@ -559,7 +559,9 @@ struct fileops linuxfileops = { .fo_read = linux_file_read, .fo_poll = linux_file_poll, .fo_close = linux_file_close, - .fo_ioctl = linux_file_ioctl + .fo_ioctl = linux_file_ioctl, + .fo_chmod = invfo_chmod, + .fo_chown = invfo_chown, }; /* diff --git a/sys/opencrypto/cryptodev.c b/sys/opencrypto/cryptodev.c index 2c0c503d2bf0b..2bc0e1f74d917 100644 --- a/sys/opencrypto/cryptodev.c +++ b/sys/opencrypto/cryptodev.c @@ -301,7 +301,9 @@ static struct fileops cryptofops = { .fo_poll = cryptof_poll, .fo_kqfilter = cryptof_kqfilter, .fo_stat = cryptof_stat, - .fo_close = cryptof_close + .fo_close = cryptof_close, + .fo_chmod = invfo_chmod, + .fo_chown = invfo_chown, }; static struct csession *csefind(struct fcrypt *, u_int); diff --git a/sys/pc98/cbus/sio.c b/sys/pc98/cbus/sio.c index 01747d7d98a35..959726f2f0194 100644 --- a/sys/pc98/cbus/sio.c +++ b/sys/pc98/cbus/sio.c @@ -31,7 +31,6 @@ * from: i386/isa sio.c,v 1.234 */ -#include "opt_comconsole.h" #include "opt_compat.h" #include "opt_gdb.h" #include "opt_kdb.h" @@ -310,7 +309,7 @@ struct com_s { struct pps_state pps; int pps_bit; -#ifdef ALT_BREAK_TO_DEBUGGER +#ifdef KDB int alt_brk_state; #endif @@ -1752,8 +1751,7 @@ determined_type: ; } if (ret) device_printf(dev, "could not activate interrupt\n"); -#if defined(KDB) && (defined(BREAK_TO_DEBUGGER) || \ - defined(ALT_BREAK_TO_DEBUGGER)) +#if defined(KDB) /* * Enable interrupts for early break-to-debugger support * on the console. @@ -1896,8 +1894,7 @@ comclose(tp) sio_setreg(com, com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); #endif -#if defined(KDB) && (defined(BREAK_TO_DEBUGGER) || \ - defined(ALT_BREAK_TO_DEBUGGER)) +#if defined(KDB) /* * Leave interrupts enabled and don't clear DTR if this is the * console. This allows us to detect break-to-debugger events @@ -2272,7 +2269,7 @@ siointr1(com) u_char rsa_buf_status = 0; int rsa_tx_fifo_size = 0; #endif /* PC98 */ -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) +#if defined(KDB) int kdb_brk; again: @@ -2369,27 +2366,11 @@ more_intr: else recv_data = inb(com->data_port); #ifdef KDB -#ifdef ALT_BREAK_TO_DEBUGGER if (com->unit == comconsole && (kdb_brk = kdb_alt_break(recv_data, &com->alt_brk_state)) != 0) { - mtx_unlock_spin(&sio_lock); - switch (kdb_brk) { - case KDB_REQ_DEBUGGER: - kdb_enter(KDB_WHY_BREAK, - "Break sequence on console"); - break; - case KDB_REQ_PANIC: - kdb_panic("panic on console"); - break; - case KDB_REQ_REBOOT: - kdb_reboot(); - break; - } - mtx_lock_spin(&sio_lock); goto again; } -#endif /* ALT_BREAK_TO_DEBUGGER */ #endif /* KDB */ if (line_status & (LSR_BI | LSR_FE | LSR_PE)) { /* @@ -2405,7 +2386,7 @@ more_intr: * Note: BI together with FE/PE means just BI. */ if (line_status & LSR_BI) { -#if defined(KDB) && defined(BREAK_TO_DEBUGGER) +#if defined(KDB) if (com->unit == comconsole) { kdb_enter(KDB_WHY_BREAK, "Line break on console"); diff --git a/sys/pc98/conf/GENERIC b/sys/pc98/conf/GENERIC index e2bed44764b79..df52ac104773d 100644 --- a/sys/pc98/conf/GENERIC +++ b/sys/pc98/conf/GENERIC @@ -39,7 +39,7 @@ options MD_ROOT # MD is a potential root device options NFSCL # New Network Filesystem Client options NFSD # New Network Filesystem Server options NFSLOCKD # Network Lock Manager -options NFS_ROOT # NFS usable as /, requires NFSCLIENT +options NFS_ROOT # NFS usable as /, requires NFSCL options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) @@ -276,7 +276,7 @@ device bpf # Berkeley packet filter #device rum # Ralink Technology RT2501USB wireless NICs #device uath # Atheros AR5523 wireless NICs #device ural # Ralink Technology RT2500USB wireless NICs -#device zyd # ZyDAS zb1211/zb1211b wireless NICs +#device zyd # ZyDAS zd1211/zd1211b wireless NICs # FireWire support #device firewire # FireWire bus code diff --git a/sys/pc98/pc98/machdep.c b/sys/pc98/pc98/machdep.c index 8bcb618759ac1..b42249caea998 100644 --- a/sys/pc98/pc98/machdep.c +++ b/sys/pc98/pc98/machdep.c @@ -1855,7 +1855,7 @@ static void getmemsize(int first) { int off, physmap_idx, pa_indx, da_indx; - u_long physmem_tunable; + u_long physmem_tunable, memtest; vm_paddr_t physmap[PHYSMAP_SIZE]; pt_entry_t *pte; quad_t dcons_addr, dcons_size; @@ -1915,6 +1915,13 @@ getmemsize(int first) if (TUNABLE_ULONG_FETCH("hw.physmem", &physmem_tunable)) Maxmem = atop(physmem_tunable); + /* + * By default keep the memtest enabled. Use a general name so that + * one could eventually do more with the code than just disable it. + */ + memtest = 1; + TUNABLE_ULONG_FETCH("hw.memtest.tests", &memtest); + if (atop(physmap[physmap_idx + 1]) != Maxmem && (boothowto & RB_VERBOSE)) printf("Physical memory use set to %ldK\n", Maxmem * 4); @@ -1991,6 +1998,8 @@ getmemsize(int first) goto do_dump_avail; page_bad = FALSE; + if (memtest == 0) + goto skip_memtest; /* * map page into kernel: valid, read/write,non-cacheable @@ -2028,6 +2037,7 @@ getmemsize(int first) */ *(int *)ptr = tmp; +skip_memtest: /* * Adjust array of valid/good pages. */ diff --git a/sys/pci/if_rlreg.h b/sys/pci/if_rlreg.h index 6ecba71495500..3a9da2e4d414e 100644 --- a/sys/pci/if_rlreg.h +++ b/sys/pci/if_rlreg.h @@ -1042,6 +1042,7 @@ struct rl_softc { * D-Link DFE-5280T device ID */ #define DLINK_DEVICEID_528T 0x4300 +#define DLINK_DEVICEID_530T_REVC 0x4302 /* * D-Link DFE-690TXD device ID diff --git a/sys/powerpc/aim/locore32.S b/sys/powerpc/aim/locore32.S index ed74af2fc7100..020d22d4913dc 100644 --- a/sys/powerpc/aim/locore32.S +++ b/sys/powerpc/aim/locore32.S @@ -91,13 +91,13 @@ GLOBAL(esym) GLOBAL(intrnames) .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 GLOBAL(sintrnames) - .word INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 + .long INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 .align 4 GLOBAL(intrcnt) .space INTRCNT_COUNT * 4 * 2 GLOBAL(sintrcnt) - .word INTRCNT_COUNT * 4 * 2 + .long INTRCNT_COUNT * 4 * 2 .text .globl btext diff --git a/sys/powerpc/aim/locore64.S b/sys/powerpc/aim/locore64.S index 9a54b79a4cdd5..64e4e628e9dcd 100644 --- a/sys/powerpc/aim/locore64.S +++ b/sys/powerpc/aim/locore64.S @@ -91,13 +91,13 @@ GLOBAL(esym) GLOBAL(intrnames) .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 GLOBAL(sintrnames) - .word INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 + .quad INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 .align 4 GLOBAL(intrcnt) .space INTRCNT_COUNT * 4 * 2 GLOBAL(sintrcnt) - .word INTRCNT_COUNT * 4 * 2 + .quad INTRCNT_COUNT * 4 * 2 .text .globl btext diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c index 23354f9fd1b06..57c35bf9add53 100644 --- a/sys/powerpc/aim/mmu_oea.c +++ b/sys/powerpc/aim/mmu_oea.c @@ -1073,12 +1073,12 @@ moea_enter_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, if (pmap_bootstrapped) mtx_assert(&vm_page_queue_mtx, MA_OWNED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0 || - (m->oflags & VPO_BUSY) != 0 || VM_OBJECT_LOCKED(m->object), + KASSERT((m->oflags & (VPO_UNMANAGED | VPO_BUSY)) != 0 || + VM_OBJECT_LOCKED(m->object), ("moea_enter_locked: page %p is not busy", m)); /* XXX change the pvo head for fake pages */ - if ((m->flags & PG_FICTITIOUS) == PG_FICTITIOUS) { + if ((m->oflags & VPO_UNMANAGED) != 0) { pvo_flags &= ~PVO_MANAGED; pvo_head = &moea_pvo_kunmanaged; zone = moea_upvo_zone; @@ -1088,7 +1088,7 @@ moea_enter_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, * If this is a managed page, and it's the first reference to the page, * clear the execness of the page. Otherwise fetch the execness. */ - if ((pg != NULL) && ((m->flags & PG_FICTITIOUS) == 0)) { + if ((pg != NULL) && ((m->oflags & VPO_UNMANAGED) == 0)) { if (LIST_EMPTY(pvo_head)) { moea_attr_clear(pg, PTE_EXEC); } else { @@ -1101,8 +1101,8 @@ moea_enter_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, if (prot & VM_PROT_WRITE) { pte_lo |= PTE_BW; if (pmap_bootstrapped && - (m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) - vm_page_flag_set(m, PG_WRITEABLE); + (m->oflags & VPO_UNMANAGED) == 0) + vm_page_aflag_set(m, PGA_WRITEABLE); } else pte_lo |= PTE_BR; @@ -1112,9 +1112,6 @@ moea_enter_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, if (wired) pvo_flags |= PVO_WIRED; - if ((m->flags & PG_FICTITIOUS) != 0) - pvo_flags |= PVO_FAKE; - error = moea_pvo_enter(pmap, zone, pvo_head, va, VM_PAGE_TO_PHYS(m), pte_lo, pvo_flags); @@ -1245,7 +1242,7 @@ boolean_t moea_is_referenced(mmu_t mmu, vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea_is_referenced: page %p is not managed", m)); return (moea_query_bit(m, PTE_REF)); } @@ -1254,17 +1251,17 @@ boolean_t moea_is_modified(mmu_t mmu, vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea_is_modified: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be - * concurrently set while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be + * concurrently set while the object is locked. Thus, if PGA_WRITEABLE * is clear, no PTEs can have PTE_CHG set. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return (FALSE); return (moea_query_bit(m, PTE_CHG)); } @@ -1286,7 +1283,7 @@ void moea_clear_reference(mmu_t mmu, vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea_clear_reference: page %p is not managed", m)); moea_clear_bit(m, PTE_REF); } @@ -1295,18 +1292,18 @@ void moea_clear_modify(mmu_t mmu, vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea_clear_modify: page %p is not managed", m)); VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); KASSERT((m->oflags & VPO_BUSY) == 0, ("moea_clear_modify: page %p is busy", m)); /* - * If the page is not PG_WRITEABLE, then no PTEs can have PTE_CHG + * If the page is not PGA_WRITEABLE, then no PTEs can have PTE_CHG * set. If the object containing the page is locked and the page is - * not VPO_BUSY, then PG_WRITEABLE cannot be concurrently set. + * not VPO_BUSY, then PGA_WRITEABLE cannot be concurrently set. */ - if ((m->flags & PG_WRITEABLE) == 0) + if ((m->aflags & PGA_WRITEABLE) == 0) return; moea_clear_bit(m, PTE_CHG); } @@ -1322,17 +1319,17 @@ moea_remove_write(mmu_t mmu, vm_page_t m) pmap_t pmap; u_int lo; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea_remove_write: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be set by - * another thread while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be set by + * another thread while the object is locked. Thus, if PGA_WRITEABLE * is clear, no page table entries need updating. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); lo = moea_attr_fetch(m); @@ -1359,7 +1356,7 @@ moea_remove_write(mmu_t mmu, vm_page_t m) moea_attr_clear(m, PTE_CHG); vm_page_dirty(m); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } @@ -1379,7 +1376,7 @@ boolean_t moea_ts_referenced(mmu_t mmu, vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea_ts_referenced: page %p is not managed", m)); return (moea_clear_bit(m, PTE_REF)); } @@ -1396,7 +1393,7 @@ moea_page_set_memattr(mmu_t mmu, vm_page_t m, vm_memattr_t ma) pmap_t pmap; u_int lo; - if (m->flags & PG_FICTITIOUS) { + if ((m->oflags & VPO_UNMANAGED) != 0) { m->md.mdpg_cache_attrs = ma; return; } @@ -1537,7 +1534,7 @@ moea_page_exists_quick(mmu_t mmu, pmap_t pmap, vm_page_t m) struct pvo_entry *pvo; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea_page_exists_quick: page %p is not managed", m)); loops = 0; rv = FALSE; @@ -1565,7 +1562,7 @@ moea_page_wired_mappings(mmu_t mmu, vm_page_t m) int count; count = 0; - if ((m->flags & PG_FICTITIOUS) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (count); vm_page_lock_queues(); LIST_FOREACH(pvo, vm_page_to_pvoh(m), pvo_vlink) @@ -1797,11 +1794,11 @@ moea_remove_all(mmu_t mmu, vm_page_t m) moea_pvo_remove(pvo, -1); PMAP_UNLOCK(pmap); } - if ((m->flags & PG_WRITEABLE) && moea_is_modified(mmu, m)) { + if ((m->aflags & PGA_WRITEABLE) && moea_is_modified(mmu, m)) { moea_attr_clear(m, PTE_CHG); vm_page_dirty(m); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } @@ -1928,8 +1925,6 @@ moea_pvo_enter(pmap_t pm, uma_zone_t zone, struct pvo_head *pvo_head, pvo->pvo_vaddr |= PVO_MANAGED; if (bootstrap) pvo->pvo_vaddr |= PVO_BOOTSTRAP; - if (flags & PVO_FAKE) - pvo->pvo_vaddr |= PVO_FAKE; moea_pte_create(&pvo->pvo_pte.pte, sr, va, pa | pte_lo); @@ -1988,7 +1983,7 @@ moea_pvo_remove(struct pvo_entry *pvo, int pteidx) /* * Save the REF/CHG bits into their cache if the page is managed. */ - if ((pvo->pvo_vaddr & (PVO_MANAGED|PVO_FAKE)) == PVO_MANAGED) { + if ((pvo->pvo_vaddr & PVO_MANAGED) == PVO_MANAGED) { struct vm_page *pg; pg = PHYS_TO_VM_PAGE(pvo->pvo_pte.pte.pte_lo & PTE_RPGN); diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c index f051b61943f60..75004622753c0 100644 --- a/sys/powerpc/aim/mmu_oea64.c +++ b/sys/powerpc/aim/mmu_oea64.c @@ -1222,12 +1222,12 @@ moea64_enter_locked(mmu_t mmu, pmap_t pmap, vm_offset_t va, vm_page_t m, if (pmap_bootstrapped) mtx_assert(&vm_page_queue_mtx, MA_OWNED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0 || - (m->oflags & VPO_BUSY) != 0 || VM_OBJECT_LOCKED(m->object), + KASSERT((m->oflags & (VPO_UNMANAGED | VPO_BUSY)) != 0 || + VM_OBJECT_LOCKED(m->object), ("moea64_enter_locked: page %p is not busy", m)); /* XXX change the pvo head for fake pages */ - if ((m->flags & PG_FICTITIOUS) == PG_FICTITIOUS) { + if ((m->oflags & VPO_UNMANAGED) != 0) { pvo_flags &= ~PVO_MANAGED; pvo_head = &moea64_pvo_kunmanaged; zone = moea64_upvo_zone; @@ -1238,8 +1238,8 @@ moea64_enter_locked(mmu_t mmu, pmap_t pmap, vm_offset_t va, vm_page_t m, if (prot & VM_PROT_WRITE) { pte_lo |= LPTE_BW; if (pmap_bootstrapped && - (m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) - vm_page_flag_set(m, PG_WRITEABLE); + (m->oflags & VPO_UNMANAGED) == 0) + vm_page_aflag_set(m, PGA_WRITEABLE); } else pte_lo |= LPTE_BR; @@ -1249,9 +1249,6 @@ moea64_enter_locked(mmu_t mmu, pmap_t pmap, vm_offset_t va, vm_page_t m, if (wired) pvo_flags |= PVO_WIRED; - if ((m->flags & PG_FICTITIOUS) != 0) - pvo_flags |= PVO_FAKE; - error = moea64_pvo_enter(mmu, pmap, zone, pvo_head, va, VM_PAGE_TO_PHYS(m), pte_lo, pvo_flags); @@ -1474,7 +1471,7 @@ boolean_t moea64_is_referenced(mmu_t mmu, vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea64_is_referenced: page %p is not managed", m)); return (moea64_query_bit(mmu, m, PTE_REF)); } @@ -1483,17 +1480,17 @@ boolean_t moea64_is_modified(mmu_t mmu, vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea64_is_modified: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be - * concurrently set while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be + * concurrently set while the object is locked. Thus, if PGA_WRITEABLE * is clear, no PTEs can have LPTE_CHG set. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return (FALSE); return (moea64_query_bit(mmu, m, LPTE_CHG)); } @@ -1515,7 +1512,7 @@ void moea64_clear_reference(mmu_t mmu, vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea64_clear_reference: page %p is not managed", m)); moea64_clear_bit(mmu, m, LPTE_REF); } @@ -1524,18 +1521,18 @@ void moea64_clear_modify(mmu_t mmu, vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea64_clear_modify: page %p is not managed", m)); VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); KASSERT((m->oflags & VPO_BUSY) == 0, ("moea64_clear_modify: page %p is busy", m)); /* - * If the page is not PG_WRITEABLE, then no PTEs can have LPTE_CHG + * If the page is not PGA_WRITEABLE, then no PTEs can have LPTE_CHG * set. If the object containing the page is locked and the page is - * not VPO_BUSY, then PG_WRITEABLE cannot be concurrently set. + * not VPO_BUSY, then PGA_WRITEABLE cannot be concurrently set. */ - if ((m->flags & PG_WRITEABLE) == 0) + if ((m->aflags & PGA_WRITEABLE) == 0) return; moea64_clear_bit(mmu, m, LPTE_CHG); } @@ -1551,17 +1548,17 @@ moea64_remove_write(mmu_t mmu, vm_page_t m) pmap_t pmap; uint64_t lo; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea64_remove_write: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be set by - * another thread while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be set by + * another thread while the object is locked. Thus, if PGA_WRITEABLE * is clear, no page table entries need updating. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); lo = moea64_attr_fetch(m); @@ -1591,7 +1588,7 @@ moea64_remove_write(mmu_t mmu, vm_page_t m) moea64_attr_clear(m, LPTE_CHG); vm_page_dirty(m); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } @@ -1611,7 +1608,7 @@ boolean_t moea64_ts_referenced(mmu_t mmu, vm_page_t m) { - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea64_ts_referenced: page %p is not managed", m)); return (moea64_clear_bit(mmu, m, LPTE_REF)); } @@ -1628,7 +1625,7 @@ moea64_page_set_memattr(mmu_t mmu, vm_page_t m, vm_memattr_t ma) pmap_t pmap; uint64_t lo; - if (m->flags & PG_FICTITIOUS) { + if ((m->oflags & VPO_UNMANAGED) != 0) { m->md.mdpg_cache_attrs = ma; return; } @@ -1763,7 +1760,7 @@ moea64_page_exists_quick(mmu_t mmu, pmap_t pmap, vm_page_t m) struct pvo_entry *pvo; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("moea64_page_exists_quick: page %p is not managed", m)); loops = 0; rv = FALSE; @@ -1791,7 +1788,7 @@ moea64_page_wired_mappings(mmu_t mmu, vm_page_t m) int count; count = 0; - if ((m->flags & PG_FICTITIOUS) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (count); vm_page_lock_queues(); LIST_FOREACH(pvo, vm_page_to_pvoh(m), pvo_vlink) @@ -2067,11 +2064,11 @@ moea64_remove_all(mmu_t mmu, vm_page_t m) moea64_pvo_remove(mmu, pvo); PMAP_UNLOCK(pmap); } - if ((m->flags & PG_WRITEABLE) && moea64_is_modified(mmu, m)) { + if ((m->aflags & PGA_WRITEABLE) && moea64_is_modified(mmu, m)) { moea64_attr_clear(m, LPTE_CHG); vm_page_dirty(m); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } @@ -2227,8 +2224,6 @@ moea64_pvo_enter(mmu_t mmu, pmap_t pm, uma_zone_t zone, pvo->pvo_vaddr |= PVO_MANAGED; if (bootstrap) pvo->pvo_vaddr |= PVO_BOOTSTRAP; - if (flags & PVO_FAKE) - pvo->pvo_vaddr |= PVO_FAKE; if (flags & PVO_LARGE) pvo->pvo_vaddr |= PVO_LARGE; @@ -2305,7 +2300,7 @@ moea64_pvo_remove(mmu_t mmu, struct pvo_entry *pvo) /* * Save the REF/CHG bits into their cache if the page is managed. */ - if ((pvo->pvo_vaddr & (PVO_MANAGED|PVO_FAKE)) == PVO_MANAGED) { + if ((pvo->pvo_vaddr & PVO_MANAGED) == PVO_MANAGED) { struct vm_page *pg; pg = PHYS_TO_VM_PAGE(pvo->pvo_pte.lpte.pte_lo & LPTE_RPGN); diff --git a/sys/powerpc/aim/trap.c b/sys/powerpc/aim/trap.c index 51dee0eabdb55..93feb515728d8 100644 --- a/sys/powerpc/aim/trap.c +++ b/sys/powerpc/aim/trap.c @@ -445,6 +445,8 @@ cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) return (error); } +#include "../../kern/subr_syscall.c" + void syscall(struct trapframe *frame) { diff --git a/sys/powerpc/booke/locore.S b/sys/powerpc/booke/locore.S index 216962d09e3df..293eec34bdd84 100644 --- a/sys/powerpc/booke/locore.S +++ b/sys/powerpc/booke/locore.S @@ -83,8 +83,7 @@ __start: * locore registers use: * r1 : stack pointer * r2 : trace pointer (AP only, for early diagnostics) - * r3-r26 : scratch registers - * r27 : kernload + * r3-r27 : scratch registers * r28 : temp TLB1 entry * r29 : initial TLB1 entry we started in * r30-r31 : arguments (metadata pointer) @@ -116,6 +115,9 @@ __start: li %r3, 0 bl tlb_inval_all + cmpwi %r30, 0 + beq done_mapping + /* * Locate the TLB1 entry that maps this code */ @@ -171,7 +173,6 @@ __start: bl 3f 3: mflr %r4 /* Use current address */ rlwinm %r4, %r4, 0, 0, 7 /* 16MB alignment mask */ - mr %r27, %r4 /* Keep kernel load address */ ori %r4, %r4, (MAS3_SX | MAS3_SW | MAS3_SR)@l mtspr SPR_MAS3, %r4 /* Set RPN and protection */ isync @@ -197,23 +198,7 @@ __start: mr %r3, %r28 bl tlb1_inval_entry -/* - * Save kernel load address for later use. - */ - lis %r3, kernload@ha - addi %r3, %r3, kernload@l - stw %r27, 0(%r3) -#ifdef SMP - /* - * APs need a separate copy of kernload info within the __boot_page - * area so they can access this value very early, before their TLBs - * are fully set up and the kernload global location is available. - */ - lis %r3, kernload_ap@ha - addi %r3, %r3, kernload_ap@l - stw %r27, 0(%r3) - msync -#endif +done_mapping: /* * Setup a temporary stack @@ -257,6 +242,7 @@ __start: __boot_page: bl 1f + .globl kernload_ap kernload_ap: .long 0 @@ -785,17 +771,15 @@ tmpstack: */ #define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */ -GLOBAL(kernload) - .long 0 GLOBAL(intrnames) .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 GLOBAL(sintrnames) - .word INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 + .long INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 .align 4 GLOBAL(intrcnt) .space INTRCNT_COUNT * 4 * 2 GLOBAL(sintrcnt) - .word INTRCNT_COUNT * 4 * 2 + .long INTRCNT_COUNT * 4 * 2 #include <powerpc/booke/trap_subr.S> diff --git a/sys/powerpc/booke/platform_bare.c b/sys/powerpc/booke/platform_bare.c index d76664e7f925b..ca3cfa2e845e3 100644 --- a/sys/powerpc/booke/platform_bare.c +++ b/sys/powerpc/booke/platform_bare.c @@ -56,7 +56,7 @@ __FBSDID("$FreeBSD$"); #ifdef SMP extern void *ap_pcpu; extern uint8_t __boot_page[]; /* Boot page body */ -extern uint32_t kernload; /* Kernel physical load address */ +extern uint32_t kernload_ap; /* Kernel physical load address */ #endif extern uint32_t *bootinfo; @@ -179,8 +179,13 @@ bare_timebase_freq(platform_t plat, struct cpuref *cpuref) pcell_t freq; if (bootinfo != NULL) { - /* Backward compatibility. See 8-STABLE. */ - ticks = bootinfo[3] >> 3; + if (bootinfo[0] == 1) { + /* Backward compatibility. See 8-STABLE. */ + ticks = bootinfo[3] >> 3; + } else { + /* Compatibility with Juniper's loader. */ + ticks = bootinfo[5] >> 3; + } } else ticks = 0; @@ -268,7 +273,7 @@ bare_smp_start_cpu(platform_t plat, struct pcpu *pc) /* * Set BPTR to the physical address of the boot page */ - bptr = ((uint32_t)__boot_page - KERNBASE) + kernload; + bptr = ((uint32_t)__boot_page - KERNBASE) + kernload_ap; ccsr_write4(OCP85XX_BPTR, (bptr >> 12) | 0x80000000); /* diff --git a/sys/powerpc/booke/pmap.c b/sys/powerpc/booke/pmap.c index 18068fcd5ced5..4d1043a2eea61 100644 --- a/sys/powerpc/booke/pmap.c +++ b/sys/powerpc/booke/pmap.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include <sys/queue.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/linker.h> #include <sys/msgbuf.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -111,8 +112,13 @@ extern int dumpsys_minidump; extern unsigned char _etext[]; extern unsigned char _end[]; -/* Kernel physical load address. */ -extern uint32_t kernload; +extern uint32_t *bootinfo; + +#ifdef SMP +extern uint32_t kernload_ap; +#endif + +vm_paddr_t kernload; vm_offset_t kernstart; vm_size_t kernsize; @@ -196,7 +202,7 @@ static void tlb_print_entry(int, uint32_t, uint32_t, uint32_t, uint32_t); static int tlb1_set_entry(vm_offset_t, vm_offset_t, vm_size_t, uint32_t); static void tlb1_write_entry(unsigned int); static int tlb1_iomapped(int, vm_paddr_t, vm_size_t, vm_offset_t *); -static vm_size_t tlb1_mapin_region(vm_offset_t, vm_offset_t, vm_size_t); +static vm_size_t tlb1_mapin_region(vm_offset_t, vm_paddr_t, vm_size_t); static vm_size_t tsize2size(unsigned int); static unsigned int size2tsize(vm_size_t); @@ -765,7 +771,7 @@ pv_remove(pmap_t pmap, vm_offset_t va, vm_page_t m) /* remove from pv_list */ TAILQ_REMOVE(&m->md.pv_list, pve, pv_link); if (TAILQ_EMPTY(&m->md.pv_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); /* free pv entry struct */ pv_free(pve); @@ -814,7 +820,7 @@ pte_remove(mmu_t mmu, pmap_t pmap, vm_offset_t va, uint8_t flags) vm_page_dirty(m); if (PTE_ISREFERENCED(pte)) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); pv_remove(pmap, va, m); } @@ -881,13 +887,11 @@ pte_enter(mmu_t mmu, pmap_t pmap, vm_page_t m, vm_offset_t va, uint32_t flags) * Insert pv_entry into pv_list for mapped page if part of managed * memory. */ - if ((m->flags & PG_FICTITIOUS) == 0) { - if ((m->flags & PG_UNMANAGED) == 0) { - flags |= PTE_MANAGED; + if ((m->oflags & VPO_UNMANAGED) == 0) { + flags |= PTE_MANAGED; - /* Create and insert pv entry. */ - pv_insert(pmap, va, m); - } + /* Create and insert pv entry. */ + pv_insert(pmap, va, m); } pmap->pm_stats.resident_count++; @@ -962,19 +966,37 @@ mmu_booke_bootstrap(mmu_t mmu, vm_offset_t start, vm_offset_t kernelend) debugf("mmu_booke_bootstrap: entered\n"); +#ifdef SMP + kernload_ap = kernload; +#endif + + /* Initialize invalidation mutex */ mtx_init(&tlbivax_mutex, "tlbivax", NULL, MTX_SPIN); /* Read TLB0 size and associativity. */ tlb0_get_tlbconf(); - /* Align kernel start and end address (kernel image). */ + /* + * Align kernel start and end address (kernel image). + * Note that kernel end does not necessarily relate to kernsize. + * kernsize is the size of the kernel that is actually mapped. + */ kernstart = trunc_page(start); data_start = round_page(kernelend); - kernsize = data_start - kernstart; - data_end = data_start; + /* + * Addresses of preloaded modules (like file systems) use + * physical addresses. Make sure we relocate those into + * virtual addresses. + */ + preload_addr_relocate = kernstart - kernload; + + /* Allocate the dynamic per-cpu area. */ + dpcpu = (void *)data_end; + data_end += DPCPU_SIZE; + /* Allocate space for the message buffer. */ msgbufp = (struct msgbuf *)data_end; data_end += msgbufsize; @@ -983,11 +1005,6 @@ mmu_booke_bootstrap(mmu_t mmu, vm_offset_t start, vm_offset_t kernelend) data_end = round_page(data_end); - /* Allocate the dynamic per-cpu area. */ - dpcpu = (void *)data_end; - data_end += DPCPU_SIZE; - dpcpu_init(dpcpu, 0); - /* Allocate space for ptbl_bufs. */ ptbl_bufs = (struct ptbl_buf *)data_end; data_end += sizeof(struct ptbl_buf) * PTBL_BUFS; @@ -1005,22 +1022,19 @@ mmu_booke_bootstrap(mmu_t mmu, vm_offset_t start, vm_offset_t kernelend) debugf(" kernel pdir at 0x%08x end = 0x%08x\n", kernel_pdir, data_end); debugf(" data_end: 0x%08x\n", data_end); - if (data_end - kernstart > 0x1000000) { - data_end = (data_end + 0x3fffff) & ~0x3fffff; - tlb1_mapin_region(kernstart + 0x1000000, - kernload + 0x1000000, data_end - kernstart - 0x1000000); - } else - data_end = (data_end + 0xffffff) & ~0xffffff; - + if (data_end - kernstart > kernsize) { + kernsize += tlb1_mapin_region(kernstart + kernsize, + kernload + kernsize, (data_end - kernstart) - kernsize); + } + data_end = kernstart + kernsize; debugf(" updated data_end: 0x%08x\n", data_end); - kernsize += data_end - data_start; - /* * Clear the structures - note we can only do it safely after the * possible additional TLB1 translations are in place (above) so that * all range up to the currently calculated 'data_end' is covered. */ + dpcpu_init(dpcpu, 0); memset((void *)ptbl_bufs, 0, sizeof(struct ptbl_buf) * PTBL_SIZE); memset((void *)kernel_pdir, 0, kernel_ptbls * PTBL_PAGES * PAGE_SIZE); @@ -1546,8 +1560,8 @@ mmu_booke_enter_locked(mmu_t mmu, pmap_t pmap, vm_offset_t va, vm_page_t m, KASSERT((va <= VM_MAXUSER_ADDRESS), ("mmu_booke_enter_locked: user pmap, non user va")); } - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0 || - (m->oflags & VPO_BUSY) != 0 || VM_OBJECT_LOCKED(m->object), + KASSERT((m->oflags & (VPO_UNMANAGED | VPO_BUSY)) != 0 || + VM_OBJECT_LOCKED(m->object), ("mmu_booke_enter_locked: page %p is not busy", m)); PMAP_LOCK_ASSERT(pmap, MA_OWNED); @@ -1586,7 +1600,7 @@ mmu_booke_enter_locked(mmu_t mmu, pmap_t pmap, vm_offset_t va, vm_page_t m, flags |= PTE_UW; if ((flags & PTE_MANAGED) != 0) - vm_page_flag_set(m, PG_WRITEABLE); + vm_page_aflag_set(m, PGA_WRITEABLE); } else { /* Handle modified pages, sense modify status. */ @@ -1652,8 +1666,8 @@ mmu_booke_enter_locked(mmu_t mmu, pmap_t pmap, vm_offset_t va, vm_page_t m, if (!su) flags |= PTE_UW; - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) - vm_page_flag_set(m, PG_WRITEABLE); + if ((m->oflags & VPO_UNMANAGED) == 0) + vm_page_aflag_set(m, PGA_WRITEABLE); } if (prot & VM_PROT_EXECUTE) { @@ -1790,7 +1804,7 @@ mmu_booke_remove_all(mmu_t mmu, vm_page_t m) pte_remove(mmu, pv->pv_pmap, pv->pv_va, hold_flag); PMAP_UNLOCK(pv->pv_pmap); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } @@ -1939,17 +1953,17 @@ mmu_booke_remove_write(mmu_t mmu, vm_page_t m) pv_entry_t pv; pte_t *pte; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("mmu_booke_remove_write: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be set by - * another thread while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be set by + * another thread while the object is locked. Thus, if PGA_WRITEABLE * is clear, no page table entries need updating. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_link) { @@ -1974,7 +1988,7 @@ mmu_booke_remove_write(mmu_t mmu, vm_page_t m) } PMAP_UNLOCK(pv->pv_pmap); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } @@ -2153,18 +2167,18 @@ mmu_booke_is_modified(mmu_t mmu, vm_page_t m) pv_entry_t pv; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("mmu_booke_is_modified: page %p is not managed", m)); rv = FALSE; /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be - * concurrently set while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be + * concurrently set while the object is locked. Thus, if PGA_WRITEABLE * is clear, no PTEs can be modified. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return (rv); vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_link) { @@ -2204,7 +2218,7 @@ mmu_booke_is_referenced(mmu_t mmu, vm_page_t m) pv_entry_t pv; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("mmu_booke_is_referenced: page %p is not managed", m)); rv = FALSE; vm_page_lock_queues(); @@ -2232,18 +2246,18 @@ mmu_booke_clear_modify(mmu_t mmu, vm_page_t m) pte_t *pte; pv_entry_t pv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("mmu_booke_clear_modify: page %p is not managed", m)); VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); KASSERT((m->oflags & VPO_BUSY) == 0, ("mmu_booke_clear_modify: page %p is busy", m)); /* - * If the page is not PG_WRITEABLE, then no PTEs can be modified. + * If the page is not PG_AWRITEABLE, then no PTEs can be modified. * If the object containing the page is locked and the page is not - * VPO_BUSY, then PG_WRITEABLE cannot be concurrently set. + * VPO_BUSY, then PG_AWRITEABLE cannot be concurrently set. */ - if ((m->flags & PG_WRITEABLE) == 0) + if ((m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_link) { @@ -2284,7 +2298,7 @@ mmu_booke_ts_referenced(mmu_t mmu, vm_page_t m) pv_entry_t pv; int count; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("mmu_booke_ts_referenced: page %p is not managed", m)); count = 0; vm_page_lock_queues(); @@ -2323,7 +2337,7 @@ mmu_booke_clear_reference(mmu_t mmu, vm_page_t m) pte_t *pte; pv_entry_t pv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("mmu_booke_clear_reference: page %p is not managed", m)); vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_link) { @@ -2384,7 +2398,7 @@ mmu_booke_page_exists_quick(mmu_t mmu, pmap_t pmap, vm_page_t m) int loops; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("mmu_booke_page_exists_quick: page %p is not managed", m)); loops = 0; rv = FALSE; @@ -2412,7 +2426,7 @@ mmu_booke_page_wired_mappings(mmu_t mmu, vm_page_t m) pte_t *pte; int count = 0; - if ((m->flags & PG_FICTITIOUS) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (count); vm_page_lock_queues(); TAILQ_FOREACH(pv, &m->md.pv_list, pv_link) { @@ -2926,22 +2940,6 @@ tlb1_set_entry(vm_offset_t va, vm_offset_t pa, vm_size_t size, return (0); } -static int -tlb1_entry_size_cmp(const void *a, const void *b) -{ - const vm_size_t *sza; - const vm_size_t *szb; - - sza = a; - szb = b; - if (*sza > *szb) - return (-1); - else if (*sza < *szb) - return (1); - else - return (0); -} - /* * Map in contiguous RAM region into the TLB1 using maximum of * KERNEL_REGION_MAX_TLB_ENTRIES entries. @@ -2950,64 +2948,60 @@ tlb1_entry_size_cmp(const void *a, const void *b) * used by all allocated entries. */ vm_size_t -tlb1_mapin_region(vm_offset_t va, vm_offset_t pa, vm_size_t size) +tlb1_mapin_region(vm_offset_t va, vm_paddr_t pa, vm_size_t size) { - vm_size_t entry_size[KERNEL_REGION_MAX_TLB_ENTRIES]; - vm_size_t mapped_size, sz, esz; - unsigned int log; - int i; - - CTR4(KTR_PMAP, "%s: region size = 0x%08x va = 0x%08x pa = 0x%08x", - __func__, size, va, pa); - - mapped_size = 0; - sz = size; - memset(entry_size, 0, sizeof(entry_size)); + vm_size_t pgs[KERNEL_REGION_MAX_TLB_ENTRIES]; + vm_size_t mapped, pgsz, base, mask; + int idx, nents; - /* Calculate entry sizes. */ - for (i = 0; i < KERNEL_REGION_MAX_TLB_ENTRIES && sz > 0; i++) { + /* Round up to the next 1M */ + size = (size + (1 << 20) - 1) & ~((1 << 20) - 1); - /* Largest region that is power of 4 and fits within size */ - log = ilog2(sz) / 2; - esz = 1 << (2 * log); - - /* If this is last entry cover remaining size. */ - if (i == KERNEL_REGION_MAX_TLB_ENTRIES - 1) { - while (esz < sz) - esz = esz << 2; + mapped = 0; + idx = 0; + base = va; + pgsz = 64*1024*1024; + while (mapped < size) { + while (mapped < size && idx < KERNEL_REGION_MAX_TLB_ENTRIES) { + while (pgsz > (size - mapped)) + pgsz >>= 2; + pgs[idx++] = pgsz; + mapped += pgsz; } - entry_size[i] = esz; - mapped_size += esz; - if (esz < sz) - sz -= esz; - else - sz = 0; + /* We under-map. Correct for this. */ + if (mapped < size) { + while (pgs[idx - 1] == pgsz) { + idx--; + mapped -= pgsz; + } + /* XXX We may increase beyond out starting point. */ + pgsz <<= 2; + pgs[idx++] = pgsz; + mapped += pgsz; + } } - /* Sort entry sizes, required to get proper entry address alignment. */ - qsort(entry_size, KERNEL_REGION_MAX_TLB_ENTRIES, - sizeof(vm_size_t), tlb1_entry_size_cmp); - - /* Load TLB1 entries. */ - for (i = 0; i < KERNEL_REGION_MAX_TLB_ENTRIES; i++) { - esz = entry_size[i]; - if (!esz) - break; - - CTR5(KTR_PMAP, "%s: entry %d: sz = 0x%08x (va = 0x%08x " - "pa = 0x%08x)", __func__, tlb1_idx, esz, va, pa); - - tlb1_set_entry(va, pa, esz, _TLB_ENTRY_MEM); - - va += esz; - pa += esz; + nents = idx; + mask = pgs[0] - 1; + /* Align address to the boundary */ + if (va & mask) { + va = (va + mask) & ~mask; + pa = (pa + mask) & ~mask; } - CTR3(KTR_PMAP, "%s: mapped size 0x%08x (wasted space 0x%08x)", - __func__, mapped_size, mapped_size - size); + for (idx = 0; idx < nents; idx++) { + pgsz = pgs[idx]; + debugf("%u: %x -> %x, size=%x\n", idx, pa, va, pgsz); + tlb1_set_entry(va, pa, pgsz, _TLB_ENTRY_MEM); + pa += pgsz; + va += pgsz; + } - return (mapped_size); + mapped = (va - base); + debugf("mapped size 0x%08x (wasted space 0x%08x)\n", + mapped, mapped - size); + return (mapped); } /* @@ -3017,19 +3011,39 @@ tlb1_mapin_region(vm_offset_t va, vm_offset_t pa, vm_size_t size) void tlb1_init(vm_offset_t ccsrbar) { - uint32_t mas0; + uint32_t mas0, mas1, mas3; + uint32_t tsz; + u_int i; - /* TLB1[0] is used to map the kernel. Save that entry. */ - mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(0); - mtspr(SPR_MAS0, mas0); - __asm __volatile("isync; tlbre"); + if (bootinfo != NULL && bootinfo[0] != 1) { + tlb1_idx = *((uint16_t *)(bootinfo + 8)); + } else + tlb1_idx = 1; + + /* The first entry/entries are used to map the kernel. */ + for (i = 0; i < tlb1_idx; i++) { + mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(i); + mtspr(SPR_MAS0, mas0); + __asm __volatile("isync; tlbre"); - tlb1[0].mas1 = mfspr(SPR_MAS1); - tlb1[0].mas2 = mfspr(SPR_MAS2); - tlb1[0].mas3 = mfspr(SPR_MAS3); + mas1 = mfspr(SPR_MAS1); + if ((mas1 & MAS1_VALID) == 0) + continue; + + mas3 = mfspr(SPR_MAS3); + + tlb1[i].mas1 = mas1; + tlb1[i].mas2 = mfspr(SPR_MAS2); + tlb1[i].mas3 = mas3; + + if (i == 0) + kernload = mas3 & MAS3_RPN; + + tsz = (mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; + kernsize += (tsz > 0) ? tsize2size(tsz) : 0; + } - /* Map in CCSRBAR in TLB1[1] */ - tlb1_idx = 1; + /* Map in CCSRBAR. */ tlb1_set_entry(CCSRBAR_VA, ccsrbar, CCSRBAR_SIZE, _TLB_ENTRY_IO); /* Setup TLB miss defaults */ diff --git a/sys/powerpc/booke/trap.c b/sys/powerpc/booke/trap.c index fc506bd361ce3..091fce08f1fb4 100644 --- a/sys/powerpc/booke/trap.c +++ b/sys/powerpc/booke/trap.c @@ -375,6 +375,8 @@ cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) return (error); } +#include "../../kern/subr_syscall.c" + void syscall(struct trapframe *frame) { diff --git a/sys/powerpc/conf/MPC85XX b/sys/powerpc/conf/MPC85XX index 13decf7026898..9964a340fbe12 100644 --- a/sys/powerpc/conf/MPC85XX +++ b/sys/powerpc/conf/MPC85XX @@ -43,7 +43,7 @@ options MD_ROOT options MPC85XX options MSDOSFS options NFS_ROOT -options NFSCLIENT +options NFSCL options NFSLOCKD options PROCFS options PSEUDOFS diff --git a/sys/powerpc/include/param.h b/sys/powerpc/include/param.h index 06b131c2a676f..f95cc08947263 100644 --- a/sys/powerpc/include/param.h +++ b/sys/powerpc/include/param.h @@ -68,7 +68,9 @@ #endif #if defined(SMP) || defined(KLD_MODULE) +#ifndef MAXCPU #define MAXCPU 8 +#endif #else #define MAXCPU 1 #endif /* SMP || KLD_MODULE */ diff --git a/sys/powerpc/include/pmap.h b/sys/powerpc/include/pmap.h index 9166d04ba7d90..688975d1ce217 100644 --- a/sys/powerpc/include/pmap.h +++ b/sys/powerpc/include/pmap.h @@ -127,10 +127,8 @@ LIST_HEAD(pvo_head, pvo_entry); #define PVO_EXECUTABLE 0x040UL /* PVO entry is executable */ #define PVO_BOOTSTRAP 0x080UL /* PVO entry allocated during bootstrap */ -#define PVO_FAKE 0x100UL /* fictitious phys page */ #define PVO_LARGE 0x200UL /* large page */ #define PVO_VADDR(pvo) ((pvo)->pvo_vaddr & ~ADDR_POFF) -#define PVO_ISFAKE(pvo) ((pvo)->pvo_vaddr & PVO_FAKE) #define PVO_PTEGIDX_GET(pvo) ((pvo)->pvo_vaddr & PVO_PTEGIDX_MASK) #define PVO_PTEGIDX_ISSET(pvo) ((pvo)->pvo_vaddr & PVO_PTEGIDX_VALID) #define PVO_PTEGIDX_CLR(pvo) \ diff --git a/sys/powerpc/mambo/mambo_console.c b/sys/powerpc/mambo/mambo_console.c index a5ef2f9de35da..880ef57b14706 100644 --- a/sys/powerpc/mambo/mambo_console.c +++ b/sys/powerpc/mambo/mambo_console.c @@ -25,8 +25,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_comconsole.h" - #include <sys/param.h> #include <sys/kdb.h> #include <sys/kernel.h> @@ -60,7 +58,7 @@ static int polltime; static struct callout mambo_callout; static struct tty *tp = NULL; -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) +#if defined(KDB) static int alt_break_state; #endif @@ -156,24 +154,8 @@ mambo_cngetc(struct consdev *cp) ch = mambocall(MAMBO_CONSOLE_READ); if (ch > 0 && ch < 0xff) { -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) - int kdb_brk; - - if ((kdb_brk = kdb_alt_break(ch, &alt_break_state)) != 0) { - switch (kdb_brk) { - case KDB_REQ_DEBUGGER: - kdb_enter(KDB_WHY_BREAK, - "Break sequence on console"); - break; - case KDB_REQ_PANIC: - kdb_panic("Panic sequence on console"); - break; - case KDB_REQ_REBOOT: - kdb_reboot(); - break; - - } - } +#if defined(KDB) + kdb_alt_break(ch, &alt_break_state); #endif return (ch); } diff --git a/sys/powerpc/mpc85xx/atpic.c b/sys/powerpc/mpc85xx/atpic.c index e1d0b39a68149..a792e54491bea 100644 --- a/sys/powerpc/mpc85xx/atpic.c +++ b/sys/powerpc/mpc85xx/atpic.c @@ -28,11 +28,11 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/bus.h> +#include <sys/cpuset.h> #include <sys/kernel.h> #include <sys/module.h> -#include <sys/bus.h> #include <sys/rman.h> -#include <sys/bus.h> #include <machine/bus.h> #include <machine/intr_machdep.h> diff --git a/sys/powerpc/powermac/fcu.c b/sys/powerpc/powermac/fcu.c index eb43ff23e1b3f..cf5b4662a604d 100644 --- a/sys/powerpc/powermac/fcu.c +++ b/sys/powerpc/powermac/fcu.c @@ -282,14 +282,14 @@ fcu_fan_set_rpm(struct fcu_fan *fan, int rpm) fan->setpoint = rpm; } else { device_printf(fan->dev, "Unknown fan type: %d\n", fan->type); - return (-1); + return (ENXIO); } buf[0] = rpm >> (8 - fcu_rpm_shift); buf[1] = rpm << fcu_rpm_shift; if (fcu_write(sc->sc_dev, sc->sc_addr, reg, buf, 2) < 0) - return (-1); + return (EIO); return (0); } @@ -377,7 +377,7 @@ fcu_fan_set_pwm(struct fcu_fan *fan, int pwm) buf[0] = (pwm * 2550) / 1000; if (fcu_write(sc->sc_dev, sc->sc_addr, reg, buf, 1) < 0) - return (-1); + return (EIO); return (0); } @@ -536,12 +536,12 @@ fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS) if (fan->type == FCU_FAN_RPM) { rpm = fcu_fan_get_rpm(fan); if (rpm < 0) - return (-1); + return (EIO); error = sysctl_handle_int(oidp, &rpm, 0, req); } else { error = fcu_fan_get_pwm(fcu, fan, &pwm, &rpm); if (error < 0) - return (-1); + return (EIO); switch (arg2 & 0xff00) { case FCU_PWM_SYSCTL_PWM: @@ -552,7 +552,7 @@ fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS) break; default: /* This should never happen */ - error = -1; + return (EINVAL); }; } diff --git a/sys/powerpc/powerpc/mmu_if.m b/sys/powerpc/powerpc/mmu_if.m index 6f60622539283..9d5b656cbac1f 100644 --- a/sys/powerpc/powerpc/mmu_if.m +++ b/sys/powerpc/powerpc/mmu_if.m @@ -584,7 +584,7 @@ METHOD void remove { /** * @brief Traverse the reverse-map list off the given physical page and - * remove all mappings. Clear the PG_WRITEABLE attribute from the page. + * remove all mappings. Clear the PGA_WRITEABLE attribute from the page. * * @param _pg physical page */ diff --git a/sys/powerpc/ps3/ps3cdrom.c b/sys/powerpc/ps3/ps3cdrom.c new file mode 100644 index 0000000000000..319090cacb561 --- /dev/null +++ b/sys/powerpc/ps3/ps3cdrom.c @@ -0,0 +1,703 @@ +/*- + * Copyright (C) 2010 Nathan Whitehorn + * Copyright (C) 2011 glevand <geoffrey.levand@mail.ru> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/module.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/ata.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/kthread.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> + +#include <vm/vm.h> +#include <vm/pmap.h> + +#include <machine/pio.h> +#include <machine/bus.h> +#include <machine/platform.h> +#include <machine/pmap.h> +#include <machine/resource.h> +#include <sys/bus.h> +#include <sys/rman.h> + +#include <cam/cam.h> +#include <cam/cam_ccb.h> +#include <cam/cam_sim.h> +#include <cam/cam_xpt_sim.h> +#include <cam/cam_debug.h> +#include <cam/scsi/scsi_all.h> + +#include "ps3bus.h" +#include "ps3-hvcall.h" + +#define PS3CDROM_LOCK_INIT(_sc) \ + mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3cdrom", \ + MTX_DEF) +#define PS3CDROM_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); +#define PS3CDROM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define PS3CDROM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define PS3CDROM_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); +#define PS3CDROM_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); + +#define PS3CDROM_MAX_XFERS 3 + +#define LV1_STORAGE_SEND_ATAPI_COMMAND 0x01 + +struct ps3cdrom_softc; + +struct ps3cdrom_xfer { + TAILQ_ENTRY(ps3cdrom_xfer) x_queue; + struct ps3cdrom_softc *x_sc; + union ccb *x_ccb; + bus_dmamap_t x_dmamap; + uint64_t x_tag; +}; + +TAILQ_HEAD(ps3cdrom_xferq, ps3cdrom_xfer); + +struct ps3cdrom_softc { + device_t sc_dev; + + struct mtx sc_mtx; + + uint64_t sc_blksize; + uint64_t sc_nblocks; + + int sc_irqid; + struct resource *sc_irq; + void *sc_irqctx; + + bus_dma_tag_t sc_dmatag; + + struct cam_sim *sc_sim; + struct cam_path *sc_path; + + struct ps3cdrom_xfer sc_xfer[PS3CDROM_MAX_XFERS]; + struct ps3cdrom_xferq sc_active_xferq; + struct ps3cdrom_xferq sc_free_xferq; +}; + +enum lv1_ata_proto { + NON_DATA_PROTO = 0x00, + PIO_DATA_IN_PROTO = 0x01, + PIO_DATA_OUT_PROTO = 0x02, + DMA_PROTO = 0x03 +}; + +enum lv1_ata_in_out { + DIR_WRITE = 0x00, + DIR_READ = 0x01 +}; + +struct lv1_atapi_cmd { + uint8_t pkt[32]; + uint32_t pktlen; + uint32_t nblocks; + uint32_t blksize; + uint32_t proto; /* enum lv1_ata_proto */ + uint32_t in_out; /* enum lv1_ata_in_out */ + uint64_t buf; + uint32_t arglen; +}; + +static void ps3cdrom_action(struct cam_sim *sim, union ccb *ccb); +static void ps3cdrom_poll(struct cam_sim *sim); +static void ps3cdrom_async(void *callback_arg, u_int32_t code, + struct cam_path* path, void *arg); + +static void ps3cdrom_intr(void *arg); + +static void ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, + int error); + +static int ps3cdrom_decode_lv1_status(uint64_t status, + u_int8_t *sense_key, u_int8_t *asc, u_int8_t *ascq); + +static int +ps3cdrom_probe(device_t dev) +{ + if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE || + ps3bus_get_devtype(dev) != PS3_DEVTYPE_CDROM) + return (ENXIO); + + device_set_desc(dev, "Playstation 3 CDROM"); + + return (BUS_PROBE_SPECIFIC); +} + +static int +ps3cdrom_attach(device_t dev) +{ + struct ps3cdrom_softc *sc = device_get_softc(dev); + struct cam_devq *devq; + struct ps3cdrom_xfer *xp; + struct ccb_setasync csa; + int i, err; + + sc->sc_dev = dev; + + PS3CDROM_LOCK_INIT(sc); + + /* Setup interrupt handler */ + + sc->sc_irqid = 0; + sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid, + RF_ACTIVE); + if (!sc->sc_irq) { + device_printf(dev, "Could not allocate IRQ\n"); + err = ENXIO; + goto fail_destroy_lock; + } + + err = bus_setup_intr(dev, sc->sc_irq, + INTR_TYPE_CAM | INTR_MPSAFE | INTR_ENTROPY, + NULL, ps3cdrom_intr, sc, &sc->sc_irqctx); + if (err) { + device_printf(dev, "Could not setup IRQ\n"); + err = ENXIO; + goto fail_release_intr; + } + + /* Setup DMA */ + + err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0, + BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, + BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0, + busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag); + if (err) { + device_printf(dev, "Could not create DMA tag\n"); + err = ENXIO; + goto fail_teardown_intr; + } + + /* Setup transfer queues */ + + TAILQ_INIT(&sc->sc_active_xferq); + TAILQ_INIT(&sc->sc_free_xferq); + + for (i = 0; i < PS3CDROM_MAX_XFERS; i++) { + xp = &sc->sc_xfer[i]; + xp->x_sc = sc; + + err = bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT, + &xp->x_dmamap); + if (err) { + device_printf(dev, "Could not create DMA map (%d)\n", + err); + goto fail_destroy_dmamap; + } + + TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); + } + + /* Setup CAM */ + + devq = cam_simq_alloc(PS3CDROM_MAX_XFERS - 1); + if (!devq) { + device_printf(dev, "Could not allocate SIM queue\n"); + err = ENOMEM; + goto fail_destroy_dmatag; + } + + sc->sc_sim = cam_sim_alloc(ps3cdrom_action, ps3cdrom_poll, "ps3cdrom", + sc, device_get_unit(dev), &sc->sc_mtx, PS3CDROM_MAX_XFERS - 1, 0, + devq); + if (!sc->sc_sim) { + device_printf(dev, "Could not allocate SIM\n"); + cam_simq_free(devq); + err = ENOMEM; + goto fail_destroy_dmatag; + } + + /* Setup XPT */ + + PS3CDROM_LOCK(sc); + + err = xpt_bus_register(sc->sc_sim, dev, 0); + if (err != CAM_SUCCESS) { + device_printf(dev, "Could not register XPT bus\n"); + err = ENXIO; + PS3CDROM_UNLOCK(sc); + goto fail_free_sim; + } + + err = xpt_create_path(&sc->sc_path, NULL, cam_sim_path(sc->sc_sim), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); + if (err != CAM_REQ_CMP) { + device_printf(dev, "Could not create XPT path\n"); + err = ENOMEM; + PS3CDROM_UNLOCK(sc); + goto fail_unregister_xpt_bus; + } + + xpt_setup_ccb(&csa.ccb_h, sc->sc_path, 5); + csa.ccb_h.func_code = XPT_SASYNC_CB; + csa.event_enable = AC_LOST_DEVICE; + csa.callback = ps3cdrom_async; + csa.callback_arg = sc->sc_sim; + xpt_action((union ccb *) &csa); + + CAM_DEBUG(sc->sc_path, CAM_DEBUG_TRACE, + ("registered SIM for ps3cdrom%d\n", device_get_unit(dev))); + + PS3CDROM_UNLOCK(sc); + + return (BUS_PROBE_SPECIFIC); + +fail_unregister_xpt_bus: + + xpt_bus_deregister(cam_sim_path(sc->sc_sim)); + +fail_free_sim: + + cam_sim_free(sc->sc_sim, TRUE); + +fail_destroy_dmamap: + + while ((xp = TAILQ_FIRST(&sc->sc_free_xferq))) { + TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue); + bus_dmamap_destroy(sc->sc_dmatag, xp->x_dmamap); + } + +fail_destroy_dmatag: + + bus_dma_tag_destroy(sc->sc_dmatag); + +fail_teardown_intr: + + bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx); + +fail_release_intr: + + bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq); + +fail_destroy_lock: + + PS3CDROM_LOCK_DESTROY(sc); + + return (err); +} + +static int +ps3cdrom_detach(device_t dev) +{ + struct ps3cdrom_softc *sc = device_get_softc(dev); + int i; + + xpt_async(AC_LOST_DEVICE, sc->sc_path, NULL); + xpt_free_path(sc->sc_path); + xpt_bus_deregister(cam_sim_path(sc->sc_sim)); + cam_sim_free(sc->sc_sim, TRUE); + + for (i = 0; i < PS3CDROM_MAX_XFERS; i++) + bus_dmamap_destroy(sc->sc_dmatag, sc->sc_xfer[i].x_dmamap); + + bus_dma_tag_destroy(sc->sc_dmatag); + + bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx); + bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq); + + PS3CDROM_LOCK_DESTROY(sc); + + return (0); +} + +static void +ps3cdrom_action(struct cam_sim *sim, union ccb *ccb) +{ + struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *)cam_sim_softc(sim); + device_t dev = sc->sc_dev; + struct ps3cdrom_xfer *xp; + int err; + + PS3CDROM_ASSERT_LOCKED(sc); + + CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, + ("function code 0x%02x\n", ccb->ccb_h.func_code)); + + switch (ccb->ccb_h.func_code) { + case XPT_SCSI_IO: + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) + break; + + if(ccb->ccb_h.target_id > 0) { + ccb->ccb_h.status = CAM_TID_INVALID; + break; + } + + if(ccb->ccb_h.target_lun > 0) { + ccb->ccb_h.status = CAM_LUN_INVALID; + break; + } + + xp = TAILQ_FIRST(&sc->sc_free_xferq); + + KASSERT(xp != NULL, ("no free transfers")); + + xp->x_ccb = ccb; + + TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue); + + err = bus_dmamap_load(sc->sc_dmatag, xp->x_dmamap, + ccb->csio.data_ptr, ccb->csio.dxfer_len, ps3cdrom_transfer, + xp, 0); + if (err && err != EINPROGRESS) { + device_printf(dev, "Could not load DMA map (%d)\n", + err); + + xp->x_ccb = NULL; + TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + break; + } + return; + case XPT_SET_TRAN_SETTINGS: + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + break; + case XPT_GET_TRAN_SETTINGS: + { + struct ccb_trans_settings *cts = &ccb->cts; + + cts->protocol = PROTO_SCSI; + cts->protocol_version = SCSI_REV_2; + cts->transport = XPORT_SPI; + cts->transport_version = 2; + cts->proto_specific.valid = 0; + cts->xport_specific.valid = 0; + ccb->ccb_h.status = CAM_REQ_CMP; + break; + } + case XPT_RESET_BUS: + case XPT_RESET_DEV: + ccb->ccb_h.status = CAM_REQ_CMP; + break; + case XPT_CALC_GEOMETRY: + cam_calc_geometry(&ccb->ccg, 1); + break; + case XPT_PATH_INQ: + { + struct ccb_pathinq *cpi = &ccb->cpi; + + cpi->version_num = 1; + cpi->hba_inquiry = 0; + cpi->target_sprt = 0; + cpi->hba_inquiry = PI_SDTR_ABLE; + cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN | PIM_NO_6_BYTE; + cpi->hba_eng_cnt = 0; + bzero(cpi->vuhba_flags, sizeof(cpi->vuhba_flags)); + cpi->max_target = 0; + cpi->max_lun = 0; + cpi->initiator_id = 7; + cpi->bus_id = cam_sim_bus(sim); + cpi->unit_number = cam_sim_unit(sim); + cpi->base_transfer_speed = 150000; + strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); + strncpy(cpi->hba_vid, "Sony", HBA_IDLEN); + strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); + cpi->transport = XPORT_SPI; + cpi->transport_version = 2; + cpi->protocol = PROTO_SCSI; + cpi->protocol_version = SCSI_REV_2; + cpi->maxio = PAGE_SIZE; + cpi->ccb_h.status = CAM_REQ_CMP; + break; + } + default: + CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, + ("unsupported function code 0x%02x\n", + ccb->ccb_h.func_code)); + ccb->ccb_h.status = CAM_REQ_INVALID; + break; + } + + xpt_done(ccb); +} + +static void +ps3cdrom_poll(struct cam_sim *sim) +{ + ps3cdrom_intr(cam_sim_softc(sim)); +} + +static void +ps3cdrom_async(void *callback_arg, u_int32_t code, + struct cam_path* path, void *arg) +{ + switch (code) { + case AC_LOST_DEVICE: + xpt_print_path(path); + break; + default: + break; + } +} + +static void +ps3cdrom_intr(void *arg) +{ + struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *) arg; + device_t dev = sc->sc_dev; + uint64_t devid = ps3bus_get_device(dev); + struct ps3cdrom_xfer *xp; + union ccb *ccb; + u_int8_t *cdb, sense_key, asc, ascq; + uint64_t tag, status; + + if (lv1_storage_get_async_status(devid, &tag, &status) != 0) + return; + + PS3CDROM_LOCK(sc); + + /* Find transfer with the returned tag */ + + TAILQ_FOREACH(xp, &sc->sc_active_xferq, x_queue) { + if (xp->x_tag == tag) + break; + } + + if (xp) { + ccb = xp->x_ccb; + cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ? + ccb->csio.cdb_io.cdb_ptr : + ccb->csio.cdb_io.cdb_bytes; + + CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, + ("ATAPI command 0x%02x tag 0x%016lx completed (0x%016lx)\n", + cdb[0], tag, status)); + + if (!status) { + ccb->csio.scsi_status = SCSI_STATUS_OK; + ccb->csio.resid = 0; + ccb->ccb_h.status = CAM_REQ_CMP; + } else { + ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + + if (!ps3cdrom_decode_lv1_status(status, &sense_key, + &asc, &ascq)) { + struct scsi_sense_data sense_data; + + CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, + ("sense key 0x%02x asc 0x%02x ascq 0x%02x\n", + sense_key, asc, ascq)); + + bzero(&sense_data, sizeof(sense_data)); + sense_data.error_code = SSD_CURRENT_ERROR; + sense_data.flags |= sense_key; + sense_data.extra_len = 0xa; + sense_data.add_sense_code = asc; + sense_data.add_sense_code_qual = ascq; + ccb->csio.sense_len = sizeof(sense_data); + bcopy(&sense_data, &ccb->csio.sense_data, + ccb->csio.sense_len); + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | + CAM_AUTOSNS_VALID; + } + + if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) + ccb->csio.resid = ccb->csio.dxfer_len; + } + + if (ccb->ccb_h.flags & CAM_DIR_IN) + bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap, + BUS_DMASYNC_POSTREAD); + + bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap); + + xp->x_ccb = NULL; + TAILQ_REMOVE(&sc->sc_active_xferq, xp, x_queue); + TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); + + xpt_done(ccb); + } else { + device_printf(dev, + "Could not find transfer with tag 0x%016lx\n", tag); + } + + PS3CDROM_UNLOCK(sc); +} + +static void +ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct ps3cdrom_xfer *xp = (struct ps3cdrom_xfer *) arg; + struct ps3cdrom_softc *sc = xp->x_sc; + device_t dev = sc->sc_dev; + uint64_t devid = ps3bus_get_device(dev); + union ccb *ccb = xp->x_ccb; + u_int8_t *cdb; + uint64_t start_sector, block_count; + int err; + + KASSERT(nsegs == 1, ("invalid number of DMA segments")); + + PS3CDROM_ASSERT_LOCKED(sc); + + if (error) { + device_printf(dev, "Could not load DMA map (%d)\n", error); + + xp->x_ccb = NULL; + TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + xpt_done(ccb); + return; + } + + cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ? + ccb->csio.cdb_io.cdb_ptr : + ccb->csio.cdb_io.cdb_bytes; + + CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, + ("ATAPI command 0x%02x cdb_len %d dxfer_len %d\n ", cdb[0], + ccb->csio.cdb_len, ccb->csio.dxfer_len)); + + switch (cdb[0]) { + case READ_10: + start_sector = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + block_count = (cdb[7] << 8) | cdb[8]; + + err = lv1_storage_read(devid, 0 /* region id */, + start_sector, block_count, 0 /* flags */, segs[0].ds_addr, + &xp->x_tag); + bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap, + BUS_DMASYNC_POSTREAD); + break; + case WRITE_10: + start_sector = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + block_count = (cdb[7] << 8) | cdb[8]; + + bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap, + BUS_DMASYNC_PREWRITE); + err = lv1_storage_write(devid, 0 /* region id */, + start_sector, block_count, 0 /* flags */, + segs[0].ds_addr, &xp->x_tag); + break; + default: + { + struct lv1_atapi_cmd atapi_cmd; + + bzero(&atapi_cmd, sizeof(atapi_cmd)); + atapi_cmd.pktlen = 12; + bcopy(cdb, atapi_cmd.pkt, ccb->csio.cdb_len); + + if (ccb->ccb_h.flags & CAM_DIR_IN) { + atapi_cmd.in_out = DIR_READ; + atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ? + DMA_PROTO : PIO_DATA_IN_PROTO; + } else if (ccb->ccb_h.flags & CAM_DIR_OUT) { + atapi_cmd.in_out = DIR_WRITE; + atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ? + DMA_PROTO : PIO_DATA_OUT_PROTO; + } else { + atapi_cmd.proto = NON_DATA_PROTO; + } + + atapi_cmd.nblocks = atapi_cmd.arglen = segs[0].ds_len; + atapi_cmd.blksize = 1; + atapi_cmd.buf = segs[0].ds_addr; + + if (ccb->ccb_h.flags & CAM_DIR_OUT) + bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap, + BUS_DMASYNC_PREWRITE); + + err = lv1_storage_send_device_command(devid, + LV1_STORAGE_SEND_ATAPI_COMMAND, vtophys(&atapi_cmd), + sizeof(atapi_cmd), atapi_cmd.buf, atapi_cmd.arglen, + &xp->x_tag); + + break; + } + } + + if (err) { + struct scsi_sense_data sense_data; + + device_printf(dev, "ATAPI command 0x%02x failed (%d)\n", + cdb[0], err); + + bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap); + + xp->x_ccb = NULL; + TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue); + + bzero(&sense_data, sizeof(sense_data)); + sense_data.error_code = SSD_CURRENT_ERROR; + sense_data.flags |= SSD_KEY_ILLEGAL_REQUEST; + ccb->csio.sense_len = sizeof(sense_data); + bcopy(&sense_data, &ccb->csio.sense_data, ccb->csio.sense_len); + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; + xpt_done(ccb); + } else { + CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, + ("ATAPI command 0x%02x tag 0x%016lx submitted\n ", cdb[0], + xp->x_tag)); + + TAILQ_INSERT_TAIL(&sc->sc_active_xferq, xp, x_queue); + ccb->ccb_h.status |= CAM_SIM_QUEUED; + } +} + +static int +ps3cdrom_decode_lv1_status(uint64_t status, u_int8_t *sense_key, u_int8_t *asc, + u_int8_t *ascq) +{ + if (((status >> 24) & 0xff) != SCSI_STATUS_CHECK_COND) + return -1; + + *sense_key = (status >> 16) & 0xff; + *asc = (status >> 8) & 0xff; + *ascq = status & 0xff; + + return (0); +} + +static device_method_t ps3cdrom_methods[] = { + DEVMETHOD(device_probe, ps3cdrom_probe), + DEVMETHOD(device_attach, ps3cdrom_attach), + DEVMETHOD(device_detach, ps3cdrom_detach), + {0, 0}, +}; + +static driver_t ps3cdrom_driver = { + "ps3cdrom", + ps3cdrom_methods, + sizeof(struct ps3cdrom_softc), +}; + +static devclass_t ps3cdrom_devclass; + +DRIVER_MODULE(ps3cdrom, ps3bus, ps3cdrom_driver, ps3cdrom_devclass, 0, 0); +MODULE_DEPEND(ps3cdrom, cam, 1, 1, 1); diff --git a/sys/rpc/clnt_dg.c b/sys/rpc/clnt_dg.c index a412c084fb952..8a69bf4e5b190 100644 --- a/sys/rpc/clnt_dg.c +++ b/sys/rpc/clnt_dg.c @@ -467,7 +467,10 @@ send_again: cu->cu_waitflag, "rpccwnd", 0); if (error) { errp->re_errno = error; - errp->re_status = stat = RPC_CANTSEND; + if (error == EINTR || error == ERESTART) + errp->re_status = stat = RPC_INTR; + else + errp->re_status = stat = RPC_CANTSEND; goto out; } } @@ -636,7 +639,7 @@ get_reply: */ if (error != EWOULDBLOCK) { errp->re_errno = error; - if (error == EINTR) + if (error == EINTR || error == ERESTART) errp->re_status = stat = RPC_INTR; else errp->re_status = stat = RPC_CANTRECV; diff --git a/sys/security/audit/audit_arg.c b/sys/security/audit/audit_arg.c index 4e155da619e0a..e4409f28bf67f 100644 --- a/sys/security/audit/audit_arg.c +++ b/sys/security/audit/audit_arg.c @@ -899,7 +899,7 @@ audit_sysclose(struct thread *td, int fd) audit_arg_fd(fd); - if (getvnode(td->td_proc->p_fd, fd, &fp) != 0) + if (getvnode(td->td_proc->p_fd, fd, 0, &fp) != 0) return; vp = fp->f_vnode; diff --git a/sys/security/audit/audit_pipe.c b/sys/security/audit/audit_pipe.c index a8db1135db761..a953eb0200da7 100644 --- a/sys/security/audit/audit_pipe.c +++ b/sys/security/audit/audit_pipe.c @@ -646,6 +646,7 @@ audit_pipe_free(struct audit_pipe *ap) cv_destroy(&ap->ap_cv); AUDIT_PIPE_SX_LOCK_DESTROY(ap); AUDIT_PIPE_LOCK_DESTROY(ap); + seldrain(&ap->ap_selinfo); knlist_destroy(&ap->ap_selinfo.si_note); TAILQ_REMOVE(&audit_pipe_list, ap, ap_list); free(ap, M_AUDIT_PIPE); diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h index f515e98e6a6e5..92aedea4ef750 100644 --- a/sys/security/mac/mac_framework.h +++ b/sys/security/mac/mac_framework.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999-2002, 2007-2009 Robert N. M. Watson + * Copyright (c) 1999-2002, 2007-2011 Robert N. M. Watson * Copyright (c) 2001-2005 Networks Associates Technology, Inc. * Copyright (c) 2005-2006 SPARTA, Inc. * All rights reserved. @@ -225,6 +225,10 @@ int mac_posixsem_check_getvalue(struct ucred *active_cred, int mac_posixsem_check_open(struct ucred *cred, struct ksem *ks); int mac_posixsem_check_post(struct ucred *active_cred, struct ucred *file_cred, struct ksem *ks); +int mac_posixsem_check_setmode(struct ucred *cred, struct ksem *ks, + mode_t mode); +int mac_posixsem_check_setowner(struct ucred *cred, struct ksem *ks, + uid_t uid, gid_t gid); int mac_posixsem_check_stat(struct ucred *active_cred, struct ucred *file_cred, struct ksem *ks); int mac_posixsem_check_unlink(struct ucred *cred, struct ksem *ks); @@ -234,9 +238,15 @@ void mac_posixsem_create(struct ucred *cred, struct ksem *ks); void mac_posixsem_destroy(struct ksem *); void mac_posixsem_init(struct ksem *); +int mac_posixshm_check_create(struct ucred *cred, const char *path); int mac_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd, int prot, int flags); -int mac_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd); +int mac_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd, + accmode_t accmode); +int mac_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd, + mode_t mode); +int mac_posixshm_check_setowner(struct ucred *cred, struct shmfd *shmfd, + uid_t uid, gid_t gid); int mac_posixshm_check_stat(struct ucred *active_cred, struct ucred *file_cred, struct shmfd *shmfd); int mac_posixshm_check_truncate(struct ucred *active_cred, diff --git a/sys/security/mac/mac_policy.h b/sys/security/mac/mac_policy.h index b874c41e74b1b..090dc4058104d 100644 --- a/sys/security/mac/mac_policy.h +++ b/sys/security/mac/mac_policy.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999-2002, 2007-2009 Robert N. M. Watson + * Copyright (c) 1999-2002, 2007-2011 Robert N. M. Watson * Copyright (c) 2001-2005 Networks Associates Technology, Inc. * Copyright (c) 2005-2006 SPARTA, Inc. * Copyright (c) 2008 Apple Inc. @@ -336,6 +336,12 @@ typedef int (*mpo_posixsem_check_open_t)(struct ucred *cred, typedef int (*mpo_posixsem_check_post_t)(struct ucred *active_cred, struct ucred *file_cred, struct ksem *ks, struct label *kslabel); +typedef int (*mpo_posixsem_check_setmode_t)(struct ucred *cred, + struct ksem *ks, struct label *shmlabel, + mode_t mode); +typedef int (*mpo_posixsem_check_setowner_t)(struct ucred *cred, + struct ksem *ks, struct label *shmlabel, + uid_t uid, gid_t gid); typedef int (*mpo_posixsem_check_stat_t)(struct ucred *active_cred, struct ucred *file_cred, struct ksem *ks, struct label *kslabel); @@ -349,11 +355,20 @@ typedef void (*mpo_posixsem_create_t)(struct ucred *cred, typedef void (*mpo_posixsem_destroy_label_t)(struct label *label); typedef void (*mpo_posixsem_init_label_t)(struct label *label); +typedef int (*mpo_posixshm_check_create_t)(struct ucred *cred, + const char *path); typedef int (*mpo_posixshm_check_mmap_t)(struct ucred *cred, struct shmfd *shmfd, struct label *shmlabel, int prot, int flags); typedef int (*mpo_posixshm_check_open_t)(struct ucred *cred, - struct shmfd *shmfd, struct label *shmlabel); + struct shmfd *shmfd, struct label *shmlabel, + accmode_t accmode); +typedef int (*mpo_posixshm_check_setmode_t)(struct ucred *cred, + struct shmfd *shmfd, struct label *shmlabel, + mode_t mode); +typedef int (*mpo_posixshm_check_setowner_t)(struct ucred *cred, + struct shmfd *shmfd, struct label *shmlabel, + uid_t uid, gid_t gid); typedef int (*mpo_posixshm_check_stat_t)(struct ucred *active_cred, struct ucred *file_cred, struct shmfd *shmfd, struct label *shmlabel); @@ -791,6 +806,8 @@ struct mac_policy_ops { mpo_posixsem_check_getvalue_t mpo_posixsem_check_getvalue; mpo_posixsem_check_open_t mpo_posixsem_check_open; mpo_posixsem_check_post_t mpo_posixsem_check_post; + mpo_posixsem_check_setmode_t mpo_posixsem_check_setmode; + mpo_posixsem_check_setowner_t mpo_posixsem_check_setowner; mpo_posixsem_check_stat_t mpo_posixsem_check_stat; mpo_posixsem_check_unlink_t mpo_posixsem_check_unlink; mpo_posixsem_check_wait_t mpo_posixsem_check_wait; @@ -798,8 +815,11 @@ struct mac_policy_ops { mpo_posixsem_destroy_label_t mpo_posixsem_destroy_label; mpo_posixsem_init_label_t mpo_posixsem_init_label; + mpo_posixshm_check_create_t mpo_posixshm_check_create; mpo_posixshm_check_mmap_t mpo_posixshm_check_mmap; mpo_posixshm_check_open_t mpo_posixshm_check_open; + mpo_posixshm_check_setmode_t mpo_posixshm_check_setmode; + mpo_posixshm_check_setowner_t mpo_posixshm_check_setowner; mpo_posixshm_check_stat_t mpo_posixshm_check_stat; mpo_posixshm_check_truncate_t mpo_posixshm_check_truncate; mpo_posixshm_check_unlink_t mpo_posixshm_check_unlink; diff --git a/sys/security/mac/mac_posix_sem.c b/sys/security/mac/mac_posix_sem.c index 9035d608c0830..461e5dbd3418a 100644 --- a/sys/security/mac/mac_posix_sem.c +++ b/sys/security/mac/mac_posix_sem.c @@ -198,3 +198,35 @@ mac_posixsem_check_wait(struct ucred *active_cred, struct ucred *file_cred, return (error); } + +MAC_CHECK_PROBE_DEFINE3(posixsem_check_setmode, "struct ucred *", + "struct ksem *", "mode_t"); + +int +mac_posixsem_check_setmode(struct ucred *cred, struct ksem *ks, mode_t mode) +{ + int error; + + MAC_POLICY_CHECK_NOSLEEP(posixsem_check_setmode, cred, ks, + ks->ks_label, mode); + MAC_CHECK_PROBE3(posixsem_check_setmode, error, cred, ks, mode); + + return (error); +} + +MAC_CHECK_PROBE_DEFINE4(posixsem_check_setowner, "struct ucred *", + "struct ks *", "uid_t", "gid_t"); + +int +mac_posixsem_check_setowner(struct ucred *cred, struct ksem *ks, uid_t uid, + gid_t gid) +{ + int error; + + MAC_POLICY_CHECK_NOSLEEP(posixsem_check_setowner, cred, ks, + ks->ks_label, uid, gid); + MAC_CHECK_PROBE4(posixsem_check_setowner, error, cred, ks, + uid, gid); + + return (error); +} diff --git a/sys/security/mac/mac_posix_shm.c b/sys/security/mac/mac_posix_shm.c index 4432a983f2d79..d5d15fc4248c9 100644 --- a/sys/security/mac/mac_posix_shm.c +++ b/sys/security/mac/mac_posix_shm.c @@ -1,6 +1,6 @@ /*- * Copyright (c) 2003-2006 SPARTA, Inc. - * Copyright (c) 2009 Robert N. M. Watson + * Copyright (c) 2009-2011 Robert N. M. Watson * All rights reserved. * * This software was developed for the FreeBSD Project in part by Network @@ -101,6 +101,20 @@ mac_posixshm_create(struct ucred *cred, struct shmfd *shmfd) shmfd->shm_label); } +MAC_CHECK_PROBE_DEFINE2(posixshm_check_create, "struct ucred *", + "const char *"); + +int +mac_posixshm_check_create(struct ucred *cred, const char *path) +{ + int error; + + MAC_POLICY_CHECK_NOSLEEP(posixshm_check_create, cred, path); + MAC_CHECK_PROBE2(posixshm_check_create, error, cred, path); + + return (error); +} + MAC_CHECK_PROBE_DEFINE4(posixshm_check_mmap, "struct ucred *", "struct shmfd *", "int", "int"); @@ -118,17 +132,18 @@ mac_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd, int prot, return (error); } -MAC_CHECK_PROBE_DEFINE2(posixshm_check_open, "struct ucred *", - "struct shmfd *"); +MAC_CHECK_PROBE_DEFINE3(posixshm_check_open, "struct ucred *", + "struct shmfd *", "accmode_t accmode"); int -mac_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd) +mac_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd, + accmode_t accmode) { int error; MAC_POLICY_CHECK_NOSLEEP(posixshm_check_open, cred, shmfd, - shmfd->shm_label); - MAC_CHECK_PROBE2(posixshm_check_open, error, cred, shmfd); + shmfd->shm_label, accmode); + MAC_CHECK_PROBE3(posixshm_check_open, error, cred, shmfd, accmode); return (error); } @@ -181,3 +196,35 @@ mac_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd) return (error); } + +MAC_CHECK_PROBE_DEFINE3(posixshm_check_setmode, "struct ucred *", + "struct shmfd *", "mode_t"); + +int +mac_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd, mode_t mode) +{ + int error; + + MAC_POLICY_CHECK_NOSLEEP(posixshm_check_setmode, cred, shmfd, + shmfd->shm_label, mode); + MAC_CHECK_PROBE3(posixshm_check_setmode, error, cred, shmfd, mode); + + return (error); +} + +MAC_CHECK_PROBE_DEFINE4(posixshm_check_setowner, "struct ucred *", + "struct shmfd *", "uid_t", "gid_t"); + +int +mac_posixshm_check_setowner(struct ucred *cred, struct shmfd *shmfd, uid_t uid, + gid_t gid) +{ + int error; + + MAC_POLICY_CHECK_NOSLEEP(posixshm_check_setowner, cred, shmfd, + shmfd->shm_label, uid, gid); + MAC_CHECK_PROBE4(posixshm_check_setowner, error, cred, shmfd, + uid, gid); + + return (error); +} diff --git a/sys/security/mac/mac_syscalls.c b/sys/security/mac/mac_syscalls.c index aea088582b312..dc275477be509 100644 --- a/sys/security/mac/mac_syscalls.c +++ b/sys/security/mac/mac_syscalls.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include "opt_mac.h" #include <sys/param.h> +#include <sys/capability.h> #include <sys/fcntl.h> #include <sys/kernel.h> #include <sys/lock.h> @@ -247,7 +248,7 @@ __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) } buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); - error = fget(td, uap->fd, &fp); + error = fget(td, uap->fd, CAP_MAC_GET, &fp); if (error) goto out; @@ -442,7 +443,7 @@ __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) return (error); } - error = fget(td, uap->fd, &fp); + error = fget(td, uap->fd, CAP_MAC_SET, &fp); if (error) goto out; diff --git a/sys/security/mac_biba/mac_biba.c b/sys/security/mac_biba/mac_biba.c index fcede07142f60..b7ca4e03044ab 100644 --- a/sys/security/mac_biba/mac_biba.c +++ b/sys/security/mac_biba/mac_biba.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999-2002, 2007-2009 Robert N. M. Watson + * Copyright (c) 1999-2002, 2007-2011 Robert N. M. Watson * Copyright (c) 2001-2005 McAfee, Inc. * Copyright (c) 2006 SPARTA, Inc. * All rights reserved. @@ -14,6 +14,9 @@ * This software was enhanced by SPARTA ISSO under SPAWAR contract * N66001-04-C-6019 ("SEFOS"). * + * This software was developed at the University of Cambridge Computer + * Laboratory with support from a grant from Google, Inc. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -1622,6 +1625,42 @@ biba_posixsem_check_openunlink(struct ucred *cred, struct ksem *ks, } static int +biba_posixsem_check_setmode(struct ucred *cred, struct ksem *ks, + struct label *kslabel, mode_t mode) +{ + struct mac_biba *subj, *obj; + + if (!biba_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(kslabel); + + if (!biba_dominate_effective(subj, obj)) + return (EACCES); + + return (0); +} + +static int +biba_posixsem_check_setowner(struct ucred *cred, struct ksem *ks, + struct label *kslabel, uid_t uid, gid_t gid) +{ + struct mac_biba *subj, *obj; + + if (!biba_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(kslabel); + + if (!biba_dominate_effective(subj, obj)) + return (EACCES); + + return (0); +} + +static int biba_posixsem_check_write(struct ucred *active_cred, struct ucred *file_cred, struct ksem *ks, struct label *kslabel) { @@ -1669,6 +1708,156 @@ biba_posixsem_create(struct ucred *cred, struct ksem *ks, biba_copy_effective(source, dest); } +static int +biba_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel, int prot, int flags) +{ + struct mac_biba *subj, *obj; + + if (!biba_enabled || !revocation_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) { + if (!biba_dominate_effective(obj, subj)) + return (EACCES); + } + if (((prot & VM_PROT_WRITE) != 0) && ((flags & MAP_SHARED) != 0)) { + if (!biba_dominate_effective(subj, obj)) + return (EACCES); + } + + return (0); +} + +static int +biba_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel, accmode_t accmode) +{ + struct mac_biba *subj, *obj; + + if (!biba_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + if (accmode & (VREAD | VEXEC | VSTAT_PERMS)) { + if (!biba_dominate_effective(obj, subj)) + return (EACCES); + } + if (accmode & VMODIFY_PERMS) { + if (!biba_dominate_effective(subj, obj)) + return (EACCES); + } + + return (0); +} + +static int +biba_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel, mode_t mode) +{ + struct mac_biba *subj, *obj; + + if (!biba_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + if (!biba_dominate_effective(subj, obj)) + return (EACCES); + + return (0); +} + +static int +biba_posixshm_check_setowner(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel, uid_t uid, gid_t gid) +{ + struct mac_biba *subj, *obj; + + if (!biba_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + if (!biba_dominate_effective(subj, obj)) + return (EACCES); + + return (0); +} + +static int +biba_posixshm_check_stat(struct ucred *active_cred, struct ucred *file_cred, + struct shmfd *shmfd, struct label *shmlabel) +{ + struct mac_biba *subj, *obj; + + if (!biba_enabled) + return (0); + + subj = SLOT(active_cred->cr_label); + obj = SLOT(shmlabel); + + if (!biba_dominate_effective(obj, subj)) + return (EACCES); + + return (0); +} + +static int +biba_posixshm_check_truncate(struct ucred *active_cred, + struct ucred *file_cred, struct shmfd *shmfd, struct label *shmlabel) +{ + struct mac_biba *subj, *obj; + + if (!biba_enabled) + return (0); + + subj = SLOT(active_cred->cr_label); + obj = SLOT(shmlabel); + + if (!biba_dominate_effective(subj, obj)) + return (EACCES); + + return (0); +} + +static int +biba_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel) +{ + struct mac_biba *subj, *obj; + + if (!biba_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + if (!biba_dominate_effective(subj, obj)) + return (EACCES); + + return (0); +} + +static void +biba_posixshm_create(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel) +{ + struct mac_biba *source, *dest; + + source = SLOT(cred->cr_label); + dest = SLOT(shmlabel); + + biba_copy_effective(source, dest); +} + /* * Some system privileges are allowed regardless of integrity grade; others * are allowed only when running with privilege with respect to the Biba @@ -3455,6 +3644,8 @@ static struct mac_policy_ops mac_biba_ops = .mpo_posixsem_check_getvalue = biba_posixsem_check_rdonly, .mpo_posixsem_check_open = biba_posixsem_check_openunlink, .mpo_posixsem_check_post = biba_posixsem_check_write, + .mpo_posixsem_check_setmode = biba_posixsem_check_setmode, + .mpo_posixsem_check_setowner = biba_posixsem_check_setowner, .mpo_posixsem_check_stat = biba_posixsem_check_rdonly, .mpo_posixsem_check_unlink = biba_posixsem_check_openunlink, .mpo_posixsem_check_wait = biba_posixsem_check_write, @@ -3462,6 +3653,17 @@ static struct mac_policy_ops mac_biba_ops = .mpo_posixsem_destroy_label = biba_destroy_label, .mpo_posixsem_init_label = biba_init_label, + .mpo_posixshm_check_mmap = biba_posixshm_check_mmap, + .mpo_posixshm_check_open = biba_posixshm_check_open, + .mpo_posixshm_check_setmode = biba_posixshm_check_setmode, + .mpo_posixshm_check_setowner = biba_posixshm_check_setowner, + .mpo_posixshm_check_stat = biba_posixshm_check_stat, + .mpo_posixshm_check_truncate = biba_posixshm_check_truncate, + .mpo_posixshm_check_unlink = biba_posixshm_check_unlink, + .mpo_posixshm_create = biba_posixshm_create, + .mpo_posixshm_destroy_label = biba_destroy_label, + .mpo_posixshm_init_label = biba_init_label, + .mpo_priv_check = biba_priv_check, .mpo_proc_check_debug = biba_proc_check_debug, diff --git a/sys/security/mac_mls/mac_mls.c b/sys/security/mac_mls/mac_mls.c index d41799d5a23f7..b68790d0259c6 100644 --- a/sys/security/mac_mls/mac_mls.c +++ b/sys/security/mac_mls/mac_mls.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999-2002, 2007-2009 Robert N. M. Watson + * Copyright (c) 1999-2002, 2007-2011 Robert N. M. Watson * Copyright (c) 2001-2005 McAfee, Inc. * Copyright (c) 2006 SPARTA, Inc. * All rights reserved. @@ -14,6 +14,9 @@ * This software was enhanced by SPARTA ISSO under SPAWAR contract * N66001-04-C-6019 ("SEFOS"). * + * This software was developed at the University of Cambridge Computer + * Laboratory with support from a grant from Google, Inc. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -1532,6 +1535,42 @@ mls_posixsem_check_rdonly(struct ucred *active_cred, struct ucred *file_cred, } static int +mls_posixsem_check_setmode(struct ucred *cred, struct ksem *ks, + struct label *shmlabel, mode_t mode) +{ + struct mac_mls *subj, *obj; + + if (!mls_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + if (!mls_dominate_effective(obj, subj)) + return (EACCES); + + return (0); +} + +static int +mls_posixsem_check_setowner(struct ucred *cred, struct ksem *ks, + struct label *shmlabel, uid_t uid, gid_t gid) +{ + struct mac_mls *subj, *obj; + + if (!mls_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + if (!mls_dominate_effective(obj, subj)) + return (EACCES); + + return (0); +} + +static int mls_posixsem_check_write(struct ucred *active_cred, struct ucred *file_cred, struct ksem *ks, struct label *kslabel) { @@ -1562,6 +1601,159 @@ mls_posixsem_create(struct ucred *cred, struct ksem *ks, } static int +mls_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel, int prot, int flags) +{ + struct mac_mls *subj, *obj; + + if (!mls_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) { + if (!mls_dominate_effective(subj, obj)) + return (EACCES); + } + if (((prot & VM_PROT_WRITE) != 0) && ((flags & MAP_SHARED) != 0)) { + if (!mls_dominate_effective(obj, subj)) + return (EACCES); + } + + return (0); +} + +static int +mls_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel, accmode_t accmode) +{ + struct mac_mls *subj, *obj; + + if (!mls_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + if (accmode & (VREAD | VEXEC | VSTAT_PERMS)) { + if (!mls_dominate_effective(subj, obj)) + return (EACCES); + } + if (accmode & VMODIFY_PERMS) { + if (!mls_dominate_effective(obj, subj)) + return (EACCES); + } + + return (0); +} + +static int +mls_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel, mode_t mode) +{ + struct mac_mls *subj, *obj; + + if (!mls_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + if (!mls_dominate_effective(obj, subj)) + return (EACCES); + + return (0); +} + +static int +mls_posixshm_check_setowner(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel, uid_t uid, gid_t gid) +{ + struct mac_mls *subj, *obj; + + if (!mls_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + if (!mls_dominate_effective(obj, subj)) + return (EACCES); + + return (0); +} + +static int +mls_posixshm_check_stat(struct ucred *active_cred, struct ucred *file_cred, + struct shmfd *shmfd, struct label *shmlabel) +{ + struct mac_mls *subj, *obj; + + if (!mls_enabled) + return (0); + + subj = SLOT(active_cred->cr_label); + obj = SLOT(shmlabel); + + if (!mls_dominate_effective(subj, obj)) + return (EACCES); + + return (0); +} + +static int +mls_posixshm_check_truncate(struct ucred *active_cred, + struct ucred *file_cred, struct shmfd *shmfd, struct label *shmlabel) +{ + struct mac_mls *subj, *obj; + + if (!mls_enabled) + return (0); + + subj = SLOT(active_cred->cr_label); + obj = SLOT(shmlabel); + + if (!mls_dominate_effective(obj, subj)) + return (EACCES); + + return (0); +} + +static int +mls_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel) +{ + struct mac_mls *subj, *obj; + + if (!mls_enabled) + return (0); + + subj = SLOT(cred->cr_label); + obj = SLOT(shmlabel); + + if (!mls_dominate_effective(obj, subj)) + return (EACCES); + + return (0); +} + +static void +mls_posixshm_create(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel) +{ + struct mac_mls *source, *dest; + + source = SLOT(cred->cr_label); + dest = SLOT(shmlabel); + + mls_copy_effective(source, dest); +} + +static int mls_proc_check_debug(struct ucred *cred, struct proc *p) { struct mac_mls *subj, *obj; @@ -3075,6 +3267,8 @@ static struct mac_policy_ops mls_ops = .mpo_posixsem_check_getvalue = mls_posixsem_check_rdonly, .mpo_posixsem_check_open = mls_posixsem_check_openunlink, .mpo_posixsem_check_post = mls_posixsem_check_write, + .mpo_posixsem_check_setmode = mls_posixsem_check_setmode, + .mpo_posixsem_check_setowner = mls_posixsem_check_setowner, .mpo_posixsem_check_stat = mls_posixsem_check_rdonly, .mpo_posixsem_check_unlink = mls_posixsem_check_openunlink, .mpo_posixsem_check_wait = mls_posixsem_check_write, @@ -3082,6 +3276,17 @@ static struct mac_policy_ops mls_ops = .mpo_posixsem_destroy_label = mls_destroy_label, .mpo_posixsem_init_label = mls_init_label, + .mpo_posixshm_check_mmap = mls_posixshm_check_mmap, + .mpo_posixshm_check_open = mls_posixshm_check_open, + .mpo_posixshm_check_setmode = mls_posixshm_check_setmode, + .mpo_posixshm_check_setowner = mls_posixshm_check_setowner, + .mpo_posixshm_check_stat = mls_posixshm_check_stat, + .mpo_posixshm_check_truncate = mls_posixshm_check_truncate, + .mpo_posixshm_check_unlink = mls_posixshm_check_unlink, + .mpo_posixshm_create = mls_posixshm_create, + .mpo_posixshm_destroy_label = mls_destroy_label, + .mpo_posixshm_init_label = mls_init_label, + .mpo_proc_check_debug = mls_proc_check_debug, .mpo_proc_check_sched = mls_proc_check_sched, .mpo_proc_check_signal = mls_proc_check_signal, diff --git a/sys/security/mac_stub/mac_stub.c b/sys/security/mac_stub/mac_stub.c index 007efb8534078..f1d3e10c4dd5d 100644 --- a/sys/security/mac_stub/mac_stub.c +++ b/sys/security/mac_stub/mac_stub.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999-2002, 2007-2009 Robert N. M. Watson + * Copyright (c) 1999-2002, 2007-2011 Robert N. M. Watson * Copyright (c) 2001-2005 McAfee, Inc. * Copyright (c) 2005-2006 SPARTA, Inc. * Copyright (c) 2008 Apple Inc. @@ -687,6 +687,22 @@ stub_posixsem_check_post(struct ucred *active_cred, struct ucred *file_cred, } static int +stub_posixsem_check_setmode(struct ucred *cred, struct ksem *ks, + struct label *kslabel, mode_t mode) +{ + + return (0); +} + +static int +stub_posixsem_check_setowner(struct ucred *cred, struct ksem *ks, + struct label *kslabel, uid_t uid, gid_t gid) +{ + + return (0); +} + +static int stub_posixsem_check_stat(struct ucred *active_cred, struct ucred *file_cred, struct ksem *ks, struct label *kslabel) { @@ -718,6 +734,13 @@ stub_posixsem_create(struct ucred *cred, struct ksem *ks, } static int +stub_posixshm_check_create(struct ucred *cred, const char *path) +{ + + return (0); +} + +static int stub_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd, struct label *shmlabel, int prot, int flags) { @@ -727,7 +750,23 @@ stub_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd, static int stub_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd, - struct label *shmlabel) + struct label *shmlabel, accmode_t accmode) +{ + + return (0); +} + +static int +stub_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel, mode_t mode) +{ + + return (0); +} + +static int +stub_posixshm_check_setowner(struct ucred *cred, struct shmfd *shmfd, + struct label *shmlabel, uid_t uid, gid_t gid) { return (0); @@ -1731,6 +1770,8 @@ static struct mac_policy_ops stub_ops = .mpo_posixsem_check_getvalue = stub_posixsem_check_getvalue, .mpo_posixsem_check_open = stub_posixsem_check_open, .mpo_posixsem_check_post = stub_posixsem_check_post, + .mpo_posixsem_check_setmode = stub_posixsem_check_setmode, + .mpo_posixsem_check_setowner = stub_posixsem_check_setowner, .mpo_posixsem_check_stat = stub_posixsem_check_stat, .mpo_posixsem_check_unlink = stub_posixsem_check_unlink, .mpo_posixsem_check_wait = stub_posixsem_check_wait, @@ -1738,8 +1779,11 @@ static struct mac_policy_ops stub_ops = .mpo_posixsem_destroy_label = stub_destroy_label, .mpo_posixsem_init_label = stub_init_label, + .mpo_posixshm_check_create = stub_posixshm_check_create, .mpo_posixshm_check_mmap = stub_posixshm_check_mmap, .mpo_posixshm_check_open = stub_posixshm_check_open, + .mpo_posixshm_check_setmode = stub_posixshm_check_setmode, + .mpo_posixshm_check_setowner = stub_posixshm_check_setowner, .mpo_posixshm_check_stat = stub_posixshm_check_stat, .mpo_posixshm_check_truncate = stub_posixshm_check_truncate, .mpo_posixshm_check_unlink = stub_posixshm_check_unlink, diff --git a/sys/security/mac_test/mac_test.c b/sys/security/mac_test/mac_test.c index bef0cb7d611ca..c92c418cd1c85 100644 --- a/sys/security/mac_test/mac_test.c +++ b/sys/security/mac_test/mac_test.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999-2002, 2007-2009 Robert N. M. Watson + * Copyright (c) 1999-2002, 2007-2011 Robert N. M. Watson * Copyright (c) 2001-2005 McAfee, Inc. * Copyright (c) 2006 SPARTA, Inc. * Copyright (c) 2008 Apple Inc. @@ -1297,6 +1297,30 @@ test_posixsem_check_post(struct ucred *active_cred, struct ucred *file_cred, return (0); } +COUNTER_DECL(posixsem_check_setmode); +static int +test_posixsem_check_setmode(struct ucred *cred, struct ksem *ks, + struct label *kslabel, mode_t mode) +{ + + LABEL_CHECK(cred->cr_label, MAGIC_CRED); + LABEL_CHECK(kslabel, MAGIC_POSIX_SHM); + COUNTER_INC(posixsem_check_setmode); + return (0); +} + +COUNTER_DECL(posixsem_check_setowner); +static int +test_posixsem_check_setowner(struct ucred *cred, struct ksem *ks, + struct label *kslabel, uid_t uid, gid_t gid) +{ + + LABEL_CHECK(cred->cr_label, MAGIC_CRED); + LABEL_CHECK(kslabel, MAGIC_POSIX_SHM); + COUNTER_INC(posixsem_check_setowner); + return (0); +} + COUNTER_DECL(posixsem_check_stat); static int test_posixsem_check_stat(struct ucred *active_cred, @@ -1366,6 +1390,15 @@ test_posixsem_init_label(struct label *label) COUNTER_INC(posixsem_init_label); } +COUNTER_DECL(posixshm_check_create); +static int +test_posixshm_check_create(struct ucred *cred, const char *path) +{ + + COUNTER_INC(posixshm_check_create); + return (0); +} + COUNTER_DECL(posixshm_check_mmap); static int test_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd, @@ -1381,7 +1414,7 @@ test_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd, COUNTER_DECL(posixshm_check_open); static int test_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd, - struct label *shmfdlabel) + struct label *shmfdlabel, accmode_t accmode) { LABEL_CHECK(cred->cr_label, MAGIC_CRED); @@ -1390,6 +1423,30 @@ test_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd, return (0); } +COUNTER_DECL(posixshm_check_setmode); +static int +test_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd, + struct label *shmfdlabel, mode_t mode) +{ + + LABEL_CHECK(cred->cr_label, MAGIC_CRED); + LABEL_CHECK(shmfdlabel, MAGIC_POSIX_SHM); + COUNTER_INC(posixshm_check_setmode); + return (0); +} + +COUNTER_DECL(posixshm_check_setowner); +static int +test_posixshm_check_setowner(struct ucred *cred, struct shmfd *shmfd, + struct label *shmfdlabel, uid_t uid, gid_t gid) +{ + + LABEL_CHECK(cred->cr_label, MAGIC_CRED); + LABEL_CHECK(shmfdlabel, MAGIC_POSIX_SHM); + COUNTER_INC(posixshm_check_setowner); + return (0); +} + COUNTER_DECL(posixshm_check_stat); static int test_posixshm_check_stat(struct ucred *active_cred, @@ -3045,6 +3102,8 @@ static struct mac_policy_ops test_ops = .mpo_posixsem_check_getvalue = test_posixsem_check_getvalue, .mpo_posixsem_check_open = test_posixsem_check_open, .mpo_posixsem_check_post = test_posixsem_check_post, + .mpo_posixsem_check_setmode = test_posixsem_check_setmode, + .mpo_posixsem_check_setowner = test_posixsem_check_setowner, .mpo_posixsem_check_stat = test_posixsem_check_stat, .mpo_posixsem_check_unlink = test_posixsem_check_unlink, .mpo_posixsem_check_wait = test_posixsem_check_wait, @@ -3052,8 +3111,11 @@ static struct mac_policy_ops test_ops = .mpo_posixsem_destroy_label = test_posixsem_destroy_label, .mpo_posixsem_init_label = test_posixsem_init_label, + .mpo_posixshm_check_create = test_posixshm_check_create, .mpo_posixshm_check_mmap = test_posixshm_check_mmap, .mpo_posixshm_check_open = test_posixshm_check_open, + .mpo_posixshm_check_setmode = test_posixshm_check_setmode, + .mpo_posixshm_check_setowner = test_posixshm_check_setowner, .mpo_posixshm_check_stat = test_posixshm_check_stat, .mpo_posixshm_check_truncate = test_posixshm_check_truncate, .mpo_posixshm_check_unlink = test_posixshm_check_unlink, diff --git a/sys/sparc64/conf/GENERIC b/sys/sparc64/conf/GENERIC index 11c5d35f71a2d..fed0272734b61 100644 --- a/sys/sparc64/conf/GENERIC +++ b/sys/sparc64/conf/GENERIC @@ -40,7 +40,7 @@ options MD_ROOT # MD is a potential root device options NFSCL # New Network Filesystem Client options NFSD # New Network Filesystem Server options NFSLOCKD # Network Lock Manager -options NFS_ROOT # NFS usable as /, requires NFSCLIENT +options NFS_ROOT # NFS usable as /, requires NFSCL #options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) @@ -257,7 +257,7 @@ device udav # Davicom DM9601E USB device rum # Ralink Technology RT2501USB wireless NICs device uath # Atheros AR5523 wireless NICs device ural # Ralink Technology RT2500USB wireless NICs -device zyd # ZyDAS zb1211/zb1211b wireless NICs +device zyd # ZyDAS zd1211/zd1211b wireless NICs # FireWire support device firewire # FireWire bus code diff --git a/sys/sparc64/include/param.h b/sys/sparc64/include/param.h index af026b293f298..66bb304513060 100644 --- a/sys/sparc64/include/param.h +++ b/sys/sparc64/include/param.h @@ -50,7 +50,9 @@ #define MID_MACHINE MID_SPARC64 #if defined(SMP) || defined(KLD_MODULE) -#define MAXCPU 16 +#ifndef MAXCPU +#define MAXCPU 64 +#endif #else #define MAXCPU 1 #endif /* SMP || KLD_MODULE */ diff --git a/sys/sparc64/sbus/sbus.c b/sys/sparc64/sbus/sbus.c index 5cf7ad2ad3987..dbe38598265af 100644 --- a/sys/sparc64/sbus/sbus.c +++ b/sys/sparc64/sbus/sbus.c @@ -303,8 +303,8 @@ sbus_attach(device_t dev) sizeof(*range), (void **)&range)) == -1) { panic("%s: error getting ranges property", __func__); } - sc->sc_rd = (struct sbus_rd *)malloc(sizeof(*sc->sc_rd) * sc->sc_nrange, - M_DEVBUF, M_NOWAIT); + sc->sc_rd = malloc(sizeof(*sc->sc_rd) * sc->sc_nrange, M_DEVBUF, + M_NOWAIT | M_ZERO); if (sc->sc_rd == NULL) panic("%s: cannot allocate rmans", __func__); /* diff --git a/sys/sparc64/sparc64/dump_machdep.c b/sys/sparc64/sparc64/dump_machdep.c index b76d14b94c51d..d5409ac4f75a8 100644 --- a/sys/sparc64/sparc64/dump_machdep.c +++ b/sys/sparc64/sparc64/dump_machdep.c @@ -23,10 +23,11 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + #include <sys/param.h> #include <sys/systm.h> #include <sys/conf.h> @@ -92,6 +93,7 @@ buf_flush(struct dumperinfo *di) error = dump_write(di, buffer, 0, dumplo, DEV_BSIZE); dumplo += DEV_BSIZE; + fragsz = 0; return (error); } @@ -169,7 +171,8 @@ dumpsys(struct dumperinfo *di) /* Determine dump offset on device. */ dumplo = di->mediaoffset + di->mediasize - totsize; - mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_SPARC64_VERSION, size, di->blocksize); + mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_SPARC64_VERSION, size, + di->blocksize); printf("Dumping %lu MB (%d chunks)\n", (u_long)(size >> 20), nreg); diff --git a/sys/sparc64/sparc64/exception.S b/sys/sparc64/sparc64/exception.S index fa2f2d5cfd479..222ddeadd21b2 100644 --- a/sys/sparc64/sparc64/exception.S +++ b/sys/sparc64/sparc64/exception.S @@ -375,13 +375,13 @@ END(rsf_fatal) intrnames: .space IV_MAX * (MAXCOMLEN + 1) sintrnames: - .word IV_MAX * (MAXCOMLEN + 1) + .quad IV_MAX * (MAXCOMLEN + 1) .globl intrcnt, sintrcnt intrcnt: .space IV_MAX * 8 sintrcnt: - .word IV_MAX * 8 + .quad IV_MAX * 8 .text diff --git a/sys/sparc64/sparc64/mp_machdep.c b/sys/sparc64/sparc64/mp_machdep.c index e5910e06f5268..9923fccb01847 100644 --- a/sys/sparc64/sparc64/mp_machdep.c +++ b/sys/sparc64/sparc64/mp_machdep.c @@ -702,9 +702,6 @@ cheetah_ipi_selected(cpuset_t cpus, u_long d0, u_long d1, u_long d2) IDR_CHEETAH_ALL_BUSY) != 0) ; intr_restore(s); - if ((ids & - (IDR_CHEETAH_ALL_BUSY | IDR_CHEETAH_ALL_NACK)) == 0) - return; bnp = 0; for (cpu = 0; cpu < mp_ncpus; cpu++) { if (CPU_ISSET(cpu, &cpus)) { @@ -713,11 +710,6 @@ cheetah_ipi_selected(cpuset_t cpus, u_long d0, u_long d1, u_long d2) bnp++; } } - /* - * On at least Fire V880 we may receive IDR_NACKs for - * CPUs we actually haven't tried to send an IPI to, - * but which apparently can be safely ignored. - */ if (CPU_EMPTY(&cpus)) return; /* diff --git a/sys/sparc64/sparc64/pmap.c b/sys/sparc64/sparc64/pmap.c index 46c5050b2bd1d..209be106747ae 100644 --- a/sys/sparc64/sparc64/pmap.c +++ b/sys/sparc64/sparc64/pmap.c @@ -1340,9 +1340,9 @@ pmap_remove_tte(struct pmap *pm, struct pmap *pm2, struct tte *tp, if ((data & TD_W) != 0) vm_page_dirty(m); if ((data & TD_REF) != 0) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); if (TAILQ_EMPTY(&m->md.tte_list)) - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); pm->pm_stats.resident_count--; } pmap_cache_remove(m, va); @@ -1390,7 +1390,7 @@ pmap_remove_all(vm_page_t m) struct tte *tp; vm_offset_t va; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_all: page %p is not managed", m)); vm_page_lock_queues(); for (tp = TAILQ_FIRST(&m->md.tte_list); tp != NULL; tp = tpn) { @@ -1403,7 +1403,7 @@ pmap_remove_all(vm_page_t m) if ((tp->tte_data & TD_WIRED) != 0) pm->pm_stats.wired_count--; if ((tp->tte_data & TD_REF) != 0) - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); if ((tp->tte_data & TD_W) != 0) vm_page_dirty(m); tp->tte_data &= ~TD_V; @@ -1414,7 +1414,7 @@ pmap_remove_all(vm_page_t m) TTE_ZERO(tp); PMAP_UNLOCK(pm); } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } @@ -1498,13 +1498,13 @@ pmap_enter_locked(pmap_t pm, vm_offset_t va, vm_page_t m, vm_prot_t prot, { struct tte *tp; vm_paddr_t pa; + vm_page_t real; u_long data; - int i; mtx_assert(&vm_page_queue_mtx, MA_OWNED); PMAP_LOCK_ASSERT(pm, MA_OWNED); - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0 || - (m->oflags & VPO_BUSY) != 0 || VM_OBJECT_LOCKED(m->object), + KASSERT((m->oflags & (VPO_UNMANAGED | VPO_BUSY)) != 0 || + VM_OBJECT_LOCKED(m->object), ("pmap_enter_locked: page %p is not busy", m)); PMAP_STATS_INC(pmap_nenter); pa = VM_PAGE_TO_PHYS(m); @@ -1514,12 +1514,9 @@ pmap_enter_locked(pmap_t pm, vm_offset_t va, vm_page_t m, vm_prot_t prot, * physical memory, convert to the real backing page. */ if ((m->flags & PG_FICTITIOUS) != 0) { - for (i = 0; phys_avail[i + 1] != 0; i += 2) { - if (pa >= phys_avail[i] && pa <= phys_avail[i + 1]) { - m = PHYS_TO_VM_PAGE(pa); - break; - } - } + real = vm_phys_paddr_to_vm_page(pa); + if (real != NULL) + m = real; } CTR6(KTR_PMAP, @@ -1562,8 +1559,8 @@ pmap_enter_locked(pmap_t pm, vm_offset_t va, vm_page_t m, vm_prot_t prot, tp->tte_data |= TD_SW; if (wired) tp->tte_data |= TD_W; - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) - vm_page_flag_set(m, PG_WRITEABLE); + if ((m->oflags & VPO_UNMANAGED) == 0) + vm_page_aflag_set(m, PGA_WRITEABLE); } else if ((data & TD_W) != 0) vm_page_dirty(m); @@ -1603,8 +1600,8 @@ pmap_enter_locked(pmap_t pm, vm_offset_t va, vm_page_t m, vm_prot_t prot, data |= TD_P; if ((prot & VM_PROT_WRITE) != 0) { data |= TD_SW; - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) - vm_page_flag_set(m, PG_WRITEABLE); + if ((m->oflags & VPO_UNMANAGED) == 0) + vm_page_aflag_set(m, PGA_WRITEABLE); } if (prot & VM_PROT_EXECUTE) { data |= TD_EXEC; @@ -1945,7 +1942,7 @@ pmap_page_exists_quick(pmap_t pm, vm_page_t m) int loops; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_page_exists_quick: page %p is not managed", m)); loops = 0; rv = FALSE; @@ -1975,7 +1972,7 @@ pmap_page_wired_mappings(vm_page_t m) int count; count = 0; - if ((m->flags & PG_FICTITIOUS) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (count); vm_page_lock_queues(); TAILQ_FOREACH(tp, &m->md.tte_list, tte_link) @@ -2006,7 +2003,7 @@ pmap_page_is_mapped(vm_page_t m) boolean_t rv; rv = FALSE; - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0) + if ((m->oflags & VPO_UNMANAGED) != 0) return (rv); vm_page_lock_queues(); TAILQ_FOREACH(tp, &m->md.tte_list, tte_link) @@ -2037,7 +2034,7 @@ pmap_ts_referenced(vm_page_t m) u_long data; int count; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_ts_referenced: page %p is not managed", m)); count = 0; vm_page_lock_queues(); @@ -2064,18 +2061,18 @@ pmap_is_modified(vm_page_t m) struct tte *tp; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_modified: page %p is not managed", m)); rv = FALSE; /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be - * concurrently set while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be + * concurrently set while the object is locked. Thus, if PGA_WRITEABLE * is clear, no TTEs can have TD_W set. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return (rv); vm_page_lock_queues(); TAILQ_FOREACH(tp, &m->md.tte_list, tte_link) { @@ -2117,7 +2114,7 @@ pmap_is_referenced(vm_page_t m) struct tte *tp; boolean_t rv; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_referenced: page %p is not managed", m)); rv = FALSE; vm_page_lock_queues(); @@ -2139,18 +2136,18 @@ pmap_clear_modify(vm_page_t m) struct tte *tp; u_long data; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_modify: page %p is not managed", m)); VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); KASSERT((m->oflags & VPO_BUSY) == 0, ("pmap_clear_modify: page %p is busy", m)); /* - * If the page is not PG_WRITEABLE, then no TTEs can have TD_W set. + * If the page is not PGA_WRITEABLE, then no TTEs can have TD_W set. * If the object containing the page is locked and the page is not - * VPO_BUSY, then PG_WRITEABLE cannot be concurrently set. + * VPO_BUSY, then PGA_WRITEABLE cannot be concurrently set. */ - if ((m->flags & PG_WRITEABLE) == 0) + if ((m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); TAILQ_FOREACH(tp, &m->md.tte_list, tte_link) { @@ -2169,7 +2166,7 @@ pmap_clear_reference(vm_page_t m) struct tte *tp; u_long data; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_reference: page %p is not managed", m)); vm_page_lock_queues(); TAILQ_FOREACH(tp, &m->md.tte_list, tte_link) { @@ -2188,17 +2185,17 @@ pmap_remove_write(vm_page_t m) struct tte *tp; u_long data; - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_write: page %p is not managed", m)); /* - * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be set by - * another thread while the object is locked. Thus, if PG_WRITEABLE + * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be set by + * another thread while the object is locked. Thus, if PGA_WRITEABLE * is clear, no page table entries need updating. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((m->oflags & VPO_BUSY) == 0 && - (m->flags & PG_WRITEABLE) == 0) + (m->aflags & PGA_WRITEABLE) == 0) return; vm_page_lock_queues(); TAILQ_FOREACH(tp, &m->md.tte_list, tte_link) { @@ -2210,7 +2207,7 @@ pmap_remove_write(vm_page_t m) tlb_page_demap(TTE_GET_PMAP(tp), TTE_GET_VA(tp)); } } - vm_page_flag_clear(m, PG_WRITEABLE); + vm_page_aflag_clear(m, PGA_WRITEABLE); vm_page_unlock_queues(); } diff --git a/sys/sparc64/sparc64/trap.c b/sys/sparc64/sparc64/trap.c index db05f06ba9264..7037e462ad0e9 100644 --- a/sys/sparc64/sparc64/trap.c +++ b/sys/sparc64/sparc64/trap.c @@ -606,6 +606,8 @@ cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) return (error); } +#include "../../kern/subr_syscall.c" + /* * Syscall handler * The arguments to the syscall are passed in the out registers by the caller, diff --git a/sys/sparc64/sparc64/tsb.c b/sys/sparc64/sparc64/tsb.c index 3130791e4d5aa..0f342596dd04a 100644 --- a/sys/sparc64/sparc64/tsb.c +++ b/sys/sparc64/sparc64/tsb.c @@ -173,7 +173,7 @@ tsb_tte_enter(pmap_t pm, vm_page_t m, vm_offset_t va, u_long sz, u_long data) enter: if ((m->flags & PG_FICTITIOUS) == 0) { data |= TD_CP; - if ((m->flags & PG_UNMANAGED) == 0) { + if ((m->oflags & VPO_UNMANAGED) == 0) { pm->pm_stats.resident_count++; data |= TD_PV; } diff --git a/sys/sys/buf.h b/sys/sys/buf.h index f57d6edb7e497..972b05379fa54 100644 --- a/sys/sys/buf.h +++ b/sys/sys/buf.h @@ -311,6 +311,12 @@ extern const char *buf_wmesg; /* Default buffer lock message */ lockdestroy(&(bp)->b_lock) /* + * Print informations on a buffer lock. + */ +#define BUF_LOCKPRINTINFO(bp) \ + lockmgr_printinfo(&(bp)->b_lock) + +/* * Buffer lock assertions. */ #if defined(INVARIANTS) && defined(INVARIANT_SUPPORT) diff --git a/sys/sys/bus.h b/sys/sys/bus.h index 09b8911eabecf..5dc92dfe07c68 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -596,7 +596,8 @@ struct driver_module_data { int dmd_pass; }; -#define EARLY_DRIVER_MODULE(name, busname, driver, devclass, evh, arg, pass) \ +#define EARLY_DRIVER_MODULE_ORDERED(name, busname, driver, devclass, \ + evh, arg, order, pass) \ \ static struct driver_module_data name##_##busname##_driver_mod = { \ evh, arg, \ @@ -612,7 +613,16 @@ static moduledata_t name##_##busname##_mod = { \ &name##_##busname##_driver_mod \ }; \ DECLARE_MODULE(name##_##busname, name##_##busname##_mod, \ - SI_SUB_DRIVERS, SI_ORDER_MIDDLE) + SI_SUB_DRIVERS, order) + +#define EARLY_DRIVER_MODULE(name, busname, driver, devclass, evh, arg, pass) \ + EARLY_DRIVER_MODULE_ORDERED(name, busname, driver, devclass, \ + evh, arg, SI_ORDER_MIDDLE, pass) + +#define DRIVER_MODULE_ORDERED(name, busname, driver, devclass, evh, arg,\ + order) \ + EARLY_DRIVER_MODULE_ORDERED(name, busname, driver, devclass, \ + evh, arg, order, BUS_PASS_DEFAULT) #define DRIVER_MODULE(name, busname, driver, devclass, evh, arg) \ EARLY_DRIVER_MODULE(name, busname, driver, devclass, evh, arg, \ diff --git a/sys/sys/capability.h b/sys/sys/capability.h index dee2e7a6a5117..81446a2819047 100644 --- a/sys/sys/capability.h +++ b/sys/sys/capability.h @@ -53,11 +53,91 @@ * mmap() and aio*() system calls will need special attention as they may * involve reads or writes depending a great deal on context. */ + +/* General file I/O. */ #define CAP_READ 0x0000000000000001ULL /* read/recv */ #define CAP_WRITE 0x0000000000000002ULL /* write/send */ #define CAP_MMAP 0x0000000000000004ULL /* mmap */ #define CAP_MAPEXEC 0x0000000000000008ULL /* mmap(2) as exec */ -#define CAP_MASK_VALID 0x000000000000000fULL +#define CAP_FEXECVE 0x0000000000000010ULL +#define CAP_FSYNC 0x0000000000000020ULL +#define CAP_FTRUNCATE 0x0000000000000040ULL +#define CAP_SEEK 0x0000000000000080ULL + +/* VFS methods. */ +#define CAP_FCHFLAGS 0x0000000000000100ULL +#define CAP_FCHDIR 0x0000000000000200ULL +#define CAP_FCHMOD 0x0000000000000400ULL +#define CAP_FCHOWN 0x0000000000000800ULL +#define CAP_FCNTL 0x0000000000001000ULL +#define CAP_FPATHCONF 0x0000000000002000ULL +#define CAP_FLOCK 0x0000000000004000ULL +#define CAP_FSCK 0x0000000000008000ULL +#define CAP_FSTAT 0x0000000000010000ULL +#define CAP_FSTATFS 0x0000000000020000ULL +#define CAP_FUTIMES 0x0000000000040000ULL +#define CAP_CREATE 0x0000000000080000ULL +#define CAP_DELETE 0x0000000000100000ULL +#define CAP_MKDIR 0x0000000000200000ULL +#define CAP_RMDIR 0x0000000000400000ULL +#define CAP_MKFIFO 0x0000000000800000ULL + +/* Lookups - used to constrain *at() calls. */ +#define CAP_LOOKUP 0x0000000001000000ULL + +/* Extended attributes. */ +#define CAP_EXTATTR_DELETE 0x0000000002000000ULL +#define CAP_EXTATTR_GET 0x0000000004000000ULL +#define CAP_EXTATTR_LIST 0x0000000008000000ULL +#define CAP_EXTATTR_SET 0x0000000010000000ULL + +/* Access Control Lists. */ +#define CAP_ACL_CHECK 0x0000000020000000ULL +#define CAP_ACL_DELETE 0x0000000040000000ULL +#define CAP_ACL_GET 0x0000000080000000ULL +#define CAP_ACL_SET 0x0000000100000000ULL + +/* Socket operations. */ +#define CAP_ACCEPT 0x0000000200000000ULL +#define CAP_BIND 0x0000000400000000ULL +#define CAP_CONNECT 0x0000000800000000ULL +#define CAP_GETPEERNAME 0x0000001000000000ULL +#define CAP_GETSOCKNAME 0x0000002000000000ULL +#define CAP_GETSOCKOPT 0x0000004000000000ULL +#define CAP_LISTEN 0x0000008000000000ULL +#define CAP_PEELOFF 0x0000010000000000ULL +#define CAP_SETSOCKOPT 0x0000020000000000ULL +#define CAP_SHUTDOWN 0x0000040000000000ULL + +#define CAP_SOCK_ALL \ + (CAP_ACCEPT | CAP_BIND | CAP_CONNECT \ + | CAP_GETPEERNAME | CAP_GETSOCKNAME | CAP_GETSOCKOPT \ + | CAP_LISTEN | CAP_PEELOFF | CAP_SETSOCKOPT | CAP_SHUTDOWN) + +/* Mandatory Access Control. */ +#define CAP_MAC_GET 0x0000080000000000ULL +#define CAP_MAC_SET 0x0000100000000000ULL + +/* Methods on semaphores. */ +#define CAP_SEM_GETVALUE 0x0000200000000000ULL +#define CAP_SEM_POST 0x0000400000000000ULL +#define CAP_SEM_WAIT 0x0000800000000000ULL + +/* kqueue events. */ +#define CAP_POLL_EVENT 0x0001000000000000ULL +#define CAP_POST_EVENT 0x0002000000000000ULL + +/* Strange and powerful rights that should not be given lightly. */ +#define CAP_IOCTL 0x0004000000000000ULL +#define CAP_TTYHOOK 0x0008000000000000ULL + +/* Process management via process descriptors. */ +#define CAP_PDGETPID 0x0010000000000000ULL +#define CAP_PDWAIT 0x0020000000000000ULL +#define CAP_PDKILL 0x0040000000000000ULL + +/* The mask of all valid method rights. */ +#define CAP_MASK_VALID 0x007fffffffffffffULL #ifdef _KERNEL @@ -67,7 +147,7 @@ * Create a capability to wrap a file object. */ int kern_capwrap(struct thread *td, struct file *fp, cap_rights_t rights, - struct file **cap, int *capfd); + int *capfd); /* * Unwrap a capability if its rights mask is a superset of 'rights'. diff --git a/sys/sys/file.h b/sys/sys/file.h index eea2c0091f658..57e7047e8b326 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -65,6 +65,7 @@ struct socket; #define DTYPE_PTS 10 /* pseudo teletype master device */ #define DTYPE_DEV 11 /* Device specific fd type */ #define DTYPE_CAPABILITY 12 /* capability */ +#define DTYPE_PROCDESC 13 /* process descriptor */ #ifdef _KERNEL @@ -85,6 +86,10 @@ typedef int fo_kqfilter_t(struct file *fp, struct knote *kn); typedef int fo_stat_t(struct file *fp, struct stat *sb, struct ucred *active_cred, struct thread *td); typedef int fo_close_t(struct file *fp, struct thread *td); +typedef int fo_chmod_t(struct file *fp, mode_t mode, + struct ucred *active_cred, struct thread *td); +typedef int fo_chown_t(struct file *fp, uid_t uid, gid_t gid, + struct ucred *active_cred, struct thread *td); typedef int fo_flags_t; struct fileops { @@ -96,6 +101,8 @@ struct fileops { fo_kqfilter_t *fo_kqfilter; fo_stat_t *fo_stat; fo_close_t *fo_close; + fo_chmod_t *fo_chmod; + fo_chown_t *fo_chown; fo_flags_t fo_flags; /* DFLAG_* below */ }; @@ -176,9 +183,13 @@ extern int maxfiles; /* kernel limit on number of open files */ extern int maxfilesperproc; /* per process limit on number of open files */ extern volatile int openfiles; /* actual number of open files */ -int fget(struct thread *td, int fd, struct file **fpp); -int fget_read(struct thread *td, int fd, struct file **fpp); -int fget_write(struct thread *td, int fd, struct file **fpp); +int fget(struct thread *td, int fd, cap_rights_t rights, struct file **fpp); +int fget_mmap(struct thread *td, int fd, cap_rights_t rights, + u_char *maxprotp, struct file **fpp); +int fget_read(struct thread *td, int fd, cap_rights_t rights, + struct file **fpp); +int fget_write(struct thread *td, int fd, cap_rights_t rights, + struct file **fpp); int fgetcap(struct thread *td, int fd, struct file **fpp); int _fdrop(struct file *fp, struct thread *td); @@ -196,12 +207,20 @@ fo_kqfilter_t soo_kqfilter; fo_stat_t soo_stat; fo_close_t soo_close; +fo_chmod_t invfo_chmod; +fo_chown_t invfo_chown; + void finit(struct file *, u_int, short, void *, struct fileops *); -int fgetvp(struct thread *td, int fd, struct vnode **vpp); -int fgetvp_read(struct thread *td, int fd, struct vnode **vpp); -int fgetvp_write(struct thread *td, int fd, struct vnode **vpp); +int fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp); +int fgetvp_rights(struct thread *td, int fd, cap_rights_t need, + cap_rights_t *have, struct vnode **vpp); +int fgetvp_read(struct thread *td, int fd, cap_rights_t rights, + struct vnode **vpp); +int fgetvp_write(struct thread *td, int fd, cap_rights_t rights, + struct vnode **vpp); -int fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp); +int fgetsock(struct thread *td, int fd, cap_rights_t rights, + struct socket **spp, u_int *fflagp); void fputsock(struct socket *sp); static __inline int @@ -224,6 +243,8 @@ static __inline fo_poll_t fo_poll; static __inline fo_kqfilter_t fo_kqfilter; static __inline fo_stat_t fo_stat; static __inline fo_close_t fo_close; +static __inline fo_chmod_t fo_chmod; +static __inline fo_chown_t fo_chown; static __inline int fo_read(struct file *fp, struct uio *uio, struct ucred *active_cred, @@ -287,6 +308,22 @@ fo_kqfilter(struct file *fp, struct knote *kn) return ((*fp->f_ops->fo_kqfilter)(fp, kn)); } +static __inline int +fo_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, + struct thread *td) +{ + + return ((*fp->f_ops->fo_chmod)(fp, mode, active_cred, td)); +} + +static __inline int +fo_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, + struct thread *td) +{ + + return ((*fp->f_ops->fo_chown)(fp, uid, gid, active_cred, td)); +} + #endif /* _KERNEL */ #endif /* !SYS_FILE_H */ diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index 2dab7416b6e08..1b87bab201d8e 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -128,7 +128,8 @@ struct filedesc *fdshare(struct filedesc *fdp); struct filedesc_to_leader * filedesc_to_leader_alloc(struct filedesc_to_leader *old, struct filedesc *fdp, struct proc *leader); -int getvnode(struct filedesc *fdp, int fd, struct file **fpp); +int getvnode(struct filedesc *fdp, int fd, cap_rights_t rights, + struct file **fpp); void mountcheckdirs(struct vnode *olddp, struct vnode *newdp); void setugidsafety(struct thread *td); diff --git a/sys/sys/kdb.h b/sys/sys/kdb.h index 2982e03c75f13..61ee0973eb146 100644 --- a/sys/sys/kdb.h +++ b/sys/sys/kdb.h @@ -64,6 +64,8 @@ extern struct pcb *kdb_thrctx; /* Current context. */ extern struct thread *kdb_thread; /* Current thread. */ int kdb_alt_break(int, int *); +int kdb_alt_break_gdb(int, int *); +int kdb_break(void); void kdb_backtrace(void); int kdb_dbbe_select(const char *); void kdb_enter(const char *, const char *); diff --git a/sys/sys/mount.h b/sys/sys/mount.h index d6366071b91ae..ecaf7b888b077 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -166,8 +166,7 @@ struct mount { int mnt_nvnodelistsize; /* (i) # of vnodes */ int mnt_writeopcount; /* (i) write syscalls pending */ int mnt_kern_flag; /* (i) kernel only flags */ - u_int mnt_flag; /* (i) flags shared with user */ - u_int mnt_xflag; /* (i) more flags shared with user */ + uint64_t mnt_flag; /* (i) flags shared with user */ u_int mnt_noasync; /* (i) # noasync overrides */ struct vfsoptlist *mnt_opt; /* current mount options */ struct vfsoptlist *mnt_optnew; /* new options passed to fs */ @@ -224,43 +223,44 @@ void __mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp); /* * User specifiable flags, stored in mnt_flag. */ -#define MNT_RDONLY 0x00000001 /* read only filesystem */ -#define MNT_SYNCHRONOUS 0x00000002 /* filesystem written synchronously */ -#define MNT_NOEXEC 0x00000004 /* can't exec from filesystem */ -#define MNT_NOSUID 0x00000008 /* don't honor setuid bits on fs */ -#define MNT_UNION 0x00000020 /* union with underlying filesystem */ -#define MNT_ASYNC 0x00000040 /* filesystem written asynchronously */ -#define MNT_SUIDDIR 0x00100000 /* special handling of SUID on dirs */ -#define MNT_SOFTDEP 0x00200000 /* soft updates being done */ -#define MNT_NOSYMFOLLOW 0x00400000 /* do not follow symlinks */ -#define MNT_GJOURNAL 0x02000000 /* GEOM journal support enabled */ -#define MNT_MULTILABEL 0x04000000 /* MAC support for individual objects */ -#define MNT_ACLS 0x08000000 /* ACL support enabled */ -#define MNT_NOATIME 0x10000000 /* disable update of file access time */ -#define MNT_NOCLUSTERR 0x40000000 /* disable cluster read */ -#define MNT_NOCLUSTERW 0x80000000 /* disable cluster write */ -#define MNT_NFS4ACLS 0x00000010 +#define MNT_RDONLY 0x0000000000000001ULL /* read only filesystem */ +#define MNT_SYNCHRONOUS 0x0000000000000002ULL /* fs written synchronously */ +#define MNT_NOEXEC 0x0000000000000004ULL /* can't exec from filesystem */ +#define MNT_NOSUID 0x0000000000000008ULL /* don't honor setuid fs bits */ +#define MNT_NFS4ACLS 0x0000000000000010ULL /* enable NFS version 4 ACLs */ +#define MNT_UNION 0x0000000000000020ULL /* union with underlying fs */ +#define MNT_ASYNC 0x0000000000000040ULL /* fs written asynchronously */ +#define MNT_SUIDDIR 0x0000000000100000ULL /* special SUID dir handling */ +#define MNT_SOFTDEP 0x0000000000200000ULL /* using soft updates */ +#define MNT_NOSYMFOLLOW 0x0000000000400000ULL /* do not follow symlinks */ +#define MNT_GJOURNAL 0x0000000002000000ULL /* GEOM journal support enabled */ +#define MNT_MULTILABEL 0x0000000004000000ULL /* MAC support for objects */ +#define MNT_ACLS 0x0000000008000000ULL /* ACL support enabled */ +#define MNT_NOATIME 0x0000000010000000ULL /* dont update file access time */ +#define MNT_NOCLUSTERR 0x0000000040000000ULL /* disable cluster read */ +#define MNT_NOCLUSTERW 0x0000000080000000ULL /* disable cluster write */ +#define MNT_SUJ 0x0000000100000000ULL /* using journaled soft updates */ /* * NFS export related mount flags. */ -#define MNT_EXRDONLY 0x00000080 /* exported read only */ -#define MNT_EXPORTED 0x00000100 /* filesystem is exported */ -#define MNT_DEFEXPORTED 0x00000200 /* exported to the world */ -#define MNT_EXPORTANON 0x00000400 /* use anon uid mapping for everyone */ -#define MNT_EXKERB 0x00000800 /* exported with Kerberos uid mapping */ -#define MNT_EXPUBLIC 0x20000000 /* public export (WebNFS) */ +#define MNT_EXRDONLY 0x0000000000000080ULL /* exported read only */ +#define MNT_EXPORTED 0x0000000000000100ULL /* filesystem is exported */ +#define MNT_DEFEXPORTED 0x0000000000000200ULL /* exported to the world */ +#define MNT_EXPORTANON 0x0000000000000400ULL /* anon uid mapping for all */ +#define MNT_EXKERB 0x0000000000000800ULL /* exported with Kerberos */ +#define MNT_EXPUBLIC 0x0000000020000000ULL /* public export (WebNFS) */ /* * Flags set by internal operations, * but visible to the user. * XXX some of these are not quite right.. (I've never seen the root flag set) */ -#define MNT_LOCAL 0x00001000 /* filesystem is stored locally */ -#define MNT_QUOTA 0x00002000 /* quotas are enabled on filesystem */ -#define MNT_ROOTFS 0x00004000 /* identifies the root filesystem */ -#define MNT_USER 0x00008000 /* mounted by a user */ -#define MNT_IGNORE 0x00800000 /* do not show entry in df */ +#define MNT_LOCAL 0x0000000000001000ULL /* filesystem is stored locally */ +#define MNT_QUOTA 0x0000000000002000ULL /* quotas are enabled on fs */ +#define MNT_ROOTFS 0x0000000000004000ULL /* identifies the root fs */ +#define MNT_USER 0x0000000000008000ULL /* mounted by a user */ +#define MNT_IGNORE 0x0000000000800000ULL /* do not show entry in df */ /* * Mask of flags that are visible to statfs(). @@ -268,7 +268,7 @@ void __mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp); * but the 'mount' program may need changing to handle this. */ #define MNT_VISFLAGMASK (MNT_RDONLY | MNT_SYNCHRONOUS | MNT_NOEXEC | \ - MNT_NOSUID | MNT_UNION | \ + MNT_NOSUID | MNT_UNION | MNT_SUJ | \ MNT_ASYNC | MNT_EXRDONLY | MNT_EXPORTED | \ MNT_DEFEXPORTED | MNT_EXPORTANON| MNT_EXKERB | \ MNT_LOCAL | MNT_USER | MNT_QUOTA | \ @@ -293,12 +293,12 @@ void __mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp); * XXX: MNT_BYFSID collides with MNT_ACLS, but because MNT_ACLS is only used for * mount(2) and MNT_BYFSID is only used for unmount(2) it's harmless. */ -#define MNT_UPDATE 0x00010000 /* not a real mount, just an update */ -#define MNT_DELEXPORT 0x00020000 /* delete export host lists */ -#define MNT_RELOAD 0x00040000 /* reload filesystem data */ -#define MNT_FORCE 0x00080000 /* force unmount or readonly change */ -#define MNT_SNAPSHOT 0x01000000 /* snapshot the filesystem */ -#define MNT_BYFSID 0x08000000 /* specify filesystem by ID. */ +#define MNT_UPDATE 0x0000000000010000ULL /* not real mount, just update */ +#define MNT_DELEXPORT 0x0000000000020000ULL /* delete export host lists */ +#define MNT_RELOAD 0x0000000000040000ULL /* reload filesystem data */ +#define MNT_FORCE 0x0000000000080000ULL /* force unmount or readonly */ +#define MNT_SNAPSHOT 0x0000000001000000ULL /* snapshot the filesystem */ +#define MNT_BYFSID 0x0000000008000000ULL /* specify filesystem by ID. */ #define MNT_CMDFLAGS (MNT_UPDATE | MNT_DELEXPORT | MNT_RELOAD | \ MNT_FORCE | MNT_SNAPSHOT | MNT_BYFSID) /* @@ -325,7 +325,6 @@ void __mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp); #define MNTK_REFEXPIRE 0x00000020 /* refcount expiring is happening */ #define MNTK_EXTENDED_SHARED 0x00000040 /* Allow shared locking for more ops */ #define MNTK_SHARED_WRITES 0x00000080 /* Allow shared locking for writes */ -#define MNTK_SUJ 0x00000100 /* Softdep journaling enabled */ #define MNTK_UNMOUNT 0x01000000 /* unmount in progress */ #define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */ #define MNTK_SUSPEND 0x08000000 /* request write suspension */ @@ -715,7 +714,8 @@ void vfs_event_signal(fsid_t *, u_int32_t, intptr_t); void vfs_freeopts(struct vfsoptlist *opts); void vfs_deleteopt(struct vfsoptlist *opts, const char *name); int vfs_buildopts(struct uio *auio, struct vfsoptlist **options); -int vfs_flagopt(struct vfsoptlist *opts, const char *name, u_int *w, u_int val); +int vfs_flagopt(struct vfsoptlist *opts, const char *name, uint64_t *w, + uint64_t val); int vfs_getopt(struct vfsoptlist *, const char *, void **, int *); int vfs_getopt_pos(struct vfsoptlist *opts, const char *name); char *vfs_getopts(struct vfsoptlist *, const char *, int *error); diff --git a/sys/sys/namei.h b/sys/sys/namei.h index 716b38d49f6cb..c68a7f7e0ba1d 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -63,6 +63,7 @@ struct nameidata { */ const char *ni_dirp; /* pathname pointer */ enum uio_seg ni_segflg; /* location of pathname */ + cap_rights_t ni_rightsneeded; /* rights required to look up vnode */ /* * Arguments to lookup. */ @@ -70,6 +71,11 @@ struct nameidata { struct vnode *ni_rootdir; /* logical root directory */ struct vnode *ni_topdir; /* logical top directory */ int ni_dirfd; /* starting directory for *at functions */ + int ni_strictrelative; /* relative lookup only; no '..' */ + /* + * Results: returned from namei + */ + cap_rights_t ni_baserights; /* rights the *at base has (or -1) */ /* * Results: returned from/manipulated by lookup */ @@ -151,11 +157,13 @@ struct nameidata { * Initialization of a nameidata structure. */ #define NDINIT(ndp, op, flags, segflg, namep, td) \ - NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, NULL, td) + NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, NULL, 0, td) #define NDINIT_AT(ndp, op, flags, segflg, namep, dirfd, td) \ - NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, td) + NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, 0, td) +#define NDINIT_ATRIGHTS(ndp, op, flags, segflg, namep, dirfd, rights, td) \ + NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, rights, td) #define NDINIT_ATVP(ndp, op, flags, segflg, namep, vp, td) \ - NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, vp, td) + NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, vp, 0, td) static __inline void NDINIT_ALL(struct nameidata *ndp, @@ -164,6 +172,7 @@ NDINIT_ALL(struct nameidata *ndp, const char *namep, int dirfd, struct vnode *startdir, + cap_rights_t rights, struct thread *td) { ndp->ni_cnd.cn_nameiop = op; @@ -172,6 +181,9 @@ NDINIT_ALL(struct nameidata *ndp, ndp->ni_dirp = namep; ndp->ni_dirfd = dirfd; ndp->ni_startdir = startdir; + ndp->ni_strictrelative = 0; + ndp->ni_rightsneeded = rights; + ndp->ni_baserights = 0; ndp->ni_cnd.cn_thread = td; } diff --git a/sys/sys/param.h b/sys/sys/param.h index 4f54eaca13a8d..0db0223e36633 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 900039 /* Master, propagated to newvers */ +#define __FreeBSD_version 900044 /* Master, propagated to newvers */ #ifdef _KERNEL #define P_OSREL_SIGSEGV 700004 diff --git a/sys/sys/pcpu.h b/sys/sys/pcpu.h index b25fcc89cb065..4a4ec005c0fd2 100644 --- a/sys/sys/pcpu.h +++ b/sys/sys/pcpu.h @@ -146,8 +146,6 @@ struct rm_queue { struct rm_queue* volatile rmq_prev; }; -#define PCPU_NAME_LEN (sizeof("CPU ") + sizeof(__XSTRING(MAXCPU)) - 1) - /* * This structure maps out the global data that needs to be kept on a * per-cpu basis. The members are accessed via the PCPU_GET/SET/PTR @@ -165,9 +163,6 @@ struct pcpu { u_int pc_cpuid; /* This cpu number */ STAILQ_ENTRY(pcpu) pc_allcpu; struct lock_list_entry *pc_spinlocks; -#ifdef KTR - char pc_name[PCPU_NAME_LEN]; /* String name for KTR */ -#endif struct vmmeter pc_cnt; /* VM stats counters */ long pc_cp_time[CPUSTATES]; /* statclock ticks */ struct device *pc_device; @@ -203,7 +198,7 @@ struct pcpu { STAILQ_HEAD(cpuhead, pcpu); extern struct cpuhead cpuhead; -extern struct pcpu *cpuid_to_pcpu[MAXCPU]; +extern struct pcpu *cpuid_to_pcpu[]; #define curcpu PCPU_GET(cpuid) #define curproc (curthread->td_proc) diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 233efe9856406..fb9791303ddc1 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -166,6 +166,7 @@ struct mqueue_notifier; struct nlminfo; struct p_sched; struct proc; +struct procdesc; struct racct; struct sleepqueue; struct td_sched; @@ -534,6 +535,7 @@ struct proc { int p_boundary_count;/* (c) Num threads at user boundary */ int p_pendingcnt; /* how many signals are pending */ struct itimers *p_itimers; /* (c) POSIX interval timers. */ + struct procdesc *p_procdesc; /* (e) Process descriptor, if any. */ /* End area that is zeroed on creation. */ #define p_endzero p_magic @@ -822,7 +824,7 @@ int enterpgrp(struct proc *p, pid_t pgid, struct pgrp *pgrp, int enterthispgrp(struct proc *p, struct pgrp *pgrp); void faultin(struct proc *p); void fixjobc(struct proc *p, struct pgrp *pgrp, int entering); -int fork1(struct thread *, int, int, struct proc **); +int fork1(struct thread *, int, int, struct proc **, int *, int); void fork_exit(void (*)(void *, struct trapframe *), void *, struct trapframe *); void fork_return(struct thread *, struct trapframe *); @@ -844,6 +846,8 @@ void pargs_hold(struct pargs *pa); void procinit(void); void proc_linkup0(struct proc *p, struct thread *td); void proc_linkup(struct proc *p, struct thread *td); +void proc_reap(struct thread *td, struct proc *p, int *status, int options, + struct rusage *rusage); void proc_reparent(struct proc *child, struct proc *newparent); struct pstats *pstats_alloc(void); void pstats_fork(struct pstats *src, struct pstats *dst); @@ -869,9 +873,6 @@ void cpu_switch(struct thread *, struct thread *, struct mtx *); void cpu_throw(struct thread *, struct thread *) __dead2; void unsleep(struct thread *); void userret(struct thread *, struct trapframe *); -struct syscall_args; -int syscallenter(struct thread *, struct syscall_args *); -void syscallret(struct thread *, int, struct syscall_args *); void cpu_exit(struct thread *); void exit1(struct thread *, int) __dead2; diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h new file mode 100644 index 0000000000000..cc8b7166f6394 --- /dev/null +++ b/sys/sys/procdesc.h @@ -0,0 +1,119 @@ +/*- + * Copyright (c) 2009 Robert N. M. Watson + * All rights reserved. + * + * This software was developed at the University of Cambridge Computer + * Laboratory with support from a grant from Google, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_PROCDESC_H_ +#define _SYS_PROCDESC_H_ + +#ifdef _KERNEL +#include <sys/selinfo.h> /* struct selinfo */ +#include <sys/_lock.h> +#include <sys/_mutex.h> + +/*- + * struct procdesc describes a process descriptor, and essentially consists + * of two pointers -- one to the file descriptor, and one to the process. + * When both become NULL, the process descriptor will be freed. An important + * invariant is that there is only ever one process descriptor for a process, + * so a single file pointer will suffice. + * + * Locking key: + * (c) - Constant after initial setup. + * (p) - Protected by the process descriptor mutex. + * (r) - Atomic eference count. + * (s) - Protected by selinfo. + * (t) - Protected by the proctree_lock + */ +struct proc; +struct sigio; +struct procdesc { + /* + * Basic process descriptor state: the process, a cache of its pid to + * satisfy queries after the process exits, and process descriptor + * refcount. + */ + struct proc *pd_proc; /* (t) Process. */ + pid_t pd_pid; /* (c) Cached pid. */ + u_int pd_refcount; /* (r) Reference count. */ + + /* + * In-flight data and notification of events. + */ + int pd_flags; /* (p) PD_ flags. */ + struct selinfo pd_selinfo; /* (p) Event notification. */ + struct mtx pd_lock; /* Protect data + events. */ +}; + +/* + * Locking macros for the procdesc itself. + */ +#define PROCDESC_LOCK_DESTROY(pd) mtx_destroy(&(pd)->pd_lock) +#define PROCDESC_LOCK_INIT(pd) mtx_init(&(pd)->pd_lock, "procdesc", NULL, \ + MTX_DEF) +#define PROCDESC_LOCK(pd) mtx_lock(&(pd)->pd_lock) +#define PROCDESC_UNLOCK(pd) mtx_unlock(&(pd)->pd_lock) + +/* + * Flags for the pd_flags field. + */ +#define PDF_CLOSED 0x00000001 /* Descriptor has closed. */ +#define PDF_SELECTED 0x00000002 /* Issue selwakeup(). */ +#define PDF_EXITED 0x00000004 /* Process exited. */ +#define PDF_DAEMON 0x00000008 /* Don't exit when procdesc closes. */ + +/* + * In-kernel interfaces to process descriptors. + */ +int procdesc_exit(struct proc *); +int procdesc_find(struct thread *, int fd, cap_rights_t, struct proc **); +int kern_pdgetpid(struct thread *, int fd, cap_rights_t, pid_t *pidp); +void procdesc_new(struct proc *, int); +void procdesc_finit(struct procdesc *, struct file *); +pid_t procdesc_pid(struct file *); +void procdesc_reap(struct proc *); + +#else /* !_KERNEL */ + +/* + * Process descriptor system calls. + */ +struct rusage; +int pdfork(int *, int); +int pdkill(int, int); +int pdgetpid(int, pid_t *); + +#endif /* _KERNEL */ + +/* + * Flags which can be passed to pdfork(2). + */ +#define PD_DAEMON 0x00000001 /* Don't exit when procdesc closes. */ + +#endif /* !_SYS_PROCDESC_H_ */ diff --git a/sys/sys/resourcevar.h b/sys/sys/resourcevar.h index f17d95f644d05..d091d85e8bfc9 100644 --- a/sys/sys/resourcevar.h +++ b/sys/sys/resourcevar.h @@ -136,6 +136,7 @@ void rucollect(struct rusage *ru, struct rusage *ru2); void rufetch(struct proc *p, struct rusage *ru); void rufetchcalc(struct proc *p, struct rusage *ru, struct timeval *up, struct timeval *sp); +void rufetchtd(struct thread *td, struct rusage *ru); void ruxagg(struct proc *p, struct thread *td); int suswintr(void *base, int word); struct uidinfo diff --git a/sys/sys/selinfo.h b/sys/sys/selinfo.h index 2d2f8485e7724..590d184ad17c1 100644 --- a/sys/sys/selinfo.h +++ b/sys/sys/selinfo.h @@ -51,6 +51,7 @@ struct selinfo { #define SEL_WAITING(si) (!TAILQ_EMPTY(&(si)->si_tdlist)) #ifdef _KERNEL +void seldrain(struct selinfo *sip); void selrecord(struct thread *selector, struct selinfo *sip); void selwakeup(struct selinfo *sip); void selwakeuppri(struct selinfo *sip, int pri); diff --git a/sys/sys/sockbuf.h b/sys/sys/sockbuf.h index b8e6699902890..bfccd74f6f7a1 100644 --- a/sys/sys/sockbuf.h +++ b/sys/sys/sockbuf.h @@ -37,7 +37,7 @@ #include <sys/_mutex.h> #include <sys/_sx.h> -#define SB_MAX (256*1024) /* default for max chars in sockbuf */ +#define SB_MAX (2*1024*1024) /* default for max chars in sockbuf */ /* * Constants for sb_flags field of struct sockbuf. diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index fa4f46f3aceee..31252c1d1215f 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD + * created from FreeBSD: head/sys/kern/syscalls.master 224987 2011-08-18 22:51:30Z jonathan */ #define SYS_syscall 0 @@ -434,6 +434,9 @@ #define SYS_cap_getrights 515 #define SYS_cap_enter 516 #define SYS_cap_getmode 517 +#define SYS_pdfork 518 +#define SYS_pdkill 519 +#define SYS_pdgetpid 520 #define SYS_pselect 522 #define SYS_getloginclass 523 #define SYS_setloginclass 524 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk index 544bbf41e05d7..e448707c53f7f 100644 --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -1,7 +1,7 @@ # FreeBSD system call names. # DO NOT EDIT-- this file is automatically generated. # $FreeBSD$ -# created from FreeBSD +# created from FreeBSD: head/sys/kern/syscalls.master 224987 2011-08-18 22:51:30Z jonathan MIASM = \ syscall.o \ exit.o \ @@ -383,6 +383,9 @@ MIASM = \ cap_getrights.o \ cap_enter.o \ cap_getmode.o \ + pdfork.o \ + pdkill.o \ + pdgetpid.o \ pselect.o \ getloginclass.o \ setloginclass.o \ diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index 90e0449965bf8..9bcb79bd0aec8 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD + * created from FreeBSD: head/sys/kern/syscalls.master 224987 2011-08-18 22:51:30Z jonathan */ #ifndef _SYS_SYSPROTO_H_ @@ -1671,6 +1671,18 @@ struct cap_enter_args { struct cap_getmode_args { char modep_l_[PADL_(u_int *)]; u_int * modep; char modep_r_[PADR_(u_int *)]; }; +struct pdfork_args { + char fdp_l_[PADL_(int *)]; int * fdp; char fdp_r_[PADR_(int *)]; + char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; +}; +struct pdkill_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char signum_l_[PADL_(int)]; int signum; char signum_r_[PADR_(int)]; +}; +struct pdgetpid_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char pidp_l_[PADL_(pid_t *)]; pid_t * pidp; char pidp_r_[PADR_(pid_t *)]; +}; struct pselect_args { char nd_l_[PADL_(int)]; int nd; char nd_r_[PADR_(int)]; char in_l_[PADL_(fd_set *)]; fd_set * in; char in_r_[PADR_(fd_set *)]; @@ -2085,6 +2097,9 @@ int cap_new(struct thread *, struct cap_new_args *); int cap_getrights(struct thread *, struct cap_getrights_args *); int cap_enter(struct thread *, struct cap_enter_args *); int cap_getmode(struct thread *, struct cap_getmode_args *); +int pdfork(struct thread *, struct pdfork_args *); +int pdkill(struct thread *, struct pdkill_args *); +int pdgetpid(struct thread *, struct pdgetpid_args *); int pselect(struct thread *, struct pselect_args *); int getloginclass(struct thread *, struct getloginclass_args *); int setloginclass(struct thread *, struct setloginclass_args *); @@ -2772,6 +2787,9 @@ int freebsd7_shmctl(struct thread *, struct freebsd7_shmctl_args *); #define SYS_AUE_cap_getrights AUE_CAP_GETRIGHTS #define SYS_AUE_cap_enter AUE_CAP_ENTER #define SYS_AUE_cap_getmode AUE_CAP_GETMODE +#define SYS_AUE_pdfork AUE_PDFORK +#define SYS_AUE_pdkill AUE_PDKILL +#define SYS_AUE_pdgetpid AUE_PDGETPID #define SYS_AUE_pselect AUE_SELECT #define SYS_AUE_getloginclass AUE_NULL #define SYS_AUE_setloginclass AUE_NULL diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 8b0de573f6f7c..7e537ee4a0822 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -160,11 +160,7 @@ void *hashinit_flags(int count, struct malloc_type *type, void *phashinit(int count, struct malloc_type *type, u_long *nentries); void g_waitidle(void); -#ifdef RESTARTABLE_PANICS -void panic(const char *, ...) __printflike(1, 2); -#else void panic(const char *, ...) __dead2 __printflike(1, 2); -#endif void cpu_boot(int); void cpu_flush_dcache(void *, size_t); diff --git a/sys/sys/unistd.h b/sys/sys/unistd.h index 9d56a3a427309..9e7f7e6d83426 100644 --- a/sys/sys/unistd.h +++ b/sys/sys/unistd.h @@ -185,11 +185,12 @@ #define RFTSIGMASK 0xFF #define RFTSIGNUM(flags) (((flags) >> RFTSIGSHIFT) & RFTSIGMASK) #define RFTSIGFLAGS(signum) ((signum) << RFTSIGSHIFT) +#define RFPROCDESC (1<<28) /* return a process descriptor */ #define RFPPWAIT (1<<31) /* parent sleeps until child exits (vfork) */ -#define RFKERNELONLY (RFSTOPPED | RFHIGHPID | RFPPWAIT) #define RFFLAGS (RFFDG | RFPROC | RFMEM | RFNOWAIT | RFCFDG | \ RFTHREAD | RFSIGSHARE | RFLINUXTHPN | RFSTOPPED | RFHIGHPID | RFTSIGZMB | \ - RFPPWAIT) + RFPROCDESC | RFPPWAIT) +#define RFKERNELONLY (RFSTOPPED | RFHIGHPID | RFPPWAIT | RFPROCDESC) #endif /* __BSD_VISIBLE */ diff --git a/sys/sys/user.h b/sys/sys/user.h index 644f9113edd55..a139d4fdfabec 100644 --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -95,13 +95,18 @@ #define WMESGLEN 8 /* size of returned wchan message */ #define LOCKNAMELEN 8 /* size of returned lock name */ -#define OCOMMLEN 16 /* size of returned thread name */ +#define TDNAMLEN 16 /* size of returned thread name */ #define COMMLEN 19 /* size of returned ki_comm name */ #define KI_EMULNAMELEN 16 /* size of returned ki_emul */ #define KI_NGROUPS 16 /* number of groups in ki_groups */ #define LOGNAMELEN 17 /* size of returned ki_login */ #define LOGINCLASSLEN 17 /* size of returned ki_loginclass */ +#ifndef BURN_BRIDGES +#define OCOMMLEN TDNAMLEN +#define ki_ocomm ki_tdname +#endif + /* Flags for the process credential. */ #define KI_CRF_CAPABILITY_MODE 0x00000001 /* @@ -167,7 +172,7 @@ struct kinfo_proc { char ki_rqindex; /* Run queue index */ u_char ki_oncpu; /* Which cpu we are on */ u_char ki_lastcpu; /* Last cpu we were on */ - char ki_ocomm[OCOMMLEN+1]; /* thread name */ + char ki_tdname[TDNAMLEN+1]; /* thread name */ char ki_wmesg[WMESGLEN+1]; /* wchan message */ char ki_login[LOGNAMELEN+1]; /* setlogin name */ char ki_lockname[LOCKNAMELEN+1]; /* lock name */ @@ -246,6 +251,8 @@ struct user { #define KF_TYPE_SHM 8 #define KF_TYPE_SEM 9 #define KF_TYPE_PTS 10 +/* no KF_TYPE_CAPABILITY (11), since capabilities wrap other file objects */ +#define KF_TYPE_PROCDESC 12 #define KF_TYPE_UNKNOWN 255 #define KF_VTYPE_VNON 0 @@ -281,6 +288,7 @@ struct user { #define KF_FLAG_TRUNC 0x00001000 #define KF_FLAG_EXCL 0x00002000 #define KF_FLAG_EXEC 0x00004000 +#define KF_FLAG_CAPABILITY 0x00008000 /* * Old format. Has variable hidden padding due to alignment. @@ -370,10 +378,15 @@ struct kinfo_file { /* Round to 64 bit alignment. */ uint32_t kf_pts_pad0[7]; } kf_pts; + struct { + pid_t kf_pid; + } kf_proc; } kf_un; uint16_t kf_status; /* Status flags. */ uint16_t kf_pad1; /* Round to 32 bit alignment. */ - int _kf_ispare[7]; /* Space for more stuff. */ + int _kf_ispare0; /* Space for more stuff. */ + cap_rights_t kf_cap_rights; /* Capability rights. */ + int _kf_ispare[4]; /* Space for more stuff. */ /* Truncated before copyout in sysctl */ char kf_path[PATH_MAX]; /* Path to file, if any. */ }; diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 1c4c7b7dab7b9..4cb6633d4cc8c 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -640,6 +640,7 @@ int _vn_lock(struct vnode *vp, int flags, char *file, int line); int vn_open(struct nameidata *ndp, int *flagp, int cmode, struct file *fp); int vn_open_cred(struct nameidata *ndp, int *flagp, int cmode, u_int vn_open_flags, struct ucred *cred, struct file *fp); +void vn_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end); int vn_pollrecord(struct vnode *vp, struct thread *p, int events); int vn_rdwr(enum uio_rw rw, struct vnode *vp, void *base, int len, off_t offset, enum uio_seg segflg, int ioflg, @@ -778,7 +779,15 @@ void vfs_mark_atime(struct vnode *vp, struct ucred *cred); struct dirent; int vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off); -int vfs_unixify_accmode(accmode_t *accmode); +int vfs_unixify_accmode(accmode_t *accmode); + +int setfmode(struct thread *td, struct ucred *cred, struct vnode *vp, int mode); +int setfown(struct thread *td, struct ucred *cred, struct vnode *vp, uid_t uid, + gid_t gid); +int vn_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, + struct thread *td); +int vn_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, + struct thread *td); #endif /* _KERNEL */ diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index 82506fbe3be4f..5f984b4b6ba37 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include "opt_quota.h" #include <sys/param.h> +#include <sys/capability.h> #include <sys/systm.h> #include <sys/bio.h> #include <sys/buf.h> @@ -1967,7 +1968,7 @@ ffs_blkfree_cg(ump, fs, devvp, bno, size, inum, dephd) ACTIVECLEAR(fs, cg); UFS_UNLOCK(ump); mp = UFSTOVFS(ump); - if (mp->mnt_flag & MNT_SOFTDEP && devvp->v_type != VREG) + if (MOUNTEDSOFTDEP(mp) && devvp->v_type != VREG) softdep_setup_blkfree(UFSTOVFS(ump), bp, bno, numfrags(fs, size), dephd); bdwrite(bp); @@ -2217,7 +2218,7 @@ ffs_freefile(ump, fs, devvp, ino, mode, wkhd) fs->fs_fmod = 1; ACTIVECLEAR(fs, cg); UFS_UNLOCK(ump); - if (UFSTOVFS(ump)->mnt_flag & MNT_SOFTDEP && devvp->v_type != VREG) + if (MOUNTEDSOFTDEP(UFSTOVFS(ump)) && devvp->v_type != VREG) softdep_setup_inofree(UFSTOVFS(ump), bp, ino + cg * fs->fs_ipg, wkhd); bdwrite(bp); @@ -2447,7 +2448,7 @@ static SYSCTL_NODE(_vfs_ffs, FFS_SET_BUFOUTPUT, setbufoutput, CTLFLAG_WR, #define DEBUG 1 #ifdef DEBUG -static int fsckcmds = 1; +static int fsckcmds = 0; SYSCTL_INT(_debug, OID_AUTO, fsckcmds, CTLFLAG_RW, &fsckcmds, 0, ""); #endif /* DEBUG */ @@ -2470,7 +2471,6 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) struct file *fp, *vfp; int vfslocked, filetype, error; static struct fileops *origops, bufferedops; - static int outcnt = 0; if (req->newlen > sizeof cmd) return (EBADRPC); @@ -2478,7 +2478,8 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) return (error); if (cmd.version != FFS_CMD_VERSION) return (ERPCMISMATCH); - if ((error = getvnode(td->td_proc->p_fd, cmd.handle, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, cmd.handle, CAP_FSCK, + &fp)) != 0) return (error); vp = fp->f_data; if (vp->v_type != VREG && vp->v_type != VDIR) { @@ -2755,7 +2756,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) break; } #ifdef DEBUG - if (fsckcmds && outcnt++ < 100) { + if (fsckcmds) { printf("%s: update inode %jd\n", mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); } @@ -2799,7 +2800,8 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) (intmax_t)cmd.value); } #endif /* DEBUG */ - if ((error = getvnode(td->td_proc->p_fd, cmd.value, &vfp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, cmd.value, + CAP_FSCK, &vfp)) != 0) break; if (vfp->f_vnode->v_type != VCHR) { fdrop(vfp, td); @@ -2857,7 +2859,6 @@ buffered_write(fp, uio, active_cred, flags, td) struct fs *fs; int error, vfslocked; daddr_t lbn; - static int outcnt = 0; /* * The devvp is associated with the /dev filesystem. To discover @@ -2875,7 +2876,7 @@ buffered_write(fp, uio, active_cred, flags, td) if ((flags & FOF_OFFSET) == 0) uio->uio_offset = fp->f_offset; #ifdef DEBUG - if (fsckcmds && outcnt++ < 100) { + if (fsckcmds) { printf("%s: buffered write for block %jd\n", fs->fs_fsmnt, (intmax_t)btodb(uio->uio_offset)); } diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index 70bcf1df4f792..bfc02564824f8 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -79,7 +79,6 @@ int ffs_isfreeblock(struct fs *, u_char *, ufs1_daddr_t); void ffs_load_inode(struct buf *, struct inode *, struct fs *, ino_t); int ffs_mountroot(void); void ffs_oldfscompat_write(struct fs *, struct ufsmount *); -void ffs_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end); int ffs_reallocblks(struct vop_reallocblks_args *); int ffs_realloccg(struct inode *, ufs2_daddr_t, ufs2_daddr_t, ufs2_daddr_t, int, int, int, struct ucred *, struct buf **); diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c index 0034029df91ac..101bdb43aa97f 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -120,18 +120,6 @@ ffs_update(vp, waitfor) } } -void -ffs_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end) -{ - vm_object_t object; - - if ((object = vp->v_object) == NULL) - return; - VM_OBJECT_LOCK(object); - vm_object_page_remove(object, start, end, 0); - VM_OBJECT_UNLOCK(object); -} - #define SINGLE 0 /* index of single indirect block */ #define DOUBLE 1 /* index of double indirect block */ #define TRIPLE 2 /* index of triple indirect block */ @@ -219,7 +207,7 @@ ffs_truncate(vp, length, flags, cred, td) (void) chkdq(ip, -extblocks, NOCRED, 0); #endif vinvalbuf(vp, V_ALT, 0, 0); - ffs_pages_remove(vp, + vn_pages_remove(vp, OFF_TO_IDX(lblktosize(fs, -extblocks)), 0); osize = ip->i_din2->di_extsize; ip->i_din2->di_blocks -= extblocks; diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index fccb296973468..6cf033a432939 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -1364,7 +1364,7 @@ softdep_flush(void) mtx_lock(&mountlist_mtx); for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { nmp = TAILQ_NEXT(mp, mnt_list); - if ((mp->mnt_flag & MNT_SOFTDEP) == 0) + if (MOUNTEDSOFTDEP(mp) == 0) continue; if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK)) continue; @@ -2423,11 +2423,11 @@ softdep_unmount(mp) MNT_ILOCK(mp); mp->mnt_flag &= ~MNT_SOFTDEP; - if ((mp->mnt_kern_flag & MNTK_SUJ) == 0) { + if (MOUNTEDSUJ(mp) == 0) { MNT_IUNLOCK(mp); return; } - mp->mnt_kern_flag &= ~MNTK_SUJ; + mp->mnt_flag &= ~MNT_SUJ; MNT_IUNLOCK(mp); journal_unmount(mp); } @@ -2637,7 +2637,8 @@ journal_mount(mp, fs, cred) out: if (error == 0) { MNT_ILOCK(mp); - mp->mnt_kern_flag |= MNTK_SUJ; + mp->mnt_flag |= MNT_SUJ; + mp->mnt_flag &= ~MNT_SOFTDEP; MNT_IUNLOCK(mp); /* * Only validate the journal contents if the @@ -3060,7 +3061,7 @@ softdep_flushjournal(mp) struct jblocks *jblocks; struct ufsmount *ump; - if ((mp->mnt_kern_flag & MNTK_SUJ) == 0) + if (MOUNTEDSUJ(mp) == 0) return; ump = VFSTOUFS(mp); jblocks = ump->softdep_jblocks; @@ -3096,7 +3097,7 @@ softdep_process_journal(mp, needwk, flags) int off; int devbsize; - if ((mp->mnt_kern_flag & MNTK_SUJ) == 0) + if (MOUNTEDSUJ(mp) == 0) return; ump = VFSTOUFS(mp); fs = ump->um_fs; @@ -3827,8 +3828,8 @@ newfreework(ump, freeblks, parent, lbn, nb, frags, off, journal) freework->fw_blkno = nb; freework->fw_frags = frags; freework->fw_indir = NULL; - freework->fw_ref = ((UFSTOVFS(ump)->mnt_kern_flag & MNTK_SUJ) == 0 || - lbn >= -NXADDR) ? 0 : NINDIR(ump->um_fs) + 1; + freework->fw_ref = (MOUNTEDSUJ(UFSTOVFS(ump)) == 0 || lbn >= -NXADDR) + ? 0 : NINDIR(ump->um_fs) + 1; freework->fw_start = freework->fw_off = off; if (journal) newjfreeblk(freeblks, lbn, nb, frags); @@ -4681,7 +4682,7 @@ softdep_setup_inomapdep(bp, ip, newinum, mode) * Allocate the journal reference add structure so that the bitmap * can be dependent on it. */ - if (mp->mnt_kern_flag & MNTK_SUJ) { + if (MOUNTEDSUJ(mp)) { jaddref = newjaddref(ip, newinum, 0, 0, mode); jaddref->ja_state |= NEWBLOCK; } @@ -4734,7 +4735,7 @@ softdep_setup_blkmapdep(bp, mp, newblkno, frags, oldfrags) * Add it to the dependency list for the buffer holding * the cylinder group map from which it was allocated. */ - if (mp->mnt_kern_flag & MNTK_SUJ) { + if (MOUNTEDSUJ(mp)) { jnewblk = malloc(sizeof(*jnewblk), M_JNEWBLK, M_SOFTDEP_FLAGS); workitem_alloc(&jnewblk->jn_list, D_JNEWBLK, mp); jnewblk->jn_jsegdep = newjsegdep(&jnewblk->jn_list); @@ -5199,7 +5200,7 @@ newfreefrag(ip, blkno, size, lbn) freefrag->ff_blkno = blkno; freefrag->ff_fragsize = size; - if ((ip->i_ump->um_mountp->mnt_kern_flag & MNTK_SUJ) != 0) { + if (MOUNTEDSUJ(UFSTOVFS(ip->i_ump))) { freefrag->ff_jdep = (struct worklist *) newjfreefrag(freefrag, ip, blkno, size, lbn); } else { @@ -6540,7 +6541,7 @@ trunc_pages(ip, length, extblocks, flags) fs = ip->i_fs; extend = OFF_TO_IDX(lblktosize(fs, -extblocks)); if ((flags & IO_EXT) != 0) - ffs_pages_remove(vp, extend, 0); + vn_pages_remove(vp, extend, 0); if ((flags & IO_NORMAL) == 0) return; BO_LOCK(&vp->v_bufobj); @@ -6566,7 +6567,7 @@ trunc_pages(ip, length, extblocks, flags) end = OFF_TO_IDX(lblktosize(fs, lbn)); } else end = extend; - ffs_pages_remove(vp, OFF_TO_IDX(OFF_MAX), end); + vn_pages_remove(vp, OFF_TO_IDX(OFF_MAX), end); } /* @@ -7254,7 +7255,7 @@ freework_freeblock(freework) freeblks = freework->fw_freeblks; ump = VFSTOUFS(freeblks->fb_list.wk_mp); fs = ump->um_fs; - needj = freeblks->fb_list.wk_mp->mnt_kern_flag & MNTK_SUJ; + needj = MOUNTEDSUJ(freeblks->fb_list.wk_mp) != 0; bsize = lfragtosize(fs, freework->fw_frags); LIST_INIT(&wkhd); /* @@ -7674,7 +7675,7 @@ indir_trunc(freework, dbn, lbn) ufs1fmt = 0; } level = lbn_level(lbn); - needj = UFSTOVFS(ump)->mnt_kern_flag & MNTK_SUJ; + needj = MOUNTEDSUJ(UFSTOVFS(ump)) != 0; lbnadd = lbn_offset(fs, level); nblocks = btodb(fs->fs_bsize); nfreework = freework; @@ -7860,7 +7861,7 @@ setup_newdir(dap, newinum, dinum, newdirbp, mkdirp) mkdir2->md_state = ATTACHED | MKDIR_PARENT; mkdir2->md_diradd = dap; mkdir2->md_jaddref = NULL; - if ((mp->mnt_kern_flag & MNTK_SUJ) == 0) { + if (MOUNTEDSUJ(mp) == 0) { mkdir1->md_state |= DEPCOMPLETE; mkdir2->md_state |= DEPCOMPLETE; } @@ -7900,7 +7901,7 @@ setup_newdir(dap, newinum, dinum, newdirbp, mkdirp) * been satisfied and mkdir2 can be freed. */ inodedep_lookup(mp, dinum, 0, &inodedep); - if (mp->mnt_kern_flag & MNTK_SUJ) { + if (MOUNTEDSUJ(mp)) { if (inodedep == NULL) panic("setup_newdir: Lost parent."); jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, @@ -8031,7 +8032,7 @@ softdep_setup_directory_add(bp, dp, diroffset, newinum, newdirbp, isnewblk) * written place it on the bufwait list, otherwise do the post-inode * write processing to put it on the id_pendinghd list. */ - if (mp->mnt_kern_flag & MNTK_SUJ) { + if (MOUNTEDSUJ(mp)) { jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, inoreflst); KASSERT(jaddref != NULL && jaddref->ja_parent == dp->i_number, @@ -8047,7 +8048,7 @@ softdep_setup_directory_add(bp, dp, diroffset, newinum, newdirbp, isnewblk) * Add the journal entries for . and .. links now that the primary * link is written. */ - if (mkdir1 != NULL && mp->mnt_kern_flag & MNTK_SUJ) { + if (mkdir1 != NULL && MOUNTEDSUJ(mp)) { jaddref = (struct jaddref *)TAILQ_PREV(&jaddref->ja_ref, inoreflst, if_deps); KASSERT(jaddref != NULL && @@ -8144,7 +8145,7 @@ softdep_change_directoryentry_offset(bp, dp, base, oldloc, newloc, entrysize) * determine if any affected adds or removes are present in the * journal. */ - if (mp->mnt_kern_flag & MNTK_SUJ) { + if (MOUNTEDSUJ(mp)) { flags = DEPALLOC; jmvref = newjmvref(dp, de->d_ino, dp->i_offset + (oldloc - base), @@ -8865,7 +8866,7 @@ softdep_setup_directory_change(bp, dp, ip, newinum, isrmdir) * processing to put it on the id_pendinghd list. */ inodedep_lookup(mp, newinum, DEPALLOC, &inodedep); - if (mp->mnt_kern_flag & MNTK_SUJ) { + if (MOUNTEDSUJ(mp)) { jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, inoreflst); KASSERT(jaddref != NULL && jaddref->ja_parent == dp->i_number, @@ -8928,7 +8929,7 @@ softdep_setup_sbupdate(ump, fs, bp) struct sbdep *sbdep; struct worklist *wk; - if ((ump->um_mountp->mnt_kern_flag & MNTK_SUJ) == 0) + if (MOUNTEDSUJ(UFSTOVFS(ump)) == 0) return; LIST_FOREACH(wk, &bp->b_dep, wk_list) if (wk->wk_type == D_SBDEP) @@ -9046,7 +9047,7 @@ unlinked_inodedep(mp, inodedep) { struct ufsmount *ump; - if ((mp->mnt_kern_flag & MNTK_SUJ) == 0) + if (MOUNTEDSUJ(mp) == 0) return; ump = VFSTOUFS(mp); ump->um_fs->fs_fmod = 1; diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 35852bf9410e9..4f688a2aa940c 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -281,7 +281,7 @@ ffs_mount(struct mount *mp) flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; - if (mp->mnt_flag & MNT_SOFTDEP) { + if (MOUNTEDSOFTDEP(mp)) { error = softdep_flushfiles(mp, flags, td); } else { error = ffs_flushfiles(mp, flags, td); @@ -307,7 +307,7 @@ ffs_mount(struct mount *mp) vfs_write_resume(mp); return (error); } - if (mp->mnt_flag & MNT_SOFTDEP) + if (MOUNTEDSOFTDEP(mp)) softdep_unmount(mp); DROP_GIANT(); g_topology_lock(); @@ -411,7 +411,7 @@ ffs_mount(struct mount *mp) * Softdep_mount() clears it in an initial mount * or ro->rw remount. */ - if (mp->mnt_flag & MNT_SOFTDEP) { + if (MOUNTEDSOFTDEP(mp)) { /* XXX: Reset too late ? */ MNT_ILOCK(mp); mp->mnt_flag &= ~MNT_ASYNC; @@ -443,7 +443,7 @@ ffs_mount(struct mount *mp) fs->fs_fsmnt); return (EINVAL); } - KASSERT((mp->mnt_flag & MNT_SOFTDEP) == 0, + KASSERT(MOUNTEDSOFTDEP(mp) == 0, ("soft updates enabled on read-only file system")); DROP_GIANT(); g_topology_lock(); @@ -530,7 +530,7 @@ ffs_mount(struct mount *mp) return (error); } if (fsckpid > 0) { - KASSERT((mp->mnt_flag & MNT_SOFTDEP) == 0, + KASSERT(MOUNTEDSOFTDEP(mp) == 0, ("soft updates enabled on read-only file system")); ump = VFSTOUFS(mp); fs = ump->um_fs; @@ -1247,7 +1247,7 @@ ffs_unmount(mp, mntflags) vn_start_write(NULL, &mp, V_WAIT); } } - if (mp->mnt_flag & MNT_SOFTDEP) + if (MOUNTEDSOFTDEP(mp)) error = softdep_flushfiles(mp, flags, td); else error = ffs_flushfiles(mp, flags, td); diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 9f528dac997b8..81c7af40811f8 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -187,8 +187,7 @@ retry: error = ffs_syncvnode(vp, ap->a_waitfor); if (error) return (error); - if (ap->a_waitfor == MNT_WAIT && - (vp->v_mount->mnt_flag & MNT_SOFTDEP)) { + if (ap->a_waitfor == MNT_WAIT && DOINGSOFTDEP(vp)) { error = softdep_fsync(vp); if (error) return (error); diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h index 7adcc73e1b429..6f3d6f9853ea5 100644 --- a/sys/ufs/ufs/inode.h +++ b/sys/ufs/ufs/inode.h @@ -174,9 +174,11 @@ struct indir { #define ITOV(ip) ((ip)->i_vnode) /* Determine if soft dependencies are being done */ -#define DOINGSOFTDEP(vp) ((vp)->v_mount->mnt_flag & MNT_SOFTDEP) -#define DOINGASYNC(vp) ((vp)->v_mount->mnt_kern_flag & MNTK_ASYNC) -#define DOINGSUJ(vp) ((vp)->v_mount->mnt_kern_flag & MNTK_SUJ) +#define DOINGSOFTDEP(vp) ((vp)->v_mount->mnt_flag & (MNT_SOFTDEP | MNT_SUJ)) +#define MOUNTEDSOFTDEP(mp) ((mp)->mnt_flag & (MNT_SOFTDEP | MNT_SUJ)) +#define DOINGASYNC(vp) ((vp)->v_mount->mnt_kern_flag & MNTK_ASYNC) +#define DOINGSUJ(vp) ((vp)->v_mount->mnt_flag & MNT_SUJ) +#define MOUNTEDSUJ(mp) ((mp)->mnt_flag & MNT_SUJ) /* This overlays the fid structure (see mount.h). */ struct ufid { diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c index 032d9cc34211d..777f3851604f2 100644 --- a/sys/ufs/ufs/ufs_extattr.c +++ b/sys/ufs/ufs/ufs_extattr.c @@ -1031,14 +1031,14 @@ vop_setextattr { struct ufsmount *ump = VFSTOUFS(mp); int error; - ufs_extattr_uepm_lock(ump, ap->a_td); - /* * XXX: No longer a supported way to delete extended attributes. */ if (ap->a_uio == NULL) return (EINVAL); + ufs_extattr_uepm_lock(ump, ap->a_td); + error = ufs_extattr_set(ap->a_vp, ap->a_attrnamespace, ap->a_name, ap->a_uio, ap->a_cred, ap->a_td); diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c index 411482a3cc25c..d46d17055b6ee 100644 --- a/sys/vm/device_pager.c +++ b/sys/vm/device_pager.c @@ -147,6 +147,7 @@ dev_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, object1 = vm_object_allocate(OBJT_DEVICE, pindex); object1->flags |= OBJ_COLORED; object1->pg_color = atop(paddr) - OFF_TO_IDX(off - PAGE_SIZE); + TAILQ_INIT(&object1->un_pager.devp.devp_pglist); mtx_lock(&dev_pager_mtx); object = vm_pager_object_lookup(&dev_pager_object_list, handle); if (object != NULL) { @@ -159,7 +160,6 @@ dev_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, object = object1; object1 = NULL; object->handle = handle; - TAILQ_INIT(&object->un_pager.devp.devp_pglist); TAILQ_INSERT_TAIL(&dev_pager_object_list, object, pager_object_list); } @@ -169,7 +169,14 @@ dev_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, } mtx_unlock(&dev_pager_mtx); dev_relthread(dev, ref); - vm_object_deallocate(object1); + if (object1 != NULL) { + object1->handle = object1; + mtx_lock(&dev_pager_mtx); + TAILQ_INSERT_TAIL(&dev_pager_object_list, object1, + pager_object_list); + mtx_unlock(&dev_pager_mtx); + vm_object_deallocate(object1); + } return (object); } diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c index f421e4fa7881c..d7da4f919126d 100644 --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -114,9 +114,9 @@ __FBSDID("$FreeBSD$"); #include <geom/geom.h> /* - * SWB_NPAGES must be a power of 2. It may be set to 1, 2, 4, 8, or 16 - * pages per allocation. We recommend you stick with the default of 8. - * The 16-page limit is due to the radix code (kern/subr_blist.c). + * SWB_NPAGES must be a power of 2. It may be set to 1, 2, 4, 8, 16 + * or 32 pages per allocation. + * The 32-page limit is due to the radix code (kern/subr_blist.c). */ #ifndef MAX_PAGEOUT_CLUSTER #define MAX_PAGEOUT_CLUSTER 16 @@ -127,14 +127,11 @@ __FBSDID("$FreeBSD$"); #endif /* - * Piecemeal swap metadata structure. Swap is stored in a radix tree. - * - * If SWB_NPAGES is 8 and sizeof(char *) == sizeof(daddr_t), our radix - * is basically 8. Assuming PAGE_SIZE == 4096, one tree level represents - * 32K worth of data, two levels represent 256K, three levels represent - * 2 MBytes. This is acceptable. - * - * Overall memory utilization is about the same as the old swap structure. + * The swblock structure maps an object and a small, fixed-size range + * of page indices to disk addresses within a swap area. + * The collection of these mappings is implemented as a hash table. + * Unused disk addresses within a swap area are allocated and managed + * using a blist. */ #define SWCORRECT(n) (sizeof(void *) * (n) / sizeof(daddr_t)) #define SWAP_META_PAGES (SWB_NPAGES * 2) @@ -662,9 +659,7 @@ swap_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, * routine is typically called only when the entire object is * about to be destroyed. * - * This routine may block, but no longer does. - * - * The object must be locked or unreferenceable. + * The object must be locked. */ static void swap_pager_dealloc(vm_object_t object) @@ -706,7 +701,7 @@ swap_pager_dealloc(vm_object_t object) * Also has the side effect of advising that somebody made a mistake * when they configured swap and didn't configure enough. * - * This routine may not block + * This routine may not sleep. * * We allocate in round-robin fashion from the configured devices. */ @@ -776,10 +771,7 @@ swp_pager_strategy(struct buf *bp) * * This routine returns the specified swap blocks back to the bitmap. * - * Note: This routine may not block (it could in the old swap code), - * and through the use of the new blist routines it does not block. - * - * This routine may not block + * This routine may not sleep. */ static void swp_pager_freeswapspace(daddr_t blk, int npages) @@ -875,21 +867,16 @@ swap_pager_reserve(vm_object_t object, vm_pindex_t start, vm_size_t size) * cases where both the source and destination have a valid swapblk, * we keep the destination's. * - * This routine is allowed to block. It may block allocating metadata + * This routine is allowed to sleep. It may sleep allocating metadata * indirectly through swp_pager_meta_build() or if paging is still in * progress on the source. * - * XXX vm_page_collapse() kinda expects us not to block because we - * supposedly do not need to allocate memory, but for the moment we - * *may* have to get a little memory from the zone allocator, but - * it is taken from the interrupt memory. We should be ok. - * * The source object contains no vm_page_t's (which is just as well) * * The source object is of type OBJT_SWAP. * - * The source and destination objects must be locked or - * inaccessible (XXX are they ?) + * The source and destination objects must be locked. + * Both object locks may temporarily be released. */ void swap_pager_copy(vm_object_t srcobject, vm_object_t dstobject, @@ -1066,7 +1053,7 @@ swap_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before, int *aft * does NOT change the m->dirty status of the page. Also: MADV_FREE * depends on it. * - * This routine may not block + * This routine may not sleep. */ static void swap_pager_unswapped(vm_page_t m) @@ -1472,7 +1459,7 @@ swap_pager_putpages(vm_object_t object, vm_page_t *m, int count, * operations, we vm_page_t->busy'd unbusy all pages ( we can do this * because we marked them all VM_PAGER_PEND on return from putpages ). * - * This routine may not block. + * This routine may not sleep. */ static void swp_pager_async_iodone(struct buf *bp) @@ -1606,7 +1593,7 @@ swp_pager_async_iodone(struct buf *bp) * status, then finish the I/O ( which decrements the * busy count and possibly wakes waiter's up ). */ - KASSERT((m->flags & PG_WRITEABLE) == 0, + KASSERT((m->aflags & PGA_WRITEABLE) == 0, ("swp_pager_async_iodone: page %p is not write" " protected", m)); vm_page_undirty(m); @@ -1657,7 +1644,7 @@ swp_pager_async_iodone(struct buf *bp) * Return 1 if at least one page in the given object is paged * out to the given swap device. * - * This routine may not block. + * This routine may not sleep. */ int swap_pager_isswapped(vm_object_t object, struct swdevt *sp) @@ -2133,16 +2120,6 @@ swaponsomething(struct vnode *vp, void *id, u_long nblks, sw_strategy_t *strateg u_long mblocks; /* - * If we go beyond this, we get overflows in the radix - * tree bitmap code. - */ - mblocks = 0x40000000 / BLIST_META_RADIX; - if (nblks > mblocks) { - printf("WARNING: reducing size to maximum of %lu blocks per swap unit\n", - mblocks); - nblks = mblocks; - } - /* * nblks is in DEV_BSIZE'd chunks, convert to PAGE_SIZE'd chunks. * First chop nblks off to page-align it, then convert. * @@ -2151,6 +2128,18 @@ swaponsomething(struct vnode *vp, void *id, u_long nblks, sw_strategy_t *strateg nblks &= ~(ctodb(1) - 1); nblks = dbtoc(nblks); + /* + * If we go beyond this, we get overflows in the radix + * tree bitmap code. + */ + mblocks = 0x40000000 / BLIST_META_RADIX; + if (nblks > mblocks) { + printf( + "WARNING: reducing swap size to maximum of %luMB per unit\n", + mblocks / 1024 / 1024 * PAGE_SIZE); + nblks = mblocks; + } + sp = malloc(sizeof *sp, M_VMPGDATA, M_WAITOK | M_ZERO); sp->sw_vp = vp; sp->sw_id = id; @@ -2365,35 +2354,53 @@ swap_pager_status(int *total, int *used) mtx_unlock(&sw_dev_mtx); } -static int -sysctl_vm_swap_info(SYSCTL_HANDLER_ARGS) +int +swap_dev_info(int name, struct xswdev *xs, char *devname, size_t len) { - int *name = (int *)arg1; - int error, n; - struct xswdev xs; struct swdevt *sp; - - if (arg2 != 1) /* name length */ - return (EINVAL); + char *tmp_devname; + int error, n; n = 0; + error = ENOENT; mtx_lock(&sw_dev_mtx); TAILQ_FOREACH(sp, &swtailq, sw_list) { - if (n == *name) { - mtx_unlock(&sw_dev_mtx); - xs.xsw_version = XSWDEV_VERSION; - xs.xsw_dev = sp->sw_dev; - xs.xsw_flags = sp->sw_flags; - xs.xsw_nblks = sp->sw_nblks; - xs.xsw_used = sp->sw_used; - - error = SYSCTL_OUT(req, &xs, sizeof(xs)); - return (error); + if (n != name) { + n++; + continue; + } + xs->xsw_version = XSWDEV_VERSION; + xs->xsw_dev = sp->sw_dev; + xs->xsw_flags = sp->sw_flags; + xs->xsw_nblks = sp->sw_nblks; + xs->xsw_used = sp->sw_used; + if (devname != NULL) { + if (vn_isdisk(sp->sw_vp, NULL)) + tmp_devname = sp->sw_vp->v_rdev->si_name; + else + tmp_devname = "[file]"; + strncpy(devname, tmp_devname, len); } - n++; + error = 0; + break; } mtx_unlock(&sw_dev_mtx); - return (ENOENT); + return (error); +} + +static int +sysctl_vm_swap_info(SYSCTL_HANDLER_ARGS) +{ + struct xswdev xs; + int error; + + if (arg2 != 1) /* name length */ + return (EINVAL); + error = swap_dev_info(*(int *)arg1, &xs, NULL, 0); + if (error != 0) + return (error); + error = SYSCTL_OUT(req, &xs, sizeof(xs)); + return (error); } SYSCTL_INT(_vm, OID_AUTO, nswapdev, CTLFLAG_RD, &nswapdev, 0, diff --git a/sys/vm/swap_pager.h b/sys/vm/swap_pager.h index c3366e8e87783..5c716d95c4e50 100644 --- a/sys/vm/swap_pager.h +++ b/sys/vm/swap_pager.h @@ -75,7 +75,8 @@ struct swdevt { extern int swap_pager_full; extern int swap_pager_avail; -struct swdevt; +struct xswdev; +int swap_dev_info(int name, struct xswdev *xs, char *devname, size_t len); void swap_pager_copy(vm_object_t, vm_object_t, vm_pindex_t, int); void swap_pager_freespace(vm_object_t, vm_pindex_t, vm_size_t); void swap_pager_swap_init(void); diff --git a/sys/vm/vm_contig.c b/sys/vm/vm_contig.c index 025312ba7f524..67ebdc3ff53c1 100644 --- a/sys/vm/vm_contig.c +++ b/sys/vm/vm_contig.c @@ -265,6 +265,7 @@ retry: vm_contig_grow_cache(tries, low, high); vm_map_lock(map); VM_OBJECT_LOCK(object); + tries++; goto retry; } while (i != 0) { diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index eeb10a4617497..1b8ac2fef17b1 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -345,9 +345,7 @@ RetryFault:; * sleeping so that the page daemon is less * likely to reclaim it. */ - vm_page_lock_queues(); - vm_page_flag_set(fs.m, PG_REFERENCED); - vm_page_unlock_queues(); + vm_page_aflag_set(fs.m, PGA_REFERENCED); vm_page_unlock(fs.m); if (fs.object != fs.first_object) { if (!VM_OBJECT_TRYLOCK( diff --git a/sys/vm/vm_kern.c b/sys/vm/vm_kern.c index 23884af0b3aa8..24c24488a86ec 100644 --- a/sys/vm/vm_kern.c +++ b/sys/vm/vm_kern.c @@ -210,7 +210,7 @@ kmem_alloc(map, size) mem = vm_page_grab(kernel_object, OFF_TO_IDX(offset + i), VM_ALLOC_NOBUSY | VM_ALLOC_ZERO | VM_ALLOC_RETRY); mem->valid = VM_PAGE_BITS_ALL; - KASSERT((mem->flags & PG_UNMANAGED) != 0, + KASSERT((mem->oflags & VPO_UNMANAGED) != 0, ("kmem_alloc: page %p is managed", mem)); } VM_OBJECT_UNLOCK(kernel_object); @@ -428,7 +428,7 @@ retry: if (flags & M_ZERO && (m->flags & PG_ZERO) == 0) pmap_zero_page(m); m->valid = VM_PAGE_BITS_ALL; - KASSERT((m->flags & PG_UNMANAGED) != 0, + KASSERT((m->oflags & VPO_UNMANAGED) != 0, ("kmem_malloc: page %p is managed", m)); } VM_OBJECT_UNLOCK(kmem_object); diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index c78571d305391..ce899e9078c27 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -48,6 +48,8 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> +#include <sys/kernel.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/sysproto.h> @@ -189,12 +191,13 @@ mmap(td, uap) struct vnode *vp; vm_offset_t addr; vm_size_t size, pageoff; - vm_prot_t prot, maxprot; + vm_prot_t cap_maxprot, prot, maxprot; void *handle; objtype_t handle_type; int flags, error; off_t pos; struct vmspace *vms = td->td_proc->p_vmspace; + cap_rights_t rights; addr = (vm_offset_t) uap->addr; size = uap->len; @@ -274,12 +277,25 @@ mmap(td, uap) handle = NULL; handle_type = OBJT_DEFAULT; maxprot = VM_PROT_ALL; + cap_maxprot = VM_PROT_ALL; } else { /* - * Mapping file, get fp for validation and - * don't let the descriptor disappear on us if we block. + * Mapping file, get fp for validation and don't let the + * descriptor disappear on us if we block. Check capability + * rights, but also return the maximum rights to be combined + * with maxprot later. */ - if ((error = fget(td, uap->fd, &fp)) != 0) + rights = CAP_MMAP; + if (prot & PROT_READ) + rights |= CAP_READ; + if ((flags & MAP_SHARED) != 0) { + if (prot & PROT_WRITE) + rights |= CAP_WRITE; + } + if (prot & PROT_EXEC) + rights |= CAP_MAPEXEC; + if ((error = fget_mmap(td, uap->fd, rights, &cap_maxprot, + &fp)) != 0) goto done; if (fp->f_type == DTYPE_SHM) { handle = fp->f_data; @@ -346,12 +362,14 @@ mmap(td, uap) } } else if (vp->v_type != VCHR || (fp->f_flag & FWRITE) != 0) { maxprot |= VM_PROT_WRITE; + cap_maxprot |= VM_PROT_WRITE; } handle = (void *)vp; handle_type = OBJT_VNODE; } map: td->td_fpop = fp; + maxprot &= cap_maxprot; error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot, flags, handle_type, handle, pos); td->td_fpop = NULL; @@ -883,16 +901,16 @@ RestartScan: if (m->dirty != 0) mincoreinfo |= MINCORE_MODIFIED_OTHER; /* - * The first test for PG_REFERENCED is an + * The first test for PGA_REFERENCED is an * optimization. The second test is * required because a concurrent pmap * operation could clear the last reference - * and set PG_REFERENCED before the call to + * and set PGA_REFERENCED before the call to * pmap_is_referenced(). */ - if ((m->flags & PG_REFERENCED) != 0 || + if ((m->aflags & PGA_REFERENCED) != 0 || pmap_is_referenced(m) || - (m->flags & PG_REFERENCED) != 0) + (m->aflags & PGA_REFERENCED) != 0) mincoreinfo |= MINCORE_REFERENCED_OTHER; } if (object != NULL) diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index b5788f5875799..3de793b84ea92 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -1087,7 +1087,9 @@ shadowlookup: vm_page_unlock(m); goto unlock_tobject; } - KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + KASSERT((m->flags & PG_FICTITIOUS) == 0, + ("vm_object_madvise: page %p is fictitious", m)); + KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("vm_object_madvise: page %p is not managed", m)); if ((m->oflags & VPO_BUSY) || m->busy) { if (advise == MADV_WILLNEED) { @@ -1096,9 +1098,7 @@ shadowlookup: * sleeping so that the page daemon is less * likely to reclaim it. */ - vm_page_lock_queues(); - vm_page_flag_set(m, PG_REFERENCED); - vm_page_unlock_queues(); + vm_page_aflag_set(m, PGA_REFERENCED); } vm_page_unlock(m); if (object != tobject) diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index 8e0c8bbaac301..341c2383abe34 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -67,30 +67,9 @@ * page queue (vm_page_queue[]), regardless of other mutexes or the * busy state of a page. * - * - a hash chain mutex is required when associating or disassociating - * a page from the VM PAGE CACHE hash table (vm_page_buckets), - * regardless of other mutexes or the busy state of a page. + * - The object mutex is held when inserting or removing + * pages from an object (vm_page_insert() or vm_page_remove()). * - * - either a hash chain mutex OR a busied page is required in order - * to modify the page flags. A hash chain mutex must be obtained in - * order to busy a page. A page's flags cannot be modified by a - * hash chain mutex if the page is marked busy. - * - * - The object memq mutex is held when inserting or removing - * pages from an object (vm_page_insert() or vm_page_remove()). This - * is different from the object's main mutex. - * - * Generally speaking, you have to be aware of side effects when running - * vm_page ops. A vm_page_lookup() will return with the hash chain - * locked, whether it was able to lookup the page or not. vm_page_free(), - * vm_page_cache(), vm_page_activate(), and a number of other routines - * will release the hash chain mutex for you. Intermediate manipulation - * routines such as vm_page_flag_set() expect the hash chain to be held - * on entry and the hash chain will remain held on return. - * - * pageq scanning can only occur with the pageq in question locked. - * We have a known bottleneck with the active queue, but the cache - * and free queues are actually arrays already. */ /* @@ -473,33 +452,68 @@ vm_page_startup(vm_offset_t vaddr) return (vaddr); } + +CTASSERT(offsetof(struct vm_page, aflags) % sizeof(uint32_t) == 0); + void -vm_page_flag_set(vm_page_t m, unsigned short bits) +vm_page_aflag_set(vm_page_t m, uint8_t bits) { + uint32_t *addr, val; - mtx_assert(&vm_page_queue_mtx, MA_OWNED); /* - * The PG_WRITEABLE flag can only be set if the page is managed and + * The PGA_WRITEABLE flag can only be set if the page is managed and * VPO_BUSY. Currently, this flag is only set by pmap_enter(). */ - KASSERT((bits & PG_WRITEABLE) == 0 || - ((m->flags & (PG_UNMANAGED | PG_FICTITIOUS)) == 0 && - (m->oflags & VPO_BUSY) != 0), ("PG_WRITEABLE and !VPO_BUSY")); - m->flags |= bits; + KASSERT((bits & PGA_WRITEABLE) == 0 || + (m->oflags & (VPO_UNMANAGED | VPO_BUSY)) == VPO_BUSY, + ("PGA_WRITEABLE and !VPO_BUSY")); + + /* + * We want to use atomic updates for m->aflags, which is a + * byte wide. Not all architectures provide atomic operations + * on the single-byte destination. Punt and access the whole + * 4-byte word with an atomic update. Parallel non-atomic + * updates to the fields included in the update by proximity + * are handled properly by atomics. + */ + addr = (void *)&m->aflags; + MPASS(((uintptr_t)addr & (sizeof(uint32_t) - 1)) == 0); + val = bits; +#if BYTE_ORDER == BIG_ENDIAN + val <<= 24; +#endif + atomic_set_32(addr, val); } void -vm_page_flag_clear(vm_page_t m, unsigned short bits) +vm_page_aflag_clear(vm_page_t m, uint8_t bits) { + uint32_t *addr, val; - mtx_assert(&vm_page_queue_mtx, MA_OWNED); /* - * The PG_REFERENCED flag can only be cleared if the object + * The PGA_REFERENCED flag can only be cleared if the object * containing the page is locked. */ - KASSERT((bits & PG_REFERENCED) == 0 || VM_OBJECT_LOCKED(m->object), - ("PG_REFERENCED and !VM_OBJECT_LOCKED")); - m->flags &= ~bits; + KASSERT((bits & PGA_REFERENCED) == 0 || VM_OBJECT_LOCKED(m->object), + ("PGA_REFERENCED and !VM_OBJECT_LOCKED")); + + /* + * See the comment in vm_page_aflag_set(). + */ + addr = (void *)&m->aflags; + MPASS(((uintptr_t)addr & (sizeof(uint32_t) - 1)) == 0); + val = bits; +#if BYTE_ORDER == BIG_ENDIAN + val <<= 24; +#endif + atomic_clear_32(addr, val); +} + +void +vm_page_reference(vm_page_t m) +{ + + vm_page_aflag_set(m, PGA_REFERENCED); } void @@ -636,7 +650,7 @@ vm_page_getfake(vm_paddr_t paddr, vm_memattr_t memattr) /* Fictitious pages don't use "segind". */ m->flags = PG_FICTITIOUS; /* Fictitious pages don't use "order" or "pool". */ - m->oflags = VPO_BUSY; + m->oflags = VPO_BUSY | VPO_UNMANAGED; m->wire_count = 1; pmap_page_set_memattr(m, memattr); return (m); @@ -874,7 +888,7 @@ vm_page_insert(vm_page_t m, vm_object_t object, vm_pindex_t pindex) * Since we are inserting a new and possibly dirty page, * update the object's OBJ_MIGHTBEDIRTY flag. */ - if (m->flags & PG_WRITEABLE) + if (m->aflags & PGA_WRITEABLE) vm_object_set_writeable_dirty(object); } @@ -896,7 +910,7 @@ vm_page_remove(vm_page_t m) vm_object_t object; vm_page_t root; - if ((m->flags & PG_UNMANAGED) == 0) + if ((m->oflags & VPO_UNMANAGED) == 0) vm_page_lock_assert(m, MA_OWNED); if ((object = m->object) == NULL) return; @@ -1388,14 +1402,15 @@ vm_page_alloc(vm_object_t object, vm_pindex_t pindex, int req) if (req & VM_ALLOC_ZERO) flags = PG_ZERO; } - if (object == NULL || object->type == OBJT_PHYS) - flags |= PG_UNMANAGED; m->flags = flags; mtx_unlock(&vm_page_queue_free_mtx); - if (req & (VM_ALLOC_NOBUSY | VM_ALLOC_NOOBJ)) - m->oflags = 0; + m->aflags = 0; + if (object == NULL || object->type == OBJT_PHYS) + m->oflags = VPO_UNMANAGED; else - m->oflags = VPO_BUSY; + m->oflags = 0; + if ((req & (VM_ALLOC_NOBUSY | VM_ALLOC_NOOBJ)) == 0) + m->oflags |= VPO_BUSY; if (req & VM_ALLOC_WIRED) { /* * The page lock is not required for wiring a page until that @@ -1479,8 +1494,9 @@ vm_page_alloc_init(vm_page_t m) if (m->flags & PG_ZERO) vm_page_zero_count--; /* Don't clear the PG_ZERO flag; we'll need it later. */ - m->flags = PG_UNMANAGED | (m->flags & PG_ZERO); - m->oflags = 0; + m->flags &= PG_ZERO; + m->aflags = 0; + m->oflags = VPO_UNMANAGED; /* Unmanaged pages don't use "act_count". */ return (drop); } @@ -1670,7 +1686,7 @@ vm_page_activate(vm_page_t m) vm_page_lock_assert(m, MA_OWNED); VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if ((queue = m->queue) != PQ_ACTIVE) { - if (m->wire_count == 0 && (m->flags & PG_UNMANAGED) == 0) { + if (m->wire_count == 0 && (m->oflags & VPO_UNMANAGED) == 0) { if (m->act_count < ACT_INIT) m->act_count = ACT_INIT; vm_page_lock_queues(); @@ -1736,7 +1752,7 @@ void vm_page_free_toq(vm_page_t m) { - if ((m->flags & PG_UNMANAGED) == 0) { + if ((m->oflags & VPO_UNMANAGED) == 0) { vm_page_lock_assert(m, MA_OWNED); KASSERT(!pmap_page_is_mapped(m), ("vm_page_free_toq: freeing mapped page %p", m)); @@ -1754,7 +1770,7 @@ vm_page_free_toq(vm_page_t m) * callback routine until after we've put the page on the * appropriate free queue. */ - if ((m->flags & PG_UNMANAGED) == 0) + if ((m->oflags & VPO_UNMANAGED) == 0) vm_pageq_remove(m); vm_page_remove(m); @@ -1834,7 +1850,7 @@ vm_page_wire(vm_page_t m) return; } if (m->wire_count == 0) { - if ((m->flags & PG_UNMANAGED) == 0) + if ((m->oflags & VPO_UNMANAGED) == 0) vm_pageq_remove(m); atomic_add_int(&cnt.v_wire_count, 1); } @@ -1862,7 +1878,7 @@ void vm_page_unwire(vm_page_t m, int activate) { - if ((m->flags & PG_UNMANAGED) == 0) + if ((m->oflags & VPO_UNMANAGED) == 0) vm_page_lock_assert(m, MA_OWNED); if ((m->flags & PG_FICTITIOUS) != 0) { KASSERT(m->wire_count == 1, @@ -1873,14 +1889,14 @@ vm_page_unwire(vm_page_t m, int activate) m->wire_count--; if (m->wire_count == 0) { atomic_subtract_int(&cnt.v_wire_count, 1); - if ((m->flags & PG_UNMANAGED) != 0 || + if ((m->oflags & VPO_UNMANAGED) != 0 || m->object == NULL) return; vm_page_lock_queues(); if (activate) vm_page_enqueue(PQ_ACTIVE, m); else { - vm_page_flag_clear(m, PG_WINATCFLS); + m->flags &= ~PG_WINATCFLS; vm_page_enqueue(PQ_INACTIVE, m); } vm_page_unlock_queues(); @@ -1921,9 +1937,9 @@ _vm_page_deactivate(vm_page_t m, int athead) */ if ((queue = m->queue) == PQ_INACTIVE) return; - if (m->wire_count == 0 && (m->flags & PG_UNMANAGED) == 0) { + if (m->wire_count == 0 && (m->oflags & VPO_UNMANAGED) == 0) { vm_page_lock_queues(); - vm_page_flag_clear(m, PG_WINATCFLS); + m->flags &= ~PG_WINATCFLS; if (queue != PQ_NONE) vm_page_queue_remove(queue, m); if (athead) @@ -1962,7 +1978,7 @@ vm_page_try_to_cache(vm_page_t m) vm_page_lock_assert(m, MA_OWNED); VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if (m->dirty || m->hold_count || m->busy || m->wire_count || - (m->oflags & VPO_BUSY) || (m->flags & PG_UNMANAGED)) + (m->oflags & (VPO_BUSY | VPO_UNMANAGED)) != 0) return (0); pmap_remove_all(m); if (m->dirty) @@ -1985,7 +2001,7 @@ vm_page_try_to_free(vm_page_t m) if (m->object != NULL) VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); if (m->dirty || m->hold_count || m->busy || m->wire_count || - (m->oflags & VPO_BUSY) || (m->flags & PG_UNMANAGED)) + (m->oflags & (VPO_BUSY | VPO_UNMANAGED)) != 0) return (0); pmap_remove_all(m); if (m->dirty) @@ -2010,7 +2026,7 @@ vm_page_cache(vm_page_t m) vm_page_lock_assert(m, MA_OWNED); object = m->object; VM_OBJECT_LOCK_ASSERT(object, MA_OWNED); - if ((m->flags & PG_UNMANAGED) || (m->oflags & VPO_BUSY) || m->busy || + if ((m->oflags & (VPO_UNMANAGED | VPO_BUSY)) || m->busy || m->hold_count || m->wire_count) panic("vm_page_cache: attempting to cache busy page"); pmap_remove_all(m); @@ -2156,15 +2172,13 @@ vm_page_dontneed(vm_page_t m) * * Perform the pmap_clear_reference() first. Otherwise, a concurrent * pmap operation, such as pmap_remove(), could clear a reference in - * the pmap and set PG_REFERENCED on the page before the + * the pmap and set PGA_REFERENCED on the page before the * pmap_clear_reference() had completed. Consequently, the page would * appear referenced based upon an old reference that occurred before * this function ran. */ pmap_clear_reference(m); - vm_page_lock_queues(); - vm_page_flag_clear(m, PG_REFERENCED); - vm_page_unlock_queues(); + vm_page_aflag_clear(m, PGA_REFERENCED); if (m->dirty == 0 && pmap_is_modified(m)) vm_page_dirty(m); @@ -2213,8 +2227,7 @@ retrylookup: * sleeping so that the page daemon is less * likely to reclaim it. */ - vm_page_lock_queues(); - vm_page_flag_set(m, PG_REFERENCED); + vm_page_aflag_set(m, PGA_REFERENCED); vm_page_sleep(m, "pgrbwt"); goto retrylookup; } else { @@ -2329,11 +2342,11 @@ vm_page_clear_dirty_mask(vm_page_t m, int pagebits) /* * If the object is locked and the page is neither VPO_BUSY nor - * PG_WRITEABLE, then the page's dirty field cannot possibly be + * PGA_WRITEABLE, then the page's dirty field cannot possibly be * set by a concurrent pmap operation. */ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); - if ((m->oflags & VPO_BUSY) == 0 && (m->flags & PG_WRITEABLE) == 0) + if ((m->oflags & VPO_BUSY) == 0 && (m->aflags & PGA_WRITEABLE) == 0) m->dirty &= ~pagebits; else { #if defined(__amd64__) || defined(__i386__) || defined(__ia64__) @@ -2657,7 +2670,8 @@ vm_page_cowsetup(vm_page_t m) { vm_page_lock_assert(m, MA_OWNED); - if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0 || + if ((m->flags & PG_FICTITIOUS) != 0 || + (m->oflags & VPO_UNMANAGED) != 0 || m->cow == USHRT_MAX - 1 || !VM_OBJECT_TRYLOCK(m->object)) return (EBUSY); m->cow++; diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index e852313edc80a..5431d7986a0e9 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -125,12 +125,13 @@ struct vm_page { struct md_page md; /* machine dependant stuff */ uint8_t queue; /* page queue index (P,Q) */ int8_t segind; - u_short flags; /* see below */ + short hold_count; /* page hold count (P) */ uint8_t order; /* index of the buddy queue */ uint8_t pool; u_short cow; /* page cow mapping count (P) */ u_int wire_count; /* wired down maps refs (P) */ - short hold_count; /* page hold count (P) */ + uint8_t aflags; /* access is atomic */ + uint8_t flags; /* see below, often immutable after alloc */ u_short oflags; /* page flags (O) */ u_char act_count; /* page usage count (O) */ u_char busy; /* page busy count (O) */ @@ -157,9 +158,18 @@ struct vm_page { * * Access to these page flags is synchronized by the lock on the object * containing the page (O). + * + * Note: VPO_UNMANAGED (used by OBJT_DEVICE, OBJT_PHYS and OBJT_SG) + * indicates that the page is not under PV management but + * otherwise should be treated as a normal page. Pages not + * under PV management cannot be paged out via the + * object/vm_page_t because there is no knowledge of their pte + * mappings, and such pages are also not on any PQ queue. + * */ #define VPO_BUSY 0x0001 /* page is in transit */ #define VPO_WANTED 0x0002 /* someone is waiting for page */ +#define VPO_UNMANAGED 0x0004 /* No PV management for page */ #define VPO_SWAPINPROG 0x0200 /* swap I/O in progress on page */ #define VPO_NOSYNC 0x0400 /* do not collect for syncer */ @@ -216,29 +226,29 @@ extern struct vpglocks pa_lock[]; /* * These are the flags defined for vm_page. * - * Note: PG_UNMANAGED (used by OBJT_PHYS) indicates that the page is - * not under PV management but otherwise should be treated as a - * normal page. Pages not under PV management cannot be paged out - * via the object/vm_page_t because there is no knowledge of their - * pte mappings, nor can they be removed from their objects via - * the object, and such pages are also not on any PQ queue. + * aflags are updated by atomic accesses. Use the vm_page_aflag_set() + * and vm_page_aflag_clear() functions to set and clear the flags. * - * PG_REFERENCED may be cleared only if the object containing the page is + * PGA_REFERENCED may be cleared only if the object containing the page is * locked. * - * PG_WRITEABLE is set exclusively on managed pages by pmap_enter(). When it + * PGA_WRITEABLE is set exclusively on managed pages by pmap_enter(). When it * does so, the page must be VPO_BUSY. */ -#define PG_CACHED 0x0001 /* page is cached */ -#define PG_FREE 0x0002 /* page is free */ -#define PG_WINATCFLS 0x0004 /* flush dirty page on inactive q */ -#define PG_FICTITIOUS 0x0008 /* physical page doesn't exist (O) */ -#define PG_WRITEABLE 0x0010 /* page is mapped writeable */ -#define PG_ZERO 0x0040 /* page is zeroed */ -#define PG_REFERENCED 0x0080 /* page has been referenced */ -#define PG_UNMANAGED 0x0800 /* No PV management for page */ -#define PG_MARKER 0x1000 /* special queue marker page */ -#define PG_SLAB 0x2000 /* object pointer is actually a slab */ +#define PGA_WRITEABLE 0x01 /* page may be mapped writeable */ +#define PGA_REFERENCED 0x02 /* page has been referenced */ + +/* + * Page flags. If changed at any other time than page allocation or + * freeing, the modification must be protected by the vm_page lock. + */ +#define PG_CACHED 0x01 /* page is cached */ +#define PG_FREE 0x02 /* page is free */ +#define PG_FICTITIOUS 0x04 /* physical page doesn't exist (O) */ +#define PG_ZERO 0x08 /* page is zeroed */ +#define PG_MARKER 0x10 /* special queue marker page */ +#define PG_SLAB 0x20 /* object pointer is actually a slab */ +#define PG_WINATCFLS 0x40 /* flush dirty page on inactive q */ /* * Misc constants. @@ -340,8 +350,8 @@ extern struct vpglocks vm_page_queue_lock; #define VM_ALLOC_COUNT_SHIFT 16 #define VM_ALLOC_COUNT(count) ((count) << VM_ALLOC_COUNT_SHIFT) -void vm_page_flag_set(vm_page_t m, unsigned short bits); -void vm_page_flag_clear(vm_page_t m, unsigned short bits); +void vm_page_aflag_set(vm_page_t m, uint8_t bits); +void vm_page_aflag_clear(vm_page_t m, uint8_t bits); void vm_page_busy(vm_page_t m); void vm_page_flash(vm_page_t m); void vm_page_io_start(vm_page_t m); @@ -376,6 +386,7 @@ vm_page_t vm_page_next(vm_page_t m); int vm_page_pa_tryrelock(pmap_t, vm_paddr_t, vm_paddr_t *); vm_page_t vm_page_prev(vm_page_t m); void vm_page_putfake(vm_page_t m); +void vm_page_reference(vm_page_t m); void vm_page_remove (vm_page_t); void vm_page_rename (vm_page_t, vm_object_t, vm_pindex_t); void vm_page_requeue(vm_page_t m); diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index e9c9927ad2c0b..5dd450e1bb3fd 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -497,7 +497,7 @@ vm_pageout_flush(vm_page_t *mc, int count, int flags, int mreq, int *prunlen) vm_page_t mt = mc[i]; KASSERT(pageout_status[i] == VM_PAGER_PEND || - (mt->flags & PG_WRITEABLE) == 0, + (mt->aflags & PGA_WRITEABLE) == 0, ("vm_pageout_flush: page %p is not write protected", mt)); switch (pageout_status[i]) { case VM_PAGER_OK: @@ -597,12 +597,10 @@ vm_pageout_object_deactivate_pages(pmap_t pmap, vm_object_t first_object, continue; } actcount = pmap_ts_referenced(p); - if ((p->flags & PG_REFERENCED) != 0) { + if ((p->aflags & PGA_REFERENCED) != 0) { if (actcount == 0) actcount = 1; - vm_page_lock_queues(); - vm_page_flag_clear(p, PG_REFERENCED); - vm_page_unlock_queues(); + vm_page_aflag_clear(p, PGA_REFERENCED); } if (p->queue != PQ_ACTIVE && actcount != 0) { vm_page_activate(p); @@ -846,7 +844,7 @@ rescan0: * references. */ if (object->ref_count == 0) { - vm_page_flag_clear(m, PG_REFERENCED); + vm_page_aflag_clear(m, PGA_REFERENCED); KASSERT(!pmap_page_is_mapped(m), ("vm_pageout_scan: page %p is mapped", m)); @@ -859,7 +857,7 @@ rescan0: * level VM system not knowing anything about existing * references. */ - } else if (((m->flags & PG_REFERENCED) == 0) && + } else if (((m->aflags & PGA_REFERENCED) == 0) && (actcount = pmap_ts_referenced(m))) { vm_page_activate(m); vm_page_unlock(m); @@ -874,8 +872,8 @@ rescan0: * "activation count" higher than normal so that we will less * likely place pages back onto the inactive queue again. */ - if ((m->flags & PG_REFERENCED) != 0) { - vm_page_flag_clear(m, PG_REFERENCED); + if ((m->aflags & PGA_REFERENCED) != 0) { + vm_page_aflag_clear(m, PGA_REFERENCED); actcount = pmap_ts_referenced(m); vm_page_activate(m); vm_page_unlock(m); @@ -891,7 +889,7 @@ rescan0: * be updated. */ if (m->dirty != VM_PAGE_BITS_ALL && - (m->flags & PG_WRITEABLE) != 0) { + (m->aflags & PGA_WRITEABLE) != 0) { /* * Avoid a race condition: Unless write access is * removed from the page, another processor could @@ -938,7 +936,7 @@ rescan0: * before being freed. This significantly extends * the thrash point for a heavily loaded machine. */ - vm_page_flag_set(m, PG_WINATCFLS); + m->flags |= PG_WINATCFLS; vm_page_requeue(m); } else if (maxlaunder > 0) { /* @@ -1178,7 +1176,7 @@ unlock_and_continue: */ actcount = 0; if (object->ref_count != 0) { - if (m->flags & PG_REFERENCED) { + if (m->aflags & PGA_REFERENCED) { actcount += 1; } actcount += pmap_ts_referenced(m); @@ -1192,7 +1190,7 @@ unlock_and_continue: /* * Since we have "tested" this bit, we need to clear it now. */ - vm_page_flag_clear(m, PG_REFERENCED); + vm_page_aflag_clear(m, PGA_REFERENCED); /* * Only if an object is currently being used, do we use the @@ -1435,8 +1433,8 @@ vm_pageout_page_stats() } actcount = 0; - if (m->flags & PG_REFERENCED) { - vm_page_flag_clear(m, PG_REFERENCED); + if (m->aflags & PGA_REFERENCED) { + vm_page_aflag_clear(m, PGA_REFERENCED); actcount += 1; } diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index 23ade6352acf7..cb652f7e186a7 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -1132,7 +1132,7 @@ vnode_pager_generic_putpages(struct vnode *vp, vm_page_t *ma, int bytecount, m = ma[ncount - 1]; KASSERT(m->busy > 0, ("vnode_pager_generic_putpages: page %p is not busy", m)); - KASSERT((m->flags & PG_WRITEABLE) == 0, + KASSERT((m->aflags & PGA_WRITEABLE) == 0, ("vnode_pager_generic_putpages: page %p is not read-only", m)); vm_page_clear_dirty(m, pgoff, PAGE_SIZE - pgoff); diff --git a/sys/x86/acpica/acpi_apm.c b/sys/x86/acpica/acpi_apm.c index 02be6e01fe5d9..776b1be602a13 100644 --- a/sys/x86/acpica/acpi_apm.c +++ b/sys/x86/acpica/acpi_apm.c @@ -297,6 +297,7 @@ apmclose(struct cdev *dev, int flag, int fmt, struct thread *td) /* Remove this clone's data from the list and free it. */ ACPI_LOCK(acpi); STAILQ_REMOVE(&acpi_sc->apm_cdevs, clone, apm_clone_data, entries); + seldrain(&clone->sel_read); knlist_destroy(&clone->sel_read.si_note); ACPI_UNLOCK(acpi); free(clone, M_APMDEV); diff --git a/sys/x86/x86/tsc.c b/sys/x86/x86/tsc.c index 0b383bf7ef217..4d1618f14b796 100644 --- a/sys/x86/x86/tsc.c +++ b/sys/x86/x86/tsc.c @@ -464,11 +464,16 @@ init_TSC_tc(void) * synchronized. If the user is sure that the system has synchronized * TSCs, set kern.timecounter.smp_tsc tunable to a non-zero value. * We also limit the frequency even lower to avoid "temporal anomalies" - * as much as possible. + * as much as possible. The TSC seems unreliable in virtualized SMP + * environments, so it is set to a negative quality in those cases. */ if (smp_cpus > 1) { - tsc_timecounter.tc_quality = test_smp_tsc(); - max_freq >>= 8; + if (vm_guest != 0) { + tsc_timecounter.tc_quality = -100; + } else { + tsc_timecounter.tc_quality = test_smp_tsc(); + max_freq >>= 8; + } } else #endif if (tsc_is_invariant) |
