* Re: [PATCH 3/3] netfilter: xt_CT: remove a compile warning
From: Tetsuo Handa @ 2012-04-03 12:28 UTC (permalink / raw)
To: pablo; +Cc: netdev
In-Reply-To: <20120403120900.GB6010@1984>
Pablo Neira Ayuso wrote:
> Indeed. The patch attached should fix this problem. Thanks.
It seems to me that the timeout object is associated with the "ct"
by successful nf_ct_timeout_ext_add() call. If yes,
+err5:
+ xt_ct_tg_timeout_put(ct);
will not be able to find the timeout object.
^ permalink raw reply
* Re: [PATCH v6 0/2] Ethernet drivers for WIZnet chips
From: Eric Dumazet @ 2012-04-03 12:29 UTC (permalink / raw)
To: Mike Sinkovsky; +Cc: netdev, linux-kernel
In-Reply-To: <4F7AE9D3.80204@permonline.ru>
On Tue, 2012-04-03 at 18:15 +0600, Mike Sinkovsky wrote:
> 03.04.2012 17:39, Eric Dumazet написал:
> > On Tue, 2012-04-03 at 16:58 +0600, Mike Sinkovsky wrote:
> >> Based on original driver from chip manufacturer, but nearly full rewite.
> >> Tested and used in production with Blackfin BF531 embedded processor.
> >>
> >> Signed-off-by: Mike Sinkovsky<msink@permonline.ru>
> >> ---
> >> v6:
> >> - remove (S0_TX_FSR< skb->len) check in TX handler, it doesn't work
> >> anyway. Chip can transmit only one frame with MTU 1500 at a time,
> >> and tx buffer size is bigger.
> >
> > So what happens if XXX frames are given to start_xmit() in a flood ?
> >
> > You removed any flow control, how can this work ?
> >
> > Device has an infinite queue ?
>
> As I understand from datasheet, device doesn't have tx queue at all.
> It have tx buffer, processor must save transmitted frame to it, and then
> save SEND command to command register. When transmission completed,
> SENDOK bit in interrupt register will be set to '1', and interrupt
> handler will be called.
>
> So, according to datasheet, driver must stop queue in start_xmit()
> routine, and wake in interrupt handler of SENDOK bit.
> I tried this, and it basically works, but SOMETIMES, very rare, I see
> tx_timeout().
>
> And without any flow control - driver works perfectly.
> Weird, don't know why.
Really this should be fixed, since your driver makes qdisc flow control
impossible (unless adding a rate limiter like HTB/CBQ)
You probably had a race on your xmit routine, and interrupt routine.
You need proper synchronization : A spinlock to make this easy, or a
smart barrier game.
^ permalink raw reply
* [PATCH] ARM: OMAP: AM33XX: CAN: d_can: Add support for Bosch D_CAN controller
From: AnilKumar Ch @ 2012-04-03 12:32 UTC (permalink / raw)
To: socketcan, m.kleine-budde, wg
Cc: linux-can, netdev, linux-omap, linux-kernel, anantgole, nsekhar,
AnilKumar Ch
This patch adds the support for Bosch D_CAN controller.
Bosch D_CAN controller is a full-CAN implementation compliant to
CAN protocol version 2.0 part A and B. Bosch D_CAN user manual
can be obtained from: http://www.semiconductors.bosch.de/media/
en/pdf/ipmodules_1/can/d_can_users_manual_111.pdf
D_CAN device is used on many SoCs like AM335x, DM8148 and DM813x
EVMs from TI, D_CAN details on AM335x can be accessed from:
http://www.ti.com/lit/ug/spruh73c/spruh73c.pdf
D_CAN can be configurable for 16, 32, 64 and 128 message objects.
The driver implementation is based on 64 message objects.
Following are the design choices made while writing the controller
driver:
1. Interface Register set IF0 has be used for receive and IF1 is
used for transmit message objects.
2. Out of the total Message objects available, half of it are kept
aside for RX purposes and the rest for TX purposes.
3. NAPI implementation is such that both the TX and RX paths
functions in polling mode.
Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
---
drivers/net/can/Kconfig | 14 +
drivers/net/can/Makefile | 1 +
drivers/net/can/d_can.c | 1487 ++++++++++++++++++++++++++++++++++++
include/linux/can/platform/d_can.h | 40 +
4 files changed, 1542 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/can/d_can.c
create mode 100644 include/linux/can/platform/d_can.h
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index bb709fd..2529cba 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -68,6 +68,20 @@ config CAN_TI_HECC
Driver for TI HECC (High End CAN Controller) module found on many
TI devices. The device specifications are available from www.ti.com
+config CAN_D_CAN
+ tristate "Bosch D_CAN Controller"
+ depends on CAN_DEV
+ ---help---
+ This driver adds support for the D_CAN device found in
+ many SoCs like am335x, dm814x and dm813x boards from TI.
+
+ The device user guide can be accessed from
+ http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/
+ can/d_can_users_manual_111.pdf
+
+ To compile this driver as a module, choose M here: the
+ module will be called d_can.
+
config CAN_MCP251X
tristate "Microchip MCP251x SPI CAN controllers"
depends on CAN_DEV && SPI && HAS_DMA
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 938be37..4bd3a87 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_CAN_C_CAN) += c_can/
obj-$(CONFIG_CAN_CC770) += cc770/
obj-$(CONFIG_CAN_AT91) += at91_can.o
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
+obj-$(CONFIG_CAN_D_CAN) += d_can.o
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
obj-$(CONFIG_CAN_BFIN) += bfin_can.o
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
diff --git a/drivers/net/can/d_can.c b/drivers/net/can/d_can.c
new file mode 100644
index 0000000..51e2986
--- /dev/null
+++ b/drivers/net/can/d_can.c
@@ -0,0 +1,1487 @@
+/*
+ * CAN bus driver for Bosch D_CAN controller
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Borrowed from C_CAN driver
+ * Copyright (C) 2010 ST Microelectronics
+ * - Bhupesh Sharma <bhupesh.sharma@st.com>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
+ * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
+ *
+ * Bosch D_CAN controller is compliant to CAN protocol version 2.0 part A and B.
+ * Bosch D_CAN user manual can be obtained from:
+ * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/
+ * d_can_users_manual_111.pdf
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/jiffies.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/can/platform/d_can.h>
+
+#define D_CAN_DRV_NAME "d_can"
+#define D_CAN_VERSION "1.0"
+#define D_CAN_DRV_DESC "CAN bus driver for Bosch D_CAN controller " \
+ D_CAN_VERSION
+
+/* TI D_CAN module registers */
+#define D_CAN_CTL 0x0 /* CAN control register */
+#define D_CAN_ES 0x4 /* Error and status */
+#define D_CAN_PARITYERR_EOI 0x4 /* Parity error EOI */
+#define D_CAN_ERRC 0x8 /* Error counter */
+#define D_CAN_BTR 0xC /* Bit timing */
+#define D_CAN_INT 0x10 /* Interrupt register */
+#define D_CAN_TEST 0x14 /* Test register */
+#define D_CAN_PERR 0x1C /* Parity Error Code */
+#define D_CAN_ABOTR 0x80 /* Auto-Bus-On Time */
+#define D_CAN_TXRQ_X 0x84 /* Transmission Request X */
+#define D_CAN_TXRQ(n) (0x88 + ((n) * 4)) /* Transmission request */
+#define D_CAN_NWDAT_X 0x98 /* New data X register */
+#define D_CAN_NWDAT(n) (0x9C + ((n) * 4)) /* New data */
+#define D_CAN_INTPND_X 0xAC /* Interrupt Pending X */
+#define D_CAN_INTPND(n) (0xB0 + ((n) * 4)) /* Interrupt Pending */
+#define D_CAN_MSGVAL_X 0xC0 /* Message Valid X */
+#define D_CAN_MSGVAL(n) (0xC4 + ((n) * 4)) /* Message Valid */
+#define D_CAN_INTMUX(n) (0xD8 + ((n) * 4)) /* Interrupt Multiplexer */
+#define D_CAN_IFCMD(n) (0x100 + ((n) * 0x20)) /* Command */
+#define D_CAN_IFMSK(n) (0x104 + ((n) * 0x20)) /* Mask */
+#define D_CAN_IFARB(n) (0x108 + ((n) * 0x20)) /* Arbitration */
+#define D_CAN_IFMCTL(n) (0x10c + ((n) * 0x20)) /* Message ctl */
+#define D_CAN_IFDATA(n) (0x110 + ((n) * 0x20)) /* DATA A */
+#define D_CAN_IFDATB(n) (0x114 + ((n) * 0x20)) /* DATA B */
+#define D_CAN_IF3OBS 0x140 /* IF3 Observation */
+#define D_CAN_IF3UPD(n) (0x160 + ((n) * 4)) /* Update enable */
+#define D_CAN_TIOC 0x1E0 /* CAN TX IO Control */
+#define D_CAN_RIOC 0x1E4 /* CAN RX IO Control */
+
+/* Control register Bit fields */
+#define D_CAN_CTL_WUBA BIT(26) /* Automatic wake-up on bus activity */
+#define D_CAN_CTL_PDR BIT(24) /* Request for local low power mode */
+#define D_CAN_CTL_DE3 BIT(20) /* Enable DMA request line for IF3 */
+#define D_CAN_CTL_DE2 BIT(19) /* Enable DMA request line for IF2 */
+#define D_CAN_CTL_DE1 BIT(18) /* Enable DMA request line for IF1 */
+#define D_CAN_CTL_IE1 BIT(17) /* Interrupt line 1 enable */
+#define D_CAN_CTL_INITDBG BIT(16) /* Init state for debug access */
+#define D_CAN_CTL_SWR BIT(15) /* S/W reset enable */
+#define D_CAN_CTL_PMD (0xF << 10) /* Parity on/off */
+#define D_CAN_CTL_ABO BIT(9) /* Auto bus on enable */
+#define D_CAN_CTL_IDS BIT(8) /* Interruption debug support enable */
+#define D_CAN_CTL_TEST BIT(7) /* Test mode enable */
+#define D_CAN_CTL_CCE BIT(6) /* Configuration change enable */
+#define D_CAN_CTL_DISABLE_AR BIT(5) /* Disable automatic retransmission */
+#define D_CAN_CTL_EIE BIT(3) /* Error interrupt enable */
+#define D_CAN_CTL_SIE BIT(2) /* Status change int enable */
+#define D_CAN_CTL_IE0 BIT(1) /* Interrupt line 0 enable */
+#define D_CAN_CTL_INIT BIT(0) /* D_CAN initialization mode */
+
+/* D_CAN Error and Status and Parity Error EOI reg bit fields */
+#define D_CAN_ES_PDA BIT(10) /* Local power-down ACK */
+#define D_CAN_ES_WUP BIT(9) /* Wkae up pending */
+#define D_CAN_ES_PER BIT(8) /* Parity error detected */
+#define D_CAN_ES_BOFF BIT(7) /* Bus off state */
+#define D_CAN_ES_EWARN BIT(6) /* Warning state */
+#define D_CAN_ES_EPASS BIT(5) /* Error passive state */
+#define D_CAN_ES_RXOK BIT(4) /* Received a msg successfully */
+#define D_CAN_ES_TXOK BIT(3) /* Transmitted a msg successfully */
+#define D_CAN_ES_LEC_MASK 0x7 /* Last error code */
+
+/* Error counter reg bit fields */
+#define D_CAN_ERRC_RP_MASK BIT(15) /* Receive error passive */
+#define D_CAN_ERRC_REC_SHIFT 8
+#define D_CAN_ERRC_REC_MASK (0x7F << 8) /* Receive err counter */
+#define D_CAN_ERRC_TEC_MASK (0xFF << 0) /* Transmit err counter */
+
+/* Bit timing reg bit fields */
+#define D_CAN_BTR_BRPE_SHIFT 16 /* Baud rate prescaler ext */
+#define D_CAN_BTR_TSEG2_SHIFT 12 /* Time seg after smpl point */
+#define D_CAN_BTR_TSEG1_SHIFT 8 /* Time seg before smpl point */
+#define D_CAN_BTR_SJW_SHIFT 6 /* Syncronization jump width */
+#define D_CAN_BTR_BRP_SHIFT 0 /* Baud rate prescaler */
+
+/* D_CAN Test register bit fields */
+#define D_CAN_TEST_RDA BIT(9) /* RAM direct access enable */
+#define D_CAN_TEST_EXL BIT(8) /* External loopback mode */
+#define D_CAN_TEST_RX BIT(7) /* Monitors the reveive pin */
+#define D_CAN_TEST_TX (0x3 << 5) /* Control of CAN_TX pin */
+#define D_CAN_TEST_LBACK BIT(4) /* Loopback mode */
+#define D_CAN_TEST_SILENT BIT(3) /* Silent mdoe */
+
+/* D_CAN IF command reg bit fields */
+#define D_CAN_IF_CMD_WR BIT(23) /* Write/read */
+#define D_CAN_IF_CMD_MASK BIT(22) /* Access to mask bits */
+#define D_CAN_IF_CMD_ARB BIT(21) /* Access to arbitration bits */
+#define D_CAN_IF_CMD_CONTROL BIT(20) /* Acess to control bits */
+#define D_CAN_IF_CMD_CIP BIT(19) /* Clear int pending */
+#define D_CAN_IF_CMD_TXRQST BIT(18) /* Access transmission request */
+#define D_CAN_IF_CMD_DATAA BIT(17) /* Access to Data Bytes 0-3 */
+#define D_CAN_IF_CMD_DATAB BIT(16) /* Access to Data Bytes 4-7 */
+#define D_CAN_IF_CMD_BUSY BIT(15) /* Busy flag */
+#define D_CAN_IF_CMD_DAM BIT(14) /* Activation of DMA */
+#define D_CAN_IF_CMD_MN_MASK 0xFF /* No. of msg's used for DMA T/F */
+#define D_CAN_IF_CMD_ALL (D_CAN_IF_CMD_MASK | D_CAN_IF_CMD_ARB | \
+ D_CAN_IF_CMD_CONTROL | D_CAN_IF_CMD_TXRQST | \
+ D_CAN_IF_CMD_DATAA | D_CAN_IF_CMD_DATAB)
+
+/* D_CAN IF mask reg bit fields */
+#define D_CAN_IF_MASK_MX BIT(31) /* Mask Extended Identifier */
+#define D_CAN_IF_MASK_MD BIT(30) /* Mask Message direction */
+
+/* D_CAN IF Arbitration */
+#define D_CAN_IF_ARB_MSGVAL BIT(31) /* Message Vaild */
+#define D_CAN_IF_ARB_MSGXTD BIT(30) /* Extended Identifier 0-11 1-29 */
+#define D_CAN_IF_ARB_DIR_XMIT BIT(29) /* Message direction 0-R 1-T */
+
+/* D_CAN IF Message control */
+#define D_CAN_IF_MCTL_NEWDAT BIT(15) /* New data available */
+#define D_CAN_IF_MCTL_MSGLST BIT(14) /* Message lost, only for receive */
+#define D_CAN_IF_MCTL_INTPND BIT(13) /* Interrupt pending */
+#define D_CAN_IF_MCTL_UMASK BIT(12) /* Use acceptance mask */
+#define D_CAN_IF_MCTL_TXIE BIT(11) /* Transmit int enable */
+#define D_CAN_IF_MCTL_RXIE BIT(10) /* Receive int enable */
+#define D_CAN_IF_MCTL_RMTEN BIT(9) /* Remote enable */
+#define D_CAN_IF_MCTL_TXRQST BIT(8) /* Transmit request */
+#define D_CAN_IF_MCTL_EOB BIT(7) /* Data frames */
+#define D_CAN_IF_MCTL_DLC_MASK 0xF /* Data length code */
+
+/* D_CAN IF3 Observation reg bit fields */
+#define D_CAN_IF3OBS_UP BIT(15) /* Update data status */
+#define D_CAN_IF3OBS_SDB BIT(12) /* DataB read out status */
+#define D_CAN_IF3OBS_SDA BIT(11) /* DataA read out status */
+#define D_CAN_IF3OBS_SC BIT(10) /* Contol bits read out status */
+#define D_CAN_IF3OBS_SA BIT(9) /* Arbitration read out status */
+#define D_CAN_IF3OBS_SM BIT(8) /* Mask bits read out status */
+#define D_CAN_IF3OBS_DB BIT(4) /* Data B read observation */
+#define D_CAN_IF3OBS_DA BIT(3) /* Data A read observation */
+#define D_CAN_IF3OBS_CTL BIT(2) /* Control read observation */
+#define D_CAN_IF3OBS_ARB BIT(1) /* Arbitration data read observation */
+#define D_CAN_IF3OBS_MASK BIT(0) /* Mask data read observation */
+
+/* D_CAN TX I/O reg bit fields */
+#define D_CAN_TIOC_PU BIT(18) /* CAN_TX pull up/down select */
+#define D_CAN_TIOC_PD BIT(17) /* CAN_TX pull disable */
+#define D_CAN_TIOC_OD BIT(16) /* CAN_TX open drain enable */
+#define D_CAN_TIOC_FUNC BIT(3) /* CAN_TX function */
+#define D_CAN_TIOC_DIR BIT(2) /* CAN_TX data direction */
+#define D_CAN_TIOC_OUT BIT(1) /* CAN_TX data out write */
+#define D_CAN_TIOC_IN BIT(0) /* CAN_TX data in */
+
+/* D_CAN RX I/O reg bit fields */
+#define D_CAN_RIOC_PU BIT(18) /* CAN_RX pull up/down select */
+#define D_CAN_RIOC_PD BIT(17) /* CAN_RX pull disable */
+#define D_CAN_RIOC_OD BIT(16) /* CAN_RX open drain enable */
+#define D_CAN_RIOC_FUNC BIT(3) /* CAN_RX function */
+#define D_CAN_RIOC_DIR BIT(2) /* CAN_RX data direction */
+#define D_CAN_RIOC_OUT BIT(1) /* CAN_RX data out write */
+#define D_CAN_RIOC_IN BIT(0) /* CAN_RX data in */
+
+/* IF register masks */
+#define IFX_WRITE_IDR(x) ((x) & 0x1FFFFFFF)
+#define IFX_CMD_BITS(x) ((x) & 0xFFFFFF00)
+#define IFX_CMD_MSG_NUMBER(x) ((x) & 0xFF)
+
+/* Message objects split */
+#define D_CAN_NUM_MSG_OBJECTS 64
+#define D_CAN_NUM_RX_MSG_OBJECTS 32
+#define D_CAN_NUM_TX_MSG_OBJECTS 32
+
+#define D_CAN_MSG_OBJ_RX_FIRST 1
+#define D_CAN_MSG_OBJ_RX_LAST (D_CAN_MSG_OBJ_RX_FIRST + \
+ D_CAN_NUM_RX_MSG_OBJECTS - 1)
+
+#define D_CAN_MSG_OBJ_TX_FIRST (D_CAN_MSG_OBJ_RX_LAST + 1)
+#define D_CAN_MSG_OBJ_TX_LAST (D_CAN_MSG_OBJ_TX_FIRST + \
+ D_CAN_NUM_TX_MSG_OBJECTS - 1)
+
+#define D_CAN_MSG_OBJ_RX_SPLIT 17
+#define D_CAN_MSG_OBJ_RX_LOW_LAST (D_CAN_MSG_OBJ_RX_SPLIT - 1)
+
+#define D_CAN_NEXT_MSG_OBJ_MASK (D_CAN_NUM_TX_MSG_OBJECTS - 1)
+
+/* global interrupt masks */
+#define D_CAN_ENABLE_ALL_INTERRUPTS 1
+#define D_CAN_DISABLE_ALL_INTERRUPTS 0
+
+/* status interrupt */
+#define D_CAN_STATUS_INTERRUPT 0x8000
+
+#define D_CAN_BUSY_TIMEOUT 14
+#define D_CAN_TIMEOUT_MS 1000
+
+/* Interface register bank number */
+#define D_CAN_IF_RX_NUM 0
+#define D_CAN_IF_TX_NUM 1
+
+#define D_CAN_GET_XREG_NUM(priv, reg) (__ffs(d_can_read(priv, reg)) >> 2)
+
+/* d_can private data structure */
+struct d_can_priv {
+ struct can_priv can; /* must be the first member */
+ struct napi_struct napi;
+ struct net_device *dev;
+ struct platform_device *pdev;
+ unsigned int tx_next;
+ unsigned int tx_echo;
+ u32 current_status;
+ u32 last_status;
+ u32 irqstatus;
+ bool is_opened;
+ void __iomem *base;
+ void (*ram_init) (unsigned int, unsigned int);
+};
+
+/* CAN Bittiming constants as per D_CAN specs */
+static struct can_bittiming_const d_can_bittiming_const = {
+ .name = D_CAN_DRV_NAME,
+ .tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */
+ .tseg1_max = 16,
+ .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024, /* 6-bit BRP field + 4-bit BRPE field*/
+ .brp_inc = 1,
+};
+
+/* d_can last error code (lec) values */
+enum d_can_lec_type {
+ LEC_NO_ERROR = 0,
+ LEC_STUFF_ERROR,
+ LEC_FORM_ERROR,
+ LEC_ACK_ERROR,
+ LEC_BIT1_ERROR,
+ LEC_BIT0_ERROR,
+ LEC_CRC_ERROR,
+ LEC_UNUSED,
+};
+
+/* d_can error types */
+enum d_can_bus_error_types {
+ NO_ERROR = 0,
+ BUS_OFF,
+ ERROR_WARNING,
+ ERROR_PASSIVE,
+};
+
+static inline void d_can_write(struct d_can_priv *priv, u32 reg, u32 val)
+{
+ writel(val, priv->base + reg);
+}
+
+static inline u32 d_can_read(struct d_can_priv *priv, u32 reg)
+{
+ return readl(priv->base + reg);
+}
+
+static inline void d_can_set_bit(struct d_can_priv *priv, u32 reg, u32 bitmask)
+{
+ d_can_write(priv, reg, d_can_read(priv, reg) | bitmask);
+}
+
+static inline u32 d_can_get_bit(struct d_can_priv *priv, u32 reg, u32 bitmask)
+{
+ return (d_can_read(priv, reg) & bitmask) ? 1 : 0;
+}
+
+static inline void d_can_clear_bit(struct d_can_priv *priv, u32 reg,
+ u32 bitmask)
+{
+ d_can_write(priv, reg, d_can_read(priv, reg) & ~bitmask);
+}
+
+static inline int get_tx_next_msg_obj(const struct d_can_priv *priv)
+{
+ return (priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) +
+ D_CAN_MSG_OBJ_TX_FIRST;
+}
+
+static inline int get_tx_echo_msg_obj(const struct d_can_priv *priv)
+{
+ return (priv->tx_echo & D_CAN_NEXT_MSG_OBJ_MASK) +
+ D_CAN_MSG_OBJ_TX_FIRST;
+}
+
+static void d_can_interrupts(struct d_can_priv *priv, unsigned int enable)
+{
+ unsigned int cntrl_save = d_can_read(priv, D_CAN_CTL);
+
+ if (enable)
+ cntrl_save |= (D_CAN_CTL_IE1 | D_CAN_CTL_EIE |
+ D_CAN_CTL_SIE | D_CAN_CTL_IE0);
+ else
+ cntrl_save &= ~(D_CAN_CTL_IE1 | D_CAN_CTL_EIE |
+ D_CAN_CTL_SIE | D_CAN_CTL_IE0);
+
+ d_can_write(priv, D_CAN_CTL, cntrl_save);
+}
+
+static inline int d_can_msg_obj_is_busy(struct d_can_priv *priv, u32 iface)
+{
+ unsigned long time_out = jiffies + msecs_to_jiffies(D_CAN_BUSY_TIMEOUT);
+
+ /* Check the status of busy bit */
+ while (d_can_get_bit(priv, D_CAN_IFCMD(iface), D_CAN_IF_CMD_BUSY) &&
+ time_after(time_out, jiffies))
+ cpu_relax();
+
+ if (time_after(jiffies, time_out))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static inline void d_can_object_get(struct net_device *dev,
+ u32 iface, u32 objno, u32 mask)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ d_can_write(priv, D_CAN_IFCMD(iface), IFX_CMD_BITS(mask) |
+ IFX_CMD_MSG_NUMBER(objno));
+
+ /*
+ * As per specs, after writing the message object number in the
+ * IF command register the transfer b/w interface register and
+ * message RAM must be complete in 4 - 14 CAN-CLK period.
+ */
+ if (d_can_msg_obj_is_busy(priv, iface))
+ netdev_err(dev, "timed out in object get\n");
+}
+
+static inline void d_can_object_put(struct net_device *dev,
+ u32 iface, u32 objno, u32 mask)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ d_can_write(priv, D_CAN_IFCMD(iface), D_CAN_IF_CMD_WR |
+ IFX_CMD_BITS(mask) | IFX_CMD_MSG_NUMBER(objno));
+
+ /*
+ * As per specs, after writing the message object number in the
+ * IF command register the transfer b/w interface register and
+ * message RAM must be complete in 4 - 14 CAN-CLK period.
+ */
+ if (d_can_msg_obj_is_busy(priv, iface))
+ netdev_err(dev, "timed out in object put\n");
+}
+
+static void d_can_write_msg_object(struct net_device *dev, u32 iface,
+ struct can_frame *frame, u32 objno)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+ unsigned int id;
+ u32 flags = 0;
+
+ if (!(frame->can_id & CAN_RTR_FLAG))
+ flags |= D_CAN_IF_ARB_DIR_XMIT;
+
+ if (frame->can_id & CAN_EFF_FLAG) {
+ id = frame->can_id & CAN_EFF_MASK;
+ flags |= D_CAN_IF_ARB_MSGXTD;
+ } else
+ id = ((frame->can_id & CAN_SFF_MASK) << 18);
+
+ flags |= D_CAN_IF_ARB_MSGVAL;
+ d_can_write(priv, D_CAN_IFARB(iface), IFX_WRITE_IDR(id) | flags);
+
+ /* Writing lower 4bytes to DATAA IF register */
+ d_can_write(priv, D_CAN_IFDATA(iface),
+ le32_to_cpu(*(u32 *)(frame->data)));
+
+ /* Writing higher 4bytes to DATAB IF register */
+ if (frame->can_dlc > 4)
+ d_can_write(priv, D_CAN_IFDATB(iface),
+ le32_to_cpu(*(u32 *)(frame->data + 4)));
+
+ /* enable TX interrupt for this message object */
+ d_can_write(priv, D_CAN_IFMCTL(iface),
+ D_CAN_IF_MCTL_TXIE | D_CAN_IF_MCTL_EOB |
+ D_CAN_IF_MCTL_TXRQST | D_CAN_IF_MCTL_NEWDAT |
+ frame->can_dlc);
+
+ /* Put message data into message RAM */
+ d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ALL);
+}
+
+/*
+ * Mark that this particular message object is received and clearing
+ * the interrupt pending register value.
+ */
+static inline void d_can_mark_rx_msg_obj(struct net_device *dev,
+ u32 iface, u32 ctrl_mask, u32 objno)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ d_can_write(priv, D_CAN_IFMCTL(iface), ctrl_mask &
+ ~(D_CAN_IF_MCTL_MSGLST | D_CAN_IF_MCTL_INTPND));
+ d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_CONTROL);
+}
+
+static inline void d_can_activate_all_lower_rx_msg_objs(struct net_device *dev,
+ u32 iface, u32 ctrl_mask)
+{
+ unsigned int i;
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ for (i = D_CAN_MSG_OBJ_RX_FIRST; i <= D_CAN_MSG_OBJ_RX_LOW_LAST; i++) {
+ d_can_write(priv, D_CAN_IFMCTL(iface), ctrl_mask &
+ ~(D_CAN_IF_MCTL_MSGLST | D_CAN_IF_MCTL_INTPND |
+ D_CAN_IF_MCTL_NEWDAT));
+ d_can_object_put(dev, iface, i, D_CAN_IF_CMD_CONTROL);
+ }
+}
+
+static inline void d_can_activate_rx_msg_obj(struct net_device *dev,
+ u32 iface, u32 ctrl_mask, u32 objno)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ d_can_write(priv, D_CAN_IFMCTL(iface), ctrl_mask &
+ ~(D_CAN_IF_MCTL_MSGLST | D_CAN_IF_MCTL_INTPND |
+ D_CAN_IF_MCTL_NEWDAT));
+ d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_CONTROL);
+}
+
+static void d_can_handle_lost_msg_obj(struct net_device *dev,
+ u32 iface, u32 objno)
+{
+ struct d_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);
+ d_can_object_get(dev, iface, objno, D_CAN_IF_CMD_ALL &
+ ~D_CAN_IF_CMD_TXRQST);
+ d_can_clear_bit(priv, D_CAN_IFMCTL(iface), D_CAN_IF_MCTL_MSGLST);
+ d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_CONTROL);
+
+ /* create an error msg */
+ skb = alloc_can_err_skb(dev, &frame);
+ if (unlikely(!skb))
+ return;
+
+ frame->can_id |= CAN_ERR_CRTL;
+ frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+ stats->rx_errors++;
+ stats->rx_over_errors++;
+
+ netif_receive_skb(skb);
+}
+
+static int d_can_read_msg_object(struct net_device *dev, u32 iface, u32 ctrl)
+{
+ unsigned int arb_val, mctl_val;
+ struct d_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *frame;
+ struct sk_buff *skb;
+ u32 data = 0;
+
+ skb = alloc_can_skb(dev, &frame);
+ if (!skb) {
+ stats->rx_dropped++;
+ return -ENOMEM;
+ }
+
+ frame->can_dlc = get_can_dlc(ctrl & 0x0F);
+ arb_val = d_can_read(priv, D_CAN_IFARB(iface));
+ mctl_val = d_can_read(priv, D_CAN_IFMCTL(iface));
+
+ if (arb_val & D_CAN_IF_ARB_MSGXTD)
+ frame->can_id = (arb_val & CAN_EFF_MASK) | CAN_EFF_FLAG;
+ else
+ frame->can_id = (arb_val >> 18) & CAN_SFF_MASK;
+
+ if (mctl_val & D_CAN_IF_MCTL_RMTEN)
+ frame->can_id |= CAN_RTR_FLAG;
+ else {
+ data = d_can_read(priv, D_CAN_IFDATA(iface));
+ /* Writing MO lower 4 data bytes to skb */
+ *(u32 *)(frame->data) = cpu_to_le32(data);
+
+ /* Writing MO higher 4 data bytes to skb */
+ if (frame->can_dlc > 4) {
+ data = d_can_read(priv, D_CAN_IFDATB(iface));
+ *(u32 *)(frame->data + 4) = cpu_to_le32(data);
+ } else
+ *(u32 *)(frame->data + 4) = 0;
+ }
+
+ netif_receive_skb(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += frame->can_dlc;
+
+ return 0;
+}
+
+static void d_can_setup_receive_object(struct net_device *dev, u32 iface,
+ u32 objno, u32 mask, u32 id, u32 mcont)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ d_can_write(priv, D_CAN_IFMCTL(iface), mcont);
+ d_can_write(priv, D_CAN_IFMSK(iface), IFX_WRITE_IDR(mask));
+ d_can_write(priv, D_CAN_IFARB(iface), IFX_WRITE_IDR(id) |
+ D_CAN_IF_ARB_MSGVAL);
+ d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ALL &
+ ~D_CAN_IF_CMD_TXRQST);
+
+ netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, d_can_read(priv,
+ D_CAN_MSGVAL(D_CAN_GET_XREG_NUM(priv, D_CAN_MSGVAL_X))));
+}
+
+static void d_can_inval_msg_object(struct net_device *dev, u32 iface, u32 objno)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ d_can_write(priv, D_CAN_IFARB(iface), 0);
+ d_can_write(priv, D_CAN_IFMCTL(iface), 0);
+ d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ARB |
+ D_CAN_IF_CMD_CONTROL);
+
+ netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, d_can_read(priv,
+ D_CAN_MSGVAL(D_CAN_GET_XREG_NUM(priv, D_CAN_MSGVAL_X))));
+}
+
+static inline int d_can_is_next_tx_obj_busy(struct d_can_priv *priv, u32 objno)
+{
+ u32 txrq_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_TXRQ_X);
+
+ /* Transmission request register's bit n-1 corresponds to
+ * message object n, we need to handle the same properly */
+ if (d_can_read(priv, D_CAN_TXRQ(txrq_x_reg_val)) &
+ (1 << (objno - D_CAN_MSG_OBJ_TX_FIRST)))
+ return 1;
+
+ return 0;
+}
+
+static netdev_tx_t d_can_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ u32 msg_obj_no;
+ struct d_can_priv *priv = netdev_priv(dev);
+ struct can_frame *frame = (struct can_frame *)skb->data;
+
+ if (can_dropped_invalid_skb(dev, skb))
+ return NETDEV_TX_OK;
+
+ msg_obj_no = get_tx_next_msg_obj(priv);
+
+ /* prepare message object for transmission */
+ d_can_write_msg_object(dev, D_CAN_IF_TX_NUM, frame, msg_obj_no);
+ can_put_echo_skb(skb, dev, msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST);
+
+ /*
+ * we have to stop the queue in case of a wrap around or
+ * if the next TX message object is still in use
+ */
+ priv->tx_next++;
+ if (d_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
+ ((priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) == 0))
+ netif_stop_queue(dev);
+
+ return NETDEV_TX_OK;
+}
+
+static void d_can_set_bittiming(struct net_device *dev)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+ const struct can_bittiming *bt = &priv->can.bittiming;
+ u32 can_btc;
+
+ can_btc = ((bt->phase_seg2 - 1) & 0x7) << D_CAN_BTR_TSEG2_SHIFT;
+ can_btc |= ((bt->phase_seg1 + bt->prop_seg - 1) & 0xF) <<
+ D_CAN_BTR_TSEG1_SHIFT;
+ can_btc |= ((bt->sjw - 1) & 0x3) << D_CAN_BTR_SJW_SHIFT;
+ /* Ten bits contains the BRP, 6 bits for BRP and upper 4 bits for brpe*/
+ can_btc |= ((bt->brp - 1) & 0x3F) << D_CAN_BTR_BRP_SHIFT;
+ can_btc |= ((((bt->brp - 1) >> 6) & 0xF) << D_CAN_BTR_BRPE_SHIFT);
+
+ d_can_write(priv, D_CAN_BTR, can_btc);
+ netdev_info(dev, "setting CAN BT = %#x\n", can_btc);
+}
+
+/*
+ * Configure D_CAN message objects for Tx and Rx purposes:
+ * D_CAN provides a total of 64 message objects that can be configured
+ * either for Tx or Rx purposes. In this driver first 32 message objects
+ * are used as a reception FIFO and the reception FIFO is signified by the
+ * EoB bit being SET. The remaining 32 message objects are kept aside for
+ * Tx purposes. See user guide document for further details on configuring
+ * message objects.
+ */
+static void d_can_configure_msg_objects(struct net_device *dev)
+{
+ unsigned int i;
+
+ /* first invalidate all message objects */
+ for (i = D_CAN_MSG_OBJ_RX_FIRST; i <= D_CAN_NUM_MSG_OBJECTS; i++)
+ d_can_inval_msg_object(dev, D_CAN_IF_RX_NUM, i);
+
+ /* setup receive message objects */
+ for (i = D_CAN_MSG_OBJ_RX_FIRST; i < D_CAN_MSG_OBJ_RX_LAST; i++)
+ d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM, i, 0, 0,
+ (D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK) &
+ ~D_CAN_IF_MCTL_EOB);
+
+ /* Last object EoB bit should be 1 for terminate */
+ d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM, D_CAN_MSG_OBJ_RX_LAST,
+ 0, 0, D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK |
+ D_CAN_IF_MCTL_EOB);
+}
+
+static void d_can_test_mode(struct net_device *dev)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ /* Test mode is enabled in this step & the specific TEST bits
+ * are enabled accordingly */
+ d_can_write(priv, D_CAN_CTL, D_CAN_CTL_EIE |
+ D_CAN_CTL_IE1 | D_CAN_CTL_IE0 | D_CAN_CTL_TEST);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ /* silent mode : bus-monitoring mode */
+ d_can_write(priv, D_CAN_TEST, D_CAN_TEST_SILENT);
+ else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
+ /* loopback mode : useful for self-test function */
+ d_can_write(priv, D_CAN_TEST, D_CAN_TEST_LBACK);
+ else
+ /* loopback + silent mode : useful for hot self-test */
+ d_can_write(priv, D_CAN_TEST, D_CAN_TEST_LBACK |
+ D_CAN_TEST_SILENT);
+}
+
+/*
+ * Configure D_CAN chip:
+ * - enable/disable auto-retransmission
+ * - set operating mode
+ * - configure message objects
+ */
+static void d_can_init(struct net_device *dev)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+ unsigned long time_out;
+
+ netdev_dbg(dev, "resetting d_can ...\n");
+ d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_SWR);
+
+ /* Enter initialization mode by setting the Init bit */
+ d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT);
+
+ /* enable automatic retransmission */
+ d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_DISABLE_AR);
+
+ /* Set the Configure Change Enable ( CCE) bit */
+ d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_CCE);
+
+ /* Wait for the Init bit to get set */
+ time_out = jiffies + msecs_to_jiffies(D_CAN_TIMEOUT_MS);
+ while (!d_can_get_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT) &&
+ time_after(time_out, jiffies))
+ cpu_relax();
+
+ if (time_after(jiffies, time_out)) {
+ netdev_err(dev, "timedout, D_CAN INIT bit is not set\n");
+ return;
+ }
+
+ /* set bittiming params */
+ d_can_set_bittiming(dev);
+
+ d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT | D_CAN_CTL_CCE);
+
+ /* Wait for the Init bit to get clear */
+ time_out = jiffies + msecs_to_jiffies(D_CAN_TIMEOUT_MS);
+ while (d_can_get_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT) &&
+ time_after(time_out, jiffies))
+ cpu_relax();
+
+ if (time_after(jiffies, time_out)) {
+ netdev_err(dev, "timedout, D_CAN INIT bit is not cleared\n");
+ return;
+ }
+
+ if (priv->can.ctrlmode & (CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_LISTENONLY))
+ d_can_test_mode(dev);
+ else
+ d_can_write(priv, D_CAN_CTL, D_CAN_CTL_EIE | D_CAN_CTL_IE1 |
+ D_CAN_CTL_SIE | D_CAN_CTL_IE0);
+
+ /* Enable TX and RX I/O Control pins */
+ d_can_write(priv, D_CAN_TIOC, D_CAN_TIOC_FUNC);
+ d_can_write(priv, D_CAN_RIOC, D_CAN_RIOC_FUNC);
+
+ /* configure message objects */
+ d_can_configure_msg_objects(dev);
+
+ /* set a LEC value so that we can check for updates later */
+ d_can_write(priv, D_CAN_ES, LEC_UNUSED);
+}
+
+static void d_can_start(struct net_device *dev)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ /* basic d_can initialization */
+ d_can_init(dev);
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ /* reset tx helper pointers */
+ priv->tx_next = priv->tx_echo = 0;
+
+ /* enable status change, error and module interrupts */
+ d_can_interrupts(priv, D_CAN_ENABLE_ALL_INTERRUPTS);
+}
+
+static void d_can_stop(struct net_device *dev)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ d_can_interrupts(priv, D_CAN_DISABLE_ALL_INTERRUPTS);
+
+ /* set the state as STOPPED */
+ priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int d_can_set_mode(struct net_device *dev, enum can_mode mode)
+{
+ switch (mode) {
+ case CAN_MODE_START:
+ d_can_start(dev);
+ netif_wake_queue(dev);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int d_can_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ unsigned int err_cnt;
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ err_cnt = d_can_read(priv, D_CAN_ERRC);
+ bec->rxerr = (err_cnt & D_CAN_ERRC_REC_MASK) >> D_CAN_ERRC_REC_SHIFT;
+ bec->txerr = err_cnt & D_CAN_ERRC_TEC_MASK;
+
+ return 0;
+}
+
+/*
+ * priv->tx_echo 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
+ * packet has been transmitted, echo it back to the CAN framework.
+ * If we discover a not yet transmitted packet, stop looking for more.
+ */
+static void d_can_do_tx(struct net_device *dev)
+{
+ u32 msg_obj_no;
+ struct d_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ u32 txrq_x_reg_val;
+ u32 txrq_reg_val;
+
+ for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
+ msg_obj_no = get_tx_echo_msg_obj(priv);
+ txrq_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_TXRQ_X);
+ txrq_reg_val = d_can_read(priv, D_CAN_TXRQ(txrq_x_reg_val));
+ if (!(txrq_reg_val & (1 << (msg_obj_no -
+ D_CAN_MSG_OBJ_TX_FIRST)))) {
+ can_get_echo_skb(dev,
+ msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST);
+ stats->tx_bytes += d_can_read(priv,
+ D_CAN_IFMCTL(D_CAN_IF_TX_NUM)) &
+ D_CAN_IF_MCTL_DLC_MASK;
+ stats->tx_packets++;
+ d_can_inval_msg_object(dev, D_CAN_IF_TX_NUM,
+ msg_obj_no);
+ } else
+ break;
+ }
+
+ /* restart queue if wrap-up or if queue stalled on last pkt */
+ if (((priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
+ ((priv->tx_echo & D_CAN_NEXT_MSG_OBJ_MASK) == 0))
+ netif_wake_queue(dev);
+}
+
+/*
+ * d_can core saves a received CAN message into the first free message
+ * object it finds free (starting with the lowest). Bits NEWDAT and
+ * INTPND are set for this message object indicating that a new message
+ * has arrived. To work-around this issue, we keep two groups of message
+ * objects whose partitioning is defined by D_CAN_MSG_OBJ_RX_SPLIT.
+ *
+ * To ensure in-order frame reception we use the following
+ * approach while re-activating a message object to receive further
+ * frames:
+ * - if the current message object number is lower than
+ * D_CAN_MSG_RX_LOW_LAST, do not clear the NEWDAT bit while clearing
+ * the INTPND bit.
+ * - if the current message object number is equal to
+ * D_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of all lower
+ * receive message objects.
+ * - if the current message object number is greater than
+ * D_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of
+ * only this message object.
+ */
+static int d_can_do_rx_poll(struct net_device *dev, int quota)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+ unsigned int msg_obj, mctrl_reg_val;
+ u32 num_rx_pkts = 0;
+ u32 intpnd_x_reg_val;
+ u32 intpnd_reg_val;
+
+ for (msg_obj = D_CAN_MSG_OBJ_RX_FIRST;
+ msg_obj <= D_CAN_MSG_OBJ_RX_LAST && quota > 0; msg_obj++) {
+
+ intpnd_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_INTPND_X);
+ intpnd_reg_val = d_can_read(priv,
+ D_CAN_INTPND(intpnd_x_reg_val));
+
+ /*
+ * as interrupt pending register's bit n-1 corresponds to
+ * message object n, we need to handle the same properly.
+ */
+ if (intpnd_reg_val & (1 << (msg_obj - 1))) {
+
+ d_can_object_get(dev, D_CAN_IF_RX_NUM, msg_obj,
+ D_CAN_IF_CMD_ALL &
+ ~D_CAN_IF_CMD_TXRQST);
+
+ mctrl_reg_val = d_can_read(priv,
+ D_CAN_IFMCTL(D_CAN_IF_RX_NUM));
+
+ if (!(mctrl_reg_val & D_CAN_IF_MCTL_NEWDAT))
+ continue;
+
+ /* read the data from the message object */
+ d_can_read_msg_object(dev, D_CAN_IF_RX_NUM,
+ mctrl_reg_val);
+
+ if (mctrl_reg_val & D_CAN_IF_MCTL_EOB)
+ d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM,
+ D_CAN_MSG_OBJ_RX_LAST, 0, 0,
+ D_CAN_IF_MCTL_RXIE |
+ D_CAN_IF_MCTL_UMASK |
+ D_CAN_IF_MCTL_EOB);
+
+ if (mctrl_reg_val & D_CAN_IF_MCTL_MSGLST) {
+ d_can_handle_lost_msg_obj(dev, D_CAN_IF_RX_NUM,
+ msg_obj);
+ num_rx_pkts++;
+ quota--;
+ continue;
+ }
+
+ if (msg_obj < D_CAN_MSG_OBJ_RX_LOW_LAST)
+ d_can_mark_rx_msg_obj(dev, D_CAN_IF_RX_NUM,
+ mctrl_reg_val, msg_obj);
+ else if (msg_obj > D_CAN_MSG_OBJ_RX_LOW_LAST)
+ /* activate this msg obj */
+ d_can_activate_rx_msg_obj(dev, D_CAN_IF_RX_NUM,
+ mctrl_reg_val, msg_obj);
+ else if (msg_obj == D_CAN_MSG_OBJ_RX_LOW_LAST)
+ /* activate all lower message objects */
+ d_can_activate_all_lower_rx_msg_objs(dev,
+ D_CAN_IF_RX_NUM, mctrl_reg_val);
+
+ num_rx_pkts++;
+ quota--;
+ }
+ }
+ return num_rx_pkts;
+}
+
+static inline int d_can_has_handle_berr(struct d_can_priv *priv)
+{
+ return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
+ (priv->current_status & LEC_UNUSED);
+}
+
+static int d_can_handle_state_change(struct net_device *dev,
+ enum d_can_bus_error_types error_type)
+{
+ unsigned int err_cnt;
+ unsigned int rx_epass;
+ struct d_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;
+
+ /* propagate the error condition to the CAN stack */
+ skb = alloc_can_err_skb(dev, &cf);
+ if (unlikely(!skb))
+ return 0;
+
+ d_can_get_berr_counter(dev, &bec);
+ err_cnt = d_can_read(priv, D_CAN_ERRC);
+ rx_epass = err_cnt & D_CAN_ERRC_RP_MASK;
+
+ switch (error_type) {
+ case ERROR_WARNING:
+ /* error warning state */
+ priv->can.can_stats.error_warning++;
+ priv->can.state = CAN_STATE_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;
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+
+ break;
+ case 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_epass)
+ cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ if (bec.txerr > 127)
+ cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+ break;
+ case 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
+ */
+ d_can_interrupts(priv, D_CAN_DISABLE_ALL_INTERRUPTS);
+ can_bus_off(dev);
+ break;
+ default:
+ break;
+ }
+ netif_receive_skb(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ return 1;
+}
+
+static int d_can_handle_bus_err(struct net_device *dev,
+ enum d_can_lec_type lec_type)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+
+ /*
+ * early exit if no lec update or no error.
+ * no lec update means that no CAN bus event has been detected
+ * since CPU wrote 0x7 value to status reg.
+ */
+ if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR)
+ return 0;
+
+ /* propagate the error condition to the CAN stack */
+ skb = alloc_can_err_skb(dev, &cf);
+ if (unlikely(!skb))
+ return 0;
+
+ /* common for all type of bus errors */
+ priv->can.can_stats.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;
+ default:
+ break;
+ }
+
+ /* set a LEC value so that we can check for updates later */
+ d_can_write(priv, D_CAN_ES, LEC_UNUSED);
+
+ netif_receive_skb(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ return 1;
+}
+
+static int d_can_poll(struct napi_struct *napi, int quota)
+{
+ int work_done = 0;
+ int lec_type = 0;
+ struct net_device *dev = napi->dev;
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ if (!priv->irqstatus)
+ goto end;
+
+ /* status events have the highest priority */
+ if (priv->irqstatus == D_CAN_STATUS_INTERRUPT) {
+ priv->current_status = d_can_read(priv, D_CAN_ES);
+
+ /* handle Tx/Rx events */
+ if (priv->current_status & D_CAN_ES_TXOK)
+ d_can_write(priv, D_CAN_ES,
+ priv->current_status & ~D_CAN_ES_TXOK);
+
+ if (priv->current_status & D_CAN_ES_RXOK)
+ d_can_write(priv, D_CAN_ES,
+ priv->current_status & ~D_CAN_ES_RXOK);
+
+ /* handle state changes */
+ if ((priv->current_status & D_CAN_ES_EWARN) &&
+ (!(priv->last_status & D_CAN_ES_EWARN))) {
+ netdev_dbg(dev, "entered error warning state\n");
+ work_done += d_can_handle_state_change(dev,
+ ERROR_WARNING);
+ }
+ if ((priv->current_status & D_CAN_ES_EPASS) &&
+ (!(priv->last_status & D_CAN_ES_EPASS))) {
+ netdev_dbg(dev, "entered error passive state\n");
+ work_done += d_can_handle_state_change(dev,
+ ERROR_PASSIVE);
+ }
+ if ((priv->current_status & D_CAN_ES_BOFF) &&
+ (!(priv->last_status & D_CAN_ES_BOFF))) {
+ netdev_dbg(dev, "entered bus off state\n");
+ work_done += d_can_handle_state_change(dev, BUS_OFF);
+ }
+
+ /* handle bus recovery events */
+ if ((!(priv->current_status & D_CAN_ES_BOFF)) &&
+ (priv->last_status & D_CAN_ES_BOFF)) {
+ netdev_dbg(dev, "left bus off state\n");
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+ if ((!(priv->current_status & D_CAN_ES_EPASS)) &&
+ (priv->last_status & D_CAN_ES_EPASS)) {
+ netdev_dbg(dev, "left error passive state\n");
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+ priv->last_status = priv->current_status;
+
+ /* handle lec errors on the bus */
+ lec_type = d_can_has_handle_berr(priv);
+ if (lec_type)
+ work_done += d_can_handle_bus_err(dev, lec_type);
+ } else if ((priv->irqstatus >= D_CAN_MSG_OBJ_RX_FIRST) &&
+ (priv->irqstatus <= D_CAN_MSG_OBJ_RX_LAST)) {
+ /* handle events corresponding to receive message objects */
+ work_done += d_can_do_rx_poll(dev, (quota - work_done));
+ } else if ((priv->irqstatus >= D_CAN_MSG_OBJ_TX_FIRST) &&
+ (priv->irqstatus <= D_CAN_MSG_OBJ_TX_LAST)) {
+ /* handle events corresponding to transmit message objects */
+ d_can_do_tx(dev);
+ }
+end:
+ if (work_done < quota) {
+ napi_complete(napi);
+ d_can_interrupts(priv, D_CAN_ENABLE_ALL_INTERRUPTS);
+ }
+ return work_done;
+}
+
+static irqreturn_t d_can_isr(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ priv->irqstatus = d_can_read(priv, D_CAN_INT);
+ if (!priv->irqstatus)
+ return IRQ_NONE;
+
+ /* disable all interrupts and schedule the NAPI */
+ d_can_interrupts(priv, D_CAN_DISABLE_ALL_INTERRUPTS);
+ napi_schedule(&priv->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int d_can_open(struct net_device *ndev)
+{
+ int err;
+ struct d_can_priv *priv = netdev_priv(ndev);
+
+ /* Open common can device */
+ err = open_candev(ndev);
+ if (err) {
+ netdev_err(ndev, "open_candev() failed %d\n", err);
+ return err;
+ }
+
+ err = request_irq(ndev->irq, &d_can_isr, IRQF_SHARED, ndev->name,
+ ndev);
+ if (err) {
+ netdev_err(ndev, "failed to request MO_ES interrupt\n");
+ goto exit_close_candev;
+ }
+
+ /* start the d_can controller */
+ d_can_start(ndev);
+ napi_enable(&priv->napi);
+ netif_start_queue(ndev);
+ priv->is_opened = true;
+
+ return 0;
+exit_close_candev:
+ close_candev(ndev);
+ return err;
+}
+
+static int d_can_close(struct net_device *ndev)
+{
+ struct d_can_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+ napi_disable(&priv->napi);
+ d_can_stop(ndev);
+ free_irq(ndev->irq, ndev);
+ close_candev(ndev);
+ priv->is_opened = false;
+
+ return 0;
+}
+
+static void d_can_reset_ram(struct d_can_priv *d_can, unsigned int instance,
+ unsigned int enable)
+{
+ if (d_can->ram_init)
+ d_can->ram_init(instance, enable);
+ /* Give some time delay for DCAN RAM initialization */
+ udelay(1);
+}
+
+static struct net_device *alloc_d_can_dev(unsigned int num_objs)
+{
+ struct net_device *dev;
+ struct d_can_priv *priv;
+
+ dev = alloc_candev(sizeof(struct d_can_priv), num_objs/2);
+ if (!dev)
+ return NULL;
+
+ priv = netdev_priv(dev);
+ netif_napi_add(dev, &priv->napi, d_can_poll, num_objs/2);
+
+ priv->dev = dev;
+ priv->can.bittiming_const = &d_can_bittiming_const;
+ priv->can.do_set_mode = d_can_set_mode;
+ priv->can.do_get_berr_counter = d_can_get_berr_counter;
+ priv->can.ctrlmode_supported = (CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_LISTENONLY |
+ CAN_CTRLMODE_BERR_REPORTING |
+ CAN_CTRLMODE_3_SAMPLES);
+ return dev;
+}
+
+static void free_d_can_dev(struct net_device *dev)
+{
+ free_candev(dev);
+}
+
+static const struct net_device_ops d_can_netdev_ops = {
+ .ndo_open = d_can_open,
+ .ndo_stop = d_can_close,
+ .ndo_start_xmit = d_can_start_xmit,
+};
+
+static int register_d_can_dev(struct net_device *dev)
+{
+ /* we support local echo */
+ dev->flags |= IFF_ECHO;
+ dev->netdev_ops = &d_can_netdev_ops;
+ return register_candev(dev);
+}
+
+static void unregister_d_can_dev(struct net_device *dev)
+{
+ struct d_can_priv *priv = netdev_priv(dev);
+
+ d_can_interrupts(priv, D_CAN_DISABLE_ALL_INTERRUPTS);
+ unregister_candev(dev);
+}
+
+static int __devinit d_can_plat_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ void __iomem *addr;
+ struct net_device *ndev;
+ struct d_can_priv *priv;
+ struct resource *mem, *irq;
+ struct d_can_platform_data *pdata;
+ struct clk *fck;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data\n");
+ goto exit;
+ }
+
+ /* get the platform data */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "No mem resource\n");
+ goto exit;
+ }
+ irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "d_can_ms");
+ if (!irq) {
+ dev_err(&pdev->dev, "No irq resource\n");
+ goto exit;
+ }
+ if (!request_mem_region(mem->start, resource_size(mem),
+ D_CAN_DRV_NAME)) {
+ dev_err(&pdev->dev, "resource unavailable\n");
+ ret = -EBUSY;
+ goto exit;
+ }
+ addr = ioremap(mem->start, resource_size(mem));
+ if (!addr) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto exit_release_mem;
+ }
+
+ /* allocate the d_can device */
+ ndev = alloc_d_can_dev(pdata->num_of_msg_objs);
+ if (!ndev) {
+ dev_err(&pdev->dev, "alloc_d_can_dev failed\n");
+ ret = -ENOMEM;
+ goto exit_iounmap;
+ }
+ fck = clk_get(&pdev->dev, "fck");
+ if (IS_ERR(fck)) {
+ dev_err(&pdev->dev, "fck is not found\n");
+ ret = -ENODEV;
+ goto exit_free_ndev;
+ }
+
+ priv = netdev_priv(ndev);
+ priv->base = addr;
+ priv->can.clock.freq = clk_get_rate(fck);
+ priv->ram_init = pdata->ram_init;
+ priv->is_opened = false;
+
+ ndev->irq = irq->start;
+ platform_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ ret = register_d_can_dev(ndev);
+ if (ret) {
+ dev_err(&pdev->dev, "registering %s failed (err = %d)\n",
+ D_CAN_DRV_NAME, ret);
+ goto exit_free_device;
+ }
+
+ /* Initialize DCAN RAM */
+ d_can_reset_ram(priv, pdev->id, 1);
+
+ dev_info(&pdev->dev, "device registered (irq = %d)\n", ndev->irq);
+ return 0;
+exit_free_device:
+ platform_set_drvdata(pdev, NULL);
+ pm_runtime_disable(&pdev->dev);
+ clk_put(fck);
+exit_free_ndev:
+ free_d_can_dev(ndev);
+exit_iounmap:
+ iounmap(addr);
+exit_release_mem:
+ release_mem_region(mem->start, resource_size(mem));
+exit:
+ dev_err(&pdev->dev, "probe failed\n");
+ return ret;
+}
+
+static int __devexit d_can_plat_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct d_can_priv *priv = netdev_priv(ndev);
+ struct resource *mem;
+
+ d_can_reset_ram(priv, pdev->id, 0);
+
+ unregister_d_can_dev(ndev);
+ platform_set_drvdata(pdev, NULL);
+
+ free_d_can_dev(ndev);
+ iounmap(priv->base);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int d_can_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ unsigned long time_out;
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct d_can_priv *priv = netdev_priv(ndev);
+
+ if (netif_running(ndev)) {
+ netif_stop_queue(ndev);
+ netif_device_detach(ndev);
+ }
+
+ d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_PDR);
+
+ /* PDA bit will become high only when all the pending
+ * transfers are completed */
+ time_out = jiffies + msecs_to_jiffies(D_CAN_TIMEOUT_MS);
+ while (!d_can_get_bit(priv, D_CAN_ES, D_CAN_ES_PDA) &&
+ time_after(time_out, jiffies))
+ cpu_relax();
+
+ if (time_after(jiffies, time_out)) {
+ netdev_err(ndev, "Not entered power down mode\n");
+ return -ETIMEDOUT;
+ }
+
+ if (priv->is_opened)
+ d_can_stop(ndev);
+
+ priv->can.state = CAN_STATE_SLEEPING;
+ /* De-initialize DCAN RAM */
+ d_can_reset_ram(priv, pdev->id, 0);
+ /* Disable the module */
+ pm_runtime_put_sync(&pdev->dev);
+ return 0;
+}
+
+static int d_can_resume(struct platform_device *pdev)
+{
+ unsigned long time_out;
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct d_can_priv *priv = netdev_priv(ndev);
+
+ /* Enable the module */
+ pm_runtime_get_sync(&pdev->dev);
+ /* Initialize DCAN RAM */
+ d_can_reset_ram(priv, pdev->id, 1);
+
+ /* Brought back from power down mode */
+ d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_PDR);
+ d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT);
+
+ /* Wait for the PDA bit to get clear */
+ time_out = jiffies + msecs_to_jiffies(D_CAN_TIMEOUT_MS);
+ while (d_can_get_bit(priv, D_CAN_ES, D_CAN_ES_PDA) &&
+ time_after(time_out, jiffies))
+ cpu_relax();
+
+ if (time_after(jiffies, time_out)) {
+ netdev_err(ndev, "Not came out from power down mode\n");
+ return -ETIMEDOUT;
+ }
+
+ if (priv->is_opened)
+ d_can_start(ndev);
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ if (netif_running(ndev)) {
+ netif_device_attach(ndev);
+ netif_start_queue(ndev);
+ }
+ return 0;
+}
+#else
+#define d_can_suspend NULL
+#define d_can_resume NULL
+#endif
+
+static struct platform_driver d_can_plat_driver = {
+ .driver = {
+ .name = D_CAN_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = d_can_plat_probe,
+ .remove = __devexit_p(d_can_plat_remove),
+ .suspend = d_can_suspend,
+ .resume = d_can_resume,
+};
+
+static int __init d_can_plat_init(void)
+{
+ return platform_driver_register(&d_can_plat_driver);
+}
+module_init(d_can_plat_init);
+
+static void __exit d_can_plat_exit(void)
+{
+ platform_driver_unregister(&d_can_plat_driver);
+}
+module_exit(d_can_plat_exit);
+
+MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(D_CAN_VERSION);
+MODULE_DESCRIPTION(D_CAN_DRV_DESC);
diff --git a/include/linux/can/platform/d_can.h b/include/linux/can/platform/d_can.h
new file mode 100644
index 0000000..b6f2a3f
--- /dev/null
+++ b/include/linux/can/platform/d_can.h
@@ -0,0 +1,40 @@
+/*
+ * D_CAN controller driver platform header
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Bosch D_CAN controller is compliant to CAN protocol version 2.0 part A and B.
+ * Bosch D_CAN user manual can be obtained from:
+ * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/
+ * d_can_users_manual_111.pdf
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CAN_PLATFORM_TI_D_CAN_H__
+#define __CAN_PLATFORM_TI_D_CAN_H__
+
+/**
+ * struct d_can_platform_data - DCAN Platform Data
+ *
+ * @num_of_msg_objs: Number of message objects
+ * @dma_support: DMA support is required/not
+ * @ram_init: DCAN RAM initialization
+ *
+ * Platform data structure to get all platform specific settings.
+ * this structure also accounts the fact that the IP may have different
+ * RAM and mailbox offsets for different SOC's
+ */
+struct d_can_platform_data {
+ unsigned int num_of_msg_objs;
+ bool dma_support;
+ void (*ram_init) (unsigned int instance, unsigned int eanble);
+};
+#endif
--
1.7.0.4
^ permalink raw reply related
* RE: [PATCH] ARM: OMAP: AM33XX: CAN: d_can: Add support for Bosch D_CAN controller
From: AnilKumar, Chimata @ 2012-04-03 12:39 UTC (permalink / raw)
To: AnilKumar, Chimata, socketcan@hartkopp.net,
m.kleine-budde@pengutronix.de, wg@grandegger.com
Cc: linux-can@vger.kernel.org, netdev@vger.kernel.org,
linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org,
Gole, Anant, Nori, Sekhar
In-Reply-To: <1333456339-9372-1-git-send-email-anilkumar@ti.com>
Hi All,
Subject line of this patch should be
"ARM: CAN: d_can: Add support for Bosch D_CAN controller"
Regards
AnilKumar
^ permalink raw reply
* Re: [PATCH] ARM: OMAP: AM33XX: CAN: d_can: Add support for Bosch D_CAN controller
From: Wolfgang Grandegger @ 2012-04-03 12:44 UTC (permalink / raw)
To: AnilKumar Ch
Cc: socketcan, m.kleine-budde, linux-can, netdev, linux-omap,
linux-kernel, anantgole, nsekhar
In-Reply-To: <1333456339-9372-1-git-send-email-anilkumar@ti.com>
On 04/03/2012 02:32 PM, AnilKumar Ch wrote:
> This patch adds the support for Bosch D_CAN controller.
>
> Bosch D_CAN controller is a full-CAN implementation compliant to
> CAN protocol version 2.0 part A and B. Bosch D_CAN user manual
> can be obtained from: http://www.semiconductors.bosch.de/media/
> en/pdf/ipmodules_1/can/d_can_users_manual_111.pdf
>
> D_CAN device is used on many SoCs like AM335x, DM8148 and DM813x
> EVMs from TI, D_CAN details on AM335x can be accessed from:
> http://www.ti.com/lit/ug/spruh73c/spruh73c.pdf
>
> D_CAN can be configurable for 16, 32, 64 and 128 message objects.
> The driver implementation is based on 64 message objects.
>
> Following are the design choices made while writing the controller
> driver:
> 1. Interface Register set IF0 has be used for receive and IF1 is
> used for transmit message objects.
> 2. Out of the total Message objects available, half of it are kept
> aside for RX purposes and the rest for TX purposes.
> 3. NAPI implementation is such that both the TX and RX paths
> functions in polling mode.
>
> Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
Please explain why this CAN controller cannot be handled by the existing
C_CAN driver, eventually with some extensions. The register layout seems
almost identical, at least.
Wolfgang.
> ---
> drivers/net/can/Kconfig | 14 +
> drivers/net/can/Makefile | 1 +
> drivers/net/can/d_can.c | 1487 ++++++++++++++++++++++++++++++++++++
> include/linux/can/platform/d_can.h | 40 +
> 4 files changed, 1542 insertions(+), 0 deletions(-)
> create mode 100644 drivers/net/can/d_can.c
> create mode 100644 include/linux/can/platform/d_can.h
>
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index bb709fd..2529cba 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -68,6 +68,20 @@ config CAN_TI_HECC
> Driver for TI HECC (High End CAN Controller) module found on many
> TI devices. The device specifications are available from www.ti.com
>
> +config CAN_D_CAN
> + tristate "Bosch D_CAN Controller"
> + depends on CAN_DEV
> + ---help---
> + This driver adds support for the D_CAN device found in
> + many SoCs like am335x, dm814x and dm813x boards from TI.
> +
> + The device user guide can be accessed from
> + http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/
> + can/d_can_users_manual_111.pdf
> +
> + To compile this driver as a module, choose M here: the
> + module will be called d_can.
> +
> config CAN_MCP251X
> tristate "Microchip MCP251x SPI CAN controllers"
> depends on CAN_DEV && SPI && HAS_DMA
> diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
> index 938be37..4bd3a87 100644
> --- a/drivers/net/can/Makefile
> +++ b/drivers/net/can/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_CAN_C_CAN) += c_can/
> obj-$(CONFIG_CAN_CC770) += cc770/
> obj-$(CONFIG_CAN_AT91) += at91_can.o
> obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
> +obj-$(CONFIG_CAN_D_CAN) += d_can.o
> obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
> obj-$(CONFIG_CAN_BFIN) += bfin_can.o
> obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
> diff --git a/drivers/net/can/d_can.c b/drivers/net/can/d_can.c
> new file mode 100644
> index 0000000..51e2986
> --- /dev/null
> +++ b/drivers/net/can/d_can.c
> @@ -0,0 +1,1487 @@
> +/*
> + * CAN bus driver for Bosch D_CAN controller
> + *
> + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
> + *
> + * Borrowed from C_CAN driver
> + * Copyright (C) 2010 ST Microelectronics
> + * - Bhupesh Sharma <bhupesh.sharma@st.com>
> + *
> + * Borrowed heavily from the C_CAN driver originally written by:
> + * Copyright (C) 2007
> + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
> + * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
> + *
> + * Bosch D_CAN controller is compliant to CAN protocol version 2.0 part A and B.
> + * Bosch D_CAN user manual can be obtained from:
> + * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/
> + * d_can_users_manual_111.pdf
> + *
> + * 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.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/netdevice.h>
> +#include <linux/errno.h>
> +#include <linux/skbuff.h>
> +#include <linux/jiffies.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +
> +#include <linux/can/dev.h>
> +#include <linux/can/error.h>
> +#include <linux/can/platform/d_can.h>
> +
> +#define D_CAN_DRV_NAME "d_can"
> +#define D_CAN_VERSION "1.0"
> +#define D_CAN_DRV_DESC "CAN bus driver for Bosch D_CAN controller " \
> + D_CAN_VERSION
> +
> +/* TI D_CAN module registers */
> +#define D_CAN_CTL 0x0 /* CAN control register */
> +#define D_CAN_ES 0x4 /* Error and status */
> +#define D_CAN_PARITYERR_EOI 0x4 /* Parity error EOI */
> +#define D_CAN_ERRC 0x8 /* Error counter */
> +#define D_CAN_BTR 0xC /* Bit timing */
> +#define D_CAN_INT 0x10 /* Interrupt register */
> +#define D_CAN_TEST 0x14 /* Test register */
> +#define D_CAN_PERR 0x1C /* Parity Error Code */
> +#define D_CAN_ABOTR 0x80 /* Auto-Bus-On Time */
> +#define D_CAN_TXRQ_X 0x84 /* Transmission Request X */
> +#define D_CAN_TXRQ(n) (0x88 + ((n) * 4)) /* Transmission request */
> +#define D_CAN_NWDAT_X 0x98 /* New data X register */
> +#define D_CAN_NWDAT(n) (0x9C + ((n) * 4)) /* New data */
> +#define D_CAN_INTPND_X 0xAC /* Interrupt Pending X */
> +#define D_CAN_INTPND(n) (0xB0 + ((n) * 4)) /* Interrupt Pending */
> +#define D_CAN_MSGVAL_X 0xC0 /* Message Valid X */
> +#define D_CAN_MSGVAL(n) (0xC4 + ((n) * 4)) /* Message Valid */
> +#define D_CAN_INTMUX(n) (0xD8 + ((n) * 4)) /* Interrupt Multiplexer */
> +#define D_CAN_IFCMD(n) (0x100 + ((n) * 0x20)) /* Command */
> +#define D_CAN_IFMSK(n) (0x104 + ((n) * 0x20)) /* Mask */
> +#define D_CAN_IFARB(n) (0x108 + ((n) * 0x20)) /* Arbitration */
> +#define D_CAN_IFMCTL(n) (0x10c + ((n) * 0x20)) /* Message ctl */
> +#define D_CAN_IFDATA(n) (0x110 + ((n) * 0x20)) /* DATA A */
> +#define D_CAN_IFDATB(n) (0x114 + ((n) * 0x20)) /* DATA B */
> +#define D_CAN_IF3OBS 0x140 /* IF3 Observation */
> +#define D_CAN_IF3UPD(n) (0x160 + ((n) * 4)) /* Update enable */
> +#define D_CAN_TIOC 0x1E0 /* CAN TX IO Control */
> +#define D_CAN_RIOC 0x1E4 /* CAN RX IO Control */
> +
> +/* Control register Bit fields */
> +#define D_CAN_CTL_WUBA BIT(26) /* Automatic wake-up on bus activity */
> +#define D_CAN_CTL_PDR BIT(24) /* Request for local low power mode */
> +#define D_CAN_CTL_DE3 BIT(20) /* Enable DMA request line for IF3 */
> +#define D_CAN_CTL_DE2 BIT(19) /* Enable DMA request line for IF2 */
> +#define D_CAN_CTL_DE1 BIT(18) /* Enable DMA request line for IF1 */
> +#define D_CAN_CTL_IE1 BIT(17) /* Interrupt line 1 enable */
> +#define D_CAN_CTL_INITDBG BIT(16) /* Init state for debug access */
> +#define D_CAN_CTL_SWR BIT(15) /* S/W reset enable */
> +#define D_CAN_CTL_PMD (0xF << 10) /* Parity on/off */
> +#define D_CAN_CTL_ABO BIT(9) /* Auto bus on enable */
> +#define D_CAN_CTL_IDS BIT(8) /* Interruption debug support enable */
> +#define D_CAN_CTL_TEST BIT(7) /* Test mode enable */
> +#define D_CAN_CTL_CCE BIT(6) /* Configuration change enable */
> +#define D_CAN_CTL_DISABLE_AR BIT(5) /* Disable automatic retransmission */
> +#define D_CAN_CTL_EIE BIT(3) /* Error interrupt enable */
> +#define D_CAN_CTL_SIE BIT(2) /* Status change int enable */
> +#define D_CAN_CTL_IE0 BIT(1) /* Interrupt line 0 enable */
> +#define D_CAN_CTL_INIT BIT(0) /* D_CAN initialization mode */
> +
> +/* D_CAN Error and Status and Parity Error EOI reg bit fields */
> +#define D_CAN_ES_PDA BIT(10) /* Local power-down ACK */
> +#define D_CAN_ES_WUP BIT(9) /* Wkae up pending */
> +#define D_CAN_ES_PER BIT(8) /* Parity error detected */
> +#define D_CAN_ES_BOFF BIT(7) /* Bus off state */
> +#define D_CAN_ES_EWARN BIT(6) /* Warning state */
> +#define D_CAN_ES_EPASS BIT(5) /* Error passive state */
> +#define D_CAN_ES_RXOK BIT(4) /* Received a msg successfully */
> +#define D_CAN_ES_TXOK BIT(3) /* Transmitted a msg successfully */
> +#define D_CAN_ES_LEC_MASK 0x7 /* Last error code */
> +
> +/* Error counter reg bit fields */
> +#define D_CAN_ERRC_RP_MASK BIT(15) /* Receive error passive */
> +#define D_CAN_ERRC_REC_SHIFT 8
> +#define D_CAN_ERRC_REC_MASK (0x7F << 8) /* Receive err counter */
> +#define D_CAN_ERRC_TEC_MASK (0xFF << 0) /* Transmit err counter */
> +
> +/* Bit timing reg bit fields */
> +#define D_CAN_BTR_BRPE_SHIFT 16 /* Baud rate prescaler ext */
> +#define D_CAN_BTR_TSEG2_SHIFT 12 /* Time seg after smpl point */
> +#define D_CAN_BTR_TSEG1_SHIFT 8 /* Time seg before smpl point */
> +#define D_CAN_BTR_SJW_SHIFT 6 /* Syncronization jump width */
> +#define D_CAN_BTR_BRP_SHIFT 0 /* Baud rate prescaler */
> +
> +/* D_CAN Test register bit fields */
> +#define D_CAN_TEST_RDA BIT(9) /* RAM direct access enable */
> +#define D_CAN_TEST_EXL BIT(8) /* External loopback mode */
> +#define D_CAN_TEST_RX BIT(7) /* Monitors the reveive pin */
> +#define D_CAN_TEST_TX (0x3 << 5) /* Control of CAN_TX pin */
> +#define D_CAN_TEST_LBACK BIT(4) /* Loopback mode */
> +#define D_CAN_TEST_SILENT BIT(3) /* Silent mdoe */
> +
> +/* D_CAN IF command reg bit fields */
> +#define D_CAN_IF_CMD_WR BIT(23) /* Write/read */
> +#define D_CAN_IF_CMD_MASK BIT(22) /* Access to mask bits */
> +#define D_CAN_IF_CMD_ARB BIT(21) /* Access to arbitration bits */
> +#define D_CAN_IF_CMD_CONTROL BIT(20) /* Acess to control bits */
> +#define D_CAN_IF_CMD_CIP BIT(19) /* Clear int pending */
> +#define D_CAN_IF_CMD_TXRQST BIT(18) /* Access transmission request */
> +#define D_CAN_IF_CMD_DATAA BIT(17) /* Access to Data Bytes 0-3 */
> +#define D_CAN_IF_CMD_DATAB BIT(16) /* Access to Data Bytes 4-7 */
> +#define D_CAN_IF_CMD_BUSY BIT(15) /* Busy flag */
> +#define D_CAN_IF_CMD_DAM BIT(14) /* Activation of DMA */
> +#define D_CAN_IF_CMD_MN_MASK 0xFF /* No. of msg's used for DMA T/F */
> +#define D_CAN_IF_CMD_ALL (D_CAN_IF_CMD_MASK | D_CAN_IF_CMD_ARB | \
> + D_CAN_IF_CMD_CONTROL | D_CAN_IF_CMD_TXRQST | \
> + D_CAN_IF_CMD_DATAA | D_CAN_IF_CMD_DATAB)
> +
> +/* D_CAN IF mask reg bit fields */
> +#define D_CAN_IF_MASK_MX BIT(31) /* Mask Extended Identifier */
> +#define D_CAN_IF_MASK_MD BIT(30) /* Mask Message direction */
> +
> +/* D_CAN IF Arbitration */
> +#define D_CAN_IF_ARB_MSGVAL BIT(31) /* Message Vaild */
> +#define D_CAN_IF_ARB_MSGXTD BIT(30) /* Extended Identifier 0-11 1-29 */
> +#define D_CAN_IF_ARB_DIR_XMIT BIT(29) /* Message direction 0-R 1-T */
> +
> +/* D_CAN IF Message control */
> +#define D_CAN_IF_MCTL_NEWDAT BIT(15) /* New data available */
> +#define D_CAN_IF_MCTL_MSGLST BIT(14) /* Message lost, only for receive */
> +#define D_CAN_IF_MCTL_INTPND BIT(13) /* Interrupt pending */
> +#define D_CAN_IF_MCTL_UMASK BIT(12) /* Use acceptance mask */
> +#define D_CAN_IF_MCTL_TXIE BIT(11) /* Transmit int enable */
> +#define D_CAN_IF_MCTL_RXIE BIT(10) /* Receive int enable */
> +#define D_CAN_IF_MCTL_RMTEN BIT(9) /* Remote enable */
> +#define D_CAN_IF_MCTL_TXRQST BIT(8) /* Transmit request */
> +#define D_CAN_IF_MCTL_EOB BIT(7) /* Data frames */
> +#define D_CAN_IF_MCTL_DLC_MASK 0xF /* Data length code */
> +
> +/* D_CAN IF3 Observation reg bit fields */
> +#define D_CAN_IF3OBS_UP BIT(15) /* Update data status */
> +#define D_CAN_IF3OBS_SDB BIT(12) /* DataB read out status */
> +#define D_CAN_IF3OBS_SDA BIT(11) /* DataA read out status */
> +#define D_CAN_IF3OBS_SC BIT(10) /* Contol bits read out status */
> +#define D_CAN_IF3OBS_SA BIT(9) /* Arbitration read out status */
> +#define D_CAN_IF3OBS_SM BIT(8) /* Mask bits read out status */
> +#define D_CAN_IF3OBS_DB BIT(4) /* Data B read observation */
> +#define D_CAN_IF3OBS_DA BIT(3) /* Data A read observation */
> +#define D_CAN_IF3OBS_CTL BIT(2) /* Control read observation */
> +#define D_CAN_IF3OBS_ARB BIT(1) /* Arbitration data read observation */
> +#define D_CAN_IF3OBS_MASK BIT(0) /* Mask data read observation */
> +
> +/* D_CAN TX I/O reg bit fields */
> +#define D_CAN_TIOC_PU BIT(18) /* CAN_TX pull up/down select */
> +#define D_CAN_TIOC_PD BIT(17) /* CAN_TX pull disable */
> +#define D_CAN_TIOC_OD BIT(16) /* CAN_TX open drain enable */
> +#define D_CAN_TIOC_FUNC BIT(3) /* CAN_TX function */
> +#define D_CAN_TIOC_DIR BIT(2) /* CAN_TX data direction */
> +#define D_CAN_TIOC_OUT BIT(1) /* CAN_TX data out write */
> +#define D_CAN_TIOC_IN BIT(0) /* CAN_TX data in */
> +
> +/* D_CAN RX I/O reg bit fields */
> +#define D_CAN_RIOC_PU BIT(18) /* CAN_RX pull up/down select */
> +#define D_CAN_RIOC_PD BIT(17) /* CAN_RX pull disable */
> +#define D_CAN_RIOC_OD BIT(16) /* CAN_RX open drain enable */
> +#define D_CAN_RIOC_FUNC BIT(3) /* CAN_RX function */
> +#define D_CAN_RIOC_DIR BIT(2) /* CAN_RX data direction */
> +#define D_CAN_RIOC_OUT BIT(1) /* CAN_RX data out write */
> +#define D_CAN_RIOC_IN BIT(0) /* CAN_RX data in */
> +
> +/* IF register masks */
> +#define IFX_WRITE_IDR(x) ((x) & 0x1FFFFFFF)
> +#define IFX_CMD_BITS(x) ((x) & 0xFFFFFF00)
> +#define IFX_CMD_MSG_NUMBER(x) ((x) & 0xFF)
> +
> +/* Message objects split */
> +#define D_CAN_NUM_MSG_OBJECTS 64
> +#define D_CAN_NUM_RX_MSG_OBJECTS 32
> +#define D_CAN_NUM_TX_MSG_OBJECTS 32
> +
> +#define D_CAN_MSG_OBJ_RX_FIRST 1
> +#define D_CAN_MSG_OBJ_RX_LAST (D_CAN_MSG_OBJ_RX_FIRST + \
> + D_CAN_NUM_RX_MSG_OBJECTS - 1)
> +
> +#define D_CAN_MSG_OBJ_TX_FIRST (D_CAN_MSG_OBJ_RX_LAST + 1)
> +#define D_CAN_MSG_OBJ_TX_LAST (D_CAN_MSG_OBJ_TX_FIRST + \
> + D_CAN_NUM_TX_MSG_OBJECTS - 1)
> +
> +#define D_CAN_MSG_OBJ_RX_SPLIT 17
> +#define D_CAN_MSG_OBJ_RX_LOW_LAST (D_CAN_MSG_OBJ_RX_SPLIT - 1)
> +
> +#define D_CAN_NEXT_MSG_OBJ_MASK (D_CAN_NUM_TX_MSG_OBJECTS - 1)
> +
> +/* global interrupt masks */
> +#define D_CAN_ENABLE_ALL_INTERRUPTS 1
> +#define D_CAN_DISABLE_ALL_INTERRUPTS 0
> +
> +/* status interrupt */
> +#define D_CAN_STATUS_INTERRUPT 0x8000
> +
> +#define D_CAN_BUSY_TIMEOUT 14
> +#define D_CAN_TIMEOUT_MS 1000
> +
> +/* Interface register bank number */
> +#define D_CAN_IF_RX_NUM 0
> +#define D_CAN_IF_TX_NUM 1
> +
> +#define D_CAN_GET_XREG_NUM(priv, reg) (__ffs(d_can_read(priv, reg)) >> 2)
> +
> +/* d_can private data structure */
> +struct d_can_priv {
> + struct can_priv can; /* must be the first member */
> + struct napi_struct napi;
> + struct net_device *dev;
> + struct platform_device *pdev;
> + unsigned int tx_next;
> + unsigned int tx_echo;
> + u32 current_status;
> + u32 last_status;
> + u32 irqstatus;
> + bool is_opened;
> + void __iomem *base;
> + void (*ram_init) (unsigned int, unsigned int);
> +};
> +
> +/* CAN Bittiming constants as per D_CAN specs */
> +static struct can_bittiming_const d_can_bittiming_const = {
> + .name = D_CAN_DRV_NAME,
> + .tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */
> + .tseg1_max = 16,
> + .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
> + .tseg2_max = 8,
> + .sjw_max = 4,
> + .brp_min = 1,
> + .brp_max = 1024, /* 6-bit BRP field + 4-bit BRPE field*/
> + .brp_inc = 1,
> +};
> +
> +/* d_can last error code (lec) values */
> +enum d_can_lec_type {
> + LEC_NO_ERROR = 0,
> + LEC_STUFF_ERROR,
> + LEC_FORM_ERROR,
> + LEC_ACK_ERROR,
> + LEC_BIT1_ERROR,
> + LEC_BIT0_ERROR,
> + LEC_CRC_ERROR,
> + LEC_UNUSED,
> +};
> +
> +/* d_can error types */
> +enum d_can_bus_error_types {
> + NO_ERROR = 0,
> + BUS_OFF,
> + ERROR_WARNING,
> + ERROR_PASSIVE,
> +};
> +
> +static inline void d_can_write(struct d_can_priv *priv, u32 reg, u32 val)
> +{
> + writel(val, priv->base + reg);
> +}
> +
> +static inline u32 d_can_read(struct d_can_priv *priv, u32 reg)
> +{
> + return readl(priv->base + reg);
> +}
> +
> +static inline void d_can_set_bit(struct d_can_priv *priv, u32 reg, u32 bitmask)
> +{
> + d_can_write(priv, reg, d_can_read(priv, reg) | bitmask);
> +}
> +
> +static inline u32 d_can_get_bit(struct d_can_priv *priv, u32 reg, u32 bitmask)
> +{
> + return (d_can_read(priv, reg) & bitmask) ? 1 : 0;
> +}
> +
> +static inline void d_can_clear_bit(struct d_can_priv *priv, u32 reg,
> + u32 bitmask)
> +{
> + d_can_write(priv, reg, d_can_read(priv, reg) & ~bitmask);
> +}
> +
> +static inline int get_tx_next_msg_obj(const struct d_can_priv *priv)
> +{
> + return (priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) +
> + D_CAN_MSG_OBJ_TX_FIRST;
> +}
> +
> +static inline int get_tx_echo_msg_obj(const struct d_can_priv *priv)
> +{
> + return (priv->tx_echo & D_CAN_NEXT_MSG_OBJ_MASK) +
> + D_CAN_MSG_OBJ_TX_FIRST;
> +}
> +
> +static void d_can_interrupts(struct d_can_priv *priv, unsigned int enable)
> +{
> + unsigned int cntrl_save = d_can_read(priv, D_CAN_CTL);
> +
> + if (enable)
> + cntrl_save |= (D_CAN_CTL_IE1 | D_CAN_CTL_EIE |
> + D_CAN_CTL_SIE | D_CAN_CTL_IE0);
> + else
> + cntrl_save &= ~(D_CAN_CTL_IE1 | D_CAN_CTL_EIE |
> + D_CAN_CTL_SIE | D_CAN_CTL_IE0);
> +
> + d_can_write(priv, D_CAN_CTL, cntrl_save);
> +}
> +
> +static inline int d_can_msg_obj_is_busy(struct d_can_priv *priv, u32 iface)
> +{
> + unsigned long time_out = jiffies + msecs_to_jiffies(D_CAN_BUSY_TIMEOUT);
> +
> + /* Check the status of busy bit */
> + while (d_can_get_bit(priv, D_CAN_IFCMD(iface), D_CAN_IF_CMD_BUSY) &&
> + time_after(time_out, jiffies))
> + cpu_relax();
> +
> + if (time_after(jiffies, time_out))
> + return -ETIMEDOUT;
> +
> + return 0;
> +}
> +
> +static inline void d_can_object_get(struct net_device *dev,
> + u32 iface, u32 objno, u32 mask)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + d_can_write(priv, D_CAN_IFCMD(iface), IFX_CMD_BITS(mask) |
> + IFX_CMD_MSG_NUMBER(objno));
> +
> + /*
> + * As per specs, after writing the message object number in the
> + * IF command register the transfer b/w interface register and
> + * message RAM must be complete in 4 - 14 CAN-CLK period.
> + */
> + if (d_can_msg_obj_is_busy(priv, iface))
> + netdev_err(dev, "timed out in object get\n");
> +}
> +
> +static inline void d_can_object_put(struct net_device *dev,
> + u32 iface, u32 objno, u32 mask)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + d_can_write(priv, D_CAN_IFCMD(iface), D_CAN_IF_CMD_WR |
> + IFX_CMD_BITS(mask) | IFX_CMD_MSG_NUMBER(objno));
> +
> + /*
> + * As per specs, after writing the message object number in the
> + * IF command register the transfer b/w interface register and
> + * message RAM must be complete in 4 - 14 CAN-CLK period.
> + */
> + if (d_can_msg_obj_is_busy(priv, iface))
> + netdev_err(dev, "timed out in object put\n");
> +}
> +
> +static void d_can_write_msg_object(struct net_device *dev, u32 iface,
> + struct can_frame *frame, u32 objno)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> + unsigned int id;
> + u32 flags = 0;
> +
> + if (!(frame->can_id & CAN_RTR_FLAG))
> + flags |= D_CAN_IF_ARB_DIR_XMIT;
> +
> + if (frame->can_id & CAN_EFF_FLAG) {
> + id = frame->can_id & CAN_EFF_MASK;
> + flags |= D_CAN_IF_ARB_MSGXTD;
> + } else
> + id = ((frame->can_id & CAN_SFF_MASK) << 18);
> +
> + flags |= D_CAN_IF_ARB_MSGVAL;
> + d_can_write(priv, D_CAN_IFARB(iface), IFX_WRITE_IDR(id) | flags);
> +
> + /* Writing lower 4bytes to DATAA IF register */
> + d_can_write(priv, D_CAN_IFDATA(iface),
> + le32_to_cpu(*(u32 *)(frame->data)));
> +
> + /* Writing higher 4bytes to DATAB IF register */
> + if (frame->can_dlc > 4)
> + d_can_write(priv, D_CAN_IFDATB(iface),
> + le32_to_cpu(*(u32 *)(frame->data + 4)));
> +
> + /* enable TX interrupt for this message object */
> + d_can_write(priv, D_CAN_IFMCTL(iface),
> + D_CAN_IF_MCTL_TXIE | D_CAN_IF_MCTL_EOB |
> + D_CAN_IF_MCTL_TXRQST | D_CAN_IF_MCTL_NEWDAT |
> + frame->can_dlc);
> +
> + /* Put message data into message RAM */
> + d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ALL);
> +}
> +
> +/*
> + * Mark that this particular message object is received and clearing
> + * the interrupt pending register value.
> + */
> +static inline void d_can_mark_rx_msg_obj(struct net_device *dev,
> + u32 iface, u32 ctrl_mask, u32 objno)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + d_can_write(priv, D_CAN_IFMCTL(iface), ctrl_mask &
> + ~(D_CAN_IF_MCTL_MSGLST | D_CAN_IF_MCTL_INTPND));
> + d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_CONTROL);
> +}
> +
> +static inline void d_can_activate_all_lower_rx_msg_objs(struct net_device *dev,
> + u32 iface, u32 ctrl_mask)
> +{
> + unsigned int i;
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + for (i = D_CAN_MSG_OBJ_RX_FIRST; i <= D_CAN_MSG_OBJ_RX_LOW_LAST; i++) {
> + d_can_write(priv, D_CAN_IFMCTL(iface), ctrl_mask &
> + ~(D_CAN_IF_MCTL_MSGLST | D_CAN_IF_MCTL_INTPND |
> + D_CAN_IF_MCTL_NEWDAT));
> + d_can_object_put(dev, iface, i, D_CAN_IF_CMD_CONTROL);
> + }
> +}
> +
> +static inline void d_can_activate_rx_msg_obj(struct net_device *dev,
> + u32 iface, u32 ctrl_mask, u32 objno)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + d_can_write(priv, D_CAN_IFMCTL(iface), ctrl_mask &
> + ~(D_CAN_IF_MCTL_MSGLST | D_CAN_IF_MCTL_INTPND |
> + D_CAN_IF_MCTL_NEWDAT));
> + d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_CONTROL);
> +}
> +
> +static void d_can_handle_lost_msg_obj(struct net_device *dev,
> + u32 iface, u32 objno)
> +{
> + struct d_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);
> + d_can_object_get(dev, iface, objno, D_CAN_IF_CMD_ALL &
> + ~D_CAN_IF_CMD_TXRQST);
> + d_can_clear_bit(priv, D_CAN_IFMCTL(iface), D_CAN_IF_MCTL_MSGLST);
> + d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_CONTROL);
> +
> + /* create an error msg */
> + skb = alloc_can_err_skb(dev, &frame);
> + if (unlikely(!skb))
> + return;
> +
> + frame->can_id |= CAN_ERR_CRTL;
> + frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
> + stats->rx_errors++;
> + stats->rx_over_errors++;
> +
> + netif_receive_skb(skb);
> +}
> +
> +static int d_can_read_msg_object(struct net_device *dev, u32 iface, u32 ctrl)
> +{
> + unsigned int arb_val, mctl_val;
> + struct d_can_priv *priv = netdev_priv(dev);
> + struct net_device_stats *stats = &dev->stats;
> + struct can_frame *frame;
> + struct sk_buff *skb;
> + u32 data = 0;
> +
> + skb = alloc_can_skb(dev, &frame);
> + if (!skb) {
> + stats->rx_dropped++;
> + return -ENOMEM;
> + }
> +
> + frame->can_dlc = get_can_dlc(ctrl & 0x0F);
> + arb_val = d_can_read(priv, D_CAN_IFARB(iface));
> + mctl_val = d_can_read(priv, D_CAN_IFMCTL(iface));
> +
> + if (arb_val & D_CAN_IF_ARB_MSGXTD)
> + frame->can_id = (arb_val & CAN_EFF_MASK) | CAN_EFF_FLAG;
> + else
> + frame->can_id = (arb_val >> 18) & CAN_SFF_MASK;
> +
> + if (mctl_val & D_CAN_IF_MCTL_RMTEN)
> + frame->can_id |= CAN_RTR_FLAG;
> + else {
> + data = d_can_read(priv, D_CAN_IFDATA(iface));
> + /* Writing MO lower 4 data bytes to skb */
> + *(u32 *)(frame->data) = cpu_to_le32(data);
> +
> + /* Writing MO higher 4 data bytes to skb */
> + if (frame->can_dlc > 4) {
> + data = d_can_read(priv, D_CAN_IFDATB(iface));
> + *(u32 *)(frame->data + 4) = cpu_to_le32(data);
> + } else
> + *(u32 *)(frame->data + 4) = 0;
> + }
> +
> + netif_receive_skb(skb);
> + stats->rx_packets++;
> + stats->rx_bytes += frame->can_dlc;
> +
> + return 0;
> +}
> +
> +static void d_can_setup_receive_object(struct net_device *dev, u32 iface,
> + u32 objno, u32 mask, u32 id, u32 mcont)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + d_can_write(priv, D_CAN_IFMCTL(iface), mcont);
> + d_can_write(priv, D_CAN_IFMSK(iface), IFX_WRITE_IDR(mask));
> + d_can_write(priv, D_CAN_IFARB(iface), IFX_WRITE_IDR(id) |
> + D_CAN_IF_ARB_MSGVAL);
> + d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ALL &
> + ~D_CAN_IF_CMD_TXRQST);
> +
> + netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, d_can_read(priv,
> + D_CAN_MSGVAL(D_CAN_GET_XREG_NUM(priv, D_CAN_MSGVAL_X))));
> +}
> +
> +static void d_can_inval_msg_object(struct net_device *dev, u32 iface, u32 objno)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + d_can_write(priv, D_CAN_IFARB(iface), 0);
> + d_can_write(priv, D_CAN_IFMCTL(iface), 0);
> + d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ARB |
> + D_CAN_IF_CMD_CONTROL);
> +
> + netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, d_can_read(priv,
> + D_CAN_MSGVAL(D_CAN_GET_XREG_NUM(priv, D_CAN_MSGVAL_X))));
> +}
> +
> +static inline int d_can_is_next_tx_obj_busy(struct d_can_priv *priv, u32 objno)
> +{
> + u32 txrq_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_TXRQ_X);
> +
> + /* Transmission request register's bit n-1 corresponds to
> + * message object n, we need to handle the same properly */
> + if (d_can_read(priv, D_CAN_TXRQ(txrq_x_reg_val)) &
> + (1 << (objno - D_CAN_MSG_OBJ_TX_FIRST)))
> + return 1;
> +
> + return 0;
> +}
> +
> +static netdev_tx_t d_can_start_xmit(struct sk_buff *skb, struct net_device *dev)
> +{
> + u32 msg_obj_no;
> + struct d_can_priv *priv = netdev_priv(dev);
> + struct can_frame *frame = (struct can_frame *)skb->data;
> +
> + if (can_dropped_invalid_skb(dev, skb))
> + return NETDEV_TX_OK;
> +
> + msg_obj_no = get_tx_next_msg_obj(priv);
> +
> + /* prepare message object for transmission */
> + d_can_write_msg_object(dev, D_CAN_IF_TX_NUM, frame, msg_obj_no);
> + can_put_echo_skb(skb, dev, msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST);
> +
> + /*
> + * we have to stop the queue in case of a wrap around or
> + * if the next TX message object is still in use
> + */
> + priv->tx_next++;
> + if (d_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
> + ((priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) == 0))
> + netif_stop_queue(dev);
> +
> + return NETDEV_TX_OK;
> +}
> +
> +static void d_can_set_bittiming(struct net_device *dev)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> + const struct can_bittiming *bt = &priv->can.bittiming;
> + u32 can_btc;
> +
> + can_btc = ((bt->phase_seg2 - 1) & 0x7) << D_CAN_BTR_TSEG2_SHIFT;
> + can_btc |= ((bt->phase_seg1 + bt->prop_seg - 1) & 0xF) <<
> + D_CAN_BTR_TSEG1_SHIFT;
> + can_btc |= ((bt->sjw - 1) & 0x3) << D_CAN_BTR_SJW_SHIFT;
> + /* Ten bits contains the BRP, 6 bits for BRP and upper 4 bits for brpe*/
> + can_btc |= ((bt->brp - 1) & 0x3F) << D_CAN_BTR_BRP_SHIFT;
> + can_btc |= ((((bt->brp - 1) >> 6) & 0xF) << D_CAN_BTR_BRPE_SHIFT);
> +
> + d_can_write(priv, D_CAN_BTR, can_btc);
> + netdev_info(dev, "setting CAN BT = %#x\n", can_btc);
> +}
> +
> +/*
> + * Configure D_CAN message objects for Tx and Rx purposes:
> + * D_CAN provides a total of 64 message objects that can be configured
> + * either for Tx or Rx purposes. In this driver first 32 message objects
> + * are used as a reception FIFO and the reception FIFO is signified by the
> + * EoB bit being SET. The remaining 32 message objects are kept aside for
> + * Tx purposes. See user guide document for further details on configuring
> + * message objects.
> + */
> +static void d_can_configure_msg_objects(struct net_device *dev)
> +{
> + unsigned int i;
> +
> + /* first invalidate all message objects */
> + for (i = D_CAN_MSG_OBJ_RX_FIRST; i <= D_CAN_NUM_MSG_OBJECTS; i++)
> + d_can_inval_msg_object(dev, D_CAN_IF_RX_NUM, i);
> +
> + /* setup receive message objects */
> + for (i = D_CAN_MSG_OBJ_RX_FIRST; i < D_CAN_MSG_OBJ_RX_LAST; i++)
> + d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM, i, 0, 0,
> + (D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK) &
> + ~D_CAN_IF_MCTL_EOB);
> +
> + /* Last object EoB bit should be 1 for terminate */
> + d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM, D_CAN_MSG_OBJ_RX_LAST,
> + 0, 0, D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK |
> + D_CAN_IF_MCTL_EOB);
> +}
> +
> +static void d_can_test_mode(struct net_device *dev)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + /* Test mode is enabled in this step & the specific TEST bits
> + * are enabled accordingly */
> + d_can_write(priv, D_CAN_CTL, D_CAN_CTL_EIE |
> + D_CAN_CTL_IE1 | D_CAN_CTL_IE0 | D_CAN_CTL_TEST);
> +
> + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
> + /* silent mode : bus-monitoring mode */
> + d_can_write(priv, D_CAN_TEST, D_CAN_TEST_SILENT);
> + else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
> + /* loopback mode : useful for self-test function */
> + d_can_write(priv, D_CAN_TEST, D_CAN_TEST_LBACK);
> + else
> + /* loopback + silent mode : useful for hot self-test */
> + d_can_write(priv, D_CAN_TEST, D_CAN_TEST_LBACK |
> + D_CAN_TEST_SILENT);
> +}
> +
> +/*
> + * Configure D_CAN chip:
> + * - enable/disable auto-retransmission
> + * - set operating mode
> + * - configure message objects
> + */
> +static void d_can_init(struct net_device *dev)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> + unsigned long time_out;
> +
> + netdev_dbg(dev, "resetting d_can ...\n");
> + d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_SWR);
> +
> + /* Enter initialization mode by setting the Init bit */
> + d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT);
> +
> + /* enable automatic retransmission */
> + d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_DISABLE_AR);
> +
> + /* Set the Configure Change Enable ( CCE) bit */
> + d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_CCE);
> +
> + /* Wait for the Init bit to get set */
> + time_out = jiffies + msecs_to_jiffies(D_CAN_TIMEOUT_MS);
> + while (!d_can_get_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT) &&
> + time_after(time_out, jiffies))
> + cpu_relax();
> +
> + if (time_after(jiffies, time_out)) {
> + netdev_err(dev, "timedout, D_CAN INIT bit is not set\n");
> + return;
> + }
> +
> + /* set bittiming params */
> + d_can_set_bittiming(dev);
> +
> + d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT | D_CAN_CTL_CCE);
> +
> + /* Wait for the Init bit to get clear */
> + time_out = jiffies + msecs_to_jiffies(D_CAN_TIMEOUT_MS);
> + while (d_can_get_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT) &&
> + time_after(time_out, jiffies))
> + cpu_relax();
> +
> + if (time_after(jiffies, time_out)) {
> + netdev_err(dev, "timedout, D_CAN INIT bit is not cleared\n");
> + return;
> + }
> +
> + if (priv->can.ctrlmode & (CAN_CTRLMODE_LOOPBACK |
> + CAN_CTRLMODE_LISTENONLY))
> + d_can_test_mode(dev);
> + else
> + d_can_write(priv, D_CAN_CTL, D_CAN_CTL_EIE | D_CAN_CTL_IE1 |
> + D_CAN_CTL_SIE | D_CAN_CTL_IE0);
> +
> + /* Enable TX and RX I/O Control pins */
> + d_can_write(priv, D_CAN_TIOC, D_CAN_TIOC_FUNC);
> + d_can_write(priv, D_CAN_RIOC, D_CAN_RIOC_FUNC);
> +
> + /* configure message objects */
> + d_can_configure_msg_objects(dev);
> +
> + /* set a LEC value so that we can check for updates later */
> + d_can_write(priv, D_CAN_ES, LEC_UNUSED);
> +}
> +
> +static void d_can_start(struct net_device *dev)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + /* basic d_can initialization */
> + d_can_init(dev);
> +
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> +
> + /* reset tx helper pointers */
> + priv->tx_next = priv->tx_echo = 0;
> +
> + /* enable status change, error and module interrupts */
> + d_can_interrupts(priv, D_CAN_ENABLE_ALL_INTERRUPTS);
> +}
> +
> +static void d_can_stop(struct net_device *dev)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + d_can_interrupts(priv, D_CAN_DISABLE_ALL_INTERRUPTS);
> +
> + /* set the state as STOPPED */
> + priv->can.state = CAN_STATE_STOPPED;
> +}
> +
> +static int d_can_set_mode(struct net_device *dev, enum can_mode mode)
> +{
> + switch (mode) {
> + case CAN_MODE_START:
> + d_can_start(dev);
> + netif_wake_queue(dev);
> + break;
> + default:
> + return -EOPNOTSUPP;
> + }
> +
> + return 0;
> +}
> +
> +static int d_can_get_berr_counter(const struct net_device *dev,
> + struct can_berr_counter *bec)
> +{
> + unsigned int err_cnt;
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + err_cnt = d_can_read(priv, D_CAN_ERRC);
> + bec->rxerr = (err_cnt & D_CAN_ERRC_REC_MASK) >> D_CAN_ERRC_REC_SHIFT;
> + bec->txerr = err_cnt & D_CAN_ERRC_TEC_MASK;
> +
> + return 0;
> +}
> +
> +/*
> + * priv->tx_echo 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
> + * packet has been transmitted, echo it back to the CAN framework.
> + * If we discover a not yet transmitted packet, stop looking for more.
> + */
> +static void d_can_do_tx(struct net_device *dev)
> +{
> + u32 msg_obj_no;
> + struct d_can_priv *priv = netdev_priv(dev);
> + struct net_device_stats *stats = &dev->stats;
> + u32 txrq_x_reg_val;
> + u32 txrq_reg_val;
> +
> + for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
> + msg_obj_no = get_tx_echo_msg_obj(priv);
> + txrq_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_TXRQ_X);
> + txrq_reg_val = d_can_read(priv, D_CAN_TXRQ(txrq_x_reg_val));
> + if (!(txrq_reg_val & (1 << (msg_obj_no -
> + D_CAN_MSG_OBJ_TX_FIRST)))) {
> + can_get_echo_skb(dev,
> + msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST);
> + stats->tx_bytes += d_can_read(priv,
> + D_CAN_IFMCTL(D_CAN_IF_TX_NUM)) &
> + D_CAN_IF_MCTL_DLC_MASK;
> + stats->tx_packets++;
> + d_can_inval_msg_object(dev, D_CAN_IF_TX_NUM,
> + msg_obj_no);
> + } else
> + break;
> + }
> +
> + /* restart queue if wrap-up or if queue stalled on last pkt */
> + if (((priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
> + ((priv->tx_echo & D_CAN_NEXT_MSG_OBJ_MASK) == 0))
> + netif_wake_queue(dev);
> +}
> +
> +/*
> + * d_can core saves a received CAN message into the first free message
> + * object it finds free (starting with the lowest). Bits NEWDAT and
> + * INTPND are set for this message object indicating that a new message
> + * has arrived. To work-around this issue, we keep two groups of message
> + * objects whose partitioning is defined by D_CAN_MSG_OBJ_RX_SPLIT.
> + *
> + * To ensure in-order frame reception we use the following
> + * approach while re-activating a message object to receive further
> + * frames:
> + * - if the current message object number is lower than
> + * D_CAN_MSG_RX_LOW_LAST, do not clear the NEWDAT bit while clearing
> + * the INTPND bit.
> + * - if the current message object number is equal to
> + * D_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of all lower
> + * receive message objects.
> + * - if the current message object number is greater than
> + * D_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of
> + * only this message object.
> + */
> +static int d_can_do_rx_poll(struct net_device *dev, int quota)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> + unsigned int msg_obj, mctrl_reg_val;
> + u32 num_rx_pkts = 0;
> + u32 intpnd_x_reg_val;
> + u32 intpnd_reg_val;
> +
> + for (msg_obj = D_CAN_MSG_OBJ_RX_FIRST;
> + msg_obj <= D_CAN_MSG_OBJ_RX_LAST && quota > 0; msg_obj++) {
> +
> + intpnd_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_INTPND_X);
> + intpnd_reg_val = d_can_read(priv,
> + D_CAN_INTPND(intpnd_x_reg_val));
> +
> + /*
> + * as interrupt pending register's bit n-1 corresponds to
> + * message object n, we need to handle the same properly.
> + */
> + if (intpnd_reg_val & (1 << (msg_obj - 1))) {
> +
> + d_can_object_get(dev, D_CAN_IF_RX_NUM, msg_obj,
> + D_CAN_IF_CMD_ALL &
> + ~D_CAN_IF_CMD_TXRQST);
> +
> + mctrl_reg_val = d_can_read(priv,
> + D_CAN_IFMCTL(D_CAN_IF_RX_NUM));
> +
> + if (!(mctrl_reg_val & D_CAN_IF_MCTL_NEWDAT))
> + continue;
> +
> + /* read the data from the message object */
> + d_can_read_msg_object(dev, D_CAN_IF_RX_NUM,
> + mctrl_reg_val);
> +
> + if (mctrl_reg_val & D_CAN_IF_MCTL_EOB)
> + d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM,
> + D_CAN_MSG_OBJ_RX_LAST, 0, 0,
> + D_CAN_IF_MCTL_RXIE |
> + D_CAN_IF_MCTL_UMASK |
> + D_CAN_IF_MCTL_EOB);
> +
> + if (mctrl_reg_val & D_CAN_IF_MCTL_MSGLST) {
> + d_can_handle_lost_msg_obj(dev, D_CAN_IF_RX_NUM,
> + msg_obj);
> + num_rx_pkts++;
> + quota--;
> + continue;
> + }
> +
> + if (msg_obj < D_CAN_MSG_OBJ_RX_LOW_LAST)
> + d_can_mark_rx_msg_obj(dev, D_CAN_IF_RX_NUM,
> + mctrl_reg_val, msg_obj);
> + else if (msg_obj > D_CAN_MSG_OBJ_RX_LOW_LAST)
> + /* activate this msg obj */
> + d_can_activate_rx_msg_obj(dev, D_CAN_IF_RX_NUM,
> + mctrl_reg_val, msg_obj);
> + else if (msg_obj == D_CAN_MSG_OBJ_RX_LOW_LAST)
> + /* activate all lower message objects */
> + d_can_activate_all_lower_rx_msg_objs(dev,
> + D_CAN_IF_RX_NUM, mctrl_reg_val);
> +
> + num_rx_pkts++;
> + quota--;
> + }
> + }
> + return num_rx_pkts;
> +}
> +
> +static inline int d_can_has_handle_berr(struct d_can_priv *priv)
> +{
> + return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
> + (priv->current_status & LEC_UNUSED);
> +}
> +
> +static int d_can_handle_state_change(struct net_device *dev,
> + enum d_can_bus_error_types error_type)
> +{
> + unsigned int err_cnt;
> + unsigned int rx_epass;
> + struct d_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;
> +
> + /* propagate the error condition to the CAN stack */
> + skb = alloc_can_err_skb(dev, &cf);
> + if (unlikely(!skb))
> + return 0;
> +
> + d_can_get_berr_counter(dev, &bec);
> + err_cnt = d_can_read(priv, D_CAN_ERRC);
> + rx_epass = err_cnt & D_CAN_ERRC_RP_MASK;
> +
> + switch (error_type) {
> + case ERROR_WARNING:
> + /* error warning state */
> + priv->can.can_stats.error_warning++;
> + priv->can.state = CAN_STATE_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;
> + cf->data[6] = bec.txerr;
> + cf->data[7] = bec.rxerr;
> +
> + break;
> + case 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_epass)
> + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
> + if (bec.txerr > 127)
> + cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
> +
> + cf->data[6] = bec.txerr;
> + cf->data[7] = bec.rxerr;
> + break;
> + case 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
> + */
> + d_can_interrupts(priv, D_CAN_DISABLE_ALL_INTERRUPTS);
> + can_bus_off(dev);
> + break;
> + default:
> + break;
> + }
> + netif_receive_skb(skb);
> + stats->rx_packets++;
> + stats->rx_bytes += cf->can_dlc;
> +
> + return 1;
> +}
> +
> +static int d_can_handle_bus_err(struct net_device *dev,
> + enum d_can_lec_type lec_type)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> + struct net_device_stats *stats = &dev->stats;
> + struct can_frame *cf;
> + struct sk_buff *skb;
> +
> + /*
> + * early exit if no lec update or no error.
> + * no lec update means that no CAN bus event has been detected
> + * since CPU wrote 0x7 value to status reg.
> + */
> + if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR)
> + return 0;
> +
> + /* propagate the error condition to the CAN stack */
> + skb = alloc_can_err_skb(dev, &cf);
> + if (unlikely(!skb))
> + return 0;
> +
> + /* common for all type of bus errors */
> + priv->can.can_stats.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;
> + default:
> + break;
> + }
> +
> + /* set a LEC value so that we can check for updates later */
> + d_can_write(priv, D_CAN_ES, LEC_UNUSED);
> +
> + netif_receive_skb(skb);
> + stats->rx_packets++;
> + stats->rx_bytes += cf->can_dlc;
> +
> + return 1;
> +}
> +
> +static int d_can_poll(struct napi_struct *napi, int quota)
> +{
> + int work_done = 0;
> + int lec_type = 0;
> + struct net_device *dev = napi->dev;
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + if (!priv->irqstatus)
> + goto end;
> +
> + /* status events have the highest priority */
> + if (priv->irqstatus == D_CAN_STATUS_INTERRUPT) {
> + priv->current_status = d_can_read(priv, D_CAN_ES);
> +
> + /* handle Tx/Rx events */
> + if (priv->current_status & D_CAN_ES_TXOK)
> + d_can_write(priv, D_CAN_ES,
> + priv->current_status & ~D_CAN_ES_TXOK);
> +
> + if (priv->current_status & D_CAN_ES_RXOK)
> + d_can_write(priv, D_CAN_ES,
> + priv->current_status & ~D_CAN_ES_RXOK);
> +
> + /* handle state changes */
> + if ((priv->current_status & D_CAN_ES_EWARN) &&
> + (!(priv->last_status & D_CAN_ES_EWARN))) {
> + netdev_dbg(dev, "entered error warning state\n");
> + work_done += d_can_handle_state_change(dev,
> + ERROR_WARNING);
> + }
> + if ((priv->current_status & D_CAN_ES_EPASS) &&
> + (!(priv->last_status & D_CAN_ES_EPASS))) {
> + netdev_dbg(dev, "entered error passive state\n");
> + work_done += d_can_handle_state_change(dev,
> + ERROR_PASSIVE);
> + }
> + if ((priv->current_status & D_CAN_ES_BOFF) &&
> + (!(priv->last_status & D_CAN_ES_BOFF))) {
> + netdev_dbg(dev, "entered bus off state\n");
> + work_done += d_can_handle_state_change(dev, BUS_OFF);
> + }
> +
> + /* handle bus recovery events */
> + if ((!(priv->current_status & D_CAN_ES_BOFF)) &&
> + (priv->last_status & D_CAN_ES_BOFF)) {
> + netdev_dbg(dev, "left bus off state\n");
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> + }
> + if ((!(priv->current_status & D_CAN_ES_EPASS)) &&
> + (priv->last_status & D_CAN_ES_EPASS)) {
> + netdev_dbg(dev, "left error passive state\n");
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> + }
> + priv->last_status = priv->current_status;
> +
> + /* handle lec errors on the bus */
> + lec_type = d_can_has_handle_berr(priv);
> + if (lec_type)
> + work_done += d_can_handle_bus_err(dev, lec_type);
> + } else if ((priv->irqstatus >= D_CAN_MSG_OBJ_RX_FIRST) &&
> + (priv->irqstatus <= D_CAN_MSG_OBJ_RX_LAST)) {
> + /* handle events corresponding to receive message objects */
> + work_done += d_can_do_rx_poll(dev, (quota - work_done));
> + } else if ((priv->irqstatus >= D_CAN_MSG_OBJ_TX_FIRST) &&
> + (priv->irqstatus <= D_CAN_MSG_OBJ_TX_LAST)) {
> + /* handle events corresponding to transmit message objects */
> + d_can_do_tx(dev);
> + }
> +end:
> + if (work_done < quota) {
> + napi_complete(napi);
> + d_can_interrupts(priv, D_CAN_ENABLE_ALL_INTERRUPTS);
> + }
> + return work_done;
> +}
> +
> +static irqreturn_t d_can_isr(int irq, void *dev_id)
> +{
> + struct net_device *dev = (struct net_device *)dev_id;
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + priv->irqstatus = d_can_read(priv, D_CAN_INT);
> + if (!priv->irqstatus)
> + return IRQ_NONE;
> +
> + /* disable all interrupts and schedule the NAPI */
> + d_can_interrupts(priv, D_CAN_DISABLE_ALL_INTERRUPTS);
> + napi_schedule(&priv->napi);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int d_can_open(struct net_device *ndev)
> +{
> + int err;
> + struct d_can_priv *priv = netdev_priv(ndev);
> +
> + /* Open common can device */
> + err = open_candev(ndev);
> + if (err) {
> + netdev_err(ndev, "open_candev() failed %d\n", err);
> + return err;
> + }
> +
> + err = request_irq(ndev->irq, &d_can_isr, IRQF_SHARED, ndev->name,
> + ndev);
> + if (err) {
> + netdev_err(ndev, "failed to request MO_ES interrupt\n");
> + goto exit_close_candev;
> + }
> +
> + /* start the d_can controller */
> + d_can_start(ndev);
> + napi_enable(&priv->napi);
> + netif_start_queue(ndev);
> + priv->is_opened = true;
> +
> + return 0;
> +exit_close_candev:
> + close_candev(ndev);
> + return err;
> +}
> +
> +static int d_can_close(struct net_device *ndev)
> +{
> + struct d_can_priv *priv = netdev_priv(ndev);
> +
> + netif_stop_queue(ndev);
> + napi_disable(&priv->napi);
> + d_can_stop(ndev);
> + free_irq(ndev->irq, ndev);
> + close_candev(ndev);
> + priv->is_opened = false;
> +
> + return 0;
> +}
> +
> +static void d_can_reset_ram(struct d_can_priv *d_can, unsigned int instance,
> + unsigned int enable)
> +{
> + if (d_can->ram_init)
> + d_can->ram_init(instance, enable);
> + /* Give some time delay for DCAN RAM initialization */
> + udelay(1);
> +}
> +
> +static struct net_device *alloc_d_can_dev(unsigned int num_objs)
> +{
> + struct net_device *dev;
> + struct d_can_priv *priv;
> +
> + dev = alloc_candev(sizeof(struct d_can_priv), num_objs/2);
> + if (!dev)
> + return NULL;
> +
> + priv = netdev_priv(dev);
> + netif_napi_add(dev, &priv->napi, d_can_poll, num_objs/2);
> +
> + priv->dev = dev;
> + priv->can.bittiming_const = &d_can_bittiming_const;
> + priv->can.do_set_mode = d_can_set_mode;
> + priv->can.do_get_berr_counter = d_can_get_berr_counter;
> + priv->can.ctrlmode_supported = (CAN_CTRLMODE_LOOPBACK |
> + CAN_CTRLMODE_LISTENONLY |
> + CAN_CTRLMODE_BERR_REPORTING |
> + CAN_CTRLMODE_3_SAMPLES);
> + return dev;
> +}
> +
> +static void free_d_can_dev(struct net_device *dev)
> +{
> + free_candev(dev);
> +}
> +
> +static const struct net_device_ops d_can_netdev_ops = {
> + .ndo_open = d_can_open,
> + .ndo_stop = d_can_close,
> + .ndo_start_xmit = d_can_start_xmit,
> +};
> +
> +static int register_d_can_dev(struct net_device *dev)
> +{
> + /* we support local echo */
> + dev->flags |= IFF_ECHO;
> + dev->netdev_ops = &d_can_netdev_ops;
> + return register_candev(dev);
> +}
> +
> +static void unregister_d_can_dev(struct net_device *dev)
> +{
> + struct d_can_priv *priv = netdev_priv(dev);
> +
> + d_can_interrupts(priv, D_CAN_DISABLE_ALL_INTERRUPTS);
> + unregister_candev(dev);
> +}
> +
> +static int __devinit d_can_plat_probe(struct platform_device *pdev)
> +{
> + int ret = 0;
> + void __iomem *addr;
> + struct net_device *ndev;
> + struct d_can_priv *priv;
> + struct resource *mem, *irq;
> + struct d_can_platform_data *pdata;
> + struct clk *fck;
> +
> + pdata = pdev->dev.platform_data;
> + if (!pdata) {
> + dev_err(&pdev->dev, "No platform data\n");
> + goto exit;
> + }
> +
> + /* get the platform data */
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!mem) {
> + ret = -ENODEV;
> + dev_err(&pdev->dev, "No mem resource\n");
> + goto exit;
> + }
> + irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "d_can_ms");
> + if (!irq) {
> + dev_err(&pdev->dev, "No irq resource\n");
> + goto exit;
> + }
> + if (!request_mem_region(mem->start, resource_size(mem),
> + D_CAN_DRV_NAME)) {
> + dev_err(&pdev->dev, "resource unavailable\n");
> + ret = -EBUSY;
> + goto exit;
> + }
> + addr = ioremap(mem->start, resource_size(mem));
> + if (!addr) {
> + dev_err(&pdev->dev, "ioremap failed\n");
> + ret = -ENOMEM;
> + goto exit_release_mem;
> + }
> +
> + /* allocate the d_can device */
> + ndev = alloc_d_can_dev(pdata->num_of_msg_objs);
> + if (!ndev) {
> + dev_err(&pdev->dev, "alloc_d_can_dev failed\n");
> + ret = -ENOMEM;
> + goto exit_iounmap;
> + }
> + fck = clk_get(&pdev->dev, "fck");
> + if (IS_ERR(fck)) {
> + dev_err(&pdev->dev, "fck is not found\n");
> + ret = -ENODEV;
> + goto exit_free_ndev;
> + }
> +
> + priv = netdev_priv(ndev);
> + priv->base = addr;
> + priv->can.clock.freq = clk_get_rate(fck);
> + priv->ram_init = pdata->ram_init;
> + priv->is_opened = false;
> +
> + ndev->irq = irq->start;
> + platform_set_drvdata(pdev, ndev);
> + SET_NETDEV_DEV(ndev, &pdev->dev);
> +
> + pm_runtime_enable(&pdev->dev);
> + pm_runtime_get_sync(&pdev->dev);
> +
> + ret = register_d_can_dev(ndev);
> + if (ret) {
> + dev_err(&pdev->dev, "registering %s failed (err = %d)\n",
> + D_CAN_DRV_NAME, ret);
> + goto exit_free_device;
> + }
> +
> + /* Initialize DCAN RAM */
> + d_can_reset_ram(priv, pdev->id, 1);
> +
> + dev_info(&pdev->dev, "device registered (irq = %d)\n", ndev->irq);
> + return 0;
> +exit_free_device:
> + platform_set_drvdata(pdev, NULL);
> + pm_runtime_disable(&pdev->dev);
> + clk_put(fck);
> +exit_free_ndev:
> + free_d_can_dev(ndev);
> +exit_iounmap:
> + iounmap(addr);
> +exit_release_mem:
> + release_mem_region(mem->start, resource_size(mem));
> +exit:
> + dev_err(&pdev->dev, "probe failed\n");
> + return ret;
> +}
> +
> +static int __devexit d_can_plat_remove(struct platform_device *pdev)
> +{
> + struct net_device *ndev = platform_get_drvdata(pdev);
> + struct d_can_priv *priv = netdev_priv(ndev);
> + struct resource *mem;
> +
> + d_can_reset_ram(priv, pdev->id, 0);
> +
> + unregister_d_can_dev(ndev);
> + platform_set_drvdata(pdev, NULL);
> +
> + free_d_can_dev(ndev);
> + iounmap(priv->base);
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + release_mem_region(mem->start, resource_size(mem));
> +
> + pm_runtime_put_sync(&pdev->dev);
> + pm_runtime_disable(&pdev->dev);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int d_can_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> + unsigned long time_out;
> + struct net_device *ndev = platform_get_drvdata(pdev);
> + struct d_can_priv *priv = netdev_priv(ndev);
> +
> + if (netif_running(ndev)) {
> + netif_stop_queue(ndev);
> + netif_device_detach(ndev);
> + }
> +
> + d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_PDR);
> +
> + /* PDA bit will become high only when all the pending
> + * transfers are completed */
> + time_out = jiffies + msecs_to_jiffies(D_CAN_TIMEOUT_MS);
> + while (!d_can_get_bit(priv, D_CAN_ES, D_CAN_ES_PDA) &&
> + time_after(time_out, jiffies))
> + cpu_relax();
> +
> + if (time_after(jiffies, time_out)) {
> + netdev_err(ndev, "Not entered power down mode\n");
> + return -ETIMEDOUT;
> + }
> +
> + if (priv->is_opened)
> + d_can_stop(ndev);
> +
> + priv->can.state = CAN_STATE_SLEEPING;
> + /* De-initialize DCAN RAM */
> + d_can_reset_ram(priv, pdev->id, 0);
> + /* Disable the module */
> + pm_runtime_put_sync(&pdev->dev);
> + return 0;
> +}
> +
> +static int d_can_resume(struct platform_device *pdev)
> +{
> + unsigned long time_out;
> + struct net_device *ndev = platform_get_drvdata(pdev);
> + struct d_can_priv *priv = netdev_priv(ndev);
> +
> + /* Enable the module */
> + pm_runtime_get_sync(&pdev->dev);
> + /* Initialize DCAN RAM */
> + d_can_reset_ram(priv, pdev->id, 1);
> +
> + /* Brought back from power down mode */
> + d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_PDR);
> + d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT);
> +
> + /* Wait for the PDA bit to get clear */
> + time_out = jiffies + msecs_to_jiffies(D_CAN_TIMEOUT_MS);
> + while (d_can_get_bit(priv, D_CAN_ES, D_CAN_ES_PDA) &&
> + time_after(time_out, jiffies))
> + cpu_relax();
> +
> + if (time_after(jiffies, time_out)) {
> + netdev_err(ndev, "Not came out from power down mode\n");
> + return -ETIMEDOUT;
> + }
> +
> + if (priv->is_opened)
> + d_can_start(ndev);
> +
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> +
> + if (netif_running(ndev)) {
> + netif_device_attach(ndev);
> + netif_start_queue(ndev);
> + }
> + return 0;
> +}
> +#else
> +#define d_can_suspend NULL
> +#define d_can_resume NULL
> +#endif
> +
> +static struct platform_driver d_can_plat_driver = {
> + .driver = {
> + .name = D_CAN_DRV_NAME,
> + .owner = THIS_MODULE,
> + },
> + .probe = d_can_plat_probe,
> + .remove = __devexit_p(d_can_plat_remove),
> + .suspend = d_can_suspend,
> + .resume = d_can_resume,
> +};
> +
> +static int __init d_can_plat_init(void)
> +{
> + return platform_driver_register(&d_can_plat_driver);
> +}
> +module_init(d_can_plat_init);
> +
> +static void __exit d_can_plat_exit(void)
> +{
> + platform_driver_unregister(&d_can_plat_driver);
> +}
> +module_exit(d_can_plat_exit);
> +
> +MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_VERSION(D_CAN_VERSION);
> +MODULE_DESCRIPTION(D_CAN_DRV_DESC);
> diff --git a/include/linux/can/platform/d_can.h b/include/linux/can/platform/d_can.h
> new file mode 100644
> index 0000000..b6f2a3f
> --- /dev/null
> +++ b/include/linux/can/platform/d_can.h
> @@ -0,0 +1,40 @@
> +/*
> + * D_CAN controller driver platform header
> + *
> + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
> + *
> + * Bosch D_CAN controller is compliant to CAN protocol version 2.0 part A and B.
> + * Bosch D_CAN user manual can be obtained from:
> + * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/
> + * d_can_users_manual_111.pdf
> + *
> + * 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.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __CAN_PLATFORM_TI_D_CAN_H__
> +#define __CAN_PLATFORM_TI_D_CAN_H__
> +
> +/**
> + * struct d_can_platform_data - DCAN Platform Data
> + *
> + * @num_of_msg_objs: Number of message objects
> + * @dma_support: DMA support is required/not
> + * @ram_init: DCAN RAM initialization
> + *
> + * Platform data structure to get all platform specific settings.
> + * this structure also accounts the fact that the IP may have different
> + * RAM and mailbox offsets for different SOC's
> + */
> +struct d_can_platform_data {
> + unsigned int num_of_msg_objs;
> + bool dma_support;
> + void (*ram_init) (unsigned int instance, unsigned int eanble);
> +};
> +#endif
^ permalink raw reply
* Re: [PATCH] ARM: OMAP: AM33XX: CAN: d_can: Add support for Bosch D_CAN controller
From: Marc Kleine-Budde @ 2012-04-03 12:49 UTC (permalink / raw)
To: Wolfgang Grandegger
Cc: AnilKumar Ch, socketcan, m.kleine-budde, linux-can, netdev,
linux-omap, linux-kernel, anantgole, nsekhar
In-Reply-To: <4F7AF0C7.7020506@grandegger.com>
[-- Attachment #1: Type: text/plain, Size: 1826 bytes --]
On 04/03/2012 02:44 PM, Wolfgang Grandegger wrote:
> On 04/03/2012 02:32 PM, AnilKumar Ch wrote:
>> This patch adds the support for Bosch D_CAN controller.
>>
>> Bosch D_CAN controller is a full-CAN implementation compliant to
>> CAN protocol version 2.0 part A and B. Bosch D_CAN user manual
>> can be obtained from: http://www.semiconductors.bosch.de/media/
>> en/pdf/ipmodules_1/can/d_can_users_manual_111.pdf
>>
>> D_CAN device is used on many SoCs like AM335x, DM8148 and DM813x
>> EVMs from TI, D_CAN details on AM335x can be accessed from:
>> http://www.ti.com/lit/ug/spruh73c/spruh73c.pdf
>>
>> D_CAN can be configurable for 16, 32, 64 and 128 message objects.
>> The driver implementation is based on 64 message objects.
>>
>> Following are the design choices made while writing the controller
>> driver:
>> 1. Interface Register set IF0 has be used for receive and IF1 is
>> used for transmit message objects.
>> 2. Out of the total Message objects available, half of it are kept
>> aside for RX purposes and the rest for TX purposes.
>> 3. NAPI implementation is such that both the TX and RX paths
>> functions in polling mode.
>>
>> Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
>
> Please explain why this CAN controller cannot be handled by the existing
> C_CAN driver, eventually with some extensions. The register layout seems
> almost identical, at least.
ACK.
Have a look at the recent at91_can driver. It has been improved to work
with a flexible number of message objects.
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]
^ permalink raw reply
* Re: stmmac: what happened to IFF_UNICAST_FLT
From: Giuseppe CAVALLARO @ 2012-04-03 12:52 UTC (permalink / raw)
To: Marc Kleine-Budde; +Cc: Rayagond Kokatanur, Linux Netdev List
In-Reply-To: <4F7ADBAF.1030204@blackshift.org>
On 4/3/2012 1:14 PM, Marc Kleine-Budde wrote:
> Hello,
>
> I think in patch "bfab27a stmmac: add the experimental PCI support" the
> flag IFF_UNICAST_FLT was lost, when the function
> stmmac_mac_device_setup() was moved around.
Hello Marc
I'm looking at this and I'll let you know.
In case of there is the issue, I'll fix and include it in the driver
updates (currently under review in the mailing list). If you have the
fix so I can include yours.
Regards
Peppe
> regards, Marc
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH 3/3] netfilter: xt_CT: remove a compile warning
From: Pablo Neira Ayuso @ 2012-04-03 12:57 UTC (permalink / raw)
To: Tetsuo Handa; +Cc: netdev
In-Reply-To: <201204032128.JEG78136.JStMOHQOVFFFLO@I-love.SAKURA.ne.jp>
[-- Attachment #1: Type: text/plain, Size: 414 bytes --]
On Tue, Apr 03, 2012 at 09:28:38PM +0900, Tetsuo Handa wrote:
> Pablo Neira Ayuso wrote:
> > Indeed. The patch attached should fix this problem. Thanks.
>
> It seems to me that the timeout object is associated with the "ct"
> by successful nf_ct_timeout_ext_add() call. If yes,
>
> +err5:
> + xt_ct_tg_timeout_put(ct);
>
> will not be able to find the timeout object.
You're right again. New patch attached.
[-- Attachment #2: 0001-netfilter-xt_CT-fix-missing-put-timeout-object-in-er.patch --]
[-- Type: text/x-diff, Size: 2728 bytes --]
>From 6b9599e7a092a241e86e376d14bb1b45902f19b5 Mon Sep 17 00:00:00 2001
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Tue, 3 Apr 2012 14:50:07 +0200
Subject: [PATCH] netfilter: xt_CT: fix missing put timeout object in error path
The error path misses putting the timeout object. This patch adds
new function xt_ct_tg_timeout_put() to put the timeout object.
Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/xt_CT.c | 28 +++++++++++++++++++++++-----
1 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index 4babb27..e2ee11a 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -150,6 +150,21 @@ err1:
return ret;
}
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+static inline void xt_ct_tg_timeout_put(struct ctnl_timeout *timeout)
+{
+ typeof(nf_ct_timeout_put_hook) timeout_put;
+
+ rcu_read_lock();
+ timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
+
+ if (timeout_put)
+ timeout_put(timeout);
+
+ rcu_read_unlock();
+}
+#endif
+
static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
{
struct xt_ct_target_info_v1 *info = par->targinfo;
@@ -158,7 +173,9 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
struct nf_conn *ct;
int ret = 0;
u8 proto;
-
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+ struct ctnl_timeout *timeout;
+#endif
if (info->flags & ~XT_CT_NOTRACK)
return -EINVAL;
@@ -216,7 +233,6 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
if (info->timeout) {
typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
- struct ctnl_timeout *timeout;
struct nf_conn_timeout *timeout_ext;
rcu_read_lock();
@@ -245,7 +261,7 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
pr_info("Timeout policy `%s' can only be "
"used by L3 protocol number %d\n",
info->timeout, timeout->l3num);
- goto err4;
+ goto err5;
}
/* Make sure the timeout policy matches any existing
* protocol tracker, otherwise default to generic.
@@ -258,13 +274,13 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
"used by L4 protocol number %d\n",
info->timeout,
timeout->l4proto->l4proto);
- goto err4;
+ goto err5;
}
timeout_ext = nf_ct_timeout_ext_add(ct, timeout,
GFP_ATOMIC);
if (timeout_ext == NULL) {
ret = -ENOMEM;
- goto err4;
+ goto err5;
}
} else {
ret = -ENOENT;
@@ -282,6 +298,8 @@ out:
return 0;
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+err5:
+ xt_ct_tg_timeout_put(timeout);
err4:
rcu_read_unlock();
#endif
--
1.7.2.5
^ permalink raw reply related
* Re: [PATCH 03/10] stmmac: sanitize the rx coe and add the type-1 csum
From: Giuseppe CAVALLARO @ 2012-04-03 13:03 UTC (permalink / raw)
To: deepaksi
Cc: netdev@vger.kernel.org, davem@davemloft.net, Srinivas KANDAGATLA,
spear-devel, Shiraz HASHIM, Viresh KUMAR,
bhutchings@solarflare.com
In-Reply-To: <4F7AAD4B.1010606@st.com>
On 4/3/2012 9:56 AM, deepaksi wrote:
> Ciao Peppe,
>
> On 4/3/2012 12:19 PM, Giuseppe CAVALLARO wrote:
>>
>> [snip]
>>> reset.
>> Previously, the stmmac called the dwmac1000_rx_coe_supported to verify
>> it could do the CSUM in Hw. If true the driver used the type 2 by
>> default.
>>
>> I've voluntarily removed this function because not necessary anymore.
>> In fact, YOU improved the rx_coe from the platform. If it is passed as
>> STMMAC_RX_COE_NONE then it means the driver is not able to perform any
>> csum for the incoming frames. This is actually used on old gmac/mac
>> cores. In new cores, the HW cap register will be used to manage and fix
>> this logic.
>> I could restore the core you are mentioning but just to do another
>> safety check at run-time in case of the user provided a broken setting
>> from the platform and there is not the HW cap register. Hmm, I do not
>> know if this actually could help indeed... just an extra check IMHO.
>
> These are the updates required in the code.
>
> In function dwmac1000_core_init(), you may need to set the IPC bit based
> on the fact that
> if rx_coe has been setup through the platform code.
> This bit set is a must for the checksum offload to be enabled. Rest of
> the code looks good.
>
Great Deepak,
sorry I had not understood your good question and thx for you call.
I was wrong and the IPC Checksum Offload has to be set in the MAC
Configuration Register (*).
static int dwmac1000_rx_coe_supported(void __iomem *ioaddr)
{
u32 value = readl(ioaddr + GMAC_CONTROL); |
|==> :-) (*)
value |= GMAC_CONTROL_IPC; |
writel(value, ioaddr + GMAC_CONTROL); |
NOTE ===>>> I'm going to remove the extra check below because
useless as I had told in my previous email.
Is it ok for you? Let me know.
value = readl(ioaddr + GMAC_CONTROL);
return !!(value& GMAC_CONTROL_IPC);
}
I'll rework it and re-send all the patches with this fix soon.
ciao
Peppe
> Deepak
>
>
>
>
>
>>> I hope this clears the things a bit. Sorry for the miscommunication.
>> No problem for the miscommunication ;-)
>>
>> Let me know
>> Ciao
>> Peppe
>>
>>> Rgds
>>> Deepak
>>>
>>>
>>>
>>>
>>>
>>>
>>>>> Regards
>>>>> Deepak
>>>>>
>>>> .
>>>>
>>>
>> .
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH 3/3] netfilter: xt_CT: remove a compile warning
From: Pablo Neira Ayuso @ 2012-04-03 13:06 UTC (permalink / raw)
To: Tetsuo Handa; +Cc: netdev
In-Reply-To: <20120403125755.GA15339@1984>
[-- Attachment #1: Type: text/plain, Size: 860 bytes --]
On Tue, Apr 03, 2012 at 02:57:55PM +0200, Pablo Neira Ayuso wrote:
> On Tue, Apr 03, 2012 at 09:28:38PM +0900, Tetsuo Handa wrote:
> > Pablo Neira Ayuso wrote:
> > > Indeed. The patch attached should fix this problem. Thanks.
> >
> > It seems to me that the timeout object is associated with the "ct"
> > by successful nf_ct_timeout_ext_add() call. If yes,
> >
> > +err5:
> > + xt_ct_tg_timeout_put(ct);
> >
> > will not be able to find the timeout object.
>
> You're right again. New patch attached.
> From 6b9599e7a092a241e86e376d14bb1b45902f19b5 Mon Sep 17 00:00:00 2001
> From: Pablo Neira Ayuso <pablo@netfilter.org>
> Date: Tue, 3 Apr 2012 14:50:07 +0200
> Subject: [PATCH] netfilter: xt_CT: fix missing put timeout object in error path
A bit better patch, no need to hold rcu_read_lock again in
xt_ct_tg_timeout_put (even if that doesn't harm).
[-- Attachment #2: 0001-netfilter-xt_CT-fix-missing-put-timeout-object-in-er.patch --]
[-- Type: text/x-diff, Size: 2677 bytes --]
>From 96a1ee814eef63a917e2a0af7a70bbf85511d285 Mon Sep 17 00:00:00 2001
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Tue, 3 Apr 2012 14:50:07 +0200
Subject: [PATCH] netfilter: xt_CT: fix missing put timeout object in error path
The error path misses putting the timeout object. This patch adds
new function xt_ct_tg_timeout_put() to put the timeout object.
Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/xt_CT.c | 24 +++++++++++++++++++-----
1 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index 4babb27..59530e9 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -150,6 +150,17 @@ err1:
return ret;
}
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout)
+{
+ typeof(nf_ct_timeout_put_hook) timeout_put;
+
+ timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
+ if (timeout_put)
+ timeout_put(timeout);
+}
+#endif
+
static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
{
struct xt_ct_target_info_v1 *info = par->targinfo;
@@ -158,7 +169,9 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
struct nf_conn *ct;
int ret = 0;
u8 proto;
-
+#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+ struct ctnl_timeout *timeout;
+#endif
if (info->flags & ~XT_CT_NOTRACK)
return -EINVAL;
@@ -216,7 +229,6 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
if (info->timeout) {
typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
- struct ctnl_timeout *timeout;
struct nf_conn_timeout *timeout_ext;
rcu_read_lock();
@@ -245,7 +257,7 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
pr_info("Timeout policy `%s' can only be "
"used by L3 protocol number %d\n",
info->timeout, timeout->l3num);
- goto err4;
+ goto err5;
}
/* Make sure the timeout policy matches any existing
* protocol tracker, otherwise default to generic.
@@ -258,13 +270,13 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
"used by L4 protocol number %d\n",
info->timeout,
timeout->l4proto->l4proto);
- goto err4;
+ goto err5;
}
timeout_ext = nf_ct_timeout_ext_add(ct, timeout,
GFP_ATOMIC);
if (timeout_ext == NULL) {
ret = -ENOMEM;
- goto err4;
+ goto err5;
}
} else {
ret = -ENOENT;
@@ -282,6 +294,8 @@ out:
return 0;
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+err5:
+ __xt_ct_tg_timeout_put(timeout);
err4:
rcu_read_unlock();
#endif
--
1.7.2.5
^ permalink raw reply related
* Re: [PATCH v6 1/2] Ethernet driver for the WIZnet W5300 chip
From: Mark Brown @ 2012-04-03 13:36 UTC (permalink / raw)
To: Mike Sinkovsky; +Cc: netdev, linux-kernel
In-Reply-To: <1333450726-24455-2-git-send-email-msink@permonline.ru>
On Tue, Apr 03, 2012 at 04:58:45PM +0600, Mike Sinkovsky wrote:
> +static irqreturn_t w5300_detect_link(int irq, void *ndev_instance)
> +{
> + struct net_device *ndev = ndev_instance;
> + struct w5300_priv *priv = netdev_priv(ndev);
> +
> + if (netif_running(ndev)) {
> + if (gpio_get_value(priv->link_gpio) != 0) {
> + netif_info(priv, link, ndev, "link is up\n");
> + netif_carrier_on(ndev);
> + } else {
> + netif_info(priv, link, ndev, "link is down\n");
> + netif_carrier_off(ndev);
> + }
> + }
> +
> + return IRQ_HANDLED;
> +}
This relies on ndev being valid and on the gpio being requested but...
> + priv->link_gpio = data->link_gpio;
> + if (gpio_is_valid(priv->link_gpio)) {
> + char *link_name = devm_kzalloc(&pdev->dev, 16, GFP_KERNEL);
> + if (!link_name)
> + return -ENOMEM;
> + snprintf(link_name, 16, "%s-link", name);
> + priv->link_irq = gpio_to_irq(priv->link_gpio);
> + if (devm_request_threaded_irq(&pdev->dev,
> + priv->link_irq, NULL, w5300_detect_link,
> + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
> + link_name, priv->ndev) < 0)
> + priv->link_gpio = -EINVAL;
> + }
...you use devm_request_threaded_irq() here and rely on it for cleanup.
Are you sure there's no possibility of the interrupt firing after you
start to tear down the device?
By using a specifically threaded IRQ you're also adding a performance
overhead for no good reason if you can call netdev_carrier_*() from IRQ
context and the GPIO is capable of generating a hard IRQ. If you use
request_any_context_irq() instead then the driver will get a hard IRQ if
that's supported.
^ permalink raw reply
* Re: [PATCH ethtool] Add the command to show the time stamping capabilities.
From: Ben Hutchings @ 2012-04-03 13:38 UTC (permalink / raw)
To: Richard Cochran
Cc: netdev, David Miller, Martin Porter, Jacob Keller, Jeff Kirsher,
John Ronciak, e1000-devel
In-Reply-To: <20120403053717.GA2155@netboy.at.omicron.at>
On Tue, 2012-04-03 at 07:37 +0200, Richard Cochran wrote:
> On Mon, Apr 02, 2012 at 08:25:58PM +0100, Ben Hutchings wrote:
> > On Sun, 2012-04-01 at 17:23 +0200, Richard Cochran wrote:
>
> > > + if (info->tx_types & (1 << HWTSTAMP_TX_OFF))
> > > + fprintf(stdout, "HWTSTAMP_TX_OFF\n");
> > > +
> > > + if (info->tx_types & (1 << HWTSTAMP_TX_ON))
> > > + fprintf(stdout, "HWTSTAMP_TX_ON\n");
> > > +
> > > + if (info->tx_types & (1 << HWTSTAMP_TX_ONESTEP_SYNC))
> > > + fprintf(stdout, "HWTSTAMP_TX_ONESTEP_SYNC\n");
> >
> > If there is no hardware timestamping available then shouldn't we see
> > HWTSTAMP_TX_OFF reported here? But that's going to be the case. Not
> > sure whether the kernel or the ethtool utility should deal with that,
> > but don't assume the ethtool utility is the only consumer.
>
> Actually, if the device does not support hardware time stamping at
> all, then ioctl SIOCSHWTSTAMP returns EOPNOTSUPP. So, HWTSTAMP_TX_ON
> means you can turn Tx time stamping on, and HWTSTAMP_TX_OFF means you
> can turn it off again. It might not seem too logical, but that is how
> the interface works.
OK, this makes sense.
> So (tx_types == 0) means no hardware timestamping available. We can
> print that as a special case, if you think it best.
[...]
I think that from an administrator's point of view it would make more
sense to see that hardware timestamping is always off. But from a
developer's point of view I can see it would make no sense to show a
mode/filter name which cannot actually be used.
So you could show tx_types == 0 or rx_filter == 0 using (1) no heading
and no list or (2) heading and a dummy entry (e.g. 'N/A'). Or maybe you
can think of something better.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* RE: [PATCH] ARM: OMAP: AM33XX: CAN: d_can: Add support for Bosch D_CAN controller
From: AnilKumar, Chimata @ 2012-04-03 13:41 UTC (permalink / raw)
To: Wolfgang Grandegger
Cc: socketcan@hartkopp.net, m.kleine-budde@pengutronix.de,
linux-can@vger.kernel.org, netdev@vger.kernel.org,
linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org,
Gole, Anant, Nori, Sekhar
In-Reply-To: <4F7AF0C7.7020506@grandegger.com>
Hi Wolfgang,
Thanks for reviewing the patch
On Tue, Apr 03, 2012 at 18:14:55, Wolfgang Grandegger wrote:
> On 04/03/2012 02:32 PM, AnilKumar Ch wrote:
> > This patch adds the support for Bosch D_CAN controller.
> >
> > Bosch D_CAN controller is a full-CAN implementation compliant to
> > CAN protocol version 2.0 part A and B. Bosch D_CAN user manual
> > can be obtained from: http://www.semiconductors.bosch.de/media/
> > en/pdf/ipmodules_1/can/d_can_users_manual_111.pdf
> >
> > D_CAN device is used on many SoCs like AM335x, DM8148 and DM813x
> > EVMs from TI, D_CAN details on AM335x can be accessed from:
> > http://www.ti.com/lit/ug/spruh73c/spruh73c.pdf
> >
> > D_CAN can be configurable for 16, 32, 64 and 128 message objects.
> > The driver implementation is based on 64 message objects.
> >
> > Following are the design choices made while writing the controller
> > driver:
> > 1. Interface Register set IF0 has be used for receive and IF1 is
> > used for transmit message objects.
> > 2. Out of the total Message objects available, half of it are kept
> > aside for RX purposes and the rest for TX purposes.
> > 3. NAPI implementation is such that both the TX and RX paths
> > functions in polling mode.
> >
> > Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
>
> Please explain why this CAN controller cannot be handled by the existing
> C_CAN driver, eventually with some extensions. The register layout seems
> almost identical, at least.
>
> Wolfgang.
>
These are the some of the pointers I can say, why I had gone for separate
file instead of existing driver:
* In case of D_CAN driver we can see all the registers are 32bit length
but in case of C_CAN registers are in 16bit length.
* Some of the registers, bit masks are different, so we have to add
checks on every API for differentiating the kind of device
* In case of D_CAN we have some extra features like direct message RAM
access, DMA support, TX/RX pins can be used as GPIO lines (if applicable),
more interrupt lines and three sets of interface registers.
* Wait timings while init bit set/reset during bit-timing initialization
are different in both the cases
* bittiming configurations are different.
Thanks
AnilKumar
^ permalink raw reply
* Re: [PATCH] ARM: OMAP: AM33XX: CAN: d_can: Add support for Bosch D_CAN controller
From: Marc Kleine-Budde @ 2012-04-03 13:49 UTC (permalink / raw)
To: AnilKumar, Chimata
Cc: Wolfgang Grandegger, socketcan@hartkopp.net,
m.kleine-budde@pengutronix.de, linux-can@vger.kernel.org,
netdev@vger.kernel.org, linux-omap@vger.kernel.org,
linux-kernel@vger.kernel.org, Gole, Anant, Nori, Sekhar
In-Reply-To: <331ABD5ECB02734CA317220B2BBEABC1317D85D0@DBDE01.ent.ti.com>
[-- Attachment #1: Type: text/plain, Size: 2873 bytes --]
On 04/03/2012 03:41 PM, AnilKumar, Chimata wrote:
> Hi Wolfgang,
>
> Thanks for reviewing the patch
>
> On Tue, Apr 03, 2012 at 18:14:55, Wolfgang Grandegger wrote:
>> On 04/03/2012 02:32 PM, AnilKumar Ch wrote:
>>> This patch adds the support for Bosch D_CAN controller.
>>>
>>> Bosch D_CAN controller is a full-CAN implementation compliant to
>>> CAN protocol version 2.0 part A and B. Bosch D_CAN user manual
>>> can be obtained from: http://www.semiconductors.bosch.de/media/
>>> en/pdf/ipmodules_1/can/d_can_users_manual_111.pdf
>>>
>>> D_CAN device is used on many SoCs like AM335x, DM8148 and DM813x
>>> EVMs from TI, D_CAN details on AM335x can be accessed from:
>>> http://www.ti.com/lit/ug/spruh73c/spruh73c.pdf
>>>
>>> D_CAN can be configurable for 16, 32, 64 and 128 message objects.
>>> The driver implementation is based on 64 message objects.
>>>
>>> Following are the design choices made while writing the controller
>>> driver:
>>> 1. Interface Register set IF0 has be used for receive and IF1 is
>>> used for transmit message objects.
>>> 2. Out of the total Message objects available, half of it are kept
>>> aside for RX purposes and the rest for TX purposes.
>>> 3. NAPI implementation is such that both the TX and RX paths
>>> functions in polling mode.
>>>
>>> Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
>>
>> Please explain why this CAN controller cannot be handled by the existing
>> C_CAN driver, eventually with some extensions. The register layout seems
>> almost identical, at least.
>>
>> Wolfgang.
>>
>
> These are the some of the pointers I can say, why I had gone for separate
> file instead of existing driver:
> * In case of D_CAN driver we can see all the registers are 32bit length
> but in case of C_CAN registers are in 16bit length.
How many bits in these 32 bit registers are used?
> * Some of the registers, bit masks are different, so we have to add
> checks on every API for differentiating the kind of device
Which registers are this? Can you give us an example?
> * In case of D_CAN we have some extra features like direct message RAM
> access, DMA support, TX/RX pins can be used as GPIO lines (if applicable),
> more interrupt lines and three sets of interface registers.
Which of these features are used in you driver?
> * Wait timings while init bit set/reset during bit-timing initialization
> are different in both the cases
That's not the hot code path, so some ifs shouldn't hurt.
> * bittiming configurations are different.
see above.
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]
^ permalink raw reply
* Re: [PATCH 3/3] netfilter: xt_CT: remove a compile warning
From: Tetsuo Handa @ 2012-04-03 14:28 UTC (permalink / raw)
To: pablo; +Cc: netdev
In-Reply-To: <20120403130620.GA15385@1984>
Pablo Neira Ayuso wrote:
> A bit better patch, no need to hold rcu_read_lock again in
> xt_ct_tg_timeout_put (even if that doesn't harm).
Patch looks OK.
By the way,
665 static struct nf_conn *
666 __nf_conntrack_alloc(struct net *net, u16 zone,
667 const struct nf_conntrack_tuple *orig,
668 const struct nf_conntrack_tuple *repl,
669 gfp_t gfp, u32 hash)
670 {
(...snipped...)
680 atomic_inc(&net->ct.count);
(...snipped...)
698 ct = kmem_cache_alloc(net->ct.nf_conntrack_cachep, gfp);
699 if (ct == NULL) {
700 atomic_dec(&net->ct.count);
701 return ERR_PTR(-ENOMEM);
702 }
(...snipped...)
720 if (zone) {
721 struct nf_conntrack_zone *nf_ct_zone;
722
723 nf_ct_zone = nf_ct_ext_add(ct, NF_CT_EXT_ZONE, GFP_ATOMIC);
724 if (!nf_ct_zone)
725 goto out_free;
726 nf_ct_zone->id = zone;
727 }
(...snipped...)
737 out_free:
I think we want to call atomic_dec() here.
738 kmem_cache_free(net->ct.nf_conntrack_cachep, ct);
739 return ERR_PTR(-ENOMEM);
740 #endif
741 }
^ permalink raw reply
* RE: [PATCH] ARM: OMAP: AM33XX: CAN: d_can: Add support for Bosch D_CAN controller
From: AnilKumar, Chimata @ 2012-04-03 14:29 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: Wolfgang Grandegger, socketcan@hartkopp.net,
m.kleine-budde@pengutronix.de, linux-can@vger.kernel.org,
netdev@vger.kernel.org, linux-omap@vger.kernel.org,
linux-kernel@vger.kernel.org, Gole, Anant, Nori, Sekhar
In-Reply-To: <4F7AFFEC.1010805@pengutronix.de>
On Tue, Apr 03, 2012 at 19:19:32, Marc Kleine-Budde wrote:
> On 04/03/2012 03:41 PM, AnilKumar, Chimata wrote:
> > Hi Wolfgang,
> >
> > Thanks for reviewing the patch
> >
> > On Tue, Apr 03, 2012 at 18:14:55, Wolfgang Grandegger wrote:
> >> On 04/03/2012 02:32 PM, AnilKumar Ch wrote:
> >>> This patch adds the support for Bosch D_CAN controller.
> >>>
> >>> Bosch D_CAN controller is a full-CAN implementation compliant to
> >>> CAN protocol version 2.0 part A and B. Bosch D_CAN user manual
> >>> can be obtained from: http://www.semiconductors.bosch.de/media/
> >>> en/pdf/ipmodules_1/can/d_can_users_manual_111.pdf
> >>>
> >>> D_CAN device is used on many SoCs like AM335x, DM8148 and DM813x
> >>> EVMs from TI, D_CAN details on AM335x can be accessed from:
> >>> http://www.ti.com/lit/ug/spruh73c/spruh73c.pdf
> >>>
> >>> D_CAN can be configurable for 16, 32, 64 and 128 message objects.
> >>> The driver implementation is based on 64 message objects.
> >>>
> >>> Following are the design choices made while writing the controller
> >>> driver:
> >>> 1. Interface Register set IF0 has be used for receive and IF1 is
> >>> used for transmit message objects.
> >>> 2. Out of the total Message objects available, half of it are kept
> >>> aside for RX purposes and the rest for TX purposes.
> >>> 3. NAPI implementation is such that both the TX and RX paths
> >>> functions in polling mode.
> >>>
> >>> Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
> >>
> >> Please explain why this CAN controller cannot be handled by the existing
> >> C_CAN driver, eventually with some extensions. The register layout seems
> >> almost identical, at least.
> >>
> >> Wolfgang.
> >>
> >
> > These are the some of the pointers I can say, why I had gone for separate
> > file instead of existing driver:
> > * In case of D_CAN driver we can see all the registers are 32bit length
> > but in case of C_CAN registers are in 16bit length.
>
> How many bits in these 32 bit registers are used?
In some cases (D_CAN_TXRQ, D_CAN_INTPND, D_CAN_MSGVAL) I have used all the
bits, in some cases used few bits.
Roughly I can say that its (higher 16bits) % of usages is similar as compare
to 16bits
While checking the status of TXRequest registers and INT pending register,
which is a hot code path, we have to put if checks for register access.
>
> > * Some of the registers, bit masks are different, so we have to add
> > checks on every API for differentiating the kind of device
>
> Which registers are this? Can you give us an example?
I am pointing out some of the resisters
* Single registers in case of D_CAN but multiple register in case of C_CAN
So masks will change MASK, ARB, INTPND
* D_CAN_IFCMD is the combination of COMM request and COMM mask registers
>
> > * In case of D_CAN we have some extra features like direct message RAM
> > access, DMA support, TX/RX pins can be used as GPIO lines (if applicable),
> > more interrupt lines and three sets of interface registers.
>
> Which of these features are used in you driver?
Right now I added only CAN functionality, in that I am using two set
of interface registers (0 and 1).
Based on other features status register are extended, we have to handle those
as well.
>
> > * Wait timings while init bit set/reset during bit-timing initialization
> > are different in both the cases
>
> That's not the hot code path, so some ifs shouldn't hurt.
>
> > * bittiming configurations are different.
>
> see above.
>
> Marc
> --
> Pengutronix e.K. | Marc Kleine-Budde |
> Industrial Linux Solutions | Phone: +49-231-2826-924 |
> Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
> Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
>
>
^ permalink raw reply
* Re: [PATCH net-next V5 7/8] net/dcb: Add an optional max rate attribute
From: John Fastabend @ 2012-04-03 14:39 UTC (permalink / raw)
To: Amir Vadai
Cc: David S. Miller, netdev, Roland Dreier, Yevgeny Petrilin,
Oren Duer, Amir Vadai
In-Reply-To: <1333451407-5293-8-git-send-email-amirv@mellanox.com>
On 4/3/2012 4:10 AM, Amir Vadai wrote:
> Although not specified in 8021Qaz spec, it could be useful to enable drivers
> whose HW supports setting a rate limit for an ETS TC. This patch adds this
> optional attribute to DCB netlink. To use it, drivers should implement and
> register the callbacks ieee_setmaxrate and ieee_getmaxrate. The units are 64
> bits long and specified in Kbps to enable usage over both slow and very fast
> networks.
>
> Signed-off-by: Amir Vadai <amirv@mellanox.com>
> ---
[...]
>
> static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = {
> @@ -1243,6 +1245,14 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
> NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets);
> }
>
> + if (ops->ieee_getmaxrate) {
> + struct ieee_maxrate maxrate;
> + err = ops->ieee_getmaxrate(netdev, &maxrate);
> + if (!err)
> + NLA_PUT(skb, DCB_ATTR_IEEE_MAXRATE, sizeof(maxrate),
> + &maxrate);
Don't use the NLA_PUT macros anymore they are error prone use nla_put(). Dave
has a series to remove these no point in adding more.
Thanks,
John
^ permalink raw reply
* Re: [PATCH 3/3] netfilter: xt_CT: remove a compile warning
From: Pablo Neira Ayuso @ 2012-04-03 14:52 UTC (permalink / raw)
To: Tetsuo Handa; +Cc: netdev
In-Reply-To: <201204032328.CDE78687.tQOHSLVFOFMJOF@I-love.SAKURA.ne.jp>
[-- Attachment #1: Type: text/plain, Size: 1288 bytes --]
On Tue, Apr 03, 2012 at 11:28:50PM +0900, Tetsuo Handa wrote:
> Pablo Neira Ayuso wrote:
> > A bit better patch, no need to hold rcu_read_lock again in
> > xt_ct_tg_timeout_put (even if that doesn't harm).
>
> Patch looks OK.
>
> By the way,
>
> 665 static struct nf_conn *
> 666 __nf_conntrack_alloc(struct net *net, u16 zone,
> 667 const struct nf_conntrack_tuple *orig,
> 668 const struct nf_conntrack_tuple *repl,
> 669 gfp_t gfp, u32 hash)
> 670 {
> (...snipped...)
> 680 atomic_inc(&net->ct.count);
> (...snipped...)
> 698 ct = kmem_cache_alloc(net->ct.nf_conntrack_cachep, gfp);
> 699 if (ct == NULL) {
> 700 atomic_dec(&net->ct.count);
> 701 return ERR_PTR(-ENOMEM);
> 702 }
> (...snipped...)
> 720 if (zone) {
> 721 struct nf_conntrack_zone *nf_ct_zone;
> 722
> 723 nf_ct_zone = nf_ct_ext_add(ct, NF_CT_EXT_ZONE, GFP_ATOMIC);
> 724 if (!nf_ct_zone)
> 725 goto out_free;
> 726 nf_ct_zone->id = zone;
> 727 }
> (...snipped...)
> 737 out_free:
>
> I think we want to call atomic_dec() here.
Good catch :-).
Patch to address this issue follows.
[-- Attachment #2: 0001-netfilter-nf_conntrack-fix-count-leak-in-error-path-.patch --]
[-- Type: text/x-diff, Size: 991 bytes --]
>From 0fca4d604c0898128014bc03ef965e0cf187a5e9 Mon Sep 17 00:00:00 2001
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Tue, 3 Apr 2012 16:45:54 +0200
Subject: [PATCH] netfilter: nf_conntrack: fix count leak in error path of __nf_conntrack_alloc
We have to decrement the conntrack counter if we fail to access the
zone extension.
Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_conntrack_core.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index cbdb754..3cc4487 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -735,6 +735,7 @@ __nf_conntrack_alloc(struct net *net, u16 zone,
#ifdef CONFIG_NF_CONNTRACK_ZONES
out_free:
+ atomic_dec(&net->ct.count);
kmem_cache_free(net->ct.nf_conntrack_cachep, ct);
return ERR_PTR(-ENOMEM);
#endif
--
1.7.2.5
^ permalink raw reply related
* [PATCH] marvell sky2 driver: fix irq number assignment bug
From: Chris Metcalf @ 2012-04-03 15:10 UTC (permalink / raw)
To: Stephen Hemminger, netdev, linux-kernel
Fix a minor bug that will display wrong IRQ number in ifconfig output.
Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
---
drivers/net/ethernet/marvell/sky2.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 423a1a2..879b0a4 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -4978,6 +4978,13 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
goto err_out_free_netdev;
}
+ /*
+ * Need to set the IRQ # for the net_device here again after
+ * setting it in sky2_init_netdev() initially, because MSI
+ * will assign a new IRQ # to this PCI device.
+ */
+ dev->irq = hw->pdev->irq;
+
err = register_netdev(dev);
if (err) {
dev_err(&pdev->dev, "cannot register net device\n");
--
1.6.5.2
^ permalink raw reply related
* [PATCH] marvell sky2 driver: fix so it works without unaligned accesses
From: Chris Metcalf @ 2012-04-03 15:13 UTC (permalink / raw)
To: Stephen Hemminger, netdev, linux-kernel
The driver uses a receive_new() routine that ends up requiring unaligned
accesses in IP header processing. If the architecture doesn't support
efficient unaligned accesses, just copy all ingress packets to the bounce
buffers instead.
This allows the driver to be used on the Tilera TILEmpower-Gx, since
the tile architecture doesn't currently handle kernel unaligned accesses,
just userspace.
Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
---
drivers/net/ethernet/marvell/sky2.c | 10 +++++++---
1 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 879b0a4..7a15482 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -2490,6 +2490,7 @@ static struct sk_buff *receive_copy(struct sky2_port *sky2,
return skb;
}
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
/* Adjust length of skb with fragments to match received data */
static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
unsigned int length)
@@ -2555,6 +2556,7 @@ nomap:
nobuf:
return NULL;
}
+#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
/*
* Receive one packet.
@@ -2598,10 +2600,12 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
goto error;
okay:
- if (length < copybreak)
- skb = receive_copy(sky2, re, length);
- else
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+ if (length >= copybreak)
skb = receive_new(sky2, re, length);
+ else
+#endif
+ skb = receive_copy(sky2, re, length);
dev->stats.rx_dropped += (skb == NULL);
--
1.6.5.2
^ permalink raw reply related
* [PATCH v2 net-next] af_unix: reduce high order page allocations
From: Eric Dumazet @ 2012-04-03 15:28 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <1333419304.18626.5.camel@edumazet-glaptop>
unix_dgram_sendmsg() currently builds linear skbs, and this can stress
page allocator with high order page allocations. When memory gets
fragmented, this can eventually fail.
We can try to use order-2 allocations for skb head (SKB_MAX_ALLOC) plus
up to 16 page fragments to lower pressure on buddy allocator.
This patch has no effect on messages of less than 16064 bytes.
(on 64bit arches with PAGE_SIZE=4096)
For bigger messages (from 16065 to 81600 bytes), this patch brings
reliability at the expense of performance penalty because of extra pages
allocations.
netperf -t DG_STREAM -T 0,2 -- -m 16064 -s 200000
->4086040 Messages / 10s
netperf -t DG_STREAM -T 0,2 -- -m 16068 -s 200000
->3901747 Messages / 10s
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
v2: use SKB_MAX_ALLOC instead of SKB_MAX_ORDER(0, 0) to not slow down
applications using up to 16000 bytes messages.
net/unix/af_unix.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index d510353..eadb902 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1442,6 +1442,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
long timeo;
struct scm_cookie tmp_scm;
int max_level;
+ int data_len = 0;
if (NULL == siocb->scm)
siocb->scm = &tmp_scm;
@@ -1475,7 +1476,13 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
if (len > sk->sk_sndbuf - 32)
goto out;
- skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err);
+ if (len > SKB_MAX_ALLOC)
+ data_len = min_t(size_t,
+ len - SKB_MAX_ALLOC,
+ MAX_SKB_FRAGS * PAGE_SIZE);
+
+ skb = sock_alloc_send_pskb(sk, len - data_len, data_len,
+ msg->msg_flags & MSG_DONTWAIT, &err);
if (skb == NULL)
goto out;
@@ -1485,8 +1492,10 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
max_level = err + 1;
unix_get_secdata(siocb->scm, skb);
- skb_reset_transport_header(skb);
- err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+ skb_put(skb, len - data_len);
+ skb->data_len = data_len;
+ skb->len = len;
+ err = skb_copy_datagram_from_iovec(skb, 0, msg->msg_iov, 0, len);
if (err)
goto out_free;
^ permalink raw reply related
* Re: [PATCH] ARM: OMAP: AM33XX: CAN: d_can: Add support for Bosch D_CAN controller
From: Marc Kleine-Budde @ 2012-04-03 15:33 UTC (permalink / raw)
To: AnilKumar, Chimata
Cc: Wolfgang Grandegger, socketcan@hartkopp.net,
m.kleine-budde@pengutronix.de, linux-can@vger.kernel.org,
netdev@vger.kernel.org, linux-omap@vger.kernel.org,
linux-kernel@vger.kernel.org, Gole, Anant, Nori, Sekhar
In-Reply-To: <331ABD5ECB02734CA317220B2BBEABC1317D86F7@DBDE01.ent.ti.com>
[-- Attachment #1: Type: text/plain, Size: 1962 bytes --]
On 04/03/2012 04:29 PM, AnilKumar, Chimata wrote:
>>>> Please explain why this CAN controller cannot be handled by the existing
>>>> C_CAN driver, eventually with some extensions. The register layout seems
>>>> almost identical, at least.
>>>>
>>>> Wolfgang.
>>>>
>>>
>>> These are the some of the pointers I can say, why I had gone for separate
>>> file instead of existing driver:
>>> * In case of D_CAN driver we can see all the registers are 32bit length
>>> but in case of C_CAN registers are in 16bit length.
>>
>> How many bits in these 32 bit registers are used?
>
> In some cases (D_CAN_TXRQ, D_CAN_INTPND, D_CAN_MSGVAL) I have used all the
> bits, in some cases used few bits.
>
> Roughly I can say that its (higher 16bits) % of usages is similar as compare
> to 16bits
>
> While checking the status of TXRequest registers and INT pending register,
> which is a hot code path, we have to put if checks for register access.
The c_can already has a c_can_read_reg32() function. It's for example
used in the rx_poll function. You can make it a function pointer (i.e.
pric->read_reg32()) for easy abstraction.
>>> * Some of the registers, bit masks are different, so we have to add
>>> checks on every API for differentiating the kind of device
>>
>> Which registers are this? Can you give us an example?
>
> I am pointing out some of the resisters
> * Single registers in case of D_CAN but multiple register in case of C_CAN
> So masks will change MASK, ARB, INTPND
> * D_CAN_IFCMD is the combination of COMM request and COMM mask registers
Maybe you can use the read_reg32 function on both c_can and d_can.
regards, Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]
^ permalink raw reply
* Re: [PATCH net: fix /proc/net/dev regression
From: Ben Greear @ 2012-04-03 15:36 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, NetDev, Mihai Maruseac
In-Reply-To: <1333441982.18626.62.camel@edumazet-glaptop>
On 04/03/2012 01:33 AM, Eric Dumazet wrote:
> Commit f04565ddf52 (dev: use name hash for dev_seq_ops) added a second
> regression, as some devices are missing from /proc/net/dev if many
> devices are defined.
>
> When seq_file buffer is filled, the last ->next/show() method is
> canceled (pos value is reverted to value prior ->next() call)
>
> Problem is after above commit, we dont restart the lookup at right
> position in ->start() method.
>
> Fix this by removing the internal 'pos' pointer added in commit, since
> we need to use the 'loff_t *pos' provided by seq_file layer.
>
> This also reverts commit 5cac98dd0 (net: Fix corruption
> in /proc/*/net/dev_mcast), since its not needed anymore.
>
> Reported-by: Ben Greear<greearb@candelatech.com>
> Signed-off-by: Eric Dumazet<eric.dumazet@gmail.com>
> Cc: Mihai Maruseac<mmaruseac@ixiacom.com>
This appears to fix the problem. I do find it mildly irritating
that the ordering is now random in /proc/net/dev, but I guess
that is the price of progress.
Tested-by: Ben Greear <greearb@candelatech.com>
Thanks for the quick fix!
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* Re: [PATCH] marvell sky2 driver: fix irq number assignment bug
From: Ben Hutchings @ 2012-04-03 15:47 UTC (permalink / raw)
To: Chris Metcalf; +Cc: Stephen Hemminger, netdev, linux-kernel
In-Reply-To: <201204031526.q33FQvFO031746@farm-0027.internal.tilera.com>
On Tue, 2012-04-03 at 11:10 -0400, Chris Metcalf wrote:
> Fix a minor bug that will display wrong IRQ number in ifconfig output.
>
> Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
> ---
> drivers/net/ethernet/marvell/sky2.c | 7 +++++++
> 1 files changed, 7 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
> index 423a1a2..879b0a4 100644
> --- a/drivers/net/ethernet/marvell/sky2.c
> +++ b/drivers/net/ethernet/marvell/sky2.c
> @@ -4978,6 +4978,13 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
> goto err_out_free_netdev;
> }
>
> + /*
> + * Need to set the IRQ # for the net_device here again after
> + * setting it in sky2_init_netdev() initially, because MSI
> + * will assign a new IRQ # to this PCI device.
> + */
> + dev->irq = hw->pdev->irq;
> +
> err = register_netdev(dev);
> if (err) {
> dev_err(&pdev->dev, "cannot register net device\n");
I think the consensus now is that net_device::irq should be left at 0
for devices that don't support manual configuration (ISA and the like).
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [PATCH] ARM: OMAP: AM33XX: CAN: d_can: Add support for Bosch D_CAN controller
From: Oliver Hartkopp @ 2012-04-03 15:54 UTC (permalink / raw)
To: AnilKumar, Chimata
Cc: m.kleine-budde@pengutronix.de, wg@grandegger.com,
linux-can@vger.kernel.org, netdev@vger.kernel.org,
linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org,
Gole, Anant, Nori, Sekhar
In-Reply-To: <331ABD5ECB02734CA317220B2BBEABC1317D84CC@DBDE01.ent.ti.com>
On 03.04.2012 14:39, AnilKumar, Chimata wrote:
> Hi All,
>
> Subject line of this patch should be
> "ARM: CAN: d_can: Add support for Bosch D_CAN controller"
No, the d_can IP core is generally not limited to ARM.
"can: Add support for Bosch D_CAN controller"
would be perfectly fine.
The correct way is:
1. post your new CAN driver to linux-can ML
2. When the major reviews & style fixes are done and the driver is fit for
mainline you can post it on ti-omap ML too
But an initial cross-posting of this CAN driver to netdev ML and linux-kernel
ML does not help anyone - it only increases traffic & confusion.
See MAINTAINERS:
http://lxr.linux.no/#linux+v3.3.1/MAINTAINERS#L1710
Thanks for following these hints,
Oliver
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox