root/drivers/net/dsa/mv88e6xxx/global1_atu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mv88e6xxx_g1_atu_fid_write
  2. mv88e6xxx_g1_atu_set_learn2all
  3. mv88e6xxx_g1_atu_set_age_time
  4. mv88e6xxx_g1_atu_op_wait
  5. mv88e6xxx_g1_atu_op
  6. mv88e6xxx_g1_atu_data_read
  7. mv88e6xxx_g1_atu_data_write
  8. mv88e6xxx_g1_atu_mac_read
  9. mv88e6xxx_g1_atu_mac_write
  10. mv88e6xxx_g1_atu_getnext
  11. mv88e6xxx_g1_atu_loadpurge
  12. mv88e6xxx_g1_atu_flushmove
  13. mv88e6xxx_g1_atu_flush
  14. mv88e6xxx_g1_atu_move
  15. mv88e6xxx_g1_atu_remove
  16. mv88e6xxx_g1_atu_prob_irq_thread_fn
  17. mv88e6xxx_g1_atu_prob_irq_setup
  18. mv88e6xxx_g1_atu_prob_irq_free

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

/* [<][>][^][v][top][bottom][index][help] */