aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/dsa
diff options
context:
space:
mode:
authorArun Ramadoss <arun.ramadoss@microchip.com>2022-09-22 12:40:27 +0530
committerJakub Kicinski <kuba@kernel.org>2022-09-26 12:42:01 -0700
commite1add7dd6183b9d4184847c310f8dd9f1a2ba7a4 (patch)
tree80896155ba3db53001dac676357830e23c6a5c6d /drivers/net/dsa
parentnet: dsa: microchip: move interrupt handling logic from lan937x to ksz_common (diff)
downloadlinux-dev-e1add7dd6183b9d4184847c310f8dd9f1a2ba7a4.tar.xz
linux-dev-e1add7dd6183b9d4184847c310f8dd9f1a2ba7a4.zip
net: dsa: microchip: use common irq routines for girq and pirq
The global port interrupt routines and individual ports interrupt routines has similar implementation except the mask & status register and number of nested irqs in them. The mask & status register and pointer to ksz_device is added to ksz_irq and uses the ksz_irq as irq_chip_data. Signed-off-by: Arun Ramadoss <arun.ramadoss@microchip.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers/net/dsa')
-rw-r--r--drivers/net/dsa/microchip/ksz_common.c264
-rw-r--r--drivers/net/dsa/microchip/ksz_common.h9
2 files changed, 81 insertions, 192 deletions
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 605ce3ffbeff..d612181b3226 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -1768,97 +1768,97 @@ static int ksz_mdio_register(struct ksz_device *dev)
return ret;
}
-static void ksz_girq_mask(struct irq_data *d)
+static void ksz_irq_mask(struct irq_data *d)
{
- struct ksz_device *dev = irq_data_get_irq_chip_data(d);
- unsigned int n = d->hwirq;
+ struct ksz_irq *kirq = irq_data_get_irq_chip_data(d);
- dev->girq.masked |= (1 << n);
+ kirq->masked |= BIT(d->hwirq);
}
-static void ksz_girq_unmask(struct irq_data *d)
+static void ksz_irq_unmask(struct irq_data *d)
{
- struct ksz_device *dev = irq_data_get_irq_chip_data(d);
- unsigned int n = d->hwirq;
+ struct ksz_irq *kirq = irq_data_get_irq_chip_data(d);
- dev->girq.masked &= ~(1 << n);
+ kirq->masked &= ~BIT(d->hwirq);
}
-static void ksz_girq_bus_lock(struct irq_data *d)
+static void ksz_irq_bus_lock(struct irq_data *d)
{
- struct ksz_device *dev = irq_data_get_irq_chip_data(d);
+ struct ksz_irq *kirq = irq_data_get_irq_chip_data(d);
- mutex_lock(&dev->lock_irq);
+ mutex_lock(&kirq->dev->lock_irq);
}
-static void ksz_girq_bus_sync_unlock(struct irq_data *d)
+static void ksz_irq_bus_sync_unlock(struct irq_data *d)
{
- struct ksz_device *dev = irq_data_get_irq_chip_data(d);
+ struct ksz_irq *kirq = irq_data_get_irq_chip_data(d);
+ struct ksz_device *dev = kirq->dev;
int ret;
- ret = ksz_write32(dev, REG_SW_PORT_INT_MASK__4, dev->girq.masked);
+ ret = ksz_write32(dev, kirq->reg_mask, kirq->masked);
if (ret)
dev_err(dev->dev, "failed to change IRQ mask\n");
mutex_unlock(&dev->lock_irq);
}
-static const struct irq_chip ksz_girq_chip = {
- .name = "ksz-global",
- .irq_mask = ksz_girq_mask,
- .irq_unmask = ksz_girq_unmask,
- .irq_bus_lock = ksz_girq_bus_lock,
- .irq_bus_sync_unlock = ksz_girq_bus_sync_unlock,
+static const struct irq_chip ksz_irq_chip = {
+ .name = "ksz-irq",
+ .irq_mask = ksz_irq_mask,
+ .irq_unmask = ksz_irq_unmask,
+ .irq_bus_lock = ksz_irq_bus_lock,
+ .irq_bus_sync_unlock = ksz_irq_bus_sync_unlock,
};
-static int ksz_girq_domain_map(struct irq_domain *d,
- unsigned int irq, irq_hw_number_t hwirq)
+static int ksz_irq_domain_map(struct irq_domain *d,
+ unsigned int irq, irq_hw_number_t hwirq)
{
- struct ksz_device *dev = d->host_data;
-
irq_set_chip_data(irq, d->host_data);
- irq_set_chip_and_handler(irq, &dev->girq.chip, handle_level_irq);
+ irq_set_chip_and_handler(irq, &ksz_irq_chip, handle_level_irq);
irq_set_noprobe(irq);
return 0;
}
-static const struct irq_domain_ops ksz_girq_domain_ops = {
- .map = ksz_girq_domain_map,
+static const struct irq_domain_ops ksz_irq_domain_ops = {
+ .map = ksz_irq_domain_map,
.xlate = irq_domain_xlate_twocell,
};
-static void ksz_girq_free(struct ksz_device *dev)
+static void ksz_irq_free(struct ksz_irq *kirq)
{
int irq, virq;
- free_irq(dev->irq, dev);
+ free_irq(kirq->irq_num, kirq);
- for (irq = 0; irq < dev->girq.nirqs; irq++) {
- virq = irq_find_mapping(dev->girq.domain, irq);
+ for (irq = 0; irq < kirq->nirqs; irq++) {
+ virq = irq_find_mapping(kirq->domain, irq);
irq_dispose_mapping(virq);
}
- irq_domain_remove(dev->girq.domain);
+ irq_domain_remove(kirq->domain);
}
-static irqreturn_t ksz_girq_thread_fn(int irq, void *dev_id)
+static irqreturn_t ksz_irq_thread_fn(int irq, void *dev_id)
{
- struct ksz_device *dev = dev_id;
+ struct ksz_irq *kirq = dev_id;
unsigned int nhandled = 0;
+ struct ksz_device *dev;
unsigned int sub_irq;
- unsigned int n;
- u32 data;
+ u8 data;
int ret;
+ u8 n;
- /* Read global interrupt status register */
- ret = ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data);
+ dev = kirq->dev;
+
+ /* Read interrupt status register */
+ ret = ksz_read8(dev, kirq->reg_status, &data);
if (ret)
goto out;
- for (n = 0; n < dev->girq.nirqs; ++n) {
- if (data & (1 << n)) {
- sub_irq = irq_find_mapping(dev->girq.domain, n);
+ for (n = 0; n < kirq->nirqs; ++n) {
+ if (data & BIT(n)) {
+ sub_irq = irq_find_mapping(kirq->domain, n);
handle_nested_irq(sub_irq);
++nhandled;
}
@@ -1867,177 +1867,63 @@ out:
return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
}
-static int ksz_girq_setup(struct ksz_device *dev)
+static int ksz_irq_common_setup(struct ksz_device *dev, struct ksz_irq *kirq)
{
- int ret, irq;
+ int ret, n;
- dev->girq.nirqs = dev->info->port_cnt;
- dev->girq.domain = irq_domain_add_simple(NULL, dev->girq.nirqs, 0,
- &ksz_girq_domain_ops, dev);
- if (!dev->girq.domain)
- return -ENOMEM;
+ kirq->dev = dev;
+ kirq->masked = ~0;
- for (irq = 0; irq < dev->girq.nirqs; irq++)
- irq_create_mapping(dev->girq.domain, irq);
+ kirq->domain = irq_domain_add_simple(dev->dev->of_node, kirq->nirqs, 0,
+ &ksz_irq_domain_ops, kirq);
+ if (!kirq->domain)
+ return -ENOMEM;
- dev->girq.chip = ksz_girq_chip;
- dev->girq.masked = ~0;
+ for (n = 0; n < kirq->nirqs; n++)
+ irq_create_mapping(kirq->domain, n);
- ret = request_threaded_irq(dev->irq, NULL, ksz_girq_thread_fn,
+ ret = request_threaded_irq(kirq->irq_num, NULL, ksz_irq_thread_fn,
IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
- dev_name(dev->dev), dev);
+ kirq->name, kirq);
if (ret)
goto out;
return 0;
out:
- ksz_girq_free(dev);
+ ksz_irq_free(kirq);
return ret;
}
-static void ksz_pirq_mask(struct irq_data *d)
-{
- struct ksz_port *port = irq_data_get_irq_chip_data(d);
- unsigned int n = d->hwirq;
-
- port->pirq.masked |= (1 << n);
-}
-
-static void ksz_pirq_unmask(struct irq_data *d)
-{
- struct ksz_port *port = irq_data_get_irq_chip_data(d);
- unsigned int n = d->hwirq;
-
- port->pirq.masked &= ~(1 << n);
-}
-
-static void ksz_pirq_bus_lock(struct irq_data *d)
-{
- struct ksz_port *port = irq_data_get_irq_chip_data(d);
- struct ksz_device *dev = port->ksz_dev;
-
- mutex_lock(&dev->lock_irq);
-}
-
-static void ksz_pirq_bus_sync_unlock(struct irq_data *d)
-{
- struct ksz_port *port = irq_data_get_irq_chip_data(d);
- struct ksz_device *dev = port->ksz_dev;
-
- ksz_pwrite8(dev, port->num, REG_PORT_INT_MASK, port->pirq.masked);
- mutex_unlock(&dev->lock_irq);
-}
-
-static const struct irq_chip ksz_pirq_chip = {
- .name = "ksz-port",
- .irq_mask = ksz_pirq_mask,
- .irq_unmask = ksz_pirq_unmask,
- .irq_bus_lock = ksz_pirq_bus_lock,
- .irq_bus_sync_unlock = ksz_pirq_bus_sync_unlock,
-};
-
-static int ksz_pirq_domain_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- struct ksz_port *port = d->host_data;
-
- irq_set_chip_data(irq, d->host_data);
- irq_set_chip_and_handler(irq, &port->pirq.chip, handle_level_irq);
- irq_set_noprobe(irq);
-
- return 0;
-}
-
-static const struct irq_domain_ops ksz_pirq_domain_ops = {
- .map = ksz_pirq_domain_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
-static void ksz_pirq_free(struct ksz_device *dev, u8 p)
-{
- struct ksz_port *port = &dev->ports[p];
- int irq, virq;
- int irq_num;
-
- irq_num = irq_find_mapping(dev->girq.domain, p);
- if (irq_num < 0)
- return;
-
- free_irq(irq_num, port);
-
- for (irq = 0; irq < port->pirq.nirqs; irq++) {
- virq = irq_find_mapping(port->pirq.domain, irq);
- irq_dispose_mapping(virq);
- }
-
- irq_domain_remove(port->pirq.domain);
-}
-
-static irqreturn_t ksz_pirq_thread_fn(int irq, void *dev_id)
+static int ksz_girq_setup(struct ksz_device *dev)
{
- struct ksz_port *port = dev_id;
- unsigned int nhandled = 0;
- struct ksz_device *dev;
- unsigned int sub_irq;
- unsigned int n;
- u8 data;
-
- dev = port->ksz_dev;
+ struct ksz_irq *girq = &dev->girq;
- /* Read port interrupt status register */
- ksz_pread8(dev, port->num, REG_PORT_INT_STATUS, &data);
+ girq->nirqs = dev->info->port_cnt;
+ girq->reg_mask = REG_SW_PORT_INT_MASK__1;
+ girq->reg_status = REG_SW_PORT_INT_STATUS__1;
+ snprintf(girq->name, sizeof(girq->name), "global_port_irq");
- for (n = 0; n < port->pirq.nirqs; ++n) {
- if (data & (1 << n)) {
- sub_irq = irq_find_mapping(port->pirq.domain, n);
- handle_nested_irq(sub_irq);
- ++nhandled;
- }
- }
+ girq->irq_num = dev->irq;
- return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
+ return ksz_irq_common_setup(dev, girq);
}
static int ksz_pirq_setup(struct ksz_device *dev, u8 p)
{
- struct ksz_port *port = &dev->ports[p];
- int ret, irq;
- int irq_num;
-
- port->pirq.nirqs = dev->info->port_nirqs;
- port->pirq.domain = irq_domain_add_simple(dev->dev->of_node,
- port->pirq.nirqs, 0,
- &ksz_pirq_domain_ops,
- port);
- if (!port->pirq.domain)
- return -ENOMEM;
-
- for (irq = 0; irq < port->pirq.nirqs; irq++)
- irq_create_mapping(port->pirq.domain, irq);
-
- port->pirq.chip = ksz_pirq_chip;
- port->pirq.masked = ~0;
+ struct ksz_irq *pirq = &dev->ports[p].pirq;
- irq_num = irq_find_mapping(dev->girq.domain, p);
- if (irq_num < 0)
- return irq_num;
+ pirq->nirqs = dev->info->port_nirqs;
+ pirq->reg_mask = dev->dev_ops->get_port_addr(p, REG_PORT_INT_MASK);
+ pirq->reg_status = dev->dev_ops->get_port_addr(p, REG_PORT_INT_STATUS);
+ snprintf(pirq->name, sizeof(pirq->name), "port_irq-%d", p);
- snprintf(port->pirq.name, sizeof(port->pirq.name), "port_irq-%d", p);
+ pirq->irq_num = irq_find_mapping(dev->girq.domain, p);
+ if (pirq->irq_num < 0)
+ return pirq->irq_num;
- ret = request_threaded_irq(irq_num, NULL, ksz_pirq_thread_fn,
- IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
- port->pirq.name, port);
- if (ret)
- goto out;
-
- return 0;
-
-out:
- ksz_pirq_free(dev, p);
-
- return ret;
+ return ksz_irq_common_setup(dev, pirq);
}
static int ksz_setup(struct dsa_switch *ds)
@@ -2119,10 +2005,10 @@ static int ksz_setup(struct dsa_switch *ds)
out_pirq:
if (dev->irq > 0)
dsa_switch_for_each_user_port(dp, dev->ds)
- ksz_pirq_free(dev, dp->index);
+ ksz_irq_free(&dev->ports[dp->index].pirq);
out_girq:
if (dev->irq > 0)
- ksz_girq_free(dev);
+ ksz_irq_free(&dev->girq);
return ret;
}
@@ -2134,9 +2020,9 @@ static void ksz_teardown(struct dsa_switch *ds)
if (dev->irq > 0) {
dsa_switch_for_each_user_port(dp, dev->ds)
- ksz_pirq_free(dev, dp->index);
+ ksz_irq_free(&dev->ports[dp->index].pirq);
- ksz_girq_free(dev);
+ ksz_irq_free(&dev->girq);
}
if (dev->dev_ops->teardown)
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index 6edce587bfd2..9cfa179575ce 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -72,10 +72,13 @@ struct ksz_chip_data {
struct ksz_irq {
u16 masked;
- struct irq_chip chip;
+ u16 reg_mask;
+ u16 reg_status;
struct irq_domain *domain;
int nirqs;
+ int irq_num;
char name[16];
+ struct ksz_device *dev;
};
struct ksz_port {
@@ -574,8 +577,8 @@ static inline int is_lan937x(struct ksz_device *dev)
#define P_MII_SEL_M 0x3
/* Interrupt */
-#define REG_SW_PORT_INT_STATUS__4 0x0018
-#define REG_SW_PORT_INT_MASK__4 0x001C
+#define REG_SW_PORT_INT_STATUS__1 0x001B
+#define REG_SW_PORT_INT_MASK__1 0x001F
#define REG_PORT_INT_STATUS 0x001B
#define REG_PORT_INT_MASK 0x001F