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 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 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 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 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