diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-12-31 08:31:57 +0100 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-12-31 08:31:57 +0100 |
commit | a9de18eb761f7c1c860964b2e5addc1a35c7e861 (patch) | |
tree | 886e75fdfd09690cd262ca69cb7f5d1d42b48602 /arch/powerpc/sysdev | |
parent | b2aaf8f74cdc84a9182f6cabf198b7763bcb9d40 (diff) | |
parent | 6a94cb73064c952255336cc57731904174b2c58f (diff) |
Merge branch 'linus' into stackprotector
Conflicts:
arch/x86/include/asm/pda.h
kernel/fork.c
Diffstat (limited to 'arch/powerpc/sysdev')
31 files changed, 1236 insertions, 748 deletions
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 72fb35b9ebc..396582835cb 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -6,3 +6,9 @@ config PPC4xx_PCI_EXPRESS bool depends on PCI && 4xx default n + +config PPC_MSI_BITMAP + bool + depends on PCI_MSI + default y if MPIC + default y if FSL_PCI diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index a90054b56d5..5afce115ab1 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -5,6 +5,7 @@ endif mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) fsl-msi-obj-$(CONFIG_PCI_MSI) += fsl_msi.o +obj-$(CONFIG_PPC_MSI_BITMAP) += msi_bitmap.o obj-$(CONFIG_PPC_MPC106) += grackle.o obj-$(CONFIG_PPC_DCR_NATIVE) += dcr-low.o @@ -15,6 +16,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y) obj-$(CONFIG_FSL_LBC) += fsl_lbc.o obj-$(CONFIG_FSL_GTM) += fsl_gtm.o +obj-$(CONFIG_MPC8xxx_GPIO) += mpc8xxx_gpio.o obj-$(CONFIG_RAPIDIO) += fsl_rio.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ @@ -35,16 +37,14 @@ obj-$(CONFIG_OF_RTC) += of_rtc.o ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_4xx) += ppc4xx_pci.o endif +obj-$(CONFIG_PPC4xx_GPIO) += ppc4xx_gpio.o -# Temporary hack until we have migrated to asm-powerpc -ifeq ($(ARCH),powerpc) obj-$(CONFIG_CPM) += cpm_common.o obj-$(CONFIG_CPM2) += cpm2.o cpm2_pic.o obj-$(CONFIG_QUICC_ENGINE) += cpm_common.o obj-$(CONFIG_PPC_DCR) += dcr.o obj-$(CONFIG_8xx) += mpc8xx_pic.o cpm1.o obj-$(CONFIG_UCODE_PATCH) += micropatch.o -endif ifeq ($(CONFIG_SUSPEND),y) obj-$(CONFIG_6xx) += 6xx-suspend.o diff --git a/arch/powerpc/sysdev/bestcomm/Kconfig b/arch/powerpc/sysdev/bestcomm/Kconfig index 57cc5656256..0b192a1c429 100644 --- a/arch/powerpc/sysdev/bestcomm/Kconfig +++ b/arch/powerpc/sysdev/bestcomm/Kconfig @@ -17,23 +17,20 @@ config PPC_BESTCOMM answer Y or M. Otherwise say N. config PPC_BESTCOMM_ATA - tristate "Bestcomm ATA task support" + tristate depends on PPC_BESTCOMM - default n help This option enables the support for the ATA task. config PPC_BESTCOMM_FEC - tristate "Bestcomm FEC tasks support" + tristate depends on PPC_BESTCOMM - default n help This option enables the support for the FEC tasks. config PPC_BESTCOMM_GEN_BD - tristate "Bestcomm GenBD tasks support" + tristate depends on PPC_BESTCOMM - default n help This option enables the support for the GenBD tasks. diff --git a/arch/powerpc/sysdev/bestcomm/ata.c b/arch/powerpc/sysdev/bestcomm/ata.c index 1f5258fb38c..901c9f91e5d 100644 --- a/arch/powerpc/sysdev/bestcomm/ata.c +++ b/arch/powerpc/sysdev/bestcomm/ata.c @@ -61,6 +61,9 @@ bcom_ata_init(int queue_len, int maxbufsize) struct bcom_ata_var *var; struct bcom_ata_inc *inc; + /* Prefetch breaks ATA DMA. Turn it off for ATA DMA */ + bcom_disable_prefetch(); + tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0); if (!tsk) return NULL; diff --git a/arch/powerpc/sysdev/bestcomm/ata.h b/arch/powerpc/sysdev/bestcomm/ata.h index 10982769c46..0b237181133 100644 --- a/arch/powerpc/sysdev/bestcomm/ata.h +++ b/arch/powerpc/sysdev/bestcomm/ata.h @@ -16,22 +16,15 @@ struct bcom_ata_bd { u32 status; - u32 dst_pa; u32 src_pa; + u32 dst_pa; }; -extern struct bcom_task * -bcom_ata_init(int queue_len, int maxbufsize); - -extern void -bcom_ata_rx_prepare(struct bcom_task *tsk); - -extern void -bcom_ata_tx_prepare(struct bcom_task *tsk); - -extern void -bcom_ata_reset_bd(struct bcom_task *tsk); - +extern struct bcom_task * bcom_ata_init(int queue_len, int maxbufsize); +extern void bcom_ata_rx_prepare(struct bcom_task *tsk); +extern void bcom_ata_tx_prepare(struct bcom_task *tsk); +extern void bcom_ata_reset_bd(struct bcom_task *tsk); +extern void bcom_ata_release(struct bcom_task *tsk); #endif /* __BESTCOMM_ATA_H__ */ diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c index 446c9ea85b3..378ebd9aac1 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm.c +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c @@ -279,7 +279,6 @@ bcom_engine_init(void) int task; phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa; unsigned int tdt_size, ctx_size, var_size, fdt_size; - u16 regval; /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */ tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt); @@ -331,10 +330,8 @@ bcom_engine_init(void) out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS); /* Disable COMM Bus Prefetch on the original 5200; it's broken */ - if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) { - regval = in_be16(&bcom_eng->regs->PtdCntrl); - out_be16(&bcom_eng->regs->PtdCntrl, regval | 1); - } + if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) + bcom_disable_prefetch(); /* Init lock */ spin_lock_init(&bcom_eng->lock); diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.h b/arch/powerpc/sysdev/bestcomm/bestcomm.h index c960a8b4965..23a95f80dfd 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm.h +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h @@ -16,8 +16,19 @@ #ifndef __BESTCOMM_H__ #define __BESTCOMM_H__ -struct bcom_bd; /* defined later on ... */ - +/** + * struct bcom_bd - Structure describing a generic BestComm buffer descriptor + * @status: The current status of this buffer. Exact meaning depends on the + * task type + * @data: An array of u32 extra data. Size of array is task dependant. + * + * Note: Don't dereference a bcom_bd pointer as an array. The size of the + * bcom_bd is variable. Use bcom_get_bd() instead. + */ +struct bcom_bd { + u32 status; + u32 data[0]; /* variable payload size */ +}; /* ======================================================================== */ /* Generic task management */ @@ -84,17 +95,6 @@ bcom_get_task_irq(struct bcom_task *tsk) { /* BD based tasks helpers */ /* ======================================================================== */ -/** - * struct bcom_bd - Structure describing a generic BestComm buffer descriptor - * @status: The current status of this buffer. Exact meaning depends on the - * task type - * @data: An array of u32 whose meaning depends on the task type. - */ -struct bcom_bd { - u32 status; - u32 data[1]; /* variable, but at least 1 */ -}; - #define BCOM_BD_READY 0x40000000ul /** _bcom_next_index - Get next input index. @@ -140,15 +140,31 @@ bcom_queue_full(struct bcom_task *tsk) } /** + * bcom_get_bd - Get a BD from the queue + * @tsk: The BestComm task structure + * index: Index of the BD to fetch + */ +static inline struct bcom_bd +*bcom_get_bd(struct bcom_task *tsk, unsigned int index) +{ + /* A cast to (void*) so the address can be incremented by the + * real size instead of by sizeof(struct bcom_bd) */ + return ((void *)tsk->bd) + (index * tsk->bd_size); +} + +/** * bcom_buffer_done - Checks if a BestComm * @tsk: The BestComm task structure */ static inline int bcom_buffer_done(struct bcom_task *tsk) { + struct bcom_bd *bd; if (bcom_queue_empty(tsk)) return 0; - return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY); + + bd = bcom_get_bd(tsk, tsk->outdex); + return !(bd->status & BCOM_BD_READY); } /** @@ -160,16 +176,21 @@ bcom_buffer_done(struct bcom_task *tsk) static inline struct bcom_bd * bcom_prepare_next_buffer(struct bcom_task *tsk) { - tsk->bd[tsk->index].status = 0; /* cleanup last status */ - return &tsk->bd[tsk->index]; + struct bcom_bd *bd; + + bd = bcom_get_bd(tsk, tsk->index); + bd->status = 0; /* cleanup last status */ + return bd; } static inline void bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie) { + struct bcom_bd *bd = bcom_get_bd(tsk, tsk->index); + tsk->cookie[tsk->index] = cookie; mb(); /* ensure the bd is really up-to-date */ - tsk->bd[tsk->index].status |= BCOM_BD_READY; + bd->status |= BCOM_BD_READY; tsk->index = _bcom_next_index(tsk); if (tsk->flags & BCOM_FLAGS_ENABLE_TASK) bcom_enable(tsk); @@ -179,10 +200,12 @@ static inline void * bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd) { void *cookie = tsk->cookie[tsk->outdex]; + struct bcom_bd *bd = bcom_get_bd(tsk, tsk->outdex); + if (p_status) - *p_status = tsk->bd[tsk->outdex].status; + *p_status = bd->status; if (p_bd) - *p_bd = &tsk->bd[tsk->outdex]; + *p_bd = bd; tsk->outdex = _bcom_next_outdex(tsk); return cookie; } diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h index 866a2915ef2..eb0d1c883c3 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h +++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h @@ -198,8 +198,8 @@ struct bcom_task_header { #define BCOM_IPR_SCTMR_1 2 #define BCOM_IPR_FEC_RX 6 #define BCOM_IPR_FEC_TX 5 -#define BCOM_IPR_ATA_RX 4 -#define BCOM_IPR_ATA_TX 3 +#define BCOM_IPR_ATA_RX 7 +#define BCOM_IPR_ATA_TX 7 #define BCOM_IPR_SCPCI_RX 2 #define BCOM_IPR_SCPCI_TX 2 #define BCOM_IPR_PSC3_RX 2 @@ -241,6 +241,22 @@ extern void bcom_set_initiator(int task, int initiator); #define TASK_ENABLE 0x8000 +/** + * bcom_disable_prefetch - Hook to disable bus prefetching + * + * ATA DMA and the original MPC5200 need this due to silicon bugs. At the + * moment disabling prefetch is a one-way street. There is no mechanism + * in place to turn prefetch back on after it has been disabled. There is + * no reason it couldn't be done, it would just be more complex to implement. + */ +static inline void bcom_disable_prefetch(void) +{ + u16 regval; + + regval = in_be16(&bcom_eng->regs->PtdCntrl); + out_be16(&bcom_eng->regs->PtdCntrl, regval | 1); +}; + static inline void bcom_enable_task(int task) { diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 4a04823e842..490473ce810 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -546,15 +546,11 @@ static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio) return !!(in_be16(&iop->dat) & pin_mask); } -static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) +static void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask, + int value) { - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); struct cpm_ioport16 __iomem *iop = mm_gc->regs; - unsigned long flags; - u16 pin_mask = 1 << (15 - gpio); - - spin_lock_irqsave(&cpm1_gc->lock, flags); if (value) cpm1_gc->cpdata |= pin_mask; @@ -562,6 +558,18 @@ static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) cpm1_gc->cpdata &= ~pin_mask; out_be16(&iop->dat, cpm1_gc->cpdata); +} + +static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); + unsigned long flags; + u16 pin_mask = 1 << (15 - gpio); + + spin_lock_irqsave(&cpm1_gc->lock, flags); + + __cpm1_gpio16_set(mm_gc, pin_mask, value); spin_unlock_irqrestore(&cpm1_gc->lock, flags); } @@ -569,14 +577,17 @@ static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); struct cpm_ioport16 __iomem *iop = mm_gc->regs; - u16 pin_mask; + unsigned long flags; + u16 pin_mask = 1 << (15 - gpio); - pin_mask = 1 << (15 - gpio); + spin_lock_irqsave(&cpm1_gc->lock, flags); setbits16(&iop->dir, pin_mask); + __cpm1_gpio16_set(mm_gc, pin_mask, val); - cpm1_gpio16_set(gc, gpio, val); + spin_unlock_irqrestore(&cpm1_gc->lock, flags); return 0; } @@ -584,13 +595,17 @@ static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); struct cpm_ioport16 __iomem *iop = mm_gc->regs; - u16 pin_mask; + unsigned long flags; + u16 pin_mask = 1 << (15 - gpio); - pin_mask = 1 << (15 - gpio); + spin_lock_irqsave(&cpm1_gc->lock, flags); clrbits16(&iop->dir, pin_mask); + spin_unlock_irqrestore(&cpm1_gc->lock, flags); + return 0; } @@ -655,15 +670,11 @@ static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio) return !!(in_be32(&iop->dat) & pin_mask); } -static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) +static void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask, + int value) { - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); struct cpm_ioport32b __iomem *iop = mm_gc->regs; - unsigned long flags; - u32 pin_mask = 1 << (31 - gpio); - - spin_lock_irqsave(&cpm1_gc->lock, flags); if (value) cpm1_gc->cpdata |= pin_mask; @@ -671,6 +682,18 @@ static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) cpm1_gc->cpdata &= ~pin_mask; out_be32(&iop->dat, cpm1_gc->cpdata); +} + +static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); + unsigned long flags; + u32 pin_mask = 1 << (31 - gpio); + + spin_lock_irqsave(&cpm1_gc->lock, flags); + + __cpm1_gpio32_set(mm_gc, pin_mask, value); spin_unlock_irqrestore(&cpm1_gc->lock, flags); } @@ -678,14 +701,17 @@ static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); struct cpm_ioport32b __iomem *iop = mm_gc->regs; - u32 pin_mask; + unsigned long flags; + u32 pin_mask = 1 << (31 - gpio); - pin_mask = 1 << (31 - gpio); + spin_lock_irqsave(&cpm1_gc->lock, flags); setbits32(&iop->dir, pin_mask); + __cpm1_gpio32_set(mm_gc, pin_mask, val); - cpm1_gpio32_set(gc, gpio, val); + spin_unlock_irqrestore(&cpm1_gc->lock, flags); return 0; } @@ -693,13 +719,17 @@ static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); struct cpm_ioport32b __iomem *iop = mm_gc->regs; - u32 pin_mask; + unsigned long flags; + u32 pin_mask = 1 << (31 - gpio); - pin_mask = 1 << (31 - gpio); + spin_lock_irqsave(&cpm1_gc->lock, flags); clrbits32(&iop->dir, pin_mask); + spin_unlock_irqrestore(&cpm1_gc->lock, flags); + return 0; } diff --git a/arch/powerpc/sysdev/dcr-low.S b/arch/powerpc/sysdev/dcr-low.S index 2078f39e2f1..d3098ef1404 100644 --- a/arch/powerpc/sysdev/dcr-low.S +++ b/arch/powerpc/sysdev/dcr-low.S @@ -11,14 +11,20 @@ #include <asm/ppc_asm.h> #include <asm/processor.h> +#include <asm/bug.h> #define DCR_ACCESS_PROLOG(table) \ + cmpli cr0,r3,1024; \ rlwinm r3,r3,4,18,27; \ lis r5,table@h; \ ori r5,r5,table@l; \ add r3,r3,r5; \ + bge- 1f; \ mtctr r3; \ - bctr + bctr; \ +1: trap; \ + EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0; \ + blr _GLOBAL(__mfdcr) DCR_ACCESS_PROLOG(__mfdcr_table) diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c index a8ba9983dd5..bb44aa9fd47 100644 --- a/arch/powerpc/sysdev/dcr.c +++ b/arch/powerpc/sysdev/dcr.c @@ -124,7 +124,8 @@ EXPORT_SYMBOL_GPL(dcr_write_generic); #endif /* defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO) */ -unsigned int dcr_resource_start(struct device_node *np, unsigned int index) +unsigned int dcr_resource_start(const struct device_node *np, + unsigned int index) { unsigned int ds; const u32 *dr = of_get_property(np, "dcr-reg", &ds); @@ -136,7 +137,7 @@ unsigned int dcr_resource_start(struct device_node *np, unsigned int index) } EXPORT_SYMBOL_GPL(dcr_resource_start); -unsigned int dcr_resource_len(struct device_node *np, unsigned int index) +unsigned int dcr_resource_len(const struct device_node *np, unsigned int index) { unsigned int ds; const u32 *dr = of_get_property(np, "dcr-reg", &ds); diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c index 422c8faef59..0494ee55920 100644 --- a/arch/powerpc/sysdev/fsl_lbc.c +++ b/arch/powerpc/sysdev/fsl_lbc.c @@ -11,14 +11,19 @@ * (at your option) any later version. */ +#include <linux/init.h> +#include <linux/module.h> #include <linux/kernel.h> +#include <linux/compiler.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/io.h> #include <linux/of.h> +#include <asm/prom.h> #include <asm/fsl_lbc.h> -spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock); - -struct fsl_lbc_regs __iomem *fsl_lbc_regs; -EXPORT_SYMBOL(fsl_lbc_regs); +static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock); +static struct fsl_lbc_regs __iomem *fsl_lbc_regs; static char __initdata *compat_lbc[] = { "fsl,pq2-localbus", @@ -127,3 +132,43 @@ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm) return 0; } EXPORT_SYMBOL(fsl_upm_find); + +/** + * fsl_upm_run_pattern - actually run an UPM pattern + * @upm: pointer to the fsl_upm structure obtained via fsl_upm_find + * @io_base: remapped pointer to where memory access should happen + * @mar: MAR register content during pattern execution + * + * This function triggers dummy write to the memory specified by the io_base, + * thus UPM pattern actually executed. Note that mar usage depends on the + * pre-programmed AMX bits in the UPM RAM. + */ +int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&fsl_lbc_lock, flags); + + out_be32(&fsl_lbc_regs->mar, mar << (32 - upm->width)); + + switch (upm->width) { + case 8: + out_8(io_base, 0x0); + break; + case 16: + out_be16(io_base, 0x0); + break; + case 32: + out_be32(io_base, 0x0); + break; + default: + ret = -EINVAL; + break; + } + + spin_unlock_irqrestore(&fsl_lbc_lock, flags); + + return ret; +} +EXPORT_SYMBOL(fsl_upm_run_pattern); diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 2c5187cc8a2..f25ce818d40 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -14,7 +14,6 @@ */ #include <linux/irq.h> #include <linux/bootmem.h> -#include <linux/bitmap.h> #include <linux/msi.h> #include <linux/pci.h> #include <linux/of_platform.h> @@ -67,95 +66,22 @@ static struct irq_host_ops fsl_msi_host_ops = { .map = fsl_msi_host_map, }; -static irq_hw_number_t fsl_msi_alloc_hwirqs(struct fsl_msi *msi, int num) -{ - unsigned long flags; - int order = get_count_order(num); - int offset; - - spin_lock_irqsave(&msi->bitmap_lock, flags); - - offset = bitmap_find_free_region(msi->fsl_msi_bitmap, - NR_MSI_IRQS, order); - - spin_unlock_irqrestore(&msi->bitmap_lock, flags); - - pr_debug("%s: allocated 0x%x (2^%d) at offset 0x%x\n", - __func__, num, order, offset); - - return offset; -} - -static void fsl_msi_free_hwirqs(struct fsl_msi *msi, int offset, int num) -{ - unsigned long flags; - int order = get_count_order(num); - - pr_debug("%s: freeing 0x%x (2^%d) at offset 0x%x\n", - __func__, num, order, offset); - - spin_lock_irqsave(&msi->bitmap_lock, flags); - bitmap_release_region(msi->fsl_msi_bitmap, offset, order); - spin_unlock_irqrestore(&msi->bitmap_lock, flags); -} - -static int fsl_msi_free_dt_hwirqs(struct fsl_msi *msi) -{ - int i; - int len; - const u32 *p; - - bitmap_allocate_region(msi->fsl_msi_bitmap, 0, - get_count_order(NR_MSI_IRQS)); - - p = of_get_property(msi->of_node, "msi-available-ranges", &len); - - if (!p) { - /* No msi-available-ranges property, - * All the 256 MSI interrupts can be used - */ - fsl_msi_free_hwirqs(msi, 0, 0x100); - return 0; - } - - if ((len % (2 * sizeof(u32))) != 0) { - printk(KERN_WARNING "fsl_msi: Malformed msi-available-ranges " - "property on %s\n", msi->of_node->full_name); - return -EINVAL; - } - - /* Format is: (<u32 start> <u32 count>)+ */ - len /= 2 * sizeof(u32); - for (i = 0; i < len; i++, p += 2) - fsl_msi_free_hwirqs(msi, *p, *(p + 1)); - - return 0; -} - static int fsl_msi_init_allocator(struct fsl_msi *msi_data) { int rc; - int size = BITS_TO_LONGS(NR_MSI_IRQS) * sizeof(u32); - msi_data->fsl_msi_bitmap = kzalloc(size, GFP_KERNEL); + rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS, + msi_data->irqhost->of_node); + if (rc) + return rc; - if (msi_data->fsl_msi_bitmap == NULL) { - pr_debug("%s: ENOMEM allocating allocator bitmap!\n", - __func__); - return -ENOMEM; + rc = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap); + if (rc < 0) { + msi_bitmap_free(&msi_data->bitmap); + return rc; } - rc = fsl_msi_free_dt_hwirqs(msi_data); - if (rc) - goto out_free; - return 0; -out_free: - kfree(msi_data->fsl_msi_bitmap); - - msi_data->fsl_msi_bitmap = NULL; - return rc; - } static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type) @@ -175,7 +101,8 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev) if (entry->irq == NO_IRQ) continue; set_irq_msi(entry->irq, NULL); - fsl_msi_free_hwirqs(msi_data, virq_to_hw(entry->irq), 1); + msi_bitmap_free_hwirqs(&msi_data->bitmap, + virq_to_hw(entry->irq), 1); irq_dispose_mapping(entry->irq); } @@ -197,15 +124,14 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq, static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) { - irq_hw_number_t hwirq; - int rc; + int rc, hwirq; unsigned int virq; struct msi_desc *entry; struct msi_msg msg; struct fsl_msi *msi_data = fsl_msi; list_for_each_entry(entry, &pdev->msi_list, list) { - hwirq = fsl_msi_alloc_hwirqs(msi_data, 1); + hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); if (hwirq < 0) { rc = hwirq; pr_debug("%s: fail allocating msi interrupt\n", @@ -216,9 +142,9 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) virq = irq_create_mapping(msi_data->irqhost, hwirq); if (virq == NO_IRQ) { - pr_debug("%s: fail mapping hwirq 0x%lx\n", + pr_debug("%s: fail mapping hwirq 0x%x\n", __func__, hwirq); - fsl_msi_free_hwirqs(msi_data, hwirq, 1); + msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1); rc = -ENOSPC; goto out_free; } @@ -317,14 +243,11 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, goto error_out; } - msi->of_node = of_node_get(dev->node); + msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR, + NR_MSI_IRQS, &fsl_msi_host_ops, 0); - msi->irqhost = irq_alloc_host(of_node_get(dev->node), - IRQ_HOST_MAP_LINEAR, - NR_MSI_IRQS, &fsl_msi_host_ops, 0); if (msi->irqhost == NULL) { dev_err(&dev->dev, "No memory for MSI irqhost\n"); - of_node_put(dev->node); err = -ENOMEM; goto error_out; } diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index a653468521f..331c7e7025b 100644 --- a/arch/powerpc/sysdev/fsl_msi.h +++ b/arch/powerpc/sysdev/fsl_msi.h @@ -13,6 +13,8 @@ #ifndef _POWERPC_SYSDEV_FSL_MSI_H #define _POWERPC_SYSDEV_FSL_MSI_H +#include <asm/msi_bitmap.h> + #define NR_MSI_REG 8 #define IRQS_PER_MSI_REG 32 #define NR_MSI_IRQS (NR_MSI_REG * IRQS_PER_MSI_REG) @@ -22,9 +24,6 @@ #define FSL_PIC_IP_IPIC 0x00000002 struct fsl_msi { - /* Device node of the MSI interrupt*/ - struct device_node *of_node; - struct irq_host *irqhost; unsigned long cascade_irq; @@ -34,8 +33,7 @@ struct fsl_msi { void __iomem *msi_regs; u32 feature; - unsigned long *fsl_msi_bitmap; - spinlock_t bitmap_lock; + struct msi_bitmap bitmap; }; #endif /* _POWERPC_SYSDEV_FSL_MSI_H */ diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 61e6d77efa4..d5f9ae0f1b7 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -1,7 +1,7 @@ /* - * MPC85xx/86xx PCI/PCIE support routing. + * MPC83xx/85xx/86xx PCI/PCIE support routing. * - * Copyright 2007 Freescale Semiconductor, Inc + * Copyright 2007,2008 Freescale Semiconductor, Inc * * Initial author: Xianghua Xiao <x.xiao@freescale.com> * Recode: ZHANG WEI <wei.zhang@freescale.com> @@ -187,7 +187,7 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; @@ -251,20 +251,47 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_header); #endif /* CONFIG_PPC_85xx || CONFIG_PPC_86xx */ -#if defined(CONFIG_PPC_83xx) +#if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x) int __init mpc83xx_add_bridge(struct device_node *dev) { int len; struct pci_controller *hose; - struct resource rsrc; + struct resource rsrc_reg; + struct resource rsrc_cfg; const int *bus_range; - int primary = 1, has_address = 0; - phys_addr_t immr = get_immrbase(); + int primary; pr_debug("Adding PCI host bridge %s\n", dev->full_name); /* Fetch host bridge registers address */ - has_address = (of_address_to_resource(dev, 0, &rsrc) == 0); + if (of_address_to_resource(dev, 0, &rsrc_reg)) { + printk(KERN_WARNING "Can't get pci register base!\n"); + return -ENOMEM; + } + + memset(&rsrc_cfg, 0, sizeof(rsrc_cfg)); + + if (of_address_to_resource(dev, 1, &rsrc_cfg)) { + printk(KERN_WARNING + "No pci config register base in dev tree, " + "using default\n"); + /* + * MPC83xx supports up to two host controllers + * one at 0x8500 has config space registers at 0x8300 + * one at 0x8600 has config space registers at 0x8380 + */ + if ((rsrc_reg.start & 0xfffff) == 0x8500) + rsrc_cfg.start = (rsrc_reg.start & 0xfff00000) + 0x8300; + else if ((rsrc_reg.start & 0xfffff) == 0x8600) + rsrc_cfg.start = (rsrc_reg.start & 0xfff00000) + 0x8380; + } + /* + * Controller at offset 0x8500 is primary + */ + if ((rsrc_reg.start & 0xfffff) == 0x8500) + primary = 1; + else + primary = 0; /* Get bus range if any */ bus_range = of_get_property(dev, "bus-range", &len); @@ -273,7 +300,7 @@ int __init mpc83xx_add_bridge(struct device_node *dev) " bus 0\n", dev->full_name); } - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; @@ -281,22 +308,11 @@ int __init mpc83xx_add_bridge(struct device_node *dev) hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; - /* MPC83xx supports up to two host controllers one at 0x8500 from immrbar - * the other at 0x8600, we consider the 0x8500 the primary controller - */ - /* PCI 1 */ - if ((rsrc.start & 0xfffff) == 0x8500) { - setup_indirect_pci(hose, immr + 0x8300, immr + 0x8304, 0); - } - /* PCI 2 */ - if ((rsrc.start & 0xfffff) == 0x8600) { - setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384, 0); - primary = 0; - } + setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 4, 0); - printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. " + printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. " "Firmware bus number: %d->%d\n", - (unsigned long long)rsrc.start, hose->first_busno, + (unsigned long long)rsrc_reg.start, hose->first_busno, hose->last_busno); pr_debug(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 214388e1180..115cb16351f 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -207,212 +207,6 @@ static int __init of_add_fixed_phys(void) arch_initcall(of_add_fixed_phys); #endif /* CONFIG_FIXED_PHY */ -static int gfar_mdio_of_init_one(struct device_node *np) -{ - int k; - struct device_node *child = NULL; - struct gianfar_mdio_data mdio_data; - struct platform_device *mdio_dev; - struct resource res; - int ret; - - memset(&res, 0, sizeof(res)); - memset(&mdio_data, 0, sizeof(mdio_data)); - - ret = of_address_to_resource(np, 0, &res); - if (ret) - return ret; - - mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", - res.start&0xfffff, &res, 1); - if (IS_ERR(mdio_dev)) - return PTR_ERR(mdio_dev); - - for (k = 0; k < 32; k++) - mdio_data.irq[k] = PHY_POLL; - - while ((child = of_get_next_child(np, child)) != NULL) { - int irq = irq_of_parse_and_map(child, 0); - if (irq != NO_IRQ) { - const u32 *id = of_get_property(child, "reg", NULL); - mdio_data.irq[*id] = irq; - } - } - - ret = platform_device_add_data(mdio_dev, &mdio_data, - sizeof(struct gianfar_mdio_data)); - if (ret) - platform_device_unregister(mdio_dev); - - return ret; -} - -static int __init gfar_mdio_of_init(void) -{ - struct device_node *np = NULL; - - for_each_compatible_node(np, NULL, "fsl,gianfar-mdio") - gfar_mdio_of_init_one(np); - - /* try the deprecated version */ - for_each_compatible_node(np, "mdio", "gianfar"); - gfar_mdio_of_init_one(np); - - return 0; -} - -arch_initcall(gfar_mdio_of_init); - -static const char *gfar_tx_intr = "tx"; -static const char *gfar_rx_intr = "rx"; -static const char *gfar_err_intr = "error"; - -static int __init gfar_of_init(void) -{ - struct device_node *np; - unsigned int i; - struct platform_device *gfar_dev; - struct resource res; - int ret; - - for (np = NULL, i = 0; - (np = of_find_compatible_node(np, "network", "gianfar")) != NULL; - i++) { - struct resource r[4]; - struct device_node *phy, *mdio; - struct gianfar_platform_data gfar_data; - const unsigned int *id; - const char *model; - const char *ctype; - const void *mac_addr; - const phandle *ph; - int n_res = 2; - - if (!of_device_is_available(np)) - continue; - - memset(r, 0, sizeof(r)); - memset(&gfar_data, 0, sizeof(gfar_data)); - - ret = of_address_to_resource(np, 0, &r[0]); - if (ret) - goto err; - - of_irq_to_resource(np, 0, &r[1]); - - model = of_get_property(np, "model", NULL); - - /* If we aren't the FEC we have multiple interrupts */ - if (model && strcasecmp(model, "FEC")) { - r[1].name = gfar_tx_intr; - - r[2].name = gfar_rx_intr; - of_irq_to_resource(np, 1, &r[2]); - - r[3].name = gfar_err_intr; - of_irq_to_resource(np, 2, &r[3]); - - n_res += 2; - } - - gfar_dev = - platform_device_register_simple("fsl-gianfar", i, &r[0], - n_res); - - if (IS_ERR(gfar_dev)) { - ret = PTR_ERR(gfar_dev); - goto err; - } - - mac_addr = of_get_mac_address(np); - if (mac_addr) - memcpy(gfar_data.mac_addr, mac_addr, 6); - - if (model && !strcasecmp(model, "TSEC")) - gfar_data.device_flags = - FSL_GIANFAR_DEV_HAS_GIGABIT | - FSL_GIANFAR_DEV_HAS_COALESCE | - FSL_GIANFAR_DEV_HAS_RMON | - FSL_GIANFAR_DEV_HAS_MULTI_INTR; - if (model && !strcasecmp(model, "eTSEC")) - gfar_data.device_flags = - FSL_GIANFAR_DEV_HAS_GIGABIT | - FSL_GIANFAR_DEV_HAS_COALESCE | - FSL_GIANFAR_DEV_HAS_RMON | - FSL_GIANFAR_DEV_HAS_MULTI_INTR | - FSL_GIANFAR_DEV_HAS_CSUM | - FSL_GIANFAR_DEV_HAS_VLAN | - FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; - - ctype = of_get_property(np, "phy-connection-type", NULL); - - /* We only care about rgmii-id. The rest are autodetected */ - if (ctype && !strcmp(ctype, "rgmii-id")) - gfar_data.interface = PHY_INTERFACE_MODE_RGMII_ID; - else - gfar_data.interface = PHY_INTERFACE_MODE_MII; - - if (of_get_property(np, "fsl,magic-packet", NULL)) - gfar_data.device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET; - - ph = of_get_property(np, "phy-handle", NULL); - if (ph == NULL) { - u32 *fixed_link; - - fixed_link = (u32 *)of_get_property(np, "fixed-link", - NULL); - if (!fixed_link) { - ret = -ENODEV; - goto unreg; - } - - snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "0"); - gfar_data.phy_id = fixed_link[0]; - } else { - phy = of_find_node_by_phandle(*ph); - - if (phy == NULL) { - ret = -ENODEV; - goto unreg; - } - - mdio = of_get_parent(phy); - - id = of_get_property(phy, "reg", NULL); - ret = of_address_to_resource(mdio, 0, &res); - if (ret) { - of_node_put(phy); - of_node_put(mdio); - goto unreg; - } - - gfar_data.phy_id = *id; - snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "%llx", - (unsigned long long)res.start&0xfffff); - - of_node_put(phy); - of_node_put(mdio); - } - - ret = - platform_device_add_data(gfar_dev, &gfar_data, - sizeof(struct - gianfar_platform_data)); - if (ret) - goto unreg; - } - - return 0; - -unreg: - platform_device_unregister(gfar_dev); -err: - return ret; -} - -arch_initcall(gfar_of_init); - - #ifdef CONFIG_PPC_83xx static int __init mpc83xx_wdt_init(void) { @@ -767,42 +561,6 @@ void fsl_rstcr_restart(char *cmd) #endif #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) -struct platform_diu_data_ops diu_ops = { - .diu_size = 1280 * 1024 * 4, /* default one 1280x1024 buffer */ -}; +struct platform_diu_data_ops diu_ops; EXPORT_SYMBOL(diu_ops); - -int __init preallocate_diu_videomemory(void) -{ - pr_debug("diu_size=%lu\n", diu_ops.diu_size); - - diu_ops.diu_mem = __alloc_bootmem(diu_ops.diu_size, 8, 0); - if (!diu_ops.diu_mem) { - printk(KERN_ERR "fsl-diu: cannot allocate %lu bytes\n", - diu_ops.diu_size); - return -ENOMEM; - } - - pr_debug("diu_mem=%p\n", diu_ops.diu_mem); - - rh_init(&diu_ops.diu_rh_info, 4096, ARRAY_SIZE(diu_ops.diu_rh_block), - diu_ops.diu_rh_block); - return rh_attach_region(&diu_ops.diu_rh_info, - (unsigned long) diu_ops.diu_mem, - diu_ops.diu_size); -} - -static int __init early_parse_diufb(char *p) -{ - if (!p) - return 1; - - diu_ops.diu_size = _ALIGN_UP(memparse(p, &p), 8); - - pr_debug("diu_size=%lu\n", diu_ops.diu_size); - - return 0; -} -early_param("diufb", early_parse_diufb); - #endif diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index 02429988735..60f7f227327 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h @@ -20,14 +20,7 @@ extern int fsl_spi_init(struct spi_board_info *board_infos, extern void fsl_rstcr_restart(char *cmd); #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) -#include <linux/bootmem.h> -#include <asm/rheap.h> struct platform_diu_data_ops { - rh_block_t diu_rh_block[16]; - rh_info_t diu_rh_info; - unsigned long diu_size; - void *diu_mem; - unsigned int (*get_pixel_format) (unsigned int bits_per_pixel, int monitor_port); void (*set_gamma_table) (int monitor_port, char *gamma_table_base); @@ -38,7 +31,6 @@ struct platform_diu_data_ops { }; extern struct platform_diu_data_ops diu_ops; -int __init preallocate_diu_videomemory(void); #endif #endif diff --git a/arch/powerpc/sysdev/grackle.c b/arch/powerpc/sysdev/grackle.c index d502927644c..5da37c2f22e 100644 --- a/arch/powerpc/sysdev/grackle.c +++ b/arch/powerpc/sysdev/grackle.c @@ -57,7 +57,7 @@ void __init setup_grackle(struct pci_controller *hose) { setup_indirect_pci(hose, 0xfec00000, 0xfee00000, 0); if (machine_is_compatible("PowerMac1,1")) - ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; + ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS); if (machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(hose, 1); #if 0 /* Disabled for now, HW problems ??? */ diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c new file mode 100644 index 00000000000..103eace3619 --- /dev/null +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c @@ -0,0 +1,171 @@ +/* + * GPIOs on MPC8349/8572/8610 and compatible + * + * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> + +#define MPC8XXX_GPIO_PINS 32 + +#define GPIO_DIR 0x00 +#define GPIO_ODR 0x04 +#define GPIO_DAT 0x08 +#define GPIO_IER 0x0c +#define GPIO_IMR 0x10 +#define GPIO_ICR 0x14 + +struct mpc8xxx_gpio_chip { + struct of_mm_gpio_chip mm_gc; + spinlock_t lock; + + /* + * shadowed data register to be able to clear/set output pins in + * open drain mode safely + */ + u32 data; +}; + +static inline u32 mpc8xxx_gpio2mask(unsigned int gpio) +{ + return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio); +} + +static inline struct mpc8xxx_gpio_chip * +to_mpc8xxx_gpio_chip(struct of_mm_gpio_chip *mm) +{ + return container_of(mm, struct mpc8xxx_gpio_chip, mm_gc); +} + +static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + + mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT); +} + +static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + + return in_be32(mm->regs + GPIO_DAT) & mpc8xxx_gpio2mask(gpio); +} + +static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + unsigned long flags; + + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + + if (val) + mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio); + else + mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(gpio); + + out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data); + + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); +} + +static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + unsigned long flags; + + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + + clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio)); + + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + + return 0; +} + +static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + unsigned long flags; + + mpc8xxx_gpio_set(gc, gpio, val); + + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + + setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio)); + + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + + return 0; +} + +static void __init mpc8xxx_add_controller(struct device_node *np) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc; + struct of_mm_gpio_chip *mm_gc; + struct of_gpio_chip *of_gc; + struct gpio_chip *gc; + int ret; + + mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL); + if (!mpc8xxx_gc) { + ret = -ENOMEM; + goto err; + } + + spin_lock_init(&mpc8xxx_gc->lock); + + mm_gc = &mpc8xxx_gc->mm_gc; + of_gc = &mm_gc->of_gc; + gc = &of_gc->gc; + + mm_gc->save_regs = mpc8xxx_gpio_save_regs; + of_gc->gpio_cells = 2; + gc->ngpio = MPC8XXX_GPIO_PINS; + gc->direction_input = mpc8xxx_gpio_dir_in; + gc->direction_output = mpc8xxx_gpio_dir_out; + gc->get = mpc8xxx_gpio_get; + gc->set = mpc8xxx_gpio_set; + + ret = of_mm_gpiochip_add(np, mm_gc); + if (ret) + goto err; + + return; + +err: + pr_err("%s: registration failed with status %d\n", + np->full_name, ret); + kfree(mpc8xxx_gc); + + return; +} + +static int __init mpc8xxx_add_gpiochips(void) +{ + struct device_node *np; + + for_each_compatible_node(np, NULL, "fsl,mpc8349-gpio") + mpc8xxx_add_controller(np); + + for_each_compatible_node(np, NULL, "fsl,mpc8572-gpio") + mpc8xxx_add_controller(np); + + for_each_compatible_node(np, NULL, "fsl,mpc8610-gpio") + mpc8xxx_add_controller(np); + + return 0; +} +arch_initcall(mpc8xxx_add_gpiochips); diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 8e3478c995e..c82babb7007 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -563,6 +563,51 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) #endif /* CONFIG_MPIC_U3_HT_IRQS */ +#ifdef CONFIG_SMP +static int irq_choose_cpu(unsigned int virt_irq) +{ + cpumask_t mask = irq_desc[virt_irq].affinity; + int cpuid; + + if (cpus_equal(mask, CPU_MASK_ALL)) { + static int irq_rover; + static DEFINE_SPINLOCK(irq_rover_lock); + unsigned long flags; + + /* Round-robin distribution... */ + do_round_robin: + spin_lock_irqsave(&irq_rover_lock, flags); + + while (!cpu_online(irq_rover)) { + if (++irq_rover >= NR_CPUS) + irq_rover = 0; + } + cpuid = irq_rover; + do { + if (++irq_rover >= NR_CPUS) + irq_rover = 0; + } while (!cpu_online(irq_rover)); + + spin_unlock_irqrestore(&irq_rover_lock, flags); + } else { + cpumask_t tmp; + + cpus_and(tmp, cpu_online_map, mask); + + if (cpus_empty(tmp)) + goto do_round_robin; + + cpuid = first_cpu(tmp); + } + + return get_hard_smp_processor_id(cpuid); +} +#else +static int irq_choose_cpu(unsigned int virt_irq) +{ + return hard_smp_processor_id(); +} +#endif #define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) @@ -616,17 +661,6 @@ static inline void mpic_eoi(struct mpic *mpic) (void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI)); } -#ifdef CONFIG_SMP -static irqreturn_t mpic_ipi_action(int irq, void *data) -{ - long ipi = (long)data; - - smp_message_recv(ipi); - - return IRQ_HANDLED; -} -#endif /* CONFIG_SMP */ - /* * Linux descriptor level callbacks */ @@ -777,12 +811,18 @@ void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) struct mpic *mpic = mpic_from_irq(irq); unsigned int src = mpic_irq_to_hw(irq); - cpumask_t tmp; + if (mpic->flags & MPIC_SINGLE_DEST_CPU) { + int cpuid = irq_choose_cpu(irq); - cpus_and(tmp, cpumask, cpu_online_map); + mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); + } else { + cpumask_t tmp; + + cpus_and(tmp, cpumask, cpu_online_map); - mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), - mpic_physmask(cpus_addr(tmp)[0])); + mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), + mpic_physmask(cpus_addr(tmp)[0])); + } } static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) @@ -1220,6 +1260,7 @@ void __init mpic_set_default_senses(struct mpic *mpic, u8 *senses, int count) void __init mpic_init(struct mpic *mpic) { int i; + int cpu; BUG_ON(mpic->num_sources == 0); @@ -1262,6 +1303,11 @@ void __init mpic_init(struct mpic *mpic) mpic_pasemi_msi_init(mpic); + if (mpic->flags & MPIC_PRIMARY) + cpu = hard_smp_processor_id(); + else + cpu = 0; + for (i = 0; i < mpic->num_sources; i++) { /* start with vector = source number, and masked */ u32 vecpri = MPIC_VECPRI_MASK | i | @@ -1272,8 +1318,7 @@ void __init mpic_init(struct mpic *mpic) continue; /* init hw */ mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); - mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), - 1 << hard_smp_processor_id()); + mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); } /* Init spurious vector */ @@ -1492,13 +1537,7 @@ unsigned int mpic_get_mcirq(void) void mpic_request_ipis(void) { struct mpic *mpic = mpic_primary; - long i, err; - static char *ipi_names[] = { - "IPI0 (call function)", - "IPI1 (reschedule)", - "IPI2 (call function single)", - "IPI3 (debugger break)", - }; + int i; BUG_ON(mpic == NULL); printk(KERN_INFO "mpic: requesting IPIs ... \n"); @@ -1507,17 +1546,10 @@ void mpic_request_ipis(void) unsigned int vipi = irq_create_mapping(mpic->irqhost, mpic->ipi_vecs[0] + i); if (vipi == NO_IRQ) { - printk(KERN_ERR "Failed to map IPI %ld\n", i); - break; - } - err = request_irq(vipi, mpic_ipi_action, - IRQF_DISABLED|IRQF_PERCPU, - ipi_names[i], (void *)i); - if (err) { - printk(KERN_ERR "Request of irq %d for IPI %ld failed\n", - vipi, i); - break; + printk(KERN_ERR "Failed to map %s\n", smp_ipi_name[i]); + continue; } + smp_request_message_ipi(vipi, i); } } diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h index fbf8a266941..6209c62a426 100644 --- a/arch/powerpc/sysdev/mpic.h +++ b/arch/powerpc/sysdev/mpic.h @@ -14,8 +14,6 @@ #ifdef CONFIG_PCI_MSI extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq); extern int mpic_msi_init_allocator(struct mpic *mpic); -extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num); -extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num); extern int mpic_u3msi_init(struct mpic *mpic); extern int mpic_pasemi_msi_init(struct mpic *mpic); #else diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c index de3e5e8bc32..1d44eee80fa 100644 --- a/arch/powerpc/sysdev/mpic_msi.c +++ b/arch/powerpc/sysdev/mpic_msi.c @@ -15,59 +15,17 @@ #include <asm/prom.h> #include <asm/hw_irq.h> #include <asm/ppc-pci.h> +#include <asm/msi_bitmap.h> #include <sysdev/mpic.h> -static void __mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq) -{ - pr_debug("mpic: reserving hwirq 0x%lx\n", hwirq); - bitmap_allocate_region(mpic->hwirq_bitmap, hwirq, 0); -} - void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq) { - unsigned long flags; - /* The mpic calls this even when there is no allocator setup */ - if (!mpic->hwirq_bitmap) + if (!mpic->msi_bitmap.bitmap) return; - spin_lock_irqsave(&mpic->bitmap_lock, flags); - __mpic_msi_reserve_hwirq(mpic, hwirq); - spin_unlock_irqrestore(&mpic->bitmap_lock, flags); -} - -irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num) -{ - unsigned long flags; - int offset, order = get_count_order(num); - - spin_lock_irqsave(&mpic->bitmap_lock, flags); - /* - * This is fast, but stricter than we need. We might want to add - * a fallback routine which does a linear search with no alignment. - */ - offset = bitmap_find_free_region(mpic->hwirq_bitmap, mpic->irq_count, - order); - spin_unlock_irqrestore(&mpic->bitmap_lock, flags); - - pr_debug("mpic: allocated 0x%x (2^%d) at offset 0x%x\n", - num, order, offset); - - return offset; -} - -void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num) -{ - unsigned long flags; - int order = get_count_order(num); - - pr_debug("mpic: freeing 0x%x (2^%d) at offset 0x%x\n", - num, order, offset); - - spin_lock_irqsave(&mpic->bitmap_lock, flags); - bitmap_release_region(mpic->hwirq_bitmap, offset, order); - spin_unlock_irqrestore(&mpic->bitmap_lock, flags); + msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq); } #ifdef CONFIG_MPIC_U3_HT_IRQS @@ -83,13 +41,13 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) /* Reserve source numbers we know are reserved in the HW */ for (i = 0; i < 8; i++) - __mpic_msi_reserve_hwirq(mpic, i); + msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); for (i = 42; i < 46; i++) - __mpic_msi_reserve_hwirq(mpic, i); + msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); for (i = 100; i < 105; i++) - __mpic_msi_reserve_hwirq(mpic, i); + msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); np = NULL; while ((np = of_find_all_nodes(np))) { @@ -99,7 +57,7 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) while (of_irq_map_one(np, index++, &oirq) == 0) { ops->xlate(mpic->irqhost, NULL, oirq.specifier, oirq.size, &hwirq, &flags); - __mpic_msi_reserve_hwirq(mpic, hwirq); + msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq); } } @@ -112,70 +70,25 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) } #endif -static int mpic_msi_reserve_dt_hwirqs(struct mpic *mpic) -{ - int i, len; - const u32 *p; - - p = of_get_property(mpic->irqhost->of_node, - "msi-available-ranges", &len); - if (!p) { - pr_debug("mpic: no msi-available-ranges property found on %s\n", - mpic->irqhost->of_node->full_name); - return -ENODEV; - } - - if (len % 8 != 0) { - printk(KERN_WARNING "mpic: Malformed msi-available-ranges " - "property on %s\n", mpic->irqhost->of_node->full_name); - return -EINVAL; - } - - bitmap_allocate_region(mpic->hwirq_bitmap, 0, - get_count_order(mpic->irq_count)); - - /* Format is: (<u32 start> <u32 count>)+ */ - len /= sizeof(u32); - for (i = 0; i < len / 2; i++, p += 2) - mpic_msi_free_hwirqs(mpic, *p, *(p + 1)); - - return 0; -} - int mpic_msi_init_allocator(struct mpic *mpic) { - int rc, size; - - BUG_ON(mpic->hwirq_bitmap); - spin_lock_init(&mpic->bitmap_lock); + int rc; - size = BITS_TO_LONGS(mpic->irq_count) * sizeof(long); - pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size); + rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count, + mpic->irqhost->of_node); + if (rc) + return rc; - mpic->hwirq_bitmap = alloc_maybe_bootmem(size, GFP_KERNEL); - - if (!mpic->hwirq_bitmap) { - pr_debug("mpic: ENOMEM allocating allocator bitmap!\n"); - return -ENOMEM; - } - - memset(mpic->hwirq_bitmap, 0, size); - - rc = mpic_msi_reserve_dt_hwirqs(mpic); - if (rc) { + rc = msi_bitmap_reserve_dt_hwirqs(&mpic->msi_bitmap); + if (rc > 0) { if (mpic->flags & MPIC_U3_HT_IRQS) rc = mpic_msi_reserve_u3_hwirqs(mpic); - if (rc) - goto out_free; + if (rc) { + msi_bitmap_free(&mpic->msi_bitmap); + return rc; + } } return 0; - - out_free: - if (mem_init_done) - kfree(mpic->hwirq_bitmap); - - mpic->hwirq_bitmap = NULL; - return rc; } diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c index 68aff607667..656cb772b69 100644 --- a/arch/powerpc/sysdev/mpic_pasemi_msi.c +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c @@ -22,6 +22,7 @@ #include <asm/prom.h> #include <asm/hw_irq.h> #include <asm/ppc-pci.h> +#include <asm/msi_bitmap.h> #include "mpic.h" @@ -81,8 +82,8 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) continue; set_irq_msi(entry->irq, NULL); - mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), - ALLOC_CHUNK); + msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, + virq_to_hw(entry->irq), ALLOC_CHUNK); irq_dispose_mapping(entry->irq); } @@ -91,11 +92,10 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) { - irq_hw_number_t hwirq; unsigned int virq; struct msi_desc *entry; struct msi_msg msg; - int ret; + int hwirq; pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n", pdev, nvec, type); @@ -109,17 +109,19 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) * few MSIs for someone, but restrictions will apply to how the * sources can be changed independently. */ - ret = mpic_msi_alloc_hwirqs(msi_mpic, ALLOC_CHUNK); - hwirq = ret; - if (ret < 0) { + hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, + ALLOC_CHUNK); + if (hwirq < 0) { pr_debug("pasemi_msi: failed allocating hwirq\n"); return hwirq; } virq = irq_create_mapping(msi_mpic->irqhost, hwirq); if (virq == NO_IRQ) { - pr_debug("pasemi_msi: failed mapping hwirq 0x%lx\n", hwirq); - mpic_msi_free_hwirqs(msi_mpic, hwirq, ALLOC_CHUNK); + pr_debug("pasemi_msi: failed mapping hwirq 0x%x\n", + hwirq); + msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, + ALLOC_CHUNK); return -ENOSPC; } @@ -133,8 +135,8 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) set_irq_chip(virq, &mpic_pasemi_msi_chip); set_irq_type(virq, IRQ_TYPE_EDGE_RISING); - pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%lx) addr 0x%x\n", - virq, hwirq, msg.address_lo); + pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%x) " \ + "addr 0x%x\n", virq, hwirq, msg.address_lo); /* Likewise, the device writes [0...511] into the target * register to generate MSI [512...1023] diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c index 6e2f8686fdf..0a8f5a9e87c 100644 --- a/arch/powerpc/sysdev/mpic_u3msi.c +++ b/arch/powerpc/sysdev/mpic_u3msi.c @@ -16,6 +16,7 @@ #include <asm/prom.h> #include <asm/hw_irq.h> #include <asm/ppc-pci.h> +#include <asm/msi_bitmap.h> #include "mpic.h" @@ -101,7 +102,8 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) continue; set_irq_msi(entry->irq, NULL); - mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), 1); + msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, + virq_to_hw(entry->irq), 1); irq_dispose_mapping(entry->irq); } @@ -110,29 +112,27 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) { - irq_hw_number_t hwirq; unsigned int virq; struct msi_desc *entry; struct msi_msg msg; u64 addr; - int ret; + int hwirq; addr = find_ht_magic_addr(pdev); msg.address_lo = addr & 0xFFFFFFFF; msg.address_hi = addr >> 32; list_for_each_entry(entry, &pdev->msi_list, list) { - ret = mpic_msi_alloc_hwirqs(msi_mpic, 1); - if (ret < 0) { + hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1); + if (hwirq < 0) { pr_debug("u3msi: failed allocating hwirq\n"); - return ret; + return hwirq; } - hwirq = ret; virq = irq_create_mapping(msi_mpic->irqhost, hwirq); if (virq == NO_IRQ) { - pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq); - mpic_msi_free_hwirqs(msi_mpic, hwirq, 1); + pr_debug("u3msi: failed mapping hwirq 0x%x\n", hwirq); + msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, 1); return -ENOSPC; } @@ -140,8 +140,8 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) set_irq_chip(virq, &mpic_u3msi_chip); set_irq_type(virq, IRQ_TYPE_EDGE_RISING); - pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) addr 0x%lx\n", - virq, hwirq, addr); + pr_debug("u3msi: allocated virq 0x%x (hw 0x%x) addr 0x%lx\n", + virq, hwirq, (unsigned long)addr); msg.data = hwirq; write_msi_msg(virq, &msg); diff --git a/arch/powerpc/sysdev/msi_bitmap.c b/arch/powerpc/sysdev/msi_bitmap.c new file mode 100644 index 00000000000..f84217b8863 --- /dev/null +++ b/arch/powerpc/sysdev/msi_bitmap.c @@ -0,0 +1,247 @@ +/* + * Copyright 2006-2008, Michael Ellerman, IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 of the + * License. + * + */ + +#include <linux/kernel.h> +#include <linux/bitmap.h> +#include <asm/msi_bitmap.h> + +int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num) +{ + unsigned long flags; + int offset, order = get_count_order(num); + + spin_lock_irqsave(&bmp->lock, flags); + /* + * This is fast, but stricter than we need. We might want to add + * a fallback routine which does a linear search with no alignment. + */ + offset = bitmap_find_free_region(bmp->bitmap, bmp->irq_count, order); + spin_unlock_irqrestore(&bmp->lock, flags); + + pr_debug("msi_bitmap: allocated 0x%x (2^%d) at offset 0x%x\n", + num, order, offset); + + return offset; +} + +void msi_bitmap_free_hwirqs(struct msi_bitmap *bmp, unsigned int offset, + unsigned int num) +{ + unsigned long flags; + int order = get_count_order(num); + + pr_debug("msi_bitmap: freeing 0x%x (2^%d) at offset 0x%x\n", + num, order, offset); + + spin_lock_irqsave(&bmp->lock, flags); + bitmap_release_region(bmp->bitmap, offset, order); + spin_unlock_irqrestore(&bmp->lock, flags); +} + +void msi_bitmap_reserve_hwirq(struct msi_bitmap *bmp, unsigned int hwirq) +{ + unsigned long flags; + + pr_debug("msi_bitmap: reserving hwirq 0x%x\n", hwirq); + + spin_lock_irqsave(&bmp->lock, flags); + bitmap_allocate_region(bmp->bitmap, hwirq, 0); + spin_unlock_irqrestore(&bmp->lock, flags); +} + +/** + * msi_bitmap_reserve_dt_hwirqs - Reserve irqs specified in the device tree. + * @bmp: pointer to the MSI bitmap. + * + * Looks in the device tree to see if there is a property specifying which + * irqs can be used for MSI. If found those irqs reserved in the device tree + * are reserved in the bitmap. + * + * Returns 0 for success, < 0 if there was an error, and > 0 if no property + * was found in the device tree. + **/ +int msi_bitmap_reserve_dt_hwirqs(struct msi_bitmap *bmp) +{ + int i, j, len; + const u32 *p; + + if (!bmp->of_node) + return 1; + + p = of_get_property(bmp->of_node, "msi-available-ranges", &len); + if (!p) { + pr_debug("msi_bitmap: no msi-available-ranges property " \ + "found on %s\n", bmp->of_node->full_name); + return 1; + } + + if (len % (2 * sizeof(u32)) != 0) { + printk(KERN_WARNING "msi_bitmap: Malformed msi-available-ranges" + " property on %s\n", bmp->of_node->full_name); + return -EINVAL; + } + + bitmap_allocate_region(bmp->bitmap, 0, get_count_order(bmp->irq_count)); + + spin_lock(&bmp->lock); + + /* Format is: (<u32 start> <u32 count>)+ */ + len /= 2 * sizeof(u32); + for (i = 0; i < len; i++, p += 2) { + for (j = 0; j < *(p + 1); j++) + bitmap_release_region(bmp->bitmap, *p + j, 0); + } + + spin_unlock(&bmp->lock); + + return 0; +} + +int msi_bitmap_alloc(struct msi_bitmap *bmp, unsigned int irq_count, + struct device_node *of_node) +{ + int size; + + if (!irq_count) + return -EINVAL; + + size = BITS_TO_LONGS(irq_count) * sizeof(long); + pr_debug("msi_bitmap: allocator bitmap size is 0x%x bytes\n", size); + + bmp->bitmap = zalloc_maybe_bootmem(size, GFP_KERNEL); + if (!bmp->bitmap) { + pr_debug("msi_bitmap: ENOMEM allocating allocator bitmap!\n"); + return -ENOMEM; + } + + /* We zalloc'ed the bitmap, so all irqs are free by default */ + spin_lock_init(&bmp->lock); + bmp->of_node = of_node_get(of_node); + bmp->irq_count = irq_count; + + return 0; +} + +void msi_bitmap_free(struct msi_bitmap *bmp) +{ + /* we can't free the bitmap we don't know if it's bootmem etc. */ + of_node_put(bmp->of_node); + bmp->bitmap = NULL; +} + +#ifdef CONFIG_MSI_BITMAP_SELFTEST + +#define check(x) \ + if (!(x)) printk("msi_bitmap: test failed at line %d\n", __LINE__); + +void test_basics(void) +{ + struct msi_bitmap bmp; + int i, size = 512; + + /* Can't allocate a bitmap of 0 irqs */ + check(msi_bitmap_alloc(&bmp, 0, NULL) != 0); + + /* of_node may be NULL */ + check(0 == msi_bitmap_alloc(&bmp, size, NULL)); + + /* Should all be free by default */ + check(0 == bitmap_find_free_region(bmp.bitmap, size, + get_count_order(size))); + bitmap_release_region(bmp.bitmap, 0, get_count_order(size)); + + /* With no node, there's no msi-available-ranges, so expect > 0 */ + check(msi_bitmap_reserve_dt_hwirqs(&bmp) > 0); + + /* Should all still be free */ + check(0 == bitmap_find_free_region(bmp.bitmap, size, + get_count_order(size))); + bitmap_release_region(bmp.bitmap, 0, get_count_order(size)); + + /* Check we can fill it up and then no more */ + for (i = 0; i < size; i++) + check(msi_bitmap_alloc_hwirqs(&bmp, 1) >= 0); + + check(msi_bitmap_alloc_hwirqs(&bmp, 1) < 0); + + /* Should all be allocated */ + check(bitmap_find_free_region(bmp.bitmap, size, 0) < 0); + + /* And if we free one we can then allocate another */ + msi_bitmap_free_hwirqs(&bmp, size / 2, 1); + check(msi_bitmap_alloc_hwirqs(&bmp, 1) == size / 2); + + msi_bitmap_free(&bmp); + + /* Clients may check bitmap == NULL for "not-allocated" */ + check(bmp.bitmap == NULL); + + kfree(bmp.bitmap); +} + +void test_of_node(void) +{ + u32 prop_data[] = { 10, 10, 25, 3, 40, 1, 100, 100, 200, 20 }; + const char *expected_str = "0-9,20-24,28-39,41-99,220-255"; + char *prop_name = "msi-available-ranges"; + char *node_name = "/fakenode"; + struct device_node of_node; + struct property prop; + struct msi_bitmap bmp; + int size = 256; + DECLARE_BITMAP(expected, size); + + /* There should really be a struct device_node allocator */ + memset(&of_node, 0, sizeof(of_node)); + kref_init(&of_node.kref); + of_node.full_name = node_name; + + check(0 == msi_bitmap_alloc(&bmp, size, &of_node)); + + /* No msi-available-ranges, so expect > 0 */ + check(msi_bitmap_reserve_dt_hwirqs(&bmp) > 0); + + /* Should all still be free */ + check(0 == bitmap_find_free_region(bmp.bitmap, size, + get_count_order(size))); + bitmap_release_region(bmp.bitmap, 0, get_count_order(size)); + + /* Now create a fake msi-available-ranges property */ + + /* There should really .. oh whatever */ + memset(&prop, 0, sizeof(prop)); + prop.name = prop_name; + prop.value = &prop_data; + prop.length = sizeof(prop_data); + + of_node.properties = ∝ + + /* msi-available-ranges, so expect == 0 */ + check(msi_bitmap_reserve_dt_hwirqs(&bmp) == 0); + + /* Check we got the expected result */ + check(0 == bitmap_parselist(expected_str, expected, size)); + check(bitmap_equal(expected, bmp.bitmap, size)); + + msi_bitmap_free(&bmp); + kfree(bmp.bitmap); +} + +int msi_bitmap_selftest(void) +{ + printk(KERN_DEBUG "Running MSI bitmap self-tests ...\n"); + + test_basics(); + test_of_node(); + + return 0; +} +late_initcall(msi_bitmap_selftest); +#endif /* CONFIG_MSI_BITMAP_SELFTEST */ diff --git a/arch/powerpc/sysdev/ppc4xx_gpio.c b/arch/powerpc/sysdev/ppc4xx_gpio.c new file mode 100644 index 00000000000..110efe2a54f --- /dev/null +++ b/arch/powerpc/sysdev/ppc4xx_gpio.c @@ -0,0 +1,217 @@ +/* + * PPC4xx gpio driver + * + * Copyright (c) 2008 Harris Corporation + * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * Copyright (c) MontaVista Software, Inc. 2008. + * + * Author: Steve Falco <sfalco@harris.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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> +#include <linux/types.h> + +#define GPIO_MASK(gpio) (0x80000000 >> (gpio)) +#define GPIO_MASK2(gpio) (0xc0000000 >> ((gpio) * 2)) + +/* Physical GPIO register layout */ +struct ppc4xx_gpio { + __be32 or; + __be32 tcr; + __be32 osrl; + __be32 osrh; + __be32 tsrl; + __be32 tsrh; + __be32 odr; + __be32 ir; + __be32 rr1; + __be32 rr2; + __be32 rr3; + __be32 reserved1; + __be32 isr1l; + __be32 isr1h; + __be32 isr2l; + __be32 isr2h; + __be32 isr3l; + __be32 isr3h; +}; + +struct ppc4xx_gpio_chip { + struct of_mm_gpio_chip mm_gc; + spinlock_t lock; +}; + +/* + * GPIO LIB API implementation for GPIOs + * + * There are a maximum of 32 gpios in each gpio controller. + */ + +static inline struct ppc4xx_gpio_chip * +to_ppc4xx_gpiochip(struct of_mm_gpio_chip *mm_gc) +{ + return container_of(mm_gc, struct ppc4xx_gpio_chip, mm_gc); +} + +static int ppc4xx_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct ppc4xx_gpio __iomem *regs = mm_gc->regs; + + return in_be32(®s->ir) & GPIO_MASK(gpio); +} + +static inline void +__ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct ppc4xx_gpio __iomem *regs = mm_gc->regs; + + if (val) + setbits32(®s->or, GPIO_MASK(gpio)); + else + clrbits32(®s->or, GPIO_MASK(gpio)); +} + +static void +ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct ppc4xx_gpio_chip *chip = to_ppc4xx_gpiochip(mm_gc); + unsigned long flags; + + spin_lock_irqsave(&chip->lock, flags); + + __ppc4xx_gpio_set(gc, gpio, val); + + spin_unlock_irqrestore(&chip->lock, flags); + + pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val); +} + +static int ppc4xx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct ppc4xx_gpio_chip *chip = to_ppc4xx_gpiochip(mm_gc); + struct ppc4xx_gpio __iomem *regs = mm_gc->regs; + unsigned long flags; + + spin_lock_irqsave(&chip->lock, flags); + + /* Disable open-drain function */ + clrbits32(®s->odr, GPIO_MASK(gpio)); + + /* Float the pin */ + clrbits32(®s->tcr, GPIO_MASK(gpio)); + + /* Bits 0-15 use TSRL/OSRL, bits 16-31 use TSRH/OSRH */ + if (gpio < 16) { + clrbits32(®s->osrl, GPIO_MASK2(gpio)); + clrbits32(®s->tsrl, GPIO_MASK2(gpio)); + } else { + clrbits32(®s->osrh, GPIO_MASK2(gpio)); + clrbits32(®s->tsrh, GPIO_MASK2(gpio)); + } + + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int +ppc4xx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct ppc4xx_gpio_chip *chip = to_ppc4xx_gpiochip(mm_gc); + struct ppc4xx_gpio __iomem *regs = mm_gc->regs; + unsigned long flags; + + spin_lock_irqsave(&chip->lock, flags); + + /* First set initial value */ + __ppc4xx_gpio_set(gc, gpio, val); + + /* Disable open-drain function */ + clrbits32(®s->odr, GPIO_MASK(gpio)); + + /* Drive the pin */ + setbits32(®s->tcr, GPIO_MASK(gpio)); + + /* Bits 0-15 use TSRL, bits 16-31 use TSRH */ + if (gpio < 16) { + clrbits32(®s->osrl, GPIO_MASK2(gpio)); + clrbits32(®s->tsrl, GPIO_MASK2(gpio)); + } else { + clrbits32(®s->osrh, GPIO_MASK2(gpio)); + clrbits32(®s->tsrh, GPIO_MASK2(gpio)); + } + + spin_unlock_irqrestore(&chip->lock, flags); + + pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val); + + return 0; +} + +static int __init ppc4xx_add_gpiochips(void) +{ + struct device_node *np; + + for_each_compatible_node(np, NULL, "ibm,ppc4xx-gpio") { + int ret; + struct ppc4xx_gpio_chip *ppc4xx_gc; + struct of_mm_gpio_chip *mm_gc; + struct of_gpio_chip *of_gc; + struct gpio_chip *gc; + + ppc4xx_gc = kzalloc(sizeof(*ppc4xx_gc), GFP_KERNEL); + if (!ppc4xx_gc) { + ret = -ENOMEM; + goto err; + } + + spin_lock_init(&ppc4xx_gc->lock); + + mm_gc = &ppc4xx_gc->mm_gc; + of_gc = &mm_gc->of_gc; + gc = &of_gc->gc; + + of_gc->gpio_cells = 2; + gc->ngpio = 32; + gc->direction_input = ppc4xx_gpio_dir_in; + gc->direction_output = ppc4xx_gpio_dir_out; + gc->get = ppc4xx_gpio_get; + gc->set = ppc4xx_gpio_set; + + ret = of_mm_gpiochip_add(np, mm_gc); + if (ret) + goto err; + continue; +err: + pr_err("%s: registration failed with status %d\n", + np->full_name, ret); + kfree(ppc4xx_gc); + /* try others anyway */ + } + return 0; +} +arch_initcall(ppc4xx_add_gpiochips); diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index fb368dfde5d..77fae5f64f2 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -30,24 +30,19 @@ #include <asm/machdep.h> #include <asm/dcr.h> #include <asm/dcr-regs.h> +#include <mm/mmu_decl.h> #include "ppc4xx_pci.h" static int dma_offset_set; -/* Move that to a useable header */ -extern unsigned long total_memory; - #define U64_TO_U32_LOW(val) ((u32)((val) & 0x00000000ffffffffULL)) #define U64_TO_U32_HIGH(val) ((u32)((val) >> 32)) -#ifdef CONFIG_RESOURCES_64BIT -#define RES_TO_U32_LOW(val) U64_TO_U32_LOW(val) -#define RES_TO_U32_HIGH(val) U64_TO_U32_HIGH(val) -#else -#define RES_TO_U32_LOW(val) (val) -#define RES_TO_U32_HIGH(val) (0) -#endif +#define RES_TO_U32_LOW(val) \ + ((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_LOW(val) : (val)) +#define RES_TO_U32_HIGH(val) \ + ((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_HIGH(val) : (0)) static inline int ppc440spe_revA(void) { @@ -105,7 +100,8 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, /* Default */ res->start = 0; - res->end = size = 0x80000000; + size = 0x80000000; + res->end = size - 1; res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; /* Get dma-ranges property */ @@ -145,12 +141,11 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, /* Use that */ res->start = pci_addr; -#ifndef CONFIG_RESOURCES_64BIT /* Beware of 32 bits resources */ - if ((pci_addr + size) > 0x100000000ull) + if (sizeof(resource_size_t) == sizeof(u32) && + (pci_addr + size) > 0x100000000ull) res->end = 0xffffffff; else -#endif res->end = res->start + size - 1; break; } @@ -167,13 +162,13 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, */ if (size < total_memory) { printk(KERN_ERR "%s: dma-ranges too small " - "(size=%llx total_memory=%lx)\n", - hose->dn->full_name, size, total_memory); + "(size=%llx total_memory=%llx)\n", + hose->dn->full_name, size, (u64)total_memory); return -ENXIO; } /* Check we are a power of 2 size and that base is a multiple of size*/ - if (!is_power_of_2(size) || + if ((size & (size - 1)) != 0 || (res->start & (size - 1)) != 0) { printk(KERN_ERR "%s: dma-ranges unaligned\n", hose->dn->full_name); @@ -199,11 +194,41 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, * 4xx PCI 2.x part */ +static int __init ppc4xx_setup_one_pci_PMM(struct pci_controller *hose, + void __iomem *reg, + u64 plb_addr, + u64 pci_addr, + u64 size, + unsigned int flags, + int index) +{ + u32 ma, pcila, pciha; + + if ((plb_addr + size) > 0xffffffffull || !is_power_of_2(size) || + size < 0x1000 || (plb_addr & (size - 1)) != 0) { + printk(KERN_WARNING "%s: Resource out of range\n", + hose->dn->full_name); + return -1; + } + ma = (0xffffffffu << ilog2(size)) | 1; + if (flags & IORESOURCE_PREFETCH) + ma |= 2; + + pciha = RES_TO_U32_HIGH(pci_addr); + pcila = RES_TO_U32_LOW(pci_addr); + + writel(plb_addr, reg + PCIL0_PMM0LA + (0x10 * index)); + writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * index)); + writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * index)); + writel(ma, reg + PCIL0_PMM0MA + (0x10 * index)); + + return 0; +} + static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, void __iomem *reg) { - u32 la, ma, pcila, pciha; - int i, j; + int i, j, found_isa_hole = 0; /* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { @@ -218,28 +243,29 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, break; } - /* Calculate register values */ - la = res->start; - pciha = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); - pcila = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); - - ma = res->end + 1 - res->start; - if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) { - printk(KERN_WARNING "%s: Resource out of range\n", - hose->dn->full_name); - continue; + /* Configure the resource */ + if (ppc4xx_setup_one_pci_PMM(hose, reg, + res->start, + res->start - hose->pci_mem_offset, + res->end + 1 - res->start, + res->flags, + j) == 0) { + j++; + + /* If the resource PCI address is 0 then we have our + * ISA memory hole + */ + if (res->start == hose->pci_mem_offset) + found_isa_hole = 1; } - ma = (0xffffffffu << ilog2(ma)) | 0x1; - if (res->flags & IORESOURCE_PREFETCH) - ma |= 0x2; - - /* Program register values */ - writel(la, reg + PCIL0_PMM0LA + (0x10 * j)); - writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * j)); - writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * j)); - writel(ma, reg + PCIL0_PMM0MA + (0x10 * j)); - j++; } + + /* Handle ISA memory hole if not already covered */ + if (j <= 2 && !found_isa_hole && hose->isa_mem_size) + if (ppc4xx_setup_one_pci_PMM(hose, reg, hose->isa_mem_phys, 0, + hose->isa_mem_size, 0, j) == 0) + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", + hose->dn->full_name); } static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose, @@ -277,9 +303,16 @@ static void __init ppc4xx_probe_pci_bridge(struct device_node *np) const int *bus_range; int primary = 0; + /* Check if device is enabled */ + if (!of_device_is_available(np)) { + printk(KERN_INFO "%s: Port disabled via device-tree\n", + np->full_name); + return; + } + /* Fetch config space registers address */ if (of_address_to_resource(np, 0, &rsrc_cfg)) { - printk(KERN_ERR "%s:Can't get PCI config register base !", + printk(KERN_ERR "%s: Can't get PCI config register base !", np->full_name); return; } @@ -350,11 +383,52 @@ static void __init ppc4xx_probe_pci_bridge(struct device_node *np) * 4xx PCI-X part */ +static int __init ppc4xx_setup_one_pcix_POM(struct pci_controller *hose, + void __iomem *reg, + u64 plb_addr, + u64 pci_addr, + u64 size, + unsigned int flags, + int index) +{ + u32 lah, lal, pciah, pcial, sa; + + if (!is_power_of_2(size) || size < 0x1000 || + (plb_addr & (size - 1)) != 0) { + printk(KERN_WARNING "%s: Resource out of range\n", + hose->dn->full_name); + return -1; + } + + /* Calculate register values */ + lah = RES_TO_U32_HIGH(plb_addr); + lal = RES_TO_U32_LOW(plb_addr); + pciah = RES_TO_U32_HIGH(pci_addr); + pcial = RES_TO_U32_LOW(pci_addr); + sa = (0xffffffffu << ilog2(size)) | 0x1; + + /* Program register values */ + if (index == 0) { + writel(lah, reg + PCIX0_POM0LAH); + writel(lal, reg + PCIX0_POM0LAL); + writel(pciah, reg + PCIX0_POM0PCIAH); + writel(pcial, reg + PCIX0_POM0PCIAL); + writel(sa, reg + PCIX0_POM0SA); + } else { + writel(lah, reg + PCIX0_POM1LAH); + writel(lal, reg + PCIX0_POM1LAL); + writel(pciah, reg + PCIX0_POM1PCIAH); + writel(pcial, reg + PCIX0_POM1PCIAL); + writel(sa, reg + PCIX0_POM1SA); + } + + return 0; +} + static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, void __iomem *reg) { - u32 lah, lal, pciah, pcial, sa; - int i, j; + int i, j, found_isa_hole = 0; /* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { @@ -369,36 +443,29 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, break; } - /* Calculate register values */ - lah = RES_TO_U32_HIGH(res->start); - lal = RES_TO_U32_LOW(res->start); - pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); - pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); - sa = res->end + 1 - res->start; - if (!is_power_of_2(sa) || sa < 0x100000 || - sa > 0xffffffffu) { - printk(KERN_WARNING "%s: Resource out of range\n", - hose->dn->full_name); - continue; - } - sa = (0xffffffffu << ilog2(sa)) | 0x1; - - /* Program register values */ - if (j == 0) { - writel(lah, reg + PCIX0_POM0LAH); - writel(lal, reg + PCIX0_POM0LAL); - writel(pciah, reg + PCIX0_POM0PCIAH); - writel(pcial, reg + PCIX0_POM0PCIAL); - writel(sa, reg + PCIX0_POM0SA); - } else { - writel(lah, reg + PCIX0_POM1LAH); - writel(lal, reg + PCIX0_POM1LAL); - writel(pciah, reg + PCIX0_POM1PCIAH); - writel(pcial, reg + PCIX0_POM1PCIAL); - writel(sa, reg + PCIX0_POM1SA); + /* Configure the resource */ + if (ppc4xx_setup_one_pcix_POM(hose, reg, + res->start, + res->start - hose->pci_mem_offset, + res->end + 1 - res->start, + res->flags, + j) == 0) { + j++; + + /* If the resource PCI address is 0 then we have our + * ISA memory hole + */ + if (res->start == hose->pci_mem_offset) + found_isa_hole = 1; } - j++; } + + /* Handle ISA memory hole if not already covered */ + if (j <= 1 && !found_isa_hole && hose->isa_mem_size) + if (ppc4xx_setup_one_pcix_POM(hose, reg, hose->isa_mem_phys, 0, + hose->isa_mem_size, 0, j) == 0) + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", + hose->dn->full_name); } static void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose, @@ -810,7 +877,7 @@ static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) switch (port->index) { case 0: mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230); - mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000136); + mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130); mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006); mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST,0x10000000); @@ -821,10 +888,10 @@ static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) mtdcri(SDR0, PESDR1_460EX_L1CDRCTL, 0x00003230); mtdcri(SDR0, PESDR1_460EX_L2CDRCTL, 0x00003230); mtdcri(SDR0, PESDR1_460EX_L3CDRCTL, 0x00003230); - mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000136); - mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000136); - mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000136); - mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000136); + mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000130); + mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000130); + mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000130); + mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000130); mtdcri(SDR0, PESDR1_460EX_L0CLK, 0x00000006); mtdcri(SDR0, PESDR1_460EX_L1CLK, 0x00000006); mtdcri(SDR0, PESDR1_460EX_L2CLK, 0x00000006); @@ -1315,12 +1382,72 @@ static struct pci_ops ppc4xx_pciex_pci_ops = .write = ppc4xx_pciex_write_config, }; +static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, + struct pci_controller *hose, + void __iomem *mbase, + u64 plb_addr, + u64 pci_addr, + u64 size, + unsigned int flags, + int index) +{ + u32 lah, lal, pciah, pcial, sa; + + if (!is_power_of_2(size) || + (index < 2 && size < 0x100000) || + (index == 2 && size < 0x100) || + (plb_addr & (size - 1)) != 0) { + printk(KERN_WARNING "%s: Resource out of range\n", + hose->dn->full_name); + return -1; + } + + /* Calculate register values */ + lah = RES_TO_U32_HIGH(plb_addr); + lal = RES_TO_U32_LOW(plb_addr); + pciah = RES_TO_U32_HIGH(pci_addr); + pcial = RES_TO_U32_LOW(pci_addr); + sa = (0xffffffffu << ilog2(size)) | 0x1; + + /* Program register values */ + switch (index) { + case 0: + out_le32(mbase + PECFG_POM0LAH, pciah); + out_le32(mbase + PECFG_POM0LAL, pcial); + dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); + dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); + /* Note that 3 here means enabled | single region */ + dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); + break; + case 1: + out_le32(mbase + PECFG_POM1LAH, pciah); + out_le32(mbase + PECFG_POM1LAL, pcial); + dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); + dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); + dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); + /* Note that 3 here means enabled | single region */ + dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); + break; + case 2: + out_le32(mbase + PECFG_POM2LAH, pciah); + out_le32(mbase + PECFG_POM2LAL, pcial); + dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); + dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); + dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); + /* Note that 3 here means enabled | IO space !!! */ + dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, sa | 3); + break; + } + + return 0; +} + static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, struct pci_controller *hose, void __iomem *mbase) { - u32 lah, lal, pciah, pcial, sa; - int i, j; + int i, j, found_isa_hole = 0; /* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { @@ -1335,53 +1462,38 @@ static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, break; } - /* Calculate register values */ - lah = RES_TO_U32_HIGH(res->start); - lal = RES_TO_U32_LOW(res->start); - pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); - pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); - sa = res->end + 1 - res->start; - if (!is_power_of_2(sa) || sa < 0x100000 || - sa > 0xffffffffu) { - printk(KERN_WARNING "%s: Resource out of range\n", - port->node->full_name); - continue; + /* Configure the resource */ + if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, + res->start, + res->start - hose->pci_mem_offset, + res->end + 1 - res->start, + res->flags, + j) == 0) { + j++; + + /* If the resource PCI address is 0 then we have our + * ISA memory hole + */ + if (res->start == hose->pci_mem_offset) + found_isa_hole = 1; } - sa = (0xffffffffu << ilog2(sa)) | 0x1; - - /* Program register values */ - switch (j) { - case 0: - out_le32(mbase + PECFG_POM0LAH, pciah); - out_le32(mbase + PECFG_POM0LAL, pcial); - dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); - dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); - dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); - dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); - break; - case 1: - out_le32(mbase + PECFG_POM1LAH, pciah); - out_le32(mbase + PECFG_POM1LAL, pcial); - dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); - dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); - dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); - dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); - break; - } - j++; } - /* Configure IO, always 64K starting at 0 */ - if (hose->io_resource.flags & IORESOURCE_IO) { - lah = RES_TO_U32_HIGH(hose->io_base_phys); - lal = RES_TO_U32_LOW(hose->io_base_phys); - out_le32(mbase + PECFG_POM2LAH, 0); - out_le32(mbase + PECFG_POM2LAL, 0); - dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); - dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); - dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); - dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0xffff0000 | 3); - } + /* Handle ISA memory hole if not already covered */ + if (j <= 1 && !found_isa_hole && hose->isa_mem_size) + if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, + hose->isa_mem_phys, 0, + hose->isa_mem_size, 0, j) == 0) + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", + hose->dn->full_name); + + /* Configure IO, always 64K starting at 0. We hard wire it to 64K ! + * Note also that it -has- to be region index 2 on this HW + */ + if (hose->io_resource.flags & IORESOURCE_IO) + ppc4xx_setup_one_pciex_POM(port, hose, mbase, + hose->io_base_phys, 0, + 0x10000, IORESOURCE_IO, 2); } static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig index 1ce546462be..76ffbc48d4b 100644 --- a/arch/powerpc/sysdev/qe_lib/Kconfig +++ b/arch/powerpc/sysdev/qe_lib/Kconfig @@ -24,12 +24,3 @@ config QE_USB bool help QE USB Host Controller support - -config QE_GPIO - bool "QE GPIO support" - depends on QUICC_ENGINE - select GENERIC_GPIO - select ARCH_REQUIRE_GPIOLIB - help - Say Y here if you're going to use hardware that connects to the - QE GPIOs. diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index b3b73ae57d6..01bce3784b0 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/param.h> #include <linux/string.h> +#include <linux/spinlock.h> #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/bootmem.h> @@ -38,6 +39,8 @@ static void qe_snums_init(void); static int qe_sdma_init(void); static DEFINE_SPINLOCK(qe_lock); +DEFINE_SPINLOCK(cmxgcr_lock); +EXPORT_SYMBOL(cmxgcr_lock); /* QE snum state */ enum qe_snum_state { diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c index 1d78071aad7..ebb442ea191 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc.c +++ b/arch/powerpc/sysdev/qe_lib/ucc.c @@ -18,6 +18,7 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/stddef.h> +#include <linux/spinlock.h> #include <linux/module.h> #include <asm/irq.h> @@ -26,9 +27,6 @@ #include <asm/qe.h> #include <asm/ucc.h> -DEFINE_SPINLOCK(cmxgcr_lock); -EXPORT_SYMBOL(cmxgcr_lock); - int ucc_set_qe_mux_mii_mng(unsigned int ucc_num) { unsigned long flags; diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c index b7aefd0d45c..a22e1a2df1a 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c @@ -107,8 +107,8 @@ xilinx_intc_init(struct device_node *np) } regs = ioremap(res.start, 32); - printk(KERN_INFO "Xilinx intc at 0x%08LX mapped to 0x%p\n", - res.start, regs); + printk(KERN_INFO "Xilinx intc at 0x%08llx mapped to 0x%p\n", + (unsigned long long) res.start, regs); /* Setup interrupt controller */ out_be32(regs + XINTC_IER, 0); /* disable all irqs */ |