* [PATCH v6] flexcan: add err_irq handler for flexcan
@ 2014-07-03 9:22 Zhao Qiang
2014-07-03 10:13 ` Marc Kleine-Budde
0 siblings, 1 reply; 2+ messages in thread
From: Zhao Qiang @ 2014-07-03 9:22 UTC (permalink / raw)
To: linuxppc-dev, wg, mkl, linux-can, B07421; +Cc: Zhao Qiang
when flexcan is not physically linked, command 'cantest' will
trigger an err_irq, add err_irq handler for it.
Signed-off-by: Zhao Qiang <B45475@freescale.com>
---
Changes for v2:
- use a space instead of tab
- use flexcan_poll_state instead of print
Changes for v3:
- return IRQ_HANDLED if err is triggered
- stop transmitted packets when there is an err_interrupt
Changes for v4:
- call flexcan_irq
Changes for v5:
- move err_int_handling code from flexcan_irq to flexcan_err_irq
- call flexcan_err_irq from flexcan_irq
Changes for v6:
- move RX_IRQ handling back to flexcan_irq
drivers/net/can/flexcan.c | 52 +++++++++++++++++++++++++++++++++++++++++------
1 file changed, 46 insertions(+), 6 deletions(-)
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index f425ec2..f6c92bc 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -208,6 +208,7 @@ struct flexcan_priv {
void __iomem *base;
u32 reg_esr;
u32 reg_ctrl_default;
+ int err_irq;
struct clk *clk_ipg;
struct clk *clk_per;
@@ -690,6 +691,28 @@ static int flexcan_poll(struct napi_struct *napi, int quota)
return work_done;
}
+static irqreturn_t flexcan_err_irq(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->base;
+ u32 reg_ctrl, reg_esr;
+ irqreturn_t ret = IRQ_NONE;
+
+ reg_esr = flexcan_read(®s->esr);
+ reg_ctrl = flexcan_read(®s->ctrl);
+
+ if (reg_esr & FLEXCAN_ESR_ALL_INT) {
+ flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, ®s->esr);
+ ret = IRQ_HANDLED;
+ }
+
+ if (reg_esr & FLEXCAN_ESR_ERR_INT)
+ flexcan_write(reg_ctrl & ~FLEXCAN_CTRL_ERR_MSK, ®s->ctrl);
+
+ return ret;
+}
+
static irqreturn_t flexcan_irq(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
@@ -698,11 +721,10 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
struct flexcan_regs __iomem *regs = priv->base;
u32 reg_iflag1, reg_esr;
- reg_iflag1 = flexcan_read(®s->iflag1);
reg_esr = flexcan_read(®s->esr);
- /* ACK all bus error and state change IRQ sources */
- if (reg_esr & FLEXCAN_ESR_ALL_INT)
- flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, ®s->esr);
+ reg_iflag1 = flexcan_read(®s->iflag1);
+
+ flexcan_err_irq(irq, dev);
/*
* schedule NAPI in case of:
@@ -944,10 +966,17 @@ static int flexcan_open(struct net_device *dev)
if (err)
goto out_close;
+ if (priv->err_irq) {
+ err = request_irq(priv->err_irq, flexcan_err_irq, IRQF_SHARED,
+ dev->name, dev);
+ if (err)
+ goto out_free_irq;
+ }
+
/* start chip and queuing */
err = flexcan_chip_start(dev);
if (err)
- goto out_free_irq;
+ goto out_free_err_irq;
can_led_event(dev, CAN_LED_EVENT_OPEN);
@@ -956,6 +985,9 @@ static int flexcan_open(struct net_device *dev)
return 0;
+ out_free_err_irq:
+ if (priv->err_irq)
+ free_irq(priv->err_irq, dev);
out_free_irq:
free_irq(dev->irq, dev);
out_close:
@@ -977,6 +1009,9 @@ static int flexcan_close(struct net_device *dev)
flexcan_chip_stop(dev);
free_irq(dev->irq, dev);
+ if (priv->err_irq)
+ free_irq(priv->err_irq, dev);
+
clk_disable_unprepare(priv->clk_per);
clk_disable_unprepare(priv->clk_ipg);
@@ -1099,7 +1134,7 @@ static int flexcan_probe(struct platform_device *pdev)
struct resource *mem;
struct clk *clk_ipg = NULL, *clk_per = NULL;
void __iomem *base;
- int err, irq;
+ int err, irq, err_irq;
u32 clock_freq = 0;
if (pdev->dev.of_node)
@@ -1126,6 +1161,10 @@ static int flexcan_probe(struct platform_device *pdev)
if (irq <= 0)
return -ENODEV;
+ err_irq = platform_get_irq(pdev, 1);
+ if (err_irq <= 0)
+ err_irq = 0;
+
base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(base))
return PTR_ERR(base);
@@ -1149,6 +1188,7 @@ static int flexcan_probe(struct platform_device *pdev)
dev->flags |= IFF_ECHO;
priv = netdev_priv(dev);
+ priv->err_irq = err_irq;
priv->can.clock.freq = clock_freq;
priv->can.bittiming_const = &flexcan_bittiming_const;
priv->can.do_set_mode = flexcan_set_mode;
--
1.8.5
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH v6] flexcan: add err_irq handler for flexcan
2014-07-03 9:22 [PATCH v6] flexcan: add err_irq handler for flexcan Zhao Qiang
@ 2014-07-03 10:13 ` Marc Kleine-Budde
0 siblings, 0 replies; 2+ messages in thread
From: Marc Kleine-Budde @ 2014-07-03 10:13 UTC (permalink / raw)
To: Zhao Qiang, linuxppc-dev, wg, linux-can, B07421
[-- Attachment #1: Type: text/plain, Size: 2994 bytes --]
On 07/03/2014 11:22 AM, Zhao Qiang wrote:
> when flexcan is not physically linked, command 'cantest' will
> trigger an err_irq, add err_irq handler for it.
>
> Signed-off-by: Zhao Qiang <B45475@freescale.com>
> ---
> Changes for v2:
> - use a space instead of tab
> - use flexcan_poll_state instead of print
> Changes for v3:
> - return IRQ_HANDLED if err is triggered
> - stop transmitted packets when there is an err_interrupt
> Changes for v4:
> - call flexcan_irq
> Changes for v5:
> - move err_int_handling code from flexcan_irq to flexcan_err_irq
> - call flexcan_err_irq from flexcan_irq
> Changes for v6:
> - move RX_IRQ handling back to flexcan_irq
>
> drivers/net/can/flexcan.c | 52 +++++++++++++++++++++++++++++++++++++++++------
> 1 file changed, 46 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
> index f425ec2..f6c92bc 100644
> --- a/drivers/net/can/flexcan.c
> +++ b/drivers/net/can/flexcan.c
> @@ -208,6 +208,7 @@ struct flexcan_priv {
> void __iomem *base;
> u32 reg_esr;
> u32 reg_ctrl_default;
> + int err_irq;
>
> struct clk *clk_ipg;
> struct clk *clk_per;
> @@ -690,6 +691,28 @@ static int flexcan_poll(struct napi_struct *napi, int quota)
> return work_done;
> }
>
> +static irqreturn_t flexcan_err_irq(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct flexcan_priv *priv = netdev_priv(dev);
> + struct flexcan_regs __iomem *regs = priv->base;
> + u32 reg_ctrl, reg_esr;
> + irqreturn_t ret = IRQ_NONE;
> +
> + reg_esr = flexcan_read(®s->esr);
> + reg_ctrl = flexcan_read(®s->ctrl);
> +
> + if (reg_esr & FLEXCAN_ESR_ALL_INT) {
> + flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, ®s->esr);
> + ret = IRQ_HANDLED;
> + }
> +
> + if (reg_esr & FLEXCAN_ESR_ERR_INT)
> + flexcan_write(reg_ctrl & ~FLEXCAN_CTRL_ERR_MSK, ®s->ctrl);
Now you just ACK the interrupts, but you're not triggering the NAPI,
where the actual error interrupts are handled.
In the current interrupt handler we are looking at two registers for
interrupts, that is "iflag1" and "esr". "iflag1" is triggered on RX,
RX-FIFO overflow and TX-complete. "esr" is triggered by errors in
general. In the interrupt handler we distinguish between bus errors
(FLEXCAN_ESR_ERR_BUS) and errors effecting a change of state
(FLEXCAN_ESR_ERR_STATE).
The next step is to figure out which bits in which register trigger the
error irq. Then move the code handling this register into the error irq
handler. As the seconds half of the error irq handling takes place in
the napi function, you have to duplicate the napi_schedule(&priv->napi).
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 242 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2014-07-03 10:13 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-07-03 9:22 [PATCH v6] flexcan: add err_irq handler for flexcan Zhao Qiang
2014-07-03 10:13 ` Marc Kleine-Budde
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).