diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-14 13:05:21 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-14 13:05:21 -0800 |
commit | 4964e0664c80680fa6b28ef91381c076a5b25c2c (patch) | |
tree | 62099c5aaeee7274bcc66bcfba35d479affa97cf /arch/mips/pci | |
parent | 0a80939b3e6af4b0dc93bf88ec02fd7e90a16f1b (diff) | |
parent | 7bf6612e8a9d6a0b3b82e8e2611942be1258b307 (diff) |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (119 commits)
MIPS: Delete unused function add_temporary_entry.
MIPS: Set default pci cache line size.
MIPS: Flush huge TLB
MIPS: Octeon: Remove SYS_SUPPORTS_HIGHMEM.
MIPS: Octeon: Add support for OCTEON II PCIe
MIPS: Octeon: Update PCI Latency timer and enable more error reporting.
MIPS: Alchemy: Update cpu-feature-overrides
MIPS: Alchemy: db1200: Improve PB1200 detection.
MIPS: Alchemy: merge Au1000 and Au1300-style IRQ controller code.
MIPS: Alchemy: chain IRQ controllers to MIPS IRQ controller
MIPS: Alchemy: irq: register pm at irq init time
MIPS: Alchemy: Touchscreen support on DB1100
MIPS: Alchemy: Hook up IrDA on DB1000/DB1100
net/irda: convert au1k_ir to platform driver.
MIPS: Alchemy: remove unused board headers
MTD: nand: make au1550nd.c a platform_driver
MIPS: Netlogic: Mark Netlogic chips as SMT capable
MIPS: Netlogic: Add support for XLP 3XX cores
MIPS: Netlogic: Merge some of XLR/XLP wakup code
MIPS: Netlogic: Add default XLP config.
...
Fix up trivial conflicts in arch/mips/kernel/{perf_event_mipsxx.c,
traps.c} and drivers/tty/serial/Makefile
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 bb82cbdbc62..c3ac4b086eb 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 5d530f89d87..d37be36dc65 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 8fbfbf2b931..389bf669d56 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 6a3bdb5ffa8..02d64f77e96 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 b5ce041cdaf..ec125bed721 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 00000000000..a4dd24a4130 --- /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 82e0fde1dba..39eb7c417e2 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 ed1c54284b8..52a1ba70b3b 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 a5807406a7f..a032ae0a533 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 20e45f30b2e..141bba56248 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 9ef840693ba..c10fbf2a19d 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 38fece16c43..3d701a962ef 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 fa8e378413b..aec2b111d35 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 0583c463e5f..fdb4d558c0c 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. */ |