summaryrefslogtreecommitdiff
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r--arch/powerpc/sysdev/6xx-suspend.S10
-rw-r--r--arch/powerpc/sysdev/Kconfig19
-rw-r--r--arch/powerpc/sysdev/Makefile11
-rw-r--r--arch/powerpc/sysdev/cpm1.c788
-rw-r--r--arch/powerpc/sysdev/cpm2.c42
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.c11
-rw-r--r--arch/powerpc/sysdev/cpm_common.c69
-rw-r--r--arch/powerpc/sysdev/cpm_gpio.c3
-rw-r--r--arch/powerpc/sysdev/dart.h15
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c103
-rw-r--r--arch/powerpc/sysdev/dcr-low.S10
-rw-r--r--arch/powerpc/sysdev/dcr.c199
-rw-r--r--arch/powerpc/sysdev/ehv_pic.c28
-rw-r--r--arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h101
-rw-r--r--arch/powerpc/sysdev/fsl_85xx_cache_sram.c160
-rw-r--r--arch/powerpc/sysdev/fsl_85xx_l2ctlr.c229
-rw-r--r--arch/powerpc/sysdev/fsl_gtm.c16
-rw-r--r--arch/powerpc/sysdev/fsl_lbc.c23
-rw-r--r--arch/powerpc/sysdev/fsl_mpic_err.c23
-rw-r--r--arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c41
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c57
-rw-r--r--arch/powerpc/sysdev/fsl_msi.h7
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c108
-rw-r--r--arch/powerpc/sysdev/fsl_pci.h11
-rw-r--r--arch/powerpc/sysdev/fsl_pmc.c10
-rw-r--r--arch/powerpc/sysdev/fsl_rcpm.c6
-rw-r--r--arch/powerpc/sysdev/fsl_rio.c106
-rw-r--r--arch/powerpc/sysdev/fsl_rio.h6
-rw-r--r--arch/powerpc/sysdev/fsl_rmu.c19
-rw-r--r--arch/powerpc/sysdev/fsl_soc.c29
-rw-r--r--arch/powerpc/sysdev/ge/Makefile1
-rw-r--r--arch/powerpc/sysdev/ge/ge_pic.c13
-rw-r--r--arch/powerpc/sysdev/grackle.c27
-rw-r--r--arch/powerpc/sysdev/i8259.c13
-rw-r--r--arch/powerpc/sysdev/indirect_pci.c7
-rw-r--r--arch/powerpc/sysdev/ipic.c70
-rw-r--r--arch/powerpc/sysdev/ipic.h6
-rw-r--r--arch/powerpc/sysdev/micropatch.c749
-rw-r--r--arch/powerpc/sysdev/mmio_nvram.c17
-rw-r--r--arch/powerpc/sysdev/mpc5xxx_clocks.c43
-rw-r--r--arch/powerpc/sysdev/mpic.c62
-rw-r--r--arch/powerpc/sysdev/mpic.h17
-rw-r--r--arch/powerpc/sysdev/mpic_msgr.c32
-rw-r--r--arch/powerpc/sysdev/mpic_msi.c18
-rw-r--r--arch/powerpc/sysdev/mpic_timer.c25
-rw-r--r--arch/powerpc/sysdev/mpic_u3msi.c23
-rw-r--r--arch/powerpc/sysdev/msi_bitmap.c10
-rw-r--r--arch/powerpc/sysdev/of_rtc.c12
-rw-r--r--arch/powerpc/sysdev/pmi.c281
-rw-r--r--arch/powerpc/sysdev/rtc_cmos_setup.c3
-rw-r--r--arch/powerpc/sysdev/scom.c236
-rw-r--r--arch/powerpc/sysdev/simple_gpio.c147
-rw-r--r--arch/powerpc/sysdev/simple_gpio.h13
-rw-r--r--arch/powerpc/sysdev/tsi108_dev.c28
-rw-r--r--arch/powerpc/sysdev/tsi108_pci.c28
-rw-r--r--arch/powerpc/sysdev/udbg_memcons.c14
-rw-r--r--arch/powerpc/sysdev/xics/Kconfig14
-rw-r--r--arch/powerpc/sysdev/xics/Makefile1
-rw-r--r--arch/powerpc/sysdev/xics/icp-hv.c11
-rw-r--r--arch/powerpc/sysdev/xics/icp-native.c56
-rw-r--r--arch/powerpc/sysdev/xics/icp-opal.c16
-rw-r--r--arch/powerpc/sysdev/xics/ics-native.c254
-rw-r--r--arch/powerpc/sysdev/xics/ics-opal.c48
-rw-r--r--arch/powerpc/sysdev/xics/ics-rtas.c49
-rw-r--r--arch/powerpc/sysdev/xics/xics-common.c152
-rw-r--r--arch/powerpc/sysdev/xilinx_intc.c88
-rw-r--r--arch/powerpc/sysdev/xilinx_pci.c132
-rw-r--r--arch/powerpc/sysdev/xive/Makefile1
-rw-r--r--arch/powerpc/sysdev/xive/common.c914
-rw-r--r--arch/powerpc/sysdev/xive/native.c252
-rw-r--r--arch/powerpc/sysdev/xive/spapr.c258
-rw-r--r--arch/powerpc/sysdev/xive/xive-internal.h25
72 files changed, 1992 insertions, 4434 deletions
diff --git a/arch/powerpc/sysdev/6xx-suspend.S b/arch/powerpc/sysdev/6xx-suspend.S
index cf48e9cb2575..e882524fff5a 100644
--- a/arch/powerpc/sysdev/6xx-suspend.S
+++ b/arch/powerpc/sysdev/6xx-suspend.S
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Enter and leave sleep state on chips with 6xx-style HID0
* power management bits, which don't leave sleep state via reset.
@@ -5,10 +6,6 @@
* Author: Scott Wood <scottwood@freescale.com>
*
* Copyright (c) 2006-2007 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
*/
#include <asm/ppc_asm.h>
@@ -29,10 +26,9 @@ _GLOBAL(mpc6xx_enter_standby)
ori r5, r5, ret_from_standby@l
mtlr r5
- CURRENT_THREAD_INFO(r5, r1)
- lwz r6, TI_LOCAL_FLAGS(r5)
+ lwz r6, TI_LOCAL_FLAGS(r2)
ori r6, r6, _TLF_SLEEPING
- stw r6, TI_LOCAL_FLAGS(r5)
+ stw r6, TI_LOCAL_FLAGS(r2)
mfmsr r5
ori r5, r5, MSR_EE
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index e0dbec780fe9..18ff2c4a814a 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -1,40 +1,27 @@
# SPDX-License-Identifier: GPL-2.0
# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
+# see Documentation/kbuild/kconfig-language.rst.
#
config PPC4xx_PCI_EXPRESS
bool
- depends on PCI && 4xx
+ depends on PCI && 44x
config PPC4xx_HSTA_MSI
bool
depends on PCI_MSI
- depends on PCI && 4xx
-
-config PPC4xx_MSI
- bool
- depends on PCI_MSI
- depends on PCI && 4xx
+ depends on PCI && 44x
config PPC_MSI_BITMAP
bool
depends on PCI_MSI
default y if MPIC
default y if FSL_PCI
- default y if PPC4xx_MSI
default y if PPC_POWERNV
source "arch/powerpc/sysdev/xics/Kconfig"
source "arch/powerpc/sysdev/xive/Kconfig"
-config PPC_SCOM
- bool
-
-config SCOM_DEBUGFS
- bool "Expose SCOM controllers via debugfs"
- depends on PPC_SCOM && DEBUG_FS
-
config GE_FPGA
bool
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index aaf23283ba0c..0834a9a12600 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
-
mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o
obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y)
obj-$(CONFIG_MPIC_TIMER) += mpic_timer.o
@@ -14,7 +12,6 @@ obj-$(CONFIG_PPC_MSI_BITMAP) += msi_bitmap.o
obj-$(CONFIG_PPC_MPC106) += grackle.o
obj-$(CONFIG_PPC_DCR_NATIVE) += dcr-low.o
-obj-$(CONFIG_PPC_PMI) += pmi.o
obj-$(CONFIG_U3_DART) += dart_iommu.o
obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o fsl_mpic_err.o
@@ -23,8 +20,6 @@ obj-$(CONFIG_FSL_PMC) += fsl_pmc.o
obj-$(CONFIG_FSL_CORENET_RCPM) += fsl_rcpm.o
obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
obj-$(CONFIG_FSL_GTM) += fsl_gtm.o
-obj-$(CONFIG_FSL_85XX_CACHE_SRAM) += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
-obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o
obj-$(CONFIG_FSL_RIO) += fsl_rio.o fsl_rmu.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc_cmos_setup.o
@@ -32,17 +27,13 @@ obj-$(CONFIG_RTC_DRV_CMOS) += rtc_cmos_setup.o
obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
obj-$(CONFIG_PPC_I8259) += i8259.o
obj-$(CONFIG_IPIC) += ipic.o
-obj-$(CONFIG_XILINX_VIRTEX) += xilinx_intc.o
-obj-$(CONFIG_XILINX_PCI) += xilinx_pci.o
obj-$(CONFIG_OF_RTC) += of_rtc.o
obj-$(CONFIG_CPM) += cpm_common.o
-obj-$(CONFIG_CPM1) += cpm1.o
obj-$(CONFIG_CPM2) += cpm2.o cpm2_pic.o cpm_gpio.o
obj-$(CONFIG_8xx_GPIO) += cpm_gpio.o
obj-$(CONFIG_QUICC_ENGINE) += cpm_common.o
obj-$(CONFIG_PPC_DCR) += dcr.o
-obj-$(CONFIG_UCODE_PATCH) += micropatch.o
obj-$(CONFIG_PPC_MPC512x) += mpc5xxx_clocks.o
obj-$(CONFIG_PPC_MPC52xx) += mpc5xxx_clocks.o
@@ -51,8 +42,6 @@ ifdef CONFIG_SUSPEND
obj-$(CONFIG_PPC_BOOK3S_32) += 6xx-suspend.o
endif
-obj-$(CONFIG_PPC_SCOM) += scom.o
-
obj-$(CONFIG_PPC_EARLY_DEBUG_MEMCONS) += udbg_memcons.o
obj-$(CONFIG_PPC_XICS) += xics/
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
deleted file mode 100644
index 4f8dcf124828..000000000000
--- a/arch/powerpc/sysdev/cpm1.c
+++ /dev/null
@@ -1,788 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * General Purpose functions for the global management of the
- * Communication Processor Module.
- * Copyright (c) 1997 Dan error_act (dmalek@jlc.net)
- *
- * In addition to the individual control of the communication
- * channels, there are a few functions that globally affect the
- * communication processor.
- *
- * Buffer descriptors must be allocated from the dual ported memory
- * space. The allocator for that is here. When the communication
- * process is reset, we reclaim the memory available. There is
- * currently no deallocator for this memory.
- * The amount of space available is platform dependent. On the
- * MBX, the EPPC software loads additional microcode into the
- * communication processor, and uses some of the DP ram for this
- * purpose. Current, the first 512 bytes and the last 256 bytes of
- * memory are used. Right now I am conservative and only use the
- * memory that can never be used for microcode. If there are
- * applications that require more DP ram, we can expand the boundaries
- * but then we have to be careful of any downloaded microcode.
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/dma-mapping.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/8xx_immap.h>
-#include <asm/cpm1.h>
-#include <asm/io.h>
-#include <asm/rheap.h>
-#include <asm/prom.h>
-#include <asm/cpm.h>
-
-#include <asm/fs_pd.h>
-
-#ifdef CONFIG_8xx_GPIO
-#include <linux/of_gpio.h>
-#endif
-
-#define CPM_MAP_SIZE (0x4000)
-
-cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */
-immap_t __iomem *mpc8xx_immr;
-static cpic8xx_t __iomem *cpic_reg;
-
-static struct irq_domain *cpm_pic_host;
-
-static void cpm_mask_irq(struct irq_data *d)
-{
- unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
-
- clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
-}
-
-static void cpm_unmask_irq(struct irq_data *d)
-{
- unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
-
- setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
-}
-
-static void cpm_end_irq(struct irq_data *d)
-{
- unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
-
- out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec));
-}
-
-static struct irq_chip cpm_pic = {
- .name = "CPM PIC",
- .irq_mask = cpm_mask_irq,
- .irq_unmask = cpm_unmask_irq,
- .irq_eoi = cpm_end_irq,
-};
-
-int cpm_get_irq(void)
-{
- int cpm_vec;
-
- /* Get the vector by setting the ACK bit and then reading
- * the register.
- */
- out_be16(&cpic_reg->cpic_civr, 1);
- cpm_vec = in_be16(&cpic_reg->cpic_civr);
- cpm_vec >>= 11;
-
- return irq_linear_revmap(cpm_pic_host, cpm_vec);
-}
-
-static int cpm_pic_host_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t hw)
-{
- pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw);
-
- irq_set_status_flags(virq, IRQ_LEVEL);
- irq_set_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq);
- return 0;
-}
-
-/* The CPM can generate the error interrupt when there is a race condition
- * between generating and masking interrupts. All we have to do is ACK it
- * and return. This is a no-op function so we don't need any special
- * tests in the interrupt handler.
- */
-static irqreturn_t cpm_error_interrupt(int irq, void *dev)
-{
- return IRQ_HANDLED;
-}
-
-static struct irqaction cpm_error_irqaction = {
- .handler = cpm_error_interrupt,
- .flags = IRQF_NO_THREAD,
- .name = "error",
-};
-
-static const struct irq_domain_ops cpm_pic_host_ops = {
- .map = cpm_pic_host_map,
-};
-
-unsigned int cpm_pic_init(void)
-{
- struct device_node *np = NULL;
- struct resource res;
- unsigned int sirq = 0, hwirq, eirq;
- int ret;
-
- pr_debug("cpm_pic_init\n");
-
- np = of_find_compatible_node(NULL, NULL, "fsl,cpm1-pic");
- if (np == NULL)
- np = of_find_compatible_node(NULL, "cpm-pic", "CPM");
- if (np == NULL) {
- printk(KERN_ERR "CPM PIC init: can not find cpm-pic node\n");
- return sirq;
- }
-
- ret = of_address_to_resource(np, 0, &res);
- if (ret)
- goto end;
-
- cpic_reg = ioremap(res.start, resource_size(&res));
- if (cpic_reg == NULL)
- goto end;
-
- sirq = irq_of_parse_and_map(np, 0);
- if (!sirq)
- goto end;
-
- /* Initialize the CPM interrupt controller. */
- hwirq = (unsigned int)virq_to_hw(sirq);
- out_be32(&cpic_reg->cpic_cicr,
- (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
- ((hwirq/2) << 13) | CICR_HP_MASK);
-
- out_be32(&cpic_reg->cpic_cimr, 0);
-
- cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL);
- if (cpm_pic_host == NULL) {
- printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
- sirq = 0;
- goto end;
- }
-
- /* Install our own error handler. */
- np = of_find_compatible_node(NULL, NULL, "fsl,cpm1");
- if (np == NULL)
- np = of_find_node_by_type(NULL, "cpm");
- if (np == NULL) {
- printk(KERN_ERR "CPM PIC init: can not find cpm node\n");
- goto end;
- }
-
- eirq = irq_of_parse_and_map(np, 0);
- if (!eirq)
- goto end;
-
- if (setup_irq(eirq, &cpm_error_irqaction))
- printk(KERN_ERR "Could not allocate CPM error IRQ!");
-
- setbits32(&cpic_reg->cpic_cicr, CICR_IEN);
-
-end:
- of_node_put(np);
- return sirq;
-}
-
-void __init cpm_reset(void)
-{
- sysconf8xx_t __iomem *siu_conf;
-
- mpc8xx_immr = ioremap(get_immrbase(), 0x4000);
- if (!mpc8xx_immr) {
- printk(KERN_CRIT "Could not map IMMR\n");
- return;
- }
-
- cpmp = &mpc8xx_immr->im_cpm;
-
-#ifndef CONFIG_PPC_EARLY_DEBUG_CPM
- /* Perform a reset.
- */
- out_be16(&cpmp->cp_cpcr, CPM_CR_RST | CPM_CR_FLG);
-
- /* Wait for it.
- */
- while (in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG);
-#endif
-
-#ifdef CONFIG_UCODE_PATCH
- cpm_load_patch(cpmp);
-#endif
-
- /* Set SDMA Bus Request priority 5.
- * On 860T, this also enables FEC priority 6. I am not sure
- * this is what we really want for some applications, but the
- * manual recommends it.
- * Bit 25, FAM can also be set to use FEC aggressive mode (860T).
- */
- siu_conf = immr_map(im_siu_conf);
- if ((mfspr(SPRN_IMMR) & 0xffff) == 0x0900) /* MPC885 */
- out_be32(&siu_conf->sc_sdcr, 0x40);
- else
- out_be32(&siu_conf->sc_sdcr, 1);
- immr_unmap(siu_conf);
-}
-
-static DEFINE_SPINLOCK(cmd_lock);
-
-#define MAX_CR_CMD_LOOPS 10000
-
-int cpm_command(u32 command, u8 opcode)
-{
- int i, ret;
- unsigned long flags;
-
- if (command & 0xffffff0f)
- return -EINVAL;
-
- spin_lock_irqsave(&cmd_lock, flags);
-
- ret = 0;
- out_be16(&cpmp->cp_cpcr, command | CPM_CR_FLG | (opcode << 8));
- for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
- if ((in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0)
- goto out;
-
- printk(KERN_ERR "%s(): Not able to issue CPM command\n", __func__);
- ret = -EIO;
-out:
- spin_unlock_irqrestore(&cmd_lock, flags);
- return ret;
-}
-EXPORT_SYMBOL(cpm_command);
-
-/* Set a baud rate generator. This needs lots of work. There are
- * four BRGs, any of which can be wired to any channel.
- * The internal baud rate clock is the system clock divided by 16.
- * This assumes the baudrate is 16x oversampled by the uart.
- */
-#define BRG_INT_CLK (get_brgfreq())
-#define BRG_UART_CLK (BRG_INT_CLK/16)
-#define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16)
-
-void
-cpm_setbrg(uint brg, uint rate)
-{
- u32 __iomem *bp;
-
- /* This is good enough to get SMCs running.....
- */
- bp = &cpmp->cp_brgc1;
- bp += brg;
- /* The BRG has a 12-bit counter. For really slow baud rates (or
- * really fast processors), we may have to further divide by 16.
- */
- if (((BRG_UART_CLK / rate) - 1) < 4096)
- out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN);
- else
- out_be32(bp, (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
- CPM_BRG_EN | CPM_BRG_DIV16);
-}
-
-struct cpm_ioport16 {
- __be16 dir, par, odr_sor, dat, intr;
- __be16 res[3];
-};
-
-struct cpm_ioport32b {
- __be32 dir, par, odr, dat;
-};
-
-struct cpm_ioport32e {
- __be32 dir, par, sor, odr, dat;
-};
-
-static void cpm1_set_pin32(int port, int pin, int flags)
-{
- struct cpm_ioport32e __iomem *iop;
- pin = 1 << (31 - pin);
-
- if (port == CPM_PORTB)
- iop = (struct cpm_ioport32e __iomem *)
- &mpc8xx_immr->im_cpm.cp_pbdir;
- else
- iop = (struct cpm_ioport32e __iomem *)
- &mpc8xx_immr->im_cpm.cp_pedir;
-
- if (flags & CPM_PIN_OUTPUT)
- setbits32(&iop->dir, pin);
- else
- clrbits32(&iop->dir, pin);
-
- if (!(flags & CPM_PIN_GPIO))
- setbits32(&iop->par, pin);
- else
- clrbits32(&iop->par, pin);
-
- if (port == CPM_PORTB) {
- if (flags & CPM_PIN_OPENDRAIN)
- setbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin);
- else
- clrbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin);
- }
-
- if (port == CPM_PORTE) {
- if (flags & CPM_PIN_SECONDARY)
- setbits32(&iop->sor, pin);
- else
- clrbits32(&iop->sor, pin);
-
- if (flags & CPM_PIN_OPENDRAIN)
- setbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin);
- else
- clrbits32(&mpc8xx_immr->im_cpm.cp_peodr, pin);
- }
-}
-
-static void cpm1_set_pin16(int port, int pin, int flags)
-{
- struct cpm_ioport16 __iomem *iop =
- (struct cpm_ioport16 __iomem *)&mpc8xx_immr->im_ioport;
-
- pin = 1 << (15 - pin);
-
- if (port != 0)
- iop += port - 1;
-
- if (flags & CPM_PIN_OUTPUT)
- setbits16(&iop->dir, pin);
- else
- clrbits16(&iop->dir, pin);
-
- if (!(flags & CPM_PIN_GPIO))
- setbits16(&iop->par, pin);
- else
- clrbits16(&iop->par, pin);
-
- if (port == CPM_PORTA) {
- if (flags & CPM_PIN_OPENDRAIN)
- setbits16(&iop->odr_sor, pin);
- else
- clrbits16(&iop->odr_sor, pin);
- }
- if (port == CPM_PORTC) {
- if (flags & CPM_PIN_SECONDARY)
- setbits16(&iop->odr_sor, pin);
- else
- clrbits16(&iop->odr_sor, pin);
- if (flags & CPM_PIN_FALLEDGE)
- setbits16(&iop->intr, pin);
- else
- clrbits16(&iop->intr, pin);
- }
-}
-
-void cpm1_set_pin(enum cpm_port port, int pin, int flags)
-{
- if (port == CPM_PORTB || port == CPM_PORTE)
- cpm1_set_pin32(port, pin, flags);
- else
- cpm1_set_pin16(port, pin, flags);
-}
-
-int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode)
-{
- int shift;
- int i, bits = 0;
- u32 __iomem *reg;
- u32 mask = 7;
-
- u8 clk_map[][3] = {
- {CPM_CLK_SCC1, CPM_BRG1, 0},
- {CPM_CLK_SCC1, CPM_BRG2, 1},
- {CPM_CLK_SCC1, CPM_BRG3, 2},
- {CPM_CLK_SCC1, CPM_BRG4, 3},
- {CPM_CLK_SCC1, CPM_CLK1, 4},
- {CPM_CLK_SCC1, CPM_CLK2, 5},
- {CPM_CLK_SCC1, CPM_CLK3, 6},
- {CPM_CLK_SCC1, CPM_CLK4, 7},
-
- {CPM_CLK_SCC2, CPM_BRG1, 0},
- {CPM_CLK_SCC2, CPM_BRG2, 1},
- {CPM_CLK_SCC2, CPM_BRG3, 2},
- {CPM_CLK_SCC2, CPM_BRG4, 3},
- {CPM_CLK_SCC2, CPM_CLK1, 4},
- {CPM_CLK_SCC2, CPM_CLK2, 5},
- {CPM_CLK_SCC2, CPM_CLK3, 6},
- {CPM_CLK_SCC2, CPM_CLK4, 7},
-
- {CPM_CLK_SCC3, CPM_BRG1, 0},
- {CPM_CLK_SCC3, CPM_BRG2, 1},
- {CPM_CLK_SCC3, CPM_BRG3, 2},
- {CPM_CLK_SCC3, CPM_BRG4, 3},
- {CPM_CLK_SCC3, CPM_CLK5, 4},
- {CPM_CLK_SCC3, CPM_CLK6, 5},
- {CPM_CLK_SCC3, CPM_CLK7, 6},
- {CPM_CLK_SCC3, CPM_CLK8, 7},
-
- {CPM_CLK_SCC4, CPM_BRG1, 0},
- {CPM_CLK_SCC4, CPM_BRG2, 1},
- {CPM_CLK_SCC4, CPM_BRG3, 2},
- {CPM_CLK_SCC4, CPM_BRG4, 3},
- {CPM_CLK_SCC4, CPM_CLK5, 4},
- {CPM_CLK_SCC4, CPM_CLK6, 5},
- {CPM_CLK_SCC4, CPM_CLK7, 6},
- {CPM_CLK_SCC4, CPM_CLK8, 7},
-
- {CPM_CLK_SMC1, CPM_BRG1, 0},
- {CPM_CLK_SMC1, CPM_BRG2, 1},
- {CPM_CLK_SMC1, CPM_BRG3, 2},
- {CPM_CLK_SMC1, CPM_BRG4, 3},
- {CPM_CLK_SMC1, CPM_CLK1, 4},
- {CPM_CLK_SMC1, CPM_CLK2, 5},
- {CPM_CLK_SMC1, CPM_CLK3, 6},
- {CPM_CLK_SMC1, CPM_CLK4, 7},
-
- {CPM_CLK_SMC2, CPM_BRG1, 0},
- {CPM_CLK_SMC2, CPM_BRG2, 1},
- {CPM_CLK_SMC2, CPM_BRG3, 2},
- {CPM_CLK_SMC2, CPM_BRG4, 3},
- {CPM_CLK_SMC2, CPM_CLK5, 4},
- {CPM_CLK_SMC2, CPM_CLK6, 5},
- {CPM_CLK_SMC2, CPM_CLK7, 6},
- {CPM_CLK_SMC2, CPM_CLK8, 7},
- };
-
- switch (target) {
- case CPM_CLK_SCC1:
- reg = &mpc8xx_immr->im_cpm.cp_sicr;
- shift = 0;
- break;
-
- case CPM_CLK_SCC2:
- reg = &mpc8xx_immr->im_cpm.cp_sicr;
- shift = 8;
- break;
-
- case CPM_CLK_SCC3:
- reg = &mpc8xx_immr->im_cpm.cp_sicr;
- shift = 16;
- break;
-
- case CPM_CLK_SCC4:
- reg = &mpc8xx_immr->im_cpm.cp_sicr;
- shift = 24;
- break;
-
- case CPM_CLK_SMC1:
- reg = &mpc8xx_immr->im_cpm.cp_simode;
- shift = 12;
- break;
-
- case CPM_CLK_SMC2:
- reg = &mpc8xx_immr->im_cpm.cp_simode;
- shift = 28;
- break;
-
- default:
- printk(KERN_ERR "cpm1_clock_setup: invalid clock target\n");
- return -EINVAL;
- }
-
- for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
- if (clk_map[i][0] == target && clk_map[i][1] == clock) {
- bits = clk_map[i][2];
- break;
- }
- }
-
- if (i == ARRAY_SIZE(clk_map)) {
- printk(KERN_ERR "cpm1_clock_setup: invalid clock combination\n");
- return -EINVAL;
- }
-
- bits <<= shift;
- mask <<= shift;
-
- if (reg == &mpc8xx_immr->im_cpm.cp_sicr) {
- if (mode == CPM_CLK_RTX) {
- bits |= bits << 3;
- mask |= mask << 3;
- } else if (mode == CPM_CLK_RX) {
- bits <<= 3;
- mask <<= 3;
- }
- }
-
- out_be32(reg, (in_be32(reg) & ~mask) | bits);
-
- return 0;
-}
-
-/*
- * GPIO LIB API implementation
- */
-#ifdef CONFIG_8xx_GPIO
-
-struct cpm1_gpio16_chip {
- struct of_mm_gpio_chip mm_gc;
- spinlock_t lock;
-
- /* shadowed data register to clear/set bits safely */
- u16 cpdata;
-
- /* IRQ associated with Pins when relevant */
- int irq[16];
-};
-
-static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc)
-{
- struct cpm1_gpio16_chip *cpm1_gc =
- container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc);
- struct cpm_ioport16 __iomem *iop = mm_gc->regs;
-
- cpm1_gc->cpdata = in_be16(&iop->dat);
-}
-
-static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio)
-{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm_ioport16 __iomem *iop = mm_gc->regs;
- u16 pin_mask;
-
- pin_mask = 1 << (15 - gpio);
-
- return !!(in_be16(&iop->dat) & pin_mask);
-}
-
-static void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask,
- int value)
-{
- struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
- struct cpm_ioport16 __iomem *iop = mm_gc->regs;
-
- if (value)
- cpm1_gc->cpdata |= pin_mask;
- else
- cpm1_gc->cpdata &= ~pin_mask;
-
- out_be16(&iop->dat, cpm1_gc->cpdata);
-}
-
-static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
-{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
- unsigned long flags;
- u16 pin_mask = 1 << (15 - gpio);
-
- spin_lock_irqsave(&cpm1_gc->lock, flags);
-
- __cpm1_gpio16_set(mm_gc, pin_mask, value);
-
- spin_unlock_irqrestore(&cpm1_gc->lock, flags);
-}
-
-static int cpm1_gpio16_to_irq(struct gpio_chip *gc, unsigned int gpio)
-{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
-
- return cpm1_gc->irq[gpio] ? : -ENXIO;
-}
-
-static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
-{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
- struct cpm_ioport16 __iomem *iop = mm_gc->regs;
- unsigned long flags;
- u16 pin_mask = 1 << (15 - gpio);
-
- spin_lock_irqsave(&cpm1_gc->lock, flags);
-
- setbits16(&iop->dir, pin_mask);
- __cpm1_gpio16_set(mm_gc, pin_mask, val);
-
- spin_unlock_irqrestore(&cpm1_gc->lock, flags);
-
- return 0;
-}
-
-static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio)
-{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
- struct cpm_ioport16 __iomem *iop = mm_gc->regs;
- unsigned long flags;
- u16 pin_mask = 1 << (15 - gpio);
-
- spin_lock_irqsave(&cpm1_gc->lock, flags);
-
- clrbits16(&iop->dir, pin_mask);
-
- spin_unlock_irqrestore(&cpm1_gc->lock, flags);
-
- return 0;
-}
-
-int cpm1_gpiochip_add16(struct device *dev)
-{
- struct device_node *np = dev->of_node;
- struct cpm1_gpio16_chip *cpm1_gc;
- struct of_mm_gpio_chip *mm_gc;
- struct gpio_chip *gc;
- u16 mask;
-
- cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
- if (!cpm1_gc)
- return -ENOMEM;
-
- spin_lock_init(&cpm1_gc->lock);
-
- if (!of_property_read_u16(np, "fsl,cpm1-gpio-irq-mask", &mask)) {
- int i, j;
-
- for (i = 0, j = 0; i < 16; i++)
- if (mask & (1 << (15 - i)))
- cpm1_gc->irq[i] = irq_of_parse_and_map(np, j++);
- }
-
- mm_gc = &cpm1_gc->mm_gc;
- gc = &mm_gc->gc;
-
- mm_gc->save_regs = cpm1_gpio16_save_regs;
- gc->ngpio = 16;
- gc->direction_input = cpm1_gpio16_dir_in;
- gc->direction_output = cpm1_gpio16_dir_out;
- gc->get = cpm1_gpio16_get;
- gc->set = cpm1_gpio16_set;
- gc->to_irq = cpm1_gpio16_to_irq;
- gc->parent = dev;
- gc->owner = THIS_MODULE;
-
- return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc);
-}
-
-struct cpm1_gpio32_chip {
- struct of_mm_gpio_chip mm_gc;
- spinlock_t lock;
-
- /* shadowed data register to clear/set bits safely */
- u32 cpdata;
-};
-
-static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
-{
- struct cpm1_gpio32_chip *cpm1_gc =
- container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc);
- struct cpm_ioport32b __iomem *iop = mm_gc->regs;
-
- cpm1_gc->cpdata = in_be32(&iop->dat);
-}
-
-static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
-{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm_ioport32b __iomem *iop = mm_gc->regs;
- u32 pin_mask;
-
- pin_mask = 1 << (31 - gpio);
-
- return !!(in_be32(&iop->dat) & pin_mask);
-}
-
-static void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask,
- int value)
-{
- struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
- struct cpm_ioport32b __iomem *iop = mm_gc->regs;
-
- if (value)
- cpm1_gc->cpdata |= pin_mask;
- else
- cpm1_gc->cpdata &= ~pin_mask;
-
- out_be32(&iop->dat, cpm1_gc->cpdata);
-}
-
-static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
-{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
- unsigned long flags;
- u32 pin_mask = 1 << (31 - gpio);
-
- spin_lock_irqsave(&cpm1_gc->lock, flags);
-
- __cpm1_gpio32_set(mm_gc, pin_mask, value);
-
- spin_unlock_irqrestore(&cpm1_gc->lock, flags);
-}
-
-static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
-{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
- struct cpm_ioport32b __iomem *iop = mm_gc->regs;
- unsigned long flags;
- u32 pin_mask = 1 << (31 - gpio);
-
- spin_lock_irqsave(&cpm1_gc->lock, flags);
-
- setbits32(&iop->dir, pin_mask);
- __cpm1_gpio32_set(mm_gc, pin_mask, val);
-
- spin_unlock_irqrestore(&cpm1_gc->lock, flags);
-
- return 0;
-}
-
-static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
-{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
- struct cpm_ioport32b __iomem *iop = mm_gc->regs;
- unsigned long flags;
- u32 pin_mask = 1 << (31 - gpio);
-
- spin_lock_irqsave(&cpm1_gc->lock, flags);
-
- clrbits32(&iop->dir, pin_mask);
-
- spin_unlock_irqrestore(&cpm1_gc->lock, flags);
-
- return 0;
-}
-
-int cpm1_gpiochip_add32(struct device *dev)
-{
- struct device_node *np = dev->of_node;
- struct cpm1_gpio32_chip *cpm1_gc;
- struct of_mm_gpio_chip *mm_gc;
- struct gpio_chip *gc;
-
- cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
- if (!cpm1_gc)
- return -ENOMEM;
-
- spin_lock_init(&cpm1_gc->lock);
-
- mm_gc = &cpm1_gc->mm_gc;
- gc = &mm_gc->gc;
-
- mm_gc->save_regs = cpm1_gpio32_save_regs;
- gc->ngpio = 32;
- gc->direction_input = cpm1_gpio32_dir_in;
- gc->direction_output = cpm1_gpio32_dir_out;
- gc->get = cpm1_gpio32_get;
- gc->set = cpm1_gpio32_set;
- gc->parent = dev;
- gc->owner = THIS_MODULE;
-
- return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc);
-}
-
-#endif /* CONFIG_8xx_GPIO */
diff --git a/arch/powerpc/sysdev/cpm2.c b/arch/powerpc/sysdev/cpm2.c
index 07718b9a2c99..14cc5ea936c0 100644
--- a/arch/powerpc/sysdev/cpm2.c
+++ b/arch/powerpc/sysdev/cpm2.c
@@ -37,12 +37,9 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/mpc8260.h>
#include <asm/page.h>
-#include <asm/pgtable.h>
#include <asm/cpm2.h>
#include <asm/rheap.h>
-#include <asm/fs_pd.h>
#include <sysdev/fsl_soc.h>
@@ -108,7 +105,7 @@ EXPORT_SYMBOL(cpm_command);
* memory mapped space.
* The baud rate clock is the system clock divided by something.
* It was set up long ago during the initial boot phase and is
- * is given to us.
+ * given to us.
* Baud rate clocks are zero-based in the driver code (as that maps
* to port numbers). Documentation uses 1-based numbering.
*/
@@ -120,9 +117,9 @@ void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src)
/* This is good enough to get SMCs running.....
*/
if (brg < 4) {
- bp = cpm2_map_size(im_brgc1, 16);
+ bp = &cpm2_immr->im_brgc1;
} else {
- bp = cpm2_map_size(im_brgc5, 16);
+ bp = &cpm2_immr->im_brgc5;
brg -= 4;
}
bp += brg;
@@ -132,16 +129,14 @@ void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src)
val |= CPM_BRG_DIV16;
out_be32(bp, val);
- cpm2_unmap(bp);
}
EXPORT_SYMBOL(__cpm2_setbrg);
-int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
+int __init cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
{
int ret = 0;
int shift;
int i, bits = 0;
- cpmux_t __iomem *im_cpmux;
u32 __iomem *reg;
u32 mask = 7;
@@ -204,35 +199,33 @@ int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
{CPM_CLK_SCC4, CPM_CLK8, 7},
};
- im_cpmux = cpm2_map(im_cpmux);
-
switch (target) {
case CPM_CLK_SCC1:
- reg = &im_cpmux->cmx_scr;
+ reg = &cpm2_immr->im_cpmux.cmx_scr;
shift = 24;
break;
case CPM_CLK_SCC2:
- reg = &im_cpmux->cmx_scr;
+ reg = &cpm2_immr->im_cpmux.cmx_scr;
shift = 16;
break;
case CPM_CLK_SCC3:
- reg = &im_cpmux->cmx_scr;
+ reg = &cpm2_immr->im_cpmux.cmx_scr;
shift = 8;
break;
case CPM_CLK_SCC4:
- reg = &im_cpmux->cmx_scr;
+ reg = &cpm2_immr->im_cpmux.cmx_scr;
shift = 0;
break;
case CPM_CLK_FCC1:
- reg = &im_cpmux->cmx_fcr;
+ reg = &cpm2_immr->im_cpmux.cmx_fcr;
shift = 24;
break;
case CPM_CLK_FCC2:
- reg = &im_cpmux->cmx_fcr;
+ reg = &cpm2_immr->im_cpmux.cmx_fcr;
shift = 16;
break;
case CPM_CLK_FCC3:
- reg = &im_cpmux->cmx_fcr;
+ reg = &cpm2_immr->im_cpmux.cmx_fcr;
shift = 8;
break;
default:
@@ -262,16 +255,14 @@ int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
out_be32(reg, (in_be32(reg) & ~mask) | bits);
- cpm2_unmap(im_cpmux);
return ret;
}
-int cpm2_smc_clk_setup(enum cpm_clk_target target, int clock)
+int __init cpm2_smc_clk_setup(enum cpm_clk_target target, int clock)
{
int ret = 0;
int shift;
int i, bits = 0;
- cpmux_t __iomem *im_cpmux;
u8 __iomem *reg;
u8 mask = 3;
@@ -286,16 +277,14 @@ int cpm2_smc_clk_setup(enum cpm_clk_target target, int clock)
{CPM_CLK_SMC2, CPM_CLK15, 3},
};
- im_cpmux = cpm2_map(im_cpmux);
-
switch (target) {
case CPM_CLK_SMC1:
- reg = &im_cpmux->cmx_smr;
+ reg = &cpm2_immr->im_cpmux.cmx_smr;
mask = 3;
shift = 4;
break;
case CPM_CLK_SMC2:
- reg = &im_cpmux->cmx_smr;
+ reg = &cpm2_immr->im_cpmux.cmx_smr;
mask = 3;
shift = 0;
break;
@@ -318,7 +307,6 @@ int cpm2_smc_clk_setup(enum cpm_clk_target target, int clock)
out_8(reg, (in_8(reg) & ~mask) | bits);
- cpm2_unmap(im_cpmux);
return ret;
}
@@ -327,7 +315,7 @@ struct cpm2_ioports {
u32 res[3];
};
-void cpm2_set_pin(int port, int pin, int flags)
+void __init cpm2_set_pin(int port, int pin, int flags)
{
struct cpm2_ioports __iomem *iop =
(struct cpm2_ioports __iomem *)&cpm2_immr->im_ioport;
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
index 9e86074719a9..4a59ed1d62ce 100644
--- a/arch/powerpc/sysdev/cpm2_pic.c
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -30,12 +30,10 @@
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <asm/immap_cpm2.h>
-#include <asm/mpc8260.h>
#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/fs_pd.h>
#include "cpm2_pic.h"
@@ -209,7 +207,7 @@ unsigned int cpm2_get_irq(void)
if (irq == 0)
return(-1);
- return irq_linear_revmap(cpm2_pic_host, irq);
+ return irq_find_mapping(cpm2_pic_host, irq);
}
static int cpm2_pic_host_map(struct irq_domain *h, unsigned int virq,
@@ -231,7 +229,7 @@ void cpm2_pic_init(struct device_node *node)
{
int i;
- cpm2_intctl = cpm2_map(im_intctl);
+ cpm2_intctl = &cpm2_immr->im_intctl;
/* Clear the CPM IRQ controller, in case it has any bits set
* from the bootloader
@@ -261,7 +259,8 @@ void cpm2_pic_init(struct device_node *node)
out_be32(&cpm2_intctl->ic_scprrl, 0x05309770);
/* create a legacy host */
- cpm2_pic_host = irq_domain_add_linear(node, 64, &cpm2_pic_host_ops, NULL);
+ cpm2_pic_host = irq_domain_create_linear(of_fwnode_handle(node), 64,
+ &cpm2_pic_host_ops, NULL);
if (cpm2_pic_host == NULL) {
printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
return;
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c
index b74508175b67..07ea605ab0e6 100644
--- a/arch/powerpc/sysdev/cpm_common.c
+++ b/arch/powerpc/sysdev/cpm_common.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Common CPM code
*
@@ -11,18 +12,12 @@
* Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
* 2006 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
*/
#include <linux/init.h>
-#include <linux/of_device.h>
#include <linux/spinlock.h>
#include <linux/export.h>
#include <linux/of.h>
-#include <linux/of_address.h>
#include <linux/slab.h>
#include <asm/udbg.h>
@@ -33,10 +28,6 @@
#include <mm/mmu_decl.h>
-#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
-#include <linux/of_gpio.h>
-#endif
-
static int __init cpm_init(void)
{
struct device_node *np;
@@ -71,6 +62,8 @@ static void udbg_putc_cpm(char c)
void __init udbg_init_cpm(void)
{
#ifdef CONFIG_PPC_8xx
+ mmu_mapin_immr();
+
cpm_udbg_txdesc = (u32 __iomem __force *)
(CONFIG_PPC_EARLY_DEBUG_CPM_ADDR - PHYS_IMMR_BASE +
VIRT_IMMR_BASE);
@@ -94,32 +87,33 @@ void __init udbg_init_cpm(void)
#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
+#include <linux/gpio/driver.h>
+
struct cpm2_ioports {
u32 dir, par, sor, odr, dat;
u32 res[3];
};
struct cpm2_gpio32_chip {
- struct of_mm_gpio_chip mm_gc;
+ struct gpio_chip gc;
+ void __iomem *regs;
spinlock_t lock;
/* shadowed data register to clear/set bits safely */
u32 cpdata;
};
-static void cpm2_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
+static void cpm2_gpio32_save_regs(struct cpm2_gpio32_chip *cpm2_gc)
{
- struct cpm2_gpio32_chip *cpm2_gc =
- container_of(mm_gc, struct cpm2_gpio32_chip, mm_gc);
- struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ struct cpm2_ioports __iomem *iop = cpm2_gc->regs;
cpm2_gc->cpdata = in_be32(&iop->dat);
}
static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
+ struct cpm2_ioports __iomem *iop = cpm2_gc->regs;
u32 pin_mask;
pin_mask = 1 << (31 - gpio);
@@ -127,11 +121,9 @@ static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
return !!(in_be32(&iop->dat) & pin_mask);
}
-static void __cpm2_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask,
- int value)
+static void __cpm2_gpio32_set(struct cpm2_gpio32_chip *cpm2_gc, u32 pin_mask, int value)
{
- struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(&mm_gc->gc);
- struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ struct cpm2_ioports __iomem *iop = cpm2_gc->regs;
if (value)
cpm2_gc->cpdata |= pin_mask;
@@ -141,32 +133,32 @@ static void __cpm2_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask,
out_be32(&iop->dat, cpm2_gc->cpdata);
}
-static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
+static int cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
spin_lock_irqsave(&cpm2_gc->lock, flags);
- __cpm2_gpio32_set(mm_gc, pin_mask, value);
+ __cpm2_gpio32_set(cpm2_gc, pin_mask, value);
spin_unlock_irqrestore(&cpm2_gc->lock, flags);
+
+ return 0;
}
static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
- struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ struct cpm2_ioports __iomem *iop = cpm2_gc->regs;
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
spin_lock_irqsave(&cpm2_gc->lock, flags);
setbits32(&iop->dir, pin_mask);
- __cpm2_gpio32_set(mm_gc, pin_mask, val);
+ __cpm2_gpio32_set(cpm2_gc, pin_mask, val);
spin_unlock_irqrestore(&cpm2_gc->lock, flags);
@@ -175,9 +167,8 @@ static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
- struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ struct cpm2_ioports __iomem *iop = cpm2_gc->regs;
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
@@ -194,19 +185,17 @@ int cpm2_gpiochip_add32(struct device *dev)
{
struct device_node *np = dev->of_node;
struct cpm2_gpio32_chip *cpm2_gc;
- struct of_mm_gpio_chip *mm_gc;
struct gpio_chip *gc;
- cpm2_gc = kzalloc(sizeof(*cpm2_gc), GFP_KERNEL);
+ cpm2_gc = devm_kzalloc(dev, sizeof(*cpm2_gc), GFP_KERNEL);
if (!cpm2_gc)
return -ENOMEM;
spin_lock_init(&cpm2_gc->lock);
- mm_gc = &cpm2_gc->mm_gc;
- gc = &mm_gc->gc;
+ gc = &cpm2_gc->gc;
- mm_gc->save_regs = cpm2_gpio32_save_regs;
+ gc->base = -1;
gc->ngpio = 32;
gc->direction_input = cpm2_gpio32_dir_in;
gc->direction_output = cpm2_gpio32_dir_out;
@@ -215,6 +204,16 @@ int cpm2_gpiochip_add32(struct device *dev)
gc->parent = dev;
gc->owner = THIS_MODULE;
- return of_mm_gpiochip_add_data(np, mm_gc, cpm2_gc);
+ gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
+ if (!gc->label)
+ return -ENOMEM;
+
+ cpm2_gc->regs = devm_of_iomap(dev, np, 0, NULL);
+ if (IS_ERR(cpm2_gc->regs))
+ return PTR_ERR(cpm2_gc->regs);
+
+ cpm2_gpio32_save_regs(cpm2_gc);
+
+ return devm_gpiochip_add_data(dev, gc, cpm2_gc);
}
#endif /* CONFIG_CPM2 || CONFIG_8xx_GPIO */
diff --git a/arch/powerpc/sysdev/cpm_gpio.c b/arch/powerpc/sysdev/cpm_gpio.c
index 0695d26bd301..40f57111e93e 100644
--- a/arch/powerpc/sysdev/cpm_gpio.c
+++ b/arch/powerpc/sysdev/cpm_gpio.c
@@ -9,7 +9,8 @@
*/
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <asm/cpm.h>
#ifdef CONFIG_8xx_GPIO
diff --git a/arch/powerpc/sysdev/dart.h b/arch/powerpc/sysdev/dart.h
index ff202edb0591..7f5df03d334c 100644
--- a/arch/powerpc/sysdev/dart.h
+++ b/arch/powerpc/sysdev/dart.h
@@ -1,19 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _POWERPC_SYSDEV_DART_H
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index a5b40d1460f1..c0d10c149661 100644
--- a/arch/powerpc/sysdev/dart_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* arch/powerpc/sysdev/dart_iommu.c
*
@@ -10,21 +11,6 @@
* Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
*
* Dynamic DMA mapping support, Apple U3, U4 & IBM CPC925 "DART" iommu.
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
@@ -38,9 +24,8 @@
#include <linux/suspend.h>
#include <linux/memblock.h>
#include <linux/gfp.h>
-#include <linux/kmemleak.h>
+#include <linux/of_address.h>
#include <asm/io.h>
-#include <asm/prom.h>
#include <asm/iommu.h>
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
@@ -158,7 +143,7 @@ static void dart_cache_sync(unsigned int *base, unsigned int count)
unsigned int tmp;
/* Perform a standard cache flush */
- flush_inval_dcache_range(start, end);
+ flush_dcache_range(start, end);
/*
* Perform the sequence described in the CPC925 manual to
@@ -240,7 +225,7 @@ static void dart_free(struct iommu_table *tbl, long index, long npages)
dart_cache_sync(orig_dp, orig_npages);
}
-static void allocate_dart(void)
+static void __init allocate_dart(void)
{
unsigned long tmp;
@@ -251,17 +236,20 @@ static void allocate_dart(void)
* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we
* will blow up an entire large page anyway in the kernel mapping.
*/
- dart_tablebase = __va(memblock_alloc_base(1UL<<24,
- 1UL<<24, 0x80000000L));
-
- /* There is no point scanning the DART space for leaks*/
- kmemleak_no_scan((void *)dart_tablebase);
+ dart_tablebase = memblock_alloc_try_nid_raw(SZ_16M, SZ_16M,
+ MEMBLOCK_LOW_LIMIT, SZ_2G,
+ NUMA_NO_NODE);
+ if (!dart_tablebase)
+ panic("Failed to allocate 16MB below 2GB for DART table\n");
/* Allocate a spare page to map all invalid DART pages. We need to do
* that to work around what looks like a problem with the HT bridge
* prefetching into invalid pages and corrupting data
*/
tmp = memblock_phys_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE);
+ if (!tmp)
+ panic("DART: table allocation failed\n");
+
dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) &
DARTMAP_RPNMASK);
@@ -352,7 +340,8 @@ static void iommu_table_dart_setup(void)
iommu_table_dart.it_index = 0;
iommu_table_dart.it_blocksize = 1;
iommu_table_dart.it_ops = &iommu_dart_ops;
- iommu_init_table(&iommu_table_dart, -1);
+ if (!iommu_init_table(&iommu_table_dart, -1, 0, 0))
+ panic("Failed to initialize iommu table");
/* Reserve the last page of the DART to avoid possible prefetch
* past the DART mapped area
@@ -360,13 +349,6 @@ static void iommu_table_dart_setup(void)
set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map);
}
-static void pci_dma_dev_setup_dart(struct pci_dev *dev)
-{
- if (dart_is_u4)
- set_dma_offset(&dev->dev, DART_U4_BYPASS_BASE);
- set_iommu_table_base(&dev->dev, &iommu_table_dart);
-}
-
static void pci_dma_bus_setup_dart(struct pci_bus *bus)
{
if (!iommu_table_dart_inited) {
@@ -390,27 +372,18 @@ static bool dart_device_on_pcie(struct device *dev)
return false;
}
-static int dart_dma_set_mask(struct device *dev, u64 dma_mask)
+static void pci_dma_dev_setup_dart(struct pci_dev *dev)
{
- if (!dev->dma_mask || !dma_supported(dev, dma_mask))
- return -EIO;
-
- /* U4 supports a DART bypass, we use it for 64-bit capable
- * devices to improve performances. However, that only works
- * for devices connected to U4 own PCIe interface, not bridged
- * through hypertransport. We need the device to support at
- * least 40 bits of addresses.
- */
- if (dart_device_on_pcie(dev) && dma_mask >= DMA_BIT_MASK(40)) {
- dev_info(dev, "Using 64-bit DMA iommu bypass\n");
- set_dma_ops(dev, &dma_nommu_ops);
- } else {
- dev_info(dev, "Using 32-bit DMA via iommu\n");
- set_dma_ops(dev, &dma_iommu_ops);
- }
+ if (dart_is_u4 && dart_device_on_pcie(&dev->dev))
+ dev->dev.archdata.dma_offset = DART_U4_BYPASS_BASE;
+ set_iommu_table_base(&dev->dev, &iommu_table_dart);
+}
- *dev->dma_mask = dma_mask;
- return 0;
+static bool iommu_bypass_supported_dart(struct pci_dev *dev, u64 mask)
+{
+ return dart_is_u4 &&
+ dart_device_on_pcie(&dev->dev) &&
+ mask >= DMA_BIT_MASK(40);
}
void __init iommu_init_early_dart(struct pci_controller_ops *controller_ops)
@@ -427,27 +400,23 @@ void __init iommu_init_early_dart(struct pci_controller_ops *controller_ops)
}
/* Initialize the DART HW */
- if (dart_init(dn) != 0)
- goto bail;
-
- /* Setup bypass if supported */
- if (dart_is_u4)
- ppc_md.dma_set_mask = dart_dma_set_mask;
-
+ if (dart_init(dn) != 0) {
+ of_node_put(dn);
+ return;
+ }
+ /*
+ * U4 supports a DART bypass, we use it for 64-bit capable devices to
+ * improve performance. However, that only works for devices connected
+ * to the U4 own PCIe interface, not bridged through hypertransport.
+ * We need the device to support at least 40 bits of addresses.
+ */
controller_ops->dma_dev_setup = pci_dma_dev_setup_dart;
controller_ops->dma_bus_setup = pci_dma_bus_setup_dart;
+ controller_ops->iommu_bypass_supported = iommu_bypass_supported_dart;
/* Setup pci_dma ops */
set_pci_dma_ops(&dma_iommu_ops);
- return;
-
- bail:
- /* If init failed, use direct iommu and null setup functions */
- controller_ops->dma_dev_setup = NULL;
- controller_ops->dma_bus_setup = NULL;
-
- /* Setup pci_dma ops */
- set_pci_dma_ops(&dma_nommu_ops);
+ of_node_put(dn);
}
#ifdef CONFIG_PM
diff --git a/arch/powerpc/sysdev/dcr-low.S b/arch/powerpc/sysdev/dcr-low.S
index e687bb2003ff..e8401b205d38 100644
--- a/arch/powerpc/sysdev/dcr-low.S
+++ b/arch/powerpc/sysdev/dcr-low.S
@@ -1,21 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* "Indirect" DCR access
*
* Copyright (c) 2004 Eugene Surovegin <ebs@ebshome.net>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
+#include <linux/export.h>
#include <asm/ppc_asm.h>
#include <asm/processor.h>
#include <asm/bug.h>
-#include <asm/export.h>
#define DCR_ACCESS_PROLOG(table) \
- cmpli cr0,r3,1024; \
+ cmplwi cr0,r3,1024; \
rlwinm r3,r3,4,18,27; \
lis r5,table@h; \
ori r5,r5,table@l; \
diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c
index d72eda568b7d..cb44a69958e7 100644
--- a/arch/powerpc/sysdev/dcr.c
+++ b/arch/powerpc/sysdev/dcr.c
@@ -1,130 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (c) Copyright 2006 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#undef DEBUG
#include <linux/kernel.h>
#include <linux/export.h>
-#include <asm/prom.h>
+#include <linux/of_address.h>
#include <asm/dcr.h>
-#ifdef CONFIG_PPC_DCR_MMIO
-static struct device_node *find_dcr_parent(struct device_node *node)
-{
- struct device_node *par, *tmp;
- const u32 *p;
-
- for (par = of_node_get(node); par;) {
- if (of_get_property(par, "dcr-controller", NULL))
- break;
- p = of_get_property(par, "dcr-parent", NULL);
- tmp = par;
- if (p == NULL)
- par = of_get_parent(par);
- else
- par = of_find_node_by_phandle(*p);
- of_node_put(tmp);
- }
- return par;
-}
-#endif
-
-#if defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO)
-
-bool dcr_map_ok_generic(dcr_host_t host)
-{
- if (host.type == DCR_HOST_NATIVE)
- return dcr_map_ok_native(host.host.native);
- else if (host.type == DCR_HOST_MMIO)
- return dcr_map_ok_mmio(host.host.mmio);
- else
- return false;
-}
-EXPORT_SYMBOL_GPL(dcr_map_ok_generic);
-
-dcr_host_t dcr_map_generic(struct device_node *dev,
- unsigned int dcr_n,
- unsigned int dcr_c)
-{
- dcr_host_t host;
- struct device_node *dp;
- const char *prop;
-
- host.type = DCR_HOST_INVALID;
-
- dp = find_dcr_parent(dev);
- if (dp == NULL)
- return host;
-
- prop = of_get_property(dp, "dcr-access-method", NULL);
-
- pr_debug("dcr_map_generic(dcr-access-method = %s)\n", prop);
-
- if (!strcmp(prop, "native")) {
- host.type = DCR_HOST_NATIVE;
- host.host.native = dcr_map_native(dev, dcr_n, dcr_c);
- } else if (!strcmp(prop, "mmio")) {
- host.type = DCR_HOST_MMIO;
- host.host.mmio = dcr_map_mmio(dev, dcr_n, dcr_c);
- }
-
- of_node_put(dp);
- return host;
-}
-EXPORT_SYMBOL_GPL(dcr_map_generic);
-
-void dcr_unmap_generic(dcr_host_t host, unsigned int dcr_c)
-{
- if (host.type == DCR_HOST_NATIVE)
- dcr_unmap_native(host.host.native, dcr_c);
- else if (host.type == DCR_HOST_MMIO)
- dcr_unmap_mmio(host.host.mmio, dcr_c);
- else /* host.type == DCR_HOST_INVALID */
- WARN_ON(true);
-}
-EXPORT_SYMBOL_GPL(dcr_unmap_generic);
-
-u32 dcr_read_generic(dcr_host_t host, unsigned int dcr_n)
-{
- if (host.type == DCR_HOST_NATIVE)
- return dcr_read_native(host.host.native, dcr_n);
- else if (host.type == DCR_HOST_MMIO)
- return dcr_read_mmio(host.host.mmio, dcr_n);
- else /* host.type == DCR_HOST_INVALID */
- WARN_ON(true);
- return 0;
-}
-EXPORT_SYMBOL_GPL(dcr_read_generic);
-
-void dcr_write_generic(dcr_host_t host, unsigned int dcr_n, u32 value)
-{
- if (host.type == DCR_HOST_NATIVE)
- dcr_write_native(host.host.native, dcr_n, value);
- else if (host.type == DCR_HOST_MMIO)
- dcr_write_mmio(host.host.mmio, dcr_n, value);
- else /* host.type == DCR_HOST_INVALID */
- WARN_ON(true);
-}
-EXPORT_SYMBOL_GPL(dcr_write_generic);
-
-#endif /* defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO) */
-
unsigned int dcr_resource_start(const struct device_node *np,
unsigned int index)
{
@@ -150,86 +36,5 @@ unsigned int dcr_resource_len(const struct device_node *np, unsigned int index)
}
EXPORT_SYMBOL_GPL(dcr_resource_len);
-#ifdef CONFIG_PPC_DCR_MMIO
-
-static u64 of_translate_dcr_address(struct device_node *dev,
- unsigned int dcr_n,
- unsigned int *out_stride)
-{
- struct device_node *dp;
- const u32 *p;
- unsigned int stride;
- u64 ret = OF_BAD_ADDR;
-
- dp = find_dcr_parent(dev);
- if (dp == NULL)
- return OF_BAD_ADDR;
-
- /* Stride is not properly defined yet, default to 0x10 for Axon */
- p = of_get_property(dp, "dcr-mmio-stride", NULL);
- stride = (p == NULL) ? 0x10 : *p;
-
- /* XXX FIXME: Which property name is to use of the 2 following ? */
- p = of_get_property(dp, "dcr-mmio-range", NULL);
- if (p == NULL)
- p = of_get_property(dp, "dcr-mmio-space", NULL);
- if (p == NULL)
- goto done;
-
- /* Maybe could do some better range checking here */
- ret = of_translate_address(dp, p);
- if (ret != OF_BAD_ADDR)
- ret += (u64)(stride) * (u64)dcr_n;
- if (out_stride)
- *out_stride = stride;
-
- done:
- of_node_put(dp);
- return ret;
-}
-
-dcr_host_mmio_t dcr_map_mmio(struct device_node *dev,
- unsigned int dcr_n,
- unsigned int dcr_c)
-{
- dcr_host_mmio_t ret = { .token = NULL, .stride = 0, .base = dcr_n };
- u64 addr;
-
- pr_debug("dcr_map(%pOF, 0x%x, 0x%x)\n",
- dev, dcr_n, dcr_c);
-
- addr = of_translate_dcr_address(dev, dcr_n, &ret.stride);
- pr_debug("translates to addr: 0x%llx, stride: 0x%x\n",
- (unsigned long long) addr, ret.stride);
- if (addr == OF_BAD_ADDR)
- return ret;
- pr_debug("mapping 0x%x bytes\n", dcr_c * ret.stride);
- ret.token = ioremap(addr, dcr_c * ret.stride);
- if (ret.token == NULL)
- return ret;
- pr_debug("mapped at 0x%p -> base is 0x%p\n",
- ret.token, ret.token - dcr_n * ret.stride);
- ret.token -= dcr_n * ret.stride;
- return ret;
-}
-EXPORT_SYMBOL_GPL(dcr_map_mmio);
-
-void dcr_unmap_mmio(dcr_host_mmio_t host, unsigned int dcr_c)
-{
- dcr_host_mmio_t h = host;
-
- if (h.token == NULL)
- return;
- h.token += host.base * h.stride;
- iounmap(h.token);
- h.token = NULL;
-}
-EXPORT_SYMBOL_GPL(dcr_unmap_mmio);
-
-#endif /* defined(CONFIG_PPC_DCR_MMIO) */
-
-#ifdef CONFIG_PPC_DCR_NATIVE
DEFINE_SPINLOCK(dcr_ind_lock);
EXPORT_SYMBOL_GPL(dcr_ind_lock);
-#endif /* defined(CONFIG_PPC_DCR_NATIVE) */
-
diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c
index 48866e6c1efb..b6f9774038e1 100644
--- a/arch/powerpc/sysdev/ehv_pic.c
+++ b/arch/powerpc/sysdev/ehv_pic.c
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -41,33 +42,33 @@ static u32 __iomem *mpic_percpu_base_vaddr;
* Linux descriptor level callbacks
*/
-void ehv_pic_unmask_irq(struct irq_data *d)
+static void ehv_pic_unmask_irq(struct irq_data *d)
{
unsigned int src = virq_to_hw(d->irq);
ev_int_set_mask(src, 0);
}
-void ehv_pic_mask_irq(struct irq_data *d)
+static void ehv_pic_mask_irq(struct irq_data *d)
{
unsigned int src = virq_to_hw(d->irq);
ev_int_set_mask(src, 1);
}
-void ehv_pic_end_irq(struct irq_data *d)
+static void ehv_pic_end_irq(struct irq_data *d)
{
unsigned int src = virq_to_hw(d->irq);
ev_int_eoi(src);
}
-void ehv_pic_direct_end_irq(struct irq_data *d)
+static void ehv_pic_direct_end_irq(struct irq_data *d)
{
out_be32(mpic_percpu_base_vaddr + MPIC_EOI / 4, 0);
}
-int ehv_pic_set_affinity(struct irq_data *d, const struct cpumask *dest,
+static int ehv_pic_set_affinity(struct irq_data *d, const struct cpumask *dest,
bool force)
{
unsigned int src = virq_to_hw(d->irq);
@@ -108,7 +109,7 @@ static unsigned int ehv_pic_type_to_vecpri(unsigned int type)
}
}
-int ehv_pic_set_irq_type(struct irq_data *d, unsigned int flow_type)
+static int ehv_pic_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
unsigned int src = virq_to_hw(d->irq);
unsigned int vecpri, vold, vnew, prio, cpu_dest;
@@ -174,7 +175,7 @@ unsigned int ehv_pic_get_irq(void)
* this will also setup revmap[] in the slow path for the first
* time, next calls will always use fast path by indexing revmap
*/
- return irq_linear_revmap(global_ehv_pic->irqhost, irq);
+ return irq_find_mapping(global_ehv_pic->irqhost, irq);
}
static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node,
@@ -255,7 +256,6 @@ void __init ehv_pic_init(void)
{
struct device_node *np, *np2;
struct ehv_pic *ehv_pic;
- int coreint_flag = 1;
np = of_find_compatible_node(NULL, NULL, "epapr,hv-pic");
if (!np) {
@@ -263,17 +263,15 @@ void __init ehv_pic_init(void)
return;
}
- if (!of_find_property(np, "has-external-proxy", NULL))
- coreint_flag = 0;
-
ehv_pic = kzalloc(sizeof(struct ehv_pic), GFP_KERNEL);
if (!ehv_pic) {
of_node_put(np);
return;
}
- ehv_pic->irqhost = irq_domain_add_linear(np, NR_EHV_PIC_INTS,
- &ehv_pic_host_ops, ehv_pic);
+ ehv_pic->irqhost = irq_domain_create_linear(of_fwnode_handle(np),
+ NR_EHV_PIC_INTS,
+ &ehv_pic_host_ops, ehv_pic);
if (!ehv_pic->irqhost) {
of_node_put(np);
kfree(ehv_pic);
@@ -291,8 +289,8 @@ void __init ehv_pic_init(void)
ehv_pic->hc_irq = ehv_pic_irq_chip;
ehv_pic->hc_irq.irq_set_affinity = ehv_pic_set_affinity;
- ehv_pic->coreint_flag = coreint_flag;
+ ehv_pic->coreint_flag = of_property_read_bool(np, "has-external-proxy");
global_ehv_pic = ehv_pic;
- irq_set_default_host(global_ehv_pic->irqhost);
+ irq_set_default_domain(global_ehv_pic->irqhost);
}
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h b/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h
deleted file mode 100644
index 2aa97ddb7b78..000000000000
--- a/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2009-2010, 2012 Freescale Semiconductor, Inc
- *
- * QorIQ based Cache Controller Memory Mapped Registers
- *
- * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __FSL_85XX_CACHE_CTLR_H__
-#define __FSL_85XX_CACHE_CTLR_H__
-
-#define L2CR_L2FI 0x40000000 /* L2 flash invalidate */
-#define L2CR_L2IO 0x00200000 /* L2 instruction only */
-#define L2CR_SRAM_ZERO 0x00000000 /* L2SRAM zero size */
-#define L2CR_SRAM_FULL 0x00010000 /* L2SRAM full size */
-#define L2CR_SRAM_HALF 0x00020000 /* L2SRAM half size */
-#define L2CR_SRAM_TWO_HALFS 0x00030000 /* L2SRAM two half sizes */
-#define L2CR_SRAM_QUART 0x00040000 /* L2SRAM one quarter size */
-#define L2CR_SRAM_TWO_QUARTS 0x00050000 /* L2SRAM two quarter size */
-#define L2CR_SRAM_EIGHTH 0x00060000 /* L2SRAM one eighth size */
-#define L2CR_SRAM_TWO_EIGHTH 0x00070000 /* L2SRAM two eighth size */
-
-#define L2SRAM_OPTIMAL_SZ_SHIFT 0x00000003 /* Optimum size for L2SRAM */
-
-#define L2SRAM_BAR_MSK_LO18 0xFFFFC000 /* Lower 18 bits */
-#define L2SRAM_BARE_MSK_HI4 0x0000000F /* Upper 4 bits */
-
-enum cache_sram_lock_ways {
- LOCK_WAYS_ZERO,
- LOCK_WAYS_EIGHTH,
- LOCK_WAYS_TWO_EIGHTH,
- LOCK_WAYS_HALF = 4,
- LOCK_WAYS_FULL = 8,
-};
-
-struct mpc85xx_l2ctlr {
- u32 ctl; /* 0x000 - L2 control */
- u8 res1[0xC];
- u32 ewar0; /* 0x010 - External write address 0 */
- u32 ewarea0; /* 0x014 - External write address extended 0 */
- u32 ewcr0; /* 0x018 - External write ctrl */
- u8 res2[4];
- u32 ewar1; /* 0x020 - External write address 1 */
- u32 ewarea1; /* 0x024 - External write address extended 1 */
- u32 ewcr1; /* 0x028 - External write ctrl 1 */
- u8 res3[4];
- u32 ewar2; /* 0x030 - External write address 2 */
- u32 ewarea2; /* 0x034 - External write address extended 2 */
- u32 ewcr2; /* 0x038 - External write ctrl 2 */
- u8 res4[4];
- u32 ewar3; /* 0x040 - External write address 3 */
- u32 ewarea3; /* 0x044 - External write address extended 3 */
- u32 ewcr3; /* 0x048 - External write ctrl 3 */
- u8 res5[0xB4];
- u32 srbar0; /* 0x100 - SRAM base address 0 */
- u32 srbarea0; /* 0x104 - SRAM base addr reg ext address 0 */
- u32 srbar1; /* 0x108 - SRAM base address 1 */
- u32 srbarea1; /* 0x10C - SRAM base addr reg ext address 1 */
- u8 res6[0xCF0];
- u32 errinjhi; /* 0xE00 - Error injection mask high */
- u32 errinjlo; /* 0xE04 - Error injection mask low */
- u32 errinjctl; /* 0xE08 - Error injection tag/ecc control */
- u8 res7[0x14];
- u32 captdatahi; /* 0xE20 - Error data high capture */
- u32 captdatalo; /* 0xE24 - Error data low capture */
- u32 captecc; /* 0xE28 - Error syndrome */
- u8 res8[0x14];
- u32 errdet; /* 0xE40 - Error detect */
- u32 errdis; /* 0xE44 - Error disable */
- u32 errinten; /* 0xE48 - Error interrupt enable */
- u32 errattr; /* 0xE4c - Error attribute capture */
- u32 erradrrl; /* 0xE50 - Error address capture low */
- u32 erradrrh; /* 0xE54 - Error address capture high */
- u32 errctl; /* 0xE58 - Error control */
- u8 res9[0x1A4];
-};
-
-struct sram_parameters {
- unsigned int sram_size;
- phys_addr_t sram_offset;
-};
-
-extern int instantiate_cache_sram(struct platform_device *dev,
- struct sram_parameters sram_params);
-extern void remove_cache_sram(struct platform_device *dev);
-
-#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
deleted file mode 100644
index 15cbdd4fde06..000000000000
--- a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright 2009-2010 Freescale Semiconductor, Inc.
- *
- * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM
- *
- * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
- *
- * This file is derived from the original work done
- * by Sylvain Munaut for the Bestcomm SRAM allocator.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/of_platform.h>
-#include <asm/pgtable.h>
-#include <asm/fsl_85xx_cache_sram.h>
-
-#include "fsl_85xx_cache_ctlr.h"
-
-struct mpc85xx_cache_sram *cache_sram;
-
-void *mpc85xx_cache_sram_alloc(unsigned int size,
- phys_addr_t *phys, unsigned int align)
-{
- unsigned long offset;
- unsigned long flags;
-
- if (unlikely(cache_sram == NULL))
- return NULL;
-
- if (!size || (size > cache_sram->size) || (align > cache_sram->size)) {
- pr_err("%s(): size(=%x) or align(=%x) zero or too big\n",
- __func__, size, align);
- return NULL;
- }
-
- if ((align & (align - 1)) || align <= 1) {
- pr_err("%s(): align(=%x) must be power of two and >1\n",
- __func__, align);
- return NULL;
- }
-
- spin_lock_irqsave(&cache_sram->lock, flags);
- offset = rh_alloc_align(cache_sram->rh, size, align, NULL);
- spin_unlock_irqrestore(&cache_sram->lock, flags);
-
- if (IS_ERR_VALUE(offset))
- return NULL;
-
- *phys = cache_sram->base_phys + offset;
-
- return (unsigned char *)cache_sram->base_virt + offset;
-}
-EXPORT_SYMBOL(mpc85xx_cache_sram_alloc);
-
-void mpc85xx_cache_sram_free(void *ptr)
-{
- unsigned long flags;
- BUG_ON(!ptr);
-
- spin_lock_irqsave(&cache_sram->lock, flags);
- rh_free(cache_sram->rh, ptr - cache_sram->base_virt);
- spin_unlock_irqrestore(&cache_sram->lock, flags);
-}
-EXPORT_SYMBOL(mpc85xx_cache_sram_free);
-
-int __init instantiate_cache_sram(struct platform_device *dev,
- struct sram_parameters sram_params)
-{
- int ret = 0;
-
- if (cache_sram) {
- dev_err(&dev->dev, "Already initialized cache-sram\n");
- return -EBUSY;
- }
-
- cache_sram = kzalloc(sizeof(struct mpc85xx_cache_sram), GFP_KERNEL);
- if (!cache_sram) {
- dev_err(&dev->dev, "Out of memory for cache_sram structure\n");
- return -ENOMEM;
- }
-
- cache_sram->base_phys = sram_params.sram_offset;
- cache_sram->size = sram_params.sram_size;
-
- if (!request_mem_region(cache_sram->base_phys, cache_sram->size,
- "fsl_85xx_cache_sram")) {
- dev_err(&dev->dev, "%pOF: request memory failed\n",
- dev->dev.of_node);
- ret = -ENXIO;
- goto out_free;
- }
-
- cache_sram->base_virt = ioremap_coherent(cache_sram->base_phys,
- cache_sram->size);
- if (!cache_sram->base_virt) {
- dev_err(&dev->dev, "%pOF: ioremap_coherent failed\n",
- dev->dev.of_node);
- ret = -ENOMEM;
- goto out_release;
- }
-
- cache_sram->rh = rh_create(sizeof(unsigned int));
- if (IS_ERR(cache_sram->rh)) {
- dev_err(&dev->dev, "%pOF: Unable to create remote heap\n",
- dev->dev.of_node);
- ret = PTR_ERR(cache_sram->rh);
- goto out_unmap;
- }
-
- rh_attach_region(cache_sram->rh, 0, cache_sram->size);
- spin_lock_init(&cache_sram->lock);
-
- dev_info(&dev->dev, "[base:0x%llx, size:0x%x] configured and loaded\n",
- (unsigned long long)cache_sram->base_phys, cache_sram->size);
-
- return 0;
-
-out_unmap:
- iounmap(cache_sram->base_virt);
-
-out_release:
- release_mem_region(cache_sram->base_phys, cache_sram->size);
-
-out_free:
- kfree(cache_sram);
- return ret;
-}
-
-void remove_cache_sram(struct platform_device *dev)
-{
- BUG_ON(!cache_sram);
-
- rh_detach_region(cache_sram->rh, 0, cache_sram->size);
- rh_destroy(cache_sram->rh);
-
- iounmap(cache_sram->base_virt);
- release_mem_region(cache_sram->base_phys, cache_sram->size);
-
- kfree(cache_sram);
- cache_sram = NULL;
-
- dev_info(&dev->dev, "MPC85xx Cache-SRAM driver unloaded\n");
-}
diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
deleted file mode 100644
index c27058e5df26..000000000000
--- a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright 2009-2010, 2012 Freescale Semiconductor, Inc.
- *
- * QorIQ (P1/P2) L2 controller init for Cache-SRAM instantiation
- *
- * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <asm/io.h>
-
-#include "fsl_85xx_cache_ctlr.h"
-
-static char *sram_size;
-static char *sram_offset;
-struct mpc85xx_l2ctlr __iomem *l2ctlr;
-
-static int get_cache_sram_params(struct sram_parameters *sram_params)
-{
- unsigned long long addr;
- unsigned int size;
-
- if (!sram_size || (kstrtouint(sram_size, 0, &size) < 0))
- return -EINVAL;
-
- if (!sram_offset || (kstrtoull(sram_offset, 0, &addr) < 0))
- return -EINVAL;
-
- sram_params->sram_offset = addr;
- sram_params->sram_size = size;
-
- return 0;
-}
-
-static int __init get_size_from_cmdline(char *str)
-{
- if (!str)
- return 0;
-
- sram_size = str;
- return 1;
-}
-
-static int __init get_offset_from_cmdline(char *str)
-{
- if (!str)
- return 0;
-
- sram_offset = str;
- return 1;
-}
-
-__setup("cache-sram-size=", get_size_from_cmdline);
-__setup("cache-sram-offset=", get_offset_from_cmdline);
-
-static int mpc85xx_l2ctlr_of_probe(struct platform_device *dev)
-{
- long rval;
- unsigned int rem;
- unsigned char ways;
- const unsigned int *prop;
- unsigned int l2cache_size;
- struct sram_parameters sram_params;
-
- if (!dev->dev.of_node) {
- dev_err(&dev->dev, "Device's OF-node is NULL\n");
- return -EINVAL;
- }
-
- prop = of_get_property(dev->dev.of_node, "cache-size", NULL);
- if (!prop) {
- dev_err(&dev->dev, "Missing L2 cache-size\n");
- return -EINVAL;
- }
- l2cache_size = *prop;
-
- if (get_cache_sram_params(&sram_params))
- return 0; /* fall back to L2 cache only */
-
- rem = l2cache_size % sram_params.sram_size;
- ways = LOCK_WAYS_FULL * sram_params.sram_size / l2cache_size;
- if (rem || (ways & (ways - 1))) {
- dev_err(&dev->dev, "Illegal cache-sram-size in command line\n");
- return -EINVAL;
- }
-
- l2ctlr = of_iomap(dev->dev.of_node, 0);
- if (!l2ctlr) {
- dev_err(&dev->dev, "Can't map L2 controller\n");
- return -EINVAL;
- }
-
- /*
- * Write bits[0-17] to srbar0
- */
- out_be32(&l2ctlr->srbar0,
- lower_32_bits(sram_params.sram_offset) & L2SRAM_BAR_MSK_LO18);
-
- /*
- * Write bits[18-21] to srbare0
- */
-#ifdef CONFIG_PHYS_64BIT
- out_be32(&l2ctlr->srbarea0,
- upper_32_bits(sram_params.sram_offset) & L2SRAM_BARE_MSK_HI4);
-#endif
-
- clrsetbits_be32(&l2ctlr->ctl, L2CR_L2E, L2CR_L2FI);
-
- switch (ways) {
- case LOCK_WAYS_EIGHTH:
- setbits32(&l2ctlr->ctl,
- L2CR_L2E | L2CR_L2FI | L2CR_SRAM_EIGHTH);
- break;
-
- case LOCK_WAYS_TWO_EIGHTH:
- setbits32(&l2ctlr->ctl,
- L2CR_L2E | L2CR_L2FI | L2CR_SRAM_QUART);
- break;
-
- case LOCK_WAYS_HALF:
- setbits32(&l2ctlr->ctl,
- L2CR_L2E | L2CR_L2FI | L2CR_SRAM_HALF);
- break;
-
- case LOCK_WAYS_FULL:
- default:
- setbits32(&l2ctlr->ctl,
- L2CR_L2E | L2CR_L2FI | L2CR_SRAM_FULL);
- break;
- }
- eieio();
-
- rval = instantiate_cache_sram(dev, sram_params);
- if (rval < 0) {
- dev_err(&dev->dev, "Can't instantiate Cache-SRAM\n");
- iounmap(l2ctlr);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int mpc85xx_l2ctlr_of_remove(struct platform_device *dev)
-{
- BUG_ON(!l2ctlr);
-
- iounmap(l2ctlr);
- remove_cache_sram(dev);
- dev_info(&dev->dev, "MPC85xx L2 controller unloaded\n");
-
- return 0;
-}
-
-static const struct of_device_id mpc85xx_l2ctlr_of_match[] = {
- {
- .compatible = "fsl,p2020-l2-cache-controller",
- },
- {
- .compatible = "fsl,p2010-l2-cache-controller",
- },
- {
- .compatible = "fsl,p1020-l2-cache-controller",
- },
- {
- .compatible = "fsl,p1011-l2-cache-controller",
- },
- {
- .compatible = "fsl,p1013-l2-cache-controller",
- },
- {
- .compatible = "fsl,p1022-l2-cache-controller",
- },
- {
- .compatible = "fsl,mpc8548-l2-cache-controller",
- },
- { .compatible = "fsl,mpc8544-l2-cache-controller",},
- { .compatible = "fsl,mpc8572-l2-cache-controller",},
- { .compatible = "fsl,mpc8536-l2-cache-controller",},
- { .compatible = "fsl,p1021-l2-cache-controller",},
- { .compatible = "fsl,p1012-l2-cache-controller",},
- { .compatible = "fsl,p1025-l2-cache-controller",},
- { .compatible = "fsl,p1016-l2-cache-controller",},
- { .compatible = "fsl,p1024-l2-cache-controller",},
- { .compatible = "fsl,p1015-l2-cache-controller",},
- { .compatible = "fsl,p1010-l2-cache-controller",},
- { .compatible = "fsl,bsc9131-l2-cache-controller",},
- {},
-};
-
-static struct platform_driver mpc85xx_l2ctlr_of_platform_driver = {
- .driver = {
- .name = "fsl-l2ctlr",
- .of_match_table = mpc85xx_l2ctlr_of_match,
- },
- .probe = mpc85xx_l2ctlr_of_probe,
- .remove = mpc85xx_l2ctlr_of_remove,
-};
-
-static __init int mpc85xx_l2ctlr_of_init(void)
-{
- return platform_driver_register(&mpc85xx_l2ctlr_of_platform_driver);
-}
-
-static void __exit mpc85xx_l2ctlr_of_exit(void)
-{
- platform_driver_unregister(&mpc85xx_l2ctlr_of_platform_driver);
-}
-
-subsys_initcall(mpc85xx_l2ctlr_of_init);
-module_exit(mpc85xx_l2ctlr_of_exit);
-
-MODULE_DESCRIPTION("Freescale MPC85xx L2 controller init");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/powerpc/sysdev/fsl_gtm.c b/arch/powerpc/sysdev/fsl_gtm.c
index d902306f4718..3dabc9621810 100644
--- a/arch/powerpc/sysdev/fsl_gtm.c
+++ b/arch/powerpc/sysdev/fsl_gtm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Freescale General-purpose Timers Module
*
@@ -6,11 +7,6 @@
* Jerry Huang <Chang-Ming.Huang@freescale.com>
* Copyright (c) MontaVista Software, Inc. 2008.
* Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/kernel.h>
@@ -81,7 +77,7 @@ struct gtm {
static LIST_HEAD(gtms);
/**
- * gtm_get_timer - request GTM timer to use it with the rest of GTM API
+ * gtm_get_timer16 - request GTM timer to use it with the rest of GTM API
* Context: non-IRQ
*
* This function reserves GTM timer for later use. It returns gtm_timer
@@ -90,7 +86,7 @@ static LIST_HEAD(gtms);
*/
struct gtm_timer *gtm_get_timer16(void)
{
- struct gtm *gtm = NULL;
+ struct gtm *gtm;
int i;
list_for_each_entry(gtm, &gtms, list_node) {
@@ -107,14 +103,14 @@ struct gtm_timer *gtm_get_timer16(void)
spin_unlock_irq(&gtm->lock);
}
- if (gtm)
+ if (!list_empty(&gtms))
return ERR_PTR(-EBUSY);
return ERR_PTR(-ENODEV);
}
EXPORT_SYMBOL(gtm_get_timer16);
/**
- * gtm_get_specific_timer - request specific GTM timer
+ * gtm_get_specific_timer16 - request specific GTM timer
* @gtm: specific GTM, pass here GTM's device_node->data
* @timer: specific timer number, Timer1 is 0.
* Context: non-IRQ
@@ -264,7 +260,7 @@ int gtm_set_timer16(struct gtm_timer *tmr, unsigned long usec, bool reload)
EXPORT_SYMBOL(gtm_set_timer16);
/**
- * gtm_set_exact_utimer16 - (re)set 16 bits timer
+ * gtm_set_exact_timer16 - (re)set 16 bits timer
* @tmr: pointer to the gtm_timer structure obtained from gtm_get_timer
* @usec: timer interval in microseconds
* @reload: if set, the timer will reset upon expiry rather than
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
index 5340a483cf55..7ed07232a69a 100644
--- a/arch/powerpc/sysdev/fsl_lbc.c
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Freescale LBC and UPM routines.
*
@@ -7,11 +8,6 @@
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
* Author: Jack Lan <Jack.Lan@freescale.com>
* Author: Roy Zang <tie-fei.zang@freescale.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/init.h>
@@ -22,13 +18,14 @@
#include <linux/types.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
#include <linux/syscore_ops.h>
-#include <asm/prom.h>
#include <asm/fsl_lbc.h>
static DEFINE_SPINLOCK(fsl_lbc_lock);
@@ -41,7 +38,7 @@ EXPORT_SYMBOL(fsl_lbc_ctrl_dev);
*
* This function converts a base address of lbc into the right format for the
* BR register. If the SOC has eLBC then it returns 32bit physical address
- * else it convers a 34bit local bus physical address to correct format of
+ * else it converts a 34bit local bus physical address to correct format of
* 32bit address for BR register (Example: MPC8641).
*/
u32 fsl_lbc_addr(phys_addr_t addr_base)
@@ -353,7 +350,7 @@ err:
#ifdef CONFIG_SUSPEND
/* save lbc registers */
-static int fsl_lbc_syscore_suspend(void)
+static int fsl_lbc_syscore_suspend(void *data)
{
struct fsl_lbc_ctrl *ctrl;
struct fsl_lbc_regs __iomem *lbc;
@@ -377,7 +374,7 @@ out:
}
/* restore lbc registers */
-static void fsl_lbc_syscore_resume(void)
+static void fsl_lbc_syscore_resume(void *data)
{
struct fsl_lbc_ctrl *ctrl;
struct fsl_lbc_regs __iomem *lbc;
@@ -411,10 +408,14 @@ static const struct of_device_id fsl_lbc_match[] = {
};
#ifdef CONFIG_SUSPEND
-static struct syscore_ops lbc_syscore_pm_ops = {
+static const struct syscore_ops lbc_syscore_pm_ops = {
.suspend = fsl_lbc_syscore_suspend,
.resume = fsl_lbc_syscore_resume,
};
+
+static struct syscore lbc_syscore_pm = {
+ .ops = &lbc_syscore_pm_ops,
+};
#endif
static struct platform_driver fsl_lbc_ctrl_driver = {
@@ -428,7 +429,7 @@ static struct platform_driver fsl_lbc_ctrl_driver = {
static int __init fsl_lbc_init(void)
{
#ifdef CONFIG_SUSPEND
- register_syscore_ops(&lbc_syscore_pm_ops);
+ register_syscore(&lbc_syscore_pm);
#endif
return platform_driver_register(&fsl_lbc_ctrl_driver);
}
diff --git a/arch/powerpc/sysdev/fsl_mpic_err.c b/arch/powerpc/sysdev/fsl_mpic_err.c
index 2a98837dc6ba..df06bb6b838f 100644
--- a/arch/powerpc/sysdev/fsl_mpic_err.c
+++ b/arch/powerpc/sysdev/fsl_mpic_err.c
@@ -1,18 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Freescale Semiconductor, Inc.
*
* Author: Varun Sethi <varun.sethi@freescale.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2 of the
- * License.
- *
*/
#include <linux/irq.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -62,7 +58,7 @@ static struct irq_chip fsl_mpic_err_chip = {
.irq_unmask = fsl_mpic_unmask_err,
};
-int mpic_setup_error_int(struct mpic *mpic, int intvec)
+int __init mpic_setup_error_int(struct mpic *mpic, int intvec)
{
int i;
@@ -103,7 +99,6 @@ static irqreturn_t fsl_error_int_handler(int irq, void *data)
struct mpic *mpic = (struct mpic *) data;
u32 eisr, eimr;
int errint;
- unsigned int cascade_irq;
eisr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EISR);
eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
@@ -112,13 +107,11 @@ static irqreturn_t fsl_error_int_handler(int irq, void *data)
return IRQ_NONE;
while (eisr) {
+ int ret;
errint = __builtin_clz(eisr);
- cascade_irq = irq_linear_revmap(mpic->irqhost,
- mpic->err_int_vecs[errint]);
- WARN_ON(!cascade_irq);
- if (cascade_irq) {
- generic_handle_irq(cascade_irq);
- } else {
+ ret = generic_handle_domain_irq(mpic->irqhost,
+ mpic->err_int_vecs[errint]);
+ if (WARN_ON(ret)) {
eimr |= 1 << (31 - errint);
mpic_fsl_err_write(mpic->err_regs, eimr);
}
@@ -128,7 +121,7 @@ static irqreturn_t fsl_error_int_handler(int irq, void *data)
return IRQ_HANDLED;
}
-void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
+void __init mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
{
unsigned int virq;
int ret;
diff --git a/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c b/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c
index 94278e8af192..06d9101a5d49 100644
--- a/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c
+++ b/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* MPIC timer wakeup driver
*
* Copyright 2013 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/kernel.h>
@@ -79,7 +75,7 @@ static ssize_t fsl_timer_wakeup_store(struct device *dev,
if (kstrtoll(buf, 0, &interval))
return -EINVAL;
- mutex_lock(&sysfs_lock);
+ guard(mutex)(&sysfs_lock);
if (fsl_wakeup->timer) {
disable_irq_wake(fsl_wakeup->timer->irq);
@@ -87,31 +83,23 @@ static ssize_t fsl_timer_wakeup_store(struct device *dev,
fsl_wakeup->timer = NULL;
}
- if (!interval) {
- mutex_unlock(&sysfs_lock);
+ if (!interval)
return count;
- }
fsl_wakeup->timer = mpic_request_timer(fsl_mpic_timer_irq,
fsl_wakeup, interval);
- if (!fsl_wakeup->timer) {
- mutex_unlock(&sysfs_lock);
+ if (!fsl_wakeup->timer)
return -EINVAL;
- }
ret = enable_irq_wake(fsl_wakeup->timer->irq);
if (ret) {
mpic_free_timer(fsl_wakeup->timer);
fsl_wakeup->timer = NULL;
- mutex_unlock(&sysfs_lock);
-
return ret;
}
mpic_start_timer(fsl_wakeup->timer);
- mutex_unlock(&sysfs_lock);
-
return count;
}
@@ -120,7 +108,8 @@ static struct device_attribute mpic_attributes = __ATTR(timer_wakeup, 0644,
static int __init fsl_wakeup_sys_init(void)
{
- int ret;
+ struct device *dev_root;
+ int ret = -EINVAL;
fsl_wakeup = kzalloc(sizeof(struct fsl_mpic_timer_wakeup), GFP_KERNEL);
if (!fsl_wakeup)
@@ -128,16 +117,26 @@ static int __init fsl_wakeup_sys_init(void)
INIT_WORK(&fsl_wakeup->free_work, fsl_free_resource);
- ret = device_create_file(mpic_subsys.dev_root, &mpic_attributes);
- if (ret)
- kfree(fsl_wakeup);
+ dev_root = bus_get_dev_root(&mpic_subsys);
+ if (dev_root) {
+ ret = device_create_file(dev_root, &mpic_attributes);
+ put_device(dev_root);
+ if (ret)
+ kfree(fsl_wakeup);
+ }
return ret;
}
static void __exit fsl_wakeup_sys_exit(void)
{
- device_remove_file(mpic_subsys.dev_root, &mpic_attributes);
+ struct device *dev_root;
+
+ dev_root = bus_get_dev_root(&mpic_subsys);
+ if (dev_root) {
+ device_remove_file(dev_root, &mpic_attributes);
+ put_device(dev_root);
+ }
mutex_lock(&sysfs_lock);
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index df95102e732c..2a007bfb038d 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2007-2011 Freescale Semiconductor, Inc.
*
@@ -5,22 +6,20 @@
* Jason Jin <Jason.jin@freescale.com>
*
* The hwirq alloc and free code reuse from sysdev/mpic_msi.c
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2 of the
- * License.
- *
*/
#include <linux/irq.h>
#include <linux/msi.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/seq_file.h>
#include <sysdev/fsl_soc.h>
-#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
#include <asm/mpic.h>
@@ -76,7 +75,7 @@ static void fsl_msi_print_chip(struct irq_data *irqd, struct seq_file *p)
srs = (hwirq >> msi_data->srs_shift) & MSI_SRS_MASK;
cascade_virq = msi_data->cascade_array[srs]->virq;
- seq_printf(p, " fsl-msi-%d", cascade_virq);
+ seq_printf(p, "fsl-msi-%d", cascade_virq);
}
@@ -130,17 +129,14 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
struct fsl_msi *msi_data;
irq_hw_number_t hwirq;
- for_each_pci_msi_entry(entry, pdev) {
- if (!entry->irq)
- continue;
+ msi_for_each_desc(entry, &pdev->dev, MSI_DESC_ASSOCIATED) {
hwirq = virq_to_hw(entry->irq);
msi_data = irq_get_chip_data(entry->irq);
irq_set_msi_desc(entry->irq, NULL);
irq_dispose_mapping(entry->irq);
+ entry->irq = 0;
msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1);
}
-
- return;
}
static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
@@ -216,11 +212,13 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
dev_err(&pdev->dev,
"node %pOF has an invalid fsl,msi phandle %u\n",
hose->dn, np->phandle);
+ of_node_put(np);
return -EINVAL;
}
+ of_node_put(np);
}
- for_each_pci_msi_entry(entry, pdev) {
+ msi_for_each_desc(entry, &pdev->dev, MSI_DESC_NOTASSOCIATED) {
/*
* Loop over all the MSI devices until we find one that has an
* available interrupt.
@@ -271,7 +269,6 @@ out_free:
static irqreturn_t fsl_msi_cascade(int irq, void *data)
{
- unsigned int cascade_irq;
struct fsl_msi *msi_data;
int msir_index = -1;
u32 msir_value = 0;
@@ -284,9 +281,6 @@ static irqreturn_t fsl_msi_cascade(int irq, void *data)
msir_index = cascade_data->index;
- if (msir_index >= NR_MSI_REG_MAX)
- cascade_irq = 0;
-
switch (msi_data->feature & FSL_PIC_IP_MASK) {
case FSL_PIC_IP_MPIC:
msir_value = fsl_msi_read(msi_data->msi_regs,
@@ -310,15 +304,15 @@ static irqreturn_t fsl_msi_cascade(int irq, void *data)
}
while (msir_value) {
+ int err;
intr_index = ffs(msir_value) - 1;
- cascade_irq = irq_linear_revmap(msi_data->irqhost,
+ err = generic_handle_domain_irq(msi_data->irqhost,
msi_hwirq(msi_data, msir_index,
intr_index + have_shift));
- if (cascade_irq) {
- generic_handle_irq(cascade_irq);
+ if (!err)
ret = IRQ_HANDLED;
- }
+
have_shift += intr_index + 1;
msir_value = msir_value >> (intr_index + 1);
}
@@ -326,7 +320,7 @@ static irqreturn_t fsl_msi_cascade(int irq, void *data)
return ret;
}
-static int fsl_of_msi_remove(struct platform_device *ofdev)
+static void fsl_of_msi_remove(struct platform_device *ofdev)
{
struct fsl_msi *msi = platform_get_drvdata(ofdev);
int virq, i;
@@ -349,8 +343,6 @@ static int fsl_of_msi_remove(struct platform_device *ofdev)
if ((msi->feature & FSL_PIC_IP_MASK) != FSL_PIC_IP_VMPIC)
iounmap(msi->msi_regs);
kfree(msi);
-
- return 0;
}
static struct lock_class_key fsl_msi_irq_class;
@@ -400,7 +392,6 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev,
static const struct of_device_id fsl_of_msi_ids[];
static int fsl_of_msi_probe(struct platform_device *dev)
{
- const struct of_device_id *match;
struct fsl_msi *msi;
struct resource res, msiir;
int err, i, j, irq_index, count;
@@ -410,10 +401,7 @@ static int fsl_of_msi_probe(struct platform_device *dev)
u32 offset;
struct pci_controller *phb;
- match = of_match_device(fsl_of_msi_ids, &dev->dev);
- if (!match)
- return -EINVAL;
- features = match->data;
+ features = device_get_match_data(&dev->dev);
printk(KERN_DEBUG "Setting up Freescale MSI support\n");
@@ -424,9 +412,8 @@ static int fsl_of_msi_probe(struct platform_device *dev)
}
platform_set_drvdata(dev, msi);
- msi->irqhost = irq_domain_add_linear(dev->dev.of_node,
- NR_MSI_IRQS_MAX, &fsl_msi_host_ops, msi);
-
+ msi->irqhost = irq_domain_create_linear(dev_fwnode(&dev->dev), NR_MSI_IRQS_MAX,
+ &fsl_msi_host_ops, msi);
if (msi->irqhost == NULL) {
dev_err(&dev->dev, "No memory for MSI irqhost\n");
err = -ENOMEM;
@@ -576,10 +563,12 @@ static const struct fsl_msi_feature ipic_msi_feature = {
.msiir_offset = 0x38,
};
+#ifdef CONFIG_EPAPR_PARAVIRT
static const struct fsl_msi_feature vmpic_msi_feature = {
.fsl_pic_ip = FSL_PIC_IP_VMPIC,
.msiir_offset = 0,
};
+#endif
static const struct of_device_id fsl_of_msi_ids[] = {
{
diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h
index a67359d993e5..e2a1bfc7c237 100644
--- a/arch/powerpc/sysdev/fsl_msi.h
+++ b/arch/powerpc/sysdev/fsl_msi.h
@@ -1,14 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2007-2008 Freescale Semiconductor, Inc. All rights reserved.
*
* Author: Tony Li <tony.li@freescale.com>
* Jason Jin <Jason.jin@freescale.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2 of the
- * License.
- *
*/
#ifndef _POWERPC_SYSDEV_FSL_MSI_H
#define _POWERPC_SYSDEV_FSL_MSI_H
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 918be816b097..4e501654cb41 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* MPC83xx/85xx/86xx PCI/PCIE support routing.
*
@@ -11,11 +12,6 @@
* MPC83xx PCI-Express support:
* Tony Li <tony.li@freescale.com>
* Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -26,6 +22,8 @@
#include <linux/interrupt.h>
#include <linux/memblock.h>
#include <linux/log2.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/suspend.h>
@@ -33,13 +31,14 @@
#include <linux/uaccess.h>
#include <asm/io.h>
-#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>
#include <asm/machdep.h>
#include <asm/mpc85xx.h>
#include <asm/disassemble.h>
#include <asm/ppc-opcode.h>
+#include <asm/swiotlb.h>
+#include <asm/setup.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
@@ -55,10 +54,10 @@ static void quirk_fsl_pcie_early(struct pci_dev *dev)
/* if we aren't in host mode don't bother */
pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type);
- if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ if ((hdr_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
return;
- dev->class = PCI_CLASS_BRIDGE_PCI << 8;
+ dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL;
fsl_pcie_bus_fixup = 1;
return;
}
@@ -114,33 +113,33 @@ static struct pci_ops fsl_indirect_pcie_ops =
static u64 pci64_dma_offset;
#ifdef CONFIG_SWIOTLB
+static void pci_dma_dev_setup_swiotlb(struct pci_dev *pdev)
+{
+ struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+
+ pdev->dev.bus_dma_limit =
+ hose->dma_window_base_cur + hose->dma_window_size - 1;
+}
+
static void setup_swiotlb_ops(struct pci_controller *hose)
{
- if (ppc_swiotlb_enable) {
+ if (ppc_swiotlb_enable)
hose->controller_ops.dma_dev_setup = pci_dma_dev_setup_swiotlb;
- set_pci_dma_ops(&powerpc_swiotlb_dma_ops);
- }
}
#else
static inline void setup_swiotlb_ops(struct pci_controller *hose) {}
#endif
-static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
+static void fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
{
- if (!dev->dma_mask || !dma_supported(dev, dma_mask))
- return -EIO;
-
/*
* Fix up PCI devices that are able to DMA to the large inbound
* mapping that allows addressing any RAM address from across PCI.
*/
if (dev_is_pci(dev) && dma_mask >= pci64_dma_offset * 2 - 1) {
- set_dma_ops(dev, &dma_nommu_ops);
- set_dma_offset(dev, pci64_dma_offset);
+ dev->bus_dma_limit = 0;
+ dev->archdata.dma_offset = pci64_dma_offset;
}
-
- *dev->dma_mask = dma_mask;
- return 0;
}
static int setup_one_atmu(struct ccsr_pci __iomem *pci,
@@ -182,6 +181,7 @@ static int setup_one_atmu(struct ccsr_pci __iomem *pci,
static bool is_kdump(void)
{
struct device_node *node;
+ bool ret;
node = of_find_node_by_type(NULL, "memory");
if (!node) {
@@ -189,7 +189,10 @@ static bool is_kdump(void)
return false;
}
- return of_property_read_bool(node, "linux,usable-memory");
+ ret = of_property_read_bool(node, "linux,usable-memory");
+ of_node_put(node);
+
+ return ret;
}
/* atmu setup for fsl pci/pcie controller */
@@ -221,7 +224,7 @@ static void setup_pci_atmu(struct pci_controller *hose)
* windows have implemented the default target value as 0xf
* for CCSR space.In all Freescale legacy devices the target
* of 0xf is reserved for local memory space. 9132 Rev1.0
- * now has local mempry space mapped to target 0x0 instead of
+ * now has local memory space mapped to target 0x0 instead of
* 0xf. Hence adding a workaround to remove the target 0xf
* defined for memory space from Inbound window attributes.
*/
@@ -458,7 +461,7 @@ static void setup_pci_atmu(struct pci_controller *hose)
}
}
-static void __init setup_pci_cmd(struct pci_controller *hose)
+static void setup_pci_cmd(struct pci_controller *hose)
{
u16 cmd;
int cap_x;
@@ -516,13 +519,14 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus)
}
}
-int fsl_add_bridge(struct platform_device *pdev, int is_primary)
+static int fsl_add_bridge(struct platform_device *pdev, int is_primary)
{
int len;
struct pci_controller *hose;
struct resource rsrc;
const int *bus_range;
u8 hdr_type, progif;
+ u32 class_code;
struct device_node *dev;
struct ccsr_pci __iomem *pci;
u16 temp;
@@ -577,7 +581,7 @@ int fsl_add_bridge(struct platform_device *pdev, int is_primary)
hose->ops = &fsl_indirect_pcie_ops;
/* For PCIE read HEADER_TYPE to identify controller mode */
early_read_config_byte(hose, 0, 0, PCI_HEADER_TYPE, &hdr_type);
- if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ if ((hdr_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
goto no_bridge;
} else {
@@ -596,6 +600,13 @@ int fsl_add_bridge(struct platform_device *pdev, int is_primary)
PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS;
if (fsl_pcie_check_link(hose))
hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
+ /* Fix Class Code to PCI_CLASS_BRIDGE_PCI_NORMAL for pre-3.0 controller */
+ if (in_be32(&pci->block_rev1) < PCIE_IP_REV_3_0) {
+ early_read_config_dword(hose, 0, 0, PCIE_FSL_CSR_CLASSCODE, &class_code);
+ class_code &= 0xff;
+ class_code |= PCI_CLASS_BRIDGE_PCI_NORMAL << 8;
+ early_write_config_dword(hose, 0, 0, PCIE_FSL_CSR_CLASSCODE, class_code);
+ }
} else {
/*
* Set PBFR(PCI Bus Function Register)[10] = 1 to
@@ -756,7 +767,7 @@ static int __init mpc83xx_pcie_setup(struct pci_controller *hose,
u32 cfg_bar;
int ret = -ENOMEM;
- pcie = zalloc_maybe_bootmem(sizeof(*pcie), GFP_KERNEL);
+ pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
if (!pcie)
return ret;
@@ -932,7 +943,7 @@ u64 fsl_pci_immrbar_base(struct pci_controller *hose)
return 0;
}
-#ifdef CONFIG_E500
+#ifdef CONFIG_PPC_E500
static int mcheck_handle_load(struct pt_regs *regs, u32 inst)
{
unsigned int rd, ra, rb, d;
@@ -1068,16 +1079,14 @@ int fsl_pci_mcheck_exception(struct pt_regs *regs)
addr += mfspr(SPRN_MCAR);
if (is_in_pci_mem_space(addr)) {
- if (user_mode(regs)) {
- pagefault_disable();
- ret = get_user(inst, (__u32 __user *)regs->nip);
- pagefault_enable();
- } else {
- ret = probe_kernel_address((void *)regs->nip, inst);
- }
+ if (user_mode(regs))
+ ret = copy_from_user_nofault(&inst,
+ (void __user *)regs->nip, sizeof(inst));
+ else
+ ret = get_kernel_nofault(inst, (void *)regs->nip);
if (!ret && mcheck_handle_load(regs, inst)) {
- regs->nip += 4;
+ regs_add_return_ip(regs, 4);
return 1;
}
}
@@ -1111,7 +1120,7 @@ static const struct of_device_id pci_ids[] = {
struct device_node *fsl_pci_primary;
-void fsl_pci_assign_primary(void)
+void __init fsl_pci_assign_primary(void)
{
struct device_node *np;
@@ -1130,6 +1139,19 @@ void fsl_pci_assign_primary(void)
}
/*
+ * If there's no PCI host bridge with ISA then check for
+ * PCI host bridge with alias "pci0" (first PCI host bridge).
+ */
+ np = of_find_node_by_path("pci0");
+ if (np && of_match_node(pci_ids, np) && of_device_is_available(np)) {
+ fsl_pci_primary = np;
+ of_node_put(np);
+ return;
+ }
+ if (np)
+ of_node_put(np);
+
+ /*
* If there's no PCI host bridge with ISA, arbitrarily
* designate one as primary. This can go away once
* various bugs with primary-less systems are fixed.
@@ -1137,7 +1159,6 @@ void fsl_pci_assign_primary(void)
for_each_matching_node(np, pci_ids) {
if (of_device_is_available(np)) {
fsl_pci_primary = np;
- of_node_put(np);
return;
}
}
@@ -1237,7 +1258,7 @@ static void fsl_pci_syscore_do_suspend(struct pci_controller *hose)
send_pme_turnoff_message(hose);
}
-static int fsl_pci_syscore_suspend(void)
+static int fsl_pci_syscore_suspend(void *data)
{
struct pci_controller *hose, *tmp;
@@ -1270,7 +1291,7 @@ static void fsl_pci_syscore_do_resume(struct pci_controller *hose)
setup_pci_atmu(hose);
}
-static void fsl_pci_syscore_resume(void)
+static void fsl_pci_syscore_resume(void *data)
{
struct pci_controller *hose, *tmp;
@@ -1278,10 +1299,14 @@ static void fsl_pci_syscore_resume(void)
fsl_pci_syscore_do_resume(hose);
}
-static struct syscore_ops pci_syscore_pm_ops = {
+static const struct syscore_ops pci_syscore_pm_ops = {
.suspend = fsl_pci_syscore_suspend,
.resume = fsl_pci_syscore_resume,
};
+
+static struct syscore pci_syscore_pm = {
+ .ops = &pci_syscore_pm_ops,
+};
#endif
void fsl_pcibios_fixup_phb(struct pci_controller *phb)
@@ -1332,12 +1357,13 @@ static struct platform_driver fsl_pci_driver = {
.of_match_table = pci_ids,
},
.probe = fsl_pci_probe,
+ .driver_managed_dma = true,
};
static int __init fsl_pci_init(void)
{
#ifdef CONFIG_PM_SLEEP
- register_syscore_ops(&pci_syscore_pm_ops);
+ register_syscore(&pci_syscore_pm);
#endif
return platform_driver_register(&fsl_pci_driver);
}
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index 151588530b06..3bc4ab9d8341 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -1,13 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* MPC85xx/86xx PCI Express structure define
*
* Copyright 2007,2011 Freescale Semiconductor, Inc
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#ifdef __KERNEL__
@@ -23,6 +18,7 @@ struct platform_device;
#define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */
#define PCIE_LTSSM_L0 0x16 /* L0 state */
+#define PCIE_FSL_CSR_CLASSCODE 0x474 /* FSL GPEX CSR */
#define PCIE_IP_REV_2_2 0x02080202 /* PCIE IP block version Rev2.2 */
#define PCIE_IP_REV_3_0 0x02080300 /* PCIE IP block version Rev3.0 */
#define PIWAR_EN 0x80000000 /* Enable */
@@ -116,7 +112,6 @@ struct ccsr_pci {
};
-extern int fsl_add_bridge(struct platform_device *pdev, int is_primary);
extern void fsl_pcibios_fixup_bus(struct pci_bus *bus);
extern void fsl_pcibios_fixup_phb(struct pci_controller *phb);
extern int mpc83xx_add_bridge(struct device_node *dev);
@@ -125,7 +120,7 @@ u64 fsl_pci_immrbar_base(struct pci_controller *hose);
extern struct device_node *fsl_pci_primary;
#ifdef CONFIG_PCI
-void fsl_pci_assign_primary(void);
+void __init fsl_pci_assign_primary(void);
#else
static inline void fsl_pci_assign_primary(void) {}
#endif
diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index 232225e7f863..9f6dd11c1344 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Suspend/resume support
*
* Copyright 2009 MontaVista Software, Inc.
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/init.h>
@@ -17,9 +13,9 @@
#include <linux/export.h>
#include <linux/suspend.h>
#include <linux/delay.h>
-#include <linux/device.h>
+#include <linux/mod_devicetable.h>
#include <linux/of_address.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
struct pmc_regs {
__be32 devdisr;
diff --git a/arch/powerpc/sysdev/fsl_rcpm.c b/arch/powerpc/sysdev/fsl_rcpm.c
index 9259a94f70e1..aacd0be613ab 100644
--- a/arch/powerpc/sysdev/fsl_rcpm.c
+++ b/arch/powerpc/sysdev/fsl_rcpm.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* RCPM(Run Control/Power Management) support
*
* Copyright 2012-2015 Freescale Semiconductor Inc.
*
* Author: Chenhui Zhao <chenhui.zhao@freescale.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index 5011ffea4e4b..f9b214b299e7 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Freescale MPC85xx/MPC86xx RapidIO support
*
@@ -15,11 +16,6 @@
*
* Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/init.h>
@@ -27,16 +23,17 @@
#include <linux/types.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
-#include <linux/device.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/machdep.h>
+#include <asm/rio.h>
#include "fsl_rio.h"
@@ -73,10 +70,10 @@
static DEFINE_SPINLOCK(fsl_rio_config_lock);
-#define __fsl_read_rio_config(x, addr, err, op) \
+#define ___fsl_read_rio_config(x, addr, err, op, barrier) \
__asm__ __volatile__( \
"1: "op" %1,0(%2)\n" \
- " eieio\n" \
+ " "barrier"\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: li %1,-1\n" \
@@ -87,6 +84,14 @@ static DEFINE_SPINLOCK(fsl_rio_config_lock);
: "=r" (err), "=r" (x) \
: "b" (addr), "i" (-EFAULT), "0" (err))
+#ifdef CONFIG_BOOKE
+#define __fsl_read_rio_config(x, addr, err, op) \
+ ___fsl_read_rio_config(x, addr, err, op, "mbar")
+#else
+#define __fsl_read_rio_config(x, addr, err, op) \
+ ___fsl_read_rio_config(x, addr, err, op, "eieio")
+#endif
+
void __iomem *rio_regs_win;
void __iomem *rmu_regs_win;
resource_size_t rio_law_start;
@@ -94,7 +99,7 @@ resource_size_t rio_law_start;
struct fsl_rio_dbell *dbell;
struct fsl_rio_pw *pw;
-#ifdef CONFIG_E500
+#ifdef CONFIG_PPC_E500
int fsl_rio_mcheck_exception(struct pt_regs *regs)
{
const struct exception_table_entry *entry;
@@ -112,8 +117,8 @@ int fsl_rio_mcheck_exception(struct pt_regs *regs)
__func__);
out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR),
0);
- regs->msr |= MSR_RI;
- regs->nip = extable_fixup(entry);
+ regs_set_recoverable(regs);
+ regs_set_return_ip(regs, extable_fixup(entry));
return 1;
}
}
@@ -299,8 +304,8 @@ static void fsl_rio_inbound_mem_init(struct rio_priv *priv)
out_be32(&priv->inb_atmu_regs[i].riwar, 0);
}
-int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
- u64 rstart, u64 size, u32 flags)
+static int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
+ u64 rstart, u64 size, u32 flags)
{
struct rio_priv *priv = mport->priv;
u32 base_size;
@@ -350,7 +355,7 @@ int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
return 0;
}
-void fsl_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart)
+static void fsl_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart)
{
u32 win_start_shift, base_start_shift;
struct rio_priv *priv = mport->priv;
@@ -438,20 +443,17 @@ static inline void fsl_rio_info(struct device *dev, u32 ccsr)
* master port with system-specific info, and registers the
* master port with the RapidIO subsystem.
*/
-int fsl_rio_setup(struct platform_device *dev)
+static int fsl_rio_setup(struct platform_device *dev)
{
struct rio_ops *ops;
struct rio_mport *port;
struct rio_priv *priv;
int rc = 0;
- const u32 *dt_range, *cell, *port_index;
+ const u32 *port_index;
u32 active_ports = 0;
- struct resource regs, rmu_regs;
struct device_node *np, *rmu_node;
- int rlen;
u32 ccsr;
- u64 range_start, range_size;
- int paw, aw, sw;
+ u64 range_start;
u32 i;
static int tmp;
struct device_node *rmu_np[MAX_MSG_UNIT_NUM] = {NULL};
@@ -461,17 +463,7 @@ int fsl_rio_setup(struct platform_device *dev)
return -ENODEV;
}
- rc = of_address_to_resource(dev->dev.of_node, 0, &regs);
- if (rc) {
- dev_err(&dev->dev, "Can't get %pOF property 'reg'\n",
- dev->dev.of_node);
- return -EFAULT;
- }
- dev_info(&dev->dev, "Of-device full name %pOF\n",
- dev->dev.of_node);
- dev_info(&dev->dev, "Regs: %pR\n", &regs);
-
- rio_regs_win = ioremap(regs.start, resource_size(&regs));
+ rio_regs_win = of_iomap(dev->dev.of_node, 0);
if (!rio_regs_win) {
dev_err(&dev->dev, "Unable to map rio register window\n");
rc = -ENOMEM;
@@ -505,13 +497,9 @@ int fsl_rio_setup(struct platform_device *dev)
rc = -ENOENT;
goto err_rmu;
}
- rc = of_address_to_resource(rmu_node, 0, &rmu_regs);
- if (rc) {
- dev_err(&dev->dev, "Can't get %pOF property 'reg'\n",
- rmu_node);
- goto err_rmu;
- }
- rmu_regs_win = ioremap(rmu_regs.start, resource_size(&rmu_regs));
+ rmu_regs_win = of_iomap(rmu_node, 0);
+
+ of_node_put(rmu_node);
if (!rmu_regs_win) {
dev_err(&dev->dev, "Unable to map rmu register window\n");
rc = -ENOMEM;
@@ -539,15 +527,12 @@ int fsl_rio_setup(struct platform_device *dev)
dbell->bellirq = irq_of_parse_and_map(np, 1);
dev_info(&dev->dev, "bellirq: %d\n", dbell->bellirq);
- aw = of_n_addr_cells(np);
- dt_range = of_get_property(np, "reg", &rlen);
- if (!dt_range) {
+ if (of_property_read_reg(np, 0, &range_start, NULL)) {
pr_err("%pOF: unable to find 'reg' property\n",
np);
rc = -ENOMEM;
goto err_pw;
}
- range_start = of_read_number(dt_range, aw);
dbell->dbell_regs = (struct rio_dbell_regs *)(rmu_regs_win +
(u32)range_start);
@@ -567,19 +552,18 @@ int fsl_rio_setup(struct platform_device *dev)
pw->dev = &dev->dev;
pw->pwirq = irq_of_parse_and_map(np, 0);
dev_info(&dev->dev, "pwirq: %d\n", pw->pwirq);
- aw = of_n_addr_cells(np);
- dt_range = of_get_property(np, "reg", &rlen);
- if (!dt_range) {
+ if (of_property_read_reg(np, 0, &range_start, NULL)) {
pr_err("%pOF: unable to find 'reg' property\n",
np);
rc = -ENOMEM;
goto err;
}
- range_start = of_read_number(dt_range, aw);
pw->pw_regs = (struct rio_pw_regs *)(rmu_regs_win + (u32)range_start);
/*set up ports node*/
for_each_child_of_node(dev->dev.of_node, np) {
+ struct resource res;
+
port_index = of_get_property(np, "cell-index", NULL);
if (!port_index) {
dev_err(&dev->dev, "Can't get %pOF property 'cell-index'\n",
@@ -587,32 +571,14 @@ int fsl_rio_setup(struct platform_device *dev)
continue;
}
- dt_range = of_get_property(np, "ranges", &rlen);
- if (!dt_range) {
+ if (of_range_to_resource(np, 0, &res)) {
dev_err(&dev->dev, "Can't get %pOF property 'ranges'\n",
np);
continue;
}
- /* Get node address wide */
- cell = of_get_property(np, "#address-cells", NULL);
- if (cell)
- aw = *cell;
- else
- aw = of_n_addr_cells(np);
- /* Get node size wide */
- cell = of_get_property(np, "#size-cells", NULL);
- if (cell)
- sw = *cell;
- else
- sw = of_n_size_cells(np);
- /* Get parent address wide wide */
- paw = of_n_addr_cells(np);
- range_start = of_read_number(dt_range + aw, paw);
- range_size = of_read_number(dt_range + aw + paw, sw);
-
- dev_info(&dev->dev, "%pOF: LAW start 0x%016llx, size 0x%016llx.\n",
- np, range_start, range_size);
+ dev_info(&dev->dev, "%pOF: LAW %pR\n",
+ np, &res);
port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
if (!port)
@@ -635,9 +601,7 @@ int fsl_rio_setup(struct platform_device *dev)
}
INIT_LIST_HEAD(&port->dbells);
- port->iores.start = range_start;
- port->iores.end = port->iores.start + range_size - 1;
- port->iores.flags = IORESOURCE_MEM;
+ port->iores = res; /* struct copy */
port->iores.name = "rio_io_win";
if (request_resource(&iomem_resource, &port->iores) < 0) {
diff --git a/arch/powerpc/sysdev/fsl_rio.h b/arch/powerpc/sysdev/fsl_rio.h
index 6c13d9a7b7b2..c526b7237abd 100644
--- a/arch/powerpc/sysdev/fsl_rio.h
+++ b/arch/powerpc/sysdev/fsl_rio.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Freescale MPC85xx/MPC86xx RapidIO support
*
@@ -17,11 +18,6 @@
*
* Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#ifndef __FSL_RIO_H
diff --git a/arch/powerpc/sysdev/fsl_rmu.c b/arch/powerpc/sysdev/fsl_rmu.c
index ebed46f80254..f956591cb64e 100644
--- a/arch/powerpc/sysdev/fsl_rmu.c
+++ b/arch/powerpc/sysdev/fsl_rmu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Freescale MPC85xx/MPC86xx RapidIO RMU support
*
@@ -17,18 +18,13 @@
*
* Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/types.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
+#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <linux/of_platform.h>
#include <linux/slab.h>
#include "fsl_rio.h"
@@ -363,7 +359,7 @@ out:
return IRQ_HANDLED;
}
-void msg_unit_error_handler(void)
+static void msg_unit_error_handler(void)
{
/*XXX: Error recovery is not implemented, we just clear errors */
@@ -1071,9 +1067,6 @@ int fsl_rio_setup_rmu(struct rio_mport *mport, struct device_node *node)
struct rio_priv *priv;
struct fsl_rmu *rmu;
u64 msg_start;
- const u32 *msg_addr;
- int mlen;
- int aw;
if (!mport || !mport->priv)
return -EINVAL;
@@ -1090,16 +1083,12 @@ int fsl_rio_setup_rmu(struct rio_mport *mport, struct device_node *node)
if (!rmu)
return -ENOMEM;
- aw = of_n_addr_cells(node);
- msg_addr = of_get_property(node, "reg", &mlen);
- if (!msg_addr) {
+ if (of_property_read_reg(node, 0, &msg_start, NULL)) {
pr_err("%pOF: unable to find 'reg' property of message-unit\n",
node);
kfree(rmu);
return -ENOMEM;
}
- msg_start = of_read_number(msg_addr, aw);
-
rmu->msg_regs = (struct rio_msg_regs *)
(rmu_regs_win + (u32)msg_start);
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 1f614fb2be56..3949ceb79e64 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* FSL SoC setup code
*
@@ -5,11 +6,6 @@
*
* 2006 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/stddef.h>
@@ -23,28 +19,21 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
#include <linux/phy.h>
#include <linux/spi/spi.h>
#include <linux/fsl_devices.h>
-#include <linux/fs_enet_pd.h>
-#include <linux/fs_uart_pd.h>
#include <linux/reboot.h>
#include <linux/atomic.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/time.h>
-#include <asm/prom.h>
#include <asm/machdep.h>
#include <sysdev/fsl_soc.h>
#include <mm/mmu_decl.h>
#include <asm/cpm2.h>
#include <asm/fsl_hcalls.h> /* For the Freescale hypervisor */
-extern void init_fcc_ioports(struct fs_platform_info*);
-extern void init_fec_ioports(struct fs_platform_info*);
-extern void init_smc_ioports(struct fs_uart_platform_info*);
static phys_addr_t immrbase = -1;
phys_addr_t get_immrbase(void)
@@ -56,18 +45,10 @@ phys_addr_t get_immrbase(void)
soc = of_find_node_by_type(NULL, "soc");
if (soc) {
- int size;
- u32 naddr;
- const __be32 *prop = of_get_property(soc, "#address-cells", &size);
-
- if (prop && size == 4)
- naddr = be32_to_cpup(prop);
- else
- naddr = 2;
+ struct resource res;
- prop = of_get_property(soc, "ranges", &size);
- if (prop)
- immrbase = of_translate_address(soc, prop + naddr);
+ if (!of_range_to_resource(soc, 0, &res))
+ immrbase = res.start;
of_node_put(soc);
}
@@ -179,7 +160,7 @@ static int __init setup_rstcr(void)
};
for_each_node_by_name(np, "global-utilities") {
- if ((of_get_property(np, "fsl,has-rstcr", NULL))) {
+ if (of_property_read_bool(np, "fsl,has-rstcr")) {
rstcr = of_iomap(np, 0) + 0xb0;
if (!rstcr) {
printk (KERN_ERR "Error: reset control "
diff --git a/arch/powerpc/sysdev/ge/Makefile b/arch/powerpc/sysdev/ge/Makefile
index 8731ffcb79b9..a63fdb379083 100644
--- a/arch/powerpc/sysdev/ge/Makefile
+++ b/arch/powerpc/sysdev/ge/Makefile
@@ -1 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_GE_FPGA) += ge_pic.o
diff --git a/arch/powerpc/sysdev/ge/ge_pic.c b/arch/powerpc/sysdev/ge/ge_pic.c
index 02553a8ce191..0bc3f0b36528 100644
--- a/arch/powerpc/sysdev/ge/ge_pic.c
+++ b/arch/powerpc/sysdev/ge/ge_pic.c
@@ -14,12 +14,14 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/spinlock.h>
#include <asm/byteorder.h>
#include <asm/io.h>
-#include <asm/prom.h>
#include <asm/irq.h>
#include "ge_pic.h"
@@ -150,7 +152,7 @@ static struct irq_chip gef_pic_chip = {
};
-/* When an interrupt is being configured, this call allows some flexibilty
+/* When an interrupt is being configured, this call allows some flexibility
* in deciding which irq_chip structure is used
*/
static int gef_pic_host_map(struct irq_domain *h, unsigned int virq,
@@ -212,8 +214,9 @@ void __init gef_pic_init(struct device_node *np)
}
/* Setup an irq_domain structure */
- gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS,
- &gef_pic_host_ops, NULL);
+ gef_pic_irq_host = irq_domain_create_linear(of_fwnode_handle(np),
+ GEF_PIC_NUM_IRQS,
+ &gef_pic_host_ops, NULL);
if (gef_pic_irq_host == NULL)
return;
@@ -242,7 +245,7 @@ unsigned int gef_pic_get_irq(void)
if (active & (0x1 << hwirq))
break;
}
- virq = irq_linear_revmap(gef_pic_irq_host,
+ virq = irq_find_mapping(gef_pic_irq_host,
(irq_hw_number_t)hwirq);
}
diff --git a/arch/powerpc/sysdev/grackle.c b/arch/powerpc/sysdev/grackle.c
index 08abe91ae798..7dce8278b71e 100644
--- a/arch/powerpc/sysdev/grackle.c
+++ b/arch/powerpc/sysdev/grackle.c
@@ -1,45 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Functions for setting up and using a MPC106 northbridge
* Extracted from arch/powerpc/platforms/powermac/pci.c.
*
* Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
* Copyright (C) 1997 Paul Mackerras (paulus@samba.org)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/of.h>
#include <asm/io.h>
-#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <asm/grackle.h>
#define GRACKLE_CFA(b, d, o) (0x80 | ((b) << 8) | ((d) << 16) \
| (((o) & ~3) << 24))
-#define GRACKLE_PICR1_STG 0x00000040
#define GRACKLE_PICR1_LOOPSNOOP 0x00000010
-/* N.B. this is called before bridges is initialized, so we can't
- use grackle_pcibios_{read,write}_config_dword. */
-static inline void grackle_set_stg(struct pci_controller* bp, int enable)
-{
- unsigned int val;
-
- out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
- val = in_le32(bp->cfg_data);
- val = enable? (val | GRACKLE_PICR1_STG) :
- (val & ~GRACKLE_PICR1_STG);
- out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
- out_le32(bp->cfg_data, val);
- (void)in_le32(bp->cfg_data);
-}
-
static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable)
{
unsigned int val;
@@ -60,7 +40,4 @@ void __init setup_grackle(struct pci_controller *hose)
pci_add_flags(PCI_REASSIGN_ALL_BUS);
if (of_machine_is_compatible("AAPL,PowerBook1998"))
grackle_set_loop_snoop(hose, 1);
-#if 0 /* Disabled for now, HW problems ??? */
- grackle_set_stg(hose, 1);
-#endif
}
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
index cb9a8b71fd0f..99bb2b916949 100644
--- a/arch/powerpc/sysdev/i8259.c
+++ b/arch/powerpc/sysdev/i8259.c
@@ -1,20 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* i8259 interrupt controller driver.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#undef DEBUG
#include <linux/ioport.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/i8259.h>
-#include <asm/prom.h>
static volatile void __iomem *pci_intack; /* RO, gives us the irq vector */
@@ -212,7 +208,7 @@ static const struct irq_domain_ops i8259_host_ops = {
.xlate = i8259_host_xlate,
};
-struct irq_domain *i8259_get_host(void)
+struct irq_domain *__init i8259_get_host(void)
{
return i8259_host;
}
@@ -264,7 +260,8 @@ void i8259_init(struct device_node *node, unsigned long intack_addr)
raw_spin_unlock_irqrestore(&i8259_lock, flags);
/* create a legacy host */
- i8259_host = irq_domain_add_legacy_isa(node, &i8259_host_ops, NULL);
+ i8259_host = irq_domain_create_legacy(of_fwnode_handle(node), NR_IRQS_LEGACY, 0, 0,
+ &i8259_host_ops, NULL);
if (i8259_host == NULL) {
printk(KERN_ERR "i8259: failed to allocate irq host !\n");
return;
diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c
index 692de9dbc680..1aacb403a010 100644
--- a/arch/powerpc/sysdev/indirect_pci.c
+++ b/arch/powerpc/sysdev/indirect_pci.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Support for indirect PCI bridges.
*
* Copyright (C) 1998 Gabriel Paubert.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
@@ -16,7 +12,6 @@
#include <linux/init.h>
#include <asm/io.h>
-#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index 8030a0f55e96..290ba8427239 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* arch/powerpc/sysdev/ipic.c
*
* IPIC routines implementations.
*
* Copyright 2005 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/kernel.h>
#include <linux/init.h>
@@ -22,9 +18,10 @@
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/fsl_devices.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/prom.h>
#include <asm/ipic.h>
#include "ipic.h"
@@ -714,8 +711,9 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
if (ipic == NULL)
return NULL;
- ipic->irqhost = irq_domain_add_linear(node, NR_IPIC_INTS,
- &ipic_host_ops, ipic);
+ ipic->irqhost = irq_domain_create_linear(of_fwnode_handle(node),
+ NR_IPIC_INTS,
+ &ipic_host_ops, ipic);
if (ipic->irqhost == NULL) {
kfree(ipic);
return NULL;
@@ -760,33 +758,17 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
ipic_write(ipic->regs, IPIC_SEMSR, temp);
primary_ipic = ipic;
- irq_set_default_host(primary_ipic->irqhost);
+ irq_set_default_domain(primary_ipic->irqhost);
ipic_write(ipic->regs, IPIC_SIMSR_H, 0);
ipic_write(ipic->regs, IPIC_SIMSR_L, 0);
- printk ("IPIC (%d IRQ sources) at %p\n", NR_IPIC_INTS,
- primary_ipic->regs);
+ pr_info("IPIC (%d IRQ sources) at MMIO %pa\n", NR_IPIC_INTS, &res.start);
return ipic;
}
-void ipic_set_highest_priority(unsigned int virq)
-{
- struct ipic *ipic = ipic_from_irq(virq);
- unsigned int src = virq_to_hw(virq);
- u32 temp;
-
- temp = ipic_read(ipic->regs, IPIC_SICFR);
-
- /* clear and set HPI */
- temp &= 0x7f000000;
- temp |= (src & 0x7f) << 24;
-
- ipic_write(ipic->regs, IPIC_SICFR, temp);
-}
-
-void ipic_set_default_priority(void)
+void __init ipic_set_default_priority(void)
{
ipic_write(primary_ipic->regs, IPIC_SIPRR_A, IPIC_PRIORITY_DEFAULT);
ipic_write(primary_ipic->regs, IPIC_SIPRR_B, IPIC_PRIORITY_DEFAULT);
@@ -796,26 +778,6 @@ void ipic_set_default_priority(void)
ipic_write(primary_ipic->regs, IPIC_SMPRR_B, IPIC_PRIORITY_DEFAULT);
}
-void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq)
-{
- struct ipic *ipic = primary_ipic;
- u32 temp;
-
- temp = ipic_read(ipic->regs, IPIC_SERMR);
- temp |= (1 << (31 - mcp_irq));
- ipic_write(ipic->regs, IPIC_SERMR, temp);
-}
-
-void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq)
-{
- struct ipic *ipic = primary_ipic;
- u32 temp;
-
- temp = ipic_read(ipic->regs, IPIC_SERMR);
- temp &= (1 << (31 - mcp_irq));
- ipic_write(ipic->regs, IPIC_SERMR, temp);
-}
-
u32 ipic_get_mcp_status(void)
{
return primary_ipic ? ipic_read(primary_ipic->regs, IPIC_SERSR) : 0;
@@ -839,7 +801,7 @@ unsigned int ipic_get_irq(void)
if (irq == 0) /* 0 --> no irq is pending */
return 0;
- return irq_linear_revmap(primary_ipic->irqhost, irq);
+ return irq_find_mapping(primary_ipic->irqhost, irq);
}
#ifdef CONFIG_SUSPEND
@@ -855,7 +817,7 @@ static struct {
u32 sercr;
} ipic_saved_state;
-static int ipic_suspend(void)
+static int ipic_suspend(void *data)
{
struct ipic *ipic = primary_ipic;
@@ -886,7 +848,7 @@ static int ipic_suspend(void)
return 0;
}
-static void ipic_resume(void)
+static void ipic_resume(void *data)
{
struct ipic *ipic = primary_ipic;
@@ -908,18 +870,22 @@ static void ipic_resume(void)
#define ipic_resume NULL
#endif
-static struct syscore_ops ipic_syscore_ops = {
+static const struct syscore_ops ipic_syscore_ops = {
.suspend = ipic_suspend,
.resume = ipic_resume,
};
+static struct syscore ipic_syscore = {
+ .ops = &ipic_syscore_ops,
+};
+
static int __init init_ipic_syscore(void)
{
if (!primary_ipic || !primary_ipic->regs)
return -ENODEV;
printk(KERN_DEBUG "Registering ipic system core operations\n");
- register_syscore_ops(&ipic_syscore_ops);
+ register_syscore(&ipic_syscore);
return 0;
}
diff --git a/arch/powerpc/sysdev/ipic.h b/arch/powerpc/sysdev/ipic.h
index 90031d1282e1..45ab614068c5 100644
--- a/arch/powerpc/sysdev/ipic.h
+++ b/arch/powerpc/sysdev/ipic.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* IPIC private definitions and structure.
*
* Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor, Inc
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#ifndef __IPIC_H__
#define __IPIC_H__
diff --git a/arch/powerpc/sysdev/micropatch.c b/arch/powerpc/sysdev/micropatch.c
deleted file mode 100644
index 33a9042fca80..000000000000
--- a/arch/powerpc/sysdev/micropatch.c
+++ /dev/null
@@ -1,749 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-/* Microcode patches for the CPM as supplied by Motorola.
- * This is the one for IIC/SPI. There is a newer one that
- * also relocates SMC2, but this would require additional changes
- * to uart.c, so I am holding off on that for a moment.
- */
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/8xx_immap.h>
-#include <asm/cpm.h>
-#include <asm/cpm1.h>
-
-/*
- * I2C/SPI relocation patch arrays.
- */
-
-#ifdef CONFIG_I2C_SPI_UCODE_PATCH
-
-static uint patch_2000[] __initdata = {
- 0x7FFFEFD9,
- 0x3FFD0000,
- 0x7FFB49F7,
- 0x7FF90000,
- 0x5FEFADF7,
- 0x5F89ADF7,
- 0x5FEFAFF7,
- 0x5F89AFF7,
- 0x3A9CFBC8,
- 0xE7C0EDF0,
- 0x77C1E1BB,
- 0xF4DC7F1D,
- 0xABAD932F,
- 0x4E08FDCF,
- 0x6E0FAFF8,
- 0x7CCF76CF,
- 0xFD1FF9CF,
- 0xABF88DC6,
- 0xAB5679F7,
- 0xB0937383,
- 0xDFCE79F7,
- 0xB091E6BB,
- 0xE5BBE74F,
- 0xB3FA6F0F,
- 0x6FFB76CE,
- 0xEE0DF9CF,
- 0x2BFBEFEF,
- 0xCFEEF9CF,
- 0x76CEAD24,
- 0x90B2DF9A,
- 0x7FDDD0BF,
- 0x4BF847FD,
- 0x7CCF76CE,
- 0xCFEF7E1F,
- 0x7F1D7DFD,
- 0xF0B6EF71,
- 0x7FC177C1,
- 0xFBC86079,
- 0xE722FBC8,
- 0x5FFFDFFF,
- 0x5FB2FFFB,
- 0xFBC8F3C8,
- 0x94A67F01,
- 0x7F1D5F39,
- 0xAFE85F5E,
- 0xFFDFDF96,
- 0xCB9FAF7D,
- 0x5FC1AFED,
- 0x8C1C5FC1,
- 0xAFDD5FC3,
- 0xDF9A7EFD,
- 0xB0B25FB2,
- 0xFFFEABAD,
- 0x5FB2FFFE,
- 0x5FCE600B,
- 0xE6BB600B,
- 0x5FCEDFC6,
- 0x27FBEFDF,
- 0x5FC8CFDE,
- 0x3A9CE7C0,
- 0xEDF0F3C8,
- 0x7F0154CD,
- 0x7F1D2D3D,
- 0x363A7570,
- 0x7E0AF1CE,
- 0x37EF2E68,
- 0x7FEE10EC,
- 0xADF8EFDE,
- 0xCFEAE52F,
- 0x7D0FE12B,
- 0xF1CE5F65,
- 0x7E0A4DF8,
- 0xCFEA5F72,
- 0x7D0BEFEE,
- 0xCFEA5F74,
- 0xE522EFDE,
- 0x5F74CFDA,
- 0x0B627385,
- 0xDF627E0A,
- 0x30D8145B,
- 0xBFFFF3C8,
- 0x5FFFDFFF,
- 0xA7F85F5E,
- 0xBFFE7F7D,
- 0x10D31450,
- 0x5F36BFFF,
- 0xAF785F5E,
- 0xBFFDA7F8,
- 0x5F36BFFE,
- 0x77FD30C0,
- 0x4E08FDCF,
- 0xE5FF6E0F,
- 0xAFF87E1F,
- 0x7E0FFD1F,
- 0xF1CF5F1B,
- 0xABF80D5E,
- 0x5F5EFFEF,
- 0x79F730A2,
- 0xAFDD5F34,
- 0x47F85F34,
- 0xAFED7FDD,
- 0x50B24978,
- 0x47FD7F1D,
- 0x7DFD70AD,
- 0xEF717EC1,
- 0x6BA47F01,
- 0x2D267EFD,
- 0x30DE5F5E,
- 0xFFFD5F5E,
- 0xFFEF5F5E,
- 0xFFDF0CA0,
- 0xAFED0A9E,
- 0xAFDD0C3A,
- 0x5F3AAFBD,
- 0x7FBDB082,
- 0x5F8247F8
-};
-
-static uint patch_2f00[] __initdata = {
- 0x3E303430,
- 0x34343737,
- 0xABF7BF9B,
- 0x994B4FBD,
- 0xBD599493,
- 0x349FFF37,
- 0xFB9B177D,
- 0xD9936956,
- 0xBBFDD697,
- 0xBDD2FD11,
- 0x31DB9BB3,
- 0x63139637,
- 0x93733693,
- 0x193137F7,
- 0x331737AF,
- 0x7BB9B999,
- 0xBB197957,
- 0x7FDFD3D5,
- 0x73B773F7,
- 0x37933B99,
- 0x1D115316,
- 0x99315315,
- 0x31694BF4,
- 0xFBDBD359,
- 0x31497353,
- 0x76956D69,
- 0x7B9D9693,
- 0x13131979,
- 0x79376935
-};
-#endif
-
-/*
- * I2C/SPI/SMC1 relocation patch arrays.
- */
-
-#ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
-
-static uint patch_2000[] __initdata = {
- 0x3fff0000,
- 0x3ffd0000,
- 0x3ffb0000,
- 0x3ff90000,
- 0x5f13eff8,
- 0x5eb5eff8,
- 0x5f88adf7,
- 0x5fefadf7,
- 0x3a9cfbc8,
- 0x77cae1bb,
- 0xf4de7fad,
- 0xabae9330,
- 0x4e08fdcf,
- 0x6e0faff8,
- 0x7ccf76cf,
- 0xfdaff9cf,
- 0xabf88dc8,
- 0xab5879f7,
- 0xb0925d8d,
- 0xdfd079f7,
- 0xb090e6bb,
- 0xe5bbe74f,
- 0x9e046f0f,
- 0x6ffb76ce,
- 0xee0cf9cf,
- 0x2bfbefef,
- 0xcfeef9cf,
- 0x76cead23,
- 0x90b3df99,
- 0x7fddd0c1,
- 0x4bf847fd,
- 0x7ccf76ce,
- 0xcfef77ca,
- 0x7eaf7fad,
- 0x7dfdf0b7,
- 0xef7a7fca,
- 0x77cafbc8,
- 0x6079e722,
- 0xfbc85fff,
- 0xdfff5fb3,
- 0xfffbfbc8,
- 0xf3c894a5,
- 0xe7c9edf9,
- 0x7f9a7fad,
- 0x5f36afe8,
- 0x5f5bffdf,
- 0xdf95cb9e,
- 0xaf7d5fc3,
- 0xafed8c1b,
- 0x5fc3afdd,
- 0x5fc5df99,
- 0x7efdb0b3,
- 0x5fb3fffe,
- 0xabae5fb3,
- 0xfffe5fd0,
- 0x600be6bb,
- 0x600b5fd0,
- 0xdfc827fb,
- 0xefdf5fca,
- 0xcfde3a9c,
- 0xe7c9edf9,
- 0xf3c87f9e,
- 0x54ca7fed,
- 0x2d3a3637,
- 0x756f7e9a,
- 0xf1ce37ef,
- 0x2e677fee,
- 0x10ebadf8,
- 0xefdecfea,
- 0xe52f7d9f,
- 0xe12bf1ce,
- 0x5f647e9a,
- 0x4df8cfea,
- 0x5f717d9b,
- 0xefeecfea,
- 0x5f73e522,
- 0xefde5f73,
- 0xcfda0b61,
- 0x5d8fdf61,
- 0xe7c9edf9,
- 0x7e9a30d5,
- 0x1458bfff,
- 0xf3c85fff,
- 0xdfffa7f8,
- 0x5f5bbffe,
- 0x7f7d10d0,
- 0x144d5f33,
- 0xbfffaf78,
- 0x5f5bbffd,
- 0xa7f85f33,
- 0xbffe77fd,
- 0x30bd4e08,
- 0xfdcfe5ff,
- 0x6e0faff8,
- 0x7eef7e9f,
- 0xfdeff1cf,
- 0x5f17abf8,
- 0x0d5b5f5b,
- 0xffef79f7,
- 0x309eafdd,
- 0x5f3147f8,
- 0x5f31afed,
- 0x7fdd50af,
- 0x497847fd,
- 0x7f9e7fed,
- 0x7dfd70a9,
- 0xef7e7ece,
- 0x6ba07f9e,
- 0x2d227efd,
- 0x30db5f5b,
- 0xfffd5f5b,
- 0xffef5f5b,
- 0xffdf0c9c,
- 0xafed0a9a,
- 0xafdd0c37,
- 0x5f37afbd,
- 0x7fbdb081,
- 0x5f8147f8,
- 0x3a11e710,
- 0xedf0ccdd,
- 0xf3186d0a,
- 0x7f0e5f06,
- 0x7fedbb38,
- 0x3afe7468,
- 0x7fedf4fc,
- 0x8ffbb951,
- 0xb85f77fd,
- 0xb0df5ddd,
- 0xdefe7fed,
- 0x90e1e74d,
- 0x6f0dcbf7,
- 0xe7decfed,
- 0xcb74cfed,
- 0xcfeddf6d,
- 0x91714f74,
- 0x5dd2deef,
- 0x9e04e7df,
- 0xefbb6ffb,
- 0xe7ef7f0e,
- 0x9e097fed,
- 0xebdbeffa,
- 0xeb54affb,
- 0x7fea90d7,
- 0x7e0cf0c3,
- 0xbffff318,
- 0x5fffdfff,
- 0xac59efea,
- 0x7fce1ee5,
- 0xe2ff5ee1,
- 0xaffbe2ff,
- 0x5ee3affb,
- 0xf9cc7d0f,
- 0xaef8770f,
- 0x7d0fb0c6,
- 0xeffbbfff,
- 0xcfef5ede,
- 0x7d0fbfff,
- 0x5ede4cf8,
- 0x7fddd0bf,
- 0x49f847fd,
- 0x7efdf0bb,
- 0x7fedfffd,
- 0x7dfdf0b7,
- 0xef7e7e1e,
- 0x5ede7f0e,
- 0x3a11e710,
- 0xedf0ccab,
- 0xfb18ad2e,
- 0x1ea9bbb8,
- 0x74283b7e,
- 0x73c2e4bb,
- 0x2ada4fb8,
- 0xdc21e4bb,
- 0xb2a1ffbf,
- 0x5e2c43f8,
- 0xfc87e1bb,
- 0xe74ffd91,
- 0x6f0f4fe8,
- 0xc7ba32e2,
- 0xf396efeb,
- 0x600b4f78,
- 0xe5bb760b,
- 0x53acaef8,
- 0x4ef88b0e,
- 0xcfef9e09,
- 0xabf8751f,
- 0xefef5bac,
- 0x741f4fe8,
- 0x751e760d,
- 0x7fdbf081,
- 0x741cafce,
- 0xefcc7fce,
- 0x751e70ac,
- 0x741ce7bb,
- 0x3372cfed,
- 0xafdbefeb,
- 0xe5bb760b,
- 0x53f2aef8,
- 0xafe8e7eb,
- 0x4bf8771e,
- 0x7e247fed,
- 0x4fcbe2cc,
- 0x7fbc30a9,
- 0x7b0f7a0f,
- 0x34d577fd,
- 0x308b5db7,
- 0xde553e5f,
- 0xaf78741f,
- 0x741f30f0,
- 0xcfef5e2c,
- 0x741f3eac,
- 0xafb8771e,
- 0x5e677fed,
- 0x0bd3e2cc,
- 0x741ccfec,
- 0xe5ca53cd,
- 0x6fcb4f74,
- 0x5dadde4b,
- 0x2ab63d38,
- 0x4bb3de30,
- 0x751f741c,
- 0x6c42effa,
- 0xefea7fce,
- 0x6ffc30be,
- 0xefec3fca,
- 0x30b3de2e,
- 0xadf85d9e,
- 0xaf7daefd,
- 0x5d9ede2e,
- 0x5d9eafdd,
- 0x761f10ac,
- 0x1da07efd,
- 0x30adfffe,
- 0x4908fb18,
- 0x5fffdfff,
- 0xafbb709b,
- 0x4ef85e67,
- 0xadf814ad,
- 0x7a0f70ad,
- 0xcfef50ad,
- 0x7a0fde30,
- 0x5da0afed,
- 0x3c12780f,
- 0xefef780f,
- 0xefef790f,
- 0xa7f85e0f,
- 0xffef790f,
- 0xefef790f,
- 0x14adde2e,
- 0x5d9eadfd,
- 0x5e2dfffb,
- 0xe79addfd,
- 0xeff96079,
- 0x607ae79a,
- 0xddfceff9,
- 0x60795dff,
- 0x607acfef,
- 0xefefefdf,
- 0xefbfef7f,
- 0xeeffedff,
- 0xebffe7ff,
- 0xafefafdf,
- 0xafbfaf7f,
- 0xaeffadff,
- 0xabffa7ff,
- 0x6fef6fdf,
- 0x6fbf6f7f,
- 0x6eff6dff,
- 0x6bff67ff,
- 0x2fef2fdf,
- 0x2fbf2f7f,
- 0x2eff2dff,
- 0x2bff27ff,
- 0x4e08fd1f,
- 0xe5ff6e0f,
- 0xaff87eef,
- 0x7e0ffdef,
- 0xf11f6079,
- 0xabf8f542,
- 0x7e0af11c,
- 0x37cfae3a,
- 0x7fec90be,
- 0xadf8efdc,
- 0xcfeae52f,
- 0x7d0fe12b,
- 0xf11c6079,
- 0x7e0a4df8,
- 0xcfea5dc4,
- 0x7d0befec,
- 0xcfea5dc6,
- 0xe522efdc,
- 0x5dc6cfda,
- 0x4e08fd1f,
- 0x6e0faff8,
- 0x7c1f761f,
- 0xfdeff91f,
- 0x6079abf8,
- 0x761cee24,
- 0xf91f2bfb,
- 0xefefcfec,
- 0xf91f6079,
- 0x761c27fb,
- 0xefdf5da7,
- 0xcfdc7fdd,
- 0xd09c4bf8,
- 0x47fd7c1f,
- 0x761ccfcf,
- 0x7eef7fed,
- 0x7dfdf093,
- 0xef7e7f1e,
- 0x771efb18,
- 0x6079e722,
- 0xe6bbe5bb,
- 0xae0ae5bb,
- 0x600bae85,
- 0xe2bbe2bb,
- 0xe2bbe2bb,
- 0xaf02e2bb,
- 0xe2bb2ff9,
- 0x6079e2bb
-};
-
-static uint patch_2f00[] __initdata = {
- 0x30303030,
- 0x3e3e3434,
- 0xabbf9b99,
- 0x4b4fbdbd,
- 0x59949334,
- 0x9fff37fb,
- 0x9b177dd9,
- 0x936956bb,
- 0xfbdd697b,
- 0xdd2fd113,
- 0x1db9f7bb,
- 0x36313963,
- 0x79373369,
- 0x3193137f,
- 0x7331737a,
- 0xf7bb9b99,
- 0x9bb19795,
- 0x77fdfd3d,
- 0x573b773f,
- 0x737933f7,
- 0xb991d115,
- 0x31699315,
- 0x31531694,
- 0xbf4fbdbd,
- 0x35931497,
- 0x35376956,
- 0xbd697b9d,
- 0x96931313,
- 0x19797937,
- 0x6935af78,
- 0xb9b3baa3,
- 0xb8788683,
- 0x368f78f7,
- 0x87778733,
- 0x3ffffb3b,
- 0x8e8f78b8,
- 0x1d118e13,
- 0xf3ff3f8b,
- 0x6bd8e173,
- 0xd1366856,
- 0x68d1687b,
- 0x3daf78b8,
- 0x3a3a3f87,
- 0x8f81378f,
- 0xf876f887,
- 0x77fd8778,
- 0x737de8d6,
- 0xbbf8bfff,
- 0xd8df87f7,
- 0xfd876f7b,
- 0x8bfff8bd,
- 0x8683387d,
- 0xb873d87b,
- 0x3b8fd7f8,
- 0xf7338883,
- 0xbb8ee1f8,
- 0xef837377,
- 0x3337b836,
- 0x817d11f8,
- 0x7378b878,
- 0xd3368b7d,
- 0xed731b7d,
- 0x833731f3,
- 0xf22f3f23
-};
-
-static uint patch_2e00[] __initdata = {
- 0x27eeeeee,
- 0xeeeeeeee,
- 0xeeeeeeee,
- 0xeeeeeeee,
- 0xee4bf4fb,
- 0xdbd259bb,
- 0x1979577f,
- 0xdfd2d573,
- 0xb773f737,
- 0x4b4fbdbd,
- 0x25b9b177,
- 0xd2d17376,
- 0x956bbfdd,
- 0x697bdd2f,
- 0xff9f79ff,
- 0xff9ff22f
-};
-#endif
-
-/*
- * USB SOF patch arrays.
- */
-
-#ifdef CONFIG_USB_SOF_UCODE_PATCH
-
-static uint patch_2000[] __initdata = {
- 0x7fff0000,
- 0x7ffd0000,
- 0x7ffb0000,
- 0x49f7ba5b,
- 0xba383ffb,
- 0xf9b8b46d,
- 0xe5ab4e07,
- 0xaf77bffe,
- 0x3f7bbf79,
- 0xba5bba38,
- 0xe7676076,
- 0x60750000
-};
-
-static uint patch_2f00[] __initdata = {
- 0x3030304c,
- 0xcab9e441,
- 0xa1aaf220
-};
-#endif
-
-void __init cpm_load_patch(cpm8xx_t *cp)
-{
- volatile uint *dp; /* Dual-ported RAM. */
- volatile cpm8xx_t *commproc;
-#if defined(CONFIG_I2C_SPI_UCODE_PATCH) || \
- defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
- volatile iic_t *iip;
- volatile struct spi_pram *spp;
-#ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
- volatile smc_uart_t *smp;
-#endif
-#endif
- int i;
-
- commproc = cp;
-
-#ifdef CONFIG_USB_SOF_UCODE_PATCH
- commproc->cp_rccr = 0;
-
- dp = (uint *)(commproc->cp_dpmem);
- for (i=0; i<(sizeof(patch_2000)/4); i++)
- *dp++ = patch_2000[i];
-
- dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
- for (i=0; i<(sizeof(patch_2f00)/4); i++)
- *dp++ = patch_2f00[i];
-
- commproc->cp_rccr = 0x0009;
-
- printk("USB SOF microcode patch installed\n");
-#endif /* CONFIG_USB_SOF_UCODE_PATCH */
-
-#if defined(CONFIG_I2C_SPI_UCODE_PATCH) || \
- defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
-
- commproc->cp_rccr = 0;
-
- dp = (uint *)(commproc->cp_dpmem);
- for (i=0; i<(sizeof(patch_2000)/4); i++)
- *dp++ = patch_2000[i];
-
- dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
- for (i=0; i<(sizeof(patch_2f00)/4); i++)
- *dp++ = patch_2f00[i];
-
- iip = (iic_t *)&commproc->cp_dparam[PROFF_IIC];
-# define RPBASE 0x0500
- iip->iic_rpbase = RPBASE;
-
- /* Put SPI above the IIC, also 32-byte aligned.
- */
- i = (RPBASE + sizeof(iic_t) + 31) & ~31;
- spp = (struct spi_pram *)&commproc->cp_dparam[PROFF_SPI];
- spp->rpbase = i;
-
-# if defined(CONFIG_I2C_SPI_UCODE_PATCH)
- commproc->cp_cpmcr1 = 0x802a;
- commproc->cp_cpmcr2 = 0x8028;
- commproc->cp_cpmcr3 = 0x802e;
- commproc->cp_cpmcr4 = 0x802c;
- commproc->cp_rccr = 1;
-
- printk("I2C/SPI microcode patch installed.\n");
-# endif /* CONFIG_I2C_SPI_UCODE_PATCH */
-
-# if defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
-
- dp = (uint *)&(commproc->cp_dpmem[0x0e00]);
- for (i=0; i<(sizeof(patch_2e00)/4); i++)
- *dp++ = patch_2e00[i];
-
- commproc->cp_cpmcr1 = 0x8080;
- commproc->cp_cpmcr2 = 0x808a;
- commproc->cp_cpmcr3 = 0x8028;
- commproc->cp_cpmcr4 = 0x802a;
- commproc->cp_rccr = 3;
-
- smp = (smc_uart_t *)&commproc->cp_dparam[PROFF_SMC1];
- smp->smc_rpbase = 0x1FC0;
-
- printk("I2C/SPI/SMC1 microcode patch installed.\n");
-# endif /* CONFIG_I2C_SPI_SMC1_UCODE_PATCH) */
-
-#endif /* some variation of the I2C/SPI patch was selected */
-}
-
-/*
- * Take this entire routine out, since no one calls it and its
- * logic is suspect.
- */
-
-#if 0
-void
-verify_patch(volatile immap_t *immr)
-{
- volatile uint *dp;
- volatile cpm8xx_t *commproc;
- int i;
-
- commproc = (cpm8xx_t *)&immr->im_cpm;
-
- printk("cp_rccr %x\n", commproc->cp_rccr);
- commproc->cp_rccr = 0;
-
- dp = (uint *)(commproc->cp_dpmem);
- for (i=0; i<(sizeof(patch_2000)/4); i++)
- if (*dp++ != patch_2000[i]) {
- printk("patch_2000 bad at %d\n", i);
- dp--;
- printk("found 0x%X, wanted 0x%X\n", *dp, patch_2000[i]);
- break;
- }
-
- dp = (uint *)&(commproc->cp_dpmem[0x0f00]);
- for (i=0; i<(sizeof(patch_2f00)/4); i++)
- if (*dp++ != patch_2f00[i]) {
- printk("patch_2f00 bad at %d\n", i);
- dp--;
- printk("found 0x%X, wanted 0x%X\n", *dp, patch_2f00[i]);
- break;
- }
-
- commproc->cp_rccr = 0x0009;
-}
-#endif
diff --git a/arch/powerpc/sysdev/mmio_nvram.c b/arch/powerpc/sysdev/mmio_nvram.c
index c31f634f1973..eb48210ef98e 100644
--- a/arch/powerpc/sysdev/mmio_nvram.c
+++ b/arch/powerpc/sysdev/mmio_nvram.c
@@ -1,34 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* memory mapped NVRAM
*
* (C) Copyright IBM Corp. 2005
*
* Authors : Utz Bacher <utz.bacher@de.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/of_address.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <asm/machdep.h>
#include <asm/nvram.h>
-#include <asm/prom.h>
static void __iomem *mmio_nvram_start;
static long mmio_nvram_len;
diff --git a/arch/powerpc/sysdev/mpc5xxx_clocks.c b/arch/powerpc/sysdev/mpc5xxx_clocks.c
index 834a6d7fbd88..58cee28e2399 100644
--- a/arch/powerpc/sysdev/mpc5xxx_clocks.c
+++ b/arch/powerpc/sysdev/mpc5xxx_clocks.c
@@ -1,31 +1,36 @@
// SPDX-License-Identifier: GPL-2.0
-/**
- * mpc5xxx_get_bus_frequency - Find the bus frequency for a device
- * @node: device node
- *
- * Returns bus frequency (IPS on MPC512x, IPB on MPC52xx),
- * or 0 if the bus frequency cannot be found.
- */
#include <linux/kernel.h>
-#include <linux/of_platform.h>
#include <linux/export.h>
+#include <linux/property.h>
+
#include <asm/mpc5xxx.h>
-unsigned long mpc5xxx_get_bus_frequency(struct device_node *node)
+/**
+ * mpc5xxx_fwnode_get_bus_frequency - Find the bus frequency for a firmware node
+ * @fwnode: firmware node
+ *
+ * Returns bus frequency (IPS on MPC512x, IPB on MPC52xx),
+ * or 0 if the bus frequency cannot be found.
+ */
+unsigned long mpc5xxx_fwnode_get_bus_frequency(struct fwnode_handle *fwnode)
{
- const unsigned int *p_bus_freq = NULL;
+ struct fwnode_handle *parent;
+ u32 bus_freq;
+ int ret;
- of_node_get(node);
- while (node) {
- p_bus_freq = of_get_property(node, "bus-frequency", NULL);
- if (p_bus_freq)
- break;
+ ret = fwnode_property_read_u32(fwnode, "bus-frequency", &bus_freq);
+ if (!ret)
+ return bus_freq;
- node = of_get_next_parent(node);
+ fwnode_for_each_parent_node(fwnode, parent) {
+ ret = fwnode_property_read_u32(parent, "bus-frequency", &bus_freq);
+ if (!ret) {
+ fwnode_handle_put(parent);
+ return bus_freq;
+ }
}
- of_node_put(node);
- return p_bus_freq ? *p_bus_freq : 0;
+ return 0;
}
-EXPORT_SYMBOL(mpc5xxx_get_bus_frequency);
+EXPORT_SYMBOL(mpc5xxx_fwnode_get_bus_frequency);
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 934a77324f6b..67e51998d1ae 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -27,13 +27,16 @@
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/slab.h>
+#include <linux/string_choices.h>
#include <linux/syscore_ops.h>
#include <linux/ratelimit.h>
+#include <linux/pgtable.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <asm/ptrace.h>
#include <asm/signal.h>
#include <asm/io.h>
-#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/machdep.h>
#include <asm/mpic.h>
@@ -47,7 +50,7 @@
#define DBG(fmt...)
#endif
-struct bus_type mpic_subsys = {
+const struct bus_type mpic_subsys = {
.name = "mpic",
.dev_name = "mpic",
};
@@ -353,7 +356,7 @@ static void __init mpic_test_broken_ipi(struct mpic *mpic)
mpic_write(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0), MPIC_VECPRI_MASK);
r = mpic_read(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0));
- if (r == le32_to_cpu(MPIC_VECPRI_MASK)) {
+ if (r == swab32(MPIC_VECPRI_MASK)) {
printk(KERN_INFO "mpic: Detected reversed IPI registers\n");
mpic->flags |= MPIC_BROKEN_IPI;
}
@@ -472,9 +475,9 @@ static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase,
addr = addr | ((u64)readl(base + HT_MSI_ADDR_HI) << 32);
}
- printk(KERN_DEBUG "mpic: - HT:%02x.%x %s MSI mapping found @ 0x%llx\n",
- PCI_SLOT(devfn), PCI_FUNC(devfn),
- flags & HT_MSI_FLAGS_ENABLE ? "enabled" : "disabled", addr);
+ pr_debug("mpic: - HT:%02x.%x %s MSI mapping found @ 0x%llx\n",
+ PCI_SLOT(devfn), PCI_FUNC(devfn),
+ str_enabled_disabled(flags & HT_MSI_FLAGS_ENABLE), addr);
if (!(flags & HT_MSI_FLAGS_ENABLE))
writeb(flags | HT_MSI_FLAGS_ENABLE, base + HT_MSI_FLAGS);
@@ -602,7 +605,7 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
/* Find an mpic associated with a given linux interrupt */
static struct mpic *mpic_find(unsigned int irq)
{
- if (irq < NUM_ISA_INTERRUPTS)
+ if (irq < NR_IRQS_LEGACY)
return NULL;
return irq_get_chip_data(irq);
@@ -964,7 +967,7 @@ static struct irq_chip mpic_irq_chip = {
};
#ifdef CONFIG_SMP
-static struct irq_chip mpic_ipi_chip = {
+static const struct irq_chip mpic_ipi_chip = {
.irq_mask = mpic_mask_ipi,
.irq_unmask = mpic_unmask_ipi,
.irq_eoi = mpic_end_ipi,
@@ -978,7 +981,7 @@ static struct irq_chip mpic_tm_chip = {
};
#ifdef CONFIG_MPIC_U3_HT_IRQS
-static struct irq_chip mpic_irq_ht_chip = {
+static const struct irq_chip mpic_irq_ht_chip = {
.irq_startup = mpic_startup_ht_irq,
.irq_shutdown = mpic_shutdown_ht_irq,
.irq_mask = mpic_mask_irq,
@@ -1258,11 +1261,11 @@ struct mpic * __init mpic_alloc(struct device_node *node,
}
/* Read extra device-tree properties into the flags variable */
- if (of_get_property(node, "big-endian", NULL))
+ if (of_property_read_bool(node, "big-endian"))
flags |= MPIC_BIG_ENDIAN;
- if (of_get_property(node, "pic-no-reset", NULL))
+ if (of_property_read_bool(node, "pic-no-reset"))
flags |= MPIC_NO_RESET;
- if (of_get_property(node, "single-cpu-affinity", NULL))
+ if (of_property_read_bool(node, "single-cpu-affinity"))
flags |= MPIC_SINGLE_DEST_CPU;
if (of_device_is_compatible(node, "fsl,mpic")) {
flags |= MPIC_FSL | MPIC_LARGE_VECTORS;
@@ -1323,8 +1326,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
psrc = of_get_property(mpic->node, "protected-sources", &psize);
if (psrc) {
/* Allocate a bitmap with one bit per interrupt */
- unsigned int mapsize = BITS_TO_LONGS(intvec_top + 1);
- mpic->protected = kcalloc(mapsize, sizeof(long), GFP_KERNEL);
+ mpic->protected = bitmap_zalloc(intvec_top + 1, GFP_KERNEL);
BUG_ON(mpic->protected == NULL);
for (i = 0; i < psize/sizeof(u32); i++) {
if (psrc[i] > intvec_top)
@@ -1405,10 +1407,8 @@ struct mpic * __init mpic_alloc(struct device_node *node,
* with device trees generated by older versions of QEMU.
* fsl_version will be zero if MPIC_FSL is not set.
*/
- if (fsl_version < 0x400 && (flags & MPIC_ENABLE_COREINT)) {
- WARN_ON(ppc_md.get_irq != mpic_get_coreint_irq);
+ if (fsl_version < 0x400 && (flags & MPIC_ENABLE_COREINT))
ppc_md.get_irq = mpic_get_irq;
- }
/* Reset */
@@ -1484,9 +1484,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
mpic->isu_mask = (1 << mpic->isu_shift) - 1;
- mpic->irqhost = irq_domain_add_linear(mpic->node,
- intvec_top,
- &mpic_host_ops, mpic);
+ mpic->irqhost = irq_domain_create_linear(of_fwnode_handle(mpic->node),
+ intvec_top,
+ &mpic_host_ops, mpic);
/*
* FIXME: The code leaks the MPIC object and mappings here; this
@@ -1521,7 +1521,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
if (!(mpic->flags & MPIC_SECONDARY)) {
mpic_primary = mpic;
- irq_set_default_host(mpic->irqhost);
+ irq_set_default_domain(mpic->irqhost);
}
return mpic;
@@ -1786,7 +1786,7 @@ static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg)
return 0;
}
- return irq_linear_revmap(mpic->irqhost, src);
+ return irq_find_mapping(mpic->irqhost, src);
}
unsigned int mpic_get_one_irq(struct mpic *mpic)
@@ -1824,7 +1824,7 @@ unsigned int mpic_get_coreint_irq(void)
return 0;
}
- return irq_linear_revmap(mpic->irqhost, src);
+ return irq_find_mapping(mpic->irqhost, src);
#else
return 0;
#endif
@@ -1840,7 +1840,7 @@ unsigned int mpic_get_mcirq(void)
}
#ifdef CONFIG_SMP
-void mpic_request_ipis(void)
+void __init mpic_request_ipis(void)
{
struct mpic *mpic = mpic_primary;
int i;
@@ -1944,7 +1944,7 @@ static void mpic_suspend_one(struct mpic *mpic)
}
}
-static int mpic_suspend(void)
+static int mpic_suspend(void *data)
{
struct mpic *mpic = mpics;
@@ -1986,7 +1986,7 @@ static void mpic_resume_one(struct mpic *mpic)
} /* end for loop */
}
-static void mpic_resume(void)
+static void mpic_resume(void *data)
{
struct mpic *mpic = mpics;
@@ -1996,19 +1996,23 @@ static void mpic_resume(void)
}
}
-static struct syscore_ops mpic_syscore_ops = {
+static const struct syscore_ops mpic_syscore_ops = {
.resume = mpic_resume,
.suspend = mpic_suspend,
};
+static struct syscore mpic_syscore = {
+ .ops = &mpic_syscore_ops,
+};
+
static int mpic_init_sys(void)
{
int rc;
- register_syscore_ops(&mpic_syscore_ops);
+ register_syscore(&mpic_syscore);
rc = subsys_system_register(&mpic_subsys, NULL);
if (rc) {
- unregister_syscore_ops(&mpic_syscore_ops);
+ unregister_syscore(&mpic_syscore);
pr_err("mpic: Failed to register subsystem!\n");
return rc;
}
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h
index 32971a41853b..bb460ff57a06 100644
--- a/arch/powerpc/sysdev/mpic.h
+++ b/arch/powerpc/sysdev/mpic.h
@@ -1,20 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _POWERPC_SYSDEV_MPIC_H
#define _POWERPC_SYSDEV_MPIC_H
/*
* Copyright 2006-2007, Michael Ellerman, IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2 of the
- * License.
- *
*/
#ifdef CONFIG_PCI_MSI
extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq);
-extern int mpic_msi_init_allocator(struct mpic *mpic);
-extern int mpic_u3msi_init(struct mpic *mpic);
+int __init mpic_msi_init_allocator(struct mpic *mpic);
+int __init mpic_u3msi_init(struct mpic *mpic);
#else
static inline void mpic_msi_reserve_hwirq(struct mpic *mpic,
irq_hw_number_t hwirq)
@@ -29,7 +24,7 @@ static inline int mpic_u3msi_init(struct mpic *mpic)
#endif
#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PPC_PASEMI)
-int mpic_pasemi_msi_init(struct mpic *mpic);
+int __init mpic_pasemi_msi_init(struct mpic *mpic);
#else
static inline int mpic_pasemi_msi_init(struct mpic *mpic) { return -1; }
#endif
@@ -42,8 +37,8 @@ extern void mpic_reset_core(int cpu);
#ifdef CONFIG_FSL_SOC
extern int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw);
-extern void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum);
-extern int mpic_setup_error_int(struct mpic *mpic, int intvec);
+void __init mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum);
+int __init mpic_setup_error_int(struct mpic *mpic, int intvec);
#else
static inline int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw)
{
diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c
index 280e964e1aa8..7b449cc51aef 100644
--- a/arch/powerpc/sysdev/mpic_msgr.c
+++ b/arch/powerpc/sysdev/mpic_msgr.c
@@ -1,30 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation.
*
* Some ideas based on un-pushed work done by Vivek Mahajan, Jason Jin, and
* Mingkai Hu from Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2 of the
- * License.
- *
*/
#include <linux/list.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/slab.h>
-#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
#include <asm/mpic_msgr.h>
#define MPIC_MSGR_REGISTERS_PER_BLOCK 4
#define MPIC_MSGR_STRIDE 0x10
-#define MPIC_MSGR_MER_OFFSET 0x100
+#define MPIC_MSGR_MER_OFFSET (0x100 / sizeof(u32))
#define MSGR_INUSE 0
#define MSGR_FREE 1
@@ -104,7 +101,7 @@ void mpic_msgr_disable(struct mpic_msgr *msgr)
EXPORT_SYMBOL_GPL(mpic_msgr_disable);
/* The following three functions are used to compute the order and number of
- * the message register blocks. They are clearly very inefficent. However,
+ * the message register blocks. They are clearly very inefficient. However,
* they are called *only* a few times during device initialization.
*/
static unsigned int mpic_msgr_number_of_blocks(void)
@@ -120,11 +117,12 @@ static unsigned int mpic_msgr_number_of_blocks(void)
for (;;) {
snprintf(buf, sizeof(buf), "mpic-msgr-block%d", count);
- if (!of_find_property(aliases, buf, NULL))
+ if (!of_property_present(aliases, buf))
break;
count += 1;
}
+ of_node_put(aliases);
}
return count;
@@ -148,12 +146,18 @@ static int mpic_msgr_block_number(struct device_node *node)
for (index = 0; index < number_of_blocks; ++index) {
struct property *prop;
+ struct device_node *tn;
snprintf(buf, sizeof(buf), "mpic-msgr-block%d", index);
prop = of_find_property(aliases, buf, NULL);
- if (node == of_find_node_by_path(prop->value))
+ tn = of_find_node_by_path(prop->value);
+ if (node == tn) {
+ of_node_put(tn);
break;
+ }
+ of_node_put(tn);
}
+ of_node_put(aliases);
return index == number_of_blocks ? -1 : index;
}
@@ -196,7 +200,7 @@ static int mpic_msgr_probe(struct platform_device *dev)
/* IO map the message register block. */
of_address_to_resource(np, 0, &rsrc);
- msgr_block_addr = ioremap(rsrc.start, resource_size(&rsrc));
+ msgr_block_addr = devm_ioremap(&dev->dev, rsrc.start, resource_size(&rsrc));
if (!msgr_block_addr) {
dev_err(&dev->dev, "Failed to iomap MPIC message registers");
return -EFAULT;
@@ -231,7 +235,7 @@ static int mpic_msgr_probe(struct platform_device *dev)
reg_number = block_number * MPIC_MSGR_REGISTERS_PER_BLOCK + i;
msgr->base = msgr_block_addr + i * MPIC_MSGR_STRIDE;
- msgr->mer = (u32 *)((u8 *)msgr->base + MPIC_MSGR_MER_OFFSET);
+ msgr->mer = msgr->base + MPIC_MSGR_MER_OFFSET;
msgr->in_use = MSGR_FREE;
msgr->num = i;
raw_spin_lock_init(&msgr->lock);
diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c
index 9ed860aee9c3..34246c8e01c2 100644
--- a/arch/powerpc/sysdev/mpic_msi.c
+++ b/arch/powerpc/sysdev/mpic_msi.c
@@ -1,18 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2006-2007, Michael Ellerman, IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2 of the
- * License.
- *
*/
#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
#include <linux/bitmap.h>
#include <linux/msi.h>
#include <asm/mpic.h>
-#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
#include <asm/msi_bitmap.h>
@@ -29,7 +25,7 @@ void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
}
#ifdef CONFIG_MPIC_U3_HT_IRQS
-static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
+static int __init mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
{
irq_hw_number_t hwirq;
const struct irq_domain_ops *ops = mpic->irqhost->ops;
@@ -42,7 +38,7 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
/* Reserve source numbers we know are reserved in the HW.
*
* This is a bit of a mix of U3 and U4 reserves but that's going
- * to work fine, we have plenty enugh numbers left so let's just
+ * to work fine, we have plenty enough numbers left so let's just
* mark anything we don't like reserved.
*/
for (i = 0; i < 8; i++)
@@ -73,13 +69,13 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
return 0;
}
#else
-static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
+static int __init mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
{
return -1;
}
#endif
-int mpic_msi_init_allocator(struct mpic *mpic)
+int __init mpic_msi_init_allocator(struct mpic *mpic)
{
int rc;
diff --git a/arch/powerpc/sysdev/mpic_timer.c b/arch/powerpc/sysdev/mpic_timer.c
index 87e7c42777a8..60f5b3934b51 100644
--- a/arch/powerpc/sysdev/mpic_timer.c
+++ b/arch/powerpc/sysdev/mpic_timer.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* MPIC timer driver
*
* Copyright 2013 Freescale Semiconductor, Inc.
* Author: Dongsheng Wang <Dongsheng.Wang@freescale.com>
* Li Yang <leoli@freescale.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/kernel.h>
@@ -20,7 +16,6 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/syscore_ops.h>
#include <sysdev/fsl_soc.h>
@@ -259,7 +254,7 @@ EXPORT_SYMBOL(mpic_start_timer);
/**
* mpic_stop_timer - stop hardware timer
- * @handle: the timer to be stoped
+ * @handle: the timer to be stopped
*
* The timer periodically generates an interrupt. Unless user stops the timer.
*/
@@ -388,7 +383,7 @@ struct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
}
EXPORT_SYMBOL(mpic_request_timer);
-static int timer_group_get_freq(struct device_node *np,
+static int __init timer_group_get_freq(struct device_node *np,
struct timer_group_priv *priv)
{
u32 div;
@@ -415,7 +410,7 @@ static int timer_group_get_freq(struct device_node *np,
return 0;
}
-static int timer_group_get_irq(struct device_node *np,
+static int __init timer_group_get_irq(struct device_node *np,
struct timer_group_priv *priv)
{
const u32 all_timer[] = { 0, TIMERS_PER_GROUP };
@@ -463,7 +458,7 @@ static int timer_group_get_irq(struct device_node *np,
return 0;
}
-static void timer_group_init(struct device_node *np)
+static void __init timer_group_init(struct device_node *np)
{
struct timer_group_priv *priv;
unsigned int i = 0;
@@ -524,7 +519,7 @@ out:
kfree(priv);
}
-static void mpic_timer_resume(void)
+static void mpic_timer_resume(void *data)
{
struct timer_group_priv *priv;
@@ -540,10 +535,14 @@ static const struct of_device_id mpic_timer_ids[] = {
{},
};
-static struct syscore_ops mpic_timer_syscore_ops = {
+static const struct syscore_ops mpic_timer_syscore_ops = {
.resume = mpic_timer_resume,
};
+static struct syscore mpic_timer_syscore = {
+ .ops = &mpic_timer_syscore_ops,
+};
+
static int __init mpic_timer_init(void)
{
struct device_node *np = NULL;
@@ -551,7 +550,7 @@ static int __init mpic_timer_init(void)
for_each_matching_node(np, mpic_timer_ids)
timer_group_init(np);
- register_syscore_ops(&mpic_timer_syscore_ops);
+ register_syscore(&mpic_timer_syscore);
if (list_empty(&timer_group_list))
return -ENODEV;
diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c
index cfc1c57d760f..492cb03c0b62 100644
--- a/arch/powerpc/sysdev/mpic_u3msi.c
+++ b/arch/powerpc/sysdev/mpic_u3msi.c
@@ -1,18 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2006, Segher Boessenkool, IBM Corporation.
* Copyright 2006-2007, Michael Ellerman, IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2 of the
- * License.
- *
*/
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/msi.h>
#include <asm/mpic.h>
-#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
#include <asm/msi_bitmap.h>
@@ -83,7 +78,7 @@ static u64 find_u4_magic_addr(struct pci_dev *pdev, unsigned int hwirq)
/* U4 PCIe MSIs need to write to the special register in
* the bridge that generates interrupts. There should be
- * theorically a register at 0xf8005000 where you just write
+ * theoretically a register at 0xf8005000 where you just write
* the MSI number and that triggers the right interrupt, but
* unfortunately, this is busted in HW, the bridge endian swaps
* the value and hits the wrong nibble in the register.
@@ -109,17 +104,13 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
struct msi_desc *entry;
irq_hw_number_t hwirq;
- for_each_pci_msi_entry(entry, pdev) {
- if (!entry->irq)
- continue;
-
+ msi_for_each_desc(entry, &pdev->dev, MSI_DESC_ASSOCIATED) {
hwirq = virq_to_hw(entry->irq);
irq_set_msi_desc(entry->irq, NULL);
irq_dispose_mapping(entry->irq);
+ entry->irq = 0;
msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, 1);
}
-
- return;
}
static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
@@ -141,7 +132,7 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
return -ENXIO;
}
- for_each_pci_msi_entry(entry, pdev) {
+ msi_for_each_desc(entry, &pdev->dev, MSI_DESC_NOTASSOCIATED) {
hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1);
if (hwirq < 0) {
pr_debug("u3msi: failed allocating hwirq\n");
@@ -179,7 +170,7 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
return 0;
}
-int mpic_u3msi_init(struct mpic *mpic)
+int __init mpic_u3msi_init(struct mpic *mpic)
{
int rc;
struct pci_controller *phb;
diff --git a/arch/powerpc/sysdev/msi_bitmap.c b/arch/powerpc/sysdev/msi_bitmap.c
index d45450f6666a..456a4f64ae0a 100644
--- a/arch/powerpc/sysdev/msi_bitmap.c
+++ b/arch/powerpc/sysdev/msi_bitmap.c
@@ -1,11 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2006-2008, Michael Ellerman, IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2 of the
- * License.
- *
*/
#include <linux/slab.h>
@@ -13,6 +8,7 @@
#include <linux/kmemleak.h>
#include <linux/bitmap.h>
#include <linux/memblock.h>
+#include <linux/of.h>
#include <asm/msi_bitmap.h>
#include <asm/setup.h>
@@ -128,7 +124,7 @@ int __ref msi_bitmap_alloc(struct msi_bitmap *bmp, unsigned int irq_count,
if (bmp->bitmap_from_slab)
bmp->bitmap = kzalloc(size, GFP_KERNEL);
else {
- bmp->bitmap = memblock_alloc(size, SMP_CACHE_BYTES);
+ bmp->bitmap = memblock_alloc_or_panic(size, SMP_CACHE_BYTES);
/* the bitmap won't be freed from memblock allocator */
kmemleak_not_leak(bmp->bitmap);
}
diff --git a/arch/powerpc/sysdev/of_rtc.c b/arch/powerpc/sysdev/of_rtc.c
index 153fdac4720f..2211937d3788 100644
--- a/arch/powerpc/sysdev/of_rtc.c
+++ b/arch/powerpc/sysdev/of_rtc.c
@@ -1,20 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Instantiate mmio-mapped RTC chips based on device tree information
*
* Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/kernel.h>
-#include <linux/of.h>
#include <linux/init.h>
+#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <asm/prom.h>
+
static __initdata struct {
const char *compatible;
char *plat_name;
diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c
deleted file mode 100644
index 9ea6a221d9d5..000000000000
--- a/arch/powerpc/sysdev/pmi.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * pmi driver
- *
- * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
- *
- * PMI (Platform Management Interrupt) is a way to communicate
- * with the BMC (Baseboard Management Controller) via interrupts.
- * Unlike IPMI it is bidirectional and has a low latency.
- *
- * Author: Christian Krafft <krafft@de.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/completion.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/workqueue.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-
-#include <asm/io.h>
-#include <asm/pmi.h>
-#include <asm/prom.h>
-
-struct pmi_data {
- struct list_head handler;
- spinlock_t handler_spinlock;
- spinlock_t pmi_spinlock;
- struct mutex msg_mutex;
- pmi_message_t msg;
- struct completion *completion;
- struct platform_device *dev;
- int irq;
- u8 __iomem *pmi_reg;
- struct work_struct work;
-};
-
-static struct pmi_data *data;
-
-static irqreturn_t pmi_irq_handler(int irq, void *dev_id)
-{
- u8 type;
- int rc;
-
- spin_lock(&data->pmi_spinlock);
-
- type = ioread8(data->pmi_reg + PMI_READ_TYPE);
- pr_debug("pmi: got message of type %d\n", type);
-
- if (type & PMI_ACK && !data->completion) {
- printk(KERN_WARNING "pmi: got unexpected ACK message.\n");
- rc = -EIO;
- goto unlock;
- }
-
- if (data->completion && !(type & PMI_ACK)) {
- printk(KERN_WARNING "pmi: expected ACK, but got %d\n", type);
- rc = -EIO;
- goto unlock;
- }
-
- data->msg.type = type;
- data->msg.data0 = ioread8(data->pmi_reg + PMI_READ_DATA0);
- data->msg.data1 = ioread8(data->pmi_reg + PMI_READ_DATA1);
- data->msg.data2 = ioread8(data->pmi_reg + PMI_READ_DATA2);
- rc = 0;
-unlock:
- spin_unlock(&data->pmi_spinlock);
-
- if (rc == -EIO) {
- rc = IRQ_HANDLED;
- goto out;
- }
-
- if (data->msg.type & PMI_ACK) {
- complete(data->completion);
- rc = IRQ_HANDLED;
- goto out;
- }
-
- schedule_work(&data->work);
-
- rc = IRQ_HANDLED;
-out:
- return rc;
-}
-
-
-static const struct of_device_id pmi_match[] = {
- { .type = "ibm,pmi", .name = "ibm,pmi" },
- { .type = "ibm,pmi" },
- {},
-};
-
-MODULE_DEVICE_TABLE(of, pmi_match);
-
-static void pmi_notify_handlers(struct work_struct *work)
-{
- struct pmi_handler *handler;
-
- spin_lock(&data->handler_spinlock);
- list_for_each_entry(handler, &data->handler, node) {
- pr_debug("pmi: notifying handler %p\n", handler);
- if (handler->type == data->msg.type)
- handler->handle_pmi_message(data->msg);
- }
- spin_unlock(&data->handler_spinlock);
-}
-
-static int pmi_of_probe(struct platform_device *dev)
-{
- struct device_node *np = dev->dev.of_node;
- int rc;
-
- if (data) {
- printk(KERN_ERR "pmi: driver has already been initialized.\n");
- rc = -EBUSY;
- goto out;
- }
-
- data = kzalloc(sizeof(struct pmi_data), GFP_KERNEL);
- if (!data) {
- printk(KERN_ERR "pmi: could not allocate memory.\n");
- rc = -ENOMEM;
- goto out;
- }
-
- data->pmi_reg = of_iomap(np, 0);
- if (!data->pmi_reg) {
- printk(KERN_ERR "pmi: invalid register address.\n");
- rc = -EFAULT;
- goto error_cleanup_data;
- }
-
- INIT_LIST_HEAD(&data->handler);
-
- mutex_init(&data->msg_mutex);
- spin_lock_init(&data->pmi_spinlock);
- spin_lock_init(&data->handler_spinlock);
-
- INIT_WORK(&data->work, pmi_notify_handlers);
-
- data->dev = dev;
-
- data->irq = irq_of_parse_and_map(np, 0);
- if (!data->irq) {
- printk(KERN_ERR "pmi: invalid interrupt.\n");
- rc = -EFAULT;
- goto error_cleanup_iomap;
- }
-
- rc = request_irq(data->irq, pmi_irq_handler, 0, "pmi", NULL);
- if (rc) {
- printk(KERN_ERR "pmi: can't request IRQ %d: returned %d\n",
- data->irq, rc);
- goto error_cleanup_iomap;
- }
-
- printk(KERN_INFO "pmi: found pmi device at addr %p.\n", data->pmi_reg);
-
- goto out;
-
-error_cleanup_iomap:
- iounmap(data->pmi_reg);
-
-error_cleanup_data:
- kfree(data);
-
-out:
- return rc;
-}
-
-static int pmi_of_remove(struct platform_device *dev)
-{
- struct pmi_handler *handler, *tmp;
-
- free_irq(data->irq, NULL);
- iounmap(data->pmi_reg);
-
- spin_lock(&data->handler_spinlock);
-
- list_for_each_entry_safe(handler, tmp, &data->handler, node)
- list_del(&handler->node);
-
- spin_unlock(&data->handler_spinlock);
-
- kfree(data);
- data = NULL;
-
- return 0;
-}
-
-static struct platform_driver pmi_of_platform_driver = {
- .probe = pmi_of_probe,
- .remove = pmi_of_remove,
- .driver = {
- .name = "pmi",
- .of_match_table = pmi_match,
- },
-};
-module_platform_driver(pmi_of_platform_driver);
-
-int pmi_send_message(pmi_message_t msg)
-{
- unsigned long flags;
- DECLARE_COMPLETION_ONSTACK(completion);
-
- if (!data)
- return -ENODEV;
-
- mutex_lock(&data->msg_mutex);
-
- data->msg = msg;
- pr_debug("pmi_send_message: msg is %08x\n", *(u32*)&msg);
-
- data->completion = &completion;
-
- spin_lock_irqsave(&data->pmi_spinlock, flags);
- iowrite8(msg.data0, data->pmi_reg + PMI_WRITE_DATA0);
- iowrite8(msg.data1, data->pmi_reg + PMI_WRITE_DATA1);
- iowrite8(msg.data2, data->pmi_reg + PMI_WRITE_DATA2);
- iowrite8(msg.type, data->pmi_reg + PMI_WRITE_TYPE);
- spin_unlock_irqrestore(&data->pmi_spinlock, flags);
-
- pr_debug("pmi_send_message: wait for completion\n");
-
- wait_for_completion_interruptible_timeout(data->completion,
- PMI_TIMEOUT);
-
- data->completion = NULL;
-
- mutex_unlock(&data->msg_mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pmi_send_message);
-
-int pmi_register_handler(struct pmi_handler *handler)
-{
- if (!data)
- return -ENODEV;
-
- spin_lock(&data->handler_spinlock);
- list_add_tail(&handler->node, &data->handler);
- spin_unlock(&data->handler_spinlock);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pmi_register_handler);
-
-void pmi_unregister_handler(struct pmi_handler *handler)
-{
- if (!data)
- return;
-
- pr_debug("pmi: unregistering handler %p\n", handler);
-
- spin_lock(&data->handler_spinlock);
- list_del(&handler->node);
- spin_unlock(&data->handler_spinlock);
-}
-EXPORT_SYMBOL_GPL(pmi_unregister_handler);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
-MODULE_DESCRIPTION("IBM Platform Management Interrupt driver");
diff --git a/arch/powerpc/sysdev/rtc_cmos_setup.c b/arch/powerpc/sysdev/rtc_cmos_setup.c
index af0f9beddca9..9a232ae5e360 100644
--- a/arch/powerpc/sysdev/rtc_cmos_setup.c
+++ b/arch/powerpc/sysdev/rtc_cmos_setup.c
@@ -14,8 +14,8 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mc146818rtc.h>
+#include <linux/of_address.h>
-#include <asm/prom.h>
static int __init add_rtc(void)
{
@@ -66,4 +66,5 @@ static int __init add_rtc(void)
}
fs_initcall(add_rtc);
+MODULE_DESCRIPTION("PPC RTC CMOS driver");
MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/sysdev/scom.c b/arch/powerpc/sysdev/scom.c
deleted file mode 100644
index a707b24a7ddb..000000000000
--- a/arch/powerpc/sysdev/scom.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2010 Benjamin Herrenschmidt, IBM Corp
- * <benh@kernel.crashing.org>
- * and David Gibson, IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <asm/debugfs.h>
-#include <asm/prom.h>
-#include <asm/scom.h>
-#include <linux/uaccess.h>
-
-const struct scom_controller *scom_controller;
-EXPORT_SYMBOL_GPL(scom_controller);
-
-struct device_node *scom_find_parent(struct device_node *node)
-{
- struct device_node *par, *tmp;
- const u32 *p;
-
- for (par = of_node_get(node); par;) {
- if (of_get_property(par, "scom-controller", NULL))
- break;
- p = of_get_property(par, "scom-parent", NULL);
- tmp = par;
- if (p == NULL)
- par = of_get_parent(par);
- else
- par = of_find_node_by_phandle(*p);
- of_node_put(tmp);
- }
- return par;
-}
-EXPORT_SYMBOL_GPL(scom_find_parent);
-
-scom_map_t scom_map_device(struct device_node *dev, int index)
-{
- struct device_node *parent;
- unsigned int cells, size;
- const __be32 *prop, *sprop;
- u64 reg, cnt;
- scom_map_t ret;
-
- parent = scom_find_parent(dev);
-
- if (parent == NULL)
- return NULL;
-
- /*
- * We support "scom-reg" properties for adding scom registers
- * to a random device-tree node with an explicit scom-parent
- *
- * We also support the simple "reg" property if the device is
- * a direct child of a scom controller.
- *
- * In case both exist, "scom-reg" takes precedence.
- */
- prop = of_get_property(dev, "scom-reg", &size);
- sprop = of_get_property(parent, "#scom-cells", NULL);
- if (!prop && parent == dev->parent) {
- prop = of_get_property(dev, "reg", &size);
- sprop = of_get_property(parent, "#address-cells", NULL);
- }
- if (!prop)
- return NULL;
- cells = sprop ? be32_to_cpup(sprop) : 1;
- size >>= 2;
-
- if (index >= (size / (2*cells)))
- return NULL;
-
- reg = of_read_number(&prop[index * cells * 2], cells);
- cnt = of_read_number(&prop[index * cells * 2 + cells], cells);
-
- ret = scom_map(parent, reg, cnt);
- of_node_put(parent);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(scom_map_device);
-
-#ifdef CONFIG_SCOM_DEBUGFS
-struct scom_debug_entry {
- struct device_node *dn;
- struct debugfs_blob_wrapper path;
- char name[16];
-};
-
-static ssize_t scom_debug_read(struct file *filp, char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct scom_debug_entry *ent = filp->private_data;
- u64 __user *ubuf64 = (u64 __user *)ubuf;
- loff_t off = *ppos;
- ssize_t done = 0;
- u64 reg, reg_cnt, val;
- scom_map_t map;
- int rc;
-
- if (off < 0 || (off & 7) || (count & 7))
- return -EINVAL;
- reg = off >> 3;
- reg_cnt = count >> 3;
-
- map = scom_map(ent->dn, reg, reg_cnt);
- if (!scom_map_ok(map))
- return -ENXIO;
-
- for (reg = 0; reg < reg_cnt; reg++) {
- rc = scom_read(map, reg, &val);
- if (!rc)
- rc = put_user(val, ubuf64);
- if (rc) {
- if (!done)
- done = rc;
- break;
- }
- ubuf64++;
- *ppos += 8;
- done += 8;
- }
- scom_unmap(map);
- return done;
-}
-
-static ssize_t scom_debug_write(struct file* filp, const char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct scom_debug_entry *ent = filp->private_data;
- u64 __user *ubuf64 = (u64 __user *)ubuf;
- loff_t off = *ppos;
- ssize_t done = 0;
- u64 reg, reg_cnt, val;
- scom_map_t map;
- int rc;
-
- if (off < 0 || (off & 7) || (count & 7))
- return -EINVAL;
- reg = off >> 3;
- reg_cnt = count >> 3;
-
- map = scom_map(ent->dn, reg, reg_cnt);
- if (!scom_map_ok(map))
- return -ENXIO;
-
- for (reg = 0; reg < reg_cnt; reg++) {
- rc = get_user(val, ubuf64);
- if (!rc)
- rc = scom_write(map, reg, val);
- if (rc) {
- if (!done)
- done = rc;
- break;
- }
- ubuf64++;
- done += 8;
- }
- scom_unmap(map);
- return done;
-}
-
-static const struct file_operations scom_debug_fops = {
- .read = scom_debug_read,
- .write = scom_debug_write,
- .open = simple_open,
- .llseek = default_llseek,
-};
-
-static int scom_debug_init_one(struct dentry *root, struct device_node *dn,
- int i)
-{
- struct scom_debug_entry *ent;
- struct dentry *dir;
-
- ent = kzalloc(sizeof(*ent), GFP_KERNEL);
- if (!ent)
- return -ENOMEM;
-
- ent->dn = of_node_get(dn);
- snprintf(ent->name, 16, "%08x", i);
- ent->path.data = (void*)kasprintf(GFP_KERNEL, "%pOF", dn);
- ent->path.size = strlen((char *)ent->path.data);
-
- dir = debugfs_create_dir(ent->name, root);
- if (!dir) {
- of_node_put(dn);
- kfree(ent->path.data);
- kfree(ent);
- return -1;
- }
-
- debugfs_create_blob("devspec", 0400, dir, &ent->path);
- debugfs_create_file("access", 0600, dir, ent, &scom_debug_fops);
-
- return 0;
-}
-
-static int scom_debug_init(void)
-{
- struct device_node *dn;
- struct dentry *root;
- int i, rc;
-
- root = debugfs_create_dir("scom", powerpc_debugfs_root);
- if (!root)
- return -1;
-
- i = rc = 0;
- for_each_node_with_property(dn, "scom-controller") {
- int id = of_get_ibm_chip_id(dn);
- if (id == -1)
- id = i;
- rc |= scom_debug_init_one(root, dn, id);
- i++;
- }
-
- return rc;
-}
-device_initcall(scom_debug_init);
-#endif /* CONFIG_SCOM_DEBUGFS */
diff --git a/arch/powerpc/sysdev/simple_gpio.c b/arch/powerpc/sysdev/simple_gpio.c
deleted file mode 100644
index f02d4576138c..000000000000
--- a/arch/powerpc/sysdev/simple_gpio.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Simple Memory-Mapped GPIOs
- *
- * Copyright (c) MontaVista Software, Inc. 2008.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/gpio/driver.h>
-#include <linux/slab.h>
-#include <asm/prom.h>
-#include "simple_gpio.h"
-
-struct u8_gpio_chip {
- struct of_mm_gpio_chip mm_gc;
- spinlock_t lock;
-
- /* shadowed data register to clear/set bits safely */
- u8 data;
-};
-
-static u8 u8_pin2mask(unsigned int pin)
-{
- return 1 << (8 - 1 - pin);
-}
-
-static int u8_gpio_get(struct gpio_chip *gc, unsigned int gpio)
-{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-
- return !!(in_8(mm_gc->regs) & u8_pin2mask(gpio));
-}
-
-static void u8_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
-{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct u8_gpio_chip *u8_gc = gpiochip_get_data(gc);
- unsigned long flags;
-
- spin_lock_irqsave(&u8_gc->lock, flags);
-
- if (val)
- u8_gc->data |= u8_pin2mask(gpio);
- else
- u8_gc->data &= ~u8_pin2mask(gpio);
-
- out_8(mm_gc->regs, u8_gc->data);
-
- spin_unlock_irqrestore(&u8_gc->lock, flags);
-}
-
-static int u8_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
-{
- return 0;
-}
-
-static int u8_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
-{
- u8_gpio_set(gc, gpio, val);
- return 0;
-}
-
-static void u8_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
-{
- struct u8_gpio_chip *u8_gc =
- container_of(mm_gc, struct u8_gpio_chip, mm_gc);
-
- u8_gc->data = in_8(mm_gc->regs);
-}
-
-static int __init u8_simple_gpiochip_add(struct device_node *np)
-{
- int ret;
- struct u8_gpio_chip *u8_gc;
- struct of_mm_gpio_chip *mm_gc;
- struct gpio_chip *gc;
-
- u8_gc = kzalloc(sizeof(*u8_gc), GFP_KERNEL);
- if (!u8_gc)
- return -ENOMEM;
-
- spin_lock_init(&u8_gc->lock);
-
- mm_gc = &u8_gc->mm_gc;
- gc = &mm_gc->gc;
-
- mm_gc->save_regs = u8_gpio_save_regs;
- gc->ngpio = 8;
- gc->direction_input = u8_gpio_dir_in;
- gc->direction_output = u8_gpio_dir_out;
- gc->get = u8_gpio_get;
- gc->set = u8_gpio_set;
-
- ret = of_mm_gpiochip_add_data(np, mm_gc, u8_gc);
- if (ret)
- goto err;
- return 0;
-err:
- kfree(u8_gc);
- return ret;
-}
-
-void __init simple_gpiochip_init(const char *compatible)
-{
- struct device_node *np;
-
- for_each_compatible_node(np, NULL, compatible) {
- int ret;
- struct resource r;
-
- ret = of_address_to_resource(np, 0, &r);
- if (ret)
- goto err;
-
- switch (resource_size(&r)) {
- case 1:
- ret = u8_simple_gpiochip_add(np);
- if (ret)
- goto err;
- break;
- default:
- /*
- * Whenever you need support for GPIO bank width > 1,
- * please just turn u8_ code into huge macros, and
- * construct needed uX_ code with it.
- */
- ret = -ENOSYS;
- goto err;
- }
- continue;
-err:
- pr_err("%pOF: registration failed, status %d\n", np, ret);
- }
-}
diff --git a/arch/powerpc/sysdev/simple_gpio.h b/arch/powerpc/sysdev/simple_gpio.h
deleted file mode 100644
index f3f3a20d39e2..000000000000
--- a/arch/powerpc/sysdev/simple_gpio.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __SYSDEV_SIMPLE_GPIO_H
-#define __SYSDEV_SIMPLE_GPIO_H
-
-#include <linux/errno.h>
-
-#ifdef CONFIG_SIMPLE_GPIO
-extern void simple_gpiochip_init(const char *compatible);
-#else
-static inline void simple_gpiochip_init(const char *compatible) {}
-#endif /* CONFIG_SIMPLE_GPIO */
-
-#endif /* __SYSDEV_SIMPLE_GPIO_H */
diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c
index 1fd0717ade02..db520c40cb6f 100644
--- a/arch/powerpc/sysdev/tsi108_dev.c
+++ b/arch/powerpc/sysdev/tsi108_dev.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* tsi108/109 device setup code
*
* Maintained by Roy Zang < tie-fei.zang@freescale.com >
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/stddef.h>
@@ -18,14 +14,16 @@
#include <linux/irq.h>
#include <linux/export.h>
#include <linux/device.h>
+#include <linux/etherdevice.h>
#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/of_net.h>
#include <asm/tsi108.h>
#include <linux/atomic.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/prom.h>
#include <mm/mmu_decl.h>
#undef DEBUG
@@ -47,20 +45,19 @@ phys_addr_t get_csrbase(void)
tsi = of_find_node_by_type(NULL, "tsi-bridge");
if (tsi) {
- unsigned int size;
- const void *prop = of_get_property(tsi, "reg", &size);
- tsi108_csr_base = of_translate_address(tsi, prop);
+ struct resource res;
+ of_address_to_resource(tsi, 0, &res);
+ tsi108_csr_base = res.start;
of_node_put(tsi);
- };
+ }
return tsi108_csr_base;
}
+EXPORT_SYMBOL(get_csrbase);
u32 get_vir_csrbase(void)
{
return (u32) (ioremap(get_csrbase(), 0x10000));
}
-
-EXPORT_SYMBOL(get_csrbase);
EXPORT_SYMBOL(get_vir_csrbase);
static int __init tsi108_eth_of_init(void)
@@ -76,7 +73,6 @@ static int __init tsi108_eth_of_init(void)
struct device_node *phy, *mdio;
hw_info tsi_eth_data;
const unsigned int *phy_id;
- const void *mac_addr;
const phandle *ph;
memset(r, 0, sizeof(r));
@@ -104,9 +100,7 @@ static int __init tsi108_eth_of_init(void)
goto err;
}
- mac_addr = of_get_mac_address(np);
- if (mac_addr)
- memcpy(tsi_eth_data.mac_addr, mac_addr, 6);
+ of_get_mac_address(np, tsi_eth_data.mac_addr);
ph = of_get_property(np, "mdio-handle", NULL);
mdio = of_find_node_by_phandle(*ph);
@@ -138,7 +132,7 @@ static int __init tsi108_eth_of_init(void)
* driver itself to phylib and use a non-misleading
* name for the workaround flag - it's not actually to
* do with the model of PHY in use */
- if (of_get_property(phy, "txc-rxc-delay-disable", NULL))
+ if (of_property_read_bool(phy, "txc-rxc-delay-disable"))
tsi_eth_data.phy_type = TSI108_PHY_BCM54XX;
of_node_put(phy);
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
index 28ff1f53cefc..07d0f6a83879 100644
--- a/arch/powerpc/sysdev/tsi108_pci.c
+++ b/arch/powerpc/sysdev/tsi108_pci.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Common routines for Tundra Semiconductor TSI108 host bridge.
*
@@ -5,27 +6,15 @@
* Author: Alex Bounine (alexandreb@tundra.com)
* Author: Roy Zang (tie-fei.zang@freescale.com)
* Add pci interrupt router host
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/interrupt.h>
+#include <linux/of_address.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -36,7 +25,6 @@
#include <asm/tsi108.h>
#include <asm/tsi108_pci.h>
#include <asm/tsi108_irq.h>
-#include <asm/prom.h>
#undef DEBUG
#ifdef DEBUG
@@ -229,9 +217,8 @@ int __init tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary)
(hose)->ops = &tsi108_direct_pci_ops;
- printk(KERN_INFO "Found tsi108 PCI host bridge at 0x%08x. "
- "Firmware bus number: %d->%d\n",
- rsrc.start, hose->first_busno, hose->last_busno);
+ pr_info("Found tsi108 PCI host bridge at 0x%pa. Firmware bus number: %d->%d\n",
+ &rsrc.start, hose->first_busno, hose->last_busno);
/* Interpret the "ranges" property */
/* This also maps the I/O region and sets isa_io/mem_base */
@@ -270,7 +257,7 @@ static void tsi108_pci_int_unmask(u_int irq)
mb();
}
-static void init_pci_source(void)
+static void __init init_pci_source(void)
{
tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_CFG_CTL,
0x0000ff00);
@@ -417,7 +404,8 @@ void __init tsi108_pci_int_init(struct device_node *node)
{
DBG("Tsi108_pci_int_init: initializing PCI interrupts\n");
- pci_irq_host = irq_domain_add_legacy_isa(node, &pci_irq_domain_ops, NULL);
+ pci_irq_host = irq_domain_create_legacy(of_fwnode_handle(node), NR_IRQS_LEGACY, 0, 0,
+ &pci_irq_domain_ops, NULL);
if (pci_irq_host == NULL) {
printk(KERN_ERR "pci_irq_host: failed to allocate irq domain!\n");
return;
diff --git a/arch/powerpc/sysdev/udbg_memcons.c b/arch/powerpc/sysdev/udbg_memcons.c
index 9998c0de12d0..4de57ba52236 100644
--- a/arch/powerpc/sysdev/udbg_memcons.c
+++ b/arch/powerpc/sysdev/udbg_memcons.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* A udbg backend which logs messages and reads input from in memory
* buffers.
@@ -11,11 +12,6 @@
*
* Copyright (C) 2003-2005 Anton Blanchard and Milton Miller, IBM Corp
* Copyright (C) 2013 Alistair Popple, IBM Corp
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
@@ -45,7 +41,7 @@ struct memcons memcons = {
.input_end = &memcons_input[CONFIG_PPC_MEMCONS_INPUT_SIZE],
};
-void memcons_putc(char c)
+static void memcons_putc(char c)
{
char *new_output_pos;
@@ -58,7 +54,7 @@ void memcons_putc(char c)
memcons.output_pos = new_output_pos;
}
-int memcons_getc_poll(void)
+static int memcons_getc_poll(void)
{
char c;
char *new_input_pos;
@@ -81,7 +77,7 @@ int memcons_getc_poll(void)
return -1;
}
-int memcons_getc(void)
+static int memcons_getc(void)
{
int c;
@@ -96,7 +92,7 @@ int memcons_getc(void)
return c;
}
-void udbg_init_memcons(void)
+void __init udbg_init_memcons(void)
{
udbg_putc = memcons_putc;
udbg_getc = memcons_getc;
diff --git a/arch/powerpc/sysdev/xics/Kconfig b/arch/powerpc/sysdev/xics/Kconfig
index 86fee428f5f1..063d9195891f 100644
--- a/arch/powerpc/sysdev/xics/Kconfig
+++ b/arch/powerpc/sysdev/xics/Kconfig
@@ -1,15 +1,17 @@
# SPDX-License-Identifier: GPL-2.0
config PPC_XICS
- def_bool n
- select PPC_SMP_MUXED_IPI
- select HARDIRQS_SW_RESEND
+ def_bool n
+ select PPC_SMP_MUXED_IPI
+ select HARDIRQS_SW_RESEND
config PPC_ICP_NATIVE
- def_bool n
+ def_bool n
config PPC_ICP_HV
- def_bool n
+ def_bool n
config PPC_ICS_RTAS
- def_bool n
+ def_bool n
+config PPC_ICS_NATIVE
+ def_bool n
diff --git a/arch/powerpc/sysdev/xics/Makefile b/arch/powerpc/sysdev/xics/Makefile
index ba1e3117b1c0..747063927c6c 100644
--- a/arch/powerpc/sysdev/xics/Makefile
+++ b/arch/powerpc/sysdev/xics/Makefile
@@ -4,4 +4,5 @@ obj-y += xics-common.o
obj-$(CONFIG_PPC_ICP_NATIVE) += icp-native.o
obj-$(CONFIG_PPC_ICP_HV) += icp-hv.o
obj-$(CONFIG_PPC_ICS_RTAS) += ics-rtas.o
+obj-$(CONFIG_PPC_ICS_NATIVE) += ics-native.o
obj-$(CONFIG_PPC_POWERNV) += ics-opal.o icp-opal.o
diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c
index bbc839a98c41..cf8db19a4f7d 100644
--- a/arch/powerpc/sysdev/xics/icp-hv.c
+++ b/arch/powerpc/sysdev/xics/icp-hv.c
@@ -1,17 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2011 IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/cpu.h>
#include <linux/of.h>
@@ -166,7 +162,7 @@ static const struct icp_ops icp_hv_ops = {
#endif
};
-int icp_hv_init(void)
+int __init icp_hv_init(void)
{
struct device_node *np;
@@ -179,6 +175,7 @@ int icp_hv_init(void)
icp_ops = &icp_hv_ops;
+ of_node_put(np);
return 0;
}
diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c
index 37bfbc54aacb..4e89158a577c 100644
--- a/arch/powerpc/sysdev/xics/icp-native.c
+++ b/arch/powerpc/sysdev/xics/icp-native.c
@@ -1,25 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2011 IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/cpu.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/spinlock.h>
#include <linux/module.h>
-#include <asm/prom.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/irq.h>
@@ -145,31 +141,10 @@ static unsigned int icp_native_get_irq(void)
static void icp_native_cause_ipi(int cpu)
{
- kvmppc_set_host_ipi(cpu, 1);
+ kvmppc_set_host_ipi(cpu);
icp_native_set_qirr(cpu, IPI_PRIORITY);
}
-#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
-void icp_native_cause_ipi_rm(int cpu)
-{
- /*
- * Currently not used to send IPIs to another CPU
- * on the same core. Only caller is KVM real mode.
- * Need the physical address of the XICS to be
- * previously saved in kvm_hstate in the paca.
- */
- void __iomem *xics_phys;
-
- /*
- * Just like the cause_ipi functions, it is required to
- * include a full barrier before causing the IPI.
- */
- xics_phys = paca_ptrs[cpu]->kvm_hstate.xics_phys;
- mb();
- __raw_rm_writeb(IPI_PRIORITY, xics_phys + XICS_MFRR);
-}
-#endif
-
/*
* Called when an interrupt is received on an off-line CPU to
* clear the interrupt, so that the CPU can go back to nap mode.
@@ -184,7 +159,7 @@ void icp_native_flush_interrupt(void)
if (vec == XICS_IPI) {
/* Clear pending IPI */
int cpu = smp_processor_id();
- kvmppc_set_host_ipi(cpu, 0);
+ kvmppc_clear_host_ipi(cpu);
icp_native_set_qirr(cpu, 0xff);
} else {
pr_err("XICS: hw interrupt 0x%x to offline cpu, disabling\n",
@@ -205,7 +180,7 @@ static irqreturn_t icp_native_ipi_action(int irq, void *dev_id)
{
int cpu = smp_processor_id();
- kvmppc_set_host_ipi(cpu, 0);
+ kvmppc_clear_host_ipi(cpu);
icp_native_set_qirr(cpu, 0xff);
return smp_ipi_demux();
@@ -240,6 +215,8 @@ static int __init icp_native_map_one_cpu(int hw_id, unsigned long addr,
rname = kasprintf(GFP_KERNEL, "CPU %d [0x%x] Interrupt Presentation",
cpu, hw_id);
+ if (!rname)
+ return -ENOMEM;
if (!request_mem_region(addr, size, rname)) {
pr_warn("icp_native: Could not reserve ICP MMIO for CPU %d, interrupt server #0x%x\n",
cpu, hw_id);
@@ -263,7 +240,7 @@ static int __init icp_native_init_one_node(struct device_node *np,
unsigned int ilen;
const __be32 *ireg;
int i;
- int reg_tuple_size;
+ int num_reg;
int num_servers = 0;
/* This code does the theorically broken assumption that the interrupt
@@ -284,21 +261,14 @@ static int __init icp_native_init_one_node(struct device_node *np,
num_servers = of_read_number(ireg + 1, 1);
}
- ireg = of_get_property(np, "reg", &ilen);
- if (!ireg) {
- pr_err("icp_native: Can't find interrupt reg property");
- return -1;
- }
-
- reg_tuple_size = (of_n_addr_cells(np) + of_n_size_cells(np)) * 4;
- if (((ilen % reg_tuple_size) != 0)
- || (num_servers && (num_servers != (ilen / reg_tuple_size)))) {
+ num_reg = of_address_count(np);
+ if (num_servers && (num_servers != num_reg)) {
pr_err("icp_native: ICP reg len (%d) != num servers (%d)",
- ilen / reg_tuple_size, num_servers);
+ num_reg, num_servers);
return -1;
}
- for (i = 0; i < (ilen / reg_tuple_size); i++) {
+ for (i = 0; i < num_reg; i++) {
struct resource r;
int err;
diff --git a/arch/powerpc/sysdev/xics/icp-opal.c b/arch/powerpc/sysdev/xics/icp-opal.c
index c71d2ea42627..4dae624b9f2f 100644
--- a/arch/powerpc/sysdev/xics/icp-opal.c
+++ b/arch/powerpc/sysdev/xics/icp-opal.c
@@ -1,16 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2016 IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/cpu.h>
#include <linux/of.h>
@@ -130,7 +127,7 @@ static void icp_opal_cause_ipi(int cpu)
{
int hw_cpu = get_hard_smp_processor_id(cpu);
- kvmppc_set_host_ipi(cpu, 1);
+ kvmppc_set_host_ipi(cpu);
opal_int_set_mfrr(hw_cpu, IPI_PRIORITY);
}
@@ -138,7 +135,7 @@ static irqreturn_t icp_opal_ipi_action(int irq, void *dev_id)
{
int cpu = smp_processor_id();
- kvmppc_set_host_ipi(cpu, 0);
+ kvmppc_clear_host_ipi(cpu);
opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
return smp_ipi_demux();
@@ -161,7 +158,7 @@ void icp_opal_flush_interrupt(void)
if (vec == XICS_IPI) {
/* Clear pending IPI */
int cpu = smp_processor_id();
- kvmppc_set_host_ipi(cpu, 0);
+ kvmppc_clear_host_ipi(cpu);
opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
} else {
pr_err("XICS: hw interrupt 0x%x to offline cpu, "
@@ -187,7 +184,7 @@ static const struct icp_ops icp_opal_ops = {
#endif
};
-int icp_opal_init(void)
+int __init icp_opal_init(void)
{
struct device_node *np;
@@ -199,6 +196,7 @@ int icp_opal_init(void)
printk("XICS: Using OPAL ICP fallbacks\n");
+ of_node_put(np);
return 0;
}
diff --git a/arch/powerpc/sysdev/xics/ics-native.c b/arch/powerpc/sysdev/xics/ics-native.c
new file mode 100644
index 000000000000..112c8a1e8159
--- /dev/null
+++ b/arch/powerpc/sysdev/xics/ics-native.c
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ICS backend for OPAL managed interrupts.
+ *
+ * Copyright 2011 IBM Corp.
+ */
+
+//#define DEBUG
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+#include <linux/msi.h>
+#include <linux/list.h>
+
+#include <asm/smp.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/errno.h>
+#include <asm/xics.h>
+#include <asm/opal.h>
+#include <asm/firmware.h>
+
+struct ics_native {
+ struct ics ics;
+ struct device_node *node;
+ void __iomem *base;
+ u32 ibase;
+ u32 icount;
+};
+#define to_ics_native(_ics) container_of(_ics, struct ics_native, ics)
+
+static void __iomem *ics_native_xive(struct ics_native *in, unsigned int vec)
+{
+ return in->base + 0x800 + ((vec - in->ibase) << 2);
+}
+
+static void ics_native_unmask_irq(struct irq_data *d)
+{
+ unsigned int vec = (unsigned int)irqd_to_hwirq(d);
+ struct ics *ics = irq_data_get_irq_chip_data(d);
+ struct ics_native *in = to_ics_native(ics);
+ unsigned int server;
+
+ pr_devel("ics-native: unmask virq %d [hw 0x%x]\n", d->irq, vec);
+
+ if (vec < in->ibase || vec >= (in->ibase + in->icount))
+ return;
+
+ server = xics_get_irq_server(d->irq, irq_data_get_affinity_mask(d), 0);
+ out_be32(ics_native_xive(in, vec), (server << 8) | DEFAULT_PRIORITY);
+}
+
+static unsigned int ics_native_startup(struct irq_data *d)
+{
+#ifdef CONFIG_PCI_MSI
+ /*
+ * The generic MSI code returns with the interrupt disabled on the
+ * card, using the MSI mask bits. Firmware doesn't appear to unmask
+ * at that level, so we do it here by hand.
+ */
+ if (irq_data_get_msi_desc(d))
+ pci_msi_unmask_irq(d);
+#endif
+
+ /* unmask it */
+ ics_native_unmask_irq(d);
+ return 0;
+}
+
+static void ics_native_do_mask(struct ics_native *in, unsigned int vec)
+{
+ out_be32(ics_native_xive(in, vec), 0xff);
+}
+
+static void ics_native_mask_irq(struct irq_data *d)
+{
+ unsigned int vec = (unsigned int)irqd_to_hwirq(d);
+ struct ics *ics = irq_data_get_irq_chip_data(d);
+ struct ics_native *in = to_ics_native(ics);
+
+ pr_devel("ics-native: mask virq %d [hw 0x%x]\n", d->irq, vec);
+
+ if (vec < in->ibase || vec >= (in->ibase + in->icount))
+ return;
+ ics_native_do_mask(in, vec);
+}
+
+static int ics_native_set_affinity(struct irq_data *d,
+ const struct cpumask *cpumask,
+ bool force)
+{
+ unsigned int vec = (unsigned int)irqd_to_hwirq(d);
+ struct ics *ics = irq_data_get_irq_chip_data(d);
+ struct ics_native *in = to_ics_native(ics);
+ int server;
+ u32 xive;
+
+ if (vec < in->ibase || vec >= (in->ibase + in->icount))
+ return -EINVAL;
+
+ server = xics_get_irq_server(d->irq, cpumask, 1);
+ if (server == -1) {
+ pr_warn("%s: No online cpus in the mask %*pb for irq %d\n",
+ __func__, cpumask_pr_args(cpumask), d->irq);
+ return -1;
+ }
+
+ xive = in_be32(ics_native_xive(in, vec));
+ xive = (xive & 0xff) | (server << 8);
+ out_be32(ics_native_xive(in, vec), xive);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static struct irq_chip ics_native_irq_chip = {
+ .name = "ICS",
+ .irq_startup = ics_native_startup,
+ .irq_mask = ics_native_mask_irq,
+ .irq_unmask = ics_native_unmask_irq,
+ .irq_eoi = NULL, /* Patched at init time */
+ .irq_set_affinity = ics_native_set_affinity,
+ .irq_set_type = xics_set_irq_type,
+ .irq_retrigger = xics_retrigger,
+};
+
+static int ics_native_check(struct ics *ics, unsigned int hw_irq)
+{
+ struct ics_native *in = to_ics_native(ics);
+
+ pr_devel("%s: hw_irq=0x%x\n", __func__, hw_irq);
+
+ if (hw_irq < in->ibase || hw_irq >= (in->ibase + in->icount))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void ics_native_mask_unknown(struct ics *ics, unsigned long vec)
+{
+ struct ics_native *in = to_ics_native(ics);
+
+ if (vec < in->ibase || vec >= (in->ibase + in->icount))
+ return;
+
+ ics_native_do_mask(in, vec);
+}
+
+static long ics_native_get_server(struct ics *ics, unsigned long vec)
+{
+ struct ics_native *in = to_ics_native(ics);
+ u32 xive;
+
+ if (vec < in->ibase || vec >= (in->ibase + in->icount))
+ return -EINVAL;
+
+ xive = in_be32(ics_native_xive(in, vec));
+ return (xive >> 8) & 0xfff;
+}
+
+static int ics_native_host_match(struct ics *ics, struct device_node *node)
+{
+ struct ics_native *in = to_ics_native(ics);
+
+ return in->node == node;
+}
+
+static struct ics ics_native_template = {
+ .check = ics_native_check,
+ .mask_unknown = ics_native_mask_unknown,
+ .get_server = ics_native_get_server,
+ .host_match = ics_native_host_match,
+ .chip = &ics_native_irq_chip,
+};
+
+static int __init ics_native_add_one(struct device_node *np)
+{
+ struct ics_native *ics;
+ u32 ranges[2];
+ int rc, count;
+
+ ics = kzalloc(sizeof(struct ics_native), GFP_KERNEL);
+ if (!ics)
+ return -ENOMEM;
+ ics->node = of_node_get(np);
+ memcpy(&ics->ics, &ics_native_template, sizeof(struct ics));
+
+ ics->base = of_iomap(np, 0);
+ if (!ics->base) {
+ pr_err("Failed to map %pOFP\n", np);
+ rc = -ENOMEM;
+ goto fail;
+ }
+
+ count = of_property_count_u32_elems(np, "interrupt-ranges");
+ if (count < 2 || count & 1) {
+ pr_err("Failed to read interrupt-ranges of %pOFP\n", np);
+ rc = -EINVAL;
+ goto fail;
+ }
+ if (count > 2) {
+ pr_warn("ICS %pOFP has %d ranges, only one supported\n",
+ np, count >> 1);
+ }
+ rc = of_property_read_u32_array(np, "interrupt-ranges",
+ ranges, 2);
+ if (rc) {
+ pr_err("Failed to read interrupt-ranges of %pOFP\n", np);
+ goto fail;
+ }
+ ics->ibase = ranges[0];
+ ics->icount = ranges[1];
+
+ pr_info("ICS native initialized for sources %d..%d\n",
+ ics->ibase, ics->ibase + ics->icount - 1);
+
+ /* Register ourselves */
+ xics_register_ics(&ics->ics);
+
+ return 0;
+fail:
+ of_node_put(ics->node);
+ kfree(ics);
+ return rc;
+}
+
+int __init ics_native_init(void)
+{
+ struct device_node *ics;
+ bool found_one = false;
+
+ /* We need to patch our irq chip's EOI to point to the
+ * right ICP
+ */
+ ics_native_irq_chip.irq_eoi = icp_ops->eoi;
+
+ /* Find native ICS in the device-tree */
+ for_each_compatible_node(ics, NULL, "openpower,xics-sources") {
+ if (ics_native_add_one(ics) == 0)
+ found_one = true;
+ }
+
+ if (found_one)
+ pr_info("ICS native backend registered\n");
+
+ return found_one ? 0 : -ENODEV;
+}
diff --git a/arch/powerpc/sysdev/xics/ics-opal.c b/arch/powerpc/sysdev/xics/ics-opal.c
index f85f916ba432..5fe73dabab79 100644
--- a/arch/powerpc/sysdev/xics/ics-opal.c
+++ b/arch/powerpc/sysdev/xics/ics-opal.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ICS backend for OPAL managed interrupts.
*
* Copyright 2011 IBM Corp.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#undef DEBUG
@@ -22,7 +18,6 @@
#include <linux/spinlock.h>
#include <linux/msi.h>
-#include <asm/prom.h>
#include <asm/smp.h>
#include <asm/machdep.h>
#include <asm/irq.h>
@@ -66,17 +61,6 @@ static void ics_opal_unmask_irq(struct irq_data *d)
static unsigned int ics_opal_startup(struct irq_data *d)
{
-#ifdef CONFIG_PCI_MSI
- /*
- * The generic MSI code returns with the interrupt disabled on the
- * card, using the MSI mask bits. Firmware doesn't appear to unmask
- * at that level, so we do it here by hand.
- */
- if (irq_data_get_msi_desc(d))
- pci_msi_unmask_irq(d);
-#endif
-
- /* unmask it */
ics_opal_unmask_irq(d);
return 0;
}
@@ -127,7 +111,6 @@ static int ics_opal_set_affinity(struct irq_data *d,
__func__, d->irq, hw_irq, rc);
return -1;
}
- server = be16_to_cpu(oserver);
wanted_server = xics_get_irq_server(d->irq, cpumask, 1);
if (wanted_server < 0) {
@@ -137,7 +120,7 @@ static int ics_opal_set_affinity(struct irq_data *d,
}
server = ics_opal_mangle_server(wanted_server);
- pr_devel("ics-hal: set-affinity irq %d [hw 0x%x] server: 0x%x/0x%x\n",
+ pr_debug("ics-hal: set-affinity irq %d [hw 0x%x] server: 0x%x/0x%x\n",
d->irq, hw_irq, wanted_server, server);
rc = opal_set_xive(hw_irq, server, priority);
@@ -161,26 +144,13 @@ static struct irq_chip ics_opal_irq_chip = {
.irq_retrigger = xics_retrigger,
};
-static int ics_opal_map(struct ics *ics, unsigned int virq);
-static void ics_opal_mask_unknown(struct ics *ics, unsigned long vec);
-static long ics_opal_get_server(struct ics *ics, unsigned long vec);
-
static int ics_opal_host_match(struct ics *ics, struct device_node *node)
{
return 1;
}
-/* Only one global & state struct ics */
-static struct ics ics_hal = {
- .map = ics_opal_map,
- .mask_unknown = ics_opal_mask_unknown,
- .get_server = ics_opal_get_server,
- .host_match = ics_opal_host_match,
-};
-
-static int ics_opal_map(struct ics *ics, unsigned int virq)
+static int ics_opal_check(struct ics *ics, unsigned int hw_irq)
{
- unsigned int hw_irq = (unsigned int)virq_to_hw(virq);
int64_t rc;
__be16 server;
int8_t priority;
@@ -193,9 +163,6 @@ static int ics_opal_map(struct ics *ics, unsigned int virq)
if (rc != OPAL_SUCCESS)
return -ENXIO;
- irq_set_chip_and_handler(virq, &ics_opal_irq_chip, handle_fasteoi_irq);
- irq_set_chip_data(virq, &ics_hal);
-
return 0;
}
@@ -226,6 +193,15 @@ static long ics_opal_get_server(struct ics *ics, unsigned long vec)
return ics_opal_unmangle_server(be16_to_cpu(server));
}
+/* Only one global & state struct ics */
+static struct ics ics_hal = {
+ .check = ics_opal_check,
+ .mask_unknown = ics_opal_mask_unknown,
+ .get_server = ics_opal_get_server,
+ .host_match = ics_opal_host_match,
+ .chip = &ics_opal_irq_chip,
+};
+
int __init ics_opal_init(void)
{
if (!firmware_has_feature(FW_FEATURE_OPAL))
diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c
index 6aabc74688a6..b772a833d9b7 100644
--- a/arch/powerpc/sysdev/xics/ics-rtas.c
+++ b/arch/powerpc/sysdev/xics/ics-rtas.c
@@ -10,7 +10,6 @@
#include <linux/spinlock.h>
#include <linux/msi.h>
-#include <asm/prom.h>
#include <asm/smp.h>
#include <asm/machdep.h>
#include <asm/irq.h>
@@ -24,19 +23,6 @@ static int ibm_set_xive;
static int ibm_int_on;
static int ibm_int_off;
-static int ics_rtas_map(struct ics *ics, unsigned int virq);
-static void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec);
-static long ics_rtas_get_server(struct ics *ics, unsigned long vec);
-static int ics_rtas_host_match(struct ics *ics, struct device_node *node);
-
-/* Only one global & state struct ics */
-static struct ics ics_rtas = {
- .map = ics_rtas_map,
- .mask_unknown = ics_rtas_mask_unknown,
- .get_server = ics_rtas_get_server,
- .host_match = ics_rtas_host_match,
-};
-
static void ics_rtas_unmask_irq(struct irq_data *d)
{
unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
@@ -70,15 +56,6 @@ static void ics_rtas_unmask_irq(struct irq_data *d)
static unsigned int ics_rtas_startup(struct irq_data *d)
{
-#ifdef CONFIG_PCI_MSI
- /*
- * The generic MSI code returns with the interrupt disabled on the
- * card, using the MSI mask bits. Firmware doesn't appear to unmask
- * at that level, so we do it here by hand.
- */
- if (irq_data_get_msi_desc(d))
- pci_msi_unmask_irq(d);
-#endif
/* unmask it */
ics_rtas_unmask_irq(d);
return 0;
@@ -146,6 +123,9 @@ static int ics_rtas_set_affinity(struct irq_data *d,
return -1;
}
+ pr_debug("%s: irq %d [hw 0x%x] server: 0x%x\n", __func__, d->irq,
+ hw_irq, irq_server);
+
status = rtas_call(ibm_set_xive, 3, 1, NULL,
hw_irq, irq_server, xics_status[1]);
@@ -169,9 +149,8 @@ static struct irq_chip ics_rtas_irq_chip = {
.irq_retrigger = xics_retrigger,
};
-static int ics_rtas_map(struct ics *ics, unsigned int virq)
+static int ics_rtas_check(struct ics *ics, unsigned int hw_irq)
{
- unsigned int hw_irq = (unsigned int)virq_to_hw(virq);
int status[2];
int rc;
@@ -183,9 +162,6 @@ static int ics_rtas_map(struct ics *ics, unsigned int virq)
if (rc)
return -ENXIO;
- irq_set_chip_and_handler(virq, &ics_rtas_irq_chip, handle_fasteoi_irq);
- irq_set_chip_data(virq, &ics_rtas);
-
return 0;
}
@@ -213,12 +189,21 @@ static int ics_rtas_host_match(struct ics *ics, struct device_node *node)
return !of_device_is_compatible(node, "chrp,iic");
}
+/* Only one global & state struct ics */
+static struct ics ics_rtas = {
+ .check = ics_rtas_check,
+ .mask_unknown = ics_rtas_mask_unknown,
+ .get_server = ics_rtas_get_server,
+ .host_match = ics_rtas_host_match,
+ .chip = &ics_rtas_irq_chip,
+};
+
__init int ics_rtas_init(void)
{
- ibm_get_xive = rtas_token("ibm,get-xive");
- ibm_set_xive = rtas_token("ibm,set-xive");
- ibm_int_on = rtas_token("ibm,int-on");
- ibm_int_off = rtas_token("ibm,int-off");
+ ibm_get_xive = rtas_function_token(RTAS_FN_IBM_GET_XIVE);
+ ibm_set_xive = rtas_function_token(RTAS_FN_IBM_SET_XIVE);
+ ibm_int_on = rtas_function_token(RTAS_FN_IBM_INT_ON);
+ ibm_int_off = rtas_function_token(RTAS_FN_IBM_INT_OFF);
/* We enable the RTAS "ICS" if RTAS is present with the
* appropriate tokens
diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c
index f87470319d71..c3fa539a9898 100644
--- a/arch/powerpc/sysdev/xics/xics-common.c
+++ b/arch/powerpc/sysdev/xics/xics-common.c
@@ -1,16 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2011 IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
*/
#include <linux/types.h>
#include <linux/threads.h>
#include <linux/kernel.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/debugfs.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
@@ -22,7 +18,6 @@
#include <linux/spinlock.h>
#include <linux/delay.h>
-#include <asm/prom.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/machdep.h>
@@ -43,7 +38,7 @@ DEFINE_PER_CPU(struct xics_cppr, xics_cppr);
struct irq_domain *xics_host;
-static LIST_HEAD(ics_list);
+static struct ics *xics_ics;
void xics_update_irq_servers(void)
{
@@ -116,18 +111,17 @@ void xics_setup_cpu(void)
void xics_mask_unknown_vec(unsigned int vec)
{
- struct ics *ics;
-
pr_err("Interrupt 0x%x (real) is invalid, disabling it.\n", vec);
- list_for_each_entry(ics, &ics_list, link)
- ics->mask_unknown(ics, vec);
+ if (WARN_ON(!xics_ics))
+ return;
+ xics_ics->mask_unknown(xics_ics, vec);
}
#ifdef CONFIG_SMP
-static void xics_request_ipi(void)
+static void __init xics_request_ipi(void)
{
unsigned int ipi;
@@ -138,7 +132,7 @@ static void xics_request_ipi(void)
* IPIs are marked IRQF_PERCPU. The handler was set in map.
*/
BUG_ON(request_irq(ipi, icp_ops->ipi_action,
- IRQF_PERCPU | IRQF_NO_THREAD, "IPI", NULL));
+ IRQF_NO_DEBUG | IRQF_PERCPU | IRQF_NO_THREAD, "IPI", NULL));
}
void __init xics_smp_probe(void)
@@ -152,7 +146,7 @@ void __init xics_smp_probe(void)
#endif /* CONFIG_SMP */
-void xics_teardown_cpu(void)
+noinstr void xics_teardown_cpu(void)
{
struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr);
@@ -165,7 +159,7 @@ void xics_teardown_cpu(void)
icp_ops->teardown_cpu();
}
-void xics_kexec_teardown_cpu(int secondary)
+noinstr void xics_kexec_teardown_cpu(int secondary)
{
xics_teardown_cpu();
@@ -189,6 +183,8 @@ void xics_migrate_irqs_away(void)
unsigned int irq, virq;
struct irq_desc *desc;
+ pr_debug("%s: CPU %u\n", __func__, cpu);
+
/* If we used to be the default server, move to the new "boot_cpuid" */
if (hw_cpu == xics_default_server)
xics_update_irq_servers();
@@ -203,17 +199,19 @@ void xics_migrate_irqs_away(void)
struct irq_chip *chip;
long server;
unsigned long flags;
- struct ics *ics;
+ struct irq_data *irqd;
/* We can't set affinity on ISA interrupts */
- if (virq < NUM_ISA_INTERRUPTS)
+ if (virq < NR_IRQS_LEGACY)
continue;
/* We only need to migrate enabled IRQS */
if (!desc->action)
continue;
- if (desc->irq_data.domain != xics_host)
+ /* We need a mapping in the XICS IRQ domain */
+ irqd = irq_domain_get_irq_data(xics_host, virq);
+ if (!irqd)
continue;
- irq = desc->irq_data.hwirq;
+ irq = irqd_to_hwirq(irqd);
/* We need to get IPIs still. */
if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
continue;
@@ -224,13 +222,10 @@ void xics_migrate_irqs_away(void)
raw_spin_lock_irqsave(&desc->lock, flags);
/* Locate interrupt server */
- server = -1;
- ics = irq_desc_get_chip_data(desc);
- if (ics)
- server = ics->get_server(ics, irq);
+ server = xics_ics->get_server(xics_ics, irq);
if (server < 0) {
- printk(KERN_ERR "%s: Can't find server for irq %d\n",
- __func__, irq);
+ pr_err("%s: Can't find server for irq %d/%x\n",
+ __func__, virq, irq);
goto unlock;
}
@@ -312,13 +307,9 @@ int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask,
static int xics_host_match(struct irq_domain *h, struct device_node *node,
enum irq_domain_bus_token bus_token)
{
- struct ics *ics;
-
- list_for_each_entry(ics, &ics_list, link)
- if (ics->host_match(ics, node))
- return 1;
-
- return 0;
+ if (WARN_ON(!xics_ics))
+ return 0;
+ return xics_ics->host_match(xics_ics, node) ? 1 : 0;
}
/* Dummies */
@@ -332,12 +323,10 @@ static struct irq_chip xics_ipi_chip = {
.irq_unmask = xics_ipi_unmask,
};
-static int xics_host_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t hw)
+static int xics_host_map(struct irq_domain *domain, unsigned int virq,
+ irq_hw_number_t hwirq)
{
- struct ics *ics;
-
- pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hw);
+ pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hwirq);
/*
* Mark interrupts as edge sensitive by default so that resend
@@ -347,18 +336,23 @@ static int xics_host_map(struct irq_domain *h, unsigned int virq,
irq_clear_status_flags(virq, IRQ_LEVEL);
/* Don't call into ICS for IPIs */
- if (hw == XICS_IPI) {
+ if (hwirq == XICS_IPI) {
irq_set_chip_and_handler(virq, &xics_ipi_chip,
handle_percpu_irq);
return 0;
}
- /* Let the ICS setup the chip data */
- list_for_each_entry(ics, &ics_list, link)
- if (ics->map(ics, virq) == 0)
- return 0;
+ if (WARN_ON(!xics_ics))
+ return -EINVAL;
+
+ if (xics_ics->check(xics_ics, hwirq))
+ return -EINVAL;
- return -EINVAL;
+ /* Let the ICS be the chip data for the XICS domain. For ICS native */
+ irq_domain_set_info(domain, virq, hwirq, xics_ics->chip,
+ xics_ics, handle_fasteoi_irq, NULL, NULL);
+
+ return 0;
}
static int xics_host_xlate(struct irq_domain *h, struct device_node *ct,
@@ -417,22 +411,76 @@ int xics_retrigger(struct irq_data *data)
return 0;
}
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+static int xics_host_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
+ unsigned long *hwirq, unsigned int *type)
+{
+ return xics_host_xlate(d, to_of_node(fwspec->fwnode), fwspec->param,
+ fwspec->param_count, hwirq, type);
+}
+
+static int xics_host_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ struct irq_fwspec *fwspec = arg;
+ irq_hw_number_t hwirq;
+ unsigned int type = IRQ_TYPE_NONE;
+ int i, rc;
+
+ rc = xics_host_domain_translate(domain, fwspec, &hwirq, &type);
+ if (rc)
+ return rc;
+
+ pr_debug("%s %d/%lx #%d\n", __func__, virq, hwirq, nr_irqs);
+
+ for (i = 0; i < nr_irqs; i++)
+ irq_domain_set_info(domain, virq + i, hwirq + i, xics_ics->chip,
+ xics_ics, handle_fasteoi_irq, NULL, NULL);
+
+ return 0;
+}
+
+static void xics_host_domain_free(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
+{
+ pr_debug("%s %d #%d\n", __func__, virq, nr_irqs);
+}
+#endif
+
static const struct irq_domain_ops xics_host_ops = {
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+ .alloc = xics_host_domain_alloc,
+ .free = xics_host_domain_free,
+ .translate = xics_host_domain_translate,
+#endif
.match = xics_host_match,
.map = xics_host_map,
.xlate = xics_host_xlate,
};
-static void __init xics_init_host(void)
+static int __init xics_allocate_domain(void)
{
- xics_host = irq_domain_add_tree(NULL, &xics_host_ops, NULL);
- BUG_ON(xics_host == NULL);
- irq_set_default_host(xics_host);
+ struct fwnode_handle *fn;
+
+ fn = irq_domain_alloc_named_fwnode("XICS");
+ if (!fn)
+ return -ENOMEM;
+
+ xics_host = irq_domain_create_tree(fn, &xics_host_ops, NULL);
+ if (!xics_host) {
+ irq_domain_free_fwnode(fn);
+ return -ENOMEM;
+ }
+
+ irq_set_default_domain(xics_host);
+ return 0;
}
void __init xics_register_ics(struct ics *ics)
{
- list_add(&ics->link, &ics_list);
+ if (WARN_ONCE(xics_ics, "XICS: Source Controller is already defined !"))
+ return;
+ xics_ics = ics;
}
static void __init xics_get_server_size(void)
@@ -482,11 +530,15 @@ void __init xics_init(void)
if (rc < 0)
rc = ics_opal_init();
if (rc < 0)
+ rc = ics_native_init();
+ if (rc < 0)
pr_warn("XICS: Cannot find a Source Controller !\n");
/* Initialize common bits */
xics_get_server_size();
xics_update_irq_servers();
- xics_init_host();
+ rc = xics_allocate_domain();
+ if (rc < 0)
+ pr_err("XICS: Failed to create IRQ domain");
xics_setup_cpu();
}
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
deleted file mode 100644
index 4a86dcff3fcd..000000000000
--- a/arch/powerpc/sysdev/xilinx_intc.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Interrupt controller driver for Xilinx Virtex FPGAs
- *
- * Copyright (C) 2007 Secret Lab Technologies Ltd.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- */
-
-/*
- * This is a driver for the interrupt controller typically found in
- * Xilinx Virtex FPGA designs.
- *
- * The interrupt sense levels are hard coded into the FPGA design with
- * typically a 1:1 relationship between irq lines and devices (no shared
- * irq lines). Therefore, this driver does not attempt to handle edge
- * and level interrupts differently.
- */
-#undef DEBUG
-
-#include <linux/kernel.h>
-#include <linux/irq.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <asm/i8259.h>
-#include <asm/irq.h>
-#include <linux/irqchip.h>
-
-#if defined(CONFIG_PPC_I8259)
-/*
- * Support code for cascading to 8259 interrupt controllers
- */
-static void xilinx_i8259_cascade(struct irq_desc *desc)
-{
- struct irq_chip *chip = irq_desc_get_chip(desc);
- unsigned int cascade_irq = i8259_irq();
-
- if (cascade_irq)
- generic_handle_irq(cascade_irq);
-
- /* Let xilinx_intc end the interrupt */
- chip->irq_unmask(&desc->irq_data);
-}
-
-static void __init xilinx_i8259_setup_cascade(void)
-{
- struct device_node *cascade_node;
- int cascade_irq;
-
- /* Initialize i8259 controller */
- cascade_node = of_find_compatible_node(NULL, NULL, "chrp,iic");
- if (!cascade_node)
- return;
-
- cascade_irq = irq_of_parse_and_map(cascade_node, 0);
- if (!cascade_irq) {
- pr_err("virtex_ml510: Failed to map cascade interrupt\n");
- goto out;
- }
-
- i8259_init(cascade_node, 0);
- irq_set_chained_handler(cascade_irq, xilinx_i8259_cascade);
-
- /* Program irq 7 (usb/audio), 14/15 (ide) to level sensitive */
- /* This looks like a dirty hack to me --gcl */
- outb(0xc0, 0x4d0);
- outb(0xc0, 0x4d1);
-
- out:
- of_node_put(cascade_node);
-}
-#else
-static inline void xilinx_i8259_setup_cascade(void) { return; }
-#endif /* defined(CONFIG_PPC_I8259) */
-
-/*
- * Initialize master Xilinx interrupt controller
- */
-void __init xilinx_intc_init_tree(void)
-{
- irqchip_init();
- xilinx_i8259_setup_cascade();
-}
diff --git a/arch/powerpc/sysdev/xilinx_pci.c b/arch/powerpc/sysdev/xilinx_pci.c
deleted file mode 100644
index fea5667699ed..000000000000
--- a/arch/powerpc/sysdev/xilinx_pci.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * PCI support for Xilinx plbv46_pci soft-core which can be used on
- * Xilinx Virtex ML410 / ML510 boards.
- *
- * Copyright 2009 Roderick Colenbrander
- * Copyright 2009 Secret Lab Technologies Ltd.
- *
- * The pci bridge fixup code was copied from ppc4xx_pci.c and was written
- * by Benjamin Herrenschmidt.
- * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/ioport.h>
-#include <linux/of.h>
-#include <linux/pci.h>
-#include <mm/mmu_decl.h>
-#include <asm/io.h>
-#include <asm/xilinx_pci.h>
-
-#define XPLB_PCI_ADDR 0x10c
-#define XPLB_PCI_DATA 0x110
-#define XPLB_PCI_BUS 0x114
-
-#define PCI_HOST_ENABLE_CMD PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
-
-static const struct of_device_id xilinx_pci_match[] = {
- { .compatible = "xlnx,plbv46-pci-1.03.a", },
- {}
-};
-
-/**
- * xilinx_pci_fixup_bridge - Block Xilinx PHB configuration.
- */
-static void xilinx_pci_fixup_bridge(struct pci_dev *dev)
-{
- struct pci_controller *hose;
- int i;
-
- if (dev->devfn || dev->bus->self)
- return;
-
- hose = pci_bus_to_host(dev->bus);
- if (!hose)
- return;
-
- if (!of_match_node(xilinx_pci_match, hose->dn))
- return;
-
- /* Hide the PCI host BARs from the kernel as their content doesn't
- * fit well in the resource management
- */
- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
- dev->resource[i].start = 0;
- dev->resource[i].end = 0;
- dev->resource[i].flags = 0;
- }
-
- dev_info(&dev->dev, "Hiding Xilinx plb-pci host bridge resources %s\n",
- pci_name(dev));
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, xilinx_pci_fixup_bridge);
-
-/**
- * xilinx_pci_exclude_device - Don't do config access for non-root bus
- *
- * This is a hack. Config access to any bus other than bus 0 does not
- * currently work on the ML510 so we prevent it here.
- */
-static int
-xilinx_pci_exclude_device(struct pci_controller *hose, u_char bus, u8 devfn)
-{
- return (bus != 0);
-}
-
-/**
- * xilinx_pci_init - Find and register a Xilinx PCI host bridge
- */
-void __init xilinx_pci_init(void)
-{
- struct pci_controller *hose;
- struct resource r;
- void __iomem *pci_reg;
- struct device_node *pci_node;
-
- pci_node = of_find_matching_node(NULL, xilinx_pci_match);
- if(!pci_node)
- return;
-
- if (of_address_to_resource(pci_node, 0, &r)) {
- pr_err("xilinx-pci: cannot resolve base address\n");
- return;
- }
-
- hose = pcibios_alloc_controller(pci_node);
- if (!hose) {
- pr_err("xilinx-pci: pcibios_alloc_controller() failed\n");
- return;
- }
-
- /* Setup config space */
- setup_indirect_pci(hose, r.start + XPLB_PCI_ADDR,
- r.start + XPLB_PCI_DATA,
- PPC_INDIRECT_TYPE_SET_CFG_TYPE);
-
- /* According to the xilinx plbv46_pci documentation the soft-core starts
- * a self-init when the bus master enable bit is set. Without this bit
- * set the pci bus can't be scanned.
- */
- early_write_config_word(hose, 0, 0, PCI_COMMAND, PCI_HOST_ENABLE_CMD);
-
- /* Set the max latency timer to 255 */
- early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0xff);
-
- /* Set the max bus number to 255 */
- pci_reg = of_iomap(pci_node, 0);
- out_8(pci_reg + XPLB_PCI_BUS, 0xff);
- iounmap(pci_reg);
-
- /* Nothing past the root bridge is working right now. By default
- * exclude config access to anything except bus 0 */
- if (!ppc_md.pci_exclude_device)
- ppc_md.pci_exclude_device = xilinx_pci_exclude_device;
-
- /* Register the host bridge with the linux kernel! */
- pci_process_bridge_OF_ranges(hose, pci_node, 1);
-
- pr_info("xilinx-pci: Registered PCI host bridge\n");
-}
diff --git a/arch/powerpc/sysdev/xive/Makefile b/arch/powerpc/sysdev/xive/Makefile
index dea2abc23f4d..e5108883894a 100644
--- a/arch/powerpc/sysdev/xive/Makefile
+++ b/arch/powerpc/sysdev/xive/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-y += common.o
obj-$(CONFIG_PPC_XIVE_NATIVE) += native.o
diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c
index 94a69a62f5db..8d0123b0ae84 100644
--- a/arch/powerpc/sysdev/xive/common.c
+++ b/arch/powerpc/sysdev/xive/common.c
@@ -1,10 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2016,2017 IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#define pr_fmt(fmt) "xive: " fmt
@@ -13,6 +9,7 @@
#include <linux/threads.h>
#include <linux/kernel.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/debugfs.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
@@ -23,8 +20,8 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/msi.h>
+#include <linux/vmalloc.h>
-#include <asm/prom.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/machdep.h>
@@ -65,22 +62,37 @@ static const struct xive_ops *xive_ops;
static struct irq_domain *xive_irq_domain;
#ifdef CONFIG_SMP
-/* The IPIs all use the same logical irq number */
-static u32 xive_ipi_irq;
+/* The IPIs use the same logical irq number when on the same chip */
+static struct xive_ipi_desc {
+ unsigned int irq;
+ char name[16];
+ atomic_t started;
+} *xive_ipis;
+
+/*
+ * Use early_cpu_to_node() for hot-plugged CPUs
+ */
+static unsigned int xive_ipi_cpu_to_irq(unsigned int cpu)
+{
+ return xive_ipis[early_cpu_to_node(cpu)].irq;
+}
#endif
/* Xive state for each CPU */
static DEFINE_PER_CPU(struct xive_cpu *, xive_cpu);
+/* An invalid CPU target */
+#define XIVE_INVALID_TARGET (-1)
+
/*
- * A "disabled" interrupt should never fire, to catch problems
- * we set its logical number to this
+ * Global toggle to switch on/off StoreEOI
*/
-#define XIVE_BAD_IRQ 0x7fffffff
-#define XIVE_MAX_IRQ (XIVE_BAD_IRQ - 1)
+static bool xive_store_eoi = true;
-/* An invalid CPU target */
-#define XIVE_INVALID_TARGET (-1)
+static bool xive_is_store_eoi(struct xive_irq_data *xd)
+{
+ return xd->flags & XIVE_IRQ_FLAG_STORE_EOI && xive_store_eoi;
+}
/*
* Read the next entry in a queue, return its content if it's valid
@@ -139,7 +151,7 @@ static u32 xive_read_eq(struct xive_q *q, bool just_peek)
static u32 xive_scan_interrupts(struct xive_cpu *xc, bool just_peek)
{
u32 irq = 0;
- u8 prio;
+ u8 prio = 0;
/* Find highest pending priority */
while (xc->pending_prio != 0) {
@@ -152,8 +164,19 @@ static u32 xive_scan_interrupts(struct xive_cpu *xc, bool just_peek)
irq = xive_read_eq(&xc->queue[prio], just_peek);
/* Found something ? That's it */
- if (irq)
- break;
+ if (irq) {
+ if (just_peek || irq_to_desc(irq))
+ break;
+ /*
+ * We should never get here; if we do then we must
+ * have failed to synchronize the interrupt properly
+ * when shutting it down.
+ */
+ pr_crit("xive: got interrupt %d without descriptor, dropping\n",
+ irq);
+ WARN_ON(1);
+ continue;
+ }
/* Clear pending bits */
xc->pending_prio &= ~(1 << prio);
@@ -189,15 +212,14 @@ static u32 xive_scan_interrupts(struct xive_cpu *xc, bool just_peek)
/*
* This is used to perform the magic loads from an ESB
- * described in xive.h
+ * described in xive-regs.h
*/
static notrace u8 xive_esb_read(struct xive_irq_data *xd, u32 offset)
{
u64 val;
- /* Handle HW errata */
- if (xd->flags & XIVE_IRQ_FLAG_SHIFT_BUG)
- offset |= offset << 4;
+ if (offset == XIVE_ESB_SET_PQ_10 && xive_is_store_eoi(xd))
+ offset |= XIVE_ESB_LD_ST_MO;
if ((xd->flags & XIVE_IRQ_FLAG_H_INT_ESB) && xive_ops->esb_rw)
val = xive_ops->esb_rw(xd->hw_irq, offset, 0, 0);
@@ -209,16 +231,27 @@ static notrace u8 xive_esb_read(struct xive_irq_data *xd, u32 offset)
static void xive_esb_write(struct xive_irq_data *xd, u32 offset, u64 data)
{
- /* Handle HW errata */
- if (xd->flags & XIVE_IRQ_FLAG_SHIFT_BUG)
- offset |= offset << 4;
-
if ((xd->flags & XIVE_IRQ_FLAG_H_INT_ESB) && xive_ops->esb_rw)
xive_ops->esb_rw(xd->hw_irq, offset, data, 1);
else
out_be64(xd->eoi_mmio + offset, data);
}
+#if defined(CONFIG_XMON) || defined(CONFIG_DEBUG_FS)
+static void xive_irq_data_dump(struct xive_irq_data *xd, char *buffer, size_t size)
+{
+ u64 val = xive_esb_read(xd, XIVE_ESB_GET);
+
+ snprintf(buffer, size, "flags=%c%c%c PQ=%c%c 0x%016llx 0x%016llx",
+ xive_is_store_eoi(xd) ? 'S' : ' ',
+ xd->flags & XIVE_IRQ_FLAG_LSI ? 'L' : ' ',
+ xd->flags & XIVE_IRQ_FLAG_H_INT_ESB ? 'H' : ' ',
+ val & XIVE_ESB_VAL_P ? 'P' : '-',
+ val & XIVE_ESB_VAL_Q ? 'Q' : '-',
+ xd->trig_page, xd->eoi_page);
+}
+#endif
+
#ifdef CONFIG_XMON
static notrace void xive_dump_eq(const char *name, struct xive_q *q)
{
@@ -230,26 +263,82 @@ static notrace void xive_dump_eq(const char *name, struct xive_q *q)
i0 = be32_to_cpup(q->qpage + idx);
idx = (idx + 1) & q->msk;
i1 = be32_to_cpup(q->qpage + idx);
- xmon_printf(" %s Q T=%d %08x %08x ...\n", name,
- q->toggle, i0, i1);
+ xmon_printf("%s idx=%d T=%d %08x %08x ...", name,
+ q->idx, q->toggle, i0, i1);
}
notrace void xmon_xive_do_dump(int cpu)
{
struct xive_cpu *xc = per_cpu(xive_cpu, cpu);
- xmon_printf("XIVE state for CPU %d:\n", cpu);
- xmon_printf(" pp=%02x cppr=%02x\n", xc->pending_prio, xc->cppr);
- xive_dump_eq("IRQ", &xc->queue[xive_irq_priority]);
+ xmon_printf("CPU %d:", cpu);
+ if (xc) {
+ xmon_printf("pp=%02x CPPR=%02x ", xc->pending_prio, xc->cppr);
+
#ifdef CONFIG_SMP
- {
- u64 val = xive_esb_read(&xc->ipi_data, XIVE_ESB_GET);
- xmon_printf(" IPI state: %x:%c%c\n", xc->hw_ipi,
- val & XIVE_ESB_VAL_P ? 'P' : 'p',
- val & XIVE_ESB_VAL_Q ? 'Q' : 'q');
- }
+ {
+ char buffer[128];
+
+ xive_irq_data_dump(&xc->ipi_data, buffer, sizeof(buffer));
+ xmon_printf("IPI=0x%08x %s", xc->hw_ipi, buffer);
+ }
#endif
+ xive_dump_eq("EQ", &xc->queue[xive_irq_priority]);
+ }
+ xmon_printf("\n");
}
+
+static struct irq_data *xive_get_irq_data(u32 hw_irq)
+{
+ unsigned int irq = irq_find_mapping(xive_irq_domain, hw_irq);
+
+ return irq ? irq_get_irq_data(irq) : NULL;
+}
+
+int xmon_xive_get_irq_config(u32 hw_irq, struct irq_data *d)
+{
+ int rc;
+ u32 target;
+ u8 prio;
+ u32 lirq;
+
+ rc = xive_ops->get_irq_config(hw_irq, &target, &prio, &lirq);
+ if (rc) {
+ xmon_printf("IRQ 0x%08x : no config rc=%d\n", hw_irq, rc);
+ return rc;
+ }
+
+ xmon_printf("IRQ 0x%08x : target=0x%x prio=%02x lirq=0x%x ",
+ hw_irq, target, prio, lirq);
+
+ if (!d)
+ d = xive_get_irq_data(hw_irq);
+
+ if (d) {
+ char buffer[128];
+
+ xive_irq_data_dump(irq_data_get_irq_chip_data(d),
+ buffer, sizeof(buffer));
+ xmon_printf("%s", buffer);
+ }
+
+ xmon_printf("\n");
+ return 0;
+}
+
+void xmon_xive_get_irq_all(void)
+{
+ unsigned int i;
+ struct irq_desc *desc;
+
+ for_each_irq_desc(i, desc) {
+ struct irq_data *d = irq_domain_get_irq_data(xive_irq_domain, i);
+
+ if (d)
+ xmon_xive_get_irq_config(irqd_to_hwirq(d), d);
+ }
+}
+
#endif /* CONFIG_XMON */
static unsigned int xive_get_irq(void)
@@ -294,7 +383,7 @@ static unsigned int xive_get_irq(void)
* CPU.
*
* If we find that there is indeed more in there, we call
- * force_external_irq_replay() to make Linux synthetize an
+ * force_external_irq_replay() to make Linux synthesize an
* external interrupt on the next call to local_irq_restore().
*/
static void xive_do_queue_eoi(struct xive_cpu *xc)
@@ -309,55 +398,46 @@ static void xive_do_queue_eoi(struct xive_cpu *xc)
* EOI an interrupt at the source. There are several methods
* to do this depending on the HW version and source type
*/
-static void xive_do_source_eoi(u32 hw_irq, struct xive_irq_data *xd)
+static void xive_do_source_eoi(struct xive_irq_data *xd)
{
+ u8 eoi_val;
+
+ xd->stale_p = false;
+
/* If the XIVE supports the new "store EOI facility, use it */
- if (xd->flags & XIVE_IRQ_FLAG_STORE_EOI)
+ if (xive_is_store_eoi(xd)) {
xive_esb_write(xd, XIVE_ESB_STORE_EOI, 0);
- else if (hw_irq && xd->flags & XIVE_IRQ_FLAG_EOI_FW) {
- /*
- * The FW told us to call it. This happens for some
- * interrupt sources that need additional HW whacking
- * beyond the ESB manipulation. For example LPC interrupts
- * on P9 DD1.0 needed a latch to be clared in the LPC bridge
- * itself. The Firmware will take care of it.
- */
- if (WARN_ON_ONCE(!xive_ops->eoi))
- return;
- xive_ops->eoi(hw_irq);
- } else {
- u8 eoi_val;
+ return;
+ }
- /*
- * Otherwise for EOI, we use the special MMIO that does
- * a clear of both P and Q and returns the old Q,
- * except for LSIs where we use the "EOI cycle" special
- * load.
- *
- * This allows us to then do a re-trigger if Q was set
- * rather than synthesizing an interrupt in software
- *
- * For LSIs the HW EOI cycle is used rather than PQ bits,
- * as they are automatically re-triggred in HW when still
- * pending.
- */
- if (xd->flags & XIVE_IRQ_FLAG_LSI)
- xive_esb_read(xd, XIVE_ESB_LOAD_EOI);
- else {
- eoi_val = xive_esb_read(xd, XIVE_ESB_SET_PQ_00);
- DBG_VERBOSE("eoi_val=%x\n", eoi_val);
-
- /* Re-trigger if needed */
- if ((eoi_val & XIVE_ESB_VAL_Q) && xd->trig_mmio)
- out_be64(xd->trig_mmio, 0);
- }
+ /*
+ * For LSIs, we use the "EOI cycle" special load rather than
+ * PQ bits, as they are automatically re-triggered in HW when
+ * still pending.
+ */
+ if (xd->flags & XIVE_IRQ_FLAG_LSI) {
+ xive_esb_read(xd, XIVE_ESB_LOAD_EOI);
+ return;
}
+
+ /*
+ * Otherwise, we use the special MMIO that does a clear of
+ * both P and Q and returns the old Q. This allows us to then
+ * do a re-trigger if Q was set rather than synthesizing an
+ * interrupt in software
+ */
+ eoi_val = xive_esb_read(xd, XIVE_ESB_SET_PQ_00);
+ DBG_VERBOSE("eoi_val=%x\n", eoi_val);
+
+ /* Re-trigger if needed */
+ if ((eoi_val & XIVE_ESB_VAL_Q) && xd->trig_mmio)
+ out_be64(xd->trig_mmio, 0);
}
-/* irq_chip eoi callback */
+/* irq_chip eoi callback, called with irq descriptor lock held */
static void xive_irq_eoi(struct irq_data *d)
{
- struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
+ struct xive_irq_data *xd = irq_data_get_irq_chip_data(d);
struct xive_cpu *xc = __this_cpu_read(xive_cpu);
DBG_VERBOSE("eoi_irq: irq=%d [0x%lx] pending=%02x\n",
@@ -368,8 +448,10 @@ static void xive_irq_eoi(struct irq_data *d)
* been passed-through to a KVM guest
*/
if (!irqd_irq_disabled(d) && !irqd_is_forwarded_to_vcpu(d) &&
- !(xd->flags & XIVE_IRQ_NO_EOI))
- xive_do_source_eoi(irqd_to_hwirq(d), xd);
+ !(xd->flags & XIVE_IRQ_FLAG_NO_EOI))
+ xive_do_source_eoi(xd);
+ else
+ xd->stale_p = true;
/*
* Clear saved_p to indicate that it's no longer occupying
@@ -382,15 +464,15 @@ static void xive_irq_eoi(struct irq_data *d)
}
/*
- * Helper used to mask and unmask an interrupt source. This
- * is only called for normal interrupts that do not require
- * masking/unmasking via firmware.
+ * Helper used to mask and unmask an interrupt source.
*/
static void xive_do_source_set_mask(struct xive_irq_data *xd,
bool mask)
{
u64 val;
+ pr_debug("%s: HW 0x%x %smask\n", __func__, xd->hw_irq, mask ? "" : "un");
+
/*
* If the interrupt had P set, it may be in a queue.
*
@@ -401,11 +483,16 @@ static void xive_do_source_set_mask(struct xive_irq_data *xd,
*/
if (mask) {
val = xive_esb_read(xd, XIVE_ESB_SET_PQ_01);
- xd->saved_p = !!(val & XIVE_ESB_VAL_P);
- } else if (xd->saved_p)
+ if (!xd->stale_p && !!(val & XIVE_ESB_VAL_P))
+ xd->saved_p = true;
+ xd->stale_p = false;
+ } else if (xd->saved_p) {
xive_esb_read(xd, XIVE_ESB_SET_PQ_10);
- else
+ xd->saved_p = false;
+ } else {
xive_esb_read(xd, XIVE_ESB_SET_PQ_00);
+ xd->stale_p = false;
+ }
}
/*
@@ -442,7 +529,7 @@ static void xive_dec_target_count(int cpu)
struct xive_cpu *xc = per_cpu(xive_cpu, cpu);
struct xive_q *q = &xc->queue[xive_irq_priority];
- if (unlikely(WARN_ON(cpu < 0 || !xc))) {
+ if (WARN_ON(cpu < 0 || !xc)) {
pr_err("%s: cpu=%d xc=%p\n", __func__, cpu, xc);
return;
}
@@ -483,7 +570,7 @@ static int xive_find_target_in_mask(const struct cpumask *mask,
* Now go through the entire mask until we find a valid
* target.
*/
- for (;;) {
+ do {
/*
* We re-check online as the fallback case passes us
* an untested affinity mask
@@ -491,12 +578,11 @@ static int xive_find_target_in_mask(const struct cpumask *mask,
if (cpu_online(cpu) && xive_try_pick_target(cpu))
return cpu;
cpu = cpumask_next(cpu, mask);
- if (cpu == first)
- break;
/* Wrap around */
if (cpu >= nr_cpu_ids)
cpu = cpumask_first(mask);
- }
+ } while (cpu != first);
+
return -1;
}
@@ -509,7 +595,7 @@ static int xive_pick_irq_target(struct irq_data *d,
const struct cpumask *affinity)
{
static unsigned int fuzz;
- struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
+ struct xive_irq_data *xd = irq_data_get_irq_chip_data(d);
cpumask_var_t mask;
int cpu = -1;
@@ -542,22 +628,14 @@ static int xive_pick_irq_target(struct irq_data *d,
static unsigned int xive_irq_startup(struct irq_data *d)
{
- struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
+ struct xive_irq_data *xd = irq_data_get_irq_chip_data(d);
unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
int target, rc;
- pr_devel("xive_irq_startup: irq %d [0x%x] data @%p\n",
- d->irq, hw_irq, d);
+ xd->saved_p = false;
+ xd->stale_p = false;
-#ifdef CONFIG_PCI_MSI
- /*
- * The generic MSI code returns with the interrupt disabled on the
- * card, using the MSI mask bits. Firmware doesn't appear to unmask
- * at that level, so we do it here by hand.
- */
- if (irq_data_get_msi_desc(d))
- pci_msi_unmask_irq(d);
-#endif
+ pr_debug("%s: irq %d [0x%x] data @%p\n", __func__, d->irq, hw_irq, d);
/* Pick a target */
target = xive_pick_irq_target(d, irq_data_get_affinity_mask(d));
@@ -592,13 +670,13 @@ static unsigned int xive_irq_startup(struct irq_data *d)
return 0;
}
+/* called with irq descriptor lock held */
static void xive_irq_shutdown(struct irq_data *d)
{
- struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
+ struct xive_irq_data *xd = irq_data_get_irq_chip_data(d);
unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
- pr_devel("xive_irq_shutdown: irq %d [0x%x] data @%p\n",
- d->irq, hw_irq, d);
+ pr_debug("%s: irq %d [0x%x] data @%p\n", __func__, d->irq, hw_irq, d);
if (WARN_ON(xd->target == XIVE_INVALID_TARGET))
return;
@@ -607,16 +685,6 @@ static void xive_irq_shutdown(struct irq_data *d)
xive_do_source_set_mask(xd, true);
/*
- * The above may have set saved_p. We clear it otherwise it
- * will prevent re-enabling later on. It is ok to forget the
- * fact that the interrupt might be in a queue because we are
- * accounting that already in xive_dec_target_count() and will
- * be re-routing it to a new queue with proper accounting when
- * it's started up again
- */
- xd->saved_p = false;
-
- /*
* Mask the interrupt in HW in the IVT/EAS and set the number
* to be the "bad" IRQ number
*/
@@ -630,46 +698,18 @@ static void xive_irq_shutdown(struct irq_data *d)
static void xive_irq_unmask(struct irq_data *d)
{
- struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
-
- pr_devel("xive_irq_unmask: irq %d data @%p\n", d->irq, xd);
+ struct xive_irq_data *xd = irq_data_get_irq_chip_data(d);
- /*
- * This is a workaround for PCI LSI problems on P9, for
- * these, we call FW to set the mask. The problems might
- * be fixed by P9 DD2.0, if that is the case, firmware
- * will no longer set that flag.
- */
- if (xd->flags & XIVE_IRQ_FLAG_MASK_FW) {
- unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
- xive_ops->configure_irq(hw_irq,
- get_hard_smp_processor_id(xd->target),
- xive_irq_priority, d->irq);
- return;
- }
+ pr_debug("%s: irq %d data @%p\n", __func__, d->irq, xd);
xive_do_source_set_mask(xd, false);
}
static void xive_irq_mask(struct irq_data *d)
{
- struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
-
- pr_devel("xive_irq_mask: irq %d data @%p\n", d->irq, xd);
+ struct xive_irq_data *xd = irq_data_get_irq_chip_data(d);
- /*
- * This is a workaround for PCI LSI problems on P9, for
- * these, we call OPAL to set the mask. The problems might
- * be fixed by P9 DD2.0, if that is the case, firmware
- * will no longer set that flag.
- */
- if (xd->flags & XIVE_IRQ_FLAG_MASK_FW) {
- unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
- xive_ops->configure_irq(hw_irq,
- get_hard_smp_processor_id(xd->target),
- 0xff, d->irq);
- return;
- }
+ pr_debug("%s: irq %d data @%p\n", __func__, d->irq, xd);
xive_do_source_set_mask(xd, true);
}
@@ -678,21 +718,17 @@ static int xive_irq_set_affinity(struct irq_data *d,
const struct cpumask *cpumask,
bool force)
{
- struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
+ struct xive_irq_data *xd = irq_data_get_irq_chip_data(d);
unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
u32 target, old_target;
int rc = 0;
- pr_devel("xive_irq_set_affinity: irq %d\n", d->irq);
+ pr_debug("%s: irq %d/0x%x\n", __func__, d->irq, hw_irq);
/* Is this valid ? */
- if (cpumask_any_and(cpumask, cpu_online_mask) >= nr_cpu_ids)
+ if (!cpumask_intersects(cpumask, cpu_online_mask))
return -EINVAL;
- /* Don't do anything if the interrupt isn't started */
- if (!irqd_is_started(d))
- return IRQ_SET_MASK_OK;
-
/*
* If existing target is already in the new mask, and is
* online then do nothing.
@@ -728,7 +764,7 @@ static int xive_irq_set_affinity(struct irq_data *d,
return rc;
}
- pr_devel(" target: 0x%x\n", target);
+ pr_debug(" target: 0x%x\n", target);
xd->target = target;
/* Give up previous target */
@@ -740,14 +776,14 @@ static int xive_irq_set_affinity(struct irq_data *d,
static int xive_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
- struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
+ struct xive_irq_data *xd = irq_data_get_irq_chip_data(d);
/*
* We only support these. This has really no effect other than setting
* the corresponding descriptor bits mind you but those will in turn
* affect the resend function when re-enabling an edge interrupt.
*
- * Set set the default to edge as explained in map().
+ * Set the default to edge as explained in map().
*/
if (flow_type == IRQ_TYPE_DEFAULT || flow_type == IRQ_TYPE_NONE)
flow_type = IRQ_TYPE_EDGE_RISING;
@@ -779,7 +815,7 @@ static int xive_irq_set_type(struct irq_data *d, unsigned int flow_type)
static int xive_irq_retrigger(struct irq_data *d)
{
- struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
+ struct xive_irq_data *xd = irq_data_get_irq_chip_data(d);
/* This should be only for MSIs */
if (WARN_ON(xd->flags & XIVE_IRQ_FLAG_LSI))
@@ -790,33 +826,23 @@ static int xive_irq_retrigger(struct irq_data *d)
* 11, then perform an EOI.
*/
xive_esb_read(xd, XIVE_ESB_SET_PQ_11);
-
- /*
- * Note: We pass "0" to the hw_irq argument in order to
- * avoid calling into the backend EOI code which we don't
- * want to do in the case of a re-trigger. Backends typically
- * only do EOI for LSIs anyway.
- */
- xive_do_source_eoi(0, xd);
+ xive_do_source_eoi(xd);
return 1;
}
+/*
+ * Caller holds the irq descriptor lock, so this won't be called
+ * concurrently with xive_get_irqchip_state on the same interrupt.
+ */
static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state)
{
- struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
+ struct xive_irq_data *xd = irq_data_get_irq_chip_data(d);
unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
int rc;
u8 pq;
/*
- * We only support this on interrupts that do not require
- * firmware calls for masking and unmasking
- */
- if (xd->flags & XIVE_IRQ_FLAG_MASK_FW)
- return -EIO;
-
- /*
* This is called by KVM with state non-NULL for enabling
* pass-through or NULL for disabling it
*/
@@ -825,6 +851,10 @@ static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state)
/* Set it to PQ=10 state to prevent further sends */
pq = xive_esb_read(xd, XIVE_ESB_SET_PQ_10);
+ if (!xd->stale_p) {
+ xd->saved_p = !!(pq & XIVE_ESB_VAL_P);
+ xd->stale_p = !xd->saved_p;
+ }
/* No target ? nothing to do */
if (xd->target == XIVE_INVALID_TARGET) {
@@ -832,7 +862,7 @@ static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state)
* An untargetted interrupt should have been
* also masked at the source
*/
- WARN_ON(pq & 2);
+ WARN_ON(xd->saved_p);
return 0;
}
@@ -844,7 +874,7 @@ static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state)
*
* This also tells us that it's in flight to a host queue
* or has already been fetched but hasn't been EOIed yet
- * by the host. This it's potentially using up a host
+ * by the host. Thus it's potentially using up a host
* queue slot. This is important to know because as long
* as this is the case, we must not hard-unmask it when
* "returning" that interrupt to the host.
@@ -852,9 +882,8 @@ static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state)
* This saved_p is cleared by the host EOI, when we know
* for sure the queue slot is no longer in use.
*/
- if (pq & 2) {
- pq = xive_esb_read(xd, XIVE_ESB_SET_PQ_11);
- xd->saved_p = true;
+ if (xd->saved_p) {
+ xive_esb_read(xd, XIVE_ESB_SET_PQ_11);
/*
* Sync the XIVE source HW to ensure the interrupt
@@ -867,8 +896,7 @@ static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state)
*/
if (xive_ops->sync_source)
xive_ops->sync_source(hw_irq);
- } else
- xd->saved_p = false;
+ }
} else {
irqd_clr_forwarded_to_vcpu(d);
@@ -913,12 +941,39 @@ static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state)
* while masked, the generic code will re-mask it anyway.
*/
if (!xd->saved_p)
- xive_do_source_eoi(hw_irq, xd);
+ xive_do_source_eoi(xd);
}
return 0;
}
+/* Called with irq descriptor lock held. */
+static int xive_get_irqchip_state(struct irq_data *data,
+ enum irqchip_irq_state which, bool *state)
+{
+ struct xive_irq_data *xd = irq_data_get_irq_chip_data(data);
+ u8 pq;
+
+ switch (which) {
+ case IRQCHIP_STATE_ACTIVE:
+ pq = xive_esb_read(xd, XIVE_ESB_GET);
+
+ /*
+ * The esb value being all 1's means we couldn't get
+ * the PQ state of the interrupt through mmio. It may
+ * happen, for example when querying a PHB interrupt
+ * while the PHB is in an error state. We consider the
+ * interrupt to be inactive in that case.
+ */
+ *state = (pq != XIVE_ESB_INVALID) && !xd->stale_p &&
+ (xd->saved_p || (!!(pq & XIVE_ESB_VAL_P) &&
+ !irqd_irq_disabled(data)));
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
static struct irq_chip xive_irq_chip = {
.name = "XIVE-IRQ",
.irq_startup = xive_irq_startup,
@@ -930,6 +985,7 @@ static struct irq_chip xive_irq_chip = {
.irq_set_type = xive_irq_set_type,
.irq_retrigger = xive_irq_retrigger,
.irq_set_vcpu_affinity = xive_irq_set_vcpu_affinity,
+ .irq_get_irqchip_state = xive_get_irqchip_state,
};
bool is_xive_irq(struct irq_chip *chip)
@@ -940,6 +996,8 @@ EXPORT_SYMBOL_GPL(is_xive_irq);
void xive_cleanup_irq_data(struct xive_irq_data *xd)
{
+ pr_debug("%s for HW 0x%x\n", __func__, xd->hw_irq);
+
if (xd->eoi_mmio) {
iounmap(xd->eoi_mmio);
if (xd->eoi_mmio == xd->trig_mmio)
@@ -953,32 +1011,40 @@ void xive_cleanup_irq_data(struct xive_irq_data *xd)
}
EXPORT_SYMBOL_GPL(xive_cleanup_irq_data);
-static int xive_irq_alloc_data(unsigned int virq, irq_hw_number_t hw)
+static struct xive_irq_data *xive_irq_alloc_data(unsigned int virq, irq_hw_number_t hw)
{
struct xive_irq_data *xd;
int rc;
xd = kzalloc(sizeof(struct xive_irq_data), GFP_KERNEL);
if (!xd)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
rc = xive_ops->populate_irq_data(hw, xd);
if (rc) {
kfree(xd);
- return rc;
+ return ERR_PTR(rc);
}
xd->target = XIVE_INVALID_TARGET;
- irq_set_handler_data(virq, xd);
- return 0;
+ /*
+ * Turn OFF by default the interrupt being mapped. A side
+ * effect of this check is the mapping the ESB page of the
+ * interrupt in the Linux address space. This prevents page
+ * fault issues in the crash handler which masks all
+ * interrupts.
+ */
+ xive_esb_read(xd, XIVE_ESB_SET_PQ_01);
+
+ return xd;
}
static void xive_irq_free_data(unsigned int virq)
{
- struct xive_irq_data *xd = irq_get_handler_data(virq);
+ struct xive_irq_data *xd = irq_get_chip_data(virq);
if (!xd)
return;
- irq_set_handler_data(virq, NULL);
+ irq_set_chip_data(virq, NULL);
xive_cleanup_irq_data(xd);
kfree(xd);
}
@@ -1017,7 +1083,7 @@ static void xive_ipi_eoi(struct irq_data *d)
DBG_VERBOSE("IPI eoi: irq=%d [0x%lx] (HW IRQ 0x%x) pending=%02x\n",
d->irq, irqd_to_hwirq(d), xc->hw_ipi, xc->pending_prio);
- xive_do_source_eoi(xc->hw_ipi, &xc->ipi_data);
+ xive_do_source_eoi(&xc->ipi_data);
xive_do_queue_eoi(xc);
}
@@ -1036,28 +1102,100 @@ static struct irq_chip xive_ipi_chip = {
.irq_unmask = xive_ipi_do_nothing,
};
-static void __init xive_request_ipi(void)
+/*
+ * IPIs are marked per-cpu. We use separate HW interrupts under the
+ * hood but associated with the same "linux" interrupt
+ */
+struct xive_ipi_alloc_info {
+ irq_hw_number_t hwirq;
+};
+
+static int xive_ipi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
{
- unsigned int virq;
+ struct xive_ipi_alloc_info *info = arg;
+ int i;
- /*
- * Initialization failed, move on, we might manage to
- * reach the point where we display our errors before
- * the system falls appart
- */
- if (!xive_irq_domain)
- return;
+ for (i = 0; i < nr_irqs; i++) {
+ irq_domain_set_info(domain, virq + i, info->hwirq + i, &xive_ipi_chip,
+ domain->host_data, handle_percpu_irq,
+ NULL, NULL);
+ }
+ return 0;
+}
+
+static const struct irq_domain_ops xive_ipi_irq_domain_ops = {
+ .alloc = xive_ipi_irq_domain_alloc,
+};
+
+static int __init xive_init_ipis(void)
+{
+ struct fwnode_handle *fwnode;
+ struct irq_domain *ipi_domain;
+ unsigned int node;
+ int ret = -ENOMEM;
+
+ fwnode = irq_domain_alloc_named_fwnode("XIVE-IPI");
+ if (!fwnode)
+ goto out;
+
+ ipi_domain = irq_domain_create_linear(fwnode, nr_node_ids,
+ &xive_ipi_irq_domain_ops, NULL);
+ if (!ipi_domain)
+ goto out_free_fwnode;
+
+ xive_ipis = kcalloc(nr_node_ids, sizeof(*xive_ipis), GFP_KERNEL | __GFP_NOFAIL);
+ if (!xive_ipis)
+ goto out_free_domain;
- /* Initialize it */
- virq = irq_create_mapping(xive_irq_domain, 0);
- xive_ipi_irq = virq;
+ for_each_node(node) {
+ struct xive_ipi_desc *xid = &xive_ipis[node];
+ struct xive_ipi_alloc_info info = { node };
- WARN_ON(request_irq(virq, xive_muxed_ipi_action,
- IRQF_PERCPU | IRQF_NO_THREAD, "IPI", NULL));
+ /*
+ * Map one IPI interrupt per node for all cpus of that node.
+ * Since the HW interrupt number doesn't have any meaning,
+ * simply use the node number.
+ */
+ ret = irq_domain_alloc_irqs(ipi_domain, 1, node, &info);
+ if (ret < 0)
+ goto out_free_xive_ipis;
+ xid->irq = ret;
+
+ snprintf(xid->name, sizeof(xid->name), "IPI-%d", node);
+ }
+
+ return ret;
+
+out_free_xive_ipis:
+ kfree(xive_ipis);
+out_free_domain:
+ irq_domain_remove(ipi_domain);
+out_free_fwnode:
+ irq_domain_free_fwnode(fwnode);
+out:
+ return ret;
+}
+
+static int xive_request_ipi(unsigned int cpu)
+{
+ struct xive_ipi_desc *xid = &xive_ipis[early_cpu_to_node(cpu)];
+ int ret;
+
+ if (atomic_inc_return(&xid->started) > 1)
+ return 0;
+
+ ret = request_irq(xid->irq, xive_muxed_ipi_action,
+ IRQF_NO_DEBUG | IRQF_PERCPU | IRQF_NO_THREAD,
+ xid->name, NULL);
+
+ WARN(ret < 0, "Failed to request IPI %d: %d\n", xid->irq, ret);
+ return ret;
}
static int xive_setup_cpu_ipi(unsigned int cpu)
{
+ unsigned int xive_ipi_irq = xive_ipi_cpu_to_irq(cpu);
struct xive_cpu *xc;
int rc;
@@ -1066,9 +1204,12 @@ static int xive_setup_cpu_ipi(unsigned int cpu)
xc = per_cpu(xive_cpu, cpu);
/* Check if we are already setup */
- if (xc->hw_ipi != 0)
+ if (xc->hw_ipi != XIVE_BAD_IRQ)
return 0;
+ /* Register the IPI */
+ xive_request_ipi(cpu);
+
/* Grab an IPI from the backend, this will populate xc->hw_ipi */
if (xive_ops->get_ipi(cpu, xc))
return -EIO;
@@ -1089,8 +1230,8 @@ static int xive_setup_cpu_ipi(unsigned int cpu)
pr_err("Failed to map IPI CPU %d\n", cpu);
return -EIO;
}
- pr_devel("CPU %d HW IPI %x, virq %d, trig_mmio=%p\n", cpu,
- xc->hw_ipi, xive_ipi_irq, xc->ipi_data.trig_mmio);
+ pr_debug("CPU %d HW IPI 0x%x, virq %d, trig_mmio=%p\n", cpu,
+ xc->hw_ipi, xive_ipi_irq, xc->ipi_data.trig_mmio);
/* Unmask it */
xive_do_source_set_mask(&xc->ipi_data, false);
@@ -1098,14 +1239,18 @@ static int xive_setup_cpu_ipi(unsigned int cpu)
return 0;
}
-static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc)
+noinstr static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc)
{
+ unsigned int xive_ipi_irq = xive_ipi_cpu_to_irq(cpu);
+
/* Disable the IPI and free the IRQ data */
/* Already cleaned up ? */
- if (xc->hw_ipi == 0)
+ if (xc->hw_ipi == XIVE_BAD_IRQ)
return;
+ /* TODO: clear IPI mapping */
+
/* Mask the IPI */
xive_do_source_set_mask(&xc->ipi_data, true);
@@ -1128,7 +1273,7 @@ void __init xive_smp_probe(void)
smp_ops->cause_ipi = xive_cause_ipi;
/* Register the IPI */
- xive_request_ipi();
+ xive_init_ipis();
/* Allocate and setup IPI for the boot CPU */
xive_setup_cpu_ipi(smp_processor_id());
@@ -1139,7 +1284,7 @@ void __init xive_smp_probe(void)
static int xive_irq_domain_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
- int rc;
+ struct xive_irq_data *xd;
/*
* Mark interrupts as edge sensitive by default so that resend
@@ -1147,39 +1292,19 @@ static int xive_irq_domain_map(struct irq_domain *h, unsigned int virq,
*/
irq_clear_status_flags(virq, IRQ_LEVEL);
-#ifdef CONFIG_SMP
- /* IPIs are special and come up with HW number 0 */
- if (hw == 0) {
- /*
- * IPIs are marked per-cpu. We use separate HW interrupts under
- * the hood but associated with the same "linux" interrupt
- */
- irq_set_chip_and_handler(virq, &xive_ipi_chip,
- handle_percpu_irq);
- return 0;
- }
-#endif
-
- rc = xive_irq_alloc_data(virq, hw);
- if (rc)
- return rc;
+ xd = xive_irq_alloc_data(virq, hw);
+ if (IS_ERR(xd))
+ return PTR_ERR(xd);
irq_set_chip_and_handler(virq, &xive_irq_chip, handle_fasteoi_irq);
+ irq_set_chip_data(virq, xd);
return 0;
}
static void xive_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
{
- struct irq_data *data = irq_get_irq_data(virq);
- unsigned int hw_irq;
-
- /* XXX Assign BAD number */
- if (!data)
- return;
- hw_irq = (unsigned int)irqd_to_hwirq(data);
- if (hw_irq)
- xive_irq_free_data(virq);
+ xive_irq_free_data(virq);
}
static int xive_irq_domain_xlate(struct irq_domain *h, struct device_node *ct,
@@ -1210,20 +1335,138 @@ static int xive_irq_domain_match(struct irq_domain *h, struct device_node *node,
return xive_ops->match(node);
}
+#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+static const char * const esb_names[] = { "RESET", "OFF", "PENDING", "QUEUED" };
+
+static const struct {
+ u64 mask;
+ char *name;
+} xive_irq_flags[] = {
+ { XIVE_IRQ_FLAG_STORE_EOI, "STORE_EOI" },
+ { XIVE_IRQ_FLAG_LSI, "LSI" },
+ { XIVE_IRQ_FLAG_H_INT_ESB, "H_INT_ESB" },
+ { XIVE_IRQ_FLAG_NO_EOI, "NO_EOI" },
+};
+
+static void xive_irq_domain_debug_show(struct seq_file *m, struct irq_domain *d,
+ struct irq_data *irqd, int ind)
+{
+ struct xive_irq_data *xd;
+ u64 val;
+ int i;
+
+ /* No IRQ domain level information. To be done */
+ if (!irqd)
+ return;
+
+ if (!is_xive_irq(irq_data_get_irq_chip(irqd)))
+ return;
+
+ seq_printf(m, "%*sXIVE:\n", ind, "");
+ ind++;
+
+ xd = irq_data_get_irq_chip_data(irqd);
+ if (!xd) {
+ seq_printf(m, "%*snot assigned\n", ind, "");
+ return;
+ }
+
+ val = xive_esb_read(xd, XIVE_ESB_GET);
+ seq_printf(m, "%*sESB: %s\n", ind, "", esb_names[val & 0x3]);
+ seq_printf(m, "%*sPstate: %s %s\n", ind, "", xd->stale_p ? "stale" : "",
+ xd->saved_p ? "saved" : "");
+ seq_printf(m, "%*sTarget: %d\n", ind, "", xd->target);
+ seq_printf(m, "%*sChip: %d\n", ind, "", xd->src_chip);
+ seq_printf(m, "%*sTrigger: 0x%016llx\n", ind, "", xd->trig_page);
+ seq_printf(m, "%*sEOI: 0x%016llx\n", ind, "", xd->eoi_page);
+ seq_printf(m, "%*sFlags: 0x%llx\n", ind, "", xd->flags);
+ for (i = 0; i < ARRAY_SIZE(xive_irq_flags); i++) {
+ if (xd->flags & xive_irq_flags[i].mask)
+ seq_printf(m, "%*s%s\n", ind + 12, "", xive_irq_flags[i].name);
+ }
+}
+#endif
+
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+static int xive_irq_domain_translate(struct irq_domain *d,
+ struct irq_fwspec *fwspec,
+ unsigned long *hwirq,
+ unsigned int *type)
+{
+ return xive_irq_domain_xlate(d, to_of_node(fwspec->fwnode),
+ fwspec->param, fwspec->param_count,
+ hwirq, type);
+}
+
+static int xive_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ struct irq_fwspec *fwspec = arg;
+ struct xive_irq_data *xd;
+ irq_hw_number_t hwirq;
+ unsigned int type = IRQ_TYPE_NONE;
+ int i, rc;
+
+ rc = xive_irq_domain_translate(domain, fwspec, &hwirq, &type);
+ if (rc)
+ return rc;
+
+ pr_debug("%s %d/0x%lx #%d\n", __func__, virq, hwirq, nr_irqs);
+
+ for (i = 0; i < nr_irqs; i++) {
+ /* TODO: call xive_irq_domain_map() */
+
+ /*
+ * Mark interrupts as edge sensitive by default so that resend
+ * actually works. Will fix that up below if needed.
+ */
+ irq_clear_status_flags(virq, IRQ_LEVEL);
+
+ /* allocates and sets handler data */
+ xd = xive_irq_alloc_data(virq + i, hwirq + i);
+ if (IS_ERR(xd))
+ return PTR_ERR(xd);
+
+ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, &xive_irq_chip, xd);
+ irq_set_handler(virq + i, handle_fasteoi_irq);
+ }
+
+ return 0;
+}
+
+static void xive_irq_domain_free(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
+{
+ int i;
+
+ pr_debug("%s %d #%d\n", __func__, virq, nr_irqs);
+
+ for (i = 0; i < nr_irqs; i++)
+ xive_irq_free_data(virq + i);
+}
+#endif
+
static const struct irq_domain_ops xive_irq_domain_ops = {
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+ .alloc = xive_irq_domain_alloc,
+ .free = xive_irq_domain_free,
+ .translate = xive_irq_domain_translate,
+#endif
.match = xive_irq_domain_match,
.map = xive_irq_domain_map,
.unmap = xive_irq_domain_unmap,
.xlate = xive_irq_domain_xlate,
+#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
+ .debug_show = xive_irq_domain_debug_show,
+#endif
};
-static void __init xive_init_host(void)
+static void __init xive_init_host(struct device_node *np)
{
- xive_irq_domain = irq_domain_add_nomap(NULL, XIVE_MAX_IRQ,
- &xive_irq_domain_ops, NULL);
+ xive_irq_domain = irq_domain_create_tree(of_fwnode_handle(np), &xive_irq_domain_ops, NULL);
if (WARN_ON(xive_irq_domain == NULL))
return;
- irq_set_default_host(xive_irq_domain);
+ irq_set_default_domain(xive_irq_domain);
}
static void xive_cleanup_cpu_queues(unsigned int cpu, struct xive_cpu *xc)
@@ -1249,16 +1492,14 @@ static int xive_prepare_cpu(unsigned int cpu)
xc = per_cpu(xive_cpu, cpu);
if (!xc) {
- struct device_node *np;
-
xc = kzalloc_node(sizeof(struct xive_cpu),
GFP_KERNEL, cpu_to_node(cpu));
if (!xc)
return -ENOMEM;
- np = of_get_cpu_node(cpu, NULL);
- if (np)
- xc->chip_id = of_get_ibm_chip_id(np);
- of_node_put(np);
+ xc->hw_ipi = XIVE_BAD_IRQ;
+ xc->chip_id = XIVE_INVALID_CHIP_ID;
+ if (xive_ops->prepare_cpu)
+ xive_ops->prepare_cpu(cpu, xc);
per_cpu(xive_cpu, cpu) = xc;
}
@@ -1283,7 +1524,7 @@ static void xive_setup_cpu(void)
#ifdef CONFIG_SMP
void xive_smp_setup_cpu(void)
{
- pr_devel("SMP setup CPU %d\n", smp_processor_id());
+ pr_debug("SMP setup CPU %d\n", smp_processor_id());
/* This will have already been done on the boot CPU */
if (smp_processor_id() != boot_cpuid)
@@ -1321,13 +1562,12 @@ static void xive_flush_cpu_queue(unsigned int cpu, struct xive_cpu *xc)
struct irq_desc *desc = irq_to_desc(irq);
struct irq_data *d = irq_desc_get_irq_data(desc);
struct xive_irq_data *xd;
- unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
/*
* Ignore anything that isn't a XIVE irq and ignore
* IPIs, so can just be dropped.
*/
- if (d->domain != xive_irq_domain || hw_irq == 0)
+ if (d->domain != xive_irq_domain)
continue;
/*
@@ -1340,14 +1580,19 @@ static void xive_flush_cpu_queue(unsigned int cpu, struct xive_cpu *xc)
cpu, irq);
#endif
raw_spin_lock(&desc->lock);
- xd = irq_desc_get_handler_data(desc);
+ xd = irq_desc_get_chip_data(desc);
+
+ /*
+ * Clear saved_p to indicate that it's no longer pending
+ */
+ xd->saved_p = false;
/*
* For LSIs, we EOI, this will cause a resend if it's
* still asserted. Otherwise do an MSI retrigger.
*/
if (xd->flags & XIVE_IRQ_FLAG_LSI)
- xive_do_source_eoi(irqd_to_hwirq(d), xd);
+ xive_do_source_eoi(xd);
else
xive_irq_retrigger(d);
@@ -1388,7 +1633,7 @@ void xive_flush_interrupt(void)
#endif /* CONFIG_SMP */
-void xive_teardown_cpu(void)
+noinstr void xive_teardown_cpu(void)
{
struct xive_cpu *xc = __this_cpu_read(xive_cpu);
unsigned int cpu = smp_processor_id();
@@ -1414,8 +1659,8 @@ void xive_shutdown(void)
xive_ops->shutdown();
}
-bool __init xive_core_init(const struct xive_ops *ops, void __iomem *area, u32 offset,
- u8 max_prio)
+bool __init xive_core_init(struct device_node *np, const struct xive_ops *ops,
+ void __iomem *area, u32 offset, u8 max_prio)
{
xive_tima = area;
xive_tima_offset = offset;
@@ -1425,10 +1670,10 @@ bool __init xive_core_init(const struct xive_ops *ops, void __iomem *area, u32 o
ppc_md.get_irq = xive_get_irq;
__xive_enabled = true;
- pr_devel("Initializing host..\n");
- xive_init_host();
+ pr_debug("Initializing host..\n");
+ xive_init_host(np);
- pr_devel("Initializing boot CPU..\n");
+ pr_debug("Initializing boot CPU..\n");
/* Allocate per-CPU data and queues */
xive_prepare_cpu(smp_processor_id());
@@ -1462,6 +1707,157 @@ __be32 *xive_queue_page_alloc(unsigned int cpu, u32 queue_shift)
static int __init xive_off(char *arg)
{
xive_cmdline_disabled = true;
- return 0;
+ return 1;
}
__setup("xive=off", xive_off);
+
+static int __init xive_store_eoi_cmdline(char *arg)
+{
+ if (!arg)
+ return 1;
+
+ if (strncmp(arg, "off", 3) == 0) {
+ pr_info("StoreEOI disabled on kernel command line\n");
+ xive_store_eoi = false;
+ }
+ return 1;
+}
+__setup("xive.store-eoi=", xive_store_eoi_cmdline);
+
+#ifdef CONFIG_DEBUG_FS
+static void xive_debug_show_ipi(struct seq_file *m, int cpu)
+{
+ struct xive_cpu *xc = per_cpu(xive_cpu, cpu);
+
+ seq_printf(m, "CPU %d: ", cpu);
+ if (xc) {
+ seq_printf(m, "pp=%02x CPPR=%02x ", xc->pending_prio, xc->cppr);
+
+#ifdef CONFIG_SMP
+ {
+ char buffer[128];
+
+ xive_irq_data_dump(&xc->ipi_data, buffer, sizeof(buffer));
+ seq_printf(m, "IPI=0x%08x %s", xc->hw_ipi, buffer);
+ }
+#endif
+ }
+ seq_puts(m, "\n");
+}
+
+static void xive_debug_show_irq(struct seq_file *m, struct irq_data *d)
+{
+ unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
+ int rc;
+ u32 target;
+ u8 prio;
+ u32 lirq;
+ char buffer[128];
+
+ rc = xive_ops->get_irq_config(hw_irq, &target, &prio, &lirq);
+ if (rc) {
+ seq_printf(m, "IRQ 0x%08x : no config rc=%d\n", hw_irq, rc);
+ return;
+ }
+
+ seq_printf(m, "IRQ 0x%08x : target=0x%x prio=%02x lirq=0x%x ",
+ hw_irq, target, prio, lirq);
+
+ xive_irq_data_dump(irq_data_get_irq_chip_data(d), buffer, sizeof(buffer));
+ seq_puts(m, buffer);
+ seq_puts(m, "\n");
+}
+
+static int xive_irq_debug_show(struct seq_file *m, void *private)
+{
+ unsigned int i;
+ struct irq_desc *desc;
+
+ for_each_irq_desc(i, desc) {
+ struct irq_data *d = irq_domain_get_irq_data(xive_irq_domain, i);
+
+ if (d)
+ xive_debug_show_irq(m, d);
+ }
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(xive_irq_debug);
+
+static int xive_ipi_debug_show(struct seq_file *m, void *private)
+{
+ int cpu;
+
+ if (xive_ops->debug_show)
+ xive_ops->debug_show(m, private);
+
+ for_each_online_cpu(cpu)
+ xive_debug_show_ipi(m, cpu);
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(xive_ipi_debug);
+
+static void xive_eq_debug_show_one(struct seq_file *m, struct xive_q *q, u8 prio)
+{
+ int i;
+
+ seq_printf(m, "EQ%d idx=%d T=%d\n", prio, q->idx, q->toggle);
+ if (q->qpage) {
+ for (i = 0; i < q->msk + 1; i++) {
+ if (!(i % 8))
+ seq_printf(m, "%05d ", i);
+ seq_printf(m, "%08x%s", be32_to_cpup(q->qpage + i),
+ (i + 1) % 8 ? " " : "\n");
+ }
+ }
+ seq_puts(m, "\n");
+}
+
+static int xive_eq_debug_show(struct seq_file *m, void *private)
+{
+ int cpu = (long)m->private;
+ struct xive_cpu *xc = per_cpu(xive_cpu, cpu);
+
+ if (xc)
+ xive_eq_debug_show_one(m, &xc->queue[xive_irq_priority],
+ xive_irq_priority);
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(xive_eq_debug);
+
+static void xive_core_debugfs_create(void)
+{
+ struct dentry *xive_dir;
+ struct dentry *xive_eq_dir;
+ long cpu;
+ char name[16];
+
+ xive_dir = debugfs_create_dir("xive", arch_debugfs_dir);
+ if (IS_ERR(xive_dir))
+ return;
+
+ debugfs_create_file("ipis", 0400, xive_dir,
+ NULL, &xive_ipi_debug_fops);
+ debugfs_create_file("interrupts", 0400, xive_dir,
+ NULL, &xive_irq_debug_fops);
+ xive_eq_dir = debugfs_create_dir("eqs", xive_dir);
+ for_each_possible_cpu(cpu) {
+ snprintf(name, sizeof(name), "cpu%ld", cpu);
+ debugfs_create_file(name, 0400, xive_eq_dir, (void *)cpu,
+ &xive_eq_debug_fops);
+ }
+ debugfs_create_bool("store-eoi", 0600, xive_dir, &xive_store_eoi);
+
+ if (xive_ops->debug_create)
+ xive_ops->debug_create(xive_dir);
+}
+#else
+static inline void xive_core_debugfs_create(void) { }
+#endif /* CONFIG_DEBUG_FS */
+
+int xive_core_debug_init(void)
+{
+ if (xive_enabled() && IS_ENABLED(CONFIG_DEBUG_FS))
+ xive_core_debugfs_create();
+
+ return 0;
+}
diff --git a/arch/powerpc/sysdev/xive/native.c b/arch/powerpc/sysdev/xive/native.c
index 1ca127d052a6..a0934b516933 100644
--- a/arch/powerpc/sysdev/xive/native.c
+++ b/arch/powerpc/sysdev/xive/native.c
@@ -1,10 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2016,2017 IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#define pr_fmt(fmt) "xive: " fmt
@@ -17,13 +13,15 @@
#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/cpumask.h>
#include <linux/mm.h>
+#include <linux/kmemleak.h>
-#include <asm/prom.h>
+#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/irq.h>
@@ -43,6 +41,7 @@ static u32 xive_queue_shift;
static u32 xive_pool_vps = XIVE_INVALID_VP;
static struct kmem_cache *xive_provision_cache;
static bool xive_has_single_esc;
+bool xive_has_save_restore;
int xive_native_populate_irq_data(u32 hw_irq, struct xive_irq_data *data)
{
@@ -64,14 +63,10 @@ int xive_native_populate_irq_data(u32 hw_irq, struct xive_irq_data *data)
opal_flags = be64_to_cpu(flags);
if (opal_flags & OPAL_XIVE_IRQ_STORE_EOI)
data->flags |= XIVE_IRQ_FLAG_STORE_EOI;
+ if (opal_flags & OPAL_XIVE_IRQ_STORE_EOI2)
+ data->flags |= XIVE_IRQ_FLAG_STORE_EOI;
if (opal_flags & OPAL_XIVE_IRQ_LSI)
data->flags |= XIVE_IRQ_FLAG_LSI;
- if (opal_flags & OPAL_XIVE_IRQ_SHIFT_BUG)
- data->flags |= XIVE_IRQ_FLAG_SHIFT_BUG;
- if (opal_flags & OPAL_XIVE_IRQ_MASK_VIA_FW)
- data->flags |= XIVE_IRQ_FLAG_MASK_FW;
- if (opal_flags & OPAL_XIVE_IRQ_EOI_VIA_FW)
- data->flags |= XIVE_IRQ_FLAG_EOI_FW;
data->eoi_page = be64_to_cpu(eoi_page);
data->trig_page = be64_to_cpu(trig_page);
data->esb_shift = be32_to_cpu(esb_shift);
@@ -115,6 +110,22 @@ int xive_native_configure_irq(u32 hw_irq, u32 target, u8 prio, u32 sw_irq)
}
EXPORT_SYMBOL_GPL(xive_native_configure_irq);
+static int xive_native_get_irq_config(u32 hw_irq, u32 *target, u8 *prio,
+ u32 *sw_irq)
+{
+ s64 rc;
+ __be64 vp;
+ __be32 lirq;
+
+ rc = opal_xive_get_irq_config(hw_irq, &vp, prio, &lirq);
+
+ *target = be64_to_cpu(vp);
+ *sw_irq = be32_to_cpu(lirq);
+
+ return rc == 0 ? 0 : -ENXIO;
+}
+
+#define vp_err(vp, fmt, ...) pr_err("VP[0x%x]: " fmt, vp, ##__VA_ARGS__)
/* This can be called multiple time to change a queue configuration */
int xive_native_configure_queue(u32 vp_id, struct xive_q *q, u8 prio,
@@ -143,7 +154,7 @@ int xive_native_configure_queue(u32 vp_id, struct xive_q *q, u8 prio,
&esc_irq_be,
NULL);
if (rc) {
- pr_err("Error %lld getting queue info prio %d\n", rc, prio);
+ vp_err(vp_id, "Failed to get queue %d info : %lld\n", prio, rc);
rc = -EIO;
goto fail;
}
@@ -166,7 +177,7 @@ int xive_native_configure_queue(u32 vp_id, struct xive_q *q, u8 prio,
msleep(OPAL_BUSY_DELAY_MS);
}
if (rc) {
- pr_err("Error %lld setting queue for prio %d\n", rc, prio);
+ vp_err(vp_id, "Failed to set queue %d info: %lld\n", prio, rc);
rc = -EIO;
} else {
/*
@@ -193,7 +204,7 @@ static void __xive_native_disable_queue(u32 vp_id, struct xive_q *q, u8 prio)
msleep(OPAL_BUSY_DELAY_MS);
}
if (rc)
- pr_err("Error %lld disabling queue for prio %d\n", rc, prio);
+ vp_err(vp_id, "Failed to disable queue %d : %lld\n", prio, rc);
}
void xive_native_disable_queue(u32 vp_id, struct xive_q *q, u8 prio)
@@ -235,6 +246,17 @@ static bool xive_native_match(struct device_node *node)
return of_device_is_compatible(node, "ibm,opal-xive-vc");
}
+static s64 opal_xive_allocate_irq(u32 chip_id)
+{
+ s64 irq = opal_xive_allocate_irq_raw(chip_id);
+
+ /*
+ * Old versions of skiboot can incorrectly return 0xffffffff to
+ * indicate no space, fix it up here.
+ */
+ return irq == 0xffffffff ? OPAL_RESOURCE : irq;
+}
+
#ifdef CONFIG_SMP
static int xive_native_get_ipi(unsigned int cpu, struct xive_cpu *xc)
{
@@ -258,12 +280,12 @@ static int xive_native_get_ipi(unsigned int cpu, struct xive_cpu *xc)
}
#endif /* CONFIG_SMP */
-u32 xive_native_alloc_irq(void)
+u32 xive_native_alloc_irq_on_chip(u32 chip_id)
{
s64 rc;
for (;;) {
- rc = opal_xive_allocate_irq(OPAL_XIVE_ANY_CHIP);
+ rc = opal_xive_allocate_irq(chip_id);
if (rc != OPAL_BUSY)
break;
msleep(OPAL_BUSY_DELAY_MS);
@@ -272,7 +294,7 @@ u32 xive_native_alloc_irq(void)
return 0;
return rc;
}
-EXPORT_SYMBOL_GPL(xive_native_alloc_irq);
+EXPORT_SYMBOL_GPL(xive_native_alloc_irq_on_chip);
void xive_native_free_irq(u32 irq)
{
@@ -291,7 +313,7 @@ static void xive_native_put_ipi(unsigned int cpu, struct xive_cpu *xc)
s64 rc;
/* Free the IPI */
- if (!xc->hw_ipi)
+ if (xc->hw_ipi == XIVE_BAD_IRQ)
return;
for (;;) {
rc = opal_xive_free_irq(xc->hw_ipi);
@@ -299,7 +321,7 @@ static void xive_native_put_ipi(unsigned int cpu, struct xive_cpu *xc)
msleep(OPAL_BUSY_DELAY_MS);
continue;
}
- xc->hw_ipi = 0;
+ xc->hw_ipi = XIVE_BAD_IRQ;
break;
}
}
@@ -361,13 +383,9 @@ static void xive_native_update_pending(struct xive_cpu *xc)
}
}
-static void xive_native_eoi(u32 hw_irq)
+static void xive_native_prepare_cpu(unsigned int cpu, struct xive_cpu *xc)
{
- /*
- * Not normally used except if specific interrupts need
- * a workaround on EOI.
- */
- opal_int_eoi(hw_irq);
+ xc->chip_id = cpu_to_chip_id(cpu);
}
static void xive_native_setup_cpu(unsigned int cpu, struct xive_cpu *xc)
@@ -397,7 +415,7 @@ static void xive_native_setup_cpu(unsigned int cpu, struct xive_cpu *xc)
return;
}
- /* Grab it's CAM value */
+ /* Grab its CAM value */
rc = opal_xive_get_vp_info(vp, NULL, &vp_cam_be, NULL, NULL);
if (rc) {
pr_err("Failed to get pool VP info CPU %d\n", cpu);
@@ -437,15 +455,30 @@ void xive_native_sync_source(u32 hw_irq)
}
EXPORT_SYMBOL_GPL(xive_native_sync_source);
+void xive_native_sync_queue(u32 hw_irq)
+{
+ opal_xive_sync(XIVE_SYNC_QUEUE, hw_irq);
+}
+EXPORT_SYMBOL_GPL(xive_native_sync_queue);
+
+#ifdef CONFIG_DEBUG_FS
+static int xive_native_debug_create(struct dentry *xive_dir)
+{
+ debugfs_create_bool("save-restore", 0600, xive_dir, &xive_has_save_restore);
+ return 0;
+}
+#endif
+
static const struct xive_ops xive_native_ops = {
.populate_irq_data = xive_native_populate_irq_data,
.configure_irq = xive_native_configure_irq,
+ .get_irq_config = xive_native_get_irq_config,
.setup_queue = xive_native_setup_queue,
.cleanup_queue = xive_native_cleanup_queue,
.match = xive_native_match,
.shutdown = xive_native_shutdown,
.update_pending = xive_native_update_pending,
- .eoi = xive_native_eoi,
+ .prepare_cpu = xive_native_prepare_cpu,
.setup_cpu = xive_native_setup_cpu,
.teardown_cpu = xive_native_teardown_cpu,
.sync_source = xive_native_sync_source,
@@ -453,10 +486,13 @@ static const struct xive_ops xive_native_ops = {
.get_ipi = xive_native_get_ipi,
.put_ipi = xive_native_put_ipi,
#endif /* CONFIG_SMP */
+#ifdef CONFIG_DEBUG_FS
+ .debug_create = xive_native_debug_create,
+#endif /* CONFIG_DEBUG_FS */
.name = "native",
};
-static bool xive_parse_provisioning(struct device_node *np)
+static bool __init xive_parse_provisioning(struct device_node *np)
{
int rc;
@@ -496,16 +532,16 @@ static bool xive_parse_provisioning(struct device_node *np)
return true;
}
-static void xive_native_setup_pools(void)
+static void __init xive_native_setup_pools(void)
{
/* Allocate a pool big enough */
- pr_debug("XIVE: Allocating VP block for pool size %u\n", nr_cpu_ids);
+ pr_debug("Allocating VP block for pool size %u\n", nr_cpu_ids);
xive_pool_vps = xive_native_alloc_vp_block(nr_cpu_ids);
if (WARN_ON(xive_pool_vps == XIVE_INVALID_VP))
- pr_err("XIVE: Failed to allocate pool VP, KVM might not function\n");
+ pr_err("Failed to allocate pool VP, KVM might not function\n");
- pr_debug("XIVE: Pool VPs allocated at 0x%x for %u max CPUs\n",
+ pr_debug("Pool VPs allocated at 0x%x for %u max CPUs\n",
xive_pool_vps, nr_cpu_ids);
}
@@ -515,14 +551,15 @@ u32 xive_native_default_eq_shift(void)
}
EXPORT_SYMBOL_GPL(xive_native_default_eq_shift);
+unsigned long xive_tima_os;
+EXPORT_SYMBOL_GPL(xive_tima_os);
+
bool __init xive_native_init(void)
{
struct device_node *np;
struct resource r;
void __iomem *tima;
- struct property *prop;
u8 max_prio = 7;
- const __be32 *p;
u32 val, cpu;
s64 rc;
@@ -540,12 +577,12 @@ bool __init xive_native_init(void)
/* Resource 1 is HV window */
if (of_address_to_resource(np, 1, &r)) {
pr_err("Failed to get thread mgmnt area resource\n");
- return false;
+ goto err_put;
}
tima = ioremap(r.start, resource_size(&r));
if (!tima) {
pr_err("Failed to map thread mgmnt area\n");
- return false;
+ goto err_put;
}
/* Read number of priorities */
@@ -553,41 +590,55 @@ bool __init xive_native_init(void)
max_prio = val - 1;
/* Iterate the EQ sizes and pick one */
- of_property_for_each_u32(np, "ibm,xive-eq-sizes", prop, p, val) {
+ of_property_for_each_u32(np, "ibm,xive-eq-sizes", val) {
xive_queue_shift = val;
if (val == PAGE_SHIFT)
break;
}
/* Do we support single escalation */
- if (of_get_property(np, "single-escalation-support", NULL) != NULL)
- xive_has_single_esc = true;
+ xive_has_single_esc = of_property_read_bool(np, "single-escalation-support");
+
+ xive_has_save_restore = of_property_read_bool(np, "vp-save-restore");
/* Configure Thread Management areas for KVM */
for_each_possible_cpu(cpu)
kvmppc_set_xive_tima(cpu, r.start, tima);
- /* Grab size of provisionning pages */
+ /* Resource 2 is OS window */
+ if (of_address_to_resource(np, 2, &r)) {
+ pr_err("Failed to get thread mgmnt area resource\n");
+ goto err_put;
+ }
+
+ xive_tima_os = r.start;
+
+ /* Grab size of provisioning pages */
xive_parse_provisioning(np);
/* Switch the XIVE to exploitation mode */
rc = opal_xive_reset(OPAL_XIVE_MODE_EXPL);
if (rc) {
pr_err("Switch to exploitation mode failed with error %lld\n", rc);
- return false;
+ goto err_put;
}
/* Setup some dummy HV pool VPs */
xive_native_setup_pools();
/* Initialize XIVE core with our backend */
- if (!xive_core_init(&xive_native_ops, tima, TM_QW3_HV_PHYS,
+ if (!xive_core_init(np, &xive_native_ops, tima, TM_QW3_HV_PHYS,
max_prio)) {
opal_xive_reset(OPAL_XIVE_MODE_EMU);
- return false;
+ goto err_put;
}
+ of_node_put(np);
pr_info("Using %dkB queues\n", 1 << (xive_queue_shift - 10));
return true;
+
+err_put:
+ of_node_put(np);
+ return false;
}
static bool xive_native_provision_pages(void)
@@ -607,6 +658,7 @@ static bool xive_native_provision_pages(void)
pr_err("Failed to allocate provisioning page\n");
return false;
}
+ kmemleak_ignore(p);
opal_xive_donate_page(chip, __pa(p));
}
return true;
@@ -672,6 +724,8 @@ int xive_native_enable_vp(u32 vp_id, bool single_escalation)
break;
msleep(OPAL_BUSY_DELAY_MS);
}
+ if (rc)
+ vp_err(vp_id, "Failed to enable VP : %lld\n", rc);
return rc ? -EIO : 0;
}
EXPORT_SYMBOL_GPL(xive_native_enable_vp);
@@ -686,6 +740,8 @@ int xive_native_disable_vp(u32 vp_id)
break;
msleep(OPAL_BUSY_DELAY_MS);
}
+ if (rc)
+ vp_err(vp_id, "Failed to disable VP : %lld\n", rc);
return rc ? -EIO : 0;
}
EXPORT_SYMBOL_GPL(xive_native_disable_vp);
@@ -697,8 +753,10 @@ int xive_native_get_vp_info(u32 vp_id, u32 *out_cam_id, u32 *out_chip_id)
s64 rc;
rc = opal_xive_get_vp_info(vp_id, NULL, &vp_cam_be, NULL, &vp_chip_id_be);
- if (rc)
+ if (rc) {
+ vp_err(vp_id, "Failed to get VP info : %lld\n", rc);
return -EIO;
+ }
*out_cam_id = be64_to_cpu(vp_cam_be) & 0xffffffffu;
*out_chip_id = be32_to_cpu(vp_chip_id_be);
@@ -711,3 +769,107 @@ bool xive_native_has_single_escalation(void)
return xive_has_single_esc;
}
EXPORT_SYMBOL_GPL(xive_native_has_single_escalation);
+
+bool xive_native_has_save_restore(void)
+{
+ return xive_has_save_restore;
+}
+EXPORT_SYMBOL_GPL(xive_native_has_save_restore);
+
+int xive_native_get_queue_info(u32 vp_id, u32 prio,
+ u64 *out_qpage,
+ u64 *out_qsize,
+ u64 *out_qeoi_page,
+ u32 *out_escalate_irq,
+ u64 *out_qflags)
+{
+ __be64 qpage;
+ __be64 qsize;
+ __be64 qeoi_page;
+ __be32 escalate_irq;
+ __be64 qflags;
+ s64 rc;
+
+ rc = opal_xive_get_queue_info(vp_id, prio, &qpage, &qsize,
+ &qeoi_page, &escalate_irq, &qflags);
+ if (rc) {
+ vp_err(vp_id, "failed to get queue %d info : %lld\n", prio, rc);
+ return -EIO;
+ }
+
+ if (out_qpage)
+ *out_qpage = be64_to_cpu(qpage);
+ if (out_qsize)
+ *out_qsize = be64_to_cpu(qsize);
+ if (out_qeoi_page)
+ *out_qeoi_page = be64_to_cpu(qeoi_page);
+ if (out_escalate_irq)
+ *out_escalate_irq = be32_to_cpu(escalate_irq);
+ if (out_qflags)
+ *out_qflags = be64_to_cpu(qflags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xive_native_get_queue_info);
+
+int xive_native_get_queue_state(u32 vp_id, u32 prio, u32 *qtoggle, u32 *qindex)
+{
+ __be32 opal_qtoggle;
+ __be32 opal_qindex;
+ s64 rc;
+
+ rc = opal_xive_get_queue_state(vp_id, prio, &opal_qtoggle,
+ &opal_qindex);
+ if (rc) {
+ vp_err(vp_id, "failed to get queue %d state : %lld\n", prio, rc);
+ return -EIO;
+ }
+
+ if (qtoggle)
+ *qtoggle = be32_to_cpu(opal_qtoggle);
+ if (qindex)
+ *qindex = be32_to_cpu(opal_qindex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xive_native_get_queue_state);
+
+int xive_native_set_queue_state(u32 vp_id, u32 prio, u32 qtoggle, u32 qindex)
+{
+ s64 rc;
+
+ rc = opal_xive_set_queue_state(vp_id, prio, qtoggle, qindex);
+ if (rc) {
+ vp_err(vp_id, "failed to set queue %d state : %lld\n", prio, rc);
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xive_native_set_queue_state);
+
+bool xive_native_has_queue_state_support(void)
+{
+ return opal_check_token(OPAL_XIVE_GET_QUEUE_STATE) &&
+ opal_check_token(OPAL_XIVE_SET_QUEUE_STATE);
+}
+EXPORT_SYMBOL_GPL(xive_native_has_queue_state_support);
+
+int xive_native_get_vp_state(u32 vp_id, u64 *out_state)
+{
+ __be64 state;
+ s64 rc;
+
+ rc = opal_xive_get_vp_state(vp_id, &state);
+ if (rc) {
+ vp_err(vp_id, "failed to get vp state : %lld\n", rc);
+ return -EIO;
+ }
+
+ if (out_state)
+ *out_state = be64_to_cpu(state);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xive_native_get_vp_state);
+
+machine_arch_initcall(powernv, xive_core_debug_init);
diff --git a/arch/powerpc/sysdev/xive/spapr.c b/arch/powerpc/sysdev/xive/spapr.c
index 575db3b06a6b..5aedbe3e8e6a 100644
--- a/arch/powerpc/sysdev/xive/spapr.c
+++ b/arch/powerpc/sysdev/xive/spapr.c
@@ -1,26 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2016,2017 IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#define pr_fmt(fmt) "xive: " fmt
#include <linux/types.h>
#include <linux/irq.h>
+#include <linux/seq_file.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/bitmap.h>
#include <linux/cpumask.h>
#include <linux/mm.h>
#include <linux/delay.h>
+#include <linux/libfdt.h>
+#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/smp.h>
@@ -29,6 +31,8 @@
#include <asm/xive.h>
#include <asm/xive-regs.h>
#include <asm/hvcall.h>
+#include <asm/svm.h>
+#include <asm/ultravisor.h>
#include "xive-internal.h"
@@ -44,18 +48,22 @@ struct xive_irq_bitmap {
static LIST_HEAD(xive_irq_bitmaps);
-static int xive_irq_bitmap_add(int base, int count)
+static int __init xive_irq_bitmap_add(int base, int count)
{
struct xive_irq_bitmap *xibm;
- xibm = kzalloc(sizeof(*xibm), GFP_ATOMIC);
+ xibm = kzalloc(sizeof(*xibm), GFP_KERNEL);
if (!xibm)
return -ENOMEM;
spin_lock_init(&xibm->lock);
xibm->base = base;
xibm->count = count;
- xibm->bitmap = kzalloc(xibm->count, GFP_KERNEL);
+ xibm->bitmap = bitmap_zalloc(xibm->count, GFP_KERNEL);
+ if (!xibm->bitmap) {
+ kfree(xibm);
+ return -ENOMEM;
+ }
list_add(&xibm->list, &xive_irq_bitmaps);
pr_info("Using IRQ range [%x-%x]", xibm->base,
@@ -63,6 +71,17 @@ static int xive_irq_bitmap_add(int base, int count)
return 0;
}
+static void xive_irq_bitmap_remove_all(void)
+{
+ struct xive_irq_bitmap *xibm, *tmp;
+
+ list_for_each_entry_safe(xibm, tmp, &xive_irq_bitmaps, list) {
+ list_del(&xibm->list);
+ bitmap_free(xibm->bitmap);
+ kfree(xibm);
+ }
+}
+
static int __xive_irq_bitmap_alloc(struct xive_irq_bitmap *xibm)
{
int irq;
@@ -169,7 +188,7 @@ static long plpar_int_get_source_info(unsigned long flags,
} while (plpar_busy_delay(rc));
if (rc) {
- pr_err("H_INT_GET_SOURCE_INFO lisn=%ld failed %ld\n", lisn, rc);
+ pr_err("H_INT_GET_SOURCE_INFO lisn=0x%lx failed %ld\n", lisn, rc);
return rc;
}
@@ -178,8 +197,8 @@ static long plpar_int_get_source_info(unsigned long flags,
*trig_page = retbuf[2];
*esb_shift = retbuf[3];
- pr_devel("H_INT_GET_SOURCE_INFO flags=%lx eoi=%lx trig=%lx shift=%lx\n",
- retbuf[0], retbuf[1], retbuf[2], retbuf[3]);
+ pr_debug("H_INT_GET_SOURCE_INFO lisn=0x%lx flags=0x%lx eoi=0x%lx trig=0x%lx shift=0x%lx\n",
+ lisn, retbuf[0], retbuf[1], retbuf[2], retbuf[3]);
return 0;
}
@@ -196,8 +215,8 @@ static long plpar_int_set_source_config(unsigned long flags,
long rc;
- pr_devel("H_INT_SET_SOURCE_CONFIG flags=%lx lisn=%lx target=%lx prio=%lx sw_irq=%lx\n",
- flags, lisn, target, prio, sw_irq);
+ pr_debug("H_INT_SET_SOURCE_CONFIG flags=0x%lx lisn=0x%lx target=%ld prio=%ld sw_irq=%ld\n",
+ flags, lisn, target, prio, sw_irq);
do {
@@ -206,7 +225,7 @@ static long plpar_int_set_source_config(unsigned long flags,
} while (plpar_busy_delay(rc));
if (rc) {
- pr_err("H_INT_SET_SOURCE_CONFIG lisn=%ld target=%lx prio=%lx failed %ld\n",
+ pr_err("H_INT_SET_SOURCE_CONFIG lisn=0x%lx target=%ld prio=%ld failed %ld\n",
lisn, target, prio, rc);
return rc;
}
@@ -214,6 +233,38 @@ static long plpar_int_set_source_config(unsigned long flags,
return 0;
}
+static long plpar_int_get_source_config(unsigned long flags,
+ unsigned long lisn,
+ unsigned long *target,
+ unsigned long *prio,
+ unsigned long *sw_irq)
+{
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+ long rc;
+
+ pr_debug("H_INT_GET_SOURCE_CONFIG flags=0x%lx lisn=0x%lx\n", flags, lisn);
+
+ do {
+ rc = plpar_hcall(H_INT_GET_SOURCE_CONFIG, retbuf, flags, lisn,
+ target, prio, sw_irq);
+ } while (plpar_busy_delay(rc));
+
+ if (rc) {
+ pr_err("H_INT_GET_SOURCE_CONFIG lisn=0x%lx failed %ld\n",
+ lisn, rc);
+ return rc;
+ }
+
+ *target = retbuf[0];
+ *prio = retbuf[1];
+ *sw_irq = retbuf[2];
+
+ pr_debug("H_INT_GET_SOURCE_CONFIG target=%ld prio=%ld sw_irq=%ld\n",
+ retbuf[0], retbuf[1], retbuf[2]);
+
+ return 0;
+}
+
static long plpar_int_get_queue_info(unsigned long flags,
unsigned long target,
unsigned long priority,
@@ -237,8 +288,8 @@ static long plpar_int_get_queue_info(unsigned long flags,
*esn_page = retbuf[0];
*esn_size = retbuf[1];
- pr_devel("H_INT_GET_QUEUE_INFO page=%lx size=%lx\n",
- retbuf[0], retbuf[1]);
+ pr_debug("H_INT_GET_QUEUE_INFO cpu=%ld prio=%ld page=0x%lx size=0x%lx\n",
+ target, priority, retbuf[0], retbuf[1]);
return 0;
}
@@ -253,8 +304,8 @@ static long plpar_int_set_queue_config(unsigned long flags,
{
long rc;
- pr_devel("H_INT_SET_QUEUE_CONFIG flags=%lx target=%lx priority=%lx qpage=%lx qsize=%lx\n",
- flags, target, priority, qpage, qsize);
+ pr_debug("H_INT_SET_QUEUE_CONFIG flags=0x%lx target=%ld priority=0x%lx qpage=0x%lx qsize=0x%lx\n",
+ flags, target, priority, qpage, qsize);
do {
rc = plpar_hcall_norets(H_INT_SET_QUEUE_CONFIG, flags, target,
@@ -262,7 +313,7 @@ static long plpar_int_set_queue_config(unsigned long flags,
} while (plpar_busy_delay(rc));
if (rc) {
- pr_err("H_INT_SET_QUEUE_CONFIG cpu=%ld prio=%ld qpage=%lx returned %ld\n",
+ pr_err("H_INT_SET_QUEUE_CONFIG cpu=%ld prio=%ld qpage=0x%lx returned %ld\n",
target, priority, qpage, rc);
return rc;
}
@@ -279,7 +330,7 @@ static long plpar_int_sync(unsigned long flags, unsigned long lisn)
} while (plpar_busy_delay(rc));
if (rc) {
- pr_err("H_INT_SYNC lisn=%ld returned %ld\n", lisn, rc);
+ pr_err("H_INT_SYNC lisn=0x%lx returned %ld\n", lisn, rc);
return rc;
}
@@ -297,8 +348,8 @@ static long plpar_int_esb(unsigned long flags,
unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
long rc;
- pr_devel("H_INT_ESB flags=%lx lisn=%lx offset=%lx in=%lx\n",
- flags, lisn, offset, in_data);
+ pr_debug("H_INT_ESB flags=0x%lx lisn=0x%lx offset=0x%lx in=0x%lx\n",
+ flags, lisn, offset, in_data);
do {
rc = plpar_hcall(H_INT_ESB, retbuf, flags, lisn, offset,
@@ -306,7 +357,7 @@ static long plpar_int_esb(unsigned long flags,
} while (plpar_busy_delay(rc));
if (rc) {
- pr_err("H_INT_ESB lisn=%ld offset=%ld returned %ld\n",
+ pr_err("H_INT_ESB lisn=0x%lx offset=0x%lx returned %ld\n",
lisn, offset, rc);
return rc;
}
@@ -359,20 +410,28 @@ static int xive_spapr_populate_irq_data(u32 hw_irq, struct xive_irq_data *data)
data->esb_shift = esb_shift;
data->trig_page = trig_page;
+ data->hw_irq = hw_irq;
+
/*
* No chip-id for the sPAPR backend. This has an impact how we
* pick a target. See xive_pick_irq_target().
*/
data->src_chip = XIVE_INVALID_CHIP_ID;
+ /*
+ * When the H_INT_ESB flag is set, the H_INT_ESB hcall should
+ * be used for interrupt management. Skip the remapping of the
+ * ESB pages which are not available.
+ */
+ if (data->flags & XIVE_IRQ_FLAG_H_INT_ESB)
+ return 0;
+
data->eoi_mmio = ioremap(data->eoi_page, 1u << data->esb_shift);
if (!data->eoi_mmio) {
pr_err("Failed to map EOI page for irq 0x%x\n", hw_irq);
return -ENOMEM;
}
- data->hw_irq = hw_irq;
-
/* Full function page supports trigger */
if (flags & XIVE_SRC_TRIGGER) {
data->trig_mmio = data->eoi_mmio;
@@ -381,6 +440,7 @@ static int xive_spapr_populate_irq_data(u32 hw_irq, struct xive_irq_data *data)
data->trig_mmio = ioremap(data->trig_page, 1u << data->esb_shift);
if (!data->trig_mmio) {
+ iounmap(data->eoi_mmio);
pr_err("Failed to map trigger page for irq 0x%x\n", hw_irq);
return -ENOMEM;
}
@@ -397,6 +457,24 @@ static int xive_spapr_configure_irq(u32 hw_irq, u32 target, u8 prio, u32 sw_irq)
return rc == 0 ? 0 : -ENXIO;
}
+static int xive_spapr_get_irq_config(u32 hw_irq, u32 *target, u8 *prio,
+ u32 *sw_irq)
+{
+ long rc;
+ unsigned long h_target;
+ unsigned long h_prio;
+ unsigned long h_sw_irq;
+
+ rc = plpar_int_get_source_config(0, hw_irq, &h_target, &h_prio,
+ &h_sw_irq);
+
+ *target = h_target;
+ *prio = h_prio;
+ *sw_irq = h_sw_irq;
+
+ return rc == 0 ? 0 : -ENXIO;
+}
+
/* This can be called multiple time to change a queue configuration */
static int xive_spapr_configure_queue(u32 target, struct xive_q *q, u8 prio,
__be32 *qpage, u32 order)
@@ -442,6 +520,9 @@ static int xive_spapr_configure_queue(u32 target, struct xive_q *q, u8 prio,
rc = -EIO;
} else {
q->qpage = qpage;
+ if (is_secure_guest())
+ uv_share_page(PHYS_PFN(qpage_phys),
+ 1 << xive_alloc_order(order));
}
fail:
return rc;
@@ -475,6 +556,8 @@ static void xive_spapr_cleanup_queue(unsigned int cpu, struct xive_cpu *xc,
hw_cpu, prio);
alloc_order = xive_alloc_order(xive_queue_shift);
+ if (is_secure_guest())
+ uv_unshare_page(PHYS_PFN(__pa(q->qpage)), 1 << alloc_order);
free_pages((unsigned long)q->qpage, alloc_order);
q->qpage = NULL;
}
@@ -482,7 +565,7 @@ static void xive_spapr_cleanup_queue(unsigned int cpu, struct xive_cpu *xc,
static bool xive_spapr_match(struct device_node *node)
{
/* Ignore cascaded controllers for the moment */
- return 1;
+ return true;
}
#ifdef CONFIG_SMP
@@ -501,11 +584,11 @@ static int xive_spapr_get_ipi(unsigned int cpu, struct xive_cpu *xc)
static void xive_spapr_put_ipi(unsigned int cpu, struct xive_cpu *xc)
{
- if (!xc->hw_ipi)
+ if (xc->hw_ipi == XIVE_BAD_IRQ)
return;
xive_irq_bitmap_free(xc->hw_ipi);
- xc->hw_ipi = 0;
+ xc->hw_ipi = XIVE_BAD_IRQ;
}
#endif /* CONFIG_SMP */
@@ -561,11 +644,6 @@ static void xive_spapr_update_pending(struct xive_cpu *xc)
}
}
-static void xive_spapr_eoi(u32 hw_irq)
-{
- /* Not used */;
-}
-
static void xive_spapr_setup_cpu(unsigned int cpu, struct xive_cpu *xc)
{
/* Only some debug on the TIMA settings */
@@ -586,15 +664,33 @@ static void xive_spapr_sync_source(u32 hw_irq)
plpar_int_sync(0, hw_irq);
}
+static int xive_spapr_debug_show(struct seq_file *m, void *private)
+{
+ struct xive_irq_bitmap *xibm;
+ char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+ if (!buf)
+ return -ENOMEM;
+
+ list_for_each_entry(xibm, &xive_irq_bitmaps, list) {
+ memset(buf, 0, PAGE_SIZE);
+ bitmap_print_to_pagebuf(true, buf, xibm->bitmap, xibm->count);
+ seq_printf(m, "bitmap #%d: %s", xibm->count, buf);
+ }
+ kfree(buf);
+
+ return 0;
+}
+
static const struct xive_ops xive_spapr_ops = {
.populate_irq_data = xive_spapr_populate_irq_data,
.configure_irq = xive_spapr_configure_irq,
+ .get_irq_config = xive_spapr_get_irq_config,
.setup_queue = xive_spapr_setup_queue,
.cleanup_queue = xive_spapr_cleanup_queue,
.match = xive_spapr_match,
.shutdown = xive_spapr_shutdown,
.update_pending = xive_spapr_update_pending,
- .eoi = xive_spapr_eoi,
.setup_cpu = xive_spapr_setup_cpu,
.teardown_cpu = xive_spapr_teardown_cpu,
.sync_source = xive_spapr_sync_source,
@@ -602,6 +698,7 @@ static const struct xive_ops xive_spapr_ops = {
#ifdef CONFIG_SMP
.get_ipi = xive_spapr_get_ipi,
.put_ipi = xive_spapr_put_ipi,
+ .debug_show = xive_spapr_debug_show,
#endif /* CONFIG_SMP */
.name = "spapr",
};
@@ -609,7 +706,7 @@ static const struct xive_ops xive_spapr_ops = {
/*
* get max priority from "/ibm,plat-res-int-priorities"
*/
-static bool xive_get_max_prio(u8 *max_prio)
+static bool __init xive_get_max_prio(u8 *max_prio)
{
struct device_node *rootdn;
const __be32 *reg;
@@ -623,6 +720,7 @@ static bool xive_get_max_prio(u8 *max_prio)
}
reg = of_get_property(rootdn, "ibm,plat-res-int-priorities", &len);
+ of_node_put(rootdn);
if (!reg) {
pr_err("Failed to read 'ibm,plat-res-int-priorities' property\n");
return false;
@@ -663,19 +761,67 @@ static bool xive_get_max_prio(u8 *max_prio)
return true;
}
+static const u8 *__init get_vec5_feature(unsigned int index)
+{
+ unsigned long root, chosen;
+ int size;
+ const u8 *vec5;
+
+ root = of_get_flat_dt_root();
+ chosen = of_get_flat_dt_subnode_by_name(root, "chosen");
+ if (chosen == -FDT_ERR_NOTFOUND)
+ return NULL;
+
+ vec5 = of_get_flat_dt_prop(chosen, "ibm,architecture-vec-5", &size);
+ if (!vec5)
+ return NULL;
+
+ if (size <= index)
+ return NULL;
+
+ return vec5 + index;
+}
+
+static bool __init xive_spapr_disabled(void)
+{
+ const u8 *vec5_xive;
+
+ vec5_xive = get_vec5_feature(OV5_INDX(OV5_XIVE_SUPPORT));
+ if (vec5_xive) {
+ u8 val;
+
+ val = *vec5_xive & OV5_FEAT(OV5_XIVE_SUPPORT);
+ switch (val) {
+ case OV5_FEAT(OV5_XIVE_EITHER):
+ case OV5_FEAT(OV5_XIVE_LEGACY):
+ break;
+ case OV5_FEAT(OV5_XIVE_EXPLOIT):
+ /* Hypervisor only supports XIVE */
+ if (xive_cmdline_disabled)
+ pr_warn("WARNING: Ignoring cmdline option xive=off\n");
+ return false;
+ default:
+ pr_warn("%s: Unknown xive support option: 0x%x\n",
+ __func__, val);
+ break;
+ }
+ }
+
+ return xive_cmdline_disabled;
+}
+
bool __init xive_spapr_init(void)
{
struct device_node *np;
struct resource r;
void __iomem *tima;
- struct property *prop;
u8 max_prio;
u32 val;
u32 len;
const __be32 *reg;
- int i;
+ int i, err;
- if (xive_cmdline_disabled)
+ if (xive_spapr_disabled())
return false;
pr_devel("%s()\n", __func__);
@@ -689,44 +835,58 @@ bool __init xive_spapr_init(void)
/* Resource 1 is the OS ring TIMA */
if (of_address_to_resource(np, 1, &r)) {
pr_err("Failed to get thread mgmnt area resource\n");
- return false;
+ goto err_put;
}
tima = ioremap(r.start, resource_size(&r));
if (!tima) {
pr_err("Failed to map thread mgmnt area\n");
- return false;
+ goto err_put;
}
if (!xive_get_max_prio(&max_prio))
- return false;
+ goto err_unmap;
/* Feed the IRQ number allocator with the ranges given in the DT */
reg = of_get_property(np, "ibm,xive-lisn-ranges", &len);
if (!reg) {
pr_err("Failed to read 'ibm,xive-lisn-ranges' property\n");
- return false;
+ goto err_unmap;
}
if (len % (2 * sizeof(u32)) != 0) {
pr_err("invalid 'ibm,xive-lisn-ranges' property\n");
- return false;
+ goto err_unmap;
}
- for (i = 0; i < len / (2 * sizeof(u32)); i++, reg += 2)
- xive_irq_bitmap_add(be32_to_cpu(reg[0]),
- be32_to_cpu(reg[1]));
+ for (i = 0; i < len / (2 * sizeof(u32)); i++, reg += 2) {
+ err = xive_irq_bitmap_add(be32_to_cpu(reg[0]),
+ be32_to_cpu(reg[1]));
+ if (err < 0)
+ goto err_mem_free;
+ }
/* Iterate the EQ sizes and pick one */
- of_property_for_each_u32(np, "ibm,xive-eq-sizes", prop, reg, val) {
+ of_property_for_each_u32(np, "ibm,xive-eq-sizes", val) {
xive_queue_shift = val;
if (val == PAGE_SHIFT)
break;
}
/* Initialize XIVE core with our backend */
- if (!xive_core_init(&xive_spapr_ops, tima, TM_QW1_OS, max_prio))
- return false;
+ if (!xive_core_init(np, &xive_spapr_ops, tima, TM_QW1_OS, max_prio))
+ goto err_mem_free;
+ of_node_put(np);
pr_info("Using %dkB queues\n", 1 << (xive_queue_shift - 10));
return true;
+
+err_mem_free:
+ xive_irq_bitmap_remove_all();
+err_unmap:
+ iounmap(tima);
+err_put:
+ of_node_put(np);
+ return false;
}
+
+machine_arch_initcall(pseries, xive_core_debug_init);
diff --git a/arch/powerpc/sysdev/xive/xive-internal.h b/arch/powerpc/sysdev/xive/xive-internal.h
index f34abed0c05f..fe6d95d54af9 100644
--- a/arch/powerpc/sysdev/xive/xive-internal.h
+++ b/arch/powerpc/sysdev/xive/xive-internal.h
@@ -1,14 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright 2016,2017 IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#ifndef __XIVE_INTERNAL_H
#define __XIVE_INTERNAL_H
+/*
+ * A "disabled" interrupt should never fire, to catch problems
+ * we set its logical number to this
+ */
+#define XIVE_BAD_IRQ 0x7fffffff
+#define XIVE_MAX_IRQ (XIVE_BAD_IRQ - 1)
+
/* Each CPU carry one of these with various per-CPU state */
struct xive_cpu {
#ifdef CONFIG_SMP
@@ -37,27 +40,32 @@ struct xive_cpu {
struct xive_ops {
int (*populate_irq_data)(u32 hw_irq, struct xive_irq_data *data);
int (*configure_irq)(u32 hw_irq, u32 target, u8 prio, u32 sw_irq);
+ int (*get_irq_config)(u32 hw_irq, u32 *target, u8 *prio,
+ u32 *sw_irq);
int (*setup_queue)(unsigned int cpu, struct xive_cpu *xc, u8 prio);
void (*cleanup_queue)(unsigned int cpu, struct xive_cpu *xc, u8 prio);
+ void (*prepare_cpu)(unsigned int cpu, struct xive_cpu *xc);
void (*setup_cpu)(unsigned int cpu, struct xive_cpu *xc);
void (*teardown_cpu)(unsigned int cpu, struct xive_cpu *xc);
bool (*match)(struct device_node *np);
void (*shutdown)(void);
void (*update_pending)(struct xive_cpu *xc);
- void (*eoi)(u32 hw_irq);
void (*sync_source)(u32 hw_irq);
u64 (*esb_rw)(u32 hw_irq, u32 offset, u64 data, bool write);
#ifdef CONFIG_SMP
int (*get_ipi)(unsigned int cpu, struct xive_cpu *xc);
void (*put_ipi)(unsigned int cpu, struct xive_cpu *xc);
#endif
+ int (*debug_show)(struct seq_file *m, void *private);
+ int (*debug_create)(struct dentry *xive_dir);
const char *name;
};
-bool xive_core_init(const struct xive_ops *ops, void __iomem *area, u32 offset,
- u8 max_prio);
+bool xive_core_init(struct device_node *np, const struct xive_ops *ops,
+ void __iomem *area, u32 offset, u8 max_prio);
__be32 *xive_queue_page_alloc(unsigned int cpu, u32 queue_shift);
+int xive_core_debug_init(void);
static inline u32 xive_alloc_order(u32 queue_shift)
{
@@ -65,5 +73,6 @@ static inline u32 xive_alloc_order(u32 queue_shift)
}
extern bool xive_cmdline_disabled;
+extern bool xive_has_save_restore;
#endif /* __XIVE_INTERNAL_H */