xref: /openbsd-src/lib/libarch/alpha/bwx.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /* $OpenBSD: bwx.c,v 1.6 2012/12/20 21:05:07 naddy Exp $ */
2 /*-
3  * Copyright (c) 1998 Doug Rabson
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #define vm_page_size (sysconf(_SC_PAGESIZE)) /* XXX  */
29 #include <sys/param.h>
30 #include <sys/mman.h>
31 #include <sys/fcntl.h>
32 #include <sys/sysctl.h>
33 #include <err.h>
34 #include <paths.h>
35 #include <machine/bwx.h>
36 #include <machine/cpu.h>
37 #include <machine/sysarch.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 
41 #include "io.h"
42 
43 #define PATH_APERTURE "/dev/xf86"
44 
45 #define mb()	__asm__ __volatile__("mb"  : : : "memory")
46 #define wmb()	__asm__ __volatile__("wmb" : : : "memory")
47 
48 static int		mem_fd = -1;	/* file descriptor to /dev/mem */
49 static void	       *bwx_int1_ports = MAP_FAILED; /* mapped int1 io ports */
50 static void	       *bwx_int2_ports = MAP_FAILED; /* mapped int2 io ports */
51 static void	       *bwx_int4_ports = MAP_FAILED; /* mapped int4 io ports */
52 static u_int64_t	bwx_io_base;	/* physical address of ports */
53 static u_int64_t	bwx_mem_base;	/* physical address of bwx mem */
54 
55 static void
56 bwx_open_mem(void)
57 {
58 
59 	if (mem_fd != -1)
60 		return;
61 	mem_fd = open(_PATH_MEM, O_RDWR);
62 	if (mem_fd < 0)
63 		mem_fd = open(PATH_APERTURE, O_RDWR);
64 	if (mem_fd < 0)
65 		err(1, "Failed to open both %s and %s", _PATH_MEM,
66 		    PATH_APERTURE);
67 }
68 
69 static void
70 bwx_close_mem(void)
71 {
72 
73 	if (mem_fd != -1) {
74 		close(mem_fd);
75 		mem_fd = -1;
76 	}
77 }
78 
79 static void
80 bwx_init(void)
81 {
82 	size_t len = sizeof(u_int64_t);
83 	int error;
84 	int mib[3];
85 
86 	mib[0] = CTL_MACHDEP;
87 	mib[1] = CPU_CHIPSET;
88 	mib[2] = CPU_CHIPSET_PORTS;
89 	if ((error = sysctl(mib, 3, &bwx_io_base, &len, NULL, 0)) < 0)
90 		err(1, "machdep.chipset.ports_base");
91 	mib[2] = CPU_CHIPSET_MEM;
92 	if ((error = sysctl(mib, 3, &bwx_mem_base, &len, 0, 0)) < 0)
93 		err(1, "machdep.chipset.memory");
94 }
95 
96 static int
97 bwx_ioperm(u_int32_t from, u_int32_t num, int on)
98 {
99 	u_int32_t start, end;
100 
101 	if (bwx_int1_ports == MAP_FAILED)
102 		bwx_init();
103 
104 	if (!on)
105 		return -1;		/* XXX can't unmap yet */
106 
107 	if (bwx_int1_ports != MAP_FAILED)
108 		return 0;
109 
110 	bwx_open_mem();
111 	start = trunc_page(from);
112 	end = round_page(from + num);
113 	if ((bwx_int1_ports = mmap(0, end-start, PROT_READ|PROT_WRITE,
114 	    MAP_SHARED, mem_fd, bwx_io_base + BWX_EV56_INT1 + start)) ==
115 	    MAP_FAILED)
116 		err(1, "mmap int1");
117 	if ((bwx_int2_ports = mmap(0, end-start, PROT_READ|PROT_WRITE,
118 	    MAP_SHARED, mem_fd, bwx_io_base + BWX_EV56_INT2 + start)) ==
119 	    MAP_FAILED)
120 		err(1, "mmap int2");
121 	if ((bwx_int4_ports = mmap(0, end-start, PROT_READ|PROT_WRITE,
122 	    MAP_SHARED, mem_fd, bwx_io_base + BWX_EV56_INT4 + start)) ==
123 	    MAP_FAILED)
124 		err(1, "mmap int4");
125 	bwx_close_mem();
126 	return 0;
127 }
128 
129 static u_int8_t
130 bwx_inb(u_int32_t port)
131 {
132 	mb();
133 	return alpha_ldbu(bwx_int1_ports + port);
134 }
135 
136 static u_int16_t
137 bwx_inw(u_int32_t port)
138 {
139 	mb();
140 	return alpha_ldwu(bwx_int2_ports + port);
141 }
142 
143 static u_int32_t
144 bwx_inl(u_int32_t port)
145 {
146 	mb();
147 	return alpha_ldlu(bwx_int4_ports + port);
148 }
149 
150 static void
151 bwx_outb(u_int32_t port, u_int8_t val)
152 {
153 	alpha_stb(bwx_int1_ports + port, val);
154 	mb();
155 	wmb();
156 }
157 
158 static void
159 bwx_outw(u_int32_t port, u_int16_t val)
160 {
161 	alpha_stw(bwx_int2_ports + port, val);
162 	mb();
163 	wmb();
164 }
165 
166 static void
167 bwx_outl(u_int32_t port, u_int32_t val)
168 {
169 	alpha_stl(bwx_int4_ports + port, val);
170 	mb();
171 	wmb();
172 }
173 
174 struct bwx_mem_handle {
175 	void	*virt1;		/* int1 address in user address-space */
176 	void	*virt2;		/* int2 address in user address-space */
177 	void	*virt4;		/* int4 address in user address-space */
178 };
179 
180 static void *
181 bwx_map_memory(u_int32_t address, u_int32_t size)
182 {
183 	struct bwx_mem_handle *h;
184 	size_t sz = (size_t)size << 5;
185 
186 	h = malloc(sizeof(struct bwx_mem_handle));
187 	if (h == NULL) return NULL;
188 	bwx_open_mem();
189 	h->virt1 = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED,
190 	    mem_fd, bwx_mem_base + BWX_EV56_INT1 + address);
191 	if (h->virt1 == MAP_FAILED) {
192 		bwx_close_mem();
193 		free(h);
194 		return NULL;
195 	}
196 	h->virt2 = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED,
197 	    mem_fd, bwx_mem_base + BWX_EV56_INT2 + address);
198 	if (h->virt2 == MAP_FAILED) {
199 		munmap(h->virt1, sz);
200 		bwx_close_mem();
201 		free(h);
202 		return NULL;
203 	}
204 	h->virt4 = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED,
205 	    mem_fd, bwx_mem_base + BWX_EV56_INT4 + address);
206 	if (h->virt4 == MAP_FAILED) {
207 		munmap(h->virt1, sz);
208 		munmap(h->virt2, sz);
209 		bwx_close_mem();
210 		free(h);
211 		return NULL;
212 	}
213 	bwx_close_mem();
214 	return h;
215 }
216 
217 static void
218 bwx_unmap_memory(void *handle, u_int32_t size)
219 {
220 	struct bwx_mem_handle *h = handle;
221 	size_t sz = (size_t)size << 5;
222 
223 	munmap(h->virt1, sz);
224 	munmap(h->virt2, sz);
225 	munmap(h->virt4, sz);
226 	free(h);
227 }
228 
229 static u_int8_t
230 bwx_readb(void *handle, u_int32_t offset)
231 {
232 	struct bwx_mem_handle *h = handle;
233 
234 	return alpha_ldbu(h->virt1 + offset);
235 }
236 
237 static u_int16_t
238 bwx_readw(void *handle, u_int32_t offset)
239 {
240 	struct bwx_mem_handle *h = handle;
241 
242 	return alpha_ldwu(h->virt2 + offset);
243 }
244 
245 static u_int32_t
246 bwx_readl(void *handle, u_int32_t offset)
247 {
248 	struct bwx_mem_handle *h = handle;
249 
250 	return alpha_ldlu(h->virt4 + offset);
251 }
252 
253 static void
254 bwx_writeb(void *handle, u_int32_t offset, u_int8_t val)
255 {
256 	struct bwx_mem_handle *h = handle;
257 
258 	alpha_stb(h->virt1 + offset, val);
259 }
260 
261 static void
262 bwx_writew(void *handle, u_int32_t offset, u_int16_t val)
263 {
264 	struct bwx_mem_handle *h = handle;
265 
266 	alpha_stw(h->virt2 + offset, val);
267 }
268 
269 static void
270 bwx_writel(void *handle, u_int32_t offset, u_int32_t val)
271 {
272 	struct bwx_mem_handle *h = handle;
273 
274 	alpha_stl(h->virt4 + offset, val);
275 }
276 
277 struct io_ops bwx_io_ops = {
278 	bwx_ioperm,
279 	bwx_inb,
280 	bwx_inw,
281 	bwx_inl,
282 	bwx_outb,
283 	bwx_outw,
284 	bwx_outl,
285 	bwx_map_memory,
286 	bwx_unmap_memory,
287 	bwx_readb,
288 	bwx_readw,
289 	bwx_readl,
290 	bwx_writeb,
291 	bwx_writew,
292 	bwx_writel,
293 };
294