0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/bitfield.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/irqdomain.h>
0012
0013 #include "chip.h"
0014 #include "global1.h"
0015
0016
0017
0018 static int mv88e6xxx_g1_atu_fid_write(struct mv88e6xxx_chip *chip, u16 fid)
0019 {
0020 return mv88e6xxx_g1_write(chip, MV88E6352_G1_ATU_FID, fid & 0xfff);
0021 }
0022
0023
0024
0025 int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip *chip, bool learn2all)
0026 {
0027 u16 val;
0028 int err;
0029
0030 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val);
0031 if (err)
0032 return err;
0033
0034 if (learn2all)
0035 val |= MV88E6XXX_G1_ATU_CTL_LEARN2ALL;
0036 else
0037 val &= ~MV88E6XXX_G1_ATU_CTL_LEARN2ALL;
0038
0039 return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val);
0040 }
0041
0042 int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip,
0043 unsigned int msecs)
0044 {
0045 const unsigned int coeff = chip->info->age_time_coeff;
0046 const unsigned int min = 0x01 * coeff;
0047 const unsigned int max = 0xff * coeff;
0048 u8 age_time;
0049 u16 val;
0050 int err;
0051
0052 if (msecs < min || msecs > max)
0053 return -ERANGE;
0054
0055
0056 age_time = (msecs + coeff / 2) / coeff;
0057
0058 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val);
0059 if (err)
0060 return err;
0061
0062
0063 val &= ~0xff0;
0064 val |= age_time << 4;
0065
0066 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val);
0067 if (err)
0068 return err;
0069
0070 dev_dbg(chip->dev, "AgeTime set to 0x%02x (%d ms)\n", age_time,
0071 age_time * coeff);
0072
0073 return 0;
0074 }
0075
0076 int mv88e6165_g1_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
0077 {
0078 int err;
0079 u16 val;
0080
0081 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val);
0082 if (err)
0083 return err;
0084
0085 *hash = val & MV88E6161_G1_ATU_CTL_HASH_MASK;
0086
0087 return 0;
0088 }
0089
0090 int mv88e6165_g1_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash)
0091 {
0092 int err;
0093 u16 val;
0094
0095 if (hash & ~MV88E6161_G1_ATU_CTL_HASH_MASK)
0096 return -EINVAL;
0097
0098 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val);
0099 if (err)
0100 return err;
0101
0102 val &= ~MV88E6161_G1_ATU_CTL_HASH_MASK;
0103 val |= hash;
0104
0105 return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val);
0106 }
0107
0108
0109
0110 static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip)
0111 {
0112 int bit = __bf_shf(MV88E6XXX_G1_ATU_OP_BUSY);
0113
0114 return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0);
0115 }
0116
0117 static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
0118 {
0119 u16 val;
0120 int err;
0121
0122
0123 if (mv88e6xxx_num_databases(chip) > 256) {
0124 err = mv88e6xxx_g1_atu_fid_write(chip, fid);
0125 if (err)
0126 return err;
0127 } else {
0128 if (mv88e6xxx_num_databases(chip) > 64) {
0129
0130 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL,
0131 &val);
0132 if (err)
0133 return err;
0134
0135 val = (val & 0x0fff) | ((fid << 8) & 0xf000);
0136 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL,
0137 val);
0138 if (err)
0139 return err;
0140 } else if (mv88e6xxx_num_databases(chip) > 16) {
0141
0142 op |= (fid & 0x30) << 4;
0143 }
0144
0145
0146 op |= fid & 0xf;
0147 }
0148
0149 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP,
0150 MV88E6XXX_G1_ATU_OP_BUSY | op);
0151 if (err)
0152 return err;
0153
0154 return mv88e6xxx_g1_atu_op_wait(chip);
0155 }
0156
0157 int mv88e6xxx_g1_atu_get_next(struct mv88e6xxx_chip *chip, u16 fid)
0158 {
0159 return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB);
0160 }
0161
0162
0163
0164 static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip,
0165 struct mv88e6xxx_atu_entry *entry)
0166 {
0167 u16 val;
0168 int err;
0169
0170 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &val);
0171 if (err)
0172 return err;
0173
0174 entry->state = val & 0xf;
0175 if (entry->state) {
0176 entry->trunk = !!(val & MV88E6XXX_G1_ATU_DATA_TRUNK);
0177 entry->portvec = (val >> 4) & mv88e6xxx_port_mask(chip);
0178 }
0179
0180 return 0;
0181 }
0182
0183 static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip,
0184 struct mv88e6xxx_atu_entry *entry)
0185 {
0186 u16 data = entry->state & 0xf;
0187
0188 if (entry->state) {
0189 if (entry->trunk)
0190 data |= MV88E6XXX_G1_ATU_DATA_TRUNK;
0191
0192 data |= (entry->portvec & mv88e6xxx_port_mask(chip)) << 4;
0193 }
0194
0195 return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_DATA, data);
0196 }
0197
0198
0199
0200
0201
0202
0203 static int mv88e6xxx_g1_atu_mac_read(struct mv88e6xxx_chip *chip,
0204 struct mv88e6xxx_atu_entry *entry)
0205 {
0206 u16 val;
0207 int i, err;
0208
0209 for (i = 0; i < 3; i++) {
0210 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01 + i, &val);
0211 if (err)
0212 return err;
0213
0214 entry->mac[i * 2] = val >> 8;
0215 entry->mac[i * 2 + 1] = val & 0xff;
0216 }
0217
0218 return 0;
0219 }
0220
0221 static int mv88e6xxx_g1_atu_mac_write(struct mv88e6xxx_chip *chip,
0222 struct mv88e6xxx_atu_entry *entry)
0223 {
0224 u16 val;
0225 int i, err;
0226
0227 for (i = 0; i < 3; i++) {
0228 val = (entry->mac[i * 2] << 8) | entry->mac[i * 2 + 1];
0229 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_MAC01 + i, val);
0230 if (err)
0231 return err;
0232 }
0233
0234 return 0;
0235 }
0236
0237
0238
0239 int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid,
0240 struct mv88e6xxx_atu_entry *entry)
0241 {
0242 int err;
0243
0244 err = mv88e6xxx_g1_atu_op_wait(chip);
0245 if (err)
0246 return err;
0247
0248
0249 if (!entry->state) {
0250 err = mv88e6xxx_g1_atu_mac_write(chip, entry);
0251 if (err)
0252 return err;
0253 }
0254
0255 err = mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB);
0256 if (err)
0257 return err;
0258
0259 err = mv88e6xxx_g1_atu_data_read(chip, entry);
0260 if (err)
0261 return err;
0262
0263 return mv88e6xxx_g1_atu_mac_read(chip, entry);
0264 }
0265
0266 int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid,
0267 struct mv88e6xxx_atu_entry *entry)
0268 {
0269 int err;
0270
0271 err = mv88e6xxx_g1_atu_op_wait(chip);
0272 if (err)
0273 return err;
0274
0275 err = mv88e6xxx_g1_atu_mac_write(chip, entry);
0276 if (err)
0277 return err;
0278
0279 err = mv88e6xxx_g1_atu_data_write(chip, entry);
0280 if (err)
0281 return err;
0282
0283 return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_LOAD_DB);
0284 }
0285
0286 static int mv88e6xxx_g1_atu_flushmove(struct mv88e6xxx_chip *chip, u16 fid,
0287 struct mv88e6xxx_atu_entry *entry,
0288 bool all)
0289 {
0290 u16 op;
0291 int err;
0292
0293 err = mv88e6xxx_g1_atu_op_wait(chip);
0294 if (err)
0295 return err;
0296
0297 err = mv88e6xxx_g1_atu_data_write(chip, entry);
0298 if (err)
0299 return err;
0300
0301
0302 if (all && fid)
0303 op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL_DB;
0304 else if (fid)
0305 op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC_DB;
0306 else if (all)
0307 op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL;
0308 else
0309 op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC;
0310
0311 return mv88e6xxx_g1_atu_op(chip, fid, op);
0312 }
0313
0314 int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip *chip, u16 fid, bool all)
0315 {
0316 struct mv88e6xxx_atu_entry entry = {
0317 .state = 0,
0318 };
0319
0320 return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all);
0321 }
0322
0323 static int mv88e6xxx_g1_atu_move(struct mv88e6xxx_chip *chip, u16 fid,
0324 int from_port, int to_port, bool all)
0325 {
0326 struct mv88e6xxx_atu_entry entry = { 0 };
0327 unsigned long mask;
0328 int shift;
0329
0330 if (!chip->info->atu_move_port_mask)
0331 return -EOPNOTSUPP;
0332
0333 mask = chip->info->atu_move_port_mask;
0334 shift = bitmap_weight(&mask, 16);
0335
0336 entry.state = 0xf;
0337 entry.portvec = from_port & mask;
0338 entry.portvec |= (to_port & mask) << shift;
0339
0340 return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all);
0341 }
0342
0343 int mv88e6xxx_g1_atu_remove(struct mv88e6xxx_chip *chip, u16 fid, int port,
0344 bool all)
0345 {
0346 int from_port = port;
0347 int to_port = chip->info->atu_move_port_mask;
0348
0349 return mv88e6xxx_g1_atu_move(chip, fid, from_port, to_port, all);
0350 }
0351
0352 static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
0353 {
0354 struct mv88e6xxx_chip *chip = dev_id;
0355 struct mv88e6xxx_atu_entry entry;
0356 int spid;
0357 int err;
0358 u16 val;
0359
0360 mv88e6xxx_reg_lock(chip);
0361
0362 err = mv88e6xxx_g1_atu_op(chip, 0,
0363 MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
0364 if (err)
0365 goto out;
0366
0367 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &val);
0368 if (err)
0369 goto out;
0370
0371 err = mv88e6xxx_g1_atu_data_read(chip, &entry);
0372 if (err)
0373 goto out;
0374
0375 err = mv88e6xxx_g1_atu_mac_read(chip, &entry);
0376 if (err)
0377 goto out;
0378
0379 spid = entry.state;
0380
0381 if (val & MV88E6XXX_G1_ATU_OP_AGE_OUT_VIOLATION) {
0382 dev_err_ratelimited(chip->dev,
0383 "ATU age out violation for %pM\n",
0384 entry.mac);
0385 }
0386
0387 if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) {
0388 dev_err_ratelimited(chip->dev,
0389 "ATU member violation for %pM portvec %x spid %d\n",
0390 entry.mac, entry.portvec, spid);
0391 chip->ports[spid].atu_member_violation++;
0392 }
0393
0394 if (val & MV88E6XXX_G1_ATU_OP_MISS_VIOLATION) {
0395 dev_err_ratelimited(chip->dev,
0396 "ATU miss violation for %pM portvec %x spid %d\n",
0397 entry.mac, entry.portvec, spid);
0398 chip->ports[spid].atu_miss_violation++;
0399 }
0400
0401 if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) {
0402 dev_err_ratelimited(chip->dev,
0403 "ATU full violation for %pM portvec %x spid %d\n",
0404 entry.mac, entry.portvec, spid);
0405 chip->ports[spid].atu_full_violation++;
0406 }
0407 mv88e6xxx_reg_unlock(chip);
0408
0409 return IRQ_HANDLED;
0410
0411 out:
0412 mv88e6xxx_reg_unlock(chip);
0413
0414 dev_err(chip->dev, "ATU problem: error %d while handling interrupt\n",
0415 err);
0416 return IRQ_HANDLED;
0417 }
0418
0419 int mv88e6xxx_g1_atu_prob_irq_setup(struct mv88e6xxx_chip *chip)
0420 {
0421 int err;
0422
0423 chip->atu_prob_irq = irq_find_mapping(chip->g1_irq.domain,
0424 MV88E6XXX_G1_STS_IRQ_ATU_PROB);
0425 if (chip->atu_prob_irq < 0)
0426 return chip->atu_prob_irq;
0427
0428 snprintf(chip->atu_prob_irq_name, sizeof(chip->atu_prob_irq_name),
0429 "mv88e6xxx-%s-g1-atu-prob", dev_name(chip->dev));
0430
0431 err = request_threaded_irq(chip->atu_prob_irq, NULL,
0432 mv88e6xxx_g1_atu_prob_irq_thread_fn,
0433 IRQF_ONESHOT, chip->atu_prob_irq_name,
0434 chip);
0435 if (err)
0436 irq_dispose_mapping(chip->atu_prob_irq);
0437
0438 return err;
0439 }
0440
0441 void mv88e6xxx_g1_atu_prob_irq_free(struct mv88e6xxx_chip *chip)
0442 {
0443 free_irq(chip->atu_prob_irq, chip);
0444 irq_dispose_mapping(chip->atu_prob_irq);
0445 }