xref: /openbsd/lib/libarch/alpha/bwx.c (revision ad0aa884)
1 /* $OpenBSD: bwx.c,v 1.10 2021/09/17 15:19:52 deraadt 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 #include <sys/types.h>
29 #include <sys/mman.h>
30 #include <sys/sysctl.h>
31 #include <machine/bwx.h>
32 #include <machine/cpu.h>
33 #include <machine/sysarch.h>
34 #include <err.h>
35 #include <fcntl.h>
36 #include <paths.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 
40 #include "io.h"
41 
42 #define	round_page(x)	(((x) + page_mask) & ~page_mask)
43 #define	trunc_page(x)	((x) & ~page_mask)
44 static long		page_mask;
45 
46 #define PATH_APERTURE "/dev/xf86"
47 
48 #define mb()	__asm__ volatile("mb"  : : : "memory")
49 #define wmb()	__asm__ volatile("wmb" : : : "memory")
50 
51 static int		mem_fd = -1;	/* file descriptor to /dev/mem */
52 static void	       *bwx_int1_ports = MAP_FAILED; /* mapped int1 io ports */
53 static void	       *bwx_int2_ports = MAP_FAILED; /* mapped int2 io ports */
54 static void	       *bwx_int4_ports = MAP_FAILED; /* mapped int4 io ports */
55 static u_int64_t	bwx_io_base;	/* physical address of ports */
56 static u_int64_t	bwx_mem_base;	/* physical address of bwx mem */
57 
58 static void
bwx_open_mem(void)59 bwx_open_mem(void)
60 {
61 
62 	if (mem_fd != -1)
63 		return;
64 	mem_fd = open(_PATH_MEM, O_RDWR);
65 	if (mem_fd < 0)
66 		mem_fd = open(PATH_APERTURE, O_RDWR);
67 	if (mem_fd < 0)
68 		err(1, "Failed to open both %s and %s", _PATH_MEM,
69 		    PATH_APERTURE);
70 }
71 
72 static void
bwx_close_mem(void)73 bwx_close_mem(void)
74 {
75 
76 	if (mem_fd != -1) {
77 		close(mem_fd);
78 		mem_fd = -1;
79 	}
80 }
81 
82 static void
bwx_init(void)83 bwx_init(void)
84 {
85 	size_t len = sizeof(u_int64_t);
86 	int error;
87 	int mib[3];
88 
89 	page_mask = getpagesize() - 1;
90 
91 	mib[0] = CTL_MACHDEP;
92 	mib[1] = CPU_CHIPSET;
93 	mib[2] = CPU_CHIPSET_PORTS;
94 	if ((error = sysctl(mib, 3, &bwx_io_base, &len, NULL, 0)) < 0)
95 		err(1, "machdep.chipset.ports_base");
96 	mib[2] = CPU_CHIPSET_MEM;
97 	if ((error = sysctl(mib, 3, &bwx_mem_base, &len, 0, 0)) < 0)
98 		err(1, "machdep.chipset.memory");
99 }
100 
101 static int
bwx_ioperm(u_int32_t from,u_int32_t num,int on)102 bwx_ioperm(u_int32_t from, u_int32_t num, int on)
103 {
104 	u_int32_t start, end;
105 
106 	if (bwx_int1_ports == MAP_FAILED)
107 		bwx_init();
108 
109 	if (!on)
110 		return -1;		/* XXX can't unmap yet */
111 
112 	if (bwx_int1_ports != MAP_FAILED)
113 		return 0;
114 
115 	bwx_open_mem();
116 	start = trunc_page(from);
117 	end = round_page(from + num);
118 	if ((bwx_int1_ports = mmap(0, end-start, PROT_READ|PROT_WRITE,
119 	    MAP_SHARED, mem_fd, bwx_io_base + BWX_EV56_INT1 + start)) ==
120 	    MAP_FAILED)
121 		err(1, "mmap int1");
122 	if ((bwx_int2_ports = mmap(0, end-start, PROT_READ|PROT_WRITE,
123 	    MAP_SHARED, mem_fd, bwx_io_base + BWX_EV56_INT2 + start)) ==
124 	    MAP_FAILED)
125 		err(1, "mmap int2");
126 	if ((bwx_int4_ports = mmap(0, end-start, PROT_READ|PROT_WRITE,
127 	    MAP_SHARED, mem_fd, bwx_io_base + BWX_EV56_INT4 + start)) ==
128 	    MAP_FAILED)
129 		err(1, "mmap int4");
130 	bwx_close_mem();
131 	return 0;
132 }
133 
134 static u_int8_t
bwx_inb(u_int32_t port)135 bwx_inb(u_int32_t port)
136 {
137 	mb();
138 	return alpha_ldbu(bwx_int1_ports + port);
139 }
140 
141 static u_int16_t
bwx_inw(u_int32_t port)142 bwx_inw(u_int32_t port)
143 {
144 	mb();
145 	return alpha_ldwu(bwx_int2_ports + port);
146 }
147 
148 static u_int32_t
bwx_inl(u_int32_t port)149 bwx_inl(u_int32_t port)
150 {
151 	mb();
152 	return alpha_ldlu(bwx_int4_ports + port);
153 }
154 
155 static void
bwx_outb(u_int32_t port,u_int8_t val)156 bwx_outb(u_int32_t port, u_int8_t val)
157 {
158 	alpha_stb(bwx_int1_ports + port, val);
159 	mb();
160 	wmb();
161 }
162 
163 static void
bwx_outw(u_int32_t port,u_int16_t val)164 bwx_outw(u_int32_t port, u_int16_t val)
165 {
166 	alpha_stw(bwx_int2_ports + port, val);
167 	mb();
168 	wmb();
169 }
170 
171 static void
bwx_outl(u_int32_t port,u_int32_t val)172 bwx_outl(u_int32_t port, u_int32_t val)
173 {
174 	alpha_stl(bwx_int4_ports + port, val);
175 	mb();
176 	wmb();
177 }
178 
179 struct bwx_mem_handle {
180 	void	*virt1;		/* int1 address in user address-space */
181 	void	*virt2;		/* int2 address in user address-space */
182 	void	*virt4;		/* int4 address in user address-space */
183 };
184 
185 static void *
bwx_map_memory(u_int32_t address,u_int32_t size)186 bwx_map_memory(u_int32_t address, u_int32_t size)
187 {
188 	struct bwx_mem_handle *h;
189 	size_t sz = (size_t)size << 5;
190 
191 	h = malloc(sizeof(struct bwx_mem_handle));
192 	if (h == NULL) return NULL;
193 	bwx_open_mem();
194 	h->virt1 = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED,
195 	    mem_fd, bwx_mem_base + BWX_EV56_INT1 + address);
196 	if (h->virt1 == MAP_FAILED) {
197 		bwx_close_mem();
198 		free(h);
199 		return NULL;
200 	}
201 	h->virt2 = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED,
202 	    mem_fd, bwx_mem_base + BWX_EV56_INT2 + address);
203 	if (h->virt2 == MAP_FAILED) {
204 		munmap(h->virt1, sz);
205 		bwx_close_mem();
206 		free(h);
207 		return NULL;
208 	}
209 	h->virt4 = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_SHARED,
210 	    mem_fd, bwx_mem_base + BWX_EV56_INT4 + address);
211 	if (h->virt4 == MAP_FAILED) {
212 		munmap(h->virt1, sz);
213 		munmap(h->virt2, sz);
214 		bwx_close_mem();
215 		free(h);
216 		return NULL;
217 	}
218 	bwx_close_mem();
219 	return h;
220 }
221 
222 static void
bwx_unmap_memory(void * handle,u_int32_t size)223 bwx_unmap_memory(void *handle, u_int32_t size)
224 {
225 	struct bwx_mem_handle *h = handle;
226 	size_t sz = (size_t)size << 5;
227 
228 	munmap(h->virt1, sz);
229 	munmap(h->virt2, sz);
230 	munmap(h->virt4, sz);
231 	free(h);
232 }
233 
234 static u_int8_t
bwx_readb(void * handle,u_int32_t offset)235 bwx_readb(void *handle, u_int32_t offset)
236 {
237 	struct bwx_mem_handle *h = handle;
238 
239 	return alpha_ldbu(h->virt1 + offset);
240 }
241 
242 static u_int16_t
bwx_readw(void * handle,u_int32_t offset)243 bwx_readw(void *handle, u_int32_t offset)
244 {
245 	struct bwx_mem_handle *h = handle;
246 
247 	return alpha_ldwu(h->virt2 + offset);
248 }
249 
250 static u_int32_t
bwx_readl(void * handle,u_int32_t offset)251 bwx_readl(void *handle, u_int32_t offset)
252 {
253 	struct bwx_mem_handle *h = handle;
254 
255 	return alpha_ldlu(h->virt4 + offset);
256 }
257 
258 static void
bwx_writeb(void * handle,u_int32_t offset,u_int8_t val)259 bwx_writeb(void *handle, u_int32_t offset, u_int8_t val)
260 {
261 	struct bwx_mem_handle *h = handle;
262 
263 	alpha_stb(h->virt1 + offset, val);
264 }
265 
266 static void
bwx_writew(void * handle,u_int32_t offset,u_int16_t val)267 bwx_writew(void *handle, u_int32_t offset, u_int16_t val)
268 {
269 	struct bwx_mem_handle *h = handle;
270 
271 	alpha_stw(h->virt2 + offset, val);
272 }
273 
274 static void
bwx_writel(void * handle,u_int32_t offset,u_int32_t val)275 bwx_writel(void *handle, u_int32_t offset, u_int32_t val)
276 {
277 	struct bwx_mem_handle *h = handle;
278 
279 	alpha_stl(h->virt4 + offset, val);
280 }
281 
282 struct io_ops bwx_io_ops = {
283 	bwx_ioperm,
284 	bwx_inb,
285 	bwx_inw,
286 	bwx_inl,
287 	bwx_outb,
288 	bwx_outw,
289 	bwx_outl,
290 	bwx_map_memory,
291 	bwx_unmap_memory,
292 	bwx_readb,
293 	bwx_readw,
294 	bwx_readl,
295 	bwx_writeb,
296 	bwx_writew,
297 	bwx_writel,
298 };
299