cardbus_map.c revision 1.28 1 /* $NetBSD: cardbus_map.c,v 1.28 2009/03/14 15:36:16 dsl Exp $ */
2
3 /*
4 * Copyright (c) 1999 and 2000
5 * HAYAKAWA Koichi. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by HAYAKAWA Koichi.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: cardbus_map.c,v 1.28 2009/03/14 15:36:16 dsl Exp $");
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41
42 #include <sys/bus.h>
43
44 #include <dev/cardbus/cardbusvar.h>
45
46 #include <dev/pci/pcireg.h> /* XXX */
47
48 #if defined DEBUG && !defined CARDBUS_MAP_DEBUG
49 #define CARDBUS_MAP_DEBUG
50 #endif
51
52 #if defined CARDBUS_MAP_DEBUG
53 #define STATIC
54 #define DPRINTF(a) printf a
55 #else
56 #define STATIC static
57 #define DPRINTF(a)
58 #endif
59
60
61 static int cardbus_io_find(cardbus_chipset_tag_t, cardbus_function_tag_t,
62 cardbustag_t, int, cardbusreg_t,
63 bus_addr_t *, bus_size_t *, int *);
64 static int cardbus_mem_find(cardbus_chipset_tag_t, cardbus_function_tag_t,
65 cardbustag_t, int, cardbusreg_t,
66 bus_addr_t *, bus_size_t *, int *);
67
68 /*
69 * static int cardbus_io_find(cardbus_chipset_tag_t cc,
70 * cardbus_function_tag_t cf, cardbustag_t tag,
71 * int reg, cardbusreg_t type, bus_addr_t *basep,
72 * bus_size_t *sizep, int *flagsp)
73 * This code is stolen from sys/dev/pci_map.c.
74 */
75 static int
76 cardbus_io_find(
77 cardbus_chipset_tag_t cc,
78 cardbus_function_tag_t cf,
79 cardbustag_t tag,
80 int reg,
81 cardbusreg_t type,
82 bus_addr_t *basep,
83 bus_size_t *sizep,
84 int *flagsp)
85 {
86 cardbusreg_t address, mask;
87 int s;
88
89 /* EXT ROM is able to map on memory space ONLY. */
90 if (reg == CARDBUS_ROM_REG) {
91 return 1;
92 }
93
94 if(reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) {
95 panic("cardbus_io_find: bad request");
96 }
97
98 /*
99 * Section 6.2.5.1, `Address Maps', tells us that:
100 *
101 * 1) The builtin software should have already mapped the device in a
102 * reasonable way.
103 *
104 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
105 * n bits of the address to 0. As recommended, we write all 1s and see
106 * what we get back.
107 */
108 s = splhigh();
109 address = cardbus_conf_read(cc, cf, tag, reg);
110 cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
111 mask = cardbus_conf_read(cc, cf, tag, reg);
112 cardbus_conf_write(cc, cf, tag, reg, address);
113 splx(s);
114
115 if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) {
116 printf("cardbus_io_find: expected type i/o, found mem\n");
117 return 1;
118 }
119
120 if (PCI_MAPREG_IO_SIZE(mask) == 0) {
121 printf("cardbus_io_find: void region\n");
122 return 1;
123 }
124
125 if (basep != 0) {
126 *basep = PCI_MAPREG_IO_ADDR(address);
127 }
128 if (sizep != 0) {
129 *sizep = PCI_MAPREG_IO_SIZE(mask);
130 }
131 if (flagsp != 0) {
132 *flagsp = 0;
133 }
134
135 return 0;
136 }
137
138
139
140 /*
141 * static int cardbus_mem_find(cardbus_chipset_tag_t cc,
142 * cardbus_function_tag_t cf, cardbustag_t tag,
143 * int reg, cardbusreg_t type, bus_addr_t *basep,
144 * bus_size_t *sizep, int *flagsp)
145 * This code is stolen from sys/dev/pci_map.c.
146 */
147 static int
148 cardbus_mem_find(cardbus_chipset_tag_t cc, cardbus_function_tag_t cf, cardbustag_t tag, int reg, cardbusreg_t type, bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
149 {
150 cardbusreg_t address, mask;
151 int s;
152
153 if (reg != CARDBUS_ROM_REG &&
154 (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3))) {
155 panic("cardbus_mem_find: bad request");
156 }
157
158 /*
159 * Section 6.2.5.1, `Address Maps', tells us that:
160 *
161 * 1) The builtin software should have already mapped the device in a
162 * reasonable way.
163 *
164 * 2) A device which wants 2^n bytes of memory will hardwire the bottom
165 * n bits of the address to 0. As recommended, we write all 1s and see
166 * what we get back.
167 */
168 s = splhigh();
169 address = cardbus_conf_read(cc, cf, tag, reg);
170 cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
171 mask = cardbus_conf_read(cc, cf, tag, reg);
172 cardbus_conf_write(cc, cf, tag, reg, address);
173 splx(s);
174
175 if (reg != CARDBUS_ROM_REG) {
176 /* memory space BAR */
177
178 if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
179 printf("cardbus_mem_find: expected type mem, found i/o\n");
180 return 1;
181 }
182 if (PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) {
183 printf("cardbus_mem_find: expected mem type %08x, found %08x\n",
184 PCI_MAPREG_MEM_TYPE(type),
185 PCI_MAPREG_MEM_TYPE(address));
186 return 1;
187 }
188 }
189
190 if (PCI_MAPREG_MEM_SIZE(mask) == 0) {
191 printf("cardbus_mem_find: void region\n");
192 return 1;
193 }
194
195 switch (PCI_MAPREG_MEM_TYPE(address)) {
196 case PCI_MAPREG_MEM_TYPE_32BIT:
197 case PCI_MAPREG_MEM_TYPE_32BIT_1M:
198 break;
199 case PCI_MAPREG_MEM_TYPE_64BIT:
200 printf("cardbus_mem_find: 64-bit memory mapping register\n");
201 return 1;
202 default:
203 printf("cardbus_mem_find: reserved mapping register type\n");
204 return 1;
205 }
206
207 if (basep != 0) {
208 *basep = PCI_MAPREG_MEM_ADDR(address);
209 }
210 if (sizep != 0) {
211 *sizep = PCI_MAPREG_MEM_SIZE(mask);
212 }
213 if (flagsp != 0) {
214 *flagsp = PCI_MAPREG_MEM_PREFETCHABLE(address) ?
215 BUS_SPACE_MAP_PREFETCHABLE : 0;
216 }
217
218 return 0;
219 }
220
221
222
223
224 /*
225 * int cardbus_mapreg_map(struct cardbus_softc *, int, int, cardbusreg_t,
226 * int bus_space_tag_t *, bus_space_handle_t *,
227 * bus_addr_t *, bus_size_t *)
228 * This function maps bus-space on the value of Base Address
229 * Register (BAR) indexed by the argument `reg' (the second argument).
230 * When the value of the BAR is not valid, such as 0x00000000, a new
231 * address should be allocated for the BAR and new address values is
232 * written on the BAR.
233 */
234 int
235 cardbus_mapreg_map(sc, func, reg, type, busflags, tagp, handlep, basep, sizep)
236 struct cardbus_softc *sc;
237 int func, reg, busflags;
238 cardbusreg_t type;
239 bus_space_tag_t *tagp;
240 bus_space_handle_t *handlep;
241 bus_addr_t *basep;
242 bus_size_t *sizep;
243 {
244 cardbus_chipset_tag_t cc = sc->sc_cc;
245 cardbus_function_tag_t cf = sc->sc_cf;
246 bus_space_tag_t bustag;
247 #if rbus
248 rbus_tag_t rbustag;
249 #endif
250 bus_space_handle_t handle;
251 bus_addr_t base;
252 bus_size_t size;
253 int flags;
254 int status = 0;
255 cardbustag_t tag;
256
257 size = 0; /* XXX gcc */
258 flags = 0; /* XXX gcc */
259
260 tag = cardbus_make_tag(cc, cf, sc->sc_bus, func);
261
262 DPRINTF(("cardbus_mapreg_map called: %s %x\n", device_xname(sc->sc_dev),
263 type));
264
265 if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
266 if (cardbus_io_find(cc, cf, tag, reg, type, &base, &size, &flags)) {
267 status = 1;
268 }
269 bustag = sc->sc_iot;
270 #if rbus
271 rbustag = sc->sc_rbus_iot;
272 #endif
273 } else {
274 if (cardbus_mem_find(cc, cf, tag, reg, type, &base, &size, &flags)){
275 status = 1;
276 }
277 bustag = sc->sc_memt;
278 #if rbus
279 rbustag = sc->sc_rbus_memt;
280 #endif
281 }
282 if (status == 0) {
283 #if rbus
284 bus_addr_t mask = size - 1;
285 if (base != 0) {
286 mask = 0xffffffff;
287 }
288 if ((*cf->cardbus_space_alloc)(cc, rbustag, base, size, mask,
289 size, busflags | flags, &base, &handle)) {
290 panic("io alloc");
291 }
292 #else
293 bus_addr_t start = 0x8300;
294 bus_addr_t end = 0x8400;
295 if (base != 0) {
296 bus_addr_t start = base;
297 bus_addr_t end = base + size;
298 }
299 if (bus_space_alloc(bustag, start, end, size, size, 0, 0, &base, &handle)) {
300 panic("io alloc");
301 }
302 #endif
303 }
304 cardbus_conf_write(cc, cf, tag, reg, base);
305
306 DPRINTF(("cardbus_mapreg_map: physaddr %lx\n", (unsigned long)base));
307
308 if (tagp != 0) {
309 *tagp = bustag;
310 }
311 if (handlep != 0) {
312 *handlep = handle;
313 }
314 if (basep != 0) {
315 *basep = base;
316 }
317 if (sizep != 0) {
318 *sizep = size;
319 }
320 cardbus_free_tag(cc, cf, tag);
321
322 return 0;
323 }
324
325
326
327
328
329 /*
330 * int cardbus_mapreg_unmap(struct cardbus_softc *sc, int func, int reg,
331 * bus_space_tag_t tag, bus_space_handle_t handle,
332 * bus_size_t size)
333 *
334 * This function releases bus-space region and close memory or io
335 * window on the bridge.
336 *
337 * Arguments:
338 * struct cardbus_softc *sc; the pointer to the device structure of cardbus.
339 * int func; the number of function on the device.
340 * int reg; the offset of BAR register.
341 */
342 int
343 cardbus_mapreg_unmap(sc, func, reg, tag, handle, size)
344 struct cardbus_softc *sc;
345 int func, reg;
346 bus_space_tag_t tag;
347 bus_space_handle_t handle;
348 bus_size_t size;
349 {
350 cardbus_chipset_tag_t cc = sc->sc_cc;
351 cardbus_function_tag_t cf = sc->sc_cf;
352 int st = 1;
353 cardbustag_t cardbustag;
354 #if rbus
355 rbus_tag_t rbustag;
356
357 if (sc->sc_iot == tag) {
358 /* bus space is io space */
359 DPRINTF(("%s: unmap i/o space\n", device_xname(sc->sc_dev)));
360 rbustag = sc->sc_rbus_iot;
361 } else if (sc->sc_memt == tag) {
362 /* bus space is memory space */
363 DPRINTF(("%s: unmap mem space\n", device_xname(sc->sc_dev)));
364 rbustag = sc->sc_rbus_memt;
365 } else {
366 return 1;
367 }
368 #endif
369
370 cardbustag = cardbus_make_tag(cc, cf, sc->sc_bus, func);
371
372 cardbus_conf_write(cc, cf, cardbustag, reg, 0);
373
374 #if rbus
375 (*cf->cardbus_space_free)(cc, rbustag, handle, size);
376 #endif
377
378 cardbus_free_tag(cc, cf, cardbustag);
379
380 return st;
381 }
382
383
384
385
386
387 /*
388 * int cardbus_save_bar(cardbus_devfunc_t);
389 *
390 * This function saves the Base Address Registers at the CardBus
391 * function denoted by the argument.
392 */
393 int cardbus_save_bar(ct)
394 cardbus_devfunc_t ct;
395 {
396 cardbustag_t tag = Cardbus_make_tag(ct);
397 cardbus_chipset_tag_t cc = ct->ct_cc;
398 cardbus_function_tag_t cf = ct->ct_cf;
399
400 ct->ct_bar[0] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE0_REG);
401 ct->ct_bar[1] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE1_REG);
402 ct->ct_bar[2] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE2_REG);
403 ct->ct_bar[3] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE3_REG);
404 ct->ct_bar[4] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE4_REG);
405 ct->ct_bar[5] = cardbus_conf_read(cc, cf, tag, CARDBUS_BASE5_REG);
406
407 DPRINTF(("cardbus_save_bar: %x %x\n", ct->ct_bar[0], ct->ct_bar[1]));
408
409 Cardbus_free_tag(ct, tag);
410
411 return 0;
412 }
413
414
415
416 /*
417 * int cardbus_restore_bar(cardbus_devfunc_t);
418 *
419 * This function saves the Base Address Registers at the CardBus
420 * function denoted by the argument.
421 */
422 int cardbus_restore_bar(ct)
423 cardbus_devfunc_t ct;
424 {
425 cardbustag_t tag = Cardbus_make_tag(ct);
426 cardbus_chipset_tag_t cc = ct->ct_cc;
427 cardbus_function_tag_t cf = ct->ct_cf;
428
429 cardbus_conf_write(cc, cf, tag, CARDBUS_BASE0_REG, ct->ct_bar[0]);
430 cardbus_conf_write(cc, cf, tag, CARDBUS_BASE1_REG, ct->ct_bar[1]);
431 cardbus_conf_write(cc, cf, tag, CARDBUS_BASE2_REG, ct->ct_bar[2]);
432 cardbus_conf_write(cc, cf, tag, CARDBUS_BASE3_REG, ct->ct_bar[3]);
433 cardbus_conf_write(cc, cf, tag, CARDBUS_BASE4_REG, ct->ct_bar[4]);
434 cardbus_conf_write(cc, cf, tag, CARDBUS_BASE5_REG, ct->ct_bar[5]);
435
436 Cardbus_free_tag(ct, tag);
437
438 return 0;
439 }
440