OSDN Git Service

octeontx2-pf: Add support for unicast MAC address filtering
authorHariprasad Kelam <hkelam@marvell.com>
Sat, 14 Nov 2020 19:52:56 +0000 (01:22 +0530)
committerJakub Kicinski <kuba@kernel.org>
Tue, 17 Nov 2020 21:48:20 +0000 (13:48 -0800)
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: Hariprasad Kelam <hkelam@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
Signed-off-by: Naveen Mamindlapalli <naveenm@marvell.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c

index 2387c40..f959688 100644 (file)
@@ -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 */
index e02293e..f297edb 100644 (file)
@@ -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);
-
-       flow_cfg->ntuple_max_flows = rsp->count;
-       flow_cfg->ntuple_offset = 0;
-       pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
+               /* 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;
index 9cf3e19..ac90302 100644 (file)
@@ -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;