Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 17 Sep 2013 17:37:04 +0000 (UTC)
From:      Nathan Whitehorn <nwhitehorn@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r255643 - in head/sys: conf powerpc/conf powerpc/pseries
Message-ID:  <201309171737.r8HHb4mX080538@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: nwhitehorn
Date: Tue Sep 17 17:37:04 2013
New Revision: 255643
URL: http://svnweb.freebsd.org/changeset/base/255643

Log:
  Merge in support for PAPR-compliant (Power Architecture Platform
  Requirements) systems from the projects/pseries branch. This in principle
  includes all IBM POWER hardware released in the last 15 years with the
  exception of POWER3-based systems when run in 64-bit mode. The main
  development target, however, has been the PAPR logical partition support
  that is the default target in KVM on POWER and QEMU -- mileage may vary
  on actual hardware at present. Much of the heavy lifting here was done
  by Andreas Tobler.
  
  Approved by:	re (kib)

Added:
  head/sys/powerpc/pseries/
  head/sys/powerpc/pseries/mmu_phyp.c   (contents, props changed)
  head/sys/powerpc/pseries/phyp-hvcall.S   (contents, props changed)
  head/sys/powerpc/pseries/phyp-hvcall.h   (contents, props changed)
  head/sys/powerpc/pseries/phyp_console.c   (contents, props changed)
  head/sys/powerpc/pseries/platform_chrp.c   (contents, props changed)
  head/sys/powerpc/pseries/plpar_iommu.c   (contents, props changed)
  head/sys/powerpc/pseries/plpar_iommu.h   (contents, props changed)
  head/sys/powerpc/pseries/rtas_dev.c   (contents, props changed)
  head/sys/powerpc/pseries/rtas_pci.c   (contents, props changed)
  head/sys/powerpc/pseries/vdevice.c   (contents, props changed)
  head/sys/powerpc/pseries/xics.c   (contents, props changed)
Modified:
  head/sys/conf/files.powerpc
  head/sys/conf/options.powerpc
  head/sys/powerpc/conf/DEFAULTS
  head/sys/powerpc/conf/GENERIC
  head/sys/powerpc/conf/GENERIC64

Modified: head/sys/conf/files.powerpc
==============================================================================
--- head/sys/conf/files.powerpc	Tue Sep 17 17:31:53 2013	(r255642)
+++ head/sys/conf/files.powerpc	Tue Sep 17 17:37:04 2013	(r255643)
@@ -225,6 +225,15 @@ powerpc/ps3/ps3disk.c		optional	ps3
 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

Modified: head/sys/conf/options.powerpc
==============================================================================
--- head/sys/conf/options.powerpc	Tue Sep 17 17:31:53 2013	(r255642)
+++ head/sys/conf/options.powerpc	Tue Sep 17 17:37:04 2013	(r255643)
@@ -22,6 +22,7 @@ MPC85XX			opt_platform.h
 POWERMAC		opt_platform.h
 PS3			opt_platform.h
 MAMBO
+PSERIES
 PSIM
 WII			opt_platform.h
 

Modified: head/sys/powerpc/conf/DEFAULTS
==============================================================================
--- head/sys/powerpc/conf/DEFAULTS	Tue Sep 17 17:31:53 2013	(r255642)
+++ head/sys/powerpc/conf/DEFAULTS	Tue Sep 17 17:37:04 2013	(r255643)
@@ -9,6 +9,7 @@ device		mem		# Memory and kernel memory 
 # UART chips on this platform
 device		uart_ns8250
 
+options 	GEOM_PART_BSD
 options 	GEOM_PART_MBR
 
 options         NEW_PCIB

Modified: head/sys/powerpc/conf/GENERIC
==============================================================================
--- head/sys/powerpc/conf/GENERIC	Tue Sep 17 17:31:53 2013	(r255642)
+++ head/sys/powerpc/conf/GENERIC	Tue Sep 17 17:37:04 2013	(r255643)
@@ -30,6 +30,7 @@ makeoptions	WITH_CTF=1
 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

Modified: head/sys/powerpc/conf/GENERIC64
==============================================================================
--- head/sys/powerpc/conf/GENERIC64	Tue Sep 17 17:31:53 2013	(r255642)
+++ head/sys/powerpc/conf/GENERIC64	Tue Sep 17 17:37:04 2013	(r255643)
@@ -30,6 +30,7 @@ makeoptions	WITH_CTF=1
 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
 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		bge		# Broadcom BCM570xx Gigabit
 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

Added: head/sys/powerpc/pseries/mmu_phyp.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/powerpc/pseries/mmu_phyp.c	Tue Sep 17 17:37:04 2013	(r255643)
@@ -0,0 +1,420 @@
+/*
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/msgbuf.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/vmmeter.h>
+
+#include <dev/ofw/openfirm.h>
+#include <machine/ofw_machdep.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_pageout.h>
+#include <vm/uma.h>
+
+#include <powerpc/aim/mmu_oea64.h>
+
+#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));
+}
+

Added: head/sys/powerpc/pseries/phyp-hvcall.S
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/powerpc/pseries/phyp-hvcall.S	Tue Sep 17 17:37:04 2013	(r255643)
@@ -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 <machine/asm.h>
+
+/* 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 */
+

Added: head/sys/powerpc/pseries/phyp-hvcall.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/powerpc/pseries/phyp-hvcall.h	Tue Sep 17 17:37:04 2013	(r255643)
@@ -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 <sys/types.h>
+
+/* 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_ */
+

Added: head/sys/powerpc/pseries/phyp_console.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/powerpc/pseries/phyp_console.c	Tue Sep 17 17:37:04 2013	(r255643)
@@ -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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/priv.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/types.h>
+#include <sys/conf.h>
+#include <sys/cons.h>
+#include <sys/tty.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+
+#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;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201309171737.r8HHb4mX080538>