pinctrl: ocelot: Fix interrupt controller

When an external device generated a level based interrupt then the
interrupt controller could miss the interrupt. The reason is that the
interrupt controller can detect only link changes.

In the following example, if there is a PHY that generates an interrupt
then the following would happen. The GPIO detected that the interrupt
line changed, and then the 'ocelot_irq_handler' was called. Here it
detects which GPIO line saw the change and for that will call the
following:
1. irq_mask
2. phy interrupt routine
3. irq_eoi
4. irq_unmask

And this works fine for simple cases, but if the PHY generates many
interrupts, for example when doing PTP timestamping, then the following
could happen. Again the function 'ocelot_irq_handler' will be called
and then from here the following could happen:
1. irq_mask
2. phy interrupt routine
3. irq_eoi
4. irq_unmask

Right before step 3(irq_eoi), the PHY will generate another interrupt.
Now the interrupt controller will acknowledge the change in the
interrupt line. So we miss the interrupt.

A solution will be to use 'handle_level_irq' instead of
'handle_fasteoi_irq', because for this will change routine order of
handling the interrupt.
1. irq_mask
2. irq_ack
3. phy interrupt routine
4. irq_unmask

And now if the PHY will generate a new interrupt before irq_unmask, the
interrupt controller will detect this because it already acknowledge the
change in interrupt line at step 2(irq_ack).

But this is not the full solution because there is another issue. In
case there are 2 PHYs that share the interrupt line. For example phy1
generates an interrupt, then the following can happen:
1.irq_mask
2.irq_ack
3.phy0 interrupt routine
4.phy1 interrupt routine
5.irq_unmask

In case phy0 will generate an interrupt while clearing the interrupt
source in phy1, then the interrupt line will be kept down by phy0. So
the interrupt controller will not see any changes in the interrupt line.
The solution here is to update 'irq_unmask' such that it can detect if
the interrupt line is still active or not. And if it is active then call
again the procedure to clear the interrupts. But we don't want to do it
every time, only if we know that the interrupt controller has not seen
already that the interrupt line has changed.

While at this, add support also for IRQ_TYPE_LEVEL_LOW.

Fixes: be36abb71d878f ("pinctrl: ocelot: add support for interrupt controller")
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
Link: https://lore.kernel.org/r/20220909145942.844102-1-horatiu.vultur@microchip.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by Horatiu Vultur and committed by Linus Walleij c297561b 76648c86

Changed files
+97 -14
drivers
+97 -14
drivers/pinctrl/pinctrl-ocelot.c
··· 331 331 const struct ocelot_pincfg_data *pincfg_data; 332 332 struct ocelot_pmx_func func[FUNC_MAX]; 333 333 u8 stride; 334 + struct workqueue_struct *wq; 334 335 }; 335 336 336 337 struct ocelot_match_data { 337 338 struct pinctrl_desc desc; 338 339 struct ocelot_pincfg_data pincfg_data; 340 + }; 341 + 342 + struct ocelot_irq_work { 343 + struct work_struct irq_work; 344 + struct irq_desc *irq_desc; 339 345 }; 340 346 341 347 #define LUTON_P(p, f0, f1) \ ··· 1819 1813 gpiochip_disable_irq(chip, gpio); 1820 1814 } 1821 1815 1816 + static void ocelot_irq_work(struct work_struct *work) 1817 + { 1818 + struct ocelot_irq_work *w = container_of(work, struct ocelot_irq_work, irq_work); 1819 + struct irq_chip *parent_chip = irq_desc_get_chip(w->irq_desc); 1820 + struct gpio_chip *chip = irq_desc_get_chip_data(w->irq_desc); 1821 + struct irq_data *data = irq_desc_get_irq_data(w->irq_desc); 1822 + unsigned int gpio = irqd_to_hwirq(data); 1823 + 1824 + local_irq_disable(); 1825 + chained_irq_enter(parent_chip, w->irq_desc); 1826 + generic_handle_domain_irq(chip->irq.domain, gpio); 1827 + chained_irq_exit(parent_chip, w->irq_desc); 1828 + local_irq_enable(); 1829 + 1830 + kfree(w); 1831 + } 1832 + 1833 + static void ocelot_irq_unmask_level(struct irq_data *data) 1834 + { 1835 + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 1836 + struct ocelot_pinctrl *info = gpiochip_get_data(chip); 1837 + struct irq_desc *desc = irq_data_to_desc(data); 1838 + unsigned int gpio = irqd_to_hwirq(data); 1839 + unsigned int bit = BIT(gpio % 32); 1840 + bool ack = false, active = false; 1841 + u8 trigger_level; 1842 + int val; 1843 + 1844 + trigger_level = irqd_get_trigger_type(data); 1845 + 1846 + /* Check if the interrupt line is still active. */ 1847 + regmap_read(info->map, REG(OCELOT_GPIO_IN, info, gpio), &val); 1848 + if ((!(val & bit) && trigger_level == IRQ_TYPE_LEVEL_LOW) || 1849 + (val & bit && trigger_level == IRQ_TYPE_LEVEL_HIGH)) 1850 + active = true; 1851 + 1852 + /* 1853 + * Check if the interrupt controller has seen any changes in the 1854 + * interrupt line. 1855 + */ 1856 + regmap_read(info->map, REG(OCELOT_GPIO_INTR, info, gpio), &val); 1857 + if (val & bit) 1858 + ack = true; 1859 + 1860 + /* Enable the interrupt now */ 1861 + gpiochip_enable_irq(chip, gpio); 1862 + regmap_update_bits(info->map, REG(OCELOT_GPIO_INTR_ENA, info, gpio), 1863 + bit, bit); 1864 + 1865 + /* 1866 + * In case the interrupt line is still active and the interrupt 1867 + * controller has not seen any changes in the interrupt line, then it 1868 + * means that there happen another interrupt while the line was active. 1869 + * So we missed that one, so we need to kick the interrupt again 1870 + * handler. 1871 + */ 1872 + if (active && !ack) { 1873 + struct ocelot_irq_work *work; 1874 + 1875 + work = kmalloc(sizeof(*work), GFP_ATOMIC); 1876 + if (!work) 1877 + return; 1878 + 1879 + work->irq_desc = desc; 1880 + INIT_WORK(&work->irq_work, ocelot_irq_work); 1881 + queue_work(info->wq, &work->irq_work); 1882 + } 1883 + } 1884 + 1822 1885 static void ocelot_irq_unmask(struct irq_data *data) 1823 1886 { 1824 1887 struct gpio_chip *chip = irq_data_get_irq_chip_data(data); ··· 1911 1836 1912 1837 static int ocelot_irq_set_type(struct irq_data *data, unsigned int type); 1913 1838 1914 - static struct irq_chip ocelot_eoi_irqchip = { 1839 + static struct irq_chip ocelot_level_irqchip = { 1915 1840 .name = "gpio", 1916 1841 .irq_mask = ocelot_irq_mask, 1917 - .irq_eoi = ocelot_irq_ack, 1918 - .irq_unmask = ocelot_irq_unmask, 1919 - .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED | 1920 - IRQCHIP_IMMUTABLE, 1842 + .irq_ack = ocelot_irq_ack, 1843 + .irq_unmask = ocelot_irq_unmask_level, 1844 + .flags = IRQCHIP_IMMUTABLE, 1921 1845 .irq_set_type = ocelot_irq_set_type, 1922 1846 GPIOCHIP_IRQ_RESOURCE_HELPERS 1923 1847 }; ··· 1933 1859 1934 1860 static int ocelot_irq_set_type(struct irq_data *data, unsigned int type) 1935 1861 { 1936 - type &= IRQ_TYPE_SENSE_MASK; 1937 - 1938 - if (!(type & (IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_HIGH))) 1939 - return -EINVAL; 1940 - 1941 - if (type & IRQ_TYPE_LEVEL_HIGH) 1942 - irq_set_chip_handler_name_locked(data, &ocelot_eoi_irqchip, 1943 - handle_fasteoi_irq, NULL); 1862 + if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) 1863 + irq_set_chip_handler_name_locked(data, &ocelot_level_irqchip, 1864 + handle_level_irq, NULL); 1944 1865 if (type & IRQ_TYPE_EDGE_BOTH) 1945 1866 irq_set_chip_handler_name_locked(data, &ocelot_irqchip, 1946 1867 handle_edge_irq, NULL); ··· 2065 1996 if (!info->desc) 2066 1997 return -ENOMEM; 2067 1998 1999 + info->wq = alloc_ordered_workqueue("ocelot_ordered", 0); 2000 + if (!info->wq) 2001 + return -ENOMEM; 2002 + 2068 2003 info->pincfg_data = &data->pincfg_data; 2069 2004 2070 2005 reset = devm_reset_control_get_optional_shared(dev, "switch"); ··· 2091 2018 dev_err(dev, "Failed to create regmap\n"); 2092 2019 return PTR_ERR(info->map); 2093 2020 } 2094 - dev_set_drvdata(dev, info->map); 2021 + dev_set_drvdata(dev, info); 2095 2022 info->dev = dev; 2096 2023 2097 2024 /* Pinconf registers */ ··· 2116 2043 return 0; 2117 2044 } 2118 2045 2046 + static int ocelot_pinctrl_remove(struct platform_device *pdev) 2047 + { 2048 + struct ocelot_pinctrl *info = platform_get_drvdata(pdev); 2049 + 2050 + destroy_workqueue(info->wq); 2051 + 2052 + return 0; 2053 + } 2054 + 2119 2055 static struct platform_driver ocelot_pinctrl_driver = { 2120 2056 .driver = { 2121 2057 .name = "pinctrl-ocelot", ··· 2132 2050 .suppress_bind_attrs = true, 2133 2051 }, 2134 2052 .probe = ocelot_pinctrl_probe, 2053 + .remove = ocelot_pinctrl_remove, 2135 2054 }; 2136 2055 module_platform_driver(ocelot_pinctrl_driver); 2137 2056 MODULE_LICENSE("Dual MIT/GPL");