Index: sys/powerpc/conf/DEFAULTS =================================================================== --- sys/powerpc/conf/DEFAULTS (revision 255602) +++ sys/powerpc/conf/DEFAULTS (working copy) @@ -9,6 +9,7 @@ # UART chips on this platform device uart_ns8250 +options GEOM_PART_BSD options GEOM_PART_MBR options NEW_PCIB Index: sys/powerpc/conf/GENERIC =================================================================== --- sys/powerpc/conf/GENERIC (revision 255602) +++ sys/powerpc/conf/GENERIC (working copy) @@ -30,6 +30,7 @@ options POWERMAC #NewWorld Apple PowerMacs options PSIM #GDB PSIM ppc simulator options MAMBO #IBM Mambo Full System Simulator +options PSERIES #PAPR-compliant systems options SCHED_ULE #ULE scheduler options PREEMPTION #Enable kernel thread preemption Index: sys/powerpc/conf/GENERIC64 =================================================================== --- sys/powerpc/conf/GENERIC64 (revision 255602) +++ sys/powerpc/conf/GENERIC64 (working copy) @@ -30,6 +30,7 @@ options POWERMAC #NewWorld Apple PowerMacs options PS3 #Sony Playstation 3 options MAMBO #IBM Mambo Full System Simulator +options PSERIES #PAPR-compliant systems (e.g. IBM p) options SCHED_ULE #ULE scheduler options PREEMPTION #Enable kernel thread preemption @@ -131,6 +132,9 @@ device uart_z8530 # Ethernet hardware +device em # Intel PRO/1000 Gigabit Ethernet Family +device igb # Intel PRO/1000 PCIE Server Gigabit Family +device ixgbe # Intel PRO/10GbE PCIE Ethernet Family device glc # Sony Playstation 3 Ethernet # PCI Ethernet NICs that use the common MII bus controller code. @@ -139,6 +143,8 @@ device gem # Sun GEM/Sun ERI/Apple GMAC device dc # DEC/Intel 21143 and various workalikes device fxp # Intel EtherExpress PRO/100B (82557, 82558) +device re # RealTek 8139C+/8169/8169S/8110S +device rl # RealTek 8129/8139 # Pseudo devices. device loop # Network loopback Index: sys/powerpc/include/spr.h =================================================================== --- sys/powerpc/include/spr.h (revision 255602) +++ sys/powerpc/include/spr.h (working copy) @@ -168,6 +168,8 @@ #define IBMPOWER3PLUS 0x0041 #define IBM970MP 0x0044 #define IBM970GX 0x0045 +#define IBMPOWER7PLUS 0x004a +#define IBMPOWER8 0x004b #define MPC860 0x0050 #define IBMCELLBE 0x0070 #define MPC8240 0x0081 Index: sys/powerpc/ofw/ofw_syscons.c =================================================================== --- sys/powerpc/ofw/ofw_syscons.c (revision 255602) +++ sys/powerpc/ofw/ofw_syscons.c (working copy) @@ -264,6 +264,10 @@ } else return (0); + if (OF_getproplen(node, "height") != sizeof(sc->sc_height) || + OF_getproplen(node, "width") != sizeof(sc->sc_width)) + return (0); + sc->sc_depth = depth; sc->sc_node = node; sc->sc_console = 1; @@ -278,6 +282,8 @@ * * XXX We assume #address-cells is 1 at this point. */ + if (OF_getproplen(node, "address") != sizeof(fb_phys)) + return (0); OF_getprop(node, "address", &fb_phys, sizeof(fb_phys)); bus_space_map(&bs_be_tag, fb_phys, sc->sc_height * sc->sc_stride, Index: sys/powerpc/powerpc/busdma_machdep.c =================================================================== --- sys/powerpc/powerpc/busdma_machdep.c (revision 255614) +++ sys/powerpc/powerpc/busdma_machdep.c (working copy) @@ -847,13 +847,16 @@ map->nsegs = nsegs; if (segs != NULL) memcpy(map->segments, segs, map->nsegs*sizeof(segs[0])); - else - segs = map->segments; if (dmat->iommu != NULL) IOMMU_MAP(dmat->iommu, map->segments, &map->nsegs, dmat->lowaddr, dmat->highaddr, dmat->alignment, dmat->boundary, dmat->iommu_cookie); + if (segs != NULL) + memcpy(segs, map->segments, map->nsegs*sizeof(segs[0])); + else + segs = map->segments; + return (segs); } Index: sys/powerpc/powerpc/cpu.c =================================================================== --- sys/powerpc/powerpc/cpu.c (revision 255602) +++ sys/powerpc/powerpc/cpu.c (working copy) @@ -141,6 +141,12 @@ { "IBM POWER7", IBMPOWER7, REVFMT_MAJMIN, PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, NULL }, + { "IBM POWER7+", IBMPOWER7PLUS, REVFMT_MAJMIN, + PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, + NULL }, + { "IBM POWER8", IBMPOWER8, REVFMT_MAJMIN, + PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, + NULL }, { "Motorola PowerPC 7400", MPC7400, REVFMT_MAJMIN, PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, cpu_6xx_setup }, { "Motorola PowerPC 7410", MPC7410, REVFMT_MAJMIN, Index: sys/powerpc/pseries/mmu_phyp.c =================================================================== --- sys/powerpc/pseries/mmu_phyp.c (revision 0) +++ sys/powerpc/pseries/mmu_phyp.c (working copy) @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2010 Andreas Tobler + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mmu_if.h" +#include "moea64_if.h" + +#include "phyp-hvcall.h" + +extern int n_slbs; + +/* + * Kernel MMU interface + */ + +static void mphyp_bootstrap(mmu_t mmup, vm_offset_t kernelstart, + vm_offset_t kernelend); +static void mphyp_cpu_bootstrap(mmu_t mmup, int ap); +static void mphyp_pte_synch(mmu_t, uintptr_t pt, struct lpte *pvo_pt); +static void mphyp_pte_clear(mmu_t, uintptr_t pt, struct lpte *pvo_pt, + uint64_t vpn, u_int64_t ptebit); +static void mphyp_pte_unset(mmu_t, uintptr_t pt, struct lpte *pvo_pt, + uint64_t vpn); +static void mphyp_pte_change(mmu_t, uintptr_t pt, struct lpte *pvo_pt, + uint64_t vpn); +static int mphyp_pte_insert(mmu_t, u_int ptegidx, struct lpte *pvo_pt); +static uintptr_t mphyp_pvo_to_pte(mmu_t, const struct pvo_entry *pvo); + +#define VSID_HASH_MASK 0x0000007fffffffffULL + + +static mmu_method_t mphyp_methods[] = { + MMUMETHOD(mmu_bootstrap, mphyp_bootstrap), + MMUMETHOD(mmu_cpu_bootstrap, mphyp_cpu_bootstrap), + + MMUMETHOD(moea64_pte_synch, mphyp_pte_synch), + MMUMETHOD(moea64_pte_clear, mphyp_pte_clear), + MMUMETHOD(moea64_pte_unset, mphyp_pte_unset), + MMUMETHOD(moea64_pte_change, mphyp_pte_change), + MMUMETHOD(moea64_pte_insert, mphyp_pte_insert), + MMUMETHOD(moea64_pvo_to_pte, mphyp_pvo_to_pte), + + { 0, 0 } +}; + +MMU_DEF_INHERIT(pseries_mmu, "mmu_phyp", mphyp_methods, 0, oea64_mmu); + +static void +mphyp_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) +{ + uint64_t final_pteg_count = 0; + char buf[8]; + uint32_t prop[2]; + uint32_t nptlp, shift = 0, slb_encoding = 0; + phandle_t dev, node, root; + int idx, len, res; + + moea64_early_bootstrap(mmup, kernelstart, kernelend); + + root = OF_peer(0); + + dev = OF_child(root); + while (dev != 0) { + res = OF_getprop(dev, "name", buf, sizeof(buf)); + if (res > 0 && strcmp(buf, "cpus") == 0) + break; + dev = OF_peer(dev); + } + + node = OF_child(dev); + + while (node != 0) { + res = OF_getprop(node, "device_type", buf, sizeof(buf)); + if (res > 0 && strcmp(buf, "cpu") == 0) + break; + node = OF_peer(node); + } + + res = OF_getprop(node, "ibm,pft-size", prop, sizeof(prop)); + if (res <= 0) + panic("mmu_phyp: unknown PFT size"); + final_pteg_count = 1 << prop[1]; + res = OF_getprop(node, "ibm,slb-size", prop, sizeof(prop[0])); + if (res > 0) + n_slbs = prop[0]; + + moea64_pteg_count = final_pteg_count / sizeof(struct lpteg); + + /* + * Scan the large page size property for PAPR compatible machines. + * See PAPR D.5 Changes to Section 5.1.4, 'CPU Node Properties' + * for the encoding of the property. + */ + + len = OF_getproplen(node, "ibm,segment-page-sizes"); + if (len > 0) { + /* + * We have to use a variable length array on the stack + * since we have very limited stack space. + */ + cell_t arr[len/sizeof(cell_t)]; + res = OF_getprop(node, "ibm,segment-page-sizes", &arr, + sizeof(arr)); + len /= 4; + idx = 0; + while (len > 0) { + shift = arr[idx]; + slb_encoding = arr[idx + 1]; + nptlp = arr[idx + 2]; + idx += 3; + len -= 3; + while (len > 0 && nptlp) { + idx += 2; + len -= 2; + nptlp--; + } + } + moea64_large_page_shift = shift; + moea64_large_page_size = 1 << shift; + } + + moea64_mid_bootstrap(mmup, kernelstart, kernelend); + moea64_late_bootstrap(mmup, kernelstart, kernelend); +} + +static void +mphyp_cpu_bootstrap(mmu_t mmup, int ap) +{ + struct slb *slb = PCPU_GET(slb); + register_t seg0; + int i; + + /* + * Install kernel SLB entries + */ + + __asm __volatile ("slbia"); + __asm __volatile ("slbmfee %0,%1; slbie %0;" : "=r"(seg0) : "r"(0)); + for (i = 0; i < 64; i++) { + if (!(slb[i].slbe & SLBE_VALID)) + continue; + + __asm __volatile ("slbmte %0, %1" :: + "r"(slb[i].slbv), "r"(slb[i].slbe)); + } +} + +static void +mphyp_pte_synch(mmu_t mmu, uintptr_t slot, struct lpte *pvo_pt) +{ + struct lpte pte; + uint64_t junk; + + phyp_pft_hcall(H_READ, 0, slot, 0, 0, &pte.pte_hi, &pte.pte_lo, + &junk); + + pvo_pt->pte_lo |= pte.pte_lo & (LPTE_CHG | LPTE_REF); +} + +static void +mphyp_pte_clear(mmu_t mmu, uintptr_t slot, struct lpte *pvo_pt, uint64_t vpn, + u_int64_t ptebit) +{ + + if (ptebit & LPTE_CHG) + phyp_hcall(H_CLEAR_MOD, 0, slot); + if (ptebit & LPTE_REF) + phyp_hcall(H_CLEAR_REF, 0, slot); +} + +static void +mphyp_pte_unset(mmu_t mmu, uintptr_t slot, struct lpte *pvo_pt, uint64_t vpn) +{ + + /* XXX: last argument can check the VPN -- set flag to enable */ + phyp_hcall(H_REMOVE, 0, slot, vpn); +} + +static void +mphyp_pte_change(mmu_t mmu, uintptr_t slot, struct lpte *pvo_pt, uint64_t vpn) +{ + struct lpte evicted; + uint64_t index, junk; + int64_t result; + + /* + * NB: this is protected by the global table lock, so this two-step + * is safe, except for the scratch-page case. No CPUs on which we run + * this code should be using scratch pages. + */ + KASSERT(!(pvo_pt->pte_hi & LPTE_LOCKED), + ("Locked pages not supported on PHYP")); + + /* XXX: optimization using H_PROTECT for common case? */ + result = phyp_hcall(H_REMOVE, 0, slot, vpn); + if (result != H_SUCCESS) + panic("mphyp_pte_change() invalidation failure: %ld\n", result); + result = phyp_pft_hcall(H_ENTER, H_EXACT, slot, pvo_pt->pte_hi, + pvo_pt->pte_lo, &index, &evicted.pte_lo, &junk); + if (result != H_SUCCESS) + panic("mphyp_pte_change() insertion failure: %ld\n", result); +} + +static __inline int +mphyp_pte_spillable_ident(u_int ptegidx, struct lpte *to_evict) +{ + uint64_t slot, junk, k; + struct lpte pt; + int i, j; + + /* Start at a random slot */ + i = mftb() % 8; + k = -1; + for (j = 0; j < 8; j++) { + slot = (ptegidx << 3) + (i + j) % 8; + phyp_pft_hcall(H_READ, 0, slot, 0, 0, &pt.pte_hi, &pt.pte_lo, + &junk); + + if (pt.pte_hi & LPTE_SWBITS) + continue; + + /* This is a candidate, so remember it */ + k = slot; + + /* Try to get a page that has not been used lately */ + if (!(pt.pte_lo & LPTE_REF)) { + memcpy(to_evict, &pt, sizeof(struct lpte)); + return (k); + } + } + + phyp_pft_hcall(H_READ, 0, slot, 0, 0, &to_evict->pte_hi, + &to_evict->pte_lo, &junk); + return (k); +} + +static int +mphyp_pte_insert(mmu_t mmu, u_int ptegidx, struct lpte *pvo_pt) +{ + int64_t result; + struct lpte evicted; + struct pvo_entry *pvo; + uint64_t index, junk; + u_int pteg_bktidx; + + /* Check for locked pages, which we can't support on this system */ + KASSERT(!(pvo_pt->pte_hi & LPTE_LOCKED), + ("Locked pages not supported on PHYP")); + + /* Initialize PTE */ + pvo_pt->pte_hi |= LPTE_VALID; + pvo_pt->pte_hi &= ~LPTE_HID; + evicted.pte_hi = 0; + + /* + * First try primary hash. + */ + pteg_bktidx = ptegidx; + result = phyp_pft_hcall(H_ENTER, 0, pteg_bktidx << 3, pvo_pt->pte_hi, + pvo_pt->pte_lo, &index, &evicted.pte_lo, &junk); + if (result == H_SUCCESS) + return (index & 0x07); + KASSERT(result == H_PTEG_FULL, ("Page insertion error: %ld " + "(ptegidx: %#x/%#x, PTE %#lx/%#lx", result, ptegidx, + moea64_pteg_count, pvo_pt->pte_hi, pvo_pt->pte_lo)); + + /* + * Next try secondary hash. + */ + pteg_bktidx ^= moea64_pteg_mask; + pvo_pt->pte_hi |= LPTE_HID; + result = phyp_pft_hcall(H_ENTER, 0, pteg_bktidx << 3, + pvo_pt->pte_hi, pvo_pt->pte_lo, &index, &evicted.pte_lo, &junk); + if (result == H_SUCCESS) + return (index & 0x07); + KASSERT(result == H_PTEG_FULL, ("Secondary page insertion error: %ld", + result)); + + /* + * Out of luck. Find a PTE to sacrifice. + */ + pteg_bktidx = ptegidx; + index = mphyp_pte_spillable_ident(pteg_bktidx, &evicted); + if (index == -1L) { + pteg_bktidx ^= moea64_pteg_mask; + index = mphyp_pte_spillable_ident(pteg_bktidx, &evicted); + } + + if (index == -1L) { + /* No freeable slots in either PTEG? We're hosed. */ + panic("mphyp_pte_insert: overflow"); + return (-1); + } + + if (pteg_bktidx == ptegidx) + pvo_pt->pte_hi &= ~LPTE_HID; + else + pvo_pt->pte_hi |= LPTE_HID; + + /* + * Synchronize the sacrifice PTE with its PVO, then mark both + * invalid. The PVO will be reused when/if the VM system comes + * here after a fault. + */ + + if (evicted.pte_hi & LPTE_HID) + pteg_bktidx ^= moea64_pteg_mask; /* PTEs indexed by primary */ + + LIST_FOREACH(pvo, &moea64_pvo_table[pteg_bktidx], pvo_olink) { + if (pvo->pvo_pte.lpte.pte_hi == evicted.pte_hi) { + KASSERT(pvo->pvo_pte.lpte.pte_hi & LPTE_VALID, + ("Invalid PVO for valid PTE!")); + phyp_hcall(H_REMOVE, 0, index, 0); + PVO_PTEGIDX_CLR(pvo); + moea64_pte_overflow++; + break; + } + } + + KASSERT(pvo->pvo_pte.lpte.pte_hi == evicted.pte_hi, + ("Unable to find PVO for spilled PTE")); + + /* + * Set the new PTE. + */ + result = phyp_pft_hcall(H_ENTER, H_EXACT, index, pvo_pt->pte_hi, + pvo_pt->pte_lo, &index, &evicted.pte_lo, &junk); + if (result == H_SUCCESS) + return (index & 0x07); + + panic("Page replacement error: %ld", result); + return (-1); +} + +static __inline u_int +va_to_pteg(uint64_t vsid, vm_offset_t addr, int large) +{ + uint64_t hash; + int shift; + + shift = large ? moea64_large_page_shift : ADDR_PIDX_SHFT; + hash = (vsid & VSID_HASH_MASK) ^ (((uint64_t)addr & ADDR_PIDX) >> + shift); + return (hash & moea64_pteg_mask); +} + +static uintptr_t +mphyp_pvo_to_pte(mmu_t mmu, const struct pvo_entry *pvo) +{ + uint64_t vsid; + u_int ptegidx; + + /* If the PTEG index is not set, then there is no page table entry */ + if (!PVO_PTEGIDX_ISSET(pvo)) + return (-1); + + vsid = PVO_VSID(pvo); + ptegidx = va_to_pteg(vsid, PVO_VADDR(pvo), pvo->pvo_vaddr & PVO_LARGE); + + /* + * We can find the actual pte entry without searching by grabbing + * the PTEG index from 3 unused bits in pvo_vaddr and by + * noticing the HID bit. + */ + if (pvo->pvo_pte.lpte.pte_hi & LPTE_HID) + ptegidx ^= moea64_pteg_mask; + + return ((ptegidx << 3) | PVO_PTEGIDX_GET(pvo)); +} + Property changes on: sys/powerpc/pseries/mmu_phyp.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: sys/powerpc/pseries/phyp-hvcall.S =================================================================== --- sys/powerpc/pseries/phyp-hvcall.S (revision 0) +++ sys/powerpc/pseries/phyp-hvcall.S (working copy) @@ -0,0 +1,68 @@ +/*- + * Copyright (C) 2010 Andreas Tobler + * 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 + +/* Hypervisor entry call. */ +#define hc .long 0x44000022 + +/* + * Simple HV calls take the same arguments, with the same ABI, as this + * C function + */ +ASENTRY(phyp_hcall) + mflr %r0 + std %r0,16(%r1) + hc /* invoke the hypervisor */ + ld %r0,16(%r1) + mtlr %r0 + blr /* return r3 = status */ + +/* + * PFT HV calls take a special ABI (see PAPR 14.5.4.1) + * + * r3-r7 arguments passed unchanged, r8-r10 are addresses of return values + * HV takes the same r3-r7, but returns values in r3, r4-r6 + */ +ASENTRY(phyp_pft_hcall) + mflr %r0 + std %r0,16(%r1) + stdu %r1,-80(%r1) + std %r8,48(%r1) /* save arguments */ + std %r9,56(%r1) + std %r10,64(%r1) + hc /* invoke the hypervisor */ + ld %r11,48(%r1) /* store results */ + std %r4,0(%r11) + ld %r11,56(%r1) + std %r5,0(%r11) + ld %r11,64(%r1) + std %r6,0(%r11) + ld %r1,0(%r1) /* exit */ + ld %r0,16(%r1) + mtlr %r0 + blr /* return r3 = status */ + Property changes on: sys/powerpc/pseries/phyp-hvcall.S ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: sys/powerpc/pseries/phyp-hvcall.h =================================================================== --- sys/powerpc/pseries/phyp-hvcall.h (revision 0) +++ sys/powerpc/pseries/phyp-hvcall.h (working copy) @@ -0,0 +1,305 @@ +/*- + * Copyright (C) 2010 Andreas Tobler + * 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$ + */ + +#ifndef _PSERIES_PHYP_HVCALL_H_ +#define _PSERIES_PHYP_HVCALL_H_ + +/* Information taken from: Power.org PAPR, Version 2.4 (December 7, 2009). */ + +#include + +/* Return codes. */ + +#define H_SUCCESS 0 +#define H_BUSY 1 /* Hardware Busy -- Retry Later. */ +#define H_CLOSED 2 /* Virtual I/O connection is closed. */ +#define H_NOT_AVAILABLE 3 +#define H_CONSTRAINED 4 /* The request called for resources in excess of + the maximum allowed. The resultant allocation + was constrained to maximum allowed. */ +#define H_PARTIAL 5 /* The request completed only partially successful. + Parameters were valid but some specific hcall + function condition prevented fully completing the + architected function, see the specific hcall + definition for possible reasons. */ +#define H_IN_PROGRESS 14 +#define H_PAGE_REGISTERED 15 +#define H_PARTIAL_STORE 16 +#define H_PENDING 17 +#define H_CONTINUE 18 + +#define H_LONG_BUSY_ORDER_1_MS 9900 /* This return code is identical to + H_BUSY, but with the added bonus of a + hint to the partition OS. If the + partition OS can delay for 1 + millisecond, the hcall will likely + succeed on a new hcall with no further + busy return codes. If the partition OS + cannot handle a delay, they are + certainly free to immediately turn + around and try again. */ +#define H_LONG_BUSY_ORDER_10_MS 9901 /* Similar to H_LONG_BUSY_ORDER_1_MS, but + the hint is 10mSec wait this time. */ + +#define H_LONG_BUSY_ORDER_100_MS 9902 /* Similar to H_LONG_BUSY_ORDER_1_MS, but + the hint is 100mSec wait this time. */ + +#define H_LONG_BUSY_ORDER_1_S 9903 /* Similar to H_LONG_BUSY_ORDER_1_MS, but + the hint is 1Sec wait this time. */ +#define H_LONG_BUSY_ORDER_10_S 9904 /* Similar to H_LONG_BUSY_ORDER_1_MS, but + the hint is 10Sec wait this time. */ +#define H_LONG_BUSY_ORDER_100_S 9905 /* Similar to H_LONG_BUSY_ORDER_1_MS, but + the hint is 100Sec wait this time. */ + +#define H_HARDWARE -1 /* Error. */ +#define H_FUNCTION -2 /* Not supported. */ +#define H_PRIVILEGE -3 /* Caller not in privileged mode. */ +#define H_PARAMETER -4 /* Outside valid range for partition or conflicting. */ +#define H_BAD_MODE -5 /* Illegal MSR value. */ +#define H_PTEG_FULL -6 /* The requested pteg was full. */ +#define H_NOT_FOUND -7 /* The requested entitiy was not found. */ +#define H_RESERVED_DABR -8 /* The requested address is reserved by the + hypervisor on this processor. */ +#define H_NOMEM -9 +#define H_AUTHORITY -10 /* The caller did not have authority to perform the + function. */ +#define H_PERMISSION -11 /* The mapping specified by the request does not + allow for the requested transfer. */ +#define H_DROPPED -12 /* One or more packets could not be delivered to + their requested destinations. */ +#define H_S_PARM -13 /* The source parameter is illegal. */ +#define H_D_PARM -14 /* The destination parameter is illegal. */ +#define H_R_PARM -15 /* The remote TCE mapping is illegal. */ +#define H_RESOURCE -16 /* One or more required resources are in use. */ +#define H_ADAPTER_PARM -17 /* Invalid adapter. */ +#define H_RH_PARM -18 /* Resource not valid or logical partition + conflicting. */ +#define H_RCQ_PARM -19 /* RCQ not valid or logical partition conflicting. */ +#define H_SCQ_PARM -20 /* SCQ not valid or logical partition conflicting. */ +#define H_EQ_PARM -21 /* EQ not valid or logical partition conflicting. */ +#define H_RT_PARM -22 /* Invalid resource type. */ +#define H_ST_PARM -23 /* Invalid service type. */ +#define H_SIGT_PARM -24 /* Invalid signalling type. */ +#define H_TOKEN_PARM -25 /* Invalid token. */ +#define H_MLENGTH_PARM -27 /* Invalid memory length. */ +#define H_MEM_PARM -28 /* Invalid memory I/O virtual address. */ +#define H_MEM_ACCESS_PARM -29 /* Invalid memory access control. */ +#define H_ATTR_PARM -30 /* Invalid attribute value. */ +#define H_PORT_PARM -31 /* Invalid port number. */ +#define H_MCG_PARM -32 /* Invalid multicast group. */ +#define H_VL_PARM -33 /* Invalid virtual lane. */ +#define H_TSIZE_PARM -34 /* Invalid trace size. */ +#define H_TRACE_PARM -35 /* Invalid trace buffer. */ +#define H_MASK_PARM -37 /* Invalid mask value. */ +#define H_MCG_FULL -38 /* Multicast attachments exceeded. */ +#define H_ALIAS_EXIST -39 /* Alias QP already defined. */ +#define H_P_COUNTER -40 /* Invalid counter specification. */ +#define H_TABLE_FULL -41 /* Resource page table full. */ +#define H_ALT_TABLE -42 /* Alternate table already exists / alternate page + table not available. */ +#define H_MR_CONDITION -43 /* Invalid memory region condition. */ +#define H_NOT_ENOUGH_RESOURCES -44 /* Insufficient resources. */ +#define H_R_STATE -45 /* Invalid resource state condition or sequencing + error. */ +#define H_RESCINDED -46 +#define H_ABORTED -54 +#define H_P2 -55 +#define H_P3 -56 +#define H_P4 -57 +#define H_P5 -58 +#define H_P6 -59 +#define H_P7 -60 +#define H_P8 -61 +#define H_P9 -62 +#define H_NOOP -63 +#define H_TOO_BIG -64 + +#define H_UNSUPPORTED -67 /* Parameter value outside of the range supported + by this implementation. */ + +/* Flags. */ +/* Table 168. Page Frame Table Access flags field definition. */ +#define H_EXACT (1UL<<(63-24)) +#define H_R_XLATE (1UL<<(63-25)) +#define H_READ_4 (1UL<<(63-26)) + +/* Table 178. CMO Page Usage State flags Definition. */ +#define H_PAGE_STATE_CHANGE (1UL<<(63-28)) +#define H_PAGE_UNUSED ((1UL<<(63-29)) | (1UL<<(63-30))) +#define H_PAGE_SET_UNUSED (H_PAGE_STATE_CHANGE | H_PAGE_UNUSED) +#define H_PAGE_SET_LOANED (H_PAGE_SET_UNUSED | (1UL<<(63-31))) +#define H_PAGE_SET_ACTIVE H_PAGE_STATE_CHANGE + +/* Table 168. Page Frame Table Access flags field definition. */ +#define H_AVPN (1UL<<(63-32)) +#define H_ANDCOND (1UL<<(63-33)) + +#define H_ICACHE_INVALIDATE (1UL<<(63-40)) +#define H_ICACHE_SYNCHRONIZE (1UL<<(63-41)) + +#define H_ZERO_PAGE (1UL<<(63-48)) +#define H_COPY_PAGE (1UL<<(63-49)) + +#define H_N (1UL<<(63-61)) +#define H_PP1 (1UL<<(63-62)) +#define H_PP2 (1UL<<(63-63)) + +/* pSeries hypervisor opcodes. */ +#define H_REMOVE 0x04 +#define H_ENTER 0x08 +#define H_READ 0x0c +#define H_CLEAR_MOD 0x10 +#define H_CLEAR_REF 0x14 +#define H_PROTECT 0x18 +#define H_GET_TCE 0x1c +#define H_PUT_TCE 0x20 +#define H_SET_SPRG0 0x24 +#define H_SET_DABR 0x28 +#define H_PAGE_INIT 0x2c +#define H_SET_ASR 0x30 +#define H_ASR_ON 0x34 +#define H_ASR_OFF 0x38 +#define H_LOGICAL_CI_LOAD 0x3c +#define H_LOGICAL_CI_STORE 0x40 +#define H_LOGICAL_CACHE_LOAD 0x44 +#define H_LOGICAL_CACHE_STORE 0x48 +#define H_LOGICAL_ICBI 0x4c +#define H_LOGICAL_DCBF 0x50 +#define H_GET_TERM_CHAR 0x54 +#define H_PUT_TERM_CHAR 0x58 +#define H_REAL_TO_LOGICAL 0x5c +#define H_HYPERVISOR_DATA 0x60 +#define H_EOI 0x64 +#define H_CPPR 0x68 +#define H_IPI 0x6c +#define H_IPOLL 0x70 +#define H_XIRR 0x74 +#define H_MIGRATE_DMA 0x78 +#define H_PERFMON 0x7c +#define H_REGISTER_VPA 0xdc +#define H_CEDE 0xe0 +#define H_CONFER 0xe4 +#define H_PROD 0xe8 +#define H_GET_PPP 0xec +#define H_SET_PPP 0xf0 +#define H_PURR 0xf4 +#define H_PIC 0xf8 +#define H_REG_CRQ 0xfc +#define H_FREE_CRQ 0x100 +#define H_VIO_SIGNAL 0x104 +#define H_SEND_CRQ 0x108 +#define H_PUT_RTCE 0x10c +#define H_COPY_RDMA 0x110 +#define H_REGISTER_LOGICAL_LAN 0x114 +#define H_FREE_LOGICAL_LAN 0x118 +#define H_ADD_LOGICAL_LAN_BUFFER 0x11c +#define H_SEND_LOGICAL_LAN 0x120 +#define H_BULK_REMOVE 0x124 +#define H_WRITE_RDMA 0x128 +#define H_READ_RDMA 0x12c +#define H_MULTICAST_CTRL 0x130 +#define H_SET_XDABR 0x134 +#define H_STUFF_TCE 0x138 +#define H_PUT_TCE_INDIRECT 0x13c +#define H_PUT_RTCE_INDIRECT 0x140 +#define H_CHANGE_LOGICAL_LAN_MAC 0x14c +#define H_VTERM_PARTNER_INFO 0x150 +#define H_REGISTER_VTERM 0x154 +#define H_FREE_VTERM 0x158 +/* Reserved .... +#define H_RESET_EVENTS 0x15c +#define H_ALLOC_RESOURCE 0x160 +#define H_FREE_RESOURCE 0x164 +#define H_MODIFY_QP 0x168 +#define H_QUERY_QP 0x16c +#define H_REREGISTER_PMR 0x170 +#define H_REGISTER_SMR 0x174 +#define H_QUERY_MR 0x178 +#define H_QUERY_MW 0x17c +#define H_QUERY_HCA 0x180 +#define H_QUERY_PORT 0x184 +#define H_MODIFY_PORT 0x188 +#define H_DEFINE_AQP1 0x18c +#define H_GET_TRACE_BUFFER 0x190 +#define H_DEFINE_AQP0 0x194 +#define H_RESIZE_MR 0x198 +#define H_ATTACH_MCQP 0x19c +#define H_DETACH_MCQP 0x1a0 +#define H_CREATE_RPT 0x1a4 +#define H_REMOVE_RPT 0x1a8 +#define H_REGISTER_RPAGES 0x1ac +#define H_DISABLE_AND_GETC 0x1b0 +#define H_ERROR_DATA 0x1b4 +#define H_GET_HCA_INFO 0x1b8 +#define H_GET_PERF_COUNT 0x1bc +#define H_MANAGE_TRACE 0x1c0 +.... */ +#define H_FREE_LOGICAL_LAN_BUFFER 0x1d4 +#define H_POLL_PENDING 0x1d8 +/* Reserved .... +#define H_QUERY_INT_STATE 0x1e4 +.... */ +#define H_LIOBN_ATTRIBUTES 0x240 +#define H_ILLAN_ATTRIBUTES 0x244 +#define H_REMOVE_RTCE 0x24c +/* Reserved ... +#define H_MODIFY_HEA_QP 0x250 +#define H_QUERY_HEA_QP 0x254 +#define H_QUERY_HEA 0x258 +#define H_QUERY_HEA_PORT 0x25c +#define H_MODIFY_HEA_PORT 0x260 +#define H_REG_BCMC 0x264 +#define H_DEREG_BCMC 0x268 +#define H_REGISTER_HEA_RPAGES 0x26c +#define H_DISABLE_AND_GET_HEA 0x270 +#define H_GET_HEA_INFO 0x274 +#define H_ALLOC_HEA_RESOURCE 0x278 +#define H_ADD_CONN 0x284 +#define H_DEL_CONN 0x288 +... */ +#define H_JOIN 0x298 +#define H_DONOR_OPERATION 0x29c +#define H_VASI_SIGNAL 0x2a0 +#define H_VASI_STATE 0x2a4 +#define H_VIOCTL 0x2a8 +#define H_VRMASD 0x2ac +#define H_ENABLE_CRQ 0x2b0 +/* Reserved ... +#define H_GET_EM_PARMS 0x2b8 +... */ +#define H_VPM_STAT 0x2bc +#define H_SET_MPP 0x2d0 +#define H_GET_MPP 0x2d4 +#define MAX_HCALL_OPCODE H_GET_MPP + +int64_t phyp_hcall(uint64_t opcode, ...); +int64_t phyp_pft_hcall(uint64_t opcode, uint64_t flags, uint64_t pteidx, + uint64_t pte_hi, uint64_t pte_lo, uint64_t *pteidx_out, uint64_t *ptelo_out, + uint64_t *r6); + +#endif /* _PSERIES_PHYP_HVCALL_H_ */ + Property changes on: sys/powerpc/pseries/phyp-hvcall.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: sys/powerpc/pseries/phyp_console.c =================================================================== --- sys/powerpc/pseries/phyp_console.c (revision 0) +++ sys/powerpc/pseries/phyp_console.c (working copy) @@ -0,0 +1,420 @@ +/*- + * Copyright (C) 2011 by Nathan Whitehorn. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. + */ + +#include +__FBSDID("$FreeBSD: projects/pseries/powerpc/phyp/phyp_console.c 214348 2010-10-25 15:41:12Z nwhitehorn $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "phyp-hvcall.h" +#include "uart_if.h" + +struct uart_phyp_softc { + device_t dev; + phandle_t node; + int vtermid; + + struct tty *tp; + struct resource *irqres; + int irqrid; + struct callout callout; + void *sc_icookie; + int polltime; + + struct mtx sc_mtx; + int protocol; + + union { + uint64_t u64[2]; + char str[16]; + } phyp_inbuf; + uint64_t inbuflen; + uint8_t outseqno; +}; + +static struct uart_phyp_softc *console_sc = NULL; +#if defined(KDB) +static int alt_break_state; +#endif + +enum { + HVTERM1, HVTERMPROT +}; + +#define VS_DATA_PACKET_HEADER 0xff +#define VS_CONTROL_PACKET_HEADER 0xfe +#define VSV_SET_MODEM_CTL 0x01 +#define VSV_MODEM_CTL_UPDATE 0x02 +#define VSV_RENEGOTIATE_CONNECTION 0x03 +#define VS_QUERY_PACKET_HEADER 0xfd +#define VSV_SEND_VERSION_NUMBER 0x01 +#define VSV_SEND_MODEM_CTL_STATUS 0x02 +#define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc + +static int uart_phyp_probe(device_t dev); +static int uart_phyp_attach(device_t dev); +static void uart_phyp_intr(void *v); + +static device_method_t uart_phyp_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, uart_phyp_probe), + DEVMETHOD(device_attach, uart_phyp_attach), + + DEVMETHOD_END +}; + +static driver_t uart_phyp_driver = { + "uart", + uart_phyp_methods, + sizeof(struct uart_phyp_softc), +}; + +DRIVER_MODULE(uart_phyp, vdevice, uart_phyp_driver, uart_devclass, 0, 0); + +static cn_probe_t uart_phyp_cnprobe; +static cn_init_t uart_phyp_cninit; +static cn_term_t uart_phyp_cnterm; +static cn_getc_t uart_phyp_cngetc; +static cn_putc_t uart_phyp_cnputc; +static cn_grab_t uart_phyp_cngrab; +static cn_ungrab_t uart_phyp_cnungrab; + +CONSOLE_DRIVER(uart_phyp); + +static void uart_phyp_ttyoutwakeup(struct tty *tp); + +static struct ttydevsw uart_phyp_tty_class = { + .tsw_flags = TF_INITLOCK|TF_CALLOUT, + .tsw_outwakeup = uart_phyp_ttyoutwakeup, +}; + +static int +uart_phyp_probe_node(struct uart_phyp_softc *sc) +{ + phandle_t node = sc->node; + uint32_t reg; + char buf[64]; + + sc->inbuflen = 0; + sc->outseqno = 0; + + if (OF_getprop(node, "name", buf, sizeof(buf)) <= 0) + return (ENXIO); + if (strcmp(buf, "vty") != 0) + return (ENXIO); + + if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0) + return (ENXIO); + if (strcmp(buf, "serial") != 0) + return (ENXIO); + + reg = -1; + OF_getprop(node, "reg", ®, sizeof(reg)); + if (reg == -1) + return (ENXIO); + sc->node = node; + + if (OF_getprop(node, "compatible", buf, sizeof(buf)) <= 0) + return (ENXIO); + if (strcmp(buf, "hvterm1") == 0) { + sc->protocol = HVTERM1; + return (0); + } else if (strcmp(buf, "hvterm-protocol") == 0) { + sc->protocol = HVTERMPROT; + return (0); + } + + return (ENXIO); +} + +static int +uart_phyp_probe(device_t dev) +{ + const char *name; + struct uart_phyp_softc sc; + int err; + + name = ofw_bus_get_name(dev); + if (name == NULL || strcmp(name, "vty") != 0) + return (ENXIO); + + sc.node = ofw_bus_get_node(dev); + err = uart_phyp_probe_node(&sc); + if (err != 0) + return (err); + + device_set_desc(dev, "POWER Hypervisor Virtual Serial Port"); + + return (err); +} + +static void +uart_phyp_cnprobe(struct consdev *cp) +{ + char buf[64]; + ihandle_t stdout; + phandle_t input, opts, chosen; + static struct uart_phyp_softc sc; + + if ((opts = OF_finddevice("/options")) == -1) + goto fail; + if ((chosen = OF_finddevice("/chosen")) == -1) + goto fail; + + /* Check if OF has an active stdin/stdout */ + input = -1; + if (OF_getprop(chosen, "stdout", &stdout, + sizeof(stdout)) == sizeof(stdout) && stdout != 0) + input = OF_instance_to_package(stdout); + if (input == -1) + goto fail; + + if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1) + goto fail; + if (strcmp(buf, "serial") != 0) + goto fail; + + sc.node = input; + if (uart_phyp_probe_node(&sc) != 0) + goto fail; + mtx_init(&sc.sc_mtx, "uart_phyp", NULL, MTX_SPIN | MTX_QUIET | + MTX_NOWITNESS); + + cp->cn_pri = CN_NORMAL; + console_sc = ≻ + return; + +fail: + cp->cn_pri = CN_DEAD; + return; +} + +static int +uart_phyp_attach(device_t dev) +{ + struct uart_phyp_softc *sc; + int unit; + + sc = device_get_softc(dev); + sc->dev = dev; + sc->node = ofw_bus_get_node(dev); + uart_phyp_probe_node(sc); + + unit = device_get_unit(dev); + sc->tp = tty_alloc(&uart_phyp_tty_class, sc); + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, + MTX_SPIN | MTX_QUIET | MTX_NOWITNESS); + + if (console_sc != NULL && console_sc->vtermid == sc->vtermid) { + sc->outseqno = console_sc->outseqno; + console_sc = sc; + sprintf(uart_phyp_consdev.cn_name, "ttyu%r", unit); + tty_init_console(sc->tp, 0); + } + + sc->irqrid = 0; +#ifdef NOTYET + sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqrid, + RF_ACTIVE | RF_SHAREABLE); +#else + sc->irqres = NULL; +#endif + if (sc->irqres != NULL) { + bus_setup_intr(dev, sc->irqres, INTR_TYPE_TTY | INTR_MPSAFE, + NULL, uart_phyp_intr, sc, &sc->sc_icookie); + } else { + callout_init(&sc->callout, CALLOUT_MPSAFE); + sc->polltime = hz / 20; + if (sc->polltime < 1) + sc->polltime = 1; + callout_reset(&sc->callout, sc->polltime, uart_phyp_intr, sc); + } + + tty_makedev(sc->tp, NULL, "u%r", unit); + + return (0); +} + +static void +uart_phyp_cninit(struct consdev *cp) +{ + + strcpy(cp->cn_name, "phypcons"); +} + +static void +uart_phyp_cnterm(struct consdev *cp) +{ +} + +static int +uart_phyp_get(struct uart_phyp_softc *sc, void *buffer, size_t bufsize) +{ + int err; + + uart_lock(&sc->sc_mtx); + if (sc->inbuflen == 0) { + err = phyp_pft_hcall(H_GET_TERM_CHAR, sc->vtermid, + 0, 0, 0, &sc->inbuflen, &sc->phyp_inbuf.u64[0], + &sc->phyp_inbuf.u64[1]); + if (err != H_SUCCESS) { + uart_unlock(&sc->sc_mtx); + return (-1); + } + } + + if (sc->inbuflen == 0) { + uart_unlock(&sc->sc_mtx); + return (0); + } + + if (bufsize > sc->inbuflen) + bufsize = sc->inbuflen; + memcpy(buffer, sc->phyp_inbuf.str, bufsize); + sc->inbuflen -= bufsize; + if (sc->inbuflen > 0) + memmove(&sc->phyp_inbuf.str[0], &sc->phyp_inbuf.str[bufsize], + sc->inbuflen); + + uart_unlock(&sc->sc_mtx); + return (bufsize); +} + +static int +uart_phyp_put(struct uart_phyp_softc *sc, void *buffer, size_t bufsize) +{ + uint16_t seqno; + uint64_t len = 0; + union { + uint64_t u64; + char bytes[8]; + } cbuf; + + uart_lock(&sc->sc_mtx); + switch (sc->protocol) { + case HVTERM1: + if (bufsize > 8) + bufsize = 8; + memcpy(&cbuf, buffer, bufsize); + len = bufsize; + break; + case HVTERMPROT: + if (bufsize > 4) + bufsize = 4; + seqno = sc->outseqno++; + cbuf.bytes[0] = VS_DATA_PACKET_HEADER; + cbuf.bytes[1] = 4 + bufsize; /* total length */ + cbuf.bytes[2] = (seqno >> 8) & 0xff; + cbuf.bytes[3] = seqno & 0xff; + memcpy(&cbuf.bytes[4], buffer, bufsize); + len = 4 + bufsize; + break; + } + phyp_hcall(H_PUT_TERM_CHAR, sc->vtermid, len, cbuf.u64, 0); + uart_unlock(&sc->sc_mtx); + + return (bufsize); +} + +static int +uart_phyp_cngetc(struct consdev *cp) +{ + unsigned char c; + int retval; + + retval = uart_phyp_get(console_sc, &c, 1); + if (retval != 1) + return (-1); +#if defined(KDB) + kdb_alt_break(c, &alt_break_state); +#endif + + return (c); +} + +static void +uart_phyp_cnputc(struct consdev *cp, int c) +{ + unsigned char ch = c; + uart_phyp_put(console_sc, &ch, 1); +} + +static void +uart_phyp_cngrab(struct consdev *cp) +{ +} + +static void +uart_phyp_cnungrab(struct consdev *cp) +{ +} + +static void +uart_phyp_ttyoutwakeup(struct tty *tp) +{ + struct uart_phyp_softc *sc; + char buffer[8]; + int len; + + sc = tty_softc(tp); + + while ((len = ttydisc_getc(tp, buffer, sizeof(buffer))) != 0) + uart_phyp_put(sc, buffer, len); +} + +static void +uart_phyp_intr(void *v) +{ + struct uart_phyp_softc *sc = v; + struct tty *tp = sc->tp; + unsigned char c; + int len; + + tty_lock(tp); + while ((len = uart_phyp_get(sc, &c, 1)) > 0) + ttydisc_rint(tp, c, 0); + ttydisc_rint_done(tp); + tty_unlock(tp); + + if (sc->irqres == NULL) + callout_reset(&sc->callout, sc->polltime, uart_phyp_intr, sc); +} + Index: sys/powerpc/pseries/platform_chrp.c =================================================================== --- sys/powerpc/pseries/platform_chrp.c (revision 0) +++ sys/powerpc/pseries/platform_chrp.c (working copy) @@ -0,0 +1,411 @@ +/*- + * Copyright (c) 2008 Marcel Moolenaar + * Copyright (c) 2009 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "platform_if.h" + +#ifdef SMP +extern void *ap_pcpu; +#endif + +#ifdef __powerpc64__ +static uint8_t splpar_vpa[640] __aligned(64); +#endif + +static vm_offset_t realmaxaddr = VM_MAX_ADDRESS; + +static int chrp_probe(platform_t); +static int chrp_attach(platform_t); +void chrp_mem_regions(platform_t, struct mem_region **phys, int *physsz, + struct mem_region **avail, int *availsz); +static vm_offset_t chrp_real_maxaddr(platform_t); +static u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref); +static int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref); +static int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref); +static int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref); +static void chrp_smp_ap_init(platform_t); +#ifdef SMP +static int chrp_smp_start_cpu(platform_t, struct pcpu *cpu); +static struct cpu_group *chrp_smp_topo(platform_t plat); +#endif +static void chrp_reset(platform_t); +#ifdef __powerpc64__ +#include "phyp-hvcall.h" +static void phyp_cpu_idle(sbintime_t sbt); +#endif + +static platform_method_t chrp_methods[] = { + PLATFORMMETHOD(platform_probe, chrp_probe), + PLATFORMMETHOD(platform_attach, chrp_attach), + PLATFORMMETHOD(platform_mem_regions, chrp_mem_regions), + PLATFORMMETHOD(platform_real_maxaddr, chrp_real_maxaddr), + PLATFORMMETHOD(platform_timebase_freq, chrp_timebase_freq), + + PLATFORMMETHOD(platform_smp_ap_init, chrp_smp_ap_init), + PLATFORMMETHOD(platform_smp_first_cpu, chrp_smp_first_cpu), + PLATFORMMETHOD(platform_smp_next_cpu, chrp_smp_next_cpu), + PLATFORMMETHOD(platform_smp_get_bsp, chrp_smp_get_bsp), +#ifdef SMP + PLATFORMMETHOD(platform_smp_start_cpu, chrp_smp_start_cpu), + PLATFORMMETHOD(platform_smp_topo, chrp_smp_topo), +#endif + + PLATFORMMETHOD(platform_reset, chrp_reset), + + { 0, 0 } +}; + +static platform_def_t chrp_platform = { + "chrp", + chrp_methods, + 0 +}; + +PLATFORM_DEF(chrp_platform); + +static int +chrp_probe(platform_t plat) +{ + if (OF_finddevice("/memory") != -1 || OF_finddevice("/memory@0") != -1) + return (BUS_PROBE_GENERIC); + + return (ENXIO); +} + +static int +chrp_attach(platform_t plat) +{ +#ifdef __powerpc64__ + /* XXX: check for /rtas/ibm,hypertas-functions? */ + if (!(mfmsr() & PSL_HV)) { + struct mem_region *phys, *avail; + int nphys, navail; + mem_regions(&phys, &nphys, &avail, &navail); + realmaxaddr = phys[0].mr_size; + + pmap_mmu_install("mmu_phyp", BUS_PROBE_SPECIFIC); + cpu_idle_hook = phyp_cpu_idle; + + /* Set up important VPA fields */ + bzero(splpar_vpa, sizeof(splpar_vpa)); + splpar_vpa[4] = (uint8_t)((sizeof(splpar_vpa) >> 8) & 0xff); + splpar_vpa[5] = (uint8_t)(sizeof(splpar_vpa) & 0xff); + splpar_vpa[0xba] = 1; /* Maintain FPRs */ + splpar_vpa[0xbb] = 1; /* Maintain PMCs */ + splpar_vpa[0xfc] = 0xff; /* Maintain full SLB */ + splpar_vpa[0xfd] = 0xff; + splpar_vpa[0xff] = 1; /* Maintain Altivec */ + mb(); + + /* Set up hypervisor CPU stuff */ + chrp_smp_ap_init(plat); + } +#endif + + return (0); +} + +void +chrp_mem_regions(platform_t plat, struct mem_region **phys, int *physsz, + struct mem_region **avail, int *availsz) +{ + ofw_mem_regions(phys,physsz,avail,availsz); +} + +static vm_offset_t +chrp_real_maxaddr(platform_t plat) +{ + return (realmaxaddr); +} + +static u_long +chrp_timebase_freq(platform_t plat, struct cpuref *cpuref) +{ + phandle_t phandle; + int32_t ticks = -1; + + phandle = cpuref->cr_hwref; + + OF_getprop(phandle, "timebase-frequency", &ticks, sizeof(ticks)); + + if (ticks <= 0) + panic("Unable to determine timebase frequency!"); + + return (ticks); +} + +static int +chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref) +{ + char buf[8]; + phandle_t cpu, dev, root; + int res, cpuid; + + root = OF_peer(0); + + dev = OF_child(root); + while (dev != 0) { + res = OF_getprop(dev, "name", buf, sizeof(buf)); + if (res > 0 && strcmp(buf, "cpus") == 0) + break; + dev = OF_peer(dev); + } + if (dev == 0) { + /* + * psim doesn't have a name property on the /cpus node, + * but it can be found directly + */ + dev = OF_finddevice("/cpus"); + if (dev == 0) + return (ENOENT); + } + + cpu = OF_child(dev); + + while (cpu != 0) { + res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); + if (res > 0 && strcmp(buf, "cpu") == 0) + break; + cpu = OF_peer(cpu); + } + if (cpu == 0) + return (ENOENT); + + cpuref->cr_hwref = cpu; + res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid, + sizeof(cpuid)); + if (res <= 0) + res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); + if (res <= 0) + cpuid = 0; + cpuref->cr_cpuid = cpuid; + + return (0); +} + +static int +chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref) +{ + char buf[8]; + phandle_t cpu; + int i, res, cpuid; + + /* Check for whether it should be the next thread */ + res = OF_getproplen(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s"); + if (res > 0) { + cell_t interrupt_servers[res/sizeof(cell_t)]; + OF_getprop(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s", + interrupt_servers, res); + for (i = 0; i < res/sizeof(cell_t) - 1; i++) { + if (interrupt_servers[i] == cpuref->cr_cpuid) { + cpuref->cr_cpuid = interrupt_servers[i+1]; + return (0); + } + } + } + + /* Next CPU core/package */ + cpu = OF_peer(cpuref->cr_hwref); + while (cpu != 0) { + res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); + if (res > 0 && strcmp(buf, "cpu") == 0) + break; + cpu = OF_peer(cpu); + } + if (cpu == 0) + return (ENOENT); + + cpuref->cr_hwref = cpu; + res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid, + sizeof(cpuid)); + if (res <= 0) + res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); + if (res <= 0) + cpuid = 0; + cpuref->cr_cpuid = cpuid; + + return (0); +} + +static int +chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref) +{ + ihandle_t inst; + phandle_t bsp, chosen; + int res, cpuid; + + chosen = OF_finddevice("/chosen"); + if (chosen == 0) + return (ENXIO); + + res = OF_getprop(chosen, "cpu", &inst, sizeof(inst)); + if (res < 0) + return (ENXIO); + + bsp = OF_instance_to_package(inst); + + /* Pick the primary thread. Can it be any other? */ + cpuref->cr_hwref = bsp; + res = OF_getprop(bsp, "ibm,ppc-interrupt-server#s", &cpuid, + sizeof(cpuid)); + if (res <= 0) + res = OF_getprop(bsp, "reg", &cpuid, sizeof(cpuid)); + if (res <= 0) + cpuid = 0; + cpuref->cr_cpuid = cpuid; + + return (0); +} + +#ifdef SMP +static int +chrp_smp_start_cpu(platform_t plat, struct pcpu *pc) +{ + cell_t start_cpu; + int result, err, timeout; + + if (!rtas_exists()) { + printf("RTAS uninitialized: unable to start AP %d\n", + pc->pc_cpuid); + return (ENXIO); + } + + start_cpu = rtas_token_lookup("start-cpu"); + if (start_cpu == -1) { + printf("RTAS unknown method: unable to start AP %d\n", + pc->pc_cpuid); + return (ENXIO); + } + + ap_pcpu = pc; + powerpc_sync(); + + result = rtas_call_method(start_cpu, 3, 1, pc->pc_cpuid, EXC_RST, pc, + &err); + if (result < 0 || err != 0) { + printf("RTAS error (%d/%d): unable to start AP %d\n", + result, err, pc->pc_cpuid); + return (ENXIO); + } + + timeout = 10000; + while (!pc->pc_awake && timeout--) + DELAY(100); + + return ((pc->pc_awake) ? 0 : EBUSY); +} + +static struct cpu_group * +chrp_smp_topo(platform_t plat) +{ + struct pcpu *pc, *last_pc; + int i, ncores, ncpus; + + ncores = ncpus = 0; + last_pc = NULL; + for (i = 0; i <= mp_maxid; i++) { + pc = pcpu_find(i); + if (pc == NULL) + continue; + if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref) + ncores++; + last_pc = pc; + ncpus++; + } + + if (ncpus % ncores != 0) { + printf("WARNING: Irregular SMP topology. Performance may be " + "suboptimal (%d CPUS, %d cores)\n", ncpus, ncores); + return (smp_topo_none()); + } + + /* Don't do anything fancier for non-threaded SMP */ + if (ncpus == ncores) + return (smp_topo_none()); + + return (smp_topo_1level(CG_SHARE_L1, ncpus / ncores, CG_FLAG_SMT)); +} +#endif + +static void +chrp_reset(platform_t platform) +{ + OF_reboot(); +} + +#ifdef __powerpc64__ +static void +phyp_cpu_idle(sbintime_t sbt) +{ + #ifdef NOTYET /* Causes hangs on QEMU */ + phyp_hcall(H_CEDE); + #endif +} + +static void +chrp_smp_ap_init(platform_t platform) +{ + if (!(mfmsr() & PSL_HV)) { + /* Set interrupt priority */ + phyp_hcall(H_CPPR, 0xff); + + /* Register VPA */ + phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(cpuid), splpar_vpa); + } +} +#else +static void +chrp_smp_ap_init(platform_t platform) +{ +} +#endif + Property changes on: sys/powerpc/pseries/platform_chrp.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: sys/powerpc/pseries/plpar_iommu.c =================================================================== --- sys/powerpc/pseries/plpar_iommu.c (revision 0) +++ sys/powerpc/pseries/plpar_iommu.c (working copy) @@ -0,0 +1,235 @@ +/*- + * Copyright (c) 2013, Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +MALLOC_DEFINE(M_PHYPIOMMU, "iommu", "IOMMU data for PAPR LPARs"); + +struct papr_iommu_map { + uint32_t iobn; + vmem_t *vmem; + struct papr_iommu_map *next; +}; + +static SLIST_HEAD(iommu_maps, iommu_map) iommu_map_head = + SLIST_HEAD_INITIALIZER(iommu_map_head); +static int papr_supports_stuff_tce = -1; + +struct iommu_map { + uint32_t iobn; + vmem_t *vmem; + + SLIST_ENTRY(iommu_map) entries; +}; + +struct dma_window { + struct iommu_map *map; + bus_addr_t start; + bus_addr_t end; +}; + +int +phyp_iommu_set_dma_tag(device_t dev, device_t child, bus_dma_tag_t tag) +{ + device_t p; + phandle_t node; + cell_t dma_acells, dma_scells, dmawindow[5]; + struct iommu_map *i; + + for (p = child; p != NULL; p = device_get_parent(p)) { + if (ofw_bus_has_prop(p, "ibm,my-dma-window")) + break; + if (ofw_bus_has_prop(p, "ibm,dma-window")) + break; + } + + if (p == NULL) + return (ENXIO); + + node = ofw_bus_get_node(p); + if (OF_getprop(node, "ibm,#dma-size-cells", &dma_scells, + sizeof(cell_t)) <= 0) + OF_searchprop(node, "#size-cells", &dma_scells, sizeof(cell_t)); + if (OF_getprop(node, "ibm,#dma-address-cells", &dma_acells, + sizeof(cell_t)) <= 0) + OF_searchprop(node, "#address-cells", &dma_acells, + sizeof(cell_t)); + + if (ofw_bus_has_prop(p, "ibm,my-dma-window")) + OF_getprop(node, "ibm,my-dma-window", dmawindow, + sizeof(cell_t)*(dma_scells + dma_acells + 1)); + else + OF_getprop(node, "ibm,dma-window", dmawindow, + sizeof(cell_t)*(dma_scells + dma_acells + 1)); + + struct dma_window *window = malloc(sizeof(struct dma_window), + M_PHYPIOMMU, M_WAITOK); + if (dma_acells == 1) + window->start = dmawindow[1]; + else + window->start = ((uint64_t)(dmawindow[1]) << 32) | dmawindow[2]; + if (dma_scells == 1) + window->end = window->start + dmawindow[dma_acells + 1]; + else + window->end = window->start + + (((uint64_t)(dmawindow[dma_acells + 1]) << 32) | + dmawindow[dma_acells + 2]); + + window->map = NULL; + SLIST_FOREACH(i, &iommu_map_head, entries) { + if (i->iobn == dmawindow[0]) { + window->map = i; + break; + } + } + + if (window->map == NULL) { + window->map = malloc(sizeof(struct iommu_map), M_PHYPIOMMU, + M_WAITOK); + window->map->iobn = dmawindow[0]; + /* + * Allocate IOMMU range beginning at PAGE_SIZE. Some drivers + * (em(4), for example) do not like getting mappings at 0. + */ + window->map->vmem = vmem_create("IOMMU mappings", PAGE_SIZE, + trunc_page(VMEM_ADDR_MAX) - PAGE_SIZE, PAGE_SIZE, 0, + M_BESTFIT | M_NOWAIT); + } + + /* + * Check experimentally whether we can use H_STUFF_TCE. It is required + * by the spec but some firmware (e.g. QEMU) does not actually support + * it + */ + if (papr_supports_stuff_tce == -1) + papr_supports_stuff_tce = !(phyp_hcall(H_STUFF_TCE, + window->map->iobn, 0, 0, 0) == H_FUNCTION); + + bus_dma_tag_set_iommu(tag, dev, window); + + return (0); +} + +int +phyp_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs, + bus_addr_t min, bus_addr_t max, bus_size_t alignment, bus_addr_t boundary, + void *cookie) +{ + struct dma_window *window = cookie; + bus_addr_t minaddr, maxaddr; + bus_addr_t alloced; + bus_size_t allocsize; + int error, i, j; + uint64_t tce; + minaddr = window->start; + maxaddr = window->end; + + /* XXX: handle exclusion range in a more useful way */ + if (min < maxaddr) + maxaddr = min; + + /* XXX: is this correct? */ + if (alignment % PAGE_SIZE != 0) + alignment = PAGE_SIZE; + + /* XXX: consolidate segs? */ + for (i = 0; i < *nsegs; i++) { + allocsize = round_page(segs[i].ds_len + + (segs[i].ds_addr & PAGE_MASK)); + error = vmem_xalloc(window->map->vmem, allocsize, alignment, 0, + boundary, minaddr, maxaddr, M_BESTFIT | M_NOWAIT, &alloced); + if (error != 0) { + panic("VMEM failure: %d\n", error); + return (error); + } + + tce = trunc_page(segs[i].ds_addr); + tce |= 0x3; /* read/write */ + if (papr_supports_stuff_tce) { + error = phyp_hcall(H_STUFF_TCE, window->map->iobn, + alloced, tce, allocsize/PAGE_SIZE); + } else { + for (j = 0; j < allocsize; j += PAGE_SIZE) + error = phyp_hcall(H_PUT_TCE, window->map->iobn, + alloced + j, tce + j); + } + + segs[i].ds_addr = alloced + (segs[i].ds_addr & PAGE_MASK); + if (error < 0) { + panic("IOMMU mapping error: %d\n", error); + return (ENOMEM); + } + } + + return (0); +} + +int +phyp_iommu_unmap(device_t dev, bus_dma_segment_t *segs, int nsegs, void *cookie) +{ + struct dma_window *window = cookie; + bus_addr_t pageround; + bus_size_t roundedsize; + int i; + bus_addr_t j; + + for (i = 0; i < nsegs; i++) { + pageround = trunc_page(segs[i].ds_addr); + roundedsize = round_page(segs[i].ds_len + + (segs[i].ds_addr & PAGE_MASK)); + + if (papr_supports_stuff_tce) { + phyp_hcall(H_STUFF_TCE, window->map->iobn, pageround, 0, + roundedsize/PAGE_SIZE); + } else { + for (j = 0; j < roundedsize; j += PAGE_SIZE) + phyp_hcall(H_PUT_TCE, window->map->iobn, + pageround + j, 0); + } + + vmem_xfree(window->map->vmem, pageround, roundedsize); + } + + return (0); +} + Property changes on: sys/powerpc/pseries/plpar_iommu.c ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: sys/powerpc/pseries/plpar_iommu.h =================================================================== --- sys/powerpc/pseries/plpar_iommu.h (revision 0) +++ sys/powerpc/pseries/plpar_iommu.h (working copy) @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2013, Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. + */ + +#ifndef _PSERIES_PHYP_IOMMU_H_ +#define _PSERIES_PHYP_IOMMU_H_ + +#include +#include + +int phyp_iommu_set_dma_tag(device_t dev, device_t child, bus_dma_tag_t tag); +int phyp_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs, + bus_addr_t min, bus_addr_t max, bus_size_t alignment, bus_addr_t boundary, + void *cookie); +int phyp_iommu_unmap(device_t dev, bus_dma_segment_t *segs, int nsegs, + void *cookie); + +#endif + Property changes on: sys/powerpc/pseries/plpar_iommu.h ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: sys/powerpc/pseries/rtas_dev.c =================================================================== --- sys/powerpc/pseries/rtas_dev.c (revision 0) +++ sys/powerpc/pseries/rtas_dev.c (working copy) @@ -0,0 +1,173 @@ +/*- + * Copyright (c) 2011 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: projects/pseries/powerpc/powermac/rtasdev.c 193156 2009-05-31 09:01:23Z nwhitehorn $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "clock_if.h" + +static int rtasdev_probe(device_t); +static int rtasdev_attach(device_t); +/* clock interface */ +static int rtas_gettime(device_t dev, struct timespec *ts); +static int rtas_settime(device_t dev, struct timespec *ts); + +static void rtas_shutdown(void *arg, int howto); + +static device_method_t rtasdev_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rtasdev_probe), + DEVMETHOD(device_attach, rtasdev_attach), + + /* clock interface */ + DEVMETHOD(clock_gettime, rtas_gettime), + DEVMETHOD(clock_settime, rtas_settime), + + { 0, 0 }, +}; + +static driver_t rtasdev_driver = { + "rtas", + rtasdev_methods, + 0 +}; + +static devclass_t rtasdev_devclass; + +DRIVER_MODULE(rtasdev, nexus, rtasdev_driver, rtasdev_devclass, 0, 0); + +static int +rtasdev_probe(device_t dev) +{ + const char *name = ofw_bus_get_name(dev); + + if (strcmp(name, "rtas") != 0) + return (ENXIO); + if (!rtas_exists()) + return (ENXIO); + + device_set_desc(dev, "Run-Time Abstraction Services"); + return (0); +} + +static int +rtasdev_attach(device_t dev) +{ + if (rtas_token_lookup("get-time-of-day") != -1) + clock_register(dev, 2000); + + EVENTHANDLER_REGISTER(shutdown_final, rtas_shutdown, NULL, + SHUTDOWN_PRI_LAST); + + return (0); +} + +static int +rtas_gettime(device_t dev, struct timespec *ts) { + struct clocktime ct; + cell_t tod[8]; + cell_t token; + int error; + + token = rtas_token_lookup("get-time-of-day"); + if (token == -1) + return (ENXIO); + error = rtas_call_method(token, 0, 8, &tod[0], &tod[1], &tod[2], + &tod[3], &tod[4], &tod[5], &tod[6], &tod[7]); + if (error < 0) + return (ENXIO); + if (tod[0] != 0) + return ((tod[0] == -1) ? ENXIO : EAGAIN); + + ct.year = tod[1]; + ct.mon = tod[2]; + ct.day = tod[3]; + ct.hour = tod[4]; + ct.min = tod[5]; + ct.sec = tod[6]; + ct.nsec = tod[7]; + + return (clock_ct_to_ts(&ct, ts)); +} + +static int +rtas_settime(device_t dev, struct timespec *ts) +{ + struct clocktime ct; + cell_t token, status; + int error; + + token = rtas_token_lookup("set-time-of-day"); + if (token == -1) + return (ENXIO); + + clock_ts_to_ct(ts, &ct); + error = rtas_call_method(token, 7, 1, ct.year, ct.mon, ct.day, ct.hour, + ct.min, ct.sec, ct.nsec, &status); + if (error < 0) + return (ENXIO); + if (status != 0) + return (((int)status < 0) ? ENXIO : EAGAIN); + + return (0); +} + +static void +rtas_shutdown(void *arg, int howto) +{ + cell_t token, status; + + if (howto & RB_HALT) { + token = rtas_token_lookup("power-off"); + if (token == -1) + return; + + rtas_call_method(token, 2, 1, 0, 0, &status); + } else { + token = rtas_token_lookup("system-reboot"); + if (token == -1) + return; + + rtas_call_method(token, 0, 1, &status); + } +} + Index: sys/powerpc/pseries/rtas_pci.c =================================================================== --- sys/powerpc/pseries/rtas_pci.c (revision 0) +++ sys/powerpc/pseries/rtas_pci.c (working copy) @@ -0,0 +1,236 @@ +/*- + * Copyright (c) 2011 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: projects/pseries/powerpc/ofw/ofw_real.c 222059 2011-05-18 15:07:36Z nwhitehorn $"); +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include "pcib_if.h" +#include "iommu_if.h" + +/* + * Device interface. + */ +static int rtaspci_probe(device_t); +static int rtaspci_attach(device_t); + +/* + * pcib interface. + */ +static u_int32_t rtaspci_read_config(device_t, u_int, u_int, u_int, + u_int, int); +static void rtaspci_write_config(device_t, u_int, u_int, u_int, + u_int, u_int32_t, int); + +/* + * IOMMU LPAR interface + */ +static bus_dma_tag_t rtaspci_get_dma_tag(device_t dev, device_t child); + +/* + * Driver methods. + */ +static device_method_t rtaspci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rtaspci_probe), + DEVMETHOD(device_attach, rtaspci_attach), + + /* pcib interface */ + DEVMETHOD(pcib_read_config, rtaspci_read_config), + DEVMETHOD(pcib_write_config, rtaspci_write_config), + + /* IOMMU functions */ + DEVMETHOD(bus_get_dma_tag, rtaspci_get_dma_tag), +#ifdef __powerpc64__ + DEVMETHOD(iommu_map, phyp_iommu_map), + DEVMETHOD(iommu_unmap, phyp_iommu_unmap), +#endif + + DEVMETHOD_END +}; + +struct rtaspci_softc { + struct ofw_pci_softc pci_sc; + bus_dma_tag_t dma_tag; + + cell_t read_pci_config, write_pci_config; + cell_t ex_read_pci_config, ex_write_pci_config; + int sc_extended_config; +}; + +static devclass_t rtaspci_devclass; +DEFINE_CLASS_1(pcib, rtaspci_driver, rtaspci_methods, + sizeof(struct rtaspci_softc), ofw_pci_driver); +DRIVER_MODULE(rtaspci, nexus, rtaspci_driver, rtaspci_devclass, 0, 0); + +static int +rtaspci_probe(device_t dev) +{ + const char *type; + + if (!rtas_exists()) + return (ENXIO); + + type = ofw_bus_get_type(dev); + + if (OF_getproplen(ofw_bus_get_node(dev), "used-by-rtas") < 0) + return (ENXIO); + if (type == NULL || strcmp(type, "pci") != 0) + return (ENXIO); + + device_set_desc(dev, "RTAS Host-PCI bridge"); + return (BUS_PROBE_GENERIC); +} + +static int +rtaspci_attach(device_t dev) +{ + struct rtaspci_softc *sc; + + sc = device_get_softc(dev); + + sc->read_pci_config = rtas_token_lookup("read-pci-config"); + sc->write_pci_config = rtas_token_lookup("write-pci-config"); + sc->ex_read_pci_config = rtas_token_lookup("ibm,read-pci-config"); + sc->ex_write_pci_config = rtas_token_lookup("ibm,write-pci-config"); + + sc->sc_extended_config = 0; + OF_getprop(ofw_bus_get_node(dev), "ibm,pci-config-space-type", + &sc->sc_extended_config, sizeof(sc->sc_extended_config)); + + bus_dma_tag_create(bus_get_dma_tag(dev), + 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, + NULL, NULL, BUS_SPACE_MAXSIZE, 0, BUS_SPACE_MAXSIZE, + 0, NULL, NULL, &sc->dma_tag); +#ifdef __powerpc64__ + if (!(mfmsr() & PSL_HV)) + phyp_iommu_set_dma_tag(dev, dev, sc->dma_tag); +#endif + + return (ofw_pci_attach(dev)); +} + +static uint32_t +rtaspci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, + int width) +{ + struct rtaspci_softc *sc; + uint32_t retval = 0xffffffff; + uint32_t config_addr; + int error, pcierror; + + sc = device_get_softc(dev); + + config_addr = ((bus & 0xff) << 16) | ((slot & 0x1f) << 11) | + ((func & 0x7) << 8) | (reg & 0xff); + if (sc->sc_extended_config) + config_addr |= (reg & 0xf00) << 16; + + if (sc->ex_read_pci_config != -1) + error = rtas_call_method(sc->ex_read_pci_config, 4, 2, + config_addr, sc->pci_sc.sc_pcir.phys_hi, + sc->pci_sc.sc_pcir.phys_mid, width, &pcierror, &retval); + else + error = rtas_call_method(sc->read_pci_config, 2, 2, + config_addr, width, &pcierror, &retval); + + /* Sign-extend output */ + switch (width) { + case 1: + retval = (int32_t)(int8_t)(retval); + break; + case 2: + retval = (int32_t)(int16_t)(retval); + break; + } + + if (error < 0 || pcierror != 0) + retval = 0xffffffff; + + return (retval); +} + +static void +rtaspci_write_config(device_t dev, u_int bus, u_int slot, u_int func, + u_int reg, uint32_t val, int width) +{ + struct rtaspci_softc *sc; + uint32_t config_addr; + int pcierror; + + sc = device_get_softc(dev); + + config_addr = ((bus & 0xff) << 16) | ((slot & 0x1f) << 11) | + ((func & 0x7) << 8) | (reg & 0xff); + if (sc->sc_extended_config) + config_addr |= (reg & 0xf00) << 16; + + if (sc->ex_write_pci_config != -1) + rtas_call_method(sc->ex_write_pci_config, 5, 1, config_addr, + sc->pci_sc.sc_pcir.phys_hi, sc->pci_sc.sc_pcir.phys_mid, + width, val, &pcierror); + else + rtas_call_method(sc->write_pci_config, 3, 1, config_addr, + width, val, &pcierror); +} + +static bus_dma_tag_t +rtaspci_get_dma_tag(device_t dev, device_t child) +{ + struct rtaspci_softc *sc; + + sc = device_get_softc(dev); + return (sc->dma_tag); +} + Index: sys/powerpc/pseries/vdevice.c =================================================================== --- sys/powerpc/pseries/vdevice.c (revision 0) +++ sys/powerpc/pseries/vdevice.c (working copy) @@ -0,0 +1,202 @@ +/*- + * Copyright (c) 2011 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int vdevice_probe(device_t); +static int vdevice_attach(device_t); +static const struct ofw_bus_devinfo *vdevice_get_devinfo(device_t dev, + device_t child); +static int vdevice_print_child(device_t dev, device_t child); +static struct resource_list *vdevice_get_resource_list (device_t, device_t); + +/* + * VDevice devinfo + */ +struct vdevice_devinfo { + struct ofw_bus_devinfo mdi_obdinfo; + struct resource_list mdi_resources; +}; + +static device_method_t vdevice_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, vdevice_probe), + DEVMETHOD(device_attach, vdevice_attach), + + /* Bus interface */ + DEVMETHOD(bus_add_child, bus_generic_add_child), + DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), + DEVMETHOD(bus_print_child, vdevice_print_child), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_get_resource_list, vdevice_get_resource_list), + + /* ofw_bus interface */ + DEVMETHOD(ofw_bus_get_devinfo, vdevice_get_devinfo), + DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), + DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), + DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), + DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), + DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), + + DEVMETHOD_END +}; + +static driver_t vdevice_driver = { + "vdevice", + vdevice_methods, + 0 +}; + +static devclass_t vdevice_devclass; + +DRIVER_MODULE(vdevice, nexus, vdevice_driver, vdevice_devclass, 0, 0); + +static int +vdevice_probe(device_t dev) +{ + const char *name; + + name = ofw_bus_get_name(dev); + + if (name == NULL || strcmp(name, "vdevice") != 0) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "IBM,vdevice")) + return (ENXIO); + + device_set_desc(dev, "POWER Hypervisor Virtual Device Root"); + + return (0); +} + +static int +vdevice_attach(device_t dev) +{ + phandle_t root, child; + device_t cdev; + int icells, i, nintr, *intr; + phandle_t iparent; + struct vdevice_devinfo *dinfo; + + root = ofw_bus_get_node(dev); + + for (child = OF_child(root); child != 0; child = OF_peer(child)) { + dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); + + if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, + child) != 0) { + free(dinfo, M_DEVBUF); + continue; + } + resource_list_init(&dinfo->mdi_resources); + + if (OF_searchprop(child, "#interrupt-cells", &icells, + sizeof(icells)) <= 0) + icells = 2; + if (OF_getprop(child, "interrupt-parent", &iparent, + sizeof(iparent)) <= 0) + iparent = -1; + nintr = OF_getprop_alloc(child, "interrupts", sizeof(*intr), + (void **)&intr); + if (nintr > 0) { + for (i = 0; i < nintr; i += icells) { + u_int irq = intr[i]; + if (iparent != -1) + irq = MAP_IRQ(iparent, intr[i]); + + resource_list_add(&dinfo->mdi_resources, + SYS_RES_IRQ, i, irq, irq, i); + } + } + + cdev = device_add_child(dev, NULL, -1); + if (cdev == NULL) { + device_printf(dev, "<%s>: device_add_child failed\n", + dinfo->mdi_obdinfo.obd_name); + ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); + free(dinfo, M_DEVBUF); + continue; + } + device_set_ivars(cdev, dinfo); + } + + return (bus_generic_attach(dev)); +} + +static const struct ofw_bus_devinfo * +vdevice_get_devinfo(device_t dev, device_t child) +{ + return (device_get_ivars(child)); +} + +static int +vdevice_print_child(device_t dev, device_t child) +{ + struct vdevice_devinfo *dinfo; + struct resource_list *rl; + int retval = 0; + + dinfo = device_get_ivars(child); + rl = &dinfo->mdi_resources; + + retval += bus_print_child_header(dev, child); + + retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); + + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static struct resource_list * +vdevice_get_resource_list (device_t dev, device_t child) +{ + struct vdevice_devinfo *dinfo; + + dinfo = device_get_ivars(child); + return (&dinfo->mdi_resources); +} + Property changes on: sys/powerpc/pseries/vdevice.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: sys/powerpc/pseries/xics.c =================================================================== --- sys/powerpc/pseries/xics.c (revision 0) +++ sys/powerpc/pseries/xics.c (working copy) @@ -0,0 +1,322 @@ +/*- + * Copyright 2011 Nathan Whitehorn + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "phyp-hvcall.h" +#include "pic_if.h" + +#define XICP_PRIORITY 5 /* Random non-zero number */ +#define XICP_IPI 2 +#define MAX_XICP_IRQS (1<<24) /* 24-bit XIRR field */ + +static int xicp_probe(device_t); +static int xicp_attach(device_t); +static int xics_probe(device_t); +static int xics_attach(device_t); + +static void xicp_bind(device_t dev, u_int irq, cpuset_t cpumask); +static void xicp_dispatch(device_t, struct trapframe *); +static void xicp_enable(device_t, u_int, u_int); +static void xicp_eoi(device_t, u_int); +static void xicp_ipi(device_t, u_int); +static void xicp_mask(device_t, u_int); +static void xicp_unmask(device_t, u_int); + +static device_method_t xicp_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, xicp_probe), + DEVMETHOD(device_attach, xicp_attach), + + /* PIC interface */ + DEVMETHOD(pic_bind, xicp_bind), + DEVMETHOD(pic_dispatch, xicp_dispatch), + DEVMETHOD(pic_enable, xicp_enable), + DEVMETHOD(pic_eoi, xicp_eoi), + DEVMETHOD(pic_ipi, xicp_ipi), + DEVMETHOD(pic_mask, xicp_mask), + DEVMETHOD(pic_unmask, xicp_unmask), + + { 0, 0 }, +}; + +static device_method_t xics_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, xics_probe), + DEVMETHOD(device_attach, xics_attach), + + { 0, 0 }, +}; + +struct xicp_softc { + struct mtx sc_mtx; + + int ibm_int_on; + int ibm_int_off; + int ibm_get_xive; + int ibm_set_xive; + + /* XXX: inefficient -- hash table? tree? */ + struct { + int irq; + int vector; + } intvecs[256]; + int nintvecs; +}; + +static driver_t xicp_driver = { + "xicp", + xicp_methods, + sizeof(struct xicp_softc) +}; + +static driver_t xics_driver = { + "xics", + xics_methods, + 0 +}; + +static devclass_t xicp_devclass; +static devclass_t xics_devclass; + +EARLY_DRIVER_MODULE(xicp, nexus, xicp_driver, xicp_devclass, 0, 0, + BUS_PASS_INTERRUPT-1); +EARLY_DRIVER_MODULE(xics, nexus, xics_driver, xics_devclass, 0, 0, + BUS_PASS_INTERRUPT); + +static int +xicp_probe(device_t dev) +{ + if (ofw_bus_get_name(dev) == NULL || strcmp(ofw_bus_get_name(dev), + "interrupt-controller") != 0) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ibm,ppc-xicp")) + return (ENXIO); + + device_set_desc(dev, "PAPR virtual interrupt controller"); + return (BUS_PROBE_GENERIC); +} + +static int +xics_probe(device_t dev) +{ + if (ofw_bus_get_name(dev) == NULL || strcmp(ofw_bus_get_name(dev), + "interrupt-controller") != 0) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ibm,ppc-xics")) + return (ENXIO); + + device_set_desc(dev, "PAPR virtual interrupt source"); + return (BUS_PROBE_GENERIC); +} + +static int +xicp_attach(device_t dev) +{ + struct xicp_softc *sc = device_get_softc(dev); + phandle_t phandle = ofw_bus_get_node(dev); + + mtx_init(&sc->sc_mtx, "XICP", NULL, MTX_DEF); + sc->nintvecs = 0; + + sc->ibm_int_on = rtas_token_lookup("ibm,int-on"); + sc->ibm_int_off = rtas_token_lookup("ibm,int-off"); + sc->ibm_set_xive = rtas_token_lookup("ibm,set-xive"); + sc->ibm_get_xive = rtas_token_lookup("ibm,get-xive"); + + if (OF_getproplen(phandle, "ibm,phandle") > 0) + OF_getprop(phandle, "ibm,phandle", &phandle, sizeof(phandle)); + + powerpc_register_pic(dev, phandle, MAX_XICP_IRQS, + 1 /* Number of IPIs */, FALSE); + root_pic = dev; + + return (0); +} + +static int +xics_attach(device_t dev) +{ + phandle_t phandle = ofw_bus_get_node(dev); + + if (OF_getproplen(phandle, "ibm,phandle") > 0) + OF_getprop(phandle, "ibm,phandle", &phandle, sizeof(phandle)); + + /* The XICP (root PIC) will handle all our interrupts */ + powerpc_register_pic(root_pic, phandle, MAX_XICP_IRQS, + 1 /* Number of IPIs */, FALSE); + + return (0); +} + +/* + * PIC I/F methods. + */ + +static void +xicp_bind(device_t dev, u_int irq, cpuset_t cpumask) +{ + struct xicp_softc *sc = device_get_softc(dev); + cell_t status, cpu; + + /* + * This doesn't appear to actually support affinity groups, so just + * use the first CPU. + */ + CPU_FOREACH(cpu) + if (CPU_ISSET(cpu, &cpumask)) break; + + rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu, XICP_PRIORITY, + &status); +} + +static void +xicp_dispatch(device_t dev, struct trapframe *tf) +{ + struct xicp_softc *sc; + uint64_t xirr, junk; + int i; + + sc = device_get_softc(dev); + for (;;) { + /* Return value in R4, use the PFT call */ + phyp_pft_hcall(H_XIRR, 0, 0, 0, 0, &xirr, &junk, &junk); + xirr &= 0x00ffffff; + + if (xirr == 0) { /* No more pending interrupts? */ + phyp_hcall(H_CPPR, (uint64_t)0xff); + break; + } + if (xirr == XICP_IPI) { /* Magic number for IPIs */ + xirr = MAX_XICP_IRQS; /* Map to FreeBSD magic */ + phyp_hcall(H_IPI, (uint64_t)(PCPU_GET(cpuid)), + 0xff); /* Clear IPI */ + } + + /* XXX: super inefficient */ + for (i = 0; i < sc->nintvecs; i++) { + if (sc->intvecs[i].irq == xirr) + break; + } + + KASSERT(i < sc->nintvecs, ("Unmapped XIRR")); + powerpc_dispatch_intr(sc->intvecs[i].vector, tf); + } +} + +static void +xicp_enable(device_t dev, u_int irq, u_int vector) +{ + struct xicp_softc *sc; + cell_t status, cpu; + + sc = device_get_softc(dev); + + KASSERT(sc->nintvecs + 1 < sizeof(sc->intvecs)/sizeof(sc->intvecs[0]), + ("Too many XICP interrupts")); + + mtx_lock(&sc->sc_mtx); + sc->intvecs[sc->nintvecs].irq = irq; + sc->intvecs[sc->nintvecs].vector = vector; + mb(); + sc->nintvecs++; + mtx_unlock(&sc->sc_mtx); + + /* IPIs are also enabled */ + if (irq == MAX_XICP_IRQS) + return; + + /* Bind to this CPU to start: distrib. ID is last entry in gserver# */ + cpu = PCPU_GET(cpuid); + rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu, XICP_PRIORITY, + &status); + xicp_unmask(dev, irq); +} + +static void +xicp_eoi(device_t dev, u_int irq) +{ + uint64_t xirr; + + if (irq == MAX_XICP_IRQS) /* Remap IPI interrupt to internal value */ + irq = XICP_IPI; + xirr = irq | (XICP_PRIORITY << 24); + + phyp_hcall(H_EOI, xirr); +} + +static void +xicp_ipi(device_t dev, u_int cpu) +{ + + phyp_hcall(H_IPI, (uint64_t)cpu, XICP_PRIORITY); +} + +static void +xicp_mask(device_t dev, u_int irq) +{ + struct xicp_softc *sc = device_get_softc(dev); + cell_t status; + + if (irq == MAX_XICP_IRQS) + return; + + rtas_call_method(sc->ibm_int_off, 1, 1, irq, &status); +} + +static void +xicp_unmask(device_t dev, u_int irq) +{ + struct xicp_softc *sc = device_get_softc(dev); + cell_t status; + + if (irq == MAX_XICP_IRQS) + return; + + rtas_call_method(sc->ibm_int_on, 1, 1, irq, &status); +} + Property changes on: sys/powerpc/pseries/xics.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: sys/conf/files.powerpc =================================================================== --- sys/conf/files.powerpc (revision 255602) +++ sys/conf/files.powerpc (working copy) @@ -225,6 +225,15 @@ powerpc/ps3/ps3pic.c optional ps3 powerpc/ps3/ps3_syscons.c optional ps3 sc powerpc/ps3/ps3-hvcall.S optional ps3 sc +powerpc/pseries/phyp-hvcall.S optional pseries powerpc64 +powerpc/pseries/mmu_phyp.c optional pseries powerpc64 +powerpc/pseries/phyp_console.c optional pseries powerpc64 +powerpc/pseries/platform_chrp.c optional pseries +powerpc/pseries/plpar_iommu.c optional pseries powerpc64 +powerpc/pseries/rtas_dev.c optional pseries +powerpc/pseries/rtas_pci.c optional pseries pci +powerpc/pseries/vdevice.c optional pseries powerpc64 +powerpc/pseries/xics.c optional pseries powerpc64 powerpc/psim/iobus.c optional psim powerpc/psim/ata_iobus.c optional ata psim powerpc/psim/openpic_iobus.c optional psim Index: sys/conf/options.powerpc =================================================================== --- sys/conf/options.powerpc (revision 255602) +++ sys/conf/options.powerpc (working copy) @@ -22,6 +22,7 @@ POWERMAC opt_platform.h PS3 opt_platform.h MAMBO +PSERIES PSIM WII opt_platform.h Index: release/powerpc/mkisoimages.sh =================================================================== --- release/powerpc/mkisoimages.sh (revision 255602) +++ release/powerpc/mkisoimages.sh (working copy) @@ -40,7 +40,7 @@ FreeBSD Install FreeBSD -boot &device;:&partition;,\ppc\chrp\loader +boot &device;:,\ppc\chrp\loader EOF bootable="$bootable -o chrp-boot"