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