nvethernetrm: mgbe: Add XDCS support

Enable multiple DMA Channels routing support
for MC/BC MAC Address with XDCS.

Bug 200565911

Change-Id: I7c9f9347361dd72e68696846a0a59e2e241e20c9
Signed-off-by: Mohan Thadikamalla <mohant@nvidia.com>
This commit is contained in:
Mohan Thadikamalla
2020-04-13 18:56:09 +05:30
committed by Bhadram Varka
parent b5a12c85e6
commit 57847505ed
3 changed files with 321 additions and 72 deletions

View File

@@ -274,6 +274,8 @@ struct osi_filter {
nveu32_t addr_mask;
/** src_dest: SA(1) or DA(0) */
nveu32_t src_dest;
/** indicates one hot encoded DMA receive channels to program */
nveu32_t dma_chansel;
};
/**
@@ -1000,6 +1002,8 @@ struct osi_core_priv_data {
unsigned int fpe_ready;
/** TSN stats counters */
struct osi_tsn_stats tsn_stats;
/** MC packets Multiple DMA channel selection flags */
nveu32_t mc_dmasel;
};
/**

View File

@@ -212,6 +212,157 @@ static nveu32_t mgbe_calculate_per_queue_fifo(nveu32_t fifo_size,
return p_fifo;
}
/**
* @brief mgbe_poll_for_mac_accrtl - Poll for Indirect Access control and status
* register operations complete.
*
* Algorithm: Waits for waits for transfer busy bit to be cleared in
* MAC Indirect address control register to complete operations.
*
* @param[in] addr: MGBE virtual base address.
*
* @note MAC needs to be out of reset and proper clock configured.
*
* @retval 0 on success
* @retval -1 on failure.
*/
static int mgbe_poll_for_mac_acrtl(struct osi_core_priv_data *osi_core)
{
nveu32_t count = 0U;
nveu32_t mac_indir_addr_ctrl = 0U;
/* Poll Until MAC_Indir_Access_Ctrl OB is clear */
while (count < MGBE_MAC_INDIR_AC_OB_RETRY) {
mac_indir_addr_ctrl = osi_readl((nveu8_t *)osi_core->base +
MGBE_MAC_INDIR_AC);
if ((mac_indir_addr_ctrl & MGBE_MAC_INDIR_AC_OB) == OSI_NONE) {
/* OB is clear exit the loop */
return 0;
}
/* wait for 10 usec for OB clear and retry */
osi_core->osd_ops.udelay(MGBE_MAC_INDIR_AC_OB_WAIT);
count++;
}
return -1;
}
/**
* @brief mgbe_mac_indir_addr_write - MAC Indirect AC register write.
*
* Algorithm: writes MAC Indirect AC register
*
* @param[in] base: MGBE virtual base address.
* @param[in] mc_no: MAC AC Mode Select number
* @param[in] addr_offset: MAC AC Address Offset.
* @param[in] value: MAC AC register value
*
* @note MAC needs to be out of reset and proper clock configured.
*
* @retval 0 on success
* @retval -1 on failure.
*/
static int mgbe_mac_indir_addr_write(struct osi_core_priv_data *osi_core,
nveu32_t mc_no,
nveu32_t addr_offset,
nveu32_t value)
{
void *base = osi_core->base;
nveu32_t addr = 0;
/* Write MAC_Indir_Access_Data register value */
osi_writel(value, (nveu8_t *)base + MGBE_MAC_INDIR_DATA);
/* Program MAC_Indir_Access_Ctrl */
addr = osi_readl((nveu8_t *)base + MGBE_MAC_INDIR_AC);
/* update Mode Select */
addr &= ~(MGBE_MAC_INDIR_AC_MSEL);
addr |= ((mc_no << MGBE_MAC_INDIR_AC_MSEL_SHIFT) &
MGBE_MAC_INDIR_AC_MSEL);
/* update Address Offset */
addr &= ~(MGBE_MAC_INDIR_AC_AOFF);
addr |= ((addr_offset << MGBE_MAC_INDIR_AC_AOFF_SHIFT) &
MGBE_MAC_INDIR_AC_AOFF);
/* Set CMD filed bit 0 for write */
addr &= ~(MGBE_MAC_INDIR_AC_CMD);
/* Set OB bit to initiate write */
addr |= MGBE_MAC_INDIR_AC_OB;
/* Write MGBE_MAC_L3L4_ADDR_CTR */
osi_writel(addr, (nveu8_t *)base + MGBE_MAC_INDIR_AC);
/* Wait until OB bit reset */
if (mgbe_poll_for_mac_acrtl(osi_core) < 0) {
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL,
"Fail to write MAC_Indir_Access_Ctrl\n", mc_no);
return -1;
}
return 0;
}
/**
* @brief mgbe_mac_indir_addr_read - MAC Indirect AC register read.
*
* Algorithm: Reads MAC Indirect AC register
*
* @param[in] base: MGBE virtual base address.
* @param[in] mc_no: MAC AC Mode Select number
* @param[in] addr_offset: MAC AC Address Offset.
* @param[in] value: Pointer MAC AC register value
*
* @note MAC needs to be out of reset and proper clock configured.
*
* @retval 0 on success
* @retval -1 on failure.
*/
static int mgbe_mac_indir_addr_read(struct osi_core_priv_data *osi_core,
nveu32_t mc_no,
nveu32_t addr_offset,
nveu32_t *value)
{
void *base = osi_core->base;
nveu32_t addr = 0;
/* Program MAC_Indir_Access_Ctrl */
addr = osi_readl((nveu8_t *)base + MGBE_MAC_INDIR_AC);
/* update Mode Select */
addr &= ~(MGBE_MAC_INDIR_AC_MSEL);
addr |= ((mc_no << MGBE_MAC_INDIR_AC_MSEL_SHIFT) &
MGBE_MAC_INDIR_AC_MSEL);
/* update Address Offset */
addr &= ~(MGBE_MAC_INDIR_AC_AOFF);
addr |= ((addr_offset << MGBE_MAC_INDIR_AC_AOFF_SHIFT) &
MGBE_MAC_INDIR_AC_AOFF);
/* Set CMD filed bit to 1 for read */
addr |= MGBE_MAC_INDIR_AC_CMD;
/* Set OB bit to initiate write */
addr |= MGBE_MAC_INDIR_AC_OB;
/* Write MGBE_MAC_L3L4_ADDR_CTR */
osi_writel(addr, (nveu8_t *)base + MGBE_MAC_INDIR_AC);
/* Wait until OB bit reset */
if (mgbe_poll_for_mac_acrtl(osi_core) < 0) {
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL,
"Fail to write MAC_Indir_Access_Ctrl\n", mc_no);
return -1;
}
/* Read MAC_Indir_Access_Data register value */
*value = osi_readl((nveu8_t *)base + MGBE_MAC_INDIR_DATA);
return 0;
}
/**
* @brief mgbe_config_l2_da_perfect_inverse_match - configure register for
* inverse or perfect match.
@@ -312,23 +463,13 @@ static int mgbe_config_mac_pkt_filter_reg(struct osi_core_priv_data *osi_core,
}
/**
* @brief mgbe_update_mac_addr_helper - Function to update DCS and MBC
* @brief mgbe_filter_args_validate - Validates the filter arguments
*
* Algorithm: This helper routine is to update passed prameter value
* based on DCS and MBC parameter. Validation of dma_chan as well as
* dsc_en status performed before updating DCS bits.
* Algorithm: This function just validates all arguments provided by
* the osi_filter structure variable.
*
* @param[in] osi_core: OSI core private data structure.
* @param[out] value: unsigned int pointer which has value read from register.
* @param[in] idx: filter index
* @param[in] dma_routing_enable: dma channel routing enable(1)
* @param[in] dma_chan: dma channel number
* @param[in] addr_mask: filter will not consider byte in comparison
* Bit 5: MAC_Address${i}_High[15:8]
* Bit 4: MAC_Address${i}_High[7:0]
* Bit 3: MAC_Address${i}_Low[31:24]
* ..
* Bit 0: MAC_Address${i}_Low[7:0]
* @param[in] filter: OSI filter structure.
*
* @note 1) MAC should be initialized and stated. see osi_start_mac()
* 2) osi_core->osd should be populated.
@@ -336,42 +477,67 @@ static int mgbe_config_mac_pkt_filter_reg(struct osi_core_priv_data *osi_core,
* @retval 0 on success
* @retval -1 on failure.
*/
static inline int mgbe_update_mac_addr_helper(
struct osi_core_priv_data *osi_core,
unsigned int *value,
unsigned int idx,
unsigned int dma_routing_enable,
unsigned int dma_chan, unsigned int addr_mask)
static int mgbe_filter_args_validate(struct osi_core_priv_data *const osi_core,
const struct osi_filter *filter)
{
int ret = 0;
/* PDC bit of MAC_Ext_Configuration register is not set so binary
* value representation.
*/
if (dma_routing_enable == OSI_ENABLE) {
if ((dma_chan < OSI_MGBE_MAX_NUM_CHANS) &&
(osi_core->dcs_en == OSI_ENABLE)) {
*value = ((dma_chan << MGBE_MAC_ADDRH_DCS_SHIFT) &
MGBE_MAC_ADDRH_DCS);
} else if (dma_chan > OSI_MGBE_MAX_NUM_CHANS - 0x1U) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_OUTOFBOUND,
"invalid dma channel\n",
(unsigned long long)dma_chan);
ret = -1;
goto err_dma_chan;
} else {
/* Do nothing */
}
nveu32_t idx = filter->index;
nveu32_t dma_routing_enable = filter->dma_routing;
nveu32_t dma_chan = filter->dma_chan;
nveu32_t addr_mask = filter->addr_mask;
nveu32_t src_dest = filter->src_dest;
nveu32_t dma_chansel = filter->dma_chansel;
/* check for valid index (0 to 31) */
if (idx >= OSI_MGBE_MAX_MAC_ADDRESS_FILTER) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_INVALID,
"invalid MAC filter index\n",
idx);
return -1;
}
/* Address mask validation */
if (addr_mask <= MGBE_MAB_ADDRH_MBC_MAX_MASK && addr_mask > OSI_NONE) {
*value = (*value |
((addr_mask << MGBE_MAC_ADDRH_MBC_SHIFT) &
MGBE_MAC_ADDRH_MBC));
/* check for DMA channel index (0 to 9) */
if ((dma_chan > OSI_MGBE_MAX_NUM_CHANS - 0x1U) &&
(dma_chan != OSI_CHAN_ANY)){
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_OUTOFBOUND,
"invalid dma channel\n",
(nveul64_t)dma_chan);
return -1;
}
err_dma_chan:
return ret;
/* validate dma_chansel argument */
if (dma_chansel > MGBE_MAC_XDCS_DMA_MAX) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_OUTOFBOUND,
"invalid dma_chansel value\n",
dma_chansel);
return -1;
}
/* validate addr_mask argument */
if (addr_mask > MGBE_MAB_ADDRH_MBC_MAX_MASK) {
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_INVALID,
"Invalid addr_mask value\n",
addr_mask);
return -1;
}
/* validate src_dest argument */
if (src_dest != OSI_SA_MATCH && src_dest != OSI_DA_MATCH) {
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_INVALID,
"Invalid src_dest value\n",
src_dest);
return -1;
}
/* validate dma_routing_enable argument */
if (dma_routing_enable != OSI_ENABLE &&
dma_routing_enable != OSI_DISABLE) {
OSI_CORE_ERR(OSI_NULL, OSI_LOG_ARG_INVALID,
"Invalid dma_routing value\n",
dma_routing_enable);
return -1;
}
return 0;
}
/**
@@ -396,20 +562,19 @@ static int mgbe_update_mac_addr_low_high_reg(
struct osi_core_priv_data *const osi_core,
const struct osi_filter *filter)
{
unsigned int idx = filter->index;
unsigned int dma_routing_enable = filter->dma_routing;
unsigned int dma_chan = filter->dma_chan;
unsigned int addr_mask = filter->addr_mask;
unsigned int src_dest = filter->src_dest;
const unsigned char *addr = filter->mac_address;
unsigned int value = 0x0U;
int ret = 0;
nveu32_t idx = filter->index;
nveu32_t dma_routing_enable = filter->dma_routing;
nveu32_t dma_chan = filter->dma_chan;
nveu32_t addr_mask = filter->addr_mask;
nveu32_t src_dest = filter->src_dest;
const nveu8_t *addr = filter->mac_address;
nveu32_t dma_chansel = filter->dma_chansel;
nveu32_t value = 0x0U;
nve32_t ret = 0;
/* check for valid index (0 to 31) */
if (idx >= OSI_MGBE_MAX_MAC_ADDRESS_FILTER) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_INVALID,
"invalid MAC filter index\n",
idx);
/* Validate filter values */
if (mgbe_filter_args_validate(osi_core, filter) < 0) {
/* Filter argments validation got failed */
return -1;
}
@@ -420,18 +585,21 @@ static int mgbe_update_mac_addr_low_high_reg(
return 0;
}
ret = mgbe_update_mac_addr_helper(osi_core, &value, idx,
dma_routing_enable, dma_chan,
addr_mask);
if (ret == -1) {
/* return on helper error */
return ret;
/* Add DMA channel to value if DCS enabled */
if ((dma_routing_enable == OSI_ENABLE) &&
(osi_core->dcs_en == OSI_ENABLE)) {
value = ((dma_chan << MGBE_MAC_ADDRH_DCS_SHIFT) &
MGBE_MAC_ADDRH_DCS);
}
/* Setting Source/Destination Address match valid for 1 to 31 index */
if ((src_dest == OSI_SA_MATCH || src_dest == OSI_DA_MATCH)) {
value = (value | ((src_dest << MGBE_MAC_ADDRH_SA_SHIFT) &
MGBE_MAC_ADDRH_SA));
if (idx != 0U) {
/* Add Address mask */
value |= ((addr_mask << MGBE_MAC_ADDRH_MBC_SHIFT) &
MGBE_MAC_ADDRH_MBC);
/* Setting Source/Destination Address match valid */
value |= ((src_dest << MGBE_MAC_ADDRH_SA_SHIFT) &
MGBE_MAC_ADDRH_SA);
}
osi_writel(((unsigned int)addr[4] |
@@ -446,6 +614,16 @@ static int mgbe_update_mac_addr_low_high_reg(
((unsigned int)addr[3] << 24)),
(unsigned char *)osi_core->base + MGBE_MAC_ADDRL((idx)));
/* Write XDCS configuration into MAC_DChSel_IndReg(x) */
if (dma_routing_enable == OSI_ENABLE) {
/* Append DCS DMA channel to XDCS hot bit selection */
dma_chansel |= (OSI_ENABLE << dma_chan);
ret = mgbe_mac_indir_addr_write(osi_core,
MGBE_MAC_DCHSEL,
idx,
dma_chansel);
}
return ret;
}
@@ -2745,7 +2923,12 @@ static nve32_t mgbe_core_init(struct osi_core_priv_data *osi_core,
osi_writel(value, (unsigned char *)osi_core->base +
MGBE_MTL_RXQ_DMA_MAP2);
/* TODO: DCS enable */
/* Enable XDCS in MAC_Extended_Configuration */
value = osi_readl((nveu8_t *)osi_core->base +
MGBE_MAC_EXT_CNF);
value |= MGBE_MAC_EXT_CNF_DDS;
osi_writel(value, (nveu8_t *)osi_core->base +
MGBE_MAC_EXT_CNF);
if (osi_core->pre_si == OSI_ENABLE) {
/* For pre silicon Tx and Rx Queue sizes are 64KB */
@@ -3691,6 +3874,16 @@ static inline int mgbe_save_registers(
}
}
/* Save MAC_DChSel_IndReg indirect addressing registers */
for (i = 0; i < OSI_MGBE_MAX_MAC_ADDRESS_FILTER; i++) {
ret = mgbe_mac_indir_addr_read(osi_core, MGBE_MAC_DCHSEL,
i, &config->reg_val[MGBE_MAC_DCHSEL_BAK_IDX(i)]);
if (ret < 0) {
/* MGBE_MAC_DCHSEL read fail return here */
return ret;
}
}
return ret;
}
@@ -3762,6 +3955,16 @@ static inline int mgbe_restore_registers(
}
}
/* Restore MAC_DChSel_IndReg indirect addressing registers */
for (i = 0; i < OSI_MGBE_MAX_MAC_ADDRESS_FILTER; i++) {
ret = mgbe_mac_indir_addr_write(osi_core, MGBE_MAC_DCHSEL,
i, config->reg_val[MGBE_MAC_DCHSEL_BAK_IDX(i)]);
if (ret < 0) {
/* MGBE_MAC_DCHSEL write fail return here */
return ret;
}
}
return ret;
}

View File

@@ -78,6 +78,7 @@
#define MGBE_MAC_LPI_TIMER_CTRL 0x00D4
#define MGBE_MAC_LPI_EN_TIMER 0x00D8
#define MGBE_MAC_1US_TIC_COUNT 0x00DC
#define MGBE_MAC_EXT_CNF 0x0140
#define MGBE_MDIO_SCCD 0x0204
#define MGBE_MDIO_SCCA 0x0200
#define MGBE_MAC_FPE_CTS 0x0280
@@ -86,6 +87,8 @@
#define MGBE_MAC_ADDRH(x) ((0x0008U * (x)) + 0x0300U)
#define MGBE_MAC_MA0LR 0x0304
#define MGBE_MAC_ADDRL(x) ((0x0008U * (x)) + 0x0304U)
#define MGBE_MAC_INDIR_AC 0x0700
#define MGBE_MAC_INDIR_DATA 0x0704
#define MGBE_MMC_TX_INTR_EN 0x0810
#define MGBE_MMC_RX_INTR_EN 0x080C
#define MGBE_MMC_CNTRL 0x0800
@@ -128,6 +131,40 @@
#define MGBE_MAX_HTR_REGS 4U
/** @} */
/**
* @addtogroup MGBE MAC Mode Select Group
*
* @brief MGBE MAC Indirect Access control and status for
* Mode Select type defines.
* @{
*/
#define MGBE_MAC_XDCS_DMA_MAX 0x3FFU
#define MGBE_MAC_INDIR_AC_OB_WAIT 10U
#define MGBE_MAC_INDIR_AC_OB_RETRY 10U
#define MGBE_MAC_DCHSEL 0U
#define MGBE_MAC_PCCTRL 1U
#define MGBE_MAC_PCNTRL 2U
#define MGBE_MAC_DPCSEL 3U
#define MGBE_MAC_VPCSEL 4U
#define MGBE_MAC_LPCSEL 5U
#define MGBE_MAC_APCSEL 6U
#define MGBE_MAC_PC_STATUS 7U
/* MGBE_MAC_INDIR_AC register defines */
#define MGBE_MAC_INDIR_AC_MSEL (OSI_BIT(19) | OSI_BIT(18) | \
OSI_BIT(17) | OSI_BIT(16))
#define MGBE_MAC_INDIR_AC_MSEL_SHIFT 16U
#define MGBE_MAC_INDIR_AC_AOFF (OSI_BIT(15) | OSI_BIT(14) | \
OSI_BIT(13) | OSI_BIT(12) | \
OSI_BIT(11) | OSI_BIT(10) | \
OSI_BIT(9) | OSI_BIT(8))
#define MGBE_MAC_INDIR_AC_AOFF_SHIFT 8U
#define MGBE_MAC_INDIR_AC_AUTO OSI_BIT(5)
#define MGBE_MAC_INDIR_AC_CMD OSI_BIT(1)
#define MGBE_MAC_INDIR_AC_OB OSI_BIT(0)
/** @} */
/**
* @addtogroup MGBE MAC L3L4 defines
*
@@ -612,6 +649,7 @@
#define MGBE_MTL_EST_ITRE_IEBE OSI_BIT(1)
#define MGBE_MTL_EST_ITRE_IECC OSI_BIT(0)
#define MGBE_MAC_SBD_INTR OSI_BIT(2)
#define MGBE_MAC_EXT_CNF_DDS OSI_BIT(7)
/** @} */
/**
@@ -686,7 +724,8 @@
#define MGBE_MAC_LPI_CSR_BAK_IDX ((MGBE_MAC_PMTCSR_BAK_IDX + 1U))
#define MGBE_MAC_LPI_TIMER_CTRL_BAK_IDX ((MGBE_MAC_LPI_CSR_BAK_IDX + 1U))
#define MGBE_MAC_LPI_EN_TIMER_BAK_IDX ((MGBE_MAC_LPI_TIMER_CTRL_BAK_IDX + 1U))
#define MGBE_MAC_TCR_BAK_IDX ((MGBE_MAC_LPI_EN_TIMER_BAK_IDX + 1U))
#define MGBE_MAC_EXT_CNF_BAK_IDX ((MGBE_MAC_LPI_EN_TIMER_BAK_IDX + 1U))
#define MGBE_MAC_TCR_BAK_IDX ((MGBE_MAC_EXT_CNF_BAK_IDX + 1U))
#define MGBE_MAC_SSIR_BAK_IDX ((MGBE_MAC_TCR_BAK_IDX + 1U))
#define MGBE_MAC_STSR_BAK_IDX ((MGBE_MAC_SSIR_BAK_IDX + 1U))
#define MGBE_MAC_STNSR_BAK_IDX ((MGBE_MAC_STSR_BAK_IDX + 1U))
@@ -772,9 +811,12 @@
/* x varies from 0-31, 32 VLAN tag filters total */
#define MGBE_MAC_VLAN_BAK_IDX(x) ((MGBE_MAC_L3_AD3R_BAK_IDX(0) + \
OSI_MGBE_MAX_L3_L4_FILTER + (x)))
/* Add MAC_DChSel_IndReg */
#define MGBE_MAC_DCHSEL_BAK_IDX(x) ((MGBE_MAC_VLAN_BAK_IDX(0) + \
MGBE_MAX_VLAN_FILTER + 1U))
#define MGBE_MAX_BAK_IDX ((MGBE_MAC_VLAN_BAK_IDX(0) + \
MGBE_MAX_VLAN_FILTER + 1U))
#define MGBE_MAX_BAK_IDX ((MGBE_MAC_DCHSEL_BAK_IDX(0) + \
OSI_MGBE_MAX_MAC_ADDRESS_FILTER + 1U))
/** @} */
/**