Commit 764a4af9 authored by David S. Miller's avatar David S. Miller

Merge branch 'octeontx2-dmasc-filtering'

Hariprasad Kelam says:

====================
DMAC based packet filtering

Each MAC block supports 32 DMAC filters which can be configured to accept
or drop packets based on address match This patch series adds mbox
handlers and extends ntuple filter callbacks to accomdate DMAC filters
such that user can install DMAC based filters on interface from ethtool.

Patch1 adds necessary mbox handlers such that mbox consumers like PF netdev
can add/delete/update DMAC filters and Patch2 adds debugfs support to dump
current list of installed filters. Patch3 adds support to call mbox
handlers upon receiving DMAC filters from ethtool ntuple commands.

Change-log:
v2 -
   - fixed indentation issues.
v3 -
   - fixed kdoc warnings
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 39d71016 79d2be38
......@@ -86,6 +86,22 @@ bool is_lmac_valid(struct cgx *cgx, int lmac_id)
return test_bit(lmac_id, &cgx->lmac_bmap);
}
/* Helper function to get sequential index
* given the enabled LMAC of a CGX
*/
static int get_sequence_id_of_lmac(struct cgx *cgx, int lmac_id)
{
int tmp, id = 0;
for_each_set_bit(tmp, &cgx->lmac_bmap, MAX_LMAC_PER_CGX) {
if (tmp == lmac_id)
break;
id++;
}
return id;
}
struct mac_ops *get_mac_ops(void *cgxd)
{
if (!cgxd)
......@@ -211,37 +227,257 @@ static u64 mac2u64 (u8 *mac_addr)
return mac;
}
static void cfg2mac(u64 cfg, u8 *mac_addr)
{
int i, index = 0;
for (i = ETH_ALEN - 1; i >= 0; i--, index++)
mac_addr[i] = (cfg >> (8 * index)) & 0xFF;
}
int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr)
{
struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev);
struct mac_ops *mac_ops;
int index, id;
u64 cfg;
/* access mac_ops to know csr_offset */
mac_ops = cgx_dev->mac_ops;
/* copy 6bytes from macaddr */
/* memcpy(&cfg, mac_addr, 6); */
cfg = mac2u64 (mac_addr);
cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (lmac_id * 0x8)),
id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
index = id * lmac->mac_to_index_bmap.max;
cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)),
cfg | CGX_DMAC_CAM_ADDR_ENABLE | ((u64)lmac_id << 49));
cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
cfg |= CGX_DMAC_CTL0_CAM_ENABLE;
cfg |= (CGX_DMAC_CTL0_CAM_ENABLE | CGX_DMAC_BCAST_MODE |
CGX_DMAC_MCAST_MODE);
cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
return 0;
}
u64 cgx_read_dmac_ctrl(void *cgxd, int lmac_id)
{
struct mac_ops *mac_ops;
struct cgx *cgx = cgxd;
if (!cgxd || !is_lmac_valid(cgxd, lmac_id))
return 0;
cgx = cgxd;
/* Get mac_ops to know csr offset */
mac_ops = cgx->mac_ops;
return cgx_read(cgxd, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
}
u64 cgx_read_dmac_entry(void *cgxd, int index)
{
struct mac_ops *mac_ops;
struct cgx *cgx;
if (!cgxd)
return 0;
cgx = cgxd;
mac_ops = cgx->mac_ops;
return cgx_read(cgx, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 8)));
}
int cgx_lmac_addr_add(u8 cgx_id, u8 lmac_id, u8 *mac_addr)
{
struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev);
struct mac_ops *mac_ops;
int index, idx;
u64 cfg = 0;
int id;
if (!lmac)
return -ENODEV;
mac_ops = cgx_dev->mac_ops;
/* Get available index where entry is to be installed */
idx = rvu_alloc_rsrc(&lmac->mac_to_index_bmap);
if (idx < 0)
return idx;
id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
index = id * lmac->mac_to_index_bmap.max + idx;
cfg = mac2u64 (mac_addr);
cfg |= CGX_DMAC_CAM_ADDR_ENABLE;
cfg |= ((u64)lmac_id << 49);
cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), cfg);
cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
cfg |= (CGX_DMAC_BCAST_MODE | CGX_DMAC_CAM_ACCEPT);
if (is_multicast_ether_addr(mac_addr)) {
cfg &= ~GENMASK_ULL(2, 1);
cfg |= CGX_DMAC_MCAST_MODE_CAM;
lmac->mcast_filters_count++;
} else if (!lmac->mcast_filters_count) {
cfg |= CGX_DMAC_MCAST_MODE;
}
cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
return idx;
}
int cgx_lmac_addr_reset(u8 cgx_id, u8 lmac_id)
{
struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev);
struct mac_ops *mac_ops;
u8 index = 0, id;
u64 cfg;
if (!lmac)
return -ENODEV;
mac_ops = cgx_dev->mac_ops;
/* Restore index 0 to its default init value as done during
* cgx_lmac_init
*/
set_bit(0, lmac->mac_to_index_bmap.bmap);
id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
index = id * lmac->mac_to_index_bmap.max + index;
cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), 0);
/* Reset CGXX_CMRX_RX_DMAC_CTL0 register to default state */
cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
cfg &= ~CGX_DMAC_CAM_ACCEPT;
cfg |= (CGX_DMAC_BCAST_MODE | CGX_DMAC_MCAST_MODE);
cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
return 0;
}
/* Allows caller to change macaddress associated with index
* in dmac filter table including index 0 reserved for
* interface mac address
*/
int cgx_lmac_addr_update(u8 cgx_id, u8 lmac_id, u8 *mac_addr, u8 index)
{
struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
struct mac_ops *mac_ops;
struct lmac *lmac;
u64 cfg;
int id;
lmac = lmac_pdata(lmac_id, cgx_dev);
if (!lmac)
return -ENODEV;
mac_ops = cgx_dev->mac_ops;
/* Validate the index */
if (index >= lmac->mac_to_index_bmap.max)
return -EINVAL;
/* ensure index is already set */
if (!test_bit(index, lmac->mac_to_index_bmap.bmap))
return -EINVAL;
id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
index = id * lmac->mac_to_index_bmap.max + index;
cfg = cgx_read(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)));
cfg &= ~CGX_RX_DMAC_ADR_MASK;
cfg |= mac2u64 (mac_addr);
cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), cfg);
return 0;
}
int cgx_lmac_addr_del(u8 cgx_id, u8 lmac_id, u8 index)
{
struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev);
struct mac_ops *mac_ops;
u8 mac[ETH_ALEN];
u64 cfg;
int id;
if (!lmac)
return -ENODEV;
mac_ops = cgx_dev->mac_ops;
/* Validate the index */
if (index >= lmac->mac_to_index_bmap.max)
return -EINVAL;
/* Skip deletion for reserved index i.e. index 0 */
if (index == 0)
return 0;
rvu_free_rsrc(&lmac->mac_to_index_bmap, index);
id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
index = id * lmac->mac_to_index_bmap.max + index;
/* Read MAC address to check whether it is ucast or mcast */
cfg = cgx_read(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)));
cfg2mac(cfg, mac);
if (is_multicast_ether_addr(mac))
lmac->mcast_filters_count--;
if (!lmac->mcast_filters_count) {
cfg = cgx_read(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
cfg &= ~GENMASK_ULL(2, 1);
cfg |= CGX_DMAC_MCAST_MODE;
cgx_write(cgx_dev, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
}
cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), 0);
return 0;
}
int cgx_lmac_addr_max_entries_get(u8 cgx_id, u8 lmac_id)
{
struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev);
if (lmac)
return lmac->mac_to_index_bmap.max;
return 0;
}
u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id)
{
struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
struct lmac *lmac = lmac_pdata(lmac_id, cgx_dev);
struct mac_ops *mac_ops;
int index;
u64 cfg;
int id;
mac_ops = cgx_dev->mac_ops;
cfg = cgx_read(cgx_dev, 0, CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8);
id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
index = id * lmac->mac_to_index_bmap.max;
cfg = cgx_read(cgx_dev, 0, CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8);
return cfg & CGX_RX_DMAC_ADR_MASK;
}
......@@ -297,35 +533,51 @@ int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable)
void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable)
{
struct cgx *cgx = cgx_get_pdata(cgx_id);
struct lmac *lmac = lmac_pdata(lmac_id, cgx);
u16 max_dmac = lmac->mac_to_index_bmap.max;
struct mac_ops *mac_ops;
int index, i;
u64 cfg = 0;
int id;
if (!cgx)
return;
id = get_sequence_id_of_lmac(cgx, lmac_id);
mac_ops = cgx->mac_ops;
if (enable) {
/* Enable promiscuous mode on LMAC */
cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
cfg &= ~(CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE);
cfg |= CGX_DMAC_BCAST_MODE;
cfg &= ~CGX_DMAC_CAM_ACCEPT;
cfg |= (CGX_DMAC_BCAST_MODE | CGX_DMAC_MCAST_MODE);
cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
cfg = cgx_read(cgx, 0,
(CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8));
cfg &= ~CGX_DMAC_CAM_ADDR_ENABLE;
cgx_write(cgx, 0,
(CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg);
for (i = 0; i < max_dmac; i++) {
index = id * max_dmac + i;
cfg = cgx_read(cgx, 0,
(CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8));
cfg &= ~CGX_DMAC_CAM_ADDR_ENABLE;
cgx_write(cgx, 0,
(CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8), cfg);
}
} else {
/* Disable promiscuous mode */
cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0);
cfg |= CGX_DMAC_CAM_ACCEPT | CGX_DMAC_MCAST_MODE;
cgx_write(cgx, lmac_id, CGXX_CMRX_RX_DMAC_CTL0, cfg);
cfg = cgx_read(cgx, 0,
(CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8));
cfg |= CGX_DMAC_CAM_ADDR_ENABLE;
cgx_write(cgx, 0,
(CGXX_CMRX_RX_DMAC_CAM0 + lmac_id * 0x8), cfg);
for (i = 0; i < max_dmac; i++) {
index = id * max_dmac + i;
cfg = cgx_read(cgx, 0,
(CGXX_CMRX_RX_DMAC_CAM0 + index * 0x8));
if ((cfg & CGX_RX_DMAC_ADR_MASK) != 0) {
cfg |= CGX_DMAC_CAM_ADDR_ENABLE;
cgx_write(cgx, 0,
(CGXX_CMRX_RX_DMAC_CAM0 +
index * 0x8),
cfg);
}
}
}
}
......@@ -1234,6 +1486,15 @@ static int cgx_lmac_init(struct cgx *cgx)
}
lmac->cgx = cgx;
lmac->mac_to_index_bmap.max =
MAX_DMAC_ENTRIES_PER_CGX / cgx->lmac_count;
err = rvu_alloc_bitmap(&lmac->mac_to_index_bmap);
if (err)
return err;
/* Reserve first entry for default MAC address */
set_bit(0, lmac->mac_to_index_bmap.bmap);
init_waitqueue_head(&lmac->wq_cmd_cmplt);
mutex_init(&lmac->cmd_lock);
spin_lock_init(&lmac->event_cb_lock);
......@@ -1274,6 +1535,7 @@ static int cgx_lmac_exit(struct cgx *cgx)
continue;
cgx->mac_ops->mac_pause_frm_config(cgx, lmac->lmac_id, false);
cgx_configure_interrupt(cgx, lmac, lmac->lmac_id, true);
kfree(lmac->mac_to_index_bmap.bmap);
kfree(lmac->name);
kfree(lmac);
}
......
......@@ -23,6 +23,7 @@
#define CGX_ID_MASK 0x7
#define MAX_LMAC_PER_CGX 4
#define MAX_DMAC_ENTRIES_PER_CGX 32
#define CGX_FIFO_LEN 65536 /* 64K for both Rx & Tx */
#define CGX_OFFSET(x) ((x) * MAX_LMAC_PER_CGX)
......@@ -46,10 +47,12 @@
#define CGXX_CMRX_RX_DMAC_CTL0 (0x1F8 + mac_ops->csr_offset)
#define CGX_DMAC_CTL0_CAM_ENABLE BIT_ULL(3)
#define CGX_DMAC_CAM_ACCEPT BIT_ULL(3)
#define CGX_DMAC_MCAST_MODE_CAM BIT_ULL(2)
#define CGX_DMAC_MCAST_MODE BIT_ULL(1)
#define CGX_DMAC_BCAST_MODE BIT_ULL(0)
#define CGXX_CMRX_RX_DMAC_CAM0 (0x200 + mac_ops->csr_offset)
#define CGX_DMAC_CAM_ADDR_ENABLE BIT_ULL(48)
#define CGX_DMAC_CAM_ENTRY_LMACID GENMASK_ULL(50, 49)
#define CGXX_CMRX_RX_DMAC_CAM1 0x400
#define CGX_RX_DMAC_ADR_MASK GENMASK_ULL(47, 0)
#define CGXX_CMRX_TX_STAT0 0x700
......@@ -139,7 +142,11 @@ int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat);
int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable);
int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable);
int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr);
int cgx_lmac_addr_reset(u8 cgx_id, u8 lmac_id);
u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id);
int cgx_lmac_addr_add(u8 cgx_id, u8 lmac_id, u8 *mac_addr);
int cgx_lmac_addr_del(u8 cgx_id, u8 lmac_id, u8 index);
int cgx_lmac_addr_max_entries_get(u8 cgx_id, u8 lmac_id);
void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable);
void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable);
int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable);
......@@ -165,4 +172,7 @@ u8 cgx_get_lmacid(void *cgxd, u8 lmac_index);
unsigned long cgx_get_lmac_bmap(void *cgxd);
void cgx_lmac_write(int cgx_id, int lmac_id, u64 offset, u64 val);
u64 cgx_lmac_read(int cgx_id, int lmac_id, u64 offset);
int cgx_lmac_addr_update(u8 cgx_id, u8 lmac_id, u8 *mac_addr, u8 index);
u64 cgx_read_dmac_ctrl(void *cgxd, int lmac_id);
u64 cgx_read_dmac_entry(void *cgxd, int index);
#endif /* CGX_H */
......@@ -10,17 +10,19 @@
#include "rvu.h"
#include "cgx.h"
/**
* struct lmac
* struct lmac - per lmac locks and properties
* @wq_cmd_cmplt: waitq to keep the process blocked until cmd completion
* @cmd_lock: Lock to serialize the command interface
* @resp: command response
* @link_info: link related information
* @mac_to_index_bmap: Mac address to CGX table index mapping
* @event_cb: callback for linkchange events
* @event_cb_lock: lock for serializing callback with unregister
* @cmd_pend: flag set before new command is started
* flag cleared after command response is received
* @cgx: parent cgx port
* @mcast_filters_count: Number of multicast filters installed
* @lmac_id: lmac port id
* @cmd_pend: flag set before new command is started
* flag cleared after command response is received
* @name: lmac port name
*/
struct lmac {
......@@ -29,12 +31,14 @@ struct lmac {
struct mutex cmd_lock;
u64 resp;
struct cgx_link_user_info link_info;
struct rsrc_bmap mac_to_index_bmap;
struct cgx_event_cb event_cb;
/* lock for serializing callback with unregister */
spinlock_t event_cb_lock;
bool cmd_pend;
struct cgx *cgx;
u8 mcast_filters_count;
u8 lmac_id;
bool cmd_pend;
char *name;
};
......
......@@ -165,7 +165,15 @@ M(CGX_SET_LINK_MODE, 0x214, cgx_set_link_mode, cgx_set_link_mode_req,\
M(CGX_FEATURES_GET, 0x215, cgx_features_get, msg_req, \
cgx_features_info_msg) \
M(RPM_STATS, 0x216, rpm_stats, msg_req, rpm_stats_rsp) \
/* NPA mbox IDs (range 0x400 - 0x5FF) */ \
M(CGX_MAC_ADDR_ADD, 0x217, cgx_mac_addr_add, cgx_mac_addr_add_req, \
cgx_mac_addr_add_rsp) \
M(CGX_MAC_ADDR_DEL, 0x218, cgx_mac_addr_del, cgx_mac_addr_del_req, \
msg_rsp) \
M(CGX_MAC_MAX_ENTRIES_GET, 0x219, cgx_mac_max_entries_get, msg_req, \
cgx_max_dmac_entries_get_rsp) \
M(CGX_MAC_ADDR_RESET, 0x21A, cgx_mac_addr_reset, msg_req, msg_rsp) \
M(CGX_MAC_ADDR_UPDATE, 0x21B, cgx_mac_addr_update, cgx_mac_addr_update_req, \
msg_rsp) \
/* NPA mbox IDs (range 0x400 - 0x5FF) */ \
M(NPA_LF_ALLOC, 0x400, npa_lf_alloc, \
npa_lf_alloc_req, npa_lf_alloc_rsp) \
......@@ -403,6 +411,38 @@ struct cgx_mac_addr_set_or_get {
u8 mac_addr[ETH_ALEN];
};
/* Structure for requesting the operation to
* add DMAC filter entry into CGX interface
*/
struct cgx_mac_addr_add_req {
struct mbox_msghdr hdr;
u8 mac_addr[ETH_ALEN];
};
/* Structure for response against the operation to
* add DMAC filter entry into CGX interface
*/
struct cgx_mac_addr_add_rsp {
struct mbox_msghdr hdr;
u8 index;
};
/* Structure for requesting the operation to
* delete DMAC filter entry from CGX interface
*/
struct cgx_mac_addr_del_req {
struct mbox_msghdr hdr;
u8 index;
};
/* Structure for response against the operation to
* get maximum supported DMAC filter entries
*/
struct cgx_max_dmac_entries_get_rsp {
struct mbox_msghdr hdr;
u8 max_dmac_filters;
};
struct cgx_link_user_info {
uint64_t link_up:1;
uint64_t full_duplex:1;
......@@ -501,6 +541,12 @@ struct cgx_set_link_mode_rsp {
int status;
};
struct cgx_mac_addr_update_req {
struct mbox_msghdr hdr;
u8 mac_addr[ETH_ALEN];
u8 index;
};
#define RVU_LMAC_FEAT_FC BIT_ULL(0) /* pause frames */
#define RVU_LMAC_FEAT_PTP BIT_ULL(1) /* precision time protocol */
#define RVU_MAC_VERSION BIT_ULL(2)
......
......@@ -657,6 +657,8 @@ void rvu_cgx_enadis_rx_bp(struct rvu *rvu, int pf, bool enable);
int rvu_cgx_start_stop_io(struct rvu *rvu, u16 pcifunc, bool start);
int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, int index,
int rxtxflag, u64 *stat);
void rvu_cgx_disable_dmac_entries(struct rvu *rvu, u16 pcifunc);
/* NPA APIs */
int rvu_npa_init(struct rvu *rvu);
void rvu_npa_freemem(struct rvu *rvu);
......@@ -742,6 +744,7 @@ void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
bool is_mac_feature_supported(struct rvu *rvu, int pf, int feature);
u32 rvu_cgx_get_fifolen(struct rvu *rvu);
void *rvu_first_cgx_pdata(struct rvu *rvu);
int cgxlmac_to_pf(struct rvu *rvu, int cgx_id, int lmac_id);
int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, u16 pcifunc, int nixlf,
int type);
......
......@@ -63,7 +63,7 @@ static u16 cgxlmac_to_pfmap(struct rvu *rvu, u8 cgx_id, u8 lmac_id)
return rvu->cgxlmac2pf_map[CGX_OFFSET(cgx_id) + lmac_id];
}
static int cgxlmac_to_pf(struct rvu *rvu, int cgx_id, int lmac_id)
int cgxlmac_to_pf(struct rvu *rvu, int cgx_id, int lmac_id)
{
unsigned long pfmap;
......@@ -454,6 +454,31 @@ int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start)
return 0;
}
void rvu_cgx_disable_dmac_entries(struct rvu *rvu, u16 pcifunc)
{
int pf = rvu_get_pf(pcifunc);
int i = 0, lmac_count = 0;
u8 max_dmac_filters;
u8 cgx_id, lmac_id;
void *cgx_dev;
if (!is_cgx_config_permitted(rvu, pcifunc))
return;
rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
cgx_dev = cgx_get_pdata(cgx_id);
lmac_count = cgx_get_lmac_cnt(cgx_dev);
max_dmac_filters = MAX_DMAC_ENTRIES_PER_CGX / lmac_count;
for (i = 0; i < max_dmac_filters; i++)
cgx_lmac_addr_del(cgx_id, lmac_id, i);
/* As cgx_lmac_addr_del does not clear entry for index 0
* so it needs to be done explicitly
*/
cgx_lmac_addr_reset(cgx_id, lmac_id);
}
int rvu_mbox_handler_cgx_start_rxtx(struct rvu *rvu, struct msg_req *req,
struct msg_rsp *rsp)
{
......@@ -557,6 +582,63 @@ int rvu_mbox_handler_cgx_mac_addr_set(struct rvu *rvu,
return 0;
}
int rvu_mbox_handler_cgx_mac_addr_add(struct rvu *rvu,
struct cgx_mac_addr_add_req *req,
struct cgx_mac_addr_add_rsp *rsp)
{
int pf = rvu_get_pf(req->hdr.pcifunc);
u8 cgx_id, lmac_id;
int rc = 0;
if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
return -EPERM;
rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
rc = cgx_lmac_addr_add(cgx_id, lmac_id, req->mac_addr);
if (rc >= 0) {
rsp->index = rc;
return 0;
}
return rc;
}
int rvu_mbox_handler_cgx_mac_addr_del(struct rvu *rvu,
struct cgx_mac_addr_del_req *req,
struct msg_rsp *rsp)
{
int pf = rvu_get_pf(req->hdr.pcifunc);
u8 cgx_id, lmac_id;
if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
return -EPERM;
rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
return cgx_lmac_addr_del(cgx_id, lmac_id, req->index);
}
int rvu_mbox_handler_cgx_mac_max_entries_get(struct rvu *rvu,
struct msg_req *req,
struct cgx_max_dmac_entries_get_rsp
*rsp)
{
int pf = rvu_get_pf(req->hdr.pcifunc);
u8 cgx_id, lmac_id;
/* If msg is received from PFs(which are not mapped to CGX LMACs)
* or VF then no entries are allocated for DMAC filters at CGX level.
* So returning zero.
*/
if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc)) {
rsp->max_dmac_filters = 0;
return 0;
}
rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
rsp->max_dmac_filters = cgx_lmac_addr_max_entries_get(cgx_id, lmac_id);
return 0;
}
int rvu_mbox_handler_cgx_mac_addr_get(struct rvu *rvu,
struct cgx_mac_addr_set_or_get *req,
struct cgx_mac_addr_set_or_get *rsp)
......@@ -953,3 +1035,30 @@ int rvu_mbox_handler_cgx_set_link_mode(struct rvu *rvu,
rsp->status = cgx_set_link_mode(cgxd, req->args, cgx_idx, lmac);
return 0;
}
int rvu_mbox_handler_cgx_mac_addr_reset(struct rvu *rvu, struct msg_req *req,
struct msg_rsp *rsp)
{
int pf = rvu_get_pf(req->hdr.pcifunc);
u8 cgx_id, lmac_id;
if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
return -EPERM;
rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
return cgx_lmac_addr_reset(cgx_id, lmac_id);
}
int rvu_mbox_handler_cgx_mac_addr_update(struct rvu *rvu,
struct cgx_mac_addr_update_req *req,
struct msg_rsp *rsp)
{
int pf = rvu_get_pf(req->hdr.pcifunc);
u8 cgx_id, lmac_id;
if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
return -EPERM;
rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
return cgx_lmac_addr_update(cgx_id, lmac_id, req->mac_addr, req->index);
}
......@@ -1971,10 +1971,9 @@ static int cgx_print_stats(struct seq_file *s, int lmac_id)
return err;
}
static int rvu_dbg_cgx_stat_display(struct seq_file *filp, void *unused)
static int rvu_dbg_derive_lmacid(struct seq_file *filp, int *lmac_id)
{
struct dentry *current_dir;
int err, lmac_id;
char *buf;
current_dir = filp->file->f_path.dentry->d_parent;
......@@ -1982,17 +1981,87 @@ static int rvu_dbg_cgx_stat_display(struct seq_file *filp, void *unused)
if (!buf)
return -EINVAL;
err = kstrtoint(buf + 1, 10, &lmac_id);
if (!err) {
err = cgx_print_stats(filp, lmac_id);
if (err)
return err;
}
return kstrtoint(buf + 1, 10, lmac_id);
}
static int rvu_dbg_cgx_stat_display(struct seq_file *filp, void *unused)
{
int lmac_id, err;
err = rvu_dbg_derive_lmacid(filp, &lmac_id);
if (!err)
return cgx_print_stats(filp, lmac_id);
return err;
}
RVU_DEBUG_SEQ_FOPS(cgx_stat, cgx_stat_display, NULL);
static int cgx_print_dmac_flt(struct seq_file *s, int lmac_id)
{
struct pci_dev *pdev = NULL;
void *cgxd = s->private;
char *bcast, *mcast;
u16 index, domain;
u8 dmac[ETH_ALEN];
struct rvu *rvu;
u64 cfg, mac;
int pf;
rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM,
PCI_DEVID_OCTEONTX2_RVU_AF, NULL));
if (!rvu)
return -ENODEV;
pf = cgxlmac_to_pf(rvu, cgx_get_cgxid(cgxd), lmac_id);
domain = 2;
pdev = pci_get_domain_bus_and_slot(domain, pf + 1, 0);
if (!pdev)
return 0;
cfg = cgx_read_dmac_ctrl(cgxd, lmac_id);
bcast = cfg & CGX_DMAC_BCAST_MODE ? "ACCEPT" : "REJECT";
mcast = cfg & CGX_DMAC_MCAST_MODE ? "ACCEPT" : "REJECT";
seq_puts(s,
"PCI dev RVUPF BROADCAST MULTICAST FILTER-MODE\n");
seq_printf(s, "%s PF%d %9s %9s",
dev_name(&pdev->dev), pf, bcast, mcast);
if (cfg & CGX_DMAC_CAM_ACCEPT)
seq_printf(s, "%12s\n\n", "UNICAST");
else
seq_printf(s, "%16s\n\n", "PROMISCUOUS");
seq_puts(s, "\nDMAC-INDEX ADDRESS\n");
for (index = 0 ; index < 32 ; index++) {
cfg = cgx_read_dmac_entry(cgxd, index);
/* Display enabled dmac entries associated with current lmac */
if (lmac_id == FIELD_GET(CGX_DMAC_CAM_ENTRY_LMACID, cfg) &&
FIELD_GET(CGX_DMAC_CAM_ADDR_ENABLE, cfg)) {
mac = FIELD_GET(CGX_RX_DMAC_ADR_MASK, cfg);
u64_to_ether_addr(mac, dmac);
seq_printf(s, "%7d %pM\n", index, dmac);
}
}
return 0;
}
static int rvu_dbg_cgx_dmac_flt_display(struct seq_file *filp, void *unused)
{
int err, lmac_id;
err = rvu_dbg_derive_lmacid(filp, &lmac_id);
if (!err)
return cgx_print_dmac_flt(filp, lmac_id);
return err;
}
RVU_DEBUG_SEQ_FOPS(cgx_dmac_flt, cgx_dmac_flt_display, NULL);
static void rvu_dbg_cgx_init(struct rvu *rvu)
{
struct mac_ops *mac_ops;
......@@ -2029,6 +2098,9 @@ static void rvu_dbg_cgx_init(struct rvu *rvu)
debugfs_create_file("stats", 0600, rvu->rvu_dbg.lmac,
cgx, &rvu_dbg_cgx_stat_fops);
debugfs_create_file("mac_filter", 0600,
rvu->rvu_dbg.lmac, cgx,
&rvu_dbg_cgx_dmac_flt_fops);
}
}
}
......
......@@ -346,6 +346,9 @@ static void nix_interface_deinit(struct rvu *rvu, u16 pcifunc, u8 nixlf)
/* Free and disable any MCAM entries used by this NIX LF */
rvu_npc_disable_mcam_entries(rvu, pcifunc, nixlf);
/* Disable DMAC filters used */
rvu_cgx_disable_dmac_entries(rvu, pcifunc);
}
int rvu_mbox_handler_nix_bp_disable(struct rvu *rvu,
......
......@@ -7,7 +7,7 @@ obj-$(CONFIG_OCTEONTX2_PF) += rvu_nicpf.o
obj-$(CONFIG_OCTEONTX2_VF) += rvu_nicvf.o
rvu_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o \
otx2_ptp.o otx2_flows.o otx2_tc.o cn10k.o
otx2_ptp.o otx2_flows.o otx2_tc.o cn10k.o otx2_dmac_flt.o
rvu_nicvf-y := otx2_vf.o
ccflags-y += -I$(srctree)/drivers/net/ethernet/marvell/octeontx2/af
......@@ -210,6 +210,9 @@ int otx2_set_mac_address(struct net_device *netdev, void *p)
/* update dmac field in vlan offload rule */
if (pfvf->flags & OTX2_FLAG_RX_VLAN_SUPPORT)
otx2_install_rxvlan_offload_flow(pfvf);
/* update dmac address in ntuple and DMAC filter list */
if (pfvf->flags & OTX2_FLAG_DMACFLTR_SUPPORT)
otx2_dmacflt_update_pfmac_flow(pfvf);
} else {
return -EPERM;
}
......
......@@ -288,6 +288,9 @@ struct otx2_flow_config {
u16 tc_flower_offset;
u16 ntuple_max_flows;
u16 tc_max_flows;
u8 dmacflt_max_flows;
u8 *bmap_to_dmacindex;
unsigned long dmacflt_bmap;
struct list_head flow_list;
};
......@@ -329,6 +332,7 @@ struct otx2_nic {
#define OTX2_FLAG_TC_FLOWER_SUPPORT BIT_ULL(11)
#define OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED BIT_ULL(12)
#define OTX2_FLAG_TC_MATCHALL_INGRESS_ENABLED BIT_ULL(13)
#define OTX2_FLAG_DMACFLTR_SUPPORT BIT_ULL(14)
u64 flags;
struct otx2_qset qset;
......@@ -834,4 +838,11 @@ int otx2_init_tc(struct otx2_nic *nic);
void otx2_shutdown_tc(struct otx2_nic *nic);
int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data);
/* CGX/RPM DMAC filters support */
int otx2_dmacflt_get_max_cnt(struct otx2_nic *pf);
int otx2_dmacflt_add(struct otx2_nic *pf, const u8 *mac, u8 bit_pos);
int otx2_dmacflt_remove(struct otx2_nic *pf, const u8 *mac, u8 bit_pos);
int otx2_dmacflt_update(struct otx2_nic *pf, u8 *mac, u8 bit_pos);
void otx2_dmacflt_reinstall_flows(struct otx2_nic *pf);
void otx2_dmacflt_update_pfmac_flow(struct otx2_nic *pfvf);
#endif /* OTX2_COMMON_H */
// SPDX-License-Identifier: GPL-2.0
/* Marvell OcteonTx2 RVU Physcial Function ethernet driver
*
* Copyright (C) 2021 Marvell.
*/
#include "otx2_common.h"
static int otx2_dmacflt_do_add(struct otx2_nic *pf, const u8 *mac,
u8 *dmac_index)
{
struct cgx_mac_addr_add_req *req;
struct cgx_mac_addr_add_rsp *rsp;
int err;
mutex_lock(&pf->mbox.lock);
req = otx2_mbox_alloc_msg_cgx_mac_addr_add(&pf->mbox);
if (!req) {
mutex_unlock(&pf->mbox.lock);
return -ENOMEM;
}
ether_addr_copy(req->mac_addr, mac);
err = otx2_sync_mbox_msg(&pf->mbox);
if (!err) {
rsp = (struct cgx_mac_addr_add_rsp *)
otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &req->hdr);
*dmac_index = rsp->index;
}
mutex_unlock(&pf->mbox.lock);
return err;
}
static int otx2_dmacflt_add_pfmac(struct otx2_nic *pf)
{
struct cgx_mac_addr_set_or_get *req;
int err;
mutex_lock(&pf->mbox.lock);
req = otx2_mbox_alloc_msg_cgx_mac_addr_set(&pf->mbox);
if (!req) {
mutex_unlock(&pf->mbox.lock);
return -ENOMEM;
}
ether_addr_copy(req->mac_addr, pf->netdev->dev_addr);
err = otx2_sync_mbox_msg(&pf->mbox);
mutex_unlock(&pf->mbox.lock);
return err;
}
int otx2_dmacflt_add(struct otx2_nic *pf, const u8 *mac, u8 bit_pos)
{
u8 *dmacindex;
/* Store dmacindex returned by CGX/RPM driver which will
* be used for macaddr update/remove
*/
dmacindex = &pf->flow_cfg->bmap_to_dmacindex[bit_pos];
if (ether_addr_equal(mac, pf->netdev->dev_addr))
return otx2_dmacflt_add_pfmac(pf);
else
return otx2_dmacflt_do_add(pf, mac, dmacindex);
}
static int otx2_dmacflt_do_remove(struct otx2_nic *pfvf, const u8 *mac,
u8 dmac_index)
{
struct cgx_mac_addr_del_req *req;
int err;
mutex_lock(&pfvf->mbox.lock);
req = otx2_mbox_alloc_msg_cgx_mac_addr_del(&pfvf->mbox);
if (!req) {
mutex_unlock(&pfvf->mbox.lock);
return -ENOMEM;
}
req->index = dmac_index;
err = otx2_sync_mbox_msg(&pfvf->mbox);
mutex_unlock(&pfvf->mbox.lock);
return err;
}
static int otx2_dmacflt_remove_pfmac(struct otx2_nic *pf)
{
struct msg_req *req;
int err;
mutex_lock(&pf->mbox.lock);
req = otx2_mbox_alloc_msg_cgx_mac_addr_reset(&pf->mbox);
if (!req) {
mutex_unlock(&pf->mbox.lock);
return -ENOMEM;
}
err = otx2_sync_mbox_msg(&pf->mbox);
mutex_unlock(&pf->mbox.lock);
return err;
}
int otx2_dmacflt_remove(struct otx2_nic *pf, const u8 *mac,
u8 bit_pos)
{
u8 dmacindex = pf->flow_cfg->bmap_to_dmacindex[bit_pos];
if (ether_addr_equal(mac, pf->netdev->dev_addr))
return otx2_dmacflt_remove_pfmac(pf);
else
return otx2_dmacflt_do_remove(pf, mac, dmacindex);
}
/* CGX/RPM blocks support max unicast entries of 32.
* on typical configuration MAC block associated
* with 4 lmacs, each lmac will have 8 dmac entries
*/
int otx2_dmacflt_get_max_cnt(struct otx2_nic *pf)
{
struct cgx_max_dmac_entries_get_rsp *rsp;
struct msg_req *msg;
int err;
mutex_lock(&pf->mbox.lock);
msg = otx2_mbox_alloc_msg_cgx_mac_max_entries_get(&pf->mbox);
if (!msg) {
mutex_unlock(&pf->mbox.lock);
return -ENOMEM;
}
err = otx2_sync_mbox_msg(&pf->mbox);
if (err)
goto out;
rsp = (struct cgx_max_dmac_entries_get_rsp *)
otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &msg->hdr);
pf->flow_cfg->dmacflt_max_flows = rsp->max_dmac_filters;
out:
mutex_unlock(&pf->mbox.lock);
return err;
}
int otx2_dmacflt_update(struct otx2_nic *pf, u8 *mac, u8 bit_pos)
{
struct cgx_mac_addr_update_req *req;
int rc;
mutex_lock(&pf->mbox.lock);
req = otx2_mbox_alloc_msg_cgx_mac_addr_update(&pf->mbox);
if (!req) {
mutex_unlock(&pf->mbox.lock);
rc = -ENOMEM;
}
ether_addr_copy(req->mac_addr, mac);
req->index = pf->flow_cfg->bmap_to_dmacindex[bit_pos];
rc = otx2_sync_mbox_msg(&pf->mbox);
mutex_unlock(&pf->mbox.lock);
return rc;
}
......@@ -18,6 +18,12 @@ struct otx2_flow {
bool is_vf;
u8 rss_ctx_id;
int vf;
bool dmac_filter;
};
enum dmac_req {
DMAC_ADDR_UPDATE,
DMAC_ADDR_DEL
};
static void otx2_clear_ntuple_flow_info(struct otx2_nic *pfvf, struct otx2_flow_config *flow_cfg)
......@@ -219,6 +225,22 @@ int otx2_mcam_flow_init(struct otx2_nic *pf)
if (!pf->mac_table)
return -ENOMEM;
otx2_dmacflt_get_max_cnt(pf);
/* DMAC filters are not allocated */
if (!pf->flow_cfg->dmacflt_max_flows)
return 0;
pf->flow_cfg->bmap_to_dmacindex =
devm_kzalloc(pf->dev, sizeof(u8) *
pf->flow_cfg->dmacflt_max_flows,
GFP_KERNEL);
if (!pf->flow_cfg->bmap_to_dmacindex)
return -ENOMEM;
pf->flags |= OTX2_FLAG_DMACFLTR_SUPPORT;
return 0;
}
......@@ -280,6 +302,12 @@ int otx2_add_macfilter(struct net_device *netdev, const u8 *mac)
{
struct otx2_nic *pf = netdev_priv(netdev);
if (bitmap_weight(&pf->flow_cfg->dmacflt_bmap,
pf->flow_cfg->dmacflt_max_flows))
netdev_warn(netdev,
"Add %pM to CGX/RPM DMAC filters list as well\n",
mac);
return otx2_do_add_macfilter(pf, mac);
}
......@@ -351,12 +379,22 @@ static void otx2_add_flow_to_list(struct otx2_nic *pfvf, struct otx2_flow *flow)
list_add(&flow->list, head);
}
static int otx2_get_maxflows(struct otx2_flow_config *flow_cfg)
{
if (flow_cfg->nr_flows == flow_cfg->ntuple_max_flows ||
bitmap_weight(&flow_cfg->dmacflt_bmap,
flow_cfg->dmacflt_max_flows))
return flow_cfg->ntuple_max_flows + flow_cfg->dmacflt_max_flows;
else
return flow_cfg->ntuple_max_flows;
}
int otx2_get_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
u32 location)
{
struct otx2_flow *iter;
if (location >= pfvf->flow_cfg->ntuple_max_flows)
if (location >= otx2_get_maxflows(pfvf->flow_cfg))
return -EINVAL;
list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
......@@ -378,7 +416,7 @@ int otx2_get_all_flows(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
int idx = 0;
int err = 0;
nfc->data = pfvf->flow_cfg->ntuple_max_flows;
nfc->data = otx2_get_maxflows(pfvf->flow_cfg);
while ((!err || err == -ENOENT) && idx < rule_cnt) {
err = otx2_get_flow(pfvf, nfc, location);
if (!err)
......@@ -760,6 +798,32 @@ int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
return 0;
}
static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,
struct ethtool_rx_flow_spec *fsp)
{
struct ethhdr *eth_mask = &fsp->m_u.ether_spec;
struct ethhdr *eth_hdr = &fsp->h_u.ether_spec;
u64 ring_cookie = fsp->ring_cookie;
u32 flow_type;
if (!(pfvf->flags & OTX2_FLAG_DMACFLTR_SUPPORT))
return false;
flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
/* CGX/RPM block dmac filtering configured for white listing
* check for action other than DROP
*/
if (flow_type == ETHER_FLOW && ring_cookie != RX_CLS_FLOW_DISC &&
!ethtool_get_flow_spec_ring_vf(ring_cookie)) {
if (is_zero_ether_addr(eth_mask->h_dest) &&
is_valid_ether_addr(eth_hdr->h_dest))
return true;
}
return false;
}
static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
{
u64 ring_cookie = flow->flow_spec.ring_cookie;
......@@ -818,14 +882,46 @@ static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
return err;
}
static int otx2_add_flow_with_pfmac(struct otx2_nic *pfvf,
struct otx2_flow *flow)
{
struct otx2_flow *pf_mac;
struct ethhdr *eth_hdr;
pf_mac = kzalloc(sizeof(*pf_mac), GFP_KERNEL);
if (!pf_mac)
return -ENOMEM;
pf_mac->entry = 0;
pf_mac->dmac_filter = true;
pf_mac->location = pfvf->flow_cfg->ntuple_max_flows;
memcpy(&pf_mac->flow_spec, &flow->flow_spec,
sizeof(struct ethtool_rx_flow_spec));
pf_mac->flow_spec.location = pf_mac->location;
/* Copy PF mac address */
eth_hdr = &pf_mac->flow_spec.h_u.ether_spec;
ether_addr_copy(eth_hdr->h_dest, pfvf->netdev->dev_addr);
/* Install DMAC filter with PF mac address */
otx2_dmacflt_add(pfvf, eth_hdr->h_dest, 0);
otx2_add_flow_to_list(pfvf, pf_mac);
pfvf->flow_cfg->nr_flows++;
set_bit(0, &pfvf->flow_cfg->dmacflt_bmap);
return 0;
}
int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)
{
struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
struct ethtool_rx_flow_spec *fsp = &nfc->fs;
struct otx2_flow *flow;
struct ethhdr *eth_hdr;
bool new = false;
int err = 0;
u32 ring;
int err;
ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
if (!(pfvf->flags & OTX2_FLAG_NTUPLE_SUPPORT))
......@@ -834,16 +930,15 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)
if (ring >= pfvf->hw.rx_queues && fsp->ring_cookie != RX_CLS_FLOW_DISC)
return -EINVAL;
if (fsp->location >= flow_cfg->ntuple_max_flows)
if (fsp->location >= otx2_get_maxflows(flow_cfg))
return -EINVAL;
flow = otx2_find_flow(pfvf, fsp->location);
if (!flow) {
flow = kzalloc(sizeof(*flow), GFP_ATOMIC);
flow = kzalloc(sizeof(*flow), GFP_KERNEL);
if (!flow)
return -ENOMEM;
flow->location = fsp->location;
flow->entry = flow_cfg->flow_ent[flow->location];
new = true;
}
/* struct copy */
......@@ -852,7 +947,54 @@ int otx2_add_flow(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc)
if (fsp->flow_type & FLOW_RSS)
flow->rss_ctx_id = nfc->rss_context;
err = otx2_add_flow_msg(pfvf, flow);
if (otx2_is_flow_rule_dmacfilter(pfvf, &flow->flow_spec)) {
eth_hdr = &flow->flow_spec.h_u.ether_spec;
/* Sync dmac filter table with updated fields */
if (flow->dmac_filter)
return otx2_dmacflt_update(pfvf, eth_hdr->h_dest,
flow->entry);
if (bitmap_full(&flow_cfg->dmacflt_bmap,
flow_cfg->dmacflt_max_flows)) {
netdev_warn(pfvf->netdev,
"Can't insert the rule %d as max allowed dmac filters are %d\n",
flow->location +
flow_cfg->dmacflt_max_flows,
flow_cfg->dmacflt_max_flows);
err = -EINVAL;
if (new)
kfree(flow);
return err;
}
/* Install PF mac address to DMAC filter list */
if (!test_bit(0, &flow_cfg->dmacflt_bmap))
otx2_add_flow_with_pfmac(pfvf, flow);
flow->dmac_filter = true;
flow->entry = find_first_zero_bit(&flow_cfg->dmacflt_bmap,
flow_cfg->dmacflt_max_flows);
fsp->location = flow_cfg->ntuple_max_flows + flow->entry;
flow->flow_spec.location = fsp->location;
flow->location = fsp->location;
set_bit(flow->entry, &flow_cfg->dmacflt_bmap);
otx2_dmacflt_add(pfvf, eth_hdr->h_dest, flow->entry);
} else {
if (flow->location >= pfvf->flow_cfg->ntuple_max_flows) {
netdev_warn(pfvf->netdev,
"Can't insert non dmac ntuple rule at %d, allowed range %d-0\n",
flow->location,
flow_cfg->ntuple_max_flows - 1);
err = -EINVAL;
} else {
flow->entry = flow_cfg->flow_ent[flow->location];
err = otx2_add_flow_msg(pfvf, flow);
}
}
if (err) {
if (new)
kfree(flow);
......@@ -890,20 +1032,70 @@ static int otx2_remove_flow_msg(struct otx2_nic *pfvf, u16 entry, bool all)
return err;
}
static void otx2_update_rem_pfmac(struct otx2_nic *pfvf, int req)
{
struct otx2_flow *iter;
struct ethhdr *eth_hdr;
bool found = false;
list_for_each_entry(iter, &pfvf->flow_cfg->flow_list, list) {
if (iter->dmac_filter && iter->entry == 0) {
eth_hdr = &iter->flow_spec.h_u.ether_spec;
if (req == DMAC_ADDR_DEL) {
otx2_dmacflt_remove(pfvf, eth_hdr->h_dest,
0);
clear_bit(0, &pfvf->flow_cfg->dmacflt_bmap);
found = true;
} else {
ether_addr_copy(eth_hdr->h_dest,
pfvf->netdev->dev_addr);
otx2_dmacflt_update(pfvf, eth_hdr->h_dest, 0);
}
break;
}
}
if (found) {
list_del(&iter->list);
kfree(iter);
pfvf->flow_cfg->nr_flows--;
}
}
int otx2_remove_flow(struct otx2_nic *pfvf, u32 location)
{
struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
struct otx2_flow *flow;
int err;
if (location >= flow_cfg->ntuple_max_flows)
if (location >= otx2_get_maxflows(flow_cfg))
return -EINVAL;
flow = otx2_find_flow(pfvf, location);
if (!flow)
return -ENOENT;
err = otx2_remove_flow_msg(pfvf, flow->entry, false);
if (flow->dmac_filter) {
struct ethhdr *eth_hdr = &flow->flow_spec.h_u.ether_spec;
/* user not allowed to remove dmac filter with interface mac */
if (ether_addr_equal(pfvf->netdev->dev_addr, eth_hdr->h_dest))
return -EPERM;
err = otx2_dmacflt_remove(pfvf, eth_hdr->h_dest,
flow->entry);
clear_bit(flow->entry, &flow_cfg->dmacflt_bmap);
/* If all dmac filters are removed delete macfilter with
* interface mac address and configure CGX/RPM block in
* promiscuous mode
*/
if (bitmap_weight(&flow_cfg->dmacflt_bmap,
flow_cfg->dmacflt_max_flows) == 1)
otx2_update_rem_pfmac(pfvf, DMAC_ADDR_DEL);
} else {
err = otx2_remove_flow_msg(pfvf, flow->entry, false);
}
if (err)
return err;
......@@ -1100,3 +1292,22 @@ int otx2_enable_rxvlan(struct otx2_nic *pf, bool enable)
mutex_unlock(&pf->mbox.lock);
return rsp_hdr->rc;
}
void otx2_dmacflt_reinstall_flows(struct otx2_nic *pf)
{
struct otx2_flow *iter;
struct ethhdr *eth_hdr;
list_for_each_entry(iter, &pf->flow_cfg->flow_list, list) {
if (iter->dmac_filter) {
eth_hdr = &iter->flow_spec.h_u.ether_spec;
otx2_dmacflt_add(pf, eth_hdr->h_dest,
iter->entry);
}
}
}
void otx2_dmacflt_update_pfmac_flow(struct otx2_nic *pfvf)
{
otx2_update_rem_pfmac(pfvf, DMAC_ADDR_UPDATE);
}
......@@ -1110,6 +1110,11 @@ static int otx2_cgx_config_loopback(struct otx2_nic *pf, bool enable)
struct msg_req *msg;
int err;
if (enable && bitmap_weight(&pf->flow_cfg->dmacflt_bmap,
pf->flow_cfg->dmacflt_max_flows))
netdev_warn(pf->netdev,
"CGX/RPM internal loopback might not work as DMAC filters are active\n");
mutex_lock(&pf->mbox.lock);
if (enable)
msg = otx2_mbox_alloc_msg_cgx_intlbk_enable(&pf->mbox);
......@@ -1644,6 +1649,10 @@ int otx2_open(struct net_device *netdev)
/* Restore pause frame settings */
otx2_config_pause_frm(pf);
/* Install DMAC Filters */
if (pf->flags & OTX2_FLAG_DMACFLTR_SUPPORT)
otx2_dmacflt_reinstall_flows(pf);
err = otx2_rxtx_enable(pf, true);
if (err)
goto err_tx_stop_queues;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment