summaryrefslogtreecommitdiff
path: root/sys
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
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')
-rw-r--r--sys/arch/amd64/pci/agp_machdep.c22
-rw-r--r--sys/arch/i386/pci/agp_machdep.c87
-rw-r--r--sys/dev/pci/agpvar.h4
-rw-r--r--sys/dev/pci/drm/i915/i915_gem_execbuffer.c12
4 files changed, 70 insertions, 55 deletions
diff --git a/sys/arch/amd64/pci/agp_machdep.c b/sys/arch/amd64/pci/agp_machdep.c
index 669b56d15f8..a09549469a4 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.12 2014/07/12 18:44:41 tedu Exp $ */
+/* $OpenBSD: agp_machdep.c,v 1.13 2014/09/20 16:15:16 kettenis Exp $ */
/*
* Copyright (c) 2008 - 2009 Owain G. Ainsworth <oga@openbsd.org>
@@ -90,7 +90,7 @@ agp_init_map(bus_space_tag_t tag, bus_addr_t address, bus_size_t size,
map->size = size;
if ((err = bus_space_map(tag, address, size, flags, &map->bsh)) != 0) {
- free(map, M_AGP, 0);
+ free(map, M_AGP, sizeof(*map));
return (err);
}
*mapp = map;
@@ -101,7 +101,7 @@ void
agp_destroy_map(struct agp_map *map)
{
bus_space_unmap(map->bst, map->bsh, map->size);
- free(map, M_AGP, 0);
+ free(map, M_AGP, sizeof(*map));
}
@@ -109,10 +109,7 @@ 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
@@ -121,3 +118,16 @@ agp_unmap_subregion(struct agp_map *map, bus_space_handle_t bsh,
{
/* subregion doesn't need unmapping, do nothing */
}
+
+void
+agp_map_atomic(struct agp_map *map, bus_size_t offset,
+ bus_space_handle_t *bshp)
+{
+ agp_map_subregion(map, offset, PAGE_SIZE, bshp);
+}
+
+void
+agp_unmap_atomic(struct agp_map *map, bus_space_handle_t bsh)
+{
+ /* subregion doesn't need unmapping, do nothing */
+}
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());
+}
diff --git a/sys/dev/pci/agpvar.h b/sys/dev/pci/agpvar.h
index 1ac56b5c38c..3101875327a 100644
--- a/sys/dev/pci/agpvar.h
+++ b/sys/dev/pci/agpvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: agpvar.h,v 1.30 2014/03/26 14:41:41 mpi Exp $ */
+/* $OpenBSD: agpvar.h,v 1.31 2014/09/20 16:15:16 kettenis Exp $ */
/* $NetBSD: agpvar.h,v 1.4 2001/10/01 21:54:48 fvdl Exp $ */
/*-
@@ -177,6 +177,8 @@ 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);
+void agp_map_atomic(struct agp_map *, bus_size_t, bus_space_handle_t *);
+void agp_unmap_atomic(struct agp_map *, bus_space_handle_t);
int agp_alloc_dmamem(bus_dma_tag_t, size_t, bus_dmamap_t *,
bus_addr_t *, bus_dma_segment_t *);
diff --git a/sys/dev/pci/drm/i915/i915_gem_execbuffer.c b/sys/dev/pci/drm/i915/i915_gem_execbuffer.c
index a3ef3dc6a0f..279596dca0a 100644
--- a/sys/dev/pci/drm/i915/i915_gem_execbuffer.c
+++ b/sys/dev/pci/drm/i915/i915_gem_execbuffer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: i915_gem_execbuffer.c,v 1.29 2014/07/12 18:48:52 tedu Exp $ */
+/* $OpenBSD: i915_gem_execbuffer.c,v 1.30 2014/09/20 16:15:16 kettenis Exp $ */
/*
* Copyright (c) 2008-2009 Owain G. Ainsworth <oga@openbsd.org>
*
@@ -233,16 +233,10 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
/* Map the page containing the relocation we're going to perform. */
reloc->offset += obj->gtt_offset;
- if ((ret = agp_map_subregion(dev_priv->agph,
- trunc_page(reloc->offset), PAGE_SIZE, &bsh)) != 0) {
- DRM_ERROR("map failed...\n");
- return -ret;
- }
-
+ agp_map_atomic(dev_priv->agph, trunc_page(reloc->offset), &bsh);
bus_space_write_4(dev_priv->bst, bsh, reloc->offset & PAGE_MASK,
reloc->delta);
-
- agp_unmap_subregion(dev_priv->agph, bsh, PAGE_SIZE);
+ agp_unmap_atomic(dev_priv->agph, bsh);
}
/* and update the user's relocation entry */