Commit a6e4bc53 authored by Wolfgang Grandegger's avatar Wolfgang Grandegger Committed by David S. Miller

can: make the number of echo skb's configurable

This patch allows the CAN controller driver to define the number of echo
skb's used for the local loopback (echo), as suggested by Kurt Van
Dijck, with the function:

  struct net_device *alloc_candev(int sizeof_priv,
                                  unsigned int echo_skb_max);

The CAN drivers have been adapted accordingly. For the ems_usb driver,
as suggested by Sebastian Haas, the number of echo skb's has been
increased to 10, which improves the transmission performance a lot.
Signed-off-by: default avatarWolfgang Grandegger <wg@grandegger.com>
Signed-off-by: default avatarKurt Van Dijck <kurt.van.dijck@eia.be>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 61321bbd
...@@ -1087,7 +1087,7 @@ static int __init at91_can_probe(struct platform_device *pdev) ...@@ -1087,7 +1087,7 @@ static int __init at91_can_probe(struct platform_device *pdev)
goto exit_release; goto exit_release;
} }
dev = alloc_candev(sizeof(struct at91_priv)); dev = alloc_candev(sizeof(struct at91_priv), AT91_MB_TX_NUM);
if (!dev) { if (!dev) {
err = -ENOMEM; err = -ENOMEM;
goto exit_iounmap; goto exit_iounmap;
......
...@@ -245,7 +245,7 @@ static void can_flush_echo_skb(struct net_device *dev) ...@@ -245,7 +245,7 @@ static void can_flush_echo_skb(struct net_device *dev)
struct net_device_stats *stats = &dev->stats; struct net_device_stats *stats = &dev->stats;
int i; int i;
for (i = 0; i < CAN_ECHO_SKB_MAX; i++) { for (i = 0; i < priv->echo_skb_max; i++) {
if (priv->echo_skb[i]) { if (priv->echo_skb[i]) {
kfree_skb(priv->echo_skb[i]); kfree_skb(priv->echo_skb[i]);
priv->echo_skb[i] = NULL; priv->echo_skb[i] = NULL;
...@@ -262,10 +262,13 @@ static void can_flush_echo_skb(struct net_device *dev) ...@@ -262,10 +262,13 @@ static void can_flush_echo_skb(struct net_device *dev)
* of the device driver. The driver must protect access to * of the device driver. The driver must protect access to
* priv->echo_skb, if necessary. * priv->echo_skb, if necessary.
*/ */
void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx) void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
unsigned int idx)
{ {
struct can_priv *priv = netdev_priv(dev); struct can_priv *priv = netdev_priv(dev);
BUG_ON(idx >= priv->echo_skb_max);
/* check flag whether this packet has to be looped back */ /* check flag whether this packet has to be looped back */
if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) { if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) {
kfree_skb(skb); kfree_skb(skb);
...@@ -311,10 +314,12 @@ EXPORT_SYMBOL_GPL(can_put_echo_skb); ...@@ -311,10 +314,12 @@ EXPORT_SYMBOL_GPL(can_put_echo_skb);
* is handled in the device driver. The driver must protect * is handled in the device driver. The driver must protect
* access to priv->echo_skb, if necessary. * access to priv->echo_skb, if necessary.
*/ */
void can_get_echo_skb(struct net_device *dev, int idx) void can_get_echo_skb(struct net_device *dev, unsigned int idx)
{ {
struct can_priv *priv = netdev_priv(dev); struct can_priv *priv = netdev_priv(dev);
BUG_ON(idx >= priv->echo_skb_max);
if (priv->echo_skb[idx]) { if (priv->echo_skb[idx]) {
netif_rx(priv->echo_skb[idx]); netif_rx(priv->echo_skb[idx]);
priv->echo_skb[idx] = NULL; priv->echo_skb[idx] = NULL;
...@@ -327,10 +332,12 @@ EXPORT_SYMBOL_GPL(can_get_echo_skb); ...@@ -327,10 +332,12 @@ EXPORT_SYMBOL_GPL(can_get_echo_skb);
* *
* The function is typically called when TX failed. * The function is typically called when TX failed.
*/ */
void can_free_echo_skb(struct net_device *dev, int idx) void can_free_echo_skb(struct net_device *dev, unsigned int idx)
{ {
struct can_priv *priv = netdev_priv(dev); struct can_priv *priv = netdev_priv(dev);
BUG_ON(idx >= priv->echo_skb_max);
if (priv->echo_skb[idx]) { if (priv->echo_skb[idx]) {
kfree_skb(priv->echo_skb[idx]); kfree_skb(priv->echo_skb[idx]);
priv->echo_skb[idx] = NULL; priv->echo_skb[idx] = NULL;
...@@ -445,17 +452,30 @@ static void can_setup(struct net_device *dev) ...@@ -445,17 +452,30 @@ static void can_setup(struct net_device *dev)
/* /*
* Allocate and setup space for the CAN network device * Allocate and setup space for the CAN network device
*/ */
struct net_device *alloc_candev(int sizeof_priv) struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)
{ {
struct net_device *dev; struct net_device *dev;
struct can_priv *priv; struct can_priv *priv;
int size;
dev = alloc_netdev(sizeof_priv, "can%d", can_setup); if (echo_skb_max)
size = ALIGN(sizeof_priv, sizeof(struct sk_buff *)) +
echo_skb_max * sizeof(struct sk_buff *);
else
size = sizeof_priv;
dev = alloc_netdev(size, "can%d", can_setup);
if (!dev) if (!dev)
return NULL; return NULL;
priv = netdev_priv(dev); priv = netdev_priv(dev);
if (echo_skb_max) {
priv->echo_skb_max = echo_skb_max;
priv->echo_skb = (void *)priv +
ALIGN(sizeof_priv, sizeof(struct sk_buff *));
}
priv->state = CAN_STATE_STOPPED; priv->state = CAN_STATE_STOPPED;
init_timer(&priv->restart_timer); init_timer(&priv->restart_timer);
......
...@@ -565,7 +565,8 @@ struct net_device *alloc_sja1000dev(int sizeof_priv) ...@@ -565,7 +565,8 @@ struct net_device *alloc_sja1000dev(int sizeof_priv)
struct net_device *dev; struct net_device *dev;
struct sja1000_priv *priv; struct sja1000_priv *priv;
dev = alloc_candev(sizeof(struct sja1000_priv) + sizeof_priv); dev = alloc_candev(sizeof(struct sja1000_priv) + sizeof_priv,
SJA1000_ECHO_SKB_MAX);
if (!dev) if (!dev)
return NULL; return NULL;
......
...@@ -50,6 +50,8 @@ ...@@ -50,6 +50,8 @@
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/platform/sja1000.h> #include <linux/can/platform/sja1000.h>
#define SJA1000_ECHO_SKB_MAX 1 /* the SJA1000 has one TX buffer object */
#define SJA1000_MAX_IRQ 20 /* max. number of interrupts handled in ISR */ #define SJA1000_MAX_IRQ 20 /* max. number of interrupts handled in ISR */
/* SJA1000 registers - manual section 6.4 (Pelican Mode) */ /* SJA1000 registers - manual section 6.4 (Pelican Mode) */
......
...@@ -74,10 +74,6 @@ MODULE_VERSION(HECC_MODULE_VERSION); ...@@ -74,10 +74,6 @@ MODULE_VERSION(HECC_MODULE_VERSION);
#define HECC_MB_TX_SHIFT 2 /* as per table above */ #define HECC_MB_TX_SHIFT 2 /* as per table above */
#define HECC_MAX_TX_MBOX BIT(HECC_MB_TX_SHIFT) #define HECC_MAX_TX_MBOX BIT(HECC_MB_TX_SHIFT)
#if (HECC_MAX_TX_MBOX > CAN_ECHO_SKB_MAX)
#error "HECC: MAX TX mailboxes should be equal or less than CAN_ECHO_SKB_MAX"
#endif
#define HECC_TX_PRIO_SHIFT (HECC_MB_TX_SHIFT) #define HECC_TX_PRIO_SHIFT (HECC_MB_TX_SHIFT)
#define HECC_TX_PRIO_MASK (MAX_TX_PRIO << HECC_MB_TX_SHIFT) #define HECC_TX_PRIO_MASK (MAX_TX_PRIO << HECC_MB_TX_SHIFT)
#define HECC_TX_MB_MASK (HECC_MAX_TX_MBOX - 1) #define HECC_TX_MB_MASK (HECC_MAX_TX_MBOX - 1)
...@@ -902,7 +898,7 @@ static int ti_hecc_probe(struct platform_device *pdev) ...@@ -902,7 +898,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
goto probe_exit_free_region; goto probe_exit_free_region;
} }
ndev = alloc_candev(sizeof(struct ti_hecc_priv)); ndev = alloc_candev(sizeof(struct ti_hecc_priv), HECC_MAX_TX_MBOX);
if (!ndev) { if (!ndev) {
dev_err(&pdev->dev, "alloc_candev failed\n"); dev_err(&pdev->dev, "alloc_candev failed\n");
err = -ENOMEM; err = -ENOMEM;
......
...@@ -232,7 +232,7 @@ MODULE_DEVICE_TABLE(usb, ems_usb_table); ...@@ -232,7 +232,7 @@ MODULE_DEVICE_TABLE(usb, ems_usb_table);
#define INTR_IN_BUFFER_SIZE 4 #define INTR_IN_BUFFER_SIZE 4
#define MAX_RX_URBS 10 #define MAX_RX_URBS 10
#define MAX_TX_URBS CAN_ECHO_SKB_MAX #define MAX_TX_URBS 10
struct ems_usb; struct ems_usb;
...@@ -1012,7 +1012,7 @@ static int ems_usb_probe(struct usb_interface *intf, ...@@ -1012,7 +1012,7 @@ static int ems_usb_probe(struct usb_interface *intf,
struct ems_usb *dev; struct ems_usb *dev;
int i, err = -ENOMEM; int i, err = -ENOMEM;
netdev = alloc_candev(sizeof(struct ems_usb)); netdev = alloc_candev(sizeof(struct ems_usb), MAX_TX_URBS);
if (!netdev) { if (!netdev) {
dev_err(netdev->dev.parent, "Couldn't alloc candev\n"); dev_err(netdev->dev.parent, "Couldn't alloc candev\n");
return -ENOMEM; return -ENOMEM;
......
...@@ -29,8 +29,6 @@ enum can_mode { ...@@ -29,8 +29,6 @@ enum can_mode {
/* /*
* CAN common private data * CAN common private data
*/ */
#define CAN_ECHO_SKB_MAX 4
struct can_priv { struct can_priv {
struct can_device_stats can_stats; struct can_device_stats can_stats;
...@@ -44,15 +42,16 @@ struct can_priv { ...@@ -44,15 +42,16 @@ struct can_priv {
int restart_ms; int restart_ms;
struct timer_list restart_timer; struct timer_list restart_timer;
struct sk_buff *echo_skb[CAN_ECHO_SKB_MAX];
int (*do_set_bittiming)(struct net_device *dev); int (*do_set_bittiming)(struct net_device *dev);
int (*do_set_mode)(struct net_device *dev, enum can_mode mode); int (*do_set_mode)(struct net_device *dev, enum can_mode mode);
int (*do_get_state)(const struct net_device *dev, int (*do_get_state)(const struct net_device *dev,
enum can_state *state); enum can_state *state);
unsigned int echo_skb_max;
struct sk_buff **echo_skb;
}; };
struct net_device *alloc_candev(int sizeof_priv); struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
void free_candev(struct net_device *dev); void free_candev(struct net_device *dev);
int open_candev(struct net_device *dev); int open_candev(struct net_device *dev);
...@@ -64,8 +63,9 @@ void unregister_candev(struct net_device *dev); ...@@ -64,8 +63,9 @@ void unregister_candev(struct net_device *dev);
int can_restart_now(struct net_device *dev); int can_restart_now(struct net_device *dev);
void can_bus_off(struct net_device *dev); void can_bus_off(struct net_device *dev);
void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx); void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
void can_get_echo_skb(struct net_device *dev, int idx); unsigned int idx);
void can_free_echo_skb(struct net_device *dev, int idx); void can_get_echo_skb(struct net_device *dev, unsigned int idx);
void can_free_echo_skb(struct net_device *dev, unsigned int idx);
#endif /* CAN_DEV_H */ #endif /* CAN_DEV_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment