xref: /openbsd-src/sys/dev/pci/pci_map.c (revision 4e1ee0786f11cc571bd0be17d38e46f635c719fc)
1 /*      $OpenBSD: pci_map.c,v 1.32 2019/06/17 11:04:06 kettenis Exp $     */
2 /*	$NetBSD: pci_map.c,v 1.7 2000/05/10 16:58:42 thorpej Exp $	*/
3 
4 /*-
5  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Charles M. Hannum; by William R. Studenmund; by Jason R. Thorpe.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * PCI device mapping.
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 
40 #include <dev/pci/pcireg.h>
41 #include <dev/pci/pcivar.h>
42 
43 #ifndef PCI_IO_START
44 #define PCI_IO_START	0
45 #endif
46 
47 #ifndef PCI_IO_END
48 #define PCI_IO_END	0xffffffff
49 #endif
50 
51 #ifndef PCI_MEM_START
52 #define PCI_MEM_START	0
53 #endif
54 
55 #ifndef PCI_MEM_END
56 #define PCI_MEM_END	0xffffffff
57 #endif
58 
59 
60 int obsd_pci_io_find(pci_chipset_tag_t, pcitag_t, int, pcireg_t,
61     bus_addr_t *, bus_size_t *, int *);
62 int obsd_pci_mem_find(pci_chipset_tag_t, pcitag_t, int, pcireg_t,
63     bus_addr_t *, bus_size_t *, int *);
64 
65 int
66 obsd_pci_io_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
67     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
68 {
69 	pcireg_t address, mask, csr;
70 	int s;
71 
72 	if (reg < PCI_MAPREG_START ||
73 #if 0
74 	    /*
75 	     * Can't do this check; some devices have mapping registers
76 	     * way out in left field.
77 	     */
78 	    reg >= PCI_MAPREG_END ||
79 #endif
80 	    (reg & 3))
81 		panic("pci_io_find: bad request");
82 
83 	/*
84 	 * Section 6.2.5.1, `Address Maps', tells us that:
85 	 *
86 	 * 1) The builtin software should have already mapped the device in a
87 	 * reasonable way.
88 	 *
89 	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
90 	 * n bits of the address to 0.  As recommended, we write all 1s while
91 	 * the device is disabled and see what we get back.
92 	 */
93 	s = splhigh();
94 	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
95 	if (csr & PCI_COMMAND_IO_ENABLE)
96 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
97 		    csr & ~PCI_COMMAND_IO_ENABLE);
98 	address = pci_conf_read(pc, tag, reg);
99 	pci_conf_write(pc, tag, reg, 0xffffffff);
100 	mask = pci_conf_read(pc, tag, reg);
101 	pci_conf_write(pc, tag, reg, address);
102 	if (csr & PCI_COMMAND_IO_ENABLE)
103 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
104 	splx(s);
105 
106 	if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) {
107 #ifdef DEBUG
108 		printf("pci_io_find: expected type i/o, found mem\n");
109 #endif
110 		return (EINVAL);
111 	}
112 
113 	if (PCI_MAPREG_IO_SIZE(mask) == 0) {
114 #ifdef DEBUG
115 		printf("pci_io_find: void region\n");
116 #endif
117 		return (ENOENT);
118 	}
119 
120 	if (basep != 0)
121 		*basep = PCI_MAPREG_IO_ADDR(address);
122 	if (sizep != 0)
123 		*sizep = PCI_MAPREG_IO_SIZE(mask);
124 	if (flagsp != 0)
125 		*flagsp = 0;
126 
127 	return (0);
128 }
129 
130 int
131 obsd_pci_mem_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
132     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
133 {
134 	pcireg_t address, mask, address1 = 0, mask1 = 0xffffffff, csr;
135 	u_int64_t waddress, wmask;
136 	int s, is64bit;
137 
138 	is64bit = (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT);
139 
140 	if (reg < PCI_MAPREG_START ||
141 #if 0
142 	    /*
143 	     * Can't do this check; some devices have mapping registers
144 	     * way out in left field.
145 	     */
146 	    reg >= PCI_MAPREG_END ||
147 #endif
148 	    (reg & 3))
149 		panic("pci_mem_find: bad request");
150 
151 	if (is64bit && (reg + 4) >= PCI_MAPREG_END)
152 		panic("pci_mem_find: bad 64-bit request");
153 
154 	/*
155 	 * Section 6.2.5.1, `Address Maps', tells us that:
156 	 *
157 	 * 1) The builtin software should have already mapped the device in a
158 	 * reasonable way.
159 	 *
160 	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
161 	 * n bits of the address to 0.  As recommended, we write all 1s while
162 	 * the device is disabled and see what we get back.
163 	 */
164 	s = splhigh();
165 	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
166 	if (csr & PCI_COMMAND_MEM_ENABLE)
167 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
168 		    csr & ~PCI_COMMAND_MEM_ENABLE);
169 	address = pci_conf_read(pc, tag, reg);
170 	pci_conf_write(pc, tag, reg, PCI_MAPREG_MEM_ADDR_MASK);
171 	mask = pci_conf_read(pc, tag, reg);
172 	pci_conf_write(pc, tag, reg, address);
173 	if (is64bit) {
174 		address1 = pci_conf_read(pc, tag, reg + 4);
175 		pci_conf_write(pc, tag, reg + 4, 0xffffffff);
176 		mask1 = pci_conf_read(pc, tag, reg + 4);
177 		pci_conf_write(pc, tag, reg + 4, address1);
178 	}
179 	if (csr & PCI_COMMAND_MEM_ENABLE)
180 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
181 	splx(s);
182 
183 	if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
184 #ifdef DEBUG
185 		printf("pci_mem_find: expected type mem, found i/o\n");
186 #endif
187 		return (EINVAL);
188 	}
189 	if (type != -1 &&
190 	    PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) {
191 #ifdef DEBUG
192 		printf("pci_mem_find: expected mem type %08x, found %08x\n",
193 		    PCI_MAPREG_MEM_TYPE(type),
194 		    PCI_MAPREG_MEM_TYPE(address));
195 #endif
196 		return (EINVAL);
197 	}
198 
199 	waddress = (u_int64_t)address1 << 32UL | address;
200 	wmask = (u_int64_t)mask1 << 32UL | mask;
201 
202 	if ((is64bit && PCI_MAPREG_MEM64_SIZE(wmask) == 0) ||
203 	    (!is64bit && PCI_MAPREG_MEM_SIZE(mask) == 0)) {
204 #ifdef DEBUG
205 		printf("pci_mem_find: void region\n");
206 #endif
207 		return (ENOENT);
208 	}
209 
210 	switch (PCI_MAPREG_MEM_TYPE(address)) {
211 	case PCI_MAPREG_MEM_TYPE_32BIT:
212 	case PCI_MAPREG_MEM_TYPE_32BIT_1M:
213 		break;
214 	case PCI_MAPREG_MEM_TYPE_64BIT:
215 		/*
216 		 * Handle the case of a 64-bit memory register on a
217 		 * platform with 32-bit addressing.  Make sure that
218 		 * the address assigned and the device's memory size
219 		 * fit in 32 bits.  We implicitly assume that if
220 		 * bus_addr_t is 64-bit, then so is bus_size_t.
221 		 */
222 		if (sizeof(u_int64_t) > sizeof(bus_addr_t) &&
223 		    (address1 != 0 || mask1 != 0xffffffff)) {
224 #ifdef DEBUG
225 			printf("pci_mem_find: 64-bit memory map which is "
226 			    "inaccessible on a 32-bit platform\n");
227 #endif
228 			return (EINVAL);
229 		}
230 		break;
231 	default:
232 #ifdef DEBUG
233 		printf("pci_mem_find: reserved mapping register type\n");
234 #endif
235 		return (EINVAL);
236 	}
237 
238 	if (sizeof(u_int64_t) > sizeof(bus_addr_t)) {
239 		if (basep != 0)
240 			*basep = PCI_MAPREG_MEM_ADDR(address);
241 		if (sizep != 0)
242 			*sizep = PCI_MAPREG_MEM_SIZE(mask);
243 	} else {
244 		if (basep != 0)
245 			*basep = PCI_MAPREG_MEM64_ADDR(waddress);
246 		if (sizep != 0)
247 			*sizep = PCI_MAPREG_MEM64_SIZE(wmask);
248 	}
249 	if (flagsp != 0)
250 		*flagsp =
251 		    PCI_MAPREG_MEM_PREFETCHABLE(address) ?
252 		      BUS_SPACE_MAP_PREFETCHABLE : 0;
253 
254 	return (0);
255 }
256 
257 int
258 pci_io_find(pci_chipset_tag_t pc, pcitag_t pcitag, int reg,
259     bus_addr_t *iobasep, bus_size_t *iosizep)
260 {
261 	return (obsd_pci_io_find(pc, pcitag, reg, 0, iobasep, iosizep, 0));
262 }
263 
264 int
265 pci_mem_find(pci_chipset_tag_t pc, pcitag_t pcitag, int reg,
266     bus_addr_t *membasep, bus_size_t *memsizep, int *cacheablep)
267 {
268 	return (obsd_pci_mem_find(pc, pcitag, reg, -1, membasep, memsizep,
269 				  cacheablep));
270 }
271 
272 pcireg_t
273 pci_mapreg_type(pci_chipset_tag_t pc, pcitag_t tag, int reg)
274 {
275 	return (_PCI_MAPREG_TYPEBITS(pci_conf_read(pc, tag, reg)));
276 }
277 
278 int
279 pci_mapreg_probe(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *typep)
280 {
281 	pcireg_t address, mask, csr;
282 	int s;
283 
284 	s = splhigh();
285 	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
286 	if (csr & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
287 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr &
288 		    ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE));
289 	address = pci_conf_read(pc, tag, reg);
290 	pci_conf_write(pc, tag, reg, 0xffffffff);
291 	mask = pci_conf_read(pc, tag, reg);
292 	pci_conf_write(pc, tag, reg, address);
293 	if (csr & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
294 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
295 	splx(s);
296 
297 	if (mask == 0) /* unimplemented mapping register */
298 		return (0);
299 
300 	if (typep)
301 		*typep = _PCI_MAPREG_TYPEBITS(address);
302 	return (1);
303 }
304 
305 int
306 pci_mapreg_info(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
307     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
308 {
309 
310 	if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO)
311 		return (obsd_pci_io_find(pc, tag, reg, type, basep, sizep,
312 		    flagsp));
313 	else
314 		return (obsd_pci_mem_find(pc, tag, reg, type, basep, sizep,
315 		    flagsp));
316 }
317 
318 int
319 pci_mapreg_assign(struct pci_attach_args *pa, int reg, pcireg_t type,
320     bus_addr_t *basep, bus_size_t *sizep)
321 {
322 	bus_addr_t base;
323 	bus_size_t size;
324 	pcireg_t csr;
325 	int rv;
326 
327 	if ((rv = pci_mapreg_info(pa->pa_pc, pa->pa_tag, reg, type,
328 	    &base, &size, NULL)) != 0)
329 		return (rv);
330 #if !defined(__sparc64__)
331 	if (base == 0) {
332 		struct extent *ex;
333 		bus_addr_t start, end;
334 
335 		if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
336 			ex = pa->pa_ioex;
337 			if (ex != NULL) {
338 				start = max(PCI_IO_START, ex->ex_start);
339 				end = min(PCI_IO_END, ex->ex_end);
340 			}
341 		} else {
342 			ex = pa->pa_memex;
343 			if (ex != NULL) {
344 				start = max(PCI_MEM_START, ex->ex_start);
345 				end = min(PCI_MEM_END, ex->ex_end);
346 			}
347 		}
348 
349 		if (ex == NULL || extent_alloc_subregion(ex, start, end,
350 		    size, size, 0, 0, 0, &base))
351 			return (EINVAL); /* disabled because of invalid BAR */
352 
353 		pci_conf_write(pa->pa_pc, pa->pa_tag, reg, base);
354 		if (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT)
355 			pci_conf_write(pa->pa_pc, pa->pa_tag, reg + 4,
356 			    (u_int64_t)base >> 32);
357 	}
358 #endif
359 
360 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
361 	if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO)
362 		csr |= PCI_COMMAND_IO_ENABLE;
363 	else
364 		csr |= PCI_COMMAND_MEM_ENABLE;
365 	/* XXX Should this only be done for devices that do DMA?  */
366 	csr |= PCI_COMMAND_MASTER_ENABLE;
367 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
368 
369 	if (basep != NULL)
370 		*basep = base;
371 	if (sizep != NULL)
372 		*sizep = size;
373 
374 	return (0);
375 }
376 
377 int
378 pci_mapreg_map(struct pci_attach_args *pa, int reg, pcireg_t type, int flags,
379     bus_space_tag_t *tagp, bus_space_handle_t *handlep, bus_addr_t *basep,
380     bus_size_t *sizep, bus_size_t maxsize)
381 {
382 	bus_space_tag_t tag;
383 	bus_space_handle_t handle;
384 	bus_addr_t base;
385 	bus_size_t size;
386 	int rv;
387 
388 	if ((rv = pci_mapreg_assign(pa, reg, type, &base, &size)) != 0)
389 		return (rv);
390 
391 	if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
392 		if ((pa->pa_flags & PCI_FLAGS_IO_ENABLED) == 0)
393 			return (EINVAL);
394 		tag = pa->pa_iot;
395 	} else {
396 		if ((pa->pa_flags & PCI_FLAGS_MEM_ENABLED) == 0)
397 			return (EINVAL);
398 		tag = pa->pa_memt;
399 	}
400 
401 	/* The caller can request limitation of the mapping's size. */
402 	if (maxsize != 0 && size > maxsize) {
403 #ifdef DEBUG
404 		printf("pci_mapreg_map: limited PCI mapping from %lx to %lx\n",
405 		    (u_long)size, (u_long)maxsize);
406 #endif
407 		size = maxsize;
408 	}
409 
410 	if (bus_space_map(tag, base, size, flags, &handle))
411 		return (1);
412 
413 	if (tagp != NULL)
414 		*tagp = tag;
415 	if (handlep != NULL)
416 		*handlep = handle;
417 	if (basep != NULL)
418 		*basep = base;
419 	if (sizep != NULL)
420 		*sizep = size;
421 
422 	return (0);
423 }
424