This one adds an option to turn of napi and process rx directly in mscan isr. As for mpc52xx this feature can be turned on by setting a rx-irq property int the device tree, e.g: c...@980 { compatible = "fsl,mpc5200b-mscan","fsl,mpc5200-mscan"; interrupts = <2 18 0>; rx-irq; reg = <0x980 0x80>; }; Default is the polling rx.
Signed-off-by: Luotao Fu <l...@pengutronix.de> --- kernel/2.6/drivers/net/can/mscan/mpc52xx_can.c | 18 +++- kernel/2.6/drivers/net/can/mscan/mscan.c | 110 +++++++++++++++--------- kernel/2.6/drivers/net/can/mscan/mscan.h | 5 +- 3 files changed, 88 insertions(+), 45 deletions(-) diff --git a/kernel/2.6/drivers/net/can/mscan/mpc52xx_can.c b/kernel/2.6/drivers/net/can/mscan/mpc52xx_can.c index 6a3d608..98fca19 100644 --- a/kernel/2.6/drivers/net/can/mscan/mpc52xx_can.c +++ b/kernel/2.6/drivers/net/can/mscan/mpc52xx_can.c @@ -340,7 +340,7 @@ static int __devinit mpc52xx_can_probe(struct of_device *ofdev, struct can_priv *priv; struct resource res; void __iomem *base; - int err, irq, res_size, clock_src; + int err, irq, res_size, clock_src, rx_mode; err = of_address_to_resource(np, 0, &res); if (err) { @@ -371,7 +371,13 @@ static int __devinit mpc52xx_can_probe(struct of_device *ofdev, goto exit_unmap_mem; } - dev = alloc_mscandev(); + if (of_get_property(np, "rx-irq", NULL)) + rx_mode = RX_IRQ; + else + rx_mode = RX_POLL; + + dev = alloc_mscandev(rx_mode); + if (!dev) { err = -ENOMEM; goto exit_dispose_irq; @@ -411,9 +417,11 @@ static int __devinit mpc52xx_can_probe(struct of_device *ofdev, dev_set_drvdata(&ofdev->dev, dev); - dev_info(&ofdev->dev, "MSCAN at 0x%lx, irq %d, clock %d Hz\n", - dev->base_addr, dev->irq, priv->clock.freq); - + dev_info(&ofdev->dev, "MSCAN at 0x%lx, irq %d," + " clock %d Hz, rx_mode: %s\n", + dev->base_addr, dev->irq, priv->clock.freq, + rx_mode == RX_IRQ ? "irq" : "polling"); + return 0; exit_free_mscan: diff --git a/kernel/2.6/drivers/net/can/mscan/mscan.c b/kernel/2.6/drivers/net/can/mscan/mscan.c index e5d5004..5b5fc54 100644 --- a/kernel/2.6/drivers/net/can/mscan/mscan.c +++ b/kernel/2.6/drivers/net/can/mscan/mscan.c @@ -101,6 +101,7 @@ struct mscan_priv { u8 cur_pri; u8 prev_buf_id; u8 tx_active; + u8 rx_mode; struct list_head tx_head; struct tx_queue_entry tx_queue[TX_QUEUE_SIZE]; @@ -331,22 +332,9 @@ static inline int check_set_state(struct net_device *dev, u8 canrflg) return ret; } -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) -static int mscan_rx_poll(struct napi_struct *napi, int quota) -#else -static int mscan_rx_poll(struct net_device *dev, int *budget) -#endif +static int mscan_rx_process(struct net_device *dev, int quota) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) - struct mscan_priv *priv = container_of(napi, struct mscan_priv, napi); - struct net_device *dev = napi->dev; -#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) - struct mscan_priv *priv = container_of(napi, struct mscan_priv, napi); - struct net_device *dev = priv->dev; -#else struct mscan_priv *priv = netdev_priv(dev); - int quota = min(dev->quota, *budget); -#endif struct mscan_regs *regs = (struct mscan_regs *)dev->base_addr; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) struct net_device_stats *stats = can_get_stats(dev); @@ -361,8 +349,10 @@ static int mscan_rx_poll(struct net_device *dev, int *budget) u8 canrflg; int i; - while (npackets < quota && ((canrflg = in_8(®s->canrflg)) & + while (((canrflg = in_8(®s->canrflg)) & (MSCAN_RXF | MSCAN_ERR_IF))) { + if (priv->rx_mode == RX_POLL && npackets >= quota) + break; skb = alloc_can_skb(dev, &frame); if (!skb) { @@ -455,16 +445,22 @@ static int mscan_rx_poll(struct net_device *dev, int *budget) out_8(®s->canrflg, MSCAN_ERR_IF); } - npackets++; - netif_receive_skb(skb); + if (priv->rx_mode == RX_POLL) { + npackets++; + netif_receive_skb(skb); + } else + netif_rx(skb); } #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) - *budget -= npackets; - dev->quota -= npackets; + if (priv->rx_mode == RX_POLL) { + *budget -= npackets; + dev->quota -= npackets; + } #endif - if (!(in_8(®s->canrflg) & (MSCAN_RXF | MSCAN_ERR_IF))) { + if ((priv->rx_mode == RX_POLL) && + !(in_8(®s->canrflg) & (MSCAN_RXF | MSCAN_ERR_IF))) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) napi_complete(&priv->napi); #elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) @@ -476,10 +472,30 @@ static int mscan_rx_poll(struct net_device *dev, int *budget) if (priv->can.state < CAN_STATE_BUS_OFF) out_8(®s->canrier, priv->shadow_canrier); ret = 0; - } + } else if (priv->rx_mode == RX_IRQ) + ret = 0; + return ret; } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) +static int mscan_rx_poll(struct napi_struct *napi, int quota) +#else +static int mscan_rx_poll(struct net_device *dev, int *budget) +#endif +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) + struct net_device *dev = napi->dev; +#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) + struct mscan_priv *priv = container_of(napi, struct mscan_priv, napi); + struct net_device *dev = priv->dev; +#else + struct mscan_priv *priv = netdev_priv(dev); + int quota = min(dev->quota, *budget); +#endif + mscan_rx_process(dev, quota); +} + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) static irqreturn_t mscan_isr(int irq, void *dev_id, struct pt_regs *r) #else @@ -535,21 +551,28 @@ static irqreturn_t mscan_isr(int irq, void *dev_id) } canrflg = in_8(®s->canrflg); - if ((canrflg & ~MSCAN_STAT_MSK) && - !test_and_set_bit(F_RX_PROGRESS, &priv->flags)) { - if (canrflg & ~MSCAN_STAT_MSK) { - priv->shadow_canrier = in_8(®s->canrier); - out_8(®s->canrier, 0); + if (canrflg & ~MSCAN_STAT_MSK) { + if (priv->rx_mode == RX_POLL + && !test_and_set_bit(F_RX_PROGRESS, &priv->flags)) { + if (canrflg & ~MSCAN_STAT_MSK) { + priv->shadow_canrier = in_8(®s->canrier); + out_8(®s->canrier, 0); #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) - napi_schedule(&priv->napi); + napi_schedule(&priv->napi); #elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) - netif_rx_schedule(dev, &priv->napi); + netif_rx_schedule(dev, &priv->napi); #else - netif_rx_schedule(dev); + netif_rx_schedule(dev); #endif + ret = IRQ_HANDLED; + } else + clear_bit(F_RX_PROGRESS, &priv->flags); + } + + if (priv->rx_mode == RX_IRQ) { + mscan_rx_process(dev, 0); ret = IRQ_HANDLED; - } else - clear_bit(F_RX_PROGRESS, &priv->flags); + } } return ret; } @@ -621,13 +644,15 @@ static int mscan_open(struct net_device *dev) return ret; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) - napi_enable(&priv->napi); + if (priv->rx_mode == RX_POLL) + napi_enable(&priv->napi); #endif ret = request_irq(dev->irq, mscan_isr, 0, dev->name, dev); if (ret < 0) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) - napi_disable(&priv->napi); + if (priv->rx_mode == RX_POLL) + napi_disable(&priv->napi); #endif printk(KERN_ERR "%s - failed to attach interrupt\n", dev->name); @@ -654,7 +679,8 @@ static int mscan_close(struct net_device *dev) netif_stop_queue(dev); #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) - napi_disable(&priv->napi); + if (priv->rx_mode == RX_POLL) + napi_disable(&priv->napi); #endif out_8(®s->cantier, 0); @@ -718,7 +744,7 @@ void unregister_mscandev(struct net_device *dev) } EXPORT_SYMBOL_GPL(unregister_mscandev); -struct net_device *alloc_mscandev(void) +struct net_device *alloc_mscandev(int rx_mode) { struct net_device *dev; struct mscan_priv *priv; @@ -729,6 +755,8 @@ struct net_device *alloc_mscandev(void) return NULL; priv = netdev_priv(dev); + priv->rx_mode = rx_mode; + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) dev->netdev_ops = &mscan_netdev_ops; #else @@ -740,13 +768,17 @@ struct net_device *alloc_mscandev(void) dev->flags |= IFF_ECHO; /* we support local echo */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28) - netif_napi_add(dev, &priv->napi, mscan_rx_poll, 8); + if (priv->rx_mode == RX_POLL) + netif_napi_add(dev, &priv->napi, mscan_rx_poll, 8); #elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) priv->dev = dev; - netif_napi_add(dev, &priv->napi, mscan_rx_poll, 8); + if (priv->rx_mode == RX_POLL) + netif_napi_add(dev, &priv->napi, mscan_rx_poll, 8); #else - dev->poll = mscan_rx_poll; - dev->weight = 8; + if (priv->rx_mode == RX_POLL) { + dev->poll = mscan_rx_poll; + dev->weight = 8; + } #endif priv->can.bittiming_const = &mscan_bittiming_const; diff --git a/kernel/2.6/drivers/net/can/mscan/mscan.h b/kernel/2.6/drivers/net/can/mscan/mscan.h index f352466..51b1c2f 100644 --- a/kernel/2.6/drivers/net/can/mscan/mscan.h +++ b/kernel/2.6/drivers/net/can/mscan/mscan.h @@ -238,7 +238,10 @@ struct mscan_platform_data { }; #endif -struct net_device *alloc_mscandev(void); +#define RX_POLL 0 +#define RX_IRQ 1 +struct net_device *alloc_mscandev(int rx_mode); + /* * clock_src: * 1 = The MSCAN clock source is the onchip Bus Clock. -- 1.6.5 _______________________________________________ Socketcan-users mailing list Socketcan-users@lists.berlios.de https://lists.berlios.de/mailman/listinfo/socketcan-users