svn commit: r212101 - in user/nwhitehorn/ps3/powerpc: aim include powerpc ps3

Nathan Whitehorn nwhitehorn at FreeBSD.org
Wed Sep 1 17:02:31 UTC 2010


Author: nwhitehorn
Date: Wed Sep  1 17:02:31 2010
New Revision: 212101
URL: http://svn.freebsd.org/changeset/base/212101

Log:
  Enable use of the high 128 MB of memory on the PS3. On PowerPC hypervisors,
  only a limited subset of physical memory is typically available in real
  mode. In addition, the information on what that subset is is typically
  hypervisor privileged. This commit extends the platform interface to
  provide a hook for querying that information, and modifies the small
  amounts of the kernel that care to use it appropriately.

Modified:
  user/nwhitehorn/ps3/powerpc/aim/mmu_oea64.c
  user/nwhitehorn/ps3/powerpc/aim/slb.c
  user/nwhitehorn/ps3/powerpc/aim/uma_machdep.c
  user/nwhitehorn/ps3/powerpc/include/platform.h
  user/nwhitehorn/ps3/powerpc/include/vmparam.h
  user/nwhitehorn/ps3/powerpc/powerpc/platform.c
  user/nwhitehorn/ps3/powerpc/powerpc/platform_if.m
  user/nwhitehorn/ps3/powerpc/ps3/if_glc.c
  user/nwhitehorn/ps3/powerpc/ps3/if_glcreg.h
  user/nwhitehorn/ps3/powerpc/ps3/mmu_ps3.c
  user/nwhitehorn/ps3/powerpc/ps3/platform_ps3.c

Modified: user/nwhitehorn/ps3/powerpc/aim/mmu_oea64.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/aim/mmu_oea64.c	Wed Sep  1 16:53:38 2010	(r212100)
+++ user/nwhitehorn/ps3/powerpc/aim/mmu_oea64.c	Wed Sep  1 17:02:31 2010	(r212101)
@@ -2338,6 +2338,9 @@ moea64_bootstrap_alloc(vm_size_t size, u
 		if (s < phys_avail[i] || e > phys_avail[i + 1])
 			continue;
 
+		if (s + size > platform_real_maxaddr())
+			continue;
+
 		if (s == phys_avail[i]) {
 			phys_avail[i] += size;
 		} else if (e == phys_avail[i + 1]) {

Modified: user/nwhitehorn/ps3/powerpc/aim/slb.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/aim/slb.c	Wed Sep  1 16:53:38 2010	(r212100)
+++ user/nwhitehorn/ps3/powerpc/aim/slb.c	Wed Sep  1 17:02:31 2010	(r212101)
@@ -40,11 +40,14 @@
 #include <vm/vm_map.h>
 
 #include <machine/md_var.h>
+#include <machine/platform.h>
 #include <machine/pmap.h>
 #include <machine/vmparam.h>
 
 uintptr_t moea64_get_unique_vsid(void);
 void moea64_release_vsid(uint64_t vsid);
+void *uma_small_alloc_core(uma_zone_t zone, int bytes, u_int8_t *flags,
+    int wait, vm_offset_t minphys, vm_offset_t maxphys);
 
 struct slbcontainer {
 	struct slb slb;
@@ -273,6 +276,18 @@ slb_compare(struct slbcontainer *a, stru
 		return (1);
 }
 
+static void *
+slb_uma_cache_alloc(uma_zone_t zone, int bytes, u_int8_t *flags, int wait)
+{
+	static vm_offset_t realmax = 0;
+
+	if (realmax == 0)
+		realmax = platform_real_maxaddr();
+
+        return (uma_small_alloc_core(zone, bytes, flags, wait, 0, realmax));
+}
+
+
 static void
 slb_zone_init(void *dummy)
 {
@@ -281,6 +296,9 @@ slb_zone_init(void *dummy)
 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM);
 	slb_cache_zone = uma_zcreate("SLB cache", 64*sizeof(struct slb),
 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM);
+
+	if (platform_real_maxaddr() != VM_MAX_ADDRESS)
+		uma_zone_set_allocf(slb_cache_zone, slb_uma_cache_alloc);
 }
 
 struct slb *

Modified: user/nwhitehorn/ps3/powerpc/aim/uma_machdep.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/aim/uma_machdep.c	Wed Sep  1 16:53:38 2010	(r212100)
+++ user/nwhitehorn/ps3/powerpc/aim/uma_machdep.c	Wed Sep  1 17:02:31 2010	(r212101)
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
 #include <vm/vm_kern.h>
 #include <vm/vm_pageout.h>
 #include <vm/vm_extern.h>
+#include <vm/vm_phys.h>
 #include <vm/uma.h>
 #include <vm/uma.h>
 #include <vm/uma_int.h>
@@ -48,9 +49,20 @@ static int hw_uma_mdpages;
 SYSCTL_INT(_hw, OID_AUTO, uma_mdpages, CTLFLAG_RD, &hw_uma_mdpages, 0,
 	   "UMA MD pages in use");
 
+void *uma_small_alloc_core(uma_zone_t zone, int bytes, u_int8_t *flags,
+    int wait, vm_offset_t minphys, vm_offset_t maxphys);
+
 void *
 uma_small_alloc(uma_zone_t zone, int bytes, u_int8_t *flags, int wait)
 {
+	return (uma_small_alloc_core(zone, bytes, flags, wait,
+	    0, VM_MAX_ADDRESS));
+}
+
+void *
+uma_small_alloc_core(uma_zone_t zone, int bytes, u_int8_t *flags, int wait,
+    vm_offset_t minphys, vm_offset_t maxphys)
+{
 	static vm_pindex_t color;
 	void *va;
 	vm_page_t m;
@@ -65,7 +77,12 @@ uma_small_alloc(uma_zone_t zone, int byt
 		pflags |= VM_ALLOC_ZERO;
 
 	for (;;) {
-		m = vm_page_alloc(NULL, color++, pflags | VM_ALLOC_NOOBJ);
+		if (minphys == 0 && maxphys == VM_MAX_ADDRESS)
+			m = vm_page_alloc(NULL, color++,
+			    pflags | VM_ALLOC_NOOBJ);
+		else
+			m = vm_phys_alloc_contig(1, minphys, maxphys, PAGE_SIZE,
+			    PAGE_SIZE);
 		if (m == NULL) {
 			if (wait & M_NOWAIT)
 				return (NULL);

Modified: user/nwhitehorn/ps3/powerpc/include/platform.h
==============================================================================
--- user/nwhitehorn/ps3/powerpc/include/platform.h	Wed Sep  1 16:53:38 2010	(r212100)
+++ user/nwhitehorn/ps3/powerpc/include/platform.h	Wed Sep  1 17:02:31 2010	(r212101)
@@ -44,6 +44,7 @@ struct mem_region {
 };
 
 void	mem_regions(struct mem_region **, int *, struct mem_region **, int *);
+vm_offset_t platform_real_maxaddr(void);
 
 u_long	platform_timebase_freq(struct cpuref *);
   

Modified: user/nwhitehorn/ps3/powerpc/include/vmparam.h
==============================================================================
--- user/nwhitehorn/ps3/powerpc/include/vmparam.h	Wed Sep  1 16:53:38 2010	(r212100)
+++ user/nwhitehorn/ps3/powerpc/include/vmparam.h	Wed Sep  1 17:02:31 2010	(r212101)
@@ -142,7 +142,11 @@ struct pmap_physseg {
 /*
  * The physical address space is densely populated.
  */
+#ifdef __powerpc64__
+#define	VM_PHYSSEG_SPARSE
+#else
 #define	VM_PHYSSEG_DENSE
+#endif
 
 /*
  * Create three free page pools: VM_FREEPOOL_DEFAULT is the default pool

Modified: user/nwhitehorn/ps3/powerpc/powerpc/platform.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/powerpc/platform.c	Wed Sep  1 16:53:38 2010	(r212100)
+++ user/nwhitehorn/ps3/powerpc/powerpc/platform.c	Wed Sep  1 17:02:31 2010	(r212101)
@@ -69,6 +69,12 @@ mem_regions(struct mem_region **phys, in
 	PLATFORM_MEM_REGIONS(plat_obj, phys, physsz, avail, availsz);
 }
 
+vm_offset_t
+platform_real_maxaddr(void)
+{
+	return (PLATFORM_REAL_MAXADDR(plat_obj));
+}
+
 const char *
 installed_platform()
 {

Modified: user/nwhitehorn/ps3/powerpc/powerpc/platform_if.m
==============================================================================
--- user/nwhitehorn/ps3/powerpc/powerpc/platform_if.m	Wed Sep  1 16:53:38 2010	(r212100)
+++ user/nwhitehorn/ps3/powerpc/powerpc/platform_if.m	Wed Sep  1 17:02:31 2010	(r212101)
@@ -34,6 +34,7 @@
 #include <machine/platform.h>
 #include <machine/platformvar.h>
 #include <machine/smp.h>
+#include <machine/vmparam.h>
 
 /**
  * @defgroup PLATFORM platform - KObj methods for PowerPC platform
@@ -66,6 +67,10 @@ CODE {
 	{
 		return (ENOENT);
 	}
+	static vm_offset_t platform_null_real_maxaddr(platform_t plat)
+	{
+		return (VM_MAX_ADDRESS);
+	}
 };
 
 /**
@@ -109,6 +114,15 @@ METHOD void mem_regions {
 };
 
 /**
+ * @brief Return the maximum address accessible in real mode
+ *   (for use with hypervisors)
+ */
+METHOD vm_offset_t real_maxaddr {
+	platform_t	_plat;
+} DEFAULT platform_null_real_maxaddr;
+
+
+/**
  * @brief Get the CPU's timebase frequency, in ticks per second.
  *
  * @param _cpu		CPU whose timebase to query

Modified: user/nwhitehorn/ps3/powerpc/ps3/if_glc.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/ps3/if_glc.c	Wed Sep  1 16:53:38 2010	(r212100)
+++ user/nwhitehorn/ps3/powerpc/ps3/if_glc.c	Wed Sep  1 17:02:31 2010	(r212101)
@@ -49,6 +49,7 @@
 
 #include <machine/pio.h>
 #include <machine/bus.h>
+#include <machine/platform.h>
 #include <machine/pmap.h>
 #include <machine/resource.h>
 #include <sys/bus.h>
@@ -110,13 +111,36 @@ glc_getphys(void *xaddr, bus_dma_segment
 	*(bus_addr_t *)xaddr = segs[0].ds_addr;
 }
 
+static bus_addr_t
+glc_map_addr(struct glc_softc *sc, bus_addr_t lpar_addr)
+{
+	static struct mem_region *regions = NULL;
+	static int rcount;
+	int i;
+
+	if (regions == NULL)
+		mem_regions(&regions, &rcount, &regions, &rcount);
+
+	for (i = 0; i < rcount; i++) {
+		if (lpar_addr >= regions[i].mr_start &&
+		    lpar_addr < regions[i].mr_start + regions[i].mr_size)
+			break;
+	}
+
+	if (i == rcount)
+		panic("glc: unable to map address %#lx", lpar_addr);
+
+	return (sc->sc_dma_base[i] + (lpar_addr - regions[i].mr_start));
+}
+
 static int 
 glc_attach(device_t dev) 
 {
 	struct glc_softc *sc;
 	struct glc_txsoft *txs;
+	struct mem_region *regions;
 	uint64_t mac64, val, junk;
-	int i, err;
+	int i, err, rcount;
 
 	sc = device_get_softc(dev);
 
@@ -184,24 +208,29 @@ glc_attach(device_t dev) 
 	 */
 
 	/* XXX: following should be integrated to busdma */
-	err = lv1_allocate_device_dma_region(sc->sc_bus, sc->sc_dev,
-	    0x8000000 /* 128 MB */, 24 /* log_2(16 MB) */,
-	    0 /* 32-bit transfers */, &sc->sc_dma_base);
-	if (err != 0) {
-		device_printf(dev, "could not allocate DMA region: %d\n", err);
-		goto fail;
-	}
+	mem_regions(&regions, &rcount, &regions, &rcount);
+	for (i = 0; i < rcount; i++) {
+		err = lv1_allocate_device_dma_region(sc->sc_bus, sc->sc_dev,
+		    regions[i].mr_size, 24 /* log_2(16 MB) */,
+		    0 /* 32-bit transfers */, &sc->sc_dma_base[i]);
+		if (err != 0) {
+			device_printf(dev,
+			    "could not allocate DMA region %d: %d\n", i, err);
+			goto fail;
+		}
 
-	err = lv1_map_device_dma_region(sc->sc_bus, sc->sc_dev, 0 /* physmem */,
-	    sc->sc_dma_base, 0x8000000 /* 128 MB */,
-	    0xf800000000000000UL /* see Cell IO/MMU docs */);
-	if (err != 0) {
-		device_printf(dev, "could not map DMA region: %d\n", err);
-		goto fail;
+		err = lv1_map_device_dma_region(sc->sc_bus, sc->sc_dev,
+		    regions[i].mr_start, sc->sc_dma_base[i], regions[i].mr_size,
+		    0xf800000000000000UL /* see Cell IO/MMU docs */);
+		if (err != 0) {
+			device_printf(dev,
+			    "could not map DMA region %d: %d\n", i, err);
+			goto fail;
+		}
 	}
 
 	err = bus_dma_tag_create(bus_get_dma_tag(dev), 32, 0,
-	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
 	    129*sizeof(struct glc_dmadesc), 1, 128*sizeof(struct glc_dmadesc),
 	    0, NULL,NULL, &sc->sc_dmadesc_tag);
 
@@ -219,11 +248,11 @@ glc_attach(device_t dev) 
 	    &sc->sc_rxdmadesc_phys, 0);
 
 	err = bus_dma_tag_create(bus_get_dma_tag(dev), 128, 0,
-	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
 	    BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL,NULL,
 	    &sc->sc_rxdma_tag);
 	err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
-	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
 	    BUS_SPACE_MAXSIZE_32BIT, 16, BUS_SPACE_MAXSIZE_32BIT, 0, NULL,NULL,
 	    &sc->sc_txdma_tag);
 
@@ -469,15 +498,15 @@ glc_add_rxbuf_dma(struct glc_softc *sc, 
 	struct glc_rxsoft *rxs = &sc->sc_rxsoft[idx];
 	
 	bzero(&sc->sc_rxdmadesc[idx], sizeof(sc->sc_rxdmadesc[idx]));
-	sc->sc_rxdmadesc[idx].paddr = sc->sc_dma_base + rxs->segment.ds_addr;
+	sc->sc_rxdmadesc[idx].paddr = glc_map_addr(sc, rxs->segment.ds_addr);
 	sc->sc_rxdmadesc[idx].len = rxs->segment.ds_len;
-	sc->sc_rxdmadesc[idx].next = sc->sc_dma_base + sc->sc_rxdmadesc_phys +
-	    ((idx + 1) % GLC_MAX_RX_PACKETS)*sizeof(sc->sc_rxdmadesc[idx]);
+	sc->sc_rxdmadesc[idx].next = glc_map_addr(sc, sc->sc_rxdmadesc_phys +
+	    ((idx + 1) % GLC_MAX_RX_PACKETS)*sizeof(sc->sc_rxdmadesc[idx]));
 	sc->sc_rxdmadesc[idx].cmd_stat = GELIC_DESCR_OWNED;
 
 	rxs->rxs_desc_slot = idx;
-	rxs->rxs_desc = sc->sc_dma_base + sc->sc_rxdmadesc_phys +
-	    idx*sizeof(struct glc_dmadesc);
+	rxs->rxs_desc = glc_map_addr(sc, sc->sc_rxdmadesc_phys +
+	    idx*sizeof(struct glc_dmadesc));
 
         return (0);
 }
@@ -544,19 +573,19 @@ glc_encap(struct glc_softc *sc, struct m
 	txs->txs_firstdesc = sc->next_txdma_slot;
 
 	idx = txs->txs_firstdesc;
-	firstslotphys = sc->sc_dma_base + sc->sc_txdmadesc_phys +
-	    txs->txs_firstdesc*sizeof(struct glc_dmadesc);
+	firstslotphys = glc_map_addr(sc, sc->sc_txdmadesc_phys +
+	    txs->txs_firstdesc*sizeof(struct glc_dmadesc));
 
 	for (i = 0; i < nsegs; i++) {
 		if (i+1 == nsegs)
 			txs->txs_lastdesc = sc->next_txdma_slot;
 
 		bzero(&sc->sc_txdmadesc[idx], sizeof(sc->sc_txdmadesc[idx]));
-		sc->sc_txdmadesc[idx].paddr = sc->sc_dma_base + segs[i].ds_addr;
+		sc->sc_txdmadesc[idx].paddr = glc_map_addr(sc, segs[i].ds_addr);
 		sc->sc_txdmadesc[idx].len = segs[i].ds_len;
-		sc->sc_txdmadesc[idx].next = sc->sc_dma_base +
+		sc->sc_txdmadesc[idx].next = glc_map_addr(sc,
 		    sc->sc_txdmadesc_phys +
-		    ((idx + 1) % GLC_MAX_TX_PACKETS)*sizeof(struct glc_dmadesc);
+		    ((idx + 1) % GLC_MAX_TX_PACKETS)*sizeof(struct glc_dmadesc));
 		sc->sc_txdmadesc[idx].cmd_stat |= GELIC_CMDSTAT_NOIPSEC;
 
 		if (i+1 == nsegs) {

Modified: user/nwhitehorn/ps3/powerpc/ps3/if_glcreg.h
==============================================================================
--- user/nwhitehorn/ps3/powerpc/ps3/if_glcreg.h	Wed Sep  1 16:53:38 2010	(r212100)
+++ user/nwhitehorn/ps3/powerpc/ps3/if_glcreg.h	Wed Sep  1 17:02:31 2010	(r212101)
@@ -70,7 +70,7 @@ struct glc_softc {
 	int		sc_tx_vlan, sc_rx_vlan;
 	int		sc_ifpflags;
 
-	uint64_t	sc_dma_base;
+	uint64_t	sc_dma_base[5];
 	bus_dma_tag_t	sc_dmadesc_tag;
 
 	int		sc_irqid;

Modified: user/nwhitehorn/ps3/powerpc/ps3/mmu_ps3.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/ps3/mmu_ps3.c	Wed Sep  1 16:53:38 2010	(r212100)
+++ user/nwhitehorn/ps3/powerpc/ps3/mmu_ps3.c	Wed Sep  1 17:02:31 2010	(r212101)
@@ -264,7 +264,7 @@ mps3_pte_insert(u_int ptegidx, struct lp
 
 	if (result != 0) {
 		/* No freeable slots in either PTEG? We're hosed. */
-		mtmsr(mfmsr() | PSL_DR); panic("moea64_pte_insert: overflow");
+		panic("mps3_pte_insert: overflow (%d)", result);
 		return (-1);
 	}
 

Modified: user/nwhitehorn/ps3/powerpc/ps3/platform_ps3.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/ps3/platform_ps3.c	Wed Sep  1 16:53:38 2010	(r212100)
+++ user/nwhitehorn/ps3/powerpc/ps3/platform_ps3.c	Wed Sep  1 17:02:31 2010	(r212101)
@@ -62,6 +62,7 @@ static int ps3_probe(platform_t);
 static int ps3_attach(platform_t);
 static void ps3_mem_regions(platform_t, struct mem_region **phys, int *physsz,
     struct mem_region **avail, int *availsz);
+static vm_offset_t ps3_real_maxaddr(platform_t);
 static u_long ps3_timebase_freq(platform_t, struct cpuref *cpuref);
 static int ps3_smp_first_cpu(platform_t, struct cpuref *cpuref);
 static int ps3_smp_next_cpu(platform_t, struct cpuref *cpuref);
@@ -73,6 +74,7 @@ static platform_method_t ps3_methods[] =
 	PLATFORMMETHOD(platform_probe, 		ps3_probe),
 	PLATFORMMETHOD(platform_attach,		ps3_attach),
 	PLATFORMMETHOD(platform_mem_regions,	ps3_mem_regions),
+	PLATFORMMETHOD(platform_real_maxaddr,	ps3_real_maxaddr),
 	PLATFORMMETHOD(platform_timebase_freq,	ps3_timebase_freq),
 
 	PLATFORMMETHOD(platform_smp_first_cpu,	ps3_smp_first_cpu),
@@ -114,34 +116,48 @@ ps3_probe(platform_t plat)
 #endif
 }
 
+#define MEM_REGIONS	2
+static struct mem_region avail_regions[MEM_REGIONS];
+
 static int
 ps3_attach(platform_t plat)
 {
+	uint64_t lpar_id, junk, ppe_id;
+
+	/* Get real mode memory region */
+	avail_regions[0].mr_start = 0;
+	lv1_get_logical_partition_id(&lpar_id);
+	lv1_get_logical_ppe_id(&ppe_id);
+	lv1_get_repository_node_value(lpar_id,
+	    lv1_repository_string("bi") >> 32, lv1_repository_string("pu"),
+	    ppe_id, lv1_repository_string("rm_size"),
+	    &avail_regions[0].mr_size, &junk);
+
+	/* Now get extended memory region */
+	lv1_get_repository_node_value(lpar_id,
+	    lv1_repository_string("bi") >> 32,
+	    lv1_repository_string("rgntotal"), 0, 0,
+	    &avail_regions[1].mr_size, &junk);
+
+	/* Convert to maximum amount we can allocate in 16 MB pages */
+	avail_regions[1].mr_size -= avail_regions[0].mr_size;
+	avail_regions[1].mr_size -= avail_regions[1].mr_size % (16*1024*1024);
+
+	lv1_allocate_memory(avail_regions[1].mr_size, 24 /* 16 MB pages */,
+	    0, 0x04 /* any address */, &avail_regions[1].mr_start, &junk);
 
 	pmap_mmu_install("mmu_ps3", BUS_PROBE_SPECIFIC);
 
 	return (0);
 }
 
-#define MEM_REGIONS	8
-static struct mem_region avail_regions[MEM_REGIONS];
-
 void
 ps3_mem_regions(platform_t plat, struct mem_region **phys, int *physsz,
     struct mem_region **avail, int *availsz)
 {
-	uint64_t lpar_id, junk, ppe_id;
-
-	avail_regions[0].mr_start = 0;
-	lv1_get_logical_partition_id(&lpar_id);
-	lv1_get_logical_ppe_id(&ppe_id);
-	lv1_get_repository_node_value(lpar_id,
-	    lv1_repository_string("bi") >> 32, lv1_repository_string("pu"),
-	    ppe_id, lv1_repository_string("rm_size"),
-	    &avail_regions[0].mr_size, &junk);
 
 	*phys = *avail = avail_regions;
-	*physsz = *availsz = 1;
+	*physsz = *availsz = MEM_REGIONS;
 }
 
 static u_long
@@ -223,3 +239,10 @@ ps3_reset(platform_t plat)
 {
 	lv1_panic(1);
 }
+
+static vm_offset_t
+ps3_real_maxaddr(platform_t plat)
+{
+	return (avail_regions[0].mr_start + avail_regions[0].mr_size);
+}
+


More information about the svn-src-user mailing list