Gentle Ping! > From: Pankaj Sharma <pankj.sharma@xxxxxxxxxxx> > Subject: [PATCH v3] can: m_can: add support for handling arbitration error > > The Bosch MCAN hardware (3.1.0 and above) supports interrupt flag to detect > Protocol error in arbitration phase. > > Transmit error statistics is currently not updated from the MCAN driver. > Protocol error in arbitration phase is a TX error and the network statistics should > be updated accordingly. > > The member "tx_error" of "struct net_device_stats" should be incremented as > arbitration is a transmit protocol error. Also "arbitration_lost" of "struct > can_device_stats" should be incremented to report arbitration lost. > > Signed-off-by: Pankaj Sharma <pankj.sharma@xxxxxxxxxxx> > Signed-off-by: Sriram Dash <sriram.dash@xxxxxxxxxxx> > --- > > changes in v3: > - handle arbitration lost stats even if the allocation of the skb fails > > changes in v2: > - common m_can_ prefix for is_protocol_err function > - handling stats even if the allocation of the skb fails > - resolving build errors on net-next branch > > drivers/net/can/m_can/m_can.c | 42 > +++++++++++++++++++++++++++++++++++ > 1 file changed, 42 insertions(+) > > diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c > index 75e7490c4299..02c5795b7393 100644 > --- a/drivers/net/can/m_can/m_can.c > +++ b/drivers/net/can/m_can/m_can.c > @@ -778,6 +778,43 @@ static inline bool is_lec_err(u32 psr) > return psr && (psr != LEC_UNUSED); > } > > +static inline bool m_can_is_protocol_err(u32 irqstatus) { > + return irqstatus & IR_ERR_LEC_31X; > +} > + > +static int m_can_handle_protocol_error(struct net_device *dev, u32 > +irqstatus) { > + struct net_device_stats *stats = &dev->stats; > + struct m_can_classdev *cdev = netdev_priv(dev); > + struct can_frame *cf; > + struct sk_buff *skb; > + > + /* propagate the error condition to the CAN stack */ > + skb = alloc_can_err_skb(dev, &cf); > + > + /* update tx error stats since there is protocol error */ > + stats->tx_errors++; > + > + /* update arbitration lost status */ > + if (cdev->version >= 31 && (irqstatus & IR_PEA)) { > + netdev_dbg(dev, "Protocol error in Arbitration fail\n"); > + cdev->can.can_stats.arbitration_lost++; > + if (skb) { > + cf->can_id |= CAN_ERR_LOSTARB; > + cf->data[0] |= CAN_ERR_LOSTARB_UNSPEC; > + } > + } > + > + if (unlikely(!skb)) { > + netdev_dbg(dev, "allocation of skb failed\n"); > + return 0; > + } > + netif_receive_skb(skb); > + > + return 1; > +} > + > static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus, > u32 psr) > { > @@ -792,6 +829,11 @@ static int m_can_handle_bus_errors(struct net_device > *dev, u32 irqstatus, > is_lec_err(psr)) > work_done += m_can_handle_lec_err(dev, psr & LEC_UNUSED); > > + /* handle protocol errors in arbitration phase */ > + if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && > + m_can_is_protocol_err(irqstatus)) > + work_done += m_can_handle_protocol_error(dev, irqstatus); > + > /* other unproccessed error interrupts */ > m_can_handle_other_err(dev, irqstatus); > > -- > 2.17.1