0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 #include "cxgb4.h"
0036 #include "smt.h"
0037 #include "t4_msg.h"
0038 #include "t4fw_api.h"
0039 #include "t4_regs.h"
0040 #include "t4_values.h"
0041
0042 struct smt_data *t4_init_smt(void)
0043 {
0044 unsigned int smt_size;
0045 struct smt_data *s;
0046 int i;
0047
0048 smt_size = SMT_SIZE;
0049
0050 s = kvzalloc(struct_size(s, smtab, smt_size), GFP_KERNEL);
0051 if (!s)
0052 return NULL;
0053 s->smt_size = smt_size;
0054 rwlock_init(&s->lock);
0055 for (i = 0; i < s->smt_size; ++i) {
0056 s->smtab[i].idx = i;
0057 s->smtab[i].state = SMT_STATE_UNUSED;
0058 eth_zero_addr(s->smtab[i].src_mac);
0059 spin_lock_init(&s->smtab[i].lock);
0060 s->smtab[i].refcnt = 0;
0061 }
0062 return s;
0063 }
0064
0065 static struct smt_entry *find_or_alloc_smte(struct smt_data *s, u8 *smac)
0066 {
0067 struct smt_entry *first_free = NULL;
0068 struct smt_entry *e, *end;
0069
0070 for (e = &s->smtab[0], end = &s->smtab[s->smt_size]; e != end; ++e) {
0071 if (e->refcnt == 0) {
0072 if (!first_free)
0073 first_free = e;
0074 } else {
0075 if (e->state == SMT_STATE_SWITCHING) {
0076
0077
0078
0079 if (memcmp(e->src_mac, smac, ETH_ALEN) == 0)
0080 goto found_reuse;
0081 }
0082 }
0083 }
0084
0085 if (first_free) {
0086 e = first_free;
0087 goto found;
0088 }
0089 return NULL;
0090
0091 found:
0092 e->state = SMT_STATE_UNUSED;
0093
0094 found_reuse:
0095 return e;
0096 }
0097
0098 static void t4_smte_free(struct smt_entry *e)
0099 {
0100 if (e->refcnt == 0) {
0101 e->state = SMT_STATE_UNUSED;
0102 }
0103 }
0104
0105
0106
0107
0108
0109
0110
0111 void cxgb4_smt_release(struct smt_entry *e)
0112 {
0113 spin_lock_bh(&e->lock);
0114 if ((--e->refcnt) == 0)
0115 t4_smte_free(e);
0116 spin_unlock_bh(&e->lock);
0117 }
0118 EXPORT_SYMBOL(cxgb4_smt_release);
0119
0120 void do_smt_write_rpl(struct adapter *adap, const struct cpl_smt_write_rpl *rpl)
0121 {
0122 unsigned int smtidx = TID_TID_G(GET_TID(rpl));
0123 struct smt_data *s = adap->smt;
0124
0125 if (unlikely(rpl->status != CPL_ERR_NONE)) {
0126 struct smt_entry *e = &s->smtab[smtidx];
0127
0128 dev_err(adap->pdev_dev,
0129 "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
0130 rpl->status, smtidx);
0131 spin_lock(&e->lock);
0132 e->state = SMT_STATE_ERROR;
0133 spin_unlock(&e->lock);
0134 return;
0135 }
0136 }
0137
0138 static int write_smt_entry(struct adapter *adapter, struct smt_entry *e)
0139 {
0140 struct cpl_t6_smt_write_req *t6req;
0141 struct smt_data *s = adapter->smt;
0142 struct cpl_smt_write_req *req;
0143 struct sk_buff *skb;
0144 int size;
0145 u8 row;
0146
0147 if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) {
0148 size = sizeof(*req);
0149 skb = alloc_skb(size, GFP_ATOMIC);
0150 if (!skb)
0151 return -ENOMEM;
0152
0153
0154
0155 req = (struct cpl_smt_write_req *)__skb_put(skb, size);
0156 INIT_TP_WR(req, 0);
0157
0158
0159
0160
0161 row = (e->idx >> 1);
0162 if (e->idx & 1) {
0163 req->pfvf1 = 0x0;
0164 memcpy(req->src_mac1, e->src_mac, ETH_ALEN);
0165
0166
0167
0168
0169 req->pfvf0 = 0x0;
0170 memcpy(req->src_mac0, s->smtab[e->idx - 1].src_mac,
0171 ETH_ALEN);
0172 } else {
0173 req->pfvf0 = 0x0;
0174 memcpy(req->src_mac0, e->src_mac, ETH_ALEN);
0175
0176
0177
0178
0179 req->pfvf1 = 0x0;
0180 memcpy(req->src_mac1, s->smtab[e->idx + 1].src_mac,
0181 ETH_ALEN);
0182 }
0183 } else {
0184 size = sizeof(*t6req);
0185 skb = alloc_skb(size, GFP_ATOMIC);
0186 if (!skb)
0187 return -ENOMEM;
0188
0189 t6req = (struct cpl_t6_smt_write_req *)__skb_put(skb, size);
0190 INIT_TP_WR(t6req, 0);
0191 req = (struct cpl_smt_write_req *)t6req;
0192
0193
0194 req->pfvf0 = 0x0;
0195 memcpy(req->src_mac0, s->smtab[e->idx].src_mac, ETH_ALEN);
0196 row = e->idx;
0197 }
0198
0199 OPCODE_TID(req) =
0200 htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, e->idx |
0201 TID_QID_V(adapter->sge.fw_evtq.abs_id)));
0202 req->params = htonl(SMTW_NORPL_V(0) |
0203 SMTW_IDX_V(row) |
0204 SMTW_OVLAN_IDX_V(0));
0205 t4_mgmt_tx(adapter, skb);
0206 return 0;
0207 }
0208
0209 static struct smt_entry *t4_smt_alloc_switching(struct adapter *adap, u16 pfvf,
0210 u8 *smac)
0211 {
0212 struct smt_data *s = adap->smt;
0213 struct smt_entry *e;
0214
0215 write_lock_bh(&s->lock);
0216 e = find_or_alloc_smte(s, smac);
0217 if (e) {
0218 spin_lock(&e->lock);
0219 if (!e->refcnt) {
0220 e->refcnt = 1;
0221 e->state = SMT_STATE_SWITCHING;
0222 e->pfvf = pfvf;
0223 memcpy(e->src_mac, smac, ETH_ALEN);
0224 write_smt_entry(adap, e);
0225 } else {
0226 ++e->refcnt;
0227 }
0228 spin_unlock(&e->lock);
0229 }
0230 write_unlock_bh(&s->lock);
0231 return e;
0232 }
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242 struct smt_entry *cxgb4_smt_alloc_switching(struct net_device *dev, u8 *smac)
0243 {
0244 struct adapter *adap = netdev2adap(dev);
0245
0246 return t4_smt_alloc_switching(adap, 0x0, smac);
0247 }
0248 EXPORT_SYMBOL(cxgb4_smt_alloc_switching);