diff options
| author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
|---|---|---|
| committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
| commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
| tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/powerpc/sysdev | |
| parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
| parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) | |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'arch/powerpc/sysdev')
48 files changed, 3944 insertions, 1080 deletions
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 396582835cb5..7b4df37ac381 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig | |||
| @@ -7,8 +7,25 @@ config PPC4xx_PCI_EXPRESS | |||
| 7 | depends on PCI && 4xx | 7 | depends on PCI && 4xx |
| 8 | default n | 8 | default n |
| 9 | 9 | ||
| 10 | config PPC4xx_MSI | ||
| 11 | bool | ||
| 12 | depends on PCI_MSI | ||
| 13 | depends on PCI && 4xx | ||
| 14 | default n | ||
| 15 | |||
| 10 | config PPC_MSI_BITMAP | 16 | config PPC_MSI_BITMAP |
| 11 | bool | 17 | bool |
| 12 | depends on PCI_MSI | 18 | depends on PCI_MSI |
| 13 | default y if MPIC | 19 | default y if MPIC |
| 14 | default y if FSL_PCI | 20 | default y if FSL_PCI |
| 21 | default y if PPC4xx_MSI | ||
| 22 | |||
| 23 | source "arch/powerpc/sysdev/xics/Kconfig" | ||
| 24 | |||
| 25 | config PPC_SCOM | ||
| 26 | bool | ||
| 27 | |||
| 28 | config SCOM_DEBUGFS | ||
| 29 | bool "Expose SCOM controllers via debugfs" | ||
| 30 | depends on PPC_SCOM | ||
| 31 | default n | ||
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 5642924fb9fb..0efa990e3344 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror | 1 | subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror |
| 2 | 2 | ||
| 3 | ifeq ($(CONFIG_PPC64),y) | 3 | ccflags-$(CONFIG_PPC64) := -mno-minimal-toc |
| 4 | EXTRA_CFLAGS += -mno-minimal-toc | ||
| 5 | endif | ||
| 6 | 4 | ||
| 7 | mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o | 5 | mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o |
| 8 | obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) | 6 | obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) |
| @@ -20,8 +18,9 @@ obj-$(CONFIG_FSL_PMC) += fsl_pmc.o | |||
| 20 | obj-$(CONFIG_FSL_LBC) += fsl_lbc.o | 18 | obj-$(CONFIG_FSL_LBC) += fsl_lbc.o |
| 21 | obj-$(CONFIG_FSL_GTM) += fsl_gtm.o | 19 | obj-$(CONFIG_FSL_GTM) += fsl_gtm.o |
| 22 | obj-$(CONFIG_MPC8xxx_GPIO) += mpc8xxx_gpio.o | 20 | obj-$(CONFIG_MPC8xxx_GPIO) += mpc8xxx_gpio.o |
| 21 | obj-$(CONFIG_FSL_85XX_CACHE_SRAM) += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o | ||
| 23 | obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o | 22 | obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o |
| 24 | obj-$(CONFIG_RAPIDIO) += fsl_rio.o | 23 | obj-$(CONFIG_FSL_RIO) += fsl_rio.o |
| 25 | obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o | 24 | obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o |
| 26 | obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ | 25 | obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ |
| 27 | obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ | 26 | obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ |
| @@ -42,6 +41,8 @@ obj-$(CONFIG_OF_RTC) += of_rtc.o | |||
| 42 | ifeq ($(CONFIG_PCI),y) | 41 | ifeq ($(CONFIG_PCI),y) |
| 43 | obj-$(CONFIG_4xx) += ppc4xx_pci.o | 42 | obj-$(CONFIG_4xx) += ppc4xx_pci.o |
| 44 | endif | 43 | endif |
| 44 | obj-$(CONFIG_PPC4xx_MSI) += ppc4xx_msi.o | ||
| 45 | obj-$(CONFIG_PPC4xx_CPM) += ppc4xx_cpm.o | ||
| 45 | obj-$(CONFIG_PPC4xx_GPIO) += ppc4xx_gpio.o | 46 | obj-$(CONFIG_PPC4xx_GPIO) += ppc4xx_gpio.o |
| 46 | 47 | ||
| 47 | obj-$(CONFIG_CPM) += cpm_common.o | 48 | obj-$(CONFIG_CPM) += cpm_common.o |
| @@ -57,3 +58,9 @@ obj-$(CONFIG_PPC_MPC52xx) += mpc5xxx_clocks.o | |||
| 57 | ifeq ($(CONFIG_SUSPEND),y) | 58 | ifeq ($(CONFIG_SUSPEND),y) |
| 58 | obj-$(CONFIG_6xx) += 6xx-suspend.o | 59 | obj-$(CONFIG_6xx) += 6xx-suspend.o |
| 59 | endif | 60 | endif |
| 61 | |||
| 62 | obj-$(CONFIG_PPC_SCOM) += scom.o | ||
| 63 | |||
| 64 | subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror | ||
| 65 | |||
| 66 | obj-$(CONFIG_PPC_XICS) += xics/ | ||
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 2659a60bd7b8..bd0d54060b94 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c | |||
| @@ -95,7 +95,7 @@ axon_ram_irq_handler(int irq, void *dev) | |||
| 95 | 95 | ||
| 96 | BUG_ON(!bank); | 96 | BUG_ON(!bank); |
| 97 | 97 | ||
| 98 | dev_err(&device->dev, "Correctable memory error occured\n"); | 98 | dev_err(&device->dev, "Correctable memory error occurred\n"); |
| 99 | bank->ecc_counter++; | 99 | bank->ecc_counter++; |
| 100 | return IRQ_HANDLED; | 100 | return IRQ_HANDLED; |
| 101 | } | 101 | } |
| @@ -172,10 +172,9 @@ static const struct block_device_operations axon_ram_devops = { | |||
| 172 | 172 | ||
| 173 | /** | 173 | /** |
| 174 | * axon_ram_probe - probe() method for platform driver | 174 | * axon_ram_probe - probe() method for platform driver |
| 175 | * @device, @device_id: see of_platform_driver method | 175 | * @device: see platform_driver method |
| 176 | */ | 176 | */ |
| 177 | static int axon_ram_probe(struct platform_device *device, | 177 | static int axon_ram_probe(struct platform_device *device) |
| 178 | const struct of_device_id *device_id) | ||
| 179 | { | 178 | { |
| 180 | static int axon_ram_bank_id = -1; | 179 | static int axon_ram_bank_id = -1; |
| 181 | struct axon_ram_bank *bank; | 180 | struct axon_ram_bank *bank; |
| @@ -217,7 +216,7 @@ static int axon_ram_probe(struct platform_device *device, | |||
| 217 | AXON_RAM_DEVICE_NAME, axon_ram_bank_id, bank->size >> 20); | 216 | AXON_RAM_DEVICE_NAME, axon_ram_bank_id, bank->size >> 20); |
| 218 | 217 | ||
| 219 | bank->ph_addr = resource.start; | 218 | bank->ph_addr = resource.start; |
| 220 | bank->io_addr = (unsigned long) ioremap_flags( | 219 | bank->io_addr = (unsigned long) ioremap_prot( |
| 221 | bank->ph_addr, bank->size, _PAGE_NO_CACHE); | 220 | bank->ph_addr, bank->size, _PAGE_NO_CACHE); |
| 222 | if (bank->io_addr == 0) { | 221 | if (bank->io_addr == 0) { |
| 223 | dev_err(&device->dev, "ioremap() failed\n"); | 222 | dev_err(&device->dev, "ioremap() failed\n"); |
| @@ -326,7 +325,7 @@ static struct of_device_id axon_ram_device_id[] = { | |||
| 326 | {} | 325 | {} |
| 327 | }; | 326 | }; |
| 328 | 327 | ||
| 329 | static struct of_platform_driver axon_ram_driver = { | 328 | static struct platform_driver axon_ram_driver = { |
| 330 | .probe = axon_ram_probe, | 329 | .probe = axon_ram_probe, |
| 331 | .remove = axon_ram_remove, | 330 | .remove = axon_ram_remove, |
| 332 | .driver = { | 331 | .driver = { |
| @@ -350,7 +349,7 @@ axon_ram_init(void) | |||
| 350 | } | 349 | } |
| 351 | azfs_minor = 0; | 350 | azfs_minor = 0; |
| 352 | 351 | ||
| 353 | return of_register_platform_driver(&axon_ram_driver); | 352 | return platform_driver_register(&axon_ram_driver); |
| 354 | } | 353 | } |
| 355 | 354 | ||
| 356 | /** | 355 | /** |
| @@ -359,7 +358,7 @@ axon_ram_init(void) | |||
| 359 | static void __exit | 358 | static void __exit |
| 360 | axon_ram_exit(void) | 359 | axon_ram_exit(void) |
| 361 | { | 360 | { |
| 362 | of_unregister_platform_driver(&axon_ram_driver); | 361 | platform_driver_unregister(&axon_ram_driver); |
| 363 | unregister_blkdev(azfs_major, AXON_RAM_DEVICE_NAME); | 362 | unregister_blkdev(azfs_major, AXON_RAM_DEVICE_NAME); |
| 364 | } | 363 | } |
| 365 | 364 | ||
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c index 650256115064..b3fbb271be87 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm.c +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c | |||
| @@ -365,8 +365,7 @@ bcom_engine_cleanup(void) | |||
| 365 | /* OF platform driver */ | 365 | /* OF platform driver */ |
| 366 | /* ======================================================================== */ | 366 | /* ======================================================================== */ |
| 367 | 367 | ||
| 368 | static int __devinit mpc52xx_bcom_probe(struct platform_device *op, | 368 | static int __devinit mpc52xx_bcom_probe(struct platform_device *op) |
| 369 | const struct of_device_id *match) | ||
| 370 | { | 369 | { |
| 371 | struct device_node *ofn_sram; | 370 | struct device_node *ofn_sram; |
| 372 | struct resource res_bcom; | 371 | struct resource res_bcom; |
| @@ -492,7 +491,7 @@ static struct of_device_id mpc52xx_bcom_of_match[] = { | |||
| 492 | MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match); | 491 | MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match); |
| 493 | 492 | ||
| 494 | 493 | ||
| 495 | static struct of_platform_driver mpc52xx_bcom_of_platform_driver = { | 494 | static struct platform_driver mpc52xx_bcom_of_platform_driver = { |
| 496 | .probe = mpc52xx_bcom_probe, | 495 | .probe = mpc52xx_bcom_probe, |
| 497 | .remove = mpc52xx_bcom_remove, | 496 | .remove = mpc52xx_bcom_remove, |
| 498 | .driver = { | 497 | .driver = { |
| @@ -510,13 +509,13 @@ static struct of_platform_driver mpc52xx_bcom_of_platform_driver = { | |||
| 510 | static int __init | 509 | static int __init |
| 511 | mpc52xx_bcom_init(void) | 510 | mpc52xx_bcom_init(void) |
| 512 | { | 511 | { |
| 513 | return of_register_platform_driver(&mpc52xx_bcom_of_platform_driver); | 512 | return platform_driver_register(&mpc52xx_bcom_of_platform_driver); |
| 514 | } | 513 | } |
| 515 | 514 | ||
| 516 | static void __exit | 515 | static void __exit |
| 517 | mpc52xx_bcom_exit(void) | 516 | mpc52xx_bcom_exit(void) |
| 518 | { | 517 | { |
| 519 | of_unregister_platform_driver(&mpc52xx_bcom_of_platform_driver); | 518 | platform_driver_unregister(&mpc52xx_bcom_of_platform_driver); |
| 520 | } | 519 | } |
| 521 | 520 | ||
| 522 | /* If we're not a module, we must make sure everything is setup before */ | 521 | /* If we're not a module, we must make sure everything is setup before */ |
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.h b/arch/powerpc/sysdev/bestcomm/bestcomm.h index 23a95f80dfdb..a0e2e6b19b57 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm.h +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | * struct bcom_bd - Structure describing a generic BestComm buffer descriptor | 20 | * struct bcom_bd - Structure describing a generic BestComm buffer descriptor |
| 21 | * @status: The current status of this buffer. Exact meaning depends on the | 21 | * @status: The current status of this buffer. Exact meaning depends on the |
| 22 | * task type | 22 | * task type |
| 23 | * @data: An array of u32 extra data. Size of array is task dependant. | 23 | * @data: An array of u32 extra data. Size of array is task dependent. |
| 24 | * | 24 | * |
| 25 | * Note: Don't dereference a bcom_bd pointer as an array. The size of the | 25 | * Note: Don't dereference a bcom_bd pointer as an array. The size of the |
| 26 | * bcom_bd is variable. Use bcom_get_bd() instead. | 26 | * bcom_bd is variable. Use bcom_get_bd() instead. |
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h index eb0d1c883c31..3b52f3ffbdf8 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h +++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h | |||
| @@ -97,7 +97,7 @@ struct bcom_task_header { | |||
| 97 | u8 reserved[8]; | 97 | u8 reserved[8]; |
| 98 | }; | 98 | }; |
| 99 | 99 | ||
| 100 | /* Descriptors stucture & co */ | 100 | /* Descriptors structure & co */ |
| 101 | #define BCOM_DESC_NOP 0x000001f8 | 101 | #define BCOM_DESC_NOP 0x000001f8 |
| 102 | #define BCOM_LCD_MASK 0x80000000 | 102 | #define BCOM_LCD_MASK 0x80000000 |
| 103 | #define BCOM_DRD_EXTENDED 0x40000000 | 103 | #define BCOM_DRD_EXTENDED 0x40000000 |
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 00852124ff4a..350787c83e22 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c | |||
| @@ -56,32 +56,32 @@ static cpic8xx_t __iomem *cpic_reg; | |||
| 56 | 56 | ||
| 57 | static struct irq_host *cpm_pic_host; | 57 | static struct irq_host *cpm_pic_host; |
| 58 | 58 | ||
| 59 | static void cpm_mask_irq(unsigned int irq) | 59 | static void cpm_mask_irq(struct irq_data *d) |
| 60 | { | 60 | { |
| 61 | unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq; | 61 | unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); |
| 62 | 62 | ||
| 63 | clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); | 63 | clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | static void cpm_unmask_irq(unsigned int irq) | 66 | static void cpm_unmask_irq(struct irq_data *d) |
| 67 | { | 67 | { |
| 68 | unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq; | 68 | unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); |
| 69 | 69 | ||
| 70 | setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); | 70 | setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | static void cpm_end_irq(unsigned int irq) | 73 | static void cpm_end_irq(struct irq_data *d) |
| 74 | { | 74 | { |
| 75 | unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq; | 75 | unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); |
| 76 | 76 | ||
| 77 | out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec)); | 77 | out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec)); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | static struct irq_chip cpm_pic = { | 80 | static struct irq_chip cpm_pic = { |
| 81 | .name = "CPM PIC", | 81 | .name = "CPM PIC", |
| 82 | .mask = cpm_mask_irq, | 82 | .irq_mask = cpm_mask_irq, |
| 83 | .unmask = cpm_unmask_irq, | 83 | .irq_unmask = cpm_unmask_irq, |
| 84 | .eoi = cpm_end_irq, | 84 | .irq_eoi = cpm_end_irq, |
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | int cpm_get_irq(void) | 87 | int cpm_get_irq(void) |
| @@ -103,8 +103,8 @@ static int cpm_pic_host_map(struct irq_host *h, unsigned int virq, | |||
| 103 | { | 103 | { |
| 104 | pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); | 104 | pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); |
| 105 | 105 | ||
| 106 | irq_to_desc(virq)->status |= IRQ_LEVEL; | 106 | irq_set_status_flags(virq, IRQ_LEVEL); |
| 107 | set_irq_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq); | 107 | irq_set_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq); |
| 108 | return 0; | 108 | return 0; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| @@ -157,7 +157,7 @@ unsigned int cpm_pic_init(void) | |||
| 157 | goto end; | 157 | goto end; |
| 158 | 158 | ||
| 159 | /* Initialize the CPM interrupt controller. */ | 159 | /* Initialize the CPM interrupt controller. */ |
| 160 | hwirq = (unsigned int)irq_map[sirq].hwirq; | 160 | hwirq = (unsigned int)virq_to_hw(sirq); |
| 161 | out_be32(&cpic_reg->cpic_cicr, | 161 | out_be32(&cpic_reg->cpic_cicr, |
| 162 | (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | | 162 | (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | |
| 163 | ((hwirq/2) << 13) | CICR_HP_MASK); | 163 | ((hwirq/2) << 13) | CICR_HP_MASK); |
| @@ -223,7 +223,7 @@ void __init cpm_reset(void) | |||
| 223 | 223 | ||
| 224 | /* Set SDMA Bus Request priority 5. | 224 | /* Set SDMA Bus Request priority 5. |
| 225 | * On 860T, this also enables FEC priority 6. I am not sure | 225 | * On 860T, this also enables FEC priority 6. I am not sure |
| 226 | * this is what we realy want for some applications, but the | 226 | * this is what we really want for some applications, but the |
| 227 | * manual recommends it. | 227 | * manual recommends it. |
| 228 | * Bit 25, FAM can also be set to use FEC aggressive mode (860T). | 228 | * Bit 25, FAM can also be set to use FEC aggressive mode (860T). |
| 229 | */ | 229 | */ |
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index fcea4ff825dd..bcab50e2a9eb 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c | |||
| @@ -78,10 +78,10 @@ static const u_char irq_to_siubit[] = { | |||
| 78 | 24, 25, 26, 27, 28, 29, 30, 31, | 78 | 24, 25, 26, 27, 28, 29, 30, 31, |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
| 81 | static void cpm2_mask_irq(unsigned int virq) | 81 | static void cpm2_mask_irq(struct irq_data *d) |
| 82 | { | 82 | { |
| 83 | int bit, word; | 83 | int bit, word; |
| 84 | unsigned int irq_nr = virq_to_hw(virq); | 84 | unsigned int irq_nr = irqd_to_hwirq(d); |
| 85 | 85 | ||
| 86 | bit = irq_to_siubit[irq_nr]; | 86 | bit = irq_to_siubit[irq_nr]; |
| 87 | word = irq_to_siureg[irq_nr]; | 87 | word = irq_to_siureg[irq_nr]; |
| @@ -90,10 +90,10 @@ static void cpm2_mask_irq(unsigned int virq) | |||
| 90 | out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); | 90 | out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | static void cpm2_unmask_irq(unsigned int virq) | 93 | static void cpm2_unmask_irq(struct irq_data *d) |
| 94 | { | 94 | { |
| 95 | int bit, word; | 95 | int bit, word; |
| 96 | unsigned int irq_nr = virq_to_hw(virq); | 96 | unsigned int irq_nr = irqd_to_hwirq(d); |
| 97 | 97 | ||
| 98 | bit = irq_to_siubit[irq_nr]; | 98 | bit = irq_to_siubit[irq_nr]; |
| 99 | word = irq_to_siureg[irq_nr]; | 99 | word = irq_to_siureg[irq_nr]; |
| @@ -102,10 +102,10 @@ static void cpm2_unmask_irq(unsigned int virq) | |||
| 102 | out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); | 102 | out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static void cpm2_ack(unsigned int virq) | 105 | static void cpm2_ack(struct irq_data *d) |
| 106 | { | 106 | { |
| 107 | int bit, word; | 107 | int bit, word; |
| 108 | unsigned int irq_nr = virq_to_hw(virq); | 108 | unsigned int irq_nr = irqd_to_hwirq(d); |
| 109 | 109 | ||
| 110 | bit = irq_to_siubit[irq_nr]; | 110 | bit = irq_to_siubit[irq_nr]; |
| 111 | word = irq_to_siureg[irq_nr]; | 111 | word = irq_to_siureg[irq_nr]; |
| @@ -113,34 +113,27 @@ static void cpm2_ack(unsigned int virq) | |||
| 113 | out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit); | 113 | out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | static void cpm2_end_irq(unsigned int virq) | 116 | static void cpm2_end_irq(struct irq_data *d) |
| 117 | { | 117 | { |
| 118 | struct irq_desc *desc; | ||
| 119 | int bit, word; | 118 | int bit, word; |
| 120 | unsigned int irq_nr = virq_to_hw(virq); | 119 | unsigned int irq_nr = irqd_to_hwirq(d); |
| 121 | 120 | ||
| 122 | desc = irq_to_desc(irq_nr); | 121 | bit = irq_to_siubit[irq_nr]; |
| 123 | if (!(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)) | 122 | word = irq_to_siureg[irq_nr]; |
| 124 | && desc->action) { | ||
| 125 | |||
| 126 | bit = irq_to_siubit[irq_nr]; | ||
| 127 | word = irq_to_siureg[irq_nr]; | ||
| 128 | 123 | ||
| 129 | ppc_cached_irq_mask[word] |= 1 << bit; | 124 | ppc_cached_irq_mask[word] |= 1 << bit; |
| 130 | out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); | 125 | out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]); |
| 131 | 126 | ||
| 132 | /* | 127 | /* |
| 133 | * Work around large numbers of spurious IRQs on PowerPC 82xx | 128 | * Work around large numbers of spurious IRQs on PowerPC 82xx |
| 134 | * systems. | 129 | * systems. |
| 135 | */ | 130 | */ |
| 136 | mb(); | 131 | mb(); |
| 137 | } | ||
| 138 | } | 132 | } |
| 139 | 133 | ||
| 140 | static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) | 134 | static int cpm2_set_irq_type(struct irq_data *d, unsigned int flow_type) |
| 141 | { | 135 | { |
| 142 | unsigned int src = virq_to_hw(virq); | 136 | unsigned int src = irqd_to_hwirq(d); |
| 143 | struct irq_desc *desc = irq_to_desc(virq); | ||
| 144 | unsigned int vold, vnew, edibit; | 137 | unsigned int vold, vnew, edibit; |
| 145 | 138 | ||
| 146 | /* Port C interrupts are either IRQ_TYPE_EDGE_FALLING or | 139 | /* Port C interrupts are either IRQ_TYPE_EDGE_FALLING or |
| @@ -162,13 +155,11 @@ static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
| 162 | goto err_sense; | 155 | goto err_sense; |
| 163 | } | 156 | } |
| 164 | 157 | ||
| 165 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); | 158 | irqd_set_trigger_type(d, flow_type); |
| 166 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; | 159 | if (flow_type & IRQ_TYPE_LEVEL_LOW) |
| 167 | if (flow_type & IRQ_TYPE_LEVEL_LOW) { | 160 | __irq_set_handler_locked(d->irq, handle_level_irq); |
| 168 | desc->status |= IRQ_LEVEL; | 161 | else |
| 169 | desc->handle_irq = handle_level_irq; | 162 | __irq_set_handler_locked(d->irq, handle_edge_irq); |
| 170 | } else | ||
| 171 | desc->handle_irq = handle_edge_irq; | ||
| 172 | 163 | ||
| 173 | /* internal IRQ senses are LEVEL_LOW | 164 | /* internal IRQ senses are LEVEL_LOW |
| 174 | * EXT IRQ and Port C IRQ senses are programmable | 165 | * EXT IRQ and Port C IRQ senses are programmable |
| @@ -179,7 +170,8 @@ static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
| 179 | if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0) | 170 | if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0) |
| 180 | edibit = (31 - (CPM2_IRQ_PORTC0 - src)); | 171 | edibit = (31 - (CPM2_IRQ_PORTC0 - src)); |
| 181 | else | 172 | else |
| 182 | return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL; | 173 | return (flow_type & IRQ_TYPE_LEVEL_LOW) ? |
| 174 | IRQ_SET_MASK_OK_NOCOPY : -EINVAL; | ||
| 183 | 175 | ||
| 184 | vold = in_be32(&cpm2_intctl->ic_siexr); | 176 | vold = in_be32(&cpm2_intctl->ic_siexr); |
| 185 | 177 | ||
| @@ -190,7 +182,7 @@ static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
| 190 | 182 | ||
| 191 | if (vold != vnew) | 183 | if (vold != vnew) |
| 192 | out_be32(&cpm2_intctl->ic_siexr, vnew); | 184 | out_be32(&cpm2_intctl->ic_siexr, vnew); |
| 193 | return 0; | 185 | return IRQ_SET_MASK_OK_NOCOPY; |
| 194 | 186 | ||
| 195 | err_sense: | 187 | err_sense: |
| 196 | pr_err("CPM2 PIC: sense type 0x%x not supported\n", flow_type); | 188 | pr_err("CPM2 PIC: sense type 0x%x not supported\n", flow_type); |
| @@ -199,11 +191,12 @@ err_sense: | |||
| 199 | 191 | ||
| 200 | static struct irq_chip cpm2_pic = { | 192 | static struct irq_chip cpm2_pic = { |
| 201 | .name = "CPM2 SIU", | 193 | .name = "CPM2 SIU", |
| 202 | .mask = cpm2_mask_irq, | 194 | .irq_mask = cpm2_mask_irq, |
| 203 | .unmask = cpm2_unmask_irq, | 195 | .irq_unmask = cpm2_unmask_irq, |
| 204 | .ack = cpm2_ack, | 196 | .irq_ack = cpm2_ack, |
| 205 | .eoi = cpm2_end_irq, | 197 | .irq_eoi = cpm2_end_irq, |
| 206 | .set_type = cpm2_set_irq_type, | 198 | .irq_set_type = cpm2_set_irq_type, |
| 199 | .flags = IRQCHIP_EOI_IF_HANDLED, | ||
| 207 | }; | 200 | }; |
| 208 | 201 | ||
| 209 | unsigned int cpm2_get_irq(void) | 202 | unsigned int cpm2_get_irq(void) |
| @@ -226,8 +219,8 @@ static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, | |||
| 226 | { | 219 | { |
| 227 | pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw); | 220 | pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw); |
| 228 | 221 | ||
| 229 | irq_to_desc(virq)->status |= IRQ_LEVEL; | 222 | irq_set_status_flags(virq, IRQ_LEVEL); |
| 230 | set_irq_chip_and_handler(virq, &cpm2_pic, handle_level_irq); | 223 | irq_set_chip_and_handler(virq, &cpm2_pic, handle_level_irq); |
| 231 | return 0; | 224 | return 0; |
| 232 | } | 225 | } |
| 233 | 226 | ||
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index 559db2b846a9..8e9e06a7ca59 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c | |||
| @@ -70,6 +70,8 @@ static int iommu_table_dart_inited; | |||
| 70 | static int dart_dirty; | 70 | static int dart_dirty; |
| 71 | static int dart_is_u4; | 71 | static int dart_is_u4; |
| 72 | 72 | ||
| 73 | #define DART_U4_BYPASS_BASE 0x8000000000ull | ||
| 74 | |||
| 73 | #define DBG(...) | 75 | #define DBG(...) |
| 74 | 76 | ||
| 75 | static inline void dart_tlb_invalidate_all(void) | 77 | static inline void dart_tlb_invalidate_all(void) |
| @@ -292,27 +294,67 @@ static void iommu_table_dart_setup(void) | |||
| 292 | set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map); | 294 | set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map); |
| 293 | } | 295 | } |
| 294 | 296 | ||
| 295 | static void pci_dma_dev_setup_dart(struct pci_dev *dev) | 297 | static void dma_dev_setup_dart(struct device *dev) |
| 296 | { | 298 | { |
| 297 | /* We only have one iommu table on the mac for now, which makes | 299 | /* We only have one iommu table on the mac for now, which makes |
| 298 | * things simple. Setup all PCI devices to point to this table | 300 | * things simple. Setup all PCI devices to point to this table |
| 299 | */ | 301 | */ |
| 300 | set_iommu_table_base(&dev->dev, &iommu_table_dart); | 302 | if (get_dma_ops(dev) == &dma_direct_ops) |
| 303 | set_dma_offset(dev, DART_U4_BYPASS_BASE); | ||
| 304 | else | ||
| 305 | set_iommu_table_base(dev, &iommu_table_dart); | ||
| 301 | } | 306 | } |
| 302 | 307 | ||
| 303 | static void pci_dma_bus_setup_dart(struct pci_bus *bus) | 308 | static void pci_dma_dev_setup_dart(struct pci_dev *dev) |
| 304 | { | 309 | { |
| 305 | struct device_node *dn; | 310 | dma_dev_setup_dart(&dev->dev); |
| 311 | } | ||
| 306 | 312 | ||
| 313 | static void pci_dma_bus_setup_dart(struct pci_bus *bus) | ||
| 314 | { | ||
| 307 | if (!iommu_table_dart_inited) { | 315 | if (!iommu_table_dart_inited) { |
| 308 | iommu_table_dart_inited = 1; | 316 | iommu_table_dart_inited = 1; |
| 309 | iommu_table_dart_setup(); | 317 | iommu_table_dart_setup(); |
| 310 | } | 318 | } |
| 319 | } | ||
| 311 | 320 | ||
| 312 | dn = pci_bus_to_OF_node(bus); | 321 | static bool dart_device_on_pcie(struct device *dev) |
| 322 | { | ||
| 323 | struct device_node *np = of_node_get(dev->of_node); | ||
| 324 | |||
| 325 | while(np) { | ||
| 326 | if (of_device_is_compatible(np, "U4-pcie") || | ||
| 327 | of_device_is_compatible(np, "u4-pcie")) { | ||
| 328 | of_node_put(np); | ||
| 329 | return true; | ||
| 330 | } | ||
| 331 | np = of_get_next_parent(np); | ||
| 332 | } | ||
| 333 | return false; | ||
| 334 | } | ||
| 313 | 335 | ||
| 314 | if (dn) | 336 | static int dart_dma_set_mask(struct device *dev, u64 dma_mask) |
| 315 | PCI_DN(dn)->iommu_table = &iommu_table_dart; | 337 | { |
| 338 | if (!dev->dma_mask || !dma_supported(dev, dma_mask)) | ||
| 339 | return -EIO; | ||
| 340 | |||
| 341 | /* U4 supports a DART bypass, we use it for 64-bit capable | ||
| 342 | * devices to improve performances. However, that only works | ||
| 343 | * for devices connected to U4 own PCIe interface, not bridged | ||
| 344 | * through hypertransport. We need the device to support at | ||
| 345 | * least 40 bits of addresses. | ||
| 346 | */ | ||
| 347 | if (dart_device_on_pcie(dev) && dma_mask >= DMA_BIT_MASK(40)) { | ||
| 348 | dev_info(dev, "Using 64-bit DMA iommu bypass\n"); | ||
| 349 | set_dma_ops(dev, &dma_direct_ops); | ||
| 350 | } else { | ||
| 351 | dev_info(dev, "Using 32-bit DMA via iommu\n"); | ||
| 352 | set_dma_ops(dev, &dma_iommu_ops); | ||
| 353 | } | ||
| 354 | dma_dev_setup_dart(dev); | ||
| 355 | |||
| 356 | *dev->dma_mask = dma_mask; | ||
| 357 | return 0; | ||
| 316 | } | 358 | } |
| 317 | 359 | ||
| 318 | void __init iommu_init_early_dart(void) | 360 | void __init iommu_init_early_dart(void) |
| @@ -324,24 +366,29 @@ void __init iommu_init_early_dart(void) | |||
| 324 | if (dn == NULL) { | 366 | if (dn == NULL) { |
| 325 | dn = of_find_compatible_node(NULL, "dart", "u4-dart"); | 367 | dn = of_find_compatible_node(NULL, "dart", "u4-dart"); |
| 326 | if (dn == NULL) | 368 | if (dn == NULL) |
| 327 | goto bail; | 369 | return; /* use default direct_dma_ops */ |
| 328 | dart_is_u4 = 1; | 370 | dart_is_u4 = 1; |
| 329 | } | 371 | } |
| 330 | 372 | ||
| 373 | /* Initialize the DART HW */ | ||
| 374 | if (dart_init(dn) != 0) | ||
| 375 | goto bail; | ||
| 376 | |||
| 331 | /* Setup low level TCE operations for the core IOMMU code */ | 377 | /* Setup low level TCE operations for the core IOMMU code */ |
| 332 | ppc_md.tce_build = dart_build; | 378 | ppc_md.tce_build = dart_build; |
| 333 | ppc_md.tce_free = dart_free; | 379 | ppc_md.tce_free = dart_free; |
| 334 | ppc_md.tce_flush = dart_flush; | 380 | ppc_md.tce_flush = dart_flush; |
| 335 | 381 | ||
| 336 | /* Initialize the DART HW */ | 382 | /* Setup bypass if supported */ |
| 337 | if (dart_init(dn) == 0) { | 383 | if (dart_is_u4) |
| 338 | ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_dart; | 384 | ppc_md.dma_set_mask = dart_dma_set_mask; |
| 339 | ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart; | ||
| 340 | 385 | ||
| 341 | /* Setup pci_dma ops */ | 386 | ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_dart; |
| 342 | set_pci_dma_ops(&dma_iommu_ops); | 387 | ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart; |
| 343 | return; | 388 | |
| 344 | } | 389 | /* Setup pci_dma ops */ |
| 390 | set_pci_dma_ops(&dma_iommu_ops); | ||
| 391 | return; | ||
| 345 | 392 | ||
| 346 | bail: | 393 | bail: |
| 347 | /* If init failed, use direct iommu and null setup functions */ | 394 | /* If init failed, use direct iommu and null setup functions */ |
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h b/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h new file mode 100644 index 000000000000..60c9c0bd5ba2 --- /dev/null +++ b/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2009-2010 Freescale Semiconductor, Inc | ||
| 3 | * | ||
| 4 | * QorIQ based Cache Controller Memory Mapped Registers | ||
| 5 | * | ||
| 6 | * Author: Vivek Mahajan <vivek.mahajan@freescale.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the | ||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 11 | * option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __FSL_85XX_CACHE_CTLR_H__ | ||
| 24 | #define __FSL_85XX_CACHE_CTLR_H__ | ||
| 25 | |||
| 26 | #define L2CR_L2FI 0x40000000 /* L2 flash invalidate */ | ||
| 27 | #define L2CR_L2IO 0x00200000 /* L2 instruction only */ | ||
| 28 | #define L2CR_SRAM_ZERO 0x00000000 /* L2SRAM zero size */ | ||
| 29 | #define L2CR_SRAM_FULL 0x00010000 /* L2SRAM full size */ | ||
| 30 | #define L2CR_SRAM_HALF 0x00020000 /* L2SRAM half size */ | ||
| 31 | #define L2CR_SRAM_TWO_HALFS 0x00030000 /* L2SRAM two half sizes */ | ||
| 32 | #define L2CR_SRAM_QUART 0x00040000 /* L2SRAM one quarter size */ | ||
| 33 | #define L2CR_SRAM_TWO_QUARTS 0x00050000 /* L2SRAM two quarter size */ | ||
| 34 | #define L2CR_SRAM_EIGHTH 0x00060000 /* L2SRAM one eighth size */ | ||
| 35 | #define L2CR_SRAM_TWO_EIGHTH 0x00070000 /* L2SRAM two eighth size */ | ||
| 36 | |||
| 37 | #define L2SRAM_OPTIMAL_SZ_SHIFT 0x00000003 /* Optimum size for L2SRAM */ | ||
| 38 | |||
| 39 | #define L2SRAM_BAR_MSK_LO18 0xFFFFC000 /* Lower 18 bits */ | ||
| 40 | #define L2SRAM_BARE_MSK_HI4 0x0000000F /* Upper 4 bits */ | ||
| 41 | |||
| 42 | enum cache_sram_lock_ways { | ||
| 43 | LOCK_WAYS_ZERO, | ||
| 44 | LOCK_WAYS_EIGHTH, | ||
| 45 | LOCK_WAYS_TWO_EIGHTH, | ||
| 46 | LOCK_WAYS_HALF = 4, | ||
| 47 | LOCK_WAYS_FULL = 8, | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct mpc85xx_l2ctlr { | ||
| 51 | u32 ctl; /* 0x000 - L2 control */ | ||
| 52 | u8 res1[0xC]; | ||
| 53 | u32 ewar0; /* 0x010 - External write address 0 */ | ||
| 54 | u32 ewarea0; /* 0x014 - External write address extended 0 */ | ||
| 55 | u32 ewcr0; /* 0x018 - External write ctrl */ | ||
| 56 | u8 res2[4]; | ||
| 57 | u32 ewar1; /* 0x020 - External write address 1 */ | ||
| 58 | u32 ewarea1; /* 0x024 - External write address extended 1 */ | ||
| 59 | u32 ewcr1; /* 0x028 - External write ctrl 1 */ | ||
| 60 | u8 res3[4]; | ||
| 61 | u32 ewar2; /* 0x030 - External write address 2 */ | ||
| 62 | u32 ewarea2; /* 0x034 - External write address extended 2 */ | ||
| 63 | u32 ewcr2; /* 0x038 - External write ctrl 2 */ | ||
| 64 | u8 res4[4]; | ||
| 65 | u32 ewar3; /* 0x040 - External write address 3 */ | ||
| 66 | u32 ewarea3; /* 0x044 - External write address extended 3 */ | ||
| 67 | u32 ewcr3; /* 0x048 - External write ctrl 3 */ | ||
| 68 | u8 res5[0xB4]; | ||
| 69 | u32 srbar0; /* 0x100 - SRAM base address 0 */ | ||
| 70 | u32 srbarea0; /* 0x104 - SRAM base addr reg ext address 0 */ | ||
| 71 | u32 srbar1; /* 0x108 - SRAM base address 1 */ | ||
| 72 | u32 srbarea1; /* 0x10C - SRAM base addr reg ext address 1 */ | ||
| 73 | u8 res6[0xCF0]; | ||
| 74 | u32 errinjhi; /* 0xE00 - Error injection mask high */ | ||
| 75 | u32 errinjlo; /* 0xE04 - Error injection mask low */ | ||
| 76 | u32 errinjctl; /* 0xE08 - Error injection tag/ecc control */ | ||
| 77 | u8 res7[0x14]; | ||
| 78 | u32 captdatahi; /* 0xE20 - Error data high capture */ | ||
| 79 | u32 captdatalo; /* 0xE24 - Error data low capture */ | ||
| 80 | u32 captecc; /* 0xE28 - Error syndrome */ | ||
| 81 | u8 res8[0x14]; | ||
| 82 | u32 errdet; /* 0xE40 - Error detect */ | ||
| 83 | u32 errdis; /* 0xE44 - Error disable */ | ||
| 84 | u32 errinten; /* 0xE48 - Error interrupt enable */ | ||
| 85 | u32 errattr; /* 0xE4c - Error attribute capture */ | ||
| 86 | u32 erradrrl; /* 0xE50 - Error address capture low */ | ||
| 87 | u32 erradrrh; /* 0xE54 - Error address capture high */ | ||
| 88 | u32 errctl; /* 0xE58 - Error control */ | ||
| 89 | u8 res9[0x1A4]; | ||
| 90 | }; | ||
| 91 | |||
| 92 | struct sram_parameters { | ||
| 93 | unsigned int sram_size; | ||
| 94 | uint64_t sram_offset; | ||
| 95 | }; | ||
| 96 | |||
| 97 | extern int instantiate_cache_sram(struct platform_device *dev, | ||
| 98 | struct sram_parameters sram_params); | ||
| 99 | extern void remove_cache_sram(struct platform_device *dev); | ||
| 100 | |||
| 101 | #endif /* __FSL_85XX_CACHE_CTLR_H__ */ | ||
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c new file mode 100644 index 000000000000..116415899176 --- /dev/null +++ b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2009-2010 Freescale Semiconductor, Inc. | ||
| 3 | * | ||
| 4 | * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM | ||
| 5 | * | ||
| 6 | * Author: Vivek Mahajan <vivek.mahajan@freescale.com> | ||
| 7 | * | ||
| 8 | * This file is derived from the original work done | ||
| 9 | * by Sylvain Munaut for the Bestcomm SRAM allocator. | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify it | ||
| 12 | * under the terms of the GNU General Public License as published by the | ||
| 13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 14 | * option) any later version. | ||
| 15 | * | ||
| 16 | * This program is distributed in the hope that it will be useful, | ||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | * GNU General Public License for more details. | ||
| 20 | * | ||
| 21 | * You should have received a copy of the GNU General Public License | ||
| 22 | * along with this program; if not, write to the Free Software | ||
| 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <linux/kernel.h> | ||
| 27 | #include <linux/slab.h> | ||
| 28 | #include <linux/err.h> | ||
| 29 | #include <linux/of_platform.h> | ||
| 30 | #include <asm/pgtable.h> | ||
| 31 | #include <asm/fsl_85xx_cache_sram.h> | ||
| 32 | |||
| 33 | #include "fsl_85xx_cache_ctlr.h" | ||
| 34 | |||
| 35 | struct mpc85xx_cache_sram *cache_sram; | ||
| 36 | |||
| 37 | void *mpc85xx_cache_sram_alloc(unsigned int size, | ||
| 38 | phys_addr_t *phys, unsigned int align) | ||
| 39 | { | ||
| 40 | unsigned long offset; | ||
| 41 | unsigned long flags; | ||
| 42 | |||
| 43 | if (unlikely(cache_sram == NULL)) | ||
| 44 | return NULL; | ||
| 45 | |||
| 46 | if (!size || (size > cache_sram->size) || (align > cache_sram->size)) { | ||
| 47 | pr_err("%s(): size(=%x) or align(=%x) zero or too big\n", | ||
| 48 | __func__, size, align); | ||
| 49 | return NULL; | ||
| 50 | } | ||
| 51 | |||
| 52 | if ((align & (align - 1)) || align <= 1) { | ||
| 53 | pr_err("%s(): align(=%x) must be power of two and >1\n", | ||
| 54 | __func__, align); | ||
| 55 | return NULL; | ||
| 56 | } | ||
| 57 | |||
| 58 | spin_lock_irqsave(&cache_sram->lock, flags); | ||
| 59 | offset = rh_alloc_align(cache_sram->rh, size, align, NULL); | ||
| 60 | spin_unlock_irqrestore(&cache_sram->lock, flags); | ||
| 61 | |||
| 62 | if (IS_ERR_VALUE(offset)) | ||
| 63 | return NULL; | ||
| 64 | |||
| 65 | *phys = cache_sram->base_phys + offset; | ||
| 66 | |||
| 67 | return (unsigned char *)cache_sram->base_virt + offset; | ||
| 68 | } | ||
| 69 | EXPORT_SYMBOL(mpc85xx_cache_sram_alloc); | ||
| 70 | |||
| 71 | void mpc85xx_cache_sram_free(void *ptr) | ||
| 72 | { | ||
| 73 | unsigned long flags; | ||
| 74 | BUG_ON(!ptr); | ||
| 75 | |||
| 76 | spin_lock_irqsave(&cache_sram->lock, flags); | ||
| 77 | rh_free(cache_sram->rh, ptr - cache_sram->base_virt); | ||
| 78 | spin_unlock_irqrestore(&cache_sram->lock, flags); | ||
| 79 | } | ||
| 80 | EXPORT_SYMBOL(mpc85xx_cache_sram_free); | ||
| 81 | |||
| 82 | int __init instantiate_cache_sram(struct platform_device *dev, | ||
| 83 | struct sram_parameters sram_params) | ||
| 84 | { | ||
| 85 | int ret = 0; | ||
| 86 | |||
| 87 | if (cache_sram) { | ||
| 88 | dev_err(&dev->dev, "Already initialized cache-sram\n"); | ||
| 89 | return -EBUSY; | ||
| 90 | } | ||
| 91 | |||
| 92 | cache_sram = kzalloc(sizeof(struct mpc85xx_cache_sram), GFP_KERNEL); | ||
| 93 | if (!cache_sram) { | ||
| 94 | dev_err(&dev->dev, "Out of memory for cache_sram structure\n"); | ||
| 95 | return -ENOMEM; | ||
| 96 | } | ||
| 97 | |||
| 98 | cache_sram->base_phys = sram_params.sram_offset; | ||
| 99 | cache_sram->size = sram_params.sram_size; | ||
| 100 | |||
| 101 | if (!request_mem_region(cache_sram->base_phys, cache_sram->size, | ||
| 102 | "fsl_85xx_cache_sram")) { | ||
| 103 | dev_err(&dev->dev, "%s: request memory failed\n", | ||
| 104 | dev->dev.of_node->full_name); | ||
| 105 | ret = -ENXIO; | ||
| 106 | goto out_free; | ||
| 107 | } | ||
| 108 | |||
| 109 | cache_sram->base_virt = ioremap_prot(cache_sram->base_phys, | ||
| 110 | cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL); | ||
| 111 | if (!cache_sram->base_virt) { | ||
| 112 | dev_err(&dev->dev, "%s: ioremap_prot failed\n", | ||
| 113 | dev->dev.of_node->full_name); | ||
| 114 | ret = -ENOMEM; | ||
| 115 | goto out_release; | ||
| 116 | } | ||
| 117 | |||
| 118 | cache_sram->rh = rh_create(sizeof(unsigned int)); | ||
| 119 | if (IS_ERR(cache_sram->rh)) { | ||
| 120 | dev_err(&dev->dev, "%s: Unable to create remote heap\n", | ||
| 121 | dev->dev.of_node->full_name); | ||
| 122 | ret = PTR_ERR(cache_sram->rh); | ||
| 123 | goto out_unmap; | ||
| 124 | } | ||
| 125 | |||
| 126 | rh_attach_region(cache_sram->rh, 0, cache_sram->size); | ||
| 127 | spin_lock_init(&cache_sram->lock); | ||
| 128 | |||
| 129 | dev_info(&dev->dev, "[base:0x%llx, size:0x%x] configured and loaded\n", | ||
| 130 | (unsigned long long)cache_sram->base_phys, cache_sram->size); | ||
| 131 | |||
| 132 | return 0; | ||
| 133 | |||
| 134 | out_unmap: | ||
| 135 | iounmap(cache_sram->base_virt); | ||
| 136 | |||
| 137 | out_release: | ||
| 138 | release_mem_region(cache_sram->base_phys, cache_sram->size); | ||
| 139 | |||
| 140 | out_free: | ||
| 141 | kfree(cache_sram); | ||
| 142 | return ret; | ||
| 143 | } | ||
| 144 | |||
| 145 | void remove_cache_sram(struct platform_device *dev) | ||
| 146 | { | ||
| 147 | BUG_ON(!cache_sram); | ||
| 148 | |||
| 149 | rh_detach_region(cache_sram->rh, 0, cache_sram->size); | ||
| 150 | rh_destroy(cache_sram->rh); | ||
| 151 | |||
| 152 | iounmap(cache_sram->base_virt); | ||
| 153 | release_mem_region(cache_sram->base_phys, cache_sram->size); | ||
| 154 | |||
| 155 | kfree(cache_sram); | ||
| 156 | cache_sram = NULL; | ||
| 157 | |||
| 158 | dev_info(&dev->dev, "MPC85xx Cache-SRAM driver unloaded\n"); | ||
| 159 | } | ||
diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c new file mode 100644 index 000000000000..5f88797dce73 --- /dev/null +++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c | |||
| @@ -0,0 +1,230 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2009-2010 Freescale Semiconductor, Inc. | ||
| 3 | * | ||
| 4 | * QorIQ (P1/P2) L2 controller init for Cache-SRAM instantiation | ||
| 5 | * | ||
| 6 | * Author: Vivek Mahajan <vivek.mahajan@freescale.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the | ||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 11 | * option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/of_platform.h> | ||
| 25 | #include <asm/io.h> | ||
| 26 | |||
| 27 | #include "fsl_85xx_cache_ctlr.h" | ||
| 28 | |||
| 29 | static char *sram_size; | ||
| 30 | static char *sram_offset; | ||
| 31 | struct mpc85xx_l2ctlr __iomem *l2ctlr; | ||
| 32 | |||
| 33 | static long get_cache_sram_size(void) | ||
| 34 | { | ||
| 35 | unsigned long val; | ||
| 36 | |||
| 37 | if (!sram_size || (strict_strtoul(sram_size, 0, &val) < 0)) | ||
| 38 | return -EINVAL; | ||
| 39 | |||
| 40 | return val; | ||
| 41 | } | ||
| 42 | |||
| 43 | static long get_cache_sram_offset(void) | ||
| 44 | { | ||
| 45 | unsigned long val; | ||
| 46 | |||
| 47 | if (!sram_offset || (strict_strtoul(sram_offset, 0, &val) < 0)) | ||
| 48 | return -EINVAL; | ||
| 49 | |||
| 50 | return val; | ||
| 51 | } | ||
| 52 | |||
| 53 | static int __init get_size_from_cmdline(char *str) | ||
| 54 | { | ||
| 55 | if (!str) | ||
| 56 | return 0; | ||
| 57 | |||
| 58 | sram_size = str; | ||
| 59 | return 1; | ||
| 60 | } | ||
| 61 | |||
| 62 | static int __init get_offset_from_cmdline(char *str) | ||
| 63 | { | ||
| 64 | if (!str) | ||
| 65 | return 0; | ||
| 66 | |||
| 67 | sram_offset = str; | ||
| 68 | return 1; | ||
| 69 | } | ||
| 70 | |||
| 71 | __setup("cache-sram-size=", get_size_from_cmdline); | ||
| 72 | __setup("cache-sram-offset=", get_offset_from_cmdline); | ||
| 73 | |||
| 74 | static int __devinit mpc85xx_l2ctlr_of_probe(struct platform_device *dev) | ||
| 75 | { | ||
| 76 | long rval; | ||
| 77 | unsigned int rem; | ||
| 78 | unsigned char ways; | ||
| 79 | const unsigned int *prop; | ||
| 80 | unsigned int l2cache_size; | ||
| 81 | struct sram_parameters sram_params; | ||
| 82 | |||
| 83 | if (!dev->dev.of_node) { | ||
| 84 | dev_err(&dev->dev, "Device's OF-node is NULL\n"); | ||
| 85 | return -EINVAL; | ||
| 86 | } | ||
| 87 | |||
| 88 | prop = of_get_property(dev->dev.of_node, "cache-size", NULL); | ||
| 89 | if (!prop) { | ||
| 90 | dev_err(&dev->dev, "Missing L2 cache-size\n"); | ||
| 91 | return -EINVAL; | ||
| 92 | } | ||
| 93 | l2cache_size = *prop; | ||
| 94 | |||
| 95 | sram_params.sram_size = get_cache_sram_size(); | ||
| 96 | if ((int)sram_params.sram_size <= 0) { | ||
| 97 | dev_err(&dev->dev, | ||
| 98 | "Entire L2 as cache, Aborting Cache-SRAM stuff\n"); | ||
| 99 | return -EINVAL; | ||
| 100 | } | ||
| 101 | |||
| 102 | sram_params.sram_offset = get_cache_sram_offset(); | ||
| 103 | if ((int64_t)sram_params.sram_offset <= 0) { | ||
| 104 | dev_err(&dev->dev, | ||
| 105 | "Entire L2 as cache, provide a valid sram offset\n"); | ||
| 106 | return -EINVAL; | ||
| 107 | } | ||
| 108 | |||
| 109 | |||
| 110 | rem = l2cache_size % sram_params.sram_size; | ||
| 111 | ways = LOCK_WAYS_FULL * sram_params.sram_size / l2cache_size; | ||
| 112 | if (rem || (ways & (ways - 1))) { | ||
| 113 | dev_err(&dev->dev, "Illegal cache-sram-size in command line\n"); | ||
| 114 | return -EINVAL; | ||
| 115 | } | ||
| 116 | |||
| 117 | l2ctlr = of_iomap(dev->dev.of_node, 0); | ||
| 118 | if (!l2ctlr) { | ||
| 119 | dev_err(&dev->dev, "Can't map L2 controller\n"); | ||
| 120 | return -EINVAL; | ||
| 121 | } | ||
| 122 | |||
| 123 | /* | ||
| 124 | * Write bits[0-17] to srbar0 | ||
| 125 | */ | ||
| 126 | out_be32(&l2ctlr->srbar0, | ||
| 127 | sram_params.sram_offset & L2SRAM_BAR_MSK_LO18); | ||
| 128 | |||
| 129 | /* | ||
| 130 | * Write bits[18-21] to srbare0 | ||
| 131 | */ | ||
| 132 | #ifdef CONFIG_PHYS_64BIT | ||
| 133 | out_be32(&l2ctlr->srbarea0, | ||
| 134 | (sram_params.sram_offset >> 32) & L2SRAM_BARE_MSK_HI4); | ||
| 135 | #endif | ||
| 136 | |||
| 137 | clrsetbits_be32(&l2ctlr->ctl, L2CR_L2E, L2CR_L2FI); | ||
| 138 | |||
| 139 | switch (ways) { | ||
| 140 | case LOCK_WAYS_EIGHTH: | ||
| 141 | setbits32(&l2ctlr->ctl, | ||
| 142 | L2CR_L2E | L2CR_L2FI | L2CR_SRAM_EIGHTH); | ||
| 143 | break; | ||
| 144 | |||
| 145 | case LOCK_WAYS_TWO_EIGHTH: | ||
| 146 | setbits32(&l2ctlr->ctl, | ||
| 147 | L2CR_L2E | L2CR_L2FI | L2CR_SRAM_QUART); | ||
| 148 | break; | ||
| 149 | |||
| 150 | case LOCK_WAYS_HALF: | ||
| 151 | setbits32(&l2ctlr->ctl, | ||
| 152 | L2CR_L2E | L2CR_L2FI | L2CR_SRAM_HALF); | ||
| 153 | break; | ||
| 154 | |||
| 155 | case LOCK_WAYS_FULL: | ||
| 156 | default: | ||
| 157 | setbits32(&l2ctlr->ctl, | ||
| 158 | L2CR_L2E | L2CR_L2FI | L2CR_SRAM_FULL); | ||
| 159 | break; | ||
| 160 | } | ||
| 161 | eieio(); | ||
| 162 | |||
| 163 | rval = instantiate_cache_sram(dev, sram_params); | ||
| 164 | if (rval < 0) { | ||
| 165 | dev_err(&dev->dev, "Can't instantiate Cache-SRAM\n"); | ||
| 166 | iounmap(l2ctlr); | ||
| 167 | return -EINVAL; | ||
| 168 | } | ||
| 169 | |||
| 170 | return 0; | ||
| 171 | } | ||
| 172 | |||
| 173 | static int __devexit mpc85xx_l2ctlr_of_remove(struct platform_device *dev) | ||
| 174 | { | ||
| 175 | BUG_ON(!l2ctlr); | ||
| 176 | |||
| 177 | iounmap(l2ctlr); | ||
| 178 | remove_cache_sram(dev); | ||
| 179 | dev_info(&dev->dev, "MPC85xx L2 controller unloaded\n"); | ||
| 180 | |||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | static struct of_device_id mpc85xx_l2ctlr_of_match[] = { | ||
| 185 | { | ||
| 186 | .compatible = "fsl,p2020-l2-cache-controller", | ||
| 187 | }, | ||
| 188 | { | ||
| 189 | .compatible = "fsl,p2010-l2-cache-controller", | ||
| 190 | }, | ||
| 191 | { | ||
| 192 | .compatible = "fsl,p1020-l2-cache-controller", | ||
| 193 | }, | ||
| 194 | { | ||
| 195 | .compatible = "fsl,p1011-l2-cache-controller", | ||
| 196 | }, | ||
| 197 | { | ||
| 198 | .compatible = "fsl,p1013-l2-cache-controller", | ||
| 199 | }, | ||
| 200 | { | ||
| 201 | .compatible = "fsl,p1022-l2-cache-controller", | ||
| 202 | }, | ||
| 203 | {}, | ||
| 204 | }; | ||
| 205 | |||
| 206 | static struct platform_driver mpc85xx_l2ctlr_of_platform_driver = { | ||
| 207 | .driver = { | ||
| 208 | .name = "fsl-l2ctlr", | ||
| 209 | .owner = THIS_MODULE, | ||
| 210 | .of_match_table = mpc85xx_l2ctlr_of_match, | ||
| 211 | }, | ||
| 212 | .probe = mpc85xx_l2ctlr_of_probe, | ||
| 213 | .remove = __devexit_p(mpc85xx_l2ctlr_of_remove), | ||
| 214 | }; | ||
| 215 | |||
| 216 | static __init int mpc85xx_l2ctlr_of_init(void) | ||
| 217 | { | ||
| 218 | return platform_driver_register(&mpc85xx_l2ctlr_of_platform_driver); | ||
| 219 | } | ||
| 220 | |||
| 221 | static void __exit mpc85xx_l2ctlr_of_exit(void) | ||
| 222 | { | ||
| 223 | platform_driver_unregister(&mpc85xx_l2ctlr_of_platform_driver); | ||
| 224 | } | ||
| 225 | |||
| 226 | subsys_initcall(mpc85xx_l2ctlr_of_init); | ||
| 227 | module_exit(mpc85xx_l2ctlr_of_exit); | ||
| 228 | |||
| 229 | MODULE_DESCRIPTION("Freescale MPC85xx L2 controller init"); | ||
| 230 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c index dceb8d1a843d..d917573cf1a8 100644 --- a/arch/powerpc/sysdev/fsl_lbc.c +++ b/arch/powerpc/sysdev/fsl_lbc.c | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Freescale LBC and UPM routines. | 2 | * Freescale LBC and UPM routines. |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2007-2008 MontaVista Software, Inc. | 4 | * Copyright © 2007-2008 MontaVista Software, Inc. |
| 5 | * Copyright © 2010 Freescale Semiconductor | ||
| 5 | * | 6 | * |
| 6 | * Author: Anton Vorontsov <avorontsov@ru.mvista.com> | 7 | * Author: Anton Vorontsov <avorontsov@ru.mvista.com> |
| 8 | * Author: Jack Lan <Jack.Lan@freescale.com> | ||
| 9 | * Author: Roy Zang <tie-fei.zang@freescale.com> | ||
| 7 | * | 10 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
| @@ -19,39 +22,37 @@ | |||
| 19 | #include <linux/types.h> | 22 | #include <linux/types.h> |
| 20 | #include <linux/io.h> | 23 | #include <linux/io.h> |
| 21 | #include <linux/of.h> | 24 | #include <linux/of.h> |
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/platform_device.h> | ||
| 27 | #include <linux/interrupt.h> | ||
| 28 | #include <linux/mod_devicetable.h> | ||
| 22 | #include <asm/prom.h> | 29 | #include <asm/prom.h> |
| 23 | #include <asm/fsl_lbc.h> | 30 | #include <asm/fsl_lbc.h> |
| 24 | 31 | ||
| 25 | static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock); | 32 | static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock); |
| 26 | static struct fsl_lbc_regs __iomem *fsl_lbc_regs; | 33 | struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev; |
| 34 | EXPORT_SYMBOL(fsl_lbc_ctrl_dev); | ||
| 27 | 35 | ||
| 28 | static char __initdata *compat_lbc[] = { | 36 | /** |
| 29 | "fsl,pq2-localbus", | 37 | * fsl_lbc_addr - convert the base address |
| 30 | "fsl,pq2pro-localbus", | 38 | * @addr_base: base address of the memory bank |
| 31 | "fsl,pq3-localbus", | 39 | * |
| 32 | "fsl,elbc", | 40 | * This function converts a base address of lbc into the right format for the |
| 33 | }; | 41 | * BR register. If the SOC has eLBC then it returns 32bit physical address |
| 34 | 42 | * else it convers a 34bit local bus physical address to correct format of | |
| 35 | static int __init fsl_lbc_init(void) | 43 | * 32bit address for BR register (Example: MPC8641). |
| 44 | */ | ||
| 45 | u32 fsl_lbc_addr(phys_addr_t addr_base) | ||
| 36 | { | 46 | { |
| 37 | struct device_node *lbus; | 47 | struct device_node *np = fsl_lbc_ctrl_dev->dev->of_node; |
| 38 | int i; | 48 | u32 addr = addr_base & 0xffff8000; |
| 39 | 49 | ||
| 40 | for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) { | 50 | if (of_device_is_compatible(np, "fsl,elbc")) |
| 41 | lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]); | 51 | return addr; |
| 42 | if (lbus) | ||
| 43 | goto found; | ||
| 44 | } | ||
| 45 | return -ENODEV; | ||
| 46 | 52 | ||
| 47 | found: | 53 | return addr | ((addr_base & 0x300000000ull) >> 19); |
| 48 | fsl_lbc_regs = of_iomap(lbus, 0); | ||
| 49 | of_node_put(lbus); | ||
| 50 | if (!fsl_lbc_regs) | ||
| 51 | return -ENOMEM; | ||
| 52 | return 0; | ||
| 53 | } | 54 | } |
| 54 | arch_initcall(fsl_lbc_init); | 55 | EXPORT_SYMBOL(fsl_lbc_addr); |
| 55 | 56 | ||
| 56 | /** | 57 | /** |
| 57 | * fsl_lbc_find - find Localbus bank | 58 | * fsl_lbc_find - find Localbus bank |
| @@ -65,15 +66,17 @@ arch_initcall(fsl_lbc_init); | |||
| 65 | int fsl_lbc_find(phys_addr_t addr_base) | 66 | int fsl_lbc_find(phys_addr_t addr_base) |
| 66 | { | 67 | { |
| 67 | int i; | 68 | int i; |
| 69 | struct fsl_lbc_regs __iomem *lbc; | ||
| 68 | 70 | ||
| 69 | if (!fsl_lbc_regs) | 71 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) |
| 70 | return -ENODEV; | 72 | return -ENODEV; |
| 71 | 73 | ||
| 72 | for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) { | 74 | lbc = fsl_lbc_ctrl_dev->regs; |
| 73 | __be32 br = in_be32(&fsl_lbc_regs->bank[i].br); | 75 | for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) { |
| 74 | __be32 or = in_be32(&fsl_lbc_regs->bank[i].or); | 76 | __be32 br = in_be32(&lbc->bank[i].br); |
| 77 | __be32 or = in_be32(&lbc->bank[i].or); | ||
| 75 | 78 | ||
| 76 | if (br & BR_V && (br & or & BR_BA) == addr_base) | 79 | if (br & BR_V && (br & or & BR_BA) == fsl_lbc_addr(addr_base)) |
| 77 | return i; | 80 | return i; |
| 78 | } | 81 | } |
| 79 | 82 | ||
| @@ -94,22 +97,27 @@ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm) | |||
| 94 | { | 97 | { |
| 95 | int bank; | 98 | int bank; |
| 96 | __be32 br; | 99 | __be32 br; |
| 100 | struct fsl_lbc_regs __iomem *lbc; | ||
| 97 | 101 | ||
| 98 | bank = fsl_lbc_find(addr_base); | 102 | bank = fsl_lbc_find(addr_base); |
| 99 | if (bank < 0) | 103 | if (bank < 0) |
| 100 | return bank; | 104 | return bank; |
| 101 | 105 | ||
| 102 | br = in_be32(&fsl_lbc_regs->bank[bank].br); | 106 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) |
| 107 | return -ENODEV; | ||
| 108 | |||
| 109 | lbc = fsl_lbc_ctrl_dev->regs; | ||
| 110 | br = in_be32(&lbc->bank[bank].br); | ||
| 103 | 111 | ||
| 104 | switch (br & BR_MSEL) { | 112 | switch (br & BR_MSEL) { |
| 105 | case BR_MS_UPMA: | 113 | case BR_MS_UPMA: |
| 106 | upm->mxmr = &fsl_lbc_regs->mamr; | 114 | upm->mxmr = &lbc->mamr; |
| 107 | break; | 115 | break; |
| 108 | case BR_MS_UPMB: | 116 | case BR_MS_UPMB: |
| 109 | upm->mxmr = &fsl_lbc_regs->mbmr; | 117 | upm->mxmr = &lbc->mbmr; |
| 110 | break; | 118 | break; |
| 111 | case BR_MS_UPMC: | 119 | case BR_MS_UPMC: |
| 112 | upm->mxmr = &fsl_lbc_regs->mcmr; | 120 | upm->mxmr = &lbc->mcmr; |
| 113 | break; | 121 | break; |
| 114 | default: | 122 | default: |
| 115 | return -EINVAL; | 123 | return -EINVAL; |
| @@ -148,9 +156,12 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar) | |||
| 148 | int ret = 0; | 156 | int ret = 0; |
| 149 | unsigned long flags; | 157 | unsigned long flags; |
| 150 | 158 | ||
| 159 | if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) | ||
| 160 | return -ENODEV; | ||
| 161 | |||
| 151 | spin_lock_irqsave(&fsl_lbc_lock, flags); | 162 | spin_lock_irqsave(&fsl_lbc_lock, flags); |
| 152 | 163 | ||
| 153 | out_be32(&fsl_lbc_regs->mar, mar); | 164 | out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar); |
| 154 | 165 | ||
| 155 | switch (upm->width) { | 166 | switch (upm->width) { |
| 156 | case 8: | 167 | case 8: |
| @@ -172,3 +183,171 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar) | |||
| 172 | return ret; | 183 | return ret; |
| 173 | } | 184 | } |
| 174 | EXPORT_SYMBOL(fsl_upm_run_pattern); | 185 | EXPORT_SYMBOL(fsl_upm_run_pattern); |
| 186 | |||
| 187 | static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl, | ||
| 188 | struct device_node *node) | ||
| 189 | { | ||
| 190 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | ||
| 191 | |||
| 192 | /* clear event registers */ | ||
| 193 | setbits32(&lbc->ltesr, LTESR_CLEAR); | ||
| 194 | out_be32(&lbc->lteatr, 0); | ||
| 195 | out_be32(&lbc->ltear, 0); | ||
| 196 | out_be32(&lbc->lteccr, LTECCR_CLEAR); | ||
| 197 | out_be32(&lbc->ltedr, LTEDR_ENABLE); | ||
| 198 | |||
| 199 | /* Set the monitor timeout value to the maximum for erratum A001 */ | ||
| 200 | if (of_device_is_compatible(node, "fsl,elbc")) | ||
| 201 | clrsetbits_be32(&lbc->lbcr, LBCR_BMT, LBCR_BMTPS); | ||
| 202 | |||
| 203 | return 0; | ||
| 204 | } | ||
| 205 | |||
| 206 | /* | ||
| 207 | * NOTE: This interrupt is used to report localbus events of various kinds, | ||
| 208 | * such as transaction errors on the chipselects. | ||
| 209 | */ | ||
| 210 | |||
| 211 | static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data) | ||
| 212 | { | ||
| 213 | struct fsl_lbc_ctrl *ctrl = data; | ||
| 214 | struct fsl_lbc_regs __iomem *lbc = ctrl->regs; | ||
| 215 | u32 status; | ||
| 216 | |||
| 217 | status = in_be32(&lbc->ltesr); | ||
| 218 | if (!status) | ||
| 219 | return IRQ_NONE; | ||
| 220 | |||
| 221 | out_be32(&lbc->ltesr, LTESR_CLEAR); | ||
| 222 | out_be32(&lbc->lteatr, 0); | ||
| 223 | out_be32(&lbc->ltear, 0); | ||
| 224 | ctrl->irq_status = status; | ||
| 225 | |||
| 226 | if (status & LTESR_BM) | ||
| 227 | dev_err(ctrl->dev, "Local bus monitor time-out: " | ||
| 228 | "LTESR 0x%08X\n", status); | ||
| 229 | if (status & LTESR_WP) | ||
| 230 | dev_err(ctrl->dev, "Write protect error: " | ||
| 231 | "LTESR 0x%08X\n", status); | ||
| 232 | if (status & LTESR_ATMW) | ||
| 233 | dev_err(ctrl->dev, "Atomic write error: " | ||
| 234 | "LTESR 0x%08X\n", status); | ||
| 235 | if (status & LTESR_ATMR) | ||
| 236 | dev_err(ctrl->dev, "Atomic read error: " | ||
| 237 | "LTESR 0x%08X\n", status); | ||
| 238 | if (status & LTESR_CS) | ||
| 239 | dev_err(ctrl->dev, "Chip select error: " | ||
| 240 | "LTESR 0x%08X\n", status); | ||
| 241 | if (status & LTESR_UPM) | ||
| 242 | ; | ||
| 243 | if (status & LTESR_FCT) { | ||
| 244 | dev_err(ctrl->dev, "FCM command time-out: " | ||
| 245 | "LTESR 0x%08X\n", status); | ||
| 246 | smp_wmb(); | ||
| 247 | wake_up(&ctrl->irq_wait); | ||
| 248 | } | ||
| 249 | if (status & LTESR_PAR) { | ||
| 250 | dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: " | ||
| 251 | "LTESR 0x%08X\n", status); | ||
| 252 | smp_wmb(); | ||
| 253 | wake_up(&ctrl->irq_wait); | ||
| 254 | } | ||
| 255 | if (status & LTESR_CC) { | ||
| 256 | smp_wmb(); | ||
| 257 | wake_up(&ctrl->irq_wait); | ||
| 258 | } | ||
| 259 | if (status & ~LTESR_MASK) | ||
| 260 | dev_err(ctrl->dev, "Unknown error: " | ||
| 261 | "LTESR 0x%08X\n", status); | ||
| 262 | return IRQ_HANDLED; | ||
| 263 | } | ||
| 264 | |||
| 265 | /* | ||
| 266 | * fsl_lbc_ctrl_probe | ||
| 267 | * | ||
| 268 | * called by device layer when it finds a device matching | ||
| 269 | * one our driver can handled. This code allocates all of | ||
| 270 | * the resources needed for the controller only. The | ||
| 271 | * resources for the NAND banks themselves are allocated | ||
| 272 | * in the chip probe function. | ||
| 273 | */ | ||
| 274 | |||
| 275 | static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev) | ||
| 276 | { | ||
| 277 | int ret; | ||
| 278 | |||
| 279 | if (!dev->dev.of_node) { | ||
| 280 | dev_err(&dev->dev, "Device OF-Node is NULL"); | ||
| 281 | return -EFAULT; | ||
| 282 | } | ||
| 283 | |||
| 284 | fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL); | ||
| 285 | if (!fsl_lbc_ctrl_dev) | ||
| 286 | return -ENOMEM; | ||
| 287 | |||
| 288 | dev_set_drvdata(&dev->dev, fsl_lbc_ctrl_dev); | ||
| 289 | |||
| 290 | spin_lock_init(&fsl_lbc_ctrl_dev->lock); | ||
| 291 | init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait); | ||
| 292 | |||
| 293 | fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0); | ||
| 294 | if (!fsl_lbc_ctrl_dev->regs) { | ||
| 295 | dev_err(&dev->dev, "failed to get memory region\n"); | ||
| 296 | ret = -ENODEV; | ||
| 297 | goto err; | ||
| 298 | } | ||
| 299 | |||
| 300 | fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0); | ||
| 301 | if (fsl_lbc_ctrl_dev->irq == NO_IRQ) { | ||
| 302 | dev_err(&dev->dev, "failed to get irq resource\n"); | ||
| 303 | ret = -ENODEV; | ||
| 304 | goto err; | ||
| 305 | } | ||
| 306 | |||
| 307 | fsl_lbc_ctrl_dev->dev = &dev->dev; | ||
| 308 | |||
| 309 | ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev, dev->dev.of_node); | ||
| 310 | if (ret < 0) | ||
| 311 | goto err; | ||
| 312 | |||
| 313 | ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0, | ||
| 314 | "fsl-lbc", fsl_lbc_ctrl_dev); | ||
| 315 | if (ret != 0) { | ||
| 316 | dev_err(&dev->dev, "failed to install irq (%d)\n", | ||
| 317 | fsl_lbc_ctrl_dev->irq); | ||
| 318 | ret = fsl_lbc_ctrl_dev->irq; | ||
| 319 | goto err; | ||
| 320 | } | ||
| 321 | |||
| 322 | /* Enable interrupts for any detected events */ | ||
| 323 | out_be32(&fsl_lbc_ctrl_dev->regs->lteir, LTEIR_ENABLE); | ||
| 324 | |||
| 325 | return 0; | ||
| 326 | |||
| 327 | err: | ||
| 328 | iounmap(fsl_lbc_ctrl_dev->regs); | ||
| 329 | kfree(fsl_lbc_ctrl_dev); | ||
| 330 | return ret; | ||
| 331 | } | ||
| 332 | |||
| 333 | static const struct of_device_id fsl_lbc_match[] = { | ||
| 334 | { .compatible = "fsl,elbc", }, | ||
| 335 | { .compatible = "fsl,pq3-localbus", }, | ||
| 336 | { .compatible = "fsl,pq2-localbus", }, | ||
| 337 | { .compatible = "fsl,pq2pro-localbus", }, | ||
| 338 | {}, | ||
| 339 | }; | ||
| 340 | |||
| 341 | static struct platform_driver fsl_lbc_ctrl_driver = { | ||
| 342 | .driver = { | ||
| 343 | .name = "fsl-lbc", | ||
| 344 | .of_match_table = fsl_lbc_match, | ||
| 345 | }, | ||
| 346 | .probe = fsl_lbc_ctrl_probe, | ||
| 347 | }; | ||
| 348 | |||
| 349 | static int __init fsl_lbc_init(void) | ||
| 350 | { | ||
| 351 | return platform_driver_register(&fsl_lbc_ctrl_driver); | ||
| 352 | } | ||
| 353 | module_init(fsl_lbc_init); | ||
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 87991d3abbab..92e78333c47c 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. | 2 | * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. |
| 3 | * | 3 | * |
| 4 | * Author: Tony Li <tony.li@freescale.com> | 4 | * Author: Tony Li <tony.li@freescale.com> |
| 5 | * Jason Jin <Jason.jin@freescale.com> | 5 | * Jason Jin <Jason.jin@freescale.com> |
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <asm/ppc-pci.h> | 24 | #include <asm/ppc-pci.h> |
| 25 | #include <asm/mpic.h> | 25 | #include <asm/mpic.h> |
| 26 | #include "fsl_msi.h" | 26 | #include "fsl_msi.h" |
| 27 | #include "fsl_pci.h" | ||
| 27 | 28 | ||
| 28 | LIST_HEAD(msi_head); | 29 | LIST_HEAD(msi_head); |
| 29 | 30 | ||
| @@ -46,14 +47,14 @@ static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg) | |||
| 46 | * We do not need this actually. The MSIR register has been read once | 47 | * We do not need this actually. The MSIR register has been read once |
| 47 | * in the cascade interrupt. So, this MSI interrupt has been acked | 48 | * in the cascade interrupt. So, this MSI interrupt has been acked |
| 48 | */ | 49 | */ |
| 49 | static void fsl_msi_end_irq(unsigned int virq) | 50 | static void fsl_msi_end_irq(struct irq_data *d) |
| 50 | { | 51 | { |
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | static struct irq_chip fsl_msi_chip = { | 54 | static struct irq_chip fsl_msi_chip = { |
| 54 | .mask = mask_msi_irq, | 55 | .irq_mask = mask_msi_irq, |
| 55 | .unmask = unmask_msi_irq, | 56 | .irq_unmask = unmask_msi_irq, |
| 56 | .ack = fsl_msi_end_irq, | 57 | .irq_ack = fsl_msi_end_irq, |
| 57 | .name = "FSL-MSI", | 58 | .name = "FSL-MSI", |
| 58 | }; | 59 | }; |
| 59 | 60 | ||
| @@ -63,10 +64,10 @@ static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, | |||
| 63 | struct fsl_msi *msi_data = h->host_data; | 64 | struct fsl_msi *msi_data = h->host_data; |
| 64 | struct irq_chip *chip = &fsl_msi_chip; | 65 | struct irq_chip *chip = &fsl_msi_chip; |
| 65 | 66 | ||
| 66 | irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_FALLING; | 67 | irq_set_status_flags(virq, IRQ_TYPE_EDGE_FALLING); |
| 67 | 68 | ||
| 68 | set_irq_chip_data(virq, msi_data); | 69 | irq_set_chip_data(virq, msi_data); |
| 69 | set_irq_chip_and_handler(virq, chip, handle_edge_irq); | 70 | irq_set_chip_and_handler(virq, chip, handle_edge_irq); |
| 70 | 71 | ||
| 71 | return 0; | 72 | return 0; |
| 72 | } | 73 | } |
| @@ -109,8 +110,8 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev) | |||
| 109 | list_for_each_entry(entry, &pdev->msi_list, list) { | 110 | list_for_each_entry(entry, &pdev->msi_list, list) { |
| 110 | if (entry->irq == NO_IRQ) | 111 | if (entry->irq == NO_IRQ) |
| 111 | continue; | 112 | continue; |
| 112 | msi_data = get_irq_data(entry->irq); | 113 | msi_data = irq_get_chip_data(entry->irq); |
| 113 | set_irq_msi(entry->irq, NULL); | 114 | irq_set_msi_desc(entry->irq, NULL); |
| 114 | msi_bitmap_free_hwirqs(&msi_data->bitmap, | 115 | msi_bitmap_free_hwirqs(&msi_data->bitmap, |
| 115 | virq_to_hw(entry->irq), 1); | 116 | virq_to_hw(entry->irq), 1); |
| 116 | irq_dispose_mapping(entry->irq); | 117 | irq_dispose_mapping(entry->irq); |
| @@ -125,13 +126,11 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq, | |||
| 125 | { | 126 | { |
| 126 | struct fsl_msi *msi_data = fsl_msi_data; | 127 | struct fsl_msi *msi_data = fsl_msi_data; |
| 127 | struct pci_controller *hose = pci_bus_to_host(pdev->bus); | 128 | struct pci_controller *hose = pci_bus_to_host(pdev->bus); |
| 128 | u32 base = 0; | 129 | u64 base = fsl_pci_immrbar_base(hose); |
| 129 | 130 | ||
| 130 | pci_bus_read_config_dword(hose->bus, | 131 | msg->address_lo = msi_data->msi_addr_lo + lower_32_bits(base); |
| 131 | PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base); | 132 | msg->address_hi = msi_data->msi_addr_hi + upper_32_bits(base); |
| 132 | 133 | ||
| 133 | msg->address_lo = msi_data->msi_addr_lo + base; | ||
| 134 | msg->address_hi = msi_data->msi_addr_hi; | ||
| 135 | msg->data = hwirq; | 134 | msg->data = hwirq; |
| 136 | 135 | ||
| 137 | pr_debug("%s: allocated srs: %d, ibs: %d\n", | 136 | pr_debug("%s: allocated srs: %d, ibs: %d\n", |
| @@ -169,8 +168,8 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
| 169 | rc = -ENOSPC; | 168 | rc = -ENOSPC; |
| 170 | goto out_free; | 169 | goto out_free; |
| 171 | } | 170 | } |
| 172 | set_irq_data(virq, msi_data); | 171 | /* chip_data is msi_data via host->hostdata in host->map() */ |
| 173 | set_irq_msi(virq, entry); | 172 | irq_set_msi_desc(virq, entry); |
| 174 | 173 | ||
| 175 | fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data); | 174 | fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data); |
| 176 | write_msi_msg(virq, &msg); | 175 | write_msi_msg(virq, &msg); |
| @@ -184,6 +183,8 @@ out_free: | |||
| 184 | 183 | ||
| 185 | static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) | 184 | static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) |
| 186 | { | 185 | { |
| 186 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
| 187 | struct irq_data *idata = irq_desc_get_irq_data(desc); | ||
| 187 | unsigned int cascade_irq; | 188 | unsigned int cascade_irq; |
| 188 | struct fsl_msi *msi_data; | 189 | struct fsl_msi *msi_data; |
| 189 | int msir_index = -1; | 190 | int msir_index = -1; |
| @@ -192,20 +193,20 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) | |||
| 192 | u32 have_shift = 0; | 193 | u32 have_shift = 0; |
| 193 | struct fsl_msi_cascade_data *cascade_data; | 194 | struct fsl_msi_cascade_data *cascade_data; |
| 194 | 195 | ||
| 195 | cascade_data = (struct fsl_msi_cascade_data *)get_irq_data(irq); | 196 | cascade_data = irq_get_handler_data(irq); |
| 196 | msi_data = cascade_data->msi_data; | 197 | msi_data = cascade_data->msi_data; |
| 197 | 198 | ||
| 198 | raw_spin_lock(&desc->lock); | 199 | raw_spin_lock(&desc->lock); |
| 199 | if ((msi_data->feature & FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) { | 200 | if ((msi_data->feature & FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) { |
| 200 | if (desc->chip->mask_ack) | 201 | if (chip->irq_mask_ack) |
| 201 | desc->chip->mask_ack(irq); | 202 | chip->irq_mask_ack(idata); |
| 202 | else { | 203 | else { |
| 203 | desc->chip->mask(irq); | 204 | chip->irq_mask(idata); |
| 204 | desc->chip->ack(irq); | 205 | chip->irq_ack(idata); |
| 205 | } | 206 | } |
| 206 | } | 207 | } |
| 207 | 208 | ||
| 208 | if (unlikely(desc->status & IRQ_INPROGRESS)) | 209 | if (unlikely(irqd_irq_inprogress(idata))) |
| 209 | goto unlock; | 210 | goto unlock; |
| 210 | 211 | ||
| 211 | msir_index = cascade_data->index; | 212 | msir_index = cascade_data->index; |
| @@ -213,7 +214,7 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) | |||
| 213 | if (msir_index >= NR_MSI_REG) | 214 | if (msir_index >= NR_MSI_REG) |
| 214 | cascade_irq = NO_IRQ; | 215 | cascade_irq = NO_IRQ; |
| 215 | 216 | ||
| 216 | desc->status |= IRQ_INPROGRESS; | 217 | irqd_set_chained_irq_inprogress(idata); |
| 217 | switch (msi_data->feature & FSL_PIC_IP_MASK) { | 218 | switch (msi_data->feature & FSL_PIC_IP_MASK) { |
| 218 | case FSL_PIC_IP_MPIC: | 219 | case FSL_PIC_IP_MPIC: |
| 219 | msir_value = fsl_msi_read(msi_data->msi_regs, | 220 | msir_value = fsl_msi_read(msi_data->msi_regs, |
| @@ -235,15 +236,15 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) | |||
| 235 | have_shift += intr_index + 1; | 236 | have_shift += intr_index + 1; |
| 236 | msir_value = msir_value >> (intr_index + 1); | 237 | msir_value = msir_value >> (intr_index + 1); |
| 237 | } | 238 | } |
| 238 | desc->status &= ~IRQ_INPROGRESS; | 239 | irqd_clr_chained_irq_inprogress(idata); |
| 239 | 240 | ||
| 240 | switch (msi_data->feature & FSL_PIC_IP_MASK) { | 241 | switch (msi_data->feature & FSL_PIC_IP_MASK) { |
| 241 | case FSL_PIC_IP_MPIC: | 242 | case FSL_PIC_IP_MPIC: |
| 242 | desc->chip->eoi(irq); | 243 | chip->irq_eoi(idata); |
| 243 | break; | 244 | break; |
| 244 | case FSL_PIC_IP_IPIC: | 245 | case FSL_PIC_IP_IPIC: |
| 245 | if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) | 246 | if (!irqd_irq_disabled(idata) && chip->irq_unmask) |
| 246 | desc->chip->unmask(irq); | 247 | chip->irq_unmask(idata); |
| 247 | break; | 248 | break; |
| 248 | } | 249 | } |
| 249 | unlock: | 250 | unlock: |
| @@ -252,7 +253,7 @@ unlock: | |||
| 252 | 253 | ||
| 253 | static int fsl_of_msi_remove(struct platform_device *ofdev) | 254 | static int fsl_of_msi_remove(struct platform_device *ofdev) |
| 254 | { | 255 | { |
| 255 | struct fsl_msi *msi = ofdev->dev.platform_data; | 256 | struct fsl_msi *msi = platform_get_drvdata(ofdev); |
| 256 | int virq, i; | 257 | int virq, i; |
| 257 | struct fsl_msi_cascade_data *cascade_data; | 258 | struct fsl_msi_cascade_data *cascade_data; |
| 258 | 259 | ||
| @@ -261,7 +262,7 @@ static int fsl_of_msi_remove(struct platform_device *ofdev) | |||
| 261 | for (i = 0; i < NR_MSI_REG; i++) { | 262 | for (i = 0; i < NR_MSI_REG; i++) { |
| 262 | virq = msi->msi_virqs[i]; | 263 | virq = msi->msi_virqs[i]; |
| 263 | if (virq != NO_IRQ) { | 264 | if (virq != NO_IRQ) { |
| 264 | cascade_data = get_irq_data(virq); | 265 | cascade_data = irq_get_handler_data(virq); |
| 265 | kfree(cascade_data); | 266 | kfree(cascade_data); |
| 266 | irq_dispose_mapping(virq); | 267 | irq_dispose_mapping(virq); |
| 267 | } | 268 | } |
| @@ -274,19 +275,53 @@ static int fsl_of_msi_remove(struct platform_device *ofdev) | |||
| 274 | return 0; | 275 | return 0; |
| 275 | } | 276 | } |
| 276 | 277 | ||
| 277 | static int __devinit fsl_of_msi_probe(struct platform_device *dev, | 278 | static int __devinit fsl_msi_setup_hwirq(struct fsl_msi *msi, |
| 278 | const struct of_device_id *match) | 279 | struct platform_device *dev, |
| 280 | int offset, int irq_index) | ||
| 279 | { | 281 | { |
| 282 | struct fsl_msi_cascade_data *cascade_data = NULL; | ||
| 283 | int virt_msir; | ||
| 284 | |||
| 285 | virt_msir = irq_of_parse_and_map(dev->dev.of_node, irq_index); | ||
| 286 | if (virt_msir == NO_IRQ) { | ||
| 287 | dev_err(&dev->dev, "%s: Cannot translate IRQ index %d\n", | ||
| 288 | __func__, irq_index); | ||
| 289 | return 0; | ||
| 290 | } | ||
| 291 | |||
| 292 | cascade_data = kzalloc(sizeof(struct fsl_msi_cascade_data), GFP_KERNEL); | ||
| 293 | if (!cascade_data) { | ||
| 294 | dev_err(&dev->dev, "No memory for MSI cascade data\n"); | ||
| 295 | return -ENOMEM; | ||
| 296 | } | ||
| 297 | |||
| 298 | msi->msi_virqs[irq_index] = virt_msir; | ||
| 299 | cascade_data->index = offset + irq_index; | ||
| 300 | cascade_data->msi_data = msi; | ||
| 301 | irq_set_handler_data(virt_msir, cascade_data); | ||
| 302 | irq_set_chained_handler(virt_msir, fsl_msi_cascade); | ||
| 303 | |||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | |||
| 307 | static const struct of_device_id fsl_of_msi_ids[]; | ||
| 308 | static int __devinit fsl_of_msi_probe(struct platform_device *dev) | ||
| 309 | { | ||
| 310 | const struct of_device_id *match; | ||
| 280 | struct fsl_msi *msi; | 311 | struct fsl_msi *msi; |
| 281 | struct resource res; | 312 | struct resource res; |
| 282 | int err, i, count; | 313 | int err, i, j, irq_index, count; |
| 283 | int rc; | 314 | int rc; |
| 284 | int virt_msir; | ||
| 285 | const u32 *p; | 315 | const u32 *p; |
| 286 | struct fsl_msi_feature *features = match->data; | 316 | struct fsl_msi_feature *features; |
| 287 | struct fsl_msi_cascade_data *cascade_data = NULL; | ||
| 288 | int len; | 317 | int len; |
| 289 | u32 offset; | 318 | u32 offset; |
| 319 | static const u32 all_avail[] = { 0, NR_MSI_IRQS }; | ||
| 320 | |||
| 321 | match = of_match_device(fsl_of_msi_ids, &dev->dev); | ||
| 322 | if (!match) | ||
| 323 | return -EINVAL; | ||
| 324 | features = match->data; | ||
| 290 | 325 | ||
| 291 | printk(KERN_DEBUG "Setting up Freescale MSI support\n"); | 326 | printk(KERN_DEBUG "Setting up Freescale MSI support\n"); |
| 292 | 327 | ||
| @@ -295,7 +330,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev, | |||
| 295 | dev_err(&dev->dev, "No memory for MSI structure\n"); | 330 | dev_err(&dev->dev, "No memory for MSI structure\n"); |
| 296 | return -ENOMEM; | 331 | return -ENOMEM; |
| 297 | } | 332 | } |
| 298 | dev->dev.platform_data = msi; | 333 | platform_set_drvdata(dev, msi); |
| 299 | 334 | ||
| 300 | msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR, | 335 | msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR, |
| 301 | NR_MSI_IRQS, &fsl_msi_host_ops, 0); | 336 | NR_MSI_IRQS, &fsl_msi_host_ops, 0); |
| @@ -333,42 +368,34 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev, | |||
| 333 | goto error_out; | 368 | goto error_out; |
| 334 | } | 369 | } |
| 335 | 370 | ||
| 336 | p = of_get_property(dev->dev.of_node, "interrupts", &count); | 371 | p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len); |
| 337 | if (!p) { | 372 | if (p && len % (2 * sizeof(u32)) != 0) { |
| 338 | dev_err(&dev->dev, "no interrupts property found on %s\n", | 373 | dev_err(&dev->dev, "%s: Malformed msi-available-ranges property\n", |
| 339 | dev->dev.of_node->full_name); | 374 | __func__); |
| 340 | err = -ENODEV; | ||
| 341 | goto error_out; | ||
| 342 | } | ||
| 343 | if (count % 8 != 0) { | ||
| 344 | dev_err(&dev->dev, "Malformed interrupts property on %s\n", | ||
| 345 | dev->dev.of_node->full_name); | ||
| 346 | err = -EINVAL; | 375 | err = -EINVAL; |
| 347 | goto error_out; | 376 | goto error_out; |
| 348 | } | 377 | } |
| 349 | offset = 0; | 378 | |
| 350 | p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len); | 379 | if (!p) |
| 351 | if (p) | 380 | p = all_avail; |
| 352 | offset = *p / IRQS_PER_MSI_REG; | 381 | |
| 353 | 382 | for (irq_index = 0, i = 0; i < len / (2 * sizeof(u32)); i++) { | |
| 354 | count /= sizeof(u32); | 383 | if (p[i * 2] % IRQS_PER_MSI_REG || |
| 355 | for (i = 0; i < min(count / 2, NR_MSI_REG); i++) { | 384 | p[i * 2 + 1] % IRQS_PER_MSI_REG) { |
| 356 | virt_msir = irq_of_parse_and_map(dev->dev.of_node, i); | 385 | printk(KERN_WARNING "%s: %s: msi available range of %u at %u is not IRQ-aligned\n", |
| 357 | if (virt_msir != NO_IRQ) { | 386 | __func__, dev->dev.of_node->full_name, |
| 358 | cascade_data = kzalloc( | 387 | p[i * 2 + 1], p[i * 2]); |
| 359 | sizeof(struct fsl_msi_cascade_data), | 388 | err = -EINVAL; |
| 360 | GFP_KERNEL); | 389 | goto error_out; |
| 361 | if (!cascade_data) { | 390 | } |
| 362 | dev_err(&dev->dev, | 391 | |
| 363 | "No memory for MSI cascade data\n"); | 392 | offset = p[i * 2] / IRQS_PER_MSI_REG; |
| 364 | err = -ENOMEM; | 393 | count = p[i * 2 + 1] / IRQS_PER_MSI_REG; |
| 394 | |||
| 395 | for (j = 0; j < count; j++, irq_index++) { | ||
| 396 | err = fsl_msi_setup_hwirq(msi, dev, offset, irq_index); | ||
| 397 | if (err) | ||
| 365 | goto error_out; | 398 | goto error_out; |
| 366 | } | ||
| 367 | msi->msi_virqs[i] = virt_msir; | ||
| 368 | cascade_data->index = i + offset; | ||
| 369 | cascade_data->msi_data = msi; | ||
| 370 | set_irq_data(virt_msir, (void *)cascade_data); | ||
| 371 | set_irq_chained_handler(virt_msir, fsl_msi_cascade); | ||
| 372 | } | 399 | } |
| 373 | } | 400 | } |
| 374 | 401 | ||
| @@ -412,7 +439,7 @@ static const struct of_device_id fsl_of_msi_ids[] = { | |||
| 412 | {} | 439 | {} |
| 413 | }; | 440 | }; |
| 414 | 441 | ||
| 415 | static struct of_platform_driver fsl_of_msi_driver = { | 442 | static struct platform_driver fsl_of_msi_driver = { |
| 416 | .driver = { | 443 | .driver = { |
| 417 | .name = "fsl-msi", | 444 | .name = "fsl-msi", |
| 418 | .owner = THIS_MODULE, | 445 | .owner = THIS_MODULE, |
| @@ -424,7 +451,7 @@ static struct of_platform_driver fsl_of_msi_driver = { | |||
| 424 | 451 | ||
| 425 | static __init int fsl_of_msi_init(void) | 452 | static __init int fsl_of_msi_init(void) |
| 426 | { | 453 | { |
| 427 | return of_register_platform_driver(&fsl_of_msi_driver); | 454 | return platform_driver_register(&fsl_of_msi_driver); |
| 428 | } | 455 | } |
| 429 | 456 | ||
| 430 | subsys_initcall(fsl_of_msi_init); | 457 | subsys_initcall(fsl_of_msi_init); |
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 4ae933225251..68ca9290df94 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * MPC83xx/85xx/86xx PCI/PCIE support routing. | 2 | * MPC83xx/85xx/86xx PCI/PCIE support routing. |
| 3 | * | 3 | * |
| 4 | * Copyright 2007-2009 Freescale Semiconductor, Inc. | 4 | * Copyright 2007-2011 Freescale Semiconductor, Inc. |
| 5 | * Copyright 2008-2009 MontaVista Software, Inc. | 5 | * Copyright 2008-2009 MontaVista Software, Inc. |
| 6 | * | 6 | * |
| 7 | * Initial author: Xianghua Xiao <x.xiao@freescale.com> | 7 | * Initial author: Xianghua Xiao <x.xiao@freescale.com> |
| @@ -34,7 +34,7 @@ | |||
| 34 | #include <sysdev/fsl_soc.h> | 34 | #include <sysdev/fsl_soc.h> |
| 35 | #include <sysdev/fsl_pci.h> | 35 | #include <sysdev/fsl_pci.h> |
| 36 | 36 | ||
| 37 | static int fsl_pcie_bus_fixup; | 37 | static int fsl_pcie_bus_fixup, is_mpc83xx_pci; |
| 38 | 38 | ||
| 39 | static void __init quirk_fsl_pcie_header(struct pci_dev *dev) | 39 | static void __init quirk_fsl_pcie_header(struct pci_dev *dev) |
| 40 | { | 40 | { |
| @@ -99,7 +99,7 @@ static void __init setup_pci_atmu(struct pci_controller *hose, | |||
| 99 | struct resource *rsrc) | 99 | struct resource *rsrc) |
| 100 | { | 100 | { |
| 101 | struct ccsr_pci __iomem *pci; | 101 | struct ccsr_pci __iomem *pci; |
| 102 | int i, j, n, mem_log, win_idx = 2; | 102 | int i, j, n, mem_log, win_idx = 3, start_idx = 1, end_idx = 4; |
| 103 | u64 mem, sz, paddr_hi = 0; | 103 | u64 mem, sz, paddr_hi = 0; |
| 104 | u64 paddr_lo = ULLONG_MAX; | 104 | u64 paddr_lo = ULLONG_MAX; |
| 105 | u32 pcicsrbar = 0, pcicsrbar_sz; | 105 | u32 pcicsrbar = 0, pcicsrbar_sz; |
| @@ -109,6 +109,13 @@ static void __init setup_pci_atmu(struct pci_controller *hose, | |||
| 109 | 109 | ||
| 110 | pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", | 110 | pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", |
| 111 | (u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1); | 111 | (u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1); |
| 112 | |||
| 113 | if (of_device_is_compatible(hose->dn, "fsl,qoriq-pcie-v2.2")) { | ||
| 114 | win_idx = 2; | ||
| 115 | start_idx = 0; | ||
| 116 | end_idx = 3; | ||
| 117 | } | ||
| 118 | |||
| 112 | pci = ioremap(rsrc->start, rsrc->end - rsrc->start + 1); | 119 | pci = ioremap(rsrc->start, rsrc->end - rsrc->start + 1); |
| 113 | if (!pci) { | 120 | if (!pci) { |
| 114 | dev_err(hose->parent, "Unable to map ATMU registers\n"); | 121 | dev_err(hose->parent, "Unable to map ATMU registers\n"); |
| @@ -118,7 +125,7 @@ static void __init setup_pci_atmu(struct pci_controller *hose, | |||
| 118 | /* Disable all windows (except powar0 since it's ignored) */ | 125 | /* Disable all windows (except powar0 since it's ignored) */ |
| 119 | for(i = 1; i < 5; i++) | 126 | for(i = 1; i < 5; i++) |
| 120 | out_be32(&pci->pow[i].powar, 0); | 127 | out_be32(&pci->pow[i].powar, 0); |
| 121 | for(i = 0; i < 3; i++) | 128 | for (i = start_idx; i < end_idx; i++) |
| 122 | out_be32(&pci->piw[i].piwar, 0); | 129 | out_be32(&pci->piw[i].piwar, 0); |
| 123 | 130 | ||
| 124 | /* Setup outbound MEM window */ | 131 | /* Setup outbound MEM window */ |
| @@ -204,7 +211,7 @@ static void __init setup_pci_atmu(struct pci_controller *hose, | |||
| 204 | mem_log++; | 211 | mem_log++; |
| 205 | } | 212 | } |
| 206 | 213 | ||
| 207 | piwar |= (mem_log - 1); | 214 | piwar |= ((mem_log - 1) & PIWAR_SZ_MASK); |
| 208 | 215 | ||
| 209 | /* Setup inbound memory window */ | 216 | /* Setup inbound memory window */ |
| 210 | out_be32(&pci->piw[win_idx].pitar, 0x00000000); | 217 | out_be32(&pci->piw[win_idx].pitar, 0x00000000); |
| @@ -317,6 +324,11 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) | |||
| 317 | struct resource rsrc; | 324 | struct resource rsrc; |
| 318 | const int *bus_range; | 325 | const int *bus_range; |
| 319 | 326 | ||
| 327 | if (!of_device_is_available(dev)) { | ||
| 328 | pr_warning("%s: disabled\n", dev->full_name); | ||
| 329 | return -ENODEV; | ||
| 330 | } | ||
| 331 | |||
| 320 | pr_debug("Adding PCI host bridge %s\n", dev->full_name); | 332 | pr_debug("Adding PCI host bridge %s\n", dev->full_name); |
| 321 | 333 | ||
| 322 | /* Fetch host bridge registers address */ | 334 | /* Fetch host bridge registers address */ |
| @@ -407,10 +419,18 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010E, quirk_fsl_pcie_header); | |||
| 407 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010, quirk_fsl_pcie_header); | 419 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010, quirk_fsl_pcie_header); |
| 408 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020E, quirk_fsl_pcie_header); | 420 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020E, quirk_fsl_pcie_header); |
| 409 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020, quirk_fsl_pcie_header); | 421 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020, quirk_fsl_pcie_header); |
| 422 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2040E, quirk_fsl_pcie_header); | ||
| 423 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2040, quirk_fsl_pcie_header); | ||
| 424 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P3041E, quirk_fsl_pcie_header); | ||
| 425 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P3041, quirk_fsl_pcie_header); | ||
| 410 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040E, quirk_fsl_pcie_header); | 426 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040E, quirk_fsl_pcie_header); |
| 411 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040, quirk_fsl_pcie_header); | 427 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040, quirk_fsl_pcie_header); |
| 412 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080E, quirk_fsl_pcie_header); | 428 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080E, quirk_fsl_pcie_header); |
| 413 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080, quirk_fsl_pcie_header); | 429 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080, quirk_fsl_pcie_header); |
| 430 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5010E, quirk_fsl_pcie_header); | ||
| 431 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5010, quirk_fsl_pcie_header); | ||
| 432 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5020E, quirk_fsl_pcie_header); | ||
| 433 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5020, quirk_fsl_pcie_header); | ||
| 414 | #endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */ | 434 | #endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */ |
| 415 | 435 | ||
| 416 | #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x) | 436 | #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x) |
| @@ -430,6 +450,13 @@ struct mpc83xx_pcie_priv { | |||
| 430 | u32 dev_base; | 450 | u32 dev_base; |
| 431 | }; | 451 | }; |
| 432 | 452 | ||
| 453 | struct pex_inbound_window { | ||
| 454 | u32 ar; | ||
| 455 | u32 tar; | ||
| 456 | u32 barl; | ||
| 457 | u32 barh; | ||
| 458 | }; | ||
| 459 | |||
| 433 | /* | 460 | /* |
| 434 | * With the convention of u-boot, the PCIE outbound window 0 serves | 461 | * With the convention of u-boot, the PCIE outbound window 0 serves |
| 435 | * as configuration transactions outbound. | 462 | * as configuration transactions outbound. |
| @@ -437,6 +464,8 @@ struct mpc83xx_pcie_priv { | |||
| 437 | #define PEX_OUTWIN0_BAR 0xCA4 | 464 | #define PEX_OUTWIN0_BAR 0xCA4 |
| 438 | #define PEX_OUTWIN0_TAL 0xCA8 | 465 | #define PEX_OUTWIN0_TAL 0xCA8 |
| 439 | #define PEX_OUTWIN0_TAH 0xCAC | 466 | #define PEX_OUTWIN0_TAH 0xCAC |
| 467 | #define PEX_RC_INWIN_BASE 0xE60 | ||
| 468 | #define PEX_RCIWARn_EN 0x1 | ||
| 440 | 469 | ||
| 441 | static int mpc83xx_pcie_exclude_device(struct pci_bus *bus, unsigned int devfn) | 470 | static int mpc83xx_pcie_exclude_device(struct pci_bus *bus, unsigned int devfn) |
| 442 | { | 471 | { |
| @@ -604,6 +633,8 @@ int __init mpc83xx_add_bridge(struct device_node *dev) | |||
| 604 | const int *bus_range; | 633 | const int *bus_range; |
| 605 | int primary; | 634 | int primary; |
| 606 | 635 | ||
| 636 | is_mpc83xx_pci = 1; | ||
| 637 | |||
| 607 | if (!of_device_is_available(dev)) { | 638 | if (!of_device_is_available(dev)) { |
| 608 | pr_warning("%s: disabled by the firmware.\n", | 639 | pr_warning("%s: disabled by the firmware.\n", |
| 609 | dev->full_name); | 640 | dev->full_name); |
| @@ -683,3 +714,40 @@ err0: | |||
| 683 | return ret; | 714 | return ret; |
| 684 | } | 715 | } |
| 685 | #endif /* CONFIG_PPC_83xx */ | 716 | #endif /* CONFIG_PPC_83xx */ |
| 717 | |||
| 718 | u64 fsl_pci_immrbar_base(struct pci_controller *hose) | ||
| 719 | { | ||
| 720 | #ifdef CONFIG_PPC_83xx | ||
| 721 | if (is_mpc83xx_pci) { | ||
| 722 | struct mpc83xx_pcie_priv *pcie = hose->dn->data; | ||
| 723 | struct pex_inbound_window *in; | ||
| 724 | int i; | ||
| 725 | |||
| 726 | /* Walk the Root Complex Inbound windows to match IMMR base */ | ||
| 727 | in = pcie->cfg_type0 + PEX_RC_INWIN_BASE; | ||
| 728 | for (i = 0; i < 4; i++) { | ||
| 729 | /* not enabled, skip */ | ||
| 730 | if (!in_le32(&in[i].ar) & PEX_RCIWARn_EN) | ||
| 731 | continue; | ||
| 732 | |||
| 733 | if (get_immrbase() == in_le32(&in[i].tar)) | ||
| 734 | return (u64)in_le32(&in[i].barh) << 32 | | ||
| 735 | in_le32(&in[i].barl); | ||
| 736 | } | ||
| 737 | |||
| 738 | printk(KERN_WARNING "could not find PCI BAR matching IMMR\n"); | ||
| 739 | } | ||
| 740 | #endif | ||
| 741 | |||
| 742 | #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx) | ||
| 743 | if (!is_mpc83xx_pci) { | ||
| 744 | u32 base; | ||
| 745 | |||
| 746 | pci_bus_read_config_dword(hose->bus, | ||
| 747 | PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base); | ||
| 748 | return base; | ||
| 749 | } | ||
| 750 | #endif | ||
| 751 | |||
| 752 | return 0; | ||
| 753 | } | ||
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h index a9d8bbebed80..a39ed5cc2c5a 100644 --- a/arch/powerpc/sysdev/fsl_pci.h +++ b/arch/powerpc/sysdev/fsl_pci.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * MPC85xx/86xx PCI Express structure define | 2 | * MPC85xx/86xx PCI Express structure define |
| 3 | * | 3 | * |
| 4 | * Copyright 2007 Freescale Semiconductor, Inc | 4 | * Copyright 2007,2011 Freescale Semiconductor, Inc |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
| @@ -21,6 +21,7 @@ | |||
| 21 | #define PIWAR_TGI_LOCAL 0x00f00000 /* target - local memory */ | 21 | #define PIWAR_TGI_LOCAL 0x00f00000 /* target - local memory */ |
| 22 | #define PIWAR_READ_SNOOP 0x00050000 | 22 | #define PIWAR_READ_SNOOP 0x00050000 |
| 23 | #define PIWAR_WRITE_SNOOP 0x00005000 | 23 | #define PIWAR_WRITE_SNOOP 0x00005000 |
| 24 | #define PIWAR_SZ_MASK 0x0000003f | ||
| 24 | 25 | ||
| 25 | /* PCI/PCI Express outbound window reg */ | 26 | /* PCI/PCI Express outbound window reg */ |
| 26 | struct pci_outbound_window_regs { | 27 | struct pci_outbound_window_regs { |
| @@ -49,7 +50,9 @@ struct ccsr_pci { | |||
| 49 | __be32 int_ack; /* 0x.008 - PCI Interrupt Acknowledge Register */ | 50 | __be32 int_ack; /* 0x.008 - PCI Interrupt Acknowledge Register */ |
| 50 | __be32 pex_otb_cpl_tor; /* 0x.00c - PCIE Outbound completion timeout register */ | 51 | __be32 pex_otb_cpl_tor; /* 0x.00c - PCIE Outbound completion timeout register */ |
| 51 | __be32 pex_conf_tor; /* 0x.010 - PCIE configuration timeout register */ | 52 | __be32 pex_conf_tor; /* 0x.010 - PCIE configuration timeout register */ |
| 52 | u8 res2[12]; | 53 | __be32 pex_config; /* 0x.014 - PCIE CONFIG Register */ |
| 54 | __be32 pex_int_status; /* 0x.018 - PCIE interrupt status */ | ||
| 55 | u8 res2[4]; | ||
| 53 | __be32 pex_pme_mes_dr; /* 0x.020 - PCIE PME and message detect register */ | 56 | __be32 pex_pme_mes_dr; /* 0x.020 - PCIE PME and message detect register */ |
| 54 | __be32 pex_pme_mes_disr; /* 0x.024 - PCIE PME and message disable register */ | 57 | __be32 pex_pme_mes_disr; /* 0x.024 - PCIE PME and message disable register */ |
| 55 | __be32 pex_pme_mes_ier; /* 0x.028 - PCIE PME and message interrupt enable register */ | 58 | __be32 pex_pme_mes_ier; /* 0x.028 - PCIE PME and message interrupt enable register */ |
| @@ -62,14 +65,14 @@ struct ccsr_pci { | |||
| 62 | * in all of the other outbound windows. | 65 | * in all of the other outbound windows. |
| 63 | */ | 66 | */ |
| 64 | struct pci_outbound_window_regs pow[5]; | 67 | struct pci_outbound_window_regs pow[5]; |
| 65 | 68 | u8 res14[96]; | |
| 66 | u8 res14[256]; | 69 | struct pci_inbound_window_regs pmit; /* 0xd00 - 0xd9c Inbound MSI */ |
| 67 | 70 | u8 res6[96]; | |
| 68 | /* PCI/PCI Express inbound window 3-1 | 71 | /* PCI/PCI Express inbound window 3-0 |
| 69 | * inbound window 1 supports only a 32-bit base address and does not | 72 | * inbound window 1 supports only a 32-bit base address and does not |
| 70 | * define an inbound window base extended address register. | 73 | * define an inbound window base extended address register. |
| 71 | */ | 74 | */ |
| 72 | struct pci_inbound_window_regs piw[3]; | 75 | struct pci_inbound_window_regs piw[4]; |
| 73 | 76 | ||
| 74 | __be32 pex_err_dr; /* 0x.e00 - PCI/PCIE error detect register */ | 77 | __be32 pex_err_dr; /* 0x.e00 - PCI/PCIE error detect register */ |
| 75 | u8 res21[4]; | 78 | u8 res21[4]; |
| @@ -88,6 +91,7 @@ struct ccsr_pci { | |||
| 88 | extern int fsl_add_bridge(struct device_node *dev, int is_primary); | 91 | extern int fsl_add_bridge(struct device_node *dev, int is_primary); |
| 89 | extern void fsl_pcibios_fixup_bus(struct pci_bus *bus); | 92 | extern void fsl_pcibios_fixup_bus(struct pci_bus *bus); |
| 90 | extern int mpc83xx_add_bridge(struct device_node *dev); | 93 | extern int mpc83xx_add_bridge(struct device_node *dev); |
| 94 | u64 fsl_pci_immrbar_base(struct pci_controller *hose); | ||
| 91 | 95 | ||
| 92 | #endif /* __POWERPC_FSL_PCI_H */ | 96 | #endif /* __POWERPC_FSL_PCI_H */ |
| 93 | #endif /* __KERNEL__ */ | 97 | #endif /* __KERNEL__ */ |
diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c index 44de8559c975..f122e8961d32 100644 --- a/arch/powerpc/sysdev/fsl_pmc.c +++ b/arch/powerpc/sysdev/fsl_pmc.c | |||
| @@ -53,13 +53,12 @@ static int pmc_suspend_valid(suspend_state_t state) | |||
| 53 | return 1; | 53 | return 1; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | static struct platform_suspend_ops pmc_suspend_ops = { | 56 | static const struct platform_suspend_ops pmc_suspend_ops = { |
| 57 | .valid = pmc_suspend_valid, | 57 | .valid = pmc_suspend_valid, |
| 58 | .enter = pmc_suspend_enter, | 58 | .enter = pmc_suspend_enter, |
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | static int pmc_probe(struct platform_device *ofdev, | 61 | static int pmc_probe(struct platform_device *ofdev) |
| 62 | const struct of_device_id *id) | ||
| 63 | { | 62 | { |
| 64 | pmc_regs = of_iomap(ofdev->dev.of_node, 0); | 63 | pmc_regs = of_iomap(ofdev->dev.of_node, 0); |
| 65 | if (!pmc_regs) | 64 | if (!pmc_regs) |
| @@ -76,7 +75,7 @@ static const struct of_device_id pmc_ids[] = { | |||
| 76 | { }, | 75 | { }, |
| 77 | }; | 76 | }; |
| 78 | 77 | ||
| 79 | static struct of_platform_driver pmc_driver = { | 78 | static struct platform_driver pmc_driver = { |
| 80 | .driver = { | 79 | .driver = { |
| 81 | .name = "fsl-pmc", | 80 | .name = "fsl-pmc", |
| 82 | .owner = THIS_MODULE, | 81 | .owner = THIS_MODULE, |
| @@ -87,6 +86,6 @@ static struct of_platform_driver pmc_driver = { | |||
| 87 | 86 | ||
| 88 | static int __init pmc_init(void) | 87 | static int __init pmc_init(void) |
| 89 | { | 88 | { |
| 90 | return of_register_platform_driver(&pmc_driver); | 89 | return platform_driver_register(&pmc_driver); |
| 91 | } | 90 | } |
| 92 | device_initcall(pmc_init); | 91 | device_initcall(pmc_init); |
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index 3017532319c8..b3fd081d56f5 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | * - Added Port-Write message handling | 10 | * - Added Port-Write message handling |
| 11 | * - Added Machine Check exception handling | 11 | * - Added Machine Check exception handling |
| 12 | * | 12 | * |
| 13 | * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc. | 13 | * Copyright (C) 2007, 2008, 2010 Freescale Semiconductor, Inc. |
| 14 | * Zhang Wei <wei.zhang@freescale.com> | 14 | * Zhang Wei <wei.zhang@freescale.com> |
| 15 | * | 15 | * |
| 16 | * Copyright 2005 MontaVista Software, Inc. | 16 | * Copyright 2005 MontaVista Software, Inc. |
| @@ -47,14 +47,33 @@ | |||
| 47 | #define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq) | 47 | #define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq) |
| 48 | #define IRQ_RIO_PW(m) (((struct rio_priv *)(m->priv))->pwirq) | 48 | #define IRQ_RIO_PW(m) (((struct rio_priv *)(m->priv))->pwirq) |
| 49 | 49 | ||
| 50 | #define IPWSR_CLEAR 0x98 | ||
| 51 | #define OMSR_CLEAR 0x1cb3 | ||
| 52 | #define IMSR_CLEAR 0x491 | ||
| 53 | #define IDSR_CLEAR 0x91 | ||
| 54 | #define ODSR_CLEAR 0x1c00 | ||
| 55 | #define LTLEECSR_ENABLE_ALL 0xFFC000FC | ||
| 56 | #define ESCSR_CLEAR 0x07120204 | ||
| 57 | |||
| 58 | #define RIO_PORT1_EDCSR 0x0640 | ||
| 59 | #define RIO_PORT2_EDCSR 0x0680 | ||
| 60 | #define RIO_PORT1_IECSR 0x10130 | ||
| 61 | #define RIO_PORT2_IECSR 0x101B0 | ||
| 62 | #define RIO_IM0SR 0x13064 | ||
| 63 | #define RIO_IM1SR 0x13164 | ||
| 64 | #define RIO_OM0SR 0x13004 | ||
| 65 | #define RIO_OM1SR 0x13104 | ||
| 66 | |||
| 50 | #define RIO_ATMU_REGS_OFFSET 0x10c00 | 67 | #define RIO_ATMU_REGS_OFFSET 0x10c00 |
| 51 | #define RIO_P_MSG_REGS_OFFSET 0x11000 | 68 | #define RIO_P_MSG_REGS_OFFSET 0x11000 |
| 52 | #define RIO_S_MSG_REGS_OFFSET 0x13000 | 69 | #define RIO_S_MSG_REGS_OFFSET 0x13000 |
| 70 | #define RIO_GCCSR 0x13c | ||
| 53 | #define RIO_ESCSR 0x158 | 71 | #define RIO_ESCSR 0x158 |
| 72 | #define RIO_PORT2_ESCSR 0x178 | ||
| 54 | #define RIO_CCSR 0x15c | 73 | #define RIO_CCSR 0x15c |
| 55 | #define RIO_LTLEDCSR 0x0608 | 74 | #define RIO_LTLEDCSR 0x0608 |
| 56 | #define RIO_LTLEDCSR_IER 0x80000000 | 75 | #define RIO_LTLEDCSR_IER 0x80000000 |
| 57 | #define RIO_LTLEDCSR_PRT 0x01000000 | 76 | #define RIO_LTLEDCSR_PRT 0x01000000 |
| 58 | #define RIO_LTLEECSR 0x060c | 77 | #define RIO_LTLEECSR 0x060c |
| 59 | #define RIO_EPWISR 0x10010 | 78 | #define RIO_EPWISR 0x10010 |
| 60 | #define RIO_ISR_AACR 0x10120 | 79 | #define RIO_ISR_AACR 0x10120 |
| @@ -87,6 +106,12 @@ | |||
| 87 | #define RIO_IPWSR_PWD 0x00000008 | 106 | #define RIO_IPWSR_PWD 0x00000008 |
| 88 | #define RIO_IPWSR_PWB 0x00000004 | 107 | #define RIO_IPWSR_PWB 0x00000004 |
| 89 | 108 | ||
| 109 | /* EPWISR Error match value */ | ||
| 110 | #define RIO_EPWISR_PINT1 0x80000000 | ||
| 111 | #define RIO_EPWISR_PINT2 0x40000000 | ||
| 112 | #define RIO_EPWISR_MU 0x00000002 | ||
| 113 | #define RIO_EPWISR_PW 0x00000001 | ||
| 114 | |||
| 90 | #define RIO_MSG_DESC_SIZE 32 | 115 | #define RIO_MSG_DESC_SIZE 32 |
| 91 | #define RIO_MSG_BUFFER_SIZE 4096 | 116 | #define RIO_MSG_BUFFER_SIZE 4096 |
| 92 | #define RIO_MIN_TX_RING_SIZE 2 | 117 | #define RIO_MIN_TX_RING_SIZE 2 |
| @@ -117,44 +142,59 @@ struct rio_atmu_regs { | |||
| 117 | }; | 142 | }; |
| 118 | 143 | ||
| 119 | struct rio_msg_regs { | 144 | struct rio_msg_regs { |
| 120 | u32 omr; | 145 | u32 omr; /* 0xD_3000 - Outbound message 0 mode register */ |
| 121 | u32 osr; | 146 | u32 osr; /* 0xD_3004 - Outbound message 0 status register */ |
| 122 | u32 pad1; | 147 | u32 pad1; |
| 123 | u32 odqdpar; | 148 | u32 odqdpar; /* 0xD_300C - Outbound message 0 descriptor queue |
| 149 | dequeue pointer address register */ | ||
| 124 | u32 pad2; | 150 | u32 pad2; |
| 125 | u32 osar; | 151 | u32 osar; /* 0xD_3014 - Outbound message 0 source address |
| 126 | u32 odpr; | 152 | register */ |
| 127 | u32 odatr; | 153 | u32 odpr; /* 0xD_3018 - Outbound message 0 destination port |
| 128 | u32 odcr; | 154 | register */ |
| 155 | u32 odatr; /* 0xD_301C - Outbound message 0 destination attributes | ||
| 156 | Register*/ | ||
| 157 | u32 odcr; /* 0xD_3020 - Outbound message 0 double-word count | ||
| 158 | register */ | ||
| 129 | u32 pad3; | 159 | u32 pad3; |
| 130 | u32 odqepar; | 160 | u32 odqepar; /* 0xD_3028 - Outbound message 0 descriptor queue |
| 161 | enqueue pointer address register */ | ||
| 131 | u32 pad4[13]; | 162 | u32 pad4[13]; |
| 132 | u32 imr; | 163 | u32 imr; /* 0xD_3060 - Inbound message 0 mode register */ |
| 133 | u32 isr; | 164 | u32 isr; /* 0xD_3064 - Inbound message 0 status register */ |
| 134 | u32 pad5; | 165 | u32 pad5; |
| 135 | u32 ifqdpar; | 166 | u32 ifqdpar; /* 0xD_306C - Inbound message 0 frame queue dequeue |
| 167 | pointer address register*/ | ||
| 136 | u32 pad6; | 168 | u32 pad6; |
| 137 | u32 ifqepar; | 169 | u32 ifqepar; /* 0xD_3074 - Inbound message 0 frame queue enqueue |
| 170 | pointer address register */ | ||
| 138 | u32 pad7[226]; | 171 | u32 pad7[226]; |
| 139 | u32 odmr; | 172 | u32 odmr; /* 0xD_3400 - Outbound doorbell mode register */ |
| 140 | u32 odsr; | 173 | u32 odsr; /* 0xD_3404 - Outbound doorbell status register */ |
| 141 | u32 res0[4]; | 174 | u32 res0[4]; |
| 142 | u32 oddpr; | 175 | u32 oddpr; /* 0xD_3418 - Outbound doorbell destination port |
| 143 | u32 oddatr; | 176 | register */ |
| 177 | u32 oddatr; /* 0xD_341c - Outbound doorbell destination attributes | ||
| 178 | register */ | ||
| 144 | u32 res1[3]; | 179 | u32 res1[3]; |
| 145 | u32 odretcr; | 180 | u32 odretcr; /* 0xD_342C - Outbound doorbell retry error threshold |
| 181 | configuration register */ | ||
| 146 | u32 res2[12]; | 182 | u32 res2[12]; |
| 147 | u32 dmr; | 183 | u32 dmr; /* 0xD_3460 - Inbound doorbell mode register */ |
| 148 | u32 dsr; | 184 | u32 dsr; /* 0xD_3464 - Inbound doorbell status register */ |
| 149 | u32 pad8; | 185 | u32 pad8; |
| 150 | u32 dqdpar; | 186 | u32 dqdpar; /* 0xD_346C - Inbound doorbell queue dequeue Pointer |
| 187 | address register */ | ||
| 151 | u32 pad9; | 188 | u32 pad9; |
| 152 | u32 dqepar; | 189 | u32 dqepar; /* 0xD_3474 - Inbound doorbell Queue enqueue pointer |
| 190 | address register */ | ||
| 153 | u32 pad10[26]; | 191 | u32 pad10[26]; |
| 154 | u32 pwmr; | 192 | u32 pwmr; /* 0xD_34E0 - Inbound port-write mode register */ |
| 155 | u32 pwsr; | 193 | u32 pwsr; /* 0xD_34E4 - Inbound port-write status register */ |
| 156 | u32 epwqbar; | 194 | u32 epwqbar; /* 0xD_34E8 - Extended Port-Write Queue Base Address |
| 157 | u32 pwqbar; | 195 | register */ |
| 196 | u32 pwqbar; /* 0xD_34EC - Inbound port-write queue base address | ||
| 197 | register */ | ||
| 158 | }; | 198 | }; |
| 159 | 199 | ||
| 160 | struct rio_tx_desc { | 200 | struct rio_tx_desc { |
| @@ -241,35 +281,32 @@ struct rio_priv { | |||
| 241 | static void __iomem *rio_regs_win; | 281 | static void __iomem *rio_regs_win; |
| 242 | 282 | ||
| 243 | #ifdef CONFIG_E500 | 283 | #ifdef CONFIG_E500 |
| 244 | static int (*saved_mcheck_exception)(struct pt_regs *regs); | 284 | int fsl_rio_mcheck_exception(struct pt_regs *regs) |
| 245 | |||
| 246 | static int fsl_rio_mcheck_exception(struct pt_regs *regs) | ||
| 247 | { | 285 | { |
| 248 | const struct exception_table_entry *entry = NULL; | 286 | const struct exception_table_entry *entry; |
| 249 | unsigned long reason = mfspr(SPRN_MCSR); | 287 | unsigned long reason; |
| 250 | 288 | ||
| 251 | if (reason & MCSR_BUS_RBERR) { | 289 | if (!rio_regs_win) |
| 252 | reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR)); | 290 | return 0; |
| 253 | if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) { | 291 | |
| 254 | /* Check if we are prepared to handle this fault */ | 292 | reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR)); |
| 255 | entry = search_exception_tables(regs->nip); | 293 | if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) { |
| 256 | if (entry) { | 294 | /* Check if we are prepared to handle this fault */ |
| 257 | pr_debug("RIO: %s - MC Exception handled\n", | 295 | entry = search_exception_tables(regs->nip); |
| 258 | __func__); | 296 | if (entry) { |
| 259 | out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), | 297 | pr_debug("RIO: %s - MC Exception handled\n", |
| 260 | 0); | 298 | __func__); |
| 261 | regs->msr |= MSR_RI; | 299 | out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), |
| 262 | regs->nip = entry->fixup; | 300 | 0); |
| 263 | return 1; | 301 | regs->msr |= MSR_RI; |
| 264 | } | 302 | regs->nip = entry->fixup; |
| 303 | return 1; | ||
| 265 | } | 304 | } |
| 266 | } | 305 | } |
| 267 | 306 | ||
| 268 | if (saved_mcheck_exception) | 307 | return 0; |
| 269 | return saved_mcheck_exception(regs); | ||
| 270 | else | ||
| 271 | return cur_cpu_spec->machine_check(regs); | ||
| 272 | } | 308 | } |
| 309 | EXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception); | ||
| 273 | #endif | 310 | #endif |
| 274 | 311 | ||
| 275 | /** | 312 | /** |
| @@ -463,7 +500,7 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid, | |||
| 463 | } | 500 | } |
| 464 | 501 | ||
| 465 | /** | 502 | /** |
| 466 | * rio_hw_add_outb_message - Add message to the MPC85xx outbound message queue | 503 | * fsl_add_outb_message - Add message to the MPC85xx outbound message queue |
| 467 | * @mport: Master port with outbound message queue | 504 | * @mport: Master port with outbound message queue |
| 468 | * @rdev: Target of outbound message | 505 | * @rdev: Target of outbound message |
| 469 | * @mbox: Outbound mailbox | 506 | * @mbox: Outbound mailbox |
| @@ -473,8 +510,8 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid, | |||
| 473 | * Adds the @buffer message to the MPC85xx outbound message queue. Returns | 510 | * Adds the @buffer message to the MPC85xx outbound message queue. Returns |
| 474 | * %0 on success or %-EINVAL on failure. | 511 | * %0 on success or %-EINVAL on failure. |
| 475 | */ | 512 | */ |
| 476 | int | 513 | static int |
| 477 | rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, | 514 | fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, |
| 478 | void *buffer, size_t len) | 515 | void *buffer, size_t len) |
| 479 | { | 516 | { |
| 480 | struct rio_priv *priv = mport->priv; | 517 | struct rio_priv *priv = mport->priv; |
| @@ -483,9 +520,8 @@ rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, | |||
| 483 | + priv->msg_tx_ring.tx_slot; | 520 | + priv->msg_tx_ring.tx_slot; |
| 484 | int ret = 0; | 521 | int ret = 0; |
| 485 | 522 | ||
| 486 | pr_debug | 523 | pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \ |
| 487 | ("RIO: rio_hw_add_outb_message(): destid %4.4x mbox %d buffer %8.8x len %8.8x\n", | 524 | "%8.8x len %8.8x\n", rdev->destid, mbox, (int)buffer, len); |
| 488 | rdev->destid, mbox, (int)buffer, len); | ||
| 489 | 525 | ||
| 490 | if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) { | 526 | if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) { |
| 491 | ret = -EINVAL; | 527 | ret = -EINVAL; |
| @@ -535,8 +571,6 @@ rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, | |||
| 535 | return ret; | 571 | return ret; |
| 536 | } | 572 | } |
| 537 | 573 | ||
| 538 | EXPORT_SYMBOL_GPL(rio_hw_add_outb_message); | ||
| 539 | |||
| 540 | /** | 574 | /** |
| 541 | * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler | 575 | * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler |
| 542 | * @irq: Linux interrupt number | 576 | * @irq: Linux interrupt number |
| @@ -581,7 +615,7 @@ fsl_rio_tx_handler(int irq, void *dev_instance) | |||
| 581 | } | 615 | } |
| 582 | 616 | ||
| 583 | /** | 617 | /** |
| 584 | * rio_open_outb_mbox - Initialize MPC85xx outbound mailbox | 618 | * fsl_open_outb_mbox - Initialize MPC85xx outbound mailbox |
| 585 | * @mport: Master port implementing the outbound message unit | 619 | * @mport: Master port implementing the outbound message unit |
| 586 | * @dev_id: Device specific pointer to pass on event | 620 | * @dev_id: Device specific pointer to pass on event |
| 587 | * @mbox: Mailbox to open | 621 | * @mbox: Mailbox to open |
| @@ -591,7 +625,8 @@ fsl_rio_tx_handler(int irq, void *dev_instance) | |||
| 591 | * and enables the outbound message unit. Returns %0 on success and | 625 | * and enables the outbound message unit. Returns %0 on success and |
| 592 | * %-EINVAL or %-ENOMEM on failure. | 626 | * %-EINVAL or %-ENOMEM on failure. |
| 593 | */ | 627 | */ |
| 594 | int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) | 628 | static int |
| 629 | fsl_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) | ||
| 595 | { | 630 | { |
| 596 | int i, j, rc = 0; | 631 | int i, j, rc = 0; |
| 597 | struct rio_priv *priv = mport->priv; | 632 | struct rio_priv *priv = mport->priv; |
| @@ -687,14 +722,14 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr | |||
| 687 | } | 722 | } |
| 688 | 723 | ||
| 689 | /** | 724 | /** |
| 690 | * rio_close_outb_mbox - Shut down MPC85xx outbound mailbox | 725 | * fsl_close_outb_mbox - Shut down MPC85xx outbound mailbox |
| 691 | * @mport: Master port implementing the outbound message unit | 726 | * @mport: Master port implementing the outbound message unit |
| 692 | * @mbox: Mailbox to close | 727 | * @mbox: Mailbox to close |
| 693 | * | 728 | * |
| 694 | * Disables the outbound message unit, free all buffers, and | 729 | * Disables the outbound message unit, free all buffers, and |
| 695 | * frees the outbound message interrupt. | 730 | * frees the outbound message interrupt. |
| 696 | */ | 731 | */ |
| 697 | void rio_close_outb_mbox(struct rio_mport *mport, int mbox) | 732 | static void fsl_close_outb_mbox(struct rio_mport *mport, int mbox) |
| 698 | { | 733 | { |
| 699 | struct rio_priv *priv = mport->priv; | 734 | struct rio_priv *priv = mport->priv; |
| 700 | /* Disable inbound message unit */ | 735 | /* Disable inbound message unit */ |
| @@ -751,7 +786,7 @@ fsl_rio_rx_handler(int irq, void *dev_instance) | |||
| 751 | } | 786 | } |
| 752 | 787 | ||
| 753 | /** | 788 | /** |
| 754 | * rio_open_inb_mbox - Initialize MPC85xx inbound mailbox | 789 | * fsl_open_inb_mbox - Initialize MPC85xx inbound mailbox |
| 755 | * @mport: Master port implementing the inbound message unit | 790 | * @mport: Master port implementing the inbound message unit |
| 756 | * @dev_id: Device specific pointer to pass on event | 791 | * @dev_id: Device specific pointer to pass on event |
| 757 | * @mbox: Mailbox to open | 792 | * @mbox: Mailbox to open |
| @@ -761,7 +796,8 @@ fsl_rio_rx_handler(int irq, void *dev_instance) | |||
| 761 | * and enables the inbound message unit. Returns %0 on success | 796 | * and enables the inbound message unit. Returns %0 on success |
| 762 | * and %-EINVAL or %-ENOMEM on failure. | 797 | * and %-EINVAL or %-ENOMEM on failure. |
| 763 | */ | 798 | */ |
| 764 | int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) | 799 | static int |
| 800 | fsl_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) | ||
| 765 | { | 801 | { |
| 766 | int i, rc = 0; | 802 | int i, rc = 0; |
| 767 | struct rio_priv *priv = mport->priv; | 803 | struct rio_priv *priv = mport->priv; |
| @@ -825,14 +861,14 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri | |||
| 825 | } | 861 | } |
| 826 | 862 | ||
| 827 | /** | 863 | /** |
| 828 | * rio_close_inb_mbox - Shut down MPC85xx inbound mailbox | 864 | * fsl_close_inb_mbox - Shut down MPC85xx inbound mailbox |
| 829 | * @mport: Master port implementing the inbound message unit | 865 | * @mport: Master port implementing the inbound message unit |
| 830 | * @mbox: Mailbox to close | 866 | * @mbox: Mailbox to close |
| 831 | * | 867 | * |
| 832 | * Disables the inbound message unit, free all buffers, and | 868 | * Disables the inbound message unit, free all buffers, and |
| 833 | * frees the inbound message interrupt. | 869 | * frees the inbound message interrupt. |
| 834 | */ | 870 | */ |
| 835 | void rio_close_inb_mbox(struct rio_mport *mport, int mbox) | 871 | static void fsl_close_inb_mbox(struct rio_mport *mport, int mbox) |
| 836 | { | 872 | { |
| 837 | struct rio_priv *priv = mport->priv; | 873 | struct rio_priv *priv = mport->priv; |
| 838 | /* Disable inbound message unit */ | 874 | /* Disable inbound message unit */ |
| @@ -847,7 +883,7 @@ void rio_close_inb_mbox(struct rio_mport *mport, int mbox) | |||
| 847 | } | 883 | } |
| 848 | 884 | ||
| 849 | /** | 885 | /** |
| 850 | * rio_hw_add_inb_buffer - Add buffer to the MPC85xx inbound message queue | 886 | * fsl_add_inb_buffer - Add buffer to the MPC85xx inbound message queue |
| 851 | * @mport: Master port implementing the inbound message unit | 887 | * @mport: Master port implementing the inbound message unit |
| 852 | * @mbox: Inbound mailbox number | 888 | * @mbox: Inbound mailbox number |
| 853 | * @buf: Buffer to add to inbound queue | 889 | * @buf: Buffer to add to inbound queue |
| @@ -855,12 +891,12 @@ void rio_close_inb_mbox(struct rio_mport *mport, int mbox) | |||
| 855 | * Adds the @buf buffer to the MPC85xx inbound message queue. Returns | 891 | * Adds the @buf buffer to the MPC85xx inbound message queue. Returns |
| 856 | * %0 on success or %-EINVAL on failure. | 892 | * %0 on success or %-EINVAL on failure. |
| 857 | */ | 893 | */ |
| 858 | int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) | 894 | static int fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) |
| 859 | { | 895 | { |
| 860 | int rc = 0; | 896 | int rc = 0; |
| 861 | struct rio_priv *priv = mport->priv; | 897 | struct rio_priv *priv = mport->priv; |
| 862 | 898 | ||
| 863 | pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n", | 899 | pr_debug("RIO: fsl_add_inb_buffer(), msg_rx_ring.rx_slot %d\n", |
| 864 | priv->msg_rx_ring.rx_slot); | 900 | priv->msg_rx_ring.rx_slot); |
| 865 | 901 | ||
| 866 | if (priv->msg_rx_ring.virt_buffer[priv->msg_rx_ring.rx_slot]) { | 902 | if (priv->msg_rx_ring.virt_buffer[priv->msg_rx_ring.rx_slot]) { |
| @@ -879,17 +915,15 @@ int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) | |||
| 879 | return rc; | 915 | return rc; |
| 880 | } | 916 | } |
| 881 | 917 | ||
| 882 | EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer); | ||
| 883 | |||
| 884 | /** | 918 | /** |
| 885 | * rio_hw_get_inb_message - Fetch inbound message from the MPC85xx message unit | 919 | * fsl_get_inb_message - Fetch inbound message from the MPC85xx message unit |
| 886 | * @mport: Master port implementing the inbound message unit | 920 | * @mport: Master port implementing the inbound message unit |
| 887 | * @mbox: Inbound mailbox number | 921 | * @mbox: Inbound mailbox number |
| 888 | * | 922 | * |
| 889 | * Gets the next available inbound message from the inbound message queue. | 923 | * Gets the next available inbound message from the inbound message queue. |
| 890 | * A pointer to the message is returned on success or NULL on failure. | 924 | * A pointer to the message is returned on success or NULL on failure. |
| 891 | */ | 925 | */ |
| 892 | void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox) | 926 | static void *fsl_get_inb_message(struct rio_mport *mport, int mbox) |
| 893 | { | 927 | { |
| 894 | struct rio_priv *priv = mport->priv; | 928 | struct rio_priv *priv = mport->priv; |
| 895 | u32 phys_buf, virt_buf; | 929 | u32 phys_buf, virt_buf; |
| @@ -926,8 +960,6 @@ void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox) | |||
| 926 | return buf; | 960 | return buf; |
| 927 | } | 961 | } |
| 928 | 962 | ||
| 929 | EXPORT_SYMBOL_GPL(rio_hw_get_inb_message); | ||
| 930 | |||
| 931 | /** | 963 | /** |
| 932 | * fsl_rio_dbell_handler - MPC85xx doorbell interrupt handler | 964 | * fsl_rio_dbell_handler - MPC85xx doorbell interrupt handler |
| 933 | * @irq: Linux interrupt number | 965 | * @irq: Linux interrupt number |
| @@ -954,7 +986,6 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) | |||
| 954 | if (dsr & DOORBELL_DSR_QFI) { | 986 | if (dsr & DOORBELL_DSR_QFI) { |
| 955 | pr_info("RIO: doorbell queue full\n"); | 987 | pr_info("RIO: doorbell queue full\n"); |
| 956 | out_be32(&priv->msg_regs->dsr, DOORBELL_DSR_QFI); | 988 | out_be32(&priv->msg_regs->dsr, DOORBELL_DSR_QFI); |
| 957 | goto out; | ||
| 958 | } | 989 | } |
| 959 | 990 | ||
| 960 | /* XXX Need to check/dispatch until queue empty */ | 991 | /* XXX Need to check/dispatch until queue empty */ |
| @@ -1051,6 +1082,40 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport) | |||
| 1051 | return rc; | 1082 | return rc; |
| 1052 | } | 1083 | } |
| 1053 | 1084 | ||
| 1085 | static void port_error_handler(struct rio_mport *port, int offset) | ||
| 1086 | { | ||
| 1087 | /*XXX: Error recovery is not implemented, we just clear errors */ | ||
| 1088 | out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); | ||
| 1089 | |||
| 1090 | if (offset == 0) { | ||
| 1091 | out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0); | ||
| 1092 | out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), 0); | ||
| 1093 | out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR); | ||
| 1094 | } else { | ||
| 1095 | out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0); | ||
| 1096 | out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), 0); | ||
| 1097 | out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR); | ||
| 1098 | } | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | static void msg_unit_error_handler(struct rio_mport *port) | ||
| 1102 | { | ||
| 1103 | struct rio_priv *priv = port->priv; | ||
| 1104 | |||
| 1105 | /*XXX: Error recovery is not implemented, we just clear errors */ | ||
| 1106 | out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); | ||
| 1107 | |||
| 1108 | out_be32((u32 *)(rio_regs_win + RIO_IM0SR), IMSR_CLEAR); | ||
| 1109 | out_be32((u32 *)(rio_regs_win + RIO_IM1SR), IMSR_CLEAR); | ||
| 1110 | out_be32((u32 *)(rio_regs_win + RIO_OM0SR), OMSR_CLEAR); | ||
| 1111 | out_be32((u32 *)(rio_regs_win + RIO_OM1SR), OMSR_CLEAR); | ||
| 1112 | |||
| 1113 | out_be32(&priv->msg_regs->odsr, ODSR_CLEAR); | ||
| 1114 | out_be32(&priv->msg_regs->dsr, IDSR_CLEAR); | ||
| 1115 | |||
| 1116 | out_be32(&priv->msg_regs->pwsr, IPWSR_CLEAR); | ||
| 1117 | } | ||
| 1118 | |||
| 1054 | /** | 1119 | /** |
| 1055 | * fsl_rio_port_write_handler - MPC85xx port write interrupt handler | 1120 | * fsl_rio_port_write_handler - MPC85xx port write interrupt handler |
| 1056 | * @irq: Linux interrupt number | 1121 | * @irq: Linux interrupt number |
| @@ -1067,18 +1132,12 @@ fsl_rio_port_write_handler(int irq, void *dev_instance) | |||
| 1067 | struct rio_priv *priv = port->priv; | 1132 | struct rio_priv *priv = port->priv; |
| 1068 | u32 epwisr, tmp; | 1133 | u32 epwisr, tmp; |
| 1069 | 1134 | ||
| 1070 | ipwmr = in_be32(&priv->msg_regs->pwmr); | ||
| 1071 | ipwsr = in_be32(&priv->msg_regs->pwsr); | ||
| 1072 | |||
| 1073 | epwisr = in_be32(priv->regs_win + RIO_EPWISR); | 1135 | epwisr = in_be32(priv->regs_win + RIO_EPWISR); |
| 1074 | if (epwisr & 0x80000000) { | 1136 | if (!(epwisr & RIO_EPWISR_PW)) |
| 1075 | tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); | 1137 | goto pw_done; |
| 1076 | pr_info("RIO_LTLEDCSR = 0x%x\n", tmp); | ||
| 1077 | out_be32(priv->regs_win + RIO_LTLEDCSR, 0); | ||
| 1078 | } | ||
| 1079 | 1138 | ||
| 1080 | if (!(epwisr & 0x00000001)) | 1139 | ipwmr = in_be32(&priv->msg_regs->pwmr); |
| 1081 | return IRQ_HANDLED; | 1140 | ipwsr = in_be32(&priv->msg_regs->pwsr); |
| 1082 | 1141 | ||
| 1083 | #ifdef DEBUG_PW | 1142 | #ifdef DEBUG_PW |
| 1084 | pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr); | 1143 | pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr); |
| @@ -1094,20 +1153,6 @@ fsl_rio_port_write_handler(int irq, void *dev_instance) | |||
| 1094 | pr_debug(" PWB"); | 1153 | pr_debug(" PWB"); |
| 1095 | pr_debug(" )\n"); | 1154 | pr_debug(" )\n"); |
| 1096 | #endif | 1155 | #endif |
| 1097 | out_be32(&priv->msg_regs->pwsr, | ||
| 1098 | ipwsr & (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD)); | ||
| 1099 | |||
| 1100 | if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) { | ||
| 1101 | priv->port_write_msg.err_count++; | ||
| 1102 | pr_info("RIO: Port-Write Transaction Err (%d)\n", | ||
| 1103 | priv->port_write_msg.err_count); | ||
| 1104 | } | ||
| 1105 | if (ipwsr & RIO_IPWSR_PWD) { | ||
| 1106 | priv->port_write_msg.discard_count++; | ||
| 1107 | pr_info("RIO: Port Discarded Port-Write Msg(s) (%d)\n", | ||
| 1108 | priv->port_write_msg.discard_count); | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | /* Schedule deferred processing if PW was received */ | 1156 | /* Schedule deferred processing if PW was received */ |
| 1112 | if (ipwsr & RIO_IPWSR_QFI) { | 1157 | if (ipwsr & RIO_IPWSR_QFI) { |
| 1113 | /* Save PW message (if there is room in FIFO), | 1158 | /* Save PW message (if there is room in FIFO), |
| @@ -1119,16 +1164,55 @@ fsl_rio_port_write_handler(int irq, void *dev_instance) | |||
| 1119 | RIO_PW_MSG_SIZE); | 1164 | RIO_PW_MSG_SIZE); |
| 1120 | } else { | 1165 | } else { |
| 1121 | priv->port_write_msg.discard_count++; | 1166 | priv->port_write_msg.discard_count++; |
| 1122 | pr_info("RIO: ISR Discarded Port-Write Msg(s) (%d)\n", | 1167 | pr_debug("RIO: ISR Discarded Port-Write Msg(s) (%d)\n", |
| 1123 | priv->port_write_msg.discard_count); | 1168 | priv->port_write_msg.discard_count); |
| 1124 | } | 1169 | } |
| 1170 | /* Clear interrupt and issue Clear Queue command. This allows | ||
| 1171 | * another port-write to be received. | ||
| 1172 | */ | ||
| 1173 | out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_QFI); | ||
| 1174 | out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ); | ||
| 1175 | |||
| 1125 | schedule_work(&priv->pw_work); | 1176 | schedule_work(&priv->pw_work); |
| 1126 | } | 1177 | } |
| 1127 | 1178 | ||
| 1128 | /* Issue Clear Queue command. This allows another | 1179 | if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) { |
| 1129 | * port-write to be received. | 1180 | priv->port_write_msg.err_count++; |
| 1130 | */ | 1181 | pr_debug("RIO: Port-Write Transaction Err (%d)\n", |
| 1131 | out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ); | 1182 | priv->port_write_msg.err_count); |
| 1183 | /* Clear Transaction Error: port-write controller should be | ||
| 1184 | * disabled when clearing this error | ||
| 1185 | */ | ||
| 1186 | out_be32(&priv->msg_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE); | ||
| 1187 | out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_TE); | ||
| 1188 | out_be32(&priv->msg_regs->pwmr, ipwmr); | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | if (ipwsr & RIO_IPWSR_PWD) { | ||
| 1192 | priv->port_write_msg.discard_count++; | ||
| 1193 | pr_debug("RIO: Port Discarded Port-Write Msg(s) (%d)\n", | ||
| 1194 | priv->port_write_msg.discard_count); | ||
| 1195 | out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_PWD); | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | pw_done: | ||
| 1199 | if (epwisr & RIO_EPWISR_PINT1) { | ||
| 1200 | tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); | ||
| 1201 | pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); | ||
| 1202 | port_error_handler(port, 0); | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | if (epwisr & RIO_EPWISR_PINT2) { | ||
| 1206 | tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); | ||
| 1207 | pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); | ||
| 1208 | port_error_handler(port, 1); | ||
| 1209 | } | ||
| 1210 | |||
| 1211 | if (epwisr & RIO_EPWISR_MU) { | ||
| 1212 | tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); | ||
| 1213 | pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); | ||
| 1214 | msg_unit_error_handler(port); | ||
| 1215 | } | ||
| 1132 | 1216 | ||
| 1133 | return IRQ_HANDLED; | 1217 | return IRQ_HANDLED; |
| 1134 | } | 1218 | } |
| @@ -1238,12 +1322,14 @@ static int fsl_rio_port_write_init(struct rio_mport *mport) | |||
| 1238 | 1322 | ||
| 1239 | 1323 | ||
| 1240 | /* Hook up port-write handler */ | 1324 | /* Hook up port-write handler */ |
| 1241 | rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, 0, | 1325 | rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, |
| 1242 | "port-write", (void *)mport); | 1326 | IRQF_SHARED, "port-write", (void *)mport); |
| 1243 | if (rc < 0) { | 1327 | if (rc < 0) { |
| 1244 | pr_err("MPC85xx RIO: unable to request inbound doorbell irq"); | 1328 | pr_err("MPC85xx RIO: unable to request inbound doorbell irq"); |
| 1245 | goto err_out; | 1329 | goto err_out; |
| 1246 | } | 1330 | } |
| 1331 | /* Enable Error Interrupt */ | ||
| 1332 | out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL); | ||
| 1247 | 1333 | ||
| 1248 | INIT_WORK(&priv->pw_work, fsl_pw_dpc); | 1334 | INIT_WORK(&priv->pw_work, fsl_pw_dpc); |
| 1249 | spin_lock_init(&priv->pw_fifo_lock); | 1335 | spin_lock_init(&priv->pw_fifo_lock); |
| @@ -1268,28 +1354,6 @@ err_out: | |||
| 1268 | return rc; | 1354 | return rc; |
| 1269 | } | 1355 | } |
| 1270 | 1356 | ||
| 1271 | static char *cmdline = NULL; | ||
| 1272 | |||
| 1273 | static int fsl_rio_get_hdid(int index) | ||
| 1274 | { | ||
| 1275 | /* XXX Need to parse multiple entries in some format */ | ||
| 1276 | if (!cmdline) | ||
| 1277 | return -1; | ||
| 1278 | |||
| 1279 | return simple_strtol(cmdline, NULL, 0); | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | static int fsl_rio_get_cmdline(char *s) | ||
| 1283 | { | ||
| 1284 | if (!s) | ||
| 1285 | return 0; | ||
| 1286 | |||
| 1287 | cmdline = s; | ||
| 1288 | return 1; | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | __setup("riohdid=", fsl_rio_get_cmdline); | ||
| 1292 | |||
| 1293 | static inline void fsl_rio_info(struct device *dev, u32 ccsr) | 1357 | static inline void fsl_rio_info(struct device *dev, u32 ccsr) |
| 1294 | { | 1358 | { |
| 1295 | const char *str; | 1359 | const char *str; |
| @@ -1406,13 +1470,19 @@ int fsl_rio_setup(struct platform_device *dev) | |||
| 1406 | ops->cwrite = fsl_rio_config_write; | 1470 | ops->cwrite = fsl_rio_config_write; |
| 1407 | ops->dsend = fsl_rio_doorbell_send; | 1471 | ops->dsend = fsl_rio_doorbell_send; |
| 1408 | ops->pwenable = fsl_rio_pw_enable; | 1472 | ops->pwenable = fsl_rio_pw_enable; |
| 1473 | ops->open_outb_mbox = fsl_open_outb_mbox; | ||
| 1474 | ops->open_inb_mbox = fsl_open_inb_mbox; | ||
| 1475 | ops->close_outb_mbox = fsl_close_outb_mbox; | ||
| 1476 | ops->close_inb_mbox = fsl_close_inb_mbox; | ||
| 1477 | ops->add_outb_message = fsl_add_outb_message; | ||
| 1478 | ops->add_inb_buffer = fsl_add_inb_buffer; | ||
| 1479 | ops->get_inb_message = fsl_get_inb_message; | ||
| 1409 | 1480 | ||
| 1410 | port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL); | 1481 | port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL); |
| 1411 | if (!port) { | 1482 | if (!port) { |
| 1412 | rc = -ENOMEM; | 1483 | rc = -ENOMEM; |
| 1413 | goto err_port; | 1484 | goto err_port; |
| 1414 | } | 1485 | } |
| 1415 | port->id = 0; | ||
| 1416 | port->index = 0; | 1486 | port->index = 0; |
| 1417 | 1487 | ||
| 1418 | priv = kzalloc(sizeof(struct rio_priv), GFP_KERNEL); | 1488 | priv = kzalloc(sizeof(struct rio_priv), GFP_KERNEL); |
| @@ -1428,6 +1498,14 @@ int fsl_rio_setup(struct platform_device *dev) | |||
| 1428 | port->iores.flags = IORESOURCE_MEM; | 1498 | port->iores.flags = IORESOURCE_MEM; |
| 1429 | port->iores.name = "rio_io_win"; | 1499 | port->iores.name = "rio_io_win"; |
| 1430 | 1500 | ||
| 1501 | if (request_resource(&iomem_resource, &port->iores) < 0) { | ||
| 1502 | dev_err(&dev->dev, "RIO: Error requesting master port region" | ||
| 1503 | " 0x%016llx-0x%016llx\n", | ||
| 1504 | (u64)port->iores.start, (u64)port->iores.end); | ||
| 1505 | rc = -ENOMEM; | ||
| 1506 | goto err_res; | ||
| 1507 | } | ||
| 1508 | |||
| 1431 | priv->pwirq = irq_of_parse_and_map(dev->dev.of_node, 0); | 1509 | priv->pwirq = irq_of_parse_and_map(dev->dev.of_node, 0); |
| 1432 | priv->bellirq = irq_of_parse_and_map(dev->dev.of_node, 2); | 1510 | priv->bellirq = irq_of_parse_and_map(dev->dev.of_node, 2); |
| 1433 | priv->txirq = irq_of_parse_and_map(dev->dev.of_node, 3); | 1511 | priv->txirq = irq_of_parse_and_map(dev->dev.of_node, 3); |
| @@ -1443,10 +1521,8 @@ int fsl_rio_setup(struct platform_device *dev) | |||
| 1443 | priv->dev = &dev->dev; | 1521 | priv->dev = &dev->dev; |
| 1444 | 1522 | ||
| 1445 | port->ops = ops; | 1523 | port->ops = ops; |
| 1446 | port->host_deviceid = fsl_rio_get_hdid(port->id); | ||
| 1447 | |||
| 1448 | port->priv = priv; | 1524 | port->priv = priv; |
| 1449 | rio_register_mport(port); | 1525 | port->phys_efptr = 0x100; |
| 1450 | 1526 | ||
| 1451 | priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1); | 1527 | priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1); |
| 1452 | rio_regs_win = priv->regs_win; | 1528 | rio_regs_win = priv->regs_win; |
| @@ -1493,6 +1569,15 @@ int fsl_rio_setup(struct platform_device *dev) | |||
| 1493 | dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n", | 1569 | dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n", |
| 1494 | port->sys_size ? 65536 : 256); | 1570 | port->sys_size ? 65536 : 256); |
| 1495 | 1571 | ||
| 1572 | if (rio_register_mport(port)) | ||
| 1573 | goto err; | ||
| 1574 | |||
| 1575 | if (port->host_deviceid >= 0) | ||
| 1576 | out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST | | ||
| 1577 | RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED); | ||
| 1578 | else | ||
| 1579 | out_be32(priv->regs_win + RIO_GCCSR, 0x00000000); | ||
| 1580 | |||
| 1496 | priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win | 1581 | priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win |
| 1497 | + RIO_ATMU_REGS_OFFSET); | 1582 | + RIO_ATMU_REGS_OFFSET); |
| 1498 | priv->maint_atmu_regs = priv->atmu_regs + 1; | 1583 | priv->maint_atmu_regs = priv->atmu_regs + 1; |
| @@ -1519,16 +1604,10 @@ int fsl_rio_setup(struct platform_device *dev) | |||
| 1519 | fsl_rio_doorbell_init(port); | 1604 | fsl_rio_doorbell_init(port); |
| 1520 | fsl_rio_port_write_init(port); | 1605 | fsl_rio_port_write_init(port); |
| 1521 | 1606 | ||
| 1522 | #ifdef CONFIG_E500 | ||
| 1523 | saved_mcheck_exception = ppc_md.machine_check_exception; | ||
| 1524 | ppc_md.machine_check_exception = fsl_rio_mcheck_exception; | ||
| 1525 | #endif | ||
| 1526 | /* Ensure that RFXE is set */ | ||
| 1527 | mtspr(SPRN_HID1, (mfspr(SPRN_HID1) | 0x20000)); | ||
| 1528 | |||
| 1529 | return 0; | 1607 | return 0; |
| 1530 | err: | 1608 | err: |
| 1531 | iounmap(priv->regs_win); | 1609 | iounmap(priv->regs_win); |
| 1610 | err_res: | ||
| 1532 | kfree(priv); | 1611 | kfree(priv); |
| 1533 | err_priv: | 1612 | err_priv: |
| 1534 | kfree(port); | 1613 | kfree(port); |
| @@ -1540,21 +1619,12 @@ err_ops: | |||
| 1540 | 1619 | ||
| 1541 | /* The probe function for RapidIO peer-to-peer network. | 1620 | /* The probe function for RapidIO peer-to-peer network. |
| 1542 | */ | 1621 | */ |
| 1543 | static int __devinit fsl_of_rio_rpn_probe(struct platform_device *dev, | 1622 | static int __devinit fsl_of_rio_rpn_probe(struct platform_device *dev) |
| 1544 | const struct of_device_id *match) | ||
| 1545 | { | 1623 | { |
| 1546 | int rc; | ||
| 1547 | printk(KERN_INFO "Setting up RapidIO peer-to-peer network %s\n", | 1624 | printk(KERN_INFO "Setting up RapidIO peer-to-peer network %s\n", |
| 1548 | dev->dev.of_node->full_name); | 1625 | dev->dev.of_node->full_name); |
| 1549 | 1626 | ||
| 1550 | rc = fsl_rio_setup(dev); | 1627 | return fsl_rio_setup(dev); |
| 1551 | if (rc) | ||
| 1552 | goto out; | ||
| 1553 | |||
| 1554 | /* Enumerate all registered ports */ | ||
| 1555 | rc = rio_init_mports(); | ||
| 1556 | out: | ||
| 1557 | return rc; | ||
| 1558 | }; | 1628 | }; |
| 1559 | 1629 | ||
| 1560 | static const struct of_device_id fsl_of_rio_rpn_ids[] = { | 1630 | static const struct of_device_id fsl_of_rio_rpn_ids[] = { |
| @@ -1564,7 +1634,7 @@ static const struct of_device_id fsl_of_rio_rpn_ids[] = { | |||
| 1564 | {}, | 1634 | {}, |
| 1565 | }; | 1635 | }; |
| 1566 | 1636 | ||
| 1567 | static struct of_platform_driver fsl_of_rio_rpn_driver = { | 1637 | static struct platform_driver fsl_of_rio_rpn_driver = { |
| 1568 | .driver = { | 1638 | .driver = { |
| 1569 | .name = "fsl-of-rio", | 1639 | .name = "fsl-of-rio", |
| 1570 | .owner = THIS_MODULE, | 1640 | .owner = THIS_MODULE, |
| @@ -1575,7 +1645,7 @@ static struct of_platform_driver fsl_of_rio_rpn_driver = { | |||
| 1575 | 1645 | ||
| 1576 | static __init int fsl_of_rio_rpn_init(void) | 1646 | static __init int fsl_of_rio_rpn_init(void) |
| 1577 | { | 1647 | { |
| 1578 | return of_register_platform_driver(&fsl_of_rio_rpn_driver); | 1648 | return platform_driver_register(&fsl_of_rio_rpn_driver); |
| 1579 | } | 1649 | } |
| 1580 | 1650 | ||
| 1581 | subsys_initcall(fsl_of_rio_rpn_init); | 1651 | subsys_initcall(fsl_of_rio_rpn_init); |
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index b91f7acdda6f..19e5015e039b 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c | |||
| @@ -209,186 +209,29 @@ static int __init of_add_fixed_phys(void) | |||
| 209 | arch_initcall(of_add_fixed_phys); | 209 | arch_initcall(of_add_fixed_phys); |
| 210 | #endif /* CONFIG_FIXED_PHY */ | 210 | #endif /* CONFIG_FIXED_PHY */ |
| 211 | 211 | ||
| 212 | static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) | 212 | #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx) |
| 213 | { | 213 | static __be32 __iomem *rstcr; |
| 214 | if (!phy_type) | ||
| 215 | return FSL_USB2_PHY_NONE; | ||
| 216 | if (!strcasecmp(phy_type, "ulpi")) | ||
| 217 | return FSL_USB2_PHY_ULPI; | ||
| 218 | if (!strcasecmp(phy_type, "utmi")) | ||
| 219 | return FSL_USB2_PHY_UTMI; | ||
| 220 | if (!strcasecmp(phy_type, "utmi_wide")) | ||
| 221 | return FSL_USB2_PHY_UTMI_WIDE; | ||
| 222 | if (!strcasecmp(phy_type, "serial")) | ||
| 223 | return FSL_USB2_PHY_SERIAL; | ||
| 224 | |||
| 225 | return FSL_USB2_PHY_NONE; | ||
| 226 | } | ||
| 227 | 214 | ||
| 228 | static int __init fsl_usb_of_init(void) | 215 | static int __init setup_rstcr(void) |
| 229 | { | 216 | { |
| 230 | struct device_node *np; | 217 | struct device_node *np; |
| 231 | unsigned int i = 0; | ||
| 232 | struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_host = NULL, | ||
| 233 | *usb_dev_dr_client = NULL; | ||
| 234 | int ret; | ||
| 235 | |||
| 236 | for_each_compatible_node(np, NULL, "fsl-usb2-mph") { | ||
| 237 | struct resource r[2]; | ||
| 238 | struct fsl_usb2_platform_data usb_data; | ||
| 239 | const unsigned char *prop = NULL; | ||
| 240 | |||
| 241 | memset(&r, 0, sizeof(r)); | ||
| 242 | memset(&usb_data, 0, sizeof(usb_data)); | ||
| 243 | |||
| 244 | ret = of_address_to_resource(np, 0, &r[0]); | ||
| 245 | if (ret) | ||
| 246 | goto err; | ||
| 247 | |||
| 248 | of_irq_to_resource(np, 0, &r[1]); | ||
| 249 | |||
| 250 | usb_dev_mph = | ||
| 251 | platform_device_register_simple("fsl-ehci", i, r, 2); | ||
| 252 | if (IS_ERR(usb_dev_mph)) { | ||
| 253 | ret = PTR_ERR(usb_dev_mph); | ||
| 254 | goto err; | ||
| 255 | } | ||
| 256 | |||
| 257 | usb_dev_mph->dev.coherent_dma_mask = 0xffffffffUL; | ||
| 258 | usb_dev_mph->dev.dma_mask = &usb_dev_mph->dev.coherent_dma_mask; | ||
| 259 | |||
| 260 | usb_data.operating_mode = FSL_USB2_MPH_HOST; | ||
| 261 | |||
| 262 | prop = of_get_property(np, "port0", NULL); | ||
| 263 | if (prop) | ||
| 264 | usb_data.port_enables |= FSL_USB2_PORT0_ENABLED; | ||
| 265 | |||
| 266 | prop = of_get_property(np, "port1", NULL); | ||
| 267 | if (prop) | ||
| 268 | usb_data.port_enables |= FSL_USB2_PORT1_ENABLED; | ||
| 269 | |||
| 270 | prop = of_get_property(np, "phy_type", NULL); | ||
| 271 | usb_data.phy_mode = determine_usb_phy(prop); | ||
| 272 | |||
| 273 | ret = | ||
| 274 | platform_device_add_data(usb_dev_mph, &usb_data, | ||
| 275 | sizeof(struct | ||
| 276 | fsl_usb2_platform_data)); | ||
| 277 | if (ret) | ||
| 278 | goto unreg_mph; | ||
| 279 | i++; | ||
| 280 | } | ||
| 281 | |||
| 282 | for_each_compatible_node(np, NULL, "fsl-usb2-dr") { | ||
| 283 | struct resource r[2]; | ||
| 284 | struct fsl_usb2_platform_data usb_data; | ||
| 285 | const unsigned char *prop = NULL; | ||
| 286 | 218 | ||
| 287 | if (!of_device_is_available(np)) | 219 | for_each_node_by_name(np, "global-utilities") { |
| 288 | continue; | 220 | if ((of_get_property(np, "fsl,has-rstcr", NULL))) { |
| 289 | 221 | rstcr = of_iomap(np, 0) + 0xb0; | |
| 290 | memset(&r, 0, sizeof(r)); | 222 | if (!rstcr) |
| 291 | memset(&usb_data, 0, sizeof(usb_data)); | 223 | printk (KERN_ERR "Error: reset control " |
| 292 | 224 | "register not mapped!\n"); | |
| 293 | ret = of_address_to_resource(np, 0, &r[0]); | 225 | break; |
| 294 | if (ret) | ||
| 295 | goto unreg_mph; | ||
| 296 | |||
| 297 | of_irq_to_resource(np, 0, &r[1]); | ||
| 298 | |||
| 299 | prop = of_get_property(np, "dr_mode", NULL); | ||
| 300 | |||
| 301 | if (!prop || !strcmp(prop, "host")) { | ||
| 302 | usb_data.operating_mode = FSL_USB2_DR_HOST; | ||
| 303 | usb_dev_dr_host = platform_device_register_simple( | ||
| 304 | "fsl-ehci", i, r, 2); | ||
| 305 | if (IS_ERR(usb_dev_dr_host)) { | ||
| 306 | ret = PTR_ERR(usb_dev_dr_host); | ||
| 307 | goto err; | ||
| 308 | } | ||
| 309 | } else if (prop && !strcmp(prop, "peripheral")) { | ||
| 310 | usb_data.operating_mode = FSL_USB2_DR_DEVICE; | ||
| 311 | usb_dev_dr_client = platform_device_register_simple( | ||
| 312 | "fsl-usb2-udc", i, r, 2); | ||
| 313 | if (IS_ERR(usb_dev_dr_client)) { | ||
| 314 | ret = PTR_ERR(usb_dev_dr_client); | ||
| 315 | goto err; | ||
| 316 | } | ||
| 317 | } else if (prop && !strcmp(prop, "otg")) { | ||
| 318 | usb_data.operating_mode = FSL_USB2_DR_OTG; | ||
| 319 | usb_dev_dr_host = platform_device_register_simple( | ||
| 320 | "fsl-ehci", i, r, 2); | ||
| 321 | if (IS_ERR(usb_dev_dr_host)) { | ||
| 322 | ret = PTR_ERR(usb_dev_dr_host); | ||
| 323 | goto err; | ||
| 324 | } | ||
| 325 | usb_dev_dr_client = platform_device_register_simple( | ||
| 326 | "fsl-usb2-udc", i, r, 2); | ||
| 327 | if (IS_ERR(usb_dev_dr_client)) { | ||
| 328 | ret = PTR_ERR(usb_dev_dr_client); | ||
| 329 | goto err; | ||
| 330 | } | ||
| 331 | } else { | ||
| 332 | ret = -EINVAL; | ||
| 333 | goto err; | ||
| 334 | } | 226 | } |
| 335 | |||
| 336 | prop = of_get_property(np, "phy_type", NULL); | ||
| 337 | usb_data.phy_mode = determine_usb_phy(prop); | ||
| 338 | |||
| 339 | if (usb_dev_dr_host) { | ||
| 340 | usb_dev_dr_host->dev.coherent_dma_mask = 0xffffffffUL; | ||
| 341 | usb_dev_dr_host->dev.dma_mask = &usb_dev_dr_host-> | ||
| 342 | dev.coherent_dma_mask; | ||
| 343 | if ((ret = platform_device_add_data(usb_dev_dr_host, | ||
| 344 | &usb_data, sizeof(struct | ||
| 345 | fsl_usb2_platform_data)))) | ||
| 346 | goto unreg_dr; | ||
| 347 | } | ||
| 348 | if (usb_dev_dr_client) { | ||
| 349 | usb_dev_dr_client->dev.coherent_dma_mask = 0xffffffffUL; | ||
| 350 | usb_dev_dr_client->dev.dma_mask = &usb_dev_dr_client-> | ||
| 351 | dev.coherent_dma_mask; | ||
| 352 | if ((ret = platform_device_add_data(usb_dev_dr_client, | ||
| 353 | &usb_data, sizeof(struct | ||
| 354 | fsl_usb2_platform_data)))) | ||
| 355 | goto unreg_dr; | ||
| 356 | } | ||
| 357 | i++; | ||
| 358 | } | 227 | } |
| 359 | return 0; | ||
| 360 | |||
| 361 | unreg_dr: | ||
| 362 | if (usb_dev_dr_host) | ||
| 363 | platform_device_unregister(usb_dev_dr_host); | ||
| 364 | if (usb_dev_dr_client) | ||
| 365 | platform_device_unregister(usb_dev_dr_client); | ||
| 366 | unreg_mph: | ||
| 367 | if (usb_dev_mph) | ||
| 368 | platform_device_unregister(usb_dev_mph); | ||
| 369 | err: | ||
| 370 | return ret; | ||
| 371 | } | ||
| 372 | |||
| 373 | arch_initcall(fsl_usb_of_init); | ||
| 374 | |||
| 375 | #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx) | ||
| 376 | static __be32 __iomem *rstcr; | ||
| 377 | 228 | ||
| 378 | static int __init setup_rstcr(void) | 229 | if (!rstcr && ppc_md.restart == fsl_rstcr_restart) |
| 379 | { | ||
| 380 | struct device_node *np; | ||
| 381 | np = of_find_node_by_name(NULL, "global-utilities"); | ||
| 382 | if ((np && of_get_property(np, "fsl,has-rstcr", NULL))) { | ||
| 383 | rstcr = of_iomap(np, 0) + 0xb0; | ||
| 384 | if (!rstcr) | ||
| 385 | printk (KERN_EMERG "Error: reset control register " | ||
| 386 | "not mapped!\n"); | ||
| 387 | } else if (ppc_md.restart == fsl_rstcr_restart) | ||
| 388 | printk(KERN_ERR "No RSTCR register, warm reboot won't work\n"); | 230 | printk(KERN_ERR "No RSTCR register, warm reboot won't work\n"); |
| 389 | 231 | ||
| 390 | if (np) | 232 | if (np) |
| 391 | of_node_put(np); | 233 | of_node_put(np); |
| 234 | |||
| 392 | return 0; | 235 | return 0; |
| 393 | } | 236 | } |
| 394 | 237 | ||
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index 6323e70e6bf4..d18bb27e4df9 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c | |||
| @@ -78,19 +78,19 @@ unsigned int i8259_irq(void) | |||
| 78 | return irq; | 78 | return irq; |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | static void i8259_mask_and_ack_irq(unsigned int irq_nr) | 81 | static void i8259_mask_and_ack_irq(struct irq_data *d) |
| 82 | { | 82 | { |
| 83 | unsigned long flags; | 83 | unsigned long flags; |
| 84 | 84 | ||
| 85 | raw_spin_lock_irqsave(&i8259_lock, flags); | 85 | raw_spin_lock_irqsave(&i8259_lock, flags); |
| 86 | if (irq_nr > 7) { | 86 | if (d->irq > 7) { |
| 87 | cached_A1 |= 1 << (irq_nr-8); | 87 | cached_A1 |= 1 << (d->irq-8); |
| 88 | inb(0xA1); /* DUMMY */ | 88 | inb(0xA1); /* DUMMY */ |
| 89 | outb(cached_A1, 0xA1); | 89 | outb(cached_A1, 0xA1); |
| 90 | outb(0x20, 0xA0); /* Non-specific EOI */ | 90 | outb(0x20, 0xA0); /* Non-specific EOI */ |
| 91 | outb(0x20, 0x20); /* Non-specific EOI to cascade */ | 91 | outb(0x20, 0x20); /* Non-specific EOI to cascade */ |
| 92 | } else { | 92 | } else { |
| 93 | cached_21 |= 1 << irq_nr; | 93 | cached_21 |= 1 << d->irq; |
| 94 | inb(0x21); /* DUMMY */ | 94 | inb(0x21); /* DUMMY */ |
| 95 | outb(cached_21, 0x21); | 95 | outb(cached_21, 0x21); |
| 96 | outb(0x20, 0x20); /* Non-specific EOI */ | 96 | outb(0x20, 0x20); /* Non-specific EOI */ |
| @@ -104,42 +104,42 @@ static void i8259_set_irq_mask(int irq_nr) | |||
| 104 | outb(cached_21,0x21); | 104 | outb(cached_21,0x21); |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | static void i8259_mask_irq(unsigned int irq_nr) | 107 | static void i8259_mask_irq(struct irq_data *d) |
| 108 | { | 108 | { |
| 109 | unsigned long flags; | 109 | unsigned long flags; |
| 110 | 110 | ||
| 111 | pr_debug("i8259_mask_irq(%d)\n", irq_nr); | 111 | pr_debug("i8259_mask_irq(%d)\n", d->irq); |
| 112 | 112 | ||
| 113 | raw_spin_lock_irqsave(&i8259_lock, flags); | 113 | raw_spin_lock_irqsave(&i8259_lock, flags); |
| 114 | if (irq_nr < 8) | 114 | if (d->irq < 8) |
| 115 | cached_21 |= 1 << irq_nr; | 115 | cached_21 |= 1 << d->irq; |
| 116 | else | 116 | else |
| 117 | cached_A1 |= 1 << (irq_nr-8); | 117 | cached_A1 |= 1 << (d->irq-8); |
| 118 | i8259_set_irq_mask(irq_nr); | 118 | i8259_set_irq_mask(d->irq); |
| 119 | raw_spin_unlock_irqrestore(&i8259_lock, flags); | 119 | raw_spin_unlock_irqrestore(&i8259_lock, flags); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | static void i8259_unmask_irq(unsigned int irq_nr) | 122 | static void i8259_unmask_irq(struct irq_data *d) |
| 123 | { | 123 | { |
| 124 | unsigned long flags; | 124 | unsigned long flags; |
| 125 | 125 | ||
| 126 | pr_debug("i8259_unmask_irq(%d)\n", irq_nr); | 126 | pr_debug("i8259_unmask_irq(%d)\n", d->irq); |
| 127 | 127 | ||
| 128 | raw_spin_lock_irqsave(&i8259_lock, flags); | 128 | raw_spin_lock_irqsave(&i8259_lock, flags); |
| 129 | if (irq_nr < 8) | 129 | if (d->irq < 8) |
| 130 | cached_21 &= ~(1 << irq_nr); | 130 | cached_21 &= ~(1 << d->irq); |
| 131 | else | 131 | else |
| 132 | cached_A1 &= ~(1 << (irq_nr-8)); | 132 | cached_A1 &= ~(1 << (d->irq-8)); |
| 133 | i8259_set_irq_mask(irq_nr); | 133 | i8259_set_irq_mask(d->irq); |
| 134 | raw_spin_unlock_irqrestore(&i8259_lock, flags); | 134 | raw_spin_unlock_irqrestore(&i8259_lock, flags); |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | static struct irq_chip i8259_pic = { | 137 | static struct irq_chip i8259_pic = { |
| 138 | .name = "i8259", | 138 | .name = "i8259", |
| 139 | .mask = i8259_mask_irq, | 139 | .irq_mask = i8259_mask_irq, |
| 140 | .disable = i8259_mask_irq, | 140 | .irq_disable = i8259_mask_irq, |
| 141 | .unmask = i8259_unmask_irq, | 141 | .irq_unmask = i8259_unmask_irq, |
| 142 | .mask_ack = i8259_mask_and_ack_irq, | 142 | .irq_mask_ack = i8259_mask_and_ack_irq, |
| 143 | }; | 143 | }; |
| 144 | 144 | ||
| 145 | static struct resource pic1_iores = { | 145 | static struct resource pic1_iores = { |
| @@ -175,28 +175,16 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq, | |||
| 175 | 175 | ||
| 176 | /* We block the internal cascade */ | 176 | /* We block the internal cascade */ |
| 177 | if (hw == 2) | 177 | if (hw == 2) |
| 178 | irq_to_desc(virq)->status |= IRQ_NOREQUEST; | 178 | irq_set_status_flags(virq, IRQ_NOREQUEST); |
| 179 | 179 | ||
| 180 | /* We use the level handler only for now, we might want to | 180 | /* We use the level handler only for now, we might want to |
| 181 | * be more cautious here but that works for now | 181 | * be more cautious here but that works for now |
| 182 | */ | 182 | */ |
| 183 | irq_to_desc(virq)->status |= IRQ_LEVEL; | 183 | irq_set_status_flags(virq, IRQ_LEVEL); |
| 184 | set_irq_chip_and_handler(virq, &i8259_pic, handle_level_irq); | 184 | irq_set_chip_and_handler(virq, &i8259_pic, handle_level_irq); |
| 185 | return 0; | 185 | return 0; |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | static void i8259_host_unmap(struct irq_host *h, unsigned int virq) | ||
| 189 | { | ||
| 190 | /* Make sure irq is masked in hardware */ | ||
| 191 | i8259_mask_irq(virq); | ||
| 192 | |||
| 193 | /* remove chip and handler */ | ||
| 194 | set_irq_chip_and_handler(virq, NULL, NULL); | ||
| 195 | |||
| 196 | /* Make sure it's completed */ | ||
| 197 | synchronize_irq(virq); | ||
| 198 | } | ||
| 199 | |||
| 200 | static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, | 188 | static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, |
| 201 | const u32 *intspec, unsigned int intsize, | 189 | const u32 *intspec, unsigned int intsize, |
| 202 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 190 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
| @@ -220,7 +208,6 @@ static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, | |||
| 220 | static struct irq_host_ops i8259_host_ops = { | 208 | static struct irq_host_ops i8259_host_ops = { |
| 221 | .match = i8259_host_match, | 209 | .match = i8259_host_match, |
| 222 | .map = i8259_host_map, | 210 | .map = i8259_host_map, |
| 223 | .unmap = i8259_host_unmap, | ||
| 224 | .xlate = i8259_host_xlate, | 211 | .xlate = i8259_host_xlate, |
| 225 | }; | 212 | }; |
| 226 | 213 | ||
diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c index 7ed809676642..82fdad885d20 100644 --- a/arch/powerpc/sysdev/indirect_pci.c +++ b/arch/powerpc/sysdev/indirect_pci.c | |||
| @@ -117,7 +117,7 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, | |||
| 117 | out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) | | 117 | out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) | |
| 118 | (devfn << 8) | reg | cfg_type)); | 118 | (devfn << 8) | reg | cfg_type)); |
| 119 | 119 | ||
| 120 | /* surpress setting of PCI_PRIMARY_BUS */ | 120 | /* suppress setting of PCI_PRIMARY_BUS */ |
| 121 | if (hose->indirect_type & PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS) | 121 | if (hose->indirect_type & PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS) |
| 122 | if ((offset == PCI_PRIMARY_BUS) && | 122 | if ((offset == PCI_PRIMARY_BUS) && |
| 123 | (bus->number == hose->first_busno)) | 123 | (bus->number == hose->first_busno)) |
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index d7b9b9c69287..7367d17364cb 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c | |||
| @@ -18,7 +18,7 @@ | |||
| 18 | #include <linux/stddef.h> | 18 | #include <linux/stddef.h> |
| 19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
| 20 | #include <linux/signal.h> | 20 | #include <linux/signal.h> |
| 21 | #include <linux/sysdev.h> | 21 | #include <linux/syscore_ops.h> |
| 22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
| 23 | #include <linux/bootmem.h> | 23 | #include <linux/bootmem.h> |
| 24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
| @@ -521,12 +521,10 @@ static inline struct ipic * ipic_from_irq(unsigned int virq) | |||
| 521 | return primary_ipic; | 521 | return primary_ipic; |
| 522 | } | 522 | } |
| 523 | 523 | ||
| 524 | #define ipic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) | 524 | static void ipic_unmask_irq(struct irq_data *d) |
| 525 | |||
| 526 | static void ipic_unmask_irq(unsigned int virq) | ||
| 527 | { | 525 | { |
| 528 | struct ipic *ipic = ipic_from_irq(virq); | 526 | struct ipic *ipic = ipic_from_irq(d->irq); |
| 529 | unsigned int src = ipic_irq_to_hw(virq); | 527 | unsigned int src = irqd_to_hwirq(d); |
| 530 | unsigned long flags; | 528 | unsigned long flags; |
| 531 | u32 temp; | 529 | u32 temp; |
| 532 | 530 | ||
| @@ -539,10 +537,10 @@ static void ipic_unmask_irq(unsigned int virq) | |||
| 539 | raw_spin_unlock_irqrestore(&ipic_lock, flags); | 537 | raw_spin_unlock_irqrestore(&ipic_lock, flags); |
| 540 | } | 538 | } |
| 541 | 539 | ||
| 542 | static void ipic_mask_irq(unsigned int virq) | 540 | static void ipic_mask_irq(struct irq_data *d) |
| 543 | { | 541 | { |
| 544 | struct ipic *ipic = ipic_from_irq(virq); | 542 | struct ipic *ipic = ipic_from_irq(d->irq); |
| 545 | unsigned int src = ipic_irq_to_hw(virq); | 543 | unsigned int src = irqd_to_hwirq(d); |
| 546 | unsigned long flags; | 544 | unsigned long flags; |
| 547 | u32 temp; | 545 | u32 temp; |
| 548 | 546 | ||
| @@ -559,10 +557,10 @@ static void ipic_mask_irq(unsigned int virq) | |||
| 559 | raw_spin_unlock_irqrestore(&ipic_lock, flags); | 557 | raw_spin_unlock_irqrestore(&ipic_lock, flags); |
| 560 | } | 558 | } |
| 561 | 559 | ||
| 562 | static void ipic_ack_irq(unsigned int virq) | 560 | static void ipic_ack_irq(struct irq_data *d) |
| 563 | { | 561 | { |
| 564 | struct ipic *ipic = ipic_from_irq(virq); | 562 | struct ipic *ipic = ipic_from_irq(d->irq); |
| 565 | unsigned int src = ipic_irq_to_hw(virq); | 563 | unsigned int src = irqd_to_hwirq(d); |
| 566 | unsigned long flags; | 564 | unsigned long flags; |
| 567 | u32 temp; | 565 | u32 temp; |
| 568 | 566 | ||
| @@ -578,10 +576,10 @@ static void ipic_ack_irq(unsigned int virq) | |||
| 578 | raw_spin_unlock_irqrestore(&ipic_lock, flags); | 576 | raw_spin_unlock_irqrestore(&ipic_lock, flags); |
| 579 | } | 577 | } |
| 580 | 578 | ||
| 581 | static void ipic_mask_irq_and_ack(unsigned int virq) | 579 | static void ipic_mask_irq_and_ack(struct irq_data *d) |
| 582 | { | 580 | { |
| 583 | struct ipic *ipic = ipic_from_irq(virq); | 581 | struct ipic *ipic = ipic_from_irq(d->irq); |
| 584 | unsigned int src = ipic_irq_to_hw(virq); | 582 | unsigned int src = irqd_to_hwirq(d); |
| 585 | unsigned long flags; | 583 | unsigned long flags; |
| 586 | u32 temp; | 584 | u32 temp; |
| 587 | 585 | ||
| @@ -601,11 +599,10 @@ static void ipic_mask_irq_and_ack(unsigned int virq) | |||
| 601 | raw_spin_unlock_irqrestore(&ipic_lock, flags); | 599 | raw_spin_unlock_irqrestore(&ipic_lock, flags); |
| 602 | } | 600 | } |
| 603 | 601 | ||
| 604 | static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type) | 602 | static int ipic_set_irq_type(struct irq_data *d, unsigned int flow_type) |
| 605 | { | 603 | { |
| 606 | struct ipic *ipic = ipic_from_irq(virq); | 604 | struct ipic *ipic = ipic_from_irq(d->irq); |
| 607 | unsigned int src = ipic_irq_to_hw(virq); | 605 | unsigned int src = irqd_to_hwirq(d); |
| 608 | struct irq_desc *desc = irq_to_desc(virq); | ||
| 609 | unsigned int vold, vnew, edibit; | 606 | unsigned int vold, vnew, edibit; |
| 610 | 607 | ||
| 611 | if (flow_type == IRQ_TYPE_NONE) | 608 | if (flow_type == IRQ_TYPE_NONE) |
| @@ -623,17 +620,16 @@ static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
| 623 | printk(KERN_ERR "ipic: edge sense not supported on internal " | 620 | printk(KERN_ERR "ipic: edge sense not supported on internal " |
| 624 | "interrupts\n"); | 621 | "interrupts\n"); |
| 625 | return -EINVAL; | 622 | return -EINVAL; |
| 623 | |||
| 626 | } | 624 | } |
| 627 | 625 | ||
| 628 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); | 626 | irqd_set_trigger_type(d, flow_type); |
| 629 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; | ||
| 630 | if (flow_type & IRQ_TYPE_LEVEL_LOW) { | 627 | if (flow_type & IRQ_TYPE_LEVEL_LOW) { |
| 631 | desc->status |= IRQ_LEVEL; | 628 | __irq_set_handler_locked(d->irq, handle_level_irq); |
| 632 | desc->handle_irq = handle_level_irq; | 629 | d->chip = &ipic_level_irq_chip; |
| 633 | desc->chip = &ipic_level_irq_chip; | ||
| 634 | } else { | 630 | } else { |
| 635 | desc->handle_irq = handle_edge_irq; | 631 | __irq_set_handler_locked(d->irq, handle_edge_irq); |
| 636 | desc->chip = &ipic_edge_irq_chip; | 632 | d->chip = &ipic_edge_irq_chip; |
| 637 | } | 633 | } |
| 638 | 634 | ||
| 639 | /* only EXT IRQ senses are programmable on ipic | 635 | /* only EXT IRQ senses are programmable on ipic |
| @@ -655,25 +651,25 @@ static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
| 655 | } | 651 | } |
| 656 | if (vold != vnew) | 652 | if (vold != vnew) |
| 657 | ipic_write(ipic->regs, IPIC_SECNR, vnew); | 653 | ipic_write(ipic->regs, IPIC_SECNR, vnew); |
| 658 | return 0; | 654 | return IRQ_SET_MASK_OK_NOCOPY; |
| 659 | } | 655 | } |
| 660 | 656 | ||
| 661 | /* level interrupts and edge interrupts have different ack operations */ | 657 | /* level interrupts and edge interrupts have different ack operations */ |
| 662 | static struct irq_chip ipic_level_irq_chip = { | 658 | static struct irq_chip ipic_level_irq_chip = { |
| 663 | .name = "IPIC", | 659 | .name = "IPIC", |
| 664 | .unmask = ipic_unmask_irq, | 660 | .irq_unmask = ipic_unmask_irq, |
| 665 | .mask = ipic_mask_irq, | 661 | .irq_mask = ipic_mask_irq, |
| 666 | .mask_ack = ipic_mask_irq, | 662 | .irq_mask_ack = ipic_mask_irq, |
| 667 | .set_type = ipic_set_irq_type, | 663 | .irq_set_type = ipic_set_irq_type, |
| 668 | }; | 664 | }; |
| 669 | 665 | ||
| 670 | static struct irq_chip ipic_edge_irq_chip = { | 666 | static struct irq_chip ipic_edge_irq_chip = { |
| 671 | .name = "IPIC", | 667 | .name = "IPIC", |
| 672 | .unmask = ipic_unmask_irq, | 668 | .irq_unmask = ipic_unmask_irq, |
| 673 | .mask = ipic_mask_irq, | 669 | .irq_mask = ipic_mask_irq, |
| 674 | .mask_ack = ipic_mask_irq_and_ack, | 670 | .irq_mask_ack = ipic_mask_irq_and_ack, |
| 675 | .ack = ipic_ack_irq, | 671 | .irq_ack = ipic_ack_irq, |
| 676 | .set_type = ipic_set_irq_type, | 672 | .irq_set_type = ipic_set_irq_type, |
| 677 | }; | 673 | }; |
| 678 | 674 | ||
| 679 | static int ipic_host_match(struct irq_host *h, struct device_node *node) | 675 | static int ipic_host_match(struct irq_host *h, struct device_node *node) |
| @@ -687,11 +683,11 @@ static int ipic_host_map(struct irq_host *h, unsigned int virq, | |||
| 687 | { | 683 | { |
| 688 | struct ipic *ipic = h->host_data; | 684 | struct ipic *ipic = h->host_data; |
| 689 | 685 | ||
| 690 | set_irq_chip_data(virq, ipic); | 686 | irq_set_chip_data(virq, ipic); |
| 691 | set_irq_chip_and_handler(virq, &ipic_level_irq_chip, handle_level_irq); | 687 | irq_set_chip_and_handler(virq, &ipic_level_irq_chip, handle_level_irq); |
| 692 | 688 | ||
| 693 | /* Set default irq type */ | 689 | /* Set default irq type */ |
| 694 | set_irq_type(virq, IRQ_TYPE_NONE); | 690 | irq_set_irq_type(virq, IRQ_TYPE_NONE); |
| 695 | 691 | ||
| 696 | return 0; | 692 | return 0; |
| 697 | } | 693 | } |
| @@ -795,7 +791,7 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) | |||
| 795 | int ipic_set_priority(unsigned int virq, unsigned int priority) | 791 | int ipic_set_priority(unsigned int virq, unsigned int priority) |
| 796 | { | 792 | { |
| 797 | struct ipic *ipic = ipic_from_irq(virq); | 793 | struct ipic *ipic = ipic_from_irq(virq); |
| 798 | unsigned int src = ipic_irq_to_hw(virq); | 794 | unsigned int src = virq_to_hw(virq); |
| 799 | u32 temp; | 795 | u32 temp; |
| 800 | 796 | ||
| 801 | if (priority > 7) | 797 | if (priority > 7) |
| @@ -823,7 +819,7 @@ int ipic_set_priority(unsigned int virq, unsigned int priority) | |||
| 823 | void ipic_set_highest_priority(unsigned int virq) | 819 | void ipic_set_highest_priority(unsigned int virq) |
| 824 | { | 820 | { |
| 825 | struct ipic *ipic = ipic_from_irq(virq); | 821 | struct ipic *ipic = ipic_from_irq(virq); |
| 826 | unsigned int src = ipic_irq_to_hw(virq); | 822 | unsigned int src = virq_to_hw(virq); |
| 827 | u32 temp; | 823 | u32 temp; |
| 828 | 824 | ||
| 829 | temp = ipic_read(ipic->regs, IPIC_SICFR); | 825 | temp = ipic_read(ipic->regs, IPIC_SICFR); |
| @@ -904,7 +900,7 @@ static struct { | |||
| 904 | u32 sercr; | 900 | u32 sercr; |
| 905 | } ipic_saved_state; | 901 | } ipic_saved_state; |
| 906 | 902 | ||
| 907 | static int ipic_suspend(struct sys_device *sdev, pm_message_t state) | 903 | static int ipic_suspend(void) |
| 908 | { | 904 | { |
| 909 | struct ipic *ipic = primary_ipic; | 905 | struct ipic *ipic = primary_ipic; |
| 910 | 906 | ||
| @@ -935,7 +931,7 @@ static int ipic_suspend(struct sys_device *sdev, pm_message_t state) | |||
| 935 | return 0; | 931 | return 0; |
| 936 | } | 932 | } |
| 937 | 933 | ||
| 938 | static int ipic_resume(struct sys_device *sdev) | 934 | static void ipic_resume(void) |
| 939 | { | 935 | { |
| 940 | struct ipic *ipic = primary_ipic; | 936 | struct ipic *ipic = primary_ipic; |
| 941 | 937 | ||
| @@ -951,44 +947,26 @@ static int ipic_resume(struct sys_device *sdev) | |||
| 951 | ipic_write(ipic->regs, IPIC_SECNR, ipic_saved_state.secnr); | 947 | ipic_write(ipic->regs, IPIC_SECNR, ipic_saved_state.secnr); |
| 952 | ipic_write(ipic->regs, IPIC_SERMR, ipic_saved_state.sermr); | 948 | ipic_write(ipic->regs, IPIC_SERMR, ipic_saved_state.sermr); |
| 953 | ipic_write(ipic->regs, IPIC_SERCR, ipic_saved_state.sercr); | 949 | ipic_write(ipic->regs, IPIC_SERCR, ipic_saved_state.sercr); |
| 954 | |||
| 955 | return 0; | ||
| 956 | } | 950 | } |
| 957 | #else | 951 | #else |
| 958 | #define ipic_suspend NULL | 952 | #define ipic_suspend NULL |
| 959 | #define ipic_resume NULL | 953 | #define ipic_resume NULL |
| 960 | #endif | 954 | #endif |
| 961 | 955 | ||
| 962 | static struct sysdev_class ipic_sysclass = { | 956 | static struct syscore_ops ipic_syscore_ops = { |
| 963 | .name = "ipic", | ||
| 964 | .suspend = ipic_suspend, | 957 | .suspend = ipic_suspend, |
| 965 | .resume = ipic_resume, | 958 | .resume = ipic_resume, |
| 966 | }; | 959 | }; |
| 967 | 960 | ||
| 968 | static struct sys_device device_ipic = { | 961 | static int __init init_ipic_syscore(void) |
| 969 | .id = 0, | ||
| 970 | .cls = &ipic_sysclass, | ||
| 971 | }; | ||
| 972 | |||
| 973 | static int __init init_ipic_sysfs(void) | ||
| 974 | { | 962 | { |
| 975 | int rc; | ||
| 976 | |||
| 977 | if (!primary_ipic || !primary_ipic->regs) | 963 | if (!primary_ipic || !primary_ipic->regs) |
| 978 | return -ENODEV; | 964 | return -ENODEV; |
| 979 | printk(KERN_DEBUG "Registering ipic with sysfs...\n"); | ||
| 980 | 965 | ||
| 981 | rc = sysdev_class_register(&ipic_sysclass); | 966 | printk(KERN_DEBUG "Registering ipic system core operations\n"); |
| 982 | if (rc) { | 967 | register_syscore_ops(&ipic_syscore_ops); |
| 983 | printk(KERN_ERR "Failed registering ipic sys class\n"); | 968 | |
| 984 | return -ENODEV; | ||
| 985 | } | ||
| 986 | rc = sysdev_register(&device_ipic); | ||
| 987 | if (rc) { | ||
| 988 | printk(KERN_ERR "Failed registering ipic sys device\n"); | ||
| 989 | return -ENODEV; | ||
| 990 | } | ||
| 991 | return 0; | 969 | return 0; |
| 992 | } | 970 | } |
| 993 | 971 | ||
| 994 | subsys_initcall(init_ipic_sysfs); | 972 | subsys_initcall(init_ipic_syscore); |
diff --git a/arch/powerpc/sysdev/mmio_nvram.c b/arch/powerpc/sysdev/mmio_nvram.c index 207324209065..ddc877a3a23a 100644 --- a/arch/powerpc/sysdev/mmio_nvram.c +++ b/arch/powerpc/sysdev/mmio_nvram.c | |||
| @@ -115,6 +115,8 @@ int __init mmio_nvram_init(void) | |||
| 115 | int ret; | 115 | int ret; |
| 116 | 116 | ||
| 117 | nvram_node = of_find_node_by_type(NULL, "nvram"); | 117 | nvram_node = of_find_node_by_type(NULL, "nvram"); |
| 118 | if (!nvram_node) | ||
| 119 | nvram_node = of_find_compatible_node(NULL, NULL, "nvram"); | ||
| 118 | if (!nvram_node) { | 120 | if (!nvram_node) { |
| 119 | printk(KERN_WARNING "nvram: no node found in device-tree\n"); | 121 | printk(KERN_WARNING "nvram: no node found in device-tree\n"); |
| 120 | return -ENODEV; | 122 | return -ENODEV; |
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index 8c27d261aba8..20924f2246f0 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c | |||
| @@ -25,10 +25,10 @@ static sysconf8xx_t __iomem *siu_reg; | |||
| 25 | 25 | ||
| 26 | int cpm_get_irq(struct pt_regs *regs); | 26 | int cpm_get_irq(struct pt_regs *regs); |
| 27 | 27 | ||
| 28 | static void mpc8xx_unmask_irq(unsigned int virq) | 28 | static void mpc8xx_unmask_irq(struct irq_data *d) |
| 29 | { | 29 | { |
| 30 | int bit, word; | 30 | int bit, word; |
| 31 | unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq; | 31 | unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); |
| 32 | 32 | ||
| 33 | bit = irq_nr & 0x1f; | 33 | bit = irq_nr & 0x1f; |
| 34 | word = irq_nr >> 5; | 34 | word = irq_nr >> 5; |
| @@ -37,10 +37,10 @@ static void mpc8xx_unmask_irq(unsigned int virq) | |||
| 37 | out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]); | 37 | out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | static void mpc8xx_mask_irq(unsigned int virq) | 40 | static void mpc8xx_mask_irq(struct irq_data *d) |
| 41 | { | 41 | { |
| 42 | int bit, word; | 42 | int bit, word; |
| 43 | unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq; | 43 | unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); |
| 44 | 44 | ||
| 45 | bit = irq_nr & 0x1f; | 45 | bit = irq_nr & 0x1f; |
| 46 | word = irq_nr >> 5; | 46 | word = irq_nr >> 5; |
| @@ -49,19 +49,19 @@ static void mpc8xx_mask_irq(unsigned int virq) | |||
| 49 | out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]); | 49 | out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | static void mpc8xx_ack(unsigned int virq) | 52 | static void mpc8xx_ack(struct irq_data *d) |
| 53 | { | 53 | { |
| 54 | int bit; | 54 | int bit; |
| 55 | unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq; | 55 | unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); |
| 56 | 56 | ||
| 57 | bit = irq_nr & 0x1f; | 57 | bit = irq_nr & 0x1f; |
| 58 | out_be32(&siu_reg->sc_sipend, 1 << (31-bit)); | 58 | out_be32(&siu_reg->sc_sipend, 1 << (31-bit)); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | static void mpc8xx_end_irq(unsigned int virq) | 61 | static void mpc8xx_end_irq(struct irq_data *d) |
| 62 | { | 62 | { |
| 63 | int bit, word; | 63 | int bit, word; |
| 64 | unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq; | 64 | unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); |
| 65 | 65 | ||
| 66 | bit = irq_nr & 0x1f; | 66 | bit = irq_nr & 0x1f; |
| 67 | word = irq_nr >> 5; | 67 | word = irq_nr >> 5; |
| @@ -70,24 +70,17 @@ static void mpc8xx_end_irq(unsigned int virq) | |||
| 70 | out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]); | 70 | out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type) | 73 | static int mpc8xx_set_irq_type(struct irq_data *d, unsigned int flow_type) |
| 74 | { | 74 | { |
| 75 | struct irq_desc *desc = irq_to_desc(virq); | ||
| 76 | |||
| 77 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); | ||
| 78 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; | ||
| 79 | if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) | ||
| 80 | desc->status |= IRQ_LEVEL; | ||
| 81 | |||
| 82 | if (flow_type & IRQ_TYPE_EDGE_FALLING) { | 75 | if (flow_type & IRQ_TYPE_EDGE_FALLING) { |
| 83 | irq_hw_number_t hw = (unsigned int)irq_map[virq].hwirq; | 76 | irq_hw_number_t hw = (unsigned int)irqd_to_hwirq(d); |
| 84 | unsigned int siel = in_be32(&siu_reg->sc_siel); | 77 | unsigned int siel = in_be32(&siu_reg->sc_siel); |
| 85 | 78 | ||
| 86 | /* only external IRQ senses are programmable */ | 79 | /* only external IRQ senses are programmable */ |
| 87 | if ((hw & 1) == 0) { | 80 | if ((hw & 1) == 0) { |
| 88 | siel |= (0x80000000 >> hw); | 81 | siel |= (0x80000000 >> hw); |
| 89 | out_be32(&siu_reg->sc_siel, siel); | 82 | out_be32(&siu_reg->sc_siel, siel); |
| 90 | desc->handle_irq = handle_edge_irq; | 83 | __irq_set_handler_locked(d->irq, handle_edge_irq); |
| 91 | } | 84 | } |
| 92 | } | 85 | } |
| 93 | return 0; | 86 | return 0; |
| @@ -95,11 +88,11 @@ static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
| 95 | 88 | ||
| 96 | static struct irq_chip mpc8xx_pic = { | 89 | static struct irq_chip mpc8xx_pic = { |
| 97 | .name = "MPC8XX SIU", | 90 | .name = "MPC8XX SIU", |
| 98 | .unmask = mpc8xx_unmask_irq, | 91 | .irq_unmask = mpc8xx_unmask_irq, |
| 99 | .mask = mpc8xx_mask_irq, | 92 | .irq_mask = mpc8xx_mask_irq, |
| 100 | .ack = mpc8xx_ack, | 93 | .irq_ack = mpc8xx_ack, |
| 101 | .eoi = mpc8xx_end_irq, | 94 | .irq_eoi = mpc8xx_end_irq, |
| 102 | .set_type = mpc8xx_set_irq_type, | 95 | .irq_set_type = mpc8xx_set_irq_type, |
| 103 | }; | 96 | }; |
| 104 | 97 | ||
| 105 | unsigned int mpc8xx_get_irq(void) | 98 | unsigned int mpc8xx_get_irq(void) |
| @@ -124,7 +117,7 @@ static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq, | |||
| 124 | pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw); | 117 | pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw); |
| 125 | 118 | ||
| 126 | /* Set default irq handle */ | 119 | /* Set default irq handle */ |
| 127 | set_irq_chip_and_handler(virq, &mpc8xx_pic, handle_level_irq); | 120 | irq_set_chip_and_handler(virq, &mpc8xx_pic, handle_level_irq); |
| 128 | return 0; | 121 | return 0; |
| 129 | } | 122 | } |
| 130 | 123 | ||
diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c index 2b69084d0f0c..fb4963abdf55 100644 --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * GPIOs on MPC8349/8572/8610 and compatible | 2 | * GPIOs on MPC512x/8349/8572/8610 and compatible |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk> | 4 | * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk> |
| 5 | * | 5 | * |
| @@ -26,6 +26,7 @@ | |||
| 26 | #define GPIO_IER 0x0c | 26 | #define GPIO_IER 0x0c |
| 27 | #define GPIO_IMR 0x10 | 27 | #define GPIO_IMR 0x10 |
| 28 | #define GPIO_ICR 0x14 | 28 | #define GPIO_ICR 0x14 |
| 29 | #define GPIO_ICR2 0x18 | ||
| 29 | 30 | ||
| 30 | struct mpc8xxx_gpio_chip { | 31 | struct mpc8xxx_gpio_chip { |
| 31 | struct of_mm_gpio_chip mm_gc; | 32 | struct of_mm_gpio_chip mm_gc; |
| @@ -37,6 +38,7 @@ struct mpc8xxx_gpio_chip { | |||
| 37 | */ | 38 | */ |
| 38 | u32 data; | 39 | u32 data; |
| 39 | struct irq_host *irq; | 40 | struct irq_host *irq; |
| 41 | void *of_dev_id_data; | ||
| 40 | }; | 42 | }; |
| 41 | 43 | ||
| 42 | static inline u32 mpc8xxx_gpio2mask(unsigned int gpio) | 44 | static inline u32 mpc8xxx_gpio2mask(unsigned int gpio) |
| @@ -143,7 +145,7 @@ static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) | |||
| 143 | 145 | ||
| 144 | static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc) | 146 | static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc) |
| 145 | { | 147 | { |
| 146 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_desc_data(desc); | 148 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc); |
| 147 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; | 149 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; |
| 148 | unsigned int mask; | 150 | unsigned int mask; |
| 149 | 151 | ||
| @@ -153,43 +155,43 @@ static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc) | |||
| 153 | 32 - ffs(mask))); | 155 | 32 - ffs(mask))); |
| 154 | } | 156 | } |
| 155 | 157 | ||
| 156 | static void mpc8xxx_irq_unmask(unsigned int virq) | 158 | static void mpc8xxx_irq_unmask(struct irq_data *d) |
| 157 | { | 159 | { |
| 158 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); | 160 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); |
| 159 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; | 161 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; |
| 160 | unsigned long flags; | 162 | unsigned long flags; |
| 161 | 163 | ||
| 162 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); | 164 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); |
| 163 | 165 | ||
| 164 | setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(virq))); | 166 | setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); |
| 165 | 167 | ||
| 166 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); | 168 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); |
| 167 | } | 169 | } |
| 168 | 170 | ||
| 169 | static void mpc8xxx_irq_mask(unsigned int virq) | 171 | static void mpc8xxx_irq_mask(struct irq_data *d) |
| 170 | { | 172 | { |
| 171 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); | 173 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); |
| 172 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; | 174 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; |
| 173 | unsigned long flags; | 175 | unsigned long flags; |
| 174 | 176 | ||
| 175 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); | 177 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); |
| 176 | 178 | ||
| 177 | clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(virq))); | 179 | clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); |
| 178 | 180 | ||
| 179 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); | 181 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); |
| 180 | } | 182 | } |
| 181 | 183 | ||
| 182 | static void mpc8xxx_irq_ack(unsigned int virq) | 184 | static void mpc8xxx_irq_ack(struct irq_data *d) |
| 183 | { | 185 | { |
| 184 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); | 186 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); |
| 185 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; | 187 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; |
| 186 | 188 | ||
| 187 | out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(virq_to_hw(virq))); | 189 | out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); |
| 188 | } | 190 | } |
| 189 | 191 | ||
| 190 | static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type) | 192 | static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) |
| 191 | { | 193 | { |
| 192 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); | 194 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); |
| 193 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; | 195 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; |
| 194 | unsigned long flags; | 196 | unsigned long flags; |
| 195 | 197 | ||
| @@ -197,14 +199,59 @@ static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type) | |||
| 197 | case IRQ_TYPE_EDGE_FALLING: | 199 | case IRQ_TYPE_EDGE_FALLING: |
| 198 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); | 200 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); |
| 199 | setbits32(mm->regs + GPIO_ICR, | 201 | setbits32(mm->regs + GPIO_ICR, |
| 200 | mpc8xxx_gpio2mask(virq_to_hw(virq))); | 202 | mpc8xxx_gpio2mask(irqd_to_hwirq(d))); |
| 201 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); | 203 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); |
| 202 | break; | 204 | break; |
| 203 | 205 | ||
| 204 | case IRQ_TYPE_EDGE_BOTH: | 206 | case IRQ_TYPE_EDGE_BOTH: |
| 205 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); | 207 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); |
| 206 | clrbits32(mm->regs + GPIO_ICR, | 208 | clrbits32(mm->regs + GPIO_ICR, |
| 207 | mpc8xxx_gpio2mask(virq_to_hw(virq))); | 209 | mpc8xxx_gpio2mask(irqd_to_hwirq(d))); |
| 210 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); | ||
| 211 | break; | ||
| 212 | |||
| 213 | default: | ||
| 214 | return -EINVAL; | ||
| 215 | } | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type) | ||
| 221 | { | ||
| 222 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); | ||
| 223 | struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; | ||
| 224 | unsigned long gpio = irqd_to_hwirq(d); | ||
| 225 | void __iomem *reg; | ||
| 226 | unsigned int shift; | ||
| 227 | unsigned long flags; | ||
| 228 | |||
| 229 | if (gpio < 16) { | ||
| 230 | reg = mm->regs + GPIO_ICR; | ||
| 231 | shift = (15 - gpio) * 2; | ||
| 232 | } else { | ||
| 233 | reg = mm->regs + GPIO_ICR2; | ||
| 234 | shift = (15 - (gpio % 16)) * 2; | ||
| 235 | } | ||
| 236 | |||
| 237 | switch (flow_type) { | ||
| 238 | case IRQ_TYPE_EDGE_FALLING: | ||
| 239 | case IRQ_TYPE_LEVEL_LOW: | ||
| 240 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); | ||
| 241 | clrsetbits_be32(reg, 3 << shift, 2 << shift); | ||
| 242 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); | ||
| 243 | break; | ||
| 244 | |||
| 245 | case IRQ_TYPE_EDGE_RISING: | ||
| 246 | case IRQ_TYPE_LEVEL_HIGH: | ||
| 247 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); | ||
| 248 | clrsetbits_be32(reg, 3 << shift, 1 << shift); | ||
| 249 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); | ||
| 250 | break; | ||
| 251 | |||
| 252 | case IRQ_TYPE_EDGE_BOTH: | ||
| 253 | spin_lock_irqsave(&mpc8xxx_gc->lock, flags); | ||
| 254 | clrbits32(reg, 3 << shift); | ||
| 208 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); | 255 | spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); |
| 209 | break; | 256 | break; |
| 210 | 257 | ||
| @@ -217,18 +264,23 @@ static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type) | |||
| 217 | 264 | ||
| 218 | static struct irq_chip mpc8xxx_irq_chip = { | 265 | static struct irq_chip mpc8xxx_irq_chip = { |
| 219 | .name = "mpc8xxx-gpio", | 266 | .name = "mpc8xxx-gpio", |
| 220 | .unmask = mpc8xxx_irq_unmask, | 267 | .irq_unmask = mpc8xxx_irq_unmask, |
| 221 | .mask = mpc8xxx_irq_mask, | 268 | .irq_mask = mpc8xxx_irq_mask, |
| 222 | .ack = mpc8xxx_irq_ack, | 269 | .irq_ack = mpc8xxx_irq_ack, |
| 223 | .set_type = mpc8xxx_irq_set_type, | 270 | .irq_set_type = mpc8xxx_irq_set_type, |
| 224 | }; | 271 | }; |
| 225 | 272 | ||
| 226 | static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, | 273 | static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, |
| 227 | irq_hw_number_t hw) | 274 | irq_hw_number_t hw) |
| 228 | { | 275 | { |
| 229 | set_irq_chip_data(virq, h->host_data); | 276 | struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data; |
| 230 | set_irq_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); | 277 | |
| 231 | set_irq_type(virq, IRQ_TYPE_NONE); | 278 | if (mpc8xxx_gc->of_dev_id_data) |
| 279 | mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data; | ||
| 280 | |||
| 281 | irq_set_chip_data(virq, h->host_data); | ||
| 282 | irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); | ||
| 283 | irq_set_irq_type(virq, IRQ_TYPE_NONE); | ||
| 232 | 284 | ||
| 233 | return 0; | 285 | return 0; |
| 234 | } | 286 | } |
| @@ -253,11 +305,21 @@ static struct irq_host_ops mpc8xxx_gpio_irq_ops = { | |||
| 253 | .xlate = mpc8xxx_gpio_irq_xlate, | 305 | .xlate = mpc8xxx_gpio_irq_xlate, |
| 254 | }; | 306 | }; |
| 255 | 307 | ||
| 308 | static struct of_device_id mpc8xxx_gpio_ids[] __initdata = { | ||
| 309 | { .compatible = "fsl,mpc8349-gpio", }, | ||
| 310 | { .compatible = "fsl,mpc8572-gpio", }, | ||
| 311 | { .compatible = "fsl,mpc8610-gpio", }, | ||
| 312 | { .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, }, | ||
| 313 | { .compatible = "fsl,qoriq-gpio", }, | ||
| 314 | {} | ||
| 315 | }; | ||
| 316 | |||
| 256 | static void __init mpc8xxx_add_controller(struct device_node *np) | 317 | static void __init mpc8xxx_add_controller(struct device_node *np) |
| 257 | { | 318 | { |
| 258 | struct mpc8xxx_gpio_chip *mpc8xxx_gc; | 319 | struct mpc8xxx_gpio_chip *mpc8xxx_gc; |
| 259 | struct of_mm_gpio_chip *mm_gc; | 320 | struct of_mm_gpio_chip *mm_gc; |
| 260 | struct gpio_chip *gc; | 321 | struct gpio_chip *gc; |
| 322 | const struct of_device_id *id; | ||
| 261 | unsigned hwirq; | 323 | unsigned hwirq; |
| 262 | int ret; | 324 | int ret; |
| 263 | 325 | ||
| @@ -297,14 +359,18 @@ static void __init mpc8xxx_add_controller(struct device_node *np) | |||
| 297 | if (!mpc8xxx_gc->irq) | 359 | if (!mpc8xxx_gc->irq) |
| 298 | goto skip_irq; | 360 | goto skip_irq; |
| 299 | 361 | ||
| 362 | id = of_match_node(mpc8xxx_gpio_ids, np); | ||
| 363 | if (id) | ||
| 364 | mpc8xxx_gc->of_dev_id_data = id->data; | ||
| 365 | |||
| 300 | mpc8xxx_gc->irq->host_data = mpc8xxx_gc; | 366 | mpc8xxx_gc->irq->host_data = mpc8xxx_gc; |
| 301 | 367 | ||
| 302 | /* ack and mask all irqs */ | 368 | /* ack and mask all irqs */ |
| 303 | out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); | 369 | out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); |
| 304 | out_be32(mm_gc->regs + GPIO_IMR, 0); | 370 | out_be32(mm_gc->regs + GPIO_IMR, 0); |
| 305 | 371 | ||
| 306 | set_irq_data(hwirq, mpc8xxx_gc); | 372 | irq_set_handler_data(hwirq, mpc8xxx_gc); |
| 307 | set_irq_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade); | 373 | irq_set_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade); |
| 308 | 374 | ||
| 309 | skip_irq: | 375 | skip_irq: |
| 310 | return; | 376 | return; |
| @@ -321,13 +387,7 @@ static int __init mpc8xxx_add_gpiochips(void) | |||
| 321 | { | 387 | { |
| 322 | struct device_node *np; | 388 | struct device_node *np; |
| 323 | 389 | ||
| 324 | for_each_compatible_node(np, NULL, "fsl,mpc8349-gpio") | 390 | for_each_matching_node(np, mpc8xxx_gpio_ids) |
| 325 | mpc8xxx_add_controller(np); | ||
| 326 | |||
| 327 | for_each_compatible_node(np, NULL, "fsl,mpc8572-gpio") | ||
| 328 | mpc8xxx_add_controller(np); | ||
| 329 | |||
| 330 | for_each_compatible_node(np, NULL, "fsl,mpc8610-gpio") | ||
| 331 | mpc8xxx_add_controller(np); | 391 | mpc8xxx_add_controller(np); |
| 332 | 392 | ||
| 333 | return 0; | 393 | return 0; |
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 7c1342618a30..58d7a534f877 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * with various broken implementations of this HW. | 6 | * with various broken implementations of this HW. |
| 7 | * | 7 | * |
| 8 | * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. | 8 | * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. |
| 9 | * Copyright 2010-2011 Freescale Semiconductor, Inc. | ||
| 9 | * | 10 | * |
| 10 | * This file is subject to the terms and conditions of the GNU General Public | 11 | * This file is subject to the terms and conditions of the GNU General Public |
| 11 | * License. See the file COPYING in the main directory of this archive | 12 | * License. See the file COPYING in the main directory of this archive |
| @@ -27,6 +28,8 @@ | |||
| 27 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
| 28 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
| 29 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 31 | #include <linux/syscore_ops.h> | ||
| 32 | #include <linux/ratelimit.h> | ||
| 30 | 33 | ||
| 31 | #include <asm/ptrace.h> | 34 | #include <asm/ptrace.h> |
| 32 | #include <asm/signal.h> | 35 | #include <asm/signal.h> |
| @@ -147,6 +150,16 @@ static u32 mpic_infos[][MPIC_IDX_END] = { | |||
| 147 | 150 | ||
| 148 | #endif /* CONFIG_MPIC_WEIRD */ | 151 | #endif /* CONFIG_MPIC_WEIRD */ |
| 149 | 152 | ||
| 153 | static inline unsigned int mpic_processor_id(struct mpic *mpic) | ||
| 154 | { | ||
| 155 | unsigned int cpu = 0; | ||
| 156 | |||
| 157 | if (mpic->flags & MPIC_PRIMARY) | ||
| 158 | cpu = hard_smp_processor_id(); | ||
| 159 | |||
| 160 | return cpu; | ||
| 161 | } | ||
| 162 | |||
| 150 | /* | 163 | /* |
| 151 | * Register accessor functions | 164 | * Register accessor functions |
| 152 | */ | 165 | */ |
| @@ -208,21 +221,38 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu | |||
| 208 | _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); | 221 | _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); |
| 209 | } | 222 | } |
| 210 | 223 | ||
| 224 | static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm) | ||
| 225 | { | ||
| 226 | unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + | ||
| 227 | ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); | ||
| 228 | |||
| 229 | if (tm >= 4) | ||
| 230 | offset += 0x1000 / 4; | ||
| 231 | |||
| 232 | return _mpic_read(mpic->reg_type, &mpic->tmregs, offset); | ||
| 233 | } | ||
| 234 | |||
| 235 | static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value) | ||
| 236 | { | ||
| 237 | unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + | ||
| 238 | ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); | ||
| 239 | |||
| 240 | if (tm >= 4) | ||
| 241 | offset += 0x1000 / 4; | ||
| 242 | |||
| 243 | _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value); | ||
| 244 | } | ||
| 245 | |||
| 211 | static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) | 246 | static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) |
| 212 | { | 247 | { |
| 213 | unsigned int cpu = 0; | 248 | unsigned int cpu = mpic_processor_id(mpic); |
| 214 | 249 | ||
| 215 | if (mpic->flags & MPIC_PRIMARY) | ||
| 216 | cpu = hard_smp_processor_id(); | ||
| 217 | return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg); | 250 | return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg); |
| 218 | } | 251 | } |
| 219 | 252 | ||
| 220 | static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) | 253 | static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) |
| 221 | { | 254 | { |
| 222 | unsigned int cpu = 0; | 255 | unsigned int cpu = mpic_processor_id(mpic); |
| 223 | |||
| 224 | if (mpic->flags & MPIC_PRIMARY) | ||
| 225 | cpu = hard_smp_processor_id(); | ||
| 226 | 256 | ||
| 227 | _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value); | 257 | _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value); |
| 228 | } | 258 | } |
| @@ -263,6 +293,8 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, | |||
| 263 | #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v)) | 293 | #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v)) |
| 264 | #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) | 294 | #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) |
| 265 | #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) | 295 | #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) |
| 296 | #define mpic_tm_read(i) _mpic_tm_read(mpic,(i)) | ||
| 297 | #define mpic_tm_write(i,v) _mpic_tm_write(mpic,(i),(v)) | ||
| 266 | #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) | 298 | #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) |
| 267 | #define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) | 299 | #define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) |
| 268 | #define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) | 300 | #define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) |
| @@ -356,7 +388,7 @@ static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source) | |||
| 356 | } | 388 | } |
| 357 | 389 | ||
| 358 | static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, | 390 | static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, |
| 359 | unsigned int irqflags) | 391 | bool level) |
| 360 | { | 392 | { |
| 361 | struct mpic_irq_fixup *fixup = &mpic->fixups[source]; | 393 | struct mpic_irq_fixup *fixup = &mpic->fixups[source]; |
| 362 | unsigned long flags; | 394 | unsigned long flags; |
| @@ -365,14 +397,14 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, | |||
| 365 | if (fixup->base == NULL) | 397 | if (fixup->base == NULL) |
| 366 | return; | 398 | return; |
| 367 | 399 | ||
| 368 | DBG("startup_ht_interrupt(0x%x, 0x%x) index: %d\n", | 400 | DBG("startup_ht_interrupt(0x%x) index: %d\n", |
| 369 | source, irqflags, fixup->index); | 401 | source, fixup->index); |
| 370 | raw_spin_lock_irqsave(&mpic->fixup_lock, flags); | 402 | raw_spin_lock_irqsave(&mpic->fixup_lock, flags); |
| 371 | /* Enable and configure */ | 403 | /* Enable and configure */ |
| 372 | writeb(0x10 + 2 * fixup->index, fixup->base + 2); | 404 | writeb(0x10 + 2 * fixup->index, fixup->base + 2); |
| 373 | tmp = readl(fixup->base + 4); | 405 | tmp = readl(fixup->base + 4); |
| 374 | tmp &= ~(0x23U); | 406 | tmp &= ~(0x23U); |
| 375 | if (irqflags & IRQ_LEVEL) | 407 | if (level) |
| 376 | tmp |= 0x22; | 408 | tmp |= 0x22; |
| 377 | writel(tmp, fixup->base + 4); | 409 | writel(tmp, fixup->base + 4); |
| 378 | raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags); | 410 | raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags); |
| @@ -384,8 +416,7 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, | |||
| 384 | #endif | 416 | #endif |
| 385 | } | 417 | } |
| 386 | 418 | ||
| 387 | static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, | 419 | static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source) |
| 388 | unsigned int irqflags) | ||
| 389 | { | 420 | { |
| 390 | struct mpic_irq_fixup *fixup = &mpic->fixups[source]; | 421 | struct mpic_irq_fixup *fixup = &mpic->fixups[source]; |
| 391 | unsigned long flags; | 422 | unsigned long flags; |
| @@ -394,7 +425,7 @@ static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, | |||
| 394 | if (fixup->base == NULL) | 425 | if (fixup->base == NULL) |
| 395 | return; | 426 | return; |
| 396 | 427 | ||
| 397 | DBG("shutdown_ht_interrupt(0x%x, 0x%x)\n", source, irqflags); | 428 | DBG("shutdown_ht_interrupt(0x%x)\n", source); |
| 398 | 429 | ||
| 399 | /* Disable */ | 430 | /* Disable */ |
| 400 | raw_spin_lock_irqsave(&mpic->fixup_lock, flags); | 431 | raw_spin_lock_irqsave(&mpic->fixup_lock, flags); |
| @@ -603,25 +634,30 @@ static int irq_choose_cpu(const struct cpumask *mask) | |||
| 603 | } | 634 | } |
| 604 | #endif | 635 | #endif |
| 605 | 636 | ||
| 606 | #define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) | ||
| 607 | |||
| 608 | /* Find an mpic associated with a given linux interrupt */ | 637 | /* Find an mpic associated with a given linux interrupt */ |
| 609 | static struct mpic *mpic_find(unsigned int irq) | 638 | static struct mpic *mpic_find(unsigned int irq) |
| 610 | { | 639 | { |
| 611 | if (irq < NUM_ISA_INTERRUPTS) | 640 | if (irq < NUM_ISA_INTERRUPTS) |
| 612 | return NULL; | 641 | return NULL; |
| 613 | 642 | ||
| 614 | return irq_to_desc(irq)->chip_data; | 643 | return irq_get_chip_data(irq); |
| 615 | } | 644 | } |
| 616 | 645 | ||
| 617 | /* Determine if the linux irq is an IPI */ | 646 | /* Determine if the linux irq is an IPI */ |
| 618 | static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq) | 647 | static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq) |
| 619 | { | 648 | { |
| 620 | unsigned int src = mpic_irq_to_hw(irq); | 649 | unsigned int src = virq_to_hw(irq); |
| 621 | 650 | ||
| 622 | return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); | 651 | return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); |
| 623 | } | 652 | } |
| 624 | 653 | ||
| 654 | /* Determine if the linux irq is a timer */ | ||
| 655 | static unsigned int mpic_is_tm(struct mpic *mpic, unsigned int irq) | ||
| 656 | { | ||
| 657 | unsigned int src = virq_to_hw(irq); | ||
| 658 | |||
| 659 | return (src >= mpic->timer_vecs[0] && src <= mpic->timer_vecs[7]); | ||
| 660 | } | ||
| 625 | 661 | ||
| 626 | /* Convert a cpu mask from logical to physical cpu numbers. */ | 662 | /* Convert a cpu mask from logical to physical cpu numbers. */ |
| 627 | static inline u32 mpic_physmask(u32 cpumask) | 663 | static inline u32 mpic_physmask(u32 cpumask) |
| @@ -629,23 +665,29 @@ static inline u32 mpic_physmask(u32 cpumask) | |||
| 629 | int i; | 665 | int i; |
| 630 | u32 mask = 0; | 666 | u32 mask = 0; |
| 631 | 667 | ||
| 632 | for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1) | 668 | for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1) |
| 633 | mask |= (cpumask & 1) << get_hard_smp_processor_id(i); | 669 | mask |= (cpumask & 1) << get_hard_smp_processor_id(i); |
| 634 | return mask; | 670 | return mask; |
| 635 | } | 671 | } |
| 636 | 672 | ||
| 637 | #ifdef CONFIG_SMP | 673 | #ifdef CONFIG_SMP |
| 638 | /* Get the mpic structure from the IPI number */ | 674 | /* Get the mpic structure from the IPI number */ |
| 639 | static inline struct mpic * mpic_from_ipi(unsigned int ipi) | 675 | static inline struct mpic * mpic_from_ipi(struct irq_data *d) |
| 640 | { | 676 | { |
| 641 | return irq_to_desc(ipi)->chip_data; | 677 | return irq_data_get_irq_chip_data(d); |
| 642 | } | 678 | } |
| 643 | #endif | 679 | #endif |
| 644 | 680 | ||
| 645 | /* Get the mpic structure from the irq number */ | 681 | /* Get the mpic structure from the irq number */ |
| 646 | static inline struct mpic * mpic_from_irq(unsigned int irq) | 682 | static inline struct mpic * mpic_from_irq(unsigned int irq) |
| 647 | { | 683 | { |
| 648 | return irq_to_desc(irq)->chip_data; | 684 | return irq_get_chip_data(irq); |
| 685 | } | ||
| 686 | |||
| 687 | /* Get the mpic structure from the irq data */ | ||
| 688 | static inline struct mpic * mpic_from_irq_data(struct irq_data *d) | ||
| 689 | { | ||
| 690 | return irq_data_get_irq_chip_data(d); | ||
| 649 | } | 691 | } |
| 650 | 692 | ||
| 651 | /* Send an EOI */ | 693 | /* Send an EOI */ |
| @@ -660,13 +702,13 @@ static inline void mpic_eoi(struct mpic *mpic) | |||
| 660 | */ | 702 | */ |
| 661 | 703 | ||
| 662 | 704 | ||
| 663 | void mpic_unmask_irq(unsigned int irq) | 705 | void mpic_unmask_irq(struct irq_data *d) |
| 664 | { | 706 | { |
| 665 | unsigned int loops = 100000; | 707 | unsigned int loops = 100000; |
| 666 | struct mpic *mpic = mpic_from_irq(irq); | 708 | struct mpic *mpic = mpic_from_irq_data(d); |
| 667 | unsigned int src = mpic_irq_to_hw(irq); | 709 | unsigned int src = irqd_to_hwirq(d); |
| 668 | 710 | ||
| 669 | DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); | 711 | DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, d->irq, src); |
| 670 | 712 | ||
| 671 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), | 713 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), |
| 672 | mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & | 714 | mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & |
| @@ -674,19 +716,20 @@ void mpic_unmask_irq(unsigned int irq) | |||
| 674 | /* make sure mask gets to controller before we return to user */ | 716 | /* make sure mask gets to controller before we return to user */ |
| 675 | do { | 717 | do { |
| 676 | if (!loops--) { | 718 | if (!loops--) { |
| 677 | printk(KERN_ERR "mpic_enable_irq timeout\n"); | 719 | printk(KERN_ERR "%s: timeout on hwirq %u\n", |
| 720 | __func__, src); | ||
| 678 | break; | 721 | break; |
| 679 | } | 722 | } |
| 680 | } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK); | 723 | } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK); |
| 681 | } | 724 | } |
| 682 | 725 | ||
| 683 | void mpic_mask_irq(unsigned int irq) | 726 | void mpic_mask_irq(struct irq_data *d) |
| 684 | { | 727 | { |
| 685 | unsigned int loops = 100000; | 728 | unsigned int loops = 100000; |
| 686 | struct mpic *mpic = mpic_from_irq(irq); | 729 | struct mpic *mpic = mpic_from_irq_data(d); |
| 687 | unsigned int src = mpic_irq_to_hw(irq); | 730 | unsigned int src = irqd_to_hwirq(d); |
| 688 | 731 | ||
| 689 | DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); | 732 | DBG("%s: disable_irq: %d (src %d)\n", mpic->name, d->irq, src); |
| 690 | 733 | ||
| 691 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), | 734 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), |
| 692 | mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) | | 735 | mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) | |
| @@ -695,18 +738,19 @@ void mpic_mask_irq(unsigned int irq) | |||
| 695 | /* make sure mask gets to controller before we return to user */ | 738 | /* make sure mask gets to controller before we return to user */ |
| 696 | do { | 739 | do { |
| 697 | if (!loops--) { | 740 | if (!loops--) { |
| 698 | printk(KERN_ERR "mpic_enable_irq timeout\n"); | 741 | printk(KERN_ERR "%s: timeout on hwirq %u\n", |
| 742 | __func__, src); | ||
| 699 | break; | 743 | break; |
| 700 | } | 744 | } |
| 701 | } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK)); | 745 | } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK)); |
| 702 | } | 746 | } |
| 703 | 747 | ||
| 704 | void mpic_end_irq(unsigned int irq) | 748 | void mpic_end_irq(struct irq_data *d) |
| 705 | { | 749 | { |
| 706 | struct mpic *mpic = mpic_from_irq(irq); | 750 | struct mpic *mpic = mpic_from_irq_data(d); |
| 707 | 751 | ||
| 708 | #ifdef DEBUG_IRQ | 752 | #ifdef DEBUG_IRQ |
| 709 | DBG("%s: end_irq: %d\n", mpic->name, irq); | 753 | DBG("%s: end_irq: %d\n", mpic->name, d->irq); |
| 710 | #endif | 754 | #endif |
| 711 | /* We always EOI on end_irq() even for edge interrupts since that | 755 | /* We always EOI on end_irq() even for edge interrupts since that |
| 712 | * should only lower the priority, the MPIC should have properly | 756 | * should only lower the priority, the MPIC should have properly |
| @@ -718,51 +762,51 @@ void mpic_end_irq(unsigned int irq) | |||
| 718 | 762 | ||
| 719 | #ifdef CONFIG_MPIC_U3_HT_IRQS | 763 | #ifdef CONFIG_MPIC_U3_HT_IRQS |
| 720 | 764 | ||
| 721 | static void mpic_unmask_ht_irq(unsigned int irq) | 765 | static void mpic_unmask_ht_irq(struct irq_data *d) |
| 722 | { | 766 | { |
| 723 | struct mpic *mpic = mpic_from_irq(irq); | 767 | struct mpic *mpic = mpic_from_irq_data(d); |
| 724 | unsigned int src = mpic_irq_to_hw(irq); | 768 | unsigned int src = irqd_to_hwirq(d); |
| 725 | 769 | ||
| 726 | mpic_unmask_irq(irq); | 770 | mpic_unmask_irq(d); |
| 727 | 771 | ||
| 728 | if (irq_to_desc(irq)->status & IRQ_LEVEL) | 772 | if (irqd_is_level_type(d)) |
| 729 | mpic_ht_end_irq(mpic, src); | 773 | mpic_ht_end_irq(mpic, src); |
| 730 | } | 774 | } |
| 731 | 775 | ||
| 732 | static unsigned int mpic_startup_ht_irq(unsigned int irq) | 776 | static unsigned int mpic_startup_ht_irq(struct irq_data *d) |
| 733 | { | 777 | { |
| 734 | struct mpic *mpic = mpic_from_irq(irq); | 778 | struct mpic *mpic = mpic_from_irq_data(d); |
| 735 | unsigned int src = mpic_irq_to_hw(irq); | 779 | unsigned int src = irqd_to_hwirq(d); |
| 736 | 780 | ||
| 737 | mpic_unmask_irq(irq); | 781 | mpic_unmask_irq(d); |
| 738 | mpic_startup_ht_interrupt(mpic, src, irq_to_desc(irq)->status); | 782 | mpic_startup_ht_interrupt(mpic, src, irqd_is_level_type(d)); |
| 739 | 783 | ||
| 740 | return 0; | 784 | return 0; |
| 741 | } | 785 | } |
| 742 | 786 | ||
| 743 | static void mpic_shutdown_ht_irq(unsigned int irq) | 787 | static void mpic_shutdown_ht_irq(struct irq_data *d) |
| 744 | { | 788 | { |
| 745 | struct mpic *mpic = mpic_from_irq(irq); | 789 | struct mpic *mpic = mpic_from_irq_data(d); |
| 746 | unsigned int src = mpic_irq_to_hw(irq); | 790 | unsigned int src = irqd_to_hwirq(d); |
| 747 | 791 | ||
| 748 | mpic_shutdown_ht_interrupt(mpic, src, irq_to_desc(irq)->status); | 792 | mpic_shutdown_ht_interrupt(mpic, src); |
| 749 | mpic_mask_irq(irq); | 793 | mpic_mask_irq(d); |
| 750 | } | 794 | } |
| 751 | 795 | ||
| 752 | static void mpic_end_ht_irq(unsigned int irq) | 796 | static void mpic_end_ht_irq(struct irq_data *d) |
| 753 | { | 797 | { |
| 754 | struct mpic *mpic = mpic_from_irq(irq); | 798 | struct mpic *mpic = mpic_from_irq_data(d); |
| 755 | unsigned int src = mpic_irq_to_hw(irq); | 799 | unsigned int src = irqd_to_hwirq(d); |
| 756 | 800 | ||
| 757 | #ifdef DEBUG_IRQ | 801 | #ifdef DEBUG_IRQ |
| 758 | DBG("%s: end_irq: %d\n", mpic->name, irq); | 802 | DBG("%s: end_irq: %d\n", mpic->name, d->irq); |
| 759 | #endif | 803 | #endif |
| 760 | /* We always EOI on end_irq() even for edge interrupts since that | 804 | /* We always EOI on end_irq() even for edge interrupts since that |
| 761 | * should only lower the priority, the MPIC should have properly | 805 | * should only lower the priority, the MPIC should have properly |
| 762 | * latched another edge interrupt coming in anyway | 806 | * latched another edge interrupt coming in anyway |
| 763 | */ | 807 | */ |
| 764 | 808 | ||
| 765 | if (irq_to_desc(irq)->status & IRQ_LEVEL) | 809 | if (irqd_is_level_type(d)) |
| 766 | mpic_ht_end_irq(mpic, src); | 810 | mpic_ht_end_irq(mpic, src); |
| 767 | mpic_eoi(mpic); | 811 | mpic_eoi(mpic); |
| 768 | } | 812 | } |
| @@ -770,23 +814,23 @@ static void mpic_end_ht_irq(unsigned int irq) | |||
| 770 | 814 | ||
| 771 | #ifdef CONFIG_SMP | 815 | #ifdef CONFIG_SMP |
| 772 | 816 | ||
| 773 | static void mpic_unmask_ipi(unsigned int irq) | 817 | static void mpic_unmask_ipi(struct irq_data *d) |
| 774 | { | 818 | { |
| 775 | struct mpic *mpic = mpic_from_ipi(irq); | 819 | struct mpic *mpic = mpic_from_ipi(d); |
| 776 | unsigned int src = mpic_irq_to_hw(irq) - mpic->ipi_vecs[0]; | 820 | unsigned int src = virq_to_hw(d->irq) - mpic->ipi_vecs[0]; |
| 777 | 821 | ||
| 778 | DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); | 822 | DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, d->irq, src); |
| 779 | mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); | 823 | mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); |
| 780 | } | 824 | } |
| 781 | 825 | ||
| 782 | static void mpic_mask_ipi(unsigned int irq) | 826 | static void mpic_mask_ipi(struct irq_data *d) |
| 783 | { | 827 | { |
| 784 | /* NEVER disable an IPI... that's just plain wrong! */ | 828 | /* NEVER disable an IPI... that's just plain wrong! */ |
| 785 | } | 829 | } |
| 786 | 830 | ||
| 787 | static void mpic_end_ipi(unsigned int irq) | 831 | static void mpic_end_ipi(struct irq_data *d) |
| 788 | { | 832 | { |
| 789 | struct mpic *mpic = mpic_from_ipi(irq); | 833 | struct mpic *mpic = mpic_from_ipi(d); |
| 790 | 834 | ||
| 791 | /* | 835 | /* |
| 792 | * IPIs are marked IRQ_PER_CPU. This has the side effect of | 836 | * IPIs are marked IRQ_PER_CPU. This has the side effect of |
| @@ -800,26 +844,42 @@ static void mpic_end_ipi(unsigned int irq) | |||
| 800 | 844 | ||
| 801 | #endif /* CONFIG_SMP */ | 845 | #endif /* CONFIG_SMP */ |
| 802 | 846 | ||
| 803 | int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask) | 847 | static void mpic_unmask_tm(struct irq_data *d) |
| 804 | { | 848 | { |
| 805 | struct mpic *mpic = mpic_from_irq(irq); | 849 | struct mpic *mpic = mpic_from_irq_data(d); |
| 806 | unsigned int src = mpic_irq_to_hw(irq); | 850 | unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; |
| 851 | |||
| 852 | DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, irq, src); | ||
| 853 | mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK); | ||
| 854 | mpic_tm_read(src); | ||
| 855 | } | ||
| 856 | |||
| 857 | static void mpic_mask_tm(struct irq_data *d) | ||
| 858 | { | ||
| 859 | struct mpic *mpic = mpic_from_irq_data(d); | ||
| 860 | unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; | ||
| 861 | |||
| 862 | mpic_tm_write(src, mpic_tm_read(src) | MPIC_VECPRI_MASK); | ||
| 863 | mpic_tm_read(src); | ||
| 864 | } | ||
| 865 | |||
| 866 | int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, | ||
| 867 | bool force) | ||
| 868 | { | ||
| 869 | struct mpic *mpic = mpic_from_irq_data(d); | ||
| 870 | unsigned int src = irqd_to_hwirq(d); | ||
| 807 | 871 | ||
| 808 | if (mpic->flags & MPIC_SINGLE_DEST_CPU) { | 872 | if (mpic->flags & MPIC_SINGLE_DEST_CPU) { |
| 809 | int cpuid = irq_choose_cpu(cpumask); | 873 | int cpuid = irq_choose_cpu(cpumask); |
| 810 | 874 | ||
| 811 | mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); | 875 | mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); |
| 812 | } else { | 876 | } else { |
| 813 | cpumask_var_t tmp; | 877 | u32 mask = cpumask_bits(cpumask)[0]; |
| 814 | |||
| 815 | alloc_cpumask_var(&tmp, GFP_KERNEL); | ||
| 816 | 878 | ||
| 817 | cpumask_and(tmp, cpumask, cpu_online_mask); | 879 | mask &= cpumask_bits(cpu_online_mask)[0]; |
| 818 | 880 | ||
| 819 | mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), | 881 | mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), |
| 820 | mpic_physmask(cpumask_bits(tmp)[0])); | 882 | mpic_physmask(mask)); |
| 821 | |||
| 822 | free_cpumask_var(tmp); | ||
| 823 | } | 883 | } |
| 824 | 884 | ||
| 825 | return 0; | 885 | return 0; |
| @@ -846,15 +906,14 @@ static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) | |||
| 846 | } | 906 | } |
| 847 | } | 907 | } |
| 848 | 908 | ||
| 849 | int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) | 909 | int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) |
| 850 | { | 910 | { |
| 851 | struct mpic *mpic = mpic_from_irq(virq); | 911 | struct mpic *mpic = mpic_from_irq_data(d); |
| 852 | unsigned int src = mpic_irq_to_hw(virq); | 912 | unsigned int src = irqd_to_hwirq(d); |
| 853 | struct irq_desc *desc = irq_to_desc(virq); | ||
| 854 | unsigned int vecpri, vold, vnew; | 913 | unsigned int vecpri, vold, vnew; |
| 855 | 914 | ||
| 856 | DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", | 915 | DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", |
| 857 | mpic, virq, src, flow_type); | 916 | mpic, d->irq, src, flow_type); |
| 858 | 917 | ||
| 859 | if (src >= mpic->irq_count) | 918 | if (src >= mpic->irq_count) |
| 860 | return -EINVAL; | 919 | return -EINVAL; |
| @@ -865,10 +924,7 @@ int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
| 865 | if (flow_type == IRQ_TYPE_NONE) | 924 | if (flow_type == IRQ_TYPE_NONE) |
| 866 | flow_type = IRQ_TYPE_LEVEL_LOW; | 925 | flow_type = IRQ_TYPE_LEVEL_LOW; |
| 867 | 926 | ||
| 868 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); | 927 | irqd_set_trigger_type(d, flow_type); |
| 869 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; | ||
| 870 | if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) | ||
| 871 | desc->status |= IRQ_LEVEL; | ||
| 872 | 928 | ||
| 873 | if (mpic_is_ht_interrupt(mpic, src)) | 929 | if (mpic_is_ht_interrupt(mpic, src)) |
| 874 | vecpri = MPIC_VECPRI_POLARITY_POSITIVE | | 930 | vecpri = MPIC_VECPRI_POLARITY_POSITIVE | |
| @@ -883,13 +939,13 @@ int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
| 883 | if (vold != vnew) | 939 | if (vold != vnew) |
| 884 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); | 940 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); |
| 885 | 941 | ||
| 886 | return 0; | 942 | return IRQ_SET_MASK_OK_NOCOPY;; |
| 887 | } | 943 | } |
| 888 | 944 | ||
| 889 | void mpic_set_vector(unsigned int virq, unsigned int vector) | 945 | void mpic_set_vector(unsigned int virq, unsigned int vector) |
| 890 | { | 946 | { |
| 891 | struct mpic *mpic = mpic_from_irq(virq); | 947 | struct mpic *mpic = mpic_from_irq(virq); |
| 892 | unsigned int src = mpic_irq_to_hw(virq); | 948 | unsigned int src = virq_to_hw(virq); |
| 893 | unsigned int vecpri; | 949 | unsigned int vecpri; |
| 894 | 950 | ||
| 895 | DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", | 951 | DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", |
| @@ -904,29 +960,49 @@ void mpic_set_vector(unsigned int virq, unsigned int vector) | |||
| 904 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); | 960 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); |
| 905 | } | 961 | } |
| 906 | 962 | ||
| 963 | void mpic_set_destination(unsigned int virq, unsigned int cpuid) | ||
| 964 | { | ||
| 965 | struct mpic *mpic = mpic_from_irq(virq); | ||
| 966 | unsigned int src = virq_to_hw(virq); | ||
| 967 | |||
| 968 | DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", | ||
| 969 | mpic, virq, src, cpuid); | ||
| 970 | |||
| 971 | if (src >= mpic->irq_count) | ||
| 972 | return; | ||
| 973 | |||
| 974 | mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); | ||
| 975 | } | ||
| 976 | |||
| 907 | static struct irq_chip mpic_irq_chip = { | 977 | static struct irq_chip mpic_irq_chip = { |
| 908 | .mask = mpic_mask_irq, | 978 | .irq_mask = mpic_mask_irq, |
| 909 | .unmask = mpic_unmask_irq, | 979 | .irq_unmask = mpic_unmask_irq, |
| 910 | .eoi = mpic_end_irq, | 980 | .irq_eoi = mpic_end_irq, |
| 911 | .set_type = mpic_set_irq_type, | 981 | .irq_set_type = mpic_set_irq_type, |
| 912 | }; | 982 | }; |
| 913 | 983 | ||
| 914 | #ifdef CONFIG_SMP | 984 | #ifdef CONFIG_SMP |
| 915 | static struct irq_chip mpic_ipi_chip = { | 985 | static struct irq_chip mpic_ipi_chip = { |
| 916 | .mask = mpic_mask_ipi, | 986 | .irq_mask = mpic_mask_ipi, |
| 917 | .unmask = mpic_unmask_ipi, | 987 | .irq_unmask = mpic_unmask_ipi, |
| 918 | .eoi = mpic_end_ipi, | 988 | .irq_eoi = mpic_end_ipi, |
| 919 | }; | 989 | }; |
| 920 | #endif /* CONFIG_SMP */ | 990 | #endif /* CONFIG_SMP */ |
| 921 | 991 | ||
| 992 | static struct irq_chip mpic_tm_chip = { | ||
| 993 | .irq_mask = mpic_mask_tm, | ||
| 994 | .irq_unmask = mpic_unmask_tm, | ||
| 995 | .irq_eoi = mpic_end_irq, | ||
| 996 | }; | ||
| 997 | |||
| 922 | #ifdef CONFIG_MPIC_U3_HT_IRQS | 998 | #ifdef CONFIG_MPIC_U3_HT_IRQS |
| 923 | static struct irq_chip mpic_irq_ht_chip = { | 999 | static struct irq_chip mpic_irq_ht_chip = { |
| 924 | .startup = mpic_startup_ht_irq, | 1000 | .irq_startup = mpic_startup_ht_irq, |
| 925 | .shutdown = mpic_shutdown_ht_irq, | 1001 | .irq_shutdown = mpic_shutdown_ht_irq, |
| 926 | .mask = mpic_mask_irq, | 1002 | .irq_mask = mpic_mask_irq, |
| 927 | .unmask = mpic_unmask_ht_irq, | 1003 | .irq_unmask = mpic_unmask_ht_irq, |
| 928 | .eoi = mpic_end_ht_irq, | 1004 | .irq_eoi = mpic_end_ht_irq, |
| 929 | .set_type = mpic_set_irq_type, | 1005 | .irq_set_type = mpic_set_irq_type, |
| 930 | }; | 1006 | }; |
| 931 | #endif /* CONFIG_MPIC_U3_HT_IRQS */ | 1007 | #endif /* CONFIG_MPIC_U3_HT_IRQS */ |
| 932 | 1008 | ||
| @@ -955,13 +1031,23 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, | |||
| 955 | WARN_ON(!(mpic->flags & MPIC_PRIMARY)); | 1031 | WARN_ON(!(mpic->flags & MPIC_PRIMARY)); |
| 956 | 1032 | ||
| 957 | DBG("mpic: mapping as IPI\n"); | 1033 | DBG("mpic: mapping as IPI\n"); |
| 958 | set_irq_chip_data(virq, mpic); | 1034 | irq_set_chip_data(virq, mpic); |
| 959 | set_irq_chip_and_handler(virq, &mpic->hc_ipi, | 1035 | irq_set_chip_and_handler(virq, &mpic->hc_ipi, |
| 960 | handle_percpu_irq); | 1036 | handle_percpu_irq); |
| 961 | return 0; | 1037 | return 0; |
| 962 | } | 1038 | } |
| 963 | #endif /* CONFIG_SMP */ | 1039 | #endif /* CONFIG_SMP */ |
| 964 | 1040 | ||
| 1041 | if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) { | ||
| 1042 | WARN_ON(!(mpic->flags & MPIC_PRIMARY)); | ||
| 1043 | |||
| 1044 | DBG("mpic: mapping as timer\n"); | ||
| 1045 | irq_set_chip_data(virq, mpic); | ||
| 1046 | irq_set_chip_and_handler(virq, &mpic->hc_tm, | ||
| 1047 | handle_fasteoi_irq); | ||
| 1048 | return 0; | ||
| 1049 | } | ||
| 1050 | |||
| 965 | if (hw >= mpic->irq_count) | 1051 | if (hw >= mpic->irq_count) |
| 966 | return -EINVAL; | 1052 | return -EINVAL; |
| 967 | 1053 | ||
| @@ -978,11 +1064,21 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, | |||
| 978 | 1064 | ||
| 979 | DBG("mpic: mapping to irq chip @%p\n", chip); | 1065 | DBG("mpic: mapping to irq chip @%p\n", chip); |
| 980 | 1066 | ||
| 981 | set_irq_chip_data(virq, mpic); | 1067 | irq_set_chip_data(virq, mpic); |
| 982 | set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); | 1068 | irq_set_chip_and_handler(virq, chip, handle_fasteoi_irq); |
| 983 | 1069 | ||
| 984 | /* Set default irq type */ | 1070 | /* Set default irq type */ |
| 985 | set_irq_type(virq, IRQ_TYPE_NONE); | 1071 | irq_set_irq_type(virq, IRQ_TYPE_NONE); |
| 1072 | |||
| 1073 | /* If the MPIC was reset, then all vectors have already been | ||
| 1074 | * initialized. Otherwise, a per source lazy initialization | ||
| 1075 | * is done here. | ||
| 1076 | */ | ||
| 1077 | if (!mpic_is_ipi(mpic, hw) && (mpic->flags & MPIC_NO_RESET)) { | ||
| 1078 | mpic_set_vector(virq, hw); | ||
| 1079 | mpic_set_destination(virq, mpic_processor_id(mpic)); | ||
| 1080 | mpic_irq_set_priority(virq, 8); | ||
| 1081 | } | ||
| 986 | 1082 | ||
| 987 | return 0; | 1083 | return 0; |
| 988 | } | 1084 | } |
| @@ -992,6 +1088,7 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, | |||
| 992 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 1088 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
| 993 | 1089 | ||
| 994 | { | 1090 | { |
| 1091 | struct mpic *mpic = h->host_data; | ||
| 995 | static unsigned char map_mpic_senses[4] = { | 1092 | static unsigned char map_mpic_senses[4] = { |
| 996 | IRQ_TYPE_EDGE_RISING, | 1093 | IRQ_TYPE_EDGE_RISING, |
| 997 | IRQ_TYPE_LEVEL_LOW, | 1094 | IRQ_TYPE_LEVEL_LOW, |
| @@ -1000,7 +1097,38 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, | |||
| 1000 | }; | 1097 | }; |
| 1001 | 1098 | ||
| 1002 | *out_hwirq = intspec[0]; | 1099 | *out_hwirq = intspec[0]; |
| 1003 | if (intsize > 1) { | 1100 | if (intsize >= 4 && (mpic->flags & MPIC_FSL)) { |
| 1101 | /* | ||
| 1102 | * Freescale MPIC with extended intspec: | ||
| 1103 | * First two cells are as usual. Third specifies | ||
| 1104 | * an "interrupt type". Fourth is type-specific data. | ||
| 1105 | * | ||
| 1106 | * See Documentation/devicetree/bindings/powerpc/fsl/mpic.txt | ||
| 1107 | */ | ||
| 1108 | switch (intspec[2]) { | ||
| 1109 | case 0: | ||
| 1110 | case 1: /* no EISR/EIMR support for now, treat as shared IRQ */ | ||
| 1111 | break; | ||
| 1112 | case 2: | ||
| 1113 | if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs)) | ||
| 1114 | return -EINVAL; | ||
| 1115 | |||
| 1116 | *out_hwirq = mpic->ipi_vecs[intspec[0]]; | ||
| 1117 | break; | ||
| 1118 | case 3: | ||
| 1119 | if (intspec[0] >= ARRAY_SIZE(mpic->timer_vecs)) | ||
| 1120 | return -EINVAL; | ||
| 1121 | |||
| 1122 | *out_hwirq = mpic->timer_vecs[intspec[0]]; | ||
| 1123 | break; | ||
| 1124 | default: | ||
| 1125 | pr_debug("%s: unknown irq type %u\n", | ||
| 1126 | __func__, intspec[2]); | ||
| 1127 | return -EINVAL; | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | *out_flags = map_mpic_senses[intspec[1] & 3]; | ||
| 1131 | } else if (intsize > 1) { | ||
| 1004 | u32 mask = 0x3; | 1132 | u32 mask = 0x3; |
| 1005 | 1133 | ||
| 1006 | /* Apple invented a new race of encoding on machines with | 1134 | /* Apple invented a new race of encoding on machines with |
| @@ -1031,6 +1159,11 @@ static struct irq_host_ops mpic_host_ops = { | |||
| 1031 | .xlate = mpic_host_xlate, | 1159 | .xlate = mpic_host_xlate, |
| 1032 | }; | 1160 | }; |
| 1033 | 1161 | ||
| 1162 | static int mpic_reset_prohibited(struct device_node *node) | ||
| 1163 | { | ||
| 1164 | return node && of_get_property(node, "pic-no-reset", NULL); | ||
| 1165 | } | ||
| 1166 | |||
| 1034 | /* | 1167 | /* |
| 1035 | * Exported functions | 1168 | * Exported functions |
| 1036 | */ | 1169 | */ |
| @@ -1058,12 +1191,12 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
| 1058 | mpic->hc_irq = mpic_irq_chip; | 1191 | mpic->hc_irq = mpic_irq_chip; |
| 1059 | mpic->hc_irq.name = name; | 1192 | mpic->hc_irq.name = name; |
| 1060 | if (flags & MPIC_PRIMARY) | 1193 | if (flags & MPIC_PRIMARY) |
| 1061 | mpic->hc_irq.set_affinity = mpic_set_affinity; | 1194 | mpic->hc_irq.irq_set_affinity = mpic_set_affinity; |
| 1062 | #ifdef CONFIG_MPIC_U3_HT_IRQS | 1195 | #ifdef CONFIG_MPIC_U3_HT_IRQS |
| 1063 | mpic->hc_ht_irq = mpic_irq_ht_chip; | 1196 | mpic->hc_ht_irq = mpic_irq_ht_chip; |
| 1064 | mpic->hc_ht_irq.name = name; | 1197 | mpic->hc_ht_irq.name = name; |
| 1065 | if (flags & MPIC_PRIMARY) | 1198 | if (flags & MPIC_PRIMARY) |
| 1066 | mpic->hc_ht_irq.set_affinity = mpic_set_affinity; | 1199 | mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity; |
| 1067 | #endif /* CONFIG_MPIC_U3_HT_IRQS */ | 1200 | #endif /* CONFIG_MPIC_U3_HT_IRQS */ |
| 1068 | 1201 | ||
| 1069 | #ifdef CONFIG_SMP | 1202 | #ifdef CONFIG_SMP |
| @@ -1071,6 +1204,9 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
| 1071 | mpic->hc_ipi.name = name; | 1204 | mpic->hc_ipi.name = name; |
| 1072 | #endif /* CONFIG_SMP */ | 1205 | #endif /* CONFIG_SMP */ |
| 1073 | 1206 | ||
| 1207 | mpic->hc_tm = mpic_tm_chip; | ||
| 1208 | mpic->hc_tm.name = name; | ||
| 1209 | |||
| 1074 | mpic->flags = flags; | 1210 | mpic->flags = flags; |
| 1075 | mpic->isu_size = isu_size; | 1211 | mpic->isu_size = isu_size; |
| 1076 | mpic->irq_count = irq_count; | 1212 | mpic->irq_count = irq_count; |
| @@ -1081,10 +1217,14 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
| 1081 | else | 1217 | else |
| 1082 | intvec_top = 255; | 1218 | intvec_top = 255; |
| 1083 | 1219 | ||
| 1084 | mpic->timer_vecs[0] = intvec_top - 8; | 1220 | mpic->timer_vecs[0] = intvec_top - 12; |
| 1085 | mpic->timer_vecs[1] = intvec_top - 7; | 1221 | mpic->timer_vecs[1] = intvec_top - 11; |
| 1086 | mpic->timer_vecs[2] = intvec_top - 6; | 1222 | mpic->timer_vecs[2] = intvec_top - 10; |
| 1087 | mpic->timer_vecs[3] = intvec_top - 5; | 1223 | mpic->timer_vecs[3] = intvec_top - 9; |
| 1224 | mpic->timer_vecs[4] = intvec_top - 8; | ||
| 1225 | mpic->timer_vecs[5] = intvec_top - 7; | ||
| 1226 | mpic->timer_vecs[6] = intvec_top - 6; | ||
| 1227 | mpic->timer_vecs[7] = intvec_top - 5; | ||
| 1088 | mpic->ipi_vecs[0] = intvec_top - 4; | 1228 | mpic->ipi_vecs[0] = intvec_top - 4; |
| 1089 | mpic->ipi_vecs[1] = intvec_top - 3; | 1229 | mpic->ipi_vecs[1] = intvec_top - 3; |
| 1090 | mpic->ipi_vecs[2] = intvec_top - 2; | 1230 | mpic->ipi_vecs[2] = intvec_top - 2; |
| @@ -1094,6 +1234,8 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
| 1094 | /* Check for "big-endian" in device-tree */ | 1234 | /* Check for "big-endian" in device-tree */ |
| 1095 | if (node && of_get_property(node, "big-endian", NULL) != NULL) | 1235 | if (node && of_get_property(node, "big-endian", NULL) != NULL) |
| 1096 | mpic->flags |= MPIC_BIG_ENDIAN; | 1236 | mpic->flags |= MPIC_BIG_ENDIAN; |
| 1237 | if (node && of_device_is_compatible(node, "fsl,mpic")) | ||
| 1238 | mpic->flags |= MPIC_FSL; | ||
| 1097 | 1239 | ||
| 1098 | /* Look for protected sources */ | 1240 | /* Look for protected sources */ |
| 1099 | if (node) { | 1241 | if (node) { |
| @@ -1151,7 +1293,15 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
| 1151 | mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); | 1293 | mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); |
| 1152 | 1294 | ||
| 1153 | /* Reset */ | 1295 | /* Reset */ |
| 1154 | if (flags & MPIC_WANTS_RESET) { | 1296 | |
| 1297 | /* When using a device-node, reset requests are only honored if the MPIC | ||
| 1298 | * is allowed to reset. | ||
| 1299 | */ | ||
| 1300 | if (mpic_reset_prohibited(node)) | ||
| 1301 | mpic->flags |= MPIC_NO_RESET; | ||
| 1302 | |||
| 1303 | if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { | ||
| 1304 | printk(KERN_DEBUG "mpic: Resetting\n"); | ||
| 1155 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), | 1305 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), |
| 1156 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | 1306 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) |
| 1157 | | MPIC_GREG_GCONF_RESET); | 1307 | | MPIC_GREG_GCONF_RESET); |
| @@ -1277,15 +1427,17 @@ void __init mpic_init(struct mpic *mpic) | |||
| 1277 | /* Set current processor priority to max */ | 1427 | /* Set current processor priority to max */ |
| 1278 | mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); | 1428 | mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); |
| 1279 | 1429 | ||
| 1280 | /* Initialize timers: just disable them all */ | 1430 | /* Initialize timers to our reserved vectors and mask them for now */ |
| 1281 | for (i = 0; i < 4; i++) { | 1431 | for (i = 0; i < 4; i++) { |
| 1282 | mpic_write(mpic->tmregs, | 1432 | mpic_write(mpic->tmregs, |
| 1283 | i * MPIC_INFO(TIMER_STRIDE) + | 1433 | i * MPIC_INFO(TIMER_STRIDE) + |
| 1284 | MPIC_INFO(TIMER_DESTINATION), 0); | 1434 | MPIC_INFO(TIMER_DESTINATION), |
| 1435 | 1 << hard_smp_processor_id()); | ||
| 1285 | mpic_write(mpic->tmregs, | 1436 | mpic_write(mpic->tmregs, |
| 1286 | i * MPIC_INFO(TIMER_STRIDE) + | 1437 | i * MPIC_INFO(TIMER_STRIDE) + |
| 1287 | MPIC_INFO(TIMER_VECTOR_PRI), | 1438 | MPIC_INFO(TIMER_VECTOR_PRI), |
| 1288 | MPIC_VECPRI_MASK | | 1439 | MPIC_VECPRI_MASK | |
| 1440 | (9 << MPIC_VECPRI_PRIORITY_SHIFT) | | ||
| 1289 | (mpic->timer_vecs[0] + i)); | 1441 | (mpic->timer_vecs[0] + i)); |
| 1290 | } | 1442 | } |
| 1291 | 1443 | ||
| @@ -1311,22 +1463,21 @@ void __init mpic_init(struct mpic *mpic) | |||
| 1311 | 1463 | ||
| 1312 | mpic_pasemi_msi_init(mpic); | 1464 | mpic_pasemi_msi_init(mpic); |
| 1313 | 1465 | ||
| 1314 | if (mpic->flags & MPIC_PRIMARY) | 1466 | cpu = mpic_processor_id(mpic); |
| 1315 | cpu = hard_smp_processor_id(); | ||
| 1316 | else | ||
| 1317 | cpu = 0; | ||
| 1318 | 1467 | ||
| 1319 | for (i = 0; i < mpic->num_sources; i++) { | 1468 | if (!(mpic->flags & MPIC_NO_RESET)) { |
| 1320 | /* start with vector = source number, and masked */ | 1469 | for (i = 0; i < mpic->num_sources; i++) { |
| 1321 | u32 vecpri = MPIC_VECPRI_MASK | i | | 1470 | /* start with vector = source number, and masked */ |
| 1322 | (8 << MPIC_VECPRI_PRIORITY_SHIFT); | 1471 | u32 vecpri = MPIC_VECPRI_MASK | i | |
| 1472 | (8 << MPIC_VECPRI_PRIORITY_SHIFT); | ||
| 1323 | 1473 | ||
| 1324 | /* check if protected */ | 1474 | /* check if protected */ |
| 1325 | if (mpic->protected && test_bit(i, mpic->protected)) | 1475 | if (mpic->protected && test_bit(i, mpic->protected)) |
| 1326 | continue; | 1476 | continue; |
| 1327 | /* init hw */ | 1477 | /* init hw */ |
| 1328 | mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); | 1478 | mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); |
| 1329 | mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); | 1479 | mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); |
| 1480 | } | ||
| 1330 | } | 1481 | } |
| 1331 | 1482 | ||
| 1332 | /* Init spurious vector */ | 1483 | /* Init spurious vector */ |
| @@ -1382,7 +1533,7 @@ void __init mpic_set_serial_int(struct mpic *mpic, int enable) | |||
| 1382 | void mpic_irq_set_priority(unsigned int irq, unsigned int pri) | 1533 | void mpic_irq_set_priority(unsigned int irq, unsigned int pri) |
| 1383 | { | 1534 | { |
| 1384 | struct mpic *mpic = mpic_find(irq); | 1535 | struct mpic *mpic = mpic_find(irq); |
| 1385 | unsigned int src = mpic_irq_to_hw(irq); | 1536 | unsigned int src = virq_to_hw(irq); |
| 1386 | unsigned long flags; | 1537 | unsigned long flags; |
| 1387 | u32 reg; | 1538 | u32 reg; |
| 1388 | 1539 | ||
| @@ -1395,6 +1546,11 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri) | |||
| 1395 | ~MPIC_VECPRI_PRIORITY_MASK; | 1546 | ~MPIC_VECPRI_PRIORITY_MASK; |
| 1396 | mpic_ipi_write(src - mpic->ipi_vecs[0], | 1547 | mpic_ipi_write(src - mpic->ipi_vecs[0], |
| 1397 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); | 1548 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); |
| 1549 | } else if (mpic_is_tm(mpic, irq)) { | ||
| 1550 | reg = mpic_tm_read(src - mpic->timer_vecs[0]) & | ||
| 1551 | ~MPIC_VECPRI_PRIORITY_MASK; | ||
| 1552 | mpic_tm_write(src - mpic->timer_vecs[0], | ||
| 1553 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); | ||
| 1398 | } else { | 1554 | } else { |
| 1399 | reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) | 1555 | reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) |
| 1400 | & ~MPIC_VECPRI_PRIORITY_MASK; | 1556 | & ~MPIC_VECPRI_PRIORITY_MASK; |
| @@ -1493,9 +1649,8 @@ static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg) | |||
| 1493 | return NO_IRQ; | 1649 | return NO_IRQ; |
| 1494 | } | 1650 | } |
| 1495 | if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { | 1651 | if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { |
| 1496 | if (printk_ratelimit()) | 1652 | printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n", |
| 1497 | printk(KERN_WARNING "%s: Got protected source %d !\n", | 1653 | mpic->name, (int)src); |
| 1498 | mpic->name, (int)src); | ||
| 1499 | mpic_eoi(mpic); | 1654 | mpic_eoi(mpic); |
| 1500 | return NO_IRQ; | 1655 | return NO_IRQ; |
| 1501 | } | 1656 | } |
| @@ -1533,9 +1688,8 @@ unsigned int mpic_get_coreint_irq(void) | |||
| 1533 | return NO_IRQ; | 1688 | return NO_IRQ; |
| 1534 | } | 1689 | } |
| 1535 | if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { | 1690 | if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { |
| 1536 | if (printk_ratelimit()) | 1691 | printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n", |
| 1537 | printk(KERN_WARNING "%s: Got protected source %d !\n", | 1692 | mpic->name, (int)src); |
| 1538 | mpic->name, (int)src); | ||
| 1539 | return NO_IRQ; | 1693 | return NO_IRQ; |
| 1540 | } | 1694 | } |
| 1541 | 1695 | ||
| @@ -1574,46 +1728,28 @@ void mpic_request_ipis(void) | |||
| 1574 | } | 1728 | } |
| 1575 | } | 1729 | } |
| 1576 | 1730 | ||
| 1577 | static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask) | 1731 | void smp_mpic_message_pass(int cpu, int msg) |
| 1578 | { | 1732 | { |
| 1579 | struct mpic *mpic = mpic_primary; | 1733 | struct mpic *mpic = mpic_primary; |
| 1734 | u32 physmask; | ||
| 1580 | 1735 | ||
| 1581 | BUG_ON(mpic == NULL); | 1736 | BUG_ON(mpic == NULL); |
| 1582 | 1737 | ||
| 1583 | #ifdef DEBUG_IPI | ||
| 1584 | DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); | ||
| 1585 | #endif | ||
| 1586 | |||
| 1587 | mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + | ||
| 1588 | ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), | ||
| 1589 | mpic_physmask(cpumask_bits(cpu_mask)[0])); | ||
| 1590 | } | ||
| 1591 | |||
| 1592 | void smp_mpic_message_pass(int target, int msg) | ||
| 1593 | { | ||
| 1594 | cpumask_var_t tmp; | ||
| 1595 | |||
| 1596 | /* make sure we're sending something that translates to an IPI */ | 1738 | /* make sure we're sending something that translates to an IPI */ |
| 1597 | if ((unsigned int)msg > 3) { | 1739 | if ((unsigned int)msg > 3) { |
| 1598 | printk("SMP %d: smp_message_pass: unknown msg %d\n", | 1740 | printk("SMP %d: smp_message_pass: unknown msg %d\n", |
| 1599 | smp_processor_id(), msg); | 1741 | smp_processor_id(), msg); |
| 1600 | return; | 1742 | return; |
| 1601 | } | 1743 | } |
| 1602 | switch (target) { | 1744 | |
| 1603 | case MSG_ALL: | 1745 | #ifdef DEBUG_IPI |
| 1604 | mpic_send_ipi(msg, cpu_online_mask); | 1746 | DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, msg); |
| 1605 | break; | 1747 | #endif |
| 1606 | case MSG_ALL_BUT_SELF: | 1748 | |
| 1607 | alloc_cpumask_var(&tmp, GFP_NOWAIT); | 1749 | physmask = 1 << get_hard_smp_processor_id(cpu); |
| 1608 | cpumask_andnot(tmp, cpu_online_mask, | 1750 | |
| 1609 | cpumask_of(smp_processor_id())); | 1751 | mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + |
| 1610 | mpic_send_ipi(msg, tmp); | 1752 | msg * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), physmask); |
| 1611 | free_cpumask_var(tmp); | ||
| 1612 | break; | ||
| 1613 | default: | ||
| 1614 | mpic_send_ipi(msg, cpumask_of(target)); | ||
| 1615 | break; | ||
| 1616 | } | ||
| 1617 | } | 1753 | } |
| 1618 | 1754 | ||
| 1619 | int __init smp_mpic_probe(void) | 1755 | int __init smp_mpic_probe(void) |
| @@ -1657,9 +1793,8 @@ void mpic_reset_core(int cpu) | |||
| 1657 | #endif /* CONFIG_SMP */ | 1793 | #endif /* CONFIG_SMP */ |
| 1658 | 1794 | ||
| 1659 | #ifdef CONFIG_PM | 1795 | #ifdef CONFIG_PM |
| 1660 | static int mpic_suspend(struct sys_device *dev, pm_message_t state) | 1796 | static void mpic_suspend_one(struct mpic *mpic) |
| 1661 | { | 1797 | { |
| 1662 | struct mpic *mpic = container_of(dev, struct mpic, sysdev); | ||
| 1663 | int i; | 1798 | int i; |
| 1664 | 1799 | ||
| 1665 | for (i = 0; i < mpic->num_sources; i++) { | 1800 | for (i = 0; i < mpic->num_sources; i++) { |
| @@ -1668,13 +1803,22 @@ static int mpic_suspend(struct sys_device *dev, pm_message_t state) | |||
| 1668 | mpic->save_data[i].dest = | 1803 | mpic->save_data[i].dest = |
| 1669 | mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); | 1804 | mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); |
| 1670 | } | 1805 | } |
| 1806 | } | ||
| 1807 | |||
| 1808 | static int mpic_suspend(void) | ||
| 1809 | { | ||
| 1810 | struct mpic *mpic = mpics; | ||
| 1811 | |||
| 1812 | while (mpic) { | ||
| 1813 | mpic_suspend_one(mpic); | ||
| 1814 | mpic = mpic->next; | ||
| 1815 | } | ||
| 1671 | 1816 | ||
| 1672 | return 0; | 1817 | return 0; |
| 1673 | } | 1818 | } |
| 1674 | 1819 | ||
| 1675 | static int mpic_resume(struct sys_device *dev) | 1820 | static void mpic_resume_one(struct mpic *mpic) |
| 1676 | { | 1821 | { |
| 1677 | struct mpic *mpic = container_of(dev, struct mpic, sysdev); | ||
| 1678 | int i; | 1822 | int i; |
| 1679 | 1823 | ||
| 1680 | for (i = 0; i < mpic->num_sources; i++) { | 1824 | for (i = 0; i < mpic->num_sources; i++) { |
| @@ -1701,33 +1845,28 @@ static int mpic_resume(struct sys_device *dev) | |||
| 1701 | } | 1845 | } |
| 1702 | #endif | 1846 | #endif |
| 1703 | } /* end for loop */ | 1847 | } /* end for loop */ |
| 1848 | } | ||
| 1704 | 1849 | ||
| 1705 | return 0; | 1850 | static void mpic_resume(void) |
| 1851 | { | ||
| 1852 | struct mpic *mpic = mpics; | ||
| 1853 | |||
| 1854 | while (mpic) { | ||
| 1855 | mpic_resume_one(mpic); | ||
| 1856 | mpic = mpic->next; | ||
| 1857 | } | ||
| 1706 | } | 1858 | } |
| 1707 | #endif | ||
| 1708 | 1859 | ||
| 1709 | static struct sysdev_class mpic_sysclass = { | 1860 | static struct syscore_ops mpic_syscore_ops = { |
| 1710 | #ifdef CONFIG_PM | ||
| 1711 | .resume = mpic_resume, | 1861 | .resume = mpic_resume, |
| 1712 | .suspend = mpic_suspend, | 1862 | .suspend = mpic_suspend, |
| 1713 | #endif | ||
| 1714 | .name = "mpic", | ||
| 1715 | }; | 1863 | }; |
| 1716 | 1864 | ||
| 1717 | static int mpic_init_sys(void) | 1865 | static int mpic_init_sys(void) |
| 1718 | { | 1866 | { |
| 1719 | struct mpic *mpic = mpics; | 1867 | register_syscore_ops(&mpic_syscore_ops); |
| 1720 | int error, id = 0; | 1868 | return 0; |
| 1721 | |||
| 1722 | error = sysdev_class_register(&mpic_sysclass); | ||
| 1723 | |||
| 1724 | while (mpic && !error) { | ||
| 1725 | mpic->sysdev.cls = &mpic_sysclass; | ||
| 1726 | mpic->sysdev.id = id++; | ||
| 1727 | error = sysdev_register(&mpic->sysdev); | ||
| 1728 | mpic = mpic->next; | ||
| 1729 | } | ||
| 1730 | return error; | ||
| 1731 | } | 1869 | } |
| 1732 | 1870 | ||
| 1733 | device_initcall(mpic_init_sys); | 1871 | device_initcall(mpic_init_sys); |
| 1872 | #endif | ||
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h index e4a6df77b8d7..13f3e8913a93 100644 --- a/arch/powerpc/sysdev/mpic.h +++ b/arch/powerpc/sysdev/mpic.h | |||
| @@ -34,9 +34,10 @@ static inline int mpic_pasemi_msi_init(struct mpic *mpic) | |||
| 34 | } | 34 | } |
| 35 | #endif | 35 | #endif |
| 36 | 36 | ||
| 37 | extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type); | 37 | extern int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type); |
| 38 | extern void mpic_set_vector(unsigned int virq, unsigned int vector); | 38 | extern void mpic_set_vector(unsigned int virq, unsigned int vector); |
| 39 | extern int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask); | 39 | extern int mpic_set_affinity(struct irq_data *d, |
| 40 | const struct cpumask *cpumask, bool force); | ||
| 40 | extern void mpic_reset_core(int cpu); | 41 | extern void mpic_reset_core(int cpu); |
| 41 | 42 | ||
| 42 | #endif /* _POWERPC_SYSDEV_MPIC_H */ | 43 | #endif /* _POWERPC_SYSDEV_MPIC_H */ |
diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c index 3b6a9a43718f..38e62382070c 100644 --- a/arch/powerpc/sysdev/mpic_pasemi_msi.c +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c | |||
| @@ -39,28 +39,28 @@ | |||
| 39 | static struct mpic *msi_mpic; | 39 | static struct mpic *msi_mpic; |
| 40 | 40 | ||
| 41 | 41 | ||
| 42 | static void mpic_pasemi_msi_mask_irq(unsigned int irq) | 42 | static void mpic_pasemi_msi_mask_irq(struct irq_data *data) |
| 43 | { | 43 | { |
| 44 | pr_debug("mpic_pasemi_msi_mask_irq %d\n", irq); | 44 | pr_debug("mpic_pasemi_msi_mask_irq %d\n", data->irq); |
| 45 | mask_msi_irq(irq); | 45 | mask_msi_irq(data); |
| 46 | mpic_mask_irq(irq); | 46 | mpic_mask_irq(data); |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | static void mpic_pasemi_msi_unmask_irq(unsigned int irq) | 49 | static void mpic_pasemi_msi_unmask_irq(struct irq_data *data) |
| 50 | { | 50 | { |
| 51 | pr_debug("mpic_pasemi_msi_unmask_irq %d\n", irq); | 51 | pr_debug("mpic_pasemi_msi_unmask_irq %d\n", data->irq); |
| 52 | mpic_unmask_irq(irq); | 52 | mpic_unmask_irq(data); |
| 53 | unmask_msi_irq(irq); | 53 | unmask_msi_irq(data); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | static struct irq_chip mpic_pasemi_msi_chip = { | 56 | static struct irq_chip mpic_pasemi_msi_chip = { |
| 57 | .shutdown = mpic_pasemi_msi_mask_irq, | 57 | .irq_shutdown = mpic_pasemi_msi_mask_irq, |
| 58 | .mask = mpic_pasemi_msi_mask_irq, | 58 | .irq_mask = mpic_pasemi_msi_mask_irq, |
| 59 | .unmask = mpic_pasemi_msi_unmask_irq, | 59 | .irq_unmask = mpic_pasemi_msi_unmask_irq, |
| 60 | .eoi = mpic_end_irq, | 60 | .irq_eoi = mpic_end_irq, |
| 61 | .set_type = mpic_set_irq_type, | 61 | .irq_set_type = mpic_set_irq_type, |
| 62 | .set_affinity = mpic_set_affinity, | 62 | .irq_set_affinity = mpic_set_affinity, |
| 63 | .name = "PASEMI-MSI", | 63 | .name = "PASEMI-MSI", |
| 64 | }; | 64 | }; |
| 65 | 65 | ||
| 66 | static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type) | 66 | static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type) |
| @@ -81,7 +81,7 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) | |||
| 81 | if (entry->irq == NO_IRQ) | 81 | if (entry->irq == NO_IRQ) |
| 82 | continue; | 82 | continue; |
| 83 | 83 | ||
| 84 | set_irq_msi(entry->irq, NULL); | 84 | irq_set_msi_desc(entry->irq, NULL); |
| 85 | msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, | 85 | msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, |
| 86 | virq_to_hw(entry->irq), ALLOC_CHUNK); | 86 | virq_to_hw(entry->irq), ALLOC_CHUNK); |
| 87 | irq_dispose_mapping(entry->irq); | 87 | irq_dispose_mapping(entry->irq); |
| @@ -131,9 +131,9 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
| 131 | */ | 131 | */ |
| 132 | mpic_set_vector(virq, 0); | 132 | mpic_set_vector(virq, 0); |
| 133 | 133 | ||
| 134 | set_irq_msi(virq, entry); | 134 | irq_set_msi_desc(virq, entry); |
| 135 | set_irq_chip(virq, &mpic_pasemi_msi_chip); | 135 | irq_set_chip(virq, &mpic_pasemi_msi_chip); |
| 136 | set_irq_type(virq, IRQ_TYPE_EDGE_RISING); | 136 | irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING); |
| 137 | 137 | ||
| 138 | pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%x) " \ | 138 | pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%x) " \ |
| 139 | "addr 0x%x\n", virq, hwirq, msg.address_lo); | 139 | "addr 0x%x\n", virq, hwirq, msg.address_lo); |
diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c index bcbfe79c704b..9a7aa0ed9c1c 100644 --- a/arch/powerpc/sysdev/mpic_u3msi.c +++ b/arch/powerpc/sysdev/mpic_u3msi.c | |||
| @@ -23,26 +23,26 @@ | |||
| 23 | /* A bit ugly, can we get this from the pci_dev somehow? */ | 23 | /* A bit ugly, can we get this from the pci_dev somehow? */ |
| 24 | static struct mpic *msi_mpic; | 24 | static struct mpic *msi_mpic; |
| 25 | 25 | ||
| 26 | static void mpic_u3msi_mask_irq(unsigned int irq) | 26 | static void mpic_u3msi_mask_irq(struct irq_data *data) |
| 27 | { | 27 | { |
| 28 | mask_msi_irq(irq); | 28 | mask_msi_irq(data); |
| 29 | mpic_mask_irq(irq); | 29 | mpic_mask_irq(data); |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | static void mpic_u3msi_unmask_irq(unsigned int irq) | 32 | static void mpic_u3msi_unmask_irq(struct irq_data *data) |
| 33 | { | 33 | { |
| 34 | mpic_unmask_irq(irq); | 34 | mpic_unmask_irq(data); |
| 35 | unmask_msi_irq(irq); | 35 | unmask_msi_irq(data); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | static struct irq_chip mpic_u3msi_chip = { | 38 | static struct irq_chip mpic_u3msi_chip = { |
| 39 | .shutdown = mpic_u3msi_mask_irq, | 39 | .irq_shutdown = mpic_u3msi_mask_irq, |
| 40 | .mask = mpic_u3msi_mask_irq, | 40 | .irq_mask = mpic_u3msi_mask_irq, |
| 41 | .unmask = mpic_u3msi_unmask_irq, | 41 | .irq_unmask = mpic_u3msi_unmask_irq, |
| 42 | .eoi = mpic_end_irq, | 42 | .irq_eoi = mpic_end_irq, |
| 43 | .set_type = mpic_set_irq_type, | 43 | .irq_set_type = mpic_set_irq_type, |
| 44 | .set_affinity = mpic_set_affinity, | 44 | .irq_set_affinity = mpic_set_affinity, |
| 45 | .name = "MPIC-U3MSI", | 45 | .name = "MPIC-U3MSI", |
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos) | 48 | static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos) |
| @@ -129,7 +129,7 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) | |||
| 129 | if (entry->irq == NO_IRQ) | 129 | if (entry->irq == NO_IRQ) |
| 130 | continue; | 130 | continue; |
| 131 | 131 | ||
| 132 | set_irq_msi(entry->irq, NULL); | 132 | irq_set_msi_desc(entry->irq, NULL); |
| 133 | msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, | 133 | msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, |
| 134 | virq_to_hw(entry->irq), 1); | 134 | virq_to_hw(entry->irq), 1); |
| 135 | irq_dispose_mapping(entry->irq); | 135 | irq_dispose_mapping(entry->irq); |
| @@ -166,9 +166,9 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
| 166 | return -ENOSPC; | 166 | return -ENOSPC; |
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | set_irq_msi(virq, entry); | 169 | irq_set_msi_desc(virq, entry); |
| 170 | set_irq_chip(virq, &mpic_u3msi_chip); | 170 | irq_set_chip(virq, &mpic_u3msi_chip); |
| 171 | set_irq_type(virq, IRQ_TYPE_EDGE_RISING); | 171 | irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING); |
| 172 | 172 | ||
| 173 | pr_debug("u3msi: allocated virq 0x%x (hw 0x%x) addr 0x%lx\n", | 173 | pr_debug("u3msi: allocated virq 0x%x (hw 0x%x) addr 0x%lx\n", |
| 174 | virq, hwirq, (unsigned long)addr); | 174 | virq, hwirq, (unsigned long)addr); |
diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c index 1398bc454999..0f6af41ebb44 100644 --- a/arch/powerpc/sysdev/mv64x60_dev.c +++ b/arch/powerpc/sysdev/mv64x60_dev.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/mv643xx.h> | 16 | #include <linux/mv643xx.h> |
| 17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| 18 | #include <linux/of_platform.h> | 18 | #include <linux/of_platform.h> |
| 19 | #include <linux/of_net.h> | ||
| 19 | #include <linux/dma-mapping.h> | 20 | #include <linux/dma-mapping.h> |
| 20 | 21 | ||
| 21 | #include <asm/prom.h> | 22 | #include <asm/prom.h> |
| @@ -345,7 +346,7 @@ static int __init mv64x60_i2c_device_setup(struct device_node *np, int id) | |||
| 345 | if (prop) | 346 | if (prop) |
| 346 | pdata.freq_m = *prop; | 347 | pdata.freq_m = *prop; |
| 347 | 348 | ||
| 348 | pdata.freq_m = 3; /* default */ | 349 | pdata.freq_n = 3; /* default */ |
| 349 | prop = of_get_property(np, "freq_n", NULL); | 350 | prop = of_get_property(np, "freq_n", NULL); |
| 350 | if (prop) | 351 | if (prop) |
| 351 | pdata.freq_n = *prop; | 352 | pdata.freq_n = *prop; |
diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c index 485b92477d7c..14d130268e7a 100644 --- a/arch/powerpc/sysdev/mv64x60_pic.c +++ b/arch/powerpc/sysdev/mv64x60_pic.c | |||
| @@ -76,9 +76,9 @@ static struct irq_host *mv64x60_irq_host; | |||
| 76 | * mv64x60_chip_low functions | 76 | * mv64x60_chip_low functions |
| 77 | */ | 77 | */ |
| 78 | 78 | ||
| 79 | static void mv64x60_mask_low(unsigned int virq) | 79 | static void mv64x60_mask_low(struct irq_data *d) |
| 80 | { | 80 | { |
| 81 | int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK; | 81 | int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; |
| 82 | unsigned long flags; | 82 | unsigned long flags; |
| 83 | 83 | ||
| 84 | spin_lock_irqsave(&mv64x60_lock, flags); | 84 | spin_lock_irqsave(&mv64x60_lock, flags); |
| @@ -89,9 +89,9 @@ static void mv64x60_mask_low(unsigned int virq) | |||
| 89 | (void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO); | 89 | (void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | static void mv64x60_unmask_low(unsigned int virq) | 92 | static void mv64x60_unmask_low(struct irq_data *d) |
| 93 | { | 93 | { |
| 94 | int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK; | 94 | int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; |
| 95 | unsigned long flags; | 95 | unsigned long flags; |
| 96 | 96 | ||
| 97 | spin_lock_irqsave(&mv64x60_lock, flags); | 97 | spin_lock_irqsave(&mv64x60_lock, flags); |
| @@ -104,18 +104,18 @@ static void mv64x60_unmask_low(unsigned int virq) | |||
| 104 | 104 | ||
| 105 | static struct irq_chip mv64x60_chip_low = { | 105 | static struct irq_chip mv64x60_chip_low = { |
| 106 | .name = "mv64x60_low", | 106 | .name = "mv64x60_low", |
| 107 | .mask = mv64x60_mask_low, | 107 | .irq_mask = mv64x60_mask_low, |
| 108 | .mask_ack = mv64x60_mask_low, | 108 | .irq_mask_ack = mv64x60_mask_low, |
| 109 | .unmask = mv64x60_unmask_low, | 109 | .irq_unmask = mv64x60_unmask_low, |
| 110 | }; | 110 | }; |
| 111 | 111 | ||
| 112 | /* | 112 | /* |
| 113 | * mv64x60_chip_high functions | 113 | * mv64x60_chip_high functions |
| 114 | */ | 114 | */ |
| 115 | 115 | ||
| 116 | static void mv64x60_mask_high(unsigned int virq) | 116 | static void mv64x60_mask_high(struct irq_data *d) |
| 117 | { | 117 | { |
| 118 | int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK; | 118 | int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; |
| 119 | unsigned long flags; | 119 | unsigned long flags; |
| 120 | 120 | ||
| 121 | spin_lock_irqsave(&mv64x60_lock, flags); | 121 | spin_lock_irqsave(&mv64x60_lock, flags); |
| @@ -126,9 +126,9 @@ static void mv64x60_mask_high(unsigned int virq) | |||
| 126 | (void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI); | 126 | (void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI); |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | static void mv64x60_unmask_high(unsigned int virq) | 129 | static void mv64x60_unmask_high(struct irq_data *d) |
| 130 | { | 130 | { |
| 131 | int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK; | 131 | int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; |
| 132 | unsigned long flags; | 132 | unsigned long flags; |
| 133 | 133 | ||
| 134 | spin_lock_irqsave(&mv64x60_lock, flags); | 134 | spin_lock_irqsave(&mv64x60_lock, flags); |
| @@ -141,18 +141,18 @@ static void mv64x60_unmask_high(unsigned int virq) | |||
| 141 | 141 | ||
| 142 | static struct irq_chip mv64x60_chip_high = { | 142 | static struct irq_chip mv64x60_chip_high = { |
| 143 | .name = "mv64x60_high", | 143 | .name = "mv64x60_high", |
| 144 | .mask = mv64x60_mask_high, | 144 | .irq_mask = mv64x60_mask_high, |
| 145 | .mask_ack = mv64x60_mask_high, | 145 | .irq_mask_ack = mv64x60_mask_high, |
| 146 | .unmask = mv64x60_unmask_high, | 146 | .irq_unmask = mv64x60_unmask_high, |
| 147 | }; | 147 | }; |
| 148 | 148 | ||
| 149 | /* | 149 | /* |
| 150 | * mv64x60_chip_gpp functions | 150 | * mv64x60_chip_gpp functions |
| 151 | */ | 151 | */ |
| 152 | 152 | ||
| 153 | static void mv64x60_mask_gpp(unsigned int virq) | 153 | static void mv64x60_mask_gpp(struct irq_data *d) |
| 154 | { | 154 | { |
| 155 | int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK; | 155 | int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; |
| 156 | unsigned long flags; | 156 | unsigned long flags; |
| 157 | 157 | ||
| 158 | spin_lock_irqsave(&mv64x60_lock, flags); | 158 | spin_lock_irqsave(&mv64x60_lock, flags); |
| @@ -163,9 +163,9 @@ static void mv64x60_mask_gpp(unsigned int virq) | |||
| 163 | (void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK); | 163 | (void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | static void mv64x60_mask_ack_gpp(unsigned int virq) | 166 | static void mv64x60_mask_ack_gpp(struct irq_data *d) |
| 167 | { | 167 | { |
| 168 | int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK; | 168 | int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; |
| 169 | unsigned long flags; | 169 | unsigned long flags; |
| 170 | 170 | ||
| 171 | spin_lock_irqsave(&mv64x60_lock, flags); | 171 | spin_lock_irqsave(&mv64x60_lock, flags); |
| @@ -178,9 +178,9 @@ static void mv64x60_mask_ack_gpp(unsigned int virq) | |||
| 178 | (void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE); | 178 | (void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE); |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | static void mv64x60_unmask_gpp(unsigned int virq) | 181 | static void mv64x60_unmask_gpp(struct irq_data *d) |
| 182 | { | 182 | { |
| 183 | int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK; | 183 | int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; |
| 184 | unsigned long flags; | 184 | unsigned long flags; |
| 185 | 185 | ||
| 186 | spin_lock_irqsave(&mv64x60_lock, flags); | 186 | spin_lock_irqsave(&mv64x60_lock, flags); |
| @@ -193,9 +193,9 @@ static void mv64x60_unmask_gpp(unsigned int virq) | |||
| 193 | 193 | ||
| 194 | static struct irq_chip mv64x60_chip_gpp = { | 194 | static struct irq_chip mv64x60_chip_gpp = { |
| 195 | .name = "mv64x60_gpp", | 195 | .name = "mv64x60_gpp", |
| 196 | .mask = mv64x60_mask_gpp, | 196 | .irq_mask = mv64x60_mask_gpp, |
| 197 | .mask_ack = mv64x60_mask_ack_gpp, | 197 | .irq_mask_ack = mv64x60_mask_ack_gpp, |
| 198 | .unmask = mv64x60_unmask_gpp, | 198 | .irq_unmask = mv64x60_unmask_gpp, |
| 199 | }; | 199 | }; |
| 200 | 200 | ||
| 201 | /* | 201 | /* |
| @@ -213,11 +213,12 @@ static int mv64x60_host_map(struct irq_host *h, unsigned int virq, | |||
| 213 | { | 213 | { |
| 214 | int level1; | 214 | int level1; |
| 215 | 215 | ||
| 216 | irq_to_desc(virq)->status |= IRQ_LEVEL; | 216 | irq_set_status_flags(virq, IRQ_LEVEL); |
| 217 | 217 | ||
| 218 | level1 = (hwirq & MV64x60_LEVEL1_MASK) >> MV64x60_LEVEL1_OFFSET; | 218 | level1 = (hwirq & MV64x60_LEVEL1_MASK) >> MV64x60_LEVEL1_OFFSET; |
| 219 | BUG_ON(level1 > MV64x60_LEVEL1_GPP); | 219 | BUG_ON(level1 > MV64x60_LEVEL1_GPP); |
| 220 | set_irq_chip_and_handler(virq, mv64x60_chips[level1], handle_level_irq); | 220 | irq_set_chip_and_handler(virq, mv64x60_chips[level1], |
| 221 | handle_level_irq); | ||
| 221 | 222 | ||
| 222 | return 0; | 223 | return 0; |
| 223 | } | 224 | } |
diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c index 24a0bb955b18..8ce4fc3d9828 100644 --- a/arch/powerpc/sysdev/pmi.c +++ b/arch/powerpc/sysdev/pmi.c | |||
| @@ -114,15 +114,14 @@ static void pmi_notify_handlers(struct work_struct *work) | |||
| 114 | 114 | ||
| 115 | spin_lock(&data->handler_spinlock); | 115 | spin_lock(&data->handler_spinlock); |
| 116 | list_for_each_entry(handler, &data->handler, node) { | 116 | list_for_each_entry(handler, &data->handler, node) { |
| 117 | pr_debug(KERN_INFO "pmi: notifying handler %p\n", handler); | 117 | pr_debug("pmi: notifying handler %p\n", handler); |
| 118 | if (handler->type == data->msg.type) | 118 | if (handler->type == data->msg.type) |
| 119 | handler->handle_pmi_message(data->msg); | 119 | handler->handle_pmi_message(data->msg); |
| 120 | } | 120 | } |
| 121 | spin_unlock(&data->handler_spinlock); | 121 | spin_unlock(&data->handler_spinlock); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | static int pmi_of_probe(struct platform_device *dev, | 124 | static int pmi_of_probe(struct platform_device *dev) |
| 125 | const struct of_device_id *match) | ||
| 126 | { | 125 | { |
| 127 | struct device_node *np = dev->dev.of_node; | 126 | struct device_node *np = dev->dev.of_node; |
| 128 | int rc; | 127 | int rc; |
| @@ -205,7 +204,7 @@ static int pmi_of_remove(struct platform_device *dev) | |||
| 205 | return 0; | 204 | return 0; |
| 206 | } | 205 | } |
| 207 | 206 | ||
| 208 | static struct of_platform_driver pmi_of_platform_driver = { | 207 | static struct platform_driver pmi_of_platform_driver = { |
| 209 | .probe = pmi_of_probe, | 208 | .probe = pmi_of_probe, |
| 210 | .remove = pmi_of_remove, | 209 | .remove = pmi_of_remove, |
| 211 | .driver = { | 210 | .driver = { |
| @@ -217,13 +216,13 @@ static struct of_platform_driver pmi_of_platform_driver = { | |||
| 217 | 216 | ||
| 218 | static int __init pmi_module_init(void) | 217 | static int __init pmi_module_init(void) |
| 219 | { | 218 | { |
| 220 | return of_register_platform_driver(&pmi_of_platform_driver); | 219 | return platform_driver_register(&pmi_of_platform_driver); |
| 221 | } | 220 | } |
| 222 | module_init(pmi_module_init); | 221 | module_init(pmi_module_init); |
| 223 | 222 | ||
| 224 | static void __exit pmi_module_exit(void) | 223 | static void __exit pmi_module_exit(void) |
| 225 | { | 224 | { |
| 226 | of_unregister_platform_driver(&pmi_of_platform_driver); | 225 | platform_driver_unregister(&pmi_of_platform_driver); |
| 227 | } | 226 | } |
| 228 | module_exit(pmi_module_exit); | 227 | module_exit(pmi_module_exit); |
| 229 | 228 | ||
diff --git a/arch/powerpc/sysdev/ppc4xx_cpm.c b/arch/powerpc/sysdev/ppc4xx_cpm.c new file mode 100644 index 000000000000..73b86cc5ea74 --- /dev/null +++ b/arch/powerpc/sysdev/ppc4xx_cpm.c | |||
| @@ -0,0 +1,346 @@ | |||
| 1 | /* | ||
| 2 | * PowerPC 4xx Clock and Power Management | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010, Applied Micro Circuits Corporation | ||
| 5 | * Victor Gallardo (vgallardo@apm.com) | ||
| 6 | * | ||
| 7 | * Based on arch/powerpc/platforms/44x/idle.c: | ||
| 8 | * Jerone Young <jyoung5@us.ibm.com> | ||
| 9 | * Copyright 2008 IBM Corp. | ||
| 10 | * | ||
| 11 | * Based on arch/powerpc/sysdev/fsl_pmc.c: | ||
| 12 | * Anton Vorontsov <avorontsov@ru.mvista.com> | ||
| 13 | * Copyright 2009 MontaVista Software, Inc. | ||
| 14 | * | ||
| 15 | * See file CREDITS for list of people who contributed to this | ||
| 16 | * project. | ||
| 17 | * | ||
| 18 | * This program is free software; you can redistribute it and/or | ||
| 19 | * modify it under the terms of the GNU General Public License as | ||
| 20 | * published by the Free Software Foundation; either version 2 of | ||
| 21 | * the License, or (at your option) any later version. | ||
| 22 | * | ||
| 23 | * This program is distributed in the hope that it will be useful, | ||
| 24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 26 | * GNU General Public License for more details. | ||
| 27 | * | ||
| 28 | * You should have received a copy of the GNU General Public License | ||
| 29 | * along with this program; if not, write to the Free Software | ||
| 30 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 31 | * MA 02111-1307 USA | ||
| 32 | */ | ||
| 33 | |||
| 34 | #include <linux/kernel.h> | ||
| 35 | #include <linux/of_platform.h> | ||
| 36 | #include <linux/sysfs.h> | ||
| 37 | #include <linux/cpu.h> | ||
| 38 | #include <linux/suspend.h> | ||
| 39 | #include <asm/dcr.h> | ||
| 40 | #include <asm/dcr-native.h> | ||
| 41 | #include <asm/machdep.h> | ||
| 42 | |||
| 43 | #define CPM_ER 0 | ||
| 44 | #define CPM_FR 1 | ||
| 45 | #define CPM_SR 2 | ||
| 46 | |||
| 47 | #define CPM_IDLE_WAIT 0 | ||
| 48 | #define CPM_IDLE_DOZE 1 | ||
| 49 | |||
| 50 | struct cpm { | ||
| 51 | dcr_host_t dcr_host; | ||
| 52 | unsigned int dcr_offset[3]; | ||
| 53 | unsigned int powersave_off; | ||
| 54 | unsigned int unused; | ||
| 55 | unsigned int idle_doze; | ||
| 56 | unsigned int standby; | ||
| 57 | unsigned int suspend; | ||
| 58 | }; | ||
| 59 | |||
| 60 | static struct cpm cpm; | ||
| 61 | |||
| 62 | struct cpm_idle_mode { | ||
| 63 | unsigned int enabled; | ||
| 64 | const char *name; | ||
| 65 | }; | ||
| 66 | |||
| 67 | static struct cpm_idle_mode idle_mode[] = { | ||
| 68 | [CPM_IDLE_WAIT] = { 1, "wait" }, /* default */ | ||
| 69 | [CPM_IDLE_DOZE] = { 0, "doze" }, | ||
| 70 | }; | ||
| 71 | |||
| 72 | static unsigned int cpm_set(unsigned int cpm_reg, unsigned int mask) | ||
| 73 | { | ||
| 74 | unsigned int value; | ||
| 75 | |||
| 76 | /* CPM controller supports 3 different types of sleep interface | ||
| 77 | * known as class 1, 2 and 3. For class 1 units, they are | ||
| 78 | * unconditionally put to sleep when the corresponding CPM bit is | ||
| 79 | * set. For class 2 and 3 units this is not case; if they can be | ||
| 80 | * put to to sleep, they will. Here we do not verify, we just | ||
| 81 | * set them and expect them to eventually go off when they can. | ||
| 82 | */ | ||
| 83 | value = dcr_read(cpm.dcr_host, cpm.dcr_offset[cpm_reg]); | ||
| 84 | dcr_write(cpm.dcr_host, cpm.dcr_offset[cpm_reg], value | mask); | ||
| 85 | |||
| 86 | /* return old state, to restore later if needed */ | ||
| 87 | return value; | ||
| 88 | } | ||
| 89 | |||
| 90 | static void cpm_idle_wait(void) | ||
| 91 | { | ||
| 92 | unsigned long msr_save; | ||
| 93 | |||
| 94 | /* save off initial state */ | ||
| 95 | msr_save = mfmsr(); | ||
| 96 | /* sync required when CPM0_ER[CPU] is set */ | ||
| 97 | mb(); | ||
| 98 | /* set wait state MSR */ | ||
| 99 | mtmsr(msr_save|MSR_WE|MSR_EE|MSR_CE|MSR_DE); | ||
| 100 | isync(); | ||
| 101 | /* return to initial state */ | ||
| 102 | mtmsr(msr_save); | ||
| 103 | isync(); | ||
| 104 | } | ||
| 105 | |||
| 106 | static void cpm_idle_sleep(unsigned int mask) | ||
| 107 | { | ||
| 108 | unsigned int er_save; | ||
| 109 | |||
| 110 | /* update CPM_ER state */ | ||
| 111 | er_save = cpm_set(CPM_ER, mask); | ||
| 112 | |||
| 113 | /* go to wait state so that CPM0_ER[CPU] can take effect */ | ||
| 114 | cpm_idle_wait(); | ||
| 115 | |||
| 116 | /* restore CPM_ER state */ | ||
| 117 | dcr_write(cpm.dcr_host, cpm.dcr_offset[CPM_ER], er_save); | ||
| 118 | } | ||
| 119 | |||
| 120 | static void cpm_idle_doze(void) | ||
| 121 | { | ||
| 122 | cpm_idle_sleep(cpm.idle_doze); | ||
| 123 | } | ||
| 124 | |||
| 125 | static void cpm_idle_config(int mode) | ||
| 126 | { | ||
| 127 | int i; | ||
| 128 | |||
| 129 | if (idle_mode[mode].enabled) | ||
| 130 | return; | ||
| 131 | |||
| 132 | for (i = 0; i < ARRAY_SIZE(idle_mode); i++) | ||
| 133 | idle_mode[i].enabled = 0; | ||
| 134 | |||
| 135 | idle_mode[mode].enabled = 1; | ||
| 136 | } | ||
| 137 | |||
| 138 | static ssize_t cpm_idle_show(struct kobject *kobj, | ||
| 139 | struct kobj_attribute *attr, char *buf) | ||
| 140 | { | ||
| 141 | char *s = buf; | ||
| 142 | int i; | ||
| 143 | |||
| 144 | for (i = 0; i < ARRAY_SIZE(idle_mode); i++) { | ||
| 145 | if (idle_mode[i].enabled) | ||
| 146 | s += sprintf(s, "[%s] ", idle_mode[i].name); | ||
| 147 | else | ||
| 148 | s += sprintf(s, "%s ", idle_mode[i].name); | ||
| 149 | } | ||
| 150 | |||
| 151 | *(s-1) = '\n'; /* convert the last space to a newline */ | ||
| 152 | |||
| 153 | return s - buf; | ||
| 154 | } | ||
| 155 | |||
| 156 | static ssize_t cpm_idle_store(struct kobject *kobj, | ||
| 157 | struct kobj_attribute *attr, | ||
| 158 | const char *buf, size_t n) | ||
| 159 | { | ||
| 160 | int i; | ||
| 161 | char *p; | ||
| 162 | int len; | ||
| 163 | |||
| 164 | p = memchr(buf, '\n', n); | ||
| 165 | len = p ? p - buf : n; | ||
| 166 | |||
| 167 | for (i = 0; i < ARRAY_SIZE(idle_mode); i++) { | ||
| 168 | if (strncmp(buf, idle_mode[i].name, len) == 0) { | ||
| 169 | cpm_idle_config(i); | ||
| 170 | return n; | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | return -EINVAL; | ||
| 175 | } | ||
| 176 | |||
| 177 | static struct kobj_attribute cpm_idle_attr = | ||
| 178 | __ATTR(idle, 0644, cpm_idle_show, cpm_idle_store); | ||
| 179 | |||
| 180 | static void cpm_idle_config_sysfs(void) | ||
| 181 | { | ||
| 182 | struct sys_device *sys_dev; | ||
| 183 | unsigned long ret; | ||
| 184 | |||
| 185 | sys_dev = get_cpu_sysdev(0); | ||
| 186 | |||
| 187 | ret = sysfs_create_file(&sys_dev->kobj, | ||
| 188 | &cpm_idle_attr.attr); | ||
| 189 | if (ret) | ||
| 190 | printk(KERN_WARNING | ||
| 191 | "cpm: failed to create idle sysfs entry\n"); | ||
| 192 | } | ||
| 193 | |||
| 194 | static void cpm_idle(void) | ||
| 195 | { | ||
| 196 | if (idle_mode[CPM_IDLE_DOZE].enabled) | ||
| 197 | cpm_idle_doze(); | ||
| 198 | else | ||
| 199 | cpm_idle_wait(); | ||
| 200 | } | ||
| 201 | |||
| 202 | static int cpm_suspend_valid(suspend_state_t state) | ||
| 203 | { | ||
| 204 | switch (state) { | ||
| 205 | case PM_SUSPEND_STANDBY: | ||
| 206 | return !!cpm.standby; | ||
| 207 | case PM_SUSPEND_MEM: | ||
| 208 | return !!cpm.suspend; | ||
| 209 | default: | ||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | static void cpm_suspend_standby(unsigned int mask) | ||
| 215 | { | ||
| 216 | unsigned long tcr_save; | ||
| 217 | |||
| 218 | /* disable decrement interrupt */ | ||
| 219 | tcr_save = mfspr(SPRN_TCR); | ||
| 220 | mtspr(SPRN_TCR, tcr_save & ~TCR_DIE); | ||
| 221 | |||
| 222 | /* go to sleep state */ | ||
| 223 | cpm_idle_sleep(mask); | ||
| 224 | |||
| 225 | /* restore decrement interrupt */ | ||
| 226 | mtspr(SPRN_TCR, tcr_save); | ||
| 227 | } | ||
| 228 | |||
| 229 | static int cpm_suspend_enter(suspend_state_t state) | ||
| 230 | { | ||
| 231 | switch (state) { | ||
| 232 | case PM_SUSPEND_STANDBY: | ||
| 233 | cpm_suspend_standby(cpm.standby); | ||
| 234 | break; | ||
| 235 | case PM_SUSPEND_MEM: | ||
| 236 | cpm_suspend_standby(cpm.suspend); | ||
| 237 | break; | ||
| 238 | } | ||
| 239 | |||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | static struct platform_suspend_ops cpm_suspend_ops = { | ||
| 244 | .valid = cpm_suspend_valid, | ||
| 245 | .enter = cpm_suspend_enter, | ||
| 246 | }; | ||
| 247 | |||
| 248 | static int cpm_get_uint_property(struct device_node *np, | ||
| 249 | const char *name) | ||
| 250 | { | ||
| 251 | int len; | ||
| 252 | const unsigned int *prop = of_get_property(np, name, &len); | ||
| 253 | |||
| 254 | if (prop == NULL || len < sizeof(u32)) | ||
| 255 | return 0; | ||
| 256 | |||
| 257 | return *prop; | ||
| 258 | } | ||
| 259 | |||
| 260 | static int __init cpm_init(void) | ||
| 261 | { | ||
| 262 | struct device_node *np; | ||
| 263 | int dcr_base, dcr_len; | ||
| 264 | int ret = 0; | ||
| 265 | |||
| 266 | if (!cpm.powersave_off) { | ||
| 267 | cpm_idle_config(CPM_IDLE_WAIT); | ||
| 268 | ppc_md.power_save = &cpm_idle; | ||
| 269 | } | ||
| 270 | |||
| 271 | np = of_find_compatible_node(NULL, NULL, "ibm,cpm"); | ||
| 272 | if (!np) { | ||
| 273 | ret = -EINVAL; | ||
| 274 | goto out; | ||
| 275 | } | ||
| 276 | |||
| 277 | dcr_base = dcr_resource_start(np, 0); | ||
| 278 | dcr_len = dcr_resource_len(np, 0); | ||
| 279 | |||
| 280 | if (dcr_base == 0 || dcr_len == 0) { | ||
| 281 | printk(KERN_ERR "cpm: could not parse dcr property for %s\n", | ||
| 282 | np->full_name); | ||
| 283 | ret = -EINVAL; | ||
| 284 | goto out; | ||
| 285 | } | ||
| 286 | |||
| 287 | cpm.dcr_host = dcr_map(np, dcr_base, dcr_len); | ||
| 288 | |||
| 289 | if (!DCR_MAP_OK(cpm.dcr_host)) { | ||
| 290 | printk(KERN_ERR "cpm: failed to map dcr property for %s\n", | ||
| 291 | np->full_name); | ||
| 292 | ret = -EINVAL; | ||
| 293 | goto out; | ||
| 294 | } | ||
| 295 | |||
| 296 | /* All 4xx SoCs with a CPM controller have one of two | ||
| 297 | * different order for the CPM registers. Some have the | ||
| 298 | * CPM registers in the following order (ER,FR,SR). The | ||
| 299 | * others have them in the following order (SR,ER,FR). | ||
| 300 | */ | ||
| 301 | |||
| 302 | if (cpm_get_uint_property(np, "er-offset") == 0) { | ||
| 303 | cpm.dcr_offset[CPM_ER] = 0; | ||
| 304 | cpm.dcr_offset[CPM_FR] = 1; | ||
| 305 | cpm.dcr_offset[CPM_SR] = 2; | ||
| 306 | } else { | ||
| 307 | cpm.dcr_offset[CPM_ER] = 1; | ||
| 308 | cpm.dcr_offset[CPM_FR] = 2; | ||
| 309 | cpm.dcr_offset[CPM_SR] = 0; | ||
| 310 | } | ||
| 311 | |||
| 312 | /* Now let's see what IPs to turn off for the following modes */ | ||
| 313 | |||
| 314 | cpm.unused = cpm_get_uint_property(np, "unused-units"); | ||
| 315 | cpm.idle_doze = cpm_get_uint_property(np, "idle-doze"); | ||
| 316 | cpm.standby = cpm_get_uint_property(np, "standby"); | ||
| 317 | cpm.suspend = cpm_get_uint_property(np, "suspend"); | ||
| 318 | |||
| 319 | /* If some IPs are unused let's turn them off now */ | ||
| 320 | |||
| 321 | if (cpm.unused) { | ||
| 322 | cpm_set(CPM_ER, cpm.unused); | ||
| 323 | cpm_set(CPM_FR, cpm.unused); | ||
| 324 | } | ||
| 325 | |||
| 326 | /* Now let's export interfaces */ | ||
| 327 | |||
| 328 | if (!cpm.powersave_off && cpm.idle_doze) | ||
| 329 | cpm_idle_config_sysfs(); | ||
| 330 | |||
| 331 | if (cpm.standby || cpm.suspend) | ||
| 332 | suspend_set_ops(&cpm_suspend_ops); | ||
| 333 | out: | ||
| 334 | if (np) | ||
| 335 | of_node_put(np); | ||
| 336 | return ret; | ||
| 337 | } | ||
| 338 | |||
| 339 | late_initcall(cpm_init); | ||
| 340 | |||
| 341 | static int __init cpm_powersave_off(char *arg) | ||
| 342 | { | ||
| 343 | cpm.powersave_off = 1; | ||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | __setup("powersave=off", cpm_powersave_off); | ||
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c new file mode 100644 index 000000000000..367af0241851 --- /dev/null +++ b/arch/powerpc/sysdev/ppc4xx_msi.c | |||
| @@ -0,0 +1,276 @@ | |||
| 1 | /* | ||
| 2 | * Adding PCI-E MSI support for PPC4XX SoCs. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010, Applied Micro Circuits Corporation | ||
| 5 | * Authors: Tirumala R Marri <tmarri@apm.com> | ||
| 6 | * Feng Kan <fkan@apm.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License as | ||
| 10 | * published by the Free Software Foundation; either version 2 of | ||
| 11 | * the License, or (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 21 | * MA 02111-1307 USA | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/irq.h> | ||
| 25 | #include <linux/bootmem.h> | ||
| 26 | #include <linux/pci.h> | ||
| 27 | #include <linux/msi.h> | ||
| 28 | #include <linux/of_platform.h> | ||
| 29 | #include <linux/interrupt.h> | ||
| 30 | #include <asm/prom.h> | ||
| 31 | #include <asm/hw_irq.h> | ||
| 32 | #include <asm/ppc-pci.h> | ||
| 33 | #include <boot/dcr.h> | ||
| 34 | #include <asm/dcr-regs.h> | ||
| 35 | #include <asm/msi_bitmap.h> | ||
| 36 | |||
| 37 | #define PEIH_TERMADH 0x00 | ||
| 38 | #define PEIH_TERMADL 0x08 | ||
| 39 | #define PEIH_MSIED 0x10 | ||
| 40 | #define PEIH_MSIMK 0x18 | ||
| 41 | #define PEIH_MSIASS 0x20 | ||
| 42 | #define PEIH_FLUSH0 0x30 | ||
| 43 | #define PEIH_FLUSH1 0x38 | ||
| 44 | #define PEIH_CNTRST 0x48 | ||
| 45 | #define NR_MSI_IRQS 4 | ||
| 46 | |||
| 47 | struct ppc4xx_msi { | ||
| 48 | u32 msi_addr_lo; | ||
| 49 | u32 msi_addr_hi; | ||
| 50 | void __iomem *msi_regs; | ||
| 51 | int msi_virqs[NR_MSI_IRQS]; | ||
| 52 | struct msi_bitmap bitmap; | ||
| 53 | struct device_node *msi_dev; | ||
| 54 | }; | ||
| 55 | |||
| 56 | static struct ppc4xx_msi ppc4xx_msi; | ||
| 57 | |||
| 58 | static int ppc4xx_msi_init_allocator(struct platform_device *dev, | ||
| 59 | struct ppc4xx_msi *msi_data) | ||
| 60 | { | ||
| 61 | int err; | ||
| 62 | |||
| 63 | err = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS, | ||
| 64 | dev->dev.of_node); | ||
| 65 | if (err) | ||
| 66 | return err; | ||
| 67 | |||
| 68 | err = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap); | ||
| 69 | if (err < 0) { | ||
| 70 | msi_bitmap_free(&msi_data->bitmap); | ||
| 71 | return err; | ||
| 72 | } | ||
| 73 | |||
| 74 | return 0; | ||
| 75 | } | ||
| 76 | |||
| 77 | static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | ||
| 78 | { | ||
| 79 | int int_no = -ENOMEM; | ||
| 80 | unsigned int virq; | ||
| 81 | struct msi_msg msg; | ||
| 82 | struct msi_desc *entry; | ||
| 83 | struct ppc4xx_msi *msi_data = &ppc4xx_msi; | ||
| 84 | |||
| 85 | list_for_each_entry(entry, &dev->msi_list, list) { | ||
| 86 | int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); | ||
| 87 | if (int_no >= 0) | ||
| 88 | break; | ||
| 89 | if (int_no < 0) { | ||
| 90 | pr_debug("%s: fail allocating msi interrupt\n", | ||
| 91 | __func__); | ||
| 92 | } | ||
| 93 | virq = irq_of_parse_and_map(msi_data->msi_dev, int_no); | ||
| 94 | if (virq == NO_IRQ) { | ||
| 95 | dev_err(&dev->dev, "%s: fail mapping irq\n", __func__); | ||
| 96 | msi_bitmap_free_hwirqs(&msi_data->bitmap, int_no, 1); | ||
| 97 | return -ENOSPC; | ||
| 98 | } | ||
| 99 | dev_dbg(&dev->dev, "%s: virq = %d\n", __func__, virq); | ||
| 100 | |||
| 101 | /* Setup msi address space */ | ||
| 102 | msg.address_hi = msi_data->msi_addr_hi; | ||
| 103 | msg.address_lo = msi_data->msi_addr_lo; | ||
| 104 | |||
| 105 | irq_set_msi_desc(virq, entry); | ||
| 106 | msg.data = int_no; | ||
| 107 | write_msi_msg(virq, &msg); | ||
| 108 | } | ||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | void ppc4xx_teardown_msi_irqs(struct pci_dev *dev) | ||
| 113 | { | ||
| 114 | struct msi_desc *entry; | ||
| 115 | struct ppc4xx_msi *msi_data = &ppc4xx_msi; | ||
| 116 | |||
| 117 | dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n"); | ||
| 118 | |||
| 119 | list_for_each_entry(entry, &dev->msi_list, list) { | ||
| 120 | if (entry->irq == NO_IRQ) | ||
| 121 | continue; | ||
| 122 | irq_set_msi_desc(entry->irq, NULL); | ||
| 123 | msi_bitmap_free_hwirqs(&msi_data->bitmap, | ||
| 124 | virq_to_hw(entry->irq), 1); | ||
| 125 | irq_dispose_mapping(entry->irq); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int type) | ||
| 130 | { | ||
| 131 | dev_dbg(&pdev->dev, "PCIE-MSI:%s called. vec %x type %d\n", | ||
| 132 | __func__, nvec, type); | ||
| 133 | if (type == PCI_CAP_ID_MSIX) | ||
| 134 | pr_debug("ppc4xx msi: MSI-X untested, trying anyway.\n"); | ||
| 135 | |||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | static int ppc4xx_setup_pcieh_hw(struct platform_device *dev, | ||
| 140 | struct resource res, struct ppc4xx_msi *msi) | ||
| 141 | { | ||
| 142 | const u32 *msi_data; | ||
| 143 | const u32 *msi_mask; | ||
| 144 | const u32 *sdr_addr; | ||
| 145 | dma_addr_t msi_phys; | ||
| 146 | void *msi_virt; | ||
| 147 | |||
| 148 | sdr_addr = of_get_property(dev->dev.of_node, "sdr-base", NULL); | ||
| 149 | if (!sdr_addr) | ||
| 150 | return -1; | ||
| 151 | |||
| 152 | SDR0_WRITE(sdr_addr, (u64)res.start >> 32); /*HIGH addr */ | ||
| 153 | SDR0_WRITE(sdr_addr + 1, res.start & 0xFFFFFFFF); /* Low addr */ | ||
| 154 | |||
| 155 | |||
| 156 | msi->msi_dev = of_find_node_by_name(NULL, "ppc4xx-msi"); | ||
| 157 | if (msi->msi_dev) | ||
| 158 | return -ENODEV; | ||
| 159 | |||
| 160 | msi->msi_regs = of_iomap(msi->msi_dev, 0); | ||
| 161 | if (!msi->msi_regs) { | ||
| 162 | dev_err(&dev->dev, "of_iomap problem failed\n"); | ||
| 163 | return -ENOMEM; | ||
| 164 | } | ||
| 165 | dev_dbg(&dev->dev, "PCIE-MSI: msi register mapped 0x%x 0x%x\n", | ||
| 166 | (u32) (msi->msi_regs + PEIH_TERMADH), (u32) (msi->msi_regs)); | ||
| 167 | |||
| 168 | msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys, GFP_KERNEL); | ||
| 169 | msi->msi_addr_hi = 0x0; | ||
| 170 | msi->msi_addr_lo = (u32) msi_phys; | ||
| 171 | dev_dbg(&dev->dev, "PCIE-MSI: msi address 0x%x\n", msi->msi_addr_lo); | ||
| 172 | |||
| 173 | /* Progam the Interrupt handler Termination addr registers */ | ||
| 174 | out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi); | ||
| 175 | out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo); | ||
| 176 | |||
| 177 | msi_data = of_get_property(dev->dev.of_node, "msi-data", NULL); | ||
| 178 | if (!msi_data) | ||
| 179 | return -1; | ||
| 180 | msi_mask = of_get_property(dev->dev.of_node, "msi-mask", NULL); | ||
| 181 | if (!msi_mask) | ||
| 182 | return -1; | ||
| 183 | /* Program MSI Expected data and Mask bits */ | ||
| 184 | out_be32(msi->msi_regs + PEIH_MSIED, *msi_data); | ||
| 185 | out_be32(msi->msi_regs + PEIH_MSIMK, *msi_mask); | ||
| 186 | |||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | static int ppc4xx_of_msi_remove(struct platform_device *dev) | ||
| 191 | { | ||
| 192 | struct ppc4xx_msi *msi = dev->dev.platform_data; | ||
| 193 | int i; | ||
| 194 | int virq; | ||
| 195 | |||
| 196 | for (i = 0; i < NR_MSI_IRQS; i++) { | ||
| 197 | virq = msi->msi_virqs[i]; | ||
| 198 | if (virq != NO_IRQ) | ||
| 199 | irq_dispose_mapping(virq); | ||
| 200 | } | ||
| 201 | |||
| 202 | if (msi->bitmap.bitmap) | ||
| 203 | msi_bitmap_free(&msi->bitmap); | ||
| 204 | iounmap(msi->msi_regs); | ||
| 205 | of_node_put(msi->msi_dev); | ||
| 206 | kfree(msi); | ||
| 207 | |||
| 208 | return 0; | ||
| 209 | } | ||
| 210 | |||
| 211 | static int __devinit ppc4xx_msi_probe(struct platform_device *dev) | ||
| 212 | { | ||
| 213 | struct ppc4xx_msi *msi; | ||
| 214 | struct resource res; | ||
| 215 | int err = 0; | ||
| 216 | |||
| 217 | msi = &ppc4xx_msi;/*keep the msi data for further use*/ | ||
| 218 | |||
| 219 | dev_dbg(&dev->dev, "PCIE-MSI: Setting up MSI support...\n"); | ||
| 220 | |||
| 221 | msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL); | ||
| 222 | if (!msi) { | ||
| 223 | dev_err(&dev->dev, "No memory for MSI structure\n"); | ||
| 224 | return -ENOMEM; | ||
| 225 | } | ||
| 226 | dev->dev.platform_data = msi; | ||
| 227 | |||
| 228 | /* Get MSI ranges */ | ||
| 229 | err = of_address_to_resource(dev->dev.of_node, 0, &res); | ||
| 230 | if (err) { | ||
| 231 | dev_err(&dev->dev, "%s resource error!\n", | ||
| 232 | dev->dev.of_node->full_name); | ||
| 233 | goto error_out; | ||
| 234 | } | ||
| 235 | |||
| 236 | if (ppc4xx_setup_pcieh_hw(dev, res, msi)) | ||
| 237 | goto error_out; | ||
| 238 | |||
| 239 | err = ppc4xx_msi_init_allocator(dev, msi); | ||
| 240 | if (err) { | ||
| 241 | dev_err(&dev->dev, "Error allocating MSI bitmap\n"); | ||
| 242 | goto error_out; | ||
| 243 | } | ||
| 244 | |||
| 245 | ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs; | ||
| 246 | ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs; | ||
| 247 | ppc_md.msi_check_device = ppc4xx_msi_check_device; | ||
| 248 | return err; | ||
| 249 | |||
| 250 | error_out: | ||
| 251 | ppc4xx_of_msi_remove(dev); | ||
| 252 | return err; | ||
| 253 | } | ||
| 254 | static const struct of_device_id ppc4xx_msi_ids[] = { | ||
| 255 | { | ||
| 256 | .compatible = "amcc,ppc4xx-msi", | ||
| 257 | }, | ||
| 258 | {} | ||
| 259 | }; | ||
| 260 | static struct platform_driver ppc4xx_msi_driver = { | ||
| 261 | .probe = ppc4xx_msi_probe, | ||
| 262 | .remove = ppc4xx_of_msi_remove, | ||
| 263 | .driver = { | ||
| 264 | .name = "ppc4xx-msi", | ||
| 265 | .owner = THIS_MODULE, | ||
| 266 | .of_match_table = ppc4xx_msi_ids, | ||
| 267 | }, | ||
| 268 | |||
| 269 | }; | ||
| 270 | |||
| 271 | static __init int ppc4xx_msi_init(void) | ||
| 272 | { | ||
| 273 | return platform_driver_register(&ppc4xx_msi_driver); | ||
| 274 | } | ||
| 275 | |||
| 276 | subsys_initcall(ppc4xx_msi_init); | ||
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.h b/arch/powerpc/sysdev/ppc4xx_pci.h index 56d9e5deccbf..c39a134e8684 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.h +++ b/arch/powerpc/sysdev/ppc4xx_pci.h | |||
| @@ -324,7 +324,7 @@ | |||
| 324 | #define PESDR0_460EX_IHS2 0x036D | 324 | #define PESDR0_460EX_IHS2 0x036D |
| 325 | 325 | ||
| 326 | /* | 326 | /* |
| 327 | * 460SX addtional DCRs | 327 | * 460SX additional DCRs |
| 328 | */ | 328 | */ |
| 329 | #define PESDRn_460SX_RCEI 0x02 | 329 | #define PESDRn_460SX_RCEI 0x02 |
| 330 | 330 | ||
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index 90020de4dcf2..904c6cbaf45b 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c | |||
| @@ -659,8 +659,7 @@ static int qe_resume(struct platform_device *ofdev) | |||
| 659 | return 0; | 659 | return 0; |
| 660 | } | 660 | } |
| 661 | 661 | ||
| 662 | static int qe_probe(struct platform_device *ofdev, | 662 | static int qe_probe(struct platform_device *ofdev) |
| 663 | const struct of_device_id *id) | ||
| 664 | { | 663 | { |
| 665 | return 0; | 664 | return 0; |
| 666 | } | 665 | } |
| @@ -670,7 +669,7 @@ static const struct of_device_id qe_ids[] = { | |||
| 670 | { }, | 669 | { }, |
| 671 | }; | 670 | }; |
| 672 | 671 | ||
| 673 | static struct of_platform_driver qe_driver = { | 672 | static struct platform_driver qe_driver = { |
| 674 | .driver = { | 673 | .driver = { |
| 675 | .name = "fsl-qe", | 674 | .name = "fsl-qe", |
| 676 | .owner = THIS_MODULE, | 675 | .owner = THIS_MODULE, |
| @@ -682,7 +681,7 @@ static struct of_platform_driver qe_driver = { | |||
| 682 | 681 | ||
| 683 | static int __init qe_drv_init(void) | 682 | static int __init qe_drv_init(void) |
| 684 | { | 683 | { |
| 685 | return of_register_platform_driver(&qe_driver); | 684 | return platform_driver_register(&qe_driver); |
| 686 | } | 685 | } |
| 687 | device_initcall(qe_drv_init); | 686 | device_initcall(qe_drv_init); |
| 688 | #endif /* defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) */ | 687 | #endif /* defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) */ |
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 541ba9863647..b2acda07220d 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c | |||
| @@ -189,15 +189,18 @@ static inline void qe_ic_write(volatile __be32 __iomem * base, unsigned int reg | |||
| 189 | 189 | ||
| 190 | static inline struct qe_ic *qe_ic_from_irq(unsigned int virq) | 190 | static inline struct qe_ic *qe_ic_from_irq(unsigned int virq) |
| 191 | { | 191 | { |
| 192 | return irq_to_desc(virq)->chip_data; | 192 | return irq_get_chip_data(virq); |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | #define virq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) | 195 | static inline struct qe_ic *qe_ic_from_irq_data(struct irq_data *d) |
| 196 | { | ||
| 197 | return irq_data_get_irq_chip_data(d); | ||
| 198 | } | ||
| 196 | 199 | ||
| 197 | static void qe_ic_unmask_irq(unsigned int virq) | 200 | static void qe_ic_unmask_irq(struct irq_data *d) |
| 198 | { | 201 | { |
| 199 | struct qe_ic *qe_ic = qe_ic_from_irq(virq); | 202 | struct qe_ic *qe_ic = qe_ic_from_irq_data(d); |
| 200 | unsigned int src = virq_to_hw(virq); | 203 | unsigned int src = irqd_to_hwirq(d); |
| 201 | unsigned long flags; | 204 | unsigned long flags; |
| 202 | u32 temp; | 205 | u32 temp; |
| 203 | 206 | ||
| @@ -210,10 +213,10 @@ static void qe_ic_unmask_irq(unsigned int virq) | |||
| 210 | raw_spin_unlock_irqrestore(&qe_ic_lock, flags); | 213 | raw_spin_unlock_irqrestore(&qe_ic_lock, flags); |
| 211 | } | 214 | } |
| 212 | 215 | ||
| 213 | static void qe_ic_mask_irq(unsigned int virq) | 216 | static void qe_ic_mask_irq(struct irq_data *d) |
| 214 | { | 217 | { |
| 215 | struct qe_ic *qe_ic = qe_ic_from_irq(virq); | 218 | struct qe_ic *qe_ic = qe_ic_from_irq_data(d); |
| 216 | unsigned int src = virq_to_hw(virq); | 219 | unsigned int src = irqd_to_hwirq(d); |
| 217 | unsigned long flags; | 220 | unsigned long flags; |
| 218 | u32 temp; | 221 | u32 temp; |
| 219 | 222 | ||
| @@ -238,9 +241,9 @@ static void qe_ic_mask_irq(unsigned int virq) | |||
| 238 | 241 | ||
| 239 | static struct irq_chip qe_ic_irq_chip = { | 242 | static struct irq_chip qe_ic_irq_chip = { |
| 240 | .name = "QEIC", | 243 | .name = "QEIC", |
| 241 | .unmask = qe_ic_unmask_irq, | 244 | .irq_unmask = qe_ic_unmask_irq, |
| 242 | .mask = qe_ic_mask_irq, | 245 | .irq_mask = qe_ic_mask_irq, |
| 243 | .mask_ack = qe_ic_mask_irq, | 246 | .irq_mask_ack = qe_ic_mask_irq, |
| 244 | }; | 247 | }; |
| 245 | 248 | ||
| 246 | static int qe_ic_host_match(struct irq_host *h, struct device_node *node) | 249 | static int qe_ic_host_match(struct irq_host *h, struct device_node *node) |
| @@ -262,10 +265,10 @@ static int qe_ic_host_map(struct irq_host *h, unsigned int virq, | |||
| 262 | /* Default chip */ | 265 | /* Default chip */ |
| 263 | chip = &qe_ic->hc_irq; | 266 | chip = &qe_ic->hc_irq; |
| 264 | 267 | ||
| 265 | set_irq_chip_data(virq, qe_ic); | 268 | irq_set_chip_data(virq, qe_ic); |
| 266 | irq_to_desc(virq)->status |= IRQ_LEVEL; | 269 | irq_set_status_flags(virq, IRQ_LEVEL); |
| 267 | 270 | ||
| 268 | set_irq_chip_and_handler(virq, chip, handle_level_irq); | 271 | irq_set_chip_and_handler(virq, chip, handle_level_irq); |
| 269 | 272 | ||
| 270 | return 0; | 273 | return 0; |
| 271 | } | 274 | } |
| @@ -381,13 +384,13 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags, | |||
| 381 | 384 | ||
| 382 | qe_ic_write(qe_ic->regs, QEIC_CICR, temp); | 385 | qe_ic_write(qe_ic->regs, QEIC_CICR, temp); |
| 383 | 386 | ||
| 384 | set_irq_data(qe_ic->virq_low, qe_ic); | 387 | irq_set_handler_data(qe_ic->virq_low, qe_ic); |
| 385 | set_irq_chained_handler(qe_ic->virq_low, low_handler); | 388 | irq_set_chained_handler(qe_ic->virq_low, low_handler); |
| 386 | 389 | ||
| 387 | if (qe_ic->virq_high != NO_IRQ && | 390 | if (qe_ic->virq_high != NO_IRQ && |
| 388 | qe_ic->virq_high != qe_ic->virq_low) { | 391 | qe_ic->virq_high != qe_ic->virq_low) { |
| 389 | set_irq_data(qe_ic->virq_high, qe_ic); | 392 | irq_set_handler_data(qe_ic->virq_high, qe_ic); |
| 390 | set_irq_chained_handler(qe_ic->virq_high, high_handler); | 393 | irq_set_chained_handler(qe_ic->virq_high, high_handler); |
| 391 | } | 394 | } |
| 392 | } | 395 | } |
| 393 | 396 | ||
diff --git a/arch/powerpc/sysdev/scom.c b/arch/powerpc/sysdev/scom.c new file mode 100644 index 000000000000..b2593ce30c9b --- /dev/null +++ b/arch/powerpc/sysdev/scom.c | |||
| @@ -0,0 +1,192 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2010 Benjamin Herrenschmidt, IBM Corp | ||
| 3 | * <benh@kernel.crashing.org> | ||
| 4 | * and David Gibson, IBM Corporation. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
| 14 | * the GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/debugfs.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <asm/prom.h> | ||
| 25 | #include <asm/scom.h> | ||
| 26 | |||
| 27 | const struct scom_controller *scom_controller; | ||
| 28 | EXPORT_SYMBOL_GPL(scom_controller); | ||
| 29 | |||
| 30 | struct device_node *scom_find_parent(struct device_node *node) | ||
| 31 | { | ||
| 32 | struct device_node *par, *tmp; | ||
| 33 | const u32 *p; | ||
| 34 | |||
| 35 | for (par = of_node_get(node); par;) { | ||
| 36 | if (of_get_property(par, "scom-controller", NULL)) | ||
| 37 | break; | ||
| 38 | p = of_get_property(par, "scom-parent", NULL); | ||
| 39 | tmp = par; | ||
| 40 | if (p == NULL) | ||
| 41 | par = of_get_parent(par); | ||
| 42 | else | ||
| 43 | par = of_find_node_by_phandle(*p); | ||
| 44 | of_node_put(tmp); | ||
| 45 | } | ||
| 46 | return par; | ||
| 47 | } | ||
| 48 | EXPORT_SYMBOL_GPL(scom_find_parent); | ||
| 49 | |||
| 50 | scom_map_t scom_map_device(struct device_node *dev, int index) | ||
| 51 | { | ||
| 52 | struct device_node *parent; | ||
| 53 | unsigned int cells, size; | ||
| 54 | const u32 *prop; | ||
| 55 | u64 reg, cnt; | ||
| 56 | scom_map_t ret; | ||
| 57 | |||
| 58 | parent = scom_find_parent(dev); | ||
| 59 | |||
| 60 | if (parent == NULL) | ||
| 61 | return 0; | ||
| 62 | |||
| 63 | prop = of_get_property(parent, "#scom-cells", NULL); | ||
| 64 | cells = prop ? *prop : 1; | ||
| 65 | |||
| 66 | prop = of_get_property(dev, "scom-reg", &size); | ||
| 67 | if (!prop) | ||
| 68 | return 0; | ||
| 69 | size >>= 2; | ||
| 70 | |||
| 71 | if (index >= (size / (2*cells))) | ||
| 72 | return 0; | ||
| 73 | |||
| 74 | reg = of_read_number(&prop[index * cells * 2], cells); | ||
| 75 | cnt = of_read_number(&prop[index * cells * 2 + cells], cells); | ||
| 76 | |||
| 77 | ret = scom_map(parent, reg, cnt); | ||
| 78 | of_node_put(parent); | ||
| 79 | |||
| 80 | return ret; | ||
| 81 | } | ||
| 82 | EXPORT_SYMBOL_GPL(scom_map_device); | ||
| 83 | |||
| 84 | #ifdef CONFIG_SCOM_DEBUGFS | ||
| 85 | struct scom_debug_entry { | ||
| 86 | struct device_node *dn; | ||
| 87 | unsigned long addr; | ||
| 88 | scom_map_t map; | ||
| 89 | spinlock_t lock; | ||
| 90 | char name[8]; | ||
| 91 | struct debugfs_blob_wrapper blob; | ||
| 92 | }; | ||
| 93 | |||
| 94 | static int scom_addr_set(void *data, u64 val) | ||
| 95 | { | ||
| 96 | struct scom_debug_entry *ent = data; | ||
| 97 | |||
| 98 | ent->addr = 0; | ||
| 99 | scom_unmap(ent->map); | ||
| 100 | |||
| 101 | ent->map = scom_map(ent->dn, val, 1); | ||
| 102 | if (scom_map_ok(ent->map)) | ||
| 103 | ent->addr = val; | ||
| 104 | else | ||
| 105 | return -EFAULT; | ||
| 106 | |||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | |||
| 110 | static int scom_addr_get(void *data, u64 *val) | ||
| 111 | { | ||
| 112 | struct scom_debug_entry *ent = data; | ||
| 113 | *val = ent->addr; | ||
| 114 | return 0; | ||
| 115 | } | ||
| 116 | DEFINE_SIMPLE_ATTRIBUTE(scom_addr_fops, scom_addr_get, scom_addr_set, | ||
| 117 | "0x%llx\n"); | ||
| 118 | |||
| 119 | static int scom_val_set(void *data, u64 val) | ||
| 120 | { | ||
| 121 | struct scom_debug_entry *ent = data; | ||
| 122 | |||
| 123 | if (!scom_map_ok(ent->map)) | ||
| 124 | return -EFAULT; | ||
| 125 | |||
| 126 | scom_write(ent->map, 0, val); | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int scom_val_get(void *data, u64 *val) | ||
| 132 | { | ||
| 133 | struct scom_debug_entry *ent = data; | ||
| 134 | |||
| 135 | if (!scom_map_ok(ent->map)) | ||
| 136 | return -EFAULT; | ||
| 137 | |||
| 138 | *val = scom_read(ent->map, 0); | ||
| 139 | return 0; | ||
| 140 | } | ||
| 141 | DEFINE_SIMPLE_ATTRIBUTE(scom_val_fops, scom_val_get, scom_val_set, | ||
| 142 | "0x%llx\n"); | ||
| 143 | |||
| 144 | static int scom_debug_init_one(struct dentry *root, struct device_node *dn, | ||
| 145 | int i) | ||
| 146 | { | ||
| 147 | struct scom_debug_entry *ent; | ||
| 148 | struct dentry *dir; | ||
| 149 | |||
| 150 | ent = kzalloc(sizeof(*ent), GFP_KERNEL); | ||
| 151 | if (!ent) | ||
| 152 | return -ENOMEM; | ||
| 153 | |||
| 154 | ent->dn = of_node_get(dn); | ||
| 155 | ent->map = SCOM_MAP_INVALID; | ||
| 156 | spin_lock_init(&ent->lock); | ||
| 157 | snprintf(ent->name, 8, "scom%d", i); | ||
| 158 | ent->blob.data = dn->full_name; | ||
| 159 | ent->blob.size = strlen(dn->full_name); | ||
| 160 | |||
| 161 | dir = debugfs_create_dir(ent->name, root); | ||
| 162 | if (!dir) { | ||
| 163 | of_node_put(dn); | ||
| 164 | kfree(ent); | ||
| 165 | return -1; | ||
| 166 | } | ||
| 167 | |||
| 168 | debugfs_create_file("addr", 0600, dir, ent, &scom_addr_fops); | ||
| 169 | debugfs_create_file("value", 0600, dir, ent, &scom_val_fops); | ||
| 170 | debugfs_create_blob("path", 0400, dir, &ent->blob); | ||
| 171 | |||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | static int scom_debug_init(void) | ||
| 176 | { | ||
| 177 | struct device_node *dn; | ||
| 178 | struct dentry *root; | ||
| 179 | int i, rc; | ||
| 180 | |||
| 181 | root = debugfs_create_dir("scom", powerpc_debugfs_root); | ||
| 182 | if (!root) | ||
| 183 | return -1; | ||
| 184 | |||
| 185 | i = rc = 0; | ||
| 186 | for_each_node_with_property(dn, "scom-controller") | ||
| 187 | rc |= scom_debug_init_one(root, dn, i++); | ||
| 188 | |||
| 189 | return rc; | ||
| 190 | } | ||
| 191 | device_initcall(scom_debug_init); | ||
| 192 | #endif /* CONFIG_SCOM_DEBUGFS */ | ||
diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c index d4d15aaf18fa..ee056807b52c 100644 --- a/arch/powerpc/sysdev/tsi108_dev.c +++ b/arch/powerpc/sysdev/tsi108_dev.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/device.h> | 20 | #include <linux/device.h> |
| 21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
| 22 | #include <linux/of_net.h> | ||
| 22 | #include <asm/tsi108.h> | 23 | #include <asm/tsi108.h> |
| 23 | 24 | ||
| 24 | #include <asm/system.h> | 25 | #include <asm/system.h> |
| @@ -83,8 +84,8 @@ static int __init tsi108_eth_of_init(void) | |||
| 83 | memset(&tsi_eth_data, 0, sizeof(tsi_eth_data)); | 84 | memset(&tsi_eth_data, 0, sizeof(tsi_eth_data)); |
| 84 | 85 | ||
| 85 | ret = of_address_to_resource(np, 0, &r[0]); | 86 | ret = of_address_to_resource(np, 0, &r[0]); |
| 86 | DBG("%s: name:start->end = %s:0x%lx-> 0x%lx\n", | 87 | DBG("%s: name:start->end = %s:%pR\n", |
| 87 | __func__,r[0].name, r[0].start, r[0].end); | 88 | __func__, r[0].name, &r[0]); |
| 88 | if (ret) | 89 | if (ret) |
| 89 | goto err; | 90 | goto err; |
| 90 | 91 | ||
| @@ -92,8 +93,8 @@ static int __init tsi108_eth_of_init(void) | |||
| 92 | r[1].start = irq_of_parse_and_map(np, 0); | 93 | r[1].start = irq_of_parse_and_map(np, 0); |
| 93 | r[1].end = irq_of_parse_and_map(np, 0); | 94 | r[1].end = irq_of_parse_and_map(np, 0); |
| 94 | r[1].flags = IORESOURCE_IRQ; | 95 | r[1].flags = IORESOURCE_IRQ; |
| 95 | DBG("%s: name:start->end = %s:0x%lx-> 0x%lx\n", | 96 | DBG("%s: name:start->end = %s:%pR\n", |
| 96 | __func__,r[1].name, r[1].start, r[1].end); | 97 | __func__, r[1].name, &r[1]); |
| 97 | 98 | ||
| 98 | tsi_eth_dev = | 99 | tsi_eth_dev = |
| 99 | platform_device_register_simple("tsi-ethernet", i++, &r[0], | 100 | platform_device_register_simple("tsi-ethernet", i++, &r[0], |
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 0ab9281e49ae..4d18658116e5 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c | |||
| @@ -343,24 +343,9 @@ static inline unsigned int get_pci_source(void) | |||
| 343 | * Linux descriptor level callbacks | 343 | * Linux descriptor level callbacks |
| 344 | */ | 344 | */ |
| 345 | 345 | ||
| 346 | static void tsi108_pci_irq_enable(u_int irq) | 346 | static void tsi108_pci_irq_unmask(struct irq_data *d) |
| 347 | { | 347 | { |
| 348 | tsi108_pci_int_unmask(irq); | 348 | tsi108_pci_int_unmask(d->irq); |
| 349 | } | ||
| 350 | |||
| 351 | static void tsi108_pci_irq_disable(u_int irq) | ||
| 352 | { | ||
| 353 | tsi108_pci_int_mask(irq); | ||
| 354 | } | ||
| 355 | |||
| 356 | static void tsi108_pci_irq_ack(u_int irq) | ||
| 357 | { | ||
| 358 | tsi108_pci_int_mask(irq); | ||
| 359 | } | ||
| 360 | |||
| 361 | static void tsi108_pci_irq_end(u_int irq) | ||
| 362 | { | ||
| 363 | tsi108_pci_int_unmask(irq); | ||
| 364 | 349 | ||
| 365 | /* Enable interrupts from PCI block */ | 350 | /* Enable interrupts from PCI block */ |
| 366 | tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE, | 351 | tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE, |
| @@ -370,16 +355,25 @@ static void tsi108_pci_irq_end(u_int irq) | |||
| 370 | mb(); | 355 | mb(); |
| 371 | } | 356 | } |
| 372 | 357 | ||
| 358 | static void tsi108_pci_irq_mask(struct irq_data *d) | ||
| 359 | { | ||
| 360 | tsi108_pci_int_mask(d->irq); | ||
| 361 | } | ||
| 362 | |||
| 363 | static void tsi108_pci_irq_ack(struct irq_data *d) | ||
| 364 | { | ||
| 365 | tsi108_pci_int_mask(d->irq); | ||
| 366 | } | ||
| 367 | |||
| 373 | /* | 368 | /* |
| 374 | * Interrupt controller descriptor for cascaded PCI interrupt controller. | 369 | * Interrupt controller descriptor for cascaded PCI interrupt controller. |
| 375 | */ | 370 | */ |
| 376 | 371 | ||
| 377 | static struct irq_chip tsi108_pci_irq = { | 372 | static struct irq_chip tsi108_pci_irq = { |
| 378 | .name = "tsi108_PCI_int", | 373 | .name = "tsi108_PCI_int", |
| 379 | .mask = tsi108_pci_irq_disable, | 374 | .irq_mask = tsi108_pci_irq_mask, |
| 380 | .ack = tsi108_pci_irq_ack, | 375 | .irq_ack = tsi108_pci_irq_ack, |
| 381 | .end = tsi108_pci_irq_end, | 376 | .irq_unmask = tsi108_pci_irq_unmask, |
| 382 | .unmask = tsi108_pci_irq_enable, | ||
| 383 | }; | 377 | }; |
| 384 | 378 | ||
| 385 | static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct, | 379 | static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct, |
| @@ -397,8 +391,8 @@ static int pci_irq_host_map(struct irq_host *h, unsigned int virq, | |||
| 397 | DBG("%s(%d, 0x%lx)\n", __func__, virq, hw); | 391 | DBG("%s(%d, 0x%lx)\n", __func__, virq, hw); |
| 398 | if ((virq >= 1) && (virq <= 4)){ | 392 | if ((virq >= 1) && (virq <= 4)){ |
| 399 | irq = virq + IRQ_PCI_INTAD_BASE - 1; | 393 | irq = virq + IRQ_PCI_INTAD_BASE - 1; |
| 400 | irq_to_desc(irq)->status |= IRQ_LEVEL; | 394 | irq_set_status_flags(irq, IRQ_LEVEL); |
| 401 | set_irq_chip(irq, &tsi108_pci_irq); | 395 | irq_set_chip(irq, &tsi108_pci_irq); |
| 402 | } | 396 | } |
| 403 | return 0; | 397 | return 0; |
| 404 | } | 398 | } |
| @@ -437,8 +431,11 @@ void __init tsi108_pci_int_init(struct device_node *node) | |||
| 437 | 431 | ||
| 438 | void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc) | 432 | void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc) |
| 439 | { | 433 | { |
| 434 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
| 440 | unsigned int cascade_irq = get_pci_source(); | 435 | unsigned int cascade_irq = get_pci_source(); |
| 436 | |||
| 441 | if (cascade_irq != NO_IRQ) | 437 | if (cascade_irq != NO_IRQ) |
| 442 | generic_handle_irq(cascade_irq); | 438 | generic_handle_irq(cascade_irq); |
| 443 | desc->chip->eoi(irq); | 439 | |
| 440 | chip->irq_eoi(&desc->irq_data); | ||
| 444 | } | 441 | } |
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 0038fb78f094..984cd2029158 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c | |||
| @@ -41,8 +41,6 @@ | |||
| 41 | #define UIC_VR 0x7 | 41 | #define UIC_VR 0x7 |
| 42 | #define UIC_VCR 0x8 | 42 | #define UIC_VCR 0x8 |
| 43 | 43 | ||
| 44 | #define uic_irq_to_hw(virq) (irq_map[virq].hwirq) | ||
| 45 | |||
| 46 | struct uic *primary_uic; | 44 | struct uic *primary_uic; |
| 47 | 45 | ||
| 48 | struct uic { | 46 | struct uic { |
| @@ -55,18 +53,17 @@ struct uic { | |||
| 55 | struct irq_host *irqhost; | 53 | struct irq_host *irqhost; |
| 56 | }; | 54 | }; |
| 57 | 55 | ||
| 58 | static void uic_unmask_irq(unsigned int virq) | 56 | static void uic_unmask_irq(struct irq_data *d) |
| 59 | { | 57 | { |
| 60 | struct irq_desc *desc = irq_to_desc(virq); | 58 | struct uic *uic = irq_data_get_irq_chip_data(d); |
| 61 | struct uic *uic = get_irq_chip_data(virq); | 59 | unsigned int src = irqd_to_hwirq(d); |
| 62 | unsigned int src = uic_irq_to_hw(virq); | ||
| 63 | unsigned long flags; | 60 | unsigned long flags; |
| 64 | u32 er, sr; | 61 | u32 er, sr; |
| 65 | 62 | ||
| 66 | sr = 1 << (31-src); | 63 | sr = 1 << (31-src); |
| 67 | spin_lock_irqsave(&uic->lock, flags); | 64 | spin_lock_irqsave(&uic->lock, flags); |
| 68 | /* ack level-triggered interrupts here */ | 65 | /* ack level-triggered interrupts here */ |
| 69 | if (desc->status & IRQ_LEVEL) | 66 | if (irqd_is_level_type(d)) |
| 70 | mtdcr(uic->dcrbase + UIC_SR, sr); | 67 | mtdcr(uic->dcrbase + UIC_SR, sr); |
| 71 | er = mfdcr(uic->dcrbase + UIC_ER); | 68 | er = mfdcr(uic->dcrbase + UIC_ER); |
| 72 | er |= sr; | 69 | er |= sr; |
| @@ -74,10 +71,10 @@ static void uic_unmask_irq(unsigned int virq) | |||
| 74 | spin_unlock_irqrestore(&uic->lock, flags); | 71 | spin_unlock_irqrestore(&uic->lock, flags); |
| 75 | } | 72 | } |
| 76 | 73 | ||
| 77 | static void uic_mask_irq(unsigned int virq) | 74 | static void uic_mask_irq(struct irq_data *d) |
| 78 | { | 75 | { |
| 79 | struct uic *uic = get_irq_chip_data(virq); | 76 | struct uic *uic = irq_data_get_irq_chip_data(d); |
| 80 | unsigned int src = uic_irq_to_hw(virq); | 77 | unsigned int src = irqd_to_hwirq(d); |
| 81 | unsigned long flags; | 78 | unsigned long flags; |
| 82 | u32 er; | 79 | u32 er; |
| 83 | 80 | ||
| @@ -88,10 +85,10 @@ static void uic_mask_irq(unsigned int virq) | |||
| 88 | spin_unlock_irqrestore(&uic->lock, flags); | 85 | spin_unlock_irqrestore(&uic->lock, flags); |
| 89 | } | 86 | } |
| 90 | 87 | ||
| 91 | static void uic_ack_irq(unsigned int virq) | 88 | static void uic_ack_irq(struct irq_data *d) |
| 92 | { | 89 | { |
| 93 | struct uic *uic = get_irq_chip_data(virq); | 90 | struct uic *uic = irq_data_get_irq_chip_data(d); |
| 94 | unsigned int src = uic_irq_to_hw(virq); | 91 | unsigned int src = irqd_to_hwirq(d); |
| 95 | unsigned long flags; | 92 | unsigned long flags; |
| 96 | 93 | ||
| 97 | spin_lock_irqsave(&uic->lock, flags); | 94 | spin_lock_irqsave(&uic->lock, flags); |
| @@ -99,11 +96,10 @@ static void uic_ack_irq(unsigned int virq) | |||
| 99 | spin_unlock_irqrestore(&uic->lock, flags); | 96 | spin_unlock_irqrestore(&uic->lock, flags); |
| 100 | } | 97 | } |
| 101 | 98 | ||
| 102 | static void uic_mask_ack_irq(unsigned int virq) | 99 | static void uic_mask_ack_irq(struct irq_data *d) |
| 103 | { | 100 | { |
| 104 | struct irq_desc *desc = irq_to_desc(virq); | 101 | struct uic *uic = irq_data_get_irq_chip_data(d); |
| 105 | struct uic *uic = get_irq_chip_data(virq); | 102 | unsigned int src = irqd_to_hwirq(d); |
| 106 | unsigned int src = uic_irq_to_hw(virq); | ||
| 107 | unsigned long flags; | 103 | unsigned long flags; |
| 108 | u32 er, sr; | 104 | u32 er, sr; |
| 109 | 105 | ||
| @@ -120,23 +116,22 @@ static void uic_mask_ack_irq(unsigned int virq) | |||
| 120 | * level interrupts are ack'ed after the actual | 116 | * level interrupts are ack'ed after the actual |
| 121 | * isr call in the uic_unmask_irq() | 117 | * isr call in the uic_unmask_irq() |
| 122 | */ | 118 | */ |
| 123 | if (!(desc->status & IRQ_LEVEL)) | 119 | if (!irqd_is_level_type(d)) |
| 124 | mtdcr(uic->dcrbase + UIC_SR, sr); | 120 | mtdcr(uic->dcrbase + UIC_SR, sr); |
| 125 | spin_unlock_irqrestore(&uic->lock, flags); | 121 | spin_unlock_irqrestore(&uic->lock, flags); |
| 126 | } | 122 | } |
| 127 | 123 | ||
| 128 | static int uic_set_irq_type(unsigned int virq, unsigned int flow_type) | 124 | static int uic_set_irq_type(struct irq_data *d, unsigned int flow_type) |
| 129 | { | 125 | { |
| 130 | struct uic *uic = get_irq_chip_data(virq); | 126 | struct uic *uic = irq_data_get_irq_chip_data(d); |
| 131 | unsigned int src = uic_irq_to_hw(virq); | 127 | unsigned int src = irqd_to_hwirq(d); |
| 132 | struct irq_desc *desc = irq_to_desc(virq); | ||
| 133 | unsigned long flags; | 128 | unsigned long flags; |
| 134 | int trigger, polarity; | 129 | int trigger, polarity; |
| 135 | u32 tr, pr, mask; | 130 | u32 tr, pr, mask; |
| 136 | 131 | ||
| 137 | switch (flow_type & IRQ_TYPE_SENSE_MASK) { | 132 | switch (flow_type & IRQ_TYPE_SENSE_MASK) { |
| 138 | case IRQ_TYPE_NONE: | 133 | case IRQ_TYPE_NONE: |
| 139 | uic_mask_irq(virq); | 134 | uic_mask_irq(d); |
| 140 | return 0; | 135 | return 0; |
| 141 | 136 | ||
| 142 | case IRQ_TYPE_EDGE_RISING: | 137 | case IRQ_TYPE_EDGE_RISING: |
| @@ -166,11 +161,6 @@ static int uic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
| 166 | mtdcr(uic->dcrbase + UIC_PR, pr); | 161 | mtdcr(uic->dcrbase + UIC_PR, pr); |
| 167 | mtdcr(uic->dcrbase + UIC_TR, tr); | 162 | mtdcr(uic->dcrbase + UIC_TR, tr); |
| 168 | 163 | ||
| 169 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); | ||
| 170 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; | ||
| 171 | if (!trigger) | ||
| 172 | desc->status |= IRQ_LEVEL; | ||
| 173 | |||
| 174 | spin_unlock_irqrestore(&uic->lock, flags); | 164 | spin_unlock_irqrestore(&uic->lock, flags); |
| 175 | 165 | ||
| 176 | return 0; | 166 | return 0; |
| @@ -178,11 +168,11 @@ static int uic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
| 178 | 168 | ||
| 179 | static struct irq_chip uic_irq_chip = { | 169 | static struct irq_chip uic_irq_chip = { |
| 180 | .name = "UIC", | 170 | .name = "UIC", |
| 181 | .unmask = uic_unmask_irq, | 171 | .irq_unmask = uic_unmask_irq, |
| 182 | .mask = uic_mask_irq, | 172 | .irq_mask = uic_mask_irq, |
| 183 | .mask_ack = uic_mask_ack_irq, | 173 | .irq_mask_ack = uic_mask_ack_irq, |
| 184 | .ack = uic_ack_irq, | 174 | .irq_ack = uic_ack_irq, |
| 185 | .set_type = uic_set_irq_type, | 175 | .irq_set_type = uic_set_irq_type, |
| 186 | }; | 176 | }; |
| 187 | 177 | ||
| 188 | static int uic_host_map(struct irq_host *h, unsigned int virq, | 178 | static int uic_host_map(struct irq_host *h, unsigned int virq, |
| @@ -190,13 +180,13 @@ static int uic_host_map(struct irq_host *h, unsigned int virq, | |||
| 190 | { | 180 | { |
| 191 | struct uic *uic = h->host_data; | 181 | struct uic *uic = h->host_data; |
| 192 | 182 | ||
| 193 | set_irq_chip_data(virq, uic); | 183 | irq_set_chip_data(virq, uic); |
| 194 | /* Despite the name, handle_level_irq() works for both level | 184 | /* Despite the name, handle_level_irq() works for both level |
| 195 | * and edge irqs on UIC. FIXME: check this is correct */ | 185 | * and edge irqs on UIC. FIXME: check this is correct */ |
| 196 | set_irq_chip_and_handler(virq, &uic_irq_chip, handle_level_irq); | 186 | irq_set_chip_and_handler(virq, &uic_irq_chip, handle_level_irq); |
| 197 | 187 | ||
| 198 | /* Set default irq type */ | 188 | /* Set default irq type */ |
| 199 | set_irq_type(virq, IRQ_TYPE_NONE); | 189 | irq_set_irq_type(virq, IRQ_TYPE_NONE); |
| 200 | 190 | ||
| 201 | return 0; | 191 | return 0; |
| 202 | } | 192 | } |
| @@ -220,16 +210,18 @@ static struct irq_host_ops uic_host_ops = { | |||
| 220 | 210 | ||
| 221 | void uic_irq_cascade(unsigned int virq, struct irq_desc *desc) | 211 | void uic_irq_cascade(unsigned int virq, struct irq_desc *desc) |
| 222 | { | 212 | { |
| 223 | struct uic *uic = get_irq_data(virq); | 213 | struct irq_chip *chip = irq_desc_get_chip(desc); |
| 214 | struct irq_data *idata = irq_desc_get_irq_data(desc); | ||
| 215 | struct uic *uic = irq_get_handler_data(virq); | ||
| 224 | u32 msr; | 216 | u32 msr; |
| 225 | int src; | 217 | int src; |
| 226 | int subvirq; | 218 | int subvirq; |
| 227 | 219 | ||
| 228 | raw_spin_lock(&desc->lock); | 220 | raw_spin_lock(&desc->lock); |
| 229 | if (desc->status & IRQ_LEVEL) | 221 | if (irqd_is_level_type(idata)) |
| 230 | desc->chip->mask(virq); | 222 | chip->irq_mask(idata); |
| 231 | else | 223 | else |
| 232 | desc->chip->mask_ack(virq); | 224 | chip->irq_mask_ack(idata); |
| 233 | raw_spin_unlock(&desc->lock); | 225 | raw_spin_unlock(&desc->lock); |
| 234 | 226 | ||
| 235 | msr = mfdcr(uic->dcrbase + UIC_MSR); | 227 | msr = mfdcr(uic->dcrbase + UIC_MSR); |
| @@ -243,10 +235,10 @@ void uic_irq_cascade(unsigned int virq, struct irq_desc *desc) | |||
| 243 | 235 | ||
| 244 | uic_irq_ret: | 236 | uic_irq_ret: |
| 245 | raw_spin_lock(&desc->lock); | 237 | raw_spin_lock(&desc->lock); |
| 246 | if (desc->status & IRQ_LEVEL) | 238 | if (irqd_is_level_type(idata)) |
| 247 | desc->chip->ack(virq); | 239 | chip->irq_ack(idata); |
| 248 | if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) | 240 | if (!irqd_irq_disabled(idata) && chip->irq_unmask) |
| 249 | desc->chip->unmask(virq); | 241 | chip->irq_unmask(idata); |
| 250 | raw_spin_unlock(&desc->lock); | 242 | raw_spin_unlock(&desc->lock); |
| 251 | } | 243 | } |
| 252 | 244 | ||
| @@ -335,8 +327,8 @@ void __init uic_init_tree(void) | |||
| 335 | 327 | ||
| 336 | cascade_virq = irq_of_parse_and_map(np, 0); | 328 | cascade_virq = irq_of_parse_and_map(np, 0); |
| 337 | 329 | ||
| 338 | set_irq_data(cascade_virq, uic); | 330 | irq_set_handler_data(cascade_virq, uic); |
| 339 | set_irq_chained_handler(cascade_virq, uic_irq_cascade); | 331 | irq_set_chained_handler(cascade_virq, uic_irq_cascade); |
| 340 | 332 | ||
| 341 | /* FIXME: setup critical cascade?? */ | 333 | /* FIXME: setup critical cascade?? */ |
| 342 | } | 334 | } |
diff --git a/arch/powerpc/sysdev/xics/Kconfig b/arch/powerpc/sysdev/xics/Kconfig new file mode 100644 index 000000000000..0031eda320c3 --- /dev/null +++ b/arch/powerpc/sysdev/xics/Kconfig | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | config PPC_XICS | ||
| 2 | def_bool n | ||
| 3 | select PPC_SMP_MUXED_IPI | ||
| 4 | |||
| 5 | config PPC_ICP_NATIVE | ||
| 6 | def_bool n | ||
| 7 | |||
| 8 | config PPC_ICP_HV | ||
| 9 | def_bool n | ||
| 10 | |||
| 11 | config PPC_ICS_RTAS | ||
| 12 | def_bool n | ||
| 13 | |||
diff --git a/arch/powerpc/sysdev/xics/Makefile b/arch/powerpc/sysdev/xics/Makefile new file mode 100644 index 000000000000..b75a6059337f --- /dev/null +++ b/arch/powerpc/sysdev/xics/Makefile | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror | ||
| 2 | |||
| 3 | obj-y += xics-common.o | ||
| 4 | obj-$(CONFIG_PPC_ICP_NATIVE) += icp-native.o | ||
| 5 | obj-$(CONFIG_PPC_ICP_HV) += icp-hv.o | ||
| 6 | obj-$(CONFIG_PPC_ICS_RTAS) += ics-rtas.o | ||
diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c new file mode 100644 index 000000000000..9518d367a64f --- /dev/null +++ b/arch/powerpc/sysdev/xics/icp-hv.c | |||
| @@ -0,0 +1,164 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2011 IBM Corporation. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | #include <linux/types.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/irq.h> | ||
| 13 | #include <linux/smp.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/cpu.h> | ||
| 17 | #include <linux/of.h> | ||
| 18 | |||
| 19 | #include <asm/smp.h> | ||
| 20 | #include <asm/irq.h> | ||
| 21 | #include <asm/errno.h> | ||
| 22 | #include <asm/xics.h> | ||
| 23 | #include <asm/io.h> | ||
| 24 | #include <asm/hvcall.h> | ||
| 25 | |||
| 26 | static inline unsigned int icp_hv_get_xirr(unsigned char cppr) | ||
| 27 | { | ||
| 28 | unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; | ||
| 29 | long rc; | ||
| 30 | |||
| 31 | rc = plpar_hcall(H_XIRR, retbuf, cppr); | ||
| 32 | if (rc != H_SUCCESS) | ||
| 33 | panic(" bad return code xirr - rc = %lx\n", rc); | ||
| 34 | return (unsigned int)retbuf[0]; | ||
| 35 | } | ||
| 36 | |||
| 37 | static inline void icp_hv_set_xirr(unsigned int value) | ||
| 38 | { | ||
| 39 | long rc = plpar_hcall_norets(H_EOI, value); | ||
| 40 | if (rc != H_SUCCESS) | ||
| 41 | panic("bad return code EOI - rc = %ld, value=%x\n", rc, value); | ||
| 42 | } | ||
| 43 | |||
| 44 | static inline void icp_hv_set_cppr(u8 value) | ||
| 45 | { | ||
| 46 | long rc = plpar_hcall_norets(H_CPPR, value); | ||
| 47 | if (rc != H_SUCCESS) | ||
| 48 | panic("bad return code cppr - rc = %lx\n", rc); | ||
| 49 | } | ||
| 50 | |||
| 51 | static inline void icp_hv_set_qirr(int n_cpu , u8 value) | ||
| 52 | { | ||
| 53 | long rc = plpar_hcall_norets(H_IPI, get_hard_smp_processor_id(n_cpu), | ||
| 54 | value); | ||
| 55 | if (rc != H_SUCCESS) | ||
| 56 | panic("bad return code qirr - rc = %lx\n", rc); | ||
| 57 | } | ||
| 58 | |||
| 59 | static void icp_hv_eoi(struct irq_data *d) | ||
| 60 | { | ||
| 61 | unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); | ||
| 62 | |||
| 63 | iosync(); | ||
| 64 | icp_hv_set_xirr((xics_pop_cppr() << 24) | hw_irq); | ||
| 65 | } | ||
| 66 | |||
| 67 | static void icp_hv_teardown_cpu(void) | ||
| 68 | { | ||
| 69 | int cpu = smp_processor_id(); | ||
| 70 | |||
| 71 | /* Clear any pending IPI */ | ||
| 72 | icp_hv_set_qirr(cpu, 0xff); | ||
| 73 | } | ||
| 74 | |||
| 75 | static void icp_hv_flush_ipi(void) | ||
| 76 | { | ||
| 77 | /* We take the ipi irq but and never return so we | ||
| 78 | * need to EOI the IPI, but want to leave our priority 0 | ||
| 79 | * | ||
| 80 | * should we check all the other interrupts too? | ||
| 81 | * should we be flagging idle loop instead? | ||
| 82 | * or creating some task to be scheduled? | ||
| 83 | */ | ||
| 84 | |||
| 85 | icp_hv_set_xirr((0x00 << 24) | XICS_IPI); | ||
| 86 | } | ||
| 87 | |||
| 88 | static unsigned int icp_hv_get_irq(void) | ||
| 89 | { | ||
| 90 | unsigned int xirr = icp_hv_get_xirr(xics_cppr_top()); | ||
| 91 | unsigned int vec = xirr & 0x00ffffff; | ||
| 92 | unsigned int irq; | ||
| 93 | |||
| 94 | if (vec == XICS_IRQ_SPURIOUS) | ||
| 95 | return NO_IRQ; | ||
| 96 | |||
| 97 | irq = irq_radix_revmap_lookup(xics_host, vec); | ||
| 98 | if (likely(irq != NO_IRQ)) { | ||
| 99 | xics_push_cppr(vec); | ||
| 100 | return irq; | ||
| 101 | } | ||
| 102 | |||
| 103 | /* We don't have a linux mapping, so have rtas mask it. */ | ||
| 104 | xics_mask_unknown_vec(vec); | ||
| 105 | |||
| 106 | /* We might learn about it later, so EOI it */ | ||
| 107 | icp_hv_set_xirr(xirr); | ||
| 108 | |||
| 109 | return NO_IRQ; | ||
| 110 | } | ||
| 111 | |||
| 112 | static void icp_hv_set_cpu_priority(unsigned char cppr) | ||
| 113 | { | ||
| 114 | xics_set_base_cppr(cppr); | ||
| 115 | icp_hv_set_cppr(cppr); | ||
| 116 | iosync(); | ||
| 117 | } | ||
| 118 | |||
| 119 | #ifdef CONFIG_SMP | ||
| 120 | |||
| 121 | static void icp_hv_cause_ipi(int cpu, unsigned long data) | ||
| 122 | { | ||
| 123 | icp_hv_set_qirr(cpu, IPI_PRIORITY); | ||
| 124 | } | ||
| 125 | |||
| 126 | static irqreturn_t icp_hv_ipi_action(int irq, void *dev_id) | ||
| 127 | { | ||
| 128 | int cpu = smp_processor_id(); | ||
| 129 | |||
| 130 | icp_hv_set_qirr(cpu, 0xff); | ||
| 131 | |||
| 132 | return smp_ipi_demux(); | ||
| 133 | } | ||
| 134 | |||
| 135 | #endif /* CONFIG_SMP */ | ||
| 136 | |||
| 137 | static const struct icp_ops icp_hv_ops = { | ||
| 138 | .get_irq = icp_hv_get_irq, | ||
| 139 | .eoi = icp_hv_eoi, | ||
| 140 | .set_priority = icp_hv_set_cpu_priority, | ||
| 141 | .teardown_cpu = icp_hv_teardown_cpu, | ||
| 142 | .flush_ipi = icp_hv_flush_ipi, | ||
| 143 | #ifdef CONFIG_SMP | ||
| 144 | .ipi_action = icp_hv_ipi_action, | ||
| 145 | .cause_ipi = icp_hv_cause_ipi, | ||
| 146 | #endif | ||
| 147 | }; | ||
| 148 | |||
| 149 | int icp_hv_init(void) | ||
| 150 | { | ||
| 151 | struct device_node *np; | ||
| 152 | |||
| 153 | np = of_find_compatible_node(NULL, NULL, "ibm,ppc-xicp"); | ||
| 154 | if (!np) | ||
| 155 | np = of_find_node_by_type(NULL, | ||
| 156 | "PowerPC-External-Interrupt-Presentation"); | ||
| 157 | if (!np) | ||
| 158 | return -ENODEV; | ||
| 159 | |||
| 160 | icp_ops = &icp_hv_ops; | ||
| 161 | |||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | |||
diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c new file mode 100644 index 000000000000..1f15ad436140 --- /dev/null +++ b/arch/powerpc/sysdev/xics/icp-native.c | |||
| @@ -0,0 +1,293 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2011 IBM Corporation. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/types.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/irq.h> | ||
| 14 | #include <linux/smp.h> | ||
| 15 | #include <linux/interrupt.h> | ||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/cpu.h> | ||
| 18 | #include <linux/of.h> | ||
| 19 | #include <linux/spinlock.h> | ||
| 20 | |||
| 21 | #include <asm/prom.h> | ||
| 22 | #include <asm/io.h> | ||
| 23 | #include <asm/smp.h> | ||
| 24 | #include <asm/irq.h> | ||
| 25 | #include <asm/errno.h> | ||
| 26 | #include <asm/xics.h> | ||
| 27 | |||
| 28 | struct icp_ipl { | ||
| 29 | union { | ||
| 30 | u32 word; | ||
| 31 | u8 bytes[4]; | ||
| 32 | } xirr_poll; | ||
| 33 | union { | ||
| 34 | u32 word; | ||
| 35 | u8 bytes[4]; | ||
| 36 | } xirr; | ||
| 37 | u32 dummy; | ||
| 38 | union { | ||
| 39 | u32 word; | ||
| 40 | u8 bytes[4]; | ||
| 41 | } qirr; | ||
| 42 | u32 link_a; | ||
| 43 | u32 link_b; | ||
| 44 | u32 link_c; | ||
| 45 | }; | ||
| 46 | |||
| 47 | static struct icp_ipl __iomem *icp_native_regs[NR_CPUS]; | ||
| 48 | |||
| 49 | static inline unsigned int icp_native_get_xirr(void) | ||
| 50 | { | ||
| 51 | int cpu = smp_processor_id(); | ||
| 52 | |||
| 53 | return in_be32(&icp_native_regs[cpu]->xirr.word); | ||
| 54 | } | ||
| 55 | |||
| 56 | static inline void icp_native_set_xirr(unsigned int value) | ||
| 57 | { | ||
| 58 | int cpu = smp_processor_id(); | ||
| 59 | |||
| 60 | out_be32(&icp_native_regs[cpu]->xirr.word, value); | ||
| 61 | } | ||
| 62 | |||
| 63 | static inline void icp_native_set_cppr(u8 value) | ||
| 64 | { | ||
| 65 | int cpu = smp_processor_id(); | ||
| 66 | |||
| 67 | out_8(&icp_native_regs[cpu]->xirr.bytes[0], value); | ||
| 68 | } | ||
| 69 | |||
| 70 | static inline void icp_native_set_qirr(int n_cpu, u8 value) | ||
| 71 | { | ||
| 72 | out_8(&icp_native_regs[n_cpu]->qirr.bytes[0], value); | ||
| 73 | } | ||
| 74 | |||
| 75 | static void icp_native_set_cpu_priority(unsigned char cppr) | ||
| 76 | { | ||
| 77 | xics_set_base_cppr(cppr); | ||
| 78 | icp_native_set_cppr(cppr); | ||
| 79 | iosync(); | ||
| 80 | } | ||
| 81 | |||
| 82 | static void icp_native_eoi(struct irq_data *d) | ||
| 83 | { | ||
| 84 | unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); | ||
| 85 | |||
| 86 | iosync(); | ||
| 87 | icp_native_set_xirr((xics_pop_cppr() << 24) | hw_irq); | ||
| 88 | } | ||
| 89 | |||
| 90 | static void icp_native_teardown_cpu(void) | ||
| 91 | { | ||
| 92 | int cpu = smp_processor_id(); | ||
| 93 | |||
| 94 | /* Clear any pending IPI */ | ||
| 95 | icp_native_set_qirr(cpu, 0xff); | ||
| 96 | } | ||
| 97 | |||
| 98 | static void icp_native_flush_ipi(void) | ||
| 99 | { | ||
| 100 | /* We take the ipi irq but and never return so we | ||
| 101 | * need to EOI the IPI, but want to leave our priority 0 | ||
| 102 | * | ||
| 103 | * should we check all the other interrupts too? | ||
| 104 | * should we be flagging idle loop instead? | ||
| 105 | * or creating some task to be scheduled? | ||
| 106 | */ | ||
| 107 | |||
| 108 | icp_native_set_xirr((0x00 << 24) | XICS_IPI); | ||
| 109 | } | ||
| 110 | |||
| 111 | static unsigned int icp_native_get_irq(void) | ||
| 112 | { | ||
| 113 | unsigned int xirr = icp_native_get_xirr(); | ||
| 114 | unsigned int vec = xirr & 0x00ffffff; | ||
| 115 | unsigned int irq; | ||
| 116 | |||
| 117 | if (vec == XICS_IRQ_SPURIOUS) | ||
| 118 | return NO_IRQ; | ||
| 119 | |||
| 120 | irq = irq_radix_revmap_lookup(xics_host, vec); | ||
| 121 | if (likely(irq != NO_IRQ)) { | ||
| 122 | xics_push_cppr(vec); | ||
| 123 | return irq; | ||
| 124 | } | ||
| 125 | |||
| 126 | /* We don't have a linux mapping, so have rtas mask it. */ | ||
| 127 | xics_mask_unknown_vec(vec); | ||
| 128 | |||
| 129 | /* We might learn about it later, so EOI it */ | ||
| 130 | icp_native_set_xirr(xirr); | ||
| 131 | |||
| 132 | return NO_IRQ; | ||
| 133 | } | ||
| 134 | |||
| 135 | #ifdef CONFIG_SMP | ||
| 136 | |||
| 137 | static void icp_native_cause_ipi(int cpu, unsigned long data) | ||
| 138 | { | ||
| 139 | icp_native_set_qirr(cpu, IPI_PRIORITY); | ||
| 140 | } | ||
| 141 | |||
| 142 | static irqreturn_t icp_native_ipi_action(int irq, void *dev_id) | ||
| 143 | { | ||
| 144 | int cpu = smp_processor_id(); | ||
| 145 | |||
| 146 | icp_native_set_qirr(cpu, 0xff); | ||
| 147 | |||
| 148 | return smp_ipi_demux(); | ||
| 149 | } | ||
| 150 | |||
| 151 | #endif /* CONFIG_SMP */ | ||
| 152 | |||
| 153 | static int __init icp_native_map_one_cpu(int hw_id, unsigned long addr, | ||
| 154 | unsigned long size) | ||
| 155 | { | ||
| 156 | char *rname; | ||
| 157 | int i, cpu = -1; | ||
| 158 | |||
| 159 | /* This may look gross but it's good enough for now, we don't quite | ||
| 160 | * have a hard -> linux processor id matching. | ||
| 161 | */ | ||
| 162 | for_each_possible_cpu(i) { | ||
| 163 | if (!cpu_present(i)) | ||
| 164 | continue; | ||
| 165 | if (hw_id == get_hard_smp_processor_id(i)) { | ||
| 166 | cpu = i; | ||
| 167 | break; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | /* Fail, skip that CPU. Don't print, it's normal, some XICS come up | ||
| 172 | * with way more entries in there than you have CPUs | ||
| 173 | */ | ||
| 174 | if (cpu == -1) | ||
| 175 | return 0; | ||
| 176 | |||
| 177 | rname = kasprintf(GFP_KERNEL, "CPU %d [0x%x] Interrupt Presentation", | ||
| 178 | cpu, hw_id); | ||
| 179 | |||
| 180 | if (!request_mem_region(addr, size, rname)) { | ||
| 181 | pr_warning("icp_native: Could not reserve ICP MMIO" | ||
| 182 | " for CPU %d, interrupt server #0x%x\n", | ||
| 183 | cpu, hw_id); | ||
| 184 | return -EBUSY; | ||
| 185 | } | ||
| 186 | |||
| 187 | icp_native_regs[cpu] = ioremap(addr, size); | ||
| 188 | if (!icp_native_regs[cpu]) { | ||
| 189 | pr_warning("icp_native: Failed ioremap for CPU %d, " | ||
| 190 | "interrupt server #0x%x, addr %#lx\n", | ||
| 191 | cpu, hw_id, addr); | ||
| 192 | release_mem_region(addr, size); | ||
| 193 | return -ENOMEM; | ||
| 194 | } | ||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | static int __init icp_native_init_one_node(struct device_node *np, | ||
| 199 | unsigned int *indx) | ||
| 200 | { | ||
| 201 | unsigned int ilen; | ||
| 202 | const u32 *ireg; | ||
| 203 | int i; | ||
| 204 | int reg_tuple_size; | ||
| 205 | int num_servers = 0; | ||
| 206 | |||
| 207 | /* This code does the theorically broken assumption that the interrupt | ||
| 208 | * server numbers are the same as the hard CPU numbers. | ||
| 209 | * This happens to be the case so far but we are playing with fire... | ||
| 210 | * should be fixed one of these days. -BenH. | ||
| 211 | */ | ||
| 212 | ireg = of_get_property(np, "ibm,interrupt-server-ranges", &ilen); | ||
| 213 | |||
| 214 | /* Do that ever happen ? we'll know soon enough... but even good'old | ||
| 215 | * f80 does have that property .. | ||
| 216 | */ | ||
| 217 | WARN_ON((ireg == NULL) || (ilen != 2*sizeof(u32))); | ||
| 218 | |||
| 219 | if (ireg) { | ||
| 220 | *indx = of_read_number(ireg, 1); | ||
| 221 | if (ilen >= 2*sizeof(u32)) | ||
| 222 | num_servers = of_read_number(ireg + 1, 1); | ||
| 223 | } | ||
| 224 | |||
| 225 | ireg = of_get_property(np, "reg", &ilen); | ||
| 226 | if (!ireg) { | ||
| 227 | pr_err("icp_native: Can't find interrupt reg property"); | ||
| 228 | return -1; | ||
| 229 | } | ||
| 230 | |||
| 231 | reg_tuple_size = (of_n_addr_cells(np) + of_n_size_cells(np)) * 4; | ||
| 232 | if (((ilen % reg_tuple_size) != 0) | ||
| 233 | || (num_servers && (num_servers != (ilen / reg_tuple_size)))) { | ||
| 234 | pr_err("icp_native: ICP reg len (%d) != num servers (%d)", | ||
| 235 | ilen / reg_tuple_size, num_servers); | ||
| 236 | return -1; | ||
| 237 | } | ||
| 238 | |||
| 239 | for (i = 0; i < (ilen / reg_tuple_size); i++) { | ||
| 240 | struct resource r; | ||
| 241 | int err; | ||
| 242 | |||
| 243 | err = of_address_to_resource(np, i, &r); | ||
| 244 | if (err) { | ||
| 245 | pr_err("icp_native: Could not translate ICP MMIO" | ||
| 246 | " for interrupt server 0x%x (%d)\n", *indx, err); | ||
| 247 | return -1; | ||
| 248 | } | ||
| 249 | |||
| 250 | if (icp_native_map_one_cpu(*indx, r.start, r.end - r.start)) | ||
| 251 | return -1; | ||
| 252 | |||
| 253 | (*indx)++; | ||
| 254 | } | ||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | |||
| 258 | static const struct icp_ops icp_native_ops = { | ||
| 259 | .get_irq = icp_native_get_irq, | ||
| 260 | .eoi = icp_native_eoi, | ||
| 261 | .set_priority = icp_native_set_cpu_priority, | ||
| 262 | .teardown_cpu = icp_native_teardown_cpu, | ||
| 263 | .flush_ipi = icp_native_flush_ipi, | ||
| 264 | #ifdef CONFIG_SMP | ||
| 265 | .ipi_action = icp_native_ipi_action, | ||
| 266 | .cause_ipi = icp_native_cause_ipi, | ||
| 267 | #endif | ||
| 268 | }; | ||
| 269 | |||
| 270 | int icp_native_init(void) | ||
| 271 | { | ||
| 272 | struct device_node *np; | ||
| 273 | u32 indx = 0; | ||
| 274 | int found = 0; | ||
| 275 | |||
| 276 | for_each_compatible_node(np, NULL, "ibm,ppc-xicp") | ||
| 277 | if (icp_native_init_one_node(np, &indx) == 0) | ||
| 278 | found = 1; | ||
| 279 | if (!found) { | ||
| 280 | for_each_node_by_type(np, | ||
| 281 | "PowerPC-External-Interrupt-Presentation") { | ||
| 282 | if (icp_native_init_one_node(np, &indx) == 0) | ||
| 283 | found = 1; | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | if (found == 0) | ||
| 288 | return -ENODEV; | ||
| 289 | |||
| 290 | icp_ops = &icp_native_ops; | ||
| 291 | |||
| 292 | return 0; | ||
| 293 | } | ||
diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c new file mode 100644 index 000000000000..c782f85cf7e4 --- /dev/null +++ b/arch/powerpc/sysdev/xics/ics-rtas.c | |||
| @@ -0,0 +1,240 @@ | |||
| 1 | #include <linux/types.h> | ||
| 2 | #include <linux/kernel.h> | ||
| 3 | #include <linux/irq.h> | ||
| 4 | #include <linux/smp.h> | ||
| 5 | #include <linux/interrupt.h> | ||
| 6 | #include <linux/init.h> | ||
| 7 | #include <linux/cpu.h> | ||
| 8 | #include <linux/of.h> | ||
| 9 | #include <linux/spinlock.h> | ||
| 10 | #include <linux/msi.h> | ||
| 11 | |||
| 12 | #include <asm/prom.h> | ||
| 13 | #include <asm/smp.h> | ||
| 14 | #include <asm/machdep.h> | ||
| 15 | #include <asm/irq.h> | ||
| 16 | #include <asm/errno.h> | ||
| 17 | #include <asm/xics.h> | ||
| 18 | #include <asm/rtas.h> | ||
| 19 | |||
| 20 | /* RTAS service tokens */ | ||
| 21 | static int ibm_get_xive; | ||
| 22 | static int ibm_set_xive; | ||
| 23 | static int ibm_int_on; | ||
| 24 | static int ibm_int_off; | ||
| 25 | |||
| 26 | static int ics_rtas_map(struct ics *ics, unsigned int virq); | ||
| 27 | static void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec); | ||
| 28 | static long ics_rtas_get_server(struct ics *ics, unsigned long vec); | ||
| 29 | static int ics_rtas_host_match(struct ics *ics, struct device_node *node); | ||
| 30 | |||
| 31 | /* Only one global & state struct ics */ | ||
| 32 | static struct ics ics_rtas = { | ||
| 33 | .map = ics_rtas_map, | ||
| 34 | .mask_unknown = ics_rtas_mask_unknown, | ||
| 35 | .get_server = ics_rtas_get_server, | ||
| 36 | .host_match = ics_rtas_host_match, | ||
| 37 | }; | ||
| 38 | |||
| 39 | static void ics_rtas_unmask_irq(struct irq_data *d) | ||
| 40 | { | ||
| 41 | unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); | ||
| 42 | int call_status; | ||
| 43 | int server; | ||
| 44 | |||
| 45 | pr_devel("xics: unmask virq %d [hw 0x%x]\n", d->irq, hw_irq); | ||
| 46 | |||
| 47 | if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) | ||
| 48 | return; | ||
| 49 | |||
| 50 | server = xics_get_irq_server(d->irq, d->affinity, 0); | ||
| 51 | |||
| 52 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hw_irq, server, | ||
| 53 | DEFAULT_PRIORITY); | ||
| 54 | if (call_status != 0) { | ||
| 55 | printk(KERN_ERR | ||
| 56 | "%s: ibm_set_xive irq %u server %x returned %d\n", | ||
| 57 | __func__, hw_irq, server, call_status); | ||
| 58 | return; | ||
| 59 | } | ||
| 60 | |||
| 61 | /* Now unmask the interrupt (often a no-op) */ | ||
| 62 | call_status = rtas_call(ibm_int_on, 1, 1, NULL, hw_irq); | ||
| 63 | if (call_status != 0) { | ||
| 64 | printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n", | ||
| 65 | __func__, hw_irq, call_status); | ||
| 66 | return; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | static unsigned int ics_rtas_startup(struct irq_data *d) | ||
| 71 | { | ||
| 72 | #ifdef CONFIG_PCI_MSI | ||
| 73 | /* | ||
| 74 | * The generic MSI code returns with the interrupt disabled on the | ||
| 75 | * card, using the MSI mask bits. Firmware doesn't appear to unmask | ||
| 76 | * at that level, so we do it here by hand. | ||
| 77 | */ | ||
| 78 | if (d->msi_desc) | ||
| 79 | unmask_msi_irq(d); | ||
| 80 | #endif | ||
| 81 | /* unmask it */ | ||
| 82 | ics_rtas_unmask_irq(d); | ||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | static void ics_rtas_mask_real_irq(unsigned int hw_irq) | ||
| 87 | { | ||
| 88 | int call_status; | ||
| 89 | |||
| 90 | if (hw_irq == XICS_IPI) | ||
| 91 | return; | ||
| 92 | |||
| 93 | call_status = rtas_call(ibm_int_off, 1, 1, NULL, hw_irq); | ||
| 94 | if (call_status != 0) { | ||
| 95 | printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n", | ||
| 96 | __func__, hw_irq, call_status); | ||
| 97 | return; | ||
| 98 | } | ||
| 99 | |||
| 100 | /* Have to set XIVE to 0xff to be able to remove a slot */ | ||
| 101 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hw_irq, | ||
| 102 | xics_default_server, 0xff); | ||
| 103 | if (call_status != 0) { | ||
| 104 | printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n", | ||
| 105 | __func__, hw_irq, call_status); | ||
| 106 | return; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | static void ics_rtas_mask_irq(struct irq_data *d) | ||
| 111 | { | ||
| 112 | unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); | ||
| 113 | |||
| 114 | pr_devel("xics: mask virq %d [hw 0x%x]\n", d->irq, hw_irq); | ||
| 115 | |||
| 116 | if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) | ||
| 117 | return; | ||
| 118 | ics_rtas_mask_real_irq(hw_irq); | ||
| 119 | } | ||
| 120 | |||
| 121 | static int ics_rtas_set_affinity(struct irq_data *d, | ||
| 122 | const struct cpumask *cpumask, | ||
| 123 | bool force) | ||
| 124 | { | ||
| 125 | unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); | ||
| 126 | int status; | ||
| 127 | int xics_status[2]; | ||
| 128 | int irq_server; | ||
| 129 | |||
| 130 | if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) | ||
| 131 | return -1; | ||
| 132 | |||
| 133 | status = rtas_call(ibm_get_xive, 1, 3, xics_status, hw_irq); | ||
| 134 | |||
| 135 | if (status) { | ||
| 136 | printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n", | ||
| 137 | __func__, hw_irq, status); | ||
| 138 | return -1; | ||
| 139 | } | ||
| 140 | |||
| 141 | irq_server = xics_get_irq_server(d->irq, cpumask, 1); | ||
| 142 | if (irq_server == -1) { | ||
| 143 | char cpulist[128]; | ||
| 144 | cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); | ||
| 145 | printk(KERN_WARNING | ||
| 146 | "%s: No online cpus in the mask %s for irq %d\n", | ||
| 147 | __func__, cpulist, d->irq); | ||
| 148 | return -1; | ||
| 149 | } | ||
| 150 | |||
| 151 | status = rtas_call(ibm_set_xive, 3, 1, NULL, | ||
| 152 | hw_irq, irq_server, xics_status[1]); | ||
| 153 | |||
| 154 | if (status) { | ||
| 155 | printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n", | ||
| 156 | __func__, hw_irq, status); | ||
| 157 | return -1; | ||
| 158 | } | ||
| 159 | |||
| 160 | return IRQ_SET_MASK_OK; | ||
| 161 | } | ||
| 162 | |||
| 163 | static struct irq_chip ics_rtas_irq_chip = { | ||
| 164 | .name = "XICS", | ||
| 165 | .irq_startup = ics_rtas_startup, | ||
| 166 | .irq_mask = ics_rtas_mask_irq, | ||
| 167 | .irq_unmask = ics_rtas_unmask_irq, | ||
| 168 | .irq_eoi = NULL, /* Patched at init time */ | ||
| 169 | .irq_set_affinity = ics_rtas_set_affinity | ||
| 170 | }; | ||
| 171 | |||
| 172 | static int ics_rtas_map(struct ics *ics, unsigned int virq) | ||
| 173 | { | ||
| 174 | unsigned int hw_irq = (unsigned int)virq_to_hw(virq); | ||
| 175 | int status[2]; | ||
| 176 | int rc; | ||
| 177 | |||
| 178 | if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)) | ||
| 179 | return -EINVAL; | ||
| 180 | |||
| 181 | /* Check if RTAS knows about this interrupt */ | ||
| 182 | rc = rtas_call(ibm_get_xive, 1, 3, status, hw_irq); | ||
| 183 | if (rc) | ||
| 184 | return -ENXIO; | ||
| 185 | |||
| 186 | irq_set_chip_and_handler(virq, &ics_rtas_irq_chip, handle_fasteoi_irq); | ||
| 187 | irq_set_chip_data(virq, &ics_rtas); | ||
| 188 | |||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | static void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec) | ||
| 193 | { | ||
| 194 | ics_rtas_mask_real_irq(vec); | ||
| 195 | } | ||
| 196 | |||
| 197 | static long ics_rtas_get_server(struct ics *ics, unsigned long vec) | ||
| 198 | { | ||
| 199 | int rc, status[2]; | ||
| 200 | |||
| 201 | rc = rtas_call(ibm_get_xive, 1, 3, status, vec); | ||
| 202 | if (rc) | ||
| 203 | return -1; | ||
| 204 | return status[0]; | ||
| 205 | } | ||
| 206 | |||
| 207 | static int ics_rtas_host_match(struct ics *ics, struct device_node *node) | ||
| 208 | { | ||
| 209 | /* IBM machines have interrupt parents of various funky types for things | ||
| 210 | * like vdevices, events, etc... The trick we use here is to match | ||
| 211 | * everything here except the legacy 8259 which is compatible "chrp,iic" | ||
| 212 | */ | ||
| 213 | return !of_device_is_compatible(node, "chrp,iic"); | ||
| 214 | } | ||
| 215 | |||
| 216 | int ics_rtas_init(void) | ||
| 217 | { | ||
| 218 | ibm_get_xive = rtas_token("ibm,get-xive"); | ||
| 219 | ibm_set_xive = rtas_token("ibm,set-xive"); | ||
| 220 | ibm_int_on = rtas_token("ibm,int-on"); | ||
| 221 | ibm_int_off = rtas_token("ibm,int-off"); | ||
| 222 | |||
| 223 | /* We enable the RTAS "ICS" if RTAS is present with the | ||
| 224 | * appropriate tokens | ||
| 225 | */ | ||
| 226 | if (ibm_get_xive == RTAS_UNKNOWN_SERVICE || | ||
| 227 | ibm_set_xive == RTAS_UNKNOWN_SERVICE) | ||
| 228 | return -ENODEV; | ||
| 229 | |||
| 230 | /* We need to patch our irq chip's EOI to point to the | ||
| 231 | * right ICP | ||
| 232 | */ | ||
| 233 | ics_rtas_irq_chip.irq_eoi = icp_ops->eoi; | ||
| 234 | |||
| 235 | /* Register ourselves */ | ||
| 236 | xics_register_ics(&ics_rtas); | ||
| 237 | |||
| 238 | return 0; | ||
| 239 | } | ||
| 240 | |||
diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c new file mode 100644 index 000000000000..445c5a01b766 --- /dev/null +++ b/arch/powerpc/sysdev/xics/xics-common.c | |||
| @@ -0,0 +1,443 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2011 IBM Corporation. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version | ||
| 7 | * 2 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | #include <linux/types.h> | ||
| 11 | #include <linux/threads.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/irq.h> | ||
| 14 | #include <linux/debugfs.h> | ||
| 15 | #include <linux/smp.h> | ||
| 16 | #include <linux/interrupt.h> | ||
| 17 | #include <linux/seq_file.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/cpu.h> | ||
| 20 | #include <linux/of.h> | ||
| 21 | #include <linux/slab.h> | ||
| 22 | #include <linux/spinlock.h> | ||
| 23 | |||
| 24 | #include <asm/prom.h> | ||
| 25 | #include <asm/io.h> | ||
| 26 | #include <asm/smp.h> | ||
| 27 | #include <asm/machdep.h> | ||
| 28 | #include <asm/irq.h> | ||
| 29 | #include <asm/errno.h> | ||
| 30 | #include <asm/rtas.h> | ||
| 31 | #include <asm/xics.h> | ||
| 32 | #include <asm/firmware.h> | ||
| 33 | |||
| 34 | /* Globals common to all ICP/ICS implementations */ | ||
| 35 | const struct icp_ops *icp_ops; | ||
| 36 | |||
| 37 | unsigned int xics_default_server = 0xff; | ||
| 38 | unsigned int xics_default_distrib_server = 0; | ||
| 39 | unsigned int xics_interrupt_server_size = 8; | ||
| 40 | |||
| 41 | DEFINE_PER_CPU(struct xics_cppr, xics_cppr); | ||
| 42 | |||
| 43 | struct irq_host *xics_host; | ||
| 44 | |||
| 45 | static LIST_HEAD(ics_list); | ||
| 46 | |||
| 47 | void xics_update_irq_servers(void) | ||
| 48 | { | ||
| 49 | int i, j; | ||
| 50 | struct device_node *np; | ||
| 51 | u32 ilen; | ||
| 52 | const u32 *ireg; | ||
| 53 | u32 hcpuid; | ||
| 54 | |||
| 55 | /* Find the server numbers for the boot cpu. */ | ||
| 56 | np = of_get_cpu_node(boot_cpuid, NULL); | ||
| 57 | BUG_ON(!np); | ||
| 58 | |||
| 59 | hcpuid = get_hard_smp_processor_id(boot_cpuid); | ||
| 60 | xics_default_server = xics_default_distrib_server = hcpuid; | ||
| 61 | |||
| 62 | pr_devel("xics: xics_default_server = 0x%x\n", xics_default_server); | ||
| 63 | |||
| 64 | ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); | ||
| 65 | if (!ireg) { | ||
| 66 | of_node_put(np); | ||
| 67 | return; | ||
| 68 | } | ||
| 69 | |||
| 70 | i = ilen / sizeof(int); | ||
| 71 | |||
| 72 | /* Global interrupt distribution server is specified in the last | ||
| 73 | * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last | ||
| 74 | * entry fom this property for current boot cpu id and use it as | ||
| 75 | * default distribution server | ||
| 76 | */ | ||
| 77 | for (j = 0; j < i; j += 2) { | ||
| 78 | if (ireg[j] == hcpuid) { | ||
| 79 | xics_default_distrib_server = ireg[j+1]; | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | pr_devel("xics: xics_default_distrib_server = 0x%x\n", | ||
| 84 | xics_default_distrib_server); | ||
| 85 | of_node_put(np); | ||
| 86 | } | ||
| 87 | |||
| 88 | /* GIQ stuff, currently only supported on RTAS setups, will have | ||
| 89 | * to be sorted properly for bare metal | ||
| 90 | */ | ||
| 91 | void xics_set_cpu_giq(unsigned int gserver, unsigned int join) | ||
| 92 | { | ||
| 93 | #ifdef CONFIG_PPC_RTAS | ||
| 94 | int index; | ||
| 95 | int status; | ||
| 96 | |||
| 97 | if (!rtas_indicator_present(GLOBAL_INTERRUPT_QUEUE, NULL)) | ||
| 98 | return; | ||
| 99 | |||
| 100 | index = (1UL << xics_interrupt_server_size) - 1 - gserver; | ||
| 101 | |||
| 102 | status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, index, join); | ||
| 103 | |||
| 104 | WARN(status < 0, "set-indicator(%d, %d, %u) returned %d\n", | ||
| 105 | GLOBAL_INTERRUPT_QUEUE, index, join, status); | ||
| 106 | #endif | ||
| 107 | } | ||
| 108 | |||
| 109 | void xics_setup_cpu(void) | ||
| 110 | { | ||
| 111 | icp_ops->set_priority(LOWEST_PRIORITY); | ||
| 112 | |||
| 113 | xics_set_cpu_giq(xics_default_distrib_server, 1); | ||
| 114 | } | ||
| 115 | |||
| 116 | void xics_mask_unknown_vec(unsigned int vec) | ||
| 117 | { | ||
| 118 | struct ics *ics; | ||
| 119 | |||
| 120 | pr_err("Interrupt 0x%x (real) is invalid, disabling it.\n", vec); | ||
| 121 | |||
| 122 | list_for_each_entry(ics, &ics_list, link) | ||
| 123 | ics->mask_unknown(ics, vec); | ||
| 124 | } | ||
| 125 | |||
| 126 | |||
| 127 | #ifdef CONFIG_SMP | ||
| 128 | |||
| 129 | static void xics_request_ipi(void) | ||
| 130 | { | ||
| 131 | unsigned int ipi; | ||
| 132 | |||
| 133 | ipi = irq_create_mapping(xics_host, XICS_IPI); | ||
| 134 | BUG_ON(ipi == NO_IRQ); | ||
| 135 | |||
| 136 | /* | ||
| 137 | * IPIs are marked IRQF_DISABLED as they must run with irqs | ||
| 138 | * disabled, and PERCPU. The handler was set in map. | ||
| 139 | */ | ||
| 140 | BUG_ON(request_irq(ipi, icp_ops->ipi_action, | ||
| 141 | IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL)); | ||
| 142 | } | ||
| 143 | |||
| 144 | int __init xics_smp_probe(void) | ||
| 145 | { | ||
| 146 | /* Setup cause_ipi callback based on which ICP is used */ | ||
| 147 | smp_ops->cause_ipi = icp_ops->cause_ipi; | ||
| 148 | |||
| 149 | /* Register all the IPIs */ | ||
| 150 | xics_request_ipi(); | ||
| 151 | |||
| 152 | return cpumask_weight(cpu_possible_mask); | ||
| 153 | } | ||
| 154 | |||
| 155 | #endif /* CONFIG_SMP */ | ||
| 156 | |||
| 157 | void xics_teardown_cpu(void) | ||
| 158 | { | ||
| 159 | struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); | ||
| 160 | |||
| 161 | /* | ||
| 162 | * we have to reset the cppr index to 0 because we're | ||
| 163 | * not going to return from the IPI | ||
| 164 | */ | ||
| 165 | os_cppr->index = 0; | ||
| 166 | icp_ops->set_priority(0); | ||
| 167 | icp_ops->teardown_cpu(); | ||
| 168 | } | ||
| 169 | |||
| 170 | void xics_kexec_teardown_cpu(int secondary) | ||
| 171 | { | ||
| 172 | xics_teardown_cpu(); | ||
| 173 | |||
| 174 | icp_ops->flush_ipi(); | ||
| 175 | |||
| 176 | /* | ||
| 177 | * Some machines need to have at least one cpu in the GIQ, | ||
| 178 | * so leave the master cpu in the group. | ||
| 179 | */ | ||
| 180 | if (secondary) | ||
| 181 | xics_set_cpu_giq(xics_default_distrib_server, 0); | ||
| 182 | } | ||
| 183 | |||
| 184 | |||
| 185 | #ifdef CONFIG_HOTPLUG_CPU | ||
| 186 | |||
| 187 | /* Interrupts are disabled. */ | ||
| 188 | void xics_migrate_irqs_away(void) | ||
| 189 | { | ||
| 190 | int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id(); | ||
| 191 | unsigned int irq, virq; | ||
| 192 | |||
| 193 | /* If we used to be the default server, move to the new "boot_cpuid" */ | ||
| 194 | if (hw_cpu == xics_default_server) | ||
| 195 | xics_update_irq_servers(); | ||
| 196 | |||
| 197 | /* Reject any interrupt that was queued to us... */ | ||
| 198 | icp_ops->set_priority(0); | ||
| 199 | |||
| 200 | /* Remove ourselves from the global interrupt queue */ | ||
| 201 | xics_set_cpu_giq(xics_default_distrib_server, 0); | ||
| 202 | |||
| 203 | /* Allow IPIs again... */ | ||
| 204 | icp_ops->set_priority(DEFAULT_PRIORITY); | ||
| 205 | |||
| 206 | for_each_irq(virq) { | ||
| 207 | struct irq_desc *desc; | ||
| 208 | struct irq_chip *chip; | ||
| 209 | long server; | ||
| 210 | unsigned long flags; | ||
| 211 | struct ics *ics; | ||
| 212 | |||
| 213 | /* We can't set affinity on ISA interrupts */ | ||
| 214 | if (virq < NUM_ISA_INTERRUPTS) | ||
| 215 | continue; | ||
| 216 | if (!virq_is_host(virq, xics_host)) | ||
| 217 | continue; | ||
| 218 | irq = (unsigned int)virq_to_hw(virq); | ||
| 219 | /* We need to get IPIs still. */ | ||
| 220 | if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) | ||
| 221 | continue; | ||
| 222 | desc = irq_to_desc(virq); | ||
| 223 | /* We only need to migrate enabled IRQS */ | ||
| 224 | if (!desc || !desc->action) | ||
| 225 | continue; | ||
| 226 | chip = irq_desc_get_chip(desc); | ||
| 227 | if (!chip || !chip->irq_set_affinity) | ||
| 228 | continue; | ||
| 229 | |||
| 230 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
| 231 | |||
| 232 | /* Locate interrupt server */ | ||
| 233 | server = -1; | ||
| 234 | ics = irq_get_chip_data(virq); | ||
| 235 | if (ics) | ||
| 236 | server = ics->get_server(ics, irq); | ||
| 237 | if (server < 0) { | ||
| 238 | printk(KERN_ERR "%s: Can't find server for irq %d\n", | ||
| 239 | __func__, irq); | ||
| 240 | goto unlock; | ||
| 241 | } | ||
| 242 | |||
| 243 | /* We only support delivery to all cpus or to one cpu. | ||
| 244 | * The irq has to be migrated only in the single cpu | ||
| 245 | * case. | ||
| 246 | */ | ||
| 247 | if (server != hw_cpu) | ||
| 248 | goto unlock; | ||
| 249 | |||
| 250 | /* This is expected during cpu offline. */ | ||
| 251 | if (cpu_online(cpu)) | ||
| 252 | pr_warning("IRQ %u affinity broken off cpu %u\n", | ||
| 253 | virq, cpu); | ||
| 254 | |||
| 255 | /* Reset affinity to all cpus */ | ||
| 256 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
| 257 | irq_set_affinity(virq, cpu_all_mask); | ||
| 258 | continue; | ||
| 259 | unlock: | ||
| 260 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
| 261 | } | ||
| 262 | } | ||
| 263 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
| 264 | |||
| 265 | #ifdef CONFIG_SMP | ||
| 266 | /* | ||
| 267 | * For the moment we only implement delivery to all cpus or one cpu. | ||
| 268 | * | ||
| 269 | * If the requested affinity is cpu_all_mask, we set global affinity. | ||
| 270 | * If not we set it to the first cpu in the mask, even if multiple cpus | ||
| 271 | * are set. This is so things like irqbalance (which set core and package | ||
| 272 | * wide affinities) do the right thing. | ||
| 273 | * | ||
| 274 | * We need to fix this to implement support for the links | ||
| 275 | */ | ||
| 276 | int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask, | ||
| 277 | unsigned int strict_check) | ||
| 278 | { | ||
| 279 | |||
| 280 | if (!distribute_irqs) | ||
| 281 | return xics_default_server; | ||
| 282 | |||
| 283 | if (!cpumask_subset(cpu_possible_mask, cpumask)) { | ||
| 284 | int server = cpumask_first_and(cpu_online_mask, cpumask); | ||
| 285 | |||
| 286 | if (server < nr_cpu_ids) | ||
| 287 | return get_hard_smp_processor_id(server); | ||
| 288 | |||
| 289 | if (strict_check) | ||
| 290 | return -1; | ||
| 291 | } | ||
| 292 | |||
| 293 | /* | ||
| 294 | * Workaround issue with some versions of JS20 firmware that | ||
| 295 | * deliver interrupts to cpus which haven't been started. This | ||
| 296 | * happens when using the maxcpus= boot option. | ||
| 297 | */ | ||
| 298 | if (cpumask_equal(cpu_online_mask, cpu_present_mask)) | ||
| 299 | return xics_default_distrib_server; | ||
| 300 | |||
| 301 | return xics_default_server; | ||
| 302 | } | ||
| 303 | #endif /* CONFIG_SMP */ | ||
| 304 | |||
| 305 | static int xics_host_match(struct irq_host *h, struct device_node *node) | ||
| 306 | { | ||
| 307 | struct ics *ics; | ||
| 308 | |||
| 309 | list_for_each_entry(ics, &ics_list, link) | ||
| 310 | if (ics->host_match(ics, node)) | ||
| 311 | return 1; | ||
| 312 | |||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | /* Dummies */ | ||
| 317 | static void xics_ipi_unmask(struct irq_data *d) { } | ||
| 318 | static void xics_ipi_mask(struct irq_data *d) { } | ||
| 319 | |||
| 320 | static struct irq_chip xics_ipi_chip = { | ||
| 321 | .name = "XICS", | ||
| 322 | .irq_eoi = NULL, /* Patched at init time */ | ||
| 323 | .irq_mask = xics_ipi_mask, | ||
| 324 | .irq_unmask = xics_ipi_unmask, | ||
| 325 | }; | ||
| 326 | |||
| 327 | static int xics_host_map(struct irq_host *h, unsigned int virq, | ||
| 328 | irq_hw_number_t hw) | ||
| 329 | { | ||
| 330 | struct ics *ics; | ||
| 331 | |||
| 332 | pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hw); | ||
| 333 | |||
| 334 | /* Insert the interrupt mapping into the radix tree for fast lookup */ | ||
| 335 | irq_radix_revmap_insert(xics_host, virq, hw); | ||
| 336 | |||
| 337 | /* They aren't all level sensitive but we just don't really know */ | ||
| 338 | irq_set_status_flags(virq, IRQ_LEVEL); | ||
| 339 | |||
| 340 | /* Don't call into ICS for IPIs */ | ||
| 341 | if (hw == XICS_IPI) { | ||
| 342 | irq_set_chip_and_handler(virq, &xics_ipi_chip, | ||
| 343 | handle_percpu_irq); | ||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | |||
| 347 | /* Let the ICS setup the chip data */ | ||
| 348 | list_for_each_entry(ics, &ics_list, link) | ||
| 349 | if (ics->map(ics, virq) == 0) | ||
| 350 | return 0; | ||
| 351 | |||
| 352 | return -EINVAL; | ||
| 353 | } | ||
| 354 | |||
| 355 | static int xics_host_xlate(struct irq_host *h, struct device_node *ct, | ||
| 356 | const u32 *intspec, unsigned int intsize, | ||
| 357 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | ||
| 358 | |||
| 359 | { | ||
| 360 | /* Current xics implementation translates everything | ||
| 361 | * to level. It is not technically right for MSIs but this | ||
| 362 | * is irrelevant at this point. We might get smarter in the future | ||
| 363 | */ | ||
| 364 | *out_hwirq = intspec[0]; | ||
| 365 | *out_flags = IRQ_TYPE_LEVEL_LOW; | ||
| 366 | |||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | static struct irq_host_ops xics_host_ops = { | ||
| 371 | .match = xics_host_match, | ||
| 372 | .map = xics_host_map, | ||
| 373 | .xlate = xics_host_xlate, | ||
| 374 | }; | ||
| 375 | |||
| 376 | static void __init xics_init_host(void) | ||
| 377 | { | ||
| 378 | xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops, | ||
| 379 | XICS_IRQ_SPURIOUS); | ||
| 380 | BUG_ON(xics_host == NULL); | ||
| 381 | irq_set_default_host(xics_host); | ||
| 382 | } | ||
| 383 | |||
| 384 | void __init xics_register_ics(struct ics *ics) | ||
| 385 | { | ||
| 386 | list_add(&ics->link, &ics_list); | ||
| 387 | } | ||
| 388 | |||
| 389 | static void __init xics_get_server_size(void) | ||
| 390 | { | ||
| 391 | struct device_node *np; | ||
| 392 | const u32 *isize; | ||
| 393 | |||
| 394 | /* We fetch the interrupt server size from the first ICS node | ||
| 395 | * we find if any | ||
| 396 | */ | ||
| 397 | np = of_find_compatible_node(NULL, NULL, "ibm,ppc-xics"); | ||
| 398 | if (!np) | ||
| 399 | return; | ||
| 400 | isize = of_get_property(np, "ibm,interrupt-server#-size", NULL); | ||
| 401 | if (!isize) | ||
| 402 | return; | ||
| 403 | xics_interrupt_server_size = *isize; | ||
| 404 | of_node_put(np); | ||
| 405 | } | ||
| 406 | |||
| 407 | void __init xics_init(void) | ||
| 408 | { | ||
| 409 | int rc = -1; | ||
| 410 | |||
| 411 | /* Fist locate ICP */ | ||
| 412 | #ifdef CONFIG_PPC_ICP_HV | ||
| 413 | if (firmware_has_feature(FW_FEATURE_LPAR)) | ||
| 414 | rc = icp_hv_init(); | ||
| 415 | #endif | ||
| 416 | #ifdef CONFIG_PPC_ICP_NATIVE | ||
| 417 | if (rc < 0) | ||
| 418 | rc = icp_native_init(); | ||
| 419 | #endif | ||
| 420 | if (rc < 0) { | ||
| 421 | pr_warning("XICS: Cannot find a Presentation Controller !\n"); | ||
| 422 | return; | ||
| 423 | } | ||
| 424 | |||
| 425 | /* Copy get_irq callback over to ppc_md */ | ||
| 426 | ppc_md.get_irq = icp_ops->get_irq; | ||
| 427 | |||
| 428 | /* Patch up IPI chip EOI */ | ||
| 429 | xics_ipi_chip.irq_eoi = icp_ops->eoi; | ||
| 430 | |||
| 431 | /* Now locate ICS */ | ||
| 432 | #ifdef CONFIG_PPC_ICS_RTAS | ||
| 433 | rc = ics_rtas_init(); | ||
| 434 | #endif | ||
| 435 | if (rc < 0) | ||
| 436 | pr_warning("XICS: Cannot find a Source Controller !\n"); | ||
| 437 | |||
| 438 | /* Initialize common bits */ | ||
| 439 | xics_get_server_size(); | ||
| 440 | xics_update_irq_servers(); | ||
| 441 | xics_init_host(); | ||
| 442 | xics_setup_cpu(); | ||
| 443 | } | ||
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c index 1e0ccfaf403e..6183799754af 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c | |||
| @@ -69,32 +69,26 @@ static unsigned char xilinx_intc_map_senses[] = { | |||
| 69 | * | 69 | * |
| 70 | * IRQ Chip common (across level and edge) operations | 70 | * IRQ Chip common (across level and edge) operations |
| 71 | */ | 71 | */ |
| 72 | static void xilinx_intc_mask(unsigned int virq) | 72 | static void xilinx_intc_mask(struct irq_data *d) |
| 73 | { | 73 | { |
| 74 | int irq = virq_to_hw(virq); | 74 | int irq = irqd_to_hwirq(d); |
| 75 | void * regs = get_irq_chip_data(virq); | 75 | void * regs = irq_data_get_irq_chip_data(d); |
| 76 | pr_debug("mask: %d\n", irq); | 76 | pr_debug("mask: %d\n", irq); |
| 77 | out_be32(regs + XINTC_CIE, 1 << irq); | 77 | out_be32(regs + XINTC_CIE, 1 << irq); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | static int xilinx_intc_set_type(unsigned int virq, unsigned int flow_type) | 80 | static int xilinx_intc_set_type(struct irq_data *d, unsigned int flow_type) |
| 81 | { | 81 | { |
| 82 | struct irq_desc *desc = irq_to_desc(virq); | ||
| 83 | |||
| 84 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); | ||
| 85 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; | ||
| 86 | if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) | ||
| 87 | desc->status |= IRQ_LEVEL; | ||
| 88 | return 0; | 82 | return 0; |
| 89 | } | 83 | } |
| 90 | 84 | ||
| 91 | /* | 85 | /* |
| 92 | * IRQ Chip level operations | 86 | * IRQ Chip level operations |
| 93 | */ | 87 | */ |
| 94 | static void xilinx_intc_level_unmask(unsigned int virq) | 88 | static void xilinx_intc_level_unmask(struct irq_data *d) |
| 95 | { | 89 | { |
| 96 | int irq = virq_to_hw(virq); | 90 | int irq = irqd_to_hwirq(d); |
| 97 | void * regs = get_irq_chip_data(virq); | 91 | void * regs = irq_data_get_irq_chip_data(d); |
| 98 | pr_debug("unmask: %d\n", irq); | 92 | pr_debug("unmask: %d\n", irq); |
| 99 | out_be32(regs + XINTC_SIE, 1 << irq); | 93 | out_be32(regs + XINTC_SIE, 1 << irq); |
| 100 | 94 | ||
| @@ -107,37 +101,37 @@ static void xilinx_intc_level_unmask(unsigned int virq) | |||
| 107 | 101 | ||
| 108 | static struct irq_chip xilinx_intc_level_irqchip = { | 102 | static struct irq_chip xilinx_intc_level_irqchip = { |
| 109 | .name = "Xilinx Level INTC", | 103 | .name = "Xilinx Level INTC", |
| 110 | .mask = xilinx_intc_mask, | 104 | .irq_mask = xilinx_intc_mask, |
| 111 | .mask_ack = xilinx_intc_mask, | 105 | .irq_mask_ack = xilinx_intc_mask, |
| 112 | .unmask = xilinx_intc_level_unmask, | 106 | .irq_unmask = xilinx_intc_level_unmask, |
| 113 | .set_type = xilinx_intc_set_type, | 107 | .irq_set_type = xilinx_intc_set_type, |
| 114 | }; | 108 | }; |
| 115 | 109 | ||
| 116 | /* | 110 | /* |
| 117 | * IRQ Chip edge operations | 111 | * IRQ Chip edge operations |
| 118 | */ | 112 | */ |
| 119 | static void xilinx_intc_edge_unmask(unsigned int virq) | 113 | static void xilinx_intc_edge_unmask(struct irq_data *d) |
| 120 | { | 114 | { |
| 121 | int irq = virq_to_hw(virq); | 115 | int irq = irqd_to_hwirq(d); |
| 122 | void *regs = get_irq_chip_data(virq); | 116 | void *regs = irq_data_get_irq_chip_data(d); |
| 123 | pr_debug("unmask: %d\n", irq); | 117 | pr_debug("unmask: %d\n", irq); |
| 124 | out_be32(regs + XINTC_SIE, 1 << irq); | 118 | out_be32(regs + XINTC_SIE, 1 << irq); |
| 125 | } | 119 | } |
| 126 | 120 | ||
| 127 | static void xilinx_intc_edge_ack(unsigned int virq) | 121 | static void xilinx_intc_edge_ack(struct irq_data *d) |
| 128 | { | 122 | { |
| 129 | int irq = virq_to_hw(virq); | 123 | int irq = irqd_to_hwirq(d); |
| 130 | void * regs = get_irq_chip_data(virq); | 124 | void * regs = irq_data_get_irq_chip_data(d); |
| 131 | pr_debug("ack: %d\n", irq); | 125 | pr_debug("ack: %d\n", irq); |
| 132 | out_be32(regs + XINTC_IAR, 1 << irq); | 126 | out_be32(regs + XINTC_IAR, 1 << irq); |
| 133 | } | 127 | } |
| 134 | 128 | ||
| 135 | static struct irq_chip xilinx_intc_edge_irqchip = { | 129 | static struct irq_chip xilinx_intc_edge_irqchip = { |
| 136 | .name = "Xilinx Edge INTC", | 130 | .name = "Xilinx Edge INTC", |
| 137 | .mask = xilinx_intc_mask, | 131 | .irq_mask = xilinx_intc_mask, |
| 138 | .unmask = xilinx_intc_edge_unmask, | 132 | .irq_unmask = xilinx_intc_edge_unmask, |
| 139 | .ack = xilinx_intc_edge_ack, | 133 | .irq_ack = xilinx_intc_edge_ack, |
| 140 | .set_type = xilinx_intc_set_type, | 134 | .irq_set_type = xilinx_intc_set_type, |
| 141 | }; | 135 | }; |
| 142 | 136 | ||
| 143 | /* | 137 | /* |
| @@ -170,15 +164,15 @@ static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct, | |||
| 170 | static int xilinx_intc_map(struct irq_host *h, unsigned int virq, | 164 | static int xilinx_intc_map(struct irq_host *h, unsigned int virq, |
| 171 | irq_hw_number_t irq) | 165 | irq_hw_number_t irq) |
| 172 | { | 166 | { |
| 173 | set_irq_chip_data(virq, h->host_data); | 167 | irq_set_chip_data(virq, h->host_data); |
| 174 | 168 | ||
| 175 | if (xilinx_intc_typetable[irq] == IRQ_TYPE_LEVEL_HIGH || | 169 | if (xilinx_intc_typetable[irq] == IRQ_TYPE_LEVEL_HIGH || |
| 176 | xilinx_intc_typetable[irq] == IRQ_TYPE_LEVEL_LOW) { | 170 | xilinx_intc_typetable[irq] == IRQ_TYPE_LEVEL_LOW) { |
| 177 | set_irq_chip_and_handler(virq, &xilinx_intc_level_irqchip, | 171 | irq_set_chip_and_handler(virq, &xilinx_intc_level_irqchip, |
| 178 | handle_level_irq); | 172 | handle_level_irq); |
| 179 | } else { | 173 | } else { |
| 180 | set_irq_chip_and_handler(virq, &xilinx_intc_edge_irqchip, | 174 | irq_set_chip_and_handler(virq, &xilinx_intc_edge_irqchip, |
| 181 | handle_edge_irq); | 175 | handle_edge_irq); |
| 182 | } | 176 | } |
| 183 | return 0; | 177 | return 0; |
| 184 | } | 178 | } |
| @@ -229,12 +223,14 @@ int xilinx_intc_get_irq(void) | |||
| 229 | */ | 223 | */ |
| 230 | static void xilinx_i8259_cascade(unsigned int irq, struct irq_desc *desc) | 224 | static void xilinx_i8259_cascade(unsigned int irq, struct irq_desc *desc) |
| 231 | { | 225 | { |
| 226 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
| 232 | unsigned int cascade_irq = i8259_irq(); | 227 | unsigned int cascade_irq = i8259_irq(); |
| 228 | |||
| 233 | if (cascade_irq) | 229 | if (cascade_irq) |
| 234 | generic_handle_irq(cascade_irq); | 230 | generic_handle_irq(cascade_irq); |
| 235 | 231 | ||
| 236 | /* Let xilinx_intc end the interrupt */ | 232 | /* Let xilinx_intc end the interrupt */ |
| 237 | desc->chip->unmask(irq); | 233 | chip->irq_unmask(&desc->irq_data); |
| 238 | } | 234 | } |
| 239 | 235 | ||
| 240 | static void __init xilinx_i8259_setup_cascade(void) | 236 | static void __init xilinx_i8259_setup_cascade(void) |
| @@ -254,7 +250,7 @@ static void __init xilinx_i8259_setup_cascade(void) | |||
| 254 | } | 250 | } |
| 255 | 251 | ||
| 256 | i8259_init(cascade_node, 0); | 252 | i8259_init(cascade_node, 0); |
| 257 | set_irq_chained_handler(cascade_irq, xilinx_i8259_cascade); | 253 | irq_set_chained_handler(cascade_irq, xilinx_i8259_cascade); |
| 258 | 254 | ||
| 259 | /* Program irq 7 (usb/audio), 14/15 (ide) to level sensitive */ | 255 | /* Program irq 7 (usb/audio), 14/15 (ide) to level sensitive */ |
| 260 | /* This looks like a dirty hack to me --gcl */ | 256 | /* This looks like a dirty hack to me --gcl */ |
