1 /*        $NetBSD: cardbus_map.c,v 1.36 2010/03/15 19:48:31 dyoung 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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: cardbus_map.c,v 1.36 2010/03/15 19:48:31 dyoung Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/device.h>
35 
36 #include <sys/bus.h>
37 
38 #include <dev/cardbus/cardbusvar.h>
39 
40 #include <dev/pci/pcireg.h>   /* XXX */
41 
42 #if defined DEBUG && !defined CARDBUS_MAP_DEBUG
43 #define CARDBUS_MAP_DEBUG
44 #endif
45 
46 #if defined CARDBUS_MAP_DEBUG
47 #define STATIC
48 #define DPRINTF(a) printf a
49 #else
50 #define STATIC static
51 #define DPRINTF(a)
52 #endif
53 
54 
55 static int cardbus_io_find(cardbus_chipset_tag_t, cardbus_function_tag_t,
56                                         pcitag_t, int, pcireg_t,
57                                         bus_addr_t *, bus_size_t *, int *);
58 static int cardbus_mem_find(cardbus_chipset_tag_t, cardbus_function_tag_t,
59                                          pcitag_t, int, pcireg_t,
60                                          bus_addr_t *, bus_size_t *, int *);
61 
62 /*
63  * static int cardbus_io_find(cardbus_chipset_tag_t cc,
64  *                                  cardbus_function_tag_t cf, pcitag_t tag,
65  *                                  int reg, pcireg_t type, bus_addr_t *basep,
66  *                                  bus_size_t *sizep, int *flagsp)
67  * This code is stolen from sys/dev/pci_map.c.
68  */
69 static int
cardbus_io_find(cardbus_chipset_tag_t cc,cardbus_function_tag_t cf,pcitag_t tag,int reg,pcireg_t type,bus_addr_t * basep,bus_size_t * sizep,int * flagsp)70 cardbus_io_find(
71     cardbus_chipset_tag_t cc,
72     cardbus_function_tag_t cf,
73     pcitag_t tag,
74     int reg,
75     pcireg_t type,
76     bus_addr_t *basep,
77     bus_size_t *sizep,
78     int *flagsp)
79 {
80           pcireg_t address, mask;
81           int s;
82 
83           /* EXT ROM is able to map on memory space ONLY. */
84           if (reg == CARDBUS_ROM_REG) {
85                     return 1;
86           }
87 
88           if(reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) {
89                     panic("cardbus_io_find: bad request");
90           }
91 
92           /*
93            * Section 6.2.5.1, `Address Maps', tells us that:
94            *
95            * 1) The builtin software should have already mapped the device in a
96            * reasonable way.
97            *
98            * 2) A device which wants 2^n bytes of memory will hardwire the bottom
99            * n bits of the address to 0.  As recommended, we write all 1s and see
100            * what we get back.
101            */
102           s = splhigh();
103           address = cardbus_conf_read(cc, cf, tag, reg);
104           cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
105           mask = cardbus_conf_read(cc, cf, tag, reg);
106           cardbus_conf_write(cc, cf, tag, reg, address);
107           splx(s);
108 
109           if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) {
110                     printf("cardbus_io_find: expected type i/o, found mem\n");
111                     return 1;
112           }
113 
114           if (PCI_MAPREG_IO_SIZE(mask) == 0) {
115                     printf("cardbus_io_find: void region\n");
116                     return 1;
117           }
118 
119           if (basep != 0) {
120                     *basep = PCI_MAPREG_IO_ADDR(address);
121           }
122           if (sizep != 0) {
123                     *sizep = PCI_MAPREG_IO_SIZE(mask);
124           }
125           if (flagsp != 0) {
126                     *flagsp = 0;
127           }
128 
129           return 0;
130 }
131 
132 
133 
134 /*
135  * static int cardbus_mem_find(cardbus_chipset_tag_t cc,
136  *                                   cardbus_function_tag_t cf, pcitag_t tag,
137  *                                   int reg, pcireg_t type, bus_addr_t *basep,
138  *                                   bus_size_t *sizep, int *flagsp)
139  * This code is stolen from sys/dev/pci_map.c.
140  */
141 static int
cardbus_mem_find(cardbus_chipset_tag_t cc,cardbus_function_tag_t cf,pcitag_t tag,int reg,pcireg_t type,bus_addr_t * basep,bus_size_t * sizep,int * flagsp)142 cardbus_mem_find(cardbus_chipset_tag_t cc, cardbus_function_tag_t cf, pcitag_t tag, int reg, pcireg_t type, bus_addr_t *basep, bus_size_t *sizep, int *flagsp)
143 {
144           pcireg_t address, mask;
145           int s;
146 
147           if (reg != CARDBUS_ROM_REG &&
148               (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3))) {
149                     panic("cardbus_mem_find: bad request");
150           }
151 
152           /*
153            * Section 6.2.5.1, `Address Maps', tells us that:
154            *
155            * 1) The builtin software should have already mapped the device in a
156            * reasonable way.
157            *
158            * 2) A device which wants 2^n bytes of memory will hardwire the bottom
159            * n bits of the address to 0.  As recommended, we write all 1s and see
160            * what we get back.
161            */
162           s = splhigh();
163           address = cardbus_conf_read(cc, cf, tag, reg);
164           cardbus_conf_write(cc, cf, tag, reg, 0xffffffff);
165           mask = cardbus_conf_read(cc, cf, tag, reg);
166           cardbus_conf_write(cc, cf, tag, reg, address);
167           splx(s);
168 
169           if (reg != CARDBUS_ROM_REG) {
170                     /* memory space BAR */
171 
172                     if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) {
173                               printf("cardbus_mem_find: expected type mem, found i/o\n");
174                               return 1;
175                     }
176                     if (PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) {
177                               printf("cardbus_mem_find: expected mem type %08x, found %08x\n",
178                                   PCI_MAPREG_MEM_TYPE(type),
179                                   PCI_MAPREG_MEM_TYPE(address));
180                               return 1;
181                     }
182           }
183 
184           if (PCI_MAPREG_MEM_SIZE(mask) == 0) {
185                     printf("cardbus_mem_find: void region\n");
186                     return 1;
187           }
188 
189           switch (PCI_MAPREG_MEM_TYPE(address)) {
190           case PCI_MAPREG_MEM_TYPE_32BIT:
191           case PCI_MAPREG_MEM_TYPE_32BIT_1M:
192                     break;
193           case PCI_MAPREG_MEM_TYPE_64BIT:
194                     printf("cardbus_mem_find: 64-bit memory mapping register\n");
195                     return 1;
196           default:
197                     printf("cardbus_mem_find: reserved mapping register type\n");
198                     return 1;
199           }
200 
201           if (basep != 0) {
202                     *basep = PCI_MAPREG_MEM_ADDR(address);
203           }
204           if (sizep != 0) {
205                     *sizep = PCI_MAPREG_MEM_SIZE(mask);
206           }
207           if (flagsp != 0) {
208                     *flagsp = PCI_MAPREG_MEM_PREFETCHABLE(address) ?
209                         BUS_SPACE_MAP_PREFETCHABLE : 0;
210           }
211 
212           return 0;
213 }
214 
215 
216 
217 
218 /*
219  * int cardbus_mapreg_map(struct cardbus_softc *, int, int, pcireg_t,
220  *                              int bus_space_tag_t *, bus_space_handle_t *,
221  *                              bus_addr_t *, bus_size_t *)
222  *    This function maps bus-space on the value of Base Address
223  *   Register (BAR) indexed by the argument `reg' (the second argument).
224  *   When the value of the BAR is not valid, such as 0x00000000, a new
225  *   address should be allocated for the BAR and new address values is
226  *   written on the BAR.
227  */
228 int
cardbus_mapreg_map(struct cardbus_softc * sc,int func,int reg,pcireg_t type,int busflags,bus_space_tag_t * tagp,bus_space_handle_t * handlep,bus_addr_t * basep,bus_size_t * sizep)229 cardbus_mapreg_map(struct cardbus_softc *sc, int func, int reg, pcireg_t type, int busflags, bus_space_tag_t *tagp, bus_space_handle_t *handlep, bus_addr_t *basep, bus_size_t *sizep)
230 {
231           cardbus_chipset_tag_t cc = sc->sc_cc;
232           cardbus_function_tag_t cf = sc->sc_cf;
233           bus_space_tag_t bustag;
234           rbus_tag_t rbustag;
235           bus_space_handle_t handle;
236           bus_addr_t base;
237           bus_size_t size;
238           int flags;
239           int status = 0;
240           pcitag_t tag;
241 
242           size = 0; /* XXX gcc */
243           flags = 0;          /* XXX gcc */
244 
245           tag = cardbus_make_tag(cc, cf, sc->sc_bus, func);
246 
247           DPRINTF(("cardbus_mapreg_map called: %s %x\n", device_xname(sc->sc_dev),
248              type));
249 
250           if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) {
251                     if (cardbus_io_find(cc, cf, tag, reg, type, &base, &size, &flags)) {
252                               status = 1;
253                     }
254                     bustag = sc->sc_iot;
255                     rbustag = sc->sc_rbus_iot;
256           } else {
257                     if (cardbus_mem_find(cc, cf, tag, reg, type, &base, &size, &flags)){
258                               status = 1;
259                     }
260                     bustag = sc->sc_memt;
261                     rbustag = sc->sc_rbus_memt;
262           }
263           if (status == 0) {
264                     bus_addr_t mask = size - 1;
265                     if (base != 0) {
266                               mask = 0xffffffff;
267                     }
268                     if ((*cf->cardbus_space_alloc)(cc, rbustag, base, size, mask,
269                         size, busflags | flags, &base, &handle)) {
270                               panic("io alloc");
271                     }
272           }
273           cardbus_conf_write(cc, cf, tag, reg, base);
274 
275           DPRINTF(("cardbus_mapreg_map: physaddr %lx\n", (unsigned long)base));
276 
277           if (tagp != 0) {
278                     *tagp = bustag;
279           }
280           if (handlep != 0) {
281                     *handlep = handle;
282           }
283           if (basep != 0) {
284                     *basep = base;
285           }
286           if (sizep != 0) {
287                     *sizep = size;
288           }
289 
290           return 0;
291 }
292 
293 
294 
295 
296 
297 /*
298  * int cardbus_mapreg_unmap(struct cardbus_softc *sc, int func, int reg,
299  *                                bus_space_tag_t tag, bus_space_handle_t handle,
300  *                                bus_size_t size)
301  *
302  *   This function releases bus-space region and close memory or io
303  *   window on the bridge.
304  *
305  *  Arguments:
306  *   struct cardbus_softc *sc; the pointer to the device structure of cardbus.
307  *   int func; the number of function on the device.
308  *   int reg; the offset of BAR register.
309  */
310 int
cardbus_mapreg_unmap(struct cardbus_softc * sc,int func,int reg,bus_space_tag_t tag,bus_space_handle_t handle,bus_size_t size)311 cardbus_mapreg_unmap(struct cardbus_softc *sc, int func, int reg, bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t size)
312 {
313           cardbus_chipset_tag_t cc = sc->sc_cc;
314           cardbus_function_tag_t cf = sc->sc_cf;
315           int st = 1;
316           pcitag_t cardbustag;
317           rbus_tag_t rbustag;
318 
319           if (sc->sc_iot == tag) {
320                     /* bus space is io space */
321                     DPRINTF(("%s: unmap i/o space\n", device_xname(sc->sc_dev)));
322                     rbustag = sc->sc_rbus_iot;
323           } else if (sc->sc_memt == tag) {
324                     /* bus space is memory space */
325                     DPRINTF(("%s: unmap mem space\n", device_xname(sc->sc_dev)));
326                     rbustag = sc->sc_rbus_memt;
327           } else {
328                     return 1;
329           }
330 
331           cardbustag = cardbus_make_tag(cc, cf, sc->sc_bus, func);
332 
333           cardbus_conf_write(cc, cf, cardbustag, reg, 0);
334 
335           (*cf->cardbus_space_free)(cc, rbustag, handle, size);
336 
337           return st;
338 }
339