1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Marvell 88E6xxx Address Translation Unit (ATU) support 4 * 5 * Copyright (c) 2008 Marvell Semiconductor 6 * Copyright (c) 2017 Savoir-faire Linux, Inc. 7 */ 8 9 #include <linux/bitfield.h> 10 #include <linux/interrupt.h> 11 #include <linux/irqdomain.h> 12 13 #include "chip.h" 14 #include "global1.h" 15 #include "trace.h" 16 17 /* Offset 0x01: ATU FID Register */ 18 19 static int mv88e6xxx_g1_atu_fid_write(struct mv88e6xxx_chip *chip, u16 fid) 20 { 21 return mv88e6xxx_g1_write(chip, MV88E6352_G1_ATU_FID, fid & 0xfff); 22 } 23 24 /* Offset 0x0A: ATU Control Register */ 25 26 int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip *chip, bool learn2all) 27 { 28 u16 val; 29 int err; 30 31 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val); 32 if (err) 33 return err; 34 35 if (learn2all) 36 val |= MV88E6XXX_G1_ATU_CTL_LEARN2ALL; 37 else 38 val &= ~MV88E6XXX_G1_ATU_CTL_LEARN2ALL; 39 40 return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val); 41 } 42 43 int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, 44 unsigned int msecs) 45 { 46 const unsigned int coeff = chip->info->age_time_coeff; 47 const unsigned int min = 0x01 * coeff; 48 const unsigned int max = 0xff * coeff; 49 u8 age_time; 50 u16 val; 51 int err; 52 53 if (msecs < min || msecs > max) 54 return -ERANGE; 55 56 /* Round to nearest multiple of coeff */ 57 age_time = (msecs + coeff / 2) / coeff; 58 59 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val); 60 if (err) 61 return err; 62 63 /* AgeTime is 11:4 bits */ 64 val &= ~0xff0; 65 val |= age_time << 4; 66 67 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val); 68 if (err) 69 return err; 70 71 dev_dbg(chip->dev, "AgeTime set to 0x%02x (%d ms)\n", age_time, 72 age_time * coeff); 73 74 return 0; 75 } 76 77 int mv88e6165_g1_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash) 78 { 79 int err; 80 u16 val; 81 82 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val); 83 if (err) 84 return err; 85 86 *hash = val & MV88E6161_G1_ATU_CTL_HASH_MASK; 87 88 return 0; 89 } 90 91 int mv88e6165_g1_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash) 92 { 93 int err; 94 u16 val; 95 96 if (hash & ~MV88E6161_G1_ATU_CTL_HASH_MASK) 97 return -EINVAL; 98 99 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val); 100 if (err) 101 return err; 102 103 val &= ~MV88E6161_G1_ATU_CTL_HASH_MASK; 104 val |= hash; 105 106 return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val); 107 } 108 109 /* Offset 0x0B: ATU Operation Register */ 110 111 static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip) 112 { 113 int bit = __bf_shf(MV88E6XXX_G1_ATU_OP_BUSY); 114 115 return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0); 116 } 117 118 static int mv88e6xxx_g1_read_atu_violation(struct mv88e6xxx_chip *chip) 119 { 120 int err; 121 122 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP, 123 MV88E6XXX_G1_ATU_OP_BUSY | 124 MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION); 125 if (err) 126 return err; 127 128 return mv88e6xxx_g1_atu_op_wait(chip); 129 } 130 131 static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op) 132 { 133 u16 val; 134 int err; 135 136 /* FID bits are dispatched all around gradually as more are supported */ 137 if (mv88e6xxx_num_databases(chip) > 256) { 138 err = mv88e6xxx_g1_atu_fid_write(chip, fid); 139 if (err) 140 return err; 141 } else { 142 if (mv88e6xxx_num_databases(chip) > 64) { 143 /* ATU DBNum[7:4] are located in ATU Control 15:12 */ 144 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, 145 &val); 146 if (err) 147 return err; 148 149 val = (val & 0x0fff) | ((fid << 8) & 0xf000); 150 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, 151 val); 152 if (err) 153 return err; 154 } else if (mv88e6xxx_num_databases(chip) > 16) { 155 /* ATU DBNum[5:4] are located in ATU Operation 9:8 */ 156 op |= (fid & 0x30) << 4; 157 } 158 159 /* ATU DBNum[3:0] are located in ATU Operation 3:0 */ 160 op |= fid & 0xf; 161 } 162 163 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP, 164 MV88E6XXX_G1_ATU_OP_BUSY | op); 165 if (err) 166 return err; 167 168 return mv88e6xxx_g1_atu_op_wait(chip); 169 } 170 171 int mv88e6xxx_g1_atu_get_next(struct mv88e6xxx_chip *chip, u16 fid) 172 { 173 return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB); 174 } 175 176 static int mv88e6xxx_g1_atu_fid_read(struct mv88e6xxx_chip *chip, u16 *fid) 177 { 178 u16 val = 0, upper = 0, op = 0; 179 int err = -EOPNOTSUPP; 180 181 if (mv88e6xxx_num_databases(chip) > 256) { 182 err = mv88e6xxx_g1_read(chip, MV88E6352_G1_ATU_FID, &val); 183 val &= 0xfff; 184 if (err) 185 return err; 186 } else { 187 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &op); 188 if (err) 189 return err; 190 if (mv88e6xxx_num_databases(chip) > 64) { 191 /* ATU DBNum[7:4] are located in ATU Control 15:12 */ 192 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, 193 &upper); 194 if (err) 195 return err; 196 197 upper = (upper >> 8) & 0x00f0; 198 } else if (mv88e6xxx_num_databases(chip) > 16) { 199 /* ATU DBNum[5:4] are located in ATU Operation 9:8 */ 200 upper = (op >> 4) & 0x30; 201 } 202 203 /* ATU DBNum[3:0] are located in ATU Operation 3:0 */ 204 val = (op & 0xf) | upper; 205 } 206 *fid = val; 207 208 return err; 209 } 210 211 /* Offset 0x0C: ATU Data Register */ 212 213 static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip, 214 struct mv88e6xxx_atu_entry *entry) 215 { 216 u16 val; 217 int err; 218 219 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &val); 220 if (err) 221 return err; 222 223 entry->state = val & 0xf; 224 if (entry->state) { 225 entry->trunk = !!(val & MV88E6XXX_G1_ATU_DATA_TRUNK); 226 entry->portvec = (val >> 4) & mv88e6xxx_port_mask(chip); 227 } 228 229 return 0; 230 } 231 232 static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip, 233 struct mv88e6xxx_atu_entry *entry) 234 { 235 u16 data = entry->state & 0xf; 236 237 if (entry->state) { 238 if (entry->trunk) 239 data |= MV88E6XXX_G1_ATU_DATA_TRUNK; 240 241 data |= (entry->portvec & mv88e6xxx_port_mask(chip)) << 4; 242 } 243 244 return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_DATA, data); 245 } 246 247 /* Offset 0x0D: ATU MAC Address Register Bytes 0 & 1 248 * Offset 0x0E: ATU MAC Address Register Bytes 2 & 3 249 * Offset 0x0F: ATU MAC Address Register Bytes 4 & 5 250 */ 251 252 static int mv88e6xxx_g1_atu_mac_read(struct mv88e6xxx_chip *chip, 253 struct mv88e6xxx_atu_entry *entry) 254 { 255 u16 val; 256 int i, err; 257 258 for (i = 0; i < 3; i++) { 259 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01 + i, &val); 260 if (err) 261 return err; 262 263 entry->mac[i * 2] = val >> 8; 264 entry->mac[i * 2 + 1] = val & 0xff; 265 } 266 267 return 0; 268 } 269 270 static int mv88e6xxx_g1_atu_mac_write(struct mv88e6xxx_chip *chip, 271 struct mv88e6xxx_atu_entry *entry) 272 { 273 u16 val; 274 int i, err; 275 276 for (i = 0; i < 3; i++) { 277 val = (entry->mac[i * 2] << 8) | entry->mac[i * 2 + 1]; 278 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_MAC01 + i, val); 279 if (err) 280 return err; 281 } 282 283 return 0; 284 } 285 286 /* Address Translation Unit operations */ 287 288 int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid, 289 struct mv88e6xxx_atu_entry *entry) 290 { 291 int err; 292 293 err = mv88e6xxx_g1_atu_op_wait(chip); 294 if (err) 295 return err; 296 297 /* Write the MAC address to iterate from only once */ 298 if (!entry->state) { 299 err = mv88e6xxx_g1_atu_mac_write(chip, entry); 300 if (err) 301 return err; 302 } 303 304 err = mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB); 305 if (err) 306 return err; 307 308 err = mv88e6xxx_g1_atu_data_read(chip, entry); 309 if (err) 310 return err; 311 312 return mv88e6xxx_g1_atu_mac_read(chip, entry); 313 } 314 315 int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid, 316 struct mv88e6xxx_atu_entry *entry) 317 { 318 int err; 319 320 err = mv88e6xxx_g1_atu_op_wait(chip); 321 if (err) 322 return err; 323 324 err = mv88e6xxx_g1_atu_mac_write(chip, entry); 325 if (err) 326 return err; 327 328 err = mv88e6xxx_g1_atu_data_write(chip, entry); 329 if (err) 330 return err; 331 332 return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_LOAD_DB); 333 } 334 335 static int mv88e6xxx_g1_atu_flushmove(struct mv88e6xxx_chip *chip, u16 fid, 336 struct mv88e6xxx_atu_entry *entry, 337 bool all) 338 { 339 u16 op; 340 int err; 341 342 err = mv88e6xxx_g1_atu_op_wait(chip); 343 if (err) 344 return err; 345 346 err = mv88e6xxx_g1_atu_data_write(chip, entry); 347 if (err) 348 return err; 349 350 /* Flush/Move all or non-static entries from all or a given database */ 351 if (all && fid) 352 op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL_DB; 353 else if (fid) 354 op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC_DB; 355 else if (all) 356 op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL; 357 else 358 op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC; 359 360 return mv88e6xxx_g1_atu_op(chip, fid, op); 361 } 362 363 int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip *chip, u16 fid, bool all) 364 { 365 struct mv88e6xxx_atu_entry entry = { 366 .state = 0, /* Null EntryState means Flush */ 367 }; 368 369 return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all); 370 } 371 372 static int mv88e6xxx_g1_atu_move(struct mv88e6xxx_chip *chip, u16 fid, 373 int from_port, int to_port, bool all) 374 { 375 struct mv88e6xxx_atu_entry entry = { 0 }; 376 unsigned long mask; 377 int shift; 378 379 if (!chip->info->atu_move_port_mask) 380 return -EOPNOTSUPP; 381 382 mask = chip->info->atu_move_port_mask; 383 shift = bitmap_weight(&mask, 16); 384 385 entry.state = 0xf; /* Full EntryState means Move */ 386 entry.portvec = from_port & mask; 387 entry.portvec |= (to_port & mask) << shift; 388 389 return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all); 390 } 391 392 int mv88e6xxx_g1_atu_remove(struct mv88e6xxx_chip *chip, u16 fid, int port, 393 bool all) 394 { 395 int from_port = port; 396 int to_port = chip->info->atu_move_port_mask; 397 398 return mv88e6xxx_g1_atu_move(chip, fid, from_port, to_port, all); 399 } 400 401 static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id) 402 { 403 struct mv88e6xxx_chip *chip = dev_id; 404 struct mv88e6xxx_atu_entry entry; 405 int err, spid; 406 u16 val, fid; 407 408 mv88e6xxx_reg_lock(chip); 409 410 err = mv88e6xxx_g1_read_atu_violation(chip); 411 if (err) 412 goto out; 413 414 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &val); 415 if (err) 416 goto out; 417 418 err = mv88e6xxx_g1_atu_fid_read(chip, &fid); 419 if (err) 420 goto out; 421 422 err = mv88e6xxx_g1_atu_data_read(chip, &entry); 423 if (err) 424 goto out; 425 426 err = mv88e6xxx_g1_atu_mac_read(chip, &entry); 427 if (err) 428 goto out; 429 430 spid = entry.state; 431 432 if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) { 433 trace_mv88e6xxx_atu_member_violation(chip->dev, spid, 434 entry.portvec, entry.mac, 435 fid); 436 chip->ports[spid].atu_member_violation++; 437 } 438 439 if (val & MV88E6XXX_G1_ATU_OP_MISS_VIOLATION) { 440 trace_mv88e6xxx_atu_miss_violation(chip->dev, spid, 441 entry.portvec, entry.mac, 442 fid); 443 chip->ports[spid].atu_miss_violation++; 444 } 445 446 if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) { 447 trace_mv88e6xxx_atu_full_violation(chip->dev, spid, 448 entry.portvec, entry.mac, 449 fid); 450 chip->ports[spid].atu_full_violation++; 451 } 452 mv88e6xxx_reg_unlock(chip); 453 454 return IRQ_HANDLED; 455 456 out: 457 mv88e6xxx_reg_unlock(chip); 458 459 dev_err(chip->dev, "ATU problem: error %d while handling interrupt\n", 460 err); 461 return IRQ_HANDLED; 462 } 463 464 int mv88e6xxx_g1_atu_prob_irq_setup(struct mv88e6xxx_chip *chip) 465 { 466 int err; 467 468 chip->atu_prob_irq = irq_find_mapping(chip->g1_irq.domain, 469 MV88E6XXX_G1_STS_IRQ_ATU_PROB); 470 if (chip->atu_prob_irq < 0) 471 return chip->atu_prob_irq; 472 473 snprintf(chip->atu_prob_irq_name, sizeof(chip->atu_prob_irq_name), 474 "mv88e6xxx-%s-g1-atu-prob", dev_name(chip->dev)); 475 476 err = request_threaded_irq(chip->atu_prob_irq, NULL, 477 mv88e6xxx_g1_atu_prob_irq_thread_fn, 478 IRQF_ONESHOT, chip->atu_prob_irq_name, 479 chip); 480 if (err) 481 irq_dispose_mapping(chip->atu_prob_irq); 482 483 return err; 484 } 485 486 void mv88e6xxx_g1_atu_prob_irq_free(struct mv88e6xxx_chip *chip) 487 { 488 free_irq(chip->atu_prob_irq, chip); 489 irq_dispose_mapping(chip->atu_prob_irq); 490 } 491