12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2720c6343SVivien Didelot /* 3720c6343SVivien Didelot * Marvell 88E6xxx Address Translation Unit (ATU) support 4720c6343SVivien Didelot * 5720c6343SVivien Didelot * Copyright (c) 2008 Marvell Semiconductor 6720c6343SVivien Didelot * Copyright (c) 2017 Savoir-faire Linux, Inc. 7720c6343SVivien Didelot */ 819fb7f69SVivien Didelot 919fb7f69SVivien Didelot #include <linux/bitfield.h> 100977644cSAndrew Lunn #include <linux/interrupt.h> 110977644cSAndrew Lunn #include <linux/irqdomain.h> 12720c6343SVivien Didelot 134d5f2ba7SVivien Didelot #include "chip.h" 14720c6343SVivien Didelot #include "global1.h" 158646384dSVladimir Oltean #include "trace.h" 16720c6343SVivien Didelot 179c13c026SVivien Didelot /* Offset 0x01: ATU FID Register */ 189c13c026SVivien Didelot 199c13c026SVivien Didelot static int mv88e6xxx_g1_atu_fid_write(struct mv88e6xxx_chip *chip, u16 fid) 209c13c026SVivien Didelot { 2127c0e600SVivien Didelot return mv88e6xxx_g1_write(chip, MV88E6352_G1_ATU_FID, fid & 0xfff); 229c13c026SVivien Didelot } 239c13c026SVivien Didelot 24720c6343SVivien Didelot /* Offset 0x0A: ATU Control Register */ 25720c6343SVivien Didelot 26c3a7d4adSVivien Didelot int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip *chip, bool learn2all) 27c3a7d4adSVivien Didelot { 28c3a7d4adSVivien Didelot u16 val; 29c3a7d4adSVivien Didelot int err; 30c3a7d4adSVivien Didelot 3127c0e600SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val); 32c3a7d4adSVivien Didelot if (err) 33c3a7d4adSVivien Didelot return err; 34c3a7d4adSVivien Didelot 35c3a7d4adSVivien Didelot if (learn2all) 3627c0e600SVivien Didelot val |= MV88E6XXX_G1_ATU_CTL_LEARN2ALL; 37c3a7d4adSVivien Didelot else 3827c0e600SVivien Didelot val &= ~MV88E6XXX_G1_ATU_CTL_LEARN2ALL; 39c3a7d4adSVivien Didelot 4027c0e600SVivien Didelot return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val); 41c3a7d4adSVivien Didelot } 42c3a7d4adSVivien Didelot 43720c6343SVivien Didelot int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, 44720c6343SVivien Didelot unsigned int msecs) 45720c6343SVivien Didelot { 46720c6343SVivien Didelot const unsigned int coeff = chip->info->age_time_coeff; 47720c6343SVivien Didelot const unsigned int min = 0x01 * coeff; 48720c6343SVivien Didelot const unsigned int max = 0xff * coeff; 49720c6343SVivien Didelot u8 age_time; 50720c6343SVivien Didelot u16 val; 51720c6343SVivien Didelot int err; 52720c6343SVivien Didelot 53720c6343SVivien Didelot if (msecs < min || msecs > max) 54720c6343SVivien Didelot return -ERANGE; 55720c6343SVivien Didelot 56720c6343SVivien Didelot /* Round to nearest multiple of coeff */ 57720c6343SVivien Didelot age_time = (msecs + coeff / 2) / coeff; 58720c6343SVivien Didelot 5927c0e600SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val); 60720c6343SVivien Didelot if (err) 61720c6343SVivien Didelot return err; 62720c6343SVivien Didelot 63720c6343SVivien Didelot /* AgeTime is 11:4 bits */ 64720c6343SVivien Didelot val &= ~0xff0; 65720c6343SVivien Didelot val |= age_time << 4; 66720c6343SVivien Didelot 6727c0e600SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val); 68bae76dd9SVivien Didelot if (err) 69bae76dd9SVivien Didelot return err; 70bae76dd9SVivien Didelot 71bae76dd9SVivien Didelot dev_dbg(chip->dev, "AgeTime set to 0x%02x (%d ms)\n", age_time, 72bae76dd9SVivien Didelot age_time * coeff); 73bae76dd9SVivien Didelot 74bae76dd9SVivien Didelot return 0; 75720c6343SVivien Didelot } 769c13c026SVivien Didelot 7723e8b470SAndrew Lunn int mv88e6165_g1_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash) 7823e8b470SAndrew Lunn { 7923e8b470SAndrew Lunn int err; 8023e8b470SAndrew Lunn u16 val; 8123e8b470SAndrew Lunn 8223e8b470SAndrew Lunn err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val); 8323e8b470SAndrew Lunn if (err) 8423e8b470SAndrew Lunn return err; 8523e8b470SAndrew Lunn 8623e8b470SAndrew Lunn *hash = val & MV88E6161_G1_ATU_CTL_HASH_MASK; 8723e8b470SAndrew Lunn 8823e8b470SAndrew Lunn return 0; 8923e8b470SAndrew Lunn } 9023e8b470SAndrew Lunn 9123e8b470SAndrew Lunn int mv88e6165_g1_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash) 9223e8b470SAndrew Lunn { 9323e8b470SAndrew Lunn int err; 9423e8b470SAndrew Lunn u16 val; 9523e8b470SAndrew Lunn 9623e8b470SAndrew Lunn if (hash & ~MV88E6161_G1_ATU_CTL_HASH_MASK) 9723e8b470SAndrew Lunn return -EINVAL; 9823e8b470SAndrew Lunn 9923e8b470SAndrew Lunn err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val); 10023e8b470SAndrew Lunn if (err) 10123e8b470SAndrew Lunn return err; 10223e8b470SAndrew Lunn 10323e8b470SAndrew Lunn val &= ~MV88E6161_G1_ATU_CTL_HASH_MASK; 10423e8b470SAndrew Lunn val |= hash; 10523e8b470SAndrew Lunn 10623e8b470SAndrew Lunn return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val); 10723e8b470SAndrew Lunn } 10823e8b470SAndrew Lunn 1099c13c026SVivien Didelot /* Offset 0x0B: ATU Operation Register */ 1109c13c026SVivien Didelot 1119c13c026SVivien Didelot static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip) 1129c13c026SVivien Didelot { 11319fb7f69SVivien Didelot int bit = __bf_shf(MV88E6XXX_G1_ATU_OP_BUSY); 11419fb7f69SVivien Didelot 11519fb7f69SVivien Didelot return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0); 1169c13c026SVivien Didelot } 1179c13c026SVivien Didelot 1184bf24ad0SHans J. Schultz static int mv88e6xxx_g1_read_atu_violation(struct mv88e6xxx_chip *chip) 1194bf24ad0SHans J. Schultz { 1204bf24ad0SHans J. Schultz int err; 1214bf24ad0SHans J. Schultz 1224bf24ad0SHans J. Schultz err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP, 1234bf24ad0SHans J. Schultz MV88E6XXX_G1_ATU_OP_BUSY | 1244bf24ad0SHans J. Schultz MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION); 1254bf24ad0SHans J. Schultz if (err) 1264bf24ad0SHans J. Schultz return err; 1274bf24ad0SHans J. Schultz 1284bf24ad0SHans J. Schultz return mv88e6xxx_g1_atu_op_wait(chip); 1294bf24ad0SHans J. Schultz } 1304bf24ad0SHans J. Schultz 1319c13c026SVivien Didelot static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op) 1329c13c026SVivien Didelot { 1339c13c026SVivien Didelot u16 val; 1349c13c026SVivien Didelot int err; 1359c13c026SVivien Didelot 1369c13c026SVivien Didelot /* FID bits are dispatched all around gradually as more are supported */ 1379c13c026SVivien Didelot if (mv88e6xxx_num_databases(chip) > 256) { 1389c13c026SVivien Didelot err = mv88e6xxx_g1_atu_fid_write(chip, fid); 1399c13c026SVivien Didelot if (err) 1409c13c026SVivien Didelot return err; 1419c13c026SVivien Didelot } else { 1427b83df0dSRasmus Villemoes if (mv88e6xxx_num_databases(chip) > 64) { 1439c13c026SVivien Didelot /* ATU DBNum[7:4] are located in ATU Control 15:12 */ 14427c0e600SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, 14527c0e600SVivien Didelot &val); 1469c13c026SVivien Didelot if (err) 1479c13c026SVivien Didelot return err; 1489c13c026SVivien Didelot 1499c13c026SVivien Didelot val = (val & 0x0fff) | ((fid << 8) & 0xf000); 15027c0e600SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, 15127c0e600SVivien Didelot val); 1529c13c026SVivien Didelot if (err) 1539c13c026SVivien Didelot return err; 1547b83df0dSRasmus Villemoes } else if (mv88e6xxx_num_databases(chip) > 16) { 1557b83df0dSRasmus Villemoes /* ATU DBNum[5:4] are located in ATU Operation 9:8 */ 1567b83df0dSRasmus Villemoes op |= (fid & 0x30) << 4; 1579c13c026SVivien Didelot } 1589c13c026SVivien Didelot 1599c13c026SVivien Didelot /* ATU DBNum[3:0] are located in ATU Operation 3:0 */ 1609c13c026SVivien Didelot op |= fid & 0xf; 1619c13c026SVivien Didelot } 1629c13c026SVivien Didelot 16327c0e600SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP, 16427c0e600SVivien Didelot MV88E6XXX_G1_ATU_OP_BUSY | op); 1659c13c026SVivien Didelot if (err) 1669c13c026SVivien Didelot return err; 1679c13c026SVivien Didelot 1689c13c026SVivien Didelot return mv88e6xxx_g1_atu_op_wait(chip); 1699c13c026SVivien Didelot } 1709c13c026SVivien Didelot 171c5f299d5SAndrew Lunn int mv88e6xxx_g1_atu_get_next(struct mv88e6xxx_chip *chip, u16 fid) 172c5f299d5SAndrew Lunn { 173c5f299d5SAndrew Lunn return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB); 174c5f299d5SAndrew Lunn } 175c5f299d5SAndrew Lunn 1764bf24ad0SHans J. Schultz static int mv88e6xxx_g1_atu_fid_read(struct mv88e6xxx_chip *chip, u16 *fid) 1774bf24ad0SHans J. Schultz { 1784bf24ad0SHans J. Schultz u16 val = 0, upper = 0, op = 0; 1794bf24ad0SHans J. Schultz int err = -EOPNOTSUPP; 1804bf24ad0SHans J. Schultz 1814bf24ad0SHans J. Schultz if (mv88e6xxx_num_databases(chip) > 256) { 1824bf24ad0SHans J. Schultz err = mv88e6xxx_g1_read(chip, MV88E6352_G1_ATU_FID, &val); 1834bf24ad0SHans J. Schultz val &= 0xfff; 1844bf24ad0SHans J. Schultz if (err) 1854bf24ad0SHans J. Schultz return err; 1864bf24ad0SHans J. Schultz } else { 1874bf24ad0SHans J. Schultz err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &op); 1884bf24ad0SHans J. Schultz if (err) 1894bf24ad0SHans J. Schultz return err; 1904bf24ad0SHans J. Schultz if (mv88e6xxx_num_databases(chip) > 64) { 1914bf24ad0SHans J. Schultz /* ATU DBNum[7:4] are located in ATU Control 15:12 */ 1924bf24ad0SHans J. Schultz err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, 1934bf24ad0SHans J. Schultz &upper); 1944bf24ad0SHans J. Schultz if (err) 1954bf24ad0SHans J. Schultz return err; 1964bf24ad0SHans J. Schultz 1974bf24ad0SHans J. Schultz upper = (upper >> 8) & 0x00f0; 1984bf24ad0SHans J. Schultz } else if (mv88e6xxx_num_databases(chip) > 16) { 1994bf24ad0SHans J. Schultz /* ATU DBNum[5:4] are located in ATU Operation 9:8 */ 2004bf24ad0SHans J. Schultz upper = (op >> 4) & 0x30; 2014bf24ad0SHans J. Schultz } 2024bf24ad0SHans J. Schultz 2034bf24ad0SHans J. Schultz /* ATU DBNum[3:0] are located in ATU Operation 3:0 */ 2044bf24ad0SHans J. Schultz val = (op & 0xf) | upper; 2054bf24ad0SHans J. Schultz } 2064bf24ad0SHans J. Schultz *fid = val; 2074bf24ad0SHans J. Schultz 2084bf24ad0SHans J. Schultz return err; 2094bf24ad0SHans J. Schultz } 2104bf24ad0SHans J. Schultz 2119c13c026SVivien Didelot /* Offset 0x0C: ATU Data Register */ 2129c13c026SVivien Didelot 213dabc1a96SVivien Didelot static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip, 214dabc1a96SVivien Didelot struct mv88e6xxx_atu_entry *entry) 215dabc1a96SVivien Didelot { 216dabc1a96SVivien Didelot u16 val; 217dabc1a96SVivien Didelot int err; 218dabc1a96SVivien Didelot 21927c0e600SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &val); 220dabc1a96SVivien Didelot if (err) 221dabc1a96SVivien Didelot return err; 222dabc1a96SVivien Didelot 223dabc1a96SVivien Didelot entry->state = val & 0xf; 224d8291a95SVivien Didelot if (entry->state) { 22527c0e600SVivien Didelot entry->trunk = !!(val & MV88E6XXX_G1_ATU_DATA_TRUNK); 22601bd96c8SVivien Didelot entry->portvec = (val >> 4) & mv88e6xxx_port_mask(chip); 227dabc1a96SVivien Didelot } 228dabc1a96SVivien Didelot 229dabc1a96SVivien Didelot return 0; 230dabc1a96SVivien Didelot } 231dabc1a96SVivien Didelot 2329c13c026SVivien Didelot static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip, 2339c13c026SVivien Didelot struct mv88e6xxx_atu_entry *entry) 2349c13c026SVivien Didelot { 2359c13c026SVivien Didelot u16 data = entry->state & 0xf; 2369c13c026SVivien Didelot 237d8291a95SVivien Didelot if (entry->state) { 2389c13c026SVivien Didelot if (entry->trunk) 23927c0e600SVivien Didelot data |= MV88E6XXX_G1_ATU_DATA_TRUNK; 2409c13c026SVivien Didelot 24101bd96c8SVivien Didelot data |= (entry->portvec & mv88e6xxx_port_mask(chip)) << 4; 2429c13c026SVivien Didelot } 2439c13c026SVivien Didelot 24427c0e600SVivien Didelot return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_DATA, data); 2459c13c026SVivien Didelot } 2469c13c026SVivien Didelot 2479c13c026SVivien Didelot /* Offset 0x0D: ATU MAC Address Register Bytes 0 & 1 2489c13c026SVivien Didelot * Offset 0x0E: ATU MAC Address Register Bytes 2 & 3 2499c13c026SVivien Didelot * Offset 0x0F: ATU MAC Address Register Bytes 4 & 5 2509c13c026SVivien Didelot */ 2519c13c026SVivien Didelot 252dabc1a96SVivien Didelot static int mv88e6xxx_g1_atu_mac_read(struct mv88e6xxx_chip *chip, 253dabc1a96SVivien Didelot struct mv88e6xxx_atu_entry *entry) 254dabc1a96SVivien Didelot { 255dabc1a96SVivien Didelot u16 val; 256dabc1a96SVivien Didelot int i, err; 257dabc1a96SVivien Didelot 258dabc1a96SVivien Didelot for (i = 0; i < 3; i++) { 25927c0e600SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01 + i, &val); 260dabc1a96SVivien Didelot if (err) 261dabc1a96SVivien Didelot return err; 262dabc1a96SVivien Didelot 263dabc1a96SVivien Didelot entry->mac[i * 2] = val >> 8; 264dabc1a96SVivien Didelot entry->mac[i * 2 + 1] = val & 0xff; 265dabc1a96SVivien Didelot } 266dabc1a96SVivien Didelot 267dabc1a96SVivien Didelot return 0; 268dabc1a96SVivien Didelot } 269dabc1a96SVivien Didelot 2709c13c026SVivien Didelot static int mv88e6xxx_g1_atu_mac_write(struct mv88e6xxx_chip *chip, 2719c13c026SVivien Didelot struct mv88e6xxx_atu_entry *entry) 2729c13c026SVivien Didelot { 2739c13c026SVivien Didelot u16 val; 2749c13c026SVivien Didelot int i, err; 2759c13c026SVivien Didelot 2769c13c026SVivien Didelot for (i = 0; i < 3; i++) { 2779c13c026SVivien Didelot val = (entry->mac[i * 2] << 8) | entry->mac[i * 2 + 1]; 27827c0e600SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_MAC01 + i, val); 2799c13c026SVivien Didelot if (err) 2809c13c026SVivien Didelot return err; 2819c13c026SVivien Didelot } 2829c13c026SVivien Didelot 2839c13c026SVivien Didelot return 0; 2849c13c026SVivien Didelot } 2859c13c026SVivien Didelot 2869c13c026SVivien Didelot /* Address Translation Unit operations */ 2879c13c026SVivien Didelot 288dabc1a96SVivien Didelot int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid, 289dabc1a96SVivien Didelot struct mv88e6xxx_atu_entry *entry) 290dabc1a96SVivien Didelot { 291dabc1a96SVivien Didelot int err; 292dabc1a96SVivien Didelot 293dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_op_wait(chip); 294dabc1a96SVivien Didelot if (err) 295dabc1a96SVivien Didelot return err; 296dabc1a96SVivien Didelot 297dabc1a96SVivien Didelot /* Write the MAC address to iterate from only once */ 298d8291a95SVivien Didelot if (!entry->state) { 299dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_mac_write(chip, entry); 300dabc1a96SVivien Didelot if (err) 301dabc1a96SVivien Didelot return err; 302dabc1a96SVivien Didelot } 303dabc1a96SVivien Didelot 30427c0e600SVivien Didelot err = mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB); 305dabc1a96SVivien Didelot if (err) 306dabc1a96SVivien Didelot return err; 307dabc1a96SVivien Didelot 308dabc1a96SVivien Didelot err = mv88e6xxx_g1_atu_data_read(chip, entry); 309dabc1a96SVivien Didelot if (err) 310dabc1a96SVivien Didelot return err; 311dabc1a96SVivien Didelot 312dabc1a96SVivien Didelot return mv88e6xxx_g1_atu_mac_read(chip, entry); 313dabc1a96SVivien Didelot } 314dabc1a96SVivien Didelot 3159c13c026SVivien Didelot int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid, 3169c13c026SVivien Didelot struct mv88e6xxx_atu_entry *entry) 3179c13c026SVivien Didelot { 3189c13c026SVivien Didelot int err; 3199c13c026SVivien Didelot 3209c13c026SVivien Didelot err = mv88e6xxx_g1_atu_op_wait(chip); 3219c13c026SVivien Didelot if (err) 3229c13c026SVivien Didelot return err; 3239c13c026SVivien Didelot 3249c13c026SVivien Didelot err = mv88e6xxx_g1_atu_mac_write(chip, entry); 3259c13c026SVivien Didelot if (err) 3269c13c026SVivien Didelot return err; 3279c13c026SVivien Didelot 3289c13c026SVivien Didelot err = mv88e6xxx_g1_atu_data_write(chip, entry); 3299c13c026SVivien Didelot if (err) 3309c13c026SVivien Didelot return err; 3319c13c026SVivien Didelot 33227c0e600SVivien Didelot return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_LOAD_DB); 3339c13c026SVivien Didelot } 334daefc943SVivien Didelot 335daefc943SVivien Didelot static int mv88e6xxx_g1_atu_flushmove(struct mv88e6xxx_chip *chip, u16 fid, 336daefc943SVivien Didelot struct mv88e6xxx_atu_entry *entry, 337daefc943SVivien Didelot bool all) 338daefc943SVivien Didelot { 339daefc943SVivien Didelot u16 op; 340daefc943SVivien Didelot int err; 341daefc943SVivien Didelot 342daefc943SVivien Didelot err = mv88e6xxx_g1_atu_op_wait(chip); 343daefc943SVivien Didelot if (err) 344daefc943SVivien Didelot return err; 345daefc943SVivien Didelot 346daefc943SVivien Didelot err = mv88e6xxx_g1_atu_data_write(chip, entry); 347daefc943SVivien Didelot if (err) 348daefc943SVivien Didelot return err; 349daefc943SVivien Didelot 350daefc943SVivien Didelot /* Flush/Move all or non-static entries from all or a given database */ 351daefc943SVivien Didelot if (all && fid) 35227c0e600SVivien Didelot op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL_DB; 353daefc943SVivien Didelot else if (fid) 35427c0e600SVivien Didelot op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC_DB; 355daefc943SVivien Didelot else if (all) 35627c0e600SVivien Didelot op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL; 357daefc943SVivien Didelot else 35827c0e600SVivien Didelot op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC; 359daefc943SVivien Didelot 360daefc943SVivien Didelot return mv88e6xxx_g1_atu_op(chip, fid, op); 361daefc943SVivien Didelot } 362daefc943SVivien Didelot 363daefc943SVivien Didelot int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip *chip, u16 fid, bool all) 364daefc943SVivien Didelot { 365daefc943SVivien Didelot struct mv88e6xxx_atu_entry entry = { 366daefc943SVivien Didelot .state = 0, /* Null EntryState means Flush */ 367daefc943SVivien Didelot }; 368daefc943SVivien Didelot 369daefc943SVivien Didelot return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all); 370daefc943SVivien Didelot } 371e606ca36SVivien Didelot 372e606ca36SVivien Didelot static int mv88e6xxx_g1_atu_move(struct mv88e6xxx_chip *chip, u16 fid, 373e606ca36SVivien Didelot int from_port, int to_port, bool all) 374e606ca36SVivien Didelot { 375e606ca36SVivien Didelot struct mv88e6xxx_atu_entry entry = { 0 }; 376e606ca36SVivien Didelot unsigned long mask; 377e606ca36SVivien Didelot int shift; 378e606ca36SVivien Didelot 379e606ca36SVivien Didelot if (!chip->info->atu_move_port_mask) 380e606ca36SVivien Didelot return -EOPNOTSUPP; 381e606ca36SVivien Didelot 382e606ca36SVivien Didelot mask = chip->info->atu_move_port_mask; 383e606ca36SVivien Didelot shift = bitmap_weight(&mask, 16); 384e606ca36SVivien Didelot 38559d4c93dSZheng Yongjun entry.state = 0xf; /* Full EntryState means Move */ 38601bd96c8SVivien Didelot entry.portvec = from_port & mask; 38701bd96c8SVivien Didelot entry.portvec |= (to_port & mask) << shift; 388e606ca36SVivien Didelot 389e606ca36SVivien Didelot return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all); 390e606ca36SVivien Didelot } 391e606ca36SVivien Didelot 392e606ca36SVivien Didelot int mv88e6xxx_g1_atu_remove(struct mv88e6xxx_chip *chip, u16 fid, int port, 393e606ca36SVivien Didelot bool all) 394e606ca36SVivien Didelot { 395e606ca36SVivien Didelot int from_port = port; 396e606ca36SVivien Didelot int to_port = chip->info->atu_move_port_mask; 397e606ca36SVivien Didelot 398e606ca36SVivien Didelot return mv88e6xxx_g1_atu_move(chip, fid, from_port, to_port, all); 399e606ca36SVivien Didelot } 4000977644cSAndrew Lunn 4010977644cSAndrew Lunn static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id) 4020977644cSAndrew Lunn { 4030977644cSAndrew Lunn struct mv88e6xxx_chip *chip = dev_id; 4040977644cSAndrew Lunn struct mv88e6xxx_atu_entry entry; 4054bf24ad0SHans J. Schultz int err, spid; 4064bf24ad0SHans J. Schultz u16 val, fid; 4070977644cSAndrew Lunn 408c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 4090977644cSAndrew Lunn 4104bf24ad0SHans J. Schultz err = mv88e6xxx_g1_read_atu_violation(chip); 4110977644cSAndrew Lunn if (err) 412*0c34aff5SHans J. Schultz goto out_unlock; 4130977644cSAndrew Lunn 4140977644cSAndrew Lunn err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &val); 4150977644cSAndrew Lunn if (err) 416*0c34aff5SHans J. Schultz goto out_unlock; 4170977644cSAndrew Lunn 4184bf24ad0SHans J. Schultz err = mv88e6xxx_g1_atu_fid_read(chip, &fid); 4194bf24ad0SHans J. Schultz if (err) 420*0c34aff5SHans J. Schultz goto out_unlock; 4214bf24ad0SHans J. Schultz 4220977644cSAndrew Lunn err = mv88e6xxx_g1_atu_data_read(chip, &entry); 4230977644cSAndrew Lunn if (err) 424*0c34aff5SHans J. Schultz goto out_unlock; 4250977644cSAndrew Lunn 4260977644cSAndrew Lunn err = mv88e6xxx_g1_atu_mac_read(chip, &entry); 4270977644cSAndrew Lunn if (err) 428*0c34aff5SHans J. Schultz goto out_unlock; 429*0c34aff5SHans J. Schultz 430*0c34aff5SHans J. Schultz mv88e6xxx_reg_unlock(chip); 4310977644cSAndrew Lunn 43275c05a74SAndrew Lunn spid = entry.state; 43375c05a74SAndrew Lunn 4340977644cSAndrew Lunn if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) { 4358646384dSVladimir Oltean trace_mv88e6xxx_atu_member_violation(chip->dev, spid, 4368646384dSVladimir Oltean entry.portvec, entry.mac, 4378646384dSVladimir Oltean fid); 43875c05a74SAndrew Lunn chip->ports[spid].atu_member_violation++; 4390977644cSAndrew Lunn } 4400977644cSAndrew Lunn 441ddca24dfSAndrew Lunn if (val & MV88E6XXX_G1_ATU_OP_MISS_VIOLATION) { 4428646384dSVladimir Oltean trace_mv88e6xxx_atu_miss_violation(chip->dev, spid, 4438646384dSVladimir Oltean entry.portvec, entry.mac, 4448646384dSVladimir Oltean fid); 44575c05a74SAndrew Lunn chip->ports[spid].atu_miss_violation++; 44665f60e45SAndrew Lunn } 4470977644cSAndrew Lunn 44865f60e45SAndrew Lunn if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) { 4498646384dSVladimir Oltean trace_mv88e6xxx_atu_full_violation(chip->dev, spid, 4508646384dSVladimir Oltean entry.portvec, entry.mac, 4518646384dSVladimir Oltean fid); 45275c05a74SAndrew Lunn chip->ports[spid].atu_full_violation++; 45365f60e45SAndrew Lunn } 4540977644cSAndrew Lunn 4550977644cSAndrew Lunn return IRQ_HANDLED; 4560977644cSAndrew Lunn 457*0c34aff5SHans J. Schultz out_unlock: 458c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 4590977644cSAndrew Lunn dev_err(chip->dev, "ATU problem: error %d while handling interrupt\n", 4600977644cSAndrew Lunn err); 4610977644cSAndrew Lunn return IRQ_HANDLED; 4620977644cSAndrew Lunn } 4630977644cSAndrew Lunn 4640977644cSAndrew Lunn int mv88e6xxx_g1_atu_prob_irq_setup(struct mv88e6xxx_chip *chip) 4650977644cSAndrew Lunn { 4660977644cSAndrew Lunn int err; 4670977644cSAndrew Lunn 4680977644cSAndrew Lunn chip->atu_prob_irq = irq_find_mapping(chip->g1_irq.domain, 4690977644cSAndrew Lunn MV88E6XXX_G1_STS_IRQ_ATU_PROB); 4700977644cSAndrew Lunn if (chip->atu_prob_irq < 0) 4719b662a3eSAndrew Lunn return chip->atu_prob_irq; 4720977644cSAndrew Lunn 4738ddf0b56SAndrew Lunn snprintf(chip->atu_prob_irq_name, sizeof(chip->atu_prob_irq_name), 4748ddf0b56SAndrew Lunn "mv88e6xxx-%s-g1-atu-prob", dev_name(chip->dev)); 4758ddf0b56SAndrew Lunn 4760977644cSAndrew Lunn err = request_threaded_irq(chip->atu_prob_irq, NULL, 4770977644cSAndrew Lunn mv88e6xxx_g1_atu_prob_irq_thread_fn, 4788ddf0b56SAndrew Lunn IRQF_ONESHOT, chip->atu_prob_irq_name, 4790977644cSAndrew Lunn chip); 4800977644cSAndrew Lunn if (err) 4810977644cSAndrew Lunn irq_dispose_mapping(chip->atu_prob_irq); 4820977644cSAndrew Lunn 4830977644cSAndrew Lunn return err; 4840977644cSAndrew Lunn } 4850977644cSAndrew Lunn 4860977644cSAndrew Lunn void mv88e6xxx_g1_atu_prob_irq_free(struct mv88e6xxx_chip *chip) 4870977644cSAndrew Lunn { 4880977644cSAndrew Lunn free_irq(chip->atu_prob_irq, chip); 4890977644cSAndrew Lunn irq_dispose_mapping(chip->atu_prob_irq); 4900977644cSAndrew Lunn } 491