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