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