Convert RX path to NAPI via can_rx_offload_*
authornorly <ny-git@enpas.org>
Sat, 5 Feb 2022 03:50:56 +0000 (04:50 +0100)
committernorly <ny-git@enpas.org>
Sat, 5 Feb 2022 04:07:09 +0000 (05:07 +0100)
module/elmcan.c

index e07ecbc6b00879252c78b6e291bf6a05c4765215..cd57cad9db3a86c24ed02b98b782a03579a40c69 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/tty.h>
+#include <linux/version.h>
 #include <linux/workqueue.h>
 
 #include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 #include <linux/can/led.h>
+#include <linux/can/rx-offload.h>
 
 MODULE_ALIAS_LDISC(N_ELMCAN);
 MODULE_DESCRIPTION("ELM327 based CAN interface");
@@ -56,6 +58,8 @@ MODULE_PARM_DESC(accept_flaky_uart, "Don't bail at the first invalid character.
 #define N_ELMCAN 29
 #endif
 
+#define ELM327_NAPI_WEIGHT 4
+
 #define ELM327_SIZE_RXBUF 256
 #define ELM327_SIZE_TXBUF 32
 
@@ -85,6 +89,8 @@ struct elmcan {
        /* This must be the first member when using alloc_candev() */
        struct can_priv can;
 
+       struct can_rx_offload offload;
+
        /* TTY and netdev devices that we're bridging */
        struct tty_struct       *tty;
        struct net_device       *dev;
@@ -313,11 +319,16 @@ static void elm327_feed_frame_to_netdev(struct elmcan *elm,
 
        memcpy(cf, frame, sizeof(struct can_frame));
 
-       elm->dev->stats.rx_packets++;
-       elm->dev->stats.rx_bytes += frame->can_dlc;
-       netif_rx_ni(skb);
+       /* Queue for NAPI pickup.
+        * rx-offload will update stats and LEDs for us.
+        */
+       if (can_rx_offload_queue_tail(&elm->offload, skb))
+               elm->dev->stats.rx_fifo_errors++;
 
-       can_led_event(elm->dev, CAN_LED_EVENT_RX);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0)
+       /* Wake NAPI */
+       can_rx_offload_irq_finish(&elm->offload);
+#endif
 }
 
  /***********************************************************************
@@ -762,6 +773,16 @@ static void elm327_parse_rxbuf(struct elmcan *elm)
   * (takes elm->lock)                                                  *
   ***********************************************************************/
 
+/* Dummy needed to use can_rx_offload */
+static struct sk_buff *elmcan_mailbox_read(struct can_rx_offload *offload,
+                                          unsigned int n, u32 *timestamp,
+                                          bool drop)
+{
+       WARN_ON(1); /* This function is a dummy, so don't call it! */
+
+       return ERR_PTR(-ENOBUFS);
+}
+
 static int elmcan_netdev_open(struct net_device *dev)
 {
        struct elmcan *elm = netdev_priv(dev);
@@ -789,6 +810,15 @@ static int elmcan_netdev_open(struct net_device *dev)
        elm327_init(elm);
        spin_unlock_bh(&elm->lock);
 
+       elm->offload.mailbox_read = elmcan_mailbox_read;
+       err = can_rx_offload_add_fifo(dev, &elm->offload, ELM327_NAPI_WEIGHT);
+       if (err) {
+               close_candev(dev);
+               return err;
+       }
+
+       can_rx_offload_enable(&elm->offload);
+
        can_led_event(dev, CAN_LED_EVENT_OPEN);
        elm->can.state = CAN_STATE_ERROR_ACTIVE;
        netif_start_queue(dev);
@@ -800,6 +830,8 @@ static int elmcan_netdev_close(struct net_device *dev)
 {
        struct elmcan *elm = netdev_priv(dev);
 
+       netif_stop_queue(dev);
+
        spin_lock_bh(&elm->lock);
        if (elm->tty) {
                /* Interrupt whatever we're doing right now */
@@ -817,8 +849,9 @@ static int elmcan_netdev_close(struct net_device *dev)
                spin_unlock_bh(&elm->lock);
        }
 
+       can_rx_offload_disable(&elm->offload);
        elm->can.state = CAN_STATE_STOPPED;
-       netif_stop_queue(dev);
+       can_rx_offload_del(&elm->offload);
        close_candev(dev);
        can_led_event(dev, CAN_LED_EVENT_STOP);