Commit 63ee5157 authored by Hariprasad Kelam's avatar Hariprasad Kelam Committed by Jakub Kicinski
Browse files

octeontx2-pf: Add support for unicast MAC address filtering



Add unicast MAC address filtering support using install flow
message. Total of 8 MCAM entries are allocated for adding
unicast mac filtering rules. If the MCAM allocation fails,
the unicast filtering support will not be advertised.

Signed-off-by: default avatarHariprasad Kelam <hkelam@marvell.com>
Signed-off-by: default avatarSunil Goutham <sgoutham@marvell.com>
Signed-off-by: default avatarNaveen Mamindlapalli <naveenm@marvell.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent f0a1913f
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -229,12 +229,21 @@ struct otx2_ptp {

#define OTX2_HW_TIMESTAMP_LEN	8

struct otx2_mac_table {
	u8 addr[ETH_ALEN];
	u16 mcam_entry;
	bool inuse;
};

struct otx2_flow_config {
	u16			entry[NPC_MAX_NONCONTIG_ENTRIES];
	u32			nr_flows;
#define OTX2_MAX_NTUPLE_FLOWS	32
#define OTX2_MCAM_COUNT		OTX2_MAX_NTUPLE_FLOWS
#define OTX2_MAX_UNICAST_FLOWS	8
#define OTX2_MCAM_COUNT		(OTX2_MAX_NTUPLE_FLOWS + \
				 OTX2_MAX_UNICAST_FLOWS)
	u32			ntuple_offset;
	u32			unicast_offset;
	u32                     ntuple_max_flows;
	struct list_head	flow_list;
};
@@ -251,6 +260,7 @@ struct otx2_nic {
#define OTX2_FLAG_INTF_DOWN			BIT_ULL(2)
#define OTX2_FLAG_MCAM_ENTRIES_ALLOC		BIT_ULL(3)
#define OTX2_FLAG_NTUPLE_SUPPORT		BIT_ULL(4)
#define OTX2_FLAG_UCAST_FLTR_SUPPORT		BIT_ULL(5)
#define OTX2_FLAG_RX_PAUSE_ENABLED		BIT_ULL(9)
#define OTX2_FLAG_TX_PAUSE_ENABLED		BIT_ULL(10)
	u64			flags;
@@ -279,6 +289,7 @@ struct otx2_nic {
	struct refill_work	*refill_wrk;
	struct workqueue_struct	*otx2_wq;
	struct work_struct	rx_mode_work;
	struct otx2_mac_table	*mac_table;

	/* Ethtool stuff */
	u32			msg_enable;
@@ -674,5 +685,7 @@ int otx2_add_flow(struct otx2_nic *pfvf,
int otx2_remove_flow(struct otx2_nic *pfvf, u32 location);
int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
			      struct npc_install_flow_req *req);
int otx2_del_macfilter(struct net_device *netdev, const u8 *mac);
int otx2_add_macfilter(struct net_device *netdev, const u8 *mac);

#endif /* OTX2_COMMON_H */
+115 −5
Original line number Diff line number Diff line
@@ -46,14 +46,21 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf)
	rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp
	       (&pfvf->mbox.mbox, 0, &req->hdr);

	if (rsp->count != req->count)
	if (rsp->count != req->count) {
		netdev_info(pfvf->netdev,
			    "Unable to allocate %d MCAM entries, got %d\n",
			    req->count, rsp->count);

		/* support only ntuples here */
		flow_cfg->ntuple_max_flows = rsp->count;
		flow_cfg->ntuple_offset = 0;
		pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
	} else {
		flow_cfg->ntuple_offset = 0;
		flow_cfg->unicast_offset = flow_cfg->ntuple_offset +
						OTX2_MAX_NTUPLE_FLOWS;
		pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
		pfvf->flags |= OTX2_FLAG_UCAST_FLTR_SUPPORT;
	}

	for (i = 0; i < rsp->count; i++)
		flow_cfg->entry[i] = rsp->entry_list[i];
@@ -82,6 +89,11 @@ int otx2_mcam_flow_init(struct otx2_nic *pf)
	if (err)
		return err;

	pf->mac_table = devm_kzalloc(pf->dev, sizeof(struct otx2_mac_table)
					* OTX2_MAX_UNICAST_FLOWS, GFP_KERNEL);
	if (!pf->mac_table)
		return -ENOMEM;

	return 0;
}

@@ -90,6 +102,104 @@ void otx2_mcam_flow_del(struct otx2_nic *pf)
	otx2_destroy_mcam_flows(pf);
}

/*  On success adds mcam entry
 *  On failure enable promisous mode
 */
static int otx2_do_add_macfilter(struct otx2_nic *pf, const u8 *mac)
{
	struct otx2_flow_config *flow_cfg = pf->flow_cfg;
	struct npc_install_flow_req *req;
	int err, i;

	if (!(pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT))
		return -ENOMEM;

	/* dont have free mcam entries or uc list is greater than alloted */
	if (netdev_uc_count(pf->netdev) > OTX2_MAX_UNICAST_FLOWS)
		return -ENOMEM;

	mutex_lock(&pf->mbox.lock);
	req = otx2_mbox_alloc_msg_npc_install_flow(&pf->mbox);
	if (!req) {
		mutex_unlock(&pf->mbox.lock);
		return -ENOMEM;
	}

	/* unicast offset starts with 32 0..31 for ntuple */
	for (i = 0; i <  OTX2_MAX_UNICAST_FLOWS; i++) {
		if (pf->mac_table[i].inuse)
			continue;
		ether_addr_copy(pf->mac_table[i].addr, mac);
		pf->mac_table[i].inuse = true;
		pf->mac_table[i].mcam_entry =
			flow_cfg->entry[i + flow_cfg->unicast_offset];
		req->entry =  pf->mac_table[i].mcam_entry;
		break;
	}

	ether_addr_copy(req->packet.dmac, mac);
	eth_broadcast_addr((u8 *)&req->mask.dmac);
	req->features = BIT_ULL(NPC_DMAC);
	req->channel = pf->hw.rx_chan_base;
	req->intf = NIX_INTF_RX;
	req->op = NIX_RX_ACTION_DEFAULT;
	req->set_cntr = 1;

	err = otx2_sync_mbox_msg(&pf->mbox);
	mutex_unlock(&pf->mbox.lock);

	return err;
}

int otx2_add_macfilter(struct net_device *netdev, const u8 *mac)
{
	struct otx2_nic *pf = netdev_priv(netdev);

	return otx2_do_add_macfilter(pf, mac);
}

static bool otx2_get_mcamentry_for_mac(struct otx2_nic *pf, const u8 *mac,
				       int *mcam_entry)
{
	int i;

	for (i = 0; i < OTX2_MAX_UNICAST_FLOWS; i++) {
		if (!pf->mac_table[i].inuse)
			continue;

		if (ether_addr_equal(pf->mac_table[i].addr, mac)) {
			*mcam_entry = pf->mac_table[i].mcam_entry;
			pf->mac_table[i].inuse = false;
			return true;
		}
	}
	return false;
}

int otx2_del_macfilter(struct net_device *netdev, const u8 *mac)
{
	struct otx2_nic *pf = netdev_priv(netdev);
	struct npc_delete_flow_req *req;
	int err, mcam_entry;

	/* check does mcam entry exists for given mac */
	if (!otx2_get_mcamentry_for_mac(pf, mac, &mcam_entry))
		return 0;

	mutex_lock(&pf->mbox.lock);
	req = otx2_mbox_alloc_msg_npc_delete_flow(&pf->mbox);
	if (!req) {
		mutex_unlock(&pf->mbox.lock);
		return -ENOMEM;
	}
	req->entry = mcam_entry;
	/* Send message to AF */
	err = otx2_sync_mbox_msg(&pf->mbox);
	mutex_unlock(&pf->mbox.lock);

	return err;
}

static struct otx2_flow *otx2_find_flow(struct otx2_nic *pfvf, u32 location)
{
	struct otx2_flow *iter;
+14 −1
Original line number Diff line number Diff line
@@ -1720,10 +1720,20 @@ static void otx2_do_set_rx_mode(struct work_struct *work)
	struct otx2_nic *pf = container_of(work, struct otx2_nic, rx_mode_work);
	struct net_device *netdev = pf->netdev;
	struct nix_rx_mode *req;
	bool promisc = false;

	if (!(netdev->flags & IFF_UP))
		return;

	if ((netdev->flags & IFF_PROMISC) ||
	    (netdev_uc_count(netdev) > OTX2_MAX_UNICAST_FLOWS)) {
		promisc = true;
	}

	/* Write unicast address to mcam entries or del from mcam */
	if (!promisc && netdev->priv_flags & IFF_UNICAST_FLT)
		__dev_uc_sync(netdev, otx2_add_macfilter, otx2_del_macfilter);

	mutex_lock(&pf->mbox.lock);
	req = otx2_mbox_alloc_msg_nix_set_rx_mode(&pf->mbox);
	if (!req) {
@@ -1733,7 +1743,7 @@ static void otx2_do_set_rx_mode(struct work_struct *work)

	req->mode = NIX_RX_MODE_UCAST;

	if (netdev->flags & IFF_PROMISC)
	if (promisc)
		req->mode |= NIX_RX_MODE_PROMISC;
	else if (netdev->flags & (IFF_ALLMULTI | IFF_MULTICAST))
		req->mode |= NIX_RX_MODE_ALLMULTI;
@@ -2125,6 +2135,9 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	if (pf->flags & OTX2_FLAG_NTUPLE_SUPPORT)
		netdev->hw_features |= NETIF_F_NTUPLE;

	if (pf->flags & OTX2_FLAG_UCAST_FLTR_SUPPORT)
		netdev->priv_flags |= IFF_UNICAST_FLT;

	netdev->gso_max_segs = OTX2_MAX_GSO_SEGS;
	netdev->watchdog_timeo = OTX2_TX_TIMEOUT;