Update memory and resource allocation code for SoC devices

The XLP on-chip devices have PCI configuration headers, but some of the
devices need custom resource allocation code.
- devices with no MEM/IO BARs with registers in PCIe extended reg
  space have to be handled in memory resource allocation
- devices without INTPIN/INTLINE in PCI header can be supported
  by having these faked with a shadow register.
- Some devices does not allow 8/16 bit access to the register space,
  he default bus space cannot be used for these.

Subclass pci and override attach and resource allocation methods to
take care of this.

Remove earlier code which did this partially.
This commit is contained in:
Jayachandran C. 2012-03-27 15:39:55 +00:00
parent c708f80e7d
commit d5d4261f35
9 changed files with 343 additions and 375 deletions

View File

@ -12,7 +12,6 @@ mips/nlm/mpreset.S standard
mips/nlm/board_eeprom.c standard
mips/nlm/board_cpld.c standard
mips/nlm/xlp_pci.c optional pci
mips/nlm/intern_dev.c optional pci
mips/nlm/uart_cpu_xlp.c optional uart
mips/nlm/usb_init.c optional usb
#

View File

@ -37,23 +37,8 @@ __FBSDID("$FreeBSD$");
#include <mips/nlm/hal/haldefs.h>
#include <mips/nlm/hal/iomap.h>
#include <mips/nlm/hal/sys.h>
#include <mips/nlm/hal/pic.h>
#include <mips/nlm/xlp.h>
#include <mips/nlm/hal/uart.h>
#include <mips/nlm/hal/mmu.h>
#include <mips/nlm/hal/pcibus.h>
#include <mips/nlm/hal/usb.h>
int pic_irt_ehci0;
int pic_irt_ehci1;
int pic_irt_uart0;
int pic_irt_uart1;
int pic_irt_pcie_lnk0;
int pic_irt_pcie_lnk1;
int pic_irt_pcie_lnk2;
int pic_irt_pcie_lnk3;
uint32_t
xlp_get_cpu_frequency(int node, int core)
{
@ -66,9 +51,9 @@ xlp_get_cpu_frequency(int node, int core)
pll_divf = ((rstval >> 10) & 0x7f) + 1;
pll_divr = ((rstval >> 8) & 0x3) + 1;
if (!nlm_is_xlp8xx_ax())
ext_div = ((rstval >> 30) & 0x3) + 1;
ext_div = ((rstval >> 30) & 0x3) + 1;
else
ext_div = 1;
ext_div = 1;
dfs_div = ((dfsval >> (core << 2)) & 0xf) + 1;
return ((800000000ULL * pll_divf)/(3 * pll_divr * ext_div * dfs_div));
@ -122,98 +107,3 @@ nlm_set_device_frequency(int node, int devtype, int frequency)
}
return (nlm_get_device_frequency(sysbase, devtype));
}
void
nlm_pic_irt_init(int node)
{
pic_irt_ehci0 = nlm_irtstart(nlm_get_usb_pcibase(node, 0));
pic_irt_ehci1 = nlm_irtstart(nlm_get_usb_pcibase(node, 3));
pic_irt_uart0 = nlm_irtstart(nlm_get_uart_pcibase(node, 0));
pic_irt_uart1 = nlm_irtstart(nlm_get_uart_pcibase(node, 1));
/* Hardcoding the PCIE IRT information as PIC doesn't
understand any value other than 78,79,80,81 for PCIE0/1/2/3 */
pic_irt_pcie_lnk0 = 78;
pic_irt_pcie_lnk1 = 79;
pic_irt_pcie_lnk2 = 80;
pic_irt_pcie_lnk3 = 81;
}
/*
* Find the IRQ for the link, each link has a different interrupt
* at the XLP pic
*/
int xlp_pcie_link_irt(int link)
{
if( (link < 0) || (link > 3))
return (-1);
return (pic_irt_pcie_lnk0 + link);
}
int
xlp_irt_to_irq(int irt)
{
if (irt == pic_irt_ehci0)
return PIC_EHCI_0_IRQ;
else if (irt == pic_irt_ehci1)
return PIC_EHCI_1_IRQ;
else if (irt == pic_irt_uart0)
return PIC_UART_0_IRQ;
else if (irt == pic_irt_uart1)
return PIC_UART_1_IRQ;
else if (irt == pic_irt_pcie_lnk0)
return PIC_PCIE_0_IRQ;
else if (irt == pic_irt_pcie_lnk1)
return PIC_PCIE_1_IRQ;
else if (irt == pic_irt_pcie_lnk2)
return PIC_PCIE_2_IRQ;
else if (irt == pic_irt_pcie_lnk3)
return PIC_PCIE_3_IRQ;
else {
if (bootverbose)
printf("Cannot find irq for IRT %d\n", irt);
return 0;
}
}
int
xlp_irq_to_irt(int irq)
{
switch (irq) {
case PIC_EHCI_0_IRQ :
return pic_irt_ehci0;
case PIC_EHCI_1_IRQ :
return pic_irt_ehci1;
case PIC_UART_0_IRQ :
return pic_irt_uart0;
case PIC_UART_1_IRQ :
return pic_irt_uart1;
case PIC_PCIE_0_IRQ :
return pic_irt_pcie_lnk0;
case PIC_PCIE_1_IRQ :
return pic_irt_pcie_lnk1;
case PIC_PCIE_2_IRQ :
return pic_irt_pcie_lnk2;
case PIC_PCIE_3_IRQ :
return pic_irt_pcie_lnk3;
default: panic("Bad IRQ %d\n", irq);
}
}
int
xlp_irq_is_picintr(int irq)
{
switch (irq) {
case PIC_EHCI_0_IRQ :
case PIC_EHCI_1_IRQ :
case PIC_UART_0_IRQ :
case PIC_UART_1_IRQ :
case PIC_PCIE_0_IRQ :
case PIC_PCIE_1_IRQ :
case PIC_PCIE_2_IRQ :
case PIC_PCIE_3_IRQ :
return (1);
default: return (0);
}
}

View File

@ -84,6 +84,9 @@
/* PCIE_INT_EN0 */
#define PCIE_MSI_INT_EN (1 << 9)
/* XXXJC: Ax workaround */
#define PCIE_LINK0_IRT 78
#if !defined(LOCORE) && !defined(__ASSEMBLY__)
#define nlm_read_pcie_reg(b, r) nlm_read_reg(b, r)
@ -93,6 +96,15 @@
#define nlm_get_pcie_regbase(node, inst) \
(nlm_get_pcie_base(node, inst) + XLP_IO_PCI_HDRSZ)
static __inline int
xlp_pcie_link_irt(int link)
{
if ((link < 0) || (link > 3))
return (-1);
return (PCIE_LINK0_IRT + link);
}
/*
* Build Intel MSI message and data values from a source. AMD64 systems
* seem to be compatible, so we use the same function for both.
@ -106,8 +118,4 @@
MSI_MIPS_DATA_ASSERT | (irq))
#endif
#ifndef LOCORE
int xlp_pcie_link_irt(int link);
#endif
#endif /* __XLP_PCIBUS_H__ */

View File

@ -174,7 +174,7 @@
#define PIC_IRT_FIRST_IRQ (PIC_IRQ_BASE)
#define PIC_IRT_LAST_IRQ 63
#define PIC_IRQ_IS_IRT(irq) ((irq) >= PIC_IRT_FIRST_IRQ)
#define XLP_IRQ_IS_PICINTR(irq) ((irq) >= PIC_IRT_FIRST_IRQ)
/*
* Misc

View File

@ -1,86 +0,0 @@
/*-
* Copyright (c) 2011 Netlogic Microsystems Inc.
*
* (based on pci/ignore_pci.c)
* Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
* Copyright (c) 2000 BSDi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* 'Ignore' driver - eats devices that show up errnoeously on PCI
* but shouldn't ever be listed or handled by a driver.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <dev/pci/pcivar.h>
#include <mips/nlm/hal/haldefs.h>
#include <mips/nlm/hal/iomap.h>
static int nlm_soc_pci_probe(device_t dev);
static device_method_t nlm_soc_pci_methods[] = {
DEVMETHOD(device_probe, nlm_soc_pci_probe),
DEVMETHOD(device_attach, bus_generic_attach),
{ 0, 0 }
};
static driver_t nlm_soc_pci_driver = {
"nlm_soc_pci",
nlm_soc_pci_methods,
0,
};
static devclass_t nlm_soc_pci_devclass;
DRIVER_MODULE(nlm_soc_pci, pci, nlm_soc_pci_driver, nlm_soc_pci_devclass, 0, 0);
static int
nlm_soc_pci_probe(device_t dev)
{
if (pci_get_vendor(dev) != PCI_VENDOR_NETLOGIC)
return(ENXIO);
/* Ignore SoC internal devices */
switch (pci_get_device(dev)) {
case PCI_DEVICE_ID_NLM_ICI:
case PCI_DEVICE_ID_NLM_PIC:
case PCI_DEVICE_ID_NLM_FMN:
device_set_desc(dev, "Netlogic Internal");
device_quiet(dev);
return(-10000);
default:
return(ENXIO);
}
}

View File

@ -141,13 +141,13 @@ xlp_establish_intr(const char *name, driver_filter_t filt,
* PIC based interrupts need ack in PIC, and some SoC
* components need additional acks (e.g. PCI)
*/
if (xlp_irq_is_picintr(irq))
if (XLP_IRQ_IS_PICINTR(irq))
errcode = intr_event_create(&ie, src, 0, irq,
xlp_pre_ithread, xlp_post_ithread, xlp_post_filter,
NULL, "hard intr%d:", irq);
else {
if (filt == NULL)
panic("Not supported - non filter percpu intr");
panic("Unsupported non filter percpu intr %d", irq);
errcode = intr_event_create(&ie, src, 0, irq,
NULL, NULL, NULL, NULL, "hard intr%d:", irq);
}

View File

@ -35,17 +35,15 @@
#include <mips/nlm/hal/iomap.h>
#define PIC_UART_0_IRQ 9
#define PIC_UART_1_IRQ 10
#define PIC_PCIE_0_IRQ 11
#define PIC_PCIE_1_IRQ 12
#define PIC_PCIE_2_IRQ 13
#define PIC_PCIE_3_IRQ 14
#define PIC_EHCI_0_IRQ 39
#define PIC_EHCI_0_IRQ 16
#define PIC_MMC_IRQ 21
/* 41 used by IRQ_SMP */
#define PIC_EHCI_1_IRQ 42
#define PIC_MMC_IRQ 43
/* XLP 8xx/4xx A0, A1, A2 CPU COP0 PRIDs */
@ -75,10 +73,8 @@ extern void xlp_enable_threads(int code);
#endif
uint32_t xlp_get_cpu_frequency(int node, int core);
int nlm_set_device_frequency(int node, int devtype, int frequency);
void nlm_pic_irt_init(int node);
int xlp_irt_to_irq(int irt);
int xlp_irq_to_irt(int irq);
int xlp_irq_is_picintr(int irq);
static __inline int nlm_processor_id(void)
{

View File

@ -98,7 +98,7 @@ __FBSDID("$FreeBSD$");
char boot1_env[4096];
uint64_t xlp_cpu_frequency;
uint64_t xlp_io_base = MIPS_PHYS_TO_KSEG1(XLP_DEFAULT_IO_BASE);
uint64_t xlp_io_base = MIPS_PHYS_TO_DIRECT_UNCACHED(XLP_DEFAULT_IO_BASE);
int xlp_ncores;
int xlp_threads_per_core;
@ -521,7 +521,6 @@ platform_start(__register_t a0 __unused,
/* initialize console so that we have printf */
boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */
nlm_pic_irt_init(0); /* complete before interrupts or console init */
init_static_kenv(boot1_env, sizeof(boot1_env));
xlp_bootargs_init(a0);

View File

@ -1,32 +1,31 @@
/*-
* Copyright (c) 2003-2009 RMI Corporation
* All rights reserved.
* Copyright (c) 2003-2012 Broadcom Corporation
* All Rights Reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of RMI Corporation, nor the names of its contributors,
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* NETLOGIC_BSD */
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@ -39,14 +38,16 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/endian.h>
#include <sys/rman.h>
#include <sys/pciio.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <sys/pciio.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pci_private.h>
#include <dev/uart/uart.h>
#include <dev/uart/uart_bus.h>
#include <dev/uart/uart_cpu.h>
@ -68,16 +69,260 @@ __FBSDID("$FreeBSD$");
#include <mips/nlm/xlp.h>
#include "pcib_if.h"
#include "pci_if.h"
struct xlp_pcib_softc {
bus_dma_tag_t sc_pci_dmat; /* PCI DMA tag pointer */
#define EMUL_MEM_START 0x16000000UL
#define EMUL_MEM_END 0x18ffffffUL
/* SoC device qurik handling */
static int irt_irq_map[4 * 256];
static int irq_irt_map[64];
static void
xlp_add_irq(int node, int irt, int irq)
{
int nodeirt = node * 256 + irt;
irt_irq_map[nodeirt] = irq;
irq_irt_map[irq] = nodeirt;
}
int
xlp_irq_to_irt(int irq)
{
return irq_irt_map[irq];
}
int
xlp_irt_to_irq(int nodeirt)
{
return irt_irq_map[nodeirt];
}
/* Override PCI a bit for SoC devices */
enum {
INTERNAL_DEV = 0x1, /* internal device, skip on enumeration */
MEM_RES_EMUL = 0x2, /* no MEM or IO bar, custom res alloc */
SHARED_IRQ = 0x4,
DEV_MMIO32 = 0x8, /* byte access not allowed to mmio */
};
struct soc_dev_desc {
u_int devid; /* device ID */
int irqbase; /* start IRQ */
u_int flags; /* flags */
int ndevs; /* to keep track of number of devices */
};
struct soc_dev_desc xlp_dev_desc[] = {
{ PCI_DEVICE_ID_NLM_ICI, 0, INTERNAL_DEV },
{ PCI_DEVICE_ID_NLM_PIC, 0, INTERNAL_DEV },
{ PCI_DEVICE_ID_NLM_FMN, 0, INTERNAL_DEV },
{ PCI_DEVICE_ID_NLM_UART, PIC_UART_0_IRQ, MEM_RES_EMUL | DEV_MMIO32},
{ PCI_DEVICE_ID_NLM_I2C, 0, MEM_RES_EMUL | DEV_MMIO32 },
{ PCI_DEVICE_ID_NLM_NOR, 0, MEM_RES_EMUL },
{ PCI_DEVICE_ID_NLM_MMC, PIC_MMC_IRQ, MEM_RES_EMUL },
{ PCI_DEVICE_ID_NLM_EHCI, PIC_EHCI_0_IRQ, 0 }
};
struct xlp_devinfo {
struct pci_devinfo pcidev;
int irq;
int flags;
u_long mem_res_start;
};
static __inline struct soc_dev_desc *
xlp_find_soc_desc(int devid)
{
struct soc_dev_desc *p;
int i, n;
n = sizeof(xlp_dev_desc) / sizeof(xlp_dev_desc[0]);
for (i = 0, p = xlp_dev_desc; i < n; i++, p++)
if (p->devid == devid)
return (p);
return (NULL);
}
static struct resource *
xlp_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
struct resource *r;
struct xlp_devinfo *xlp_devinfo;
int busno;
/*
* Do custom allocation for MEMORY resource for SoC device if
* MEM_RES_EMUL flag is set
*/
busno = pci_get_bus(child);
if ((type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) && busno == 0) {
xlp_devinfo = (struct xlp_devinfo *)device_get_ivars(child);
if ((xlp_devinfo->flags & MEM_RES_EMUL) != 0) {
/* no emulation for IO ports */
if (type == SYS_RES_IOPORT)
return (NULL);
start = xlp_devinfo->mem_res_start;
count = XLP_PCIE_CFG_SIZE - XLP_IO_PCI_HDRSZ;
end = start + count - 1;
r = BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
type, rid, start, end, count, flags);
if (r == NULL)
return (NULL);
if ((xlp_devinfo->flags & DEV_MMIO32) != 0)
rman_set_bustag(r, rmi_uart_bus_space);
return (r);
}
}
/* Not custom alloc, use PCI code */
return (pci_alloc_resource(bus, child, type, rid, start, end, count,
flags));
}
static int
xlp_pci_release_resource(device_t bus, device_t child, int type, int rid,
struct resource *r)
{
u_long start;
/* If custom alloc, handle that */
start = rman_get_start(r);
if (type == SYS_RES_MEMORY && pci_get_bus(child) == 0 &&
start >= EMUL_MEM_START && start <= EMUL_MEM_END)
return (BUS_RELEASE_RESOURCE(device_get_parent(bus), child,
type, rid, r));
/* use default PCI function */
return (bus_generic_rl_release_resource(bus, child, type, rid, r));
}
static void
xlp_add_soc_child(device_t pcib, device_t dev, int b, int s, int f)
{
struct pci_devinfo *dinfo;
struct xlp_devinfo *xlp_dinfo;
struct soc_dev_desc *si;
uint64_t pcibase;
int domain, node, irt, irq, flags, devoffset, num;
uint16_t devid;
domain = pcib_get_domain(dev);
node = s / 8;
devoffset = XLP_HDR_OFFSET(node, 0, s % 8, f);
if (!nlm_dev_exists(devoffset))
return;
/* Find if there is a desc for the SoC device */
devid = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_DEVICE, 2);
si = xlp_find_soc_desc(devid);
/* update flags and irq from desc if available */
irq = 0;
flags = 0;
if (si != NULL) {
if (si->irqbase != 0)
irq = si->irqbase + si->ndevs;
flags = si->flags;
si->ndevs++;
}
/* skip internal devices */
if ((flags & INTERNAL_DEV) != 0)
return;
/* PCIe interfaces are special, bug in Ax */
if (devid == PCI_DEVICE_ID_NLM_PCIE) {
xlp_add_irq(node, xlp_pcie_link_irt(f), PIC_PCIE_0_IRQ + f);
} else {
/* Stash intline and pin in shadow reg for devices */
pcibase = nlm_pcicfg_base(devoffset);
irt = nlm_irtstart(pcibase);
num = nlm_irtnum(pcibase);
if (irq != 0 && num > 0) {
xlp_add_irq(node, irt, irq);
nlm_write_reg(pcibase, XLP_PCI_DEVSCRATCH_REG0,
(1 << 8) | irq);
}
}
dinfo = pci_read_device(pcib, domain, b, s, f, sizeof(*xlp_dinfo));
if (dinfo == NULL)
return;
xlp_dinfo = (struct xlp_devinfo *)dinfo;
xlp_dinfo->irq = irq;
xlp_dinfo->flags = flags;
if ((flags & MEM_RES_EMUL) != 0)
xlp_dinfo->mem_res_start = XLP_DEFAULT_IO_BASE + devoffset +
XLP_IO_PCI_HDRSZ;
pci_add_child(dev, dinfo);
}
static int
xlp_pci_attach(device_t dev)
{
device_t pcib = device_get_parent(dev);
int maxslots, s, f, pcifunchigh;
int busno;
uint8_t hdrtype;
/*
* The on-chip devices are on a bus that is almost, but not
* quite, completely like PCI. Add those things by hand.
*/
busno = pcib_get_bus(dev);
maxslots = PCIB_MAXSLOTS(pcib);
for (s = 0; s <= maxslots; s++) {
pcifunchigh = 0;
f = 0;
hdrtype = PCIB_READ_CONFIG(pcib, busno, s, f, PCIR_HDRTYPE, 1);
if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
continue;
if (hdrtype & PCIM_MFDEV)
pcifunchigh = PCI_FUNCMAX;
for (f = 0; f <= pcifunchigh; f++)
xlp_add_soc_child(pcib, dev, busno, s, f);
}
return (bus_generic_attach(dev));
}
static int
xlp_pci_probe(device_t dev)
{
device_t pcib;
pcib = device_get_parent(dev);
/*
* Only the top level bus has SoC devices, leave the rest to
* Generic PCI code
*/
if (strcmp(device_get_nameunit(pcib), "pcib0") != 0)
return (ENXIO);
device_set_desc(dev, "XLP SoCbus");
return (BUS_PROBE_DEFAULT);
}
static devclass_t pci_devclass;
static device_method_t xlp_pci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, xlp_pci_probe),
DEVMETHOD(device_attach, xlp_pci_attach),
DEVMETHOD(bus_alloc_resource, xlp_pci_alloc_resource),
DEVMETHOD(bus_release_resource, xlp_pci_release_resource),
DEVMETHOD_END
};
DEFINE_CLASS_1(pci, xlp_pci_driver, xlp_pci_methods, 0, pci_driver);
DRIVER_MODULE(xlp_pci, pcib, xlp_pci_driver, pci_devclass, 0, 0);
static devclass_t pcib_devclass;
static struct rman irq_rman, port_rman, mem_rman, emul_rman;
static void
xlp_pci_init_resources(void)
xlp_pcib_init_resources(void)
{
irq_rman.rm_start = 0;
irq_rman.rm_end = 255;
@ -112,7 +357,7 @@ xlp_pci_init_resources(void)
emul_rman.rm_type = RMAN_ARRAY;
emul_rman.rm_descr = "Emulated MEMIO";
if (rman_init(&emul_rman)
|| rman_manage_region(&emul_rman, 0x16000000UL, 0x18ffffffUL))
|| rman_manage_region(&emul_rman, EMUL_MEM_START, EMUL_MEM_END))
panic("pci_init_resources emul_rman");
}
@ -121,7 +366,7 @@ xlp_pcib_probe(device_t dev)
{
device_set_desc(dev, "XLP PCI bus");
xlp_pci_init_resources();
xlp_pcib_init_resources();
return (0);
}
@ -173,20 +418,15 @@ xlp_pcib_read_config(device_t dev, u_int b, u_int s, u_int f,
else if ((width == 4) && (reg & 3))
return 0xFFFFFFFF;
data = nlm_read_pci_reg(cfgaddr, regindex);
/*
* Fix up read data in some SoC devices
* to emulate complete PCIe header
* The intline and int pin of SoC devices are DOA, except
* for bridges (slot %8 == 1).
* use the values we stashed in a writable PCI scratch reg.
*/
if (b == 0) {
int dev = s % 8;
if (b == 0 && regindex == 0xf && s % 8 > 1)
regindex = XLP_PCI_DEVSCRATCH_REG0;
/* Fake intpin on config read for UART/I2C, USB, SD/Flash */
if (regindex == 0xf &&
(dev == 6 || dev == 2 || dev == 7))
data |= 0x1 << 8; /* Fake int pin */
}
data = nlm_read_pci_reg(cfgaddr, regindex);
if (width == 1)
return ((data >> ((reg & 3) << 3)) & 0xff);
else if (width == 2)
@ -221,8 +461,12 @@ xlp_pcib_write_config(device_t dev, u_int b, u_int s, u_int f,
data = val;
}
/*
* use shadow reg for intpin/intline which are dead
*/
if (b == 0 && regindex == 0xf && s % 8 > 1)
regindex = XLP_PCI_DEVSCRATCH_REG0;
nlm_write_pci_reg(cfgaddr, regindex, data);
return;
}
/*
@ -230,7 +474,7 @@ xlp_pcib_write_config(device_t dev, u_int b, u_int s, u_int f,
* from the link's IO and MEM address ranges.
*/
static void
xlp_pci_hardware_swap_enable(int node, int link)
xlp_pcib_hardware_swap_enable(int node, int link)
{
uint64_t bbase, linkpcibase;
uint32_t bar;
@ -263,7 +507,7 @@ xlp_pcib_attach(device_t dev)
/* enable hardware swap on all nodes/links */
for (node = 0; node < XLP_MAX_NODES; node++)
for (link = 0; link < 4; link++)
xlp_pci_hardware_swap_enable(node, link);
xlp_pcib_hardware_swap_enable(node, link);
device_add_child(dev, "pci", 0);
bus_generic_attach(dev);
@ -384,7 +628,7 @@ bridge_pcie_ack(int irq)
}
static int
mips_platform_pci_setup_intr(device_t dev, device_t child,
mips_platform_pcib_setup_intr(device_t dev, device_t child,
struct resource *irq, int flags, driver_filter_t *filt,
driver_intr_t *intr, void *arg, void **cookiep)
{
@ -401,11 +645,11 @@ mips_platform_pci_setup_intr(device_t dev, device_t child,
return (EINVAL);
}
xlpirq = rman_get_start(irq);
if (strcmp(device_get_name(dev), "pcib") != 0) {
device_printf(dev, "ret 0 on dev\n");
if (xlpirq == 0)
return (0);
if (strcmp(device_get_name(dev), "pcib") != 0)
return (0);
}
/*
* temporary hack for MSI, we support just one device per
@ -465,7 +709,7 @@ mips_platform_pci_setup_intr(device_t dev, device_t child,
}
static int
mips_platform_pci_teardown_intr(device_t dev, device_t child,
mips_platform_pcib_teardown_intr(device_t dev, device_t child,
struct resource *irq, void *cookie)
{
if (strcmp(device_get_name(child), "pci") == 0) {
@ -475,146 +719,65 @@ mips_platform_pci_teardown_intr(device_t dev, device_t child,
return (bus_generic_teardown_intr(dev, child, irq, cookie));
}
static void
assign_soc_resource(device_t child, int type, u_long *startp, u_long *endp,
u_long *countp, struct rman **rm, bus_space_tag_t *bst, vm_offset_t *va)
{
int devid, inst, node, unit;
uint32_t val;
devid = pci_get_device(child);
inst = pci_get_function(child);
node = pci_get_slot(child) / 8;
unit = device_get_unit(child);
*rm = NULL;
*va = 0;
*bst = 0;
if (type == SYS_RES_MEMORY) {
switch (devid) {
case PCI_DEVICE_ID_NLM_UART:
*va = nlm_get_uart_regbase(node, inst);
*startp = MIPS_KSEG1_TO_PHYS(*va);
*countp = 0x100;
*rm = &emul_rman;
*bst = uart_bus_space_mem;
break;
case PCI_DEVICE_ID_NLM_I2C:
*va = nlm_pcicfg_base(XLP_IO_I2C_OFFSET(node, unit)) +
XLP_IO_PCI_HDRSZ;
*startp = MIPS_KSEG1_TO_PHYS(*va);
*countp = 0x100;
*rm = &emul_rman;
*bst = uart_bus_space_mem;
break;
case PCI_DEVICE_ID_NLM_NOR:
/* XXXJC: support multiple chip selects */
val = nlm_read_pci_reg(nlm_get_gbu_regbase(node), 0);
*startp = val << 8;
*va = MIPS_PHYS_TO_KSEG1(*startp);
/* XXXJC: count is not correct */
*countp = 0x100;
*rm = &emul_rman;
break;
}
/* calculate end if allocated */
if (*rm)
*endp = *startp + *countp - 1;
} else if (type != SYS_RES_IRQ) {
/*
* IRQ allocation is done by route_interrupt,
* for any other request print warning.
*/
printf("Unknown type %d in req for [%x%x]\n",
type, devid, inst);
}
}
static struct resource *
xlp_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
xlp_pcib_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
struct rman *rm = NULL;
struct resource *rv;
vm_offset_t va = 0;
void *va;
int needactivate = flags & RF_ACTIVE;
bus_space_tag_t bst = 0;
/*
* For SoC PCI devices, we have to assign resources correctly
* since the IRQ and MEM resources depend on the block.
* If the address is not from BAR0, then we use emul_rman
*/
if (pci_get_bus(child) == 0 &&
pci_get_vendor(child) == PCI_VENDOR_NETLOGIC)
assign_soc_resource(child, type, &start, &end,
&count, &rm, &bst, &va);
if (rm == NULL) {
switch (type) {
case SYS_RES_IRQ:
rm = &irq_rman;
break;
switch (type) {
case SYS_RES_IRQ:
rm = &irq_rman;
break;
case SYS_RES_IOPORT:
rm = &port_rman;
break;
case SYS_RES_IOPORT:
rm = &port_rman;
break;
case SYS_RES_MEMORY:
case SYS_RES_MEMORY:
if (start >= EMUL_MEM_START && start <= EMUL_MEM_END)
rm = &emul_rman;
else
rm = &mem_rman;
break;
default:
return (0);
}
default:
return (0);
}
rv = rman_reserve_resource(rm, start, end, count, flags, child);
if (rv == 0)
return (0);
if (rv == NULL)
return (NULL);
rman_set_rid(rv, *rid);
if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
if (va == 0)
va = (vm_offset_t)pmap_mapdev(start, count);
if (bst == 0)
bst = rmi_bus_space;
rman_set_bushandle(rv, va);
rman_set_virtual(rv, (void *)va);
rman_set_bustag(rv, bst);
va = pmap_mapdev(start, count);
rman_set_bushandle(rv, (bus_space_handle_t)va);
rman_set_bustag(rv, rmi_bus_space);
}
if (needactivate) {
if (bus_activate_resource(child, type, *rid, rv)) {
rman_release_resource(rv);
return (NULL);
}
}
return (rv);
}
static int
xlp_pci_release_resource(device_t bus, device_t child, int type, int rid,
xlp_pcib_release_resource(device_t bus, device_t child, int type, int rid,
struct resource *r)
{
return (rman_release_resource(r));
}
static bus_dma_tag_t
xlp_pci_get_dma_tag(device_t bus, device_t child)
{
struct xlp_pcib_softc *sc;
sc = device_get_softc(bus);
return (sc->sc_pci_dmat);
}
static int
xlp_pci_activate_resource(device_t bus, device_t child, int type, int rid,
xlp_pcib_activate_resource(device_t bus, device_t child, int type, int rid,
struct resource *r)
{
@ -622,7 +785,7 @@ xlp_pci_activate_resource(device_t bus, device_t child, int type, int rid,
}
static int
xlp_pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
xlp_pcib_deactivate_resource(device_t bus, device_t child, int type, int rid,
struct resource *r)
{
@ -630,7 +793,7 @@ xlp_pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
}
static int
mips_pci_route_interrupt(device_t bus, device_t dev, int pin)
mips_pcib_route_interrupt(device_t bus, device_t dev, int pin)
{
int irt, link;
@ -685,19 +848,18 @@ static device_method_t xlp_pcib_methods[] = {
/* Bus interface */
DEVMETHOD(bus_read_ivar, xlp_pcib_read_ivar),
DEVMETHOD(bus_write_ivar, xlp_pcib_write_ivar),
DEVMETHOD(bus_alloc_resource, xlp_pci_alloc_resource),
DEVMETHOD(bus_release_resource, xlp_pci_release_resource),
DEVMETHOD(bus_get_dma_tag, xlp_pci_get_dma_tag),
DEVMETHOD(bus_activate_resource, xlp_pci_activate_resource),
DEVMETHOD(bus_deactivate_resource, xlp_pci_deactivate_resource),
DEVMETHOD(bus_setup_intr, mips_platform_pci_setup_intr),
DEVMETHOD(bus_teardown_intr, mips_platform_pci_teardown_intr),
DEVMETHOD(bus_alloc_resource, xlp_pcib_alloc_resource),
DEVMETHOD(bus_release_resource, xlp_pcib_release_resource),
DEVMETHOD(bus_activate_resource, xlp_pcib_activate_resource),
DEVMETHOD(bus_deactivate_resource, xlp_pcib_deactivate_resource),
DEVMETHOD(bus_setup_intr, mips_platform_pcib_setup_intr),
DEVMETHOD(bus_teardown_intr, mips_platform_pcib_teardown_intr),
/* pcib interface */
DEVMETHOD(pcib_maxslots, xlp_pcib_maxslots),
DEVMETHOD(pcib_read_config, xlp_pcib_read_config),
DEVMETHOD(pcib_write_config, xlp_pcib_write_config),
DEVMETHOD(pcib_route_interrupt, mips_pci_route_interrupt),
DEVMETHOD(pcib_route_interrupt, mips_pcib_route_interrupt),
DEVMETHOD(pcib_alloc_msi, xlp_alloc_msi),
DEVMETHOD(pcib_release_msi, xlp_release_msi),
@ -709,7 +871,7 @@ static device_method_t xlp_pcib_methods[] = {
static driver_t xlp_pcib_driver = {
"pcib",
xlp_pcib_methods,
sizeof(struct xlp_pcib_softc),
1, /* no softc */
};
DRIVER_MODULE(pcib, nexus, xlp_pcib_driver, pcib_devclass, 0, 0);