Commit 1a34e7f2 authored by Huacai Chen's avatar Huacai Chen
Browse files

Merge tags 'acpi-6.2-rc1' and 'irq-core-2022-12-10' into loongarch-next

LoongArch architecture changes for 6.2 depend on the acpi and irqchip
changes to work, so merge them to create a base.
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -285,3 +285,13 @@ to bridges between the PCI root and the device, MSIs are disabled.
It is also worth checking the device driver to see whether it supports MSIs.
For example, it may contain calls to pci_alloc_irq_vectors() with the
PCI_IRQ_MSI or PCI_IRQ_MSIX flags.


List of device drivers MSI(-X) APIs
===================================

The PCI/MSI subystem has a dedicated C file for its exported device driver
APIs — `drivers/pci/msi/api.c`. The following functions are exported:

.. kernel-doc:: drivers/pci/msi/api.c
   :export:
+34 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/interrupt-controller/loongarch,cpu-interrupt-controller.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: LoongArch CPU Interrupt Controller

maintainers:
  - Liu Peibao <liupeibao@loongson.cn>

properties:
  compatible:
    const: loongarch,cpu-interrupt-controller

  '#interrupt-cells':
    const: 1

  interrupt-controller: true

additionalProperties: false

required:
  - compatible
  - '#interrupt-cells'
  - interrupt-controller

examples:
  - |
    interrupt-controller {
      compatible = "loongarch,cpu-interrupt-controller";
      #interrupt-cells = <1>;
      interrupt-controller;
    };
+0 −33
Original line number Diff line number Diff line
* Mediatek 27xx cirq

In Mediatek SOCs, the CIRQ is a low power interrupt controller designed to
work outside MCUSYS which comprises with Cortex-Ax cores,CCI and GIC.
The external interrupts (outside MCUSYS) will feed through CIRQ and connect
to GIC in MCUSYS. When CIRQ is enabled, it will record the edge-sensitive
interrupts and generate a pulse signal to parent interrupt controller when
flush command is executed. With CIRQ, MCUSYS can be completely turned off
to improve the system power consumption without losing interrupts.

Required properties:
- compatible: should be one of
  - "mediatek,mt2701-cirq" for mt2701 CIRQ
  - "mediatek,mt8135-cirq" for mt8135 CIRQ
  - "mediatek,mt8173-cirq" for mt8173 CIRQ
  and "mediatek,cirq" as a fallback.
- interrupt-controller : Identifies the node as an interrupt controller.
- #interrupt-cells : Use the same format as specified by GIC in arm,gic.txt.
- reg: Physical base address of the cirq registers and length of memory
  mapped region.
- mediatek,ext-irq-range: Identifies external irq number range in different
  SOCs.

Example:
	cirq: interrupt-controller@10204000 {
		compatible = "mediatek,mt2701-cirq",
			     "mediatek,mtk-cirq";
		interrupt-controller;
		#interrupt-cells = <3>;
		interrupt-parent = <&sysirq>;
		reg = <0 0x10204000 0 0x400>;
		mediatek,ext-irq-start = <32 200>;
	};
+68 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/interrupt-controller/mediatek,mtk-cirq.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: MediaTek System Interrupt Controller

maintainers:
  - Youlin Pei <youlin.pei@mediatek.com>

description:
  In MediaTek SoCs, the CIRQ is a low power interrupt controller designed to
  work outside of MCUSYS which comprises with Cortex-Ax cores, CCI and GIC.
  The external interrupts (outside MCUSYS) will feed through CIRQ and connect
  to GIC in MCUSYS. When CIRQ is enabled, it will record the edge-sensitive
  interrupts and generate a pulse signal to parent interrupt controller when
  flush command is executed. With CIRQ, MCUSYS can be completely turned off
  to improve the system power consumption without losing interrupts.


properties:
  compatible:
    items:
      - enum:
          - mediatek,mt2701-cirq
          - mediatek,mt8135-cirq
          - mediatek,mt8173-cirq
          - mediatek,mt8192-cirq
      - const: mediatek,mtk-cirq

  reg:
    maxItems: 1

  '#interrupt-cells':
    const: 3

  interrupt-controller: true

  mediatek,ext-irq-range:
    $ref: /schemas/types.yaml#/definitions/uint32-array
    items:
      - description: First CIRQ interrupt
      - description: Last CIRQ interrupt
    description:
      Identifies the range of external interrupts in different SoCs

required:
  - compatible
  - reg
  - '#interrupt-cells'
  - interrupt-controller
  - mediatek,ext-irq-range

additionalProperties: false

examples:
  - |
    #include <dt-bindings/interrupt-controller/irq.h>

    cirq: interrupt-controller@10204000 {
        compatible = "mediatek,mt2701-cirq", "mediatek,mtk-cirq";
        reg = <0x10204000 0x400>;
        #interrupt-cells = <3>;
        interrupt-controller;
        interrupt-parent = <&sysirq>;
        mediatek,ext-irq-range = <32 200>;
    };
+106 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#define pr_fmt(fmt) "ACPI: " fmt

#include <linux/acpi.h>
#include <linux/arm-smccc.h>
#include <linux/cpumask.h>
#include <linux/efi.h>
#include <linux/efi-bgrt.h>
@@ -411,3 +412,108 @@ void arch_reserve_mem_area(acpi_physical_address addr, size_t size)
{
	memblock_mark_nomap(addr, size);
}

#ifdef CONFIG_ACPI_FFH
/*
 * Implements ARM64 specific callbacks to support ACPI FFH Operation Region as
 * specified in https://developer.arm.com/docs/den0048/latest
 */
struct acpi_ffh_data {
	struct acpi_ffh_info info;
	void (*invoke_ffh_fn)(unsigned long a0, unsigned long a1,
			      unsigned long a2, unsigned long a3,
			      unsigned long a4, unsigned long a5,
			      unsigned long a6, unsigned long a7,
			      struct arm_smccc_res *args,
			      struct arm_smccc_quirk *res);
	void (*invoke_ffh64_fn)(const struct arm_smccc_1_2_regs *args,
				struct arm_smccc_1_2_regs *res);
};

int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
{
	enum arm_smccc_conduit conduit;
	struct acpi_ffh_data *ffh_ctxt;

	ffh_ctxt = kzalloc(sizeof(*ffh_ctxt), GFP_KERNEL);
	if (!ffh_ctxt)
		return -ENOMEM;

	if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
		return -EOPNOTSUPP;

	conduit = arm_smccc_1_1_get_conduit();
	if (conduit == SMCCC_CONDUIT_NONE) {
		pr_err("%s: invalid SMCCC conduit\n", __func__);
		return -EOPNOTSUPP;
	}

	if (conduit == SMCCC_CONDUIT_SMC) {
		ffh_ctxt->invoke_ffh_fn = __arm_smccc_smc;
		ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_smc;
	} else {
		ffh_ctxt->invoke_ffh_fn = __arm_smccc_hvc;
		ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_hvc;
	}

	memcpy(ffh_ctxt, handler_ctxt, sizeof(ffh_ctxt->info));

	*region_ctxt = ffh_ctxt;
	return AE_OK;
}

static bool acpi_ffh_smccc_owner_allowed(u32 fid)
{
	int owner = ARM_SMCCC_OWNER_NUM(fid);

	if (owner == ARM_SMCCC_OWNER_STANDARD ||
	    owner == ARM_SMCCC_OWNER_SIP || owner == ARM_SMCCC_OWNER_OEM)
		return true;

	return false;
}

int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_context)
{
	int ret = 0;
	struct acpi_ffh_data *ffh_ctxt = region_context;

	if (ffh_ctxt->info.offset == 0) {
		/* SMC/HVC 32bit call */
		struct arm_smccc_res res;
		u32 a[8] = { 0 }, *ptr = (u32 *)value;

		if (!ARM_SMCCC_IS_FAST_CALL(*ptr) || ARM_SMCCC_IS_64(*ptr) ||
		    !acpi_ffh_smccc_owner_allowed(*ptr) ||
		    ffh_ctxt->info.length > 32) {
			ret = AE_ERROR;
		} else {
			int idx, len = ffh_ctxt->info.length >> 2;

			for (idx = 0; idx < len; idx++)
				a[idx] = *(ptr + idx);

			ffh_ctxt->invoke_ffh_fn(a[0], a[1], a[2], a[3], a[4],
						a[5], a[6], a[7], &res, NULL);
			memcpy(value, &res, sizeof(res));
		}

	} else if (ffh_ctxt->info.offset == 1) {
		/* SMC/HVC 64bit call */
		struct arm_smccc_1_2_regs *r = (struct arm_smccc_1_2_regs *)value;

		if (!ARM_SMCCC_IS_FAST_CALL(r->a0) || !ARM_SMCCC_IS_64(r->a0) ||
		    !acpi_ffh_smccc_owner_allowed(r->a0) ||
		    ffh_ctxt->info.length > sizeof(*r)) {
			ret = AE_ERROR;
		} else {
			ffh_ctxt->invoke_ffh64_fn(r, r);
			memcpy(value, r, ffh_ctxt->info.length);
		}
	} else {
		ret = AE_ERROR;
	}

	return ret;
}
#endif /* CONFIG_ACPI_FFH */
Loading