xref: /openbsd/sys/arch/i386/pci/agp_machdep.c (revision cecf84d4)
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