From 9beebc2b5d0038a65977a7a14909598c64ce070f Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 28 Sep 2023 09:24:28 +0200 Subject: [PATCH 01/27] can: dev: add can_state_get_by_berr_counter() to return the CAN state based on the current error counters Some CAN controllers do not have a register that contains the current CAN state, but only a register that contains the error counters. Introduce a new function can_state_get_by_berr_counter() that returns the current TX and RX state depending on the provided CAN bit error counters. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-1-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev/dev.c | 22 ++++++++++++++++++++++ include/linux/can/dev.h | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index 82b12902fc35..3a3be5cdfc1f 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -90,6 +90,28 @@ const char *can_get_state_str(const enum can_state state) } EXPORT_SYMBOL_GPL(can_get_state_str); +static enum can_state can_state_err_to_state(u16 err) +{ + if (err < CAN_ERROR_WARNING_THRESHOLD) + return CAN_STATE_ERROR_ACTIVE; + if (err < CAN_ERROR_PASSIVE_THRESHOLD) + return CAN_STATE_ERROR_WARNING; + if (err < CAN_BUS_OFF_THRESHOLD) + return CAN_STATE_ERROR_PASSIVE; + + return CAN_STATE_BUS_OFF; +} + +void can_state_get_by_berr_counter(const struct net_device *dev, + const struct can_berr_counter *bec, + enum can_state *tx_state, + enum can_state *rx_state) +{ + *tx_state = can_state_err_to_state(bec->txerr); + *rx_state = can_state_err_to_state(bec->rxerr); +} +EXPORT_SYMBOL_GPL(can_state_get_by_berr_counter); + void can_change_state(struct net_device *dev, struct can_frame *cf, enum can_state tx_state, enum can_state rx_state) { diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 982ba245eb41..1b92aed49363 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -195,6 +195,10 @@ int can_restart_now(struct net_device *dev); void can_bus_off(struct net_device *dev); const char *can_get_state_str(const enum can_state state); +void can_state_get_by_berr_counter(const struct net_device *dev, + const struct can_berr_counter *bec, + enum can_state *tx_state, + enum can_state *rx_state); void can_change_state(struct net_device *dev, struct can_frame *cf, enum can_state tx_state, enum can_state rx_state); From e26ccc4658c10fc949e475238f94a20b19e96b56 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 18 Apr 2023 16:26:52 +0200 Subject: [PATCH 02/27] can: at91_can: use a consistent indention Convert the driver to use a consistent indention of one space after defines and in enums. That makes it easier to add new defines, which will be done in the coming patches. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-2-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 124 ++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 4621266851ed..367ccf109652 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -25,89 +25,89 @@ #include #include -#define AT91_MB_MASK(i) ((1 << (i)) - 1) +#define AT91_MB_MASK(i) ((1 << (i)) - 1) /* 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, + 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))) +#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_CANEN 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_MR_CANEN 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_SR_RBSY BIT(29) -#define AT91_MMR_PRIO_SHIFT (16) +#define AT91_MMR_PRIO_SHIFT (16) -#define AT91_MID_MIDE BIT(29) +#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_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) +#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, + 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_ERRA BIT(16) -#define AT91_IRQ_WARN BIT(17) -#define AT91_IRQ_ERRP BIT(18) -#define AT91_IRQ_BOFF BIT(19) -#define AT91_IRQ_SLEEP BIT(20) -#define AT91_IRQ_WAKEUP BIT(21) -#define AT91_IRQ_TOVF BIT(22) -#define AT91_IRQ_TSTP BIT(23) -#define AT91_IRQ_CERR BIT(24) -#define AT91_IRQ_SERR BIT(25) -#define AT91_IRQ_AERR BIT(26) -#define AT91_IRQ_FERR BIT(27) -#define AT91_IRQ_BERR BIT(28) +#define AT91_IRQ_ERRA BIT(16) +#define AT91_IRQ_WARN BIT(17) +#define AT91_IRQ_ERRP BIT(18) +#define AT91_IRQ_BOFF BIT(19) +#define AT91_IRQ_SLEEP BIT(20) +#define AT91_IRQ_WAKEUP BIT(21) +#define AT91_IRQ_TOVF BIT(22) +#define AT91_IRQ_TSTP BIT(23) +#define AT91_IRQ_CERR BIT(24) +#define AT91_IRQ_SERR BIT(25) +#define AT91_IRQ_AERR BIT(26) +#define AT91_IRQ_FERR BIT(27) +#define AT91_IRQ_BERR BIT(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_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) +#define AT91_IRQ_ALL (0x1fffffff) enum at91_devtype { AT91_DEVTYPE_SAM9263, From 18c98714748364354701c18e93b60f6550171014 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Sun, 23 Apr 2023 13:47:40 +0200 Subject: [PATCH 03/27] can: at91_can: at91_irq_tx(): remove one level of indention Improve code readability by removing one level of indention. If a mailbox is not ready, continue the loop early. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-3-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 367ccf109652..966980d4b5dd 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -844,15 +844,14 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) * parked in the echo queue. */ reg_msr = at91_read(priv, AT91_MSR(mb)); - if (likely(reg_msr & AT91_MSR_MRDY && - ~reg_msr & AT91_MSR_MABT)) { - /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */ - dev->stats.tx_bytes += - can_get_echo_skb(dev, - mb - get_mb_tx_first(priv), - NULL); - dev->stats.tx_packets++; - } + if (unlikely(!(reg_msr & AT91_MSR_MRDY && + ~reg_msr & AT91_MSR_MABT))) + continue; + + /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */ + dev->stats.tx_bytes += + can_get_echo_skb(dev, mb - get_mb_tx_first(priv), NULL); + dev->stats.tx_packets++; } /* restart queue if we don't have a wrap around but restart if From bd7854e83900b0f4c1ec5ddc91c447509f23b160 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 18 Apr 2023 16:35:54 +0200 Subject: [PATCH 04/27] can: at91_can: BR register: convert to FIELD_PREP() Use FIELD_PREP() to access the individual fields of the BR register. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-4-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 966980d4b5dd..79eb78b9f8ae 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -6,6 +6,7 @@ * (C) 2008, 2009, 2010, 2011 by Marc Kleine-Budde */ +#include #include #include #include @@ -64,6 +65,13 @@ enum at91_reg { #define AT91_SR_RBSY BIT(29) +#define AT91_BR_PHASE2_MASK GENMASK(2, 0) +#define AT91_BR_PHASE1_MASK GENMASK(6, 4) +#define AT91_BR_PROPAG_MASK GENMASK(10, 8) +#define AT91_BR_SJW_MASK GENMASK(13, 12) +#define AT91_BR_BRP_MASK GENMASK(22, 16) +#define AT91_BR_SMP BIT(24) + #define AT91_MMR_PRIO_SHIFT (16) #define AT91_MID_MIDE BIT(29) @@ -353,12 +361,16 @@ static int at91_set_bittiming(struct net_device *dev) { const struct at91_priv *priv = netdev_priv(dev); const struct can_bittiming *bt = &priv->can.bittiming; - u32 reg_br; + u32 reg_br = 0; - reg_br = ((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 << 24 : 0) | - ((bt->brp - 1) << 16) | ((bt->sjw - 1) << 12) | - ((bt->prop_seg - 1) << 8) | ((bt->phase_seg1 - 1) << 4) | - ((bt->phase_seg2 - 1) << 0); + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) + reg_br |= AT91_BR_SMP; + + reg_br |= FIELD_PREP(AT91_BR_BRP_MASK, bt->brp - 1) | + FIELD_PREP(AT91_BR_SJW_MASK, bt->sjw - 1) | + FIELD_PREP(AT91_BR_PROPAG_MASK, bt->prop_seg - 1) | + FIELD_PREP(AT91_BR_PHASE1_MASK, bt->phase_seg1 - 1) | + FIELD_PREP(AT91_BR_PHASE2_MASK, bt->phase_seg2 - 1); netdev_info(dev, "writing AT91_BR: 0x%08x\n", reg_br); From abe1348753b3e062da7e0bfee1da0eef9dffe336 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 18 Apr 2023 16:35:54 +0200 Subject: [PATCH 05/27] can: at91_can: ECR register: convert to FIELD_GET() Use FIELD_GET() to access the individual fields of the ECR register. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-5-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 79eb78b9f8ae..7597da543348 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -72,6 +72,9 @@ enum at91_reg { #define AT91_BR_BRP_MASK GENMASK(22, 16) #define AT91_BR_SMP BIT(24) +#define AT91_ECR_REC_MASK GENMASK(8, 0) +#define AT91_ECR_TEC_MASK GENMASK(23, 16) + #define AT91_MMR_PRIO_SHIFT (16) #define AT91_MID_MIDE BIT(29) @@ -385,8 +388,8 @@ static int at91_get_berr_counter(const struct net_device *dev, const struct at91_priv *priv = netdev_priv(dev); u32 reg_ecr = at91_read(priv, AT91_ECR); - bec->rxerr = reg_ecr & 0xff; - bec->txerr = reg_ecr >> 16; + bec->rxerr = FIELD_GET(AT91_ECR_REC_MASK, reg_ecr); + bec->txerr = FIELD_GET(AT91_ECR_TEC_MASK, reg_ecr); return 0; } From 53558ac133c0a8d4fd4c81d6c7885dacd3cca557 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 18 Apr 2023 16:35:54 +0200 Subject: [PATCH 06/27] can: at91_can: MMR registers: convert to FIELD_PREP() Use FIELD_PREP() to access the individual fields of the MMR register. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-6-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 7597da543348..16a62f649418 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -75,7 +75,9 @@ enum at91_reg { #define AT91_ECR_REC_MASK GENMASK(8, 0) #define AT91_ECR_TEC_MASK GENMASK(23, 16) -#define AT91_MMR_PRIO_SHIFT (16) +#define AT91_MMR_MTIMEMARK_MASK GENMASK(15, 0) +#define AT91_MMR_PRIOR_MASK GENMASK(19, 16) +#define AT91_MMR_MOT_MASK GENMASK(26, 24) #define AT91_MID_MIDE BIT(29) @@ -299,9 +301,12 @@ static inline void at91_write(const struct at91_priv *priv, enum at91_reg reg, static inline void set_mb_mode_prio(const struct at91_priv *priv, unsigned int mb, enum at91_mb_mode mode, - int prio) + u8 prio) { - at91_write(priv, AT91_MMR(mb), (mode << 24) | (prio << 16)); + const u32 reg_mmr = FIELD_PREP(AT91_MMR_MOT_MASK, mode) | + FIELD_PREP(AT91_MMR_PRIOR_MASK, prio); + + at91_write(priv, AT91_MMR(mb), reg_mmr); } static inline void set_mb_mode(const struct at91_priv *priv, unsigned int mb, From 90aa9a250cf2def73e890177867155f6ce956912 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 18 Apr 2023 16:35:54 +0200 Subject: [PATCH 07/27] can: at91_can: MID registers: convert access to FIELD_PREP(), FIELD_GET() Use FIELD_PREP() and FIELD_GET() to access the individual fields of the MID register. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-7-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 16a62f649418..ec028fe833f0 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -79,6 +79,8 @@ enum at91_reg { #define AT91_MMR_PRIOR_MASK GENMASK(19, 16) #define AT91_MMR_MOT_MASK GENMASK(26, 24) +#define AT91_MID_MIDVB_MASK GENMASK(17, 0) +#define AT91_MID_MIDVA_MASK GENMASK(28, 18) #define AT91_MID_MIDE BIT(29) #define AT91_MSR_MRTR BIT(20) @@ -320,9 +322,10 @@ static inline u32 at91_can_id_to_reg_mid(canid_t can_id) u32 reg_mid; if (can_id & CAN_EFF_FLAG) - reg_mid = (can_id & CAN_EFF_MASK) | AT91_MID_MIDE; + reg_mid = FIELD_PREP(AT91_MID_MIDVA_MASK | AT91_MID_MIDVB_MASK, can_id) | + AT91_MID_MIDE; else - reg_mid = (can_id & CAN_SFF_MASK) << 18; + reg_mid = FIELD_PREP(AT91_MID_MIDVA_MASK, can_id); return reg_mid; } @@ -590,9 +593,10 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb, reg_mid = at91_read(priv, AT91_MID(mb)); if (reg_mid & AT91_MID_MIDE) - cf->can_id = ((reg_mid >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG; + cf->can_id = FIELD_GET(AT91_MID_MIDVA_MASK | AT91_MID_MIDVB_MASK, reg_mid) | + CAN_EFF_FLAG; else - cf->can_id = (reg_mid >> 18) & CAN_SFF_MASK; + cf->can_id = FIELD_GET(AT91_MID_MIDVA_MASK, reg_mid); reg_msr = at91_read(priv, AT91_MSR(mb)); cf->len = can_cc_dlc2len((reg_msr >> 16) & 0xf); From bdfff1433cd6e2f47155f7bf205bcee32001a075 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 18 Apr 2023 16:35:54 +0200 Subject: [PATCH 08/27] can: at91_can: MSR Register: convert to FIELD_PREP() Use FIELD_PREP() to access the individual fields of the MSR register. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-8-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index ec028fe833f0..41dd2ea239b9 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -83,6 +83,8 @@ enum at91_reg { #define AT91_MID_MIDVA_MASK GENMASK(28, 18) #define AT91_MID_MIDE BIT(29) +#define AT91_MSR_MTIMESTAMP_MASK GENMASK(15, 0) +#define AT91_MSR_MDLC_MASK GENMASK(19, 16) #define AT91_MSR_MRTR BIT(20) #define AT91_MSR_MABT BIT(22) #define AT91_MSR_MRDY BIT(23) @@ -599,7 +601,7 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb, cf->can_id = FIELD_GET(AT91_MID_MIDVA_MASK, reg_mid); reg_msr = at91_read(priv, AT91_MSR(mb)); - cf->len = can_cc_dlc2len((reg_msr >> 16) & 0xf); + cf->len = can_cc_dlc2len(FIELD_GET(AT91_MSR_MDLC_MASK, reg_msr)); if (reg_msr & AT91_MSR_MRTR) { cf->can_id |= CAN_RTR_FLAG; From 5e9c5bcc017d24fe0e990aa793086d4eb175079c Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 18 Apr 2023 16:35:54 +0200 Subject: [PATCH 09/27] can: at91_can: MCR Register: convert to FIELD_PREP() Use FIELD_PREP() to access the individual fields of the MCR register. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-9-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 41dd2ea239b9..0269e2a6508a 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -90,7 +90,9 @@ enum at91_reg { #define AT91_MSR_MRDY BIT(23) #define AT91_MSR_MMI BIT(24) +#define AT91_MCR_MDLC_MASK GENMASK(19, 16) #define AT91_MCR_MRTR BIT(20) +#define AT91_MCR_MACR BIT(22) #define AT91_MCR_MTCR BIT(23) /* Mailbox Modes */ @@ -490,8 +492,12 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } reg_mid = at91_can_id_to_reg_mid(cf->can_id); - reg_mcr = ((cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0) | - (cf->len << 16) | AT91_MCR_MTCR; + + reg_mcr = FIELD_PREP(AT91_MCR_MDLC_MASK, cf->len) | + AT91_MCR_MTCR; + + if (cf->can_id & CAN_RTR_FLAG) + reg_mcr |= AT91_MCR_MRTR; /* disable MB while writing ID (see datasheet) */ set_mb_mode(priv, mb, AT91_MB_MODE_DISABLED); From 63446dc70316e104d8454d4a2143a652d2d47a99 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Sun, 10 May 2015 17:25:14 +0200 Subject: [PATCH 10/27] can: at91_can: add more register definitions Add more register definitions found in the data sheet. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-10-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 0269e2a6508a..f23d036d947d 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -64,6 +64,8 @@ enum at91_reg { #define AT91_MR_DRPT BIT(7) #define AT91_SR_RBSY BIT(29) +#define AT91_SR_TBSY BIT(30) +#define AT91_SR_OVLSY BIT(31) #define AT91_BR_PHASE2_MASK GENMASK(2, 0) #define AT91_BR_PHASE1_MASK GENMASK(6, 4) @@ -72,9 +74,13 @@ enum at91_reg { #define AT91_BR_BRP_MASK GENMASK(22, 16) #define AT91_BR_SMP BIT(24) +#define AT91_TIM_TIMER_MASK GENMASK(15, 0) + #define AT91_ECR_REC_MASK GENMASK(8, 0) #define AT91_ECR_TEC_MASK GENMASK(23, 16) +#define AT91_TCR_TIMRST BIT(31) + #define AT91_MMR_MTIMEMARK_MASK GENMASK(15, 0) #define AT91_MMR_PRIOR_MASK GENMASK(19, 16) #define AT91_MMR_MOT_MASK GENMASK(26, 24) From 2b08e5217a1d151bd8901ad2b7de220227e04b0d Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 28 Sep 2023 22:02:16 +0200 Subject: [PATCH 11/27] can: at91_can: at91_setup_mailboxes(): update comments Since 6388b3961420 ("can: at91_can: add support for the AT91SAM9X5 SOCs") the number of mailboxes used for RX and TX is no longer constant, but depends on the IP core used. Remove the fixed number of mailboxes from the comment. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-11-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index f23d036d947d..b94fb35dc59e 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -347,8 +347,8 @@ static void at91_setup_mailboxes(struct net_device *dev) u32 reg_mid; /* Due to a chip bug (errata 50.2.6.3 & 50.3.5.3) the first - * mailbox is disabled. The next 11 mailboxes are used as a - * reception FIFO. The last mailbox is configured with + * mailbox is disabled. The next mailboxes are used as a + * reception FIFO. The last of the RX mailboxes is configured with * overwrite option. The overwrite flag indicates a FIFO * overflow. */ @@ -369,7 +369,7 @@ static void at91_setup_mailboxes(struct net_device *dev) at91_write(priv, AT91_MID(i), AT91_MID_MIDE); } - /* The last 4 mailboxes are used for transmitting. */ + /* The last mailboxes are used for transmitting. */ for (i = get_mb_tx_first(priv); i <= get_mb_tx_last(priv); i++) set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0); From 2f1a01a82fca5fa734dbe653cce54463f61f0299 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 21 Apr 2023 18:15:15 +0200 Subject: [PATCH 12/27] can: at91_can: rename struct at91_priv::{tx_next,tx_echo} to {tx_head,tx_tail} To increase code readability, use the same naming of the counters for the TX FIFO as in the other drivers implementing the same algorithm. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-12-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 56 +++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index b94fb35dc59e..092652fd7352 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -154,8 +154,8 @@ struct at91_priv { void __iomem *reg_base; u32 reg_sr; - unsigned int tx_next; - unsigned int tx_echo; + unsigned int tx_head; + unsigned int tx_tail; unsigned int rx_next; struct at91_devtype_data devtype_data; @@ -253,24 +253,24 @@ static inline unsigned int get_mb_tx_last(const struct at91_priv *priv) return get_mb_tx_first(priv) + get_mb_tx_num(priv) - 1; } -static inline unsigned int get_next_prio_shift(const struct at91_priv *priv) +static inline unsigned int get_head_prio_shift(const struct at91_priv *priv) { return get_mb_tx_shift(priv); } -static inline unsigned int get_next_prio_mask(const struct at91_priv *priv) +static inline unsigned int get_head_prio_mask(const struct at91_priv *priv) { return 0xf << get_mb_tx_shift(priv); } -static inline unsigned int get_next_mb_mask(const struct at91_priv *priv) +static inline unsigned int get_head_mb_mask(const struct at91_priv *priv) { return AT91_MB_MASK(get_mb_tx_shift(priv)); } -static inline unsigned int get_next_mask(const struct at91_priv *priv) +static inline unsigned int get_head_mask(const struct at91_priv *priv) { - return get_next_mb_mask(priv) | get_next_prio_mask(priv); + return get_head_mb_mask(priv) | get_head_prio_mask(priv); } static inline unsigned int get_irq_mb_rx(const struct at91_priv *priv) @@ -285,19 +285,19 @@ static inline unsigned int get_irq_mb_tx(const struct at91_priv *priv) ~AT91_MB_MASK(get_mb_tx_first(priv)); } -static inline unsigned int get_tx_next_mb(const struct at91_priv *priv) +static inline unsigned int get_tx_head_mb(const struct at91_priv *priv) { - return (priv->tx_next & get_next_mb_mask(priv)) + get_mb_tx_first(priv); + return (priv->tx_head & get_head_mb_mask(priv)) + get_mb_tx_first(priv); } -static inline unsigned int get_tx_next_prio(const struct at91_priv *priv) +static inline unsigned int get_tx_head_prio(const struct at91_priv *priv) { - return (priv->tx_next >> get_next_prio_shift(priv)) & 0xf; + return (priv->tx_head >> get_head_prio_shift(priv)) & 0xf; } -static inline unsigned int get_tx_echo_mb(const struct at91_priv *priv) +static inline unsigned int get_tx_tail_mb(const struct at91_priv *priv) { - return (priv->tx_echo & get_next_mb_mask(priv)) + get_mb_tx_first(priv); + return (priv->tx_tail & get_head_mb_mask(priv)) + get_mb_tx_first(priv); } static inline u32 at91_read(const struct at91_priv *priv, enum at91_reg reg) @@ -374,7 +374,7 @@ static void at91_setup_mailboxes(struct net_device *dev) set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0); /* Reset tx and rx helper pointers */ - priv->tx_next = priv->tx_echo = 0; + priv->tx_head = priv->tx_tail = 0; priv->rx_next = get_mb_rx_first(priv); } @@ -470,11 +470,11 @@ static void at91_chip_stop(struct net_device *dev, enum can_state state) * stop sending, waiting for all messages to be delivered, then start * again with mailbox AT91_MB_TX_FIRST prio 0. * - * We use the priv->tx_next as counter for the next transmission + * We use the priv->tx_head as counter for the next transmission * mailbox, but without the offset AT91_MB_TX_FIRST. The lower bits * encode the mailbox number, the upper 4 bits the mailbox priority: * - * priv->tx_next = (prio << get_next_prio_shift(priv)) | + * priv->tx_head = (prio << get_next_prio_shift(priv)) | * (mb - get_mb_tx_first(priv)); * */ @@ -488,8 +488,8 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) if (can_dev_dropped_skb(dev, skb)) return NETDEV_TX_OK; - mb = get_tx_next_mb(priv); - prio = get_tx_next_prio(priv); + mb = get_tx_head_mb(priv); + prio = get_tx_head_prio(priv); if (unlikely(!(at91_read(priv, AT91_MSR(mb)) & AT91_MSR_MRDY))) { netif_stop_queue(dev); @@ -521,15 +521,15 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) /* we have to stop the queue and deliver all messages in case * of a prio+mb counter wrap around. This is the case if - * tx_next buffer prio and mailbox equals 0. + * tx_head buffer prio and mailbox equals 0. * * also stop the queue if next buffer is still in use * (== not ready) */ - priv->tx_next++; - if (!(at91_read(priv, AT91_MSR(get_tx_next_mb(priv))) & + priv->tx_head++; + if (!(at91_read(priv, AT91_MSR(get_tx_head_mb(priv))) & AT91_MSR_MRDY) || - (priv->tx_next & get_next_mask(priv)) == 0) + (priv->tx_head & get_head_mask(priv)) == 0) netif_stop_queue(dev); /* Enable interrupt for this mailbox */ @@ -849,11 +849,11 @@ static int at91_poll(struct napi_struct *napi, int quota) /* theory of operation: * - * priv->tx_echo holds the number of the oldest can_frame put for + * priv->tx_tail holds the number of the oldest can_frame put for * transmission into the hardware, but not yet ACKed by the CAN tx * complete IRQ. * - * We iterate from priv->tx_echo to priv->tx_next and check if the + * We iterate from priv->tx_tail to priv->tx_head and check if the * packet has been transmitted, echo it back to the CAN framework. If * we discover a not yet transmitted package, stop looking for more. * @@ -866,8 +866,8 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) /* masking of reg_sr not needed, already done by at91_irq */ - for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) { - mb = get_tx_echo_mb(priv); + for (/* nix */; (priv->tx_head - priv->tx_tail) > 0; priv->tx_tail++) { + mb = get_tx_tail_mb(priv); /* no event in mailbox? */ if (!(reg_sr & (1 << mb))) @@ -896,8 +896,8 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) * we get a TX int for the last can frame directly before a * wrap around. */ - if ((priv->tx_next & get_next_mask(priv)) != 0 || - (priv->tx_echo & get_next_mask(priv)) == 0) + if ((priv->tx_head & get_head_mask(priv)) != 0 || + (priv->tx_tail & get_head_mask(priv)) == 0) netif_wake_queue(dev); } From ccd7cd07051fbd50bbbc6a55547d965c3392f318 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 18 Apr 2023 16:36:30 +0200 Subject: [PATCH 13/27] can: at91_can: at91_set_bittiming(): demote register output to debug level This message isn't really helpful for the general reader of the kernel logs, so should not be printed with info level. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-13-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 092652fd7352..f92d8a75d1b1 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -393,7 +393,7 @@ static int at91_set_bittiming(struct net_device *dev) FIELD_PREP(AT91_BR_PHASE1_MASK, bt->phase_seg1 - 1) | FIELD_PREP(AT91_BR_PHASE2_MASK, bt->phase_seg2 - 1); - netdev_info(dev, "writing AT91_BR: 0x%08x\n", reg_br); + netdev_dbg(dev, "writing AT91_BR: 0x%08x\n", reg_br); at91_write(priv, AT91_BR, reg_br); From 8227088cb3c2afb58a45a946d92f6bf93d04d6de Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 1 May 2023 18:14:41 +0200 Subject: [PATCH 14/27] can: at91_can: at91_chip_start(): don't disable IRQs twice In at91_chip_start() first all IRQs are disabled, they do not have to be disabled again at the end of the function before the requested IRQs are enabled. Remove the 2nd disable of all IRQs at the end of the function. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-14-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index f92d8a75d1b1..3f3c6f2107a8 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -438,7 +438,6 @@ static void at91_chip_start(struct net_device *dev) /* Enable interrupts */ reg_ier = get_irq_mb_rx(priv) | AT91_IRQ_ERRP | AT91_IRQ_ERR_FRAME; - at91_write(priv, AT91_IDR, AT91_IRQ_ALL); at91_write(priv, AT91_IER, reg_ier); } From 99f4ff41bbb0a22b3c4bf800b060833255f6ae2a Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 1 May 2023 18:14:41 +0200 Subject: [PATCH 15/27] can: at91_can: at91_open(): forward request_irq()'s return value in case or an error If request_irq() fails, forward the return value. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-15-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 3f3c6f2107a8..bfe414581fa1 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -1128,11 +1128,10 @@ static int at91_open(struct net_device *dev) goto out; /* register interrupt handler */ - if (request_irq(dev->irq, at91_irq, IRQF_SHARED, - dev->name, dev)) { - err = -EAGAIN; + err = request_irq(dev->irq, at91_irq, IRQF_SHARED, + dev->name, dev); + if (err) goto out_close; - } /* start chip and queuing */ at91_chip_start(dev); From 3ecc09856afb83a02c4079db595f9dcc8122b3be Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 1 May 2023 18:14:41 +0200 Subject: [PATCH 16/27] can: at91_can: add CAN transceiver support Add support for Linux-PHY based CAN transceivers. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-16-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index bfe414581fa1..94e9740c80de 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -150,6 +151,7 @@ struct at91_devtype_data { struct at91_priv { struct can_priv can; /* must be the first member! */ struct napi_struct napi; + struct phy *transceiver; void __iomem *reg_base; @@ -1118,20 +1120,24 @@ static int at91_open(struct net_device *dev) struct at91_priv *priv = netdev_priv(dev); int err; - err = clk_prepare_enable(priv->clk); + err = phy_power_on(priv->transceiver); if (err) return err; /* check or determine and set bittime */ err = open_candev(dev); if (err) - goto out; + goto out_phy_power_off; + + err = clk_prepare_enable(priv->clk); + if (err) + goto out_close_candev; /* register interrupt handler */ err = request_irq(dev->irq, at91_irq, IRQF_SHARED, dev->name, dev); if (err) - goto out_close; + goto out_clock_disable_unprepare; /* start chip and queuing */ at91_chip_start(dev); @@ -1140,10 +1146,12 @@ static int at91_open(struct net_device *dev) return 0; - out_close: - close_candev(dev); - out: + out_clock_disable_unprepare: clk_disable_unprepare(priv->clk); + out_close_candev: + close_candev(dev); + out_phy_power_off: + phy_power_off(priv->transceiver); return err; } @@ -1160,6 +1168,7 @@ static int at91_close(struct net_device *dev) free_irq(dev->irq, dev); clk_disable_unprepare(priv->clk); + phy_power_off(priv->transceiver); close_candev(dev); @@ -1284,6 +1293,7 @@ static const struct at91_devtype_data *at91_can_get_driver_data(struct platform_ static int at91_can_probe(struct platform_device *pdev) { const struct at91_devtype_data *devtype_data; + struct phy *transceiver; struct net_device *dev; struct at91_priv *priv; struct resource *res; @@ -1332,6 +1342,13 @@ static int at91_can_probe(struct platform_device *pdev) goto exit_iounmap; } + transceiver = devm_phy_optional_get(&pdev->dev, NULL); + if (IS_ERR(transceiver)) { + err = PTR_ERR(transceiver); + dev_err_probe(&pdev->dev, err, "failed to get phy\n"); + goto exit_iounmap; + } + dev->netdev_ops = &at91_netdev_ops; dev->ethtool_ops = &at91_ethtool_ops; dev->irq = irq; @@ -1352,6 +1369,9 @@ static int at91_can_probe(struct platform_device *pdev) netif_napi_add_weight(dev, &priv->napi, at91_poll, get_mb_rx_num(priv)); + if (transceiver) + priv->can.bitrate_max = transceiver->attrs.max_link_rate; + if (at91_is_sam9263(priv)) dev->sysfs_groups[0] = &at91_sysfs_attr_group; From 864c6f07d3c4a4ed40fca932d9aec17607c6cc96 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 1 May 2023 18:14:41 +0200 Subject: [PATCH 17/27] can: at91_can: at91_poll_err(): fold in at91_poll_err_frame() This is a preparation patch for the cleanup of at91_poll_err(). Fold at91_poll_err_frame() into at91_poll_err() so that it can be easier modified. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-17-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 94e9740c80de..2071011ee812 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -751,10 +751,18 @@ static int at91_poll_rx(struct net_device *dev, int quota) return received; } -static void at91_poll_err_frame(struct net_device *dev, - struct can_frame *cf, u32 reg_sr) +static int at91_poll_err(struct net_device *dev, int quota, u32 reg_sr) { struct at91_priv *priv = netdev_priv(dev); + struct sk_buff *skb; + struct can_frame *cf; + + if (quota == 0) + return 0; + + skb = alloc_can_err_skb(dev, &cf); + if (unlikely(!skb)) + return 0; /* CRC error */ if (reg_sr & AT91_IRQ_CERR) { @@ -797,21 +805,6 @@ static void at91_poll_err_frame(struct net_device *dev, cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; cf->data[2] |= CAN_ERR_PROT_BIT; } -} - -static int at91_poll_err(struct net_device *dev, int quota, u32 reg_sr) -{ - struct sk_buff *skb; - struct can_frame *cf; - - if (quota == 0) - return 0; - - skb = alloc_can_err_skb(dev, &cf); - if (unlikely(!skb)) - return 0; - - at91_poll_err_frame(dev, cf, reg_sr); netif_receive_skb(skb); From aa3f5d935cbb302dce89e8f278f6e8a3e2ecea18 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 1 May 2023 18:14:41 +0200 Subject: [PATCH 18/27] can: at91_can: at91_poll_err(): increase stats even if no quota left or OOM at91_poll_err() allocates a can error SKB, to inform the user space about the CAN error. Then it fills the SKB with information the error information and increases the net device error stats. In case no SBK can be allocated (e.g. due to an OOM) or the NAPI quota is 0 the function is left early and no stats are updated. This is not helpful to the user, as there is no information about the faulty CAN bus. Increase the error stats even if no quota is left or no SKB can be allocated. While there treat No-Acknowledgment as a bus error, too. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-18-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 71 ++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 2071011ee812..5b611657b41f 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -753,59 +753,64 @@ static int at91_poll_rx(struct net_device *dev, int quota) static int at91_poll_err(struct net_device *dev, int quota, u32 reg_sr) { + struct net_device_stats *stats = &dev->stats; struct at91_priv *priv = netdev_priv(dev); struct sk_buff *skb; - struct can_frame *cf; + struct can_frame *cf = NULL; - if (quota == 0) - return 0; + priv->can.can_stats.bus_error++; - skb = alloc_can_err_skb(dev, &cf); - if (unlikely(!skb)) - return 0; + if (quota) { + skb = alloc_can_err_skb(dev, &cf); + if (cf) + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + } - /* CRC error */ if (reg_sr & AT91_IRQ_CERR) { - netdev_dbg(dev, "CERR irq\n"); - dev->stats.rx_errors++; - priv->can.can_stats.bus_error++; - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + netdev_dbg(dev, "CRC error\n"); + + stats->rx_errors++; + if (cf) + cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; } - /* Stuffing Error */ if (reg_sr & AT91_IRQ_SERR) { - netdev_dbg(dev, "SERR irq\n"); - dev->stats.rx_errors++; - priv->can.can_stats.bus_error++; - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - cf->data[2] |= CAN_ERR_PROT_STUFF; + netdev_dbg(dev, "Stuff error\n"); + + stats->rx_errors++; + if (cf) + cf->data[2] |= CAN_ERR_PROT_STUFF; } - /* Acknowledgement Error */ if (reg_sr & AT91_IRQ_AERR) { - netdev_dbg(dev, "AERR irq\n"); - dev->stats.tx_errors++; - cf->can_id |= CAN_ERR_ACK; + netdev_dbg(dev, "NACK error\n"); + + stats->tx_errors++; + if (cf) { + cf->can_id |= CAN_ERR_ACK; + cf->data[2] |= CAN_ERR_PROT_TX; + } } - /* Form error */ if (reg_sr & AT91_IRQ_FERR) { - netdev_dbg(dev, "FERR irq\n"); - dev->stats.rx_errors++; - priv->can.can_stats.bus_error++; - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - cf->data[2] |= CAN_ERR_PROT_FORM; + netdev_dbg(dev, "Format error\n"); + + stats->rx_errors++; + if (cf) + cf->data[2] |= CAN_ERR_PROT_FORM; } - /* Bit Error */ if (reg_sr & AT91_IRQ_BERR) { - netdev_dbg(dev, "BERR irq\n"); - dev->stats.tx_errors++; - priv->can.can_stats.bus_error++; - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - cf->data[2] |= CAN_ERR_PROT_BIT; + netdev_dbg(dev, "Bit error\n"); + + stats->tx_errors++; + if (cf) + cf->data[2] |= CAN_ERR_PROT_TX | CAN_ERR_PROT_BIT; } + if (!cf) + return 0; + netif_receive_skb(skb); return 1; From d3f4cf05402b06631f282e23dcba85daed732e38 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 1 May 2023 18:14:41 +0200 Subject: [PATCH 19/27] can: at91_can: at91_irq_err_frame(): call directly from IRQ handler This is a preparation patch to convert the driver to the rx-offload helper. In rx-offload RX, TX-done and CAN error handling are done in the IRQ handler, SKB are pushed to the network stack in the NAPI poll function. Move the CAN frame error handling from the NAPI function at91_poll() to the IRQ handler at91_poll(). To reflect this change, rename at91_poll_err() to at91_irq_err_frame(). Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-19-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 5b611657b41f..a84da1995816 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -155,7 +155,6 @@ struct at91_priv { void __iomem *reg_base; - u32 reg_sr; unsigned int tx_head; unsigned int tx_tail; unsigned int rx_next; @@ -751,7 +750,7 @@ static int at91_poll_rx(struct net_device *dev, int quota) return received; } -static int at91_poll_err(struct net_device *dev, int quota, u32 reg_sr) +static void at91_irq_err_frame(struct net_device *dev, const u32 reg_sr) { struct net_device_stats *stats = &dev->stats; struct at91_priv *priv = netdev_priv(dev); @@ -760,11 +759,9 @@ static int at91_poll_err(struct net_device *dev, int quota, u32 reg_sr) priv->can.can_stats.bus_error++; - if (quota) { - skb = alloc_can_err_skb(dev, &cf); - if (cf) - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - } + skb = alloc_can_err_skb(dev, &cf); + if (cf) + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; if (reg_sr & AT91_IRQ_CERR) { netdev_dbg(dev, "CRC error\n"); @@ -809,11 +806,9 @@ static int at91_poll_err(struct net_device *dev, int quota, u32 reg_sr) } if (!cf) - return 0; + return; netif_receive_skb(skb); - - return 1; } static int at91_poll(struct napi_struct *napi, int quota) @@ -826,13 +821,6 @@ static int at91_poll(struct napi_struct *napi, int quota) if (reg_sr & get_irq_mb_rx(priv)) work_done += at91_poll_rx(dev, quota - work_done); - /* The error bits are clear on read, - * so use saved value from irq handler. - */ - reg_sr |= priv->reg_sr; - if (reg_sr & AT91_IRQ_ERR_FRAME) - work_done += at91_poll_err(dev, quota - work_done, reg_sr); - if (work_done < quota) { /* enable IRQs for frame errors and all mailboxes >= rx_next */ u32 reg_ier = AT91_IRQ_ERR_FRAME; @@ -1092,14 +1080,10 @@ static irqreturn_t at91_irq(int irq, void *dev_id) handled = IRQ_HANDLED; - /* Receive or error interrupt? -> napi */ - if (reg_sr & (get_irq_mb_rx(priv) | AT91_IRQ_ERR_FRAME)) { - /* The error bits are clear on read, - * save for later use. - */ - priv->reg_sr = reg_sr; + /* Receive interrupt? -> napi */ + if (reg_sr & get_irq_mb_rx(priv)) { at91_write(priv, AT91_IDR, - get_irq_mb_rx(priv) | AT91_IRQ_ERR_FRAME); + get_irq_mb_rx(priv)); napi_schedule(&priv->napi); } @@ -1109,6 +1093,10 @@ static irqreturn_t at91_irq(int irq, void *dev_id) at91_irq_err(dev); + /* Frame Error Interrupt */ + if (reg_sr & AT91_IRQ_ERR_FRAME) + at91_irq_err_frame(dev, reg_sr); + exit: return handled; } From e0c9db91d60ba44705a7f333cbed2be8b32b293c Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 28 Sep 2023 11:15:15 +0200 Subject: [PATCH 20/27] can: at91_can: at91_irq_err_frame(): move next to at91_irq_err() This is a cleanup patch, no functional change intended. As at91_irq_err_frame() is called from the IRQ handler move it in front of the IRQ handler next to at91_irq_err(). Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-20-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 122 ++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index a84da1995816..6b017fd695c0 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -750,67 +750,6 @@ static int at91_poll_rx(struct net_device *dev, int quota) return received; } -static void at91_irq_err_frame(struct net_device *dev, const u32 reg_sr) -{ - struct net_device_stats *stats = &dev->stats; - struct at91_priv *priv = netdev_priv(dev); - struct sk_buff *skb; - struct can_frame *cf = NULL; - - priv->can.can_stats.bus_error++; - - skb = alloc_can_err_skb(dev, &cf); - if (cf) - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - - if (reg_sr & AT91_IRQ_CERR) { - netdev_dbg(dev, "CRC error\n"); - - stats->rx_errors++; - if (cf) - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; - } - - if (reg_sr & AT91_IRQ_SERR) { - netdev_dbg(dev, "Stuff error\n"); - - stats->rx_errors++; - if (cf) - cf->data[2] |= CAN_ERR_PROT_STUFF; - } - - if (reg_sr & AT91_IRQ_AERR) { - netdev_dbg(dev, "NACK error\n"); - - stats->tx_errors++; - if (cf) { - cf->can_id |= CAN_ERR_ACK; - cf->data[2] |= CAN_ERR_PROT_TX; - } - } - - if (reg_sr & AT91_IRQ_FERR) { - netdev_dbg(dev, "Format error\n"); - - stats->rx_errors++; - if (cf) - cf->data[2] |= CAN_ERR_PROT_FORM; - } - - if (reg_sr & AT91_IRQ_BERR) { - netdev_dbg(dev, "Bit error\n"); - - stats->tx_errors++; - if (cf) - cf->data[2] |= CAN_ERR_PROT_TX | CAN_ERR_PROT_BIT; - } - - if (!cf) - return; - - netif_receive_skb(skb); -} - static int at91_poll(struct napi_struct *napi, int quota) { struct net_device *dev = napi->dev; @@ -1061,6 +1000,67 @@ static void at91_irq_err(struct net_device *dev) priv->can.state = new_state; } +static void at91_irq_err_frame(struct net_device *dev, const u32 reg_sr) +{ + struct net_device_stats *stats = &dev->stats; + struct at91_priv *priv = netdev_priv(dev); + struct sk_buff *skb; + struct can_frame *cf = NULL; + + priv->can.can_stats.bus_error++; + + skb = alloc_can_err_skb(dev, &cf); + if (cf) + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + + if (reg_sr & AT91_IRQ_CERR) { + netdev_dbg(dev, "CRC error\n"); + + stats->rx_errors++; + if (cf) + cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; + } + + if (reg_sr & AT91_IRQ_SERR) { + netdev_dbg(dev, "Stuff error\n"); + + stats->rx_errors++; + if (cf) + cf->data[2] |= CAN_ERR_PROT_STUFF; + } + + if (reg_sr & AT91_IRQ_AERR) { + netdev_dbg(dev, "NACK error\n"); + + stats->tx_errors++; + if (cf) { + cf->can_id |= CAN_ERR_ACK; + cf->data[2] |= CAN_ERR_PROT_TX; + } + } + + if (reg_sr & AT91_IRQ_FERR) { + netdev_dbg(dev, "Format error\n"); + + stats->rx_errors++; + if (cf) + cf->data[2] |= CAN_ERR_PROT_FORM; + } + + if (reg_sr & AT91_IRQ_BERR) { + netdev_dbg(dev, "Bit error\n"); + + stats->tx_errors++; + if (cf) + cf->data[2] |= CAN_ERR_PROT_TX | CAN_ERR_PROT_BIT; + } + + if (!cf) + return; + + netif_receive_skb(skb); +} + /* interrupt handler */ static irqreturn_t at91_irq(int irq, void *dev_id) From efad777c3e97472fbd6aa4e5db11dcb3ef3eae90 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 1 May 2023 18:14:41 +0200 Subject: [PATCH 21/27] can: at91_can: at91_irq_err(): rename to at91_irq_err_line() This is a cleanup patch, no functional change intended. The function at91_irq_err() only handles the CAN line errors, so rename it accordingly to at91_irq_err_line(). Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-21-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 6b017fd695c0..4249a1c95769 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -954,7 +954,7 @@ static int at91_get_state_by_bec(const struct net_device *dev, return 0; } -static void at91_irq_err(struct net_device *dev) +static void at91_irq_err_line(struct net_device *dev) { struct at91_priv *priv = netdev_priv(dev); struct sk_buff *skb; @@ -1091,7 +1091,7 @@ static irqreturn_t at91_irq(int irq, void *dev_id) if (reg_sr & get_irq_mb_tx(priv)) at91_irq_tx(dev, reg_sr); - at91_irq_err(dev); + at91_irq_err_line(dev); /* Frame Error Interrupt */ if (reg_sr & AT91_IRQ_ERR_FRAME) From 910f179aa0de17bab654291548aec378f74db293 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 1 May 2023 18:14:41 +0200 Subject: [PATCH 22/27] can: at91_can: at91_irq_err_line(): make use of can_state_get_by_berr_counter() On the sam9263 the SR bits for bus off, error passive, warning limit, and error active are not latched and reflect the current status of the controller. On the sam9x5 and newer SoCs these bits are latched. To simplify the code, use can_state_get_by_berr_counter() to get the state of the controller regardless of the SoC version. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-22-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 51 ++++---------------------------------- 1 file changed, 5 insertions(+), 46 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 4249a1c95769..68b611d0fa6c 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -932,58 +932,17 @@ static void at91_irq_err_state(struct net_device *dev, at91_write(priv, AT91_IER, reg_ier); } -static int at91_get_state_by_bec(const struct net_device *dev, - enum can_state *state) -{ - struct can_berr_counter bec; - int err; - - err = at91_get_berr_counter(dev, &bec); - if (err) - return err; - - if (bec.txerr < 96 && bec.rxerr < 96) - *state = CAN_STATE_ERROR_ACTIVE; - else if (bec.txerr < 128 && bec.rxerr < 128) - *state = CAN_STATE_ERROR_WARNING; - else if (bec.txerr < 256 && bec.rxerr < 256) - *state = CAN_STATE_ERROR_PASSIVE; - else - *state = CAN_STATE_BUS_OFF; - - return 0; -} - static void at91_irq_err_line(struct net_device *dev) { + enum can_state new_state, rx_state, tx_state; struct at91_priv *priv = netdev_priv(dev); + struct can_berr_counter bec; struct sk_buff *skb; struct can_frame *cf; - enum can_state new_state; - u32 reg_sr; - int err; - if (at91_is_sam9263(priv)) { - reg_sr = at91_read(priv, AT91_SR); - - /* we need to look at the unmasked reg_sr */ - if (unlikely(reg_sr & AT91_IRQ_BOFF)) { - new_state = CAN_STATE_BUS_OFF; - } else if (unlikely(reg_sr & AT91_IRQ_ERRP)) { - new_state = CAN_STATE_ERROR_PASSIVE; - } else if (unlikely(reg_sr & AT91_IRQ_WARN)) { - new_state = CAN_STATE_ERROR_WARNING; - } else if (likely(reg_sr & AT91_IRQ_ERRA)) { - new_state = CAN_STATE_ERROR_ACTIVE; - } else { - netdev_err(dev, "BUG! hardware in undefined state\n"); - return; - } - } else { - err = at91_get_state_by_bec(dev, &new_state); - if (err) - return; - } + at91_get_berr_counter(dev, &bec); + can_state_get_by_berr_counter(dev, &bec, &tx_state, &rx_state); + new_state = max(tx_state, rx_state); /* state hasn't changed */ if (likely(new_state == priv->can.state)) From f13e86993d85ac98b12159ca9e31dc0357e5a926 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 1 May 2023 18:14:41 +0200 Subject: [PATCH 23/27] can: at91_can: at91_irq_err_line(): take reg_sr into account for bus off The at91 CAN controller automatically recovers from bus-off after 128 occurrences of 11 consecutive recessive bits. After an auto-recovered bus-off, the error counters no longer reflect this fact. On the sam9263 the state bits in the SR register show the current state (based on the current error counters), while on sam9x5 and newer SoCs these bits are latched. Take any latched bus-off information from the SR register into account when calculating the CAN new state, to start the standard CAN bus off handling. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-23-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 68b611d0fa6c..fbe58a1a1989 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -437,6 +437,11 @@ static void at91_chip_start(struct net_device *dev) priv->can.state = CAN_STATE_ERROR_ACTIVE; + /* Dummy read to clear latched line error interrupts on + * sam9x5 and newer SoCs. + */ + at91_read(priv, AT91_SR); + /* Enable interrupts */ reg_ier = get_irq_mb_rx(priv) | AT91_IRQ_ERRP | AT91_IRQ_ERR_FRAME; at91_write(priv, AT91_IER, reg_ier); @@ -932,7 +937,7 @@ static void at91_irq_err_state(struct net_device *dev, at91_write(priv, AT91_IER, reg_ier); } -static void at91_irq_err_line(struct net_device *dev) +static void at91_irq_err_line(struct net_device *dev, const u32 reg_sr) { enum can_state new_state, rx_state, tx_state; struct at91_priv *priv = netdev_priv(dev); @@ -942,6 +947,23 @@ static void at91_irq_err_line(struct net_device *dev) at91_get_berr_counter(dev, &bec); can_state_get_by_berr_counter(dev, &bec, &tx_state, &rx_state); + + /* The chip automatically recovers from bus-off after 128 + * occurrences of 11 consecutive recessive bits. + * + * After an auto-recovered bus-off, the error counters no + * longer reflect this fact. On the sam9263 the state bits in + * the SR register show the current state (based on the + * current error counters), while on sam9x5 and newer SoCs + * these bits are latched. + * + * Take any latched bus-off information from the SR register + * into account when calculating the CAN new state, to start + * the standard CAN bus off handling. + */ + if (reg_sr & AT91_IRQ_BOFF) + rx_state = CAN_STATE_BUS_OFF; + new_state = max(tx_state, rx_state); /* state hasn't changed */ @@ -1050,7 +1072,7 @@ static irqreturn_t at91_irq(int irq, void *dev_id) if (reg_sr & get_irq_mb_tx(priv)) at91_irq_tx(dev, reg_sr); - at91_irq_err_line(dev); + at91_irq_err_line(dev, reg_sr); /* Frame Error Interrupt */ if (reg_sr & AT91_IRQ_ERR_FRAME) From 9df2faf947bc4e7a48dbd7768ccb95337bb12c44 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 1 May 2023 18:14:41 +0200 Subject: [PATCH 24/27] can: at91_can: at91_irq_err_line(): make use of can_change_state() and can_bus_off() The driver implements a hand crafted CAN state handling. Update the driver to make use of can_change_state(), introduced in ("can: dev: Consolidate and unify state change handling") Also switch from hand crafted CAN bus off handling to can_bus_off(): In case of a bus off, abort all pending TX requests, switch off the device and let can_bus_off() handle the device restart. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-24-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 131 ++++++------------------------------- 1 file changed, 21 insertions(+), 110 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index fbe58a1a1989..a413589109b2 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -443,7 +443,7 @@ static void at91_chip_start(struct net_device *dev) at91_read(priv, AT91_SR); /* Enable interrupts */ - reg_ier = get_irq_mb_rx(priv) | AT91_IRQ_ERRP | AT91_IRQ_ERR_FRAME; + reg_ier = get_irq_mb_rx(priv) | AT91_IRQ_ERR_LINE | AT91_IRQ_ERR_FRAME; at91_write(priv, AT91_IER, reg_ier); } @@ -452,6 +452,11 @@ static void at91_chip_stop(struct net_device *dev, enum can_state state) struct at91_priv *priv = netdev_priv(dev); u32 reg_mr; + /* Abort any pending TX requests. However this doesn't seem to + * work in case of bus-off on sama5d3. + */ + at91_write(priv, AT91_ACR, get_irq_mb_tx(priv)); + /* disable interrupts */ at91_write(priv, AT91_IDR, AT91_IRQ_ALL); @@ -832,111 +837,6 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) netif_wake_queue(dev); } -static void at91_irq_err_state(struct net_device *dev, - struct can_frame *cf, enum can_state new_state) -{ - struct at91_priv *priv = netdev_priv(dev); - u32 reg_idr = 0, reg_ier = 0; - struct can_berr_counter bec; - - at91_get_berr_counter(dev, &bec); - - switch (priv->can.state) { - case CAN_STATE_ERROR_ACTIVE: - /* from: ERROR_ACTIVE - * to : ERROR_WARNING, ERROR_PASSIVE, BUS_OFF - * => : there was a warning int - */ - if (new_state >= CAN_STATE_ERROR_WARNING && - new_state <= CAN_STATE_BUS_OFF) { - netdev_dbg(dev, "Error Warning IRQ\n"); - priv->can.can_stats.error_warning++; - - cf->can_id |= CAN_ERR_CRTL; - cf->data[1] = (bec.txerr > bec.rxerr) ? - CAN_ERR_CRTL_TX_WARNING : - CAN_ERR_CRTL_RX_WARNING; - } - fallthrough; - case CAN_STATE_ERROR_WARNING: - /* from: ERROR_ACTIVE, ERROR_WARNING - * to : ERROR_PASSIVE, BUS_OFF - * => : error passive int - */ - if (new_state >= CAN_STATE_ERROR_PASSIVE && - new_state <= CAN_STATE_BUS_OFF) { - netdev_dbg(dev, "Error Passive IRQ\n"); - priv->can.can_stats.error_passive++; - - cf->can_id |= CAN_ERR_CRTL; - cf->data[1] = (bec.txerr > bec.rxerr) ? - CAN_ERR_CRTL_TX_PASSIVE : - CAN_ERR_CRTL_RX_PASSIVE; - } - break; - case CAN_STATE_BUS_OFF: - /* from: BUS_OFF - * to : ERROR_ACTIVE, ERROR_WARNING, ERROR_PASSIVE - */ - if (new_state <= CAN_STATE_ERROR_PASSIVE) { - cf->can_id |= CAN_ERR_RESTARTED; - - netdev_dbg(dev, "restarted\n"); - priv->can.can_stats.restarts++; - - netif_carrier_on(dev); - netif_wake_queue(dev); - } - break; - default: - break; - } - - /* process state changes depending on the new state */ - switch (new_state) { - case CAN_STATE_ERROR_ACTIVE: - /* actually we want to enable AT91_IRQ_WARN here, but - * it screws up the system under certain - * circumstances. so just enable AT91_IRQ_ERRP, thus - * the "fallthrough" - */ - netdev_dbg(dev, "Error Active\n"); - cf->can_id |= CAN_ERR_PROT; - cf->data[2] = CAN_ERR_PROT_ACTIVE; - fallthrough; - case CAN_STATE_ERROR_WARNING: - reg_idr = AT91_IRQ_ERRA | AT91_IRQ_WARN | AT91_IRQ_BOFF; - reg_ier = AT91_IRQ_ERRP; - break; - case CAN_STATE_ERROR_PASSIVE: - reg_idr = AT91_IRQ_ERRA | AT91_IRQ_WARN | AT91_IRQ_ERRP; - reg_ier = AT91_IRQ_BOFF; - break; - case CAN_STATE_BUS_OFF: - reg_idr = AT91_IRQ_ERRA | AT91_IRQ_ERRP | - AT91_IRQ_WARN | AT91_IRQ_BOFF; - reg_ier = 0; - - cf->can_id |= CAN_ERR_BUSOFF; - - netdev_dbg(dev, "bus-off\n"); - netif_carrier_off(dev); - priv->can.can_stats.bus_off++; - - /* turn off chip, if restart is disabled */ - if (!priv->can.restart_ms) { - at91_chip_stop(dev, CAN_STATE_BUS_OFF); - return; - } - break; - default: - break; - } - - at91_write(priv, AT91_IDR, reg_idr); - at91_write(priv, AT91_IER, reg_ier); -} - static void at91_irq_err_line(struct net_device *dev, const u32 reg_sr) { enum can_state new_state, rx_state, tx_state; @@ -970,15 +870,22 @@ static void at91_irq_err_line(struct net_device *dev, const u32 reg_sr) if (likely(new_state == priv->can.state)) return; + /* The skb allocation might fail, but can_change_state() + * handles cf == NULL. + */ skb = alloc_can_err_skb(dev, &cf); + can_change_state(dev, cf, tx_state, rx_state); + + if (new_state == CAN_STATE_BUS_OFF) { + at91_chip_stop(dev, CAN_STATE_BUS_OFF); + can_bus_off(dev); + } + if (unlikely(!skb)) return; - at91_irq_err_state(dev, cf, new_state); netif_rx(skb); - - priv->can.state = new_state; } static void at91_irq_err_frame(struct net_device *dev, const u32 reg_sr) @@ -1072,7 +979,11 @@ static irqreturn_t at91_irq(int irq, void *dev_id) if (reg_sr & get_irq_mb_tx(priv)) at91_irq_tx(dev, reg_sr); - at91_irq_err_line(dev, reg_sr); + /* Line Error interrupt */ + if (reg_sr & AT91_IRQ_ERR_LINE || + priv->can.state > CAN_STATE_ERROR_ACTIVE) { + at91_irq_err_line(dev, reg_sr); + } /* Frame Error Interrupt */ if (reg_sr & AT91_IRQ_ERR_FRAME) From 3db6154e44dba8626cd6e31e15bd29d1c3861ca8 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 28 Sep 2023 10:05:17 +0200 Subject: [PATCH 25/27] can: at91_can: at91_irq_err_line(): send error counters with state change Since 3e5c291c7942 ("can: add CAN_ERR_CNT flag to notify availability of error counter") there is a dedicated flag to inform the user space, that there are CAN error counters in the CAN error frame. In case the device is not in bus off mode, send the error counters to user space and set CAN_ERR_CNT. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-25-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index a413589109b2..d5e1d1b2cdd1 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -884,6 +884,11 @@ static void at91_irq_err_line(struct net_device *dev, const u32 reg_sr) if (unlikely(!skb)) return; + if (new_state != CAN_STATE_BUS_OFF) { + cf->can_id |= CAN_ERR_CNT; + cf->data[6] = bec.txerr; + cf->data[7] = bec.rxerr; + } netif_rx(skb); } From dd94a2f1f2f848a2534c4b0115db752a55b7eb03 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 28 Sep 2023 11:15:15 +0200 Subject: [PATCH 26/27] can: at91_can: at91_alloc_can_err_skb() introduce new function This is a preparation patch to convert the driver to make use of the rx-offload helper. With rx-offload the received CAN frames are sorted by their timestamp. Regular CAN RX'ed and TX'ed CAN frames are timestamped by the hardware. Error events are not. Introduce a new function at91_alloc_can_err_skb() the allocates an error SKB and reads the current timestamp from the controller. Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-26-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index d5e1d1b2cdd1..ca62aa027e5f 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -576,6 +576,22 @@ static inline void at91_activate_rx_mb(const struct at91_priv *priv, at91_write(priv, AT91_TCR, mask); } +static inline u32 at91_get_timestamp(const struct at91_priv *priv) +{ + return at91_read(priv, AT91_TIM); +} + +static inline struct sk_buff * +at91_alloc_can_err_skb(struct net_device *dev, + struct can_frame **cf, u32 *timestamp) +{ + const struct at91_priv *priv = netdev_priv(dev); + + *timestamp = at91_get_timestamp(priv); + + return alloc_can_err_skb(dev, cf); +} + /** * at91_rx_overflow_err - send error frame due to rx overflow * @dev: net device From 137f59d5dab4bd55ab3d40080de18bf641bdc26a Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Sun, 10 May 2015 17:25:14 +0200 Subject: [PATCH 27/27] can: at91_can: switch to rx-offload implementation The current at91_can driver uses NAPI to handle RX'ed CAN frames, the RX IRQ is disabled and a NAPI poll is scheduled. Then in at91_poll_rx() the RX'ed CAN frames are tried to read in order from the device. This approach has 2 drawbacks: - Under high system load it might take too long from the initial RX IRQ to the NAPI poll function to run. This causes RX buffer overflows. - The algorithm to read the CAN frames in order is not bullet proof and may fail under certain use cases/system loads. The rx-offload helper fixes these problems by reading the RX'ed CAN frames in the interrupt handler and adding it to a list sorted by RX timestamp. This list of RX'ed SKBs is then passed to the networking stack via NAPI. Convert the RX path to rx-offload, pass all CAN error frames with can_rx_offload_queue_timestamp(). Link: https://lore.kernel.org/all/20231005-at91_can-rx_offload-v2-27-9987d53600e0@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/Kconfig | 1 + drivers/net/can/at91_can.c | 340 +++++++++++-------------------------- 2 files changed, 100 insertions(+), 241 deletions(-) diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 649453a3c858..8d6fc0852bf7 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -89,6 +89,7 @@ config CAN_RX_OFFLOAD config CAN_AT91 tristate "Atmel AT91 onchip CAN controller" depends on (ARCH_AT91 || COMPILE_TEST) && HAS_IOMEM + select CAN_RX_OFFLOAD help This is a driver for the SoC CAN controller in Atmel's AT91SAM9263 and AT91SAM9X5 processors. diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index ca62aa027e5f..11f434d708b3 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -3,7 +3,7 @@ * at91_can.c - CAN network driver for AT91 SoC CAN controller * * (C) 2007 by Hans J. Koch - * (C) 2008, 2009, 2010, 2011 by Marc Kleine-Budde + * (C) 2008, 2009, 2010, 2011, 2023 by Marc Kleine-Budde */ #include @@ -26,6 +26,7 @@ #include #include +#include #define AT91_MB_MASK(i) ((1 << (i)) - 1) @@ -142,7 +143,6 @@ enum at91_devtype { struct at91_devtype_data { unsigned int rx_first; - unsigned int rx_split; unsigned int rx_last; unsigned int tx_shift; enum at91_devtype type; @@ -150,14 +150,13 @@ struct at91_devtype_data { struct at91_priv { struct can_priv can; /* must be the first member! */ - struct napi_struct napi; + struct can_rx_offload offload; struct phy *transceiver; void __iomem *reg_base; unsigned int tx_head; unsigned int tx_tail; - unsigned int rx_next; struct at91_devtype_data devtype_data; struct clk *clk; @@ -166,9 +165,13 @@ struct at91_priv { canid_t mb0_id; }; +static inline struct at91_priv *rx_offload_to_priv(struct can_rx_offload *offload) +{ + return container_of(offload, struct at91_priv, offload); +} + static const struct at91_devtype_data at91_at91sam9263_data = { .rx_first = 1, - .rx_split = 8, .rx_last = 11, .tx_shift = 2, .type = AT91_DEVTYPE_SAM9263, @@ -176,7 +179,6 @@ static const struct at91_devtype_data at91_at91sam9263_data = { static const struct at91_devtype_data at91_at91sam9x5_data = { .rx_first = 0, - .rx_split = 4, .rx_last = 5, .tx_shift = 1, .type = AT91_DEVTYPE_SAM9X5, @@ -213,27 +215,6 @@ static inline unsigned int get_mb_rx_last(const struct at91_priv *priv) return priv->devtype_data.rx_last; } -static inline unsigned int get_mb_rx_split(const struct at91_priv *priv) -{ - return priv->devtype_data.rx_split; -} - -static inline unsigned int get_mb_rx_num(const struct at91_priv *priv) -{ - return get_mb_rx_last(priv) - get_mb_rx_first(priv) + 1; -} - -static inline unsigned int get_mb_rx_low_last(const struct at91_priv *priv) -{ - return get_mb_rx_split(priv) - 1; -} - -static inline unsigned int get_mb_rx_low_mask(const struct at91_priv *priv) -{ - return AT91_MB_MASK(get_mb_rx_split(priv)) & - ~AT91_MB_MASK(get_mb_rx_first(priv)); -} - static inline unsigned int get_mb_tx_shift(const struct at91_priv *priv) { return priv->devtype_data.tx_shift; @@ -374,9 +355,8 @@ static void at91_setup_mailboxes(struct net_device *dev) for (i = get_mb_tx_first(priv); i <= get_mb_tx_last(priv); i++) set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0); - /* Reset tx and rx helper pointers */ + /* Reset tx helper pointers */ priv->tx_head = priv->tx_tail = 0; - priv->rx_next = get_mb_rx_first(priv); } static int at91_set_bittiming(struct net_device *dev) @@ -548,34 +528,6 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -/** - * at91_activate_rx_low - activate lower rx mailboxes - * @priv: a91 context - * - * Reenables the lower mailboxes for reception of new CAN messages - */ -static inline void at91_activate_rx_low(const struct at91_priv *priv) -{ - u32 mask = get_mb_rx_low_mask(priv); - - at91_write(priv, AT91_TCR, mask); -} - -/** - * at91_activate_rx_mb - reactive single rx mailbox - * @priv: a91 context - * @mb: mailbox to reactivate - * - * Reenables given mailbox for reception of new CAN messages - */ -static inline void at91_activate_rx_mb(const struct at91_priv *priv, - unsigned int mb) -{ - u32 mask = 1 << mb; - - at91_write(priv, AT91_TCR, mask); -} - static inline u32 at91_get_timestamp(const struct at91_priv *priv) { return at91_read(priv, AT91_TIM); @@ -600,37 +552,60 @@ static void at91_rx_overflow_err(struct net_device *dev) { struct net_device_stats *stats = &dev->stats; struct sk_buff *skb; + struct at91_priv *priv = netdev_priv(dev); struct can_frame *cf; + u32 timestamp; + int err; netdev_dbg(dev, "RX buffer overflow\n"); stats->rx_over_errors++; stats->rx_errors++; - skb = alloc_can_err_skb(dev, &cf); + skb = at91_alloc_can_err_skb(dev, &cf, ×tamp); if (unlikely(!skb)) return; cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; - netif_receive_skb(skb); + err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp); + if (err) + stats->rx_fifo_errors++; } /** - * at91_read_mb - read CAN msg from mailbox (lowlevel impl) - * @dev: net device + * at91_mailbox_read - read CAN msg from mailbox + * @offload: rx-offload * @mb: mailbox number to read from - * @cf: can frame where to store message + * @timestamp: pointer to 32 bit timestamp + * @drop: true indicated mailbox to mark as read and drop frame * - * Reads a CAN message from the given mailbox and stores data into - * given can frame. "mb" and "cf" must be valid. + * Reads a CAN message from the given mailbox if not empty. */ -static void at91_read_mb(struct net_device *dev, unsigned int mb, - struct can_frame *cf) +static struct sk_buff *at91_mailbox_read(struct can_rx_offload *offload, + unsigned int mb, u32 *timestamp, + bool drop) { - const struct at91_priv *priv = netdev_priv(dev); + const struct at91_priv *priv = rx_offload_to_priv(offload); + struct can_frame *cf; + struct sk_buff *skb; u32 reg_msr, reg_mid; + reg_msr = at91_read(priv, AT91_MSR(mb)); + if (!(reg_msr & AT91_MSR_MRDY)) + return NULL; + + if (unlikely(drop)) { + skb = ERR_PTR(-ENOBUFS); + goto mark_as_read; + } + + skb = alloc_can_skb(offload->dev, &cf); + if (unlikely(!skb)) { + skb = ERR_PTR(-ENOMEM); + goto mark_as_read; + } + reg_mid = at91_read(priv, AT91_MID(mb)); if (reg_mid & AT91_MID_MIDE) cf->can_id = FIELD_GET(AT91_MID_MIDVA_MASK | AT91_MID_MIDVB_MASK, reg_mid) | @@ -638,7 +613,9 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb, else cf->can_id = FIELD_GET(AT91_MID_MIDVA_MASK, reg_mid); - reg_msr = at91_read(priv, AT91_MSR(mb)); + /* extend timestamp to full 32 bit */ + *timestamp = FIELD_GET(AT91_MSR_MTIMESTAMP_MASK, reg_msr) << 16; + cf->len = can_cc_dlc2len(FIELD_GET(AT91_MSR_MDLC_MASK, reg_msr)); if (reg_msr & AT91_MSR_MRTR) { @@ -652,151 +629,12 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb, at91_write(priv, AT91_MID(mb), AT91_MID_MIDE); if (unlikely(mb == get_mb_rx_last(priv) && reg_msr & AT91_MSR_MMI)) - at91_rx_overflow_err(dev); -} + at91_rx_overflow_err(offload->dev); -/** - * at91_read_msg - read CAN message from mailbox - * @dev: net device - * @mb: mail box to read from - * - * Reads a CAN message from given mailbox, and put into linux network - * RX queue, does all housekeeping chores (stats, ...) - */ -static void at91_read_msg(struct net_device *dev, unsigned int mb) -{ - struct net_device_stats *stats = &dev->stats; - struct can_frame *cf; - struct sk_buff *skb; + mark_as_read: + at91_write(priv, AT91_MCR(mb), AT91_MCR_MTCR); - skb = alloc_can_skb(dev, &cf); - if (unlikely(!skb)) { - stats->rx_dropped++; - return; - } - - at91_read_mb(dev, mb, cf); - - stats->rx_packets++; - if (!(cf->can_id & CAN_RTR_FLAG)) - stats->rx_bytes += cf->len; - - netif_receive_skb(skb); -} - -/** - * at91_poll_rx - read multiple CAN messages from mailboxes - * @dev: net device - * @quota: max number of pkgs we're allowed to receive - * - * Theory of Operation: - * - * About 3/4 of the mailboxes (get_mb_rx_first()...get_mb_rx_last()) - * on the chip are reserved for RX. We split them into 2 groups. The - * lower group ranges from get_mb_rx_first() to get_mb_rx_low_last(). - * - * Like it or not, but the chip always saves a received CAN message - * into the first free mailbox it finds (starting with the - * lowest). This makes it very difficult to read the messages in the - * right order from the chip. This is how we work around that problem: - * - * The first message goes into mb nr. 1 and issues an interrupt. All - * rx ints are disabled in the interrupt handler and a napi poll is - * scheduled. We read the mailbox, but do _not_ re-enable the mb (to - * receive another message). - * - * lower mbxs upper - * ____^______ __^__ - * / \ / \ - * +-+-+-+-+-+-+-+-++-+-+-+-+ - * | |x|x|x|x|x|x|x|| | | | | - * +-+-+-+-+-+-+-+-++-+-+-+-+ - * 0 0 0 0 0 0 0 0 0 0 1 1 \ mail - * 0 1 2 3 4 5 6 7 8 9 0 1 / box - * ^ - * | - * \ - * unused, due to chip bug - * - * The variable priv->rx_next points to the next mailbox to read a - * message from. As long we're in the lower mailboxes we just read the - * mailbox but not re-enable it. - * - * With completion of the last of the lower mailboxes, we re-enable the - * whole first group, but continue to look for filled mailboxes in the - * upper mailboxes. Imagine the second group like overflow mailboxes, - * which takes CAN messages if the lower goup is full. While in the - * upper group we re-enable the mailbox right after reading it. Giving - * the chip more room to store messages. - * - * After finishing we look again in the lower group if we've still - * quota. - * - */ -static int at91_poll_rx(struct net_device *dev, int quota) -{ - struct at91_priv *priv = netdev_priv(dev); - u32 reg_sr = at91_read(priv, AT91_SR); - const unsigned long *addr = (unsigned long *)®_sr; - unsigned int mb; - int received = 0; - - if (priv->rx_next > get_mb_rx_low_last(priv) && - reg_sr & get_mb_rx_low_mask(priv)) - netdev_info(dev, - "order of incoming frames cannot be guaranteed\n"); - - again: - for (mb = find_next_bit(addr, get_mb_tx_first(priv), priv->rx_next); - mb < get_mb_tx_first(priv) && quota > 0; - reg_sr = at91_read(priv, AT91_SR), - mb = find_next_bit(addr, get_mb_tx_first(priv), ++priv->rx_next)) { - at91_read_msg(dev, mb); - - /* reactivate mailboxes */ - if (mb == get_mb_rx_low_last(priv)) - /* all lower mailboxed, if just finished it */ - at91_activate_rx_low(priv); - else if (mb > get_mb_rx_low_last(priv)) - /* only the mailbox we read */ - at91_activate_rx_mb(priv, mb); - - received++; - quota--; - } - - /* upper group completed, look again in lower */ - if (priv->rx_next > get_mb_rx_low_last(priv) && - mb > get_mb_rx_last(priv)) { - priv->rx_next = get_mb_rx_first(priv); - if (quota > 0) - goto again; - } - - return received; -} - -static int at91_poll(struct napi_struct *napi, int quota) -{ - struct net_device *dev = napi->dev; - const struct at91_priv *priv = netdev_priv(dev); - u32 reg_sr = at91_read(priv, AT91_SR); - int work_done = 0; - - if (reg_sr & get_irq_mb_rx(priv)) - work_done += at91_poll_rx(dev, quota - work_done); - - if (work_done < quota) { - /* enable IRQs for frame errors and all mailboxes >= rx_next */ - u32 reg_ier = AT91_IRQ_ERR_FRAME; - - reg_ier |= get_irq_mb_rx(priv) & ~AT91_MB_MASK(priv->rx_next); - - napi_complete_done(napi, work_done); - at91_write(priv, AT91_IER, reg_ier); - } - - return work_done; + return skb; } /* theory of operation: @@ -816,8 +654,6 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) u32 reg_msr; unsigned int mb; - /* masking of reg_sr not needed, already done by at91_irq */ - for (/* nix */; (priv->tx_head - priv->tx_tail) > 0; priv->tx_tail++) { mb = get_tx_tail_mb(priv); @@ -855,11 +691,14 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) static void at91_irq_err_line(struct net_device *dev, const u32 reg_sr) { + struct net_device_stats *stats = &dev->stats; enum can_state new_state, rx_state, tx_state; struct at91_priv *priv = netdev_priv(dev); struct can_berr_counter bec; struct sk_buff *skb; struct can_frame *cf; + u32 timestamp; + int err; at91_get_berr_counter(dev, &bec); can_state_get_by_berr_counter(dev, &bec, &tx_state, &rx_state); @@ -889,7 +728,7 @@ static void at91_irq_err_line(struct net_device *dev, const u32 reg_sr) /* The skb allocation might fail, but can_change_state() * handles cf == NULL. */ - skb = alloc_can_err_skb(dev, &cf); + skb = at91_alloc_can_err_skb(dev, &cf, ×tamp); can_change_state(dev, cf, tx_state, rx_state); if (new_state == CAN_STATE_BUS_OFF) { @@ -906,19 +745,23 @@ static void at91_irq_err_line(struct net_device *dev, const u32 reg_sr) cf->data[7] = bec.rxerr; } - netif_rx(skb); + err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp); + if (err) + stats->rx_fifo_errors++; } static void at91_irq_err_frame(struct net_device *dev, const u32 reg_sr) { struct net_device_stats *stats = &dev->stats; struct at91_priv *priv = netdev_priv(dev); + struct can_frame *cf; struct sk_buff *skb; - struct can_frame *cf = NULL; + u32 timestamp; + int err; priv->can.can_stats.bus_error++; - skb = alloc_can_err_skb(dev, &cf); + skb = at91_alloc_can_err_skb(dev, &cf, ×tamp); if (cf) cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; @@ -967,50 +810,62 @@ static void at91_irq_err_frame(struct net_device *dev, const u32 reg_sr) if (!cf) return; - netif_receive_skb(skb); + err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp); + if (err) + stats->rx_fifo_errors++; +} + +static u32 at91_get_reg_sr_rx(const struct at91_priv *priv, u32 *reg_sr_p) +{ + const u32 reg_sr = at91_read(priv, AT91_SR); + + *reg_sr_p |= reg_sr; + + return reg_sr & get_irq_mb_rx(priv); } -/* interrupt handler - */ static irqreturn_t at91_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; struct at91_priv *priv = netdev_priv(dev); irqreturn_t handled = IRQ_NONE; - u32 reg_sr, reg_imr; + u32 reg_sr = 0, reg_sr_rx; + int ret; - reg_sr = at91_read(priv, AT91_SR); - reg_imr = at91_read(priv, AT91_IMR); + /* Receive interrupt + * Some bits of AT91_SR are cleared on read, keep them in reg_sr. + */ + while ((reg_sr_rx = at91_get_reg_sr_rx(priv, ®_sr))) { + ret = can_rx_offload_irq_offload_timestamp(&priv->offload, + reg_sr_rx); + handled = IRQ_HANDLED; - /* Ignore masked interrupts */ - reg_sr &= reg_imr; - if (!reg_sr) - goto exit; - - handled = IRQ_HANDLED; - - /* Receive interrupt? -> napi */ - if (reg_sr & get_irq_mb_rx(priv)) { - at91_write(priv, AT91_IDR, - get_irq_mb_rx(priv)); - napi_schedule(&priv->napi); + if (!ret) + break; } /* Transmission complete interrupt */ - if (reg_sr & get_irq_mb_tx(priv)) + if (reg_sr & get_irq_mb_tx(priv)) { at91_irq_tx(dev, reg_sr); + handled = IRQ_HANDLED; + } /* Line Error interrupt */ if (reg_sr & AT91_IRQ_ERR_LINE || priv->can.state > CAN_STATE_ERROR_ACTIVE) { at91_irq_err_line(dev, reg_sr); + handled = IRQ_HANDLED; } /* Frame Error Interrupt */ - if (reg_sr & AT91_IRQ_ERR_FRAME) + if (reg_sr & AT91_IRQ_ERR_FRAME) { at91_irq_err_frame(dev, reg_sr); + handled = IRQ_HANDLED; + } + + if (handled) + can_rx_offload_irq_finish(&priv->offload); - exit: return handled; } @@ -1040,7 +895,7 @@ static int at91_open(struct net_device *dev) /* start chip and queuing */ at91_chip_start(dev); - napi_enable(&priv->napi); + can_rx_offload_enable(&priv->offload); netif_start_queue(dev); return 0; @@ -1062,7 +917,7 @@ static int at91_close(struct net_device *dev) struct at91_priv *priv = netdev_priv(dev); netif_stop_queue(dev); - napi_disable(&priv->napi); + can_rx_offload_disable(&priv->offload); at91_chip_stop(dev, CAN_STATE_STOPPED); free_irq(dev->irq, dev); @@ -1265,8 +1120,11 @@ static int at91_can_probe(struct platform_device *pdev) priv->clk = clk; priv->pdata = dev_get_platdata(&pdev->dev); priv->mb0_id = 0x7ff; + priv->offload.mailbox_read = at91_mailbox_read; + priv->offload.mb_first = devtype_data->rx_first; + priv->offload.mb_last = devtype_data->rx_last; - netif_napi_add_weight(dev, &priv->napi, at91_poll, get_mb_rx_num(priv)); + can_rx_offload_add_timestamp(dev, &priv->offload); if (transceiver) priv->can.bitrate_max = transceiver->attrs.max_link_rate;