1 /* $NetBSD: pci_map.c,v 1.7 2000/05/10 16:58:42 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum; by William R. Studenmund; by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * PCI device mapping. 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/device.h> 46 47 #include <dev/pci/pcireg.h> 48 #include <dev/pci/pcivar.h> 49 50 static int pci_io_find __P((pci_chipset_tag_t, pcitag_t, int, pcireg_t, 51 bus_addr_t *, bus_size_t *, int *)); 52 static int pci_mem_find __P((pci_chipset_tag_t, pcitag_t, int, pcireg_t, 53 bus_addr_t *, bus_size_t *, int *)); 54 55 static int 56 pci_io_find(pc, tag, reg, type, basep, sizep, flagsp) 57 pci_chipset_tag_t pc; 58 pcitag_t tag; 59 int reg; 60 pcireg_t type; 61 bus_addr_t *basep; 62 bus_size_t *sizep; 63 int *flagsp; 64 { 65 pcireg_t address, mask; 66 int s; 67 68 if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) 69 panic("pci_io_find: bad request"); 70 71 /* 72 * Section 6.2.5.1, `Address Maps', tells us that: 73 * 74 * 1) The builtin software should have already mapped the device in a 75 * reasonable way. 76 * 77 * 2) A device which wants 2^n bytes of memory will hardwire the bottom 78 * n bits of the address to 0. As recommended, we write all 1s and see 79 * what we get back. 80 */ 81 s = splhigh(); 82 address = pci_conf_read(pc, tag, reg); 83 pci_conf_write(pc, tag, reg, 0xffffffff); 84 mask = pci_conf_read(pc, tag, reg); 85 pci_conf_write(pc, tag, reg, address); 86 splx(s); 87 88 if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_IO) { 89 printf("pci_io_find: expected type i/o, found mem\n"); 90 return (1); 91 } 92 93 if (PCI_MAPREG_IO_SIZE(mask) == 0) { 94 printf("pci_io_find: void region\n"); 95 return (1); 96 } 97 98 if (basep != 0) 99 *basep = PCI_MAPREG_IO_ADDR(address); 100 if (sizep != 0) 101 *sizep = PCI_MAPREG_IO_SIZE(mask); 102 if (flagsp != 0) 103 *flagsp = 0; 104 105 return (0); 106 } 107 108 static int 109 pci_mem_find(pc, tag, reg, type, basep, sizep, flagsp) 110 pci_chipset_tag_t pc; 111 pcitag_t tag; 112 int reg; 113 pcireg_t type; 114 bus_addr_t *basep; 115 bus_size_t *sizep; 116 int *flagsp; 117 { 118 pcireg_t address, mask, address1 = 0, mask1 = 0xffffffff; 119 u_int64_t waddress, wmask; 120 int s, is64bit; 121 122 is64bit = (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT); 123 124 if (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3)) 125 panic("pci_mem_find: bad request"); 126 127 if (is64bit && (reg + 4) >= PCI_MAPREG_END) 128 panic("pci_mem_find: bad 64-bit request"); 129 130 /* 131 * Section 6.2.5.1, `Address Maps', tells us that: 132 * 133 * 1) The builtin software should have already mapped the device in a 134 * reasonable way. 135 * 136 * 2) A device which wants 2^n bytes of memory will hardwire the bottom 137 * n bits of the address to 0. As recommended, we write all 1s and see 138 * what we get back. 139 */ 140 s = splhigh(); 141 address = pci_conf_read(pc, tag, reg); 142 pci_conf_write(pc, tag, reg, 0xffffffff); 143 mask = pci_conf_read(pc, tag, reg); 144 pci_conf_write(pc, tag, reg, address); 145 if (is64bit) { 146 address1 = pci_conf_read(pc, tag, reg + 4); 147 pci_conf_write(pc, tag, reg + 4, 0xffffffff); 148 mask1 = pci_conf_read(pc, tag, reg + 4); 149 pci_conf_write(pc, tag, reg + 4, address1); 150 } 151 splx(s); 152 153 if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) { 154 printf("pci_mem_find: expected type mem, found i/o\n"); 155 return (1); 156 } 157 if (PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) { 158 printf("pci_mem_find: expected mem type %08x, found %08x\n", 159 PCI_MAPREG_MEM_TYPE(type), 160 PCI_MAPREG_MEM_TYPE(address)); 161 return (1); 162 } 163 164 waddress = (u_int64_t)address1 << 32UL | address; 165 wmask = (u_int64_t)mask1 << 32UL | mask; 166 167 if (PCI_MAPREG_MEM64_SIZE(wmask) == 0) { 168 printf("pci_mem_find: void region\n"); 169 return (1); 170 } 171 172 switch (PCI_MAPREG_MEM_TYPE(address)) { 173 case PCI_MAPREG_MEM_TYPE_32BIT: 174 case PCI_MAPREG_MEM_TYPE_32BIT_1M: 175 break; 176 case PCI_MAPREG_MEM_TYPE_64BIT: 177 /* 178 * Handle the case of a 64-bit memory register on a 179 * platform with 32-bit addressing. Make sure that 180 * the address assigned and the device's memory size 181 * fit in 32 bits. We implicitly assume that if 182 * bus_addr_t is 64-bit, then so is bus_size_t. 183 */ 184 if (sizeof(u_int64_t) > sizeof(bus_addr_t) && 185 (address1 != 0 || mask1 != 0xffffffff)) { 186 printf("pci_mem_find: 64-bit memory map which is " 187 "inaccessible on a 32-bit platform\n"); 188 return (1); 189 } 190 break; 191 default: 192 printf("pci_mem_find: reserved mapping register type\n"); 193 return (1); 194 } 195 196 if (sizeof(u_int64_t) > sizeof(bus_addr_t)) { 197 if (basep != 0) 198 *basep = PCI_MAPREG_MEM_ADDR(address); 199 if (sizep != 0) 200 *sizep = PCI_MAPREG_MEM_SIZE(mask); 201 } else { 202 if (basep != 0) 203 *basep = PCI_MAPREG_MEM64_ADDR(waddress); 204 if (sizep != 0) 205 *sizep = PCI_MAPREG_MEM64_SIZE(wmask); 206 } 207 if (flagsp != 0) 208 *flagsp = PCI_MAPREG_MEM_PREFETCHABLE(address) ? 209 BUS_SPACE_MAP_PREFETCHABLE : 0; 210 211 return (0); 212 } 213 214 pcireg_t 215 pci_mapreg_type(pc, tag, reg) 216 pci_chipset_tag_t pc; 217 pcitag_t tag; 218 int reg; 219 { 220 pcireg_t rv; 221 222 rv = pci_conf_read(pc, tag, reg); 223 if (PCI_MAPREG_TYPE(rv) == PCI_MAPREG_TYPE_IO) 224 rv &= PCI_MAPREG_TYPE_MASK; 225 else 226 rv &= PCI_MAPREG_TYPE_MASK|PCI_MAPREG_MEM_TYPE_MASK; 227 return (rv); 228 } 229 230 int 231 pci_mapreg_info(pc, tag, reg, type, basep, sizep, flagsp) 232 pci_chipset_tag_t pc; 233 pcitag_t tag; 234 int reg; 235 pcireg_t type; 236 bus_addr_t *basep; 237 bus_size_t *sizep; 238 int *flagsp; 239 { 240 241 if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) 242 return (pci_io_find(pc, tag, reg, type, basep, sizep, 243 flagsp)); 244 else 245 return (pci_mem_find(pc, tag, reg, type, basep, sizep, 246 flagsp)); 247 } 248 249 int 250 pci_mapreg_map(pa, reg, type, busflags, tagp, handlep, basep, sizep) 251 struct pci_attach_args *pa; 252 int reg, busflags; 253 pcireg_t type; 254 bus_space_tag_t *tagp; 255 bus_space_handle_t *handlep; 256 bus_addr_t *basep; 257 bus_size_t *sizep; 258 { 259 bus_space_tag_t tag; 260 bus_space_handle_t handle; 261 bus_addr_t base; 262 bus_size_t size; 263 int flags; 264 265 if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_IO) { 266 if ((pa->pa_flags & PCI_FLAGS_IO_ENABLED) == 0) 267 return (1); 268 if (pci_io_find(pa->pa_pc, pa->pa_tag, reg, type, &base, 269 &size, &flags)) 270 return (1); 271 tag = pa->pa_iot; 272 } else { 273 if ((pa->pa_flags & PCI_FLAGS_MEM_ENABLED) == 0) 274 return (1); 275 if (pci_mem_find(pa->pa_pc, pa->pa_tag, reg, type, &base, 276 &size, &flags)) 277 return (1); 278 tag = pa->pa_memt; 279 } 280 281 if (bus_space_map(tag, base, size, busflags | flags, &handle)) 282 return (1); 283 284 if (tagp != 0) 285 *tagp = tag; 286 if (handlep != 0) 287 *handlep = handle; 288 if (basep != 0) 289 *basep = base; 290 if (sizep != 0) 291 *sizep = size; 292 293 return (0); 294 } 295