diff --git a/include/osi_common.h b/include/osi_common.h index 2d786c1..1667263 100644 --- a/include/osi_common.h +++ b/include/osi_common.h @@ -212,8 +212,8 @@ #define EQOS_MAX_MAC_ADDRESS_FILTER 128U #define EQOS_MAX_L3_L4_FILTER 8U #define EQOS_MAX_HTR_REGS 8U -#define OSI_EQOS_MAX_NUM_CHANS 4U -#define OSI_EQOS_MAX_NUM_QUEUES 4U +#define OSI_EQOS_MAX_NUM_CHANS 8U +#define OSI_EQOS_MAX_NUM_QUEUES 8U #define OSI_L2_FILTER_INDEX_ANY 127U #define OSI_CHAN_ANY 0xFFU @@ -238,6 +238,7 @@ #define OSI_MAC_HW_EQOS 0U #define OSI_ETH_ALEN 6U +#define OSI_MAX_VM_IRQS 5U #define BOOLEAN_FALSE (0U != 0U) #define OSI_NULL ((void *)0) diff --git a/include/osi_dma.h b/include/osi_dma.h index 6b7f78f..b4ddce7 100644 --- a/include/osi_dma.h +++ b/include/osi_dma.h @@ -320,7 +320,7 @@ struct osi_tx_ring { struct osi_dma_priv_data; /** - *@brief MAC DMA Channel operations + * @brief MAC DMA Channel operations */ struct osi_dma_chan_ops { /** Called to set Transmit Ring length */ @@ -365,6 +365,22 @@ struct osi_dma_chan_ops { unsigned int chan, unsigned int set, unsigned int interval); + /** Called to get Global DMA status */ + unsigned int (*get_global_dma_status)(void *addr); + /** Called to clear VM Tx interrupt */ + void (*clear_vm_tx_intr)(void *addr, unsigned int chan); + /** Called to clear VM Rx interrupt */ + void (*clear_vm_rx_intr)(void *addr, unsigned int chan); +}; + +/** + * @brief OSI VM IRQ data + */ +struct osi_vm_irq_data { + /** Number of VM channels per VM IRQ */ + unsigned int num_vm_chans; + /** Array of VM channel list */ + unsigned int vm_chans[OSI_EQOS_MAX_NUM_CHANS]; }; /** @@ -420,6 +436,10 @@ struct osi_dma_priv_data { unsigned int slot_interval[OSI_EQOS_MAX_NUM_CHANS]; /** Array of DMA channel slot enabled status from DT*/ unsigned int slot_enabled[OSI_EQOS_MAX_NUM_CHANS]; + /** number of VM IRQ's */ + unsigned int num_vm_irqs; + /** Array of VM IRQ's */ + struct osi_vm_irq_data irq_data[OSI_MAX_VM_IRQS]; }; /** @@ -522,6 +542,44 @@ int osi_disable_chan_rx_intr(struct osi_dma_priv_data *osi_dma, int osi_enable_chan_rx_intr(struct osi_dma_priv_data *osi_dma, unsigned int chan); +/** + * @brief osi_clear_vm_tx_intr - Handles VM Tx interrupt source. + * + * Algorithm: Clear Tx interrupt source at wrapper level and DMA level. + * + * @param[in] osi_dma: DMA private data. + * @param[in] chan: DMA tx channel number. + * + * @note + * 1) MAC needs to be out of reset and proper clocks need to be configured. + * 2) DMA HW init need to be completed successfully, see osi_hw_dma_init + * + * @retval 0 on success + * @retval -1 on failure. + */ +int osi_clear_vm_tx_intr(struct osi_dma_priv_data *osi_dma, + unsigned int chan); + +/** + * @brief osi_clear_vm_rx_intr - Handles VM Rx interrupt source. + * + * Algorithm: Clear Rx interrupt source at wrapper level and DMA level. + * + * @param[in] osi_dma: DMA private data. + * @param[in] chan: DMA rx channel number. + * + * @note + * 1) MAC needs to be out of reset and proper clocks need to be configured. + * 2) DMA HW init need to be completed successfully, see osi_hw_dma_init + * 3) Mapping of physical IRQ line to DMA channel need to be maintained at + * OS Dependent layer and pass corresponding channel number. + * + * @retval 0 on success + * @retval -1 on failure. + */ +int osi_clear_vm_rx_intr(struct osi_dma_priv_data *osi_dma, + unsigned int chan); + /** * @brief Start DMA * @@ -817,4 +875,19 @@ int osi_clear_rx_pkt_err_stats(struct osi_dma_priv_data *osi_dma); * @retval 0 if ring has outstanding packets. */ int osi_txring_empty(struct osi_dma_priv_data *osi_dma, unsigned int chan); + +/** + * @brief osi_get_global_dma_status - Gets DMA status. + * + * Algorithm: Returns global DMA Tx/Rx interrupt status + * + * @param[in] osi_dma: OSI DMA private data structure. + * + * @note + * Dependencies: None. + * Protection: None. + * + * @retval status + */ +unsigned int osi_get_global_dma_status(struct osi_dma_priv_data *osi_dma); #endif /* OSI_DMA_H */ diff --git a/osi/core/eqos_core.c b/osi/core/eqos_core.c index 9998480..97e5288 100644 --- a/osi/core/eqos_core.c +++ b/osi/core/eqos_core.c @@ -1511,10 +1511,17 @@ static int eqos_core_init(struct osi_core_priv_data *const osi_core, osi_writel(EQOS_MMC_CNTRL_CNTRST, (unsigned char *)osi_core->base + EQOS_MMC_CNTRL); - /* AXI ASID CTRL */ + /* AXI ASID CTRL for channel 0 to 3 */ osi_writel(EQOS_AXI_ASID_CTRL_VAL, (unsigned char *)osi_core->base + EQOS_AXI_ASID_CTRL); + /* AXI ASID1 CTRL for channel 4 to 7 */ + if (osi_core->mac_ver > OSI_EQOS_MAC_5_00) { + osi_writel(EQOS_AXI_ASID1_CTRL_VAL, + (unsigned char *)osi_core->base + + EQOS_AXI_ASID1_CTRL); + } + /* Mapping MTL Rx queue and DMA Rx channel */ /* TODO: Need to add EQOS_MTL_RXQ_DMA_MAP1 for EQOS */ value = osi_readl((unsigned char *)osi_core->base + diff --git a/osi/core/eqos_core.h b/osi/core/eqos_core.h index 3e10492..168db02 100644 --- a/osi/core/eqos_core.h +++ b/osi/core/eqos_core.h @@ -165,6 +165,7 @@ */ #define EQOS_CLOCK_CTRL_0 0x8000U #define EQOS_AXI_ASID_CTRL 0x8400U +#define EQOS_AXI_ASID1_CTRL 0x8404U #define EQOS_PAD_CRTL 0x8800U #define EQOS_PAD_AUTO_CAL_CFG 0x8804U #define EQOS_PAD_AUTO_CAL_STAT 0x880CU @@ -393,18 +394,25 @@ #define EQOS_DMA_CHX_STATUS_RWT OSI_BIT(9) #define EQOS_DMA_CHX_STATUS_FBE OSI_BIT(10) -#define EQOS_AXI_ASID_CTRL_CH3_SHIFT 24 -#define EQOS_AXI_ASID_CTRL_CH2_SHIFT 16 -#define EQOS_AXI_ASID_CTRL_CH1_SHIFT 8 +#define EQOS_ASID_CTRL_SHIFT_24 24U +#define EQOS_ASID_CTRL_SHIFT_16 16U +#define EQOS_ASID_CTRL_SHIFT_8 8U #define TEGRA_SID_EQOS (unsigned int)20 -#define TEGRA_SID_EQOS_CH3 ((TEGRA_SID_EQOS) << EQOS_AXI_ASID_CTRL_CH3_SHIFT) -#define TEGRA_SID_EQOS_CH2 ((TEGRA_SID_EQOS) << EQOS_AXI_ASID_CTRL_CH2_SHIFT) -#define TEGRA_SID_EQOS_CH1 ((TEGRA_SID_EQOS) << EQOS_AXI_ASID_CTRL_CH1_SHIFT) +#define TEGRA_SID_EQOS_CH3 ((TEGRA_SID_EQOS) << EQOS_ASID_CTRL_SHIFT_24) +#define TEGRA_SID_EQOS_CH2 ((TEGRA_SID_EQOS) << EQOS_ASID_CTRL_SHIFT_16) +#define TEGRA_SID_EQOS_CH1 ((TEGRA_SID_EQOS) << EQOS_ASID_CTRL_SHIFT_8) #define EQOS_AXI_ASID_CTRL_VAL ((TEGRA_SID_EQOS_CH3) |\ (TEGRA_SID_EQOS_CH2) |\ (TEGRA_SID_EQOS_CH1) |\ (TEGRA_SID_EQOS)) +#define TEGRA_SID_EQOS_CH7 ((TEGRA_SID_EQOS) << EQOS_ASID_CTRL_SHIFT_24) +#define TEGRA_SID_EQOS_CH6 ((TEGRA_SID_EQOS) << EQOS_ASID_CTRL_SHIFT_16) +#define TEGRA_SID_EQOS_CH5 ((TEGRA_SID_EQOS) << EQOS_ASID_CTRL_SHIFT_8) +#define EQOS_AXI_ASID1_CTRL_VAL ((TEGRA_SID_EQOS_CH7) |\ + (TEGRA_SID_EQOS_CH6) |\ + (TEGRA_SID_EQOS_CH5) |\ + (TEGRA_SID_EQOS)) /** @} */ void update_ehfc_rfa_rfd(unsigned int rx_fifo, unsigned int *value); diff --git a/osi/dma/eqos_dma.c b/osi/dma/eqos_dma.c index 5abd4ba..5828646 100644 --- a/osi/dma/eqos_dma.c +++ b/osi/dma/eqos_dma.c @@ -689,6 +689,40 @@ static void eqos_configure_dma_channel(unsigned int chan, } } +/** + * @brief eqos_dma_chan_to_vmirq_map - Map DMA channels to a specific VM IRQ. + * + * @param[in] osi_dma: OSI private data structure. + * + * Algorithm: Programs HW to map DMA channels to specific VM. + * + * @note + * Dependencies: OSD layer needs to update number of VM channels and + * DMA channel list in osi_vm_irq_data. + * Protection: None. + * + * @retval None. + */ +static void eqos_dma_chan_to_vmirq_map(struct osi_dma_priv_data *osi_dma) +{ + struct osi_vm_irq_data *irq_data; + unsigned int i, j; + unsigned int chan; + + for (i = 0; i < osi_dma->num_vm_irqs; i++) { + irq_data = &osi_dma->irq_data[i]; + for (j = 0; j < irq_data->num_vm_chans; j++) { + chan = irq_data->vm_chans[j]; + if (chan >= OSI_EQOS_MAX_NUM_CHANS) { + continue; + } + osi_writel(OSI_BIT(i), + (unsigned char *)osi_dma->base + + EQOS_VIRT_INTR_APB_CHX_CNTRL(chan)); + } + } +} + /** * @brief eqos_init_dma_channel - DMA channel INIT * @@ -704,6 +738,8 @@ static void eqos_init_dma_channel(struct osi_dma_priv_data *osi_dma) for (chinx = 0; chinx < osi_dma->num_dma_chans; chinx++) { eqos_configure_dma_channel(osi_dma->dma_chans[chinx], osi_dma); } + + eqos_dma_chan_to_vmirq_map(osi_dma); } /** @@ -732,9 +768,70 @@ static void eqos_set_rx_buf_len(struct osi_dma_priv_data *osi_dma) } /** - * @brief eqos_dma_chan_ops - EQOS DMA operations + * @brief eqos_get_global_dma_status - Gets DMA status. * + * Algorithm: Returns global DMA Tx/Rx interrupt status + * + * @param[in] addr: MAC base address. + * + * @note + * Dependencies: None. + * Protection: None. + * + * @retval status */ +static unsigned int eqos_get_global_dma_status(void *addr) +{ + return osi_readl((unsigned char *)addr + EQOS_GLOBAL_DMA_STATUS); +} + +/** + * @brief eqos_clear_vm_tx_intr - Handle VM Tx interrupt + * + * @param[in] addr: MAC base address. + * @param[in] chan: DMA Tx channel number. + * + * Algorithm: Clear Tx interrupt source at DMA and wrapper level. + * + * @note + * Dependencies: None. + * Protection: None. + * @retval None. + */ +static void eqos_clear_vm_tx_intr(void *addr, unsigned int chan) +{ + CHECK_CHAN_BOUND(chan); + + osi_writel(EQOS_DMA_CHX_STATUS_CLEAR_TX, + (unsigned char *)addr + EQOS_DMA_CHX_STATUS(chan)); + osi_writel(EQOS_VIRT_INTR_CHX_STATUS_TX, + (unsigned char *)addr + EQOS_VIRT_INTR_CHX_STATUS(chan)); +} + +/** + * @brief eqos_clear_vm_rx_intr - Handle VM Rx interrupt + * + * @param[in] addr: MAC base address. + * @param[in] chan: DMA Rx channel number. + * + * Algorithm: Clear Rx interrupt source at DMA and wrapper level. + * + * @note + * Dependencies: None. + * Protection: None. + * + * @retval None. + */ +static void eqos_clear_vm_rx_intr(void *addr, unsigned int chan) +{ + CHECK_CHAN_BOUND(chan); + + osi_writel(EQOS_DMA_CHX_STATUS_CLEAR_RX, + (unsigned char *)addr + EQOS_DMA_CHX_STATUS(chan)); + osi_writel(EQOS_VIRT_INTR_CHX_STATUS_RX, + (unsigned char *)addr + EQOS_VIRT_INTR_CHX_STATUS(chan)); +} + static struct osi_dma_chan_ops eqos_dma_chan_ops = { .set_tx_ring_len = eqos_set_tx_ring_len, .set_rx_ring_len = eqos_set_rx_ring_len, @@ -752,6 +849,9 @@ static struct osi_dma_chan_ops eqos_dma_chan_ops = { .set_rx_buf_len = eqos_set_rx_buf_len, .validate_regs = eqos_validate_dma_regs, .config_slot = eqos_config_slot, + .get_global_dma_status = eqos_get_global_dma_status, + .clear_vm_tx_intr = eqos_clear_vm_tx_intr, + .clear_vm_rx_intr = eqos_clear_vm_rx_intr, }; /** diff --git a/osi/dma/eqos_dma.h b/osi/dma/eqos_dma.h index 3d8f50f..e528375 100644 --- a/osi/dma/eqos_dma.h +++ b/osi/dma/eqos_dma.h @@ -38,23 +38,25 @@ * @brief EQOS DMA Channel register offsets * @{ */ -#define EQOS_DMA_CHX_CTRL(x) ((0x0080U * (x)) + 0x1100U) -#define EQOS_DMA_CHX_TX_CTRL(x) ((0x0080U * (x)) + 0x1104U) -#define EQOS_DMA_CHX_RX_CTRL(x) ((0x0080U * (x)) + 0x1108U) -#define EQOS_DMA_CHX_INTR_ENA(x) ((0x0080U * (x)) + 0x1134U) -#define EQOS_DMA_CHX_RX_WDT(x) ((0x0080U * (x)) + 0x1138U) -#define EQOS_DMA_CHX_SLOT_CTRL(x) ((0x0080U * (x)) + 0x113CU) +#define EQOS_DMA_CHX_CTRL(x) ((0x0080U * (x)) + 0x1100U) +#define EQOS_DMA_CHX_TX_CTRL(x) ((0x0080U * (x)) + 0x1104U) +#define EQOS_DMA_CHX_RX_CTRL(x) ((0x0080U * (x)) + 0x1108U) +#define EQOS_DMA_CHX_INTR_ENA(x) ((0x0080U * (x)) + 0x1134U) +#define EQOS_DMA_CHX_RX_WDT(x) ((0x0080U * (x)) + 0x1138U) +#define EQOS_DMA_CHX_SLOT_CTRL(x) ((0x0080U * (x)) + 0x113CU) -#define EQOS_DMA_CHX_RDTP(x) ((0x0080U * (x)) + 0x1128U) -#define EQOS_DMA_CHX_RDLH(x) ((0x0080U * (x)) + 0x1118U) -#define EQOS_DMA_CHX_RDLA(x) ((0x0080U * (x)) + 0x111CU) -#define EQOS_DMA_CHX_RDRL(x) ((0x0080U * (x)) + 0x1130U) -#define EQOS_DMA_CHX_TDTP(x) ((0x0080U * (x)) + 0x1120U) -#define EQOS_DMA_CHX_TDLH(x) ((0x0080U * (x)) + 0x1110U) -#define EQOS_DMA_CHX_TDLA(x) ((0x0080U * (x)) + 0x1114U) -#define EQOS_DMA_CHX_TDRL(x) ((0x0080U * (x)) + 0x112CU) -#define EQOS_VIRT_INTR_CHX_STATUS(x) (0x8604U + ((x) * 8U)) -#define EQOS_VIRT_INTR_CHX_CNTRL(x) (0x8600U + ((x) * 8U)) +#define EQOS_DMA_CHX_RDTP(x) ((0x0080U * (x)) + 0x1128U) +#define EQOS_DMA_CHX_RDLH(x) ((0x0080U * (x)) + 0x1118U) +#define EQOS_DMA_CHX_RDLA(x) ((0x0080U * (x)) + 0x111CU) +#define EQOS_DMA_CHX_RDRL(x) ((0x0080U * (x)) + 0x1130U) +#define EQOS_DMA_CHX_TDTP(x) ((0x0080U * (x)) + 0x1120U) +#define EQOS_DMA_CHX_TDLH(x) ((0x0080U * (x)) + 0x1110U) +#define EQOS_DMA_CHX_TDLA(x) ((0x0080U * (x)) + 0x1114U) +#define EQOS_DMA_CHX_TDRL(x) ((0x0080U * (x)) + 0x112CU) +#define EQOS_VIRT_INTR_APB_CHX_CNTRL(x) (0x8200U + ((x) * 4U)) +#define EQOS_VIRT_INTR_CHX_STATUS(x) (0x8604U + ((x) * 8U)) +#define EQOS_VIRT_INTR_CHX_CNTRL(x) (0x8600U + ((x) * 8U)) +#define EQOS_GLOBAL_DMA_STATUS (0x8700U) /** @} */ /** @@ -63,11 +65,11 @@ * @brief Values defined for the DMA channel registers * @{ */ -#define EQOS_VIRT_INTR_CHX_STATUS_TX OSI_BIT(0) -#define EQOS_VIRT_INTR_CHX_STATUS_RX OSI_BIT(1) -#define EQOS_DMA_CHX_STATUS_TI OSI_BIT(0) -#define EQOS_DMA_CHX_STATUS_RI OSI_BIT(6) -#define EQOS_DMA_CHX_STATUS_NIS OSI_BIT(15) +#define EQOS_VIRT_INTR_CHX_STATUS_TX OSI_BIT(0) +#define EQOS_VIRT_INTR_CHX_STATUS_RX OSI_BIT(1) +#define EQOS_DMA_CHX_STATUS_TI OSI_BIT(0) +#define EQOS_DMA_CHX_STATUS_RI OSI_BIT(6) +#define EQOS_DMA_CHX_STATUS_NIS OSI_BIT(15) #define EQOS_DMA_CHX_STATUS_CLEAR_TX \ (EQOS_DMA_CHX_STATUS_TI | EQOS_DMA_CHX_STATUS_NIS) #define EQOS_DMA_CHX_STATUS_CLEAR_RX \ diff --git a/osi/dma/osi_dma.c b/osi/dma/osi_dma.c index c66ca3a..4fea528 100644 --- a/osi/dma/osi_dma.c +++ b/osi/dma/osi_dma.c @@ -146,6 +146,40 @@ int osi_enable_chan_rx_intr(struct osi_dma_priv_data *osi_dma, return -1; } +int osi_clear_vm_tx_intr(struct osi_dma_priv_data *osi_dma, + unsigned int chan) +{ + if ((osi_dma != OSI_NULL) && (osi_dma->ops != OSI_NULL) && + (osi_dma->ops->clear_vm_tx_intr != OSI_NULL)) { + osi_dma->ops->clear_vm_tx_intr(osi_dma->base, chan); + return 0; + } + + return -1; +} + +int osi_clear_vm_rx_intr(struct osi_dma_priv_data *osi_dma, + unsigned int chan) +{ + if ((osi_dma != OSI_NULL) && (osi_dma->ops != OSI_NULL) && + (osi_dma->ops->clear_vm_rx_intr != OSI_NULL)) { + osi_dma->ops->clear_vm_rx_intr(osi_dma->base, chan); + return 0; + } + + return -1; +} + +unsigned int osi_get_global_dma_status(struct osi_dma_priv_data *osi_dma) +{ + if ((osi_dma != OSI_NULL) && (osi_dma->ops != OSI_NULL) && + (osi_dma->ops->get_global_dma_status != OSI_NULL)) { + return osi_dma->ops->get_global_dma_status(osi_dma->base); + } + + return 0; +} + int osi_start_dma(struct osi_dma_priv_data *osi_dma, unsigned int chan) {