[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <D5ECB3C7A6F99444980976A8C6D896384DEE082650@EAPEX1MAIL1.st.com>
Date: Tue, 25 Jan 2011 12:36:31 +0800
From: Bhupesh SHARMA <bhupesh.sharma@...com>
To: Wolfgang Grandegger <wg@...ndegger.com>
Cc: "netdev@...r.kernel.org" <netdev@...r.kernel.org>,
"Socketcan-core@...ts.berlios.de" <Socketcan-core@...ts.berlios.de>,
David Miller <davem@...emloft.net>,
Marc Kleine-Budde <mkl@...gutronix.de>
Subject: RE: [PATCH net-next-2.6 v5 1/1] can: c_can: Added support for Bosch
C_CAN controller
Hi Wolfgang,
Thanks for your review.
Please see my comments inline:
> Hi Bhupesh,
>
> at a closer look, I realized one more issue, apart from some minor
> ones...
>
> On 01/20/2011 10:20 AM, Bhupesh Sharma wrote:
> > Bosch C_CAN controller is a full-CAN implementation which is
> compliant
> > to CAN protocol version 2.0 part A and B. Bosch C_CAN user manual can
> be
> > obtained from:
> > http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/
> > c_can/users_manual_c_can.pdf
> >
> > This patch adds the support for this controller.
> > The following are the design choices made while writing the
> controller
> > driver:
> > 1. Interface Register set IF1 has be used only in the current design.
> > 2. Out of the 32 Message objects available, 16 are kept aside for RX
> > purposes and the rest for TX purposes.
> > 3. NAPI implementation is such that both the TX and RX paths function
> > in polling mode.
> >
> > Signed-off-by: Bhupesh Sharma <bhupesh.sharma@...com>
> > ---
> > Changes since V4:
> > 1. Insured correct ISR implementation to allow shared IRQs.
> > 2. To ensure better understanding of message object numbers
> > and thierusage modified C_CAN_MSG_OBJ_RX_FIRST value from 0
>
> Typo!
Ok :)
> > to 1.
> > 3. Corrected coding style globally.
> > 4. Renamed Interface registers as *ifregs*.
> >
> > drivers/net/can/Kconfig | 2 +
> > drivers/net/can/Makefile | 1 +
> > drivers/net/can/c_can/Kconfig | 15 +
> > drivers/net/can/c_can/Makefile | 8 +
> > drivers/net/can/c_can/c_can.c | 958
> ++++++++++++++++++++++++++++++++
> > drivers/net/can/c_can/c_can.h | 229 ++++++++
> > drivers/net/can/c_can/c_can_platform.c | 207 +++++++
> > 7 files changed, 1420 insertions(+), 0 deletions(-)
> > create mode 100644 drivers/net/can/c_can/Kconfig
> > create mode 100644 drivers/net/can/c_can/Makefile
> > create mode 100644 drivers/net/can/c_can/c_can.c
> > create mode 100644 drivers/net/can/c_can/c_can.h
> > create mode 100644 drivers/net/can/c_can/c_can_platform.c
> >
> > diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> > index 9d9e453..50549b5 100644
> > --- a/drivers/net/can/Kconfig
> > +++ b/drivers/net/can/Kconfig
> > @@ -86,6 +86,8 @@ source "drivers/net/can/mscan/Kconfig"
> >
> > source "drivers/net/can/sja1000/Kconfig"
> >
> > +source "drivers/net/can/c_can/Kconfig"
> > +
> > source "drivers/net/can/usb/Kconfig"
> >
> > config CAN_DEBUG_DEVICES
> > diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
> > index 0057537..c3efeb3 100644
> > --- a/drivers/net/can/Makefile
> > +++ b/drivers/net/can/Makefile
> > @@ -11,6 +11,7 @@ obj-y += usb/
> >
> > obj-$(CONFIG_CAN_SJA1000) += sja1000/
> > obj-$(CONFIG_CAN_MSCAN) += mscan/
> > +obj-$(CONFIG_CAN_C_CAN) += c_can/
> > obj-$(CONFIG_CAN_AT91) += at91_can.o
> > obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
> > obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
> > diff --git a/drivers/net/can/c_can/Kconfig
> b/drivers/net/can/c_can/Kconfig
> > new file mode 100644
> > index 0000000..ffb9773
> > --- /dev/null
> > +++ b/drivers/net/can/c_can/Kconfig
> > @@ -0,0 +1,15 @@
> > +menuconfig CAN_C_CAN
> > + tristate "Bosch C_CAN devices"
> > + depends on CAN_DEV && HAS_IOMEM
> > +
> > +if CAN_C_CAN
> > +
> > +config CAN_C_CAN_PLATFORM
> > + tristate "Generic Platform Bus based C_CAN driver"
> > + ---help---
> > + This driver adds support for the C_CAN chips connected to
> > + the "platform bus" (Linux abstraction for directly to the
> > + processor attached devices) which can be found on various
> > + boards from ST Microelectronics (http://www.st.com)
> > + like the SPEAr1310 and SPEAr320 evaluation boards.
> > +endif
> > diff --git a/drivers/net/can/c_can/Makefile
> b/drivers/net/can/c_can/Makefile
> > new file mode 100644
> > index 0000000..9273f6d
> > --- /dev/null
> > +++ b/drivers/net/can/c_can/Makefile
> > @@ -0,0 +1,8 @@
> > +#
> > +# Makefile for the Bosch C_CAN controller drivers.
> > +#
> > +
> > +obj-$(CONFIG_CAN_C_CAN) += c_can.o
> > +obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
> > +
> > +ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
> > diff --git a/drivers/net/can/c_can/c_can.c
> b/drivers/net/can/c_can/c_can.c
> > new file mode 100644
> > index 0000000..66a400b
> > --- /dev/null
> > +++ b/drivers/net/can/c_can/c_can.c
>
> ...
>
> > +static void c_can_handle_lost_msg_obj(struct net_device *dev,
> > + int iface, int objno)
> > +{
> > + struct c_can_priv *priv = netdev_priv(dev);
> > + struct net_device_stats *stats = &dev->stats;
> > + struct sk_buff *skb;
> > + struct can_frame *frame;
> > +
> > + netdev_err(dev, "msg lost in buffer %d\n", objno);
> > +
> > + c_can_object_get(dev, iface, objno, IF_COMM_ALL &
> > + ~IF_COMM_TXRQST);
>
> Does fit on one line.
OK.
> ...
>
> > +static void c_can_inval_msg_object(struct net_device *dev, int
> iface, int objno)
> > +{
> > + struct c_can_priv *priv = netdev_priv(dev);
> > +
> > + priv->write_reg(priv, &priv->regs->ifregs[iface].arb1, 0);
> > + priv->write_reg(priv, &priv->regs->ifregs[iface].arb2, 0);
> > + priv->write_reg(priv, &priv->regs->ifregs[iface].msg_cntrl, 0);
> > +
> > + c_can_object_put(dev, iface, objno,
> > + IF_COMM_ARB | IF_COMM_CONTROL);
>
> Ditto
Ok.
> ...
>
> > +static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
> > +{
> > + return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
> > + (priv->current_status & STATUS_LEC_MASK);
> > +}
> > +
> > +static int c_can_err(struct net_device *dev,
> > + enum c_can_bus_error_types error_type,
> > + enum c_can_lec_type lec_type)
> > +{
> > + unsigned int reg_err_counter;
> > + unsigned int rx_err_passive;
> > + struct c_can_priv *priv = netdev_priv(dev);
> > + struct net_device_stats *stats = &dev->stats;
> > + struct can_frame *cf;
> > + struct sk_buff *skb;
> > + struct can_berr_counter bec;
> > +
> > + /* propogate the error condition to the CAN stack */
> > + skb = alloc_can_err_skb(dev, &cf);
> > + if (unlikely(!skb))
> > + return 0;
> > +
> > + c_can_get_berr_counter(dev, &bec);
> > + reg_err_counter = priv->read_reg(priv, &priv->regs->err_cnt);
> > + rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
> > + ERR_CNT_RP_SHIFT;
> > +
> > + if (error_type & C_CAN_ERROR_WARNING) {
> > + /* error warning state */
> > + priv->can.can_stats.error_warning++;
> > + priv->can.state = CAN_STATE_ERROR_WARNING;
> > + cf->can_id |= CAN_ERR_CRTL;
> > + if (bec.rxerr > 96)
> > + cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
> > + if (bec.txerr > 96)
> > + cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
> > + }
> > + if (error_type & C_CAN_ERROR_PASSIVE) {
> > + /* error passive state */
> > + priv->can.can_stats.error_passive++;
> > + priv->can.state = CAN_STATE_ERROR_PASSIVE;
> > + cf->can_id |= CAN_ERR_CRTL;
> > + if (rx_err_passive)
> > + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
> > + if (bec.txerr > 127)
> > + cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
> > + }
> > + if (error_type & C_CAN_BUS_OFF) {
> > + /* bus-off state */
> > + priv->can.state = CAN_STATE_BUS_OFF;
> > + cf->can_id |= CAN_ERR_BUSOFF;
> > + /*
> > + * disable all interrupts in bus-off mode to ensure that
> > + * the CPU is not hogged down
> > + */
> > + c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
> > + can_bus_off(dev);
> > + }
> > +
> > + /*
> > + * check for 'last error code' which tells us the
> > + * type of the last error to occur on the CAN bus
> > + */
> > +
> > + /* common for all type of bus errors */
> > + priv->can.can_stats.bus_error++;
>
> Does a state change always come together with a bus error?
>
> > + stats->rx_errors++;
> > + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
> > + cf->data[2] |= CAN_ERR_PROT_UNSPEC;
> > +
> > + switch (lec_type) {
> > + case LEC_STUFF_ERROR:
> > + netdev_dbg(dev, "stuff error\n");
> > + cf->data[2] |= CAN_ERR_PROT_STUFF;
> > + break;
> > +
> > + case LEC_FORM_ERROR:
> > + netdev_dbg(dev, "form error\n");
> > + cf->data[2] |= CAN_ERR_PROT_FORM;
> > + break;
> > +
> > + case LEC_ACK_ERROR:
> > + netdev_dbg(dev, "ack error\n");
> > + cf->data[2] |= (CAN_ERR_PROT_LOC_ACK |
> > + CAN_ERR_PROT_LOC_ACK_DEL);
> > + break;
> > +
> > + case LEC_BIT1_ERROR:
> > + netdev_dbg(dev, "bit1 error\n");
> > + cf->data[2] |= CAN_ERR_PROT_BIT1;
> > + break;
> > +
> > + case LEC_BIT0_ERROR:
> > + netdev_dbg(dev, "bit0 error\n");
> > + cf->data[2] |= CAN_ERR_PROT_BIT0;
> > + break;
> > +
> > + case LEC_CRC_ERROR:
> > + netdev_dbg(dev, "CRC error\n");
> > + cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
> > + CAN_ERR_PROT_LOC_CRC_DEL);
> > + break;
> > + }
>
> From the C_CAN manual:
>
> "The LEC field holds a code which indicates the type of the last error
> to occur on the CAN bus. This field will be cleared to '0' when a
> message has been transferred (reception or transmission) without error.
> The unused code '7' may be written by the CPU to check for updates."
>
> Not sure if it's necessary to reset the lec at init and after an error
> to 0x7 and check it. More below...
Hmm.. The default value of Status Register is 0x0 at INIT so I am not
sure if LEC needs to be reset at init. However using the unused code
0x7 seems necessary to check for updates as per specs.
I will modify the same in V6.
> > + netif_receive_skb(skb);
> > + stats->rx_packets++;
> > + stats->rx_bytes += cf->can_dlc;
> > +
> > + return 1;
> > +}
> > +
> > +static int c_can_poll(struct napi_struct *napi, int quota)
> > +{
> > + u16 irqstatus;
> > + int lec_type = 0;
> > + int work_done = 0;
> > + struct net_device *dev = napi->dev;
> > + struct c_can_priv *priv = netdev_priv(dev);
> > + enum c_can_bus_error_types error_type = C_CAN_NO_ERROR;
> > +
> > + irqstatus = priv->read_reg(priv, &priv->regs->interrupt);
> > + if (!irqstatus)
> > + goto end;
> > +
> > + /* status events have the highest priority */
> > + if (irqstatus == STATUS_INTERRUPT) {
> > + priv->current_status = priv->read_reg(priv,
> > + &priv->regs->status);
> > +
> > + /* handle Tx/Rx events */
> > + if (priv->current_status & STATUS_TXOK)
> > + priv->write_reg(priv, &priv->regs->status,
> > + priv->current_status & ~STATUS_TXOK);
> > +
> > + if (priv->current_status & STATUS_RXOK)
> > + priv->write_reg(priv, &priv->regs->status,
> > + priv->current_status & ~STATUS_RXOK);
> > +
> > + /* handle bus error events */
> > + if (priv->current_status & STATUS_EWARN) {
> > + netdev_dbg(dev,
> > + "entered error warning state\n");
>
> Does fit on one line.
OK.
> > + error_type = C_CAN_ERROR_WARNING;
> > + }
> > + if ((priv->current_status & STATUS_EPASS) &&
> > + (!(priv->last_status & STATUS_EPASS))) {
> > + netdev_dbg(dev,
> > + "entered error passive state\n");
>
> Ditto.
OK.
> > + error_type = C_CAN_ERROR_PASSIVE;
> > + }
> > + if ((priv->current_status & STATUS_BOFF) &&
> > + (!(priv->last_status & STATUS_BOFF))) {
> > + netdev_dbg(dev,
> > + "entered bus off state\n");
>
> Ditto.
OK.
> > + error_type = C_CAN_BUS_OFF;
> > + }
> > +
> > + /* handle bus recovery events */
> > + if ((!(priv->current_status & STATUS_EPASS)) &&
> > + (priv->last_status & STATUS_EPASS)) {
> > + netdev_dbg(dev,
> > + "left error passive state\n");
>
> Ditto.
OK.
> > + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> > + }
> > + if ((!(priv->current_status & STATUS_BOFF)) &&
> > + (priv->last_status & STATUS_BOFF)) {
> > + netdev_dbg(dev,
> > + "left bus off state\n");
> > + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> > + }
> > +
> > + priv->last_status = priv->current_status;
> > +
> > + /* handle error on the bus */
> > + lec_type = c_can_has_and_handle_berr(priv);
> > + if (lec_type && (error_type != C_CAN_NO_ERROR))
> > + work_done += c_can_err(dev, error_type, lec_type);
>
> State changes are only reported if berr_reporting is enabled and a bus
> error occured. This needs to be fixed.
As I mentioned earlier in a response to a review comment, the Bus Error
reporting for C_CAN seems different from sja1000 and flexcan approaches.
Do you think it will be useful to drop CAN_CTRLMODE_BERR_REPORTING from
priv->can.ctrlmode_supported as done by *pch* driver? Or do you have
a better idea..
> Feel free to send the output of "candump any,0:0,#FFFFFFFF" when
> sending
> messages without cable connected and with a bus error provocuted.
OK. I will try to cross-compile candump for my arm-v7 architecture
and will send the output.
> Apart form that the patch looks really good.
:)
> Wolfgang.
Regards,
Bhupesh
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists