summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoroga <oga@openbsd.org>2010-05-10 22:06:04 +0000
committeroga <oga@openbsd.org>2010-05-10 22:06:04 +0000
commita9eb44cd5fbd133014a3312b536c2284eb5311a7 (patch)
tree4c691f7b7feef742bb1e03baf49ea5174aea7aa7
parent/* XXX - we don't use __COMPILER_INT64__ */ so remove it. (diff)
downloadwireguard-openbsd-a9eb44cd5fbd133014a3312b536c2284eb5311a7.tar.xz
wireguard-openbsd-a9eb44cd5fbd133014a3312b536c2284eb5311a7.zip
Continue with the horrible habit of using agp_machdep.c for agp related MD
things that there really isn't a decent api for elsewhere. Since on recent intel IGPs the gtt aperture is too big (256meg is not uncommon) to be mapped on a kva-constrained arch like i386, introduce an agp mapping api that does things depending on arch. On amd64 which can afford the space (and will use the direct mapping again soon)just do bus_space_map() on init, then parcels things out using bus_space_subregion(), thus avoiding map/unmap overhead on every call (this is how inteldrm does things right now). On i386, we do bus_space_map() and bus_space_unmap as appropriate. Linux has some tricks here involving ``atomic'' maps that are on only one cpu and that you may not sleep with to avoid the ipi overhead for tlb flushing. For now we don't go down that route but it is being considered. I am also considering if it is worth abstracting this a little more, improving the api and making it a general MD interface. Tested by myself on i386 and amd64 and by drahn@ (who has one of the machines with an aperture that is too big) on i386.
-rw-r--r--sys/arch/amd64/pci/agp_machdep.c55
-rw-r--r--sys/arch/i386/pci/agp_machdep.c96
-rw-r--r--sys/dev/pci/agpvar.h11
3 files changed, 159 insertions, 3 deletions
diff --git a/sys/arch/amd64/pci/agp_machdep.c b/sys/arch/amd64/pci/agp_machdep.c
index 5e320e95293..94a94d5fdb7 100644
--- a/sys/arch/amd64/pci/agp_machdep.c
+++ b/sys/arch/amd64/pci/agp_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: agp_machdep.c,v 1.5 2010/04/08 01:26:44 oga Exp $ */
+/* $OpenBSD: agp_machdep.c,v 1.6 2010/05/10 22:06:04 oga Exp $ */
/*
* Copyright (c) 2008 - 2009 Owain G. Ainsworth <oga@openbsd.org>
@@ -174,6 +174,59 @@ agp_bus_dma_set_alignment(bus_dma_tag_t tag, bus_dmamap_t dmam,
sg_dmamap_set_alignment(tag, dmam, alignment);
}
+struct agp_map {
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+};
+
+int
+agp_init_map(bus_space_tag_t tag, bus_addr_t address, bus_size_t size,
+ int flags, struct agp_map **mapp)
+{
+ struct agp_map *map;
+ int err;
+
+ map = malloc(sizeof(*map), M_AGP, M_WAITOK | M_CANFAIL);
+ if (map == NULL)
+ return (ENOMEM);
+
+ map->bst = tag;
+ map->size = size;
+
+ if ((err = bus_space_map(tag, address, size, flags, &map->bsh)) != 0) {
+ free(map, M_AGP);
+ return (err);
+ }
+ *mapp = map;
+ return (0);
+}
+
+void
+agp_destroy_map(struct agp_map *map)
+{
+ bus_space_unmap(map->bst, map->bsh, map->size);
+ free(map, M_AGP);
+}
+
+
+int
+agp_map_subregion(struct agp_map *map, bus_size_t offset, bus_size_t size,
+ bus_space_handle_t *bshp)
+{
+ if (offset > map->size || size > map->size || offset + size > map->size)
+ return (EINVAL);
+ return (bus_space_subregion(map->bst, map->bsh, offset, size, bshp));
+
+}
+
+void
+agp_unmap_subregion(struct agp_map *map, bus_space_handle_t bsh,
+ bus_size_t size)
+{
+ /* subregion doesn't need unmapping, do nothing */
+}
+
/*
* ick ick ick. However, the rest of this driver is supposedly MI (though
* they only exist on x86), so this can't be in dev/pci.
diff --git a/sys/arch/i386/pci/agp_machdep.c b/sys/arch/i386/pci/agp_machdep.c
index e63e00cc243..e6eaa41a00c 100644
--- a/sys/arch/i386/pci/agp_machdep.c
+++ b/sys/arch/i386/pci/agp_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: agp_machdep.c,v 1.11 2010/04/08 01:26:44 oga Exp $ */
+/* $OpenBSD: agp_machdep.c,v 1.12 2010/05/10 22:06:04 oga Exp $ */
/*
* Copyright (c) 2008 - 2009 Owain G. Ainsworth <oga@openbsd.org>
@@ -174,6 +174,100 @@ agp_bus_dma_set_alignment(bus_dma_tag_t tag, bus_dmamap_t dmam,
sg_dmamap_set_alignment(tag, dmam, alignment);
}
+struct agp_map {
+ bus_space_tag_t bst;
+ bus_addr_t addr;
+ bus_size_t size;
+ int flags;
+};
+
+extern struct extent *ioport_ex;
+extern struct extent *iomem_ex;
+
+int
+agp_init_map(bus_space_tag_t tag, bus_addr_t address, bus_size_t size,
+ int flags, struct agp_map **mapp)
+{
+ struct extent *ex;
+ struct agp_map *map;
+ int error;
+
+ switch (tag) {
+ case I386_BUS_SPACE_IO:
+ ex = ioport_ex;
+ if (flags & BUS_SPACE_MAP_LINEAR)
+ return (EINVAL);
+ break;
+
+ case I386_BUS_SPACE_MEM:
+ ex = iomem_ex;
+ break;
+
+ default:
+ panic("agp_init_map: bad bus space tag");
+ }
+ /*
+ * We grab the extent out of the bus region ourselves
+ * so we don't need to do these allocations every time.
+ */
+ error = extent_alloc_region(ex, address, size,
+ EX_NOWAIT | EX_MALLOCOK);
+ if (error)
+ return (error);
+
+ map = malloc(sizeof(*map), M_AGP, M_WAITOK | M_CANFAIL);
+ if (map == NULL)
+ return (ENOMEM);
+
+ map->bst = tag;
+ map->addr = address;
+ map->size = size;
+ map->flags = flags;
+
+ *mapp = map;
+ return (0);
+}
+
+void
+agp_destroy_map(struct agp_map *map)
+{
+ struct extent *ex;
+
+ switch (map->bst) {
+ case I386_BUS_SPACE_IO:
+ ex = ioport_ex;
+ break;
+
+ case I386_BUS_SPACE_MEM:
+ ex = iomem_ex;
+ break;
+
+ default:
+ panic("agp_destroy_map: bad bus space tag");
+ }
+
+ if (extent_free(ex, map->addr, map->size,
+ EX_NOWAIT | EX_MALLOCOK ))
+ printf("agp_destroy_map: can't free region\n");
+ free(map, M_AGP);
+}
+
+
+int
+agp_map_subregion(struct agp_map *map, bus_size_t offset, bus_size_t size,
+ bus_space_handle_t *bshp)
+{
+ return (_bus_space_map(map->bst, map->addr + offset, size,
+ map->flags, bshp));
+}
+
+void
+agp_unmap_subregion(struct agp_map *map, bus_space_handle_t bsh,
+ bus_size_t size)
+{
+ return (_bus_space_unmap(map->bst, bsh, size, NULL));
+}
+
/*
* ick ick ick. However, the rest of this driver is supposedly MI (though
* they only exist on x86), so this can't be in dev/pci.
diff --git a/sys/dev/pci/agpvar.h b/sys/dev/pci/agpvar.h
index e9a3bb0ab37..2a9f6be4694 100644
--- a/sys/dev/pci/agpvar.h
+++ b/sys/dev/pci/agpvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: agpvar.h,v 1.21 2010/04/08 01:26:44 oga Exp $ */
+/* $OpenBSD: agpvar.h,v 1.22 2010/05/10 22:06:04 oga Exp $ */
/* $NetBSD: agpvar.h,v 1.4 2001/10/01 21:54:48 fvdl Exp $ */
/*-
@@ -148,6 +148,8 @@ struct agp_gatt {
size_t ag_size;
};
+struct agp_map;
+
/*
* Functions private to the AGP code.
*/
@@ -162,6 +164,13 @@ void agp_flush_cache_range(vaddr_t, vsize_t);
int agp_generic_bind_memory(struct agp_softc *, struct agp_memory *,
bus_size_t);
int agp_generic_unbind_memory(struct agp_softc *, struct agp_memory *);
+int agp_init_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, struct
+ agp_map **);
+void agp_destroy_map(struct agp_map *);
+int agp_map_subregion(struct agp_map *, bus_size_t, bus_size_t,
+ bus_space_handle_t *);
+void agp_unmap_subregion(struct agp_map *, bus_space_handle_t,
+ bus_size_t);
int agp_alloc_dmamem(bus_dma_tag_t, size_t, bus_dmamap_t *,
bus_addr_t *, bus_dma_segment_t *);