linux/drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (c) 2019 Chelsio Communications, Inc. All rights reserved. */
   3
   4#include "cxgb4.h"
   5
   6static int cxgb4_mps_ref_dec_by_mac(struct adapter *adap,
   7                                    const u8 *addr, const u8 *mask)
   8{
   9        u8 bitmask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  10        struct mps_entries_ref *mps_entry, *tmp;
  11        int ret = -EINVAL;
  12
  13        spin_lock_bh(&adap->mps_ref_lock);
  14        list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) {
  15                if (ether_addr_equal(mps_entry->addr, addr) &&
  16                    ether_addr_equal(mps_entry->mask, mask ? mask : bitmask)) {
  17                        if (!refcount_dec_and_test(&mps_entry->refcnt)) {
  18                                spin_unlock_bh(&adap->mps_ref_lock);
  19                                return -EBUSY;
  20                        }
  21                        list_del(&mps_entry->list);
  22                        kfree(mps_entry);
  23                        ret = 0;
  24                        break;
  25                }
  26        }
  27        spin_unlock_bh(&adap->mps_ref_lock);
  28        return ret;
  29}
  30
  31static int cxgb4_mps_ref_dec(struct adapter *adap, u16 idx)
  32{
  33        struct mps_entries_ref *mps_entry, *tmp;
  34        int ret = -EINVAL;
  35
  36        spin_lock(&adap->mps_ref_lock);
  37        list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) {
  38                if (mps_entry->idx == idx) {
  39                        if (!refcount_dec_and_test(&mps_entry->refcnt)) {
  40                                spin_unlock(&adap->mps_ref_lock);
  41                                return -EBUSY;
  42                        }
  43                        list_del(&mps_entry->list);
  44                        kfree(mps_entry);
  45                        ret = 0;
  46                        break;
  47                }
  48        }
  49        spin_unlock(&adap->mps_ref_lock);
  50        return ret;
  51}
  52
  53static int cxgb4_mps_ref_inc(struct adapter *adap, const u8 *mac_addr,
  54                             u16 idx, const u8 *mask)
  55{
  56        u8 bitmask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  57        struct mps_entries_ref *mps_entry;
  58        int ret = 0;
  59
  60        spin_lock_bh(&adap->mps_ref_lock);
  61        list_for_each_entry(mps_entry, &adap->mps_ref, list) {
  62                if (mps_entry->idx == idx) {
  63                        refcount_inc(&mps_entry->refcnt);
  64                        goto unlock;
  65                }
  66        }
  67        mps_entry = kzalloc(sizeof(*mps_entry), GFP_ATOMIC);
  68        if (!mps_entry) {
  69                ret = -ENOMEM;
  70                goto unlock;
  71        }
  72        ether_addr_copy(mps_entry->mask, mask ? mask : bitmask);
  73        ether_addr_copy(mps_entry->addr, mac_addr);
  74        mps_entry->idx = idx;
  75        refcount_set(&mps_entry->refcnt, 1);
  76        list_add_tail(&mps_entry->list, &adap->mps_ref);
  77unlock:
  78        spin_unlock_bh(&adap->mps_ref_lock);
  79        return ret;
  80}
  81
  82int cxgb4_free_mac_filt(struct adapter *adap, unsigned int viid,
  83                        unsigned int naddr, const u8 **addr, bool sleep_ok)
  84{
  85        int ret, i;
  86
  87        for (i = 0; i < naddr; i++) {
  88                if (!cxgb4_mps_ref_dec_by_mac(adap, addr[i], NULL)) {
  89                        ret = t4_free_mac_filt(adap, adap->mbox, viid,
  90                                               1, &addr[i], sleep_ok);
  91                        if (ret < 0)
  92                                return ret;
  93                }
  94        }
  95
  96        /* return number of filters freed */
  97        return naddr;
  98}
  99
 100int cxgb4_alloc_mac_filt(struct adapter *adap, unsigned int viid,
 101                         bool free, unsigned int naddr, const u8 **addr,
 102                         u16 *idx, u64 *hash, bool sleep_ok)
 103{
 104        int ret, i;
 105
 106        ret = t4_alloc_mac_filt(adap, adap->mbox, viid, free,
 107                                naddr, addr, idx, hash, sleep_ok);
 108        if (ret < 0)
 109                return ret;
 110
 111        for (i = 0; i < naddr; i++) {
 112                if (idx[i] != 0xffff) {
 113                        if (cxgb4_mps_ref_inc(adap, addr[i], idx[i], NULL)) {
 114                                ret = -ENOMEM;
 115                                goto error;
 116                        }
 117                }
 118        }
 119
 120        goto out;
 121error:
 122        cxgb4_free_mac_filt(adap, viid, naddr, addr, sleep_ok);
 123
 124out:
 125        /* Returns a negative error number or the number of filters allocated */
 126        return ret;
 127}
 128
 129int cxgb4_update_mac_filt(struct port_info *pi, unsigned int viid,
 130                          int *tcam_idx, const u8 *addr,
 131                          bool persistent, u8 *smt_idx)
 132{
 133        int ret;
 134
 135        ret = cxgb4_change_mac(pi, viid, tcam_idx,
 136                               addr, persistent, smt_idx);
 137        if (ret < 0)
 138                return ret;
 139
 140        cxgb4_mps_ref_inc(pi->adapter, addr, *tcam_idx, NULL);
 141        return ret;
 142}
 143
 144int cxgb4_free_raw_mac_filt(struct adapter *adap,
 145                            unsigned int viid,
 146                            const u8 *addr,
 147                            const u8 *mask,
 148                            unsigned int idx,
 149                            u8 lookup_type,
 150                            u8 port_id,
 151                            bool sleep_ok)
 152{
 153        int ret = 0;
 154
 155        if (!cxgb4_mps_ref_dec(adap, idx))
 156                ret = t4_free_raw_mac_filt(adap, viid, addr,
 157                                           mask, idx, lookup_type,
 158                                           port_id, sleep_ok);
 159
 160        return ret;
 161}
 162
 163int cxgb4_alloc_raw_mac_filt(struct adapter *adap,
 164                             unsigned int viid,
 165                             const u8 *addr,
 166                             const u8 *mask,
 167                             unsigned int idx,
 168                             u8 lookup_type,
 169                             u8 port_id,
 170                             bool sleep_ok)
 171{
 172        int ret;
 173
 174        ret = t4_alloc_raw_mac_filt(adap, viid, addr,
 175                                    mask, idx, lookup_type,
 176                                    port_id, sleep_ok);
 177        if (ret < 0)
 178                return ret;
 179
 180        if (cxgb4_mps_ref_inc(adap, addr, ret, mask)) {
 181                ret = -ENOMEM;
 182                t4_free_raw_mac_filt(adap, viid, addr,
 183                                     mask, idx, lookup_type,
 184                                     port_id, sleep_ok);
 185        }
 186
 187        return ret;
 188}
 189
 190int cxgb4_free_encap_mac_filt(struct adapter *adap, unsigned int viid,
 191                              int idx, bool sleep_ok)
 192{
 193        int ret = 0;
 194
 195        if (!cxgb4_mps_ref_dec(adap, idx))
 196                ret = t4_free_encap_mac_filt(adap, viid, idx, sleep_ok);
 197
 198        return ret;
 199}
 200
 201int cxgb4_alloc_encap_mac_filt(struct adapter *adap, unsigned int viid,
 202                               const u8 *addr, const u8 *mask,
 203                               unsigned int vni, unsigned int vni_mask,
 204                               u8 dip_hit, u8 lookup_type, bool sleep_ok)
 205{
 206        int ret;
 207
 208        ret = t4_alloc_encap_mac_filt(adap, viid, addr, mask, vni, vni_mask,
 209                                      dip_hit, lookup_type, sleep_ok);
 210        if (ret < 0)
 211                return ret;
 212
 213        if (cxgb4_mps_ref_inc(adap, addr, ret, mask)) {
 214                ret = -ENOMEM;
 215                t4_free_encap_mac_filt(adap, viid, ret, sleep_ok);
 216        }
 217        return ret;
 218}
 219
 220int cxgb4_init_mps_ref_entries(struct adapter *adap)
 221{
 222        spin_lock_init(&adap->mps_ref_lock);
 223        INIT_LIST_HEAD(&adap->mps_ref);
 224
 225        return 0;
 226}
 227
 228void cxgb4_free_mps_ref_entries(struct adapter *adap)
 229{
 230        struct mps_entries_ref *mps_entry, *tmp;
 231
 232        if (list_empty(&adap->mps_ref))
 233                return;
 234
 235        spin_lock(&adap->mps_ref_lock);
 236        list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) {
 237                list_del(&mps_entry->list);
 238                kfree(mps_entry);
 239        }
 240        spin_unlock(&adap->mps_ref_lock);
 241}
 242