1 /* $OpenBSD: agp_machdep.c,v 1.20 2014/11/16 12:30:57 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2008 - 2009 Owain G. Ainsworth <oga@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 /* 19 * Copyright (c) 2002 Michael Shalayeff 20 * All rights reserved. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 1. Redistributions of source code must retain the above copyright 26 * notice, this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright 28 * notice, this list of conditions and the following disclaimer in the 29 * documentation and/or other materials provided with the distribution. 30 * 31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 32 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 34 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 35 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 37 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 41 * THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/malloc.h> 47 #include <sys/rwlock.h> 48 49 #include <dev/pci/pcivar.h> 50 #include <dev/pci/pcireg.h> 51 #include <dev/pci/pcidevs.h> 52 #include <dev/pci/agpvar.h> 53 54 #include <uvm/uvm_extern.h> 55 56 #include <machine/cpufunc.h> 57 #include <machine/bus.h> 58 #include <machine/pmap.h> 59 60 void 61 agp_flush_cache(void) 62 { 63 wbinvd(); 64 } 65 66 void 67 agp_flush_cache_range(vaddr_t va, vsize_t sz) 68 { 69 pmap_flush_cache(va, sz); 70 } 71 72 struct agp_map { 73 bus_space_tag_t bst; 74 bus_addr_t addr; 75 bus_size_t size; 76 int flags; 77 vaddr_t va; 78 }; 79 80 extern struct extent *iomem_ex; 81 82 int 83 agp_init_map(bus_space_tag_t tag, bus_addr_t address, bus_size_t size, 84 int flags, struct agp_map **mapp) 85 { 86 struct agp_map *map; 87 int error; 88 89 KASSERT(tag == I386_BUS_SPACE_MEM); 90 91 /* 92 * We grab the extent out of the bus region ourselves 93 * so we don't need to do these allocations every time. 94 */ 95 error = extent_alloc_region(iomem_ex, address, size, 96 EX_NOWAIT | EX_MALLOCOK); 97 if (error) 98 return (error); 99 100 map = malloc(sizeof(*map), M_AGP, M_WAITOK | M_CANFAIL); 101 if (map == NULL) 102 return (ENOMEM); 103 104 map->bst = tag; 105 map->addr = address; 106 map->size = size; 107 map->flags = flags; 108 109 map->va = (vaddr_t)km_alloc(PAGE_SIZE, &kv_any, &kp_none, &kd_waitok); 110 if (map->va == 0) { 111 free(map, M_AGP, sizeof(*map)); 112 return (ENOMEM); 113 } 114 115 *mapp = map; 116 return (0); 117 } 118 119 void 120 agp_destroy_map(struct agp_map *map) 121 { 122 if (extent_free(iomem_ex, map->addr, map->size, 123 EX_NOWAIT | EX_MALLOCOK )) 124 printf("%s: can't free region\n",__func__); 125 km_free((void *)map->va, PAGE_SIZE, &kv_any, &kp_none); 126 free(map, M_AGP, sizeof(*map)); 127 } 128 129 130 int 131 agp_map_subregion(struct agp_map *map, bus_size_t offset, bus_size_t size, 132 bus_space_handle_t *bshp) 133 { 134 return (_bus_space_map(map->bst, map->addr + offset, size, 135 map->flags, bshp)); 136 } 137 138 void 139 agp_unmap_subregion(struct agp_map *map, bus_space_handle_t bsh, 140 bus_size_t size) 141 { 142 return (_bus_space_unmap(map->bst, bsh, size, NULL)); 143 } 144 145 void 146 agp_map_atomic(struct agp_map *map, bus_size_t offset, 147 bus_space_handle_t *bshp) 148 { 149 int pmap_flags = PMAP_NOCACHE; 150 paddr_t pa; 151 152 KASSERT((offset & PGOFSET) == 0); 153 154 if (map->flags & BUS_SPACE_MAP_CACHEABLE) 155 pmap_flags = 0; 156 else if (map->flags & BUS_SPACE_MAP_PREFETCHABLE) 157 pmap_flags = PMAP_WC; 158 159 pa = bus_space_mmap(map->bst, map->addr, offset, 0, 0); 160 pmap_kenter_pa(map->va, pa | pmap_flags, PROT_READ | PROT_WRITE); 161 pmap_update(pmap_kernel()); 162 163 *bshp = (bus_space_handle_t)map->va; 164 } 165 166 void 167 agp_unmap_atomic(struct agp_map *map, bus_space_handle_t bsh) 168 { 169 KASSERT(bsh == (bus_space_handle_t)map->va); 170 171 pmap_kremove(map->va, PAGE_SIZE); 172 pmap_update(pmap_kernel()); 173 } 174