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 <[email protected]>
---
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
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-users