All of lore.kernel.org
 help / color / mirror / Atom feed
From: Wolfgang Grandegger <wg@grandegger.com>
To: Masayuki Ohtak <masa-korg@dsn.okisemi.com>
Cc: "David S. Miller" <davem@davemloft.net>,
	Wolfram Sang <w.sang@pengutronix.de>,
	Christian Pellegrin <chripell@fsfe.org>,
	Barry Song <21cnbao@gmail.com>,
	Samuel Ortiz <sameo@linux.intel.com>,
	socketcan-core@lists.berlios.de, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, meego-dev@meego.com,
	"" <andrew.chih.howe.khor@intel.com>, "" <qi.wang@intel.com>,
	gregkh@suse.de, "" <yong.y.wang@intel.com>,
	Tomoya MORINAGA <morinaga526@dsn.okisemi.com>,
	arjan@linux.intel.com
Subject: Re: [MeeGo-Dev][PATCH v2] Topcliff: Update PCH_CAN driver to 2.6.35
Date: Wed, 15 Sep 2010 09:36:12 +0200	[thread overview]
Message-ID: <4C90776C.8040000@grandegger.com> (raw)
In-Reply-To: <4C8E1773.9090000@dsn.okisemi.com>

Hi Ohtake,

On 09/13/2010 02:22 PM, Masayuki Ohtak wrote:
> CAN driver of Topcliff PCH
> 
> Topcliff PCH is the platform controller hub that is going to be used in
> Intel's upcoming general embedded platform. All IO peripherals in
> Topcliff PCH are actually devices sitting on AMBA bus. 
> Topcliff PCH has CAN I/F. This driver enables CAN function.
> 
> Signed-off-by: Masayuki Ohtake <masa-korg@dsn.okisemi.com>

Ouch! Still 3600 lines of code...

> ---
>  drivers/net/can/Kconfig   |    8 +
>  drivers/net/can/Makefile  |    1 +
>  drivers/net/can/pch_can.c | 3601 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 3610 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/can/pch_can.c
> 
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index 2c5227c..5c98a20 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -73,6 +73,14 @@ config CAN_JANZ_ICAN3
>  	  This driver can also be built as a module. If so, the module will be
>  	  called janz-ican3.ko.
>  
> +config PCH_CAN
> +	tristate "PCH CAN"
> +	depends on  CAN_DEV
> +	---help---
> +	  This driver is for PCH CAN of Topcliff which is an IOH for x86
> +	  embedded processor.
> +	  This driver can access CAN bus.
> +
>  source "drivers/net/can/mscan/Kconfig"
>  
>  source "drivers/net/can/sja1000/Kconfig"
> diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
> index 9047cd0..3ddc6a7 100644
> --- a/drivers/net/can/Makefile
> +++ b/drivers/net/can/Makefile
> @@ -16,5 +16,6 @@ obj-$(CONFIG_CAN_TI_HECC)	+= ti_hecc.o
>  obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
>  obj-$(CONFIG_CAN_BFIN)		+= bfin_can.o
>  obj-$(CONFIG_CAN_JANZ_ICAN3)	+= janz-ican3.o
> +obj-$(CONFIG_PCH_CAN)		+= pch_can.o
>  
>  ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
> diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
> new file mode 100644
> index 0000000..0de978f
> --- /dev/null
> +++ b/drivers/net/can/pch_can.c
> @@ -0,0 +1,3601 @@
> +/*
> + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/sched.h>
> +#include <linux/pci.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/errno.h>
> +#include <linux/netdevice.h>
> +#include <linux/skbuff.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/can.h>
> +#include <linux/can/dev.h>
> +#include <linux/can/error.h>
> +
> +#define MAX_CAN_DEVICES		1
> +#define MAX_BITRATE		0x3e8
> +#define NUM_NODES		2000	/* Maximum number of
> +						 Software FIFO nodes. */
> +#define MAX_MSG_OBJ		32
> +#define MSG_OBJ_RX		0 /* The receive message object flag. */
> +#define MSG_OBJ_TX		1 /* The transmit message object flag. */
> +
> +#define ENABLE			1 /* The enable flag */
> +#define DISABLE			0 /* The disable flag */
> +#define CAN_CTRL_INIT		0x0001 /* The INIT bit of CANCONT register. */
> +#define CAN_CTRL_IE		0x0002 /* The IE bit of CAN control register */
> +#define CAN_CTRL_SIE		0x0004
> +#define CAN_CTRL_EIE		0x0008
> +#define CAN_CTRL_DAR		0x0020
> +#define CAN_CTRL_IE_SIE_EIE	0x000e
> +#define CAN_CTRL_CCE		0x0040
> +#define CAN_CTRL_OPT		0x0080 /* The OPT bit of CANCONT register. */
> +#define CAN_OPT_SILENT		0x0008 /* The Silent bit of CANOPT register. */
> +#define CAN_CMASK_RX_TX_SET	0x00f3
> +#define CAN_CMASK_RX_TX_GET	0x0073
> +#define CAN_CMASK_ALL		0xff
> +#define CAN_CMASK_RDWR		0x80
> +#define CAN_CMASK_ARB		0x20
> +#define CAN_CMASK_CTRL		0x10
> +#define CAN_CMASK_MASK		0x40
> +#define CAN_CMASK_CLPNT		0x08
> +
> +#define CAN_CMASK_NEWINT	0x04 /* The TxRqst/NewDat bit for the CMASK
> +					register. */
> +
> +#define CAN_IF_MCONT_NEWDAT	0x8000 /* The NewDat bit of the MCONT
> +					  register. */
> +
> +#define CAN_IF_MCONT_INTPND	0x2000 /* The IntPnd bit of the MCONT
> +					  register. */
> +
> +#define CAN_IF_MCONT_UMASK		0x1000
> +#define CAN_IF_MCONT_TXIE		0x0800
> +#define CAN_IF_MCONT_RXIE		0x0400
> +#define CAN_IF_MCONT_RMTEN		0x0200
> +#define CAN_IF_MCONT_TXRQXT		0x0100
> +#define CAN_IF_MCONT_EOB		0x0080
> +#define CAN_IF_MCONT_MSGLOST		0x4000
> +#define CAN_MASK2_MDIR_MXTD		0xc000
> +#define CAN_ID2_MSGVAL_XTD_DIR		0xe000
> +#define CAN_ID2_MSGVAL_DIR		0xa000
> +#define CAN_ID2_DIR			0x2000
> +#define CAN_ID_MSGVAL			0x8000
> +#define CAN_IF_MASK2_MDIR		((u32)1 << 14)
> +#define CAN_IF_MASK2_MXTD		((u32)1 << 15)
> +
> +#define CAN_STATUS_INT			0x8000 /* The status interrupt value of
> +						  the CAN device. */
> +
> +#define CAN_IF_CREQ_BUSY		0x8000 /* The Busy flag bit of the CREQ
> +						  register. */
> +
> +#define CAN_ID2_XTD			0x4000 /* The Xtd bit of ID2
> +						  register. */
> +
> +#define CAN_SRST_BIT			0x0001
> +#define CAN_CONT_OFFSET			0x00	/*Can Control register */
> +#define CAN_STAT_OFFSET			0x04
> +#define CAN_ERRC_OFFSET			0x08
> +#define CAN_BITT_OFFSET			0x0c
> +#define CAN_INT_OFFSET			0x010
> +#define CAN_OPT_OFFSET			0x14	/*Extended function register */
> +#define CAN_BRPE_OFFSET			0x18
> +
> +/* Message interface one (IF1) registers */
> +#define CAN_IF1_CREQ_OFFSET		0x020
> +#define CAN_IF1_CMASK_OFFSET		0x024
> +#define CAN_IF1_ID1_OFFSET		0x030
> +#define CAN_IF1_ID2_OFFSET		0x034
> +#define CAN_IF1_MCONT_OFFSET		0x038
> +#define CAN_IF1_DATAA1_OFFSET		0x03C
> +#define CAN_IF1_DATAA2_OFFSET		0x040
> +#define CAN_IF1_DATAB1_OFFSET		0x044
> +#define CAN_IF1_DATAB2_OFFSET		0x048
> +#define CAN_IF1_MASK1_OFFSET		0x028
> +#define CAN_IF1_MASK2_OFFSET		0x02c
> +#define CAN_IF2_CREQ_OFFSET		0x080
> +#define CAN_IF2_CMASK_OFFSET		0x084
> +#define CAN_IF2_ID1_OFFSET		0x090
> +#define CAN_IF2_ID2_OFFSET		0x094
> +#define CAN_IF2_MCONT_OFFSET		0x098
> +#define CAN_IF2_DATAA1_OFFSET		0x09c
> +#define CAN_IF2_DATAA2_OFFSET		0x0a0
> +#define CAN_IF2_DATAB1_OFFSET		0x0a4
> +#define CAN_IF2_DATAB2_OFFSET		0x0a8
> +#define CAN_IF2_MASK1_OFFSET		0x088
> +#define CAN_IF2_MASK2_OFFSET		0x08c
> +#define CAN_TREQ1_OFFSET		0x100
> +#define CAN_TREQ2_OFFSET		0x104
> +#define CAN_SRST_OFFSET			0x1FC

Using a structure to describe you register layout seems much more
appropriate for your driver. E.g.:

struct pch_can_regs {
	u32 cont;
	u32 stat;
	u32 errc;
	...
};

Then the registers are accessed via:

ioread32(&regs->stat);
iowrite32(&regs->cont, value);

This results in more readable code and you profit from type checking.

> +/* bit position of certain controller bits. */
> +#define BIT_BITT_BRP			0
> +#define BIT_BITT_SJW			6
> +#define BIT_BITT_TSEG1			8
> +#define BIT_BITT_TSEG2			12
> +#define BIT_IF1_MCONT_RXIE		10
> +#define BIT_IF2_MCONT_TXIE		11
> +#define BIT_BRPE_BRPE			6
> +#define BIT_ES_TXERRCNT			0
> +#define BIT_ES_RXERRCNT			8
> +#define MSK_BITT_BRP			0x3f
> +#define MSK_BITT_SJW			0xc0
> +#define MSK_BITT_TSEG1			0xf00
> +#define MSK_BITT_TSEG2			0x7000
> +#define MSK_BRPE_BRPE			0x3c0
> +#define MSK_BRPE_GET			0x0f
> +#define MSK_CTRL_IE_SIE_EIE		0x07
> +#define MSK_MCONT_TXIE			0x08
> +#define MSK_MCONT_RXIE			0x10
> +#define MSK_ALL_THREE			0x07
> +#define MSK_ALL_FOUR			0x0f
> +#define MSK_ALL_EIGHT			0xff
> +#define MSK_ALL_ELEVEN			0x7ff
> +#define MSK_ALL_THIRTEEN		0x1fff
> +#define MSK_ALL_SIXTEEN			0xffff
> +
> +/* Error */
> +#define MSK_ES_TXERRCNT	((u32)0xff << BIT_ES_TXERRCNT)	/* Tx err count */
> +#define MSK_ES_RXERRCNT	((u32)0x7f << BIT_ES_RXERRCNT)	/* Rx err count */
> +
> +#define PCH_CAN_BIT_SET(reg, bitmask)	\
> +		(iowrite32((ioread32((reg)) | ((u32)(bitmask))), (reg)))
> +#define PCH_CAN_BIT_CLEAR(reg, bitmask)	\
> +		(iowrite32((ioread32((reg)) & ~((u32)(bitmask))), (reg)))

Please use static inline functions and try to avoid casts.

> +#define PCH_CAN_NO_TX_BUFF		1 /* The flag value for denoting the
> +					     unavailability of the transmit
> +					     message object. */
> +
> +#define ERROR_COUNT			96
> +#define PCH_CAN_MSG_DATA_LEN		8	/* CAN Msg data length */
> +
> +#define PCH_CAN_NULL			NULL
> +
> +#define PCI_DEVICE_ID_INTEL_PCH1_CAN	0x8818
> +#define DRIVER_NAME			"can"
> +
> +#define PCH_CAN_CLOCK_DEFAULT_OFFSET	0
> +#define PCH_CAN_CLOCK_62_5_OFFSET	0
> +#define PCH_CAN_CLOCK_24_OFFSET		8
> +#define PCH_CAN_CLOCK_50_OFFSET		16
> +
> +#define COUNTER_LIMIT 0xFFFF
> +
> +
> +
> +enum pch_can_listen_mode {
> +	PCH_CAN_ACTIVE = 0,
> +	PCH_CAN_LISTEN
> +};
> +
> +enum pch_can_run_mode {
> +	PCH_CAN_STOP = 0,
> +	PCH_CAN_RUN
> +};
> +
> +enum pch_can_arbiter {
> +	PCH_CAN_ROUND_ROBIN = 0,
> +	PCH_CAN_FIXED_PRIORITY
> +};
> +
> +enum pch_can_auto_restart {
> +	CAN_MANUAL = 0,
> +	CAN_AUTO
> +};

Please remove the above enums or explain why you need them.

> +enum pch_can_baud {
> +	PCH_CAN_BAUD_10 = 0,
> +	PCH_CAN_BAUD_20,
> +	PCH_CAN_BAUD_50,
> +	PCH_CAN_BAUD_125,
> +	PCH_CAN_BAUD_250,
> +	PCH_CAN_BAUD_500,
> +	PCH_CAN_BAUD_800,
> +	PCH_CAN_BAUD_1000
> +};

Dead code. Not used anywhere.

> +enum pch_can_interrupt {
> +	CAN_ENABLE,
> +	CAN_DISABLE,
> +	CAN_ALL,
> +	CAN_NONE
> +};
> +

Please remove the above enum or explain why you need it.

> +/**
> + * struct pch_can_msg - CAN message structure
> + * @ide:	Standard/extended msg
> + * @id:		11 or 29 bit msg id
> + * @dlc:	Size of data
> + * @data:	Message pay load
> + * @rtr:	RTR message
> + */
> +struct pch_can_msg {
> +	unsigned short ide;
> +	unsigned int id;
> +	unsigned short dlc;
> +	unsigned char data[PCH_CAN_MSG_DATA_LEN];
> +	unsigned short rtr;
> +};


Please remove the above intermediate struct or explain why you need it.

> +/**
> + * pch_can_timing - CAN bittiming structure
> + * @bitrate:	Bitrate (kbps)
> + * @cfg_bitrate:BRP
> + * @cfg_tseg1:	Tseg1
> + * @cfg_tseg2:	Tseg2
> + * @cfg_sjw:	Sync jump width
> + * @smpl_mode:	Sampling mode
> + * @edge_mode:	Edge R / D
> + */
> +struct pch_can_timing {
> +	unsigned int bitrate;
> +	unsigned int cfg_bitrate;
> +	unsigned int cfg_tseg1;
> +	unsigned int cfg_tseg2;
> +	unsigned int cfg_sjw;
> +	unsigned int smpl_mode;
> +	unsigned int edge_mode;
> +};
> +
> +/**
> + * struct pch_can_error - CAN error structure
> + * @rxgte96:	Rx err cnt >=96
> + * @txgte96:	Tx err cnt >=96
> + * @error_stat:	Error state of CAN node,
> + *		00=error active (normal)
> + *		01=error passive
> + *		1x=bus off
> + * @rx_err_cnt:	Rx error count
> + * @tx_err_cnt:	Tx error count
> + */
> +struct pch_can_error {
> +	unsigned int rxgte96;
> +	unsigned int txgte96;
> +	unsigned int error_stat;
> +	unsigned int rx_err_cnt;
> +	unsigned int tx_err_cnt;
> +};

Ditto.

> +/**
> + * struct pch_can_acc_filter - CAN Filter structure
> + * @id:		The id/mask data
> + * @id_ext:	Standard/extended ID
> + * @rtr:	RTR message
> + */
> +struct pch_can_acc_filter {
> +	unsigned int id;
> +	unsigned int id_ext;
> +	unsigned int rtr;
> +};

Ditto.

> +/**
> + * struct pch_can_rx_filter - CAN RX filter
> + * @num:	Filter number
> + * @umask:	UMask value
> + * @amr:	Acceptance Mask Reg
> + * @aidr:	Acceptance Control Reg
> + */
> +struct pch_can_rx_filter {
> +	unsigned int num;
> +	unsigned int umask;
> +	struct pch_can_acc_filter amr;
> +	struct pch_can_acc_filter aidr;
> +};

Ditto.

> +/**
> + * struct pch_can_os - structure to store the CAN device information.
> + * @can:		CAN: device handle
> + * @opened:		Linux opened device
> + * @can_num:		Linux: CAN Number
> + * @pci_remap:		Linux: MMap regs
> + * @dev:		Linux: PCI Device
> + * @irq:		Linux: IRQ
> + * @block_mode:		Blocking / non-blocking
> + * @read_wait_queue:	Linux: Read wait queue
> + * @write_wait_queue:	Linux: Write wait queue
> + * @write_wait_flag:	Linux: Write wait flag
> + * @read_wait_flag:	Linux: Read wait flag
> + * @open_spinlock:	Linux: Open lock variable
> + * @is_suspending:	Linux: Is suspending state
> + * @inode:		Linux: inode
> + * @timing:		CAN: timing
> + * @run_mode:		CAN: run mode
> + * @listen_mode:	CAN: listen mode
> + * @arbiter_mode:	CAN: arbiter mode
> + * @tx_enable:		CAN: Tx buffer state
> + * @rx_enable:		CAN: Rx buffer state
> + * @rx_link:		CAN: Rx link set
> + * @int_enables:	CAN: ints enabled
> + * @int_stat:		CAN: int status
> + * @bus_off_interrupt:	CAN: Buss off int flag
> + * @rx_filter:		CAN: Rx filters
> + * @ndev:		net_device pointer
> + * @tx_spinlock:	CAN: transmission lock variable
> + */
> +struct pch_can_os {
> +	struct can_hw *can;
> +	unsigned int opened;
> +	unsigned int can_num;
> +	void __iomem *pci_remap;
> +	struct pci_dev *dev;
> +	unsigned int irq;
> +	int block_mode;
> +	wait_queue_head_t read_wait_queue;
> +	wait_queue_head_t write_wait_queue;

Not used anywhere! Dead code :-(.

> +	unsigned int write_wait_flag;
> +	unsigned int read_wait_flag;
> +	spinlock_t open_spinlock;
> +	unsigned int is_suspending;
> +	struct inode *inode;
> +	struct pch_can_timing timing;
> +	enum pch_can_run_mode run_mode;
> +	enum pch_can_listen_mode listen_mode;
> +	enum pch_can_arbiter arbiter_mode;
> +	unsigned int tx_enable[MAX_MSG_OBJ];
> +	unsigned int rx_enable[MAX_MSG_OBJ];
> +	unsigned int rx_link[MAX_MSG_OBJ];
> +	unsigned int int_enables;
> +	unsigned int int_stat;
> +	unsigned int bus_off_interrupt;
> +	struct pch_can_rx_filter rx_filter[MAX_MSG_OBJ];
> +	struct net_device *ndev;
> +	spinlock_t tx_spinlock;
> +	struct mutex pch_mutex;
> +};

Why do you need an extra structure here? Is pch_can_priv not OK?

> +/**
> + * struct pch_can_priv - CAN driver private data structure
> + * @can:		MUST be first member/field
> + * @ndev:		Pointer to net_device structure
> + * @clk:		unused
> + * @base:		Base address
> + * @pch_can_os_p:	Pointer to CAN device information
> + * @have_msi:		PCI MSI mode flag
> + *
> + * Longer description of this structure.
> + */
> +struct pch_can_priv {
> +	struct can_priv can;
> +	struct net_device *ndev;
> +	struct clk *clk;
> +	void __iomem *base;
> +	struct pch_can_os pch_can_os_p;
> +	unsigned int have_msi;
> +};
> +
> +struct can_hw {
> +	void __iomem *io_base;
> +};

See above.

> +static unsigned int pch_can_clock = 50000; /*50MH*/
> +
> +/*
> +The number of message objects that has to be configured as receive/send
> +objects.
> +Topcliff CAN has total 32 message objects.
> +*/
> +static unsigned int pch_can_rx_buf_size = 1;
> +static unsigned int pch_can_tx_buf_size = 1;
> +
> +
> +static enum pch_can_auto_restart restat_mode = CAN_MANUAL; /* The variable used
> +							      to store the
> +							      restart mode. */
> +
> +static struct can_bittiming_const pch_can_bittiming_const = {
> +	.name = KBUILD_MODNAME,
> +	.tseg1_min = 1,
> +	.tseg1_max = 16,
> +	.tseg2_min = 1,
> +	.tseg2_max = 8,
> +	.sjw_max = 4,
> +	.brp_min = 1,
> +	.brp_max = 1024, /* 6bit + extended 4bit */
> +	.brp_inc = 1,
> +};
> +
> +static const struct pci_device_id pch_can_pcidev_id[] __devinitdata = {
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH1_CAN)},
> +	{}
> +};
> +
> +/*
> +This variable is used to store the configuration (receive /transmit) of the
> +available message objects.
> +This variable is used for storing the message object configuration related
> +information. It includes the information about which message object is used as
> +Receiver and Transmitter.
> +*/

Please use the usual Linux style for comments:

/*
 *
 */

> +static unsigned int pch_msg_obj_conf[MAX_MSG_OBJ] = {
> +	3, 3, 3, 3,
> +	3, 3, 3, 3,
> +	3, 3, 3, 3,
> +	3, 3, 3, 3,
> +	3, 3, 3, 3,
> +	3, 3, 3, 3,
> +	3, 3, 3, 3,
> +	3, 3, 3, 3
> +};
> +
> +static struct can_hw *pch_can_create(void __iomem *io_base,
> +				     struct net_device *ndev)
> +{
> +	struct can_hw *can;
> +
> +	if (!io_base) {
> +		dev_err(&ndev->dev, "%s -> Invalid IO Base\n", __func__);
> +		return NULL;
> +	}
> +
> +	/* Allocates memory for the handle. */
> +	can = kmalloc(sizeof(struct can_hw), GFP_KERNEL);
> +	if (!can) {	/* Allocation failed */
> +		dev_err(&ndev->dev,
> +			"%s -> CAN Memory allocation failed\n", __func__);
> +		return NULL;
> +	}
> +
> +	can->io_base = io_base;
> +	dev_dbg(&ndev->dev,
> +		"%s -> Handle Creation successful.\n", __func__);

Please restrict debugging output to a few useful messages for the final
user. Puh, I stop reviewing here because of too much issues, which have
already been pointed out with you previous patch. I share most of the
other comments on that patch. Please work on your *code quality*. I also
believe that *rewriting* the driver from *scratch* using an existing
Socket-CAN driver as example is the most efficient way towards a clean
and compact driver with, let's say, less than approximately 1000 lines
of code.

Wolfgang.

WARNING: multiple messages have this Message-ID (diff)
From: Wolfgang Grandegger <wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
To: Masayuki Ohtak <masa-korg-ECg8zkTtlr0C6LszWs/t0g@public.gmane.org>
Cc: andrew.chih.howe.khor-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org,
	Samuel Ortiz <sameo-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>,
	netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	gregkh-l3A5Bk7waGM@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org,
	yong.y.wang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org,
	Tomoya MORINAGA
	<morinaga526-ECg8zkTtlr0C6LszWs/t0g@public.gmane.org>,
	meego-dev-WXzIur8shnEAvxtiuMwx3w@public.gmane.org,
	arjan-VuQAYsv1563Yd54FQh9/CA@public.gmane.org,
	"David S. Miller" <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>,
	Christian Pellegrin <chripell-VaTbYqLCNhc@public.gmane.org>,
	qi.wang-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org
Subject: Re: [MeeGo-Dev][PATCH v2] Topcliff: Update PCH_CAN driver to 2.6.35
Date: Wed, 15 Sep 2010 09:36:12 +0200	[thread overview]
Message-ID: <4C90776C.8040000@grandegger.com> (raw)
In-Reply-To: <4C8E1773.9090000-ECg8zkTtlr0C6LszWs/t0g@public.gmane.org>

Hi Ohtake,

On 09/13/2010 02:22 PM, Masayuki Ohtak wrote:
> CAN driver of Topcliff PCH
> 
> Topcliff PCH is the platform controller hub that is going to be used in
> Intel's upcoming general embedded platform. All IO peripherals in
> Topcliff PCH are actually devices sitting on AMBA bus. 
> Topcliff PCH has CAN I/F. This driver enables CAN function.
> 
> Signed-off-by: Masayuki Ohtake <masa-korg-ECg8zkTtlr0C6LszWs/t0g@public.gmane.org>

Ouch! Still 3600 lines of code...

> ---
>  drivers/net/can/Kconfig   |    8 +
>  drivers/net/can/Makefile  |    1 +
>  drivers/net/can/pch_can.c | 3601 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 3610 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/can/pch_can.c
> 
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index 2c5227c..5c98a20 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -73,6 +73,14 @@ config CAN_JANZ_ICAN3
>  	  This driver can also be built as a module. If so, the module will be
>  	  called janz-ican3.ko.
>  
> +config PCH_CAN
> +	tristate "PCH CAN"
> +	depends on  CAN_DEV
> +	---help---
> +	  This driver is for PCH CAN of Topcliff which is an IOH for x86
> +	  embedded processor.
> +	  This driver can access CAN bus.
> +
>  source "drivers/net/can/mscan/Kconfig"
>  
>  source "drivers/net/can/sja1000/Kconfig"
> diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
> index 9047cd0..3ddc6a7 100644
> --- a/drivers/net/can/Makefile
> +++ b/drivers/net/can/Makefile
> @@ -16,5 +16,6 @@ obj-$(CONFIG_CAN_TI_HECC)	+= ti_hecc.o
>  obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
>  obj-$(CONFIG_CAN_BFIN)		+= bfin_can.o
>  obj-$(CONFIG_CAN_JANZ_ICAN3)	+= janz-ican3.o
> +obj-$(CONFIG_PCH_CAN)		+= pch_can.o
>  
>  ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
> diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
> new file mode 100644
> index 0000000..0de978f
> --- /dev/null
> +++ b/drivers/net/can/pch_can.c
> @@ -0,0 +1,3601 @@
> +/*
> + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/sched.h>
> +#include <linux/pci.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/errno.h>
> +#include <linux/netdevice.h>
> +#include <linux/skbuff.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/can.h>
> +#include <linux/can/dev.h>
> +#include <linux/can/error.h>
> +
> +#define MAX_CAN_DEVICES		1
> +#define MAX_BITRATE		0x3e8
> +#define NUM_NODES		2000	/* Maximum number of
> +						 Software FIFO nodes. */
> +#define MAX_MSG_OBJ		32
> +#define MSG_OBJ_RX		0 /* The receive message object flag. */
> +#define MSG_OBJ_TX		1 /* The transmit message object flag. */
> +
> +#define ENABLE			1 /* The enable flag */
> +#define DISABLE			0 /* The disable flag */
> +#define CAN_CTRL_INIT		0x0001 /* The INIT bit of CANCONT register. */
> +#define CAN_CTRL_IE		0x0002 /* The IE bit of CAN control register */
> +#define CAN_CTRL_SIE		0x0004
> +#define CAN_CTRL_EIE		0x0008
> +#define CAN_CTRL_DAR		0x0020
> +#define CAN_CTRL_IE_SIE_EIE	0x000e
> +#define CAN_CTRL_CCE		0x0040
> +#define CAN_CTRL_OPT		0x0080 /* The OPT bit of CANCONT register. */
> +#define CAN_OPT_SILENT		0x0008 /* The Silent bit of CANOPT register. */
> +#define CAN_CMASK_RX_TX_SET	0x00f3
> +#define CAN_CMASK_RX_TX_GET	0x0073
> +#define CAN_CMASK_ALL		0xff
> +#define CAN_CMASK_RDWR		0x80
> +#define CAN_CMASK_ARB		0x20
> +#define CAN_CMASK_CTRL		0x10
> +#define CAN_CMASK_MASK		0x40
> +#define CAN_CMASK_CLPNT		0x08
> +
> +#define CAN_CMASK_NEWINT	0x04 /* The TxRqst/NewDat bit for the CMASK
> +					register. */
> +
> +#define CAN_IF_MCONT_NEWDAT	0x8000 /* The NewDat bit of the MCONT
> +					  register. */
> +
> +#define CAN_IF_MCONT_INTPND	0x2000 /* The IntPnd bit of the MCONT
> +					  register. */
> +
> +#define CAN_IF_MCONT_UMASK		0x1000
> +#define CAN_IF_MCONT_TXIE		0x0800
> +#define CAN_IF_MCONT_RXIE		0x0400
> +#define CAN_IF_MCONT_RMTEN		0x0200
> +#define CAN_IF_MCONT_TXRQXT		0x0100
> +#define CAN_IF_MCONT_EOB		0x0080
> +#define CAN_IF_MCONT_MSGLOST		0x4000
> +#define CAN_MASK2_MDIR_MXTD		0xc000
> +#define CAN_ID2_MSGVAL_XTD_DIR		0xe000
> +#define CAN_ID2_MSGVAL_DIR		0xa000
> +#define CAN_ID2_DIR			0x2000
> +#define CAN_ID_MSGVAL			0x8000
> +#define CAN_IF_MASK2_MDIR		((u32)1 << 14)
> +#define CAN_IF_MASK2_MXTD		((u32)1 << 15)
> +
> +#define CAN_STATUS_INT			0x8000 /* The status interrupt value of
> +						  the CAN device. */
> +
> +#define CAN_IF_CREQ_BUSY		0x8000 /* The Busy flag bit of the CREQ
> +						  register. */
> +
> +#define CAN_ID2_XTD			0x4000 /* The Xtd bit of ID2
> +						  register. */
> +
> +#define CAN_SRST_BIT			0x0001
> +#define CAN_CONT_OFFSET			0x00	/*Can Control register */
> +#define CAN_STAT_OFFSET			0x04
> +#define CAN_ERRC_OFFSET			0x08
> +#define CAN_BITT_OFFSET			0x0c
> +#define CAN_INT_OFFSET			0x010
> +#define CAN_OPT_OFFSET			0x14	/*Extended function register */
> +#define CAN_BRPE_OFFSET			0x18
> +
> +/* Message interface one (IF1) registers */
> +#define CAN_IF1_CREQ_OFFSET		0x020
> +#define CAN_IF1_CMASK_OFFSET		0x024
> +#define CAN_IF1_ID1_OFFSET		0x030
> +#define CAN_IF1_ID2_OFFSET		0x034
> +#define CAN_IF1_MCONT_OFFSET		0x038
> +#define CAN_IF1_DATAA1_OFFSET		0x03C
> +#define CAN_IF1_DATAA2_OFFSET		0x040
> +#define CAN_IF1_DATAB1_OFFSET		0x044
> +#define CAN_IF1_DATAB2_OFFSET		0x048
> +#define CAN_IF1_MASK1_OFFSET		0x028
> +#define CAN_IF1_MASK2_OFFSET		0x02c
> +#define CAN_IF2_CREQ_OFFSET		0x080
> +#define CAN_IF2_CMASK_OFFSET		0x084
> +#define CAN_IF2_ID1_OFFSET		0x090
> +#define CAN_IF2_ID2_OFFSET		0x094
> +#define CAN_IF2_MCONT_OFFSET		0x098
> +#define CAN_IF2_DATAA1_OFFSET		0x09c
> +#define CAN_IF2_DATAA2_OFFSET		0x0a0
> +#define CAN_IF2_DATAB1_OFFSET		0x0a4
> +#define CAN_IF2_DATAB2_OFFSET		0x0a8
> +#define CAN_IF2_MASK1_OFFSET		0x088
> +#define CAN_IF2_MASK2_OFFSET		0x08c
> +#define CAN_TREQ1_OFFSET		0x100
> +#define CAN_TREQ2_OFFSET		0x104
> +#define CAN_SRST_OFFSET			0x1FC

Using a structure to describe you register layout seems much more
appropriate for your driver. E.g.:

struct pch_can_regs {
	u32 cont;
	u32 stat;
	u32 errc;
	...
};

Then the registers are accessed via:

ioread32(&regs->stat);
iowrite32(&regs->cont, value);

This results in more readable code and you profit from type checking.

> +/* bit position of certain controller bits. */
> +#define BIT_BITT_BRP			0
> +#define BIT_BITT_SJW			6
> +#define BIT_BITT_TSEG1			8
> +#define BIT_BITT_TSEG2			12
> +#define BIT_IF1_MCONT_RXIE		10
> +#define BIT_IF2_MCONT_TXIE		11
> +#define BIT_BRPE_BRPE			6
> +#define BIT_ES_TXERRCNT			0
> +#define BIT_ES_RXERRCNT			8
> +#define MSK_BITT_BRP			0x3f
> +#define MSK_BITT_SJW			0xc0
> +#define MSK_BITT_TSEG1			0xf00
> +#define MSK_BITT_TSEG2			0x7000
> +#define MSK_BRPE_BRPE			0x3c0
> +#define MSK_BRPE_GET			0x0f
> +#define MSK_CTRL_IE_SIE_EIE		0x07
> +#define MSK_MCONT_TXIE			0x08
> +#define MSK_MCONT_RXIE			0x10
> +#define MSK_ALL_THREE			0x07
> +#define MSK_ALL_FOUR			0x0f
> +#define MSK_ALL_EIGHT			0xff
> +#define MSK_ALL_ELEVEN			0x7ff
> +#define MSK_ALL_THIRTEEN		0x1fff
> +#define MSK_ALL_SIXTEEN			0xffff
> +
> +/* Error */
> +#define MSK_ES_TXERRCNT	((u32)0xff << BIT_ES_TXERRCNT)	/* Tx err count */
> +#define MSK_ES_RXERRCNT	((u32)0x7f << BIT_ES_RXERRCNT)	/* Rx err count */
> +
> +#define PCH_CAN_BIT_SET(reg, bitmask)	\
> +		(iowrite32((ioread32((reg)) | ((u32)(bitmask))), (reg)))
> +#define PCH_CAN_BIT_CLEAR(reg, bitmask)	\
> +		(iowrite32((ioread32((reg)) & ~((u32)(bitmask))), (reg)))

Please use static inline functions and try to avoid casts.

> +#define PCH_CAN_NO_TX_BUFF		1 /* The flag value for denoting the
> +					     unavailability of the transmit
> +					     message object. */
> +
> +#define ERROR_COUNT			96
> +#define PCH_CAN_MSG_DATA_LEN		8	/* CAN Msg data length */
> +
> +#define PCH_CAN_NULL			NULL
> +
> +#define PCI_DEVICE_ID_INTEL_PCH1_CAN	0x8818
> +#define DRIVER_NAME			"can"
> +
> +#define PCH_CAN_CLOCK_DEFAULT_OFFSET	0
> +#define PCH_CAN_CLOCK_62_5_OFFSET	0
> +#define PCH_CAN_CLOCK_24_OFFSET		8
> +#define PCH_CAN_CLOCK_50_OFFSET		16
> +
> +#define COUNTER_LIMIT 0xFFFF
> +
> +
> +
> +enum pch_can_listen_mode {
> +	PCH_CAN_ACTIVE = 0,
> +	PCH_CAN_LISTEN
> +};
> +
> +enum pch_can_run_mode {
> +	PCH_CAN_STOP = 0,
> +	PCH_CAN_RUN
> +};
> +
> +enum pch_can_arbiter {
> +	PCH_CAN_ROUND_ROBIN = 0,
> +	PCH_CAN_FIXED_PRIORITY
> +};
> +
> +enum pch_can_auto_restart {
> +	CAN_MANUAL = 0,
> +	CAN_AUTO
> +};

Please remove the above enums or explain why you need them.

> +enum pch_can_baud {
> +	PCH_CAN_BAUD_10 = 0,
> +	PCH_CAN_BAUD_20,
> +	PCH_CAN_BAUD_50,
> +	PCH_CAN_BAUD_125,
> +	PCH_CAN_BAUD_250,
> +	PCH_CAN_BAUD_500,
> +	PCH_CAN_BAUD_800,
> +	PCH_CAN_BAUD_1000
> +};

Dead code. Not used anywhere.

> +enum pch_can_interrupt {
> +	CAN_ENABLE,
> +	CAN_DISABLE,
> +	CAN_ALL,
> +	CAN_NONE
> +};
> +

Please remove the above enum or explain why you need it.

> +/**
> + * struct pch_can_msg - CAN message structure
> + * @ide:	Standard/extended msg
> + * @id:		11 or 29 bit msg id
> + * @dlc:	Size of data
> + * @data:	Message pay load
> + * @rtr:	RTR message
> + */
> +struct pch_can_msg {
> +	unsigned short ide;
> +	unsigned int id;
> +	unsigned short dlc;
> +	unsigned char data[PCH_CAN_MSG_DATA_LEN];
> +	unsigned short rtr;
> +};


Please remove the above intermediate struct or explain why you need it.

> +/**
> + * pch_can_timing - CAN bittiming structure
> + * @bitrate:	Bitrate (kbps)
> + * @cfg_bitrate:BRP
> + * @cfg_tseg1:	Tseg1
> + * @cfg_tseg2:	Tseg2
> + * @cfg_sjw:	Sync jump width
> + * @smpl_mode:	Sampling mode
> + * @edge_mode:	Edge R / D
> + */
> +struct pch_can_timing {
> +	unsigned int bitrate;
> +	unsigned int cfg_bitrate;
> +	unsigned int cfg_tseg1;
> +	unsigned int cfg_tseg2;
> +	unsigned int cfg_sjw;
> +	unsigned int smpl_mode;
> +	unsigned int edge_mode;
> +};
> +
> +/**
> + * struct pch_can_error - CAN error structure
> + * @rxgte96:	Rx err cnt >=96
> + * @txgte96:	Tx err cnt >=96
> + * @error_stat:	Error state of CAN node,
> + *		00=error active (normal)
> + *		01=error passive
> + *		1x=bus off
> + * @rx_err_cnt:	Rx error count
> + * @tx_err_cnt:	Tx error count
> + */
> +struct pch_can_error {
> +	unsigned int rxgte96;
> +	unsigned int txgte96;
> +	unsigned int error_stat;
> +	unsigned int rx_err_cnt;
> +	unsigned int tx_err_cnt;
> +};

Ditto.

> +/**
> + * struct pch_can_acc_filter - CAN Filter structure
> + * @id:		The id/mask data
> + * @id_ext:	Standard/extended ID
> + * @rtr:	RTR message
> + */
> +struct pch_can_acc_filter {
> +	unsigned int id;
> +	unsigned int id_ext;
> +	unsigned int rtr;
> +};

Ditto.

> +/**
> + * struct pch_can_rx_filter - CAN RX filter
> + * @num:	Filter number
> + * @umask:	UMask value
> + * @amr:	Acceptance Mask Reg
> + * @aidr:	Acceptance Control Reg
> + */
> +struct pch_can_rx_filter {
> +	unsigned int num;
> +	unsigned int umask;
> +	struct pch_can_acc_filter amr;
> +	struct pch_can_acc_filter aidr;
> +};

Ditto.

> +/**
> + * struct pch_can_os - structure to store the CAN device information.
> + * @can:		CAN: device handle
> + * @opened:		Linux opened device
> + * @can_num:		Linux: CAN Number
> + * @pci_remap:		Linux: MMap regs
> + * @dev:		Linux: PCI Device
> + * @irq:		Linux: IRQ
> + * @block_mode:		Blocking / non-blocking
> + * @read_wait_queue:	Linux: Read wait queue
> + * @write_wait_queue:	Linux: Write wait queue
> + * @write_wait_flag:	Linux: Write wait flag
> + * @read_wait_flag:	Linux: Read wait flag
> + * @open_spinlock:	Linux: Open lock variable
> + * @is_suspending:	Linux: Is suspending state
> + * @inode:		Linux: inode
> + * @timing:		CAN: timing
> + * @run_mode:		CAN: run mode
> + * @listen_mode:	CAN: listen mode
> + * @arbiter_mode:	CAN: arbiter mode
> + * @tx_enable:		CAN: Tx buffer state
> + * @rx_enable:		CAN: Rx buffer state
> + * @rx_link:		CAN: Rx link set
> + * @int_enables:	CAN: ints enabled
> + * @int_stat:		CAN: int status
> + * @bus_off_interrupt:	CAN: Buss off int flag
> + * @rx_filter:		CAN: Rx filters
> + * @ndev:		net_device pointer
> + * @tx_spinlock:	CAN: transmission lock variable
> + */
> +struct pch_can_os {
> +	struct can_hw *can;
> +	unsigned int opened;
> +	unsigned int can_num;
> +	void __iomem *pci_remap;
> +	struct pci_dev *dev;
> +	unsigned int irq;
> +	int block_mode;
> +	wait_queue_head_t read_wait_queue;
> +	wait_queue_head_t write_wait_queue;

Not used anywhere! Dead code :-(.

> +	unsigned int write_wait_flag;
> +	unsigned int read_wait_flag;
> +	spinlock_t open_spinlock;
> +	unsigned int is_suspending;
> +	struct inode *inode;
> +	struct pch_can_timing timing;
> +	enum pch_can_run_mode run_mode;
> +	enum pch_can_listen_mode listen_mode;
> +	enum pch_can_arbiter arbiter_mode;
> +	unsigned int tx_enable[MAX_MSG_OBJ];
> +	unsigned int rx_enable[MAX_MSG_OBJ];
> +	unsigned int rx_link[MAX_MSG_OBJ];
> +	unsigned int int_enables;
> +	unsigned int int_stat;
> +	unsigned int bus_off_interrupt;
> +	struct pch_can_rx_filter rx_filter[MAX_MSG_OBJ];
> +	struct net_device *ndev;
> +	spinlock_t tx_spinlock;
> +	struct mutex pch_mutex;
> +};

Why do you need an extra structure here? Is pch_can_priv not OK?

> +/**
> + * struct pch_can_priv - CAN driver private data structure
> + * @can:		MUST be first member/field
> + * @ndev:		Pointer to net_device structure
> + * @clk:		unused
> + * @base:		Base address
> + * @pch_can_os_p:	Pointer to CAN device information
> + * @have_msi:		PCI MSI mode flag
> + *
> + * Longer description of this structure.
> + */
> +struct pch_can_priv {
> +	struct can_priv can;
> +	struct net_device *ndev;
> +	struct clk *clk;
> +	void __iomem *base;
> +	struct pch_can_os pch_can_os_p;
> +	unsigned int have_msi;
> +};
> +
> +struct can_hw {
> +	void __iomem *io_base;
> +};

See above.

> +static unsigned int pch_can_clock = 50000; /*50MH*/
> +
> +/*
> +The number of message objects that has to be configured as receive/send
> +objects.
> +Topcliff CAN has total 32 message objects.
> +*/
> +static unsigned int pch_can_rx_buf_size = 1;
> +static unsigned int pch_can_tx_buf_size = 1;
> +
> +
> +static enum pch_can_auto_restart restat_mode = CAN_MANUAL; /* The variable used
> +							      to store the
> +							      restart mode. */
> +
> +static struct can_bittiming_const pch_can_bittiming_const = {
> +	.name = KBUILD_MODNAME,
> +	.tseg1_min = 1,
> +	.tseg1_max = 16,
> +	.tseg2_min = 1,
> +	.tseg2_max = 8,
> +	.sjw_max = 4,
> +	.brp_min = 1,
> +	.brp_max = 1024, /* 6bit + extended 4bit */
> +	.brp_inc = 1,
> +};
> +
> +static const struct pci_device_id pch_can_pcidev_id[] __devinitdata = {
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH1_CAN)},
> +	{}
> +};
> +
> +/*
> +This variable is used to store the configuration (receive /transmit) of the
> +available message objects.
> +This variable is used for storing the message object configuration related
> +information. It includes the information about which message object is used as
> +Receiver and Transmitter.
> +*/

Please use the usual Linux style for comments:

/*
 *
 */

> +static unsigned int pch_msg_obj_conf[MAX_MSG_OBJ] = {
> +	3, 3, 3, 3,
> +	3, 3, 3, 3,
> +	3, 3, 3, 3,
> +	3, 3, 3, 3,
> +	3, 3, 3, 3,
> +	3, 3, 3, 3,
> +	3, 3, 3, 3,
> +	3, 3, 3, 3
> +};
> +
> +static struct can_hw *pch_can_create(void __iomem *io_base,
> +				     struct net_device *ndev)
> +{
> +	struct can_hw *can;
> +
> +	if (!io_base) {
> +		dev_err(&ndev->dev, "%s -> Invalid IO Base\n", __func__);
> +		return NULL;
> +	}
> +
> +	/* Allocates memory for the handle. */
> +	can = kmalloc(sizeof(struct can_hw), GFP_KERNEL);
> +	if (!can) {	/* Allocation failed */
> +		dev_err(&ndev->dev,
> +			"%s -> CAN Memory allocation failed\n", __func__);
> +		return NULL;
> +	}
> +
> +	can->io_base = io_base;
> +	dev_dbg(&ndev->dev,
> +		"%s -> Handle Creation successful.\n", __func__);

Please restrict debugging output to a few useful messages for the final
user. Puh, I stop reviewing here because of too much issues, which have
already been pointed out with you previous patch. I share most of the
other comments on that patch. Please work on your *code quality*. I also
believe that *rewriting* the driver from *scratch* using an existing
Socket-CAN driver as example is the most efficient way towards a clean
and compact driver with, let's say, less than approximately 1000 lines
of code.

Wolfgang.

  parent reply	other threads:[~2010-09-15  7:35 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-09-13 12:22 [MeeGo-Dev][PATCH v2] Topcliff: Update PCH_CAN driver to 2.6.35 Masayuki Ohtak
2010-09-13 15:14 ` Marc Kleine-Budde
2010-09-13 15:14   ` Marc Kleine-Budde
2010-09-16  8:51   ` Masayuki Ohtake
2010-09-16  8:51     ` Masayuki Ohtake
2010-09-16  9:10     ` Wolfgang Grandegger
2010-09-16  9:10       ` Wolfgang Grandegger
2010-09-16 23:55       ` Masayuki Ohtake
2010-09-16 23:55         ` Masayuki Ohtake
2010-09-13 18:47 ` Daniel Baluta
2010-09-13 18:47   ` Daniel Baluta
2010-09-15  7:36 ` Wolfgang Grandegger [this message]
2010-09-15  7:36   ` Wolfgang Grandegger
  -- strict thread matches above, loose matches on Subject: below --
2010-09-13 12:22 Masayuki Ohtak

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4C90776C.8040000@grandegger.com \
    --to=wg@grandegger.com \
    --cc=21cnbao@gmail.com \
    --cc=andrew.chih.howe.khor@intel.com \
    --cc=arjan@linux.intel.com \
    --cc=chripell@fsfe.org \
    --cc=davem@davemloft.net \
    --cc=gregkh@suse.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=masa-korg@dsn.okisemi.com \
    --cc=meego-dev@meego.com \
    --cc=morinaga526@dsn.okisemi.com \
    --cc=netdev@vger.kernel.org \
    --cc=qi.wang@intel.com \
    --cc=sameo@linux.intel.com \
    --cc=socketcan-core@lists.berlios.de \
    --cc=w.sang@pengutronix.de \
    --cc=yong.y.wang@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.