diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-02-15 16:24:37 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-02-15 16:24:37 -0500 |
commit | ca994a36f585432458ead9133fcfe05440edbb7b (patch) | |
tree | be05512153a9cd5cbe1f1234bc09fd9cd388ec58 /arch/mips/pci | |
parent | 12325280dfeba18164f9c47e226a40ab34e23ee7 (diff) | |
parent | 2504a6423b9ab4c36df78227055995644de19edb (diff) | |
download | op-kernel-dev-ca994a36f585432458ead9133fcfe05440edbb7b.zip op-kernel-dev-ca994a36f585432458ead9133fcfe05440edbb7b.tar.gz |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
Conflicts:
net/mac80211/debugfs_sta.c
net/mac80211/sta_info.h
Diffstat (limited to 'arch/mips/pci')
-rw-r--r-- | arch/mips/pci/Makefile | 3 | ||||
-rw-r--r-- | arch/mips/pci/msi-octeon.c | 2 | ||||
-rw-r--r-- | arch/mips/pci/ops-pmcmsp.c | 2 | ||||
-rw-r--r-- | arch/mips/pci/ops-tx3927.c | 2 | ||||
-rw-r--r-- | arch/mips/pci/pci-alchemy.c | 138 | ||||
-rw-r--r-- | arch/mips/pci/pci-ath724x.c | 174 | ||||
-rw-r--r-- | arch/mips/pci/pci-bcm63xx.c | 4 | ||||
-rw-r--r-- | arch/mips/pci/pci-octeon.c | 16 | ||||
-rw-r--r-- | arch/mips/pci/pci-tx4927.c | 2 | ||||
-rw-r--r-- | arch/mips/pci/pci-tx4938.c | 2 | ||||
-rw-r--r-- | arch/mips/pci/pci-tx4939.c | 2 | ||||
-rw-r--r-- | arch/mips/pci/pci-xlr.c | 128 | ||||
-rw-r--r-- | arch/mips/pci/pci.c | 29 | ||||
-rw-r--r-- | arch/mips/pci/pcie-octeon.c | 1349 |
14 files changed, 1436 insertions, 417 deletions
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index bb82cbdb..c3ac4b0 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ ops-bcm63xx.o obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o +obj-$(CONFIG_SOC_AR724X) += pci-ath724x.o # # These are still pretty much in the old state, watch, go blind. @@ -55,7 +56,7 @@ obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o obj-$(CONFIG_MIKROTIK_RB532) += pci-rc32434.o ops-rc32434.o fixup-rc32434.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += pci-octeon.o pcie-octeon.o -obj-$(CONFIG_NLM_XLR) += pci-xlr.o +obj-$(CONFIG_CPU_XLR) += pci-xlr.o ifdef CONFIG_PCI_MSI obj-$(CONFIG_CPU_CAVIUM_OCTEON) += msi-octeon.o diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c index 5d530f8..d37be36 100644 --- a/arch/mips/pci/msi-octeon.c +++ b/arch/mips/pci/msi-octeon.c @@ -162,7 +162,7 @@ msi_irq_allocated: msg.address_hi = (0 + CVMX_NPEI_PCIE_MSI_RCV) >> 32; break; default: - panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type\n"); + panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type"); } msg.data = irq - OCTEON_IRQ_MSI_BIT0; diff --git a/arch/mips/pci/ops-pmcmsp.c b/arch/mips/pci/ops-pmcmsp.c index 8fbfbf2..389bf66 100644 --- a/arch/mips/pci/ops-pmcmsp.c +++ b/arch/mips/pci/ops-pmcmsp.c @@ -405,7 +405,7 @@ int msp_pcibios_config_access(unsigned char access_type, if (pciirqflag == 0) { ret = request_irq(MSP_INT_PCI,/* Hardcoded internal MSP7120 wiring */ bpci_interrupt, - IRQF_SHARED | IRQF_DISABLED, + IRQF_SHARED, "PMC MSP PCI Host", preg); if (ret != 0) diff --git a/arch/mips/pci/ops-tx3927.c b/arch/mips/pci/ops-tx3927.c index 6a3bdb5..02d64f77 100644 --- a/arch/mips/pci/ops-tx3927.c +++ b/arch/mips/pci/ops-tx3927.c @@ -225,7 +225,7 @@ void __init tx3927_setup_pcierr_irq(void) { if (request_irq(TXX9_IRQ_BASE + TX3927_IR_PCI, tx3927_pcierr_interrupt, - IRQF_DISABLED, "PCI error", + 0, "PCI error", (void *)TX3927_PCIC_REG)) printk(KERN_WARNING "Failed to request irq for PCIERR\n"); } diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c index b5ce041..ec125bed 100644 --- a/arch/mips/pci/pci-alchemy.c +++ b/arch/mips/pci/pci-alchemy.c @@ -13,9 +13,11 @@ #include <linux/platform_device.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/syscore_ops.h> #include <linux/vmalloc.h> #include <asm/mach-au1x00/au1000.h> +#include <asm/tlbmisc.h> #ifdef CONFIG_DEBUG_PCI #define DBG(x...) printk(KERN_DEBUG x) @@ -41,6 +43,12 @@ struct alchemy_pci_context { int (*board_pci_idsel)(unsigned int devsel, int assert); }; +/* for syscore_ops. There's only one PCI controller on Alchemy chips, so this + * should suffice for now. + */ +static struct alchemy_pci_context *__alchemy_pci_ctx; + + /* IO/MEM resources for PCI. Keep the memres in sync with __fixup_bigphys_addr * in arch/mips/alchemy/common/setup.c */ @@ -99,18 +107,6 @@ static int config_access(unsigned char access_type, struct pci_bus *bus, return -1; } - /* YAMON on all db1xxx boards wipes the TLB and writes zero to C0_wired - * on resume, clearing our wired entry. Unfortunately the ->resume() - * callback is called way way way too late (and ->suspend() too early) - * to have them destroy and recreate it. Instead just test if c0_wired - * is now lower than the index we retrieved before suspending and then - * recreate the entry if necessary. Of course this is totally bonkers - * and breaks as soon as someone else adds another wired entry somewhere - * else. Anyone have any ideas how to handle this better? - */ - if (unlikely(read_c0_wired() < ctx->wired_entry)) - alchemy_pci_wired_entry(ctx); - local_irq_save(flags); r = __raw_readl(ctx->regs + PCI_REG_STATCMD) & 0x0000ffff; r |= PCI_STATCMD_STATUS(0x2000); @@ -304,6 +300,62 @@ static int alchemy_pci_def_idsel(unsigned int devsel, int assert) return 1; /* success */ } +/* save PCI controller register contents. */ +static int alchemy_pci_suspend(void) +{ + struct alchemy_pci_context *ctx = __alchemy_pci_ctx; + if (!ctx) + return 0; + + ctx->pm[0] = __raw_readl(ctx->regs + PCI_REG_CMEM); + ctx->pm[1] = __raw_readl(ctx->regs + PCI_REG_CONFIG) & 0x0009ffff; + ctx->pm[2] = __raw_readl(ctx->regs + PCI_REG_B2BMASK_CCH); + ctx->pm[3] = __raw_readl(ctx->regs + PCI_REG_B2BBASE0_VID); + ctx->pm[4] = __raw_readl(ctx->regs + PCI_REG_B2BBASE1_SID); + ctx->pm[5] = __raw_readl(ctx->regs + PCI_REG_MWMASK_DEV); + ctx->pm[6] = __raw_readl(ctx->regs + PCI_REG_MWBASE_REV_CCL); + ctx->pm[7] = __raw_readl(ctx->regs + PCI_REG_ID); + ctx->pm[8] = __raw_readl(ctx->regs + PCI_REG_CLASSREV); + ctx->pm[9] = __raw_readl(ctx->regs + PCI_REG_PARAM); + ctx->pm[10] = __raw_readl(ctx->regs + PCI_REG_MBAR); + ctx->pm[11] = __raw_readl(ctx->regs + PCI_REG_TIMEOUT); + + return 0; +} + +static void alchemy_pci_resume(void) +{ + struct alchemy_pci_context *ctx = __alchemy_pci_ctx; + if (!ctx) + return; + + __raw_writel(ctx->pm[0], ctx->regs + PCI_REG_CMEM); + __raw_writel(ctx->pm[2], ctx->regs + PCI_REG_B2BMASK_CCH); + __raw_writel(ctx->pm[3], ctx->regs + PCI_REG_B2BBASE0_VID); + __raw_writel(ctx->pm[4], ctx->regs + PCI_REG_B2BBASE1_SID); + __raw_writel(ctx->pm[5], ctx->regs + PCI_REG_MWMASK_DEV); + __raw_writel(ctx->pm[6], ctx->regs + PCI_REG_MWBASE_REV_CCL); + __raw_writel(ctx->pm[7], ctx->regs + PCI_REG_ID); + __raw_writel(ctx->pm[8], ctx->regs + PCI_REG_CLASSREV); + __raw_writel(ctx->pm[9], ctx->regs + PCI_REG_PARAM); + __raw_writel(ctx->pm[10], ctx->regs + PCI_REG_MBAR); + __raw_writel(ctx->pm[11], ctx->regs + PCI_REG_TIMEOUT); + wmb(); + __raw_writel(ctx->pm[1], ctx->regs + PCI_REG_CONFIG); + wmb(); + + /* YAMON on all db1xxx boards wipes the TLB and writes zero to C0_wired + * on resume, making it necessary to recreate it as soon as possible. + */ + ctx->wired_entry = 8191; /* impossibly high value */ + alchemy_pci_wired_entry(ctx); /* install it */ +} + +static struct syscore_ops alchemy_pci_pmops = { + .suspend = alchemy_pci_suspend, + .resume = alchemy_pci_resume, +}; + static int __devinit alchemy_pci_probe(struct platform_device *pdev) { struct alchemy_pci_platdata *pd = pdev->dev.platform_data; @@ -396,7 +448,8 @@ static int __devinit alchemy_pci_probe(struct platform_device *pdev) ret = -ENOMEM; goto out4; } - ctx->wired_entry = 8192; /* impossibly high value */ + ctx->wired_entry = 8191; /* impossibly high value */ + alchemy_pci_wired_entry(ctx); /* install it */ set_io_port_base((unsigned long)ctx->alchemy_pci_ctrl.io_map_base); @@ -408,7 +461,9 @@ static int __devinit alchemy_pci_probe(struct platform_device *pdev) __raw_writel(val, ctx->regs + PCI_REG_CONFIG); wmb(); + __alchemy_pci_ctx = ctx; platform_set_drvdata(pdev, ctx); + register_syscore_ops(&alchemy_pci_pmops); register_pci_controller(&ctx->alchemy_pci_ctrl); return 0; @@ -425,68 +480,11 @@ out: return ret; } - -#ifdef CONFIG_PM -/* save PCI controller register contents. */ -static int alchemy_pci_suspend(struct device *dev) -{ - struct alchemy_pci_context *ctx = dev_get_drvdata(dev); - - ctx->pm[0] = __raw_readl(ctx->regs + PCI_REG_CMEM); - ctx->pm[1] = __raw_readl(ctx->regs + PCI_REG_CONFIG) & 0x0009ffff; - ctx->pm[2] = __raw_readl(ctx->regs + PCI_REG_B2BMASK_CCH); - ctx->pm[3] = __raw_readl(ctx->regs + PCI_REG_B2BBASE0_VID); - ctx->pm[4] = __raw_readl(ctx->regs + PCI_REG_B2BBASE1_SID); - ctx->pm[5] = __raw_readl(ctx->regs + PCI_REG_MWMASK_DEV); - ctx->pm[6] = __raw_readl(ctx->regs + PCI_REG_MWBASE_REV_CCL); - ctx->pm[7] = __raw_readl(ctx->regs + PCI_REG_ID); - ctx->pm[8] = __raw_readl(ctx->regs + PCI_REG_CLASSREV); - ctx->pm[9] = __raw_readl(ctx->regs + PCI_REG_PARAM); - ctx->pm[10] = __raw_readl(ctx->regs + PCI_REG_MBAR); - ctx->pm[11] = __raw_readl(ctx->regs + PCI_REG_TIMEOUT); - - return 0; -} - -static int alchemy_pci_resume(struct device *dev) -{ - struct alchemy_pci_context *ctx = dev_get_drvdata(dev); - - __raw_writel(ctx->pm[0], ctx->regs + PCI_REG_CMEM); - __raw_writel(ctx->pm[2], ctx->regs + PCI_REG_B2BMASK_CCH); - __raw_writel(ctx->pm[3], ctx->regs + PCI_REG_B2BBASE0_VID); - __raw_writel(ctx->pm[4], ctx->regs + PCI_REG_B2BBASE1_SID); - __raw_writel(ctx->pm[5], ctx->regs + PCI_REG_MWMASK_DEV); - __raw_writel(ctx->pm[6], ctx->regs + PCI_REG_MWBASE_REV_CCL); - __raw_writel(ctx->pm[7], ctx->regs + PCI_REG_ID); - __raw_writel(ctx->pm[8], ctx->regs + PCI_REG_CLASSREV); - __raw_writel(ctx->pm[9], ctx->regs + PCI_REG_PARAM); - __raw_writel(ctx->pm[10], ctx->regs + PCI_REG_MBAR); - __raw_writel(ctx->pm[11], ctx->regs + PCI_REG_TIMEOUT); - wmb(); - __raw_writel(ctx->pm[1], ctx->regs + PCI_REG_CONFIG); - wmb(); - - return 0; -} - -static const struct dev_pm_ops alchemy_pci_pmops = { - .suspend = alchemy_pci_suspend, - .resume = alchemy_pci_resume, -}; - -#define ALCHEMY_PCICTL_PM (&alchemy_pci_pmops) - -#else -#define ALCHEMY_PCICTL_PM NULL -#endif - static struct platform_driver alchemy_pcictl_driver = { .probe = alchemy_pci_probe, .driver = { .name = "alchemy-pci", .owner = THIS_MODULE, - .pm = ALCHEMY_PCICTL_PM, }, }; diff --git a/arch/mips/pci/pci-ath724x.c b/arch/mips/pci/pci-ath724x.c new file mode 100644 index 0000000..a4dd24a --- /dev/null +++ b/arch/mips/pci/pci-ath724x.c @@ -0,0 +1,174 @@ +/* + * Atheros 724x PCI support + * + * Copyright (C) 2011 RenĂ© Bolldorf <xsecute@googlemail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/pci.h> +#include <asm/mach-ath79/pci-ath724x.h> + +#define reg_read(_phys) (*(unsigned int *) KSEG1ADDR(_phys)) +#define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val)) + +#define ATH724X_PCI_DEV_BASE 0x14000000 +#define ATH724X_PCI_MEM_BASE 0x10000000 +#define ATH724X_PCI_MEM_SIZE 0x08000000 + +static DEFINE_SPINLOCK(ath724x_pci_lock); +static struct ath724x_pci_data *pci_data; +static int pci_data_size; + +static int ath724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, + int size, uint32_t *value) +{ + unsigned long flags, addr, tval, mask; + + if (devfn) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (where & (size - 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + spin_lock_irqsave(&ath724x_pci_lock, flags); + + switch (size) { + case 1: + addr = where & ~3; + mask = 0xff000000 >> ((where % 4) * 8); + tval = reg_read(ATH724X_PCI_DEV_BASE + addr); + tval = tval & ~mask; + *value = (tval >> ((4 - (where % 4))*8)); + break; + case 2: + addr = where & ~3; + mask = 0xffff0000 >> ((where % 4)*8); + tval = reg_read(ATH724X_PCI_DEV_BASE + addr); + tval = tval & ~mask; + *value = (tval >> ((4 - (where % 4))*8)); + break; + case 4: + *value = reg_read(ATH724X_PCI_DEV_BASE + where); + break; + default: + spin_unlock_irqrestore(&ath724x_pci_lock, flags); + + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + spin_unlock_irqrestore(&ath724x_pci_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, + int size, uint32_t value) +{ + unsigned long flags, tval, addr, mask; + + if (devfn) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (where & (size - 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + spin_lock_irqsave(&ath724x_pci_lock, flags); + + switch (size) { + case 1: + addr = (ATH724X_PCI_DEV_BASE + where) & ~3; + mask = 0xff000000 >> ((where % 4)*8); + tval = reg_read(addr); + tval = tval & ~mask; + tval |= (value << ((4 - (where % 4))*8)) & mask; + reg_write(addr, tval); + break; + case 2: + addr = (ATH724X_PCI_DEV_BASE + where) & ~3; + mask = 0xffff0000 >> ((where % 4)*8); + tval = reg_read(addr); + tval = tval & ~mask; + tval |= (value << ((4 - (where % 4))*8)) & mask; + reg_write(addr, tval); + break; + case 4: + reg_write((ATH724X_PCI_DEV_BASE + where), value); + break; + default: + spin_unlock_irqrestore(&ath724x_pci_lock, flags); + + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + spin_unlock_irqrestore(&ath724x_pci_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops ath724x_pci_ops = { + .read = ath724x_pci_read, + .write = ath724x_pci_write, +}; + +static struct resource ath724x_io_resource = { + .name = "PCI IO space", + .start = 0, + .end = 0, + .flags = IORESOURCE_IO, +}; + +static struct resource ath724x_mem_resource = { + .name = "PCI memory space", + .start = ATH724X_PCI_MEM_BASE, + .end = ATH724X_PCI_MEM_BASE + ATH724X_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct pci_controller ath724x_pci_controller = { + .pci_ops = &ath724x_pci_ops, + .io_resource = &ath724x_io_resource, + .mem_resource = &ath724x_mem_resource, +}; + +void ath724x_pci_add_data(struct ath724x_pci_data *data, int size) +{ + pci_data = data; + pci_data_size = size; +} + +int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) +{ + unsigned int devfn = dev->devfn; + int irq = -1; + + if (devfn > pci_data_size - 1) + return irq; + + irq = pci_data[devfn].irq; + + return irq; +} + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + unsigned int devfn = dev->devfn; + + if (devfn > pci_data_size - 1) + return PCIBIOS_DEVICE_NOT_FOUND; + + dev->dev.platform_data = pci_data[devfn].pdata; + + return PCIBIOS_SUCCESSFUL; +} + +static int __init ath724x_pcibios_init(void) +{ + register_pci_controller(&ath724x_pci_controller); + + return PCIBIOS_SUCCESSFUL; +} + +arch_initcall(ath724x_pcibios_init); diff --git a/arch/mips/pci/pci-bcm63xx.c b/arch/mips/pci/pci-bcm63xx.c index 82e0fde..39eb7c4 100644 --- a/arch/mips/pci/pci-bcm63xx.c +++ b/arch/mips/pci/pci-bcm63xx.c @@ -99,7 +99,7 @@ static int __init bcm63xx_pci_init(void) unsigned int mem_size; u32 val; - if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358()) + if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358() && !BCMCPU_IS_6368()) return -ENODEV; if (!bcm63xx_pci_enabled) @@ -159,7 +159,7 @@ static int __init bcm63xx_pci_init(void) /* setup PCI to local bus access, used by PCI device to target * local RAM while bus mastering */ bcm63xx_int_cfg_writel(0, PCI_BASE_ADDRESS_3); - if (BCMCPU_IS_6358()) + if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) val = MPI_SP0_REMAP_ENABLE_MASK; else val = 0; diff --git a/arch/mips/pci/pci-octeon.c b/arch/mips/pci/pci-octeon.c index ed1c542..52a1ba7 100644 --- a/arch/mips/pci/pci-octeon.c +++ b/arch/mips/pci/pci-octeon.c @@ -99,7 +99,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev) */ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 / 4); /* Set latency timers for all devices */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 48); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); /* Enable reporting System errors and parity errors on all devices */ /* Enable parity checking and error reporting */ @@ -109,7 +109,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev) if (dev->subordinate) { /* Set latency timers on sub bridges */ - pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 48); + pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 64); /* More bridge error detection */ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config); config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR; @@ -121,14 +121,10 @@ int pcibios_plat_dev_init(struct pci_dev *dev) if (pos) { /* Update Device Control */ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config); - /* Correctable Error Reporting */ - config |= PCI_EXP_DEVCTL_CERE; - /* Non-Fatal Error Reporting */ - config |= PCI_EXP_DEVCTL_NFERE; - /* Fatal Error Reporting */ - config |= PCI_EXP_DEVCTL_FERE; - /* Unsupported Request */ - config |= PCI_EXP_DEVCTL_URRE; + config |= PCI_EXP_DEVCTL_CERE; /* Correctable Error Reporting */ + config |= PCI_EXP_DEVCTL_NFERE; /* Non-Fatal Error Reporting */ + config |= PCI_EXP_DEVCTL_FERE; /* Fatal Error Reporting */ + config |= PCI_EXP_DEVCTL_URRE; /* Unsupported Request */ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config); } diff --git a/arch/mips/pci/pci-tx4927.c b/arch/mips/pci/pci-tx4927.c index a580740..a032ae0 100644 --- a/arch/mips/pci/pci-tx4927.c +++ b/arch/mips/pci/pci-tx4927.c @@ -85,7 +85,7 @@ void __init tx4927_setup_pcierr_irq(void) { if (request_irq(TXX9_IRQ_BASE + TX4927_IR_PCIERR, tx4927_pcierr_interrupt, - IRQF_DISABLED, "PCI error", + 0, "PCI error", (void *)TX4927_PCIC_REG)) printk(KERN_WARNING "Failed to request irq for PCIERR\n"); } diff --git a/arch/mips/pci/pci-tx4938.c b/arch/mips/pci/pci-tx4938.c index 20e45f3..141bba5 100644 --- a/arch/mips/pci/pci-tx4938.c +++ b/arch/mips/pci/pci-tx4938.c @@ -136,7 +136,7 @@ void __init tx4938_setup_pcierr_irq(void) { if (request_irq(TXX9_IRQ_BASE + TX4938_IR_PCIERR, tx4927_pcierr_interrupt, - IRQF_DISABLED, "PCI error", + 0, "PCI error", (void *)TX4927_PCIC_REG)) printk(KERN_WARNING "Failed to request irq for PCIERR\n"); } diff --git a/arch/mips/pci/pci-tx4939.c b/arch/mips/pci/pci-tx4939.c index 9ef8406..c10fbf2 100644 --- a/arch/mips/pci/pci-tx4939.c +++ b/arch/mips/pci/pci-tx4939.c @@ -101,7 +101,7 @@ void __init tx4939_setup_pcierr_irq(void) { if (request_irq(TXX9_IRQ_BASE + TX4939_IR_PCIERR, tx4927_pcierr_interrupt, - IRQF_DISABLED, "PCI error", + 0, "PCI error", (void *)TX4939_PCIC_REG)) pr_warning("Failed to request irq for PCIERR\n"); } diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c index 38fece1..3d701a9 100644 --- a/arch/mips/pci/pci-xlr.c +++ b/arch/mips/pci/pci-xlr.c @@ -36,12 +36,18 @@ #include <linux/pci.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/msi.h> #include <linux/mm.h> +#include <linux/irq.h> +#include <linux/irqdesc.h> #include <linux/console.h> #include <asm/io.h> #include <asm/netlogic/interrupt.h> +#include <asm/netlogic/haldefs.h> + +#include <asm/netlogic/xlr/msidef.h> #include <asm/netlogic/xlr/iomap.h> #include <asm/netlogic/xlr/pic.h> #include <asm/netlogic/xlr/xlr.h> @@ -150,7 +156,7 @@ struct pci_controller nlm_pci_controller = { .io_offset = 0x00000000UL, }; -int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +static int get_irq_vector(const struct pci_dev *dev) { if (!nlm_chip_is_xls()) return PIC_PCIX_IRQ; /* for XLR just one IRQ*/ @@ -182,6 +188,101 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) return 0; } +#ifdef CONFIG_PCI_MSI +void destroy_irq(unsigned int irq) +{ + /* nothing to do yet */ +} + +void arch_teardown_msi_irq(unsigned int irq) +{ + destroy_irq(irq); +} + +int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) +{ + struct msi_msg msg; + int irq, ret; + + irq = get_irq_vector(dev); + if (irq <= 0) + return 1; + + msg.address_hi = MSI_ADDR_BASE_HI; + msg.address_lo = MSI_ADDR_BASE_LO | + MSI_ADDR_DEST_MODE_PHYSICAL | + MSI_ADDR_REDIRECTION_CPU; + + msg.data = MSI_DATA_TRIGGER_EDGE | + MSI_DATA_LEVEL_ASSERT | + MSI_DATA_DELIVERY_FIXED; + + ret = irq_set_msi_desc(irq, desc); + if (ret < 0) { + destroy_irq(irq); + return ret; + } + + write_msi_msg(irq, &msg); + return 0; +} +#endif + +/* Extra ACK needed for XLR on chip PCI controller */ +static void xlr_pci_ack(struct irq_data *d) +{ + uint64_t pcibase = nlm_mmio_base(NETLOGIC_IO_PCIX_OFFSET); + + nlm_read_reg(pcibase, (0x140 >> 2)); +} + +/* Extra ACK needed for XLS on chip PCIe controller */ +static void xls_pcie_ack(struct irq_data *d) +{ + uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET); + + switch (d->irq) { + case PIC_PCIE_LINK0_IRQ: + nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK1_IRQ: + nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK2_IRQ: + nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK3_IRQ: + nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff); + break; + } +} + +/* For XLS B silicon, the 3,4 PCI interrupts are different */ +static void xls_pcie_ack_b(struct irq_data *d) +{ + uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET); + + switch (d->irq) { + case PIC_PCIE_LINK0_IRQ: + nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK1_IRQ: + nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff); + break; + case PIC_PCIE_XLSB0_LINK2_IRQ: + nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff); + break; + case PIC_PCIE_XLSB0_LINK3_IRQ: + nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff); + break; + } +} + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + return get_irq_vector(dev); +} + /* Do platform specific device initialization at pci_enable_device() time */ int pcibios_plat_dev_init(struct pci_dev *dev) { @@ -204,6 +305,31 @@ static int __init pcibios_init(void) pr_info("Registering XLR/XLS PCIX/PCIE Controller.\n"); register_pci_controller(&nlm_pci_controller); + /* + * For PCI interrupts, we need to ack the PCI controller too, overload + * irq handler data to do this + */ + if (nlm_chip_is_xls()) { + if (nlm_chip_is_xls_b()) { + irq_set_handler_data(PIC_PCIE_LINK0_IRQ, + xls_pcie_ack_b); + irq_set_handler_data(PIC_PCIE_LINK1_IRQ, + xls_pcie_ack_b); + irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ, + xls_pcie_ack_b); + irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, + xls_pcie_ack_b); + } else { + irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack); + irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack); + irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack); + irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack); + } + } else { + /* XLR PCI controller ACK */ + irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack); + } + return 0; } diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index fa8e378..aec2b11 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -4,8 +4,11 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * - * Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2003, 04, 11 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2011 Wind River Systems, + * written by Ralf Baechle (ralf@linux-mips.org) */ +#include <linux/bug.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/bootmem.h> @@ -14,6 +17,8 @@ #include <linux/types.h> #include <linux/pci.h> +#include <asm/cpu-info.h> + /* * Indicate whether we respect the PCI setup left by the firmware. * @@ -157,10 +162,32 @@ out: "Skipping PCI bus scan due to resource conflict\n"); } +static void __init pcibios_set_cache_line_size(void) +{ + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int lsize; + + /* + * Set PCI cacheline size to that of the highest level in the + * cache hierarchy. + */ + lsize = c->dcache.linesz; + lsize = c->scache.linesz ? : lsize; + lsize = c->tcache.linesz ? : lsize; + + BUG_ON(!lsize); + + pci_dfl_cache_line_size = lsize >> 2; + + pr_debug("PCI: pci_cache_line_size set to %d bytes\n", lsize); +} + static int __init pcibios_init(void) { struct pci_controller *hose; + pcibios_set_cache_line_size(); + /* Scan all of the recorded PCI controllers. */ for (hose = hose_head; hose; hose = hose->next) pcibios_scanbus(hose); diff --git a/arch/mips/pci/pcie-octeon.c b/arch/mips/pci/pcie-octeon.c index 0583c463..fdb4d55 100644 --- a/arch/mips/pci/pcie-octeon.c +++ b/arch/mips/pci/pcie-octeon.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2007, 2008 Cavium Networks + * Copyright (C) 2007, 2008, 2009, 2010, 2011 Cavium Networks */ #include <linux/kernel.h> #include <linux/init.h> @@ -11,15 +11,32 @@ #include <linux/interrupt.h> #include <linux/time.h> #include <linux/delay.h> +#include <linux/module.h> #include <asm/octeon/octeon.h> #include <asm/octeon/cvmx-npei-defs.h> #include <asm/octeon/cvmx-pciercx-defs.h> #include <asm/octeon/cvmx-pescx-defs.h> #include <asm/octeon/cvmx-pexp-defs.h> +#include <asm/octeon/cvmx-pemx-defs.h> +#include <asm/octeon/cvmx-dpi-defs.h> +#include <asm/octeon/cvmx-sli-defs.h> +#include <asm/octeon/cvmx-sriox-defs.h> #include <asm/octeon/cvmx-helper-errata.h> #include <asm/octeon/pci-octeon.h> +#define MRRS_CN5XXX 0 /* 128 byte Max Read Request Size */ +#define MPS_CN5XXX 0 /* 128 byte Max Packet Size (Limit of most PCs) */ +#define MRRS_CN6XXX 3 /* 1024 byte Max Read Request Size */ +#define MPS_CN6XXX 0 /* 128 byte Max Packet Size (Limit of most PCs) */ + +/* Module parameter to disable PCI probing */ +static int pcie_disable; +module_param(pcie_disable, int, S_IRUGO); + +static int enable_pcie_14459_war; +static int enable_pcie_bus_num_war[2]; + union cvmx_pcie_address { uint64_t u64; struct { @@ -75,6 +92,8 @@ union cvmx_pcie_address { } mem; }; +static int cvmx_pcie_rc_initialize(int pcie_port); + #include <dma-coherence.h> /** @@ -154,12 +173,21 @@ static inline uint64_t cvmx_pcie_get_mem_size(int pcie_port) */ static uint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset) { - union cvmx_pescx_cfg_rd pescx_cfg_rd; - pescx_cfg_rd.u64 = 0; - pescx_cfg_rd.s.addr = cfg_offset; - cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64); - pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port)); - return pescx_cfg_rd.s.data; + if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { + union cvmx_pescx_cfg_rd pescx_cfg_rd; + pescx_cfg_rd.u64 = 0; + pescx_cfg_rd.s.addr = cfg_offset; + cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64); + pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port)); + return pescx_cfg_rd.s.data; + } else { + union cvmx_pemx_cfg_rd pemx_cfg_rd; + pemx_cfg_rd.u64 = 0; + pemx_cfg_rd.s.addr = cfg_offset; + cvmx_write_csr(CVMX_PEMX_CFG_RD(pcie_port), pemx_cfg_rd.u64); + pemx_cfg_rd.u64 = cvmx_read_csr(CVMX_PEMX_CFG_RD(pcie_port)); + return pemx_cfg_rd.s.data; + } } /** @@ -173,11 +201,19 @@ static uint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset) static void cvmx_pcie_cfgx_write(int pcie_port, uint32_t cfg_offset, uint32_t val) { - union cvmx_pescx_cfg_wr pescx_cfg_wr; - pescx_cfg_wr.u64 = 0; - pescx_cfg_wr.s.addr = cfg_offset; - pescx_cfg_wr.s.data = val; - cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64); + if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { + union cvmx_pescx_cfg_wr pescx_cfg_wr; + pescx_cfg_wr.u64 = 0; + pescx_cfg_wr.s.addr = cfg_offset; + pescx_cfg_wr.s.data = val; + cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64); + } else { + union cvmx_pemx_cfg_wr pemx_cfg_wr; + pemx_cfg_wr.u64 = 0; + pemx_cfg_wr.s.addr = cfg_offset; + pemx_cfg_wr.s.data = val; + cvmx_write_csr(CVMX_PEMX_CFG_WR(pcie_port), pemx_cfg_wr.u64); + } } /** @@ -348,7 +384,6 @@ static void cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int fn, static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) { union cvmx_pciercx_cfg030 pciercx_cfg030; - union cvmx_npei_ctl_status2 npei_ctl_status2; union cvmx_pciercx_cfg070 pciercx_cfg070; union cvmx_pciercx_cfg001 pciercx_cfg001; union cvmx_pciercx_cfg032 pciercx_cfg032; @@ -365,21 +400,21 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) /* Max Read Request Size (PCIE*_CFG030[MRRS]) */ /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */ /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */ - pciercx_cfg030.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port)); - /* - * Max payload size = 128 bytes for best Octeon DMA - * performance. - */ - pciercx_cfg030.s.mps = 0; + + pciercx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port)); + if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) { + pciercx_cfg030.s.mps = MPS_CN5XXX; + pciercx_cfg030.s.mrrs = MRRS_CN5XXX; + } else { + pciercx_cfg030.s.mps = MPS_CN6XXX; + pciercx_cfg030.s.mrrs = MRRS_CN6XXX; + } /* - * Max read request size = 128 bytes for best Octeon DMA - * performance. + * Enable relaxed order processing. This will allow devices to + * affect read response ordering. */ - pciercx_cfg030.s.mrrs = 0; - /* Enable relaxed ordering. */ pciercx_cfg030.s.ro_en = 1; - /* Enable no snoop. */ + /* Enable no snoop processing. Not used by Octeon */ pciercx_cfg030.s.ns_en = 1; /* Correctable error reporting enable. */ pciercx_cfg030.s.ce_en = 1; @@ -389,50 +424,67 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) pciercx_cfg030.s.fe_en = 1; /* Unsupported request reporting enable. */ pciercx_cfg030.s.ur_en = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), - pciercx_cfg030.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), pciercx_cfg030.u32); - /* - * Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match - * PCIE*_CFG030[MPS] - * - * Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not - * exceed PCIE*_CFG030[MRRS]. - */ - npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2); - /* Max payload size = 128 bytes for best Octeon DMA performance */ - npei_ctl_status2.s.mps = 0; - /* Max read request size = 128 bytes for best Octeon DMA performance */ - npei_ctl_status2.s.mrrs = 0; - if (pcie_port) - npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */ - else - npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */ - cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); + + if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { + union cvmx_npei_ctl_status2 npei_ctl_status2; + /* + * Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match + * PCIE*_CFG030[MPS]. Max Read Request Size + * (NPEI_CTL_STATUS2[MRRS]) must not exceed + * PCIE*_CFG030[MRRS] + */ + npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2); + /* Max payload size = 128 bytes for best Octeon DMA performance */ + npei_ctl_status2.s.mps = MPS_CN5XXX; + /* Max read request size = 128 bytes for best Octeon DMA performance */ + npei_ctl_status2.s.mrrs = MRRS_CN5XXX; + if (pcie_port) + npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */ + else + npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */ + + cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); + } else { + /* + * Max Payload Size (DPI_SLI_PRTX_CFG[MPS]) must match + * PCIE*_CFG030[MPS]. Max Read Request Size + * (DPI_SLI_PRTX_CFG[MRRS]) must not exceed + * PCIE*_CFG030[MRRS]. + */ + union cvmx_dpi_sli_prtx_cfg prt_cfg; + union cvmx_sli_s2m_portx_ctl sli_s2m_portx_ctl; + prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port)); + prt_cfg.s.mps = MPS_CN6XXX; + prt_cfg.s.mrrs = MRRS_CN6XXX; + /* Max outstanding load request. */ + prt_cfg.s.molr = 32; + cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64); + + sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port)); + sli_s2m_portx_ctl.s.mrrs = MRRS_CN6XXX; + cvmx_write_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port), sli_s2m_portx_ctl.u64); + } /* ECRC Generation (PCIE*_CFG070[GE,CE]) */ - pciercx_cfg070.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port)); + pciercx_cfg070.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port)); pciercx_cfg070.s.ge = 1; /* ECRC generation enable. */ pciercx_cfg070.s.ce = 1; /* ECRC check enable. */ - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), - pciercx_cfg070.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), pciercx_cfg070.u32); /* - * Access Enables (PCIE*_CFG001[MSAE,ME]) ME and MSAE should - * always be set. - * - * Interrupt Disable (PCIE*_CFG001[I_DIS]) System Error - * Message Enable (PCIE*_CFG001[SEE]) + * Access Enables (PCIE*_CFG001[MSAE,ME]) + * ME and MSAE should always be set. + * Interrupt Disable (PCIE*_CFG001[I_DIS]) + * System Error Message Enable (PCIE*_CFG001[SEE]) */ - pciercx_cfg001.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port)); + pciercx_cfg001.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port)); pciercx_cfg001.s.msae = 1; /* Memory space enable. */ pciercx_cfg001.s.me = 1; /* Bus master enable. */ pciercx_cfg001.s.i_dis = 1; /* INTx assertion disable. */ pciercx_cfg001.s.see = 1; /* SERR# enable */ - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), - pciercx_cfg001.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), pciercx_cfg001.u32); /* Advanced Error Recovery Message Enables */ /* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */ @@ -440,14 +492,11 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) /* Use CVMX_PCIERCX_CFG067 hardware default */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG069(pcie_port), 0); - /* Active State Power Management (PCIE*_CFG032[ASLPC]) */ - pciercx_cfg032.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); - pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */ - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), - pciercx_cfg032.u32); - /* Entrance Latencies (PCIE*_CFG451[L0EL,L1EL]) */ + /* Active State Power Management (PCIE*_CFG032[ASLPC]) */ + pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); + pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */ + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), pciercx_cfg032.u32); /* * Link Width Mode (PCIERCn_CFG452[LME]) - Set during @@ -462,8 +511,8 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) pciercx_cfg006.s.pbnum = 1; pciercx_cfg006.s.sbnum = 1; pciercx_cfg006.s.subbnum = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), - pciercx_cfg006.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), pciercx_cfg006.u32); + /* * Memory-mapped I/O BAR (PCIERCn_CFG008) @@ -473,8 +522,8 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) pciercx_cfg008.u32 = 0; pciercx_cfg008.s.mb_addr = 0x100; pciercx_cfg008.s.ml_addr = 0; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), - pciercx_cfg008.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), pciercx_cfg008.u32); + /* * Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011) @@ -482,72 +531,51 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) * PCIERCn_CFG011[UMEM_LIMIT],PCIERCn_CFG009[LMEM_LIMIT] < * PCIERCn_CFG010[UMEM_BASE],PCIERCn_CFG009[LMEM_BASE] */ - pciercx_cfg009.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port)); - pciercx_cfg010.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port)); - pciercx_cfg011.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port)); + pciercx_cfg009.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port)); + pciercx_cfg010.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port)); + pciercx_cfg011.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port)); pciercx_cfg009.s.lmem_base = 0x100; pciercx_cfg009.s.lmem_limit = 0; pciercx_cfg010.s.umem_base = 0x100; pciercx_cfg011.s.umem_limit = 0; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), - pciercx_cfg009.u32); - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), - pciercx_cfg010.u32); - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), - pciercx_cfg011.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), pciercx_cfg009.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), pciercx_cfg010.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), pciercx_cfg011.u32); /* * System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE]) * PME Interrupt Enables (PCIERCn_CFG035[PMEIE]) - */ - pciercx_cfg035.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port)); - /* System error on correctable error enable. */ - pciercx_cfg035.s.secee = 1; - /* System error on fatal error enable. */ - pciercx_cfg035.s.sefee = 1; - /* System error on non-fatal error enable. */ - pciercx_cfg035.s.senfee = 1; - /* PME interrupt enable. */ - pciercx_cfg035.s.pmeie = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), - pciercx_cfg035.u32); + */ + pciercx_cfg035.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port)); + pciercx_cfg035.s.secee = 1; /* System error on correctable error enable. */ + pciercx_cfg035.s.sefee = 1; /* System error on fatal error enable. */ + pciercx_cfg035.s.senfee = 1; /* System error on non-fatal error enable. */ + pciercx_cfg035.s.pmeie = 1; /* PME interrupt enable. */ + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), pciercx_cfg035.u32); /* * Advanced Error Recovery Interrupt Enables * (PCIERCn_CFG075[CERE,NFERE,FERE]) */ - pciercx_cfg075.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port)); - /* Correctable error reporting enable. */ - pciercx_cfg075.s.cere = 1; - /* Non-fatal error reporting enable. */ - pciercx_cfg075.s.nfere = 1; - /* Fatal error reporting enable. */ - pciercx_cfg075.s.fere = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), - pciercx_cfg075.u32); + pciercx_cfg075.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port)); + pciercx_cfg075.s.cere = 1; /* Correctable error reporting enable. */ + pciercx_cfg075.s.nfere = 1; /* Non-fatal error reporting enable. */ + pciercx_cfg075.s.fere = 1; /* Fatal error reporting enable. */ + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), pciercx_cfg075.u32); - /* HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN], + /* + * HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN], * PCIERCn_CFG034[DLLS_EN,CCINT_EN]) */ - pciercx_cfg034.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port)); - /* Hot-plug interrupt enable. */ - pciercx_cfg034.s.hpint_en = 1; - /* Data Link Layer state changed enable */ - pciercx_cfg034.s.dlls_en = 1; - /* Command completed interrupt enable. */ - pciercx_cfg034.s.ccint_en = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), - pciercx_cfg034.u32); + pciercx_cfg034.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port)); + pciercx_cfg034.s.hpint_en = 1; /* Hot-plug interrupt enable. */ + pciercx_cfg034.s.dlls_en = 1; /* Data Link Layer state changed enable */ + pciercx_cfg034.s.ccint_en = 1; /* Command completed interrupt enable. */ + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), pciercx_cfg034.u32); } /** - * Initialize a host mode PCIe link. This function takes a PCIe + * Initialize a host mode PCIe gen 1 link. This function takes a PCIe * port from reset to a link up state. Software can then begin * configuring the rest of the link. * @@ -555,7 +583,7 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) * * Returns Zero on success */ -static int __cvmx_pcie_rc_initialize_link(int pcie_port) +static int __cvmx_pcie_rc_initialize_link_gen1(int pcie_port) { uint64_t start_cycle; union cvmx_pescx_ctl_status pescx_ctl_status; @@ -564,18 +592,15 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port) union cvmx_pciercx_cfg448 pciercx_cfg448; /* Set the lane width */ - pciercx_cfg452.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port)); + pciercx_cfg452.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port)); pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); - if (pescx_ctl_status.s.qlm_cfg == 0) { + if (pescx_ctl_status.s.qlm_cfg == 0) /* We're in 8 lane (56XX) or 4 lane (54XX) mode */ pciercx_cfg452.s.lme = 0xf; - } else { + else /* We're in 4 lane (56XX) or 2 lane (52XX) mode */ pciercx_cfg452.s.lme = 0x7; - } - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), - pciercx_cfg452.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), pciercx_cfg452.u32); /* * CN52XX pass 1.x has an errata where length mismatches on UR @@ -584,19 +609,15 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port) */ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { union cvmx_pciercx_cfg455 pciercx_cfg455; - pciercx_cfg455.u32 = - cvmx_pcie_cfgx_read(pcie_port, - CVMX_PCIERCX_CFG455(pcie_port)); + pciercx_cfg455.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG455(pcie_port)); pciercx_cfg455.s.m_cpl_len_err = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), - pciercx_cfg455.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), pciercx_cfg455.u32); } /* Lane swap needs to be manually enabled for CN52XX */ if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1)) { pescx_ctl_status.s.lane_swp = 1; - cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), - pescx_ctl_status.u64); + cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64); } /* Bring up the link */ @@ -612,24 +633,18 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port) __cvmx_helper_errata_qlm_disable_2nd_order_cdr(0); /* Wait for the link to come up */ - cvmx_dprintf("PCIe: Waiting for port %d link\n", pcie_port); start_cycle = cvmx_get_cycle(); do { - if (cvmx_get_cycle() - start_cycle > - 2 * cvmx_sysinfo_get()->cpu_clock_hz) { - cvmx_dprintf("PCIe: Port %d link timeout\n", - pcie_port); + if (cvmx_get_cycle() - start_cycle > 2 * octeon_get_clock_rate()) { + cvmx_dprintf("PCIe: Port %d link timeout\n", pcie_port); return -1; } cvmx_wait(10000); - pciercx_cfg032.u32 = - cvmx_pcie_cfgx_read(pcie_port, - CVMX_PCIERCX_CFG032(pcie_port)); + pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); } while (pciercx_cfg032.s.dlla == 0); - /* Display the link status */ - cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, - pciercx_cfg032.s.nlw); + /* Clear all pending errors */ + cvmx_write_csr(CVMX_PEXP_NPEI_INT_SUM, cvmx_read_csr(CVMX_PEXP_NPEI_INT_SUM)); /* * Update the Replay Time Limit. Empirically, some PCIe @@ -639,8 +654,7 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port) * our actual 256 byte MPS. The numbers below are directly * from the PCIe spec table 3-4. */ - pciercx_cfg448.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); + pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); switch (pciercx_cfg032.s.nlw) { case 1: /* 1 lane */ pciercx_cfg448.s.rtl = 1677; @@ -655,21 +669,28 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port) pciercx_cfg448.s.rtl = 258; break; } - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), - pciercx_cfg448.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32); return 0; } +static void __cvmx_increment_ba(union cvmx_sli_mem_access_subidx *pmas) +{ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + pmas->cn68xx.ba++; + else + pmas->cn63xx.ba++; +} + /** - * Initialize a PCIe port for use in host(RC) mode. It doesn't + * Initialize a PCIe gen 1 port for use in host(RC) mode. It doesn't * enumerate the bus. * * @pcie_port: PCIe port to initialize * * Returns Zero on success */ -static int cvmx_pcie_rc_initialize(int pcie_port) +static int __cvmx_pcie_rc_initialize_gen1(int pcie_port) { int i; int base; @@ -682,16 +703,17 @@ static int cvmx_pcie_rc_initialize(int pcie_port) union cvmx_npei_mem_access_subidx mem_access_subid; union cvmx_npei_dbg_data npei_dbg_data; union cvmx_pescx_ctl_status2 pescx_ctl_status2; + union cvmx_pciercx_cfg032 pciercx_cfg032; union cvmx_npei_bar1_indexx bar1_index; +retry: /* * Make sure we aren't trying to setup a target mode interface * in host mode. */ npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); if ((pcie_port == 0) && !npei_ctl_status.s.host_mode) { - cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called " - "on port0, but port0 is not in host mode\n"); + cvmx_dprintf("PCIe: Port %d in endpoint mode\n", pcie_port); return -1; } @@ -702,9 +724,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port) if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); if ((pcie_port == 1) && npei_dbg_data.cn52xx.qlm0_link_width) { - cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() " - "called on port1, but port1 is " - "disabled\n"); + cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called on port1, but port1 is disabled\n"); return -1; } } @@ -733,7 +753,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port) * the board. As a workaround for this bug, we bring * both PCIe ports out of reset at the same time * instead of on separate calls. So for port 0, we - * bring both out of reset and do nothing on port 1. + * bring both out of reset and do nothing on port 1 */ if (pcie_port == 0) { ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); @@ -746,13 +766,10 @@ static int cvmx_pcie_rc_initialize(int pcie_port) if (ciu_soft_prst.s.soft_prst == 0) { /* Reset the ports */ ciu_soft_prst.s.soft_prst = 1; - cvmx_write_csr(CVMX_CIU_SOFT_PRST, - ciu_soft_prst.u64); - ciu_soft_prst.u64 = - cvmx_read_csr(CVMX_CIU_SOFT_PRST1); + cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); + ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); ciu_soft_prst.s.soft_prst = 1; - cvmx_write_csr(CVMX_CIU_SOFT_PRST1, - ciu_soft_prst.u64); + cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); /* Wait until pcie resets the ports. */ udelay(2000); } @@ -782,11 +799,9 @@ static int cvmx_pcie_rc_initialize(int pcie_port) /* Reset the port */ ciu_soft_prst.s.soft_prst = 1; if (pcie_port) - cvmx_write_csr(CVMX_CIU_SOFT_PRST1, - ciu_soft_prst.u64); + cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); else - cvmx_write_csr(CVMX_CIU_SOFT_PRST, - ciu_soft_prst.u64); + cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); /* Wait until pcie resets the ports. */ udelay(2000); } @@ -808,25 +823,21 @@ static int cvmx_pcie_rc_initialize(int pcie_port) */ cvmx_wait(400000); - /* PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of CN56XX and - CN52XX, so we only probe it on newer chips */ - if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) - && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { + /* + * PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of + * CN56XX and CN52XX, so we only probe it on newer chips + */ + if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { /* Clear PCLK_RUN so we can check if the clock is running */ - pescx_ctl_status2.u64 = - cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); + pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); pescx_ctl_status2.s.pclk_run = 1; - cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port), - pescx_ctl_status2.u64); - /* - * Now that we cleared PCLK_RUN, wait for it to be set - * again telling us the clock is running. + cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port), pescx_ctl_status2.u64); + /* Now that we cleared PCLK_RUN, wait for it to be set + * again telling us the clock is running */ if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CTL_STATUS2(pcie_port), - union cvmx_pescx_ctl_status2, - pclk_run, ==, 1, 10000)) { - cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n", - pcie_port); + union cvmx_pescx_ctl_status2, pclk_run, ==, 1, 10000)) { + cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n", pcie_port); return -1; } } @@ -836,30 +847,26 @@ static int cvmx_pcie_rc_initialize(int pcie_port) * the board probably hasn't wired the clocks up and the * interface should be skipped. */ - pescx_ctl_status2.u64 = - cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); + pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); if (pescx_ctl_status2.s.pcierst) { - cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", - pcie_port); + cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", pcie_port); return -1; } /* - * Check BIST2 status. If any bits are set skip this interface. This - * is an attempt to catch PCIE-813 on pass 1 parts. + * Check BIST2 status. If any bits are set skip this + * interface. This is an attempt to catch PCIE-813 on pass 1 + * parts. */ - pescx_bist_status2.u64 = - cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port)); + pescx_bist_status2.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port)); if (pescx_bist_status2.u64) { - cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this " - "port isn't hooked up, skipping.\n", + cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this port isn't hooked up, skipping.\n", pcie_port); return -1; } /* Check BIST status */ - pescx_bist_status.u64 = - cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port)); + pescx_bist_status.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port)); if (pescx_bist_status.u64) cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pescx_bist_status.u64)); @@ -868,50 +875,37 @@ static int cvmx_pcie_rc_initialize(int pcie_port) __cvmx_pcie_rc_initialize_config_space(pcie_port); /* Bring the link up */ - if (__cvmx_pcie_rc_initialize_link(pcie_port)) { - cvmx_dprintf - ("PCIe: ERROR: cvmx_pcie_rc_initialize_link() failed\n"); + if (__cvmx_pcie_rc_initialize_link_gen1(pcie_port)) { + cvmx_dprintf("PCIe: Failed to initialize port %d, probably the slot is empty\n", + pcie_port); return -1; } /* Store merge control (NPEI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */ npei_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL); - /* Allow 16 words to combine */ - npei_mem_access_ctl.s.max_word = 0; - /* Wait up to 127 cycles for more data */ - npei_mem_access_ctl.s.timer = 127; + npei_mem_access_ctl.s.max_word = 0; /* Allow 16 words to combine */ + npei_mem_access_ctl.s.timer = 127; /* Wait up to 127 cycles for more data */ cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL, npei_mem_access_ctl.u64); /* Setup Mem access SubDIDs */ mem_access_subid.u64 = 0; - /* Port the request is sent to. */ - mem_access_subid.s.port = pcie_port; - /* Due to an errata on pass 1 chips, no merging is allowed. */ - mem_access_subid.s.nmerge = 1; - /* Endian-swap for Reads. */ - mem_access_subid.s.esr = 1; - /* Endian-swap for Writes. */ - mem_access_subid.s.esw = 1; - /* No Snoop for Reads. */ - mem_access_subid.s.nsr = 1; - /* No Snoop for Writes. */ - mem_access_subid.s.nsw = 1; - /* Disable Relaxed Ordering for Reads. */ - mem_access_subid.s.ror = 0; - /* Disable Relaxed Ordering for Writes. */ - mem_access_subid.s.row = 0; - /* PCIe Address Bits <63:34>. */ - mem_access_subid.s.ba = 0; + mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */ + mem_access_subid.s.nmerge = 1; /* Due to an errata on pass 1 chips, no merging is allowed. */ + mem_access_subid.s.esr = 1; /* Endian-swap for Reads. */ + mem_access_subid.s.esw = 1; /* Endian-swap for Writes. */ + mem_access_subid.s.nsr = 0; /* Enable Snooping for Reads. Octeon doesn't care, but devices might want this more conservative setting */ + mem_access_subid.s.nsw = 0; /* Enable Snoop for Writes. */ + mem_access_subid.s.ror = 0; /* Disable Relaxed Ordering for Reads. */ + mem_access_subid.s.row = 0; /* Disable Relaxed Ordering for Writes. */ + mem_access_subid.s.ba = 0; /* PCIe Adddress Bits <63:34>. */ /* * Setup mem access 12-15 for port 0, 16-19 for port 1, * supplying 36 bits of address space. */ for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) { - cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i), - mem_access_subid.u64); - /* Set each SUBID to extend the addressable range */ - mem_access_subid.s.ba += 1; + cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64); + mem_access_subid.s.ba += 1; /* Set each SUBID to extend the addressable range */ } /* @@ -927,7 +921,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port) /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */ cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0); - /* BAR1 follows BAR2 with a gap. */ + /* BAR1 follows BAR2 with a gap so it has the same address as for gen2. */ cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE); bar1_index.u32 = 0; @@ -992,14 +986,474 @@ static int cvmx_pcie_rc_initialize(int pcie_port) npei_ctl_port.s.waitl_com = 0; cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT0, npei_ctl_port.u64); } + + /* + * Both pass 1 and pass 2 of CN52XX and CN56XX have an errata + * that causes TLP ordering to not be preserved after multiple + * PCIe port resets. This code detects this fault and corrects + * it by aligning the TLP counters properly. Another link + * reset is then performed. See PCIE-13340 + */ + if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS2_X) || + OCTEON_IS_MODEL(OCTEON_CN52XX_PASS2_X) || + OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { + union cvmx_npei_dbg_data dbg_data; + int old_in_fif_p_count; + int in_fif_p_count; + int out_p_count; + int in_p_offset = (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) ? 4 : 1; + int i; + + /* + * Choose a write address of 1MB. It should be + * harmless as all bars haven't been setup. + */ + uint64_t write_address = (cvmx_pcie_get_mem_base_address(pcie_port) + 0x100000) | (1ull<<63); + + /* + * Make sure at least in_p_offset have been executed before we try and + * read in_fif_p_count + */ + i = in_p_offset; + while (i--) { + cvmx_write64_uint32(write_address, 0); + cvmx_wait(10000); + } + + /* + * Read the IN_FIF_P_COUNT from the debug + * select. IN_FIF_P_COUNT can be unstable sometimes so + * read it twice with a write between the reads. This + * way we can tell the value is good as it will + * increment by one due to the write + */ + cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd7fc : 0xcffc); + cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT); + do { + dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); + old_in_fif_p_count = dbg_data.s.data & 0xff; + cvmx_write64_uint32(write_address, 0); + cvmx_wait(10000); + dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); + in_fif_p_count = dbg_data.s.data & 0xff; + } while (in_fif_p_count != ((old_in_fif_p_count+1) & 0xff)); + + /* Update in_fif_p_count for it's offset with respect to out_p_count */ + in_fif_p_count = (in_fif_p_count + in_p_offset) & 0xff; + + /* Read the OUT_P_COUNT from the debug select */ + cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd00f : 0xc80f); + cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT); + dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); + out_p_count = (dbg_data.s.data>>1) & 0xff; + + /* Check that the two counters are aligned */ + if (out_p_count != in_fif_p_count) { + cvmx_dprintf("PCIe: Port %d aligning TLP counters as workaround to maintain ordering\n", pcie_port); + while (in_fif_p_count != 0) { + cvmx_write64_uint32(write_address, 0); + cvmx_wait(10000); + in_fif_p_count = (in_fif_p_count + 1) & 0xff; + } + /* + * The EBH5200 board swapped the PCIe reset + * lines on the board. This means we must + * bring both links down and up, which will + * cause the PCIe0 to need alignment + * again. Lots of messages will be displayed, + * but everything should work + */ + if ((cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200) && + (pcie_port == 1)) + cvmx_pcie_rc_initialize(0); + /* Rety bringing this port up */ + goto retry; + } + } + + /* Display the link status */ + pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); + cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, pciercx_cfg032.s.nlw); + return 0; } +/** + * Initialize a host mode PCIe gen 2 link. This function takes a PCIe + * port from reset to a link up state. Software can then begin + * configuring the rest of the link. + * + * @pcie_port: PCIe port to initialize + * + * Return Zero on success. + */ +static int __cvmx_pcie_rc_initialize_link_gen2(int pcie_port) +{ + uint64_t start_cycle; + union cvmx_pemx_ctl_status pem_ctl_status; + union cvmx_pciercx_cfg032 pciercx_cfg032; + union cvmx_pciercx_cfg448 pciercx_cfg448; -/* Above was cvmx-pcie.c, below original pcie.c */ + /* Bring up the link */ + pem_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port)); + pem_ctl_status.s.lnk_enb = 1; + cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pem_ctl_status.u64); + + /* Wait for the link to come up */ + start_cycle = cvmx_get_cycle(); + do { + if (cvmx_get_cycle() - start_cycle > octeon_get_clock_rate()) + return -1; + cvmx_wait(10000); + pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); + } while ((pciercx_cfg032.s.dlla == 0) || (pciercx_cfg032.s.lt == 1)); + + /* + * Update the Replay Time Limit. Empirically, some PCIe + * devices take a little longer to respond than expected under + * load. As a workaround for this we configure the Replay Time + * Limit to the value expected for a 512 byte MPS instead of + * our actual 256 byte MPS. The numbers below are directly + * from the PCIe spec table 3-4 + */ + pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); + switch (pciercx_cfg032.s.nlw) { + case 1: /* 1 lane */ + pciercx_cfg448.s.rtl = 1677; + break; + case 2: /* 2 lanes */ + pciercx_cfg448.s.rtl = 867; + break; + case 4: /* 4 lanes */ + pciercx_cfg448.s.rtl = 462; + break; + case 8: /* 8 lanes */ + pciercx_cfg448.s.rtl = 258; + break; + } + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32); + + return 0; +} /** + * Initialize a PCIe gen 2 port for use in host(RC) mode. It doesn't enumerate + * the bus. + * + * @pcie_port: PCIe port to initialize + * + * Returns Zero on success. + */ +static int __cvmx_pcie_rc_initialize_gen2(int pcie_port) +{ + int i; + union cvmx_ciu_soft_prst ciu_soft_prst; + union cvmx_mio_rst_ctlx mio_rst_ctl; + union cvmx_pemx_bar_ctl pemx_bar_ctl; + union cvmx_pemx_ctl_status pemx_ctl_status; + union cvmx_pemx_bist_status pemx_bist_status; + union cvmx_pemx_bist_status2 pemx_bist_status2; + union cvmx_pciercx_cfg032 pciercx_cfg032; + union cvmx_pciercx_cfg515 pciercx_cfg515; + union cvmx_sli_ctl_portx sli_ctl_portx; + union cvmx_sli_mem_access_ctl sli_mem_access_ctl; + union cvmx_sli_mem_access_subidx mem_access_subid; + union cvmx_sriox_status_reg sriox_status_reg; + union cvmx_pemx_bar1_indexx bar1_index; + + if (octeon_has_feature(OCTEON_FEATURE_SRIO)) { + /* Make sure this interface isn't SRIO */ + if (OCTEON_IS_MODEL(OCTEON_CN66XX)) { + /* + * The CN66XX requires reading the + * MIO_QLMX_CFG register to figure out the + * port type. + */ + union cvmx_mio_qlmx_cfg qlmx_cfg; + qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(pcie_port)); + + if (qlmx_cfg.s.qlm_spd == 15) { + pr_notice("PCIe: Port %d is disabled, skipping.\n", pcie_port); + return -1; + } + + switch (qlmx_cfg.s.qlm_spd) { + case 0x1: /* SRIO 1x4 short */ + case 0x3: /* SRIO 1x4 long */ + case 0x4: /* SRIO 2x2 short */ + case 0x6: /* SRIO 2x2 long */ + pr_notice("PCIe: Port %d is SRIO, skipping.\n", pcie_port); + return -1; + case 0x9: /* SGMII */ + pr_notice("PCIe: Port %d is SGMII, skipping.\n", pcie_port); + return -1; + case 0xb: /* XAUI */ + pr_notice("PCIe: Port %d is XAUI, skipping.\n", pcie_port); + return -1; + case 0x0: /* PCIE gen2 */ + case 0x8: /* PCIE gen2 (alias) */ + case 0x2: /* PCIE gen1 */ + case 0xa: /* PCIE gen1 (alias) */ + break; + default: + pr_notice("PCIe: Port %d is unknown, skipping.\n", pcie_port); + return -1; + } + } else { + sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(pcie_port)); + if (sriox_status_reg.s.srio) { + pr_notice("PCIe: Port %d is SRIO, skipping.\n", pcie_port); + return -1; + } + } + } + +#if 0 + /* This code is so that the PCIe analyzer is able to see 63XX traffic */ + pr_notice("PCIE : init for pcie analyzer.\n"); + cvmx_helper_qlm_jtag_init(); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); + cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); + cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); + cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); + cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); + cvmx_helper_qlm_jtag_update(pcie_port); +#endif + + /* Make sure we aren't trying to setup a target mode interface in host mode */ + mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port)); + if (!mio_rst_ctl.s.host_mode) { + pr_notice("PCIe: Port %d in endpoint mode.\n", pcie_port); + return -1; + } + + /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0)) { + if (pcie_port) { + union cvmx_ciu_qlm1 ciu_qlm; + ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1); + ciu_qlm.s.txbypass = 1; + ciu_qlm.s.txdeemph = 5; + ciu_qlm.s.txmargin = 0x17; + cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64); + } else { + union cvmx_ciu_qlm0 ciu_qlm; + ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0); + ciu_qlm.s.txbypass = 1; + ciu_qlm.s.txdeemph = 5; + ciu_qlm.s.txmargin = 0x17; + cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64); + } + } + /* Bring the PCIe out of reset */ + if (pcie_port) + ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); + else + ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); + /* + * After a chip reset the PCIe will also be in reset. If it + * isn't, most likely someone is trying to init it again + * without a proper PCIe reset + */ + if (ciu_soft_prst.s.soft_prst == 0) { + /* Reset the port */ + ciu_soft_prst.s.soft_prst = 1; + if (pcie_port) + cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); + else + cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); + /* Wait until pcie resets the ports. */ + udelay(2000); + } + if (pcie_port) { + ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); + ciu_soft_prst.s.soft_prst = 0; + cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); + } else { + ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); + ciu_soft_prst.s.soft_prst = 0; + cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); + } + + /* Wait for PCIe reset to complete */ + udelay(1000); + + /* + * Check and make sure PCIe came out of reset. If it doesn't + * the board probably hasn't wired the clocks up and the + * interface should be skipped. + */ + if (CVMX_WAIT_FOR_FIELD64(CVMX_MIO_RST_CTLX(pcie_port), union cvmx_mio_rst_ctlx, rst_done, ==, 1, 10000)) { + pr_notice("PCIe: Port %d stuck in reset, skipping.\n", pcie_port); + return -1; + } + + /* Check BIST status */ + pemx_bist_status.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS(pcie_port)); + if (pemx_bist_status.u64) + pr_notice("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status.u64)); + pemx_bist_status2.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS2(pcie_port)); + /* Errata PCIE-14766 may cause the lower 6 bits to be randomly set on CN63XXp1 */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)) + pemx_bist_status2.u64 &= ~0x3full; + if (pemx_bist_status2.u64) + pr_notice("PCIe: BIST2 FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status2.u64)); + + /* Initialize the config space CSRs */ + __cvmx_pcie_rc_initialize_config_space(pcie_port); + + /* Enable gen2 speed selection */ + pciercx_cfg515.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG515(pcie_port)); + pciercx_cfg515.s.dsc = 1; + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG515(pcie_port), pciercx_cfg515.u32); + + /* Bring the link up */ + if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) { + /* + * Some gen1 devices don't handle the gen 2 training + * correctly. Disable gen2 and try again with only + * gen1 + */ + union cvmx_pciercx_cfg031 pciercx_cfg031; + pciercx_cfg031.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG031(pcie_port)); + pciercx_cfg031.s.mls = 1; + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG031(pcie_port), pciercx_cfg031.u32); + if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) { + pr_notice("PCIe: Link timeout on port %d, probably the slot is empty\n", pcie_port); + return -1; + } + } + + /* Store merge control (SLI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */ + sli_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL); + sli_mem_access_ctl.s.max_word = 0; /* Allow 16 words to combine */ + sli_mem_access_ctl.s.timer = 127; /* Wait up to 127 cycles for more data */ + cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL, sli_mem_access_ctl.u64); + + /* Setup Mem access SubDIDs */ + mem_access_subid.u64 = 0; + mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */ + mem_access_subid.s.nmerge = 0; /* Allow merging as it works on CN6XXX. */ + mem_access_subid.s.esr = 1; /* Endian-swap for Reads. */ + mem_access_subid.s.esw = 1; /* Endian-swap for Writes. */ + mem_access_subid.s.wtype = 0; /* "No snoop" and "Relaxed ordering" are not set */ + mem_access_subid.s.rtype = 0; /* "No snoop" and "Relaxed ordering" are not set */ + /* PCIe Adddress Bits <63:34>. */ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + mem_access_subid.cn68xx.ba = 0; + else + mem_access_subid.cn63xx.ba = 0; + + /* + * Setup mem access 12-15 for port 0, 16-19 for port 1, + * supplying 36 bits of address space. + */ + for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) { + cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64); + /* Set each SUBID to extend the addressable range */ + __cvmx_increment_ba(&mem_access_subid); + } + + /* + * Disable the peer to peer forwarding register. This must be + * setup by the OS after it enumerates the bus and assigns + * addresses to the PCIe busses. + */ + for (i = 0; i < 4; i++) { + cvmx_write_csr(CVMX_PEMX_P2P_BARX_START(i, pcie_port), -1); + cvmx_write_csr(CVMX_PEMX_P2P_BARX_END(i, pcie_port), -1); + } + + /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */ + cvmx_write_csr(CVMX_PEMX_P2N_BAR0_START(pcie_port), 0); + + /* + * Set Octeon's BAR2 to decode 0-2^41. Bar0 and Bar1 take + * precedence where they overlap. It also overlaps with the + * device addresses, so make sure the peer to peer forwarding + * is set right. + */ + cvmx_write_csr(CVMX_PEMX_P2N_BAR2_START(pcie_port), 0); + + /* + * Setup BAR2 attributes + * Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM]) + * - PTLP_RO,CTLP_RO should normally be set (except for debug). + * - WAIT_COM=0 will likely work for all applications. + * Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM]) + */ + pemx_bar_ctl.u64 = cvmx_read_csr(CVMX_PEMX_BAR_CTL(pcie_port)); + pemx_bar_ctl.s.bar1_siz = 3; /* 256MB BAR1*/ + pemx_bar_ctl.s.bar2_enb = 1; + pemx_bar_ctl.s.bar2_esx = 1; + pemx_bar_ctl.s.bar2_cax = 0; + cvmx_write_csr(CVMX_PEMX_BAR_CTL(pcie_port), pemx_bar_ctl.u64); + sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port)); + sli_ctl_portx.s.ptlp_ro = 1; + sli_ctl_portx.s.ctlp_ro = 1; + sli_ctl_portx.s.wait_com = 0; + sli_ctl_portx.s.waitl_com = 0; + cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port), sli_ctl_portx.u64); + + /* BAR1 follows BAR2 */ + cvmx_write_csr(CVMX_PEMX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE); + + bar1_index.u64 = 0; + bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22); + bar1_index.s.ca = 1; /* Not Cached */ + bar1_index.s.end_swp = 1; /* Endian Swap mode */ + bar1_index.s.addr_v = 1; /* Valid entry */ + + for (i = 0; i < 16; i++) { + cvmx_write_csr(CVMX_PEMX_BAR1_INDEXX(i, pcie_port), bar1_index.u64); + /* 256MB / 16 >> 22 == 4 */ + bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22); + } + + /* + * Allow config retries for 250ms. Count is based off the 5Ghz + * SERDES clock. + */ + pemx_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port)); + pemx_ctl_status.s.cfg_rtry = 250 * 5000000 / 0x10000; + cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pemx_ctl_status.u64); + + /* Display the link status */ + pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); + pr_notice("PCIe: Port %d link active, %d lanes, speed gen%d\n", pcie_port, pciercx_cfg032.s.nlw, pciercx_cfg032.s.ls); + + return 0; +} + +/** + * Initialize a PCIe port for use in host(RC) mode. It doesn't enumerate the bus. + * + * @pcie_port: PCIe port to initialize + * + * Returns Zero on success + */ +static int cvmx_pcie_rc_initialize(int pcie_port) +{ + int result; + if (octeon_has_feature(OCTEON_FEATURE_NPEI)) + result = __cvmx_pcie_rc_initialize_gen1(pcie_port); + else + result = __cvmx_pcie_rc_initialize_gen2(pcie_port); + return result; +} + +/* Above was cvmx-pcie.c, below original pcie.c */ + +/** * Map a PCI device to the appropriate interrupt line * * @dev: The Linux PCI device structure for the device to map @@ -1027,11 +1481,12 @@ int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev, */ while (dev->bus && dev->bus->parent) dev = to_pci_dev(dev->bus->bridge); - /* If the root bus is number 0 and the PEX 8114 is the + /* + * If the root bus is number 0 and the PEX 8114 is the * root, assume we are behind the miswired bus. We * need to correct the swizzle level by two. Yuck. */ - if ((dev->bus->number == 0) && + if ((dev->bus->number == 1) && (dev->vendor == 0x10b5) && (dev->device == 0x8114)) { /* * The pin field is one based, not zero. We @@ -1048,39 +1503,73 @@ int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev, return pin - 1 + OCTEON_IRQ_PCI_INT0; } -/** +static void set_cfg_read_retry(u32 retry_cnt) +{ + union cvmx_pemx_ctl_status pemx_ctl; + pemx_ctl.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(1)); + pemx_ctl.s.cfg_rtry = retry_cnt; + cvmx_write_csr(CVMX_PEMX_CTL_STATUS(1), pemx_ctl.u64); +} + + +static u32 disable_cfg_read_retry(void) +{ + u32 retry_cnt; + + union cvmx_pemx_ctl_status pemx_ctl; + pemx_ctl.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(1)); + retry_cnt = pemx_ctl.s.cfg_rtry; + pemx_ctl.s.cfg_rtry = 0; + cvmx_write_csr(CVMX_PEMX_CTL_STATUS(1), pemx_ctl.u64); + return retry_cnt; +} + +static int is_cfg_retry(void) +{ + union cvmx_pemx_int_sum pemx_int_sum; + pemx_int_sum.u64 = cvmx_read_csr(CVMX_PEMX_INT_SUM(1)); + if (pemx_int_sum.s.crs_dr) + return 1; + return 0; +} + +/* * Read a value from configuration space * - * @bus: - * @devfn: - * @reg: - * @size: - * @val: - * Returns */ -static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus, - unsigned int devfn, int reg, int size, - u32 *val) +static int octeon_pcie_read_config(unsigned int pcie_port, struct pci_bus *bus, + unsigned int devfn, int reg, int size, + u32 *val) { union octeon_cvmemctl cvmmemctl; union octeon_cvmemctl cvmmemctl_save; int bus_number = bus->number; + int cfg_retry = 0; + int retry_cnt = 0; + int max_retry_cnt = 10; + u32 cfg_retry_cnt = 0; + cvmmemctl_save.u64 = 0; + BUG_ON(pcie_port >= ARRAY_SIZE(enable_pcie_bus_num_war)); /* * For the top level bus make sure our hardware bus number - * matches the software one. + * matches the software one */ if (bus->parent == NULL) { - union cvmx_pciercx_cfg006 pciercx_cfg006; - pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port, - CVMX_PCIERCX_CFG006(pcie_port)); - if (pciercx_cfg006.s.pbnum != bus_number) { - pciercx_cfg006.s.pbnum = bus_number; - pciercx_cfg006.s.sbnum = bus_number; - pciercx_cfg006.s.subbnum = bus_number; - cvmx_pcie_cfgx_write(pcie_port, - CVMX_PCIERCX_CFG006(pcie_port), - pciercx_cfg006.u32); + if (enable_pcie_bus_num_war[pcie_port]) + bus_number = 0; + else { + union cvmx_pciercx_cfg006 pciercx_cfg006; + pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port, + CVMX_PCIERCX_CFG006(pcie_port)); + if (pciercx_cfg006.s.pbnum != bus_number) { + pciercx_cfg006.s.pbnum = bus_number; + pciercx_cfg006.s.sbnum = bus_number; + pciercx_cfg006.s.subbnum = bus_number; + cvmx_pcie_cfgx_write(pcie_port, + CVMX_PCIERCX_CFG006(pcie_port), + pciercx_cfg006.u32); + } } } @@ -1116,29 +1605,52 @@ static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus, */ #if 1 /* Use this option if you aren't using either slot */ - if (bus_number == 1) + if (bus_number == 2) return PCIBIOS_FUNC_NOT_SUPPORTED; #elif 0 /* * Use this option if you are using the first slot but * not the second. */ - if ((bus_number == 1) && (devfn >> 3 != 2)) + if ((bus_number == 2) && (devfn >> 3 != 2)) return PCIBIOS_FUNC_NOT_SUPPORTED; #elif 0 /* * Use this option if you are using the second slot * but not the first. */ - if ((bus_number == 1) && (devfn >> 3 != 3)) + if ((bus_number == 2) && (devfn >> 3 != 3)) return PCIBIOS_FUNC_NOT_SUPPORTED; #elif 0 /* Use this opion if you are using both slots */ - if ((bus_number == 1) && + if ((bus_number == 2) && !((devfn == (2 << 3)) || (devfn == (3 << 3)))) return PCIBIOS_FUNC_NOT_SUPPORTED; #endif + /* The following #if gives a more complicated example. This is + the required checks for running a Nitrox CN16XX-NHBX in the + slot of the EBH5600. This card has a PLX PCIe bridge with + four Nitrox PLX parts behind it */ +#if 0 + /* PLX bridge with 4 ports */ + if ((bus_number == 4) && + !((devfn >> 3 >= 1) && (devfn >> 3 <= 4))) + return PCIBIOS_FUNC_NOT_SUPPORTED; + /* Nitrox behind PLX 1 */ + if ((bus_number == 5) && (devfn >> 3 != 0)) + return PCIBIOS_FUNC_NOT_SUPPORTED; + /* Nitrox behind PLX 2 */ + if ((bus_number == 6) && (devfn >> 3 != 0)) + return PCIBIOS_FUNC_NOT_SUPPORTED; + /* Nitrox behind PLX 3 */ + if ((bus_number == 7) && (devfn >> 3 != 0)) + return PCIBIOS_FUNC_NOT_SUPPORTED; + /* Nitrox behind PLX 4 */ + if ((bus_number == 8) && (devfn >> 3 != 0)) + return PCIBIOS_FUNC_NOT_SUPPORTED; +#endif + /* * Shorten the DID timeout so bus errors for PCIe * config reads from non existent devices happen @@ -1152,26 +1664,48 @@ static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus, __write_64bit_c0_register($11, 7, cvmmemctl.u64); } - switch (size) { - case 4: - *val = cvmx_pcie_config_read32(pcie_port, bus_number, - devfn >> 3, devfn & 0x7, reg); + if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && (enable_pcie_14459_war)) + cfg_retry_cnt = disable_cfg_read_retry(); + + pr_debug("pcie_cfg_rd port=%d b=%d devfn=0x%03x reg=0x%03x" + " size=%d ", pcie_port, bus_number, devfn, reg, size); + do { + switch (size) { + case 4: + *val = cvmx_pcie_config_read32(pcie_port, bus_number, + devfn >> 3, devfn & 0x7, reg); break; - case 2: - *val = cvmx_pcie_config_read16(pcie_port, bus_number, - devfn >> 3, devfn & 0x7, reg); + case 2: + *val = cvmx_pcie_config_read16(pcie_port, bus_number, + devfn >> 3, devfn & 0x7, reg); break; - case 1: - *val = cvmx_pcie_config_read8(pcie_port, bus_number, devfn >> 3, - devfn & 0x7, reg); + case 1: + *val = cvmx_pcie_config_read8(pcie_port, bus_number, + devfn >> 3, devfn & 0x7, reg); break; - default: - return PCIBIOS_FUNC_NOT_SUPPORTED; - } + default: + if (OCTEON_IS_MODEL(OCTEON_CN63XX)) + set_cfg_read_retry(cfg_retry_cnt); + return PCIBIOS_FUNC_NOT_SUPPORTED; + } + if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && + (enable_pcie_14459_war)) { + cfg_retry = is_cfg_retry(); + retry_cnt++; + if (retry_cnt > max_retry_cnt) { + pr_err(" pcie cfg_read retries failed. retry_cnt=%d\n", + retry_cnt); + cfg_retry = 0; + } + } + } while (cfg_retry); + if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && (enable_pcie_14459_war)) + set_cfg_read_retry(cfg_retry_cnt); + pr_debug("val=%08x : tries=%02d\n", *val, retry_cnt); if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1) || OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_1)) - __write_64bit_c0_register($11, 7, cvmmemctl_save.u64); + write_c0_cvmmemctl(cvmmemctl_save.u64); return PCIBIOS_SUCCESSFUL; } @@ -1187,42 +1721,56 @@ static int octeon_pcie1_read_config(struct pci_bus *bus, unsigned int devfn, return octeon_pcie_read_config(1, bus, devfn, reg, size, val); } +static int octeon_dummy_read_config(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 *val) +{ + return PCIBIOS_FUNC_NOT_SUPPORTED; +} - -/** +/* * Write a value to PCI configuration space - * - * @bus: - * @devfn: - * @reg: - * @size: - * @val: - * Returns */ -static inline int octeon_pcie_write_config(int pcie_port, struct pci_bus *bus, - unsigned int devfn, int reg, - int size, u32 val) +static int octeon_pcie_write_config(unsigned int pcie_port, struct pci_bus *bus, + unsigned int devfn, int reg, + int size, u32 val) { int bus_number = bus->number; + BUG_ON(pcie_port >= ARRAY_SIZE(enable_pcie_bus_num_war)); + + if ((bus->parent == NULL) && (enable_pcie_bus_num_war[pcie_port])) + bus_number = 0; + + pr_debug("pcie_cfg_wr port=%d b=%d devfn=0x%03x" + " reg=0x%03x size=%d val=%08x\n", pcie_port, bus_number, devfn, + reg, size, val); + + switch (size) { case 4: cvmx_pcie_config_write32(pcie_port, bus_number, devfn >> 3, devfn & 0x7, reg, val); - return PCIBIOS_SUCCESSFUL; + break; case 2: cvmx_pcie_config_write16(pcie_port, bus_number, devfn >> 3, devfn & 0x7, reg, val); - return PCIBIOS_SUCCESSFUL; + break; case 1: cvmx_pcie_config_write8(pcie_port, bus_number, devfn >> 3, devfn & 0x7, reg, val); - return PCIBIOS_SUCCESSFUL; + break; + default: + return PCIBIOS_FUNC_NOT_SUPPORTED; } #if PCI_CONFIG_SPACE_DELAY + /* + * Delay on writes so that devices have time to come up. Some + * bridges need this to allow time for the secondary busses to + * work + */ udelay(PCI_CONFIG_SPACE_DELAY); #endif - return PCIBIOS_FUNC_NOT_SUPPORTED; + return PCIBIOS_SUCCESSFUL; } static int octeon_pcie0_write_config(struct pci_bus *bus, unsigned int devfn, @@ -1237,6 +1785,12 @@ static int octeon_pcie1_write_config(struct pci_bus *bus, unsigned int devfn, return octeon_pcie_write_config(1, bus, devfn, reg, size, val); } +static int octeon_dummy_write_config(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 val) +{ + return PCIBIOS_FUNC_NOT_SUPPORTED; +} + static struct pci_ops octeon_pcie0_ops = { octeon_pcie0_read_config, octeon_pcie0_write_config, @@ -1279,6 +1833,35 @@ static struct pci_controller octeon_pcie1_controller = { .io_resource = &octeon_pcie1_io_resource, }; +static struct pci_ops octeon_dummy_ops = { + octeon_dummy_read_config, + octeon_dummy_write_config, +}; + +static struct resource octeon_dummy_mem_resource = { + .name = "Virtual PCIe MEM", + .flags = IORESOURCE_MEM, +}; + +static struct resource octeon_dummy_io_resource = { + .name = "Virtual PCIe IO", + .flags = IORESOURCE_IO, +}; + +static struct pci_controller octeon_dummy_controller = { + .pci_ops = &octeon_dummy_ops, + .mem_resource = &octeon_dummy_mem_resource, + .io_resource = &octeon_dummy_io_resource, +}; + +static int device_needs_bus_num_war(uint32_t deviceid) +{ +#define IDT_VENDOR_ID 0x111d + + if ((deviceid & 0xffff) == IDT_VENDOR_ID) + return 1; + return 0; +} /** * Initialize the Octeon PCIe controllers @@ -1287,19 +1870,27 @@ static struct pci_controller octeon_pcie1_controller = { */ static int __init octeon_pcie_setup(void) { - union cvmx_npei_ctl_status npei_ctl_status; int result; + int host_mode; + int srio_war15205 = 0, port; + union cvmx_sli_ctl_portx sli_ctl_portx; + union cvmx_sriox_status_reg sriox_status_reg; /* These chips don't have PCIe */ if (!octeon_has_feature(OCTEON_FEATURE_PCIE)) return 0; + /* No PCIe simulation */ + if (octeon_is_simulation()) + return 0; + + /* Disable PCI if instructed on the command line */ + if (pcie_disable) + return 0; + /* Point pcibios_map_irq() to the PCIe version of it */ octeon_pcibios_map_irq = octeon_pcie_pcibios_map_irq; - /* Use the PCIe based DMA mappings */ - octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE; - /* * PCIe I/O range. It is based on port 0 but includes up until * port 1's end. @@ -1310,11 +1901,43 @@ static int __init octeon_pcie_setup(void) cvmx_pcie_get_io_base_address(1) - cvmx_pcie_get_io_base_address(0) + cvmx_pcie_get_io_size(1) - 1; - npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); - if (npei_ctl_status.s.host_mode) { + /* + * Create a dummy PCIe controller to swallow up bus 0. IDT bridges + * don't work if the primary bus number is zero. Here we add a fake + * PCIe controller that the kernel will give bus 0. This allows + * us to not change the normal kernel bus enumeration + */ + octeon_dummy_controller.io_map_base = -1; + octeon_dummy_controller.mem_resource->start = (1ull<<48); + octeon_dummy_controller.mem_resource->end = (1ull<<48); + register_pci_controller(&octeon_dummy_controller); + + if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { + union cvmx_npei_ctl_status npei_ctl_status; + npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); + host_mode = npei_ctl_status.s.host_mode; + octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE; + } else { + union cvmx_mio_rst_ctlx mio_rst_ctl; + mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(0)); + host_mode = mio_rst_ctl.s.host_mode; + octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE2; + } + + if (host_mode) { pr_notice("PCIe: Initializing port 0\n"); + /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { + sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(0)); + if (sriox_status_reg.s.srio) { + srio_war15205 += 1; /* Port is SRIO */ + port = 0; + } + } result = cvmx_pcie_rc_initialize(0); if (result == 0) { + uint32_t device0; /* Memory offsets are physical addresses */ octeon_pcie0_controller.mem_offset = cvmx_pcie_get_mem_base_address(0); @@ -1343,60 +1966,134 @@ static int __init octeon_pcie_setup(void) octeon_pcie0_controller.io_resource->start = 4 << 10; octeon_pcie0_controller.io_resource->end = cvmx_pcie_get_io_size(0) - 1; + msleep(100); /* Some devices need extra time */ register_pci_controller(&octeon_pcie0_controller); + device0 = cvmx_pcie_config_read32(0, 0, 0, 0, 0); + enable_pcie_bus_num_war[0] = + device_needs_bus_num_war(device0); } } else { pr_notice("PCIe: Port 0 in endpoint mode, skipping.\n"); + /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { + srio_war15205 += 1; + port = 0; + } } - /* Skip the 2nd port on CN52XX if port 0 is in 4 lane mode */ - if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { - union cvmx_npei_dbg_data npei_dbg_data; - npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); - if (npei_dbg_data.cn52xx.qlm0_link_width) - return 0; + if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { + host_mode = 1; + /* Skip the 2nd port on CN52XX if port 0 is in 4 lane mode */ + if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { + union cvmx_npei_dbg_data dbg_data; + dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); + if (dbg_data.cn52xx.qlm0_link_width) + host_mode = 0; + } + } else { + union cvmx_mio_rst_ctlx mio_rst_ctl; + mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(1)); + host_mode = mio_rst_ctl.s.host_mode; } - pr_notice("PCIe: Initializing port 1\n"); - result = cvmx_pcie_rc_initialize(1); - if (result == 0) { - /* Memory offsets are physical addresses */ - octeon_pcie1_controller.mem_offset = - cvmx_pcie_get_mem_base_address(1); - /* IO offsets are Mips virtual addresses */ - octeon_pcie1_controller.io_map_base = - CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(1)); - octeon_pcie1_controller.io_offset = - cvmx_pcie_get_io_base_address(1) - - cvmx_pcie_get_io_base_address(0); - /* - * To keep things similar to PCI, we start device - * addresses at the same place as PCI uisng big bar - * support. This normally translates to 4GB-256MB, - * which is the same as most x86 PCs. - */ - octeon_pcie1_controller.mem_resource->start = - cvmx_pcie_get_mem_base_address(1) + (4ul << 30) - - (OCTEON_PCI_BAR1_HOLE_SIZE << 20); - octeon_pcie1_controller.mem_resource->end = - cvmx_pcie_get_mem_base_address(1) + - cvmx_pcie_get_mem_size(1) - 1; - /* - * Ports must be above 16KB for the ISA bus filtering - * in the PCI-X to PCI bridge. - */ - octeon_pcie1_controller.io_resource->start = - cvmx_pcie_get_io_base_address(1) - - cvmx_pcie_get_io_base_address(0); - octeon_pcie1_controller.io_resource->end = - octeon_pcie1_controller.io_resource->start + - cvmx_pcie_get_io_size(1) - 1; - register_pci_controller(&octeon_pcie1_controller); + if (host_mode) { + pr_notice("PCIe: Initializing port 1\n"); + /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { + sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(1)); + if (sriox_status_reg.s.srio) { + srio_war15205 += 1; /* Port is SRIO */ + port = 1; + } + } + result = cvmx_pcie_rc_initialize(1); + if (result == 0) { + uint32_t device0; + /* Memory offsets are physical addresses */ + octeon_pcie1_controller.mem_offset = + cvmx_pcie_get_mem_base_address(1); + /* + * To calculate the address for accessing the 2nd PCIe device, + * either 'io_map_base' (pci_iomap()), or 'mips_io_port_base' + * (ioport_map()) value is added to + * pci_resource_start(dev,bar)). The 'mips_io_port_base' is set + * only once based on first PCIe. Also changing 'io_map_base' + * based on first slot's value so that both the routines will + * work properly. + */ + octeon_pcie1_controller.io_map_base = + CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(0)); + /* IO offsets are Mips virtual addresses */ + octeon_pcie1_controller.io_offset = + cvmx_pcie_get_io_base_address(1) - + cvmx_pcie_get_io_base_address(0); + /* + * To keep things similar to PCI, we start device + * addresses at the same place as PCI uisng big bar + * support. This normally translates to 4GB-256MB, + * which is the same as most x86 PCs. + */ + octeon_pcie1_controller.mem_resource->start = + cvmx_pcie_get_mem_base_address(1) + (4ul << 30) - + (OCTEON_PCI_BAR1_HOLE_SIZE << 20); + octeon_pcie1_controller.mem_resource->end = + cvmx_pcie_get_mem_base_address(1) + + cvmx_pcie_get_mem_size(1) - 1; + /* + * Ports must be above 16KB for the ISA bus filtering + * in the PCI-X to PCI bridge. + */ + octeon_pcie1_controller.io_resource->start = + cvmx_pcie_get_io_base_address(1) - + cvmx_pcie_get_io_base_address(0); + octeon_pcie1_controller.io_resource->end = + octeon_pcie1_controller.io_resource->start + + cvmx_pcie_get_io_size(1) - 1; + msleep(100); /* Some devices need extra time */ + register_pci_controller(&octeon_pcie1_controller); + device0 = cvmx_pcie_config_read32(1, 0, 0, 0, 0); + enable_pcie_bus_num_war[1] = + device_needs_bus_num_war(device0); + } + } else { + pr_notice("PCIe: Port 1 not in root complex mode, skipping.\n"); + /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { + srio_war15205 += 1; + port = 1; + } + } + + /* + * CN63XX pass 1_x/2.0 errata PCIe-15205 requires setting all + * of SRIO MACs SLI_CTL_PORT*[INT*_MAP] to similar value and + * all of PCIe Macs SLI_CTL_PORT*[INT*_MAP] to different value + * from the previous set values + */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { + if (srio_war15205 == 1) { + sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(port)); + sli_ctl_portx.s.inta_map = 1; + sli_ctl_portx.s.intb_map = 1; + sli_ctl_portx.s.intc_map = 1; + sli_ctl_portx.s.intd_map = 1; + cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(port), sli_ctl_portx.u64); + + sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(!port)); + sli_ctl_portx.s.inta_map = 0; + sli_ctl_portx.s.intb_map = 0; + sli_ctl_portx.s.intc_map = 0; + sli_ctl_portx.s.intd_map = 0; + cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(!port), sli_ctl_portx.u64); + } } octeon_pci_dma_init(); return 0; } - arch_initcall(octeon_pcie_setup); |