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)
44static 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
51static int		mem_fd = -1;	/* file descriptor to /dev/mem */
52static void	       *bwx_int1_ports = MAP_FAILED; /* mapped int1 io ports */
53static void	       *bwx_int2_ports = MAP_FAILED; /* mapped int2 io ports */
54static void	       *bwx_int4_ports = MAP_FAILED; /* mapped int4 io ports */
55static u_int64_t	bwx_io_base;	/* physical address of ports */
56static u_int64_t	bwx_mem_base;	/* physical address of bwx mem */
57
58static void
59bwx_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
72static void
73bwx_close_mem(void)
74{
75
76	if (mem_fd != -1) {
77		close(mem_fd);
78		mem_fd = -1;
79	}
80}
81
82static void
83bwx_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
101static int
102bwx_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
134static u_int8_t
135bwx_inb(u_int32_t port)
136{
137	mb();
138	return alpha_ldbu(bwx_int1_ports + port);
139}
140
141static u_int16_t
142bwx_inw(u_int32_t port)
143{
144	mb();
145	return alpha_ldwu(bwx_int2_ports + port);
146}
147
148static u_int32_t
149bwx_inl(u_int32_t port)
150{
151	mb();
152	return alpha_ldlu(bwx_int4_ports + port);
153}
154
155static void
156bwx_outb(u_int32_t port, u_int8_t val)
157{
158	alpha_stb(bwx_int1_ports + port, val);
159	mb();
160	wmb();
161}
162
163static void
164bwx_outw(u_int32_t port, u_int16_t val)
165{
166	alpha_stw(bwx_int2_ports + port, val);
167	mb();
168	wmb();
169}
170
171static void
172bwx_outl(u_int32_t port, u_int32_t val)
173{
174	alpha_stl(bwx_int4_ports + port, val);
175	mb();
176	wmb();
177}
178
179struct 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
185static void *
186bwx_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
222static void
223bwx_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
234static u_int8_t
235bwx_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
242static u_int16_t
243bwx_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
250static u_int32_t
251bwx_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
258static void
259bwx_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
266static void
267bwx_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
274static void
275bwx_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
282struct 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