1 1.55 thorpej /* $NetBSD: pciconf.c,v 1.55 2022/09/25 17:52:25 thorpej Exp $ */ 2 1.1 briggs 3 1.1 briggs /* 4 1.1 briggs * Copyright 2001 Wasabi Systems, Inc. 5 1.1 briggs * All rights reserved. 6 1.1 briggs * 7 1.1 briggs * Written by Allen Briggs for Wasabi Systems, Inc. 8 1.1 briggs * 9 1.1 briggs * Redistribution and use in source and binary forms, with or without 10 1.1 briggs * modification, are permitted provided that the following conditions 11 1.1 briggs * are met: 12 1.1 briggs * 1. Redistributions of source code must retain the above copyright 13 1.1 briggs * notice, this list of conditions and the following disclaimer. 14 1.1 briggs * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 briggs * notice, this list of conditions and the following disclaimer in the 16 1.1 briggs * documentation and/or other materials provided with the distribution. 17 1.1 briggs * 3. All advertising materials mentioning features or use of this software 18 1.1 briggs * must display the following acknowledgement: 19 1.1 briggs * This product includes software developed for the NetBSD Project by 20 1.1 briggs * Wasabi Systems, Inc. 21 1.1 briggs * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 briggs * or promote products derived from this software without specific prior 23 1.1 briggs * written permission. 24 1.1 briggs * 25 1.1 briggs * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 briggs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 briggs * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 briggs * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 briggs * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 briggs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 briggs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 briggs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 briggs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 briggs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 briggs * POSSIBILITY OF SUCH DAMAGE. 36 1.1 briggs */ 37 1.1 briggs /* 38 1.1 briggs * Derived in part from code from PMON/2000 (http://pmon.groupbsd.org/). 39 1.1 briggs */ 40 1.1 briggs 41 1.2 briggs /* 42 1.2 briggs * To do: 43 1.10 thorpej * - Perform all data structure allocation dynamically, don't have 44 1.10 thorpej * statically-sized arrays ("oops, you lose because you have too 45 1.10 thorpej * many slots filled!") 46 1.7 thorpej * - Do this in 2 passes, with an MD hook to control the behavior: 47 1.7 thorpej * (1) Configure the bus (possibly including expansion 48 1.7 thorpej * ROMs. 49 1.7 thorpej * (2) Another pass to disable expansion ROMs if they're 50 1.7 thorpej * mapped (since you're not supposed to leave them 51 1.7 thorpej * mapped when you're not using them). 52 1.7 thorpej * This would facilitate MD code executing the expansion ROMs 53 1.7 thorpej * if necessary (possibly with an x86 emulator) to configure 54 1.7 thorpej * devices (e.g. VGA cards). 55 1.2 briggs * - Deal with "anything can be hot-plugged" -- i.e., carry configuration 56 1.8 briggs * information around & be able to reconfigure on the fly 57 1.2 briggs * - Deal with segments (See IA64 System Abstraction Layer) 58 1.2 briggs * - Deal with subtractive bridges (& non-spec positive/subtractive decode) 59 1.2 briggs * - Deal with ISA/VGA/VGA palette snooping 60 1.2 briggs * - Deal with device capabilities on bridges 61 1.8 briggs * - Worry about changing a bridge to/from transparency 62 1.8 briggs * From thorpej (05/25/01) 63 1.8 briggs * - Try to handle devices that are already configured (perhaps using that 64 1.8 briggs * as a hint to where we put other devices) 65 1.2 briggs */ 66 1.13 lukem 67 1.13 lukem #include <sys/cdefs.h> 68 1.55 thorpej __KERNEL_RCSID(0, "$NetBSD: pciconf.c,v 1.55 2022/09/25 17:52:25 thorpej Exp $"); 69 1.2 briggs 70 1.1 briggs #include "opt_pci.h" 71 1.1 briggs 72 1.1 briggs #include <sys/param.h> 73 1.1 briggs #include <sys/queue.h> 74 1.1 briggs #include <sys/systm.h> 75 1.32 matt #include <sys/kmem.h> 76 1.47 thorpej #include <sys/vmem.h> 77 1.1 briggs 78 1.1 briggs #include <dev/pci/pcivar.h> 79 1.1 briggs #include <dev/pci/pciconf.h> 80 1.1 briggs #include <dev/pci/pcidevs.h> 81 1.22 briggs #include <dev/pci/pccbbreg.h> 82 1.1 briggs 83 1.48 thorpej int pci_conf_debug = 0; 84 1.1 briggs 85 1.1 briggs #if !defined(MIN) 86 1.1 briggs #define MIN(a,b) (((a)<(b))?(a):(b)) 87 1.1 briggs #define MAX(a,b) (((a)>(b))?(a):(b)) 88 1.1 briggs #endif 89 1.1 briggs 90 1.1 briggs /* per-bus constants. */ 91 1.10 thorpej #define MAX_CONF_DEV 32 /* Arbitrary */ 92 1.1 briggs #define MAX_CONF_MEM (3 * MAX_CONF_DEV) /* Avg. 3 per device -- Arb. */ 93 1.8 briggs #define MAX_CONF_IO (3 * MAX_CONF_DEV) /* Avg. 1 per device -- Arb. */ 94 1.1 briggs 95 1.1 briggs struct _s_pciconf_bus_t; /* Forward declaration */ 96 1.1 briggs 97 1.47 thorpej struct pciconf_resource { 98 1.47 thorpej vmem_t *arena; 99 1.47 thorpej bus_addr_t min_addr; 100 1.47 thorpej bus_addr_t max_addr; 101 1.47 thorpej bus_size_t total_size; 102 1.47 thorpej }; 103 1.47 thorpej 104 1.47 thorpej #define PCICONF_RESOURCE_NTYPES 3 105 1.47 thorpej CTASSERT(PCICONF_RESOURCE_IO < PCICONF_RESOURCE_NTYPES); 106 1.47 thorpej CTASSERT(PCICONF_RESOURCE_MEM < PCICONF_RESOURCE_NTYPES); 107 1.47 thorpej CTASSERT(PCICONF_RESOURCE_PREFETCHABLE_MEM < PCICONF_RESOURCE_NTYPES); 108 1.47 thorpej 109 1.47 thorpej static const char *pciconf_resource_names[] = { 110 1.47 thorpej [PCICONF_RESOURCE_IO] = "pci-io", 111 1.47 thorpej [PCICONF_RESOURCE_MEM] = "pci-mem", 112 1.47 thorpej [PCICONF_RESOURCE_PREFETCHABLE_MEM] = "pci-pmem", 113 1.47 thorpej }; 114 1.47 thorpej 115 1.47 thorpej struct pciconf_resources { 116 1.47 thorpej struct pciconf_resource resources[PCICONF_RESOURCE_NTYPES]; 117 1.47 thorpej }; 118 1.47 thorpej 119 1.49 jmcneill struct pciconf_resource_rsvd { 120 1.49 jmcneill int type; 121 1.49 jmcneill uint64_t start; 122 1.49 jmcneill bus_size_t size; 123 1.50 jmcneill void (*callback)(void *, uint64_t); 124 1.50 jmcneill void *callback_arg; 125 1.49 jmcneill LIST_ENTRY(pciconf_resource_rsvd) next; 126 1.49 jmcneill }; 127 1.49 jmcneill 128 1.49 jmcneill static LIST_HEAD(, pciconf_resource_rsvd) pciconf_resource_reservations = 129 1.49 jmcneill LIST_HEAD_INITIALIZER(pciconf_resource_reservations); 130 1.49 jmcneill 131 1.1 briggs typedef struct _s_pciconf_dev_t { 132 1.1 briggs int ipin; 133 1.1 briggs int iline; 134 1.1 briggs int min_gnt; 135 1.1 briggs int max_lat; 136 1.2 briggs int enable; 137 1.1 briggs pcitag_t tag; 138 1.1 briggs pci_chipset_tag_t pc; 139 1.1 briggs struct _s_pciconf_bus_t *ppb; /* I am really a bridge */ 140 1.51 skrll pcireg_t ea_cap_ptr; 141 1.1 briggs } pciconf_dev_t; 142 1.1 briggs 143 1.1 briggs typedef struct _s_pciconf_win_t { 144 1.1 briggs pciconf_dev_t *dev; 145 1.1 briggs int reg; /* 0 for busses */ 146 1.1 briggs int align; 147 1.1 briggs int prefetch; 148 1.39 msaitoh uint64_t size; 149 1.39 msaitoh uint64_t address; 150 1.1 briggs } pciconf_win_t; 151 1.1 briggs 152 1.1 briggs typedef struct _s_pciconf_bus_t { 153 1.1 briggs int busno; 154 1.1 briggs int next_busno; 155 1.1 briggs int last_busno; 156 1.1 briggs int max_mingnt; 157 1.1 briggs int min_maxlat; 158 1.14 thorpej int cacheline_size; 159 1.1 briggs int prefetch; 160 1.1 briggs int fast_b2b; 161 1.1 briggs int freq_66; 162 1.1 briggs int def_ltim; 163 1.1 briggs int max_ltim; 164 1.1 briggs int bandwidth_used; 165 1.1 briggs int swiz; 166 1.2 briggs int io_32bit; 167 1.2 briggs int pmem_64bit; 168 1.44 thorpej int mem_64bit; 169 1.36 matt int io_align; 170 1.36 matt int mem_align; 171 1.36 matt int pmem_align; 172 1.1 briggs 173 1.1 briggs int ndevs; 174 1.1 briggs pciconf_dev_t device[MAX_CONF_DEV]; 175 1.1 briggs 176 1.1 briggs /* These should be sorted in order of decreasing size */ 177 1.1 briggs int nmemwin; 178 1.1 briggs pciconf_win_t pcimemwin[MAX_CONF_MEM]; 179 1.1 briggs int niowin; 180 1.1 briggs pciconf_win_t pciiowin[MAX_CONF_IO]; 181 1.1 briggs 182 1.1 briggs bus_size_t io_total; 183 1.1 briggs bus_size_t mem_total; 184 1.1 briggs bus_size_t pmem_total; 185 1.1 briggs 186 1.47 thorpej struct pciconf_resource io_res; 187 1.47 thorpej struct pciconf_resource mem_res; 188 1.47 thorpej struct pciconf_resource pmem_res; 189 1.1 briggs 190 1.1 briggs pci_chipset_tag_t pc; 191 1.1 briggs struct _s_pciconf_bus_t *parent_bus; 192 1.1 briggs } pciconf_bus_t; 193 1.1 briggs 194 1.1 briggs static int probe_bus(pciconf_bus_t *); 195 1.1 briggs static void alloc_busno(pciconf_bus_t *, pciconf_bus_t *); 196 1.18 simonb static void set_busreg(pci_chipset_tag_t, pcitag_t, int, int, int); 197 1.4 simonb static int pci_do_device_query(pciconf_bus_t *, pcitag_t, int, int, int); 198 1.1 briggs static int setup_iowins(pciconf_bus_t *); 199 1.1 briggs static int setup_memwins(pciconf_bus_t *); 200 1.1 briggs static int configure_bridge(pciconf_dev_t *); 201 1.1 briggs static int configure_bus(pciconf_bus_t *); 202 1.47 thorpej static uint64_t pci_allocate_range(struct pciconf_resource *, uint64_t, int, 203 1.47 thorpej bool); 204 1.1 briggs static pciconf_win_t *get_io_desc(pciconf_bus_t *, bus_size_t); 205 1.1 briggs static pciconf_win_t *get_mem_desc(pciconf_bus_t *, bus_size_t); 206 1.1 briggs static pciconf_bus_t *query_bus(pciconf_bus_t *, pciconf_dev_t *, int); 207 1.1 briggs 208 1.1 briggs static void print_tag(pci_chipset_tag_t, pcitag_t); 209 1.1 briggs 210 1.47 thorpej static vmem_t * 211 1.47 thorpej create_vmem_arena(const char *name, bus_addr_t start, bus_size_t size, 212 1.47 thorpej int flags) 213 1.47 thorpej { 214 1.47 thorpej KASSERT(start < VMEM_ADDR_MAX); 215 1.47 thorpej KASSERT(size == 0 || 216 1.47 thorpej (VMEM_ADDR_MAX - start) >= (size - 1)); 217 1.47 thorpej 218 1.47 thorpej return vmem_create(name, start, size, 219 1.47 thorpej 1, /*quantum*/ 220 1.47 thorpej NULL, /*importfn*/ 221 1.47 thorpej NULL, /*releasefn*/ 222 1.47 thorpej NULL, /*source*/ 223 1.47 thorpej 0, /*qcache_max*/ 224 1.47 thorpej flags, 225 1.47 thorpej IPL_NONE); 226 1.47 thorpej } 227 1.47 thorpej 228 1.47 thorpej static int 229 1.47 thorpej init_range_resource(struct pciconf_resource *r, const char *name, 230 1.47 thorpej bus_addr_t start, bus_addr_t size) 231 1.47 thorpej { 232 1.47 thorpej r->arena = create_vmem_arena(name, start, size, VM_NOSLEEP); 233 1.47 thorpej if (r->arena == NULL) 234 1.47 thorpej return ENOMEM; 235 1.47 thorpej 236 1.47 thorpej r->min_addr = start; 237 1.47 thorpej r->max_addr = start + (size - 1); 238 1.47 thorpej r->total_size = size; 239 1.47 thorpej 240 1.47 thorpej return 0; 241 1.47 thorpej } 242 1.47 thorpej 243 1.47 thorpej static void 244 1.47 thorpej fini_range_resource(struct pciconf_resource *r) 245 1.47 thorpej { 246 1.47 thorpej if (r->arena) { 247 1.47 thorpej vmem_xfreeall(r->arena); 248 1.47 thorpej vmem_destroy(r->arena); 249 1.47 thorpej } 250 1.47 thorpej memset(r, 0, sizeof(*r)); 251 1.47 thorpej } 252 1.47 thorpej 253 1.1 briggs static void 254 1.1 briggs print_tag(pci_chipset_tag_t pc, pcitag_t tag) 255 1.1 briggs { 256 1.1 briggs int bus, dev, func; 257 1.1 briggs 258 1.1 briggs pci_decompose_tag(pc, tag, &bus, &dev, &func); 259 1.1 briggs printf("PCI: bus %d, device %d, function %d: ", bus, dev, func); 260 1.1 briggs } 261 1.1 briggs 262 1.44 thorpej #ifdef _LP64 263 1.44 thorpej #define __used_only_lp64 __unused 264 1.44 thorpej #else 265 1.44 thorpej #define __used_only_lp64 /* nothing */ 266 1.44 thorpej #endif /* _LP64 */ 267 1.44 thorpej 268 1.1 briggs /************************************************************************/ 269 1.1 briggs /************************************************************************/ 270 1.1 briggs /*********************** Bus probing routines ***********************/ 271 1.1 briggs /************************************************************************/ 272 1.1 briggs /************************************************************************/ 273 1.1 briggs static pciconf_win_t * 274 1.1 briggs get_io_desc(pciconf_bus_t *pb, bus_size_t size) 275 1.1 briggs { 276 1.1 briggs int i, n; 277 1.1 briggs 278 1.1 briggs n = pb->niowin; 279 1.40 msaitoh for (i = n; i > 0 && size > pb->pciiowin[i-1].size; i--) 280 1.1 briggs pb->pciiowin[i] = pb->pciiowin[i-1]; /* struct copy */ 281 1.1 briggs return &pb->pciiowin[i]; 282 1.1 briggs } 283 1.1 briggs 284 1.1 briggs static pciconf_win_t * 285 1.1 briggs get_mem_desc(pciconf_bus_t *pb, bus_size_t size) 286 1.1 briggs { 287 1.1 briggs int i, n; 288 1.1 briggs 289 1.1 briggs n = pb->nmemwin; 290 1.40 msaitoh for (i = n; i > 0 && size > pb->pcimemwin[i-1].size; i--) 291 1.1 briggs pb->pcimemwin[i] = pb->pcimemwin[i-1]; /* struct copy */ 292 1.1 briggs return &pb->pcimemwin[i]; 293 1.1 briggs } 294 1.1 briggs 295 1.1 briggs /* 296 1.1 briggs * Set up bus common stuff, then loop over devices & functions. 297 1.1 briggs * If we find something, call pci_do_device_query()). 298 1.1 briggs */ 299 1.1 briggs static int 300 1.1 briggs probe_bus(pciconf_bus_t *pb) 301 1.1 briggs { 302 1.33 dyoung int device; 303 1.33 dyoung uint8_t devs[32]; 304 1.33 dyoung int i, n; 305 1.1 briggs 306 1.1 briggs pb->ndevs = 0; 307 1.1 briggs pb->niowin = 0; 308 1.1 briggs pb->nmemwin = 0; 309 1.1 briggs pb->freq_66 = 1; 310 1.21 augustss #ifdef PCICONF_NO_FAST_B2B 311 1.21 augustss pb->fast_b2b = 0; 312 1.21 augustss #else 313 1.1 briggs pb->fast_b2b = 1; 314 1.21 augustss #endif 315 1.1 briggs pb->prefetch = 1; 316 1.1 briggs pb->max_mingnt = 0; /* we are looking for the maximum */ 317 1.1 briggs pb->min_maxlat = 0x100; /* we are looking for the minimum */ 318 1.1 briggs pb->bandwidth_used = 0; 319 1.4 simonb 320 1.33 dyoung n = pci_bus_devorder(pb->pc, pb->busno, devs, __arraycount(devs)); 321 1.33 dyoung for (i = 0; i < n; i++) { 322 1.1 briggs pcitag_t tag; 323 1.1 briggs pcireg_t id, bhlcr; 324 1.1 briggs int function, nfunction; 325 1.4 simonb int confmode; 326 1.1 briggs 327 1.33 dyoung device = devs[i]; 328 1.33 dyoung 329 1.1 briggs tag = pci_make_tag(pb->pc, pb->busno, device, 0); 330 1.1 briggs if (pci_conf_debug) { 331 1.1 briggs print_tag(pb->pc, tag); 332 1.1 briggs } 333 1.1 briggs id = pci_conf_read(pb->pc, tag, PCI_ID_REG); 334 1.1 briggs 335 1.4 simonb if (pci_conf_debug) { 336 1.4 simonb printf("id=%x: Vendor=%x, Product=%x\n", 337 1.40 msaitoh id, PCI_VENDOR(id), PCI_PRODUCT(id)); 338 1.4 simonb } 339 1.1 briggs /* Invalid vendor ID value? */ 340 1.1 briggs if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) 341 1.1 briggs continue; 342 1.1 briggs 343 1.1 briggs bhlcr = pci_conf_read(pb->pc, tag, PCI_BHLC_REG); 344 1.1 briggs nfunction = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; 345 1.40 msaitoh for (function = 0; function < nfunction; function++) { 346 1.1 briggs tag = pci_make_tag(pb->pc, pb->busno, device, function); 347 1.1 briggs id = pci_conf_read(pb->pc, tag, PCI_ID_REG); 348 1.1 briggs if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) 349 1.1 briggs continue; 350 1.40 msaitoh if (pb->ndevs + 1 < MAX_CONF_DEV) { 351 1.1 briggs if (pci_conf_debug) { 352 1.1 briggs print_tag(pb->pc, tag); 353 1.3 thorpej printf("Found dev 0x%04x 0x%04x -- " 354 1.3 thorpej "really probing.\n", 355 1.3 thorpej PCI_VENDOR(id), PCI_PRODUCT(id)); 356 1.1 briggs } 357 1.4 simonb #ifdef __HAVE_PCI_CONF_HOOK 358 1.4 simonb confmode = pci_conf_hook(pb->pc, pb->busno, 359 1.4 simonb device, function, id); 360 1.4 simonb if (confmode == 0) 361 1.4 simonb continue; 362 1.4 simonb #else 363 1.6 thorpej /* 364 1.6 thorpej * Don't enable expansion ROMS -- some cards 365 1.6 thorpej * share address decoders between the EXPROM 366 1.6 thorpej * and PCI memory space, and enabling the ROM 367 1.6 thorpej * when not needed will cause all sorts of 368 1.6 thorpej * lossage. 369 1.6 thorpej */ 370 1.28 gdamore confmode = PCI_CONF_DEFAULT; 371 1.4 simonb #endif 372 1.1 briggs if (pci_do_device_query(pb, tag, device, 373 1.4 simonb function, confmode)) 374 1.1 briggs return -1; 375 1.1 briggs pb->ndevs++; 376 1.1 briggs } 377 1.1 briggs } 378 1.1 briggs } 379 1.1 briggs return 0; 380 1.1 briggs } 381 1.1 briggs 382 1.1 briggs static void 383 1.1 briggs alloc_busno(pciconf_bus_t *parent, pciconf_bus_t *pb) 384 1.1 briggs { 385 1.1 briggs pb->busno = parent->next_busno; 386 1.17 augustss pb->next_busno = pb->busno + 1; 387 1.17 augustss } 388 1.17 augustss 389 1.17 augustss static void 390 1.17 augustss set_busreg(pci_chipset_tag_t pc, pcitag_t tag, int prim, int sec, int sub) 391 1.17 augustss { 392 1.17 augustss pcireg_t busreg; 393 1.17 augustss 394 1.52 skrll busreg = __SHIFTIN(prim, PCI_BRIDGE_BUS_PRIMARY); 395 1.52 skrll busreg |= __SHIFTIN(sec, PCI_BRIDGE_BUS_SECONDARY); 396 1.52 skrll busreg |= __SHIFTIN(sub, PCI_BRIDGE_BUS_SUBORDINATE); 397 1.17 augustss pci_conf_write(pc, tag, PCI_BRIDGE_BUS_REG, busreg); 398 1.1 briggs } 399 1.1 briggs 400 1.1 briggs static pciconf_bus_t * 401 1.1 briggs query_bus(pciconf_bus_t *parent, pciconf_dev_t *pd, int dev) 402 1.1 briggs { 403 1.1 briggs pciconf_bus_t *pb; 404 1.17 augustss pcireg_t io, pmem; 405 1.1 briggs pciconf_win_t *pi, *pm; 406 1.1 briggs 407 1.42 chs pb = kmem_zalloc(sizeof (pciconf_bus_t), KM_SLEEP); 408 1.14 thorpej pb->cacheline_size = parent->cacheline_size; 409 1.1 briggs pb->parent_bus = parent; 410 1.1 briggs alloc_busno(parent, pb); 411 1.1 briggs 412 1.36 matt pb->mem_align = 0x100000; /* 1M alignment */ 413 1.36 matt pb->pmem_align = 0x100000; /* 1M alignment */ 414 1.36 matt pb->io_align = 0x1000; /* 4K alignment */ 415 1.36 matt 416 1.17 augustss set_busreg(parent->pc, pd->tag, parent->busno, pb->busno, 0xff); 417 1.1 briggs 418 1.1 briggs pb->swiz = parent->swiz + dev; 419 1.1 briggs 420 1.47 thorpej memset(&pb->io_res, 0, sizeof(pb->io_res)); 421 1.47 thorpej memset(&pb->mem_res, 0, sizeof(pb->mem_res)); 422 1.47 thorpej memset(&pb->pmem_res, 0, sizeof(pb->pmem_res)); 423 1.47 thorpej 424 1.1 briggs pb->pc = parent->pc; 425 1.1 briggs pb->io_total = pb->mem_total = pb->pmem_total = 0; 426 1.1 briggs 427 1.2 briggs pb->io_32bit = 0; 428 1.2 briggs if (parent->io_32bit) { 429 1.11 thorpej io = pci_conf_read(parent->pc, pd->tag, PCI_BRIDGE_STATIO_REG); 430 1.40 msaitoh if (PCI_BRIDGE_IO_32BITS(io)) 431 1.2 briggs pb->io_32bit = 1; 432 1.2 briggs } 433 1.2 briggs 434 1.2 briggs pb->pmem_64bit = 0; 435 1.2 briggs if (parent->pmem_64bit) { 436 1.11 thorpej pmem = pci_conf_read(parent->pc, pd->tag, 437 1.2 briggs PCI_BRIDGE_PREFETCHMEM_REG); 438 1.40 msaitoh if (PCI_BRIDGE_PREFETCHMEM_64BITS(pmem)) 439 1.2 briggs pb->pmem_64bit = 1; 440 1.2 briggs } 441 1.2 briggs 442 1.44 thorpej /* Bridges only forward a 32-bit range of non-prefetcable memory. */ 443 1.44 thorpej pb->mem_64bit = 0; 444 1.44 thorpej 445 1.1 briggs if (probe_bus(pb)) { 446 1.1 briggs printf("Failed to probe bus %d\n", pb->busno); 447 1.1 briggs goto err; 448 1.1 briggs } 449 1.1 briggs 450 1.17 augustss /* We have found all subordinate busses now, reprogram busreg. */ 451 1.40 msaitoh pb->last_busno = pb->next_busno - 1; 452 1.17 augustss parent->next_busno = pb->next_busno; 453 1.17 augustss set_busreg(parent->pc, pd->tag, parent->busno, pb->busno, 454 1.17 augustss pb->last_busno); 455 1.17 augustss if (pci_conf_debug) 456 1.17 augustss printf("PCI bus bridge (parent %d) covers busses %d-%d\n", 457 1.17 augustss parent->busno, pb->busno, pb->last_busno); 458 1.17 augustss 459 1.1 briggs if (pb->io_total > 0) { 460 1.1 briggs if (parent->niowin >= MAX_CONF_IO) { 461 1.35 matt printf("pciconf: too many (%d) I/O windows\n", 462 1.35 matt parent->niowin); 463 1.1 briggs goto err; 464 1.1 briggs } 465 1.36 matt pb->io_total |= pb->io_align - 1; /* Round up */ 466 1.1 briggs pi = get_io_desc(parent, pb->io_total); 467 1.1 briggs pi->dev = pd; 468 1.1 briggs pi->reg = 0; 469 1.1 briggs pi->size = pb->io_total; 470 1.36 matt pi->align = pb->io_align; /* 4K min alignment */ 471 1.36 matt if (parent->io_align < pb->io_align) 472 1.36 matt parent->io_align = pb->io_align; 473 1.1 briggs pi->prefetch = 0; 474 1.1 briggs parent->niowin++; 475 1.1 briggs parent->io_total += pb->io_total; 476 1.1 briggs } 477 1.1 briggs 478 1.1 briggs if (pb->mem_total > 0) { 479 1.1 briggs if (parent->nmemwin >= MAX_CONF_MEM) { 480 1.35 matt printf("pciconf: too many (%d) MEM windows\n", 481 1.35 matt parent->nmemwin); 482 1.1 briggs goto err; 483 1.1 briggs } 484 1.40 msaitoh pb->mem_total |= pb->mem_align - 1; /* Round up */ 485 1.1 briggs pm = get_mem_desc(parent, pb->mem_total); 486 1.1 briggs pm->dev = pd; 487 1.1 briggs pm->reg = 0; 488 1.1 briggs pm->size = pb->mem_total; 489 1.36 matt pm->align = pb->mem_align; /* 1M min alignment */ 490 1.36 matt if (parent->mem_align < pb->mem_align) 491 1.36 matt parent->mem_align = pb->mem_align; 492 1.1 briggs pm->prefetch = 0; 493 1.1 briggs parent->nmemwin++; 494 1.1 briggs parent->mem_total += pb->mem_total; 495 1.1 briggs } 496 1.1 briggs 497 1.1 briggs if (pb->pmem_total > 0) { 498 1.1 briggs if (parent->nmemwin >= MAX_CONF_MEM) { 499 1.10 thorpej printf("pciconf: too many MEM windows\n"); 500 1.1 briggs goto err; 501 1.1 briggs } 502 1.40 msaitoh pb->pmem_total |= pb->pmem_align - 1; /* Round up */ 503 1.1 briggs pm = get_mem_desc(parent, pb->pmem_total); 504 1.1 briggs pm->dev = pd; 505 1.1 briggs pm->reg = 0; 506 1.1 briggs pm->size = pb->pmem_total; 507 1.36 matt pm->align = pb->pmem_align; /* 1M alignment */ 508 1.36 matt if (parent->pmem_align < pb->pmem_align) 509 1.36 matt parent->pmem_align = pb->pmem_align; 510 1.1 briggs pm->prefetch = 1; 511 1.1 briggs parent->nmemwin++; 512 1.1 briggs parent->pmem_total += pb->pmem_total; 513 1.1 briggs } 514 1.1 briggs 515 1.1 briggs return pb; 516 1.1 briggs err: 517 1.32 matt kmem_free(pb, sizeof(*pb)); 518 1.1 briggs return NULL; 519 1.1 briggs } 520 1.1 briggs 521 1.50 jmcneill static struct pciconf_resource_rsvd * 522 1.49 jmcneill pci_resource_is_reserved(int type, uint64_t addr, uint64_t size) 523 1.49 jmcneill { 524 1.49 jmcneill struct pciconf_resource_rsvd *rsvd; 525 1.49 jmcneill 526 1.49 jmcneill LIST_FOREACH(rsvd, &pciconf_resource_reservations, next) { 527 1.49 jmcneill if (rsvd->type != type) 528 1.49 jmcneill continue; 529 1.49 jmcneill if (rsvd->start <= addr + size && rsvd->start + rsvd->size >= addr) 530 1.50 jmcneill return rsvd; 531 1.49 jmcneill } 532 1.49 jmcneill 533 1.50 jmcneill return NULL; 534 1.49 jmcneill } 535 1.49 jmcneill 536 1.50 jmcneill static struct pciconf_resource_rsvd * 537 1.50 jmcneill pci_bar_is_reserved(pciconf_bus_t *pb, pciconf_dev_t *pd, int br) 538 1.49 jmcneill { 539 1.49 jmcneill pcireg_t base, base64, mask, mask64; 540 1.50 jmcneill pcitag_t tag; 541 1.49 jmcneill uint64_t addr, size; 542 1.49 jmcneill 543 1.49 jmcneill /* 544 1.50 jmcneill * Resource reservation does not apply to bridges 545 1.49 jmcneill */ 546 1.50 jmcneill if (pd->ppb) 547 1.50 jmcneill return NULL; 548 1.49 jmcneill 549 1.50 jmcneill tag = pd->tag; 550 1.49 jmcneill 551 1.50 jmcneill /* 552 1.50 jmcneill * Look to see if this device is enabled and one of the resources 553 1.50 jmcneill * is already in use (eg. firmware configured console device). 554 1.50 jmcneill */ 555 1.50 jmcneill base = pci_conf_read(pb->pc, tag, br); 556 1.50 jmcneill pci_conf_write(pb->pc, tag, br, 0xffffffff); 557 1.50 jmcneill mask = pci_conf_read(pb->pc, tag, br); 558 1.50 jmcneill pci_conf_write(pb->pc, tag, br, base); 559 1.50 jmcneill 560 1.50 jmcneill switch (PCI_MAPREG_TYPE(base)) { 561 1.50 jmcneill case PCI_MAPREG_TYPE_IO: 562 1.50 jmcneill addr = PCI_MAPREG_IO_ADDR(base); 563 1.50 jmcneill size = PCI_MAPREG_IO_SIZE(mask); 564 1.50 jmcneill return pci_resource_is_reserved(PCI_CONF_MAP_IO, addr, size); 565 1.50 jmcneill 566 1.50 jmcneill case PCI_MAPREG_TYPE_MEM: 567 1.50 jmcneill if (PCI_MAPREG_MEM_TYPE(base) == PCI_MAPREG_MEM_TYPE_64BIT) { 568 1.50 jmcneill base64 = pci_conf_read(pb->pc, tag, br + 4); 569 1.50 jmcneill pci_conf_write(pb->pc, tag, br + 4, 0xffffffff); 570 1.50 jmcneill mask64 = pci_conf_read(pb->pc, tag, br + 4); 571 1.50 jmcneill pci_conf_write(pb->pc, tag, br + 4, base64); 572 1.50 jmcneill addr = (uint64_t)PCI_MAPREG_MEM64_ADDR( 573 1.50 jmcneill (((uint64_t)base64) << 32) | base); 574 1.50 jmcneill size = (uint64_t)PCI_MAPREG_MEM64_SIZE( 575 1.50 jmcneill (((uint64_t)mask64) << 32) | mask); 576 1.50 jmcneill } else { 577 1.50 jmcneill addr = PCI_MAPREG_MEM_ADDR(base); 578 1.50 jmcneill size = PCI_MAPREG_MEM_SIZE(mask); 579 1.49 jmcneill } 580 1.50 jmcneill return pci_resource_is_reserved(PCI_CONF_MAP_MEM, addr, size); 581 1.50 jmcneill 582 1.50 jmcneill default: 583 1.50 jmcneill return NULL; 584 1.49 jmcneill } 585 1.49 jmcneill } 586 1.49 jmcneill 587 1.1 briggs static int 588 1.39 msaitoh pci_do_device_query(pciconf_bus_t *pb, pcitag_t tag, int dev, int func, 589 1.39 msaitoh int mode) 590 1.1 briggs { 591 1.1 briggs pciconf_dev_t *pd; 592 1.1 briggs pciconf_win_t *pi, *pm; 593 1.39 msaitoh pcireg_t classreg, cmd, icr, bhlc, bar, mask, bar64, mask64, 594 1.39 msaitoh busreg; 595 1.39 msaitoh uint64_t size; 596 1.22 briggs int br, width, reg_start, reg_end; 597 1.1 briggs 598 1.1 briggs pd = &pb->device[pb->ndevs]; 599 1.1 briggs pd->pc = pb->pc; 600 1.1 briggs pd->tag = tag; 601 1.1 briggs pd->ppb = NULL; 602 1.4 simonb pd->enable = mode; 603 1.51 skrll pd->ea_cap_ptr = 0; 604 1.1 briggs 605 1.37 matt classreg = pci_conf_read(pb->pc, tag, PCI_CLASS_REG); 606 1.1 briggs 607 1.1 briggs cmd = pci_conf_read(pb->pc, tag, PCI_COMMAND_STATUS_REG); 608 1.32 matt bhlc = pci_conf_read(pb->pc, tag, PCI_BHLC_REG); 609 1.1 briggs 610 1.51 skrll if (pci_get_capability(pb->pc, tag, PCI_CAP_EA, &pd->ea_cap_ptr, 611 1.51 skrll NULL)) { 612 1.51 skrll /* XXX Skip devices with EA for now. */ 613 1.51 skrll print_tag(pb->pc, tag); 614 1.51 skrll printf("skipping devices with Enhanced Allocations\n"); 615 1.51 skrll return 0; 616 1.51 skrll } 617 1.51 skrll 618 1.37 matt if (PCI_CLASS(classreg) != PCI_CLASS_BRIDGE 619 1.32 matt && PCI_HDRTYPE_TYPE(bhlc) != PCI_HDRTYPE_PPB) { 620 1.1 briggs cmd &= ~(PCI_COMMAND_MASTER_ENABLE | 621 1.1 briggs PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE); 622 1.1 briggs pci_conf_write(pb->pc, tag, PCI_COMMAND_STATUS_REG, cmd); 623 1.3 thorpej } else if (pci_conf_debug) { 624 1.3 thorpej print_tag(pb->pc, tag); 625 1.3 thorpej printf("device is a bridge; not clearing enables\n"); 626 1.1 briggs } 627 1.1 briggs 628 1.1 briggs if ((cmd & PCI_STATUS_BACKTOBACK_SUPPORT) == 0) 629 1.1 briggs pb->fast_b2b = 0; 630 1.1 briggs 631 1.1 briggs if ((cmd & PCI_STATUS_66MHZ_SUPPORT) == 0) 632 1.1 briggs pb->freq_66 = 0; 633 1.1 briggs 634 1.22 briggs switch (PCI_HDRTYPE_TYPE(bhlc)) { 635 1.22 briggs case PCI_HDRTYPE_DEVICE: 636 1.22 briggs reg_start = PCI_MAPREG_START; 637 1.22 briggs reg_end = PCI_MAPREG_END; 638 1.22 briggs break; 639 1.22 briggs case PCI_HDRTYPE_PPB: 640 1.1 briggs pd->ppb = query_bus(pb, pd, dev); 641 1.1 briggs if (pd->ppb == NULL) 642 1.1 briggs return -1; 643 1.1 briggs return 0; 644 1.22 briggs case PCI_HDRTYPE_PCB: 645 1.22 briggs reg_start = PCI_MAPREG_START; 646 1.22 briggs reg_end = PCI_MAPREG_PCB_END; 647 1.22 briggs 648 1.22 briggs busreg = pci_conf_read(pb->pc, tag, PCI_BUSNUM); 649 1.52 skrll busreg = (busreg & 0xff000000) | 650 1.41 msaitoh __SHIFTIN(pb->busno, PCI_BRIDGE_BUS_PRIMARY) | 651 1.41 msaitoh __SHIFTIN(pb->next_busno, PCI_BRIDGE_BUS_SECONDARY) | 652 1.41 msaitoh __SHIFTIN(pb->next_busno, PCI_BRIDGE_BUS_SUBORDINATE); 653 1.22 briggs pci_conf_write(pb->pc, tag, PCI_BUSNUM, busreg); 654 1.22 briggs 655 1.24 simonb pb->next_busno++; 656 1.22 briggs break; 657 1.22 briggs default: 658 1.22 briggs return -1; 659 1.1 briggs } 660 1.1 briggs 661 1.1 briggs icr = pci_conf_read(pb->pc, tag, PCI_INTERRUPT_REG); 662 1.1 briggs pd->ipin = PCI_INTERRUPT_PIN(icr); 663 1.1 briggs pd->iline = PCI_INTERRUPT_LINE(icr); 664 1.1 briggs pd->min_gnt = PCI_MIN_GNT(icr); 665 1.1 briggs pd->max_lat = PCI_MAX_LAT(icr); 666 1.1 briggs if (pd->iline || pd->ipin) { 667 1.8 briggs pci_conf_interrupt(pb->pc, pb->busno, dev, pd->ipin, pb->swiz, 668 1.1 briggs &pd->iline); 669 1.1 briggs icr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); 670 1.1 briggs icr |= (pd->iline << PCI_INTERRUPT_LINE_SHIFT); 671 1.1 briggs pci_conf_write(pb->pc, tag, PCI_INTERRUPT_REG, icr); 672 1.1 briggs } 673 1.1 briggs 674 1.1 briggs if (pd->min_gnt != 0 || pd->max_lat != 0) { 675 1.1 briggs if (pd->min_gnt != 0 && pd->min_gnt > pb->max_mingnt) 676 1.1 briggs pb->max_mingnt = pd->min_gnt; 677 1.1 briggs 678 1.1 briggs if (pd->max_lat != 0 && pd->max_lat < pb->min_maxlat) 679 1.1 briggs pb->min_maxlat = pd->max_lat; 680 1.1 briggs 681 1.1 briggs pb->bandwidth_used += pd->min_gnt * 4000000 / 682 1.1 briggs (pd->min_gnt + pd->max_lat); 683 1.1 briggs } 684 1.1 briggs 685 1.1 briggs width = 4; 686 1.22 briggs for (br = reg_start; br < reg_end; br += width) { 687 1.3 thorpej #if 0 688 1.8 briggs /* XXX Should only ignore if IDE not in legacy mode? */ 689 1.37 matt if (PCI_CLASS(classreg) == PCI_CLASS_MASS_STORAGE && 690 1.37 matt PCI_SUBCLASS(classreg) == PCI_SUBCLASS_MASS_STORAGE_IDE) { 691 1.1 briggs break; 692 1.1 briggs } 693 1.3 thorpej #endif 694 1.1 briggs bar = pci_conf_read(pb->pc, tag, br); 695 1.3 thorpej pci_conf_write(pb->pc, tag, br, 0xffffffff); 696 1.1 briggs mask = pci_conf_read(pb->pc, tag, br); 697 1.1 briggs pci_conf_write(pb->pc, tag, br, bar); 698 1.1 briggs width = 4; 699 1.1 briggs 700 1.8 briggs if ( (mode & PCI_CONF_MAP_IO) 701 1.8 briggs && (PCI_MAPREG_TYPE(mask) == PCI_MAPREG_TYPE_IO)) { 702 1.8 briggs /* 703 1.8 briggs * Upper 16 bits must be one. Devices may hardwire 704 1.8 briggs * them to zero, though, per PCI 2.2, 6.2.5.1, p 203. 705 1.8 briggs */ 706 1.3 thorpej mask |= 0xffff0000; 707 1.3 thorpej 708 1.3 thorpej size = PCI_MAPREG_IO_SIZE(mask); 709 1.3 thorpej if (size == 0) { 710 1.3 thorpej if (pci_conf_debug) { 711 1.3 thorpej print_tag(pb->pc, tag); 712 1.3 thorpej printf("I/O BAR 0x%x is void\n", br); 713 1.3 thorpej } 714 1.3 thorpej continue; 715 1.3 thorpej } 716 1.1 briggs 717 1.1 briggs if (pb->niowin >= MAX_CONF_IO) { 718 1.10 thorpej printf("pciconf: too many I/O windows\n"); 719 1.1 briggs return -1; 720 1.1 briggs } 721 1.1 briggs 722 1.1 briggs pi = get_io_desc(pb, size); 723 1.1 briggs pi->dev = pd; 724 1.1 briggs pi->reg = br; 725 1.43 msaitoh pi->size = (uint64_t)size; 726 1.1 briggs pi->align = 4; 727 1.36 matt if (pb->io_align < pi->size) 728 1.36 matt pb->io_align = pi->size; 729 1.1 briggs pi->prefetch = 0; 730 1.1 briggs if (pci_conf_debug) { 731 1.1 briggs print_tag(pb->pc, tag); 732 1.23 scw printf("Register 0x%x, I/O size %" PRIu64 "\n", 733 1.1 briggs br, pi->size); 734 1.1 briggs } 735 1.1 briggs pb->niowin++; 736 1.1 briggs pb->io_total += size; 737 1.4 simonb } else if ((mode & PCI_CONF_MAP_MEM) 738 1.4 simonb && (PCI_MAPREG_TYPE(mask) == PCI_MAPREG_TYPE_MEM)) { 739 1.1 briggs switch (PCI_MAPREG_MEM_TYPE(mask)) { 740 1.1 briggs case PCI_MAPREG_MEM_TYPE_32BIT: 741 1.1 briggs case PCI_MAPREG_MEM_TYPE_32BIT_1M: 742 1.43 msaitoh size = (uint64_t)PCI_MAPREG_MEM_SIZE(mask); 743 1.1 briggs break; 744 1.1 briggs case PCI_MAPREG_MEM_TYPE_64BIT: 745 1.1 briggs bar64 = pci_conf_read(pb->pc, tag, br + 4); 746 1.1 briggs pci_conf_write(pb->pc, tag, br + 4, 0xffffffff); 747 1.1 briggs mask64 = pci_conf_read(pb->pc, tag, br + 4); 748 1.1 briggs pci_conf_write(pb->pc, tag, br + 4, bar64); 749 1.43 msaitoh size = (uint64_t)PCI_MAPREG_MEM64_SIZE( 750 1.43 msaitoh (((uint64_t)mask64) << 32) | mask); 751 1.1 briggs width = 8; 752 1.16 briggs break; 753 1.1 briggs default: 754 1.1 briggs print_tag(pb->pc, tag); 755 1.1 briggs printf("reserved mapping type 0x%x\n", 756 1.1 briggs PCI_MAPREG_MEM_TYPE(mask)); 757 1.1 briggs continue; 758 1.1 briggs } 759 1.1 briggs 760 1.3 thorpej if (size == 0) { 761 1.3 thorpej if (pci_conf_debug) { 762 1.3 thorpej print_tag(pb->pc, tag); 763 1.3 thorpej printf("MEM%d BAR 0x%x is void\n", 764 1.3 thorpej PCI_MAPREG_MEM_TYPE(mask) == 765 1.3 thorpej PCI_MAPREG_MEM_TYPE_64BIT ? 766 1.3 thorpej 64 : 32, br); 767 1.3 thorpej } 768 1.3 thorpej continue; 769 1.16 briggs } else { 770 1.16 briggs if (pci_conf_debug) { 771 1.16 briggs print_tag(pb->pc, tag); 772 1.36 matt printf("MEM%d BAR 0x%x has size %#lx\n", 773 1.16 briggs PCI_MAPREG_MEM_TYPE(mask) == 774 1.16 briggs PCI_MAPREG_MEM_TYPE_64BIT ? 775 1.43 msaitoh 64 : 32, 776 1.43 msaitoh br, (unsigned long)size); 777 1.16 briggs } 778 1.3 thorpej } 779 1.3 thorpej 780 1.1 briggs if (pb->nmemwin >= MAX_CONF_MEM) { 781 1.10 thorpej printf("pciconf: too many memory windows\n"); 782 1.1 briggs return -1; 783 1.1 briggs } 784 1.1 briggs 785 1.1 briggs pm = get_mem_desc(pb, size); 786 1.1 briggs pm->dev = pd; 787 1.1 briggs pm->reg = br; 788 1.1 briggs pm->size = size; 789 1.1 briggs pm->align = 4; 790 1.1 briggs pm->prefetch = PCI_MAPREG_MEM_PREFETCHABLE(mask); 791 1.1 briggs if (pci_conf_debug) { 792 1.1 briggs print_tag(pb->pc, tag); 793 1.23 scw printf("Register 0x%x, memory size %" 794 1.23 scw PRIu64 "\n", br, pm->size); 795 1.1 briggs } 796 1.1 briggs pb->nmemwin++; 797 1.1 briggs if (pm->prefetch) { 798 1.1 briggs pb->pmem_total += size; 799 1.36 matt if (pb->pmem_align < pm->size) 800 1.36 matt pb->pmem_align = pm->size; 801 1.1 briggs } else { 802 1.1 briggs pb->mem_total += size; 803 1.36 matt if (pb->mem_align < pm->size) 804 1.36 matt pb->mem_align = pm->size; 805 1.1 briggs } 806 1.1 briggs } 807 1.1 briggs } 808 1.1 briggs 809 1.4 simonb if (mode & PCI_CONF_MAP_ROM) { 810 1.4 simonb bar = pci_conf_read(pb->pc, tag, PCI_MAPREG_ROM); 811 1.4 simonb pci_conf_write(pb->pc, tag, PCI_MAPREG_ROM, 0xfffffffe); 812 1.4 simonb mask = pci_conf_read(pb->pc, tag, PCI_MAPREG_ROM); 813 1.4 simonb pci_conf_write(pb->pc, tag, PCI_MAPREG_ROM, bar); 814 1.4 simonb 815 1.4 simonb if (mask != 0 && mask != 0xffffffff) { 816 1.4 simonb if (pb->nmemwin >= MAX_CONF_MEM) { 817 1.10 thorpej printf("pciconf: too many memory windows\n"); 818 1.4 simonb return -1; 819 1.4 simonb } 820 1.43 msaitoh size = (uint64_t)PCI_MAPREG_MEM_SIZE(mask); 821 1.1 briggs 822 1.4 simonb pm = get_mem_desc(pb, size); 823 1.4 simonb pm->dev = pd; 824 1.4 simonb pm->reg = PCI_MAPREG_ROM; 825 1.4 simonb pm->size = size; 826 1.4 simonb pm->align = 4; 827 1.44 thorpej pm->prefetch = 0; 828 1.4 simonb if (pci_conf_debug) { 829 1.4 simonb print_tag(pb->pc, tag); 830 1.23 scw printf("Expansion ROM memory size %" 831 1.23 scw PRIu64 "\n", pm->size); 832 1.4 simonb } 833 1.4 simonb pb->nmemwin++; 834 1.44 thorpej if (pm->prefetch) { 835 1.44 thorpej pb->pmem_total += size; 836 1.44 thorpej if (pb->pmem_align < pm->size) 837 1.44 thorpej pb->pmem_align = pm->size; 838 1.44 thorpej } else { 839 1.44 thorpej pb->mem_total += size; 840 1.44 thorpej if (pb->mem_align < pm->size) 841 1.44 thorpej pb->mem_align = pm->size; 842 1.44 thorpej } 843 1.1 briggs } 844 1.8 briggs } else { 845 1.28 gdamore /* Don't enable ROMs if we aren't going to map them. */ 846 1.28 gdamore mode &= ~PCI_CONF_ENABLE_ROM; 847 1.28 gdamore pd->enable &= ~PCI_CONF_ENABLE_ROM; 848 1.28 gdamore } 849 1.28 gdamore 850 1.28 gdamore if (!(mode & PCI_CONF_ENABLE_ROM)) { 851 1.8 briggs /* Ensure ROM is disabled */ 852 1.8 briggs bar = pci_conf_read(pb->pc, tag, PCI_MAPREG_ROM); 853 1.8 briggs pci_conf_write(pb->pc, tag, PCI_MAPREG_ROM, 854 1.8 briggs bar & ~PCI_MAPREG_ROM_ENABLE); 855 1.1 briggs } 856 1.1 briggs 857 1.1 briggs return 0; 858 1.1 briggs } 859 1.1 briggs 860 1.1 briggs /************************************************************************/ 861 1.1 briggs /************************************************************************/ 862 1.1 briggs /******************** Bus configuration routines ********************/ 863 1.1 briggs /************************************************************************/ 864 1.1 briggs /************************************************************************/ 865 1.39 msaitoh static uint64_t 866 1.47 thorpej pci_allocate_range(struct pciconf_resource * const r, const uint64_t amt, 867 1.44 thorpej const int align, const bool ok64 __used_only_lp64) 868 1.1 briggs { 869 1.47 thorpej vmem_size_t const size = (vmem_size_t) amt; 870 1.47 thorpej vmem_addr_t result; 871 1.47 thorpej int error; 872 1.44 thorpej 873 1.44 thorpej #ifdef _LP64 874 1.44 thorpej /* 875 1.44 thorpej * If a 64-bit range IS OK, then we prefer allocating above 4GB. 876 1.44 thorpej * 877 1.47 thorpej * XXX We guard this with _LP64 because vmem uses uintptr_t 878 1.44 thorpej * internally. 879 1.44 thorpej */ 880 1.44 thorpej if (!ok64) { 881 1.47 thorpej error = vmem_xalloc(r->arena, size, align, 0, 0, 882 1.47 thorpej VMEM_ADDR_MIN, 0xffffffffUL, 883 1.47 thorpej VM_BESTFIT | VM_NOSLEEP, 884 1.47 thorpej &result); 885 1.47 thorpej } else { 886 1.47 thorpej error = vmem_xalloc(r->arena, size, align, 0, 0, 887 1.47 thorpej (1UL << 32), VMEM_ADDR_MAX, 888 1.47 thorpej VM_BESTFIT | VM_NOSLEEP, 889 1.47 thorpej &result); 890 1.47 thorpej if (error) { 891 1.47 thorpej error = vmem_xalloc(r->arena, size, align, 0, 0, 892 1.47 thorpej VMEM_ADDR_MIN, VMEM_ADDR_MAX, 893 1.47 thorpej VM_BESTFIT | VM_NOSLEEP, 894 1.47 thorpej &result); 895 1.44 thorpej } 896 1.44 thorpej } 897 1.47 thorpej #else 898 1.47 thorpej error = vmem_xalloc(r->arena, size, align, 0, 0, 899 1.47 thorpej VMEM_ADDR_MIN, 0xffffffffUL, 900 1.47 thorpej VM_BESTFIT | VM_NOSLEEP, 901 1.47 thorpej &result); 902 1.44 thorpej #endif /* _L64 */ 903 1.44 thorpej 904 1.47 thorpej if (error) 905 1.36 matt return ~0ULL; 906 1.47 thorpej 907 1.47 thorpej return result; 908 1.1 briggs } 909 1.1 briggs 910 1.1 briggs static int 911 1.1 briggs setup_iowins(pciconf_bus_t *pb) 912 1.1 briggs { 913 1.1 briggs pciconf_win_t *pi; 914 1.1 briggs pciconf_dev_t *pd; 915 1.50 jmcneill struct pciconf_resource_rsvd *rsvd; 916 1.50 jmcneill int error; 917 1.1 briggs 918 1.40 msaitoh for (pi = pb->pciiowin; pi < &pb->pciiowin[pb->niowin]; pi++) { 919 1.1 briggs if (pi->size == 0) 920 1.1 briggs continue; 921 1.1 briggs 922 1.1 briggs pd = pi->dev; 923 1.50 jmcneill rsvd = pci_bar_is_reserved(pb, pd, pi->reg); 924 1.50 jmcneill 925 1.47 thorpej if (pb->io_res.arena == NULL) { 926 1.46 jmcneill /* Bus has no IO ranges, disable IO BAR */ 927 1.46 jmcneill pi->address = 0; 928 1.46 jmcneill pd->enable &= ~PCI_CONF_ENABLE_IO; 929 1.46 jmcneill goto write_ioaddr; 930 1.46 jmcneill } 931 1.50 jmcneill 932 1.47 thorpej pi->address = pci_allocate_range(&pb->io_res, pi->size, 933 1.44 thorpej pi->align, false); 934 1.36 matt if (~pi->address == 0) { 935 1.1 briggs print_tag(pd->pc, pd->tag); 936 1.23 scw printf("Failed to allocate PCI I/O space (%" 937 1.23 scw PRIu64 " req)\n", pi->size); 938 1.1 briggs return -1; 939 1.1 briggs } 940 1.1 briggs if (pd->ppb && pi->reg == 0) { 941 1.47 thorpej error = init_range_resource(&pd->ppb->io_res, 942 1.47 thorpej "ppb-io", pi->address, pi->size); 943 1.47 thorpej if (error) { 944 1.1 briggs print_tag(pd->pc, pd->tag); 945 1.47 thorpej printf("Failed to alloc I/O arena for bus %d\n", 946 1.1 briggs pd->ppb->busno); 947 1.1 briggs return -1; 948 1.1 briggs } 949 1.1 briggs continue; 950 1.1 briggs } 951 1.26 tsutsui if (!pb->io_32bit && pi->address > 0xFFFF) { 952 1.26 tsutsui pi->address = 0; 953 1.26 tsutsui pd->enable &= ~PCI_CONF_ENABLE_IO; 954 1.26 tsutsui } else { 955 1.26 tsutsui pd->enable |= PCI_CONF_ENABLE_IO; 956 1.26 tsutsui } 957 1.46 jmcneill write_ioaddr: 958 1.1 briggs if (pci_conf_debug) { 959 1.1 briggs print_tag(pd->pc, pd->tag); 960 1.23 scw printf("Putting %" PRIu64 " I/O bytes @ %#" PRIx64 961 1.23 scw " (reg %x)\n", pi->size, pi->address, pi->reg); 962 1.1 briggs } 963 1.1 briggs pci_conf_write(pd->pc, pd->tag, pi->reg, 964 1.1 briggs PCI_MAPREG_IO_ADDR(pi->address) | PCI_MAPREG_TYPE_IO); 965 1.50 jmcneill 966 1.50 jmcneill if (rsvd != NULL && rsvd->start != pi->address) 967 1.50 jmcneill rsvd->callback(rsvd->callback_arg, pi->address); 968 1.1 briggs } 969 1.1 briggs return 0; 970 1.1 briggs } 971 1.1 briggs 972 1.1 briggs static int 973 1.1 briggs setup_memwins(pciconf_bus_t *pb) 974 1.1 briggs { 975 1.1 briggs pciconf_win_t *pm; 976 1.1 briggs pciconf_dev_t *pd; 977 1.1 briggs pcireg_t base; 978 1.47 thorpej struct pciconf_resource *r; 979 1.50 jmcneill struct pciconf_resource_rsvd *rsvd; 980 1.44 thorpej bool ok64; 981 1.47 thorpej int error; 982 1.1 briggs 983 1.40 msaitoh for (pm = pb->pcimemwin; pm < &pb->pcimemwin[pb->nmemwin]; pm++) { 984 1.1 briggs if (pm->size == 0) 985 1.1 briggs continue; 986 1.1 briggs 987 1.44 thorpej ok64 = false; 988 1.1 briggs pd = pm->dev; 989 1.50 jmcneill rsvd = pci_bar_is_reserved(pb, pd, pm->reg); 990 1.50 jmcneill 991 1.44 thorpej if (pm->prefetch) { 992 1.47 thorpej r = &pb->pmem_res; 993 1.44 thorpej ok64 = pb->pmem_64bit; 994 1.44 thorpej } else { 995 1.47 thorpej r = &pb->mem_res; 996 1.44 thorpej ok64 = pb->mem_64bit && pd->ppb == NULL; 997 1.44 thorpej } 998 1.44 thorpej 999 1.44 thorpej /* 1000 1.44 thorpej * We need to figure out if the memory BAR is 64-bit 1001 1.44 thorpej * capable or not. If it's not, then we need to constrain 1002 1.44 thorpej * the address allocation. 1003 1.44 thorpej */ 1004 1.44 thorpej if (pm->reg == PCI_MAPREG_ROM) { 1005 1.44 thorpej ok64 = false; 1006 1.44 thorpej } else if (ok64) { 1007 1.44 thorpej base = pci_conf_read(pd->pc, pd->tag, pm->reg); 1008 1.44 thorpej ok64 = PCI_MAPREG_MEM_TYPE(base) == 1009 1.44 thorpej PCI_MAPREG_MEM_TYPE_64BIT; 1010 1.44 thorpej } 1011 1.44 thorpej 1012 1.47 thorpej pm->address = pci_allocate_range(r, pm->size, pm->align, 1013 1.44 thorpej ok64); 1014 1.53 jmcneill if (~pm->address == 0 && r == &pb->pmem_res) { 1015 1.53 jmcneill r = &pb->mem_res; 1016 1.53 jmcneill pm->address = pci_allocate_range(r, pm->size, 1017 1.53 jmcneill pm->align, ok64); 1018 1.53 jmcneill } 1019 1.36 matt if (~pm->address == 0) { 1020 1.1 briggs print_tag(pd->pc, pd->tag); 1021 1.1 briggs printf( 1022 1.23 scw "Failed to allocate PCI memory space (%" PRIu64 1023 1.44 thorpej " req, prefetch=%d ok64=%d)\n", pm->size, 1024 1.44 thorpej pm->prefetch, (int)ok64); 1025 1.1 briggs return -1; 1026 1.1 briggs } 1027 1.1 briggs if (pd->ppb && pm->reg == 0) { 1028 1.47 thorpej const char *name = pm->prefetch ? "ppb-pmem" 1029 1.47 thorpej : "ppb-mem"; 1030 1.47 thorpej r = pm->prefetch ? &pd->ppb->pmem_res 1031 1.47 thorpej : &pd->ppb->mem_res; 1032 1.47 thorpej error = init_range_resource(r, name, 1033 1.47 thorpej pm->address, pm->size); 1034 1.47 thorpej if (error) { 1035 1.1 briggs print_tag(pd->pc, pd->tag); 1036 1.47 thorpej printf("Failed to alloc MEM arena for bus %d\n", 1037 1.1 briggs pd->ppb->busno); 1038 1.1 briggs return -1; 1039 1.1 briggs } 1040 1.1 briggs continue; 1041 1.1 briggs } 1042 1.44 thorpej if (!ok64 && pm->address > 0xFFFFFFFFULL) { 1043 1.2 briggs pm->address = 0; 1044 1.26 tsutsui pd->enable &= ~PCI_CONF_ENABLE_MEM; 1045 1.39 msaitoh } else 1046 1.8 briggs pd->enable |= PCI_CONF_ENABLE_MEM; 1047 1.39 msaitoh 1048 1.1 briggs if (pm->reg != PCI_MAPREG_ROM) { 1049 1.1 briggs if (pci_conf_debug) { 1050 1.1 briggs print_tag(pd->pc, pd->tag); 1051 1.1 briggs printf( 1052 1.23 scw "Putting %" PRIu64 " MEM bytes @ %#" 1053 1.23 scw PRIx64 " (reg %x)\n", pm->size, 1054 1.23 scw pm->address, pm->reg); 1055 1.1 briggs } 1056 1.1 briggs base = pci_conf_read(pd->pc, pd->tag, pm->reg); 1057 1.1 briggs base = PCI_MAPREG_MEM_ADDR(pm->address) | 1058 1.1 briggs PCI_MAPREG_MEM_TYPE(base); 1059 1.1 briggs pci_conf_write(pd->pc, pd->tag, pm->reg, base); 1060 1.1 briggs if (PCI_MAPREG_MEM_TYPE(base) == 1061 1.1 briggs PCI_MAPREG_MEM_TYPE_64BIT) { 1062 1.1 briggs base = (pcireg_t) 1063 1.1 briggs (PCI_MAPREG_MEM64_ADDR(pm->address) >> 32); 1064 1.1 briggs pci_conf_write(pd->pc, pd->tag, pm->reg + 4, 1065 1.1 briggs base); 1066 1.1 briggs } 1067 1.1 briggs } 1068 1.50 jmcneill 1069 1.50 jmcneill if (rsvd != NULL && rsvd->start != pm->address) { 1070 1.54 jmcneill /* 1071 1.54 jmcneill * Resource allocation will never reuse a reserved 1072 1.54 jmcneill * address. Check to see if the BAR is still reserved 1073 1.54 jmcneill * to cover the case where the new resource was not 1074 1.54 jmcneill * applied. In this case, there is no need to notify 1075 1.54 jmcneill * the device callback of a change. 1076 1.54 jmcneill */ 1077 1.54 jmcneill if (!pci_bar_is_reserved(pb, pd, pm->reg)) { 1078 1.54 jmcneill rsvd->callback(rsvd->callback_arg, pm->address); 1079 1.54 jmcneill } 1080 1.50 jmcneill } 1081 1.1 briggs } 1082 1.40 msaitoh for (pm = pb->pcimemwin; pm < &pb->pcimemwin[pb->nmemwin]; pm++) { 1083 1.1 briggs if (pm->reg == PCI_MAPREG_ROM && pm->address != -1) { 1084 1.1 briggs pd = pm->dev; 1085 1.29 gdamore if (!(pd->enable & PCI_CONF_MAP_ROM)) 1086 1.28 gdamore continue; 1087 1.1 briggs if (pci_conf_debug) { 1088 1.1 briggs print_tag(pd->pc, pd->tag); 1089 1.1 briggs printf( 1090 1.23 scw "Putting %" PRIu64 " ROM bytes @ %#" 1091 1.23 scw PRIx64 " (reg %x)\n", pm->size, 1092 1.23 scw pm->address, pm->reg); 1093 1.1 briggs } 1094 1.29 gdamore base = (pcireg_t) pm->address; 1095 1.29 gdamore if (pd->enable & PCI_CONF_ENABLE_ROM) 1096 1.29 gdamore base |= PCI_MAPREG_ROM_ENABLE; 1097 1.29 gdamore 1098 1.1 briggs pci_conf_write(pd->pc, pd->tag, pm->reg, base); 1099 1.1 briggs } 1100 1.1 briggs } 1101 1.1 briggs return 0; 1102 1.1 briggs } 1103 1.1 briggs 1104 1.44 thorpej static bool 1105 1.47 thorpej constrain_bridge_mem_range(struct pciconf_resource * const r, 1106 1.44 thorpej u_long * const base, 1107 1.44 thorpej u_long * const limit, 1108 1.44 thorpej const bool ok64 __used_only_lp64) 1109 1.44 thorpej { 1110 1.44 thorpej 1111 1.47 thorpej *base = r->min_addr; 1112 1.47 thorpej *limit = r->max_addr; 1113 1.44 thorpej 1114 1.44 thorpej #ifdef _LP64 1115 1.44 thorpej if (!ok64) { 1116 1.47 thorpej if (r->min_addr >= (1UL << 32)) { 1117 1.44 thorpej return true; 1118 1.44 thorpej } 1119 1.47 thorpej if (r->max_addr > 0xffffffffUL) { 1120 1.44 thorpej *limit = 0xffffffffUL; 1121 1.44 thorpej } 1122 1.44 thorpej } 1123 1.44 thorpej #endif /* _LP64 */ 1124 1.44 thorpej 1125 1.44 thorpej return false; 1126 1.44 thorpej } 1127 1.44 thorpej 1128 1.1 briggs /* 1129 1.1 briggs * Configure I/O, memory, and prefetcable memory spaces, then make 1130 1.1 briggs * a call to configure_bus(). 1131 1.1 briggs */ 1132 1.1 briggs static int 1133 1.1 briggs configure_bridge(pciconf_dev_t *pd) 1134 1.1 briggs { 1135 1.1 briggs unsigned long io_base, io_limit, mem_base, mem_limit; 1136 1.1 briggs pciconf_bus_t *pb; 1137 1.1 briggs pcireg_t io, iohigh, mem, cmd; 1138 1.1 briggs int rv; 1139 1.38 msaitoh bool isprefetchmem64; 1140 1.44 thorpej bool bad_range; 1141 1.1 briggs 1142 1.1 briggs pb = pd->ppb; 1143 1.1 briggs /* Configure I/O base & limit*/ 1144 1.47 thorpej if (pb->io_res.arena) { 1145 1.47 thorpej io_base = pb->io_res.min_addr; 1146 1.47 thorpej io_limit = pb->io_res.max_addr; 1147 1.2 briggs } else { 1148 1.2 briggs io_base = 0x1000; /* 4K */ 1149 1.2 briggs io_limit = 0x0000; 1150 1.1 briggs } 1151 1.2 briggs if (pb->io_32bit) { 1152 1.41 msaitoh iohigh = __SHIFTIN(io_base >> 16, PCI_BRIDGE_IOHIGH_BASE) | 1153 1.41 msaitoh __SHIFTIN(io_limit >> 16, PCI_BRIDGE_IOHIGH_LIMIT); 1154 1.2 briggs } else { 1155 1.2 briggs if (io_limit > 0xFFFF) { 1156 1.2 briggs printf("Bus %d bridge does not support 32-bit I/O. ", 1157 1.2 briggs pb->busno); 1158 1.2 briggs printf("Disabling I/O accesses\n"); 1159 1.2 briggs io_base = 0x1000; /* 4K */ 1160 1.2 briggs io_limit = 0x0000; 1161 1.2 briggs } 1162 1.2 briggs iohigh = 0; 1163 1.2 briggs } 1164 1.9 briggs io = pci_conf_read(pb->pc, pd->tag, PCI_BRIDGE_STATIO_REG) & 1165 1.41 msaitoh PCI_BRIDGE_STATIO_STATUS; 1166 1.41 msaitoh io |= __SHIFTIN((io_base >> 8) & PCI_BRIDGE_STATIO_IOADDR, 1167 1.41 msaitoh PCI_BRIDGE_STATIO_IOBASE); 1168 1.41 msaitoh io |= __SHIFTIN((io_limit >> 8) & PCI_BRIDGE_STATIO_IOADDR, 1169 1.41 msaitoh PCI_BRIDGE_STATIO_IOLIMIT); 1170 1.2 briggs pci_conf_write(pb->pc, pd->tag, PCI_BRIDGE_STATIO_REG, io); 1171 1.2 briggs pci_conf_write(pb->pc, pd->tag, PCI_BRIDGE_IOHIGH_REG, iohigh); 1172 1.1 briggs 1173 1.1 briggs /* Configure mem base & limit */ 1174 1.44 thorpej bad_range = false; 1175 1.47 thorpej if (pb->mem_res.arena) { 1176 1.47 thorpej bad_range = constrain_bridge_mem_range(&pb->mem_res, 1177 1.44 thorpej &mem_base, 1178 1.44 thorpej &mem_limit, 1179 1.44 thorpej false); 1180 1.2 briggs } else { 1181 1.2 briggs mem_base = 0x100000; /* 1M */ 1182 1.2 briggs mem_limit = 0x000000; 1183 1.1 briggs } 1184 1.44 thorpej if (bad_range) { 1185 1.2 briggs printf("Bus %d bridge MEM range out of range. ", pb->busno); 1186 1.2 briggs printf("Disabling MEM accesses\n"); 1187 1.2 briggs mem_base = 0x100000; /* 1M */ 1188 1.2 briggs mem_limit = 0x000000; 1189 1.2 briggs } 1190 1.41 msaitoh mem = __SHIFTIN((mem_base >> 16) & PCI_BRIDGE_MEMORY_ADDR, 1191 1.41 msaitoh PCI_BRIDGE_MEMORY_BASE); 1192 1.41 msaitoh mem |= __SHIFTIN((mem_limit >> 16) & PCI_BRIDGE_MEMORY_ADDR, 1193 1.41 msaitoh PCI_BRIDGE_MEMORY_LIMIT); 1194 1.2 briggs pci_conf_write(pb->pc, pd->tag, PCI_BRIDGE_MEMORY_REG, mem); 1195 1.1 briggs 1196 1.1 briggs /* Configure prefetchable mem base & limit */ 1197 1.44 thorpej mem = pci_conf_read(pb->pc, pd->tag, PCI_BRIDGE_PREFETCHMEM_REG); 1198 1.44 thorpej isprefetchmem64 = PCI_BRIDGE_PREFETCHMEM_64BITS(mem); 1199 1.44 thorpej bad_range = false; 1200 1.47 thorpej if (pb->pmem_res.arena) { 1201 1.47 thorpej bad_range = constrain_bridge_mem_range(&pb->pmem_res, 1202 1.44 thorpej &mem_base, 1203 1.44 thorpej &mem_limit, 1204 1.44 thorpej isprefetchmem64); 1205 1.2 briggs } else { 1206 1.2 briggs mem_base = 0x100000; /* 1M */ 1207 1.2 briggs mem_limit = 0x000000; 1208 1.1 briggs } 1209 1.44 thorpej if (bad_range) { 1210 1.2 briggs printf("Bus %d bridge does not support 64-bit PMEM. ", 1211 1.2 briggs pb->busno); 1212 1.2 briggs printf("Disabling prefetchable-MEM accesses\n"); 1213 1.2 briggs mem_base = 0x100000; /* 1M */ 1214 1.2 briggs mem_limit = 0x000000; 1215 1.2 briggs } 1216 1.41 msaitoh mem = __SHIFTIN((mem_base >> 16) & PCI_BRIDGE_PREFETCHMEM_ADDR, 1217 1.41 msaitoh PCI_BRIDGE_PREFETCHMEM_BASE); 1218 1.41 msaitoh mem |= __SHIFTIN((mem_limit >> 16) & PCI_BRIDGE_PREFETCHMEM_ADDR, 1219 1.41 msaitoh PCI_BRIDGE_PREFETCHMEM_LIMIT); 1220 1.2 briggs pci_conf_write(pb->pc, pd->tag, PCI_BRIDGE_PREFETCHMEM_REG, mem); 1221 1.2 briggs /* 1222 1.2 briggs * XXX -- 64-bit systems need a lot more than just this... 1223 1.2 briggs */ 1224 1.38 msaitoh if (isprefetchmem64) { 1225 1.39 msaitoh mem_base = (uint64_t)mem_base >> 32; 1226 1.39 msaitoh mem_limit = (uint64_t)mem_limit >> 32; 1227 1.41 msaitoh pci_conf_write(pb->pc, pd->tag, 1228 1.41 msaitoh PCI_BRIDGE_PREFETCHBASEUP32_REG, mem_base & 0xffffffff); 1229 1.41 msaitoh pci_conf_write(pb->pc, pd->tag, 1230 1.41 msaitoh PCI_BRIDGE_PREFETCHLIMITUP32_REG, mem_limit & 0xffffffff); 1231 1.32 matt } 1232 1.1 briggs 1233 1.1 briggs rv = configure_bus(pb); 1234 1.1 briggs 1235 1.47 thorpej fini_range_resource(&pb->io_res); 1236 1.47 thorpej fini_range_resource(&pb->mem_res); 1237 1.47 thorpej fini_range_resource(&pb->pmem_res); 1238 1.47 thorpej 1239 1.1 briggs if (rv == 0) { 1240 1.1 briggs cmd = pci_conf_read(pd->pc, pd->tag, PCI_BRIDGE_CONTROL_REG); 1241 1.41 msaitoh cmd &= ~PCI_BRIDGE_CONTROL; /* Clear control bit first */ 1242 1.41 msaitoh cmd |= PCI_BRIDGE_CONTROL_PERE | PCI_BRIDGE_CONTROL_SERR; 1243 1.41 msaitoh if (pb->fast_b2b) 1244 1.41 msaitoh cmd |= PCI_BRIDGE_CONTROL_SECFASTB2B; 1245 1.41 msaitoh 1246 1.1 briggs pci_conf_write(pd->pc, pd->tag, PCI_BRIDGE_CONTROL_REG, cmd); 1247 1.1 briggs cmd = pci_conf_read(pd->pc, pd->tag, PCI_COMMAND_STATUS_REG); 1248 1.1 briggs cmd |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE; 1249 1.1 briggs pci_conf_write(pd->pc, pd->tag, PCI_COMMAND_STATUS_REG, cmd); 1250 1.1 briggs } 1251 1.1 briggs 1252 1.1 briggs return rv; 1253 1.1 briggs } 1254 1.1 briggs 1255 1.1 briggs /* 1256 1.1 briggs * Calculate latency values, allocate I/O and MEM segments, then set them 1257 1.1 briggs * up. If a PCI-PCI bridge is found, configure the bridge separately, 1258 1.1 briggs * which will cause a recursive call back here. 1259 1.1 briggs */ 1260 1.1 briggs static int 1261 1.1 briggs configure_bus(pciconf_bus_t *pb) 1262 1.1 briggs { 1263 1.1 briggs pciconf_dev_t *pd; 1264 1.8 briggs int def_ltim, max_ltim, band, bus_mhz; 1265 1.1 briggs 1266 1.20 simonb if (pb->ndevs == 0) { 1267 1.20 simonb if (pci_conf_debug) 1268 1.20 simonb printf("PCI bus %d - no devices\n", pb->busno); 1269 1.39 msaitoh return 1; 1270 1.20 simonb } 1271 1.8 briggs bus_mhz = pb->freq_66 ? 66 : 33; 1272 1.8 briggs max_ltim = pb->max_mingnt * bus_mhz / 4; /* cvt to cycle count */ 1273 1.30 briggs band = 4000000; /* 0.25us cycles/sec */ 1274 1.1 briggs if (band < pb->bandwidth_used) { 1275 1.31 gavan printf("PCI bus %d: Warning: Total bandwidth exceeded!? (%d)\n", 1276 1.31 gavan pb->busno, pb->bandwidth_used); 1277 1.1 briggs def_ltim = -1; 1278 1.1 briggs } else { 1279 1.1 briggs def_ltim = (band - pb->bandwidth_used) / pb->ndevs; 1280 1.1 briggs if (def_ltim > pb->min_maxlat) 1281 1.1 briggs def_ltim = pb->min_maxlat; 1282 1.8 briggs def_ltim = def_ltim * bus_mhz / 4; 1283 1.1 briggs } 1284 1.1 briggs def_ltim = (def_ltim + 7) & ~7; 1285 1.1 briggs max_ltim = (max_ltim + 7) & ~7; 1286 1.1 briggs 1287 1.43 msaitoh pb->def_ltim = MIN(def_ltim, 255); 1288 1.43 msaitoh pb->max_ltim = MIN(MAX(max_ltim, def_ltim), 255); 1289 1.1 briggs 1290 1.1 briggs /* 1291 1.1 briggs * Now we have what we need to initialize the devices. 1292 1.1 briggs * It would probably be better if we could allocate all of these 1293 1.1 briggs * for all busses at once, but "not right now". First, get a list 1294 1.1 briggs * of free memory ranges from the m.d. system. 1295 1.1 briggs */ 1296 1.1 briggs if (setup_iowins(pb) || setup_memwins(pb)) { 1297 1.36 matt printf("PCI bus configuration failed: " 1298 1.36 matt "unable to assign all I/O and memory ranges.\n"); 1299 1.1 briggs return -1; 1300 1.1 briggs } 1301 1.1 briggs 1302 1.1 briggs /* 1303 1.1 briggs * Configure the latency for the devices, and enable them. 1304 1.1 briggs */ 1305 1.40 msaitoh for (pd = pb->device; pd < &pb->device[pb->ndevs]; pd++) { 1306 1.37 matt pcireg_t cmd, classreg, misc; 1307 1.1 briggs int ltim; 1308 1.1 briggs 1309 1.1 briggs if (pci_conf_debug) { 1310 1.1 briggs print_tag(pd->pc, pd->tag); 1311 1.1 briggs printf("Configuring device.\n"); 1312 1.1 briggs } 1313 1.37 matt classreg = pci_conf_read(pd->pc, pd->tag, PCI_CLASS_REG); 1314 1.1 briggs misc = pci_conf_read(pd->pc, pd->tag, PCI_BHLC_REG); 1315 1.1 briggs cmd = pci_conf_read(pd->pc, pd->tag, PCI_COMMAND_STATUS_REG); 1316 1.26 tsutsui if (pd->enable & PCI_CONF_ENABLE_PARITY) 1317 1.26 tsutsui cmd |= PCI_COMMAND_PARITY_ENABLE; 1318 1.26 tsutsui if (pd->enable & PCI_CONF_ENABLE_SERR) 1319 1.26 tsutsui cmd |= PCI_COMMAND_SERR_ENABLE; 1320 1.1 briggs if (pb->fast_b2b) 1321 1.1 briggs cmd |= PCI_COMMAND_BACKTOBACK_ENABLE; 1322 1.37 matt if (PCI_CLASS(classreg) != PCI_CLASS_BRIDGE || 1323 1.37 matt PCI_SUBCLASS(classreg) != PCI_SUBCLASS_BRIDGE_PCI) { 1324 1.8 briggs if (pd->enable & PCI_CONF_ENABLE_IO) 1325 1.8 briggs cmd |= PCI_COMMAND_IO_ENABLE; 1326 1.8 briggs if (pd->enable & PCI_CONF_ENABLE_MEM) 1327 1.8 briggs cmd |= PCI_COMMAND_MEM_ENABLE; 1328 1.8 briggs if (pd->enable & PCI_CONF_ENABLE_BM) 1329 1.8 briggs cmd |= PCI_COMMAND_MASTER_ENABLE; 1330 1.8 briggs ltim = pd->min_gnt * bus_mhz / 4; 1331 1.1 briggs ltim = MIN (MAX (pb->def_ltim, ltim), pb->max_ltim); 1332 1.1 briggs } else { 1333 1.8 briggs cmd |= PCI_COMMAND_MASTER_ENABLE; 1334 1.1 briggs ltim = MIN (pb->def_ltim, pb->max_ltim); 1335 1.1 briggs } 1336 1.26 tsutsui if ((pd->enable & 1337 1.43 msaitoh (PCI_CONF_ENABLE_MEM | PCI_CONF_ENABLE_IO)) == 0) { 1338 1.2 briggs print_tag(pd->pc, pd->tag); 1339 1.2 briggs printf("Disabled due to lack of resources.\n"); 1340 1.2 briggs cmd &= ~(PCI_COMMAND_MASTER_ENABLE | 1341 1.2 briggs PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE); 1342 1.2 briggs } 1343 1.1 briggs pci_conf_write(pd->pc, pd->tag, PCI_COMMAND_STATUS_REG, cmd); 1344 1.1 briggs 1345 1.14 thorpej misc &= ~((PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT) | 1346 1.14 thorpej (PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT)); 1347 1.14 thorpej misc |= (ltim & PCI_LATTIMER_MASK) << PCI_LATTIMER_SHIFT; 1348 1.15 kleink misc |= ((pb->cacheline_size >> 2) & PCI_CACHELINE_MASK) << 1349 1.14 thorpej PCI_CACHELINE_SHIFT; 1350 1.1 briggs pci_conf_write(pd->pc, pd->tag, PCI_BHLC_REG, misc); 1351 1.1 briggs 1352 1.1 briggs if (pd->ppb) { 1353 1.1 briggs if (configure_bridge(pd) < 0) 1354 1.1 briggs return -1; 1355 1.1 briggs continue; 1356 1.1 briggs } 1357 1.1 briggs } 1358 1.1 briggs 1359 1.39 msaitoh if (pci_conf_debug) 1360 1.1 briggs printf("PCI bus %d configured\n", pb->busno); 1361 1.1 briggs 1362 1.1 briggs return 0; 1363 1.1 briggs } 1364 1.1 briggs 1365 1.44 thorpej static bool 1366 1.47 thorpej mem_region_ok64(struct pciconf_resource * const r __used_only_lp64) 1367 1.44 thorpej { 1368 1.44 thorpej bool rv = false; 1369 1.44 thorpej 1370 1.44 thorpej #ifdef _LP64 1371 1.44 thorpej /* 1372 1.47 thorpej * XXX We need to guard this with _LP64 because vmem uses 1373 1.47 thorpej * uintptr_t internally. 1374 1.44 thorpej */ 1375 1.47 thorpej vmem_size_t result; 1376 1.47 thorpej if (vmem_xalloc(r->arena, 1/*size*/, 1/*align*/, 0/*phase*/, 1377 1.47 thorpej 0/*nocross*/, (1UL << 32), VMEM_ADDR_MAX, 1378 1.47 thorpej VM_INSTANTFIT | VM_NOSLEEP, &result) == 0) { 1379 1.47 thorpej vmem_free(r->arena, result, 1); 1380 1.44 thorpej rv = true; 1381 1.44 thorpej } 1382 1.44 thorpej #endif /* _LP64 */ 1383 1.44 thorpej 1384 1.44 thorpej return rv; 1385 1.44 thorpej } 1386 1.44 thorpej 1387 1.1 briggs /* 1388 1.47 thorpej * pciconf_resource_init: 1389 1.47 thorpej * 1390 1.47 thorpej * Allocate and initilize a pci configuration resources container. 1391 1.47 thorpej */ 1392 1.47 thorpej struct pciconf_resources * 1393 1.47 thorpej pciconf_resource_init(void) 1394 1.47 thorpej { 1395 1.47 thorpej struct pciconf_resources *rs; 1396 1.47 thorpej 1397 1.47 thorpej rs = kmem_zalloc(sizeof(*rs), KM_SLEEP); 1398 1.47 thorpej 1399 1.47 thorpej return (rs); 1400 1.47 thorpej } 1401 1.47 thorpej 1402 1.47 thorpej /* 1403 1.47 thorpej * pciconf_resource_fini: 1404 1.47 thorpej * 1405 1.47 thorpej * Dispose of a pci configuration resources container. 1406 1.47 thorpej */ 1407 1.47 thorpej void 1408 1.47 thorpej pciconf_resource_fini(struct pciconf_resources *rs) 1409 1.47 thorpej { 1410 1.47 thorpej int i; 1411 1.47 thorpej 1412 1.47 thorpej for (i = 0; i < PCICONF_RESOURCE_NTYPES; i++) { 1413 1.47 thorpej fini_range_resource(&rs->resources[i]); 1414 1.47 thorpej } 1415 1.47 thorpej 1416 1.47 thorpej kmem_free(rs, sizeof(*rs)); 1417 1.47 thorpej } 1418 1.47 thorpej 1419 1.47 thorpej /* 1420 1.47 thorpej * pciconf_resource_add: 1421 1.47 thorpej * 1422 1.47 thorpej * Add a pci configuration resource to a container. 1423 1.47 thorpej */ 1424 1.47 thorpej int 1425 1.47 thorpej pciconf_resource_add(struct pciconf_resources *rs, int type, 1426 1.47 thorpej bus_addr_t start, bus_size_t size) 1427 1.47 thorpej { 1428 1.47 thorpej bus_addr_t end = start + (size - 1); 1429 1.47 thorpej struct pciconf_resource *r; 1430 1.49 jmcneill struct pciconf_resource_rsvd *rsvd; 1431 1.49 jmcneill int error, rsvd_type, align; 1432 1.49 jmcneill vmem_addr_t result; 1433 1.47 thorpej bool first; 1434 1.47 thorpej 1435 1.47 thorpej if (size == 0 || end <= start) 1436 1.47 thorpej return EINVAL; 1437 1.47 thorpej 1438 1.47 thorpej if (type < 0 || type >= PCICONF_RESOURCE_NTYPES) 1439 1.47 thorpej return EINVAL; 1440 1.47 thorpej 1441 1.47 thorpej r = &rs->resources[type]; 1442 1.47 thorpej 1443 1.47 thorpej first = r->arena == NULL; 1444 1.47 thorpej if (first) { 1445 1.47 thorpej r->arena = create_vmem_arena(pciconf_resource_names[type], 1446 1.47 thorpej 0, 0, VM_SLEEP); 1447 1.47 thorpej r->min_addr = VMEM_ADDR_MAX; 1448 1.47 thorpej r->max_addr = VMEM_ADDR_MIN; 1449 1.47 thorpej } 1450 1.47 thorpej 1451 1.47 thorpej error = vmem_add(r->arena, start, size, VM_SLEEP); 1452 1.47 thorpej if (error == 0) { 1453 1.47 thorpej if (start < r->min_addr) 1454 1.47 thorpej r->min_addr = start; 1455 1.47 thorpej if (end > r->max_addr) 1456 1.47 thorpej r->max_addr = end; 1457 1.47 thorpej } 1458 1.47 thorpej 1459 1.47 thorpej r->total_size += size; 1460 1.47 thorpej 1461 1.49 jmcneill switch (type) { 1462 1.49 jmcneill case PCICONF_RESOURCE_IO: 1463 1.49 jmcneill rsvd_type = PCI_CONF_MAP_IO; 1464 1.49 jmcneill align = 0x1000; 1465 1.49 jmcneill break; 1466 1.49 jmcneill case PCICONF_RESOURCE_MEM: 1467 1.49 jmcneill case PCICONF_RESOURCE_PREFETCHABLE_MEM: 1468 1.49 jmcneill rsvd_type = PCI_CONF_MAP_MEM; 1469 1.49 jmcneill align = 0x100000; 1470 1.49 jmcneill break; 1471 1.49 jmcneill default: 1472 1.49 jmcneill rsvd_type = 0; 1473 1.49 jmcneill align = 0; 1474 1.49 jmcneill break; 1475 1.49 jmcneill } 1476 1.49 jmcneill 1477 1.49 jmcneill /* 1478 1.49 jmcneill * Exclude reserved ranges from available resources 1479 1.49 jmcneill */ 1480 1.49 jmcneill LIST_FOREACH(rsvd, &pciconf_resource_reservations, next) { 1481 1.49 jmcneill if (rsvd->type != rsvd_type) 1482 1.49 jmcneill continue; 1483 1.49 jmcneill /* 1484 1.49 jmcneill * The reserved range may not be within our resource window. 1485 1.49 jmcneill * That's fine, so ignore the error. 1486 1.49 jmcneill */ 1487 1.49 jmcneill (void)vmem_xalloc(r->arena, rsvd->size, align, 0, 0, 1488 1.49 jmcneill rsvd->start, rsvd->start + rsvd->size, 1489 1.49 jmcneill VM_BESTFIT | VM_NOSLEEP, 1490 1.49 jmcneill &result); 1491 1.49 jmcneill } 1492 1.49 jmcneill 1493 1.47 thorpej return 0; 1494 1.47 thorpej } 1495 1.47 thorpej 1496 1.47 thorpej /* 1497 1.49 jmcneill * pciconf_resource_reserve: 1498 1.49 jmcneill * 1499 1.49 jmcneill * Mark a pci configuration resource as in-use. Devices 1500 1.50 jmcneill * already configured to use these resources are notified 1501 1.50 jmcneill * during resource assignment if their resources are changed. 1502 1.49 jmcneill */ 1503 1.49 jmcneill void 1504 1.50 jmcneill pciconf_resource_reserve(int type, bus_addr_t start, bus_size_t size, 1505 1.50 jmcneill void (*callback)(void *, uint64_t), void *callback_arg) 1506 1.49 jmcneill { 1507 1.49 jmcneill struct pciconf_resource_rsvd *rsvd; 1508 1.49 jmcneill 1509 1.49 jmcneill rsvd = kmem_zalloc(sizeof(*rsvd), KM_SLEEP); 1510 1.49 jmcneill rsvd->type = type; 1511 1.49 jmcneill rsvd->start = start; 1512 1.49 jmcneill rsvd->size = size; 1513 1.50 jmcneill rsvd->callback = callback; 1514 1.50 jmcneill rsvd->callback_arg = callback_arg; 1515 1.49 jmcneill LIST_INSERT_HEAD(&pciconf_resource_reservations, rsvd, next); 1516 1.49 jmcneill } 1517 1.49 jmcneill 1518 1.49 jmcneill /* 1519 1.1 briggs * Let's configure the PCI bus. 1520 1.1 briggs * This consists of basically scanning for all existing devices, 1521 1.1 briggs * identifying their needs, and then making another pass over them 1522 1.1 briggs * to set: 1523 1.1 briggs * 1. I/O addresses 1524 1.1 briggs * 2. Memory addresses (Prefetchable and not) 1525 1.1 briggs * 3. PCI command register 1526 1.1 briggs * 4. The latency part of the PCI BHLC (BIST (Built-In Self Test), 1527 1.1 briggs * Header type, Latency timer, Cache line size) register 1528 1.1 briggs * 1529 1.1 briggs * The command register is set to enable fast back-to-back transactions 1530 1.25 perry * if the host bridge says it can handle it. We also configure 1531 1.1 briggs * Master Enable, SERR enable, parity enable, and (if this is not a 1532 1.1 briggs * PCI-PCI bridge) the I/O and Memory spaces. Apparently some devices 1533 1.1 briggs * will not report some I/O space. 1534 1.1 briggs * 1535 1.1 briggs * The latency is computed to be a "fair share" of the bus bandwidth. 1536 1.1 briggs * The bus bandwidth variable is initialized to the number of PCI cycles 1537 1.1 briggs * in one second. The number of cycles taken for one transaction by each 1538 1.1 briggs * device (MAX_LAT + MIN_GNT) is then subtracted from the bandwidth. 1539 1.1 briggs * Care is taken to ensure that the latency timer won't be set such that 1540 1.1 briggs * it would exceed the critical time for any device. 1541 1.1 briggs * 1542 1.1 briggs * This is complicated somewhat due to the presence of bridges. PCI-PCI 1543 1.1 briggs * bridges are probed and configured recursively. 1544 1.1 briggs */ 1545 1.1 briggs int 1546 1.47 thorpej pci_configure_bus(pci_chipset_tag_t pc, struct pciconf_resources *rs, 1547 1.47 thorpej int firstbus, int cacheline_size) 1548 1.1 briggs { 1549 1.1 briggs pciconf_bus_t *pb; 1550 1.1 briggs int rv; 1551 1.1 briggs 1552 1.42 chs pb = kmem_zalloc(sizeof (pciconf_bus_t), KM_SLEEP); 1553 1.12 thorpej pb->busno = firstbus; 1554 1.1 briggs pb->next_busno = pb->busno + 1; 1555 1.1 briggs pb->last_busno = 255; 1556 1.14 thorpej pb->cacheline_size = cacheline_size; 1557 1.1 briggs pb->parent_bus = NULL; 1558 1.1 briggs pb->swiz = 0; 1559 1.2 briggs pb->io_32bit = 1; 1560 1.47 thorpej pb->io_res = rs->resources[PCICONF_RESOURCE_IO]; 1561 1.47 thorpej 1562 1.47 thorpej pb->mem_res = rs->resources[PCICONF_RESOURCE_MEM]; 1563 1.47 thorpej if (pb->mem_res.arena == NULL) 1564 1.47 thorpej pb->mem_res = rs->resources[PCICONF_RESOURCE_PREFETCHABLE_MEM]; 1565 1.47 thorpej 1566 1.47 thorpej pb->pmem_res = rs->resources[PCICONF_RESOURCE_PREFETCHABLE_MEM]; 1567 1.47 thorpej if (pb->pmem_res.arena == NULL) 1568 1.47 thorpej pb->pmem_res = rs->resources[PCICONF_RESOURCE_MEM]; 1569 1.39 msaitoh 1570 1.44 thorpej /* 1571 1.47 thorpej * Probe the memory region arenas to see if allocation of 1572 1.47 thorpej * 64-bit addresses is possible. 1573 1.44 thorpej */ 1574 1.47 thorpej pb->mem_64bit = mem_region_ok64(&pb->mem_res); 1575 1.47 thorpej pb->pmem_64bit = mem_region_ok64(&pb->pmem_res); 1576 1.44 thorpej 1577 1.1 briggs pb->pc = pc; 1578 1.1 briggs pb->io_total = pb->mem_total = pb->pmem_total = 0; 1579 1.1 briggs 1580 1.1 briggs rv = probe_bus(pb); 1581 1.40 msaitoh pb->last_busno = pb->next_busno - 1; 1582 1.39 msaitoh if (rv == 0) 1583 1.1 briggs rv = configure_bus(pb); 1584 1.1 briggs 1585 1.1 briggs /* 1586 1.1 briggs * All done! 1587 1.1 briggs */ 1588 1.32 matt kmem_free(pb, sizeof(*pb)); 1589 1.1 briggs return rv; 1590 1.1 briggs } 1591