* [PATCH v3 net-next-2.6] can: Driver for the Microchip MCP251x SPI CAN controllers
From: Christian Pellegrin @ 2009-11-03 9:07 UTC (permalink / raw)
To: wg-5Yr1BZd7O62+XT7JhA+gdA, socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
netdev-u79uwXL29TY76Z2rM5mHXA, pthomas8589-Re5JQEeQqe8AvxtiuMwx3w
Cc: Christian Pellegrin
In-Reply-To: <4AEF37C1.9030706-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
Signed-off-by: Christian Pellegrin <chripell-VaTbYqLCNhc@public.gmane.org>
---
drivers/net/can/Kconfig | 6 +
drivers/net/can/Makefile | 1 +
drivers/net/can/mcp251x.c | 1164 ++++++++++++++++++++++++++++++++++
include/linux/can/platform/mcp251x.h | 36 +
4 files changed, 1207 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/can/mcp251x.c
create mode 100644 include/linux/can/platform/mcp251x.h
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 26d77cc..b819cc2 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -102,6 +102,12 @@ 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_MCP251X
+ tristate "Microchip MCP251x SPI CAN controllers"
+ depends on CAN_DEV && SPI
+ ---help---
+ Driver for the Microchip MCP251x SPI CAN controllers.
+
config CAN_DEBUG_DEVICES
bool "CAN devices debugging messages"
depends on CAN
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 31f4ab5..1489181 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -12,5 +12,6 @@ obj-y += usb/
obj-$(CONFIG_CAN_SJA1000) += sja1000/
obj-$(CONFIG_CAN_AT91) += at91_can.o
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
+obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
new file mode 100644
index 0000000..8f48f4b
--- /dev/null
+++ b/drivers/net/can/mcp251x.c
@@ -0,0 +1,1164 @@
+/*
+ * CAN bus driver for Microchip 251x CAN Controller with SPI Interface
+ *
+ * MCP2510 support and bug fixes by Christian Pellegrin
+ * <chripell-LERDrqjqfvZg9hUCZPvPmw@public.gmane.org>
+ *
+ * Copyright 2009 Christian Pellegrin EVOL S.r.l.
+ *
+ * Copyright 2007 Raymarine UK, Ltd. All Rights Reserved.
+ * Written under contract by:
+ * Chris Elston, Katalix Systems, Ltd.
+ *
+ * Based on Microchip MCP251x CAN controller driver written by
+ * David Vrabel, Copyright 2006 Arcom Control Systems Ltd.
+ *
+ * Based on CAN bus driver for the CCAN controller written by
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix
+ * - Simon Kallweit, intefo AG
+ * Copyright 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ *
+ * Your platform definition file should specify something like:
+ *
+ * static struct mcp251x_platform_data mcp251x_info = {
+ * .oscillator_frequency = 8000000,
+ * .board_specific_setup = &mcp251x_setup,
+ * .model = CAN_MCP251X_MCP2510,
+ * .power_enable = mcp251x_power_enable,
+ * .transceiver_enable = NULL,
+ * };
+ *
+ * static struct spi_board_info spi_board_info[] = {
+ * {
+ * .modalias = "mcp251x",
+ * .platform_data = &mcp251x_info,
+ * .irq = IRQ_EINT13,
+ * .max_speed_hz = 2*1000*1000,
+ * .chip_select = 2,
+ * },
+ * };
+ *
+ * Please see mcp251x.h for a description of the fields in
+ * struct mcp251x_platform_data.
+ *
+ */
+
+#include <linux/can.h>
+#include <linux/can/core.h>
+#include <linux/can/dev.h>
+#include <linux/can/platform/mcp251x.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/uaccess.h>
+
+/* SPI interface instruction set */
+#define INSTRUCTION_WRITE 0x02
+#define INSTRUCTION_READ 0x03
+#define INSTRUCTION_BIT_MODIFY 0x05
+#define INSTRUCTION_LOAD_TXB(n) (0x40 + 2 * (n))
+#define INSTRUCTION_READ_RXB(n) (((n) == 0) ? 0x90 : 0x94)
+#define INSTRUCTION_RESET 0xC0
+
+/* MPC251x registers */
+#define CANSTAT 0x0e
+#define CANCTRL 0x0f
+# define CANCTRL_REQOP_MASK 0xe0
+# define CANCTRL_REQOP_CONF 0x80
+# define CANCTRL_REQOP_LISTEN_ONLY 0x60
+# define CANCTRL_REQOP_LOOPBACK 0x40
+# define CANCTRL_REQOP_SLEEP 0x20
+# define CANCTRL_REQOP_NORMAL 0x00
+# define CANCTRL_OSM 0x08
+# define CANCTRL_ABAT 0x10
+#define TEC 0x1c
+#define REC 0x1d
+#define CNF1 0x2a
+# define CNF1_SJW_SHIFT 6
+#define CNF2 0x29
+# define CNF2_BTLMODE 0x80
+# define CNF2_SAM 0x40
+# define CNF2_PS1_SHIFT 3
+#define CNF3 0x28
+# define CNF3_SOF 0x08
+# define CNF3_WAKFIL 0x04
+# define CNF3_PHSEG2_MASK 0x07
+#define CANINTE 0x2b
+# define CANINTE_MERRE 0x80
+# define CANINTE_WAKIE 0x40
+# define CANINTE_ERRIE 0x20
+# define CANINTE_TX2IE 0x10
+# define CANINTE_TX1IE 0x08
+# define CANINTE_TX0IE 0x04
+# define CANINTE_RX1IE 0x02
+# define CANINTE_RX0IE 0x01
+#define CANINTF 0x2c
+# define CANINTF_MERRF 0x80
+# define CANINTF_WAKIF 0x40
+# define CANINTF_ERRIF 0x20
+# define CANINTF_TX2IF 0x10
+# define CANINTF_TX1IF 0x08
+# define CANINTF_TX0IF 0x04
+# define CANINTF_RX1IF 0x02
+# define CANINTF_RX0IF 0x01
+#define EFLG 0x2d
+# define EFLG_EWARN 0x01
+# define EFLG_RXWAR 0x02
+# define EFLG_TXWAR 0x04
+# define EFLG_RXEP 0x08
+# define EFLG_TXEP 0x10
+# define EFLG_TXBO 0x20
+# define EFLG_RX0OVR 0x40
+# define EFLG_RX1OVR 0x80
+#define TXBCTRL(n) (((n) * 0x10) + 0x30 + TXBCTRL_OFF)
+# define TXBCTRL_ABTF 0x40
+# define TXBCTRL_MLOA 0x20
+# define TXBCTRL_TXERR 0x10
+# define TXBCTRL_TXREQ 0x08
+#define TXBSIDH(n) (((n) * 0x10) + 0x30 + TXBSIDH_OFF)
+# define SIDH_SHIFT 3
+#define TXBSIDL(n) (((n) * 0x10) + 0x30 + TXBSIDL_OFF)
+# define SIDL_SID_MASK 7
+# define SIDL_SID_SHIFT 5
+# define SIDL_EXIDE_SHIFT 3
+# define SIDL_EID_SHIFT 16
+# define SIDL_EID_MASK 3
+#define TXBEID8(n) (((n) * 0x10) + 0x30 + TXBEID8_OFF)
+#define TXBEID0(n) (((n) * 0x10) + 0x30 + TXBEID0_OFF)
+#define TXBDLC(n) (((n) * 0x10) + 0x30 + TXBDLC_OFF)
+# define DLC_RTR_SHIFT 6
+#define TXBCTRL_OFF 0
+#define TXBSIDH_OFF 1
+#define TXBSIDL_OFF 2
+#define TXBEID8_OFF 3
+#define TXBEID0_OFF 4
+#define TXBDLC_OFF 5
+#define TXBDAT_OFF 6
+#define RXBCTRL(n) (((n) * 0x10) + 0x60 + RXBCTRL_OFF)
+# define RXBCTRL_BUKT 0x04
+# define RXBCTRL_RXM0 0x20
+# define RXBCTRL_RXM1 0x40
+#define RXBSIDH(n) (((n) * 0x10) + 0x60 + RXBSIDH_OFF)
+# define RXBSIDH_SHIFT 3
+#define RXBSIDL(n) (((n) * 0x10) + 0x60 + RXBSIDL_OFF)
+# define RXBSIDL_IDE 0x08
+# define RXBSIDL_EID 3
+# define RXBSIDL_SHIFT 5
+#define RXBEID8(n) (((n) * 0x10) + 0x60 + RXBEID8_OFF)
+#define RXBEID0(n) (((n) * 0x10) + 0x60 + RXBEID0_OFF)
+#define RXBDLC(n) (((n) * 0x10) + 0x60 + RXBDLC_OFF)
+# define RXBDLC_LEN_MASK 0x0f
+# define RXBDLC_RTR 0x40
+#define RXBCTRL_OFF 0
+#define RXBSIDH_OFF 1
+#define RXBSIDL_OFF 2
+#define RXBEID8_OFF 3
+#define RXBEID0_OFF 4
+#define RXBDLC_OFF 5
+#define RXBDAT_OFF 6
+
+#define GET_BYTE(val, byte) \
+ (((val) >> ((byte) * 8)) & 0xff)
+#define SET_BYTE(val, byte) \
+ (((val) & 0xff) << ((byte) * 8))
+
+/*
+ * Buffer size required for the largest SPI transfer (i.e., reading a
+ * frame)
+ */
+#define CAN_FRAME_MAX_DATA_LEN 8
+#define SPI_TRANSFER_BUF_LEN (6 + CAN_FRAME_MAX_DATA_LEN)
+#define CAN_FRAME_MAX_BITS 128
+
+#define TX_ECHO_SKB_MAX 1
+
+#define DEVICE_NAME "mcp251x"
+
+static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */
+module_param(mcp251x_enable_dma, int, S_IRUGO);
+MODULE_PARM_DESC(mcp251x_enable_dma, "Enable SPI DMA. Default: 0 (Off)");
+
+static struct can_bittiming_const mcp251x_bittiming_const = {
+ .name = DEVICE_NAME,
+ .tseg1_min = 3,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+};
+
+struct mcp251x_priv {
+ struct can_priv can;
+ struct net_device *net;
+ struct spi_device *spi;
+
+ struct mutex spi_lock; /* SPI buffer lock */
+ u8 *spi_tx_buf;
+ u8 *spi_rx_buf;
+ dma_addr_t spi_tx_dma;
+ dma_addr_t spi_rx_dma;
+
+ struct sk_buff *tx_skb;
+ int tx_len;
+ struct workqueue_struct *wq;
+ struct work_struct tx_work;
+ struct work_struct irq_work;
+ struct completion awake;
+ int wake;
+ int force_quit;
+ int after_suspend;
+#define AFTER_SUSPEND_UP 1
+#define AFTER_SUSPEND_DOWN 2
+#define AFTER_SUSPEND_POWER 4
+#define AFTER_SUSPEND_RESTART 8
+ int restart_tx;
+};
+
+static void mcp251x_clean(struct net_device *net)
+{
+ struct mcp251x_priv *priv = netdev_priv(net);
+
+ net->stats.tx_errors++;
+ if (priv->tx_skb)
+ dev_kfree_skb(priv->tx_skb);
+ if (priv->tx_len)
+ can_free_echo_skb(priv->net, 0);
+ priv->tx_skb = NULL;
+ priv->tx_len = 0;
+}
+
+/*
+ * Note about handling of error return of mcp251x_spi_trans: accessing
+ * registers via SPI is not really different conceptually than using
+ * normal I/O assembler instructions, although it's much more
+ * complicated from a practical POV. So it's not advisable to always
+ * check the return value of this function. Imagine that every
+ * read{b,l}, write{b,l} and friends would be bracketed in "if ( < 0)
+ * error();", it would be a great mess (well there are some situation
+ * when exception handling C++ like could be useful after all). So we
+ * just check that transfers are OK at the beginning of our
+ * conversation with the chip and to avoid doing really nasty things
+ * (like injecting bogus packets in the network stack).
+ */
+static int mcp251x_spi_trans(struct spi_device *spi, int len)
+{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct spi_transfer t = {
+ .tx_buf = priv->spi_tx_buf,
+ .rx_buf = priv->spi_rx_buf,
+ .len = len,
+ .cs_change = 0,
+ };
+ struct spi_message m;
+ int ret;
+
+ spi_message_init(&m);
+
+ if (mcp251x_enable_dma) {
+ t.tx_dma = priv->spi_tx_dma;
+ t.rx_dma = priv->spi_rx_dma;
+ m.is_dma_mapped = 1;
+ }
+
+ spi_message_add_tail(&t, &m);
+
+ ret = spi_sync(spi, &m);
+ if (ret)
+ dev_err(&spi->dev, "spi transfer failed: ret = %d\n", ret);
+ return ret;
+}
+
+static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
+{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ u8 val = 0;
+
+ mutex_lock(&priv->spi_lock);
+
+ priv->spi_tx_buf[0] = INSTRUCTION_READ;
+ priv->spi_tx_buf[1] = reg;
+
+ mcp251x_spi_trans(spi, 3);
+ val = priv->spi_rx_buf[2];
+
+ mutex_unlock(&priv->spi_lock);
+
+ return val;
+}
+
+static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
+{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
+ mutex_lock(&priv->spi_lock);
+
+ priv->spi_tx_buf[0] = INSTRUCTION_WRITE;
+ priv->spi_tx_buf[1] = reg;
+ priv->spi_tx_buf[2] = val;
+
+ mcp251x_spi_trans(spi, 3);
+
+ mutex_unlock(&priv->spi_lock);
+}
+
+static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
+ u8 mask, uint8_t val)
+{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
+ mutex_lock(&priv->spi_lock);
+
+ priv->spi_tx_buf[0] = INSTRUCTION_BIT_MODIFY;
+ priv->spi_tx_buf[1] = reg;
+ priv->spi_tx_buf[2] = mask;
+ priv->spi_tx_buf[3] = val;
+
+ mcp251x_spi_trans(spi, 4);
+
+ mutex_unlock(&priv->spi_lock);
+}
+
+static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
+ int len, int tx_buf_idx)
+{
+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
+ if (pdata->model == CAN_MCP251X_MCP2510) {
+ int i;
+
+ for (i = 1; i < TXBDAT_OFF + len; i++)
+ mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + i,
+ buf[i]);
+ } else {
+ mutex_lock(&priv->spi_lock);
+ memcpy(priv->spi_tx_buf, buf, TXBDAT_OFF + len);
+ mcp251x_spi_trans(spi, TXBDAT_OFF + len);
+ mutex_unlock(&priv->spi_lock);
+ }
+}
+
+static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
+ int tx_buf_idx)
+{
+ u32 sid, eid, exide, rtr;
+ u8 buf[SPI_TRANSFER_BUF_LEN];
+
+ exide = (frame->can_id & CAN_EFF_FLAG) ? 1 : 0; /* Extended ID Enable */
+ if (exide)
+ sid = (frame->can_id & CAN_EFF_MASK) >> 18;
+ else
+ sid = frame->can_id & CAN_SFF_MASK; /* Standard ID */
+ eid = frame->can_id & CAN_EFF_MASK; /* Extended ID */
+ rtr = (frame->can_id & CAN_RTR_FLAG) ? 1 : 0; /* Remote transmission */
+
+ buf[TXBCTRL_OFF] = INSTRUCTION_LOAD_TXB(tx_buf_idx);
+ buf[TXBSIDH_OFF] = sid >> SIDH_SHIFT;
+ buf[TXBSIDL_OFF] = ((sid & SIDL_SID_MASK) << SIDL_SID_SHIFT) |
+ (exide << SIDL_EXIDE_SHIFT) |
+ ((eid >> SIDL_EID_SHIFT) & SIDL_EID_MASK);
+ buf[TXBEID8_OFF] = GET_BYTE(eid, 1);
+ buf[TXBEID0_OFF] = GET_BYTE(eid, 0);
+ buf[TXBDLC_OFF] = (rtr << DLC_RTR_SHIFT) | frame->can_dlc;
+ memcpy(buf + TXBDAT_OFF, frame->data, frame->can_dlc);
+ mcp251x_hw_tx_frame(spi, buf, frame->can_dlc, tx_buf_idx);
+ mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ);
+}
+
+static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
+ int buf_idx)
+{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+
+ if (pdata->model == CAN_MCP251X_MCP2510) {
+ int i, len;
+
+ for (i = 1; i < RXBDAT_OFF; i++)
+ buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);
+ len = buf[RXBDLC_OFF] & RXBDLC_LEN_MASK;
+ if (len > 8)
+ len = 8;
+ for (; i < (RXBDAT_OFF + len); i++)
+ buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);
+ } else {
+ mutex_lock(&priv->spi_lock);
+
+ priv->spi_tx_buf[RXBCTRL_OFF] = INSTRUCTION_READ_RXB(buf_idx);
+ mcp251x_spi_trans(spi, SPI_TRANSFER_BUF_LEN);
+ memcpy(buf, priv->spi_rx_buf, SPI_TRANSFER_BUF_LEN);
+
+ mutex_unlock(&priv->spi_lock);
+ }
+}
+
+static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
+{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct sk_buff *skb;
+ struct can_frame *frame;
+ u8 buf[SPI_TRANSFER_BUF_LEN];
+
+ skb = alloc_can_skb(priv->net, &frame);
+ if (!skb) {
+ dev_err(&spi->dev, "cannot allocate RX skb\n");
+ priv->net->stats.rx_dropped++;
+ return;
+ }
+
+ mcp251x_hw_rx_frame(spi, buf, buf_idx);
+ if (buf[RXBSIDL_OFF] & RXBSIDL_IDE) {
+ /* Extended ID format */
+ frame->can_id = CAN_EFF_FLAG;
+ frame->can_id |=
+ /* Extended ID part */
+ SET_BYTE(buf[RXBSIDL_OFF] & RXBSIDL_EID, 2) |
+ SET_BYTE(buf[RXBEID8_OFF], 1) |
+ SET_BYTE(buf[RXBEID0_OFF], 0) |
+ /* Standard ID part */
+ (((buf[RXBSIDH_OFF] << RXBSIDH_SHIFT) |
+ (buf[RXBSIDL_OFF] >> RXBSIDL_SHIFT)) << 18);
+ /* Remote transmission request */
+ if (buf[RXBDLC_OFF] & RXBDLC_RTR)
+ frame->can_id |= CAN_RTR_FLAG;
+ } else {
+ /* Standard ID format */
+ frame->can_id =
+ (buf[RXBSIDH_OFF] << RXBSIDH_SHIFT) |
+ (buf[RXBSIDL_OFF] >> RXBSIDL_SHIFT);
+ }
+ /* Data length */
+ frame->can_dlc = buf[RXBDLC_OFF] & RXBDLC_LEN_MASK;
+ if (frame->can_dlc > 8) {
+ dev_warn(&spi->dev, "invalid frame recevied\n");
+ priv->net->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ return;
+ }
+ memcpy(frame->data, buf + RXBDAT_OFF, frame->can_dlc);
+
+ priv->net->stats.rx_packets++;
+ priv->net->stats.rx_bytes += frame->can_dlc;
+ netif_rx(skb);
+}
+
+static void mcp251x_hw_sleep(struct spi_device *spi)
+{
+ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP);
+}
+
+static void mcp251x_hw_wakeup(struct spi_device *spi)
+{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
+ priv->wake = 1;
+
+ /* Can only wake up by generating a wake-up interrupt. */
+ mcp251x_write_bits(spi, CANINTE, CANINTE_WAKIE, CANINTE_WAKIE);
+ mcp251x_write_bits(spi, CANINTF, CANINTF_WAKIF, CANINTF_WAKIF);
+
+ /* Wait until the device is awake */
+ if (!wait_for_completion_timeout(&priv->awake, HZ))
+ dev_err(&spi->dev, "MCP251x didn't wake-up\n");
+}
+
+static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *net)
+{
+ struct mcp251x_priv *priv = netdev_priv(net);
+ struct spi_device *spi = priv->spi;
+
+ if (priv->tx_skb || priv->tx_len) {
+ dev_warn(&spi->dev, "hard_xmit called while tx busy\n");
+ netif_stop_queue(net);
+ return NETDEV_TX_BUSY;
+ }
+
+ if (skb->len != sizeof(struct can_frame)) {
+ dev_err(&spi->dev, "dropping packet - bad length\n");
+ dev_kfree_skb(skb);
+ net->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ netif_stop_queue(net);
+ priv->tx_skb = skb;
+ net->trans_start = jiffies;
+ queue_work(priv->wq, &priv->tx_work);
+
+ return NETDEV_TX_OK;
+}
+
+static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)
+{
+ struct mcp251x_priv *priv = netdev_priv(net);
+
+ switch (mode) {
+ case CAN_MODE_START:
+ /* We have to delay work since SPI I/O may sleep */
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ priv->restart_tx = 1;
+ if (priv->can.restart_ms == 0)
+ priv->after_suspend = AFTER_SUSPEND_RESTART;
+ queue_work(priv->wq, &priv->irq_work);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static void mcp251x_set_normal_mode(struct spi_device *spi)
+{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ unsigned long timeout;
+
+ /* Enable interrupts */
+ mcp251x_write_reg(spi, CANINTE,
+ CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE |
+ CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE |
+ CANINTF_MERRF);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+ /* Put device into loopback mode */
+ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LOOPBACK);
+ } else {
+ /* Put device into normal mode */
+ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL);
+
+ /* Wait for the device to enter normal mode */
+ timeout = jiffies + HZ;
+ while (mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) {
+ schedule();
+ if (time_after(jiffies, timeout)) {
+ dev_err(&spi->dev, "MCP251x didn't"
+ " enter in normal mode\n");
+ return;
+ }
+ }
+ }
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+}
+
+static int mcp251x_do_set_bittiming(struct net_device *net)
+{
+ struct mcp251x_priv *priv = netdev_priv(net);
+ struct can_bittiming *bt = &priv->can.bittiming;
+ struct spi_device *spi = priv->spi;
+
+ mcp251x_write_reg(spi, CNF1, ((bt->sjw - 1) << CNF1_SJW_SHIFT) |
+ (bt->brp - 1));
+ mcp251x_write_reg(spi, CNF2, CNF2_BTLMODE |
+ (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES ?
+ CNF2_SAM : 0) |
+ ((bt->phase_seg1 - 1) << CNF2_PS1_SHIFT) |
+ (bt->prop_seg - 1));
+ mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK,
+ (bt->phase_seg2 - 1));
+ dev_info(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n",
+ mcp251x_read_reg(spi, CNF1),
+ mcp251x_read_reg(spi, CNF2),
+ mcp251x_read_reg(spi, CNF3));
+
+ return 0;
+}
+
+static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
+ struct spi_device *spi)
+{
+ int ret;
+
+ ret = open_candev(net);
+ if (ret) {
+ dev_err(&spi->dev, "unable to set initial baudrate!\n");
+ return ret;
+ }
+
+ /* Enable RX0->RX1 buffer roll over and disable filters */
+ mcp251x_write_bits(spi, RXBCTRL(0),
+ RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1,
+ RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1);
+ mcp251x_write_bits(spi, RXBCTRL(1),
+ RXBCTRL_RXM0 | RXBCTRL_RXM1,
+ RXBCTRL_RXM0 | RXBCTRL_RXM1);
+ return 0;
+}
+
+static void mcp251x_hw_reset(struct spi_device *spi)
+{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ int ret;
+
+ mutex_lock(&priv->spi_lock);
+
+ priv->spi_tx_buf[0] = INSTRUCTION_RESET;
+
+ ret = spi_write(spi, priv->spi_tx_buf, 1);
+
+ mutex_unlock(&priv->spi_lock);
+
+ if (ret)
+ dev_err(&spi->dev, "reset failed: ret = %d\n", ret);
+ /* Wait for reset to finish */
+ mdelay(10);
+}
+
+static int mcp251x_hw_probe(struct spi_device *spi)
+{
+ int st1, st2;
+
+ mcp251x_hw_reset(spi);
+
+ /*
+ * Please note that these are "magic values" based on after
+ * reset defaults taken from data sheet which allows us to see
+ * if we really have a chip on the bus (we avoid common all
+ * zeroes or all ones situations)
+ */
+ st1 = mcp251x_read_reg(spi, CANSTAT) & 0xEE;
+ st2 = mcp251x_read_reg(spi, CANCTRL) & 0x17;
+
+ dev_dbg(&spi->dev, "CANSTAT 0x%02x CANCTRL 0x%02x\n", st1, st2);
+
+ /* Check for power up default values */
+ return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
+}
+
+static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
+{
+ struct net_device *net = (struct net_device *)dev_id;
+ struct mcp251x_priv *priv = netdev_priv(net);
+
+ /* Schedule bottom half */
+ if (!work_pending(&priv->irq_work))
+ queue_work(priv->wq, &priv->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static int mcp251x_open(struct net_device *net)
+{
+ struct mcp251x_priv *priv = netdev_priv(net);
+ struct spi_device *spi = priv->spi;
+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+ int ret;
+
+ if (pdata->transceiver_enable)
+ pdata->transceiver_enable(1);
+
+ priv->force_quit = 0;
+ priv->tx_skb = NULL;
+ priv->tx_len = 0;
+
+ ret = request_irq(spi->irq, mcp251x_can_isr,
+ IRQF_TRIGGER_FALLING, DEVICE_NAME, net);
+ if (ret) {
+ dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
+ if (pdata->transceiver_enable)
+ pdata->transceiver_enable(0);
+ return ret;
+ }
+
+ mcp251x_hw_wakeup(spi);
+ mcp251x_hw_reset(spi);
+ ret = mcp251x_setup(net, priv, spi);
+ if (ret) {
+ free_irq(spi->irq, net);
+ if (pdata->transceiver_enable)
+ pdata->transceiver_enable(0);
+ return ret;
+ }
+ mcp251x_set_normal_mode(spi);
+ netif_wake_queue(net);
+
+ return 0;
+}
+
+static int mcp251x_stop(struct net_device *net)
+{
+ struct mcp251x_priv *priv = netdev_priv(net);
+ struct spi_device *spi = priv->spi;
+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+
+ close_candev(net);
+
+ /* Disable and clear pending interrupts */
+ mcp251x_write_reg(spi, CANINTE, 0x00);
+ mcp251x_write_reg(spi, CANINTF, 0x00);
+
+ priv->force_quit = 1;
+ free_irq(spi->irq, net);
+ flush_workqueue(priv->wq);
+
+ mcp251x_write_reg(spi, TXBCTRL(0), 0);
+ if (priv->tx_skb || priv->tx_len)
+ mcp251x_clean(net);
+
+ mcp251x_hw_sleep(spi);
+
+ if (pdata->transceiver_enable)
+ pdata->transceiver_enable(0);
+
+ priv->can.state = CAN_STATE_STOPPED;
+
+ return 0;
+}
+
+static void mcp251x_tx_work_handler(struct work_struct *ws)
+{
+ struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,
+ tx_work);
+ struct spi_device *spi = priv->spi;
+ struct net_device *net = priv->net;
+ struct can_frame *frame;
+
+ if (priv->tx_skb) {
+ frame = (struct can_frame *)priv->tx_skb->data;
+
+ if (priv->can.state == CAN_STATE_BUS_OFF) {
+ mcp251x_clean(net);
+ netif_wake_queue(net);
+ return;
+ }
+ if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
+ frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
+ mcp251x_hw_tx(spi, frame, 0);
+ priv->tx_len = 1 + frame->can_dlc;
+ can_put_echo_skb(priv->tx_skb, net, 0);
+ priv->tx_skb = NULL;
+ }
+}
+
+static void mcp251x_irq_work_handler(struct work_struct *ws)
+{
+ struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,
+ irq_work);
+ struct spi_device *spi = priv->spi;
+ struct net_device *net = priv->net;
+ u8 txbnctrl;
+ u8 intf;
+ enum can_state new_state;
+
+ if (priv->after_suspend) {
+ mdelay(10);
+ mcp251x_hw_reset(spi);
+ mcp251x_setup(net, priv, spi);
+ if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
+ mcp251x_set_normal_mode(spi);
+ } else if (priv->after_suspend & AFTER_SUSPEND_UP) {
+ netif_device_attach(net);
+ /* Clean since we lost tx buffer */
+ if (priv->tx_skb || priv->tx_len) {
+ mcp251x_clean(net);
+ netif_wake_queue(net);
+ }
+ mcp251x_set_normal_mode(spi);
+ } else {
+ mcp251x_hw_sleep(spi);
+ }
+ priv->after_suspend = 0;
+ }
+
+ if (priv->can.restart_ms == 0 && priv->can.state == CAN_STATE_BUS_OFF)
+ return;
+
+ while (!priv->force_quit && !freezing(current)) {
+ u8 eflag = mcp251x_read_reg(spi, EFLG);
+ int can_id = 0, data1 = 0;
+
+ mcp251x_write_reg(spi, EFLG, 0x00);
+
+ if (priv->restart_tx) {
+ priv->restart_tx = 0;
+ mcp251x_write_reg(spi, TXBCTRL(0), 0);
+ if (priv->tx_skb || priv->tx_len)
+ mcp251x_clean(net);
+ netif_wake_queue(net);
+ can_id |= CAN_ERR_RESTARTED;
+ }
+
+ if (priv->wake) {
+ /* Wait whilst the device wakes up */
+ mdelay(10);
+ priv->wake = 0;
+ }
+
+ intf = mcp251x_read_reg(spi, CANINTF);
+ mcp251x_write_bits(spi, CANINTF, intf, 0x00);
+
+ /* Update can state */
+ if (eflag & EFLG_TXBO) {
+ new_state = CAN_STATE_BUS_OFF;
+ can_id |= CAN_ERR_BUSOFF;
+ } else if (eflag & EFLG_TXEP) {
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ can_id |= CAN_ERR_CRTL;
+ data1 |= CAN_ERR_CRTL_TX_PASSIVE;
+ } else if (eflag & EFLG_RXEP) {
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ can_id |= CAN_ERR_CRTL;
+ data1 |= CAN_ERR_CRTL_RX_PASSIVE;
+ } else if (eflag & EFLG_TXWAR) {
+ new_state = CAN_STATE_ERROR_WARNING;
+ can_id |= CAN_ERR_CRTL;
+ data1 |= CAN_ERR_CRTL_TX_WARNING;
+ } else if (eflag & EFLG_RXWAR) {
+ new_state = CAN_STATE_ERROR_WARNING;
+ can_id |= CAN_ERR_CRTL;
+ data1 |= CAN_ERR_CRTL_RX_WARNING;
+ } else {
+ new_state = CAN_STATE_ERROR_ACTIVE;
+ }
+
+ /* Update can state statistics */
+ switch (priv->can.state) {
+ case CAN_STATE_ERROR_ACTIVE:
+ if (new_state >= CAN_STATE_ERROR_WARNING &&
+ new_state <= CAN_STATE_BUS_OFF)
+ priv->can.can_stats.error_warning++;
+ case CAN_STATE_ERROR_WARNING: /* fallthrough */
+ if (new_state >= CAN_STATE_ERROR_PASSIVE &&
+ new_state <= CAN_STATE_BUS_OFF)
+ priv->can.can_stats.error_passive++;
+ break;
+ default:
+ break;
+ }
+ priv->can.state = new_state;
+
+ if ((intf & CANINTF_ERRIF) || (can_id & CAN_ERR_RESTARTED)) {
+ struct sk_buff *skb;
+ struct can_frame *frame;
+
+ /* Create error frame */
+ skb = alloc_can_err_skb(net, &frame);
+ if (skb) {
+ /* Set error frame flags based on bus state */
+ frame->can_id = can_id;
+ frame->data[1] = data1;
+
+ /* Update net stats for overflows */
+ if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
+ if (eflag & EFLG_RX0OVR)
+ net->stats.rx_over_errors++;
+ if (eflag & EFLG_RX1OVR)
+ net->stats.rx_over_errors++;
+ frame->can_id |= CAN_ERR_CRTL;
+ frame->data[1] |=
+ CAN_ERR_CRTL_RX_OVERFLOW;
+ }
+
+ netif_rx(skb);
+ } else {
+ dev_info(&spi->dev,
+ "cannot allocate error skb\n");
+ }
+ }
+
+ if (priv->can.state == CAN_STATE_BUS_OFF) {
+ if (priv->can.restart_ms == 0) {
+ can_bus_off(net);
+ mcp251x_hw_sleep(spi);
+ return;
+ }
+ }
+
+ if (intf == 0)
+ break;
+
+ if (intf & CANINTF_WAKIF)
+ complete(&priv->awake);
+
+ if (intf & CANINTF_MERRF) {
+ /* If there are pending Tx buffers, restart queue */
+ txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));
+ if (!(txbnctrl & TXBCTRL_TXREQ)) {
+ if (priv->tx_skb || priv->tx_len)
+ mcp251x_clean(net);
+ netif_wake_queue(net);
+ }
+ }
+
+ if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) {
+ net->stats.tx_packets++;
+ net->stats.tx_bytes += priv->tx_len - 1;
+ if (priv->tx_len) {
+ can_get_echo_skb(net, 0);
+ priv->tx_len = 0;
+ }
+ netif_wake_queue(net);
+ }
+
+ if (intf & CANINTF_RX0IF)
+ mcp251x_hw_rx(spi, 0);
+
+ if (intf & CANINTF_RX1IF)
+ mcp251x_hw_rx(spi, 1);
+ }
+}
+
+static const struct net_device_ops mcp251x_netdev_ops = {
+ .ndo_open = mcp251x_open,
+ .ndo_stop = mcp251x_stop,
+ .ndo_start_xmit = mcp251x_hard_start_xmit,
+};
+
+static int __devinit mcp251x_can_probe(struct spi_device *spi)
+{
+ struct net_device *net;
+ struct mcp251x_priv *priv;
+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+ int ret = -ENODEV;
+
+ if (!pdata)
+ /* Platform data is required for osc freq */
+ goto error_out;
+
+ /* Allocate can/net device */
+ net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);
+ if (!net) {
+ ret = -ENOMEM;
+ goto error_alloc;
+ }
+
+ net->netdev_ops = &mcp251x_netdev_ops;
+ net->flags |= IFF_ECHO;
+
+ priv = netdev_priv(net);
+ priv->can.bittiming_const = &mcp251x_bittiming_const;
+ priv->can.do_set_mode = mcp251x_do_set_mode;
+ priv->can.clock.freq = pdata->oscillator_frequency / 2;
+ priv->can.do_set_bittiming = mcp251x_do_set_bittiming;
+ priv->net = net;
+ dev_set_drvdata(&spi->dev, priv);
+
+ priv->spi = spi;
+ mutex_init(&priv->spi_lock);
+
+ /* If requested, allocate DMA buffers */
+ if (mcp251x_enable_dma) {
+ spi->dev.coherent_dma_mask = ~0;
+
+ /*
+ * Minimum coherent DMA allocation is PAGE_SIZE, so allocate
+ * that much and share it between Tx and Rx DMA buffers.
+ */
+ priv->spi_tx_buf = dma_alloc_coherent(&spi->dev,
+ PAGE_SIZE,
+ &priv->spi_tx_dma,
+ GFP_DMA);
+
+ if (priv->spi_tx_buf) {
+ priv->spi_rx_buf = (u8 *)(priv->spi_tx_buf +
+ (PAGE_SIZE / 2));
+ priv->spi_rx_dma = (dma_addr_t)(priv->spi_tx_dma +
+ (PAGE_SIZE / 2));
+ } else {
+ /* Fall back to non-DMA */
+ mcp251x_enable_dma = 0;
+ }
+ }
+
+ /* Allocate non-DMA buffers */
+ if (!mcp251x_enable_dma) {
+ priv->spi_tx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
+ if (!priv->spi_tx_buf) {
+ ret = -ENOMEM;
+ goto error_tx_buf;
+ }
+ priv->spi_rx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
+ if (!priv->spi_tx_buf) {
+ ret = -ENOMEM;
+ goto error_rx_buf;
+ }
+ }
+
+ if (pdata->power_enable)
+ pdata->power_enable(1);
+
+ /* Call out to platform specific setup */
+ if (pdata->board_specific_setup)
+ pdata->board_specific_setup(spi);
+
+ SET_NETDEV_DEV(net, &spi->dev);
+
+ priv->wq = create_freezeable_workqueue("mcp251x_wq");
+
+ INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
+ INIT_WORK(&priv->irq_work, mcp251x_irq_work_handler);
+
+ init_completion(&priv->awake);
+
+ /* Configure the SPI bus */
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+
+ if (!mcp251x_hw_probe(spi)) {
+ dev_info(&spi->dev, "Probe failed\n");
+ goto error_probe;
+ }
+ mcp251x_hw_sleep(spi);
+
+ if (pdata->transceiver_enable)
+ pdata->transceiver_enable(0);
+
+ ret = register_candev(net);
+ if (!ret) {
+ dev_info(&spi->dev, "probed\n");
+ return ret;
+ }
+error_probe:
+ if (!mcp251x_enable_dma)
+ kfree(priv->spi_rx_buf);
+error_rx_buf:
+ if (!mcp251x_enable_dma)
+ kfree(priv->spi_tx_buf);
+error_tx_buf:
+ free_candev(net);
+ if (mcp251x_enable_dma)
+ dma_free_coherent(&spi->dev, PAGE_SIZE,
+ priv->spi_tx_buf, priv->spi_tx_dma);
+error_alloc:
+ if (pdata->power_enable)
+ pdata->power_enable(0);
+ dev_err(&spi->dev, "probe failed\n");
+error_out:
+ return ret;
+}
+
+static int __devexit mcp251x_can_remove(struct spi_device *spi)
+{
+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct net_device *net = priv->net;
+
+ unregister_candev(net);
+ free_candev(net);
+
+ priv->force_quit = 1;
+ flush_workqueue(priv->wq);
+ destroy_workqueue(priv->wq);
+
+ if (mcp251x_enable_dma) {
+ dma_free_coherent(&spi->dev, PAGE_SIZE,
+ priv->spi_tx_buf, priv->spi_tx_dma);
+ } else {
+ kfree(priv->spi_tx_buf);
+ kfree(priv->spi_rx_buf);
+ }
+
+ if (pdata->power_enable)
+ pdata->power_enable(0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state)
+{
+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct net_device *net = priv->net;
+
+ if (netif_running(net)) {
+ netif_device_detach(net);
+
+ mcp251x_hw_sleep(spi);
+ if (pdata->transceiver_enable)
+ pdata->transceiver_enable(0);
+ priv->after_suspend = AFTER_SUSPEND_UP;
+ } else {
+ priv->after_suspend = AFTER_SUSPEND_DOWN;
+ }
+
+ if (pdata->power_enable) {
+ pdata->power_enable(0);
+ priv->after_suspend |= AFTER_SUSPEND_POWER;
+ }
+
+ return 0;
+}
+
+static int mcp251x_can_resume(struct spi_device *spi)
+{
+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
+ if (priv->after_suspend & AFTER_SUSPEND_POWER) {
+ pdata->power_enable(1);
+ queue_work(priv->wq, &priv->irq_work);
+ } else {
+ if (priv->after_suspend & AFTER_SUSPEND_UP) {
+ if (pdata->transceiver_enable)
+ pdata->transceiver_enable(1);
+ queue_work(priv->wq, &priv->irq_work);
+ } else {
+ priv->after_suspend = 0;
+ }
+ }
+ return 0;
+}
+#else
+#define mcp251x_can_suspend NULL
+#define mcp251x_can_resume NULL
+#endif
+
+static struct spi_driver mcp251x_can_driver = {
+ .driver = {
+ .name = DEVICE_NAME,
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+
+ .probe = mcp251x_can_probe,
+ .remove = __devexit_p(mcp251x_can_remove),
+ .suspend = mcp251x_can_suspend,
+ .resume = mcp251x_can_resume,
+};
+
+static int __init mcp251x_can_init(void)
+{
+ return spi_register_driver(&mcp251x_can_driver);
+}
+
+static void __exit mcp251x_can_exit(void)
+{
+ spi_unregister_driver(&mcp251x_can_driver);
+}
+
+module_init(mcp251x_can_init);
+module_exit(mcp251x_can_exit);
+
+MODULE_AUTHOR("Chris Elston <celston-Bm0nJX+W7e9BDgjK7y7TUQ@public.gmane.org>, "
+ "Christian Pellegrin <chripell-LERDrqjqfvZg9hUCZPvPmw@public.gmane.org>");
+MODULE_DESCRIPTION("Microchip 251x CAN driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/can/platform/mcp251x.h b/include/linux/can/platform/mcp251x.h
new file mode 100644
index 0000000..1448177
--- /dev/null
+++ b/include/linux/can/platform/mcp251x.h
@@ -0,0 +1,36 @@
+#ifndef __CAN_PLATFORM_MCP251X_H__
+#define __CAN_PLATFORM_MCP251X_H__
+
+/*
+ *
+ * CAN bus driver for Microchip 251x CAN Controller with SPI Interface
+ *
+ */
+
+#include <linux/spi/spi.h>
+
+/**
+ * struct mcp251x_platform_data - MCP251X SPI CAN controller platform data
+ * @oscillator_frequency: - oscillator frequency in Hz
+ * @model: - actual type of chip
+ * @board_specific_setup: - called before probing the chip (power,reset)
+ * @transceiver_enable: - called to power on/off the transceiver
+ * @power_enable: - called to power on/off the mcp *and* the
+ * transceiver
+ *
+ * Please note that you should define power_enable or transceiver_enable or
+ * none of them. Defining both of them is no use.
+ *
+ */
+
+struct mcp251x_platform_data {
+ unsigned long oscillator_frequency;
+ int model;
+#define CAN_MCP251X_MCP2510 0
+#define CAN_MCP251X_MCP2515 1
+ int (*board_specific_setup)(struct spi_device *spi);
+ int (*transceiver_enable)(int enable);
+ int (*power_enable) (int enable);
+};
+
+#endif /* __CAN_PLATFORM_MCP251X_H__ */
--
1.5.6.5
^ permalink raw reply related
* [PATCH net-next-2.6] bnx2: avoid compiler warnings
From: Eric Dumazet @ 2009-11-03 9:17 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List, Michael Chan
drivers/net/bnx2.c: In function ‘bnx2_enable_forced_2g5’:
drivers/net/bnx2.c:1447: warning: ‘bmcr’ may be used uninitialized in this function
drivers/net/bnx2.c: In function ‘bnx2_disable_forced_2g5’:
drivers/net/bnx2.c:1482: warning: ‘bmcr’ may be used uninitialized in this function
One fix would be to have an initial value, but a plain return might be better.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 08cddb6..539d23b 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -1466,6 +1466,8 @@ bnx2_enable_forced_2g5(struct bnx2 *bp)
} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
bmcr |= BCM5708S_BMCR_FORCE_2500;
+ } else {
+ return;
}
if (bp->autoneg & AUTONEG_SPEED) {
@@ -1500,6 +1502,8 @@ bnx2_disable_forced_2g5(struct bnx2 *bp)
} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
bmcr &= ~BCM5708S_BMCR_FORCE_2500;
+ } else {
+ return;
}
if (bp->autoneg & AUTONEG_SPEED)
^ permalink raw reply related
* Re: [PATCH] net: Support specifying the network namespace upon device creation.
From: Eric Dumazet @ 2009-11-03 9:28 UTC (permalink / raw)
To: Eric W. Biederman; +Cc: David Miller, netdev
In-Reply-To: <m1eioggeux.fsf@fess.ebiederm.org>
Eric W. Biederman a écrit :
> There is no good reason to not support userspace specifying the
> network namespace during device creation, and it makes it easier
> to create a network device and pass it to a child network namespace
> with a well known name.
>
> We have to be careful to ensure that the target network namespace
> for the new device exists through the life of the call. To keep
> that logic clear I have factored out the network namespace grabbing
> logic into rtnl_link_get_net.
>
> In addtion we need to continue to pass the source network namespace
> to the rtnl_link_ops.newlink method so that we can find the base
> device source network namespace.
>
> Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
Very nice, with only one long line you could wrap differently.
> -static int ipgre_newlink(struct net_device *dev, struct nlattr *tb[],
> +static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[],
> struct nlattr *data[])
> {
> struct ip_tunnel *nt;
^ permalink raw reply
* Re: HTB accuracy on 10GbE
From: Jarek Poplawski @ 2009-11-03 9:33 UTC (permalink / raw)
To: Badalian Vyacheslav
Cc: Stephen Hemminger, Patrick McHardy, Ryousei Takano,
Linux Netdev List, takano-ryousei, Eric Dumazet, David Miller
In-Reply-To: <4AEFDF22.8000405@bigtelecom.ru>
On 03-11-2009 08:43, Badalian Vyacheslav wrote:
> Hello dear netdev team!
Hello dear BIG Telecom!
>
> Linux all time go with the times :)
> Network in world go to use 10G technologies. I can test any stress patches in produce system for linux developers :)
> I discharge from out company in 1 December and have 1 month for all tests.
> I believe that linux net dev team do it easy. Need only begin :) Lets do it together :)
>
> Jarek, you many times help to us fix small problems in HTB, thanks for this!
> All work great!
Really?! As a matter of fact there isn't fully used the last change,
especially this part:
http://marc.info/?l=linux-netdev&m=124453482324409&w=2
And nobody even noticed it for quite a long time. I'm not even sure
Ryousei needs this now for anything but comparing with some better
tool...
Best regards,
Jarek P.
PS: Slavon, (as usual ;-) wrap the lines and don't top post, please.
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Changli Gao @ 2009-11-03 9:47 UTC (permalink / raw)
To: Jarek Poplawski; +Cc: Jamal Hadi Salim, devik, netdev
In-Reply-To: <20091103080022.GA6718@ff.dom.local>
On Tue, Nov 3, 2009 at 4:00 PM, Jarek Poplawski <jarkao2@gmail.com> wrote:
>
>> It means that a class, which sends packets
>> in ceil rate, can also enter HTB_CAN_SEND state now and then.
>
> Yes, a class is entitled to send on it's own then with it's guaranteed
> rate, without depending on borrowing.
I don't think so. The class should _NOT_ enter HTB_CAN_SEND mode when
its data rate is higher than its rate specification. In other word, a
class should enter HTB_CAN_SEND mode only when its data rate isn't
higher than its rate specification. Otherwise, it will get additional
tokens and reach a higher data rate than its ceil specification. This
may affect other classes.
--
Regards,
Changli Gao(xiaosuo@gmail.com)
^ permalink raw reply
* Re: [PATCH] usbnet: Do not implement ethtool get_link() if link state is unknown
From: David Brownell @ 2009-11-03 9:41 UTC (permalink / raw)
To: David Miller; +Cc: ben, greg, jacmet, steve.glendinning, netdev
In-Reply-To: <20091103.010129.100672838.davem@davemloft.net>
On Tuesday 03 November 2009, David Miller wrote:
> > Having two tables for this is needlessly ugly.
>
> Yes, it's really cruddy how the USB network driver tries to share
> so much state amongst such very different devices :-)
That framework just grew ... started out as one driver,
nearly ten years back (yow!!), then generalized. Folk
seemed to appreciate not reinventing some stuff. ;)
If it had started out with this many devices, it might have
looked more like a library. Sharing code implies sharing
at least some state representations; the balance could might
be worth shifting by now.
> All kidding aside, I think the alternative is for the USB network
> driver to call ethtool_op_get_link() if it cannot determine the
> link state in hardware.
There's usbnet_get_link() which does just that. But
there may be some ancient debris confusing things.
^ permalink raw reply
* Re: [PATCH] net: Support specifying the network namespace upon device creation.
From: Eric W. Biederman @ 2009-11-03 9:50 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <4AEFF7BB.4090301@gmail.com>
Eric Dumazet <eric.dumazet@gmail.com> writes:
>
> Very nice, with only one long line you could wrap differently.
Say again? Was that very nice with respect to the rest of the patch?
Or sarcasm because I overlooked this wrap at 80 columns
opportunity in ipgre?
Eric
>
>> -static int ipgre_newlink(struct net_device *dev, struct nlattr *tb[],
>> +static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[],
>> struct nlattr *data[])
>> {
>> struct ip_tunnel *nt;
>
> --
> 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] net: Support specifying the network namespace upon device creation.
From: Eric Dumazet @ 2009-11-03 9:56 UTC (permalink / raw)
To: Eric W. Biederman; +Cc: David Miller, netdev
In-Reply-To: <m1ws28ey3k.fsf@fess.ebiederm.org>
Eric W. Biederman a écrit :
> Eric Dumazet <eric.dumazet@gmail.com> writes:
>> Very nice, with only one long line you could wrap differently.
>
> Say again? Was that very nice with respect to the rest of the patch?
> Or sarcasm because I overlooked this wrap at 80 columns
> opportunity in ipgre?
>
> Eric
>>
>>> -static int ipgre_newlink(struct net_device *dev, struct nlattr *tb[],
>>> +static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[],
>>> struct nlattr *data[])
>>> {
>>> struct ip_tunnel *nt;
Hmm, I am very sorry you take it as a sarcasm, I would not treat you or anyone like that.
I was basically Acking your patch, with only one minor note about one line becoming a bit long.
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
It would be better to write :
static int ipgre_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
^ permalink raw reply
* Re: [PATCH] usbnet: Do not implement ethtool get_link() if link state is unknown
From: David Miller @ 2009-11-03 10:04 UTC (permalink / raw)
To: david-b; +Cc: ben, greg, jacmet, steve.glendinning, netdev
In-Reply-To: <200911030141.27905.david-b@pacbell.net>
From: David Brownell <david-b@pacbell.net>
Date: Tue, 3 Nov 2009 02:41:27 -0700
> On Tuesday 03 November 2009, David Miller wrote:
>> All kidding aside, I think the alternative is for the USB network
>> driver to call ethtool_op_get_link() if it cannot determine the
>> link state in hardware.
>
> There's usbnet_get_link() which does just that. But
> there may be some ancient debris confusing things.
It's perfect, and Ben's patch is completely unnecessary.
^ permalink raw reply
* Re: [PATCH] net: Support specifying the network namespace upon device creation.
From: David Miller @ 2009-11-03 10:05 UTC (permalink / raw)
To: ebiederm; +Cc: eric.dumazet, netdev
In-Reply-To: <m1ws28ey3k.fsf@fess.ebiederm.org>
From: ebiederm@xmission.com (Eric W. Biederman)
Date: Tue, 03 Nov 2009 01:50:23 -0800
> Eric Dumazet <eric.dumazet@gmail.com> writes:
>>
>> Very nice, with only one long line you could wrap differently.
>
> Say again? Was that very nice with respect to the rest of the patch?
> Or sarcasm because I overlooked this wrap at 80 columns
> opportunity in ipgre?
It can also be argued that for functions, wrapping the args is
worse because it makes grep output less useful. In fact that's,
I believe, Linus's most recent recommendation in this area :)
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Jarek Poplawski @ 2009-11-03 10:05 UTC (permalink / raw)
To: Changli Gao; +Cc: Jamal Hadi Salim, devik, netdev
In-Reply-To: <412e6f7f0911030147k659e0079ibd1f424fef0a487f@mail.gmail.com>
On Tue, Nov 03, 2009 at 05:47:17PM +0800, Changli Gao wrote:
> On Tue, Nov 3, 2009 at 4:00 PM, Jarek Poplawski <jarkao2@gmail.com> wrote:
> >
> >> It means that a class, which sends packets
> >> in ceil rate, can also enter HTB_CAN_SEND state now and then.
> >
> > Yes, a class is entitled to send on it's own then with it's guaranteed
> > rate, without depending on borrowing.
>
> I don't think so. The class should _NOT_ enter HTB_CAN_SEND mode when
> its data rate is higher than its rate specification. In other word, a
> class should enter HTB_CAN_SEND mode only when its data rate isn't
> higher than its rate specification. Otherwise, it will get additional
> tokens and reach a higher data rate than its ceil specification. This
> may affect other classes.
The ceil specification is controlled only by ctokens, which are always
updated, so no such risk.
Regards,
Jarek P.
^ permalink raw reply
* Re: [PATCH] e1000: the power down when running ifdown command
From: Naohiro Ooiwa @ 2009-11-03 10:06 UTC (permalink / raw)
To: Jeff Kirsher
Cc: jesse.brandeburg, peter.p.waskiewicz.jr, john.ronciak, davem,
Andrew Morton, netdev, svaidy, e1000-devel
In-Reply-To: <9929d2390911021626j4a2e4a96neaba49ffd8775dc9@mail.gmail.com>
Jeff Kirsher wrote:
> 2009/10/31 Naohiro Ooiwa <nooiwa@miraclelinux.com>:
>
> I have added this patch to my tree for testing. This patch requires a
> fair amount of regression testing, so once its passed testing I will
> push the patch to David/netdev.
I appreciate the marge your tree.
If there is anything I can do, please let me know.
And I know this patch is good for e100 driver too.
I would really like to create patch for it.
How do you think about e100 driver.
Thanks,
Naohiro Ooiwa
^ permalink raw reply
* Re: [PATCH] net: Support specifying the network namespace upon device creation.
From: Eric W. Biederman @ 2009-11-03 10:06 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <4AEFFE32.4050808@gmail.com>
Eric Dumazet <eric.dumazet@gmail.com> writes:
> Eric W. Biederman a écrit :
>> Eric Dumazet <eric.dumazet@gmail.com> writes:
>>> Very nice, with only one long line you could wrap differently.
>>
>> Say again? Was that very nice with respect to the rest of the patch?
>> Or sarcasm because I overlooked this wrap at 80 columns
>> opportunity in ipgre?
>>
>> Eric
>>>
>>>> -static int ipgre_newlink(struct net_device *dev, struct nlattr *tb[],
>>>> +static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[],
>>>> struct nlattr *data[])
>>>> {
>>>> struct ip_tunnel *nt;
>
> Hmm, I am very sorry you take it as a sarcasm, I would not treat you or anyone like that.
I wasn't certain so I asked. You were sufficiently terse I wasn't certain
what you meant.
> I was basically Acking your patch, with only one minor note about one line becoming a bit long.
>
> Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
>
> It would be better to write :
>
> static int ipgre_newlink(struct net *src_net, struct net_device *dev,
> struct nlattr *tb[], struct nlattr *data[])
Agreed.
Eric
^ permalink raw reply
* Re: HTB accuracy on 10GbE
From: Badalian Vyacheslav @ 2009-11-03 10:13 UTC (permalink / raw)
Cc: Patrick McHardy, Linux Netdev List
In-Reply-To: <20091103093333.GB6718@ff.dom.local>
> Really?! As a matter of fact there isn't fully used the last change,
> especially this part:
>
> http://marc.info/?l=linux-netdev&m=124453482324409&w=2
>
> And nobody even noticed it for quite a long time. I'm not even sure
> Ryousei needs this now for anything but comparing with some better
> tool...
>
> Best regards,
> Jarek P.
>
> PS: Slavon, (as usual ;-) wrap the lines and don't top post, please.
>
>
These changes have not been tested and applied to kernel?
As I now remember, I promised to test this patch and judging by
correspondence so it and have not made. My error - I am ready to
correct it. Probably there were difficulties, and is then banal
has forgotten.
It is possible to receive once again full патчсет for the test?
Best regals, Slavon
^ permalink raw reply
* Re: [PATCH] net: Support specifying the network namespace upon device creation.
From: Eric Dumazet @ 2009-11-03 10:16 UTC (permalink / raw)
To: David Miller; +Cc: ebiederm, netdev
In-Reply-To: <20091103.020555.156050455.davem@davemloft.net>
David Miller a écrit :
> It can also be argued that for functions, wrapping the args is
> worse because it makes grep output less useful. In fact that's,
> I believe, Linus's most recent recommendation in this area :)
Yes, true.
One thing I usually miss is the { next to "struct some_name" declarations,
to ease games based on "grep"
Would you accept one boring cleanup patch in include/net like following ?
diff --git a/include/net/route.h b/include/net/route.h
index 40f6346..1524b75 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -49,8 +49,7 @@
struct fib_nh;
struct inet_peer;
-struct rtable
-{
+struct rtable {
union
{
struct dst_entry dst;
@@ -77,16 +76,14 @@ struct rtable
struct inet_peer *peer; /* long-living peer info */
};
-struct ip_rt_acct
-{
+struct ip_rt_acct {
__u32 o_bytes;
__u32 o_packets;
__u32 i_bytes;
__u32 i_packets;
};
-struct rt_cache_stat
-{
+struct rt_cache_stat {
unsigned int in_hit;
unsigned int in_slow_tot;
unsigned int in_slow_mc;
^ permalink raw reply related
* Re: [PATCH] sysctl: reduce ram usage by 40 %
From: Eric W. Biederman @ 2009-11-03 10:23 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S. Miller, Greg KH, Benjamin LaHaise, Octavian Purdila,
netdev, Cosmin Ratiu, linux-kernel
In-Reply-To: <4AEFD544.6040602@gmail.com>
Eric Dumazet <eric.dumazet@gmail.com> writes:
> Eric Dumazet a écrit :
>
>> Its curious because in my tests the biggest problems come from
>> kernel/sysctl.c (__register_sysctl_paths) consuming 80% of cpu
>> in following attempt to create 20.000 devices
I bet that is Al's cute glue all the sysctl data structures together
patch. It improves readdir and lookup at a small cost at registration
time.
>> (disable hotplug before trying this, and ipv6 too !)
>> modprobe dummy numdummies=20000
>> I believe we should address __register_sysctl_paths() scalability
>> problems too.
Agreed.
>> I dont know what is the 'sentinel' we allocate after each struct ctl_table
>> But I suspect we could reduce size requirement of the 'sentinel' to include
>> only needed fields for the sentinel (and move them at start of ctl_table)
The sentinel is just a NULL terminator.
> Here is the patch to reduce ram usage of sysctl :
>
> [PATCH] sysctl: reduce ram usage by 40 %
>
> We currently reserve space for a so called sentinel, a full struct ctl_table
> for each ctl_table. We can cheat a bit since only needed fields of a sentinel
> are ctl_name and procname. Add a new structure (struct ctl_table_sentinel)
> that includes a full ctl_table and only required part of a sentinel.
Before we address sysctl I would like to get out my patchset that
makes sys_sysctl a wrapper around the ascii version of
/proc/sys/net. Once that goes in it becomes much easier to do things
and perform radical surgery on sysctl. Little things like .ctl_name and
.strategy go away.
Have you happened to look at the other cost of /proc proper? Hmm.
Except for /proc/net/dev_snmp6 it doesn't look like we keep per
interface directories in proc so without ivp6 you won't see the proc
generic code at all.
The practical consequence is if /proc/net/dev_snmp6 is not painful during
registration right now we can probably convert all of /proc/sys/net to proc
generic after my other changes are in.
Eric
^ permalink raw reply
* Re: [PATCH] net: Support specifying the network namespace upon device creation.
From: Eric W. Biederman @ 2009-11-03 10:32 UTC (permalink / raw)
To: David Miller; +Cc: eric.dumazet, netdev
In-Reply-To: <20091103.020555.156050455.davem@davemloft.net>
David Miller <davem@davemloft.net> writes:
> From: ebiederm@xmission.com (Eric W. Biederman)
> Date: Tue, 03 Nov 2009 01:50:23 -0800
>
>> Eric Dumazet <eric.dumazet@gmail.com> writes:
>>>
>>> Very nice, with only one long line you could wrap differently.
>>
>> Say again? Was that very nice with respect to the rest of the patch?
>> Or sarcasm because I overlooked this wrap at 80 columns
>> opportunity in ipgre?
>
> It can also be argued that for functions, wrapping the args is
> worse because it makes grep output less useful. In fact that's,
> I believe, Linus's most recent recommendation in this area :)
The arguments are already wrapped in this instance.
But since I don't have clear guidance to change the patch I
will leave it.
Eric
^ permalink raw reply
* Re: [PATCH 1/3] sysfs directory scaling: rbtree for dirent name lookups
From: Eric W. Biederman @ 2009-11-03 10:41 UTC (permalink / raw)
To: Benjamin LaHaise
Cc: Eric Dumazet, Greg Kroah-Hartman, Octavian Purdila, netdev,
Cosmin Ratiu, linux-kernel
In-Reply-To: <20091101163130.GA7911@kvack.org>
Benjamin LaHaise <bcrl@lhnet.ca> writes:
> Use an rbtree in sysfs_dirent to speed up file lookup times
>
> Systems with large numbers (tens of thousands and more) of network
> interfaces stress the sysfs code in ways that make the linear search for
> a name match take far too long. Avoid this by using an rbtree.
Please take a look at the cleanups_scaling branch at:
kernel.org:/pub/scm/linux/kernel/git/ebiederm/linux-2.6.32-rc5-sysfs-enhancements
I haven't spent a lot of time on it but it is possible to get everything
except the rbtree without increasing the size of sysfs_dirent. Also we
don't need the both the rbtree and a linked list.
In particular see:
commit 50623bbb82da3bd1d596b9173a91ed1b5aa168b8
Author: Eric W. Biederman <ebiederm@maxwell.aristanetworks.com>
Date: Sat Oct 31 04:11:18 2009 -0700
sysfs: Sort sysfs directories by name hash.
This is a step in preparation for introducing a more efficient
data structure than a linked list for sysfs entries. By ordering
by name hash instead of by inode sysfs_lookup can be speeded
up as well as allowing restarting after seekdir.
Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
Meanwhile back to pushing the most important ones for real.
Eric
^ permalink raw reply
* Re: [PATCH] net: Support specifying the network namespace upon device creation.
From: David Miller @ 2009-11-03 10:44 UTC (permalink / raw)
To: eric.dumazet; +Cc: ebiederm, netdev
In-Reply-To: <4AF0031B.4060708@gmail.com>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Tue, 03 Nov 2009 11:16:59 +0100
> David Miller a écrit :
>
>> It can also be argued that for functions, wrapping the args is
>> worse because it makes grep output less useful. In fact that's,
>> I believe, Linus's most recent recommendation in this area :)
>
> Yes, true.
>
> One thing I usually miss is the { next to "struct some_name" declarations,
> to ease games based on "grep"
>
> Would you accept one boring cleanup patch in include/net like following ?
Absolutely.
^ permalink raw reply
* Re: HTB accuracy on 10GbE
From: Jarek Poplawski @ 2009-11-03 10:54 UTC (permalink / raw)
To: Badalian Vyacheslav; +Cc: Patrick McHardy, Linux Netdev List
In-Reply-To: <4AF0023C.5010404@bigtelecom.ru>
On 03-11-2009 11:13, Badalian Vyacheslav wrote:
>> Really?! As a matter of fact there isn't fully used the last change,
>> especially this part:
>>
>> http://marc.info/?l=linux-netdev&m=124453482324409&w=2
>>
>> And nobody even noticed it for quite a long time. I'm not even sure
>> Ryousei needs this now for anything but comparing with some better
>> tool...
>
> These changes have not been tested and applied to kernel?
>
> As I now remember, I promised to test this patch and judging by
> correspondence so it and have not made. My error - I am ready to
> correct it. Probably there were difficulties, and is then banal
> has forgotten.
> It is possible to receive once again full ???°N~?N~?N~???N~? for the test?
There were a few iproute changes, tested enough I guess. Alas, I
didn't keep them (they could be found around with link above).
But it's not about your testing. I meant: since nobody noticed
something was (still) wrong with 1G scheduling, why bother with 10G?
Best regards,
Jarek P.
PS: ...and don't remove me from CC, please ;-)
^ permalink raw reply
* Re: [Bugme-new] [Bug 14427] New: ipv6 forward cause strange route
From: YOSHIFUJI Hideaki @ 2009-11-03 11:06 UTC (permalink / raw)
To: Andrew Morton, green
Cc: netdev, bugzilla-daemon, bugme-daemon, yoshfuji, Pekka Savola,
davem
In-Reply-To: <20091102223237.c0102f19.akpm@linux-foundation.org>
Hello.
This is not a bug but a feature of IPv6 called "subnet anycast
address." The address is automatically assigned on routers.
References:
RFC 2526: Reserved IPv6 Subnet Anycast Addresses
RFC 3627: Use of /127 Prefix Length Between Routers Considered Harmful
--yoshfuji
Andrew Morton wrote:
> (switched to email. Please respond via emailed reply-to-all, not via the
> bugzilla web interface).
>
> On Sat, 17 Oct 2009 10:42:01 GMT bugzilla-daemon@bugzilla.kernel.org wrote:
>
>> http://bugzilla.kernel.org/show_bug.cgi?id=14427
>>
>> Summary: ipv6 forward cause strange route
>> Product: Networking
>> Version: 2.5
>> Platform: All
>> OS/Version: Linux
>> Tree: Mainline
>> Status: NEW
>> Severity: normal
>> Priority: P1
>> Component: IPV6
>> AssignedTo: yoshfuji@linux-ipv6.org
>> ReportedBy: green@msu.ru
>> Regression: No
>>
>>
>> When enabling forwarding for IPv6 on interface, in the routing table local
>> appears new route. It like route to local ip but with all host bits set to 0.
>> Example:
>> --------------------------------------------------
>> # cat /proc/sys/net/ipv6/conf/eth0/forwarding
>> 0
>> # ip -6 addr add 2001:db8:1:1::5/64 dev eth0
>> # ip -6 route show table local
>> ...
>> local 2001:db8:1:1::5 via :: dev lo proto none metric 0 mtu 16436 advmss
>> 16376 hoplimit 4294967295
>> ...
>> # echo 1 > /proc/sys/net/ipv6/conf/eth0/forwarding
>> # ip -6 route show table local
>> ...
>> local 2001:db8:1:1:: via :: dev lo proto none metric 0 mtu 16436 advmss
>> 16376 hoplimit 4294967295
>> local 2001:db8:1:1::5 via :: dev lo proto none metric 0 mtu 16436 advmss
>> 16376 hoplimit 4294967295
>> ...
>> --------------------------------------------------
>> After enabling forwarding, route "2001:db8:1:1:: via :: dev lo" is added. No
>> matter, forwarding is enabled before or after adding of address, this route is
>> "on" with forwarding and "off" without it.
>> Such behavior causes problems with /127 network masks. For example:
>> --------------------------------------------------
>> # echo 1 > /proc/sys/net/ipv6/conf/eth0/forwarding
>> # ip -6 addr add 2001:db8:1:1::5/127 dev eth0
>> # ip -6 route add default via 2001:db8:1:1::4
>> RTNETLINK answers: Invalid argument
>> --------------------------------------------------
>> But if we disable forwarding (and strange route) when adding needed route, we
>> will succeed.
>> --------------------------------------------------
>> # echo 0 > /proc/sys/net/ipv6/conf/eth0/forwarding
>> # ip -6 route add default via 2001:db8:1:1::4
>> # echo 1 > /proc/sys/net/ipv6/conf/eth0/forwarding
>> --------------------------------------------------
>> Default route remains in the table after enabling forwarding and it is doing in
>> work. But in this case we still can not access 2001:db8:1:1::4, because it is
>> routed to loopback:
>> --------------------------------------------------
>> # ping6 -c 1 2001:db8:1:1::4
>> PING 2001:db8:1:1::4(2001:db8:1:1::4) 56 data bytes
>> 64 bytes from 2001:db8:1:1::5: icmp_seq=1 ttl=64 time=0.114 ms
>> --------------------------------------------------
>> We get reply from self interface.
>>
>> This was tested on x86 and x86_64 with 2.6.30 kernel and some previous versions
>> on ArchLinux (2.6.30 x86 and x86_64), Ubuntu (2.6.28-15-generic x86_64) and
>> gentoo (2.6.30-gentoo-r5 x86_64).
>>
>
> --
> 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: HTB accuracy on 10GbE
From: Badalian Vyacheslav @ 2009-11-03 11:13 UTC (permalink / raw)
To: Jarek Poplawski; +Cc: Patrick McHardy, Linux Netdev List
In-Reply-To: <20091103105413.GD6718@ff.dom.local>
Jarek Poplawski пишет:
> On 03-11-2009 11:13, Badalian Vyacheslav wrote:
>>> Really?! As a matter of fact there isn't fully used the last change,
>>> especially this part:
>>>
>>> http://marc.info/?l=linux-netdev&m=124453482324409&w=2
>>>
>>> And nobody even noticed it for quite a long time. I'm not even sure
>>> Ryousei needs this now for anything but comparing with some better
>>> tool...
>> These changes have not been tested and applied to kernel?
>>
>> As I now remember, I promised to test this patch and judging by
>> correspondence so it and have not made. My error - I am ready to
>> correct it. Probably there were difficulties, and is then banal
>> has forgotten.
>> It is possible to receive once again full ???°N~?N~?N~???N~? for the test?
>
> There were a few iproute changes, tested enough I guess. Alas, I
> didn't keep them (they could be found around with link above).
>
> But it's not about your testing. I meant: since nobody noticed
> something was (still) wrong with 1G scheduling, why bother with 10G?
>
Ok. In next week we get server and test it :)
> Best regards,
> Jarek P.
>
> PS: ...and don't remove me from CC, please ;-)
>
>
Sorry. My mail server have limit CC :)
^ permalink raw reply
* Re: [Bugme-new] [Bug 14427] New: ipv6 forward cause strange route
From: YOSHIFUJI Hideaki @ 2009-11-03 11:19 UTC (permalink / raw)
To: Andrew Morton, green
Cc: netdev, bugzilla-daemon, bugme-daemon, Pekka Savola, davem
In-Reply-To: <4AF00EA0.7030407@linux-ipv6.org>
I wrote:
> This is not a bug but a feature of IPv6 called "subnet anycast
> address." The address is automatically assigned on routers.
>
> References:
> RFC 2526: Reserved IPv6 Subnet Anycast Addresses
> RFC 3627: Use of /127 Prefix Length Between Routers Considered Harmful
I should say "Subnet-router anycast address" and
RFC3513: Internet Protocol Version 6 (IPv6) Addressing
Architecture".
Sorry for confusion.
--yoshfuji
^ permalink raw reply
* Re: [PATCHv6 3/3] vhost_net: a kernel-level virtio server
From: Michael S. Tsirkin @ 2009-11-03 11:57 UTC (permalink / raw)
To: Daniel Walker
Cc: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm,
hpa, gregory.haskins, Rusty Russell, s.hetze
In-Reply-To: <1257206758.11429.70.camel@c-dwalke-linux.qualcomm.com>
On Mon, Nov 02, 2009 at 04:05:58PM -0800, Daniel Walker wrote:
>
> Random style issues below .. Part of this is just stuff checkpatch
> found.
Thanks very much, I'll fix these.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCHv6 1/3] tun: export underlying socket
From: Arnd Bergmann @ 2009-11-03 12:12 UTC (permalink / raw)
To: virtualization
Cc: Michael S. Tsirkin, netdev, kvm, linux-kernel, mingo, linux-mm,
akpm, hpa, gregory.haskins, Rusty Russell, s.hetze
In-Reply-To: <20091102222612.GB15184@redhat.com>
On Monday 02 November 2009, Michael S. Tsirkin wrote:
> Tun device looks similar to a packet socket
> in that both pass complete frames from/to userspace.
>
> This patch fills in enough fields in the socket underlying tun driver
> to support sendmsg/recvmsg operations, and message flags
> MSG_TRUNC and MSG_DONTWAIT, and exports access to this socket
> to modules. Regular read/write behaviour is unchanged.
>
> This way, code using raw sockets to inject packets
> into a physical device, can support injecting
> packets into host network stack almost without modification.
>
> First user of this interface will be vhost virtualization
> accelerator.
You mentioned before that you wanted to export the socket
using some ioctl function returning an open file descriptor,
which seemed to be a cleaner approach than this one.
What was your reason for changing?
> index 3f5fd52..404abe0 100644
> --- a/include/linux/if_tun.h
> +++ b/include/linux/if_tun.h
> @@ -86,4 +86,18 @@ struct tun_filter {
> __u8 addr[0][ETH_ALEN];
> };
>
> +#ifdef __KERNEL__
> +#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE)
> +struct socket *tun_get_socket(struct file *);
> +#else
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +struct file;
> +struct socket;
> +static inline struct socket *tun_get_socket(struct file *f)
> +{
> + return ERR_PTR(-EINVAL);
> +}
> +#endif /* CONFIG_TUN */
> +#endif /* __KERNEL__ */
> #endif /* __IF_TUN_H */
Is this a leftover from testing? Exporting the function for !__KERNEL__
seems pointless.
Arnd <><
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ 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