1 /* $OpenBSD: pci_map.c,v 1.33 2023/04/13 15:07:43 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
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
obsd_pci_io_find(pci_chipset_tag_t pc,pcitag_t tag,int reg,pcireg_t type,bus_addr_t * basep,bus_size_t * sizep,int * flagsp)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
obsd_pci_mem_find(pci_chipset_tag_t pc,pcitag_t tag,int reg,pcireg_t type,bus_addr_t * basep,bus_size_t * sizep,int * flagsp)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 pcireg_t
pci_mapreg_type(pci_chipset_tag_t pc,pcitag_t tag,int reg)258 pci_mapreg_type(pci_chipset_tag_t pc, pcitag_t tag, int reg)
259 {
260 return (_PCI_MAPREG_TYPEBITS(pci_conf_read(pc, tag, reg)));
261 }
262
263 int
pci_mapreg_probe(pci_chipset_tag_t pc,pcitag_t tag,int reg,pcireg_t * typep)264 pci_mapreg_probe(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *typep)
265 {
266 pcireg_t address, mask, csr;
267 int s;
268
269 s = splhigh();
270 csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
271 if (csr & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
272 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr &
273 ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE));
274 address = pci_conf_read(pc, tag, reg);
275 pci_conf_write(pc, tag, reg, 0xffffffff);
276 mask = pci_conf_read(pc, tag, reg);
277 pci_conf_write(pc, tag, reg, address);
278 if (csr & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
279 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
280 splx(s);
281
282 if (mask == 0) /* unimplemented mapping register */
283 return (0);
284
285 if (typep)
286 *typep = _PCI_MAPREG_TYPEBITS(address);
287 return (1);
288 }
289
290 int
pci_mapreg_info(pci_chipset_tag_t pc,pcitag_t tag,int reg,pcireg_t type,bus_addr_t * basep,bus_size_t * sizep,int * flagsp)291 pci_mapreg_info(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type,
292 bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
293 {
294
295 if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO)
296 return (obsd_pci_io_find(pc, tag, reg, type, basep, sizep,
297 flagsp));
298 else
299 return (obsd_pci_mem_find(pc, tag, reg, type, basep, sizep,
300 flagsp));
301 }
302
303 int
pci_mapreg_assign(struct pci_attach_args * pa,int reg,pcireg_t type,bus_addr_t * basep,bus_size_t * sizep)304 pci_mapreg_assign(struct pci_attach_args *pa, int reg, pcireg_t type,
305 bus_addr_t *basep, bus_size_t *sizep)
306 {
307 bus_addr_t base;
308 bus_size_t size;
309 pcireg_t csr;
310 int rv;
311
312 if ((rv = pci_mapreg_info(pa->pa_pc, pa->pa_tag, reg, type,
313 &base, &size, NULL)) != 0)
314 return (rv);
315 #if !defined(__sparc64__)
316 if (base == 0) {
317 struct extent *ex;
318 bus_addr_t start, end;
319
320 if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
321 ex = pa->pa_ioex;
322 if (ex != NULL) {
323 start = max(PCI_IO_START, ex->ex_start);
324 end = min(PCI_IO_END, ex->ex_end);
325 }
326 } else {
327 ex = pa->pa_memex;
328 if (ex != NULL) {
329 start = max(PCI_MEM_START, ex->ex_start);
330 end = min(PCI_MEM_END, ex->ex_end);
331 }
332 }
333
334 if (ex == NULL || extent_alloc_subregion(ex, start, end,
335 size, size, 0, 0, 0, &base))
336 return (EINVAL); /* disabled because of invalid BAR */
337
338 pci_conf_write(pa->pa_pc, pa->pa_tag, reg, base);
339 if (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT)
340 pci_conf_write(pa->pa_pc, pa->pa_tag, reg + 4,
341 (u_int64_t)base >> 32);
342 }
343 #endif
344
345 csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
346 if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO)
347 csr |= PCI_COMMAND_IO_ENABLE;
348 else
349 csr |= PCI_COMMAND_MEM_ENABLE;
350 /* XXX Should this only be done for devices that do DMA? */
351 csr |= PCI_COMMAND_MASTER_ENABLE;
352 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
353
354 if (basep != NULL)
355 *basep = base;
356 if (sizep != NULL)
357 *sizep = size;
358
359 return (0);
360 }
361
362 int
pci_mapreg_map(struct pci_attach_args * pa,int reg,pcireg_t type,int flags,bus_space_tag_t * tagp,bus_space_handle_t * handlep,bus_addr_t * basep,bus_size_t * sizep,bus_size_t maxsize)363 pci_mapreg_map(struct pci_attach_args *pa, int reg, pcireg_t type, int flags,
364 bus_space_tag_t *tagp, bus_space_handle_t *handlep, bus_addr_t *basep,
365 bus_size_t *sizep, bus_size_t maxsize)
366 {
367 bus_space_tag_t tag;
368 bus_space_handle_t handle;
369 bus_addr_t base;
370 bus_size_t size;
371 int rv;
372
373 if ((rv = pci_mapreg_assign(pa, reg, type, &base, &size)) != 0)
374 return (rv);
375
376 if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
377 if ((pa->pa_flags & PCI_FLAGS_IO_ENABLED) == 0)
378 return (EINVAL);
379 tag = pa->pa_iot;
380 } else {
381 if ((pa->pa_flags & PCI_FLAGS_MEM_ENABLED) == 0)
382 return (EINVAL);
383 tag = pa->pa_memt;
384 }
385
386 /* The caller can request limitation of the mapping's size. */
387 if (maxsize != 0 && size > maxsize) {
388 #ifdef DEBUG
389 printf("pci_mapreg_map: limited PCI mapping from %lx to %lx\n",
390 (u_long)size, (u_long)maxsize);
391 #endif
392 size = maxsize;
393 }
394
395 if (bus_space_map(tag, base, size, flags, &handle))
396 return (1);
397
398 if (tagp != NULL)
399 *tagp = tag;
400 if (handlep != NULL)
401 *handlep = handle;
402 if (basep != NULL)
403 *basep = base;
404 if (sizep != NULL)
405 *sizep = size;
406
407 return (0);
408 }
409