Skip to content
Permalink
Browse files

drivers/pcie: verify PCI(e) assigned interrupts

A new function pcie_irq_enable() is added to be used in lieu of
irq_enable() when the target device is PCI(e)-attached. The function
attempts to use MSI, when configured in the kernel and supported by
the endpoint; failing that, it will verify that IRQ requested is in
fact routed to the device by the boot firmware before enabling it.

The NS16550 UART driver is updated to use pcie_irq_enable().

The PCI(e) shell is extended to dump information about wired IRQs.

The up_squared devicetree is fixed (reverted?) to IRQ5 for UART1.

The galileo enables MSI by default.

Signed-off-by: Charles E. Youse <charles.youse@intel.com>
  • Loading branch information...
Charles E. Youse authored and nashif committed Apr 20, 2019
1 parent ff1952c commit 18833ac0efd119a8d794f00a8dd8f8b61c1d9433
@@ -2,6 +2,7 @@

CONFIG_X86=y
CONFIG_PCIE=y
CONFIG_PCIE_MSI=y
CONFIG_SOC_QUARK_X1000=y
CONFIG_SOC_SERIES_QUARK_X1000=y
CONFIG_BOARD_GALILEO=y
@@ -52,7 +52,7 @@

label = "UART_1";
clock-frequency = <1843200>;
interrupts = <3 IRQ_TYPE_LEVEL_LOW 3>;
interrupts = <5 IRQ_TYPE_LEVEL_LOW 3>;
interrupt-parent = <&intc>;

status = "ok";
@@ -4,9 +4,14 @@
* SPDX-License-Identifier: Apache-2.0
*/

#include <kernel.h>
#include <stdbool.h>
#include <drivers/pcie/pcie.h>

#if CONFIG_PCIE_MSI
#include <drivers/pcie/msi.h>
#endif

/* functions documented in drivers/pcie/pcie.h */

bool pcie_probe(pcie_bdf_t bdf, pcie_id_t id)
@@ -78,3 +83,21 @@ u32_t pcie_get_iobar(pcie_bdf_t bdf, unsigned int index)
{
return pcie_get_bar(bdf, index, true);
}

bool pcie_irq_enable(pcie_bdf_t bdf, unsigned int irq)
{
#if CONFIG_PCIE_MSI
if (pcie_set_msi(bdf, irq))
return true;
#endif

u32_t data;

data = pcie_conf_read(bdf, PCIE_CONF_INTR);
if (PCIE_CONF_INTR_IRQ(data) == irq) {
irq_enable(irq);
return true;
}

return false;
}
@@ -88,6 +88,12 @@ static void show(const struct shell *shell, pcie_bdf_t bdf)
shell_fprintf(shell, SHELL_NORMAL, "\n");
show_bars(shell, bdf);
show_msi(shell, bdf);
data = pcie_conf_read(bdf, PCIE_CONF_INTR);
if (PCIE_CONF_INTR_IRQ(data) != PCIE_CONF_INTR_IRQ_NONE) {
shell_fprintf(shell, SHELL_NORMAL,
" wired interrupt on IRQ %d\n",
PCIE_CONF_INTR_IRQ(data));
}
}
}

@@ -827,12 +827,16 @@ static void irq_config_func_0(struct device *dev)
DT_UART_NS16550_PORT_0_IRQ_PRI,
uart_ns16550_isr, DEVICE_GET(uart_ns16550_0),
DT_UART_NS16550_PORT_0_IRQ_FLAGS);
irq_enable(DT_UART_NS16550_PORT_0_IRQ);
#if defined(UART_NS16550_PCIE_ENABLED) && CONFIG_PCIE_MSI

#ifdef UART_NS16550_PCIE_ENABLED
if (DEV_CFG(dev)->pcie) {
pcie_set_msi(DT_UART_NS16550_PORT_0_BASE_ADDR,
DT_UART_NS16550_PORT_0_IRQ);
pcie_irq_enable(DT_UART_NS16550_PORT_0_BASE_ADDR,
DT_UART_NS16550_PORT_0_IRQ);
} else {
irq_enable(DT_UART_NS16550_PORT_0_IRQ);
}
#else
irq_enable(DT_UART_NS16550_PORT_0_IRQ);
#endif
}
#endif
@@ -887,12 +891,16 @@ static void irq_config_func_1(struct device *dev)
DT_UART_NS16550_PORT_1_IRQ_PRI,
uart_ns16550_isr, DEVICE_GET(uart_ns16550_1),
DT_UART_NS16550_PORT_1_IRQ_FLAGS);
irq_enable(DT_UART_NS16550_PORT_1_IRQ);
#if defined(UART_NS16550_PCIE_ENABLED) && CONFIG_PCIE_MSI

#ifdef UART_NS16550_PCIE_ENABLED
if (DEV_CFG(dev)->pcie) {
pcie_set_msi(DT_UART_NS16550_PORT_1_BASE_ADDR,
DT_UART_NS16550_PORT_1_IRQ);
pcie_irq_enable(DT_UART_NS16550_PORT_1_BASE_ADDR,
DT_UART_NS16550_PORT_1_IRQ);
} else {
irq_enable(DT_UART_NS16550_PORT_1_IRQ);
}
#else
irq_enable(DT_UART_NS16550_PORT_1_IRQ);
#endif
}
#endif
@@ -948,12 +956,15 @@ static void irq_config_func_2(struct device *dev)
uart_ns16550_isr, DEVICE_GET(uart_ns16550_2),
DT_UART_NS16550_PORT_2_IRQ_FLAGS);

irq_enable(DT_UART_NS16550_PORT_2_IRQ);
#if defined(UART_NS16550_PCIE_ENABLED) && CONFIG_PCIE_MSI
#ifdef UART_NS16550_PCIE_ENABLED
if (DEV_CFG(dev)->pcie) {
pcie_set_msi(DT_UART_NS16550_PORT_2_BASE_ADDR,
DT_UART_NS16550_PORT_2_IRQ);
pcie_irq_enable(DT_UART_NS16550_PORT_2_BASE_ADDR,
DT_UART_NS16550_PORT_2_IRQ);
} else {
irq_enable(DT_UART_NS16550_PORT_2_IRQ);
}
#else
irq_enable(DT_UART_NS16550_PORT_2_IRQ);
#endif
}
#endif
@@ -1008,12 +1019,16 @@ static void irq_config_func_3(struct device *dev)
DT_UART_NS16550_PORT_3_IRQ_PRI,
uart_ns16550_isr, DEVICE_GET(uart_ns16550_3),
DT_UART_NS16550_PORT_3_IRQ_FLAGS);
irq_enable(DT_UART_NS16550_PORT_3_IRQ);
#if defined(UART_NS16550_PCIE_ENABLED) && CONFIG_PCIE_MSI

#ifdef UART_NS16550_PCIE_ENABLED
if (DEV_CFG(dev)->pcie) {
pcie_set_msi(DT_UART_NS16550_PORT_3_BASE_ADDR,
DT_UART_NS16550_PORT_3_IRQ);
pcie_irq_enable(DT_UART_NS16550_PORT_3_BASE_ADDR,
DT_UART_NS16550_PORT_3_IRQ);
} else {
irq_enable(DT_UART_NS16550_PORT_3_IRQ);
}
#else
irq_enable(DT_UART_NS16550_PORT_3_IRQ);
#endif
}
#endif
@@ -103,6 +103,21 @@ extern u32_t pcie_get_iobar(pcie_bdf_t bdf, unsigned int index);
*/
extern void pcie_set_cmd(pcie_bdf_t bdf, u32_t bits, bool on);

/**
* @brief Enable the PCI(e) endpoint to generate the specified IRQ.
*
* @param bdf the PCI(e) endpoint
* @param irq the IRQ to generate
* @return true if successful, false otherwise
*
* If MSI is enabled and the endpoint supports it, the endpoint will
* be configured to generate the specified IRQ via MSI. Otherwise, the
* endpoint configuration space is queried to ensure that its wired
* IRQ has been routed by the boot firmware to the specified IRQ, and
* and the IRQ is enabled (at the I/O APIC, or wherever appropriate).
*/
extern bool pcie_irq_enable(pcie_bdf_t bdf, unsigned int irq);

/*
* Configuration word 0 aligns directly with pcie_id_t.
*/
@@ -161,6 +176,18 @@ extern void pcie_set_cmd(pcie_bdf_t bdf, u32_t bits, bool on);
#define PCIE_CONF_BAR_ADDR(w) ((w) & 0xFFFFFFF0U)
#define PCIE_CONF_BAR_NONE 0U

/*
* Word 15 contains information related to interrupts.
*
* We're only interested in the low byte, which is [supposed to be] set by
* the firmware to indicate which wire IRQ the device interrupt is routed to.
*/

#define PCIE_CONF_INTR 15U

#define PCIE_CONF_INTR_IRQ(w) ((w) & 0xFFU)
#define PCIE_CONF_INTR_IRQ_NONE 0xFFU /* no interrupt routed */

#ifdef __cplusplus
}
#endif

0 comments on commit 18833ac

Please sign in to comment.
You can’t perform that action at this time.