Module Name: src
Committed By: palle
Date: Thu Sep 3 19:43:35 UTC 2015
Modified Files:
src/sys/arch/sparc64/dev: iommu.c iommuvar.h vpci.c
Log Message:
sun4v: iommu setup seems to work now - device detection is now possible - parts
from OpenBSD - ok mrg@, martin@
To generate a diff of this commit:
cvs rdiff -u -r1.108 -r1.109 src/sys/arch/sparc64/dev/iommu.c
cvs rdiff -u -r1.21 -r1.22 src/sys/arch/sparc64/dev/iommuvar.h
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/sparc64/dev/vpci.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/sparc64/dev/iommu.c
diff -u src/sys/arch/sparc64/dev/iommu.c:1.108 src/sys/arch/sparc64/dev/iommu.c:1.109
--- src/sys/arch/sparc64/dev/iommu.c:1.108 Sun Aug 24 19:09:43 2014
+++ src/sys/arch/sparc64/dev/iommu.c Thu Sep 3 19:43:35 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: iommu.c,v 1.108 2014/08/24 19:09:43 palle Exp $ */
+/* $NetBSD: iommu.c,v 1.109 2015/09/03 19:43:35 palle Exp $ */
/*
* Copyright (c) 1999, 2000 Matthew R. Green
@@ -59,7 +59,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.108 2014/08/24 19:09:43 palle Exp $");
+__KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.109 2015/09/03 19:43:35 palle Exp $");
#include "opt_ddb.h"
@@ -101,6 +101,10 @@ int iommudebug = 0x0;
static int iommu_strbuf_flush_done(struct strbuf_ctl *);
static void _iommu_dvmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
bus_size_t, int);
+static void iommu_enter_sun4u(struct strbuf_ctl *sb, vaddr_t va, int64_t pa, int flags);
+static void iommu_enter_sun4v(struct strbuf_ctl *sb, vaddr_t va, int64_t pa, int flags);
+static void iommu_remove_sun4u(struct iommu_state *is, vaddr_t va, size_t len);
+static void iommu_remove_sun4v(struct iommu_state *is, vaddr_t va, size_t len);
/*
* initialise the UltraSPARC IOMMU (SBUS or PCI):
@@ -118,6 +122,8 @@ iommu_init(char *name, struct iommu_stat
struct vm_page *pg;
struct pglist pglist;
+ DPRINTF(IDB_INFO, ("iommu_init: tsbsize %x iovabase %x\n", tsbsize, iovabase));
+
/*
* Setup the iommu.
*
@@ -181,17 +187,18 @@ iommu_init(char *name, struct iommu_stat
if (iommudebug & IDB_INFO)
{
/* Probe the iommu */
-
- printf("iommu cr=%llx tsb=%llx\n",
- (unsigned long long)bus_space_read_8(is->is_bustag,
+ if (!CPU_ISSUN4V) {
+ printf("iommu cr=%llx tsb=%llx\n",
+ (unsigned long long)bus_space_read_8(is->is_bustag,
is->is_iommu,
offsetof(struct iommureg, iommu_cr)),
- (unsigned long long)bus_space_read_8(is->is_bustag,
+ (unsigned long long)bus_space_read_8(is->is_bustag,
is->is_iommu,
offsetof(struct iommureg, iommu_tsb)));
- printf("TSB base %p phys %llx\n", (void *)is->is_tsb,
- (unsigned long long)is->is_ptsb);
- delay(1000000); /* 1 s */
+ printf("TSB base %p phys %llx\n", (void *)is->is_tsb,
+ (unsigned long long)is->is_ptsb);
+ delay(1000000); /* 1 s */
+ }
}
#endif
@@ -207,8 +214,9 @@ iommu_init(char *name, struct iommu_stat
is->is_dvmamap = extent_create(name,
is->is_dvmabase, is->is_dvmaend,
0, 0, EX_NOWAIT);
- /* XXXMRG Check is_dvmamap is valid. */
-
+ if (!is->is_dvmamap)
+ panic("iommu_init: extent_create() failed");
+
mutex_init(&is->is_lock, MUTEX_DEFAULT, IPL_HIGH);
/*
@@ -237,6 +245,9 @@ iommu_reset(struct iommu_state *is)
int i;
struct strbuf_ctl *sb;
+ if (CPU_ISSUN4V)
+ return;
+
IOMMUREG_WRITE(is, iommu_tsb, is->is_ptsb);
/* Enable IOMMU in diagnostic mode */
@@ -276,9 +287,22 @@ iommu_reset(struct iommu_state *is)
/*
* Here are the iommu control routines.
*/
+
void
iommu_enter(struct strbuf_ctl *sb, vaddr_t va, int64_t pa, int flags)
{
+ DPRINTF(IDB_IOMMU, ("iommu_enter: va %lx pa %lx flags %x\n",
+ va, (long)pa, flags));
+ if (!CPU_ISSUN4V)
+ iommu_enter_sun4u(sb, va, pa, flags);
+ else
+ iommu_enter_sun4v(sb, va, pa, flags);
+}
+
+
+void
+iommu_enter_sun4u(struct strbuf_ctl *sb, vaddr_t va, int64_t pa, int flags)
+{
struct iommu_state *is = sb->sb_is;
int strbuf = (flags & BUS_DMA_STREAMING);
int64_t tte;
@@ -311,6 +335,35 @@ iommu_enter(struct strbuf_ctl *sb, vaddr
(u_long)tte));
}
+void
+iommu_enter_sun4v(struct strbuf_ctl *sb, vaddr_t va, int64_t pa, int flags)
+{
+ struct iommu_state *is = sb->sb_is;
+ u_int64_t tsbid = IOTSBSLOT(va, is->is_tsbsize);
+ paddr_t page_list[1], addr;
+ u_int64_t attr, nmapped;
+ int err;
+
+#ifdef DIAGNOSTIC
+ if (va < is->is_dvmabase || (va + PAGE_MASK) > is->is_dvmaend)
+ panic("viommu_enter: va %#lx not in DVMA space", va);
+#endif
+
+ attr = PCI_MAP_ATTR_READ | PCI_MAP_ATTR_WRITE;
+ if (flags & BUS_DMA_READ)
+ attr &= ~PCI_MAP_ATTR_READ;
+ if (flags & BUS_DMA_WRITE)
+ attr &= ~PCI_MAP_ATTR_WRITE;
+
+ page_list[0] = trunc_page(pa);
+ if (!pmap_extract(pmap_kernel(), (vaddr_t)page_list, &addr))
+ panic("viommu_enter: pmap_extract failed");
+ err = hv_pci_iommu_map(is->is_devhandle, tsbid, 1, attr,
+ addr, &nmapped);
+ if (err != H_EOK || nmapped != 1)
+ panic("hv_pci_iommu_map: err=%d, nmapped=%lu", err, (long unsigned int)nmapped);
+}
+
/*
* Find the value of a DVMA address (debug routine).
*/
@@ -334,9 +387,22 @@ iommu_extract(struct iommu_state *is, va
*
* XXX: this function needs better internal error checking.
*/
+
+
void
iommu_remove(struct iommu_state *is, vaddr_t va, size_t len)
{
+ DPRINTF(IDB_IOMMU, ("iommu_remove: va %lx len %zu\n", va, len));
+ if (!CPU_ISSUN4V)
+ iommu_remove_sun4u(is, va, len);
+ else
+ iommu_remove_sun4v(is, va, len);
+}
+
+void
+iommu_remove_sun4u(struct iommu_state *is, vaddr_t va, size_t len)
+{
+
int slot;
#ifdef DIAGNOSTIC
@@ -389,6 +455,27 @@ iommu_remove(struct iommu_state *is, vad
}
}
+void
+iommu_remove_sun4v(struct iommu_state *is, vaddr_t va, size_t len)
+{
+ u_int64_t tsbid = IOTSBSLOT(va, is->is_tsbsize);
+ u_int64_t ndemapped;
+ int err;
+
+#ifdef DIAGNOSTIC
+ if (va < is->is_dvmabase || (va + PAGE_MASK) > is->is_dvmaend)
+ panic("iommu_remove: va 0x%lx not in DVMA space", (u_long)va);
+ if (va != trunc_page(va)) {
+ printf("iommu_remove: unaligned va: %lx\n", va);
+ va = trunc_page(va);
+ }
+#endif
+
+ err = hv_pci_iommu_demap(is->is_devhandle, tsbid, 1, &ndemapped);
+ if (err != H_EOK || ndemapped != 1)
+ panic("hv_pci_iommu_unmap: err=%d", err);
+}
+
static int
iommu_strbuf_flush_done(struct strbuf_ctl *sb)
{
Index: src/sys/arch/sparc64/dev/iommuvar.h
diff -u src/sys/arch/sparc64/dev/iommuvar.h:1.21 src/sys/arch/sparc64/dev/iommuvar.h:1.22
--- src/sys/arch/sparc64/dev/iommuvar.h:1.21 Sun Mar 25 03:51:33 2012
+++ src/sys/arch/sparc64/dev/iommuvar.h Thu Sep 3 19:43:35 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: iommuvar.h,v 1.21 2012/03/25 03:51:33 mrg Exp $ */
+/* $NetBSD: iommuvar.h,v 1.22 2015/09/03 19:43:35 palle Exp $ */
/*
* Copyright (c) 1999 Matthew R. Green
@@ -65,6 +65,7 @@ struct iommu_state {
/* copies of our parents state, to allow us to be self contained */
bus_space_tag_t is_bustag; /* our bus tag */
bus_space_handle_t is_iommu; /* IOMMU registers */
+ uint64_t is_devhandle; /* for sun4v hypervisor calls */
};
/* interfaces for PCI/SBUS code */
Index: src/sys/arch/sparc64/dev/vpci.c
diff -u src/sys/arch/sparc64/dev/vpci.c:1.1 src/sys/arch/sparc64/dev/vpci.c:1.2
--- src/sys/arch/sparc64/dev/vpci.c:1.1 Thu Feb 12 04:48:37 2015
+++ src/sys/arch/sparc64/dev/vpci.c Thu Sep 3 19:43:35 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: vpci.c,v 1.1 2015/02/12 04:48:37 palle Exp $ */
+/* $NetBSD: vpci.c,v 1.2 2015/09/03 19:43:35 palle Exp $ */
/*
* Copyright (c) 2015 Palle Lyckegaard
* All rights reserved.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vpci.c,v 1.1 2015/02/12 04:48:37 palle Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vpci.c,v 1.2 2015/09/03 19:43:35 palle Exp $");
#include <sys/param.h>
#include <sys/device.h>
@@ -56,11 +56,13 @@ __KERNEL_RCSID(0, "$NetBSD: vpci.c,v 1.1
#include <sparc64/hypervisor.h>
#ifdef DEBUG
-#define VDB_PROM 0x01
-#define VDB_BUSMAP 0x02
-#define VDB_INTR 0x04
-#define VDB_CONF 0x08
-int vpci_debug = 0xff;
+#define VDB_PROM 0x01
+#define VDB_BUSMAP 0x02
+#define VDB_INTR 0x04
+#define VDB_CONF_READ 0x08
+#define VDB_CONF_WRITE 0x10
+#define VDB_CONF VDB_CONF_READ|VDB_CONF_WRITE
+int vpci_debug = 0x00;
#define DPRINTF(l, s) do { if (vpci_debug & l) printf s; } while (0)
#else
#define DPRINTF(l, s)
@@ -94,10 +96,7 @@ CFATTACH_DECL_NEW(vpci, sizeof(struct vp
vpci_match, vpci_attach, NULL, NULL);
void vpci_init(struct vpci_softc */*FIXME, int*/, struct mainbus_attach_args *);
-#if 0
-FIXME
void vpci_init_iommu(struct vpci_softc *, struct vpci_pbm *);
-#endif
pci_chipset_tag_t vpci_alloc_chipset(struct vpci_pbm *, int,
pci_chipset_tag_t);
bus_space_tag_t vpci_alloc_mem_tag(struct vpci_pbm *);
@@ -233,20 +232,9 @@ FiXME
panic("vpci: can't get bus-range");
for (int range = 0; range < nranges; range++)
DPRINTF(VDB_PROM, ("\nvpci_attach: bus-range %d %08x", range, busranges[range]));
-#if 0
-FIXME
- printf(": \"%s\", rev %d, ign %x, bus %c %d to %d\n",
- sc->sc_oberon ? "Oberon" : "Fire",
- prom_getpropint(sc->sc_node, "module-revision#", 0), sc->sc_ign,
- busa ? 'A' : 'B', busranges[0], busranges[1]);
-#else
- printf(": ign %x, bus %d to %d\n", sc->sc_ign, busranges[0], busranges[1]);
-#endif
- printf("%s: ", device_xname(sc->sc_dev));
-#if 0
-FIXME
+
vpci_init_iommu(sc, pbm);
-#endif
+
pbm->vp_memt = vpci_alloc_mem_tag(pbm);
pbm->vp_iot = vpci_alloc_io_tag(pbm);
pbm->vp_cfgt = vpci_alloc_config_tag(pbm);
@@ -284,14 +272,15 @@ FIXME
config_found(sc->sc_dev, &pba, vpci_print);
}
-#if 0
-FIXME
void
vpci_init_iommu(struct vpci_softc *sc, struct vpci_pbm *pbm)
{
struct iommu_state *is = &pbm->vp_is;
- int tsbsize = 7;
+ int *vdma = NULL;
+ int nitem;
+ int tsbsize = 0;
u_int32_t iobase = -1;
+ u_int32_t iolen = 0;
char *name;
pbm->vp_sb.sb_is = is;
@@ -302,6 +291,20 @@ vpci_init_iommu(struct vpci_softc *sc, s
panic("vpci: unable to create iommu handle");
}
+ /* Construct tsbsize */
+ if (!prom_getprop(sc->sc_node, "virtual-dma", sizeof(vdma), &nitem,
+ (void **)&vdma)) {
+ DPRINTF(VDB_BUSMAP, ("vpci_init_iommu: vdma[0]=0x%x vdma[1]=0x%x\n",
+ vdma[0], vdma[1]));
+ iobase = vdma[0];
+ iolen = vdma[1];
+ for (tsbsize = 8; (1 << (tsbsize+23)) > iolen; tsbsize--) ;
+ DPRINTF(VDB_BUSMAP, ("vpci_init_iommu: iobase=0x%x iolen = 0x%x tsbsize=0x%x\n",
+ iobase, iolen, tsbsize));
+ free(vdma, M_DEVBUF);
+ } else
+ panic("vpci_init_iommu: getprop virtual-dma failed");
+
/* We have no STC. */
is->is_sb[0] = NULL;
@@ -313,13 +316,10 @@ vpci_init_iommu(struct vpci_softc *sc, s
/* Tell iommu how to set the TSB size. */
is->is_flags = IOMMU_TSBSIZE_IN_PTSB;
- /* On Oberon, we need to flush the cache. */
- if (sc->sc_oberon)
- is->is_flags |= IOMMU_FLUSH_CACHE;
-
+ is->is_devhandle = pbm->vp_devhandle;
iommu_init(name, is, tsbsize, iobase);
}
-#endif
+
int
vpci_print(void *aux, const char *p)
@@ -336,7 +336,7 @@ vpci_conf_read(pci_chipset_tag_t pc, pci
uint64_t error_flag, data;
int64_t hv_rc;
- DPRINTF(VDB_CONF, ("%s: tag %lx reg %x ", __func__, (long)tag, reg));
+ DPRINTF(VDB_CONF_READ, ("%s: tag %lx reg %x ", __func__, (long)tag, reg));
hv_rc = hv_pci_config_get(pbm->vp_devhandle, PCITAG_OFFSET(tag), reg, 4,
&error_flag, &data);
if (hv_rc != H_EOK)
@@ -344,7 +344,7 @@ vpci_conf_read(pci_chipset_tag_t pc, pci
hv_rc);
pcireg_t val = error_flag ? (pcireg_t)~0 : data;
- DPRINTF(VDB_CONF, (" returning %08x\n", (u_int)val));
+ DPRINTF(VDB_CONF_READ, (" returning %08x\n", (u_int)val));
return val;
}
@@ -355,14 +355,14 @@ vpci_conf_write(pci_chipset_tag_t pc, pc
struct vpci_pbm *pbm = pc->cookie;
uint64_t error_flag;
int64_t hv_rc;
- DPRINTF(VDB_CONF, ("%s: tag %lx; reg %x; data %x", __func__,
+ DPRINTF(VDB_CONF_WRITE, ("%s: tag %lx; reg %x; data %x", __func__,
(long)tag, reg, (int)data));
hv_rc = hv_pci_config_put(pbm->vp_devhandle, PCITAG_OFFSET(tag), reg, 4,
data, &error_flag);
if (hv_rc != H_EOK)
panic("hv_pci_config_put() failed - rc = %" PRId64 "\n",
hv_rc);
- DPRINTF(VDB_CONF, (" .. done\n"));
+ DPRINTF(VDB_CONF_WRITE, (" .. done\n"));
}
/*
@@ -371,8 +371,6 @@ vpci_conf_write(pci_chipset_tag_t pc, pc
int
vpci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
- DPRINTF(VDB_INTR, ("vpci_intr_map()\n"));
-
struct vpci_pbm *pbm = pa->pa_pc->cookie;
uint64_t devhandle = pbm->vp_devhandle;
uint64_t devino = INTINO(*ihp);
@@ -459,8 +457,8 @@ vpci_alloc_dma_tag(struct vpci_pbm *pbm)
dt->_dmamap_sync = iommu_dvmamap_sync;
dt->_dmamem_alloc = iommu_dvmamem_alloc;
dt->_dmamem_free = iommu_dvmamem_free;
- dt->_dmamem_map = iommu_dvmamem_map;
- dt->_dmamem_unmap = iommu_dvmamem_unmap;
+ dt->_dmamem_map = iommu_dvmamem_map;
+ dt->_dmamem_unmap = iommu_dvmamem_unmap;
PCOPY(_dmamem_mmap);
#undef PCOPY
return (dt);
@@ -508,14 +506,14 @@ vpci_bus_map(bus_space_tag_t t, bus_addr
struct vpci_softc *sc = pbm->vp_sc;
int i, ss;
- DPRINTF(VDB_BUSMAP, ("vpci_bus_map: type %d off %qx sz %qx flags %d\n",
+ DPRINTF(VDB_BUSMAP, ("vpci_bus_map: type %d off %qx sz %qx flags %d",
t->type,
(unsigned long long)offset,
(unsigned long long)size,
flags));
ss = sparc_pci_childspace(t->type);
- DPRINTF(VDB_BUSMAP, (" cspace %d", ss));
+ DPRINTF(VDB_BUSMAP, (" cspace %d\n", ss));
if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
printf("\n_vpci_bus_map: invalid parent");