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#include <dev/pci/pcib_private.h>
57
58#include <machine/bus.h>
59#include <machine/resource.h>
60#include <machine/smp.h>
61#include <machine/intr.h>
62
63#include <arm64/cavium/thunder_pcie_common.h>
64#include <arm64/cavium/thunder_pcie_pem.h>
65#include "pcib_if.h"
66
67#define	THUNDER_PEM_DEVICE_ID		0xa020
68#define	THUNDER_PEM_VENDOR_ID		0x177d
69
70/* ThunderX specific defines */
71#define	THUNDER_PEMn_REG_BASE(unit)	(0x87e0c0000000UL | ((unit) << 24))
72#define	PCIERC_CFG002			0x08
73#define	PCIERC_CFG006			0x18
74#define	PCIERC_CFG032			0x80
75#define	PCIERC_CFG006_SEC_BUS(reg)	(((reg) >> 8) & 0xFF)
76#define	PEM_CFG_RD_REG_ALIGN(reg)	((reg) & ~0x3)
77#define	PEM_CFG_RD_REG_DATA(val)	(((val) >> 32) & 0xFFFFFFFF)
78#define	PEM_CFG_RD			0x30
79#define	PEM_CFG_LINK_MASK		0x3
80#define	PEM_CFG_LINK_RDY		0x3
81#define	PEM_CFG_SLIX_TO_REG(slix)	((slix) << 4)
82#define	SBNUM_OFFSET			0x8
83#define	SBNUM_MASK			0xFF
84#define	PEM_ON_REG			0x420
85#define	PEM_CTL_STATUS			0x0
86#define	PEM_LINK_ENABLE			(1 << 4)
87#define	PEM_LINK_DLLA			(1 << 29)
88#define	PEM_LINK_LT			(1 << 27)
89#define	PEM_BUS_SHIFT			(24)
90#define	PEM_SLOT_SHIFT			(19)
91#define	PEM_FUNC_SHIFT			(16)
92#define	SLIX_S2M_REGX_ACC		0x874001000000UL
93#define	SLIX_S2M_REGX_ACC_SIZE		0x1000
94#define	SLIX_S2M_REGX_ACC_SPACING	0x001000000000UL
95#define	SLI_BASE			0x880000000000UL
96#define	SLI_WINDOW_SPACING		0x004000000000UL
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
124static int thunder_pem_activate_resource(device_t, device_t, int, int,
125    struct resource *);
126static int thunder_pem_adjust_resource(device_t, device_t, int,
127    struct resource *, rman_res_t, rman_res_t);
128static struct resource * thunder_pem_alloc_resource(device_t, device_t, int,
129    int *, rman_res_t, rman_res_t, rman_res_t, u_int);
130static int thunder_pem_alloc_msi(device_t, device_t, int, int, int *);
131static int thunder_pem_release_msi(device_t, device_t, int, int *);
132static int thunder_pem_alloc_msix(device_t, device_t, int *);
133static int thunder_pem_release_msix(device_t, device_t, int);
134static int thunder_pem_map_msi(device_t, device_t, int, uint64_t *, uint32_t *);
135static int thunder_pem_get_id(device_t, device_t, enum pci_id_type,
136    uintptr_t *);
137static int thunder_pem_attach(device_t);
138static int thunder_pem_deactivate_resource(device_t, device_t, int, int,
139    struct resource *);
140static bus_dma_tag_t thunder_pem_get_dma_tag(device_t, device_t);
141static int thunder_pem_detach(device_t);
142static uint64_t thunder_pem_config_reg_read(struct thunder_pem_softc *, int);
143static int thunder_pem_link_init(struct thunder_pem_softc *);
144static int thunder_pem_maxslots(device_t);
145static int thunder_pem_probe(device_t);
146static uint32_t thunder_pem_read_config(device_t, u_int, u_int, u_int, u_int,
147    int);
148static int thunder_pem_read_ivar(device_t, device_t, int, uintptr_t *);
149static void thunder_pem_release_all(device_t);
150static int thunder_pem_release_resource(device_t, device_t, int, int,
151    struct resource *);
152static struct rman * thunder_pem_rman(struct thunder_pem_softc *, int);
153static void thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *,
154    int, int);
155static void thunder_pem_write_config(device_t, u_int, u_int, u_int, u_int,
156    uint32_t, int);
157static int thunder_pem_write_ivar(device_t, device_t, int, uintptr_t);
158
159/* Global handlers for SLI interface */
160static bus_space_handle_t sli0_s2m_regx_base = 0;
161static bus_space_handle_t sli1_s2m_regx_base = 0;
162
163static device_method_t thunder_pem_methods[] = {
164	/* Device interface */
165	DEVMETHOD(device_probe,			thunder_pem_probe),
166	DEVMETHOD(device_attach,		thunder_pem_attach),
167	DEVMETHOD(device_detach,		thunder_pem_detach),
168
169	/* Bus interface */
170	DEVMETHOD(bus_read_ivar,		thunder_pem_read_ivar),
171	DEVMETHOD(bus_write_ivar,		thunder_pem_write_ivar),
172	DEVMETHOD(bus_alloc_resource,		thunder_pem_alloc_resource),
173	DEVMETHOD(bus_release_resource,		thunder_pem_release_resource),
174	DEVMETHOD(bus_adjust_resource,		thunder_pem_adjust_resource),
175	DEVMETHOD(bus_activate_resource,	thunder_pem_activate_resource),
176	DEVMETHOD(bus_deactivate_resource,	thunder_pem_deactivate_resource),
177	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
178	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
179
180	DEVMETHOD(bus_get_dma_tag,		thunder_pem_get_dma_tag),
181
182	/* pcib interface */
183	DEVMETHOD(pcib_maxslots,		thunder_pem_maxslots),
184	DEVMETHOD(pcib_read_config,		thunder_pem_read_config),
185	DEVMETHOD(pcib_write_config,		thunder_pem_write_config),
186	DEVMETHOD(pcib_alloc_msix,		thunder_pem_alloc_msix),
187	DEVMETHOD(pcib_release_msix,		thunder_pem_release_msix),
188	DEVMETHOD(pcib_alloc_msi,		thunder_pem_alloc_msi),
189	DEVMETHOD(pcib_release_msi,		thunder_pem_release_msi),
190	DEVMETHOD(pcib_map_msi,			thunder_pem_map_msi),
191	DEVMETHOD(pcib_get_id,			thunder_pem_get_id),
192
193	DEVMETHOD_END
194};
195
196DEFINE_CLASS_0(pcib, thunder_pem_driver, thunder_pem_methods,
197    sizeof(struct thunder_pem_softc));
198
199static devclass_t thunder_pem_devclass;
200extern struct bus_space memmap_bus;
201
202DRIVER_MODULE(thunder_pem, pci, thunder_pem_driver, thunder_pem_devclass, 0, 0);
203MODULE_DEPEND(thunder_pem, pci, 1, 1, 1);
204
205static int
206thunder_pem_maxslots(device_t dev)
207{
208
209#if 0
210	/* max slots per bus acc. to standard */
211	return (PCI_SLOTMAX);
212#else
213	/*
214	 * ARM64TODO Workaround - otherwise an em(4) interface appears to be
215	 * present on every PCI function on the bus to which it is connected
216	 */
217	return (0);
218#endif
219}
220
221static int
222thunder_pem_read_ivar(device_t dev, device_t child, int index,
223    uintptr_t *result)
224{
225	struct thunder_pem_softc *sc;
226	int secondary_bus = 0;
227
228	sc = device_get_softc(dev);
229
230	if (index == PCIB_IVAR_BUS) {
231		secondary_bus = thunder_pem_config_reg_read(sc, PCIERC_CFG006);
232		*result = PCIERC_CFG006_SEC_BUS(secondary_bus);
233		return (0);
234	}
235	if (index == PCIB_IVAR_DOMAIN) {
236		*result = sc->id;
237		return (0);
238	}
239
240	return (ENOENT);
241}
242
243static int
244thunder_pem_write_ivar(device_t dev, device_t child, int index,
245    uintptr_t value)
246{
247
248	return (ENOENT);
249}
250
251static int
252thunder_pem_activate_resource(device_t dev, device_t child, int type, int rid,
253    struct resource *r)
254{
255	int err;
256	bus_addr_t paddr;
257	bus_size_t psize;
258	bus_space_handle_t vaddr;
259	struct thunder_pem_softc *sc;
260
261	if ((err = rman_activate_resource(r)) != 0)
262		return (err);
263
264	sc = device_get_softc(dev);
265
266	/*
267	 * If this is a memory resource, map it into the kernel.
268	 */
269	if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
270		paddr = (bus_addr_t)rman_get_start(r);
271		psize = (bus_size_t)rman_get_size(r);
272
273		paddr = range_addr_pci_to_phys(sc->ranges, paddr);
274
275		err = bus_space_map(&memmap_bus, paddr, psize, 0, &vaddr);
276		if (err != 0) {
277			rman_deactivate_resource(r);
278			return (err);
279		}
280		rman_set_bustag(r, &memmap_bus);
281		rman_set_virtual(r, (void *)vaddr);
282		rman_set_bushandle(r, vaddr);
283	}
284	return (0);
285}
286
287/*
288 * This function is an exact copy of nexus_deactivate_resource()
289 * Keep it up-to-date with all changes in nexus. To be removed
290 * once bus-mapping interface is developed.
291 */
292static int
293thunder_pem_deactivate_resource(device_t bus, device_t child, int type, int rid,
294    struct resource *r)
295{
296	bus_size_t psize;
297	bus_space_handle_t vaddr;
298
299	psize = (bus_size_t)rman_get_size(r);
300	vaddr = rman_get_bushandle(r);
301
302	if (vaddr != 0) {
303		bus_space_unmap(&memmap_bus, vaddr, psize);
304		rman_set_virtual(r, NULL);
305		rman_set_bushandle(r, 0);
306	}
307
308	return (rman_deactivate_resource(r));
309}
310
311static int
312thunder_pem_adjust_resource(device_t dev, device_t child, int type,
313    struct resource *res, rman_res_t start, rman_res_t end)
314{
315	struct thunder_pem_softc *sc;
316	struct rman *rm;
317
318	sc = device_get_softc(dev);
319#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
320	if (type == PCI_RES_BUS)
321		return (pci_domain_adjust_bus(sc->id, child, res, start, end));
322#endif
323
324	rm = thunder_pem_rman(sc, type);
325	if (rm == NULL)
326		return (bus_generic_adjust_resource(dev, child, type, res,
327		    start, end));
328	if (!rman_is_region_manager(res, rm))
329		/*
330		 * This means a child device has a memory or I/O
331		 * resource not from you which shouldn't happen.
332		 */
333		return (EINVAL);
334	return (rman_adjust_resource(res, start, end));
335}
336
337static bus_dma_tag_t
338thunder_pem_get_dma_tag(device_t dev, device_t child)
339{
340	struct thunder_pem_softc *sc;
341
342	sc = device_get_softc(dev);
343	return (sc->dmat);
344}
345
346static int
347thunder_pem_alloc_msi(device_t pci, device_t child, int count, int maxcount,
348    int *irqs)
349{
350	device_t bus;
351
352	bus = device_get_parent(pci);
353	return (PCIB_ALLOC_MSI(device_get_parent(bus), child, count, maxcount,
354	    irqs));
355}
356
357static int
358thunder_pem_release_msi(device_t pci, device_t child, int count, int *irqs)
359{
360	device_t bus;
361
362	bus = device_get_parent(pci);
363	return (PCIB_RELEASE_MSI(device_get_parent(bus), child, count, irqs));
364}
365
366static int
367thunder_pem_alloc_msix(device_t pci, device_t child, int *irq)
368{
369	device_t bus;
370
371	bus = device_get_parent(pci);
372	return (PCIB_ALLOC_MSIX(device_get_parent(bus), child, irq));
373}
374
375static int
376thunder_pem_release_msix(device_t pci, device_t child, int irq)
377{
378	device_t bus;
379
380	bus = device_get_parent(pci);
381	return (PCIB_RELEASE_MSIX(device_get_parent(bus), child, irq));
382}
383
384static int
385thunder_pem_map_msi(device_t pci, device_t child, int irq, uint64_t *addr,
386    uint32_t *data)
387{
388	device_t bus;
389
390	bus = device_get_parent(pci);
391	return (PCIB_MAP_MSI(device_get_parent(bus), child, irq, addr, data));
392}
393
394static int
395thunder_pem_get_id(device_t pci, device_t child, enum pci_id_type type,
396    uintptr_t *id)
397{
398	int bsf;
399	int pem;
400
401	if (type != PCI_ID_MSI)
402		return (pcib_get_id(pci, child, type, id));
403
404	bsf = pci_get_rid(child);
405
406	/* PEM (PCIe MAC/root complex) number is equal to domain */
407	pem = pci_get_domain(child);
408
409	/*
410	 * Set appropriate device ID (passed by the HW along with
411	 * the transaction to memory) for different root complex
412	 * numbers using hard-coded domain portion for each group.
413	 */
414	if (pem < 3)
415		*id = (0x1 << PCI_RID_DOMAIN_SHIFT) | bsf;
416	else if (pem < 6)
417		*id = (0x3 << PCI_RID_DOMAIN_SHIFT) | bsf;
418	else if (pem < 9)
419		*id = (0x9 << PCI_RID_DOMAIN_SHIFT) | bsf;
420	else if (pem < 12)
421		*id = (0xB << PCI_RID_DOMAIN_SHIFT) | bsf;
422	else
423		return (ENXIO);
424
425	return (0);
426}
427
428static int
429thunder_pem_identify(device_t dev)
430{
431	struct thunder_pem_softc *sc;
432	rman_res_t start;
433
434	sc = device_get_softc(dev);
435	start = rman_get_start(sc->reg);
436
437	/* Calculate PEM designations from its address */
438	sc->node = (start >> SLI_NODE_SHIFT) & SLI_NODE_MASK;
439	sc->id = ((start >> SLI_ID_SHIFT) & SLI_ID_MASK) +
440	    (SLI_PEMS_PER_NODE * sc->node);
441	sc->sli = sc->id % SLI_PEMS_PER_GROUP;
442	sc->sli_group = (sc->id / SLI_PEMS_PER_GROUP) % SLI_GROUPS_PER_NODE;
443	sc->sli_window_base = SLI_BASE |
444	    (((uint64_t)sc->node) << SLI_NODE_SHIFT) |
445	    ((uint64_t)sc->sli_group << SLI_GROUP_SHIFT);
446	sc->sli_window_base += SLI_WINDOW_SPACING * sc->sli;
447
448	return (0);
449}
450
451static void
452thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *sc,
453    int sli_group, int slix)
454{
455	uint64_t regval;
456	bus_space_handle_t handle = 0;
457
458	KASSERT(slix >= 0 && slix <= SLI_ACC_REG_CNT, ("Invalid SLI index"));
459
460	if (sli_group == 0)
461		handle = sli0_s2m_regx_base;
462	else if (sli_group == 1)
463		handle = sli1_s2m_regx_base;
464	else
465		device_printf(sc->dev, "SLI group is not correct\n");
466
467	if (handle) {
468		/* Clear lower 32-bits of the SLIx register */
469		regval = bus_space_read_8(sc->reg_bst, handle,
470		    PEM_CFG_SLIX_TO_REG(slix));
471		regval &= ~(0xFFFFFFFFUL);
472		bus_space_write_8(sc->reg_bst, handle,
473		    PEM_CFG_SLIX_TO_REG(slix), regval);
474	}
475}
476
477static int
478thunder_pem_link_init(struct thunder_pem_softc *sc)
479{
480	uint64_t regval;
481
482	/* check whether PEM is safe to access. */
483	regval = bus_space_read_8(sc->reg_bst, sc->reg_bsh, PEM_ON_REG);
484	if ((regval & PEM_CFG_LINK_MASK) != PEM_CFG_LINK_RDY) {
485		device_printf(sc->dev, "PEM%d is not ON\n", sc->id);
486		return (ENXIO);
487	}
488
489	regval = bus_space_read_8(sc->reg_bst, sc->reg_bsh, PEM_CTL_STATUS);
490	regval |= PEM_LINK_ENABLE;
491	bus_space_write_8(sc->reg_bst, sc->reg_bsh, PEM_CTL_STATUS, regval);
492
493	/* Wait 1ms as per Cavium specification */
494	DELAY(1000);
495
496	regval = thunder_pem_config_reg_read(sc, PCIERC_CFG032);
497
498	if (((regval & PEM_LINK_DLLA) == 0) || ((regval & PEM_LINK_LT) != 0)) {
499		device_printf(sc->dev, "PCIe RC: Port %d Link Timeout\n",
500		    sc->id);
501		return (ENXIO);
502	}
503
504	return (0);
505}
506
507static int
508thunder_pem_init(struct thunder_pem_softc *sc)
509{
510	int i, retval = 0;
511
512	retval = thunder_pem_link_init(sc);
513	if (retval) {
514		device_printf(sc->dev, "%s failed\n", __func__);
515		return retval;
516	}
517
518	/* To support 32-bit PCIe devices, set S2M_REGx_ACC[BA]=0x0 */
519	for (i = 0; i < SLI_ACC_REG_CNT; i++) {
520		thunder_pem_slix_s2m_regx_acc_modify(sc, sc->sli_group, i);
521	}
522
523	return (retval);
524}
525
526static uint64_t
527thunder_pem_config_reg_read(struct thunder_pem_softc *sc, int reg)
528{
529	uint64_t data;
530
531	/* Write to ADDR register */
532	bus_space_write_8(sc->reg_bst, sc->reg_bsh, PEM_CFG_RD,
533	    PEM_CFG_RD_REG_ALIGN(reg));
534	bus_space_barrier(sc->reg_bst, sc->reg_bsh, PEM_CFG_RD, 8,
535	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
536	/* Read from DATA register */
537	data = PEM_CFG_RD_REG_DATA(bus_space_read_8(sc->reg_bst, sc->reg_bsh,
538	    PEM_CFG_RD));
539
540	return (data);
541}
542
543static uint32_t
544thunder_pem_read_config(device_t dev, u_int bus, u_int slot,
545    u_int func, u_int reg, int bytes)
546{
547	uint64_t offset;
548	uint32_t data;
549	struct thunder_pem_softc *sc;
550	bus_space_tag_t	t;
551	bus_space_handle_t h;
552
553	if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) ||
554	    (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX))
555		return (~0U);
556
557	sc = device_get_softc(dev);
558
559	/* Calculate offset */
560	offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) |
561	    (func << PEM_FUNC_SHIFT);
562	t = sc->reg_bst;
563	h = sc->pem_sli_base;
564
565	bus_space_map(sc->reg_bst, sc->sli_window_base + offset,
566	    PCIE_REGMAX, 0, &h);
567
568	switch (bytes) {
569	case 1:
570		data = bus_space_read_1(t, h, reg);
571		break;
572	case 2:
573		data = le16toh(bus_space_read_2(t, h, reg));
574		break;
575	case 4:
576		data = le32toh(bus_space_read_4(t, h, reg));
577		break;
578	default:
579		data = ~0U;
580		break;
581	}
582
583	bus_space_unmap(sc->reg_bst, h, PCIE_REGMAX);
584
585	return (data);
586}
587
588static void
589thunder_pem_write_config(device_t dev, u_int bus, u_int slot,
590    u_int func, u_int reg, uint32_t val, int bytes)
591{
592	uint64_t offset;
593	struct thunder_pem_softc *sc;
594	bus_space_tag_t	t;
595	bus_space_handle_t h;
596
597	if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) ||
598	    (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX))
599		return;
600
601	sc = device_get_softc(dev);
602
603	/* Calculate offset */
604	offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) |
605	    (func << PEM_FUNC_SHIFT);
606	t = sc->reg_bst;
607	h = sc->pem_sli_base;
608
609	bus_space_map(sc->reg_bst, sc->sli_window_base + offset,
610	    PCIE_REGMAX, 0, &h);
611
612	switch (bytes) {
613	case 1:
614		bus_space_write_1(t, h, reg, val);
615		break;
616	case 2:
617		bus_space_write_2(t, h, reg, htole16(val));
618		break;
619	case 4:
620		bus_space_write_4(t, h, reg, htole32(val));
621		break;
622	default:
623		break;
624	}
625
626	bus_space_unmap(sc->reg_bst, h, PCIE_REGMAX);
627}
628
629static struct resource *
630thunder_pem_alloc_resource(device_t dev, device_t child, int type, int *rid,
631    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
632{
633	struct thunder_pem_softc *sc = device_get_softc(dev);
634	struct rman *rm = NULL;
635	struct resource *res;
636	device_t parent_dev;
637
638#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
639	if (type == PCI_RES_BUS)
640		return (pci_domain_alloc_bus(sc->id, child, rid, start,  end,
641		    count, flags));
642#endif
643	rm = thunder_pem_rman(sc, type);
644	if (rm == NULL) {
645		/* Find parent device. On ThunderX we know an exact path. */
646		parent_dev = device_get_parent(device_get_parent(dev));
647		return (BUS_ALLOC_RESOURCE(parent_dev, dev, type, rid, start,
648		    end, count, flags));
649	}
650
651	if (!RMAN_IS_DEFAULT_RANGE(start, end)) {
652		/*
653		 * We might get PHYS addresses here inherited from EFI.
654		 * Convert to PCI if necessary.
655		 */
656		if (range_addr_is_phys(sc->ranges, start, count)) {
657			start = range_addr_phys_to_pci(sc->ranges, start);
658			end = start + count - 1;
659		}
660	}
661
662	if (bootverbose) {
663		device_printf(dev,
664		    "thunder_pem_alloc_resource: start=%#lx, end=%#lx, count=%#lx\n",
665		    start, end, count);
666	}
667
668	res = rman_reserve_resource(rm, start, end, count, flags, child);
669	if (res == NULL)
670		goto fail;
671
672	rman_set_rid(res, *rid);
673
674	if (flags & RF_ACTIVE)
675		if (bus_activate_resource(child, type, *rid, res)) {
676			rman_release_resource(res);
677			goto fail;
678		}
679
680	return (res);
681
682fail:
683	if (bootverbose) {
684		device_printf(dev, "%s FAIL: type=%d, rid=%d, "
685		    "start=%016lx, end=%016lx, count=%016lx, flags=%x\n",
686		    __func__, type, *rid, start, end, count, flags);
687	}
688
689	return (NULL);
690}
691
692static int
693thunder_pem_release_resource(device_t dev, device_t child, int type, int rid,
694    struct resource *res)
695{
696	device_t parent_dev;
697#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
698	struct thunder_pem_softc *sc = device_get_softc(dev);
699
700	if (type == PCI_RES_BUS)
701		return (pci_domain_release_bus(sc->id, child, rid, res));
702#endif
703	/* Find parent device. On ThunderX we know an exact path. */
704	parent_dev = device_get_parent(device_get_parent(dev));
705
706	if ((type != SYS_RES_MEMORY) && (type != SYS_RES_IOPORT))
707		return (BUS_RELEASE_RESOURCE(parent_dev, child,
708		    type, rid, res));
709
710	return (rman_release_resource(res));
711}
712
713static struct rman *
714thunder_pem_rman(struct thunder_pem_softc *sc, int type)
715{
716
717	switch (type) {
718	case SYS_RES_IOPORT:
719		return (&sc->io_rman);
720	case SYS_RES_MEMORY:
721		return (&sc->mem_rman);
722	default:
723		break;
724	}
725
726	return (NULL);
727}
728
729static int
730thunder_pem_probe(device_t dev)
731{
732	uint16_t pci_vendor_id;
733	uint16_t pci_device_id;
734
735	pci_vendor_id = pci_get_vendor(dev);
736	pci_device_id = pci_get_device(dev);
737
738	if ((pci_vendor_id == THUNDER_PEM_VENDOR_ID) &&
739	    (pci_device_id == THUNDER_PEM_DEVICE_ID)) {
740		device_set_desc_copy(dev, THUNDER_PEM_DESC);
741		return (0);
742	}
743
744	return (ENXIO);
745}
746
747static int
748thunder_pem_attach(device_t dev)
749{
750	devclass_t pci_class;
751	device_t parent;
752	struct thunder_pem_softc *sc;
753	int error;
754	int rid;
755	int tuple;
756	uint64_t base, size;
757	struct rman *rman;
758
759	sc = device_get_softc(dev);
760	sc->dev = dev;
761
762	/* Allocate memory for resource */
763	pci_class = devclass_find("pci");
764	parent = device_get_parent(dev);
765	if (device_get_devclass(parent) == pci_class)
766		rid = PCIR_BAR(0);
767	else
768		rid = RID_PEM_SPACE;
769
770	sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
771	    &rid, RF_ACTIVE);
772	if (sc->reg == NULL) {
773		device_printf(dev, "Failed to allocate resource\n");
774		return (ENXIO);
775	}
776	sc->reg_bst = rman_get_bustag(sc->reg);
777	sc->reg_bsh = rman_get_bushandle(sc->reg);
778
779	/* Create the parent DMA tag to pass down the coherent flag */
780	error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
781	    1, 0,			/* alignment, bounds */
782	    BUS_SPACE_MAXADDR,		/* lowaddr */
783	    BUS_SPACE_MAXADDR,		/* highaddr */
784	    NULL, NULL,			/* filter, filterarg */
785	    BUS_SPACE_MAXSIZE,		/* maxsize */
786	    BUS_SPACE_UNRESTRICTED,	/* nsegments */
787	    BUS_SPACE_MAXSIZE,		/* maxsegsize */
788	    BUS_DMA_COHERENT,		/* flags */
789	    NULL, NULL,			/* lockfunc, lockarg */
790	    &sc->dmat);
791	if (error != 0)
792		return (error);
793
794	/* Map SLI, do it only once */
795	if (!sli0_s2m_regx_base) {
796		bus_space_map(sc->reg_bst, SLIX_S2M_REGX_ACC,
797		    SLIX_S2M_REGX_ACC_SIZE, 0, &sli0_s2m_regx_base);
798	}
799	if (!sli1_s2m_regx_base) {
800		bus_space_map(sc->reg_bst, SLIX_S2M_REGX_ACC +
801		    SLIX_S2M_REGX_ACC_SPACING, SLIX_S2M_REGX_ACC_SIZE, 0,
802		    &sli1_s2m_regx_base);
803	}
804
805	if ((sli0_s2m_regx_base == 0) || (sli1_s2m_regx_base == 0)) {
806		device_printf(dev,
807		    "bus_space_map failed to map slix_s2m_regx_base\n");
808		goto fail;
809	}
810
811	/* Identify PEM */
812	if (thunder_pem_identify(dev) != 0)
813		goto fail;
814
815	/* Initialize rman and allocate regions */
816	sc->mem_rman.rm_type = RMAN_ARRAY;
817	sc->mem_rman.rm_descr = "PEM PCIe Memory";
818	error = rman_init(&sc->mem_rman);
819	if (error != 0) {
820		device_printf(dev, "memory rman_init() failed. error = %d\n",
821		    error);
822		goto fail;
823	}
824	sc->io_rman.rm_type = RMAN_ARRAY;
825	sc->io_rman.rm_descr = "PEM PCIe IO";
826	error = rman_init(&sc->io_rman);
827	if (error != 0) {
828		device_printf(dev, "IO rman_init() failed. error = %d\n",
829		    error);
830		goto fail_mem;
831	}
832
833	/*
834	 * We ignore the values that may have been provided in FDT
835	 * and configure ranges according to the below formula
836	 * for all types of devices. This is because some DTBs provided
837	 * by EFI do not have proper ranges property or don't have them
838	 * at all.
839	 */
840	/* Fill memory window */
841	sc->ranges[0].pci_base = PCI_MEMORY_BASE;
842	sc->ranges[0].size = PCI_MEMORY_SIZE;
843	sc->ranges[0].phys_base = sc->sli_window_base + SLI_PCI_OFFSET +
844	    sc->ranges[0].pci_base;
845	sc->ranges[0].flags = SYS_RES_MEMORY;
846
847	/* Fill IO window */
848	sc->ranges[1].pci_base = PCI_IO_BASE;
849	sc->ranges[1].size = PCI_IO_SIZE;
850	sc->ranges[1].phys_base = sc->sli_window_base + SLI_PCI_OFFSET +
851	    sc->ranges[1].pci_base;
852	sc->ranges[1].flags = SYS_RES_IOPORT;
853
854	for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
855		base = sc->ranges[tuple].pci_base;
856		size = sc->ranges[tuple].size;
857		if (size == 0)
858			continue; /* empty range element */
859
860		rman = thunder_pem_rman(sc, sc->ranges[tuple].flags);
861		if (rman != NULL)
862			error = rman_manage_region(rman, base,
863			    base + size - 1);
864		else
865			error = EINVAL;
866		if (error) {
867			device_printf(dev,
868			    "rman_manage_region() failed. error = %d\n", error);
869			rman_fini(&sc->mem_rman);
870			return (error);
871		}
872		if (bootverbose) {
873			device_printf(dev,
874			    "\tPCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx, Flags:0x%jx\n",
875			    sc->ranges[tuple].pci_base,
876			    sc->ranges[tuple].phys_base,
877			    sc->ranges[tuple].size,
878			    sc->ranges[tuple].flags);
879		}
880	}
881
882	if (thunder_pem_init(sc)) {
883		device_printf(dev, "Failure during PEM init\n");
884		goto fail_io;
885	}
886
887	device_add_child(dev, "pci", -1);
888
889	return (bus_generic_attach(dev));
890
891fail_io:
892	rman_fini(&sc->io_rman);
893fail_mem:
894	rman_fini(&sc->mem_rman);
895fail:
896	bus_free_resource(dev, SYS_RES_MEMORY, sc->reg);
897	return (ENXIO);
898}
899
900static void
901thunder_pem_release_all(device_t dev)
902{
903	struct thunder_pem_softc *sc;
904
905	sc = device_get_softc(dev);
906
907	rman_fini(&sc->io_rman);
908	rman_fini(&sc->mem_rman);
909
910	if (sc->reg != NULL)
911		bus_free_resource(dev, SYS_RES_MEMORY, sc->reg);
912}
913
914static int
915thunder_pem_detach(device_t dev)
916{
917
918	thunder_pem_release_all(dev);
919
920	return (0);
921}
922