@@ -228,10 +228,17 @@ 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;
u32 ntuple_offset;
+ u32 unicast_offset;
u32 ntuple_max_flows;
struct list_head flow_list;
};
@@ -248,6 +255,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;
@@ -673,5 +681,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 */
@@ -10,8 +10,10 @@
/* helper macros to support mcam flows */
#define OTX2_MAX_NTUPLE_FLOWS 32
+#define OTX2_MAX_UNICAST_FLOWS 8
-#define OTX2_MCAM_COUNT OTX2_MAX_NTUPLE_FLOWS
+#define OTX2_MCAM_COUNT (OTX2_MAX_NTUPLE_FLOWS + \
+ OTX2_MAX_UNICAST_FLOWS)
#define OTX2_DEFAULT_ACTION 0x1
@@ -35,7 +37,13 @@ int otx2_mcam_flow_init(struct otx2_nic *pf)
pf->flow_cfg->ntuple_max_flows = OTX2_MAX_NTUPLE_FLOWS;
- pf->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
+ pf->flags |= OTX2_FLAG_NTUPLE_SUPPORT |
+ OTX2_FLAG_UCAST_FLTR_SUPPORT;
+
+ 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;
}
@@ -77,13 +85,19 @@ 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, "number of rules truncated to %d\n",
rsp->count);
-
- /* support only ntuples here */
- flow_cfg->ntuple_max_flows = rsp->count;
- flow_cfg->ntuple_offset = 0;
+ /* support only ntuples here */
+ flow_cfg->ntuple_max_flows = rsp->count;
+ flow_cfg->ntuple_offset = 0;
+ pfvf->netdev->priv_flags &= ~IFF_UNICAST_FLT;
+ pfvf->flags &= ~OTX2_FLAG_UCAST_FLTR_SUPPORT;
+ } else {
+ flow_cfg->ntuple_offset = 0;
+ flow_cfg->unicast_offset = flow_cfg->ntuple_offset +
+ OTX2_MAX_NTUPLE_FLOWS;
+ }
for (i = 0; i < rsp->count; i++)
flow_cfg->entry[i] = rsp->entry_list[i];
@@ -94,6 +108,116 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf)
return 0;
}
+/* 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_MCAM_ENTRIES_ALLOC)) {
+ err = otx2_alloc_mcam_entries(pf);
+ if (err)
+ return err;
+ }
+
+ 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);
+ u64_to_ether_addr(0xffffffffffffull, 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);
+ int err;
+
+ err = otx2_do_add_macfilter(pf, mac);
+ if (err) {
+ netdev->flags |= IFF_PROMISC;
+ return err;
+ }
+ return 0;
+}
+
+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;
@@ -1724,6 +1724,10 @@ void otx2_do_set_rx_mode(struct work_struct *work)
if (!(netdev->flags & IFF_UP))
return;
+ /* Write unicast address to mcam entries or del from mcam */
+ if (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) {
@@ -2118,6 +2122,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
netdev->hw_features |= NETIF_F_LOOPBACK | NETIF_F_NTUPLE |
NETIF_F_RXALL;
+ netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->gso_max_segs = OTX2_MAX_GSO_SEGS;
netdev->watchdog_timeo = OTX2_TX_TIMEOUT;