net: stmmac: Add Flexible RX Parser support in XGMAC

XGMAC cores also support the Flexible RX Parser feature. Add the support
for it in the XGMAC core.

Signed-off-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jose Abreu 2019-08-07 10:03:17 +02:00 committed by David S. Miller
parent 56e58d6c8a
commit d6e1c12cf9
3 changed files with 206 additions and 0 deletions

View File

@ -112,6 +112,9 @@
#define XGMAC_HWFEAT_RXQCNT GENMASK(3, 0)
#define XGMAC_HW_FEATURE3 0x00000128
#define XGMAC_HWFEAT_ASP GENMASK(15, 14)
#define XGMAC_HWFEAT_FRPES GENMASK(12, 11)
#define XGMAC_HWFEAT_FRPPB GENMASK(10, 9)
#define XGMAC_HWFEAT_FRPSEL BIT(3)
#define XGMAC_MAC_DPP_FSM_INT_STATUS 0x00000150
#define XGMAC_MAC_FSM_CONTROL 0x00000158
#define XGMAC_PRTYEN BIT(1)
@ -145,6 +148,7 @@
/* MTL Registers */
#define XGMAC_MTL_OPMODE 0x00001000
#define XGMAC_FRPE BIT(15)
#define XGMAC_ETSALG GENMASK(6, 5)
#define XGMAC_WRR (0x0 << 5)
#define XGMAC_WFQ (0x1 << 5)
@ -160,6 +164,15 @@
#define XGMAC_TC_PRTY_MAP1 0x00001044
#define XGMAC_PSTC(x) GENMASK((x) * 8 + 7, (x) * 8)
#define XGMAC_PSTC_SHIFT(x) ((x) * 8)
#define XGMAC_MTL_RXP_CONTROL_STATUS 0x000010a0
#define XGMAC_RXPI BIT(31)
#define XGMAC_NPE GENMASK(23, 16)
#define XGMAC_NVE GENMASK(7, 0)
#define XGMAC_MTL_RXP_IACC_CTRL_ST 0x000010b0
#define XGMAC_STARTBUSY BIT(31)
#define XGMAC_WRRDN BIT(16)
#define XGMAC_ADDR GENMASK(9, 0)
#define XGMAC_MTL_RXP_IACC_DATA 0x000010b4
#define XGMAC_MTL_ECC_CONTROL 0x000010c0
#define XGMAC_MTL_SAFETY_INT_STATUS 0x000010c4
#define XGMAC_MEUIS BIT(1)

View File

@ -808,6 +808,195 @@ static int dwxgmac3_safety_feat_dump(struct stmmac_safety_stats *stats,
return 0;
}
static int dwxgmac3_rxp_disable(void __iomem *ioaddr)
{
u32 val = readl(ioaddr + XGMAC_MTL_OPMODE);
val &= ~XGMAC_FRPE;
writel(val, ioaddr + XGMAC_MTL_OPMODE);
return 0;
}
static void dwxgmac3_rxp_enable(void __iomem *ioaddr)
{
u32 val;
val = readl(ioaddr + XGMAC_MTL_OPMODE);
val |= XGMAC_FRPE;
writel(val, ioaddr + XGMAC_MTL_OPMODE);
}
static int dwxgmac3_rxp_update_single_entry(void __iomem *ioaddr,
struct stmmac_tc_entry *entry,
int pos)
{
int ret, i;
for (i = 0; i < (sizeof(entry->val) / sizeof(u32)); i++) {
int real_pos = pos * (sizeof(entry->val) / sizeof(u32)) + i;
u32 val;
/* Wait for ready */
ret = readl_poll_timeout(ioaddr + XGMAC_MTL_RXP_IACC_CTRL_ST,
val, !(val & XGMAC_STARTBUSY), 1, 10000);
if (ret)
return ret;
/* Write data */
val = *((u32 *)&entry->val + i);
writel(val, ioaddr + XGMAC_MTL_RXP_IACC_DATA);
/* Write pos */
val = real_pos & XGMAC_ADDR;
writel(val, ioaddr + XGMAC_MTL_RXP_IACC_CTRL_ST);
/* Write OP */
val |= XGMAC_WRRDN;
writel(val, ioaddr + XGMAC_MTL_RXP_IACC_CTRL_ST);
/* Start Write */
val |= XGMAC_STARTBUSY;
writel(val, ioaddr + XGMAC_MTL_RXP_IACC_CTRL_ST);
/* Wait for done */
ret = readl_poll_timeout(ioaddr + XGMAC_MTL_RXP_IACC_CTRL_ST,
val, !(val & XGMAC_STARTBUSY), 1, 10000);
if (ret)
return ret;
}
return 0;
}
static struct stmmac_tc_entry *
dwxgmac3_rxp_get_next_entry(struct stmmac_tc_entry *entries,
unsigned int count, u32 curr_prio)
{
struct stmmac_tc_entry *entry;
u32 min_prio = ~0x0;
int i, min_prio_idx;
bool found = false;
for (i = count - 1; i >= 0; i--) {
entry = &entries[i];
/* Do not update unused entries */
if (!entry->in_use)
continue;
/* Do not update already updated entries (i.e. fragments) */
if (entry->in_hw)
continue;
/* Let last entry be updated last */
if (entry->is_last)
continue;
/* Do not return fragments */
if (entry->is_frag)
continue;
/* Check if we already checked this prio */
if (entry->prio < curr_prio)
continue;
/* Check if this is the minimum prio */
if (entry->prio < min_prio) {
min_prio = entry->prio;
min_prio_idx = i;
found = true;
}
}
if (found)
return &entries[min_prio_idx];
return NULL;
}
static int dwxgmac3_rxp_config(void __iomem *ioaddr,
struct stmmac_tc_entry *entries,
unsigned int count)
{
struct stmmac_tc_entry *entry, *frag;
int i, ret, nve = 0;
u32 curr_prio = 0;
u32 old_val, val;
/* Force disable RX */
old_val = readl(ioaddr + XGMAC_RX_CONFIG);
val = old_val & ~XGMAC_CONFIG_RE;
writel(val, ioaddr + XGMAC_RX_CONFIG);
/* Disable RX Parser */
ret = dwxgmac3_rxp_disable(ioaddr);
if (ret)
goto re_enable;
/* Set all entries as NOT in HW */
for (i = 0; i < count; i++) {
entry = &entries[i];
entry->in_hw = false;
}
/* Update entries by reverse order */
while (1) {
entry = dwxgmac3_rxp_get_next_entry(entries, count, curr_prio);
if (!entry)
break;
curr_prio = entry->prio;
frag = entry->frag_ptr;
/* Set special fragment requirements */
if (frag) {
entry->val.af = 0;
entry->val.rf = 0;
entry->val.nc = 1;
entry->val.ok_index = nve + 2;
}
ret = dwxgmac3_rxp_update_single_entry(ioaddr, entry, nve);
if (ret)
goto re_enable;
entry->table_pos = nve++;
entry->in_hw = true;
if (frag && !frag->in_hw) {
ret = dwxgmac3_rxp_update_single_entry(ioaddr, frag, nve);
if (ret)
goto re_enable;
frag->table_pos = nve++;
frag->in_hw = true;
}
}
if (!nve)
goto re_enable;
/* Update all pass entry */
for (i = 0; i < count; i++) {
entry = &entries[i];
if (!entry->is_last)
continue;
ret = dwxgmac3_rxp_update_single_entry(ioaddr, entry, nve);
if (ret)
goto re_enable;
entry->table_pos = nve++;
}
/* Assume n. of parsable entries == n. of valid entries */
val = (nve << 16) & XGMAC_NPE;
val |= nve & XGMAC_NVE;
writel(val, ioaddr + XGMAC_MTL_RXP_CONTROL_STATUS);
/* Enable RX Parser */
dwxgmac3_rxp_enable(ioaddr);
re_enable:
/* Re-enable RX */
writel(old_val, ioaddr + XGMAC_RX_CONFIG);
return ret;
}
const struct stmmac_ops dwxgmac210_ops = {
.core_init = dwxgmac2_core_init,
.set_mac = dwxgmac2_set_mac,
@ -843,6 +1032,7 @@ const struct stmmac_ops dwxgmac210_ops = {
.set_mac_loopback = dwxgmac2_set_mac_loopback,
.rss_configure = dwxgmac2_rss_configure,
.update_vlan_hash = dwxgmac2_update_vlan_hash,
.rxp_config = dwxgmac3_rxp_config,
};
int dwxgmac2_setup(struct stmmac_priv *priv)

View File

@ -403,6 +403,9 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
/* MAC HW feature 3 */
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3);
dma_cap->asp = (hw_cap & XGMAC_HWFEAT_ASP) >> 14;
dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11;
dma_cap->frpbs = (hw_cap & XGMAC_HWFEAT_FRPPB) >> 9;
dma_cap->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3;
}
static void dwxgmac2_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 nchan)