* [PATCH V2 0/4] net-next: mediatek: IRQ cleanups, fixes and grouping @ 2016-06-29 11:38 John Crispin 2016-06-29 11:38 ` [PATCH V2 1/4] net-next: mediatek: remove superfluous register reads John Crispin ` (4 more replies) 0 siblings, 5 replies; 14+ messages in thread From: John Crispin @ 2016-06-29 11:38 UTC (permalink / raw) To: David S. Miller Cc: Felix Fietkau, Sean Wang, netdev, linux-mediatek, linux-kernel, John Crispin This series contains 2 small code cleanups that are leftovers from the MIPS support. There is also a small fix that adds proper locking to the code accessing the IRQ registers. Without this fix we saw deadlocks caused by the last patch of the series, which adds IRQ grouping. The grouping feature allows us to use different IRQs for TX and RX. By doing so we can use affinity to let the SoC handle the IRQs on different cores. This series depends on a previous series currently sitting in net.git starting with commit 562c5a70400c ("net: mediatek: only wake the queue if it is stopped") up to commit 82c6544dddc6 ("net: mediatek: remove superfluous queue wake up call") John Crispin (4): net-next: mediatek: remove superfluous register reads net-next: mediatek: don't use intermediate variables to store IRQ masks net-next: mediatek: add IRQ locking net-next: mediatek: add support for IRQ grouping drivers/net/ethernet/mediatek/mtk_eth_soc.c | 174 +++++++++++++++++---------- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 16 ++- 2 files changed, 122 insertions(+), 68 deletions(-) -- 1.7.10.4 ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH V2 1/4] net-next: mediatek: remove superfluous register reads 2016-06-29 11:38 [PATCH V2 0/4] net-next: mediatek: IRQ cleanups, fixes and grouping John Crispin @ 2016-06-29 11:38 ` John Crispin 2016-06-29 11:38 ` John Crispin ` (3 subsequent siblings) 4 siblings, 0 replies; 14+ messages in thread From: John Crispin @ 2016-06-29 11:38 UTC (permalink / raw) To: David S. Miller Cc: Felix Fietkau, Sean Wang, netdev, linux-mediatek, linux-kernel, John Crispin The driver was originally written for MIPS based SoC. These required the IRQ mask register to be read after writing it to ensure that the content was actually applied. As this version only works on ARM based SoCs, we can safely remove the 2 reads as they are no longer required. Signed-off-by: John Crispin <john@phrozen.org> --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index d1cdc2d..5a3a4e9 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -332,8 +332,6 @@ static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask) val = mtk_r32(eth, MTK_QDMA_INT_MASK); mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK); - /* flush write */ - mtk_r32(eth, MTK_QDMA_INT_MASK); } static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask) @@ -342,8 +340,6 @@ static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask) val = mtk_r32(eth, MTK_QDMA_INT_MASK); mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK); - /* flush write */ - mtk_r32(eth, MTK_QDMA_INT_MASK); } static int mtk_set_mac_address(struct net_device *dev, void *p) -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH V2 2/4] net-next: mediatek: don't use intermediate variables to store IRQ masks @ 2016-06-29 11:38 ` John Crispin 0 siblings, 0 replies; 14+ messages in thread From: John Crispin @ 2016-06-29 11:38 UTC (permalink / raw) To: David S. Miller Cc: Felix Fietkau, Sean Wang, netdev, linux-mediatek, linux-kernel, John Crispin The code currently uses variables to store and never modify the bit masks of interrupts. This is legacy code from an early version of the driver that supported MIPS based SoCs where the IRQ bits depended on the actual SoC. As the bits are the same for all ARM based SoCs using this driver we can remove the intermediate variables. Signed-off-by: John Crispin <john@phrozen.org> --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 5a3a4e9..d6c3a17 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -794,7 +794,7 @@ drop: } static int mtk_poll_rx(struct napi_struct *napi, int budget, - struct mtk_eth *eth, u32 rx_intr) + struct mtk_eth *eth) { struct mtk_rx_ring *ring = ð->rx_ring; int idx = ring->calc_idx; @@ -882,7 +882,7 @@ release_desc: } if (done < budget) - mtk_w32(eth, rx_intr, MTK_QMTK_INT_STATUS); + mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS); return done; } @@ -967,28 +967,26 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) static int mtk_poll(struct napi_struct *napi, int budget) { struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi); - u32 status, status2, mask, tx_intr, rx_intr, status_intr; + u32 status, status2, mask; int tx_done, rx_done; bool tx_again = false; status = mtk_r32(eth, MTK_QMTK_INT_STATUS); status2 = mtk_r32(eth, MTK_INT_STATUS2); - tx_intr = MTK_TX_DONE_INT; - rx_intr = MTK_RX_DONE_INT; - status_intr = (MTK_GDM1_AF | MTK_GDM2_AF); tx_done = 0; rx_done = 0; tx_again = 0; - if (status & tx_intr) + if (status & MTK_TX_DONE_INT) tx_done = mtk_poll_tx(eth, budget, &tx_again); - if (status & rx_intr) - rx_done = mtk_poll_rx(napi, budget, eth, rx_intr); + if (status & MTK_RX_DONE_INT) + rx_done = mtk_poll_rx(napi, budget, eth); - if (unlikely(status2 & status_intr)) { + if (unlikely(status2 & (MTK_GDM1_AF | MTK_GDM2_AF))) { mtk_stats_update(eth); - mtk_w32(eth, status_intr, MTK_INT_STATUS2); + mtk_w32(eth, (MTK_GDM1_AF | MTK_GDM2_AF), + MTK_INT_STATUS2); } if (unlikely(netif_msg_intr(eth))) { @@ -1006,7 +1004,7 @@ static int mtk_poll(struct napi_struct *napi, int budget) return budget; napi_complete(napi); - mtk_irq_enable(eth, tx_intr | rx_intr); + mtk_irq_enable(eth, MTK_RX_DONE_INT | MTK_RX_DONE_INT); return rx_done; } -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH V2 2/4] net-next: mediatek: don't use intermediate variables to store IRQ masks @ 2016-06-29 11:38 ` John Crispin 0 siblings, 0 replies; 14+ messages in thread From: John Crispin @ 2016-06-29 11:38 UTC (permalink / raw) To: David S. Miller Cc: Sean Wang, netdev-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, John Crispin, Felix Fietkau The code currently uses variables to store and never modify the bit masks of interrupts. This is legacy code from an early version of the driver that supported MIPS based SoCs where the IRQ bits depended on the actual SoC. As the bits are the same for all ARM based SoCs using this driver we can remove the intermediate variables. Signed-off-by: John Crispin <john-Pj+rj9U5foFAfugRpC6u6w@public.gmane.org> --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 5a3a4e9..d6c3a17 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -794,7 +794,7 @@ drop: } static int mtk_poll_rx(struct napi_struct *napi, int budget, - struct mtk_eth *eth, u32 rx_intr) + struct mtk_eth *eth) { struct mtk_rx_ring *ring = ð->rx_ring; int idx = ring->calc_idx; @@ -882,7 +882,7 @@ release_desc: } if (done < budget) - mtk_w32(eth, rx_intr, MTK_QMTK_INT_STATUS); + mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS); return done; } @@ -967,28 +967,26 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) static int mtk_poll(struct napi_struct *napi, int budget) { struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi); - u32 status, status2, mask, tx_intr, rx_intr, status_intr; + u32 status, status2, mask; int tx_done, rx_done; bool tx_again = false; status = mtk_r32(eth, MTK_QMTK_INT_STATUS); status2 = mtk_r32(eth, MTK_INT_STATUS2); - tx_intr = MTK_TX_DONE_INT; - rx_intr = MTK_RX_DONE_INT; - status_intr = (MTK_GDM1_AF | MTK_GDM2_AF); tx_done = 0; rx_done = 0; tx_again = 0; - if (status & tx_intr) + if (status & MTK_TX_DONE_INT) tx_done = mtk_poll_tx(eth, budget, &tx_again); - if (status & rx_intr) - rx_done = mtk_poll_rx(napi, budget, eth, rx_intr); + if (status & MTK_RX_DONE_INT) + rx_done = mtk_poll_rx(napi, budget, eth); - if (unlikely(status2 & status_intr)) { + if (unlikely(status2 & (MTK_GDM1_AF | MTK_GDM2_AF))) { mtk_stats_update(eth); - mtk_w32(eth, status_intr, MTK_INT_STATUS2); + mtk_w32(eth, (MTK_GDM1_AF | MTK_GDM2_AF), + MTK_INT_STATUS2); } if (unlikely(netif_msg_intr(eth))) { @@ -1006,7 +1004,7 @@ static int mtk_poll(struct napi_struct *napi, int budget) return budget; napi_complete(napi); - mtk_irq_enable(eth, tx_intr | rx_intr); + mtk_irq_enable(eth, MTK_RX_DONE_INT | MTK_RX_DONE_INT); return rx_done; } -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH V2 2/4] net-next: mediatek: don't use intermediate variables to store IRQ masks 2016-06-29 11:38 ` John Crispin @ 2016-06-30 6:03 ` kbuild test robot -1 siblings, 0 replies; 14+ messages in thread From: kbuild test robot @ 2016-06-30 6:03 UTC (permalink / raw) To: John Crispin Cc: kbuild-all, David S. Miller, Felix Fietkau, Sean Wang, netdev, linux-mediatek, linux-kernel, John Crispin [-- Attachment #1: Type: text/plain, Size: 2583 bytes --] Hi, [auto build test ERROR on net/master] [also build test ERROR on v4.7-rc5 next-20160629] [cannot apply to net-next/master] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/John-Crispin/net-next-mediatek-IRQ-cleanups-fixes-and-grouping/20160629-194341 config: arm-allmodconfig (attached as .config) compiler: arm-linux-gnueabi-gcc (Debian 5.3.1-8) 5.3.1 20160205 reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=arm Note: the linux-review/John-Crispin/net-next-mediatek-IRQ-cleanups-fixes-and-grouping/20160629-194341 HEAD e8462c612b33003fba7c1a70328c7fb7872d8507 builds fine. It only hurts bisectibility. All errors (new ones prefixed by >>): drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_poll': >> drivers/net/ethernet/mediatek/mtk_eth_soc.c:1003:16: error: 'tx_intr' undeclared (first use in this function) if (status & (tx_intr | rx_intr)) ^ drivers/net/ethernet/mediatek/mtk_eth_soc.c:1003:16: note: each undeclared identifier is reported only once for each function it appears in >> drivers/net/ethernet/mediatek/mtk_eth_soc.c:1003:26: error: 'rx_intr' undeclared (first use in this function) if (status & (tx_intr | rx_intr)) ^ vim +/tx_intr +1003 drivers/net/ethernet/mediatek/mtk_eth_soc.c 656e7052 John Crispin 2016-03-08 997 } 656e7052 John Crispin 2016-03-08 998 656e7052 John Crispin 2016-03-08 999 if (tx_again || rx_done == budget) 656e7052 John Crispin 2016-03-08 1000 return budget; 656e7052 John Crispin 2016-03-08 1001 656e7052 John Crispin 2016-03-08 1002 status = mtk_r32(eth, MTK_QMTK_INT_STATUS); 656e7052 John Crispin 2016-03-08 @1003 if (status & (tx_intr | rx_intr)) 656e7052 John Crispin 2016-03-08 1004 return budget; 656e7052 John Crispin 2016-03-08 1005 656e7052 John Crispin 2016-03-08 1006 napi_complete(napi); :::::: The code at line 1003 was first introduced by commit :::::: 656e705243fd0c2864b89634ea16ed444ef64dc6 net-next: mediatek: add support for MT7623 ethernet :::::: TO: John Crispin <blogic@openwrt.org> :::::: CC: David S. Miller <davem@davemloft.net> --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/octet-stream, Size: 57589 bytes --] ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH V2 2/4] net-next: mediatek: don't use intermediate variables to store IRQ masks @ 2016-06-30 6:03 ` kbuild test robot 0 siblings, 0 replies; 14+ messages in thread From: kbuild test robot @ 2016-06-30 6:03 UTC (permalink / raw) Cc: kbuild-all, David S. Miller, Felix Fietkau, Sean Wang, netdev, linux-mediatek, linux-kernel, John Crispin [-- Attachment #1: Type: text/plain, Size: 2583 bytes --] Hi, [auto build test ERROR on net/master] [also build test ERROR on v4.7-rc5 next-20160629] [cannot apply to net-next/master] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/John-Crispin/net-next-mediatek-IRQ-cleanups-fixes-and-grouping/20160629-194341 config: arm-allmodconfig (attached as .config) compiler: arm-linux-gnueabi-gcc (Debian 5.3.1-8) 5.3.1 20160205 reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=arm Note: the linux-review/John-Crispin/net-next-mediatek-IRQ-cleanups-fixes-and-grouping/20160629-194341 HEAD e8462c612b33003fba7c1a70328c7fb7872d8507 builds fine. It only hurts bisectibility. All errors (new ones prefixed by >>): drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_poll': >> drivers/net/ethernet/mediatek/mtk_eth_soc.c:1003:16: error: 'tx_intr' undeclared (first use in this function) if (status & (tx_intr | rx_intr)) ^ drivers/net/ethernet/mediatek/mtk_eth_soc.c:1003:16: note: each undeclared identifier is reported only once for each function it appears in >> drivers/net/ethernet/mediatek/mtk_eth_soc.c:1003:26: error: 'rx_intr' undeclared (first use in this function) if (status & (tx_intr | rx_intr)) ^ vim +/tx_intr +1003 drivers/net/ethernet/mediatek/mtk_eth_soc.c 656e7052 John Crispin 2016-03-08 997 } 656e7052 John Crispin 2016-03-08 998 656e7052 John Crispin 2016-03-08 999 if (tx_again || rx_done == budget) 656e7052 John Crispin 2016-03-08 1000 return budget; 656e7052 John Crispin 2016-03-08 1001 656e7052 John Crispin 2016-03-08 1002 status = mtk_r32(eth, MTK_QMTK_INT_STATUS); 656e7052 John Crispin 2016-03-08 @1003 if (status & (tx_intr | rx_intr)) 656e7052 John Crispin 2016-03-08 1004 return budget; 656e7052 John Crispin 2016-03-08 1005 656e7052 John Crispin 2016-03-08 1006 napi_complete(napi); :::::: The code at line 1003 was first introduced by commit :::::: 656e705243fd0c2864b89634ea16ed444ef64dc6 net-next: mediatek: add support for MT7623 ethernet :::::: TO: John Crispin <blogic@openwrt.org> :::::: CC: David S. Miller <davem@davemloft.net> --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/octet-stream, Size: 57589 bytes --] ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH V2 2/4] net-next: mediatek: don't use intermediate variables to store IRQ masks 2016-06-30 6:03 ` kbuild test robot (?) @ 2016-06-30 7:33 ` John Crispin -1 siblings, 0 replies; 14+ messages in thread From: John Crispin @ 2016-06-30 7:33 UTC (permalink / raw) To: kbuild test robot Cc: Sean Wang, netdev, linux-kernel, linux-mediatek, kbuild-all, David S. Miller, Felix Fietkau On 30/06/2016 08:03, kbuild test robot wrote: > Hi, > > [auto build test ERROR on net/master] > [also build test ERROR on v4.7-rc5 next-20160629] > [cannot apply to net-next/master] > [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] > > url: https://github.com/0day-ci/linux/commits/John-Crispin/net-next-mediatek-IRQ-cleanups-fixes-and-grouping/20160629-194341 > config: arm-allmodconfig (attached as .config) > compiler: arm-linux-gnueabi-gcc (Debian 5.3.1-8) 5.3.1 20160205 > reproduce: > wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross > chmod +x ~/bin/make.cross > # save the attached .config to linux build tree > make.cross ARCH=arm > > Note: the linux-review/John-Crispin/net-next-mediatek-IRQ-cleanups-fixes-and-grouping/20160629-194341 HEAD e8462c612b33003fba7c1a70328c7fb7872d8507 builds fine. > It only hurts bisectibility. > > All errors (new ones prefixed by >>): > > drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_poll': >>> drivers/net/ethernet/mediatek/mtk_eth_soc.c:1003:16: error: 'tx_intr' undeclared (first use in this function) > if (status & (tx_intr | rx_intr)) > ^ > drivers/net/ethernet/mediatek/mtk_eth_soc.c:1003:16: note: each undeclared identifier is reported only once for each function it appears in >>> drivers/net/ethernet/mediatek/mtk_eth_soc.c:1003:26: error: 'rx_intr' undeclared (first use in this function) > if (status & (tx_intr | rx_intr)) > ^ > > vim +/tx_intr +1003 drivers/net/ethernet/mediatek/mtk_eth_soc.c > > 656e7052 John Crispin 2016-03-08 997 } > 656e7052 John Crispin 2016-03-08 998 > 656e7052 John Crispin 2016-03-08 999 if (tx_again || rx_done == budget) > 656e7052 John Crispin 2016-03-08 1000 return budget; > 656e7052 John Crispin 2016-03-08 1001 > 656e7052 John Crispin 2016-03-08 1002 status = mtk_r32(eth, MTK_QMTK_INT_STATUS); > 656e7052 John Crispin 2016-03-08 @1003 if (status & (tx_intr | rx_intr)) > 656e7052 John Crispin 2016-03-08 1004 return budget; > 656e7052 John Crispin 2016-03-08 1005 > 656e7052 John Crispin 2016-03-08 1006 napi_complete(napi); > > :::::: The code at line 1003 was first introduced by commit > :::::: 656e705243fd0c2864b89634ea16ed444ef64dc6 net-next: mediatek: add support for MT7623 ethernet > > :::::: TO: John Crispin <blogic@openwrt.org> > :::::: CC: David S. Miller <davem@davemloft.net> > > --- > 0-DAY kernel test infrastructure Open Source Technology Center > https://lists.01.org/pipermail/kbuild-all Intel Corporation Hi, This series depends on a previous series currently sitting in net.git starting with commit 562c5a70400c ("net: mediatek: only wake the queue if it is stopped") up to commit 82c6544dddc6 ("net: mediatek: remove superfluous queue wake up call") i just double checked and with the series applied this compile error is gone John ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH V2 3/4] net-next: mediatek: add IRQ locking @ 2016-06-29 11:38 ` John Crispin 0 siblings, 0 replies; 14+ messages in thread From: John Crispin @ 2016-06-29 11:38 UTC (permalink / raw) To: David S. Miller Cc: Felix Fietkau, Sean Wang, netdev, linux-mediatek, linux-kernel, John Crispin The code that enables and disables IRQs is missing proper locking. After adding the IRQ grouping patch and routing the RX and TX IRQs to different cores we experienced IRQ stalls. Fix this by adding proper locking. We use a dedicated lock to reduce the latency if the IRQ code. Signed-off-by: John Crispin <john@phrozen.org> --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 +++++++ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index d6c3a17..698caba 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -328,18 +328,24 @@ static void mtk_mdio_cleanup(struct mtk_eth *eth) static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask) { + unsigned long flags; u32 val; + spin_lock_irqsave(ð->irq_lock, flags); val = mtk_r32(eth, MTK_QDMA_INT_MASK); mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK); + spin_unlock_irqrestore(ð->irq_lock, flags); } static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask) { + unsigned long flags; u32 val; + spin_lock_irqsave(ð->irq_lock, flags); val = mtk_r32(eth, MTK_QDMA_INT_MASK); mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK); + spin_unlock_irqrestore(ð->irq_lock, flags); } static int mtk_set_mac_address(struct net_device *dev, void *p) @@ -1760,6 +1766,7 @@ static int mtk_probe(struct platform_device *pdev) return PTR_ERR(eth->base); spin_lock_init(ð->page_lock); + spin_lock_init(ð->irq_lock); eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "mediatek,ethsys"); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index a5eb7c6..3159d2a 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -373,6 +373,7 @@ struct mtk_eth { void __iomem *base; struct reset_control *rstc; spinlock_t page_lock; + spinlock_t irq_lock; struct net_device dummy_dev; struct net_device *netdev[MTK_MAX_DEVS]; struct mtk_mac *mac[MTK_MAX_DEVS]; -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH V2 3/4] net-next: mediatek: add IRQ locking @ 2016-06-29 11:38 ` John Crispin 0 siblings, 0 replies; 14+ messages in thread From: John Crispin @ 2016-06-29 11:38 UTC (permalink / raw) To: David S. Miller Cc: Sean Wang, netdev-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, John Crispin, Felix Fietkau The code that enables and disables IRQs is missing proper locking. After adding the IRQ grouping patch and routing the RX and TX IRQs to different cores we experienced IRQ stalls. Fix this by adding proper locking. We use a dedicated lock to reduce the latency if the IRQ code. Signed-off-by: John Crispin <john-Pj+rj9U5foFAfugRpC6u6w@public.gmane.org> --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 +++++++ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index d6c3a17..698caba 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -328,18 +328,24 @@ static void mtk_mdio_cleanup(struct mtk_eth *eth) static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask) { + unsigned long flags; u32 val; + spin_lock_irqsave(ð->irq_lock, flags); val = mtk_r32(eth, MTK_QDMA_INT_MASK); mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK); + spin_unlock_irqrestore(ð->irq_lock, flags); } static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask) { + unsigned long flags; u32 val; + spin_lock_irqsave(ð->irq_lock, flags); val = mtk_r32(eth, MTK_QDMA_INT_MASK); mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK); + spin_unlock_irqrestore(ð->irq_lock, flags); } static int mtk_set_mac_address(struct net_device *dev, void *p) @@ -1760,6 +1766,7 @@ static int mtk_probe(struct platform_device *pdev) return PTR_ERR(eth->base); spin_lock_init(ð->page_lock); + spin_lock_init(ð->irq_lock); eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "mediatek,ethsys"); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index a5eb7c6..3159d2a 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -373,6 +373,7 @@ struct mtk_eth { void __iomem *base; struct reset_control *rstc; spinlock_t page_lock; + spinlock_t irq_lock; struct net_device dummy_dev; struct net_device *netdev[MTK_MAX_DEVS]; struct mtk_mac *mac[MTK_MAX_DEVS]; -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH V2 4/4] net-next: mediatek: add support for IRQ grouping @ 2016-06-29 11:38 ` John Crispin 0 siblings, 0 replies; 14+ messages in thread From: John Crispin @ 2016-06-29 11:38 UTC (permalink / raw) To: David S. Miller Cc: Felix Fietkau, Sean Wang, netdev, linux-mediatek, linux-kernel, John Crispin The ethernet core has 3 IRQs. Using the IRQ grouping registers we are able to separate TX and RX IRQs, which allows us to service them on separate cores. This patch splits the IRQ handler into 2 separate functions, one for TX and another for RX. The TX housekeeping is split out into its own NAPI handler. Signed-off-by: John Crispin <john@phrozen.org> --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 155 +++++++++++++++++---------- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 15 ++- 2 files changed, 111 insertions(+), 59 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 698caba..7056a37 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -893,17 +893,17 @@ release_desc: return done; } -static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) +static int mtk_poll_tx(struct mtk_eth *eth, int budget) { struct mtk_tx_ring *ring = ð->tx_ring; struct mtk_tx_dma *desc; struct sk_buff *skb; struct mtk_tx_buf *tx_buf; - int total = 0, done[MTK_MAX_DEVS]; + unsigned int done[MTK_MAX_DEVS]; unsigned int bytes[MTK_MAX_DEVS]; u32 cpu, dma; static int condition; - int i; + int total = 0, i; memset(done, 0, sizeof(done)); memset(bytes, 0, sizeof(bytes)); @@ -954,15 +954,6 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) total += done[i]; } - /* read hw index again make sure no new tx packet */ - if (cpu != dma || cpu != mtk_r32(eth, MTK_QTX_DRX_PTR)) - *tx_again = true; - else - mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS); - - if (!total) - return 0; - if (mtk_queue_stopped(eth) && (atomic_read(&ring->free_count) > ring->thresh)) mtk_wake_queue(eth); @@ -970,47 +961,75 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) return total; } -static int mtk_poll(struct napi_struct *napi, int budget) +static void mtk_handle_status_irq(struct mtk_eth *eth) { - struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi); - u32 status, status2, mask; - int tx_done, rx_done; - bool tx_again = false; - - status = mtk_r32(eth, MTK_QMTK_INT_STATUS); - status2 = mtk_r32(eth, MTK_INT_STATUS2); - tx_done = 0; - rx_done = 0; - tx_again = 0; - - if (status & MTK_TX_DONE_INT) - tx_done = mtk_poll_tx(eth, budget, &tx_again); - - if (status & MTK_RX_DONE_INT) - rx_done = mtk_poll_rx(napi, budget, eth); + u32 status2 = mtk_r32(eth, MTK_INT_STATUS2); if (unlikely(status2 & (MTK_GDM1_AF | MTK_GDM2_AF))) { mtk_stats_update(eth); mtk_w32(eth, (MTK_GDM1_AF | MTK_GDM2_AF), MTK_INT_STATUS2); } +} + +static int mtk_napi_tx(struct napi_struct *napi, int budget) +{ + struct mtk_eth *eth = container_of(napi, struct mtk_eth, tx_napi); + u32 status, mask; + int tx_done = 0; + + mtk_handle_status_irq(eth); + mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS); + tx_done = mtk_poll_tx(eth, budget); + + if (unlikely(netif_msg_intr(eth))) { + status = mtk_r32(eth, MTK_QMTK_INT_STATUS); + mask = mtk_r32(eth, MTK_QDMA_INT_MASK); + dev_info(eth->dev, + "done tx %d, intr 0x%08x/0x%x\n", + tx_done, status, mask); + } + + if (tx_done == budget) + return budget; + + status = mtk_r32(eth, MTK_QMTK_INT_STATUS); + if (status & MTK_TX_DONE_INT) + return budget; + + napi_complete(napi); + mtk_irq_enable(eth, MTK_TX_DONE_INT); + + return tx_done; +} + +static int mtk_napi_rx(struct napi_struct *napi, int budget) +{ + struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi); + u32 status, mask; + int rx_done = 0; + + mtk_handle_status_irq(eth); + mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS); + rx_done = mtk_poll_rx(napi, budget, eth); if (unlikely(netif_msg_intr(eth))) { + status = mtk_r32(eth, MTK_QMTK_INT_STATUS); mask = mtk_r32(eth, MTK_QDMA_INT_MASK); - netdev_info(eth->netdev[0], - "done tx %d, rx %d, intr 0x%08x/0x%x\n", - tx_done, rx_done, status, mask); + dev_info(eth->dev, + "done rx %d, intr 0x%08x/0x%x\n", + rx_done, status, mask); } - if (tx_again || rx_done == budget) + if (rx_done == budget) return budget; status = mtk_r32(eth, MTK_QMTK_INT_STATUS); - if (status & (tx_intr | rx_intr)) + if (status & MTK_RX_DONE_INT) return budget; napi_complete(napi); - mtk_irq_enable(eth, MTK_RX_DONE_INT | MTK_RX_DONE_INT); + mtk_irq_enable(eth, MTK_RX_DONE_INT); return rx_done; } @@ -1246,22 +1265,26 @@ static void mtk_tx_timeout(struct net_device *dev) schedule_work(ð->pending_work); } -static irqreturn_t mtk_handle_irq(int irq, void *_eth) +static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth) { struct mtk_eth *eth = _eth; - u32 status; - status = mtk_r32(eth, MTK_QMTK_INT_STATUS); - if (unlikely(!status)) - return IRQ_NONE; + if (likely(napi_schedule_prep(ð->rx_napi))) { + __napi_schedule(ð->rx_napi); + mtk_irq_disable(eth, MTK_RX_DONE_INT); + } - if (likely(status & (MTK_RX_DONE_INT | MTK_TX_DONE_INT))) { - if (likely(napi_schedule_prep(ð->rx_napi))) - __napi_schedule(ð->rx_napi); - } else { - mtk_w32(eth, status, MTK_QMTK_INT_STATUS); + return IRQ_HANDLED; +} + +static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth) +{ + struct mtk_eth *eth = _eth; + + if (likely(napi_schedule_prep(ð->tx_napi))) { + __napi_schedule(ð->tx_napi); + mtk_irq_disable(eth, MTK_TX_DONE_INT); } - mtk_irq_disable(eth, (MTK_RX_DONE_INT | MTK_TX_DONE_INT)); return IRQ_HANDLED; } @@ -1274,7 +1297,7 @@ static void mtk_poll_controller(struct net_device *dev) u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT; mtk_irq_disable(eth, int_mask); - mtk_handle_irq(dev->irq, dev); + mtk_handle_irq(dev->irq[0], dev); mtk_irq_enable(eth, int_mask); } #endif @@ -1310,6 +1333,7 @@ static int mtk_open(struct net_device *dev) if (err) return err; + napi_enable(ð->tx_napi); napi_enable(ð->rx_napi); mtk_irq_enable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT); } @@ -1358,6 +1382,7 @@ static int mtk_stop(struct net_device *dev) return 0; mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT); + napi_disable(ð->tx_napi); napi_disable(ð->rx_napi); mtk_stop_dma(eth, MTK_QDMA_GLO_CFG); @@ -1395,7 +1420,11 @@ static int __init mtk_hw_init(struct mtk_eth *eth) /* Enable RX VLan Offloading */ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); - err = devm_request_irq(eth->dev, eth->irq, mtk_handle_irq, 0, + err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, + dev_name(eth->dev), eth); + if (err) + return err; + err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, dev_name(eth->dev), eth); if (err) return err; @@ -1411,7 +1440,11 @@ static int __init mtk_hw_init(struct mtk_eth *eth) mtk_w32(eth, 0, MTK_RST_GL); /* FE int grouping */ - mtk_w32(eth, 0, MTK_FE_INT_GRP); + mtk_w32(eth, MTK_TX_DONE_INT, MTK_PDMA_INT_GRP1); + mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_GRP2); + mtk_w32(eth, MTK_TX_DONE_INT, MTK_QDMA_INT_GRP1); + mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2); + mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); for (i = 0; i < 2; i++) { u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i)); @@ -1459,7 +1492,9 @@ static void mtk_uninit(struct net_device *dev) phy_disconnect(mac->phy_dev); mtk_mdio_cleanup(eth); mtk_irq_disable(eth, ~0); - free_irq(dev->irq, dev); + free_irq(eth->irq[0], dev); + free_irq(eth->irq[1], dev); + free_irq(eth->irq[2], dev); } static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -1733,10 +1768,10 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) dev_err(eth->dev, "error bringing up device\n"); goto free_netdev; } - eth->netdev[id]->irq = eth->irq; + eth->netdev[id]->irq = eth->irq[0]; netif_info(eth, probe, eth->netdev[id], "mediatek frame engine at 0x%08lx, irq %d\n", - eth->netdev[id]->base_addr, eth->netdev[id]->irq); + eth->netdev[id]->base_addr, eth->irq[0]); return 0; @@ -1753,6 +1788,7 @@ static int mtk_probe(struct platform_device *pdev) struct mtk_soc_data *soc; struct mtk_eth *eth; int err; + int i; match = of_match_device(of_mtk_match, &pdev->dev); soc = (struct mtk_soc_data *)match->data; @@ -1788,10 +1824,12 @@ static int mtk_probe(struct platform_device *pdev) return PTR_ERR(eth->rstc); } - eth->irq = platform_get_irq(pdev, 0); - if (eth->irq < 0) { - dev_err(&pdev->dev, "no IRQ resource found\n"); - return -ENXIO; + for (i = 0; i < 3; i++) { + eth->irq[i] = platform_get_irq(pdev, i); + if (eth->irq[i] < 0) { + dev_err(&pdev->dev, "no IRQ%d resource found\n", i); + return -ENXIO; + } } eth->clk_ethif = devm_clk_get(&pdev->dev, "ethif"); @@ -1832,7 +1870,9 @@ static int mtk_probe(struct platform_device *pdev) * for NAPI to work */ init_dummy_netdev(ð->dummy_dev); - netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_poll, + netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx, + MTK_NAPI_WEIGHT); + netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_napi_rx, MTK_NAPI_WEIGHT); platform_set_drvdata(pdev, eth); @@ -1853,6 +1893,7 @@ static int mtk_remove(struct platform_device *pdev) clk_disable_unprepare(eth->clk_gp1); clk_disable_unprepare(eth->clk_gp2); + netif_napi_del(ð->tx_napi); netif_napi_del(ð->rx_napi); mtk_cleanup(eth); platform_set_drvdata(pdev, NULL); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 3159d2a..f82e3ac 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -68,6 +68,10 @@ /* Unicast Filter MAC Address Register - High */ #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000)) +/* PDMA Interrupt grouping registers */ +#define MTK_PDMA_INT_GRP1 0xa50 +#define MTK_PDMA_INT_GRP2 0xa54 + /* QDMA TX Queue Configuration Registers */ #define MTK_QTX_CFG(x) (0x1800 + (x * 0x10)) #define QDMA_RES_THRES 4 @@ -125,6 +129,11 @@ #define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \ MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3) +/* QDMA Interrupt grouping registers */ +#define MTK_QDMA_INT_GRP1 0x1a20 +#define MTK_QDMA_INT_GRP2 0x1a24 +#define MTK_RLS_DONE_INT BIT(0) + /* QDMA Interrupt Status Register */ #define MTK_QDMA_INT_MASK 0x1A1C @@ -356,7 +365,8 @@ struct mtk_rx_ring { * @dma_refcnt: track how many netdevs are using the DMA engine * @tx_ring: Pointer to the memore holding info about the TX ring * @rx_ring: Pointer to the memore holding info about the RX ring - * @rx_napi: The NAPI struct + * @tx_napi: The TX NAPI struct + * @rx_napi: The RX NAPI struct * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring * @phy_scratch_ring: physical address of scratch_ring * @scratch_head: The scratch memory that scratch_ring points to. @@ -377,7 +387,7 @@ struct mtk_eth { struct net_device dummy_dev; struct net_device *netdev[MTK_MAX_DEVS]; struct mtk_mac *mac[MTK_MAX_DEVS]; - int irq; + int irq[3]; u32 msg_enable; unsigned long sysclk; struct regmap *ethsys; @@ -385,6 +395,7 @@ struct mtk_eth { atomic_t dma_refcnt; struct mtk_tx_ring tx_ring; struct mtk_rx_ring rx_ring; + struct napi_struct tx_napi; struct napi_struct rx_napi; struct mtk_tx_dma *scratch_ring; dma_addr_t phy_scratch_ring; -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH V2 4/4] net-next: mediatek: add support for IRQ grouping @ 2016-06-29 11:38 ` John Crispin 0 siblings, 0 replies; 14+ messages in thread From: John Crispin @ 2016-06-29 11:38 UTC (permalink / raw) To: David S. Miller Cc: Sean Wang, netdev-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, John Crispin, Felix Fietkau The ethernet core has 3 IRQs. Using the IRQ grouping registers we are able to separate TX and RX IRQs, which allows us to service them on separate cores. This patch splits the IRQ handler into 2 separate functions, one for TX and another for RX. The TX housekeeping is split out into its own NAPI handler. Signed-off-by: John Crispin <john-Pj+rj9U5foFAfugRpC6u6w@public.gmane.org> --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 155 +++++++++++++++++---------- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 15 ++- 2 files changed, 111 insertions(+), 59 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 698caba..7056a37 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -893,17 +893,17 @@ release_desc: return done; } -static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) +static int mtk_poll_tx(struct mtk_eth *eth, int budget) { struct mtk_tx_ring *ring = ð->tx_ring; struct mtk_tx_dma *desc; struct sk_buff *skb; struct mtk_tx_buf *tx_buf; - int total = 0, done[MTK_MAX_DEVS]; + unsigned int done[MTK_MAX_DEVS]; unsigned int bytes[MTK_MAX_DEVS]; u32 cpu, dma; static int condition; - int i; + int total = 0, i; memset(done, 0, sizeof(done)); memset(bytes, 0, sizeof(bytes)); @@ -954,15 +954,6 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) total += done[i]; } - /* read hw index again make sure no new tx packet */ - if (cpu != dma || cpu != mtk_r32(eth, MTK_QTX_DRX_PTR)) - *tx_again = true; - else - mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS); - - if (!total) - return 0; - if (mtk_queue_stopped(eth) && (atomic_read(&ring->free_count) > ring->thresh)) mtk_wake_queue(eth); @@ -970,47 +961,75 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) return total; } -static int mtk_poll(struct napi_struct *napi, int budget) +static void mtk_handle_status_irq(struct mtk_eth *eth) { - struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi); - u32 status, status2, mask; - int tx_done, rx_done; - bool tx_again = false; - - status = mtk_r32(eth, MTK_QMTK_INT_STATUS); - status2 = mtk_r32(eth, MTK_INT_STATUS2); - tx_done = 0; - rx_done = 0; - tx_again = 0; - - if (status & MTK_TX_DONE_INT) - tx_done = mtk_poll_tx(eth, budget, &tx_again); - - if (status & MTK_RX_DONE_INT) - rx_done = mtk_poll_rx(napi, budget, eth); + u32 status2 = mtk_r32(eth, MTK_INT_STATUS2); if (unlikely(status2 & (MTK_GDM1_AF | MTK_GDM2_AF))) { mtk_stats_update(eth); mtk_w32(eth, (MTK_GDM1_AF | MTK_GDM2_AF), MTK_INT_STATUS2); } +} + +static int mtk_napi_tx(struct napi_struct *napi, int budget) +{ + struct mtk_eth *eth = container_of(napi, struct mtk_eth, tx_napi); + u32 status, mask; + int tx_done = 0; + + mtk_handle_status_irq(eth); + mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS); + tx_done = mtk_poll_tx(eth, budget); + + if (unlikely(netif_msg_intr(eth))) { + status = mtk_r32(eth, MTK_QMTK_INT_STATUS); + mask = mtk_r32(eth, MTK_QDMA_INT_MASK); + dev_info(eth->dev, + "done tx %d, intr 0x%08x/0x%x\n", + tx_done, status, mask); + } + + if (tx_done == budget) + return budget; + + status = mtk_r32(eth, MTK_QMTK_INT_STATUS); + if (status & MTK_TX_DONE_INT) + return budget; + + napi_complete(napi); + mtk_irq_enable(eth, MTK_TX_DONE_INT); + + return tx_done; +} + +static int mtk_napi_rx(struct napi_struct *napi, int budget) +{ + struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi); + u32 status, mask; + int rx_done = 0; + + mtk_handle_status_irq(eth); + mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS); + rx_done = mtk_poll_rx(napi, budget, eth); if (unlikely(netif_msg_intr(eth))) { + status = mtk_r32(eth, MTK_QMTK_INT_STATUS); mask = mtk_r32(eth, MTK_QDMA_INT_MASK); - netdev_info(eth->netdev[0], - "done tx %d, rx %d, intr 0x%08x/0x%x\n", - tx_done, rx_done, status, mask); + dev_info(eth->dev, + "done rx %d, intr 0x%08x/0x%x\n", + rx_done, status, mask); } - if (tx_again || rx_done == budget) + if (rx_done == budget) return budget; status = mtk_r32(eth, MTK_QMTK_INT_STATUS); - if (status & (tx_intr | rx_intr)) + if (status & MTK_RX_DONE_INT) return budget; napi_complete(napi); - mtk_irq_enable(eth, MTK_RX_DONE_INT | MTK_RX_DONE_INT); + mtk_irq_enable(eth, MTK_RX_DONE_INT); return rx_done; } @@ -1246,22 +1265,26 @@ static void mtk_tx_timeout(struct net_device *dev) schedule_work(ð->pending_work); } -static irqreturn_t mtk_handle_irq(int irq, void *_eth) +static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth) { struct mtk_eth *eth = _eth; - u32 status; - status = mtk_r32(eth, MTK_QMTK_INT_STATUS); - if (unlikely(!status)) - return IRQ_NONE; + if (likely(napi_schedule_prep(ð->rx_napi))) { + __napi_schedule(ð->rx_napi); + mtk_irq_disable(eth, MTK_RX_DONE_INT); + } - if (likely(status & (MTK_RX_DONE_INT | MTK_TX_DONE_INT))) { - if (likely(napi_schedule_prep(ð->rx_napi))) - __napi_schedule(ð->rx_napi); - } else { - mtk_w32(eth, status, MTK_QMTK_INT_STATUS); + return IRQ_HANDLED; +} + +static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth) +{ + struct mtk_eth *eth = _eth; + + if (likely(napi_schedule_prep(ð->tx_napi))) { + __napi_schedule(ð->tx_napi); + mtk_irq_disable(eth, MTK_TX_DONE_INT); } - mtk_irq_disable(eth, (MTK_RX_DONE_INT | MTK_TX_DONE_INT)); return IRQ_HANDLED; } @@ -1274,7 +1297,7 @@ static void mtk_poll_controller(struct net_device *dev) u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT; mtk_irq_disable(eth, int_mask); - mtk_handle_irq(dev->irq, dev); + mtk_handle_irq(dev->irq[0], dev); mtk_irq_enable(eth, int_mask); } #endif @@ -1310,6 +1333,7 @@ static int mtk_open(struct net_device *dev) if (err) return err; + napi_enable(ð->tx_napi); napi_enable(ð->rx_napi); mtk_irq_enable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT); } @@ -1358,6 +1382,7 @@ static int mtk_stop(struct net_device *dev) return 0; mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT); + napi_disable(ð->tx_napi); napi_disable(ð->rx_napi); mtk_stop_dma(eth, MTK_QDMA_GLO_CFG); @@ -1395,7 +1420,11 @@ static int __init mtk_hw_init(struct mtk_eth *eth) /* Enable RX VLan Offloading */ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); - err = devm_request_irq(eth->dev, eth->irq, mtk_handle_irq, 0, + err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, + dev_name(eth->dev), eth); + if (err) + return err; + err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, dev_name(eth->dev), eth); if (err) return err; @@ -1411,7 +1440,11 @@ static int __init mtk_hw_init(struct mtk_eth *eth) mtk_w32(eth, 0, MTK_RST_GL); /* FE int grouping */ - mtk_w32(eth, 0, MTK_FE_INT_GRP); + mtk_w32(eth, MTK_TX_DONE_INT, MTK_PDMA_INT_GRP1); + mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_GRP2); + mtk_w32(eth, MTK_TX_DONE_INT, MTK_QDMA_INT_GRP1); + mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2); + mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); for (i = 0; i < 2; i++) { u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i)); @@ -1459,7 +1492,9 @@ static void mtk_uninit(struct net_device *dev) phy_disconnect(mac->phy_dev); mtk_mdio_cleanup(eth); mtk_irq_disable(eth, ~0); - free_irq(dev->irq, dev); + free_irq(eth->irq[0], dev); + free_irq(eth->irq[1], dev); + free_irq(eth->irq[2], dev); } static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -1733,10 +1768,10 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) dev_err(eth->dev, "error bringing up device\n"); goto free_netdev; } - eth->netdev[id]->irq = eth->irq; + eth->netdev[id]->irq = eth->irq[0]; netif_info(eth, probe, eth->netdev[id], "mediatek frame engine at 0x%08lx, irq %d\n", - eth->netdev[id]->base_addr, eth->netdev[id]->irq); + eth->netdev[id]->base_addr, eth->irq[0]); return 0; @@ -1753,6 +1788,7 @@ static int mtk_probe(struct platform_device *pdev) struct mtk_soc_data *soc; struct mtk_eth *eth; int err; + int i; match = of_match_device(of_mtk_match, &pdev->dev); soc = (struct mtk_soc_data *)match->data; @@ -1788,10 +1824,12 @@ static int mtk_probe(struct platform_device *pdev) return PTR_ERR(eth->rstc); } - eth->irq = platform_get_irq(pdev, 0); - if (eth->irq < 0) { - dev_err(&pdev->dev, "no IRQ resource found\n"); - return -ENXIO; + for (i = 0; i < 3; i++) { + eth->irq[i] = platform_get_irq(pdev, i); + if (eth->irq[i] < 0) { + dev_err(&pdev->dev, "no IRQ%d resource found\n", i); + return -ENXIO; + } } eth->clk_ethif = devm_clk_get(&pdev->dev, "ethif"); @@ -1832,7 +1870,9 @@ static int mtk_probe(struct platform_device *pdev) * for NAPI to work */ init_dummy_netdev(ð->dummy_dev); - netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_poll, + netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx, + MTK_NAPI_WEIGHT); + netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_napi_rx, MTK_NAPI_WEIGHT); platform_set_drvdata(pdev, eth); @@ -1853,6 +1893,7 @@ static int mtk_remove(struct platform_device *pdev) clk_disable_unprepare(eth->clk_gp1); clk_disable_unprepare(eth->clk_gp2); + netif_napi_del(ð->tx_napi); netif_napi_del(ð->rx_napi); mtk_cleanup(eth); platform_set_drvdata(pdev, NULL); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 3159d2a..f82e3ac 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -68,6 +68,10 @@ /* Unicast Filter MAC Address Register - High */ #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000)) +/* PDMA Interrupt grouping registers */ +#define MTK_PDMA_INT_GRP1 0xa50 +#define MTK_PDMA_INT_GRP2 0xa54 + /* QDMA TX Queue Configuration Registers */ #define MTK_QTX_CFG(x) (0x1800 + (x * 0x10)) #define QDMA_RES_THRES 4 @@ -125,6 +129,11 @@ #define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \ MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3) +/* QDMA Interrupt grouping registers */ +#define MTK_QDMA_INT_GRP1 0x1a20 +#define MTK_QDMA_INT_GRP2 0x1a24 +#define MTK_RLS_DONE_INT BIT(0) + /* QDMA Interrupt Status Register */ #define MTK_QDMA_INT_MASK 0x1A1C @@ -356,7 +365,8 @@ struct mtk_rx_ring { * @dma_refcnt: track how many netdevs are using the DMA engine * @tx_ring: Pointer to the memore holding info about the TX ring * @rx_ring: Pointer to the memore holding info about the RX ring - * @rx_napi: The NAPI struct + * @tx_napi: The TX NAPI struct + * @rx_napi: The RX NAPI struct * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring * @phy_scratch_ring: physical address of scratch_ring * @scratch_head: The scratch memory that scratch_ring points to. @@ -377,7 +387,7 @@ struct mtk_eth { struct net_device dummy_dev; struct net_device *netdev[MTK_MAX_DEVS]; struct mtk_mac *mac[MTK_MAX_DEVS]; - int irq; + int irq[3]; u32 msg_enable; unsigned long sysclk; struct regmap *ethsys; @@ -385,6 +395,7 @@ struct mtk_eth { atomic_t dma_refcnt; struct mtk_tx_ring tx_ring; struct mtk_rx_ring rx_ring; + struct napi_struct tx_napi; struct napi_struct rx_napi; struct mtk_tx_dma *scratch_ring; dma_addr_t phy_scratch_ring; -- 1.7.10.4 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH V2 4/4] net-next: mediatek: add support for IRQ grouping 2016-06-29 11:38 ` John Crispin @ 2016-06-30 5:04 ` kbuild test robot -1 siblings, 0 replies; 14+ messages in thread From: kbuild test robot @ 2016-06-30 5:04 UTC (permalink / raw) To: John Crispin Cc: kbuild-all, David S. Miller, Felix Fietkau, Sean Wang, netdev, linux-mediatek, linux-kernel, John Crispin [-- Attachment #1: Type: text/plain, Size: 1811 bytes --] Hi, [auto build test ERROR on net/master] [also build test ERROR on next-20160629] [cannot apply to net-next/master v4.7-rc5] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/John-Crispin/net-next-mediatek-IRQ-cleanups-fixes-and-grouping/20160629-194341 config: arm-allmodconfig (attached as .config) compiler: arm-linux-gnueabi-gcc (Debian 5.3.1-8) 5.3.1 20160205 reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=arm All errors (new ones prefixed by >>): drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_poll_controller': >> drivers/net/ethernet/mediatek/mtk_eth_soc.c:1300:2: error: implicit declaration of function 'mtk_handle_irq' [-Werror=implicit-function-declaration] mtk_handle_irq(dev->irq[0], dev); ^ >> drivers/net/ethernet/mediatek/mtk_eth_soc.c:1300:25: error: subscripted value is neither array nor pointer nor vector mtk_handle_irq(dev->irq[0], dev); ^ cc1: some warnings being treated as errors vim +/mtk_handle_irq +1300 drivers/net/ethernet/mediatek/mtk_eth_soc.c 1294 { 1295 struct mtk_mac *mac = netdev_priv(dev); 1296 struct mtk_eth *eth = mac->hw; 1297 u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT; 1298 1299 mtk_irq_disable(eth, int_mask); > 1300 mtk_handle_irq(dev->irq[0], dev); 1301 mtk_irq_enable(eth, int_mask); 1302 } 1303 #endif --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/octet-stream, Size: 57589 bytes --] ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH V2 4/4] net-next: mediatek: add support for IRQ grouping @ 2016-06-30 5:04 ` kbuild test robot 0 siblings, 0 replies; 14+ messages in thread From: kbuild test robot @ 2016-06-30 5:04 UTC (permalink / raw) Cc: kbuild-all, David S. Miller, Felix Fietkau, Sean Wang, netdev, linux-mediatek, linux-kernel, John Crispin [-- Attachment #1: Type: text/plain, Size: 1811 bytes --] Hi, [auto build test ERROR on net/master] [also build test ERROR on next-20160629] [cannot apply to net-next/master v4.7-rc5] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/John-Crispin/net-next-mediatek-IRQ-cleanups-fixes-and-grouping/20160629-194341 config: arm-allmodconfig (attached as .config) compiler: arm-linux-gnueabi-gcc (Debian 5.3.1-8) 5.3.1 20160205 reproduce: wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=arm All errors (new ones prefixed by >>): drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_poll_controller': >> drivers/net/ethernet/mediatek/mtk_eth_soc.c:1300:2: error: implicit declaration of function 'mtk_handle_irq' [-Werror=implicit-function-declaration] mtk_handle_irq(dev->irq[0], dev); ^ >> drivers/net/ethernet/mediatek/mtk_eth_soc.c:1300:25: error: subscripted value is neither array nor pointer nor vector mtk_handle_irq(dev->irq[0], dev); ^ cc1: some warnings being treated as errors vim +/mtk_handle_irq +1300 drivers/net/ethernet/mediatek/mtk_eth_soc.c 1294 { 1295 struct mtk_mac *mac = netdev_priv(dev); 1296 struct mtk_eth *eth = mac->hw; 1297 u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT; 1298 1299 mtk_irq_disable(eth, int_mask); > 1300 mtk_handle_irq(dev->irq[0], dev); 1301 mtk_irq_enable(eth, int_mask); 1302 } 1303 #endif --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/octet-stream, Size: 57589 bytes --] ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH V2 0/4] net-next: mediatek: IRQ cleanups, fixes and grouping 2016-06-29 11:38 [PATCH V2 0/4] net-next: mediatek: IRQ cleanups, fixes and grouping John Crispin ` (3 preceding siblings ...) 2016-06-29 11:38 ` John Crispin @ 2016-06-30 12:52 ` David Miller 4 siblings, 0 replies; 14+ messages in thread From: David Miller @ 2016-06-30 12:52 UTC (permalink / raw) To: john; +Cc: nbd, keyhaede, netdev, linux-mediatek, linux-kernel From: John Crispin <john@phrozen.org> Date: Wed, 29 Jun 2016 13:38:07 +0200 > This series contains 2 small code cleanups that are leftovers from the > MIPS support. There is also a small fix that adds proper locking to the > code accessing the IRQ registers. Without this fix we saw deadlocks caused > by the last patch of the series, which adds IRQ grouping. The grouping > feature allows us to use different IRQs for TX and RX. By doing so we can > use affinity to let the SoC handle the IRQs on different cores. > > This series depends on a previous series currently sitting in net.git > starting with > commit 562c5a70400c ("net: mediatek: only wake the queue if it is stopped") > up to > commit 82c6544dddc6 ("net: mediatek: remove superfluous queue wake up call") Series applied, thanks. ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2016-06-30 12:53 UTC | newest] Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-06-29 11:38 [PATCH V2 0/4] net-next: mediatek: IRQ cleanups, fixes and grouping John Crispin 2016-06-29 11:38 ` [PATCH V2 1/4] net-next: mediatek: remove superfluous register reads John Crispin 2016-06-29 11:38 ` [PATCH V2 2/4] net-next: mediatek: don't use intermediate variables to store IRQ masks John Crispin 2016-06-29 11:38 ` John Crispin 2016-06-30 6:03 ` kbuild test robot 2016-06-30 6:03 ` kbuild test robot 2016-06-30 7:33 ` John Crispin 2016-06-29 11:38 ` [PATCH V2 3/4] net-next: mediatek: add IRQ locking John Crispin 2016-06-29 11:38 ` John Crispin 2016-06-29 11:38 ` [PATCH V2 4/4] net-next: mediatek: add support for IRQ grouping John Crispin 2016-06-29 11:38 ` John Crispin 2016-06-30 5:04 ` kbuild test robot 2016-06-30 5:04 ` kbuild test robot 2016-06-30 12:52 ` [PATCH V2 0/4] net-next: mediatek: IRQ cleanups, fixes and grouping David Miller
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.