1198160Srrs/*-
2198160Srrs * Copyright (c) 2003-2009 RMI Corporation
3198160Srrs * All rights reserved.
4198160Srrs *
5198160Srrs * Redistribution and use in source and binary forms, with or without
6198160Srrs * modification, are permitted provided that the following conditions
7198160Srrs * are met:
8198160Srrs * 1. Redistributions of source code must retain the above copyright
9198160Srrs *    notice, this list of conditions and the following disclaimer.
10198160Srrs * 2. Redistributions in binary form must reproduce the above copyright
11198160Srrs *    notice, this list of conditions and the following disclaimer in the
12198160Srrs *    documentation and/or other materials provided with the distribution.
13198160Srrs * 3. Neither the name of RMI Corporation, nor the names of its contributors,
14198160Srrs *    may be used to endorse or promote products derived from this software
15198160Srrs *    without specific prior written permission.
16198160Srrs *
17198160Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18198160Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19198160Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20198160Srrs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21198160Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22198160Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23198160Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24198160Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25198160Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26198160Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27198160Srrs * SUCH DAMAGE.
28198160Srrs *
29198160Srrs * RMI_BSD */
30198160Srrs#include <sys/cdefs.h>
31204136Srrs__FBSDID("$FreeBSD$");
32198160Srrs
33198160Srrs#include <sys/param.h>
34204136Srrs#include <sys/systm.h>
35198160Srrs#include <sys/types.h>
36198160Srrs#include <sys/kernel.h>
37198160Srrs#include <sys/module.h>
38198160Srrs#include <sys/malloc.h>
39198160Srrs#include <sys/bus.h>
40204136Srrs#include <sys/endian.h>
41211994Sjchandra#include <sys/rman.h>
42211994Sjchandra
43198160Srrs#include <vm/vm.h>
44198160Srrs#include <vm/vm_param.h>
45198160Srrs#include <vm/pmap.h>
46198160Srrs
47198160Srrs#include <dev/pci/pcivar.h>
48198160Srrs#include <dev/pci/pcireg.h>
49198160Srrs
50211994Sjchandra#include <machine/bus.h>
51211994Sjchandra#include <machine/md_var.h>
52211994Sjchandra#include <machine/intr_machdep.h>
53211994Sjchandra#include <machine/cpuregs.h>
54211994Sjchandra
55211994Sjchandra#include <mips/rmi/rmi_mips_exts.h>
56211994Sjchandra#include <mips/rmi/interrupt.h>
57198607Srrs#include <mips/rmi/iomap.h>
58198607Srrs#include <mips/rmi/pic.h>
59198607Srrs#include <mips/rmi/board.h>
60198607Srrs#include <mips/rmi/pcibus.h>
61204136Srrs
62198160Srrs#include "pcib_if.h"
63198160Srrs
64204136Srrs#define pci_cfg_offset(bus,slot,devfn,where) (((bus)<<16) + ((slot) << 11)+((devfn)<<8)+(where))
65204136Srrs#define PCIE_LINK_STATE    0x4000
66204136Srrs
67198160Srrs#define LSU_CFG0_REGID       0
68198160Srrs#define LSU_CERRLOG_REGID    9
69198160Srrs#define LSU_CERROVF_REGID    10
70198160Srrs#define LSU_CERRINT_REGID    11
71198160Srrs
72198160Srrs/* MSI support */
73204136Srrs#define MSI_MIPS_ADDR_DEST		0x000ff000
74204136Srrs#define MSI_MIPS_ADDR_RH		0x00000008
75204136Srrs#define MSI_MIPS_ADDR_RH_OFF		0x00000000
76204136Srrs#define MSI_MIPS_ADDR_RH_ON		0x00000008
77204136Srrs#define MSI_MIPS_ADDR_DM		0x00000004
78204136Srrs#define MSI_MIPS_ADDR_DM_PHYSICAL	0x00000000
79204136Srrs#define MSI_MIPS_ADDR_DM_LOGICAL	0x00000004
80198160Srrs
81198160Srrs/* Fields in data for Intel MSI messages. */
82204136Srrs#define MSI_MIPS_DATA_TRGRMOD		0x00008000	/* Trigger mode */
83204136Srrs#define MSI_MIPS_DATA_TRGREDG		0x00000000	/* edge */
84204136Srrs#define MSI_MIPS_DATA_TRGRLVL		0x00008000	/* level */
85198160Srrs
86204136Srrs#define MSI_MIPS_DATA_LEVEL		0x00004000	/* Polarity. */
87204136Srrs#define MSI_MIPS_DATA_DEASSERT		0x00000000
88204136Srrs#define MSI_MIPS_DATA_ASSERT		0x00004000
89198160Srrs
90204136Srrs#define MSI_MIPS_DATA_DELMOD		0x00000700	/* Delivery Mode */
91204136Srrs#define MSI_MIPS_DATA_DELFIXED		0x00000000	/* fixed */
92204136Srrs#define MSI_MIPS_DATA_DELLOPRI		0x00000100	/* lowest priority */
93198160Srrs
94204136Srrs#define MSI_MIPS_DATA_INTVEC		0x000000ff
95198160Srrs
96198160Srrs/*
97198160Srrs * Build Intel MSI message and data values from a source.  AMD64 systems
98198160Srrs * seem to be compatible, so we use the same function for both.
99198160Srrs */
100198160Srrs#define MIPS_MSI_ADDR(cpu)					       \
101198160Srrs        (MSI_MIPS_ADDR_BASE | (cpu) << 12 |			       \
102198160Srrs	 MSI_MIPS_ADDR_RH_OFF | MSI_MIPS_ADDR_DM_PHYSICAL)
103198160Srrs
104198160Srrs#define MIPS_MSI_DATA(irq)					       \
105198160Srrs        (MSI_MIPS_DATA_TRGRLVL | MSI_MIPS_DATA_DELFIXED |	       \
106198160Srrs	 MSI_MIPS_DATA_ASSERT | (irq))
107198160Srrs
108204136Srrsstruct xlr_pcib_softc {
109213484Sjchandra	bus_dma_tag_t	sc_pci_dmat;	/* PCI DMA tag pointer */
110198160Srrs};
111204136Srrs
112198625Srrsstatic devclass_t pcib_devclass;
113204136Srrsstatic void *xlr_pci_config_base;
114204136Srrsstatic struct rman irq_rman, port_rman, mem_rman;
115198160Srrs
116204136Srrsstatic void
117204136Srrsxlr_pci_init_resources(void)
118204136Srrs{
119211811Sjchandra
120204136Srrs	irq_rman.rm_start = 0;
121204136Srrs	irq_rman.rm_end = 255;
122204136Srrs	irq_rman.rm_type = RMAN_ARRAY;
123204136Srrs	irq_rman.rm_descr = "PCI Mapped Interrupts";
124204136Srrs	if (rman_init(&irq_rman)
125204136Srrs	    || rman_manage_region(&irq_rman, 0, 255))
126204136Srrs		panic("pci_init_resources irq_rman");
127198160Srrs
128204136Srrs	port_rman.rm_start = 0;
129221218Sjhb	port_rman.rm_end = ~0ul;
130204136Srrs	port_rman.rm_type = RMAN_ARRAY;
131204136Srrs	port_rman.rm_descr = "I/O ports";
132204136Srrs	if (rman_init(&port_rman)
133204136Srrs	    || rman_manage_region(&port_rman, 0x10000000, 0x1fffffff))
134204136Srrs		panic("pci_init_resources port_rman");
135204136Srrs
136204136Srrs	mem_rman.rm_start = 0;
137221218Sjhb	mem_rman.rm_end = ~0ul;
138204136Srrs	mem_rman.rm_type = RMAN_ARRAY;
139204136Srrs	mem_rman.rm_descr = "I/O memory";
140204136Srrs	if (rman_init(&mem_rman)
141204136Srrs	    || rman_manage_region(&mem_rman, 0xd0000000, 0xdfffffff))
142204136Srrs		panic("pci_init_resources mem_rman");
143204136Srrs}
144204136Srrs
145198160Srrsstatic int
146198160Srrsxlr_pcib_probe(device_t dev)
147198160Srrs{
148211811Sjchandra
149204136Srrs	if (xlr_board_info.is_xls)
150204136Srrs		device_set_desc(dev, "XLS PCIe bus");
151204136Srrs	else
152204136Srrs		device_set_desc(dev, "XLR PCI bus");
153198160Srrs
154204136Srrs	xlr_pci_init_resources();
155204136Srrs	xlr_pci_config_base = (void *)MIPS_PHYS_TO_KSEG1(DEFAULT_PCI_CONFIG_BASE);
156198160Srrs
157211811Sjchandra	return (0);
158198160Srrs}
159198160Srrs
160198160Srrsstatic int
161204136Srrsxlr_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
162198160Srrs{
163211811Sjchandra
164198160Srrs	switch (which) {
165204136Srrs	case PCIB_IVAR_DOMAIN:
166204136Srrs		*result = 0;
167204136Srrs		return (0);
168198625Srrs	case PCIB_IVAR_BUS:
169198160Srrs		*result = 0;
170204136Srrs		return (0);
171198160Srrs	}
172204136Srrs	return (ENOENT);
173198160Srrs}
174198160Srrs
175198160Srrsstatic int
176204136Srrsxlr_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
177204136Srrs{
178204136Srrs	switch (which) {
179204136Srrs	case PCIB_IVAR_DOMAIN:
180204136Srrs		return (EINVAL);
181204136Srrs	case PCIB_IVAR_BUS:
182204136Srrs		return (EINVAL);
183204136Srrs	}
184204136Srrs	return (ENOENT);
185204136Srrs}
186204136Srrs
187204136Srrsstatic int
188198160Srrsxlr_pcib_maxslots(device_t dev)
189198160Srrs{
190211811Sjchandra
191204136Srrs	return (PCI_SLOTMAX);
192198160Srrs}
193198160Srrs
194198625Srrsstatic __inline__ void
195198625Srrsdisable_and_clear_cache_error(void)
196198625Srrs{
197211811Sjchandra	uint64_t lsu_cfg0;
198198625Srrs
199212366Sjchandra	lsu_cfg0 = read_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CFG0_REGID);
200198625Srrs	lsu_cfg0 = lsu_cfg0 & ~0x2e;
201212366Sjchandra	write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CFG0_REGID, lsu_cfg0);
202198625Srrs	/* Clear cache error log */
203212366Sjchandra	write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID, 0);
204198160Srrs}
205198160Srrs
206198625Srrsstatic __inline__ void
207198625Srrsclear_and_enable_cache_error(void)
208198625Srrs{
209198625Srrs	uint64_t lsu_cfg0 = 0;
210198160Srrs
211198625Srrs	/* first clear the cache error logging register */
212212366Sjchandra	write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID, 0);
213212366Sjchandra	write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERROVF_REGID, 0);
214212366Sjchandra	write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERRINT_REGID, 0);
215198160Srrs
216212366Sjchandra	lsu_cfg0 = read_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CFG0_REGID);
217198625Srrs	lsu_cfg0 = lsu_cfg0 | 0x2e;
218212366Sjchandra	write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CFG0_REGID, lsu_cfg0);
219198160Srrs}
220198160Srrs
221198625Srrsstatic uint32_t
222204136Srrspci_cfg_read_32bit(uint32_t addr)
223198160Srrs{
224204136Srrs	uint32_t temp = 0;
225209808Sjchandra	uint32_t *p = (uint32_t *)xlr_pci_config_base + addr / sizeof(uint32_t);
226204136Srrs	uint64_t cerr_cpu_log = 0;
227204136Srrs
228204136Srrs	disable_and_clear_cache_error();
229204136Srrs	temp = bswap32(*p);
230204136Srrs
231204136Srrs	/* Read cache err log */
232212366Sjchandra	cerr_cpu_log = read_xlr_ctrl_register(CPU_BLOCKID_LSU,
233211811Sjchandra	    LSU_CERRLOG_REGID);
234204136Srrs	if (cerr_cpu_log) {
235204136Srrs		/* Device don't exist. */
236204136Srrs		temp = ~0x0;
237204136Srrs	}
238204136Srrs	clear_and_enable_cache_error();
239211811Sjchandra	return (temp);
240204136Srrs}
241204136Srrs
242204136Srrsstatic u_int32_t
243204136Srrsxlr_pcib_read_config(device_t dev, u_int b, u_int s, u_int f,
244204136Srrs			u_int reg, int width)
245204136Srrs{
246198625Srrs	uint32_t data = 0;
247198160Srrs
248198160Srrs	if ((width == 2) && (reg & 1))
249198160Srrs		return 0xFFFFFFFF;
250198160Srrs	else if ((width == 4) && (reg & 3))
251198160Srrs		return 0xFFFFFFFF;
252198160Srrs
253204136Srrs	data = pci_cfg_read_32bit(pci_cfg_offset(b, s, f, reg));
254198160Srrs
255198160Srrs	if (width == 1)
256198160Srrs		return ((data >> ((reg & 3) << 3)) & 0xff);
257198160Srrs	else if (width == 2)
258198160Srrs		return ((data >> ((reg & 3) << 3)) & 0xffff);
259198160Srrs	else
260211811Sjchandra		return (data);
261198160Srrs}
262198160Srrs
263204136Srrsstatic void
264204136Srrsxlr_pcib_write_config(device_t dev, u_int b, u_int s, u_int f,
265204136Srrs		u_int reg, u_int32_t val, int width)
266198625Srrs{
267198160Srrs	uint32_t cfgaddr = pci_cfg_offset(b, s, f, reg);
268204136Srrs	uint32_t data = 0, *p;
269198160Srrs
270198160Srrs	if ((width == 2) && (reg & 1))
271198625Srrs		return;
272198160Srrs	else if ((width == 4) && (reg & 3))
273198625Srrs		return;
274198160Srrs
275198160Srrs	if (width == 1) {
276198160Srrs		data = pci_cfg_read_32bit(cfgaddr);
277198160Srrs		data = (data & ~(0xff << ((reg & 3) << 3))) |
278198160Srrs		    (val << ((reg & 3) << 3));
279198160Srrs	} else if (width == 2) {
280198160Srrs		data = pci_cfg_read_32bit(cfgaddr);
281198160Srrs		data = (data & ~(0xffff << ((reg & 3) << 3))) |
282198160Srrs		    (val << ((reg & 3) << 3));
283198160Srrs	} else {
284198625Srrs		data = val;
285198160Srrs	}
286198160Srrs
287209808Sjchandra	p = (uint32_t *)xlr_pci_config_base + cfgaddr / sizeof(uint32_t);
288204136Srrs	*p = bswap32(data);
289198160Srrs
290198625Srrs	return;
291198160Srrs}
292198160Srrs
293198625Srrsstatic int
294198625Srrsxlr_pcib_attach(device_t dev)
295198160Srrs{
296213484Sjchandra	struct xlr_pcib_softc *sc;
297213484Sjchandra	sc = device_get_softc(dev);
298213484Sjchandra
299213484Sjchandra	/*
300213484Sjchandra	 * XLR C revision chips cannot do DMA above 2G physical address
301213484Sjchandra	 * create a parent tag with this lowaddr
302213484Sjchandra	 */
303213484Sjchandra	if (xlr_is_c_revision()) {
304213484Sjchandra		if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
305213484Sjchandra		    0x7fffffff, ~0, NULL, NULL, 0x7fffffff,
306213484Sjchandra		    0xff, 0x7fffffff, 0, NULL, NULL, &sc->sc_pci_dmat) != 0)
307213484Sjchandra			panic("%s: bus_dma_tag_create failed", __func__);
308213484Sjchandra	}
309198160Srrs	device_add_child(dev, "pci", 0);
310198160Srrs	bus_generic_attach(dev);
311211811Sjchandra	return (0);
312198160Srrs}
313198160Srrs
314198160Srrsstatic void
315198625Srrsxlr_pcib_identify(driver_t * driver, device_t parent)
316198160Srrs{
317211811Sjchandra
318198625Srrs	BUS_ADD_CHILD(parent, 0, "pcib", 0);
319198160Srrs}
320198160Srrs
321212285Sjchandra/*
322212285Sjchandra * XLS PCIe can have upto 4 links, and each link has its on IRQ
323212285Sjchandra * Find the link on which the device is on
324212285Sjchandra */
325198160Srrsstatic int
326212285Sjchandraxls_pcie_link(device_t pcib, device_t dev)
327198160Srrs{
328198160Srrs	device_t parent, tmp;
329198160Srrs
330198160Srrs	/* find the lane on which the slot is connected to */
331212285Sjchandra	printf("xls_pcie_link : bus %s dev %s\n", device_get_nameunit(pcib),
332212285Sjchandra		device_get_nameunit(dev));
333198160Srrs	tmp = dev;
334198160Srrs	while (1) {
335198625Srrs		parent = device_get_parent(tmp);
336198160Srrs		if (parent == NULL || parent == pcib) {
337198625Srrs			device_printf(dev, "Cannot find parent bus\n");
338212285Sjchandra			return (-1);
339198160Srrs		}
340198160Srrs		if (strcmp(device_get_nameunit(parent), "pci0") == 0)
341198160Srrs			break;
342198160Srrs		tmp = parent;
343198160Srrs	}
344212285Sjchandra	return (pci_get_slot(tmp));
345212285Sjchandra}
346198160Srrs
347212285Sjchandra/*
348212285Sjchandra * Find the IRQ for the link, each link has a different interrupt
349212285Sjchandra * at the XLS pic
350212285Sjchandra */
351212285Sjchandrastatic int
352212285Sjchandraxls_pcie_link_irq(int link)
353212285Sjchandra{
354212285Sjchandra
355212285Sjchandra	switch (link) {
356198625Srrs	case 0:
357212285Sjchandra		return (PIC_PCIE_LINK0_IRQ);
358198625Srrs	case 1:
359212285Sjchandra		return (PIC_PCIE_LINK1_IRQ);
360198625Srrs	case 2:
361213199Sjchandra		if (xlr_is_xls_b0())
362213199Sjchandra			return (PIC_PCIE_B0_LINK2_IRQ);
363213199Sjchandra		else
364213199Sjchandra			return (PIC_PCIE_LINK2_IRQ);
365198625Srrs	case 3:
366213199Sjchandra		if (xlr_is_xls_b0())
367213199Sjchandra			return (PIC_PCIE_B0_LINK3_IRQ);
368213199Sjchandra		else
369213199Sjchandra			return (PIC_PCIE_LINK3_IRQ);
370198160Srrs	}
371212285Sjchandra	return (-1);
372212285Sjchandra}
373198160Srrs
374212285Sjchandrastatic int
375212285Sjchandraxlr_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs)
376212285Sjchandra{
377212285Sjchandra	int i, link;
378212285Sjchandra
379198625Srrs	/*
380212285Sjchandra	 * Each link has 32 MSIs that can be allocated, but for now
381212285Sjchandra	 * we only support one device per link.
382212285Sjchandra	 * msi_alloc() equivalent is needed when we start supporting
383212285Sjchandra	 * bridges on the PCIe link.
384198625Srrs	 */
385212285Sjchandra	link = xls_pcie_link(pcib, dev);
386212285Sjchandra	if (link == -1)
387212285Sjchandra		return (ENXIO);
388198160Srrs
389212285Sjchandra	/*
390212285Sjchandra	 * encode the irq so that we know it is a MSI interrupt when we
391212285Sjchandra	 * setup interrupts
392212285Sjchandra	 */
393212285Sjchandra	for (i = 0; i < count; i++)
394212285Sjchandra		irqs[i] = 64 + link * 32 + i;
395212285Sjchandra
396211811Sjchandra	return (0);
397198160Srrs}
398198160Srrs
399198160Srrsstatic int
400198160Srrsxlr_release_msi(device_t pcib, device_t dev, int count, int *irqs)
401198160Srrs{
402211811Sjchandra	device_printf(dev, "%s: msi release %d\n", device_get_nameunit(pcib),
403211811Sjchandra	    count);
404211811Sjchandra	return (0);
405198160Srrs}
406198160Srrs
407198160Srrsstatic int
408212285Sjchandraxlr_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
409212285Sjchandra    uint32_t *data)
410198160Srrs{
411212285Sjchandra	int msi;
412211811Sjchandra
413212285Sjchandra	if (irq >= 64) {
414212285Sjchandra		msi = irq - 64;
415198160Srrs		*addr = MIPS_MSI_ADDR(0);
416212285Sjchandra		*data = MIPS_MSI_DATA(msi);
417211811Sjchandra		return (0);
418212285Sjchandra	} else {
419211811Sjchandra		device_printf(dev, "%s: map_msi for irq %d  - ignored",
420211811Sjchandra		    device_get_nameunit(pcib), irq);
421198160Srrs		return (ENXIO);
422198160Srrs	}
423198160Srrs}
424198160Srrs
425204136Srrsstatic void
426211893Sjchandrabridge_pcix_ack(int irq)
427204136Srrs{
428211811Sjchandra
429217625Sjchandra	(void)xlr_read_reg(xlr_io_mmio(XLR_IO_PCIX_OFFSET), 0x140 >> 2);
430204136Srrs}
431204136Srrs
432204136Srrsstatic void
433211893Sjchandrabridge_pcie_ack(int irq)
434204136Srrs{
435204136Srrs	uint32_t reg;
436204136Srrs	xlr_reg_t *pcie_mmio_le = xlr_io_mmio(XLR_IO_PCIE_1_OFFSET);
437204136Srrs
438204136Srrs	switch (irq) {
439211811Sjchandra	case PIC_PCIE_LINK0_IRQ:
440211811Sjchandra		reg = PCIE_LINK0_MSI_STATUS;
441211811Sjchandra		break;
442211811Sjchandra	case PIC_PCIE_LINK1_IRQ:
443211811Sjchandra		reg = PCIE_LINK1_MSI_STATUS;
444211811Sjchandra		break;
445211811Sjchandra	case PIC_PCIE_LINK2_IRQ:
446213199Sjchandra	case PIC_PCIE_B0_LINK2_IRQ:
447211811Sjchandra		reg = PCIE_LINK2_MSI_STATUS;
448211811Sjchandra		break;
449211811Sjchandra	case PIC_PCIE_LINK3_IRQ:
450213199Sjchandra	case PIC_PCIE_B0_LINK3_IRQ:
451211811Sjchandra		reg = PCIE_LINK3_MSI_STATUS;
452211811Sjchandra		break;
453204136Srrs	default:
454204136Srrs		return;
455204136Srrs	}
456204136Srrs	xlr_write_reg(pcie_mmio_le, reg>>2, 0xffffffff);
457204136Srrs}
458204136Srrs
459204136Srrsstatic int
460204136Srrsmips_platform_pci_setup_intr(device_t dev, device_t child,
461212285Sjchandra    struct resource *irq, int flags, driver_filter_t *filt,
462212285Sjchandra    driver_intr_t *intr, void *arg, void **cookiep)
463204136Srrs{
464204136Srrs	int error = 0;
465204136Srrs	int xlrirq;
466204136Srrs
467204136Srrs	error = rman_activate_resource(irq);
468204136Srrs	if (error)
469204136Srrs		return error;
470204136Srrs	if (rman_get_start(irq) != rman_get_end(irq)) {
471204136Srrs		device_printf(dev, "Interrupt allocation %lu != %lu\n",
472204136Srrs		    rman_get_start(irq), rman_get_end(irq));
473211811Sjchandra		return (EINVAL);
474204136Srrs	}
475204136Srrs	xlrirq = rman_get_start(irq);
476204136Srrs
477204136Srrs	if (strcmp(device_get_name(dev), "pcib") != 0)
478211811Sjchandra		return (0);
479204136Srrs
480204136Srrs	if (xlr_board_info.is_xls == 0) {
481211893Sjchandra		xlr_establish_intr(device_get_name(child), filt,
482211893Sjchandra		    intr, arg, PIC_PCIX_IRQ, flags, cookiep, bridge_pcix_ack);
483212248Sjchandra		pic_setup_intr(PIC_IRT_PCIX_INDEX, PIC_PCIX_IRQ, 0x1, 1);
484204136Srrs	} else {
485212285Sjchandra		/*
486212285Sjchandra		 * temporary hack for MSI, we support just one device per
487212285Sjchandra		 * link, and assign the link interrupt to the device interrupt
488212285Sjchandra		 */
489212285Sjchandra		if (xlrirq >= 64) {
490212285Sjchandra			xlrirq -= 64;
491212285Sjchandra			if (xlrirq % 32 != 0)
492212285Sjchandra				return (0);
493212285Sjchandra			xlrirq = xls_pcie_link_irq(xlrirq / 32);
494212285Sjchandra			if (xlrirq == -1)
495212285Sjchandra				return (EINVAL);
496212285Sjchandra		}
497211893Sjchandra		xlr_establish_intr(device_get_name(child), filt,
498211893Sjchandra		    intr, arg, xlrirq, flags, cookiep, bridge_pcie_ack);
499212248Sjchandra		pic_setup_intr(xlrirq - PIC_IRQ_BASE, xlrirq, 0x1, 1);
500204136Srrs	}
501204136Srrs
502211811Sjchandra	return (bus_generic_setup_intr(dev, child, irq, flags, filt, intr,
503211811Sjchandra	    arg, cookiep));
504204136Srrs}
505204136Srrs
506204136Srrsstatic int
507204136Srrsmips_platform_pci_teardown_intr(device_t dev, device_t child,
508204136Srrs    struct resource *irq, void *cookie)
509204136Srrs{
510204136Srrs	if (strcmp(device_get_name(child), "pci") == 0) {
511204136Srrs		/* if needed reprogram the pic to clear pcix related entry */
512204136Srrs		device_printf(dev, "teardown intr\n");
513204136Srrs	}
514211811Sjchandra	return (bus_generic_teardown_intr(dev, child, irq, cookie));
515204136Srrs}
516204136Srrs
517204136Srrsstatic struct resource *
518204136Srrsxlr_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
519204136Srrs	u_long start, u_long end, u_long count, u_int flags)
520204136Srrs{
521204136Srrs	struct rman *rm;
522204136Srrs	struct resource *rv;
523204136Srrs	vm_offset_t va;
524204136Srrs	int needactivate = flags & RF_ACTIVE;
525204136Srrs
526204136Srrs	switch (type) {
527204136Srrs	case SYS_RES_IRQ:
528204136Srrs		rm = &irq_rman;
529204136Srrs		break;
530204136Srrs
531204136Srrs	case SYS_RES_IOPORT:
532204136Srrs		rm = &port_rman;
533204136Srrs		break;
534204136Srrs
535204136Srrs	case SYS_RES_MEMORY:
536204136Srrs		rm = &mem_rman;
537204136Srrs		break;
538204136Srrs
539204136Srrs	default:
540211811Sjchandra		return (0);
541204136Srrs	}
542204136Srrs
543204136Srrs	rv = rman_reserve_resource(rm, start, end, count, flags, child);
544204136Srrs	if (rv == 0)
545211811Sjchandra		return (0);
546204136Srrs
547204136Srrs	rman_set_rid(rv, *rid);
548204136Srrs
549204136Srrs	if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
550204136Srrs		va = (vm_offset_t)pmap_mapdev(start, count);
551204136Srrs		rman_set_bushandle(rv, va);
552204136Srrs		/* bushandle is same as virtual addr */
553204136Srrs		rman_set_virtual(rv, (void *)va);
554204136Srrs		rman_set_bustag(rv, rmi_pci_bus_space);
555204136Srrs	}
556204136Srrs
557204136Srrs	if (needactivate) {
558204136Srrs		if (bus_activate_resource(child, type, *rid, rv)) {
559204136Srrs			rman_release_resource(rv);
560204136Srrs			return (NULL);
561204136Srrs		}
562204136Srrs	}
563211811Sjchandra	return (rv);
564204136Srrs}
565204136Srrs
566204136Srrsstatic int
567204136Srrsxlr_pci_release_resource(device_t bus, device_t child, int type, int rid,
568204136Srrs		       struct resource *r)
569204136Srrs{
570211811Sjchandra
571204136Srrs	return (rman_release_resource(r));
572204136Srrs}
573204136Srrs
574213484Sjchandrastatic bus_dma_tag_t
575213484Sjchandraxlr_pci_get_dma_tag(device_t bus, device_t child)
576213484Sjchandra{
577213484Sjchandra	struct xlr_pcib_softc *sc;
578213484Sjchandra
579213484Sjchandra	sc = device_get_softc(bus);
580213484Sjchandra	return (sc->sc_pci_dmat);
581213484Sjchandra}
582213484Sjchandra
583204136Srrsstatic int
584204136Srrsxlr_pci_activate_resource(device_t bus, device_t child, int type, int rid,
585204136Srrs                      struct resource *r)
586204136Srrs{
587211811Sjchandra
588204136Srrs	return (rman_activate_resource(r));
589204136Srrs}
590204136Srrs
591204136Srrsstatic int
592204136Srrsxlr_pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
593204136Srrs                          struct resource *r)
594204136Srrs{
595211811Sjchandra
596204136Srrs	return (rman_deactivate_resource(r));
597204136Srrs}
598204136Srrs
599204136Srrsstatic int
600204136Srrsmips_pci_route_interrupt(device_t bus, device_t dev, int pin)
601204136Srrs{
602212285Sjchandra	int irq, link;
603211811Sjchandra
604204136Srrs	/*
605204136Srrs	 * Validate requested pin number.
606204136Srrs	 */
607204136Srrs	if ((pin < 1) || (pin > 4))
608204136Srrs		return (255);
609204136Srrs
610204136Srrs	if (xlr_board_info.is_xls) {
611212285Sjchandra		link = xls_pcie_link(bus, dev);
612212285Sjchandra		irq = xls_pcie_link_irq(link);
613212285Sjchandra		if (irq != -1)
614212285Sjchandra			return (irq);
615204136Srrs	} else {
616212285Sjchandra		if (pin == 1)
617212285Sjchandra			return (PIC_PCIX_IRQ);
618204136Srrs	}
619204136Srrs
620204136Srrs	return (255);
621204136Srrs}
622204136Srrs
623198160Srrsstatic device_method_t xlr_pcib_methods[] = {
624198160Srrs	/* Device interface */
625198625Srrs	DEVMETHOD(device_identify, xlr_pcib_identify),
626198625Srrs	DEVMETHOD(device_probe, xlr_pcib_probe),
627198625Srrs	DEVMETHOD(device_attach, xlr_pcib_attach),
628198160Srrs
629198160Srrs	/* Bus interface */
630198625Srrs	DEVMETHOD(bus_read_ivar, xlr_pcib_read_ivar),
631204136Srrs	DEVMETHOD(bus_write_ivar, xlr_pcib_write_ivar),
632198625Srrs	DEVMETHOD(bus_alloc_resource, xlr_pci_alloc_resource),
633204136Srrs	DEVMETHOD(bus_release_resource, xlr_pci_release_resource),
634213484Sjchandra	DEVMETHOD(bus_get_dma_tag, xlr_pci_get_dma_tag),
635204136Srrs	DEVMETHOD(bus_activate_resource, xlr_pci_activate_resource),
636204136Srrs	DEVMETHOD(bus_deactivate_resource, xlr_pci_deactivate_resource),
637198625Srrs	DEVMETHOD(bus_setup_intr, mips_platform_pci_setup_intr),
638204136Srrs	DEVMETHOD(bus_teardown_intr, mips_platform_pci_teardown_intr),
639198160Srrs
640198160Srrs	/* pcib interface */
641198625Srrs	DEVMETHOD(pcib_maxslots, xlr_pcib_maxslots),
642198625Srrs	DEVMETHOD(pcib_read_config, xlr_pcib_read_config),
643198625Srrs	DEVMETHOD(pcib_write_config, xlr_pcib_write_config),
644198625Srrs	DEVMETHOD(pcib_route_interrupt, mips_pci_route_interrupt),
645198160Srrs
646198625Srrs	DEVMETHOD(pcib_alloc_msi, xlr_alloc_msi),
647198625Srrs	DEVMETHOD(pcib_release_msi, xlr_release_msi),
648198625Srrs	DEVMETHOD(pcib_map_msi, xlr_map_msi),
649198625Srrs
650227843Smarius	DEVMETHOD_END
651198160Srrs};
652198160Srrs
653198160Srrsstatic driver_t xlr_pcib_driver = {
654198160Srrs	"pcib",
655198160Srrs	xlr_pcib_methods,
656204136Srrs	sizeof(struct xlr_pcib_softc),
657198160Srrs};
658198160Srrs
659208165SrrsDRIVER_MODULE(pcib, iodi, xlr_pcib_driver, pcib_devclass, 0, 0);
660