Skip to content

Commit

Permalink
net: stmmac: Implement L3/L4 Filters using TC Flower
Browse files Browse the repository at this point in the history
Implement filters for Layer 3 and Layer 4 using TC Flower API. Add the
corresponding callbacks in XGMAC core.

Signed-off-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jose Abreu authored and David S. Miller committed Sep 5, 2019
1 parent c104891 commit 425eabd
Show file tree
Hide file tree
Showing 8 changed files with 488 additions and 2 deletions.
1 change: 1 addition & 0 deletions drivers/net/ethernet/stmicro/stmmac/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ struct dma_features {
unsigned int sphen;
unsigned int vlins;
unsigned int dvlan;
unsigned int l3l4fnum;
};

/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
Expand Down
30 changes: 30 additions & 0 deletions drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#define XGMAC_CORE_INIT_RX 0
#define XGMAC_PACKET_FILTER 0x00000008
#define XGMAC_FILTER_RA BIT(31)
#define XGMAC_FILTER_IPFE BIT(20)
#define XGMAC_FILTER_VTFE BIT(16)
#define XGMAC_FILTER_HPF BIT(10)
#define XGMAC_FILTER_PCF BIT(7)
Expand Down Expand Up @@ -119,6 +120,7 @@
#define XGMAC_HWFEAT_VLHASH BIT(4)
#define XGMAC_HWFEAT_GMIISEL BIT(1)
#define XGMAC_HW_FEATURE1 0x00000120
#define XGMAC_HWFEAT_L3L4FNUM GENMASK(30, 27)
#define XGMAC_HWFEAT_RSSEN BIT(20)
#define XGMAC_HWFEAT_TSOEN BIT(18)
#define XGMAC_HWFEAT_SPHEN BIT(17)
Expand Down Expand Up @@ -150,6 +152,34 @@
#define XGMAC_DCS GENMASK(19, 16)
#define XGMAC_DCS_SHIFT 16
#define XGMAC_ADDRx_LOW(x) (0x00000304 + (x) * 0x8)
#define XGMAC_L3L4_ADDR_CTRL 0x00000c00
#define XGMAC_IDDR GENMASK(15, 8)
#define XGMAC_IDDR_SHIFT 8
#define XGMAC_IDDR_FNUM 4
#define XGMAC_TT BIT(1)
#define XGMAC_XB BIT(0)
#define XGMAC_L3L4_DATA 0x00000c04
#define XGMAC_L3L4_CTRL 0x0
#define XGMAC_L4DPIM0 BIT(21)
#define XGMAC_L4DPM0 BIT(20)
#define XGMAC_L4SPIM0 BIT(19)
#define XGMAC_L4SPM0 BIT(18)
#define XGMAC_L4PEN0 BIT(16)
#define XGMAC_L3HDBM0 GENMASK(15, 11)
#define XGMAC_L3HSBM0 GENMASK(10, 6)
#define XGMAC_L3DAIM0 BIT(5)
#define XGMAC_L3DAM0 BIT(4)
#define XGMAC_L3SAIM0 BIT(3)
#define XGMAC_L3SAM0 BIT(2)
#define XGMAC_L3PEN0 BIT(0)
#define XGMAC_L4_ADDR 0x1
#define XGMAC_L4DP0 GENMASK(31, 16)
#define XGMAC_L4DP0_SHIFT 16
#define XGMAC_L4SP0 GENMASK(15, 0)
#define XGMAC_L3_ADDR0 0x4
#define XGMAC_L3_ADDR1 0x5
#define XGMAC_L3_ADDR2 0x6
#define XMGAC_L3_ADDR3 0x7
#define XGMAC_ARP_ADDR 0x00000c10
#define XGMAC_RSS_CTRL 0x00000c80
#define XGMAC_UDP4TE BIT(3)
Expand Down
177 changes: 177 additions & 0 deletions drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,181 @@ static void dwxgmac2_enable_vlan(struct mac_device_info *hw, u32 type)
writel(value, ioaddr + XGMAC_VLAN_INCL);
}

static int dwxgmac2_filter_wait(struct mac_device_info *hw)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;

if (readl_poll_timeout(ioaddr + XGMAC_L3L4_ADDR_CTRL, value,
!(value & XGMAC_XB), 100, 10000))
return -EBUSY;
return 0;
}

static int dwxgmac2_filter_read(struct mac_device_info *hw, u32 filter_no,
u8 reg, u32 *data)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
int ret;

ret = dwxgmac2_filter_wait(hw);
if (ret)
return ret;

value = ((filter_no << XGMAC_IDDR_FNUM) | reg) << XGMAC_IDDR_SHIFT;
value |= XGMAC_TT | XGMAC_XB;
writel(value, ioaddr + XGMAC_L3L4_ADDR_CTRL);

ret = dwxgmac2_filter_wait(hw);
if (ret)
return ret;

*data = readl(ioaddr + XGMAC_L3L4_DATA);
return 0;
}

static int dwxgmac2_filter_write(struct mac_device_info *hw, u32 filter_no,
u8 reg, u32 data)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
int ret;

ret = dwxgmac2_filter_wait(hw);
if (ret)
return ret;

writel(data, ioaddr + XGMAC_L3L4_DATA);

value = ((filter_no << XGMAC_IDDR_FNUM) | reg) << XGMAC_IDDR_SHIFT;
value |= XGMAC_XB;
writel(value, ioaddr + XGMAC_L3L4_ADDR_CTRL);

return dwxgmac2_filter_wait(hw);
}

static int dwxgmac2_config_l3_filter(struct mac_device_info *hw, u32 filter_no,
bool en, bool ipv6, bool sa, bool inv,
u32 match)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
int ret;

value = readl(ioaddr + XGMAC_PACKET_FILTER);
value |= XGMAC_FILTER_IPFE;
writel(value, ioaddr + XGMAC_PACKET_FILTER);

ret = dwxgmac2_filter_read(hw, filter_no, XGMAC_L3L4_CTRL, &value);
if (ret)
return ret;

/* For IPv6 not both SA/DA filters can be active */
if (ipv6) {
value |= XGMAC_L3PEN0;
value &= ~(XGMAC_L3SAM0 | XGMAC_L3SAIM0);
value &= ~(XGMAC_L3DAM0 | XGMAC_L3DAIM0);
if (sa) {
value |= XGMAC_L3SAM0;
if (inv)
value |= XGMAC_L3SAIM0;
} else {
value |= XGMAC_L3DAM0;
if (inv)
value |= XGMAC_L3DAIM0;
}
} else {
value &= ~XGMAC_L3PEN0;
if (sa) {
value |= XGMAC_L3SAM0;
if (inv)
value |= XGMAC_L3SAIM0;
} else {
value |= XGMAC_L3DAM0;
if (inv)
value |= XGMAC_L3DAIM0;
}
}

ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, value);
if (ret)
return ret;

if (sa) {
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3_ADDR0, match);
if (ret)
return ret;
} else {
ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3_ADDR1, match);
if (ret)
return ret;
}

if (!en)
return dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, 0);

return 0;
}

static int dwxgmac2_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
bool en, bool udp, bool sa, bool inv,
u32 match)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
int ret;

value = readl(ioaddr + XGMAC_PACKET_FILTER);
value |= XGMAC_FILTER_IPFE;
writel(value, ioaddr + XGMAC_PACKET_FILTER);

ret = dwxgmac2_filter_read(hw, filter_no, XGMAC_L3L4_CTRL, &value);
if (ret)
return ret;

if (udp) {
value |= XGMAC_L4PEN0;
} else {
value &= ~XGMAC_L4PEN0;
}

value &= ~(XGMAC_L4SPM0 | XGMAC_L4SPIM0);
value &= ~(XGMAC_L4DPM0 | XGMAC_L4DPIM0);
if (sa) {
value |= XGMAC_L4SPM0;
if (inv)
value |= XGMAC_L4SPIM0;
} else {
value |= XGMAC_L4DPM0;
if (inv)
value |= XGMAC_L4DPIM0;
}

ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, value);
if (ret)
return ret;

if (sa) {
value = match & XGMAC_L4SP0;

ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
if (ret)
return ret;
} else {
value = (match << XGMAC_L4DP0_SHIFT) & XGMAC_L4DP0;

ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value);
if (ret)
return ret;
}

if (!en)
return dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, 0);

return 0;
}

const struct stmmac_ops dwxgmac210_ops = {
.core_init = dwxgmac2_core_init,
.set_mac = dwxgmac2_set_mac,
Expand Down Expand Up @@ -1203,6 +1378,8 @@ const struct stmmac_ops dwxgmac210_ops = {
.flex_pps_config = dwxgmac2_flex_pps_config,
.sarc_configure = dwxgmac2_sarc_configure,
.enable_vlan = dwxgmac2_enable_vlan,
.config_l3_filter = dwxgmac2_config_l3_filter,
.config_l4_filter = dwxgmac2_config_l4_filter,
};

int dwxgmac2_setup(struct stmmac_priv *priv)
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,

/* MAC HW feature 1 */
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1);
dma_cap->l3l4fnum = (hw_cap & XGMAC_HWFEAT_L3L4FNUM) >> 27;
dma_cap->rssen = (hw_cap & XGMAC_HWFEAT_RSSEN) >> 20;
dma_cap->tsoen = (hw_cap & XGMAC_HWFEAT_TSOEN) >> 18;
dma_cap->sphen = (hw_cap & XGMAC_HWFEAT_SPHEN) >> 17;
Expand Down
16 changes: 16 additions & 0 deletions drivers/net/ethernet/stmicro/stmmac/hwif.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,13 @@ struct stmmac_ops {
int (*get_mac_tx_timestamp)(struct mac_device_info *hw, u64 *ts);
/* Source Address Insertion / Replacement */
void (*sarc_configure)(void __iomem *ioaddr, int val);
/* Filtering */
int (*config_l3_filter)(struct mac_device_info *hw, u32 filter_no,
bool en, bool ipv6, bool sa, bool inv,
u32 match);
int (*config_l4_filter)(struct mac_device_info *hw, u32 filter_no,
bool en, bool udp, bool sa, bool inv,
u32 match);
};

#define stmmac_core_init(__priv, __args...) \
Expand Down Expand Up @@ -443,6 +450,10 @@ struct stmmac_ops {
stmmac_do_callback(__priv, mac, get_mac_tx_timestamp, __args)
#define stmmac_sarc_configure(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, sarc_configure, __args)
#define stmmac_config_l3_filter(__priv, __args...) \
stmmac_do_callback(__priv, mac, config_l3_filter, __args)
#define stmmac_config_l4_filter(__priv, __args...) \
stmmac_do_callback(__priv, mac, config_l4_filter, __args)

/* PTP and HW Timer helpers */
struct stmmac_hwtimestamp {
Expand Down Expand Up @@ -499,13 +510,16 @@ struct stmmac_mode_ops {
struct stmmac_priv;
struct tc_cls_u32_offload;
struct tc_cbs_qopt_offload;
struct flow_cls_offload;

struct stmmac_tc_ops {
int (*init)(struct stmmac_priv *priv);
int (*setup_cls_u32)(struct stmmac_priv *priv,
struct tc_cls_u32_offload *cls);
int (*setup_cbs)(struct stmmac_priv *priv,
struct tc_cbs_qopt_offload *qopt);
int (*setup_cls)(struct stmmac_priv *priv,
struct flow_cls_offload *cls);
};

#define stmmac_tc_init(__priv, __args...) \
Expand All @@ -514,6 +528,8 @@ struct stmmac_tc_ops {
stmmac_do_callback(__priv, tc, setup_cls_u32, __args)
#define stmmac_tc_setup_cbs(__priv, __args...) \
stmmac_do_callback(__priv, tc, setup_cbs, __args)
#define stmmac_tc_setup_cls(__priv, __args...) \
stmmac_do_callback(__priv, tc, setup_cls, __args)

struct stmmac_counters;

Expand Down
12 changes: 12 additions & 0 deletions drivers/net/ethernet/stmicro/stmmac/stmmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ struct stmmac_rss {
u32 table[STMMAC_RSS_MAX_TABLE_SIZE];
};

#define STMMAC_FLOW_ACTION_DROP BIT(0)
struct stmmac_flow_entry {
unsigned long cookie;
unsigned long action;
u8 ip_proto;
int in_use;
int idx;
int is_l4;
};

struct stmmac_priv {
/* Frequently used values are kept adjacent for cache effect */
u32 tx_coal_frames;
Expand Down Expand Up @@ -216,6 +226,8 @@ struct stmmac_priv {
unsigned int tc_entries_max;
unsigned int tc_off_max;
struct stmmac_tc_entry *tc_entries;
unsigned int flow_entries_max;
struct stmmac_flow_entry *flow_entries;

/* Pulse Per Second output */
struct stmmac_pps_cfg pps[STMMAC_PPS_MAX];
Expand Down
9 changes: 7 additions & 2 deletions drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3931,12 +3931,17 @@ static int stmmac_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
struct stmmac_priv *priv = cb_priv;
int ret = -EOPNOTSUPP;

if (!tc_cls_can_offload_and_chain0(priv->dev, type_data))
return ret;

stmmac_disable_all_queues(priv);

switch (type) {
case TC_SETUP_CLSU32:
if (tc_cls_can_offload_and_chain0(priv->dev, type_data))
ret = stmmac_tc_setup_cls_u32(priv, priv, type_data);
ret = stmmac_tc_setup_cls_u32(priv, priv, type_data);
break;
case TC_SETUP_CLSFLOWER:
ret = stmmac_tc_setup_cls(priv, priv, type_data);
break;
default:
break;
Expand Down
Loading

0 comments on commit 425eabd

Please sign in to comment.