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