mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull IRQ chip updates from Ingo Molnar:
"A late irqchips update:
- New TI INTR/INTA set of drivers
- Rewrite of the stm32mp1-exti driver as a platform driver
- Update the IOMMU MSI mapping API to be RT friendly
- A number of cleanups and other low impact fixes"
* 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (34 commits)
iommu/dma-iommu: Remove iommu_dma_map_msi_msg()
irqchip/gic-v3-mbi: Don't map the MSI page in mbi_compose_m{b, s}i_msg()
irqchip/ls-scfg-msi: Don't map the MSI page in ls_scfg_msi_compose_msg()
irqchip/gic-v3-its: Don't map the MSI page in its_irq_compose_msi_msg()
irqchip/gicv2m: Don't map the MSI page in gicv2m_compose_msi_msg()
iommu/dma-iommu: Split iommu_dma_map_msi_msg() in two parts
genirq/msi: Add a new field in msi_desc to store an IOMMU cookie
arm64: arch_k3: Enable interrupt controller drivers
irqchip/ti-sci-inta: Add msi domain support
soc: ti: Add MSI domain bus support for Interrupt Aggregator
irqchip/ti-sci-inta: Add support for Interrupt Aggregator driver
dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings
irqchip/ti-sci-intr: Add support for Interrupt Router driver
dt-bindings: irqchip: Introduce TISCI Interrupt router bindings
gpio: thunderx: Use the default parent apis for {request,release}_resources
genirq: Introduce irq_chip_{request,release}_resource_parent() apis
firmware: ti_sci: Add helper apis to manage resources
firmware: ti_sci: Add RM mapping table for am654
firmware: ti_sci: Add support for IRQ management
firmware: ti_sci: Add support for RM core ops
...
This commit is contained in:
@@ -24,7 +24,8 @@ relationship between the TI-SCI parent node to the child node.
|
||||
|
||||
Required properties:
|
||||
-------------------
|
||||
- compatible: should be "ti,k2g-sci"
|
||||
- compatible: should be "ti,k2g-sci" for TI 66AK2G SoC
|
||||
should be "ti,am654-sci" for for TI AM654 SoC
|
||||
- mbox-names:
|
||||
"rx" - Mailbox corresponding to receive path
|
||||
"tx" - Mailbox corresponding to transmit path
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
Texas Instruments K3 Interrupt Aggregator
|
||||
=========================================
|
||||
|
||||
The Interrupt Aggregator (INTA) provides a centralized machine
|
||||
which handles the termination of system events to that they can
|
||||
be coherently processed by the host(s) in the system. A maximum
|
||||
of 64 events can be mapped to a single interrupt.
|
||||
|
||||
|
||||
Interrupt Aggregator
|
||||
+-----------------------------------------+
|
||||
| Intmap VINT |
|
||||
| +--------------+ +------------+ |
|
||||
m ------>| | vint | bit | | 0 |.....|63| vint0 |
|
||||
. | +--------------+ +------------+ | +------+
|
||||
. | . . | | HOST |
|
||||
Globalevents ------>| . . |------>| IRQ |
|
||||
. | . . | | CTRL |
|
||||
. | . . | +------+
|
||||
n ------>| +--------------+ +------------+ |
|
||||
| | vint | bit | | 0 |.....|63| vintx |
|
||||
| +--------------+ +------------+ |
|
||||
| |
|
||||
+-----------------------------------------+
|
||||
|
||||
Configuration of these Intmap registers that maps global events to vint is done
|
||||
by a system controller (like the Device Memory and Security Controller on K3
|
||||
AM654 SoC). Driver should request the system controller to get the range
|
||||
of global events and vints assigned to the requesting host. Management
|
||||
of these requested resources should be handled by driver and requests
|
||||
system controller to map specific global event to vint, bit pair.
|
||||
|
||||
Communication between the host processor running an OS and the system
|
||||
controller happens through a protocol called TI System Control Interface
|
||||
(TISCI protocol). For more details refer:
|
||||
Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
|
||||
|
||||
TISCI Interrupt Aggregator Node:
|
||||
-------------------------------
|
||||
- compatible: Must be "ti,sci-inta".
|
||||
- reg: Should contain registers location and length.
|
||||
- interrupt-controller: Identifies the node as an interrupt controller
|
||||
- msi-controller: Identifies the node as an MSI controller.
|
||||
- interrupt-parent: phandle of irq parent.
|
||||
- ti,sci: Phandle to TI-SCI compatible System controller node.
|
||||
- ti,sci-dev-id: TISCI device ID of the Interrupt Aggregator.
|
||||
- ti,sci-rm-range-vint: Array of TISCI subtype ids representing vints(inta
|
||||
outputs) range within this INTA, assigned to the
|
||||
requesting host context.
|
||||
- ti,sci-rm-range-global-event: Array of TISCI subtype ids representing the
|
||||
global events range reaching this IA and are assigned
|
||||
to the requesting host context.
|
||||
|
||||
Example:
|
||||
--------
|
||||
main_udmass_inta: interrupt-controller@33d00000 {
|
||||
compatible = "ti,sci-inta";
|
||||
reg = <0x0 0x33d00000 0x0 0x100000>;
|
||||
interrupt-controller;
|
||||
msi-controller;
|
||||
interrupt-parent = <&main_navss_intr>;
|
||||
ti,sci = <&dmsc>;
|
||||
ti,sci-dev-id = <179>;
|
||||
ti,sci-rm-range-vint = <0x0>;
|
||||
ti,sci-rm-range-global-event = <0x1>;
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
Texas Instruments K3 Interrupt Router
|
||||
=====================================
|
||||
|
||||
The Interrupt Router (INTR) module provides a mechanism to mux M
|
||||
interrupt inputs to N interrupt outputs, where all M inputs are selectable
|
||||
to be driven per N output. An Interrupt Router can either handle edge triggered
|
||||
or level triggered interrupts and that is fixed in hardware.
|
||||
|
||||
Interrupt Router
|
||||
+----------------------+
|
||||
| Inputs Outputs |
|
||||
+-------+ | +------+ +-----+ |
|
||||
| GPIO |----------->| | irq0 | | 0 | | Host IRQ
|
||||
+-------+ | +------+ +-----+ | controller
|
||||
| . . | +-------+
|
||||
+-------+ | . . |----->| IRQ |
|
||||
| INTA |----------->| . . | +-------+
|
||||
+-------+ | . +-----+ |
|
||||
| +------+ | N | |
|
||||
| | irqM | +-----+ |
|
||||
| +------+ |
|
||||
| |
|
||||
+----------------------+
|
||||
|
||||
There is one register per output (MUXCNTL_N) that controls the selection.
|
||||
Configuration of these MUXCNTL_N registers is done by a system controller
|
||||
(like the Device Memory and Security Controller on K3 AM654 SoC). System
|
||||
controller will keep track of the used and unused registers within the Router.
|
||||
Driver should request the system controller to get the range of GIC IRQs
|
||||
assigned to the requesting hosts. It is the drivers responsibility to keep
|
||||
track of Host IRQs.
|
||||
|
||||
Communication between the host processor running an OS and the system
|
||||
controller happens through a protocol called TI System Control Interface
|
||||
(TISCI protocol). For more details refer:
|
||||
Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
|
||||
|
||||
TISCI Interrupt Router Node:
|
||||
----------------------------
|
||||
Required Properties:
|
||||
- compatible: Must be "ti,sci-intr".
|
||||
- ti,intr-trigger-type: Should be one of the following:
|
||||
1: If intr supports edge triggered interrupts.
|
||||
4: If intr supports level triggered interrupts.
|
||||
- interrupt-controller: Identifies the node as an interrupt controller
|
||||
- #interrupt-cells: Specifies the number of cells needed to encode an
|
||||
interrupt source. The value should be 2.
|
||||
First cell should contain the TISCI device ID of source
|
||||
Second cell should contain the interrupt source offset
|
||||
within the device.
|
||||
- ti,sci: Phandle to TI-SCI compatible System controller node.
|
||||
- ti,sci-dst-id: TISCI device ID of the destination IRQ controller.
|
||||
- ti,sci-rm-range-girq: Array of TISCI subtype ids representing the host irqs
|
||||
assigned to this interrupt router. Each subtype id
|
||||
corresponds to a range of host irqs.
|
||||
|
||||
For more details on TISCI IRQ resource management refer:
|
||||
http://downloads.ti.com/tisci/esd/latest/2_tisci_msgs/rm/rm_irq.html
|
||||
|
||||
Example:
|
||||
--------
|
||||
The following example demonstrates both interrupt router node and the consumer
|
||||
node(main gpio) on the AM654 SoC:
|
||||
|
||||
main_intr: interrupt-controller0 {
|
||||
compatible = "ti,sci-intr";
|
||||
ti,intr-trigger-type = <1>;
|
||||
interrupt-controller;
|
||||
interrupt-parent = <&gic500>;
|
||||
#interrupt-cells = <2>;
|
||||
ti,sci = <&dmsc>;
|
||||
ti,sci-dst-id = <56>;
|
||||
ti,sci-rm-range-girq = <0x1>;
|
||||
};
|
||||
|
||||
main_gpio0: gpio@600000 {
|
||||
...
|
||||
interrupt-parent = <&main_intr>;
|
||||
interrupts = <57 256>, <57 257>, <57 258>,
|
||||
<57 259>, <57 260>, <57 261>;
|
||||
...
|
||||
};
|
||||
@@ -15547,6 +15547,12 @@ F: Documentation/devicetree/bindings/reset/ti,sci-reset.txt
|
||||
F: Documentation/devicetree/bindings/clock/ti,sci-clk.txt
|
||||
F: drivers/clk/keystone/sci-clk.c
|
||||
F: drivers/reset/reset-ti-sci.c
|
||||
F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.txt
|
||||
F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
|
||||
F: drivers/irqchip/irq-ti-sci-intr.c
|
||||
F: drivers/irqchip/irq-ti-sci-inta.c
|
||||
F: include/linux/soc/ti/ti_sci_inta_msi.h
|
||||
F: drivers/soc/ti/ti_sci_inta_msi.c
|
||||
|
||||
Texas Instruments ASoC drivers
|
||||
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
|
||||
@@ -87,6 +87,11 @@ config ARCH_EXYNOS
|
||||
config ARCH_K3
|
||||
bool "Texas Instruments Inc. K3 multicore SoC architecture"
|
||||
select PM_GENERIC_DOMAINS if PM
|
||||
select MAILBOX
|
||||
select TI_MESSAGE_MANAGER
|
||||
select TI_SCI_PROTOCOL
|
||||
select TI_SCI_INTR_IRQCHIP
|
||||
select TI_SCI_INTA_IRQCHIP
|
||||
help
|
||||
This enables support for Texas Instruments' K3 multicore SoC
|
||||
architecture.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,13 @@
|
||||
#define TI_SCI_MSG_QUERY_CLOCK_FREQ 0x010d
|
||||
#define TI_SCI_MSG_GET_CLOCK_FREQ 0x010e
|
||||
|
||||
/* Resource Management Requests */
|
||||
#define TI_SCI_MSG_GET_RESOURCE_RANGE 0x1500
|
||||
|
||||
/* IRQ requests */
|
||||
#define TI_SCI_MSG_SET_IRQ 0x1000
|
||||
#define TI_SCI_MSG_FREE_IRQ 0x1001
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_hdr - Generic Message Header for All messages and responses
|
||||
* @type: Type of messages: One of TI_SCI_MSG* values
|
||||
@@ -461,4 +468,99 @@ struct ti_sci_msg_resp_get_clock_freq {
|
||||
u64 freq_hz;
|
||||
} __packed;
|
||||
|
||||
#define TI_SCI_IRQ_SECONDARY_HOST_INVALID 0xff
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_req_get_resource_range - Request to get a host's assigned
|
||||
* range of resources.
|
||||
* @hdr: Generic Header
|
||||
* @type: Unique resource assignment type
|
||||
* @subtype: Resource assignment subtype within the resource type.
|
||||
* @secondary_host: Host processing entity to which the resources are
|
||||
* allocated. This is required only when the destination
|
||||
* host id id different from ti sci interface host id,
|
||||
* else TI_SCI_IRQ_SECONDARY_HOST_INVALID can be passed.
|
||||
*
|
||||
* Request type is TI_SCI_MSG_GET_RESOURCE_RANGE. Responded with requested
|
||||
* resource range which is of type TI_SCI_MSG_GET_RESOURCE_RANGE.
|
||||
*/
|
||||
struct ti_sci_msg_req_get_resource_range {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
#define MSG_RM_RESOURCE_TYPE_MASK GENMASK(9, 0)
|
||||
#define MSG_RM_RESOURCE_SUBTYPE_MASK GENMASK(5, 0)
|
||||
u16 type;
|
||||
u8 subtype;
|
||||
u8 secondary_host;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_resp_get_resource_range - Response to resource get range.
|
||||
* @hdr: Generic Header
|
||||
* @range_start: Start index of the resource range.
|
||||
* @range_num: Number of resources in the range.
|
||||
*
|
||||
* Response to request TI_SCI_MSG_GET_RESOURCE_RANGE.
|
||||
*/
|
||||
struct ti_sci_msg_resp_get_resource_range {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
u16 range_start;
|
||||
u16 range_num;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ti_sci_msg_req_manage_irq - Request to configure/release the route
|
||||
* between the dev and the host.
|
||||
* @hdr: Generic Header
|
||||
* @valid_params: Bit fields defining the validity of interrupt source
|
||||
* parameters. If a bit is not set, then corresponding
|
||||
* field is not valid and will not be used for route set.
|
||||
* Bit field definitions:
|
||||
* 0 - Valid bit for @dst_id
|
||||
* 1 - Valid bit for @dst_host_irq
|
||||
* 2 - Valid bit for @ia_id
|
||||
* 3 - Valid bit for @vint
|
||||
* 4 - Valid bit for @global_event
|
||||
* 5 - Valid bit for @vint_status_bit_index
|
||||
* 31 - Valid bit for @secondary_host
|
||||
* @src_id: IRQ source peripheral ID.
|
||||
* @src_index: IRQ source index within the peripheral
|
||||
* @dst_id: IRQ Destination ID. Based on the architecture it can be
|
||||
* IRQ controller or host processor ID.
|
||||
* @dst_host_irq: IRQ number of the destination host IRQ controller
|
||||
* @ia_id: Device ID of the interrupt aggregator in which the
|
||||
* vint resides.
|
||||
* @vint: Virtual interrupt number if the interrupt route
|
||||
* is through an interrupt aggregator.
|
||||
* @global_event: Global event that is to be mapped to interrupt
|
||||
* aggregator virtual interrupt status bit.
|
||||
* @vint_status_bit: Virtual interrupt status bit if the interrupt route
|
||||
* utilizes an interrupt aggregator status bit.
|
||||
* @secondary_host: Host ID of the IRQ destination computing entity. This is
|
||||
* required only when destination host id is different
|
||||
* from ti sci interface host id.
|
||||
*
|
||||
* Request type is TI_SCI_MSG_SET/RELEASE_IRQ.
|
||||
* Response is generic ACK / NACK message.
|
||||
*/
|
||||
struct ti_sci_msg_req_manage_irq {
|
||||
struct ti_sci_msg_hdr hdr;
|
||||
#define MSG_FLAG_DST_ID_VALID TI_SCI_MSG_FLAG(0)
|
||||
#define MSG_FLAG_DST_HOST_IRQ_VALID TI_SCI_MSG_FLAG(1)
|
||||
#define MSG_FLAG_IA_ID_VALID TI_SCI_MSG_FLAG(2)
|
||||
#define MSG_FLAG_VINT_VALID TI_SCI_MSG_FLAG(3)
|
||||
#define MSG_FLAG_GLB_EVNT_VALID TI_SCI_MSG_FLAG(4)
|
||||
#define MSG_FLAG_VINT_STS_BIT_VALID TI_SCI_MSG_FLAG(5)
|
||||
#define MSG_FLAG_SHOST_VALID TI_SCI_MSG_FLAG(31)
|
||||
u32 valid_params;
|
||||
u16 src_id;
|
||||
u16 src_index;
|
||||
u16 dst_id;
|
||||
u16 dst_host_irq;
|
||||
u16 ia_id;
|
||||
u16 vint;
|
||||
u16 global_event;
|
||||
u8 vint_status_bit;
|
||||
u8 secondary_host;
|
||||
} __packed;
|
||||
|
||||
#endif /* __TI_SCI_H */
|
||||
|
||||
@@ -363,22 +363,16 @@ static int thunderx_gpio_irq_request_resources(struct irq_data *data)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
struct thunderx_gpio *txgpio = txline->txgpio;
|
||||
struct irq_data *parent_data = data->parent_data;
|
||||
int r;
|
||||
|
||||
r = gpiochip_lock_as_irq(&txgpio->chip, txline->line);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (parent_data && parent_data->chip->irq_request_resources) {
|
||||
r = parent_data->chip->irq_request_resources(parent_data);
|
||||
if (r)
|
||||
goto error;
|
||||
}
|
||||
r = irq_chip_request_resources_parent(data);
|
||||
if (r)
|
||||
gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -386,10 +380,8 @@ static void thunderx_gpio_irq_release_resources(struct irq_data *data)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
struct thunderx_gpio *txgpio = txline->txgpio;
|
||||
struct irq_data *parent_data = data->parent_data;
|
||||
|
||||
if (parent_data && parent_data->chip->irq_release_resources)
|
||||
parent_data->chip->irq_release_resources(parent_data);
|
||||
irq_chip_release_resources_parent(data);
|
||||
|
||||
gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ config IOMMU_DMA
|
||||
bool
|
||||
select IOMMU_API
|
||||
select IOMMU_IOVA
|
||||
select IRQ_MSI_IOMMU
|
||||
select NEED_SG_DMA_LENGTH
|
||||
|
||||
config FSL_PAMU
|
||||
|
||||
@@ -907,17 +907,18 @@ out_free_page:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg)
|
||||
int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr)
|
||||
{
|
||||
struct device *dev = msi_desc_to_dev(irq_get_msi_desc(irq));
|
||||
struct device *dev = msi_desc_to_dev(desc);
|
||||
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
|
||||
struct iommu_dma_cookie *cookie;
|
||||
struct iommu_dma_msi_page *msi_page;
|
||||
phys_addr_t msi_addr = (u64)msg->address_hi << 32 | msg->address_lo;
|
||||
unsigned long flags;
|
||||
|
||||
if (!domain || !domain->iova_cookie)
|
||||
return;
|
||||
if (!domain || !domain->iova_cookie) {
|
||||
desc->iommu_cookie = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cookie = domain->iova_cookie;
|
||||
|
||||
@@ -930,19 +931,26 @@ void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg)
|
||||
msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain);
|
||||
spin_unlock_irqrestore(&cookie->msi_lock, flags);
|
||||
|
||||
if (WARN_ON(!msi_page)) {
|
||||
/*
|
||||
* We're called from a void callback, so the best we can do is
|
||||
* 'fail' by filling the message with obviously bogus values.
|
||||
* Since we got this far due to an IOMMU being present, it's
|
||||
* not like the existing address would have worked anyway...
|
||||
*/
|
||||
msg->address_hi = ~0U;
|
||||
msg->address_lo = ~0U;
|
||||
msg->data = ~0U;
|
||||
} else {
|
||||
msg->address_hi = upper_32_bits(msi_page->iova);
|
||||
msg->address_lo &= cookie_msi_granule(cookie) - 1;
|
||||
msg->address_lo += lower_32_bits(msi_page->iova);
|
||||
}
|
||||
msi_desc_set_iommu_cookie(desc, msi_page);
|
||||
|
||||
if (!msi_page)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iommu_dma_compose_msi_msg(struct msi_desc *desc,
|
||||
struct msi_msg *msg)
|
||||
{
|
||||
struct device *dev = msi_desc_to_dev(desc);
|
||||
const struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
|
||||
const struct iommu_dma_msi_page *msi_page;
|
||||
|
||||
msi_page = msi_desc_get_iommu_cookie(desc);
|
||||
|
||||
if (!domain || !domain->iova_cookie || WARN_ON(!msi_page))
|
||||
return;
|
||||
|
||||
msg->address_hi = upper_32_bits(msi_page->iova);
|
||||
msg->address_lo &= cookie_msi_granule(domain->iova_cookie) - 1;
|
||||
msg->address_lo += lower_32_bits(msi_page->iova);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ config IRQCHIP
|
||||
|
||||
config ARM_GIC
|
||||
bool
|
||||
select IRQ_DOMAIN
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||
@@ -33,7 +32,6 @@ config GIC_NON_BANKED
|
||||
|
||||
config ARM_GIC_V3
|
||||
bool
|
||||
select IRQ_DOMAIN
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select PARTITION_PERCPU
|
||||
@@ -59,7 +57,6 @@ config ARM_GIC_V3_ITS_FSL_MC
|
||||
|
||||
config ARM_NVIC
|
||||
bool
|
||||
select IRQ_DOMAIN
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select GENERIC_IRQ_CHIP
|
||||
|
||||
@@ -358,7 +355,6 @@ config STM32_EXTI
|
||||
config QCOM_IRQ_COMBINER
|
||||
bool "QCOM IRQ combiner support"
|
||||
depends on ARCH_QCOM && ACPI
|
||||
select IRQ_DOMAIN
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
Say yes here to add support for the IRQ combiner devices embedded
|
||||
@@ -375,7 +371,6 @@ config IRQ_UNIPHIER_AIDET
|
||||
config MESON_IRQ_GPIO
|
||||
bool "Meson GPIO Interrupt Multiplexer"
|
||||
depends on ARCH_MESON
|
||||
select IRQ_DOMAIN
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
Support Meson SoC Family GPIO Interrupt Multiplexer
|
||||
@@ -391,7 +386,6 @@ config GOLDFISH_PIC
|
||||
config QCOM_PDC
|
||||
bool "QCOM PDC"
|
||||
depends on ARCH_QCOM
|
||||
select IRQ_DOMAIN
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
Power Domain Controller driver to manage and configure wakeup
|
||||
@@ -431,6 +425,27 @@ config LS1X_IRQ
|
||||
help
|
||||
Support for the Loongson-1 platform Interrupt Controller.
|
||||
|
||||
config TI_SCI_INTR_IRQCHIP
|
||||
bool
|
||||
depends on TI_SCI_PROTOCOL
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
This enables the irqchip driver support for K3 Interrupt router
|
||||
over TI System Control Interface available on some new TI's SoCs.
|
||||
If you wish to use interrupt router irq resources managed by the
|
||||
TI System Controller, say Y here. Otherwise, say N.
|
||||
|
||||
config TI_SCI_INTA_IRQCHIP
|
||||
bool
|
||||
depends on TI_SCI_PROTOCOL
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select TI_SCI_INTA_MSI_DOMAIN
|
||||
help
|
||||
This enables the irqchip driver support for K3 Interrupt aggregator
|
||||
over TI System Control Interface available on some new TI's SoCs.
|
||||
If you wish to use interrupt aggregator irq resources managed by the
|
||||
TI System Controller, say Y here. Otherwise, say N.
|
||||
|
||||
endmenu
|
||||
|
||||
config SIFIVE_PLIC
|
||||
|
||||
@@ -98,3 +98,5 @@ obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o
|
||||
obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
|
||||
obj-$(CONFIG_MADERA_IRQ) += irq-madera.o
|
||||
obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
|
||||
obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
|
||||
obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
|
||||
|
||||
@@ -343,6 +343,9 @@ int __init bcm7038_l1_of_init(struct device_node *dn,
|
||||
goto out_unmap;
|
||||
}
|
||||
|
||||
pr_info("registered BCM7038 L1 intc (%pOF, IRQs: %d)\n",
|
||||
dn, IRQS_PER_WORD * intc->n_words);
|
||||
|
||||
return 0;
|
||||
|
||||
out_unmap:
|
||||
|
||||
@@ -318,6 +318,9 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn,
|
||||
}
|
||||
}
|
||||
|
||||
pr_info("registered %s intc (%pOF, parent IRQ(s): %d)\n",
|
||||
intc_name, dn, data->num_parent_irqs);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_domain:
|
||||
|
||||
@@ -264,6 +264,8 @@ static int __init brcmstb_l2_intc_of_init(struct device_node *np,
|
||||
ct->chip.irq_set_wake = irq_gc_set_wake;
|
||||
}
|
||||
|
||||
pr_info("registered L2 intc (%pOF, parent irq: %d)\n", np, parent_irq);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_domain:
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_clock.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -28,17 +27,27 @@ struct gic_clk_data {
|
||||
const char *const *clocks;
|
||||
};
|
||||
|
||||
struct gic_chip_pm {
|
||||
struct gic_chip_data *chip_data;
|
||||
const struct gic_clk_data *clk_data;
|
||||
struct clk_bulk_data *clks;
|
||||
};
|
||||
|
||||
static int gic_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct gic_chip_data *gic = dev_get_drvdata(dev);
|
||||
struct gic_chip_pm *chip_pm = dev_get_drvdata(dev);
|
||||
struct gic_chip_data *gic = chip_pm->chip_data;
|
||||
const struct gic_clk_data *data = chip_pm->clk_data;
|
||||
int ret;
|
||||
|
||||
ret = pm_clk_resume(dev);
|
||||
if (ret)
|
||||
ret = clk_bulk_prepare_enable(data->num_clocks, chip_pm->clks);
|
||||
if (ret) {
|
||||
dev_err(dev, "clk_enable failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* On the very first resume, the pointer to the driver data
|
||||
* On the very first resume, the pointer to chip_pm->chip_data
|
||||
* will be NULL and this is intentional, because we do not
|
||||
* want to restore the GIC on the very first resume. So if
|
||||
* the pointer is not valid just return.
|
||||
@@ -54,35 +63,14 @@ static int gic_runtime_resume(struct device *dev)
|
||||
|
||||
static int gic_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct gic_chip_data *gic = dev_get_drvdata(dev);
|
||||
struct gic_chip_pm *chip_pm = dev_get_drvdata(dev);
|
||||
struct gic_chip_data *gic = chip_pm->chip_data;
|
||||
const struct gic_clk_data *data = chip_pm->clk_data;
|
||||
|
||||
gic_dist_save(gic);
|
||||
gic_cpu_save(gic);
|
||||
|
||||
return pm_clk_suspend(dev);
|
||||
}
|
||||
|
||||
static int gic_get_clocks(struct device *dev, const struct gic_clk_data *data)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (!dev || !data)
|
||||
return -EINVAL;
|
||||
|
||||
ret = pm_clk_create(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < data->num_clocks; i++) {
|
||||
ret = of_pm_clk_add_clk(dev, data->clocks[i]);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add clock %s\n",
|
||||
data->clocks[i]);
|
||||
pm_clk_destroy(dev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
clk_bulk_disable_unprepare(data->num_clocks, chip_pm->clks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -91,8 +79,8 @@ static int gic_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct gic_clk_data *data;
|
||||
struct gic_chip_data *gic;
|
||||
int ret, irq;
|
||||
struct gic_chip_pm *chip_pm;
|
||||
int ret, irq, i;
|
||||
|
||||
data = of_device_get_match_data(&pdev->dev);
|
||||
if (!data) {
|
||||
@@ -100,28 +88,41 @@ static int gic_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chip_pm = devm_kzalloc(dev, sizeof(*chip_pm), GFP_KERNEL);
|
||||
if (!chip_pm)
|
||||
return -ENOMEM;
|
||||
|
||||
irq = irq_of_parse_and_map(dev->of_node, 0);
|
||||
if (!irq) {
|
||||
dev_err(dev, "no parent interrupt found!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = gic_get_clocks(dev, data);
|
||||
chip_pm->clks = devm_kcalloc(dev, data->num_clocks,
|
||||
sizeof(*chip_pm->clks), GFP_KERNEL);
|
||||
if (!chip_pm->clks)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < data->num_clocks; i++)
|
||||
chip_pm->clks[i].id = data->clocks[i];
|
||||
|
||||
ret = devm_clk_bulk_get(dev, data->num_clocks, chip_pm->clks);
|
||||
if (ret)
|
||||
goto irq_dispose;
|
||||
|
||||
chip_pm->clk_data = data;
|
||||
dev_set_drvdata(dev, chip_pm);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0)
|
||||
goto rpm_disable;
|
||||
|
||||
ret = gic_of_init_child(dev, &gic, irq);
|
||||
ret = gic_of_init_child(dev, &chip_pm->chip_data, irq);
|
||||
if (ret)
|
||||
goto rpm_put;
|
||||
|
||||
platform_set_drvdata(pdev, gic);
|
||||
|
||||
pm_runtime_put(dev);
|
||||
|
||||
dev_info(dev, "GIC IRQ controller registered\n");
|
||||
@@ -132,7 +133,6 @@ rpm_put:
|
||||
pm_runtime_put_sync(dev);
|
||||
rpm_disable:
|
||||
pm_runtime_disable(dev);
|
||||
pm_clk_destroy(dev);
|
||||
irq_dispose:
|
||||
irq_dispose_mapping(irq);
|
||||
|
||||
@@ -142,6 +142,8 @@ irq_dispose:
|
||||
static const struct dev_pm_ops gic_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(gic_runtime_suspend,
|
||||
gic_runtime_resume, NULL)
|
||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
static const char * const gic400_clocks[] = {
|
||||
|
||||
@@ -110,7 +110,7 @@ static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET)
|
||||
msg->data -= v2m->spi_offset;
|
||||
|
||||
iommu_dma_map_msi_msg(data->irq, msg);
|
||||
iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg);
|
||||
}
|
||||
|
||||
static struct irq_chip gicv2m_irq_chip = {
|
||||
@@ -167,6 +167,7 @@ static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq,
|
||||
static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs, void *args)
|
||||
{
|
||||
msi_alloc_info_t *info = args;
|
||||
struct v2m_data *v2m = NULL, *tmp;
|
||||
int hwirq, offset, i, err = 0;
|
||||
|
||||
@@ -186,6 +187,11 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
|
||||
hwirq = v2m->spi_start + offset;
|
||||
|
||||
err = iommu_dma_prepare_msi(info->desc,
|
||||
v2m->res.start + V2M_MSI_SETSPI_NS);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
err = gicv2m_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
|
||||
if (err)
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/list_sort.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/mm.h>
|
||||
@@ -1179,7 +1178,7 @@ static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
|
||||
msg->address_hi = upper_32_bits(addr);
|
||||
msg->data = its_get_event_id(d);
|
||||
|
||||
iommu_dma_map_msi_msg(d->irq, msg);
|
||||
iommu_dma_compose_msi_msg(irq_data_get_msi_desc(d), msg);
|
||||
}
|
||||
|
||||
static int its_irq_set_irqchip_state(struct irq_data *d,
|
||||
@@ -1465,9 +1464,8 @@ static struct lpi_range *mk_lpi_range(u32 base, u32 span)
|
||||
{
|
||||
struct lpi_range *range;
|
||||
|
||||
range = kzalloc(sizeof(*range), GFP_KERNEL);
|
||||
range = kmalloc(sizeof(*range), GFP_KERNEL);
|
||||
if (range) {
|
||||
INIT_LIST_HEAD(&range->entry);
|
||||
range->base_id = base;
|
||||
range->span = span;
|
||||
}
|
||||
@@ -1475,31 +1473,6 @@ static struct lpi_range *mk_lpi_range(u32 base, u32 span)
|
||||
return range;
|
||||
}
|
||||
|
||||
static int lpi_range_cmp(void *priv, struct list_head *a, struct list_head *b)
|
||||
{
|
||||
struct lpi_range *ra, *rb;
|
||||
|
||||
ra = container_of(a, struct lpi_range, entry);
|
||||
rb = container_of(b, struct lpi_range, entry);
|
||||
|
||||
return ra->base_id - rb->base_id;
|
||||
}
|
||||
|
||||
static void merge_lpi_ranges(void)
|
||||
{
|
||||
struct lpi_range *range, *tmp;
|
||||
|
||||
list_for_each_entry_safe(range, tmp, &lpi_range_list, entry) {
|
||||
if (!list_is_last(&range->entry, &lpi_range_list) &&
|
||||
(tmp->base_id == (range->base_id + range->span))) {
|
||||
tmp->base_id = range->base_id;
|
||||
tmp->span += range->span;
|
||||
list_del(&range->entry);
|
||||
kfree(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int alloc_lpi_range(u32 nr_lpis, u32 *base)
|
||||
{
|
||||
struct lpi_range *range, *tmp;
|
||||
@@ -1529,25 +1502,49 @@ static int alloc_lpi_range(u32 nr_lpis, u32 *base)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void merge_lpi_ranges(struct lpi_range *a, struct lpi_range *b)
|
||||
{
|
||||
if (&a->entry == &lpi_range_list || &b->entry == &lpi_range_list)
|
||||
return;
|
||||
if (a->base_id + a->span != b->base_id)
|
||||
return;
|
||||
b->base_id = a->base_id;
|
||||
b->span += a->span;
|
||||
list_del(&a->entry);
|
||||
kfree(a);
|
||||
}
|
||||
|
||||
static int free_lpi_range(u32 base, u32 nr_lpis)
|
||||
{
|
||||
struct lpi_range *new;
|
||||
int err = 0;
|
||||
struct lpi_range *new, *old;
|
||||
|
||||
new = mk_lpi_range(base, nr_lpis);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&lpi_range_lock);
|
||||
|
||||
new = mk_lpi_range(base, nr_lpis);
|
||||
if (!new) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
list_for_each_entry_reverse(old, &lpi_range_list, entry) {
|
||||
if (old->base_id < base)
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* old is the last element with ->base_id smaller than base,
|
||||
* so new goes right after it. If there are no elements with
|
||||
* ->base_id smaller than base, &old->entry ends up pointing
|
||||
* at the head of the list, and inserting new it the start of
|
||||
* the list is the right thing to do in that case as well.
|
||||
*/
|
||||
list_add(&new->entry, &old->entry);
|
||||
/*
|
||||
* Now check if we can merge with the preceding and/or
|
||||
* following ranges.
|
||||
*/
|
||||
merge_lpi_ranges(old, new);
|
||||
merge_lpi_ranges(new, list_next_entry(new, entry));
|
||||
|
||||
list_add(&new->entry, &lpi_range_list);
|
||||
list_sort(NULL, &lpi_range_list, lpi_range_cmp);
|
||||
merge_lpi_ranges();
|
||||
out:
|
||||
mutex_unlock(&lpi_range_lock);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init its_lpi_init(u32 id_bits)
|
||||
@@ -2487,7 +2484,7 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* We ignore "dev" entierely, and rely on the dev_id that has
|
||||
* We ignore "dev" entirely, and rely on the dev_id that has
|
||||
* been passed via the scratchpad. This limits this domain's
|
||||
* usefulness to upper layers that definitely know that they
|
||||
* are built on top of the ITS.
|
||||
@@ -2566,6 +2563,7 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
{
|
||||
msi_alloc_info_t *info = args;
|
||||
struct its_device *its_dev = info->scratchpad[0].ptr;
|
||||
struct its_node *its = its_dev->its;
|
||||
irq_hw_number_t hwirq;
|
||||
int err;
|
||||
int i;
|
||||
@@ -2574,6 +2572,10 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = iommu_dma_prepare_msi(info->desc, its->get_msi_base(its_dev));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
err = its_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
|
||||
if (err)
|
||||
|
||||
@@ -84,6 +84,7 @@ static void mbi_free_msi(struct mbi_range *mbi, unsigned int hwirq,
|
||||
static int mbi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs, void *args)
|
||||
{
|
||||
msi_alloc_info_t *info = args;
|
||||
struct mbi_range *mbi = NULL;
|
||||
int hwirq, offset, i, err = 0;
|
||||
|
||||
@@ -104,6 +105,11 @@ static int mbi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
|
||||
hwirq = mbi->spi_start + offset;
|
||||
|
||||
err = iommu_dma_prepare_msi(info->desc,
|
||||
mbi_phys_base + GICD_SETSPI_NSR);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
err = mbi_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
|
||||
if (err)
|
||||
@@ -142,7 +148,7 @@ static void mbi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
msg[0].address_lo = lower_32_bits(mbi_phys_base + GICD_SETSPI_NSR);
|
||||
msg[0].data = data->parent_data->hwirq;
|
||||
|
||||
iommu_dma_map_msi_msg(data->irq, msg);
|
||||
iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
@@ -202,7 +208,7 @@ static void mbi_compose_mbi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
msg[1].address_lo = lower_32_bits(mbi_phys_base + GICD_CLRSPI_NSR);
|
||||
msg[1].data = data->parent_data->hwirq;
|
||||
|
||||
iommu_dma_map_msi_msg(data->irq, &msg[1]);
|
||||
iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), &msg[1]);
|
||||
}
|
||||
|
||||
/* Platform-MSI specific irqchip */
|
||||
|
||||
@@ -144,7 +144,6 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct irqsteer_data *data;
|
||||
struct resource *res;
|
||||
u32 irqs_num;
|
||||
int i, ret;
|
||||
|
||||
@@ -152,8 +151,7 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
data->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
data->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(data->regs)) {
|
||||
dev_err(&pdev->dev, "failed to initialize reg\n");
|
||||
return PTR_ERR(data->regs);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user