diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index d6d9d66b81ce..e30d0eaf2b5f 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -413,19 +413,26 @@ static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = { static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) { int irq, virq; + u16 mask; + + mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &mask); + mask |= GENMASK(chip->g1_irq.nirqs, 0); + mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask); + + free_irq(chip->irq, chip); for (irq = 0; irq < 16; irq++) { - virq = irq_find_mapping(chip->g2_irq.domain, irq); + virq = irq_find_mapping(chip->g1_irq.domain, irq); irq_dispose_mapping(virq); } - irq_domain_remove(chip->g2_irq.domain); + irq_domain_remove(chip->g1_irq.domain); } static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) { - int err, irq; - u16 reg; + int err, irq, virq; + u16 reg, mask; chip->g1_irq.nirqs = chip->info->g1_irqs; chip->g1_irq.domain = irq_domain_add_simple( @@ -440,32 +447,41 @@ static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) chip->g1_irq.chip = mv88e6xxx_g1_irq_chip; chip->g1_irq.masked = ~0; - err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, ®); + err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &mask); if (err) - goto out; + goto out_mapping; - reg &= ~GENMASK(chip->g1_irq.nirqs, 0); + mask &= ~GENMASK(chip->g1_irq.nirqs, 0); - err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, reg); + err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask); if (err) - goto out; + goto out_disable; /* Reading the interrupt status clears (most of) them */ err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, ®); if (err) - goto out; + goto out_disable; err = request_threaded_irq(chip->irq, NULL, mv88e6xxx_g1_irq_thread_fn, IRQF_ONESHOT | IRQF_TRIGGER_FALLING, dev_name(chip->dev), chip); if (err) - goto out; + goto out_disable; return 0; -out: - mv88e6xxx_g1_irq_free(chip); +out_disable: + mask |= GENMASK(chip->g1_irq.nirqs, 0); + mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask); + +out_mapping: + for (irq = 0; irq < 16; irq++) { + virq = irq_find_mapping(chip->g1_irq.domain, irq); + irq_dispose_mapping(virq); + } + + irq_domain_remove(chip->g1_irq.domain); return err; } @@ -3897,10 +3913,14 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) out_mdio: mv88e6xxx_mdio_unregister(chip); out_g2_irq: - if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT)) + if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT) && chip->irq > 0) mv88e6xxx_g2_irq_free(chip); out_g1_irq: - mv88e6xxx_g1_irq_free(chip); + if (chip->irq > 0) { + mutex_lock(&chip->reg_lock); + mv88e6xxx_g1_irq_free(chip); + mutex_unlock(&chip->reg_lock); + } out: return err; } @@ -3914,9 +3934,11 @@ static void mv88e6xxx_remove(struct mdio_device *mdiodev) mv88e6xxx_unregister_switch(chip); mv88e6xxx_mdio_unregister(chip); - if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT)) - mv88e6xxx_g2_irq_free(chip); - mv88e6xxx_g1_irq_free(chip); + if (chip->irq > 0) { + if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_INT)) + mv88e6xxx_g2_irq_free(chip); + mv88e6xxx_g1_irq_free(chip); + } } static const struct of_device_id mv88e6xxx_of_match[] = { diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index 1a0b13521d13..536a27c9735f 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -507,6 +507,9 @@ void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip) { int irq, virq; + free_irq(chip->device_irq, chip); + irq_dispose_mapping(chip->device_irq); + for (irq = 0; irq < 16; irq++) { virq = irq_find_mapping(chip->g2_irq.domain, irq); irq_dispose_mapping(virq); @@ -517,8 +520,7 @@ void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip) int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip) { - int device_irq; - int err, irq; + int err, irq, virq; if (!chip->dev->of_node) return -EINVAL; @@ -534,22 +536,28 @@ int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip) chip->g2_irq.chip = mv88e6xxx_g2_irq_chip; chip->g2_irq.masked = ~0; - device_irq = irq_find_mapping(chip->g1_irq.domain, - GLOBAL_STATUS_IRQ_DEVICE); - if (device_irq < 0) { - err = device_irq; + chip->device_irq = irq_find_mapping(chip->g1_irq.domain, + GLOBAL_STATUS_IRQ_DEVICE); + if (chip->device_irq < 0) { + err = chip->device_irq; goto out; } - err = devm_request_threaded_irq(chip->dev, device_irq, NULL, - mv88e6xxx_g2_irq_thread_fn, - IRQF_ONESHOT, "mv88e6xxx-g1", chip); + err = request_threaded_irq(chip->device_irq, NULL, + mv88e6xxx_g2_irq_thread_fn, + IRQF_ONESHOT, "mv88e6xxx-g1", chip); if (err) goto out; return 0; + out: - mv88e6xxx_g2_irq_free(chip); + for (irq = 0; irq < 16; irq++) { + virq = irq_find_mapping(chip->g2_irq.domain, irq); + irq_dispose_mapping(virq); + } + + irq_domain_remove(chip->g2_irq.domain); return err; } diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 929613021eff..a3869504f881 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -714,6 +714,7 @@ struct mv88e6xxx_chip { struct mv88e6xxx_irq g1_irq; struct mv88e6xxx_irq g2_irq; int irq; + int device_irq; }; struct mv88e6xxx_bus_ops {