summaryrefslogtreecommitdiff
path: root/sys/arch/i386/pci
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2014-09-20 16:15:17 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2014-09-20 16:15:17 +0000
commitffe2e156cb1636f64046b180aab6bf8e6a812d35 (patch)
tree5b59bbc738acbc6e2d59d857ed0955cbde44b90a /sys/arch/i386/pci
parentaf6c0aa460d486cee6637557789a4cacc75fe4d6 (diff)
On i386, agp_map_subregion might sleep, which is not allowed in some of
the inteldrm code. Fix this by adding new interfaces that can map a single page without sleeping and use that in the execbuffer fast path that needs this "atomic" behaviour. Should fix the panic I've seen under memory pressure on i386.
Diffstat (limited to 'sys/arch/i386/pci')
-rw-r--r--sys/arch/i386/pci/agp_machdep.c87
1 files changed, 48 insertions, 39 deletions
diff --git a/sys/arch/i386/pci/agp_machdep.c b/sys/arch/i386/pci/agp_machdep.c
index 5af66c3131a..c4e4ec37988 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.18 2014/07/12 18:44:42 tedu Exp $ */
+/* $OpenBSD: agp_machdep.c,v 1.19 2014/09/20 16:15:16 kettenis Exp $ */
/*
* Copyright (c) 2008 - 2009 Owain G. Ainsworth <oga@openbsd.org>
@@ -74,38 +74,25 @@ struct agp_map {
bus_addr_t addr;
bus_size_t size;
int flags;
+ vaddr_t va;
};
-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");
- }
+ struct agp_map *map;
+ int error;
+
+ KASSERT(tag == I386_BUS_SPACE_MEM);
+
/*
* 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,
+ error = extent_alloc_region(iomem_ex, address, size,
EX_NOWAIT | EX_MALLOCOK);
if (error)
return (error);
@@ -119,6 +106,12 @@ agp_init_map(bus_space_tag_t tag, bus_addr_t address, bus_size_t size,
map->size = size;
map->flags = flags;
+ map->va = (vaddr_t)km_alloc(PAGE_SIZE, &kv_any, &kp_none, &kd_waitok);
+ if (map->va == 0) {
+ free(map, M_AGP, sizeof(*map));
+ return (ENOMEM);
+ }
+
*mapp = map;
return (0);
}
@@ -126,25 +119,11 @@ agp_init_map(bus_space_tag_t tag, bus_addr_t address, bus_size_t size,
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,
+ if (extent_free(iomem_ex, map->addr, map->size,
EX_NOWAIT | EX_MALLOCOK ))
- printf("agp_destroy_map: can't free region\n");
- free(map, M_AGP, 0);
+ printf("%s: can't free region\n",__func__);
+ km_free((void *)map->va, PAGE_SIZE, &kv_any, &kp_none);
+ free(map, M_AGP, sizeof(*map));
}
@@ -162,3 +141,33 @@ agp_unmap_subregion(struct agp_map *map, bus_space_handle_t bsh,
{
return (_bus_space_unmap(map->bst, bsh, size, NULL));
}
+
+void
+agp_map_atomic(struct agp_map *map, bus_size_t offset,
+ bus_space_handle_t *bshp)
+{
+ int pmap_flags = PMAP_NOCACHE;
+ paddr_t pa;
+
+ KASSERT((offset & PGOFSET) == 0);
+
+ if (map->flags & BUS_SPACE_MAP_CACHEABLE)
+ pmap_flags = 0;
+ else if (map->flags & BUS_SPACE_MAP_PREFETCHABLE)
+ pmap_flags = PMAP_WC;
+
+ pa = bus_space_mmap(map->bst, map->addr, offset, 0, 0);
+ pmap_kenter_pa(map->va, pa | pmap_flags, VM_PROT_READ | VM_PROT_WRITE);
+ pmap_update(pmap_kernel());
+
+ *bshp = (bus_space_handle_t)map->va;
+}
+
+void
+agp_unmap_atomic(struct agp_map *map, bus_space_handle_t bsh)
+{
+ KASSERT(bsh == (bus_space_handle_t)map->va);
+
+ pmap_kremove(map->va, PAGE_SIZE);
+ pmap_update(pmap_kernel());
+}