Skip to content

Commit 294d711

Browse files
lunndavem330
authored andcommitted
net: dsa: mv88e6xxx: Poll when no interrupt defined
Not all boards have the interrupt output from the switch connected to a GPIO line. In such cases, phylib has to poll the internal PHYs, rather than receive an interrupt when there is a change in the link state. phylib polls once per second, and per PHY reads around 4 words. With a switch typically having 4 internal PHYs, this means 16 MDIO transactions per second. Rather than performing this phylib level polling, have the driver poll the interrupt status register. If the status register indicates an interrupt condition processing of interrupts in the same way as if a GPIO was used. Polling 10 times a second places less load on the MDIO bus. But rather than taking on average 0.5s to detect a link change, it takes less than 0.05s. Additionally, other interrupts, such as the watchdog, ATU and VTU violations will be reported. Signed-off-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 65b53bf commit 294d711

File tree

2 files changed

+106
-43
lines changed

2 files changed

+106
-43
lines changed

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 103 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,8 @@ static void mv88e6xxx_g1_irq_unmask(struct irq_data *d)
253253
chip->g1_irq.masked &= ~(1 << n);
254254
}
255255

256-
static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
256+
static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
257257
{
258-
struct mv88e6xxx_chip *chip = dev_id;
259258
unsigned int nhandled = 0;
260259
unsigned int sub_irq;
261260
unsigned int n;
@@ -280,6 +279,13 @@ static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
280279
return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
281280
}
282281

282+
static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id)
283+
{
284+
struct mv88e6xxx_chip *chip = dev_id;
285+
286+
return mv88e6xxx_g1_irq_thread_work(chip);
287+
}
288+
283289
static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
284290
{
285291
struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
@@ -335,7 +341,7 @@ static const struct irq_domain_ops mv88e6xxx_g1_irq_domain_ops = {
335341
.xlate = irq_domain_xlate_twocell,
336342
};
337343

338-
static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
344+
static void mv88e6xxx_g1_irq_free_common(struct mv88e6xxx_chip *chip)
339345
{
340346
int irq, virq;
341347
u16 mask;
@@ -344,8 +350,6 @@ static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
344350
mask &= ~GENMASK(chip->g1_irq.nirqs, 0);
345351
mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask);
346352

347-
free_irq(chip->irq, chip);
348-
349353
for (irq = 0; irq < chip->g1_irq.nirqs; irq++) {
350354
virq = irq_find_mapping(chip->g1_irq.domain, irq);
351355
irq_dispose_mapping(virq);
@@ -354,7 +358,14 @@ static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
354358
irq_domain_remove(chip->g1_irq.domain);
355359
}
356360

357-
static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
361+
static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
362+
{
363+
mv88e6xxx_g1_irq_free(chip);
364+
365+
free_irq(chip->irq, chip);
366+
}
367+
368+
static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip)
358369
{
359370
int err, irq, virq;
360371
u16 reg, mask;
@@ -387,13 +398,6 @@ static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
387398
if (err)
388399
goto out_disable;
389400

390-
err = request_threaded_irq(chip->irq, NULL,
391-
mv88e6xxx_g1_irq_thread_fn,
392-
IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
393-
dev_name(chip->dev), chip);
394-
if (err)
395-
goto out_disable;
396-
397401
return 0;
398402

399403
out_disable:
@@ -411,6 +415,62 @@ static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
411415
return err;
412416
}
413417

418+
static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
419+
{
420+
int err;
421+
422+
err = mv88e6xxx_g1_irq_setup_common(chip);
423+
if (err)
424+
return err;
425+
426+
err = request_threaded_irq(chip->irq, NULL,
427+
mv88e6xxx_g1_irq_thread_fn,
428+
IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
429+
dev_name(chip->dev), chip);
430+
if (err)
431+
mv88e6xxx_g1_irq_free_common(chip);
432+
433+
return err;
434+
}
435+
436+
static void mv88e6xxx_irq_poll(struct kthread_work *work)
437+
{
438+
struct mv88e6xxx_chip *chip = container_of(work,
439+
struct mv88e6xxx_chip,
440+
irq_poll_work.work);
441+
mv88e6xxx_g1_irq_thread_work(chip);
442+
443+
kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
444+
msecs_to_jiffies(100));
445+
}
446+
447+
static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip)
448+
{
449+
int err;
450+
451+
err = mv88e6xxx_g1_irq_setup_common(chip);
452+
if (err)
453+
return err;
454+
455+
kthread_init_delayed_work(&chip->irq_poll_work,
456+
mv88e6xxx_irq_poll);
457+
458+
chip->kworker = kthread_create_worker(0, dev_name(chip->dev));
459+
if (IS_ERR(chip->kworker))
460+
return PTR_ERR(chip->kworker);
461+
462+
kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work,
463+
msecs_to_jiffies(100));
464+
465+
return 0;
466+
}
467+
468+
static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip)
469+
{
470+
kthread_cancel_delayed_work_sync(&chip->irq_poll_work);
471+
kthread_destroy_worker(chip->kworker);
472+
}
473+
414474
int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask)
415475
{
416476
int i;
@@ -4034,33 +4094,34 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
40344094
goto out;
40354095
}
40364096

4037-
if (chip->irq > 0) {
4038-
/* Has to be performed before the MDIO bus is created,
4039-
* because the PHYs will link there interrupts to these
4040-
* interrupt controllers
4041-
*/
4042-
mutex_lock(&chip->reg_lock);
4097+
/* Has to be performed before the MDIO bus is created, because
4098+
* the PHYs will link there interrupts to these interrupt
4099+
* controllers
4100+
*/
4101+
mutex_lock(&chip->reg_lock);
4102+
if (chip->irq > 0)
40434103
err = mv88e6xxx_g1_irq_setup(chip);
4044-
mutex_unlock(&chip->reg_lock);
4045-
4046-
if (err)
4047-
goto out;
4048-
4049-
if (chip->info->g2_irqs > 0) {
4050-
err = mv88e6xxx_g2_irq_setup(chip);
4051-
if (err)
4052-
goto out_g1_irq;
4053-
}
4104+
else
4105+
err = mv88e6xxx_irq_poll_setup(chip);
4106+
mutex_unlock(&chip->reg_lock);
40544107

4055-
err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
4056-
if (err)
4057-
goto out_g2_irq;
4108+
if (err)
4109+
goto out;
40584110

4059-
err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
4111+
if (chip->info->g2_irqs > 0) {
4112+
err = mv88e6xxx_g2_irq_setup(chip);
40604113
if (err)
4061-
goto out_g1_atu_prob_irq;
4114+
goto out_g1_irq;
40624115
}
40634116

4117+
err = mv88e6xxx_g1_atu_prob_irq_setup(chip);
4118+
if (err)
4119+
goto out_g2_irq;
4120+
4121+
err = mv88e6xxx_g1_vtu_prob_irq_setup(chip);
4122+
if (err)
4123+
goto out_g1_atu_prob_irq;
4124+
40644125
err = mv88e6xxx_mdios_register(chip, np);
40654126
if (err)
40664127
goto out_g1_vtu_prob_irq;
@@ -4074,20 +4135,19 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
40744135
out_mdio:
40754136
mv88e6xxx_mdios_unregister(chip);
40764137
out_g1_vtu_prob_irq:
4077-
if (chip->irq > 0)
4078-
mv88e6xxx_g1_vtu_prob_irq_free(chip);
4138+
mv88e6xxx_g1_vtu_prob_irq_free(chip);
40794139
out_g1_atu_prob_irq:
4080-
if (chip->irq > 0)
4081-
mv88e6xxx_g1_atu_prob_irq_free(chip);
4140+
mv88e6xxx_g1_atu_prob_irq_free(chip);
40824141
out_g2_irq:
4083-
if (chip->info->g2_irqs > 0 && chip->irq > 0)
4142+
if (chip->info->g2_irqs > 0)
40844143
mv88e6xxx_g2_irq_free(chip);
40854144
out_g1_irq:
4086-
if (chip->irq > 0) {
4087-
mutex_lock(&chip->reg_lock);
4145+
mutex_lock(&chip->reg_lock);
4146+
if (chip->irq > 0)
40884147
mv88e6xxx_g1_irq_free(chip);
4089-
mutex_unlock(&chip->reg_lock);
4090-
}
4148+
else
4149+
mv88e6xxx_irq_poll_free(chip);
4150+
mutex_unlock(&chip->reg_lock);
40914151
out:
40924152
return err;
40934153
}

drivers/net/dsa/mv88e6xxx/chip.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/if_vlan.h>
1616
#include <linux/irq.h>
1717
#include <linux/gpio/consumer.h>
18+
#include <linux/kthread.h>
1819
#include <linux/phy.h>
1920
#include <linux/ptp_clock_kernel.h>
2021
#include <linux/timecounter.h>
@@ -245,6 +246,8 @@ struct mv88e6xxx_chip {
245246
int watchdog_irq;
246247
int atu_prob_irq;
247248
int vtu_prob_irq;
249+
struct kthread_worker *kworker;
250+
struct kthread_delayed_work irq_poll_work;
248251

249252
/* GPIO resources */
250253
u8 gpio_data[2];

0 commit comments

Comments
 (0)