xref: /freebsd/sys/dev/bhnd/bhndb/bhndb_pci.c (revision 094fc1ed0f2627525c7b0342efcbad5be7a8546a)
1 /*-
2  * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
3  * Copyright (c) 2017 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * Portions of this software were developed by Landon Fuller
7  * under sponsorship from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer,
14  *    without modification.
15  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
16  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
17  *    redistribution must be conditioned upon including a substantially
18  *    similar Disclaimer requirement for further binary redistribution.
19  *
20  * NO WARRANTY
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
24  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
25  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
26  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGES.
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 /*
38  * PCI-specific implementation for the BHNDB bridge driver.
39  *
40  * Provides support for bridging from a PCI parent bus to a BHND-compatible
41  * bus (e.g. bcma or siba) via a Broadcom PCI core configured in end-point
42  * mode.
43  *
44  * This driver handles all initial generic host-level PCI interactions with a
45  * PCI/PCIe bridge core operating in endpoint mode. Once the bridged bhnd(4)
46  * bus has been enumerated, this driver works in tandem with a core-specific
47  * bhnd_pci_hostb driver to manage the PCI core.
48  */
49 
50 #include <sys/param.h>
51 #include <sys/kernel.h>
52 #include <sys/bus.h>
53 #include <sys/limits.h>
54 #include <sys/malloc.h>
55 #include <sys/module.h>
56 #include <sys/systm.h>
57 
58 #include <dev/pci/pcireg.h>
59 #include <dev/pci/pcivar.h>
60 
61 #include <dev/bhnd/bhnd.h>
62 #include <dev/bhnd/bhndreg.h>
63 
64 #include <dev/bhnd/bhnd_erom.h>
65 #include <dev/bhnd/bhnd_eromvar.h>
66 
67 #include <dev/bhnd/cores/pci/bhnd_pcireg.h>
68 
69 #include "bhndb_pcireg.h"
70 #include "bhndb_pcivar.h"
71 #include "bhndb_private.h"
72 
73 struct bhndb_pci_eio;
74 
75 static int		bhndb_pci_init_msi(struct bhndb_pci_softc *sc);
76 static int		bhndb_pci_read_core_table(device_t dev,
77 			    struct bhnd_chipid *chipid,
78 			    struct bhnd_core_info **cores, u_int *ncores,
79 			    bhnd_erom_class_t **eromcls);
80 static int		bhndb_pci_add_children(struct bhndb_pci_softc *sc);
81 
82 static bool		bhndb_is_pcie_attached(device_t dev);
83 
84 static int		bhndb_enable_pci_clocks(device_t dev);
85 static int		bhndb_disable_pci_clocks(device_t dev);
86 
87 static int		bhndb_pci_compat_setregwin(device_t dev,
88 			    device_t pci_dev, const struct bhndb_regwin *,
89 			    bhnd_addr_t);
90 static int		bhndb_pci_fast_setregwin(device_t dev, device_t pci_dev,
91 			    const struct bhndb_regwin *, bhnd_addr_t);
92 
93 static void		bhndb_init_sromless_pci_config(
94 			    struct bhndb_pci_softc *sc);
95 
96 static bus_addr_t	bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc);
97 static bus_size_t	bhndb_pci_sprom_size(struct bhndb_pci_softc *sc);
98 
99 static int		bhndb_pci_eio_init(struct bhndb_pci_eio *pio,
100 			    device_t dev, device_t pci_dev,
101 			    struct bhndb_host_resources *hr);
102 static int		bhndb_pci_eio_map(struct bhnd_erom_io *eio,
103 			    bhnd_addr_t addr, bhnd_size_t size);
104 static uint32_t		bhndb_pci_eio_read(struct bhnd_erom_io *eio,
105 			    bhnd_size_t offset, u_int width);
106 
107 #define	BHNDB_PCI_MSI_COUNT	1
108 
109 /* bhndb_pci erom I/O implementation */
110 struct bhndb_pci_eio {
111 	struct bhnd_erom_io		 eio;
112 	device_t			 dev;		/**< bridge device */
113 	device_t			 pci_dev;	/**< parent PCI device */
114 	struct bhndb_host_resources	*hr;		/**< borrowed reference to host resources */
115 	const struct bhndb_regwin	*win;		/**< mapped register window, or NULL */
116 	struct resource			*res;		/**< resource containing the register window, or NULL if no window mapped */
117 	bhnd_addr_t			 res_target;	/**< current target address (if mapped) */
118 	bool				 mapped;	/**< true if a valid mapping exists, false otherwise */
119 	bhnd_addr_t			 addr;		/**< mapped address */
120 	bhnd_size_t			 size;		/**< mapped size */
121 };
122 
123 /**
124  * Default bhndb_pci implementation of device_probe().
125  *
126  * Verifies that the parent is a PCI/PCIe device.
127  */
128 static int
129 bhndb_pci_probe(device_t dev)
130 {
131 	device_t	parent;
132 	devclass_t	parent_bus;
133 	devclass_t	pci;
134 
135 	/* Our parent must be a PCI/PCIe device. */
136 	pci = devclass_find("pci");
137 	parent = device_get_parent(dev);
138 	parent_bus = device_get_devclass(device_get_parent(parent));
139 
140 	if (parent_bus != pci)
141 		return (ENXIO);
142 
143 	device_set_desc(dev, "PCI-BHND bridge");
144 
145 	return (BUS_PROBE_DEFAULT);
146 }
147 
148 /* Configure MSI interrupts */
149 static int
150 bhndb_pci_init_msi(struct bhndb_pci_softc *sc)
151 {
152 	int error;
153 
154 	/* Is MSI available? */
155 	if (pci_msi_count(sc->parent) < BHNDB_PCI_MSI_COUNT)
156 		return (ENXIO);
157 
158 	/* Allocate expected message count */
159 	sc->intr.msi_count = BHNDB_PCI_MSI_COUNT;
160 	if ((error = pci_alloc_msi(sc->parent, &sc->intr.msi_count))) {
161 		device_printf(sc->dev, "failed to allocate MSI interrupts: "
162 		    "%d\n", error);
163 		return (error);
164 	}
165 
166 	if (sc->intr.msi_count < BHNDB_PCI_MSI_COUNT)
167 		return (ENXIO);
168 
169 	/* MSI uses resource IDs starting at 1 */
170 	sc->intr.intr_rid = 1;
171 
172 	return (0);
173 }
174 
175 static int
176 bhndb_pci_attach(device_t dev)
177 {
178 	struct bhndb_pci_softc	*sc;
179 	struct bhnd_chipid	 cid;
180 	struct bhnd_core_info	*cores, hostb_core;
181 	bhnd_erom_class_t	*erom_class;
182 	u_int			 ncores;
183 	int			 error, reg;
184 
185 	sc = device_get_softc(dev);
186 	sc->dev = dev;
187 	sc->parent = device_get_parent(dev);
188 	sc->set_regwin = NULL;
189 
190 	cores = NULL;
191 
192 	/* Enable PCI bus mastering */
193 	pci_enable_busmaster(sc->parent);
194 
195 	/* Set up PCI interrupt handling */
196 	if (bhndb_pci_init_msi(sc) == 0) {
197 		device_printf(dev, "Using MSI interrupts on %s\n",
198 		    device_get_nameunit(sc->parent));
199 	} else {
200 		device_printf(dev, "Using INTx interrupts on %s\n",
201 		    device_get_nameunit(sc->parent));
202 		sc->intr.intr_rid = 0;
203 	}
204 
205 	/* Determine our bridge device class */
206 	sc->pci_devclass = BHND_DEVCLASS_PCI;
207 	if (pci_find_cap(sc->parent, PCIY_EXPRESS, &reg) == 0)
208 		sc->pci_devclass = BHND_DEVCLASS_PCIE;
209 	else
210 		sc->pci_devclass = BHND_DEVCLASS_PCI;
211 
212 	/* Enable clocks (if required by this hardware) */
213 	if ((error = bhndb_enable_pci_clocks(sc->dev)))
214 		goto cleanup;
215 
216 	/* Identify the chip and enumerate the bridged cores */
217 	error = bhndb_pci_read_core_table(dev, &cid, &cores, &ncores,
218 	    &erom_class);
219 	if (error)
220 		goto cleanup;
221 
222 	/* Select the appropriate register window handler */
223 	if (cid.chip_type == BHND_CHIPTYPE_SIBA) {
224 		sc->set_regwin = bhndb_pci_compat_setregwin;
225 	} else {
226 		sc->set_regwin = bhndb_pci_fast_setregwin;
227 	}
228 
229 	/* Determine our host bridge core */
230 	error = bhndb_find_hostb_core(cores, ncores, sc->pci_devclass,
231 	    &hostb_core);
232 	if (error)
233 		goto cleanup;
234 
235 	/* Perform bridge attach */
236 	error = bhndb_attach(dev, &cid, cores, ncores, &hostb_core, erom_class);
237 	if (error)
238 		goto cleanup;
239 
240 	/* Fix-up power on defaults for SROM-less devices. */
241 	bhndb_init_sromless_pci_config(sc);
242 
243 	/* Add any additional child devices */
244 	if ((error = bhndb_pci_add_children(sc)))
245 		goto cleanup;
246 
247 	/* Probe and attach our children */
248 	if ((error = bus_generic_attach(dev)))
249 		goto cleanup;
250 
251 	free(cores, M_BHND);
252 
253 	return (0);
254 
255 cleanup:
256 	device_delete_children(dev);
257 	bhndb_disable_pci_clocks(sc->dev);
258 
259 	if (sc->intr.msi_count > 0)
260 		pci_release_msi(dev);
261 
262 	if (cores != NULL)
263 		free(cores, M_BHND);
264 
265 	pci_disable_busmaster(sc->parent);
266 
267 	return (error);
268 }
269 
270 static int
271 bhndb_pci_detach(device_t dev)
272 {
273 	struct bhndb_pci_softc	*sc;
274 	int			 error;
275 
276 	sc = device_get_softc(dev);
277 
278 	/* Attempt to detach our children */
279 	if ((error = bus_generic_detach(dev)))
280 		return (error);
281 
282 	/* Perform generic bridge detach */
283 	if ((error = bhndb_generic_detach(dev)))
284 		return (error);
285 
286 	/* Disable clocks (if required by this hardware) */
287 	if ((error = bhndb_disable_pci_clocks(sc->dev)))
288 		return (error);
289 
290 	/* Release MSI interrupts */
291 	if (sc->intr.msi_count > 0)
292 		pci_release_msi(dev);
293 
294 	/* Disable PCI bus mastering */
295 	pci_disable_busmaster(sc->parent);
296 
297 	return (0);
298 }
299 
300 /**
301  * Use the generic PCI bridge hardware configuration to enumerate the bridged
302  * bhnd(4) bus' core table.
303  *
304  * @note This function may be safely called prior to device attach, (e.g.
305  * from DEVICE_PROBE).
306  * @note This function requires exclusive ownership over allocating and
307  * configuring host bridge resources, and should only be called prior to
308  * completion of device attach and full configuration of the bridge.
309  *
310  * @param	dev		The bhndb_pci bridge device.
311  * @param[out]	chipid		On success, the parsed chip identification.
312  * @param[out]	cores		On success, the enumerated core table. The
313  *				caller is responsible for freeing this table via
314  *				bhndb_pci_free_core_table().
315  * @param[out]	ncores		On success, the number of cores found in
316  *				@p cores.
317  * @param[out]	eromcls		On success, a pointer to the erom class used to
318  *				parse the device enumeration table. This
319  *				argument may be NULL if the class is not
320  *				desired.
321  *
322  * @retval 0		success
323  * @retval non-zero	if enumerating the bridged bhnd(4) bus fails, a regular
324  * 			unix error code will be returned.
325  */
326 static int
327 bhndb_pci_read_core_table(device_t dev, struct bhnd_chipid *chipid,
328     struct bhnd_core_info **cores, u_int *ncores,
329     bhnd_erom_class_t **eromcls)
330 {
331 	const struct bhndb_hwcfg	*cfg;
332 	struct bhndb_host_resources	*hr;
333 	struct bhndb_pci_eio		 pio;
334 	struct bhnd_core_info		*erom_cores;
335 	const struct bhnd_chipid	*hint;
336 	struct bhnd_chipid		 cid;
337 	bhnd_erom_class_t		*erom_class;
338 	bhnd_erom_t			*erom;
339 	device_t			 parent_dev;
340 	u_int				 erom_ncores;
341 	int				 error;
342 
343 	parent_dev = device_get_parent(dev);
344 	erom = NULL;
345 	erom_cores = NULL;
346 
347 	/* Fetch our chipid hint (if any) and generic hardware configuration */
348 	cfg = BHNDB_BUS_GET_GENERIC_HWCFG(parent_dev, dev);
349 	hint = BHNDB_BUS_GET_CHIPID(parent_dev, dev);
350 
351 	/* Allocate our host resources */
352 	if ((error = bhndb_alloc_host_resources(parent_dev, cfg, &hr)))
353 		return (error);
354 
355 	/* Initialize our erom I/O state */
356 	if ((error = bhndb_pci_eio_init(&pio, dev, parent_dev, hr)))
357 		goto failed;
358 
359 	/* Map the first bus core from our bridged bhnd(4) bus */
360 	error = bhndb_pci_eio_map(&pio.eio, BHND_DEFAULT_CHIPC_ADDR,
361 	    BHND_DEFAULT_CORE_SIZE);
362 	if (error)
363 		goto failed;
364 
365 	/* Probe for a usable EROM class, and read the chip identifier */
366 	erom_class = bhnd_erom_probe_driver_classes(device_get_devclass(dev),
367 	    &pio.eio, hint, &cid);
368 	if (erom_class == NULL) {
369 		device_printf(dev, "device enumeration unsupported; no "
370 		    "compatible driver found\n");
371 
372 		error = ENXIO;
373 		goto failed;
374 	}
375 
376 	/* Allocate EROM parser */
377 	if ((erom = bhnd_erom_alloc(erom_class, &cid, &pio.eio)) == NULL) {
378 		device_printf(dev, "failed to allocate device enumeration "
379 		    "table parser\n");
380 		error = ENXIO;
381 		goto failed;
382 	}
383 
384 	/* Read the full core table */
385 	error = bhnd_erom_get_core_table(erom, &erom_cores, &erom_ncores);
386 	if (error) {
387 		device_printf(dev, "error fetching core table: %d\n", error);
388 		goto failed;
389 	}
390 
391 	/* Provide the results to our caller */
392 	*cores = malloc(sizeof(erom_cores[0]) * erom_ncores, M_BHND, M_WAITOK);
393 	memcpy(*cores, erom_cores, sizeof(erom_cores[0]) * erom_ncores);
394 	*ncores = erom_ncores;
395 
396 	*chipid = cid;
397 	if (eromcls != NULL)
398 		*eromcls = erom_class;
399 
400 	/* Clean up */
401 	bhnd_erom_free_core_table(erom, erom_cores);
402 	bhnd_erom_free(erom);
403 	bhndb_release_host_resources(hr);
404 
405 	return (0);
406 
407 failed:
408 	if (erom_cores != NULL)
409 		bhnd_erom_free_core_table(erom, erom_cores);
410 
411 	if (erom != NULL)
412 		bhnd_erom_free(erom);
413 
414 	bhndb_release_host_resources(hr);
415 	return (error);
416 }
417 
418 static int
419 bhndb_pci_add_children(struct bhndb_pci_softc *sc)
420 {
421 	bus_size_t		 nv_sz;
422 	int			 error;
423 
424 	/**
425 	 * If SPROM is mapped directly into BAR0, add child NVRAM
426 	 * device.
427 	 */
428 	nv_sz = bhndb_pci_sprom_size(sc);
429 	if (nv_sz > 0) {
430 		struct bhndb_devinfo	*dinfo;
431 		device_t		 child;
432 
433 		if (bootverbose) {
434 			device_printf(sc->dev, "found SPROM (%ju bytes)\n",
435 			    (uintmax_t)nv_sz);
436 		}
437 
438 		/* Add sprom device, ordered early enough to be available
439 		 * before the bridged bhnd(4) bus is attached. */
440 		child = BUS_ADD_CHILD(sc->dev,
441 		    BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY, "bhnd_nvram", -1);
442 		if (child == NULL) {
443 			device_printf(sc->dev, "failed to add sprom device\n");
444 			return (ENXIO);
445 		}
446 
447 		/* Initialize device address space and resource covering the
448 		 * BAR0 SPROM shadow. */
449 		dinfo = device_get_ivars(child);
450 		dinfo->addrspace = BHNDB_ADDRSPACE_NATIVE;
451 
452 		error = bus_set_resource(child, SYS_RES_MEMORY, 0,
453 		    bhndb_pci_sprom_addr(sc), nv_sz);
454 		if (error) {
455 			device_printf(sc->dev,
456 			    "failed to register sprom resources\n");
457 			return (error);
458 		}
459 	}
460 
461 	return (0);
462 }
463 
464 static const struct bhndb_regwin *
465 bhndb_pci_sprom_regwin(struct bhndb_pci_softc *sc)
466 {
467 	struct bhndb_resources		*bres;
468 	const struct bhndb_hwcfg	*cfg;
469 	const struct bhndb_regwin	*sprom_win;
470 
471 	bres = sc->bhndb.bus_res;
472 	cfg = bres->cfg;
473 
474 	sprom_win = bhndb_regwin_find_type(cfg->register_windows,
475 	    BHNDB_REGWIN_T_SPROM, BHNDB_PCI_V0_BAR0_SPROM_SIZE);
476 
477 	return (sprom_win);
478 }
479 
480 static bus_addr_t
481 bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc)
482 {
483 	const struct bhndb_regwin	*sprom_win;
484 	struct resource			*r;
485 
486 	/* Fetch the SPROM register window */
487 	sprom_win = bhndb_pci_sprom_regwin(sc);
488 	KASSERT(sprom_win != NULL, ("requested sprom address on PCI_V2+"));
489 
490 	/* Fetch the associated resource */
491 	r = bhndb_host_resource_for_regwin(sc->bhndb.bus_res->res, sprom_win);
492 	KASSERT(r != NULL, ("missing resource for sprom window\n"));
493 
494 	return (rman_get_start(r) + sprom_win->win_offset);
495 }
496 
497 static bus_size_t
498 bhndb_pci_sprom_size(struct bhndb_pci_softc *sc)
499 {
500 	const struct bhndb_regwin	*sprom_win;
501 	uint32_t			 sctl;
502 	bus_size_t			 sprom_sz;
503 
504 	sprom_win = bhndb_pci_sprom_regwin(sc);
505 
506 	/* PCI_V2 and later devices map SPROM/OTP via ChipCommon */
507 	if (sprom_win == NULL)
508 		return (0);
509 
510 	/* Determine SPROM size */
511 	sctl = pci_read_config(sc->parent, BHNDB_PCI_SPROM_CONTROL, 4);
512 	if (sctl & BHNDB_PCI_SPROM_BLANK)
513 		return (0);
514 
515 	switch (sctl & BHNDB_PCI_SPROM_SZ_MASK) {
516 	case BHNDB_PCI_SPROM_SZ_1KB:
517 		sprom_sz = (1 * 1024);
518 		break;
519 
520 	case BHNDB_PCI_SPROM_SZ_4KB:
521 		sprom_sz = (4 * 1024);
522 		break;
523 
524 	case BHNDB_PCI_SPROM_SZ_16KB:
525 		sprom_sz = (16 * 1024);
526 		break;
527 
528 	case BHNDB_PCI_SPROM_SZ_RESERVED:
529 	default:
530 		device_printf(sc->dev, "invalid PCI sprom size 0x%x\n", sctl);
531 		return (0);
532 	}
533 
534 	if (sprom_sz > sprom_win->win_size) {
535 		device_printf(sc->dev,
536 		    "PCI sprom size (0x%x) overruns defined register window\n",
537 		    sctl);
538 		return (0);
539 	}
540 
541 	return (sprom_sz);
542 }
543 
544 /*
545  * On devices without a SROM, the PCI(e) cores will be initialized with
546  * their Power-on-Reset defaults; this can leave two of the BAR0 PCI windows
547  * mapped to the wrong core.
548  *
549  * This function updates the SROM shadow to point the BAR0 windows at the
550  * current PCI core.
551  *
552  * Applies to all PCI/PCIe revisions.
553  */
554 static void
555 bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc)
556 {
557 	struct bhndb_resources		*bres;
558 	const struct bhndb_hwcfg	*cfg;
559 	const struct bhndb_regwin	*win;
560 	struct bhnd_core_info		 hostb_core;
561 	struct resource			*core_regs;
562 	bus_size_t			 srom_offset;
563 	u_int				 pci_cidx, sprom_cidx;
564 	uint16_t			 val;
565 	int				 error;
566 
567 	bres = sc->bhndb.bus_res;
568 	cfg = bres->cfg;
569 
570 	/* Find our hostb core */
571 	error = BHNDB_GET_HOSTB_CORE(sc->dev, sc->bhndb.bus_dev, &hostb_core);
572 	if (error) {
573 		device_printf(sc->dev, "no host bridge device found\n");
574 		return;
575 	}
576 
577 	if (hostb_core.vendor != BHND_MFGID_BCM)
578 		return;
579 
580 	switch (hostb_core.device) {
581 	case BHND_COREID_PCI:
582 		srom_offset = BHND_PCI_SRSH_PI_OFFSET;
583 		break;
584 	case BHND_COREID_PCIE:
585 		srom_offset = BHND_PCIE_SRSH_PI_OFFSET;
586 		break;
587 	default:
588 		device_printf(sc->dev, "unsupported PCI host bridge device\n");
589 		return;
590 	}
591 
592 	/* Locate the static register window mapping the PCI core */
593 	win = bhndb_regwin_find_core(cfg->register_windows, sc->pci_devclass,
594 	    0, BHND_PORT_DEVICE, 0, 0);
595 	if (win == NULL) {
596 		device_printf(sc->dev, "missing PCI core register window\n");
597 		return;
598 	}
599 
600 	/* Fetch the resource containing the register window */
601 	core_regs = bhndb_host_resource_for_regwin(bres->res, win);
602 	if (core_regs == NULL) {
603 		device_printf(sc->dev, "missing PCI core register resource\n");
604 		return;
605 	}
606 
607 	/* Fetch the SPROM's configured core index */
608 	val = bus_read_2(core_regs, win->win_offset + srom_offset);
609 	sprom_cidx = (val & BHND_PCI_SRSH_PI_MASK) >> BHND_PCI_SRSH_PI_SHIFT;
610 
611 	/* If it doesn't match host bridge's core index, update the index
612 	 * value */
613 	pci_cidx = hostb_core.core_idx;
614 	if (sprom_cidx != pci_cidx) {
615 		val &= ~BHND_PCI_SRSH_PI_MASK;
616 		val |= (pci_cidx << BHND_PCI_SRSH_PI_SHIFT);
617 		bus_write_2(core_regs,
618 		    win->win_offset + srom_offset, val);
619 	}
620 }
621 
622 static int
623 bhndb_pci_resume(device_t dev)
624 {
625 	struct bhndb_pci_softc	*sc;
626 	int			 error;
627 
628 	sc = device_get_softc(dev);
629 
630 	/* Enable clocks (if supported by this hardware) */
631 	if ((error = bhndb_enable_pci_clocks(sc->dev)))
632 		return (error);
633 
634 	/* Perform resume */
635 	return (bhndb_generic_resume(dev));
636 }
637 
638 static int
639 bhndb_pci_suspend(device_t dev)
640 {
641 	struct bhndb_pci_softc	*sc;
642 	int			 error;
643 
644 	sc = device_get_softc(dev);
645 
646 	/* Disable clocks (if supported by this hardware) */
647 	if ((error = bhndb_disable_pci_clocks(sc->dev)))
648 		return (error);
649 
650 	/* Perform suspend */
651 	return (bhndb_generic_suspend(dev));
652 }
653 
654 static int
655 bhndb_pci_set_window_addr(device_t dev, const struct bhndb_regwin *rw,
656     bhnd_addr_t addr)
657 {
658 	struct bhndb_pci_softc *sc = device_get_softc(dev);
659 	return (sc->set_regwin(sc->dev, sc->parent, rw, addr));
660 }
661 
662 /**
663  * A siba(4) and bcma(4)-compatible bhndb_set_window_addr implementation.
664  *
665  * On siba(4) devices, it's possible that writing a PCI window register may
666  * not succeed; it's necessary to immediately read the configuration register
667  * and retry if not set to the desired value.
668  *
669  * This is not necessary on bcma(4) devices, but other than the overhead of
670  * validating the register, there's no harm in performing the verification.
671  */
672 static int
673 bhndb_pci_compat_setregwin(device_t dev, device_t pci_dev,
674     const struct bhndb_regwin *rw, bhnd_addr_t addr)
675 {
676 	int		error;
677 	int		reg;
678 
679 	if (rw->win_type != BHNDB_REGWIN_T_DYN)
680 		return (ENODEV);
681 
682 	reg = rw->d.dyn.cfg_offset;
683 	for (u_int i = 0; i < BHNDB_PCI_BARCTRL_WRITE_RETRY; i++) {
684 		if ((error = bhndb_pci_fast_setregwin(dev, pci_dev, rw, addr)))
685 			return (error);
686 
687 		if (pci_read_config(pci_dev, reg, 4) == addr)
688 			return (0);
689 
690 		DELAY(10);
691 	}
692 
693 	/* Unable to set window */
694 	return (ENODEV);
695 }
696 
697 /**
698  * A bcma(4)-only bhndb_set_window_addr implementation.
699  */
700 static int
701 bhndb_pci_fast_setregwin(device_t dev, device_t pci_dev,
702     const struct bhndb_regwin *rw, bhnd_addr_t addr)
703 {
704 	/* The PCI bridge core only supports 32-bit addressing, regardless
705 	 * of the bus' support for 64-bit addressing */
706 	if (addr > UINT32_MAX)
707 		return (ERANGE);
708 
709 	switch (rw->win_type) {
710 	case BHNDB_REGWIN_T_DYN:
711 		/* Addresses must be page aligned */
712 		if (addr % rw->win_size != 0)
713 			return (EINVAL);
714 
715 		pci_write_config(pci_dev, rw->d.dyn.cfg_offset, addr, 4);
716 		break;
717 	default:
718 		return (ENODEV);
719 	}
720 
721 	return (0);
722 }
723 
724 static int
725 bhndb_pci_populate_board_info(device_t dev, device_t child,
726     struct bhnd_board_info *info)
727 {
728 	struct bhndb_pci_softc	*sc;
729 
730 	sc = device_get_softc(dev);
731 
732 	/*
733 	 * On a subset of Apple BCM4360 modules, always prefer the
734 	 * PCI subdevice to the SPROM-supplied boardtype.
735 	 *
736 	 * TODO:
737 	 *
738 	 * Broadcom's own drivers implement this override, and then later use
739 	 * the remapped BCM4360 board type to determine the required
740 	 * board-specific workarounds.
741 	 *
742 	 * Without access to this hardware, it's unclear why this mapping
743 	 * is done, and we must do the same. If we can survey the hardware
744 	 * in question, it may be possible to replace this behavior with
745 	 * explicit references to the SPROM-supplied boardtype(s) in our
746 	 * quirk definitions.
747 	 */
748 	if (pci_get_subvendor(sc->parent) == PCI_VENDOR_APPLE) {
749 		switch (info->board_type) {
750 		case BHND_BOARD_BCM94360X29C:
751 		case BHND_BOARD_BCM94360X29CP2:
752 		case BHND_BOARD_BCM94360X51:
753 		case BHND_BOARD_BCM94360X51P2:
754 			info->board_type = 0;	/* allow override below */
755 			break;
756 		default:
757 			break;
758 		}
759 	}
760 
761 	/* If NVRAM did not supply vendor/type info, provide the PCI
762 	 * subvendor/subdevice values. */
763 	if (info->board_vendor == 0)
764 		info->board_vendor = pci_get_subvendor(sc->parent);
765 
766 	if (info->board_type == 0)
767 		info->board_type = pci_get_subdevice(sc->parent);
768 
769 	return (0);
770 }
771 
772 /**
773  * Return true if the bridge device @p bhndb is attached via PCIe,
774  * false otherwise.
775  *
776  * @param dev The bhndb bridge device
777  */
778 static bool
779 bhndb_is_pcie_attached(device_t dev)
780 {
781 	int reg;
782 
783 	if (pci_find_cap(device_get_parent(dev), PCIY_EXPRESS, &reg) == 0)
784 		return (true);
785 
786 	return (false);
787 }
788 
789 /**
790  * Enable externally managed clocks, if required.
791  *
792  * Some PCI chipsets (BCM4306, possibly others) chips do not support
793  * the idle low-power clock. Clocking must be bootstrapped at
794  * attach/resume by directly adjusting GPIO registers exposed in the
795  * PCI config space, and correspondingly, explicitly shutdown at
796  * detach/suspend.
797  *
798  * @note This function may be safely called prior to device attach, (e.g.
799  * from DEVICE_PROBE).
800  *
801  * @param dev The bhndb bridge device
802  */
803 static int
804 bhndb_enable_pci_clocks(device_t dev)
805 {
806 	device_t		pci_dev;
807 	uint32_t		gpio_in, gpio_out, gpio_en;
808 	uint32_t		gpio_flags;
809 	uint16_t		pci_status;
810 
811 	pci_dev = device_get_parent(dev);
812 
813 	/* Only supported and required on PCI devices */
814 	if (!bhndb_is_pcie_attached(dev))
815 		return (0);
816 
817 	/* Read state of XTAL pin */
818 	gpio_in = pci_read_config(pci_dev, BHNDB_PCI_GPIO_IN, 4);
819 	if (gpio_in & BHNDB_PCI_GPIO_XTAL_ON)
820 		return (0); /* already enabled */
821 
822 	/* Fetch current config */
823 	gpio_out = pci_read_config(pci_dev, BHNDB_PCI_GPIO_OUT, 4);
824 	gpio_en = pci_read_config(pci_dev, BHNDB_PCI_GPIO_OUTEN, 4);
825 
826 	/* Set PLL_OFF/XTAL_ON pins to HIGH and enable both pins */
827 	gpio_flags = (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON);
828 	gpio_out |= gpio_flags;
829 	gpio_en |= gpio_flags;
830 
831 	pci_write_config(pci_dev, BHNDB_PCI_GPIO_OUT, gpio_out, 4);
832 	pci_write_config(pci_dev, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4);
833 	DELAY(1000);
834 
835 	/* Reset PLL_OFF */
836 	gpio_out &= ~BHNDB_PCI_GPIO_PLL_OFF;
837 	pci_write_config(pci_dev, BHNDB_PCI_GPIO_OUT, gpio_out, 4);
838 	DELAY(5000);
839 
840 	/* Clear any PCI 'sent target-abort' flag. */
841 	pci_status = pci_read_config(pci_dev, PCIR_STATUS, 2);
842 	pci_status &= ~PCIM_STATUS_STABORT;
843 	pci_write_config(pci_dev, PCIR_STATUS, pci_status, 2);
844 
845 	return (0);
846 }
847 
848 /**
849  * Disable externally managed clocks, if required.
850  *
851  * This function may be safely called prior to device attach, (e.g.
852  * from DEVICE_PROBE).
853  *
854  * @param dev The bhndb bridge device
855  */
856 static int
857 bhndb_disable_pci_clocks(device_t dev)
858 {
859 	device_t	pci_dev;
860 	uint32_t	gpio_out, gpio_en;
861 
862 	pci_dev = device_get_parent(dev);
863 
864 	/* Only supported and required on PCI devices */
865 	if (bhndb_is_pcie_attached(dev))
866 		return (0);
867 
868 	/* Fetch current config */
869 	gpio_out = pci_read_config(pci_dev, BHNDB_PCI_GPIO_OUT, 4);
870 	gpio_en = pci_read_config(pci_dev, BHNDB_PCI_GPIO_OUTEN, 4);
871 
872 	/* Set PLL_OFF to HIGH, XTAL_ON to LOW. */
873 	gpio_out &= ~BHNDB_PCI_GPIO_XTAL_ON;
874 	gpio_out |= BHNDB_PCI_GPIO_PLL_OFF;
875 	pci_write_config(pci_dev, BHNDB_PCI_GPIO_OUT, gpio_out, 4);
876 
877 	/* Enable both output pins */
878 	gpio_en |= (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON);
879 	pci_write_config(pci_dev, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4);
880 
881 	return (0);
882 }
883 
884 static bhnd_clksrc
885 bhndb_pci_pwrctl_get_clksrc(device_t dev, device_t child,
886 	bhnd_clock clock)
887 {
888 	struct bhndb_pci_softc	*sc;
889 	uint32_t		 gpio_out;
890 
891 	sc = device_get_softc(dev);
892 
893 	/* Only supported on PCI devices */
894 	if (bhndb_is_pcie_attached(sc->dev))
895 		return (ENODEV);
896 
897 	/* Only ILP is supported */
898 	if (clock != BHND_CLOCK_ILP)
899 		return (ENXIO);
900 
901 	gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4);
902 	if (gpio_out & BHNDB_PCI_GPIO_SCS)
903 		return (BHND_CLKSRC_PCI);
904 	else
905 		return (BHND_CLKSRC_XTAL);
906 }
907 
908 static int
909 bhndb_pci_pwrctl_gate_clock(device_t dev, device_t child,
910 	bhnd_clock clock)
911 {
912 	struct bhndb_pci_softc *sc = device_get_softc(dev);
913 
914 	/* Only supported on PCI devices */
915 	if (bhndb_is_pcie_attached(sc->dev))
916 		return (ENODEV);
917 
918 	/* Only HT is supported */
919 	if (clock != BHND_CLOCK_HT)
920 		return (ENXIO);
921 
922 	return (bhndb_disable_pci_clocks(sc->dev));
923 }
924 
925 static int
926 bhndb_pci_pwrctl_ungate_clock(device_t dev, device_t child,
927 	bhnd_clock clock)
928 {
929 	struct bhndb_pci_softc *sc = device_get_softc(dev);
930 
931 	/* Only supported on PCI devices */
932 	if (bhndb_is_pcie_attached(sc->dev))
933 		return (ENODEV);
934 
935 	/* Only HT is supported */
936 	if (clock != BHND_CLOCK_HT)
937 		return (ENXIO);
938 
939 	return (bhndb_enable_pci_clocks(sc->dev));
940 }
941 
942 static int
943 bhndb_pci_assign_intr(device_t dev, device_t child, int rid)
944 {
945 	struct bhndb_pci_softc	*sc;
946 	rman_res_t		 start, count;
947 	int			 error;
948 
949 	sc = device_get_softc(dev);
950 
951 	/* Is the rid valid? */
952 	if (rid >= bhnd_get_intr_count(child))
953 		return (EINVAL);
954 
955 	/* Fetch our common PCI interrupt's start/count. */
956 	error = bus_get_resource(sc->parent, SYS_RES_IRQ, sc->intr.intr_rid,
957 	    &start, &count);
958 	if (error)
959 		return (error);
960 
961 	/* Add to child's resource list */
962         return (bus_set_resource(child, SYS_RES_IRQ, rid, start, count));
963 }
964 
965 /**
966  * Initialize a new bhndb PCI bridge EROM I/O instance. This EROM I/O
967  * implementation supports mapping of the device enumeration table via the
968  * @p hr host resources.
969  *
970  * @param pio		The instance to be initialized.
971  * @param dev		The bridge device.
972  * @param pci_dev	The bridge's parent PCI device.
973  * @param hr		The host resources to be used to map the device
974  *			enumeration table.
975  */
976 static int
977 bhndb_pci_eio_init(struct bhndb_pci_eio *pio, device_t dev, device_t pci_dev,
978     struct bhndb_host_resources *hr)
979 {
980 	memset(&pio->eio, sizeof(pio->eio), 0);
981 	pio->eio.map = bhndb_pci_eio_map;
982 	pio->eio.read = bhndb_pci_eio_read;
983 	pio->eio.fini = NULL;
984 
985 	pio->dev = dev;
986 	pio->pci_dev = pci_dev;
987 	pio->hr = hr;
988 	pio->win = NULL;
989 	pio->res = NULL;
990 
991 	return (0);
992 }
993 
994 /**
995  * Attempt to adjust the dynamic register window backing @p pio to permit
996  * reading @p size bytes at @p addr.
997  *
998  * If @p addr or @p size fall outside the existing mapped range, or if
999  * @p pio is not backed by a dynamic register window, ENXIO will be returned.
1000  *
1001  * @param pio	The bhndb PCI erom I/O state to be modified.
1002  * @param addr	The address to be include
1003  */
1004 static int
1005 bhndb_pci_eio_adjust_mapping(struct bhndb_pci_eio *pio, bhnd_addr_t addr,
1006     bhnd_size_t size)
1007 {
1008 	bhnd_addr_t	 target;
1009 	bhnd_size_t	 offset;
1010 	int		 error;
1011 
1012 
1013 	KASSERT(pio->win != NULL, ("missing register window"));
1014 	KASSERT(pio->res != NULL, ("missing regwin resource"));
1015 	KASSERT(pio->win->win_type == BHNDB_REGWIN_T_DYN,
1016 	    ("unexpected window type %d", pio->win->win_type));
1017 
1018 	/* The requested subrange must fall within the total mapped range */
1019 	if (addr < pio->addr || (addr - pio->addr) > pio->size ||
1020 	    size > pio->size || (addr - pio->addr) - pio->size < size)
1021 	{
1022 		return (ENXIO);
1023 	}
1024 
1025 	/* Do we already have a useable mapping? */
1026 	if (addr >= pio->res_target &&
1027 	    addr <= pio->res_target + pio->win->win_size &&
1028 	    (pio->res_target + pio->win->win_size) - addr >= size)
1029 	{
1030 		return (0);
1031 	}
1032 
1033 	/* Page-align the target address */
1034 	offset = addr % pio->win->win_size;
1035 	target = addr - offset;
1036 
1037 	/* Configure the register window */
1038 	error = bhndb_pci_compat_setregwin(pio->dev, pio->pci_dev, pio->win,
1039 	    target);
1040 	if (error) {
1041 		device_printf(pio->dev, "failed to configure dynamic register "
1042 		    "window: %d\n", error);
1043 		return (error);
1044 	}
1045 
1046 	pio->res_target = target;
1047 	return (0);
1048 }
1049 
1050 /* bhnd_erom_io_map() implementation */
1051 static int
1052 bhndb_pci_eio_map(struct bhnd_erom_io *eio, bhnd_addr_t addr,
1053     bhnd_size_t size)
1054 {
1055 	struct bhndb_pci_eio		*pio;
1056 	const struct bhndb_regwin	*regwin;
1057 	struct resource			*r;
1058 	bhnd_addr_t			 target;
1059 	bhnd_size_t			 offset;
1060 	int				 error;
1061 
1062 	pio = (struct bhndb_pci_eio *)eio;
1063 
1064 	/* Locate a useable dynamic register window */
1065 	regwin = bhndb_regwin_find_type(pio->hr->cfg->register_windows,
1066 	    BHNDB_REGWIN_T_DYN, MIN(size, BHND_DEFAULT_CORE_SIZE));
1067 	if (regwin == NULL) {
1068 		device_printf(pio->dev, "unable to map %#jx+%#jx; no "
1069 		    "usable dynamic register window found\n", addr, size);
1070 		return (ENXIO);
1071 	}
1072 
1073 	/* Locate the host resource mapping our register window */
1074 	if ((r = bhndb_host_resource_for_regwin(pio->hr, regwin)) == NULL) {
1075 		device_printf(pio->dev, "unable to map %#jx+%#jx; no "
1076 		    "usable register resource found\n", addr, size);
1077 		return (ENXIO);
1078 	}
1079 
1080 	/* Page-align the target address */
1081 	offset = addr % regwin->win_size;
1082 	target = addr - offset;
1083 
1084 	/* Configure the register window */
1085 	error = bhndb_pci_compat_setregwin(pio->dev, pio->pci_dev, regwin,
1086 	    target);
1087 	if (error) {
1088 		device_printf(pio->dev, "failed to configure dynamic register "
1089 		    "window: %d\n", error);
1090 		return (error);
1091 	}
1092 
1093 	/* Update our mapping state */
1094 	pio->win = regwin;
1095 	pio->res = r;
1096 	pio->addr = addr;
1097 	pio->size = size;
1098 	pio->res_target = target;
1099 
1100 	return (0);
1101 }
1102 
1103 /* bhnd_erom_io_read() implementation */
1104 static uint32_t
1105 bhndb_pci_eio_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width)
1106 {
1107 	struct bhndb_pci_eio		*pio;
1108 	bhnd_addr_t			 addr;
1109 	bus_size_t			 res_offset;
1110 	int				 error;
1111 
1112 	pio = (struct bhndb_pci_eio *)eio;
1113 
1114 	/* Calculate absolute address */
1115 	if (BHND_SIZE_MAX - offset < pio->addr) {
1116 		device_printf(pio->dev, "invalid offset %#jx+%#jx\n", pio->addr,
1117 		    offset);
1118 		return (UINT32_MAX);
1119 	}
1120 
1121 	addr = pio->addr + offset;
1122 
1123 	/* Adjust the mapping for our read */
1124 	if ((error = bhndb_pci_eio_adjust_mapping(pio, addr, width))) {
1125 		device_printf(pio->dev, "failed to adjust register mapping: "
1126 		    "%d\n", error);
1127 		return (UINT32_MAX);
1128 	}
1129 
1130 	KASSERT(pio->res_target <= addr, ("invalid mapping (%#jx vs. %#jx)",
1131 	    pio->res_target, addr));
1132 
1133 	/* Determine the actual read offset within our register window
1134 	 * resource */
1135 	res_offset = (addr - pio->res_target) + pio->win->win_offset;
1136 
1137 	/* Perform our read */
1138 	switch (width) {
1139 	case 1:
1140 		return (bus_read_1(pio->res, res_offset));
1141 	case 2:
1142 		return (bus_read_2(pio->res, res_offset));
1143 	case 4:
1144 		return (bus_read_4(pio->res, res_offset));
1145 	default:
1146 		panic("unsupported width: %u", width);
1147 	}
1148 }
1149 
1150 static device_method_t bhndb_pci_methods[] = {
1151 	/* Device interface */
1152 	DEVMETHOD(device_probe,			bhndb_pci_probe),
1153 	DEVMETHOD(device_attach,		bhndb_pci_attach),
1154 	DEVMETHOD(device_resume,		bhndb_pci_resume),
1155 	DEVMETHOD(device_suspend,		bhndb_pci_suspend),
1156 	DEVMETHOD(device_detach,		bhndb_pci_detach),
1157 
1158 	/* BHND interface */
1159 	DEVMETHOD(bhnd_bus_assign_intr,		bhndb_pci_assign_intr),
1160 
1161 	DEVMETHOD(bhnd_bus_pwrctl_get_clksrc,	bhndb_pci_pwrctl_get_clksrc),
1162 	DEVMETHOD(bhnd_bus_pwrctl_gate_clock,	bhndb_pci_pwrctl_gate_clock),
1163 	DEVMETHOD(bhnd_bus_pwrctl_ungate_clock,	bhndb_pci_pwrctl_ungate_clock),
1164 
1165 	/* BHNDB interface */
1166 	DEVMETHOD(bhndb_set_window_addr,	bhndb_pci_set_window_addr),
1167 	DEVMETHOD(bhndb_populate_board_info,	bhndb_pci_populate_board_info),
1168 
1169 	DEVMETHOD_END
1170 };
1171 
1172 DEFINE_CLASS_1(bhndb, bhndb_pci_driver, bhndb_pci_methods,
1173     sizeof(struct bhndb_pci_softc), bhndb_driver);
1174 
1175 MODULE_VERSION(bhndb_pci, 1);
1176 MODULE_DEPEND(bhndb_pci, bhnd_pci_hostb, 1, 1, 1);
1177 MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1);
1178 MODULE_DEPEND(bhndb_pci, bhndb, 1, 1, 1);
1179 MODULE_DEPEND(bhndb_pci, bhnd, 1, 1, 1);
1180