Marc Kleine-Budde wrote:
> Wolfgang Grandegger wrote:
>>> here "./strip-src -m -i -v 2.6.31" version of the at91 driver,
>>> featuring:
>>> - reworked RX-path
>>> - NAPI for RX and CAN frame errors
>>> TX and CAN state is still managed from irq handler
>>> - CAN chip is turned off after a bus off
>>> the NAPI is stopped via a work_queue, because
>>> NAPI cannot be disabled from IRQ context
>>> (where the bus off is detected).
>> Very nice. Do you really need to stop the NAPI in case of bus-off? You
>> stopped the device and no more message will come in anyhow.
>
> hmmm...I'll try
It would be nice if we could get rid of the work queue. For the MSCAN on
the MPC5200, NAPI is also not disabled on bus-off and the controller
behaves similar (doing automatic bus-off recovery).
>>> I have to figure out if disabling NAPI is possbile from NAPI conext, so
>>> CAN state transition might be moved to NAPI, too.
>
> for the record:
> no, we would get a deadlock then..(waiting in NAPI for NAPI to end)
OK, I see.
>>> Bus off and manual restart via the "ip" utility is working. However the
>>> last remaining bits of the auto recover handling must be removed,
>>> though.
>> Did you follow our recent discussion on how to handle auto recovery? The
>> preferred solution is to *stop* the device if priv->can.restart_ms ==
>> 0. If it's > 0, the hardware should do the recovery and when the state
>> changes to error-active, an RESTARTED error message should be generated.
>
> okay, will change.
>
>>> The driver with NAPI receiving messages with a length of 1 on a 1 Mbit
>>> link without swapping the messages (tested with pengutronix cansequence).
>> Please use Vladislavs' canecho_gen/duts at 125kB/sec, which is more
>> sensitive. Don't forget to fix the unhanded errno ENOBUFS of the write
>> functions.
>
> using select/poll would be better than calling sched_yield
Well, yes, could this easily be achieved? Oliver?
>>> However if I add some "ping -f" load the driver keeps working (tested
>>> with looking at the data bytes in the driver), but the userspace doesn't
>>> get enough cpu cycles so AFAICS the pacakges must be dropped in the
>>> network layer.
>>>
>>> Even on the 1 Mbit link the total number IRQs isn't reduced by NAPI
>>> (less than 1%). But with NAPI I can enable the Acknowledgement Error
>>> even on 1 Mbit, and the system doesn't lock up. It generated ~15K Int/s.
>> With NAPI, message processing is moved from the interrupt to the process
>> context, which efficiently avoids lockups. As longs as CPU resources are
>> available, no messages will be dropped.
>
>>> Adding again "ping -f" load, the CAN interrupts drop to ~11K Int/s,
>>> the Ethernet causes only ~7K Int/s.
>>>
>>> Maybe we can think of some really "slow" polling for such interrupts.
>>> IIRC the SJA1000 has the same problem.
>> I remember some discussion on this topic a long time ago and there it
>> was regarded important to get and inspect all bus errors. Throttling was
>> not accepted.
>
> As we see with the above numbers, we lose about 4000 errors per second
> if ethernet traffic hits the box. I was just thinking about polling this
> particular error if it hits the chip.
This is a general issue and I think we should re-discuss it sooner than
later.
>>> Here's the driver, comments welcome. There are some functions, that
>>> might be moved out of the driver into can/dev.c (alloc_can*frame).
>> There are various general coding style issues:
[snip]
>>> +/* Common registers */
>>> +enum at91_reg {
>>> + AT91_MR = 0x000,
>>> + AT91_IER = 0x004,
>>> + AT91_IDR = 0x008,
>>> + AT91_IMR = 0x00C,
>>> + AT91_SR = 0x010,
>>> + AT91_BR = 0x014,
>>> + AT91_TIM = 0x018,
>>> + AT91_TIMESTP = 0x01C,
>>> + AT91_ECR = 0x020,
>>> + AT91_TCR = 0x024,
>>> + AT91_ACR = 0x028,
>>> +};
>>> +
>>> +/* Mailbox registers (0 <= i <= 15) */
>>> +#define AT91_MMR(i) (enum at91_reg)(0x200 + ((i) * 0x20))
>>> +#define AT91_MAM(i) (enum at91_reg)(0x204 + ((i) * 0x20))
>>> +#define AT91_MID(i) (enum at91_reg)(0x208 + ((i) * 0x20))
>>> +#define AT91_MFID(i) (enum at91_reg)(0x20C + ((i) * 0x20))
>>> +#define AT91_MSR(i) (enum at91_reg)(0x210 + ((i) * 0x20))
>>> +#define AT91_MDL(i) (enum at91_reg)(0x214 + ((i) * 0x20))
>>> +#define AT91_MDH(i) (enum at91_reg)(0x218 + ((i) * 0x20))
>>> +#define AT91_MCR(i) (enum at91_reg)(0x21C + ((i) * 0x20))
>>> +
>>> +/* Register bits */
>>> +#define AT91_MR_AT91EN BIT(0)
>>> +#define AT91_MR_LPM BIT(1)
>>> +#define AT91_MR_ABM BIT(2)
>>> +#define AT91_MR_OVL BIT(3)
>>> +#define AT91_MR_TEOF BIT(4)
>>> +#define AT91_MR_TTM BIT(5)
>>> +#define AT91_MR_TIMFRZ BIT(6)
>>> +#define AT91_MR_DRPT BIT(7)
>>> +
>>> +#define AT91_SR_RBSY BIT(29)
>>> +
>>> +#define AT91_MMR_PRIO_SHIFT (16)
>>> +
>>> +#define AT91_MID_MIDE BIT(29)
>>> +
>>> +#define AT91_MSR_MRTR BIT(20)
>>> +#define AT91_MSR_MABT BIT(22)
>>> +#define AT91_MSR_MRDY BIT(23)
>>> +#define AT91_MSR_MMI BIT(24)
>>> +
>>> +#define AT91_MCR_MRTR BIT(20)
>>> +#define AT91_MCR_MTCR BIT(23)
>>> +
>>> +/* Mailbox Modes */
>>> +enum at91_mb_mode {
>>> + AT91_MB_MODE_DISABLED = 0,
>>> + AT91_MB_MODE_RX = 1,
>>> + AT91_MB_MODE_RX_OVRWR = 2,
>>> + AT91_MB_MODE_TX = 3,
>>> + AT91_MB_MODE_CONSUMER = 4,
>>> + AT91_MB_MODE_PRODUCER = 5,
>>> +};
>>> +
>>> +/* Interrupt mask bits */
>>> +#define AT91_IRQ_MB_RX ((1 << (AT91_MB_RX_LAST + 1)) \
>>> + - (1 << AT91_MB_RX_FIRST))
>>> +#define AT91_IRQ_MB_TX ((1 << (AT91_MB_TX_LAST + 1)) \
>>> + - (1 << AT91_MB_TX_FIRST))
>>> +#define AT91_IRQ_MB_AL (AT91_IRQ_MB_RX | AT91_IRQ_MB_TX)
>>> +
>>> +#define AT91_IRQ_ERRA (1 << 16)
>>> +#define AT91_IRQ_WARN (1 << 17)
>>> +#define AT91_IRQ_ERRP (1 << 18)
>>> +#define AT91_IRQ_BOFF (1 << 19)
>>> +#define AT91_IRQ_SLEEP (1 << 20)
>>> +#define AT91_IRQ_WAKEUP (1 << 21)
>>> +#define AT91_IRQ_TOVF (1 << 22)
>>> +#define AT91_IRQ_TSTP (1 << 23)
>>> +#define AT91_IRQ_CERR (1 << 24)
>>> +#define AT91_IRQ_SERR (1 << 25)
>>> +#define AT91_IRQ_AERR (1 << 26)
>>> +#define AT91_IRQ_FERR (1 << 27)
>>> +#define AT91_IRQ_BERR (1 << 28)
>>> +
>>> +#define AT91_IRQ_ERR_ALL (0x1fff0000)
>>> +#define AT91_IRQ_ERR_FRAME (AT91_IRQ_CERR | AT91_IRQ_SERR | \
>>> + AT91_IRQ_AERR | AT91_IRQ_FERR | AT91_IRQ_BERR)
>>> +#define AT91_IRQ_ERR_LINE (AT91_IRQ_ERRA | AT91_IRQ_WARN | \
>>> + AT91_IRQ_ERRP | AT91_IRQ_BOFF)
>>> +
>>> +#define AT91_IRQ_ALL (0x1fffffff)
>>> +
>>> +struct at91_priv {
>>> + struct can_priv can; /* must be the first member! */
>>> + struct net_device *dev;
>>> + struct napi_struct napi;
>>> +
>>> + void __iomem *reg_base;
>>> +
>>> + u32 reg_sr;
>>> + unsigned int tx_next;
>>> + unsigned int tx_echo;
>>> + unsigned int rx_next;
>>> +
>>> + struct work_struct bus_off_task;
>>> +
>>> + struct clk *clk;
>>> + struct at91_can_data *pdata;
>>> +};
>>> +
>>> +
>>> +static struct can_bittiming_const at91_bittiming_const = {
>>> + .tseg1_min = 4,
>>> + .tseg1_max = 16,
>>> + .tseg2_min = 2,
>>> + .tseg2_max = 8,
>>> + .sjw_max = 4,
>>> + .brp_min = 2,
>>> + .brp_max = 128,
>>> + .brp_inc = 1,
>>> +};
>> Why do you don't use tab here fore aligment of the numbers?
>
> As Wolfram pointed out:
>
>> There are a few of those. Such kind of indentation is ususally
>> rejected upstream, too. If one of the member names ever changes, "="
>> will get misaligned again (or you'd need to alter lines just for
>> beautification which would make git blame less useful). So, one space
>> after the names should do.
I know, but then you probably also want to fix the enums above. In the
file header, I'm more relaxed, especially because defines are usually
aligned as well.
>>> +
>>> +static inline int get_tx_next_mb(struct at91_priv *priv)
>>> +{
>>> + return (priv->tx_next & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST;
>>> +}
>>> +
>>> +static inline int get_tx_next_prio(struct at91_priv *priv)
>>> +{
>>> + return (priv->tx_next >> AT91_NEXT_PRIO_SHIFT) & 0xf;
>>> +}
>>> +
>>> +static inline int get_tx_echo_mb(struct at91_priv *priv)
>>> +{
>>> + return (priv->tx_echo & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST;
>>> +}
>>> +
>>> +
>>> +static inline u32 at91_read(struct net_device *dev, enum at91_reg reg)
>>> +{
>>> + struct at91_priv *priv = netdev_priv(dev);
>>> + return readl(priv->reg_base + reg);
>>> +}
>>> +
>>> +static inline void
>>> +at91_write(struct net_device *dev, enum at91_reg reg, u32 value)
>>> +{
>>> + struct at91_priv *priv = netdev_priv(dev);
>>> + writel(value, priv->reg_base + reg);
>>> +}
>>> +
>>> +
>>> +static inline void
>>> +set_mb_mode_prio(struct net_device *dev, unsigned int mb,
>>> + enum at91_mb_mode mode, int prio)
>>> +{
>>> + at91_write(dev, AT91_MMR(mb),
>>> + (mode << 24) | (prio << 16));
>> Fits on one line?
>
> it does, fixed
>
>>> +}
>>> +
>>> +static inline void
>>> +set_mb_mode(struct net_device *dev, unsigned int mb, enum at91_mb_mode
>>> mode)
>>> +{
>>> + set_mb_mode_prio(dev, mb, mode, 0);
>>> +}
>>> +
>>> +
>>> +static struct sk_buff *
>>> +alloc_can_frame(struct net_device *dev, struct can_frame **cf)
>>> +{
>>> + struct sk_buff *skb;
>>> +
>>> + skb = netdev_alloc_skb(dev, sizeof(struct can_frame));
>>> + if (unlikely(!skb))
A (rate limited) dev_err would be nice here as well.
>>> + return NULL;
>>> +
>>> + skb->protocol = htons(ETH_P_CAN);
>>> + skb->ip_summed = CHECKSUM_UNNECESSARY;
>>> + *cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
>>> +
>>> + return skb;
>>> +}
>>> +
>>> +
>>> +static struct sk_buff *
>>> +alloc_can_err_frame(struct net_device *dev, struct can_frame **cf)
>>> +{
>>> + struct sk_buff *skb;
>>> +
>>> + skb = alloc_can_frame(dev, cf);
>>> + if (unlikely(!skb))
>>> + return NULL;
>>> +
>>> + memset(*cf, 0, sizeof(struct can_frame));
>>> + (*cf)->can_id = CAN_ERR_FLAG;
>>> + (*cf)->can_dlc = CAN_ERR_DLC;
>>> +
>>> + return skb;
>>> +}
>> Yes, we should put similar functions into dev.[ch]. But I would use the
>> suffix "skb" instead of "frame" because the return value is of type
>> "static struct sk_buff *". Patches are welcome.
>
> fixed. patches against which tree?
First again SVN trunk.
Wolfgang.
_______________________________________________
Socketcan-core mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core