xref: /openbsd-src/sys/dev/pci/pci_map.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*      $OpenBSD: pci_map.c,v 1.30 2013/02/09 20:43:33 miod 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 #include <sys/device.h>
40 
41 #include <dev/pci/pcireg.h>
42 #include <dev/pci/pcivar.h>
43 
44 #ifndef PCI_IO_START
45 #define PCI_IO_START	0
46 #endif
47 
48 #ifndef PCI_IO_END
49 #define PCI_IO_END	0xffffffff
50 #endif
51 
52 #ifndef PCI_MEM_START
53 #define PCI_MEM_START	0
54 #endif
55 
56 #ifndef PCI_MEM_END
57 #define PCI_MEM_END	0xffffffff
58 #endif
59 
60 
61 int obsd_pci_io_find(pci_chipset_tag_t, pcitag_t, int, pcireg_t,
62     bus_addr_t *, bus_size_t *, int *);
63 int obsd_pci_mem_find(pci_chipset_tag_t, pcitag_t, int, pcireg_t,
64     bus_addr_t *, bus_size_t *, int *);
65 
66 int
67 obsd_pci_io_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
68     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
69 {
70 	pcireg_t address, mask, csr;
71 	int s;
72 
73 	if (reg < PCI_MAPREG_START ||
74 #if 0
75 	    /*
76 	     * Can't do this check; some devices have mapping registers
77 	     * way out in left field.
78 	     */
79 	    reg >= PCI_MAPREG_END ||
80 #endif
81 	    (reg & 3))
82 		panic("pci_io_find: bad request");
83 
84 	/*
85 	 * Section 6.2.5.1, `Address Maps', tells us that:
86 	 *
87 	 * 1) The builtin software should have already mapped the device in a
88 	 * reasonable way.
89 	 *
90 	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
91 	 * n bits of the address to 0.  As recommended, we write all 1s while
92 	 * the device is disabled and see what we get back.
93 	 */
94 	s = splhigh();
95 	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
96 	if (csr & PCI_COMMAND_IO_ENABLE)
97 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
98 		    csr & ~PCI_COMMAND_IO_ENABLE);
99 	address = pci_conf_read(pc, tag, reg);
100 	pci_conf_write(pc, tag, reg, 0xffffffff);
101 	mask = pci_conf_read(pc, tag, reg);
102 	pci_conf_write(pc, tag, reg, address);
103 	if (csr & PCI_COMMAND_IO_ENABLE)
104 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
105 	splx(s);
106 
107 	if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) {
108 #ifdef DEBUG
109 		printf("pci_io_find: expected type i/o, found mem\n");
110 #endif
111 		return (EINVAL);
112 	}
113 
114 	if (PCI_MAPREG_IO_SIZE(mask) == 0) {
115 #ifdef DEBUG
116 		printf("pci_io_find: void region\n");
117 #endif
118 		return (ENOENT);
119 	}
120 
121 	if (basep != 0)
122 		*basep = PCI_MAPREG_IO_ADDR(address);
123 	if (sizep != 0)
124 		*sizep = PCI_MAPREG_IO_SIZE(mask);
125 	if (flagsp != 0)
126 		*flagsp = 0;
127 
128 	return (0);
129 }
130 
131 int
132 obsd_pci_mem_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
133     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
134 {
135 	pcireg_t address, mask, address1 = 0, mask1 = 0xffffffff, csr;
136 	u_int64_t waddress, wmask;
137 	int s, is64bit;
138 
139 	is64bit = (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT);
140 
141 	if (reg < PCI_MAPREG_START ||
142 #if 0
143 	    /*
144 	     * Can't do this check; some devices have mapping registers
145 	     * way out in left field.
146 	     */
147 	    reg >= PCI_MAPREG_END ||
148 #endif
149 	    (reg & 3))
150 		panic("pci_mem_find: bad request");
151 
152 	if (is64bit && (reg + 4) >= PCI_MAPREG_END)
153 		panic("pci_mem_find: bad 64-bit request");
154 
155 	/*
156 	 * Section 6.2.5.1, `Address Maps', tells us that:
157 	 *
158 	 * 1) The builtin software should have already mapped the device in a
159 	 * reasonable way.
160 	 *
161 	 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
162 	 * n bits of the address to 0.  As recommended, we write all 1s while
163 	 * the device is disabled and see what we get back.
164 	 */
165 	s = splhigh();
166 	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
167 	if (csr & PCI_COMMAND_MEM_ENABLE)
168 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
169 		    csr & ~PCI_COMMAND_MEM_ENABLE);
170 	address = pci_conf_read(pc, tag, reg);
171 	pci_conf_write(pc, tag, reg, PCI_MAPREG_MEM_ADDR_MASK);
172 	mask = pci_conf_read(pc, tag, reg);
173 	pci_conf_write(pc, tag, reg, address);
174 	if (is64bit) {
175 		address1 = pci_conf_read(pc, tag, reg + 4);
176 		pci_conf_write(pc, tag, reg + 4, 0xffffffff);
177 		mask1 = pci_conf_read(pc, tag, reg + 4);
178 		pci_conf_write(pc, tag, reg + 4, address1);
179 	}
180 	if (csr & PCI_COMMAND_MEM_ENABLE)
181 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
182 	splx(s);
183 
184 	if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
185 #ifdef DEBUG
186 		printf("pci_mem_find: expected type mem, found i/o\n");
187 #endif
188 		return (EINVAL);
189 	}
190 	if (type != -1 &&
191 	    PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) {
192 #ifdef DEBUG
193 		printf("pci_mem_find: expected mem type %08x, found %08x\n",
194 		    PCI_MAPREG_MEM_TYPE(type),
195 		    PCI_MAPREG_MEM_TYPE(address));
196 #endif
197 		return (EINVAL);
198 	}
199 
200 	waddress = (u_int64_t)address1 << 32UL | address;
201 	wmask = (u_int64_t)mask1 << 32UL | mask;
202 
203 	if ((is64bit && PCI_MAPREG_MEM64_SIZE(wmask) == 0) ||
204 	    (!is64bit && PCI_MAPREG_MEM_SIZE(mask) == 0)) {
205 #ifdef DEBUG
206 		printf("pci_mem_find: void region\n");
207 #endif
208 		return (ENOENT);
209 	}
210 
211 	switch (PCI_MAPREG_MEM_TYPE(address)) {
212 	case PCI_MAPREG_MEM_TYPE_32BIT:
213 	case PCI_MAPREG_MEM_TYPE_32BIT_1M:
214 		break;
215 	case PCI_MAPREG_MEM_TYPE_64BIT:
216 		/*
217 		 * Handle the case of a 64-bit memory register on a
218 		 * platform with 32-bit addressing.  Make sure that
219 		 * the address assigned and the device's memory size
220 		 * fit in 32 bits.  We implicitly assume that if
221 		 * bus_addr_t is 64-bit, then so is bus_size_t.
222 		 */
223 		if (sizeof(u_int64_t) > sizeof(bus_addr_t) &&
224 		    (address1 != 0 || mask1 != 0xffffffff)) {
225 #ifdef DEBUG
226 			printf("pci_mem_find: 64-bit memory map which is "
227 			    "inaccessible on a 32-bit platform\n");
228 #endif
229 			return (EINVAL);
230 		}
231 		break;
232 	default:
233 #ifdef DEBUG
234 		printf("pci_mem_find: reserved mapping register type\n");
235 #endif
236 		return (EINVAL);
237 	}
238 
239 	if (sizeof(u_int64_t) > sizeof(bus_addr_t)) {
240 		if (basep != 0)
241 			*basep = PCI_MAPREG_MEM_ADDR(address);
242 		if (sizep != 0)
243 			*sizep = PCI_MAPREG_MEM_SIZE(mask);
244 	} else {
245 		if (basep != 0)
246 			*basep = PCI_MAPREG_MEM64_ADDR(waddress);
247 		if (sizep != 0)
248 			*sizep = PCI_MAPREG_MEM64_SIZE(wmask);
249 	}
250 	if (flagsp != 0)
251 		*flagsp =
252 		    PCI_MAPREG_MEM_PREFETCHABLE(address) ?
253 		      BUS_SPACE_MAP_PREFETCHABLE : 0;
254 
255 	return (0);
256 }
257 
258 int
259 pci_io_find(pci_chipset_tag_t pc, pcitag_t pcitag, int reg,
260     bus_addr_t *iobasep, bus_size_t *iosizep)
261 {
262 	return (obsd_pci_io_find(pc, pcitag, reg, 0, iobasep, iosizep, 0));
263 }
264 
265 int
266 pci_mem_find(pci_chipset_tag_t pc, pcitag_t pcitag, int reg,
267     bus_addr_t *membasep, bus_size_t *memsizep, int *cacheablep)
268 {
269 	return (obsd_pci_mem_find(pc, pcitag, reg, -1, membasep, memsizep,
270 				  cacheablep));
271 }
272 
273 pcireg_t
274 pci_mapreg_type(pci_chipset_tag_t pc, pcitag_t tag, int reg)
275 {
276 	return (_PCI_MAPREG_TYPEBITS(pci_conf_read(pc, tag, reg)));
277 }
278 
279 int
280 pci_mapreg_probe(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *typep)
281 {
282 	pcireg_t address, mask, csr;
283 	int s;
284 
285 	s = splhigh();
286 	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
287 	if (csr & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
288 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr &
289 		    ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE));
290 	address = pci_conf_read(pc, tag, reg);
291 	pci_conf_write(pc, tag, reg, 0xffffffff);
292 	mask = pci_conf_read(pc, tag, reg);
293 	pci_conf_write(pc, tag, reg, address);
294 	if (csr & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
295 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
296 	splx(s);
297 
298 	if (mask == 0) /* unimplemented mapping register */
299 		return (0);
300 
301 	if (typep)
302 		*typep = _PCI_MAPREG_TYPEBITS(address);
303 	return (1);
304 }
305 
306 int
307 pci_mapreg_info(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
308     bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
309 {
310 
311 	if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO)
312 		return (obsd_pci_io_find(pc, tag, reg, type, basep, sizep,
313 		    flagsp));
314 	else
315 		return (obsd_pci_mem_find(pc, tag, reg, type, basep, sizep,
316 		    flagsp));
317 }
318 
319 int
320 pci_mapreg_map(struct pci_attach_args *pa, int reg, pcireg_t type, int flags,
321     bus_space_tag_t *tagp, bus_space_handle_t *handlep, bus_addr_t *basep,
322     bus_size_t *sizep, bus_size_t maxsize)
323 {
324 	bus_space_tag_t tag;
325 	bus_space_handle_t handle;
326 	bus_addr_t base;
327 	bus_size_t size;
328 	pcireg_t csr;
329 	int rv;
330 
331 	if ((rv = pci_mapreg_info(pa->pa_pc, pa->pa_tag, reg, type,
332 	    &base, &size, NULL)) != 0)
333 		return (rv);
334 #if !defined(__sparc64__)
335 	if (base == 0) {
336 		struct extent *ex;
337 		bus_addr_t start, end;
338 
339 		if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
340 			ex = pa->pa_ioex;
341 			if (ex != NULL) {
342 				start = max(PCI_IO_START, ex->ex_start);
343 				end = min(PCI_IO_END, ex->ex_end);
344 			}
345 		} else {
346 			ex = pa->pa_memex;
347 			if (ex != NULL) {
348 				start = max(PCI_MEM_START, ex->ex_start);
349 				end = min(PCI_MEM_END, ex->ex_end);
350 			}
351 		}
352 
353 		if (ex == NULL || extent_alloc_subregion(ex, start, end,
354 		    size, size, 0, 0, 0, &base))
355 			return (EINVAL); /* disabled because of invalid BAR */
356 
357 		pci_conf_write(pa->pa_pc, pa->pa_tag, reg, base);
358 		if (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT)
359 			pci_conf_write(pa->pa_pc, pa->pa_tag, reg + 4,
360 			    (u_int64_t)base >> 32);
361 	}
362 #endif
363 
364 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
365 	if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO)
366 		csr |= PCI_COMMAND_IO_ENABLE;
367 	else
368 		csr |= PCI_COMMAND_MEM_ENABLE;
369 	/* XXX Should this only be done for devices that do DMA?  */
370 	csr |= PCI_COMMAND_MASTER_ENABLE;
371 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
372 
373 	if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
374 		if ((pa->pa_flags & PCI_FLAGS_IO_ENABLED) == 0)
375 			return (EINVAL);
376 		tag = pa->pa_iot;
377 	} else {
378 		if ((pa->pa_flags & PCI_FLAGS_MEM_ENABLED) == 0)
379 			return (EINVAL);
380 		tag = pa->pa_memt;
381 	}
382 
383 	/* The caller can request limitation of the mapping's size. */
384 	if (maxsize != 0 && size > maxsize) {
385 #ifdef DEBUG
386 		printf("pci_mapreg_map: limited PCI mapping from %lx to %lx\n",
387 		    (u_long)size, (u_long)maxsize);
388 #endif
389 		size = maxsize;
390 	}
391 
392 	if (bus_space_map(tag, base, size, flags, &handle))
393 		return (1);
394 
395 	if (tagp != NULL)
396 		*tagp = tag;
397 	if (handlep != NULL)
398 		*handlep = handle;
399 	if (basep != NULL)
400 		*basep = base;
401 	if (sizep != NULL)
402 		*sizep = size;
403 
404 	return (0);
405 }
406