drivers: ethernet: imx_netc: add GIC MSI support

It could use GIC ITS as MSI controller on Cortex-A Core, so added
GIC ITS MSI support for NETC drivers.

Signed-off-by: Jiafei Pan <Jiafei.Pan@nxp.com>
This commit is contained in:
Jiafei Pan 2025-05-22 17:13:15 +08:00 committed by Fabio Baltieri
parent bd432c2727
commit 30b6adf42d
6 changed files with 128 additions and 2 deletions

View File

@ -12,11 +12,25 @@ menuconfig ETH_NXP_IMX_NETC
if ETH_NXP_IMX_NETC
DT_GIC_ITS_COMPAT := arm,gic-v3-its
DT_NETC_PATH := $(dt_nodelabel_path,netc)
DT_NETC_INT_PARENT_PATH := $(dt_node_ph_prop_path,$(DT_NETC_PATH),msi-parent)
DT_NETC_INT_IS_GIC := $(dt_node_has_compat,$(DT_NETC_INT_PARENT_PATH),$(DT_GIC_ITS_COMPAT))
config ETH_NXP_IMX_NETC_MSI_GIC
bool
default y if ($(DT_NETC_INT_IS_GIC) && DT_HAS_ARM_GIC_V3_ITS_ENABLED)
depends on GIC_V3_ITS
help
Use GIC ITS controller as MSI module for NXP NETC
if !ETH_NXP_IMX_NETC_MSI_GIC
config ETH_NXP_IMX_MSGINTR
int "Message Interrupt module select"
default 1
help
Message Interrupt module select.
endif
config ETH_NXP_IMX_RX_THREAD_PRIO
int "RX thread priority"

View File

@ -21,6 +21,9 @@ LOG_MODULE_REGISTER(nxp_imx_eth);
#include <zephyr/net/phy.h>
#include <ethernet/eth_stats.h>
#include <zephyr/net/dsa_core.h>
#ifdef CONFIG_GIC_V3_ITS
#include <zephyr/drivers/interrupt_controller/gicv3_its.h>
#endif
#include "../eth.h"
#include "eth_nxp_imx_netc_priv.h"
@ -173,6 +176,28 @@ static void netc_eth_rx_thread(void *arg1, void *unused1, void *unused2)
}
}
#ifdef CONFIG_ETH_NXP_IMX_NETC_MSI_GIC
static void netc_tx_isr_handler(const void *arg)
{
const struct device *dev = (const struct device *)arg;
struct netc_eth_data *data = dev->data;
EP_CleanTxIntrFlags(&data->handle, 1, 0);
data->tx_done = true;
}
static void netc_rx_isr_handler(const void *arg)
{
const struct device *dev = (const struct device *)arg;
struct netc_eth_data *data = dev->data;
EP_CleanRxIntrFlags(&data->handle, 1);
k_sem_give(&data->rx_sem);
}
#else /* CONFIG_ETH_NXP_IMX_NETC_MSI_GIC */
static void msgintr_isr(void)
{
uint32_t irqs = NETC_MSGINTR->MSI[NETC_MSGINTR_CHANNEL].MSIR;
@ -203,6 +228,8 @@ static void msgintr_isr(void)
SDK_ISR_EXIT_BARRIER;
}
#endif
int netc_eth_init_common(const struct device *dev)
{
const struct netc_eth_config *config = dev->config;
@ -222,6 +249,51 @@ int netc_eth_init_common(const struct device *dev)
#endif
/* MSIX entry configuration */
#ifdef CONFIG_ETH_NXP_IMX_NETC_MSI_GIC
int ret;
if (config->msi_dev == NULL) {
LOG_ERR("MSI device is not configured");
return -ENODEV;
}
ret = its_setup_deviceid(config->msi_dev, config->msi_device_id, NETC_MSIX_ENTRY_NUM);
if (ret != 0) {
LOG_ERR("Failed to setup device ID for MSI: %d", ret);
return ret;
}
data->tx_intid = its_alloc_intid(config->msi_dev);
data->rx_intid = its_alloc_intid(config->msi_dev);
msg_addr = its_get_msi_addr(config->msi_dev);
msix_entry[NETC_TX_MSIX_ENTRY_IDX].control = kNETC_MsixIntrMaskBit;
msix_entry[NETC_TX_MSIX_ENTRY_IDX].msgAddr = msg_addr;
msix_entry[NETC_TX_MSIX_ENTRY_IDX].msgData = NETC_TX_MSIX_ENTRY_IDX;
ret = its_map_intid(config->msi_dev, config->msi_device_id, NETC_TX_MSIX_ENTRY_IDX,
data->tx_intid);
if (ret != 0) {
LOG_ERR("Failed to map TX MSI interrupt: %d", ret);
return ret;
}
msix_entry[NETC_RX_MSIX_ENTRY_IDX].control = kNETC_MsixIntrMaskBit;
msix_entry[NETC_RX_MSIX_ENTRY_IDX].msgAddr = msg_addr;
msix_entry[NETC_RX_MSIX_ENTRY_IDX].msgData = NETC_RX_MSIX_ENTRY_IDX;
ret = its_map_intid(config->msi_dev, config->msi_device_id, NETC_RX_MSIX_ENTRY_IDX,
data->rx_intid);
if (ret != 0) {
LOG_ERR("Failed to map RX MSI interrupt: %d", ret);
return ret;
}
if (!irq_is_enabled(data->tx_intid)) {
irq_connect_dynamic(data->tx_intid, 0, netc_tx_isr_handler, dev, 0);
irq_enable(data->tx_intid);
}
if (!irq_is_enabled(data->rx_intid)) {
irq_connect_dynamic(data->rx_intid, 0, netc_rx_isr_handler, dev, 0);
irq_enable(data->rx_intid);
}
#else
msg_addr = MSGINTR_GetIntrSelectAddr(NETC_MSGINTR, NETC_MSGINTR_CHANNEL);
msix_entry[NETC_TX_MSIX_ENTRY_IDX].control = kNETC_MsixIntrMaskBit;
msix_entry[NETC_TX_MSIX_ENTRY_IDX].msgAddr = msg_addr;
@ -235,6 +307,7 @@ int netc_eth_init_common(const struct device *dev)
IRQ_CONNECT(NETC_MSGINTR_IRQ, 0, msgintr_isr, 0, 0);
irq_enable(NETC_MSGINTR_IRQ);
}
#endif
/* Endpoint configuration. */
EP_GetDefaultConfig(&ep_config);

View File

@ -9,7 +9,9 @@
#include "nxp_imx_netc.h"
#include "fsl_netc_endpoint.h"
#ifndef CONFIG_ETH_NXP_IMX_NETC_MSI_GIC
#include "fsl_msgintr.h"
#endif
/* Buffer and descriptor alignment */
#define NETC_BUFF_ALIGN 64
@ -33,6 +35,7 @@
#define NETC_MSGINTR_IRQ DT_IRQN_BY_IDX(DT_NODELABEL(netc), 0)
#endif
#ifndef CONFIG_ETH_NXP_IMX_NETC_MSI_GIC
#if (CONFIG_ETH_NXP_IMX_MSGINTR == 1)
#define NETC_MSGINTR MSGINTR1
#ifndef NETC_MSGINTR_IRQ
@ -46,6 +49,7 @@
#else
#error "Current CONFIG_ETH_NXP_IMX_MSGINTR not support"
#endif
#endif /* CONFIG_ETH_NXP_IMX_NETC_MSI_GIC */
/* Timeout for various operations */
#define NETC_TIMEOUT K_MSEC(20)
@ -90,8 +94,13 @@ struct netc_eth_config {
void (*bdr_init)(netc_bdr_config_t *bdr_config, netc_rx_bdr_config_t *rx_bdr_config,
netc_tx_bdr_config_t *tx_bdr_config);
const struct pinctrl_dev_config *pincfg;
#ifdef CONFIG_ETH_NXP_IMX_NETC_MSI_GIC
const struct device *msi_dev;
uint8_t msi_device_id; /* MSI device ID */
#else
uint8_t tx_intr_msg_data;
uint8_t rx_intr_msg_data;
#endif
#ifdef CONFIG_PTP_CLOCK_NXP_NETC
const struct device *ptp_clock;
#endif
@ -113,6 +122,10 @@ struct netc_eth_data {
K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ETH_NXP_IMX_RX_THREAD_STACK_SIZE);
uint8_t *rx_frame;
#ifdef CONFIG_ETH_NXP_IMX_NETC_MSI_GIC
unsigned int tx_intid;
unsigned int rx_intid;
#endif
};
int netc_eth_init_common(const struct device *dev);

View File

@ -200,8 +200,14 @@ static const struct ethernet_api netc_eth_api = {.iface_api.init = netc_eth_ifac
.pseudo_mac = DT_ENUM_HAS_VALUE(DT_DRV_INST(n), phy_connection_type, internal), \
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
.si_idx = (DT_INST_PROP(n, mac_index) << 8) | DT_INST_PROP(n, si_index), \
.tx_intr_msg_data = NETC_TX_INTR_MSG_DATA_START + n, \
.rx_intr_msg_data = NETC_RX_INTR_MSG_DATA_START + n, \
IF_ENABLED(CONFIG_ETH_NXP_IMX_NETC_MSI_GIC, \
(.msi_device_id = DT_INST_PROP_OR(n, msi_device_id, 0), \
.msi_dev = (COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_PARENT(n), msi_parent), \
(DEVICE_DT_GET(DT_PHANDLE(DT_INST_PARENT(n), msi_parent))), NULL)), \
)) \
IF_DISABLED(CONFIG_ETH_NXP_IMX_NETC_MSI_GIC, \
(.tx_intr_msg_data = NETC_TX_INTR_MSG_DATA_START + n, \
.rx_intr_msg_data = NETC_RX_INTR_MSG_DATA_START + n,)) \
IF_ENABLED(CONFIG_PTP_CLOCK_NXP_NETC, \
(.ptp_clock = DEVICE_DT_GET(DT_INST_PHANDLE(n, ptp_clock)),)) \
}; \

View File

@ -20,3 +20,7 @@ properties:
required: true
type: int
description: The SI index of this PSI.
msi-device-id:
type: int
description: The device ID passed to MSI controller.

View File

@ -0,0 +1,16 @@
# Copyright 2025 NXP
# SPDX-License-Identifier: Apache-2.0
description: NXP i.MX NETC Controller
compatible: "nxp,imx-netc"
include: [base.yaml]
properties:
reg:
required: true
msi-parent:
type: phandle
description: MSI controller