xref: /freebsd/sys/arm64/cavium/thunder_pcie_pem.c (revision 0b3105a37d7adcadcb720112fed4dc4e8040be99)
1 /*-
2  * Copyright (c) 2015 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Semihalf under
6  * the sponsorship of the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /* PCIe external MAC root complex driver (PEM) for Cavium Thunder SOC */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include "opt_platform.h"
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/bus.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/module.h>
43 #include <sys/rman.h>
44 #include <sys/endian.h>
45 
46 #ifdef FDT
47 #include <dev/ofw/openfirm.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
50 #include <dev/ofw/ofw_pci.h>
51 #endif
52 
53 #include <dev/pci/pcivar.h>
54 #include <dev/pci/pcireg.h>
55 #include <dev/pci/pci_host_generic.h>
56 
57 #include <machine/bus.h>
58 #include <machine/resource.h>
59 #include <machine/smp.h>
60 #include <machine/intr.h>
61 
62 #include <arm64/cavium/thunder_pcie_common.h>
63 #include <arm64/cavium/thunder_pcie_pem.h>
64 #include "pcib_if.h"
65 
66 #define	THUNDER_PEM_DEVICE_ID		0xa020
67 #define	THUNDER_PEM_VENDOR_ID		0x177d
68 
69 /* ThunderX specific defines */
70 #define	THUNDER_PEMn_REG_BASE(unit)	(0x87e0c0000000UL | ((unit) << 24))
71 #define	PCIERC_CFG002			0x08
72 #define	PCIERC_CFG006			0x18
73 #define	PCIERC_CFG032			0x80
74 #define	PCIERC_CFG006_SEC_BUS(reg)	(((reg) >> 8) & 0xFF)
75 #define	PEM_CFG_RD_REG_ALIGN(reg)	((reg) & ~0x3)
76 #define	PEM_CFG_RD_REG_DATA(val)	(((val) >> 32) & 0xFFFFFFFF)
77 #define	PEM_CFG_RD			0x30
78 #define	PEM_CFG_LINK_MASK		0x3
79 #define	PEM_CFG_LINK_RDY		0x3
80 #define	PEM_CFG_SLIX_TO_REG(slix)	((slix) << 4)
81 #define	SBNUM_OFFSET			0x8
82 #define	SBNUM_MASK			0xFF
83 #define	PEM_ON_REG			0x420
84 #define	PEM_CTL_STATUS			0x0
85 #define	PEM_LINK_ENABLE			(1 << 4)
86 #define	PEM_LINK_DLLA			(1 << 29)
87 #define	PEM_LINK_LT			(1 << 27)
88 #define	PEM_BUS_SHIFT			(24)
89 #define	PEM_SLOT_SHIFT			(19)
90 #define	PEM_FUNC_SHIFT			(16)
91 #define	SLIX_S2M_REGX_ACC		0x874001000000UL
92 #define	SLIX_S2M_REGX_ACC_SIZE		0x1000
93 #define	SLIX_S2M_REGX_ACC_SPACING	0x001000000000UL
94 #define	SLI_BASE			0x880000000000UL
95 #define	SLI_WINDOW_SPACING		0x004000000000UL
96 #define	SLI_WINDOW_SIZE			0x0000FF000000UL
97 #define	SLI_PCI_OFFSET			0x001000000000UL
98 #define	SLI_NODE_SHIFT			(44)
99 #define	SLI_NODE_MASK			(3)
100 #define	SLI_GROUP_SHIFT			(40)
101 #define	SLI_ID_SHIFT			(24)
102 #define	SLI_ID_MASK			(7)
103 #define	SLI_PEMS_PER_GROUP		(3)
104 #define	SLI_GROUPS_PER_NODE		(2)
105 #define	SLI_PEMS_PER_NODE		(SLI_PEMS_PER_GROUP * SLI_GROUPS_PER_NODE)
106 #define	SLI_ACC_REG_CNT			(256)
107 
108 /*
109  * Each PEM device creates its own bus with
110  * own address translation, so we can adjust bus addresses
111  * as we want. To support 32-bit cards let's assume
112  * PCI window assignment looks as following:
113  *
114  * 0x00000000 - 0x000FFFFF	IO
115  * 0x00100000 - 0xFFFFFFFF	Memory
116  */
117 #define	PCI_IO_BASE		0x00000000UL
118 #define	PCI_IO_SIZE		0x00100000UL
119 #define	PCI_MEMORY_BASE		PCI_IO_SIZE
120 #define	PCI_MEMORY_SIZE		0xFFF00000UL
121 
122 #define	RID_PEM_SPACE		1
123 
124 static struct resource * thunder_pem_alloc_resource(device_t, device_t, int,
125     int *, rman_res_t, rman_res_t, rman_res_t, u_int);
126 static int thunder_pem_attach(device_t);
127 static int thunder_pem_detach(device_t);
128 static uint64_t thunder_pem_config_reg_read(struct thunder_pem_softc *, int);
129 static int thunder_pem_link_init(struct thunder_pem_softc *);
130 static int thunder_pem_maxslots(device_t);
131 static int thunder_pem_probe(device_t);
132 static uint32_t thunder_pem_read_config(device_t, u_int, u_int, u_int, u_int,
133     int);
134 static int thunder_pem_read_ivar(device_t, device_t, int, uintptr_t *);
135 static void thunder_pem_release_all(device_t);
136 static int thunder_pem_release_resource(device_t, device_t, int, int,
137     struct resource *);
138 static void thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *,
139     int, int);
140 static void thunder_pem_write_config(device_t, u_int, u_int, u_int, u_int,
141     uint32_t, int);
142 static int thunder_pem_write_ivar(device_t, device_t, int, uintptr_t);
143 
144 /* Global handlers for SLI interface */
145 static bus_space_handle_t sli0_s2m_regx_base = 0;
146 static bus_space_handle_t sli1_s2m_regx_base = 0;
147 
148 static device_method_t thunder_pem_methods[] = {
149 	/* Device interface */
150 	DEVMETHOD(device_probe,			thunder_pem_probe),
151 	DEVMETHOD(device_attach,		thunder_pem_attach),
152 	DEVMETHOD(device_detach,		thunder_pem_detach),
153 	DEVMETHOD(pcib_maxslots,		thunder_pem_maxslots),
154 	DEVMETHOD(pcib_read_config,		thunder_pem_read_config),
155 	DEVMETHOD(pcib_write_config,		thunder_pem_write_config),
156 	DEVMETHOD(bus_read_ivar,		thunder_pem_read_ivar),
157 	DEVMETHOD(bus_write_ivar,		thunder_pem_write_ivar),
158 	DEVMETHOD(bus_alloc_resource,		thunder_pem_alloc_resource),
159 	DEVMETHOD(bus_release_resource,		thunder_pem_release_resource),
160 	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
161 	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
162 	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
163 	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
164 
165 	DEVMETHOD(pcib_map_msi,			arm_map_msi),
166 	DEVMETHOD(pcib_alloc_msix,		arm_alloc_msix),
167 	DEVMETHOD(pcib_release_msix,		arm_release_msix),
168 	DEVMETHOD(pcib_alloc_msi,		arm_alloc_msi),
169 	DEVMETHOD(pcib_release_msi,		arm_release_msi),
170 	DEVMETHOD_END
171 };
172 
173 DEFINE_CLASS_0(pcib, thunder_pem_driver, thunder_pem_methods,
174     sizeof(struct thunder_pem_softc));
175 
176 static devclass_t thunder_pem_devclass;
177 
178 DRIVER_MODULE(thunder_pem, pci, thunder_pem_driver, thunder_pem_devclass, 0, 0);
179 MODULE_DEPEND(thunder_pem, pci, 1, 1, 1);
180 
181 static int
182 thunder_pem_maxslots(device_t dev)
183 {
184 
185 #if 0
186 	/* max slots per bus acc. to standard */
187 	return (PCI_SLOTMAX);
188 #else
189 	/*
190 	 * ARM64TODO Workaround - otherwise an em(4) interface appears to be
191 	 * present on every PCI function on the bus to which it is connected
192 	 */
193 	return (0);
194 #endif
195 }
196 
197 static int
198 thunder_pem_read_ivar(device_t dev, device_t child, int index,
199     uintptr_t *result)
200 {
201 	struct thunder_pem_softc *sc;
202 	int secondary_bus = 0;
203 
204 	sc = device_get_softc(dev);
205 
206 	if (index == PCIB_IVAR_BUS) {
207 		secondary_bus = thunder_pem_config_reg_read(sc, PCIERC_CFG006);
208 		*result = PCIERC_CFG006_SEC_BUS(secondary_bus);
209 		return (0);
210 	}
211 	if (index == PCIB_IVAR_DOMAIN) {
212 		*result = sc->id;
213 		return (0);
214 	}
215 
216 	return (ENOENT);
217 }
218 
219 static int
220 thunder_pem_write_ivar(device_t dev, device_t child, int index,
221     uintptr_t value)
222 {
223 
224 	return (ENOENT);
225 }
226 
227 static int
228 thunder_pem_identify(device_t dev)
229 {
230 	struct thunder_pem_softc *sc;
231 	rman_res_t start;
232 
233 	sc = device_get_softc(dev);
234 	start = rman_get_start(sc->reg);
235 
236 	/* Calculate PEM designations from its address */
237 	sc->node = (start >> SLI_NODE_SHIFT) & SLI_NODE_MASK;
238 	sc->id = ((start >> SLI_ID_SHIFT) & SLI_ID_MASK) +
239 	    (SLI_PEMS_PER_NODE * sc->node);
240 	sc->sli = sc->id % SLI_PEMS_PER_GROUP;
241 	sc->sli_group = (sc->id / SLI_PEMS_PER_GROUP) % SLI_GROUPS_PER_NODE;
242 	sc->sli_window_base = SLI_BASE |
243 	    (((uint64_t)sc->node) << SLI_NODE_SHIFT) |
244 	    ((uint64_t)sc->sli_group << SLI_GROUP_SHIFT);
245 	sc->sli_window_base += SLI_WINDOW_SPACING * sc->sli;
246 
247 	return (0);
248 }
249 
250 static void
251 thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *sc,
252     int sli_group, int slix)
253 {
254 	uint64_t regval;
255 	bus_space_handle_t handle = 0;
256 
257 	KASSERT(slix >= 0 && slix <= SLI_ACC_REG_CNT, ("Invalid SLI index"));
258 
259 	if (sli_group == 0)
260 		handle = sli0_s2m_regx_base;
261 	else if (sli_group == 1)
262 		handle = sli1_s2m_regx_base;
263 	else
264 		device_printf(sc->dev, "SLI group is not correct\n");
265 
266 	if (handle) {
267 		/* Clear lower 32-bits of the SLIx register */
268 		regval = bus_space_read_8(sc->reg_bst, handle,
269 		    PEM_CFG_SLIX_TO_REG(slix));
270 		regval &= ~(0xFFFFFFFFUL);
271 		bus_space_write_8(sc->reg_bst, handle,
272 		    PEM_CFG_SLIX_TO_REG(slix), regval);
273 	}
274 }
275 
276 static int
277 thunder_pem_link_init(struct thunder_pem_softc *sc)
278 {
279 	uint64_t regval;
280 
281 	/* check whether PEM is safe to access. */
282 	regval = bus_space_read_8(sc->reg_bst, sc->reg_bsh, PEM_ON_REG);
283 	if ((regval & PEM_CFG_LINK_MASK) != PEM_CFG_LINK_RDY) {
284 		device_printf(sc->dev, "PEM%d is not ON\n", sc->id);
285 		return (ENXIO);
286 	}
287 
288 	regval = bus_space_read_8(sc->reg_bst, sc->reg_bsh, PEM_CTL_STATUS);
289 	regval |= PEM_LINK_ENABLE;
290 	bus_space_write_8(sc->reg_bst, sc->reg_bsh, PEM_CTL_STATUS, regval);
291 
292 	/* Wait 1ms as per Cavium specification */
293 	DELAY(1000);
294 
295 	regval = thunder_pem_config_reg_read(sc, PCIERC_CFG032);
296 
297 	if (((regval & PEM_LINK_DLLA) == 0) || ((regval & PEM_LINK_LT) != 0)) {
298 		device_printf(sc->dev, "PCIe RC: Port %d Link Timeout\n",
299 		    sc->id);
300 		return (ENXIO);
301 	}
302 
303 	return (0);
304 }
305 
306 static int
307 thunder_pem_init(struct thunder_pem_softc *sc)
308 {
309 	int i, retval = 0;
310 
311 	retval = thunder_pem_link_init(sc);
312 	if (retval) {
313 		device_printf(sc->dev, "%s failed\n", __func__);
314 		return retval;
315 	}
316 
317 	retval = bus_space_map(sc->reg_bst, sc->sli_window_base,
318 	    SLI_WINDOW_SIZE, 0, &sc->pem_sli_base);
319 	if (retval) {
320 		device_printf(sc->dev,
321 		    "Unable to map RC%d pem_addr base address", sc->id);
322 		return (ENOMEM);
323 	}
324 
325 	/* To support 32-bit PCIe devices, set S2M_REGx_ACC[BA]=0x0 */
326 	for (i = 0; i < SLI_ACC_REG_CNT; i++) {
327 		thunder_pem_slix_s2m_regx_acc_modify(sc, sc->sli_group, i);
328 	}
329 
330 	return (retval);
331 }
332 
333 static uint64_t
334 thunder_pem_config_reg_read(struct thunder_pem_softc *sc, int reg)
335 {
336 	uint64_t data;
337 
338 	/* Write to ADDR register */
339 	bus_space_write_8(sc->reg_bst, sc->reg_bsh, PEM_CFG_RD,
340 	    PEM_CFG_RD_REG_ALIGN(reg));
341 	bus_space_barrier(sc->reg_bst, sc->reg_bsh, PEM_CFG_RD, 8,
342 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
343 	/* Read from DATA register */
344 	data = PEM_CFG_RD_REG_DATA(bus_space_read_8(sc->reg_bst, sc->reg_bsh,
345 	    PEM_CFG_RD));
346 
347 	return (data);
348 }
349 
350 static uint32_t
351 thunder_pem_read_config(device_t dev, u_int bus, u_int slot,
352     u_int func, u_int reg, int bytes)
353 {
354 	uint64_t offset;
355 	uint32_t data;
356 	struct thunder_pem_softc *sc;
357 	bus_space_tag_t	t;
358 	bus_space_handle_t h;
359 
360 	if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) ||
361 	    (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX))
362 		return (~0U);
363 
364 	sc = device_get_softc(dev);
365 
366 	/* Calculate offset */
367 	offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) |
368 	    (func << PEM_FUNC_SHIFT) | reg;
369 	t = sc->reg_bst;
370 	h = sc->pem_sli_base;
371 
372 	switch (bytes) {
373 	case 1:
374 		data = bus_space_read_1(t, h, offset);
375 		break;
376 	case 2:
377 		data = le16toh(bus_space_read_2(t, h, offset));
378 		break;
379 	case 4:
380 		data = le32toh(bus_space_read_4(t, h, offset));
381 		break;
382 	default:
383 		return (~0U);
384 	}
385 
386 	return (data);
387 }
388 
389 static void
390 thunder_pem_write_config(device_t dev, u_int bus, u_int slot,
391     u_int func, u_int reg, uint32_t val, int bytes)
392 {
393 	uint64_t offset;
394 	struct thunder_pem_softc *sc;
395 	bus_space_tag_t	t;
396 	bus_space_handle_t h;
397 
398 	if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) ||
399 	    (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX))
400 		return;
401 
402 	sc = device_get_softc(dev);
403 
404 	/* Calculate offset */
405 	offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) |
406 	    (func << PEM_FUNC_SHIFT) | reg;
407 	t = sc->reg_bst;
408 	h = sc->pem_sli_base;
409 
410 	switch (bytes) {
411 	case 1:
412 		bus_space_write_1(t, h, offset, val);
413 		break;
414 	case 2:
415 		bus_space_write_2(t, h, offset, htole16(val));
416 		break;
417 	case 4:
418 		bus_space_write_4(t, h, offset, htole32(val));
419 		break;
420 	default:
421 		return;
422 	}
423 }
424 
425 static struct resource *
426 thunder_pem_alloc_resource(device_t dev, device_t child, int type, int *rid,
427     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
428 {
429 	struct thunder_pem_softc *sc = device_get_softc(dev);
430 	struct rman *rm = NULL;
431 	struct resource *res;
432 	device_t parent_dev;
433 
434 	switch (type) {
435 	case SYS_RES_IOPORT:
436 		rm = &sc->io_rman;
437 		break;
438 	case SYS_RES_MEMORY:
439 		rm = &sc->mem_rman;
440 		break;
441 	default:
442 		/* Find parent device. On ThunderX we know an exact path. */
443 		parent_dev = device_get_parent(device_get_parent(dev));
444 		return (BUS_ALLOC_RESOURCE(parent_dev, dev, type, rid, start,
445 		    end, count, flags));
446 	};
447 
448 	if (RMAN_IS_DEFAULT_RANGE(start, end)) {
449 		device_printf(dev,
450 		    "Cannot allocate resource with unspecified range\n");
451 		goto fail;
452 	}
453 
454 	/* Translate PCI address to host PHYS */
455 	if (range_addr_is_pci(sc->ranges, start, count) == 0)
456 		goto fail;
457 	start = range_addr_pci_to_phys(sc->ranges, start);
458 	end = start + count - 1;
459 
460 	if (bootverbose) {
461 		device_printf(dev,
462 		    "rman_reserve_resource: start=%#lx, end=%#lx, count=%#lx\n",
463 		    start, end, count);
464 	}
465 
466 	res = rman_reserve_resource(rm, start, end, count, flags, child);
467 	if (res == NULL)
468 		goto fail;
469 
470 	rman_set_rid(res, *rid);
471 
472 	if (flags & RF_ACTIVE)
473 		if (bus_activate_resource(child, type, *rid, res)) {
474 			rman_release_resource(res);
475 			goto fail;
476 		}
477 
478 	return (res);
479 
480 fail:
481 	if (bootverbose) {
482 		device_printf(dev, "%s FAIL: type=%d, rid=%d, "
483 		    "start=%016lx, end=%016lx, count=%016lx, flags=%x\n",
484 		    __func__, type, *rid, start, end, count, flags);
485 	}
486 
487 	return (NULL);
488 }
489 
490 static int
491 thunder_pem_release_resource(device_t dev, device_t child, int type, int rid,
492     struct resource *res)
493 {
494 	device_t parent_dev;
495 
496 	/* Find parent device. On ThunderX we know an exact path. */
497 	parent_dev = device_get_parent(device_get_parent(dev));
498 
499 	if ((type != SYS_RES_MEMORY) && (type != SYS_RES_IOPORT))
500 		return (BUS_RELEASE_RESOURCE(parent_dev, child,
501 		    type, rid, res));
502 
503 	return (rman_release_resource(res));
504 }
505 
506 static int
507 thunder_pem_probe(device_t dev)
508 {
509 	uint16_t pci_vendor_id;
510 	uint16_t pci_device_id;
511 
512 	pci_vendor_id = pci_get_vendor(dev);
513 	pci_device_id = pci_get_device(dev);
514 
515 	if ((pci_vendor_id == THUNDER_PEM_VENDOR_ID) &&
516 	    (pci_device_id == THUNDER_PEM_DEVICE_ID)) {
517 		device_set_desc_copy(dev, THUNDER_PEM_DESC);
518 		return (0);
519 	}
520 
521 	return (ENXIO);
522 }
523 
524 static int
525 thunder_pem_attach(device_t dev)
526 {
527 	devclass_t pci_class;
528 	device_t parent;
529 	struct thunder_pem_softc *sc;
530 	int error;
531 	int rid;
532 
533 	sc = device_get_softc(dev);
534 	sc->dev = dev;
535 
536 	/* Allocate memory for resource */
537 	pci_class = devclass_find("pci");
538 	parent = device_get_parent(dev);
539 	if (device_get_devclass(parent) == pci_class)
540 		rid = PCIR_BAR(0);
541 	else
542 		rid = RID_PEM_SPACE;
543 
544 	sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
545 	    &rid, RF_ACTIVE);
546 	if (sc->reg == NULL) {
547 		device_printf(dev, "Failed to allocate resource\n");
548 		return (ENXIO);
549 	}
550 	sc->reg_bst = rman_get_bustag(sc->reg);
551 	sc->reg_bsh = rman_get_bushandle(sc->reg);
552 
553 	/* Map SLI, do it only once */
554 	if (!sli0_s2m_regx_base) {
555 		bus_space_map(sc->reg_bst, SLIX_S2M_REGX_ACC,
556 		    SLIX_S2M_REGX_ACC_SIZE, 0, &sli0_s2m_regx_base);
557 	}
558 	if (!sli1_s2m_regx_base) {
559 		bus_space_map(sc->reg_bst, SLIX_S2M_REGX_ACC +
560 		    SLIX_S2M_REGX_ACC_SPACING, SLIX_S2M_REGX_ACC_SIZE, 0,
561 		    &sli1_s2m_regx_base);
562 	}
563 
564 	if ((sli0_s2m_regx_base == 0) || (sli1_s2m_regx_base == 0)) {
565 		device_printf(dev,
566 		    "bus_space_map failed to map slix_s2m_regx_base\n");
567 		goto fail;
568 	}
569 
570 	/* Identify PEM */
571 	if (thunder_pem_identify(dev) != 0)
572 		goto fail;
573 
574 	/* Initialize rman and allocate regions */
575 	sc->mem_rman.rm_type = RMAN_ARRAY;
576 	sc->mem_rman.rm_descr = "PEM PCIe Memory";
577 	error = rman_init(&sc->mem_rman);
578 	if (error != 0) {
579 		device_printf(dev, "memory rman_init() failed. error = %d\n",
580 		    error);
581 		goto fail;
582 	}
583 	sc->io_rman.rm_type = RMAN_ARRAY;
584 	sc->io_rman.rm_descr = "PEM PCIe IO";
585 	error = rman_init(&sc->io_rman);
586 	if (error != 0) {
587 		device_printf(dev, "IO rman_init() failed. error = %d\n",
588 		    error);
589 		goto fail_mem;
590 	}
591 
592 	/*
593 	 * We ignore the values that may have been provided in FDT
594 	 * and configure ranges according to the below formula
595 	 * for all types of devices. This is because some DTBs provided
596 	 * by EFI do not have proper ranges property or don't have them
597 	 * at all.
598 	 */
599 	/* Fill memory window */
600 	sc->ranges[0].pci_base = PCI_MEMORY_BASE;
601 	sc->ranges[0].size = PCI_MEMORY_SIZE;
602 	sc->ranges[0].phys_base = sc->sli_window_base + SLI_PCI_OFFSET +
603 	    sc->ranges[0].pci_base;
604 	rman_manage_region(&sc->mem_rman, sc->ranges[0].phys_base,
605 	    sc->ranges[0].phys_base + sc->ranges[0].size - 1);
606 
607 	/* Fill IO window */
608 	sc->ranges[1].pci_base = PCI_IO_BASE;
609 	sc->ranges[1].size = PCI_IO_SIZE;
610 	sc->ranges[1].phys_base = sc->sli_window_base + SLI_PCI_OFFSET +
611 	    sc->ranges[1].pci_base;
612 	rman_manage_region(&sc->io_rman, sc->ranges[1].phys_base,
613 	    sc->ranges[1].phys_base + sc->ranges[1].size - 1);
614 
615 	if (thunder_pem_init(sc)) {
616 		device_printf(dev, "Failure during PEM init\n");
617 		goto fail_io;
618 	}
619 
620 	device_add_child(dev, "pci", -1);
621 
622 	return (bus_generic_attach(dev));
623 
624 fail_io:
625 	rman_fini(&sc->io_rman);
626 fail_mem:
627 	rman_fini(&sc->mem_rman);
628 fail:
629 	bus_free_resource(dev, SYS_RES_MEMORY, sc->reg);
630 	return (ENXIO);
631 }
632 
633 static void
634 thunder_pem_release_all(device_t dev)
635 {
636 	struct thunder_pem_softc *sc;
637 
638 	sc = device_get_softc(dev);
639 
640 	rman_fini(&sc->io_rman);
641 	rman_fini(&sc->mem_rman);
642 
643 	if (sc->reg != NULL)
644 		bus_free_resource(dev, SYS_RES_MEMORY, sc->reg);
645 }
646 
647 static int
648 thunder_pem_detach(device_t dev)
649 {
650 
651 	thunder_pem_release_all(dev);
652 
653 	return (0);
654 }
655