if (err)
goto out_g1_irq;
}
+
+ err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
+ if (err)
+ goto out_g2_irq;
}
err = mv88e6xxx_mdios_register(chip, np);
if (err)
- goto out_g2_irq;
+ goto out_g1_atu_prob_irq;
err = mv88e6xxx_register_switch(chip);
if (err)
out_mdio:
mv88e6xxx_mdios_unregister(chip);
+out_g1_atu_prob_irq:
+ mv88e6xxx_g1_atu_prob_irq_free(chip);
out_g2_irq:
if (chip->info->g2_irqs > 0 && chip->irq > 0)
mv88e6xxx_g2_irq_free(chip);
mv88e6xxx_mdios_unregister(chip);
if (chip->irq > 0) {
+ mv88e6xxx_g1_atu_prob_irq_free(chip);
if (chip->info->g2_irqs > 0)
mv88e6xxx_g2_irq_free(chip);
mutex_lock(&chip->reg_lock);
#define MV88E6XXX_G1_STS_IRQ_STATS 6
#define MV88E6XXX_G1_STS_IRQ_VTU_PROBLEM 5
#define MV88E6XXX_G1_STS_IRQ_VTU_DONE 4
-#define MV88E6XXX_G1_STS_IRQ_ATU_PROBLEM 3
+#define MV88E6XXX_G1_STS_IRQ_ATU_PROB 3
#define MV88E6XXX_G1_STS_IRQ_ATU_DONE 2
#define MV88E6XXX_G1_STS_IRQ_TCAM_DONE 1
#define MV88E6XXX_G1_STS_IRQ_EEPROM_DONE 0
#define MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL_DB 0x5000
#define MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC_DB 0x6000
#define MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION 0x7000
+#define MV88E6XXX_G1_ATU_OP_AGE_OUT_VIOLATION BIT(7)
+#define MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION BIT(6)
+#define MV88E6XXX_G1_ATU_OP_MISS_VIOLTATION BIT(5)
+#define MV88E6XXX_G1_ATU_OP_FULL_VIOLATION BIT(4)
/* Offset 0x0C: ATU Data Register */
#define MV88E6XXX_G1_ATU_DATA 0x0c
int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip *chip, u16 fid, bool all);
int mv88e6xxx_g1_atu_remove(struct mv88e6xxx_chip *chip, u16 fid, int port,
bool all);
+int mv88e6xxx_g1_atu_prob_irq_setup(struct mv88e6xxx_chip *chip);
+void mv88e6xxx_g1_atu_prob_irq_free(struct mv88e6xxx_chip *chip);
int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_vtu_entry *entry);
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include "chip.h"
#include "global1.h"
return mv88e6xxx_g1_atu_move(chip, fid, from_port, to_port, all);
}
+
+static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
+{
+ struct mv88e6xxx_chip *chip = dev_id;
+ struct mv88e6xxx_atu_entry entry;
+ int err;
+ u16 val;
+
+ mutex_lock(&chip->reg_lock);
+
+ err = mv88e6xxx_g1_atu_op(chip, 0,
+ MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
+ if (err)
+ goto out;
+
+ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &val);
+ if (err)
+ goto out;
+
+ err = mv88e6xxx_g1_atu_data_read(chip, &entry);
+ if (err)
+ goto out;
+
+ err = mv88e6xxx_g1_atu_mac_read(chip, &entry);
+ if (err)
+ goto out;
+
+ mutex_unlock(&chip->reg_lock);
+
+ if (val & MV88E6XXX_G1_ATU_OP_AGE_OUT_VIOLATION) {
+ dev_err_ratelimited(chip->dev,
+ "ATU age out violation for %pM\n",
+ entry.mac);
+ }
+
+ if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) {
+ dev_err_ratelimited(chip->dev,
+ "ATU member violation for %pM portvec %x\n",
+ entry.mac, entry.portvec);
+ }
+
+ if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION)
+ dev_err_ratelimited(chip->dev,
+ "ATU miss violation for %pM portvec %x\n",
+ entry.mac, entry.portvec);
+
+ if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION)
+ dev_err_ratelimited(chip->dev,
+ "ATU full violation for %pM portvec %x\n",
+ entry.mac, entry.portvec);
+
+ return IRQ_HANDLED;
+
+out:
+ mutex_unlock(&chip->reg_lock);
+
+ dev_err(chip->dev, "ATU problem: error %d while handling interrupt\n",
+ err);
+ return IRQ_HANDLED;
+}
+
+int mv88e6xxx_g1_atu_prob_irq_setup(struct mv88e6xxx_chip *chip)
+{
+ int err;
+
+ chip->atu_prob_irq = irq_find_mapping(chip->g1_irq.domain,
+ MV88E6XXX_G1_STS_IRQ_ATU_PROB);
+ if (chip->atu_prob_irq < 0)
+ return chip->device_irq;
+
+ err = request_threaded_irq(chip->atu_prob_irq, NULL,
+ mv88e6xxx_g1_atu_prob_irq_thread_fn,
+ IRQF_ONESHOT, "mv88e6xxx-g1-atu-prob",
+ chip);
+ if (err)
+ irq_dispose_mapping(chip->atu_prob_irq);
+
+ return err;
+}
+
+void mv88e6xxx_g1_atu_prob_irq_free(struct mv88e6xxx_chip *chip)
+{
+ free_irq(chip->atu_prob_irq, chip);
+ irq_dispose_mapping(chip->atu_prob_irq);
+}