1 /* 2 * Marvell 88E6xxx VLAN [Spanning Tree] Translation Unit (VTU [STU]) support 3 * 4 * Copyright (c) 2008 Marvell Semiconductor 5 * Copyright (c) 2015 CMC Electronics, Inc. 6 * Copyright (c) 2017 Savoir-faire Linux, Inc. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 */ 13 14 #include "chip.h" 15 #include "global1.h" 16 17 /* Offset 0x02: VTU FID Register */ 18 19 static int mv88e6xxx_g1_vtu_fid_read(struct mv88e6xxx_chip *chip, 20 struct mv88e6xxx_vtu_entry *entry) 21 { 22 u16 val; 23 int err; 24 25 err = mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID, &val); 26 if (err) 27 return err; 28 29 entry->fid = val & MV88E6352_G1_VTU_FID_MASK; 30 31 return 0; 32 } 33 34 static int mv88e6xxx_g1_vtu_fid_write(struct mv88e6xxx_chip *chip, 35 struct mv88e6xxx_vtu_entry *entry) 36 { 37 u16 val = entry->fid & MV88E6352_G1_VTU_FID_MASK; 38 39 return mv88e6xxx_g1_write(chip, MV88E6352_G1_VTU_FID, val); 40 } 41 42 /* Offset 0x03: VTU SID Register */ 43 44 static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip *chip, 45 struct mv88e6xxx_vtu_entry *entry) 46 { 47 u16 val; 48 int err; 49 50 err = mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID, &val); 51 if (err) 52 return err; 53 54 entry->sid = val & MV88E6352_G1_VTU_SID_MASK; 55 56 return 0; 57 } 58 59 static int mv88e6xxx_g1_vtu_sid_write(struct mv88e6xxx_chip *chip, 60 struct mv88e6xxx_vtu_entry *entry) 61 { 62 u16 val = entry->sid & MV88E6352_G1_VTU_SID_MASK; 63 64 return mv88e6xxx_g1_write(chip, MV88E6352_G1_VTU_SID, val); 65 } 66 67 /* Offset 0x05: VTU Operation Register */ 68 69 static int mv88e6xxx_g1_vtu_op_wait(struct mv88e6xxx_chip *chip) 70 { 71 return mv88e6xxx_g1_wait(chip, MV88E6XXX_G1_VTU_OP, 72 MV88E6XXX_G1_VTU_OP_BUSY); 73 } 74 75 static int mv88e6xxx_g1_vtu_op(struct mv88e6xxx_chip *chip, u16 op) 76 { 77 int err; 78 79 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_OP, 80 MV88E6XXX_G1_VTU_OP_BUSY | op); 81 if (err) 82 return err; 83 84 return mv88e6xxx_g1_vtu_op_wait(chip); 85 } 86 87 /* Offset 0x06: VTU VID Register */ 88 89 static int mv88e6xxx_g1_vtu_vid_read(struct mv88e6xxx_chip *chip, 90 struct mv88e6xxx_vtu_entry *entry) 91 { 92 u16 val; 93 int err; 94 95 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID, &val); 96 if (err) 97 return err; 98 99 entry->vid = val & 0xfff; 100 101 if (val & MV88E6390_G1_VTU_VID_PAGE) 102 entry->vid |= 0x1000; 103 104 entry->valid = !!(val & MV88E6XXX_G1_VTU_VID_VALID); 105 106 return 0; 107 } 108 109 static int mv88e6xxx_g1_vtu_vid_write(struct mv88e6xxx_chip *chip, 110 struct mv88e6xxx_vtu_entry *entry) 111 { 112 u16 val = entry->vid & 0xfff; 113 114 if (entry->vid & 0x1000) 115 val |= MV88E6390_G1_VTU_VID_PAGE; 116 117 if (entry->valid) 118 val |= MV88E6XXX_G1_VTU_VID_VALID; 119 120 return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_VID, val); 121 } 122 123 /* Offset 0x07: VTU/STU Data Register 1 124 * Offset 0x08: VTU/STU Data Register 2 125 * Offset 0x09: VTU/STU Data Register 3 126 */ 127 128 static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip, 129 struct mv88e6xxx_vtu_entry *entry) 130 { 131 u16 regs[3]; 132 int i; 133 134 /* Read all 3 VTU/STU Data registers */ 135 for (i = 0; i < 3; ++i) { 136 u16 *reg = ®s[i]; 137 int err; 138 139 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg); 140 if (err) 141 return err; 142 } 143 144 /* Extract MemberTag and PortState data */ 145 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 146 unsigned int member_offset = (i % 4) * 4; 147 unsigned int state_offset = member_offset + 2; 148 149 entry->member[i] = (regs[i / 4] >> member_offset) & 0x3; 150 entry->state[i] = (regs[i / 4] >> state_offset) & 0x3; 151 } 152 153 return 0; 154 } 155 156 static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip *chip, 157 struct mv88e6xxx_vtu_entry *entry) 158 { 159 u16 regs[3] = { 0 }; 160 int i; 161 162 /* Insert MemberTag and PortState data */ 163 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 164 unsigned int member_offset = (i % 4) * 4; 165 unsigned int state_offset = member_offset + 2; 166 167 regs[i / 4] |= (entry->member[i] & 0x3) << member_offset; 168 regs[i / 4] |= (entry->state[i] & 0x3) << state_offset; 169 } 170 171 /* Write all 3 VTU/STU Data registers */ 172 for (i = 0; i < 3; ++i) { 173 u16 reg = regs[i]; 174 int err; 175 176 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg); 177 if (err) 178 return err; 179 } 180 181 return 0; 182 } 183 184 static int mv88e6390_g1_vtu_data_read(struct mv88e6xxx_chip *chip, u8 *data) 185 { 186 u16 regs[2]; 187 int i; 188 189 /* Read the 2 VTU/STU Data registers */ 190 for (i = 0; i < 2; ++i) { 191 u16 *reg = ®s[i]; 192 int err; 193 194 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg); 195 if (err) 196 return err; 197 } 198 199 /* Extract data */ 200 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 201 unsigned int offset = (i % 8) * 2; 202 203 data[i] = (regs[i / 8] >> offset) & 0x3; 204 } 205 206 return 0; 207 } 208 209 static int mv88e6390_g1_vtu_data_write(struct mv88e6xxx_chip *chip, u8 *data) 210 { 211 u16 regs[2] = { 0 }; 212 int i; 213 214 /* Insert data */ 215 for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { 216 unsigned int offset = (i % 8) * 2; 217 218 regs[i / 8] |= (data[i] & 0x3) << offset; 219 } 220 221 /* Write the 2 VTU/STU Data registers */ 222 for (i = 0; i < 2; ++i) { 223 u16 reg = regs[i]; 224 int err; 225 226 err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg); 227 if (err) 228 return err; 229 } 230 231 return 0; 232 } 233 234 /* VLAN Translation Unit Operations */ 235 236 static int mv88e6xxx_g1_vtu_stu_getnext(struct mv88e6xxx_chip *chip, 237 struct mv88e6xxx_vtu_entry *entry) 238 { 239 int err; 240 241 err = mv88e6xxx_g1_vtu_sid_write(chip, entry); 242 if (err) 243 return err; 244 245 err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_GET_NEXT); 246 if (err) 247 return err; 248 249 err = mv88e6xxx_g1_vtu_sid_read(chip, entry); 250 if (err) 251 return err; 252 253 return mv88e6xxx_g1_vtu_vid_read(chip, entry); 254 } 255 256 static int mv88e6xxx_g1_vtu_stu_get(struct mv88e6xxx_chip *chip, 257 struct mv88e6xxx_vtu_entry *vtu) 258 { 259 struct mv88e6xxx_vtu_entry stu; 260 int err; 261 262 err = mv88e6xxx_g1_vtu_sid_read(chip, vtu); 263 if (err) 264 return err; 265 266 stu.sid = vtu->sid - 1; 267 268 err = mv88e6xxx_g1_vtu_stu_getnext(chip, &stu); 269 if (err) 270 return err; 271 272 if (stu.sid != vtu->sid || !stu.valid) 273 return -EINVAL; 274 275 return 0; 276 } 277 278 static int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip, 279 struct mv88e6xxx_vtu_entry *entry) 280 { 281 int err; 282 283 err = mv88e6xxx_g1_vtu_op_wait(chip); 284 if (err) 285 return err; 286 287 /* To get the next higher active VID, the VTU GetNext operation can be 288 * started again without setting the VID registers since it already 289 * contains the last VID. 290 * 291 * To save a few hardware accesses and abstract this to the caller, 292 * write the VID only once, when the entry is given as invalid. 293 */ 294 if (!entry->valid) { 295 err = mv88e6xxx_g1_vtu_vid_write(chip, entry); 296 if (err) 297 return err; 298 } 299 300 err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_GET_NEXT); 301 if (err) 302 return err; 303 304 return mv88e6xxx_g1_vtu_vid_read(chip, entry); 305 } 306 307 int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip, 308 struct mv88e6xxx_vtu_entry *entry) 309 { 310 u16 val; 311 int err; 312 313 err = mv88e6xxx_g1_vtu_getnext(chip, entry); 314 if (err) 315 return err; 316 317 if (entry->valid) { 318 err = mv88e6185_g1_vtu_data_read(chip, entry); 319 if (err) 320 return err; 321 322 /* VTU DBNum[3:0] are located in VTU Operation 3:0 323 * VTU DBNum[7:4] are located in VTU Operation 11:8 324 */ 325 err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP, &val); 326 if (err) 327 return err; 328 329 entry->fid = val & 0x000f; 330 entry->fid |= (val & 0x0f00) >> 4; 331 } 332 333 return 0; 334 } 335 336 int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chip, 337 struct mv88e6xxx_vtu_entry *entry) 338 { 339 int err; 340 341 /* Fetch VLAN MemberTag data from the VTU */ 342 err = mv88e6xxx_g1_vtu_getnext(chip, entry); 343 if (err) 344 return err; 345 346 if (entry->valid) { 347 /* Fetch (and mask) VLAN PortState data from the STU */ 348 err = mv88e6xxx_g1_vtu_stu_get(chip, entry); 349 if (err) 350 return err; 351 352 err = mv88e6185_g1_vtu_data_read(chip, entry); 353 if (err) 354 return err; 355 356 err = mv88e6xxx_g1_vtu_fid_read(chip, entry); 357 if (err) 358 return err; 359 } 360 361 return 0; 362 } 363 364 int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *chip, 365 struct mv88e6xxx_vtu_entry *entry) 366 { 367 int err; 368 369 /* Fetch VLAN MemberTag data from the VTU */ 370 err = mv88e6xxx_g1_vtu_getnext(chip, entry); 371 if (err) 372 return err; 373 374 if (entry->valid) { 375 err = mv88e6390_g1_vtu_data_read(chip, entry->member); 376 if (err) 377 return err; 378 379 /* Fetch VLAN PortState data from the STU */ 380 err = mv88e6xxx_g1_vtu_stu_get(chip, entry); 381 if (err) 382 return err; 383 384 err = mv88e6390_g1_vtu_data_read(chip, entry->state); 385 if (err) 386 return err; 387 388 err = mv88e6xxx_g1_vtu_fid_read(chip, entry); 389 if (err) 390 return err; 391 } 392 393 return 0; 394 } 395 396 int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, 397 struct mv88e6xxx_vtu_entry *entry) 398 { 399 u16 op = MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE; 400 int err; 401 402 err = mv88e6xxx_g1_vtu_op_wait(chip); 403 if (err) 404 return err; 405 406 err = mv88e6xxx_g1_vtu_vid_write(chip, entry); 407 if (err) 408 return err; 409 410 if (entry->valid) { 411 err = mv88e6185_g1_vtu_data_write(chip, entry); 412 if (err) 413 return err; 414 415 /* VTU DBNum[3:0] are located in VTU Operation 3:0 416 * VTU DBNum[7:4] are located in VTU Operation 11:8 417 */ 418 op |= entry->fid & 0x000f; 419 op |= (entry->fid & 0x00f0) << 8; 420 } 421 422 return mv88e6xxx_g1_vtu_op(chip, op); 423 } 424 425 int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, 426 struct mv88e6xxx_vtu_entry *entry) 427 { 428 int err; 429 430 err = mv88e6xxx_g1_vtu_op_wait(chip); 431 if (err) 432 return err; 433 434 err = mv88e6xxx_g1_vtu_vid_write(chip, entry); 435 if (err) 436 return err; 437 438 if (entry->valid) { 439 /* Write MemberTag and PortState data */ 440 err = mv88e6185_g1_vtu_data_write(chip, entry); 441 if (err) 442 return err; 443 444 err = mv88e6xxx_g1_vtu_sid_write(chip, entry); 445 if (err) 446 return err; 447 448 /* Load STU entry */ 449 err = mv88e6xxx_g1_vtu_op(chip, 450 MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); 451 if (err) 452 return err; 453 454 err = mv88e6xxx_g1_vtu_fid_write(chip, entry); 455 if (err) 456 return err; 457 } 458 459 /* Load/Purge VTU entry */ 460 return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE); 461 } 462 463 int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, 464 struct mv88e6xxx_vtu_entry *entry) 465 { 466 int err; 467 468 err = mv88e6xxx_g1_vtu_op_wait(chip); 469 if (err) 470 return err; 471 472 err = mv88e6xxx_g1_vtu_vid_write(chip, entry); 473 if (err) 474 return err; 475 476 if (entry->valid) { 477 /* Write PortState data */ 478 err = mv88e6390_g1_vtu_data_write(chip, entry->state); 479 if (err) 480 return err; 481 482 err = mv88e6xxx_g1_vtu_sid_write(chip, entry); 483 if (err) 484 return err; 485 486 /* Load STU entry */ 487 err = mv88e6xxx_g1_vtu_op(chip, 488 MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); 489 if (err) 490 return err; 491 492 /* Write MemberTag data */ 493 err = mv88e6390_g1_vtu_data_write(chip, entry->member); 494 if (err) 495 return err; 496 497 err = mv88e6xxx_g1_vtu_fid_write(chip, entry); 498 if (err) 499 return err; 500 } 501 502 /* Load/Purge VTU entry */ 503 return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE); 504 } 505 506 int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip) 507 { 508 int err; 509 510 err = mv88e6xxx_g1_vtu_op_wait(chip); 511 if (err) 512 return err; 513 514 return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_FLUSH_ALL); 515 } 516