can: netlink support for bus-error reporting and counters

This patch makes the bus-error reporting configurable and allows to
retrieve the CAN TX and RX bus error counters via netlink interface.
I have added support for the SJA1000. The TX and RX bus error counters
are also copied to the data fields 6..7 of error messages when state
changes are reported.

Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Wolfgang Grandegger 2010-02-22 22:21:17 +00:00 committed by David S. Miller
parent 78ca90ea99
commit 52c793f240
4 changed files with 44 additions and 7 deletions

View File

@ -574,6 +574,7 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
[IFLA_CAN_BITTIMING_CONST] [IFLA_CAN_BITTIMING_CONST]
= { .len = sizeof(struct can_bittiming_const) }, = { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) }, [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) },
[IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
}; };
static int can_changelink(struct net_device *dev, static int can_changelink(struct net_device *dev,
@ -649,6 +650,8 @@ static size_t can_get_size(const struct net_device *dev)
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
size += sizeof(struct can_bittiming); /* IFLA_CAN_BITTIMING */ size += sizeof(struct can_bittiming); /* IFLA_CAN_BITTIMING */
size += sizeof(struct can_clock); /* IFLA_CAN_CLOCK */ size += sizeof(struct can_clock); /* IFLA_CAN_CLOCK */
if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */
size += sizeof(struct can_berr_counter);
if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */ if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */
size += sizeof(struct can_bittiming_const); size += sizeof(struct can_bittiming_const);
@ -659,6 +662,7 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
{ {
struct can_priv *priv = netdev_priv(dev); struct can_priv *priv = netdev_priv(dev);
struct can_ctrlmode cm = {.flags = priv->ctrlmode}; struct can_ctrlmode cm = {.flags = priv->ctrlmode};
struct can_berr_counter bec;
enum can_state state = priv->state; enum can_state state = priv->state;
if (priv->do_get_state) if (priv->do_get_state)
@ -669,6 +673,8 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
NLA_PUT(skb, IFLA_CAN_BITTIMING, NLA_PUT(skb, IFLA_CAN_BITTIMING,
sizeof(priv->bittiming), &priv->bittiming); sizeof(priv->bittiming), &priv->bittiming);
NLA_PUT(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock); NLA_PUT(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock);
if (priv->do_get_berr_counter && !priv->do_get_berr_counter(dev, &bec))
NLA_PUT(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec);
if (priv->bittiming_const) if (priv->bittiming_const)
NLA_PUT(skb, IFLA_CAN_BITTIMING_CONST, NLA_PUT(skb, IFLA_CAN_BITTIMING_CONST,
sizeof(*priv->bittiming_const), priv->bittiming_const); sizeof(*priv->bittiming_const), priv->bittiming_const);

View File

@ -130,8 +130,12 @@ static void set_normal_mode(struct net_device *dev)
/* check reset bit */ /* check reset bit */
if ((status & MOD_RM) == 0) { if ((status & MOD_RM) == 0) {
priv->can.state = CAN_STATE_ERROR_ACTIVE; priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* enable all interrupts */ /* enable interrupts */
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
priv->write_reg(priv, REG_IER, IRQ_ALL); priv->write_reg(priv, REG_IER, IRQ_ALL);
else
priv->write_reg(priv, REG_IER,
IRQ_ALL & ~IRQ_BEI);
return; return;
} }
@ -203,6 +207,17 @@ static int sja1000_set_bittiming(struct net_device *dev)
return 0; return 0;
} }
static int sja1000_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
struct sja1000_priv *priv = netdev_priv(dev);
bec->txerr = priv->read_reg(priv, REG_TXERR);
bec->rxerr = priv->read_reg(priv, REG_RXERR);
return 0;
}
/* /*
* initialize SJA1000 chip: * initialize SJA1000 chip:
* - reset chip * - reset chip
@ -437,6 +452,8 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
CAN_ERR_CRTL_TX_PASSIVE : CAN_ERR_CRTL_TX_PASSIVE :
CAN_ERR_CRTL_RX_PASSIVE; CAN_ERR_CRTL_RX_PASSIVE;
} }
cf->data[6] = txerr;
cf->data[7] = rxerr;
} }
priv->can.state = state; priv->can.state = state;
@ -567,7 +584,9 @@ struct net_device *alloc_sja1000dev(int sizeof_priv)
priv->can.bittiming_const = &sja1000_bittiming_const; priv->can.bittiming_const = &sja1000_bittiming_const;
priv->can.do_set_bittiming = sja1000_set_bittiming; priv->can.do_set_bittiming = sja1000_set_bittiming;
priv->can.do_set_mode = sja1000_set_mode; priv->can.do_set_mode = sja1000_set_mode;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; priv->can.do_get_berr_counter = sja1000_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_BERR_REPORTING;
if (sizeof_priv) if (sizeof_priv)
priv->priv = (void *)priv + sizeof(struct sja1000_priv); priv->priv = (void *)priv + sizeof(struct sja1000_priv);

View File

@ -47,6 +47,8 @@ struct can_priv {
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);
int (*do_get_berr_counter)(const struct net_device *dev,
struct can_berr_counter *bec);
unsigned int echo_skb_max; unsigned int echo_skb_max;
struct sk_buff **echo_skb; struct sk_buff **echo_skb;

View File

@ -69,6 +69,14 @@ enum can_state {
CAN_STATE_MAX CAN_STATE_MAX
}; };
/*
* CAN bus error counters
*/
struct can_berr_counter {
__u16 txerr;
__u16 rxerr;
};
/* /*
* CAN controller mode * CAN controller mode
*/ */
@ -77,10 +85,11 @@ struct can_ctrlmode {
__u32 flags; __u32 flags;
}; };
#define CAN_CTRLMODE_LOOPBACK 0x1 /* Loopback mode */ #define CAN_CTRLMODE_LOOPBACK 0x01 /* Loopback mode */
#define CAN_CTRLMODE_LISTENONLY 0x2 /* Listen-only mode */ #define CAN_CTRLMODE_LISTENONLY 0x02 /* Listen-only mode */
#define CAN_CTRLMODE_3_SAMPLES 0x4 /* Triple sampling mode */ #define CAN_CTRLMODE_3_SAMPLES 0x04 /* Triple sampling mode */
#define CAN_CTRLMODE_ONE_SHOT 0x8 /* One-Shot mode */ #define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */
#define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */
/* /*
* CAN device statistics * CAN device statistics
@ -106,6 +115,7 @@ enum {
IFLA_CAN_CTRLMODE, IFLA_CAN_CTRLMODE,
IFLA_CAN_RESTART_MS, IFLA_CAN_RESTART_MS,
IFLA_CAN_RESTART, IFLA_CAN_RESTART,
IFLA_CAN_BERR_COUNTER,
__IFLA_CAN_MAX __IFLA_CAN_MAX
}; };