* [PATCH v2] can: xilinx CAN controller support.
From: Kedareswara rao Appana @ 2014-02-12 7:10 UTC (permalink / raw)
To: wg, mkl, michal.simek, grant.likely, robh+dt, linux-can
Cc: netdev, linux-arm-kernel, linux-kernel, devicetree,
Kedareswara rao Appana
In-Reply-To: <\>
This patch adds xilinx CAN controller support.
This driver supports both ZYNQ CANPS IP and
Soft IP AXI CAN controller.
Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com>
---
This patch is rebased on the 3.14 rc2 kernel.
Changes for v2:
- Updated with the review comments.
- Removed unnecessary debug prints.
- included tx,rx fifo depths in ZYNQ CANPS case also.
---
.../devicetree/bindings/net/can/xilinx_can.txt | 45 +
drivers/net/can/Kconfig | 7 +
drivers/net/can/Makefile | 1 +
drivers/net/can/xilinx_can.c | 1153 ++++++++++++++++++++
4 files changed, 1206 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/can/xilinx_can.txt
create mode 100644 drivers/net/can/xilinx_can.c
diff --git a/Documentation/devicetree/bindings/net/can/xilinx_can.txt b/Documentation/devicetree/bindings/net/can/xilinx_can.txt
new file mode 100644
index 0000000..0e57103
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/xilinx_can.txt
@@ -0,0 +1,45 @@
+Xilinx Axi CAN/Zynq CANPS controller Device Tree Bindings
+---------------------------------------------------------
+
+Required properties:
+- compatible : Should be "xlnx,zynq-can-1.00.a" for Zynq CAN
+ controllers and "xlnx,axi-can-1.00.a" for Axi CAN
+ controllers.
+- reg : Physical base address and size of the Axi CAN/Zynq
+ CANPS registers map.
+- interrupts : Property with a value describing the interrupt
+ number.
+- interrupt-parent : Must be core interrupt controller
+- clock-names : List of input clock names - "ref_clk", "aper_clk"
+ (See clock bindings for details. Two clocks are
+ required for Zynq CAN. For Axi CAN
+ case it is one(ref_clk)).
+- clocks : Clock phandles (see clock bindings for details).
+- tx-fifo-depth : Can Tx fifo depth.
+- rx-fifo-depth : Can Rx fifo depth.
+
+
+Example:
+
+For Zynq CANPS Dts file:
+ zynq_can_0: zynq-can@e0008000 {
+ compatible = "xlnx,zynq-can-1.00.a";
+ clocks = <&clkc 19>, <&clkc 36>;
+ clock-names = "ref_clk", "aper_clk";
+ reg = <0xe0008000 0x1000>;
+ interrupts = <0 28 4>;
+ interrupt-parent = <&intc>;
+ tx-fifo-depth = <0x40>;
+ rx-fifo-depth = <0x40>;
+ };
+For Axi CAN Dts file:
+ axi_can_0: axi-can@40000000 {
+ compatible = "xlnx,axi-can-1.00.a";
+ clocks = <&clkc 0>;
+ clock-names = "ref_clk" ;
+ reg = <0x40000000 0x10000>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 59 1>;
+ tx-fifo-depth = <0x40>;
+ rx-fifo-depth = <0x40>;
+ };
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 9e7d95d..b180239 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -125,6 +125,13 @@ config CAN_GRCAN
endian syntheses of the cores would need some modifications on
the hardware level to work.
+config CAN_XILINXCAN
+ tristate "Xilinx CAN"
+ depends on ARCH_ZYNQ || MICROBLAZE
+ ---help---
+ Xilinx CAN driver. This driver supports both soft AXI CAN IP and
+ Zynq CANPS IP.
+
source "drivers/net/can/mscan/Kconfig"
source "drivers/net/can/sja1000/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index c744039..0b8e11e 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -25,5 +25,6 @@ obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
obj-$(CONFIG_PCH_CAN) += pch_can.o
obj-$(CONFIG_CAN_GRCAN) += grcan.o
+obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c
new file mode 100644
index 0000000..642e6b4
--- /dev/null
+++ b/drivers/net/can/xilinx_can.c
@@ -0,0 +1,1153 @@
+/* Xilinx CAN device driver
+ *
+ * Copyright (C) 2012 - 2014 Xilinx, Inc.
+ * Copyright (C) 2009 PetaLogix. All rights reserved.
+ *
+ * Description:
+ * This driver is developed for Axi CAN IP and for Zynq CANPS Controller.
+ * 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, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/can/led.h>
+
+#define DRIVER_NAME "XILINX_CAN"
+
+/* CAN registers set */
+#define XCAN_SRR_OFFSET 0x00 /* Software reset */
+#define XCAN_MSR_OFFSET 0x04 /* Mode select */
+#define XCAN_BRPR_OFFSET 0x08 /* Baud rate prescaler */
+#define XCAN_BTR_OFFSET 0x0C /* Bit timing */
+#define XCAN_ECR_OFFSET 0x10 /* Error counter */
+#define XCAN_ESR_OFFSET 0x14 /* Error status */
+#define XCAN_SR_OFFSET 0x18 /* Status */
+#define XCAN_ISR_OFFSET 0x1C /* Interrupt status */
+#define XCAN_IER_OFFSET 0x20 /* Interrupt enable */
+#define XCAN_ICR_OFFSET 0x24 /* Interrupt clear */
+#define XCAN_TXFIFO_ID_OFFSET 0x30 /* TX FIFO ID */
+#define XCAN_TXFIFO_DLC_OFFSET 0x34 /* TX FIFO DLC */
+#define XCAN_TXFIFO_DW1_OFFSET 0x38 /* TX FIFO Data Word 1 */
+#define XCAN_TXFIFO_DW2_OFFSET 0x3C /* TX FIFO Data Word 2 */
+#define XCAN_RXFIFO_ID_OFFSET 0x50 /* RX FIFO ID */
+#define XCAN_RXFIFO_DLC_OFFSET 0x54 /* RX FIFO DLC */
+#define XCAN_RXFIFO_DW1_OFFSET 0x58 /* RX FIFO Data Word 1 */
+#define XCAN_RXFIFO_DW2_OFFSET 0x5C /* RX FIFO Data Word 2 */
+
+/* CAN register bit masks - XCAN_<REG>_<BIT>_MASK */
+#define XCAN_SRR_CEN_MASK 0x00000002 /* CAN enable */
+#define XCAN_SRR_RESET_MASK 0x00000001 /* Soft Reset the CAN core */
+#define XCAN_MSR_LBACK_MASK 0x00000002 /* Loop back mode select */
+#define XCAN_MSR_SLEEP_MASK 0x00000001 /* Sleep mode select */
+#define XCAN_BRPR_BRP_MASK 0x000000FF /* Baud rate prescaler */
+#define XCAN_BTR_SJW_MASK 0x00000180 /* Synchronous jump width */
+#define XCAN_BTR_TS2_MASK 0x00000070 /* Time segment 2 */
+#define XCAN_BTR_TS1_MASK 0x0000000F /* Time segment 1 */
+#define XCAN_ECR_REC_MASK 0x0000FF00 /* Receive error counter */
+#define XCAN_ECR_TEC_MASK 0x000000FF /* Transmit error counter */
+#define XCAN_ESR_ACKER_MASK 0x00000010 /* ACK error */
+#define XCAN_ESR_BERR_MASK 0x00000008 /* Bit error */
+#define XCAN_ESR_STER_MASK 0x00000004 /* Stuff error */
+#define XCAN_ESR_FMER_MASK 0x00000002 /* Form error */
+#define XCAN_ESR_CRCER_MASK 0x00000001 /* CRC error */
+#define XCAN_SR_TXFLL_MASK 0x00000400 /* TX FIFO is full */
+#define XCAN_SR_ESTAT_MASK 0x00000180 /* Error status */
+#define XCAN_SR_ERRWRN_MASK 0x00000040 /* Error warning */
+#define XCAN_SR_NORMAL_MASK 0x00000008 /* Normal mode */
+#define XCAN_SR_LBACK_MASK 0x00000002 /* Loop back mode */
+#define XCAN_SR_CONFIG_MASK 0x00000001 /* Configuration mode */
+#define XCAN_IXR_TXFEMP_MASK 0x00004000 /* TX FIFO Empty */
+#define XCAN_IXR_WKUP_MASK 0x00000800 /* Wake up interrupt */
+#define XCAN_IXR_SLP_MASK 0x00000400 /* Sleep interrupt */
+#define XCAN_IXR_BSOFF_MASK 0x00000200 /* Bus off interrupt */
+#define XCAN_IXR_ERROR_MASK 0x00000100 /* Error interrupt */
+#define XCAN_IXR_RXNEMP_MASK 0x00000080 /* RX FIFO NotEmpty intr */
+#define XCAN_IXR_RXOFLW_MASK 0x00000040 /* RX FIFO Overflow intr */
+#define XCAN_IXR_RXOK_MASK 0x00000010 /* Message received intr */
+#define XCAN_IXR_TXOK_MASK 0x00000002 /* TX successful intr */
+#define XCAN_IXR_ARBLST_MASK 0x00000001 /* Arbitration lost intr */
+#define XCAN_IDR_ID1_MASK 0xFFE00000 /* Standard msg identifier */
+#define XCAN_IDR_SRR_MASK 0x00100000 /* Substitute remote TXreq */
+#define XCAN_IDR_IDE_MASK 0x00080000 /* Identifier extension */
+#define XCAN_IDR_ID2_MASK 0x0007FFFE /* Extended message ident */
+#define XCAN_IDR_RTR_MASK 0x00000001 /* Remote TX request */
+#define XCAN_DLCR_DLC_MASK 0xF0000000 /* Data length code */
+
+#define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\
+ XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \
+ XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \
+ XCAN_IXR_ARBLST_MASK | XCAN_IXR_RXOK_MASK)
+
+/* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */
+#define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */
+#define XCAN_BTR_TS2_SHIFT 4 /* Time segment 2 */
+#define XCAN_IDR_ID1_SHIFT 21 /* Standard Messg Identifier */
+#define XCAN_IDR_ID2_SHIFT 1 /* Extended Message Identifier */
+#define XCAN_DLCR_DLC_SHIFT 28 /* Data length code */
+#define XCAN_ESR_REC_SHIFT 8 /* Rx Error Count */
+
+/* CAN frame length constants */
+#define XCAN_ECHO_SKB_MAX 64
+#define XCAN_FRAME_MAX_DATA_LEN 8
+#define XCAN_TIMEOUT (50 * HZ)
+
+/**
+ * struct xcan_priv - This definition define CAN driver instance
+ * @can: CAN private data structure.
+ * @open_time: For holding timeout values
+ * @waiting_ech_skb_index: Pointer for skb
+ * @ech_skb_next: This tell the next packet in the queue
+ * @waiting_ech_skb_num: Gives the number of packets waiting
+ * @xcan_echo_skb_max_tx: Maximum number packets the driver can send
+ * @xcan_echo_skb_max_rx: Maximum number packets the driver can receive
+ * @napi: NAPI structure
+ * @ech_skb_lock: For spinlock purpose
+ * @read_reg: For reading data from CAN registers
+ * @write_reg: For writing data to CAN registers
+ * @dev: Network device data structure
+ * @reg_base: Ioremapped address to registers
+ * @irq_flags: For request_irq()
+ * @aperclk: Pointer to struct clk
+ * @devclk: Pointer to struct clk
+ */
+struct xcan_priv {
+ struct can_priv can;
+ int open_time;
+ int waiting_ech_skb_index;
+ int ech_skb_next;
+ int waiting_ech_skb_num;
+ int xcan_echo_skb_max_tx;
+ int xcan_echo_skb_max_rx;
+ struct napi_struct napi;
+ spinlock_t ech_skb_lock;
+ u32 (*read_reg)(const struct xcan_priv *priv, int reg);
+ void (*write_reg)(const struct xcan_priv *priv, int reg, u32 val);
+ struct net_device *dev;
+ void __iomem *reg_base;
+ unsigned long irq_flags;
+ struct clk *aperclk;
+ struct clk *devclk;
+};
+
+/* CAN Bittiming constants as per Xilinx CAN specs */
+static const struct can_bittiming_const xcan_bittiming_const = {
+ .name = DRIVER_NAME,
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+};
+
+/**
+ * xcan_write_reg - Write a value to the device register
+ * @priv: Driver private data structure
+ * @reg: Register offset
+ * @val: Value to write at the Register offset
+ *
+ * Write data to the paricular CAN register
+ */
+static void xcan_write_reg(const struct xcan_priv *priv, int reg, u32 val)
+{
+ writel(val, priv->reg_base + reg);
+}
+
+/**
+ * xcan_read_reg - Read a value from the device register
+ * @priv: Driver private data structure
+ * @reg: Register offset
+ *
+ * Read data from the particular CAN register
+ * Return: value read from the CAN register
+ */
+static u32 xcan_read_reg(const struct xcan_priv *priv, int reg)
+{
+ return readl(priv->reg_base + reg);
+}
+
+/**
+ * set_reset_mode - Resets the CAN device mode
+ * @ndev: Pointer to net_device structure
+ *
+ * This is the driver reset mode routine.The driver
+ * enters into configuration mode.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int set_reset_mode(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ unsigned long timeout;
+
+ priv->can.state = CAN_STATE_STOPPED;
+
+ timeout = jiffies + XCAN_TIMEOUT;
+ while (!(priv->read_reg(priv, XCAN_SR_OFFSET) & XCAN_SR_CONFIG_MASK)) {
+ if (time_after(jiffies, timeout)) {
+ netdev_warn(ndev, "timedout waiting for config mode\n");
+ return -ETIMEDOUT;
+ }
+ usleep_range(500, 10000);
+ }
+
+ return 0;
+}
+
+/**
+ * xcan_set_bittiming - CAN set bit timing routine
+ * @ndev: Pointer to net_device structure
+ *
+ * This is the driver set bittiming routine.
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_set_bittiming(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ struct can_bittiming *bt = &priv->can.bittiming;
+ u32 btr0, btr1;
+ u32 is_config_mode;
+
+ /* Check whether Xilinx CAN is in configuration mode.
+ * It cannot set bit timing if Xilinx CAN is not in configuration mode.
+ */
+ is_config_mode = priv->read_reg(priv, XCAN_SR_OFFSET) &
+ XCAN_SR_CONFIG_MASK;
+ if (!is_config_mode) {
+ netdev_alert(ndev,
+ "Cannot set bittiming can is not in config mode\n");
+ return -EPERM;
+ }
+
+ /* Setting Baud Rate prescalar value in BRPR Register */
+ btr0 = (bt->brp - 1) & XCAN_BRPR_BRP_MASK;
+
+ /* Setting Time Segment 1 in BTR Register */
+ btr1 = (bt->prop_seg + bt->phase_seg1 - 1) & XCAN_BTR_TS1_MASK;
+
+ /* Setting Time Segment 2 in BTR Register */
+ btr1 |= ((bt->phase_seg2 - 1) << XCAN_BTR_TS2_SHIFT) &
+ XCAN_BTR_TS2_MASK;
+
+ /* Setting Synchronous jump width in BTR Register */
+ btr1 |= ((bt->sjw - 1) << XCAN_BTR_SJW_SHIFT) & XCAN_BTR_SJW_MASK;
+
+ priv->write_reg(priv, XCAN_BRPR_OFFSET, btr0);
+ priv->write_reg(priv, XCAN_BTR_OFFSET, btr1);
+
+ netdev_dbg(ndev, "BRPR=0x%08x, BTR=0x%08x\n",
+ priv->read_reg(priv, XCAN_BRPR_OFFSET),
+ priv->read_reg(priv, XCAN_BTR_OFFSET));
+
+ return 0;
+}
+
+/**
+ * xcan_start - This the drivers start routine
+ * @ndev: Pointer to net_device structure
+ *
+ * This is the drivers start routine.
+ * Based on the State of the CAN device it puts
+ * the CAN device into a proper mode.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_start(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ u32 err;
+ unsigned long timeout;
+
+ /* Check if it is in reset mode */
+ if (priv->can.state != CAN_STATE_STOPPED)
+ err = set_reset_mode(ndev);
+ if (err < 0)
+ return err;
+
+ /* Enable interrupts */
+ priv->write_reg(priv, XCAN_IER_OFFSET, XCAN_INTR_ALL);
+
+ /* Check whether it is loopback mode or normal mode */
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
+ /* Put device into loopback mode */
+ priv->write_reg(priv, XCAN_MSR_OFFSET, XCAN_MSR_LBACK_MASK);
+ else
+ /* The device is in normal mode */
+ priv->write_reg(priv, XCAN_MSR_OFFSET, 0);
+
+ if (priv->can.state == CAN_STATE_STOPPED) {
+ /* Enable Xilinx CAN */
+ priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK);
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ timeout = jiffies + XCAN_TIMEOUT;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+ while ((priv->read_reg(priv, XCAN_SR_OFFSET)
+ & XCAN_SR_LBACK_MASK) == 0) {
+ if (time_after(jiffies, timeout)) {
+ netdev_warn(ndev,
+ "timedout for loopback mode\n");
+ return -ETIMEDOUT;
+ }
+ usleep_range(500, 10000);
+ }
+ } else {
+ while ((priv->read_reg(priv, XCAN_SR_OFFSET)
+ & XCAN_SR_NORMAL_MASK) == 0) {
+ if (time_after(jiffies, timeout)) {
+ netdev_warn(ndev,
+ "timedout for normal mode\n");
+ return -ETIMEDOUT;
+ }
+ usleep_range(500, 10000);
+ }
+ }
+ netdev_dbg(ndev, "status:#x%08x\n",
+ priv->read_reg(priv, XCAN_SR_OFFSET));
+ }
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ return 0;
+}
+
+/**
+ * xcan_do_set_mode - This sets the mode of the driver
+ * @ndev: Pointer to net_device structure
+ * @mode: Tells the mode of the driver
+ *
+ * This check the drivers state and calls the
+ * the corresponding modes to set.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_do_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+ int ret;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ ret = xcan_start(ndev);
+ if (ret < 0)
+ netdev_err(ndev, "xcan_start failed!\n");
+ netif_wake_queue(ndev);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * xcan_start_xmit - Starts the transmission
+ * @skb: sk_buff pointer that contains data to be Txed
+ * @ndev: Pointer to net_device structure
+ *
+ * This function is invoked from upper layers to initiate transmission. This
+ * function uses the next available free txbuff and populates their fields to
+ * start the transmission.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ u32 id, dlc, data[2] = {0, 0}, rtr = 0;
+ unsigned long flags;
+
+ if (can_dropped_invalid_skb(ndev, skb))
+ return NETDEV_TX_OK;
+
+ /* Watch carefully on the bit sequence */
+ if (cf->can_id & CAN_EFF_FLAG) {
+ /* Extended CAN ID format */
+ id = ((cf->can_id & CAN_EFF_MASK) << XCAN_IDR_ID2_SHIFT) &
+ XCAN_IDR_ID2_MASK;
+ id |= (((cf->can_id & CAN_EFF_MASK) >>
+ (CAN_EFF_ID_BITS-CAN_SFF_ID_BITS)) <<
+ XCAN_IDR_ID1_SHIFT) & XCAN_IDR_ID1_MASK;
+
+ /* The substibute remote TX request bit should be "1"
+ * for extended frames as in the Xilinx CAN datasheet
+ */
+ id |= XCAN_IDR_IDE_MASK | XCAN_IDR_SRR_MASK;
+
+ if (cf->can_id & CAN_RTR_FLAG) {
+ /* Extended frames remote TX request */
+ id |= XCAN_IDR_RTR_MASK;
+ rtr = 1;
+ }
+ } else {
+ /* Standard CAN ID format */
+ id = ((cf->can_id & CAN_SFF_MASK) << XCAN_IDR_ID1_SHIFT) &
+ XCAN_IDR_ID1_MASK;
+
+ if (cf->can_id & CAN_RTR_FLAG) {
+ /* Extended frames remote TX request */
+ id |= XCAN_IDR_SRR_MASK;
+ rtr = 1;
+ }
+ }
+
+ dlc = (cf->can_dlc & 0xf) << XCAN_DLCR_DLC_SHIFT;
+
+ if (dlc > 0)
+ data[0] = be32_to_cpup((__be32 *)(cf->data + 0));
+ if (dlc > 4)
+ data[1] = be32_to_cpup((__be32 *)(cf->data + 4));
+
+ can_put_echo_skb(skb, ndev, priv->ech_skb_next);
+
+ /* Write the Frame to Xilinx CAN TX FIFO */
+ priv->write_reg(priv, XCAN_TXFIFO_ID_OFFSET, id);
+ priv->write_reg(priv, XCAN_TXFIFO_DLC_OFFSET, dlc);
+ if (!rtr) {
+ priv->write_reg(priv, XCAN_TXFIFO_DW1_OFFSET, data[0]);
+ priv->write_reg(priv, XCAN_TXFIFO_DW2_OFFSET, data[1]);
+ stats->tx_bytes += cf->can_dlc;
+ }
+
+ priv->ech_skb_next = (priv->ech_skb_next + 1) %
+ priv->xcan_echo_skb_max_tx;
+
+ spin_lock_irqsave(&priv->ech_skb_lock, flags);
+ priv->waiting_ech_skb_num++;
+ spin_unlock_irqrestore(&priv->ech_skb_lock, flags);
+
+ /* Check if the TX buffer is full */
+ if (priv->read_reg(priv, XCAN_SR_OFFSET) & XCAN_SR_TXFLL_MASK) {
+ netif_stop_queue(ndev);
+ netdev_err(ndev, "TX register is still full!\n");
+ return NETDEV_TX_BUSY;
+ } else if (priv->waiting_ech_skb_num == priv->xcan_echo_skb_max_tx) {
+ netif_stop_queue(ndev);
+ netdev_err(ndev, "waiting:0x%08x, max:0x%08x\n",
+ priv->waiting_ech_skb_num, priv->xcan_echo_skb_max_tx);
+ return NETDEV_TX_BUSY;
+ }
+
+ return NETDEV_TX_OK;
+}
+
+/**
+ * xcan_rx - Is called from CAN isr to complete the received
+ * frame processing
+ * @ndev: Pointer to net_device structure
+ *
+ * This function is invoked from the CAN isr(poll) to process the Rx frames. It
+ * does minimal processing and invokes "netif_receive_skb" to complete further
+ * processing.
+ * Return: 0 on success and negative error value on error
+ */
+static int xcan_rx(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ u32 id_xcan, dlc, data[2] = {0, 0}, rtr = 0;
+
+ skb = alloc_can_skb(ndev, &cf);
+ if (!skb)
+ return -ENOMEM;
+
+ /* Read a frame from Xilinx zynq CANPS */
+ id_xcan = priv->read_reg(priv, XCAN_RXFIFO_ID_OFFSET);
+ dlc = priv->read_reg(priv, XCAN_RXFIFO_DLC_OFFSET) & XCAN_DLCR_DLC_MASK;
+
+ /* Change Xilinx CAN data length format to socketCAN data format */
+ cf->can_dlc = get_can_dlc((dlc & XCAN_DLCR_DLC_MASK) >>
+ XCAN_DLCR_DLC_SHIFT);
+
+ /* Change Xilinx CAN ID format to socketCAN ID format */
+ if (id_xcan & XCAN_IDR_IDE_MASK) {
+ /* The received frame is an Extended format frame */
+ cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 3;
+ cf->can_id |= (id_xcan & XCAN_IDR_ID2_MASK) >>
+ XCAN_IDR_ID2_SHIFT;
+ cf->can_id |= CAN_EFF_FLAG;
+ if (id_xcan & XCAN_IDR_RTR_MASK) {
+ cf->can_id |= CAN_RTR_FLAG;
+ rtr = 1;
+ }
+ } else {
+ /* The received frame is a standard format frame */
+ cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >>
+ XCAN_IDR_ID1_SHIFT;
+ if (id_xcan & XCAN_IDR_RTR_MASK) {
+ cf->can_id |= CAN_RTR_FLAG;
+ rtr = 1;
+ }
+ }
+
+ if (!rtr) {
+ data[0] = priv->read_reg(priv, XCAN_RXFIFO_DW1_OFFSET);
+ data[1] = priv->read_reg(priv, XCAN_RXFIFO_DW2_OFFSET);
+
+ /* Change Xilinx CAN data format to socketCAN data format */
+ *(__be32 *)(cf->data) = cpu_to_be32(data[0]);
+ if (cf->can_dlc > 4)
+ *(__be32 *)(cf->data + 4) = cpu_to_be32(data[1]);
+ }
+ can_led_event(ndev, CAN_LED_EVENT_RX);
+
+ netif_receive_skb(skb);
+
+ stats->rx_bytes += cf->can_dlc;
+ stats->rx_packets++;
+ return 0;
+}
+
+/**
+ * xcan_err_interrupt - error frame Isr
+ * @ndev: net_device pointer
+ * @isr: interrupt status register value
+ *
+ * This is the CAN error interrupt and it will
+ * check the the type of error and forward the error
+ * frame to upper layers.
+ */
+static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ u32 err_status, status;
+
+ skb = alloc_can_err_skb(ndev, &cf);
+ if (!skb) {
+ netdev_err(ndev, "alloc_can_err_skb() failed!\n");
+ return;
+ }
+
+ err_status = priv->read_reg(priv, XCAN_ESR_OFFSET);
+ priv->write_reg(priv, XCAN_ESR_OFFSET, err_status);
+ status = priv->read_reg(priv, XCAN_SR_OFFSET);
+
+ if (isr & XCAN_IXR_BSOFF_MASK) {
+ priv->can.state = CAN_STATE_BUS_OFF;
+ cf->can_id |= CAN_ERR_BUSOFF;
+ priv->can.can_stats.bus_off++;
+ /* Leave device in Config Mode in bus-off state */
+ priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK);
+ can_bus_off(ndev);
+ } else if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK) {
+ cf->can_id |= CAN_ERR_CRTL;
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ priv->can.can_stats.error_passive++;
+ cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE |
+ CAN_ERR_CRTL_TX_PASSIVE;
+ } else if (status & XCAN_SR_ERRWRN_MASK) {
+ cf->can_id |= CAN_ERR_CRTL;
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ priv->can.can_stats.error_warning++;
+ cf->data[1] |= CAN_ERR_CRTL_RX_WARNING |
+ CAN_ERR_CRTL_TX_WARNING;
+ }
+
+ /* Check for Arbitration lost interrupt */
+ if (isr & XCAN_IXR_ARBLST_MASK) {
+ cf->can_id |= CAN_ERR_LOSTARB;
+ cf->data[0] = CAN_ERR_LOSTARB_UNSPEC;
+ priv->can.can_stats.arbitration_lost++;
+ }
+
+ /* Check for RX FIFO Overflow interrupt */
+ if (isr & XCAN_IXR_RXOFLW_MASK) {
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
+ stats->rx_over_errors++;
+ stats->rx_errors++;
+ priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK);
+ }
+
+ /* Check for error interrupt */
+ if (isr & XCAN_IXR_ERROR_MASK) {
+ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+ cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+
+ /* Check for Ack error interrupt */
+ if (err_status & XCAN_ESR_ACKER_MASK) {
+ cf->can_id |= CAN_ERR_ACK;
+ cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+ stats->tx_errors++;
+ }
+
+ /* Check for Bit error interrupt */
+ if (err_status & XCAN_ESR_BERR_MASK) {
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_BIT;
+ stats->tx_errors++;
+ }
+
+ /* Check for Stuff error interrupt */
+ if (err_status & XCAN_ESR_STER_MASK) {
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_STUFF;
+ stats->rx_errors++;
+ }
+
+ /* Check for Form error interrupt */
+ if (err_status & XCAN_ESR_FMER_MASK) {
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_FORM;
+ stats->rx_errors++;
+ }
+
+ /* Check for CRC error interrupt */
+ if (err_status & XCAN_ESR_CRCER_MASK) {
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ |
+ CAN_ERR_PROT_LOC_CRC_DEL;
+ stats->rx_errors++;
+ }
+ priv->can.can_stats.bus_error++;
+ }
+
+ netif_rx(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ netdev_dbg(ndev, "%s: error status register:0x%x\n",
+ __func__, priv->read_reg(priv, XCAN_ESR_OFFSET));
+}
+
+/**
+ * xcan_state_interrupt - It will check the state of the CAN device
+ * @ndev: net_device pointer
+ * @isr: interrupt status register value
+ *
+ * This will checks the state of the CAN device
+ * and puts the device into appropriate state.
+ */
+static void xcan_state_interrupt(struct net_device *ndev, u32 isr)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+
+ /* Check for Sleep interrupt if set put CAN device in sleep state */
+ if (isr & XCAN_IXR_SLP_MASK)
+ priv->can.state = CAN_STATE_SLEEPING;
+
+ /* Check for Wake up interrupt if set put CAN device in Active state */
+ if (isr & XCAN_IXR_WKUP_MASK)
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+}
+
+/**
+ * xcan_rx_poll - Poll routine for rx packets (NAPI)
+ * @napi: napi structure pointer
+ * @quota: Max number of rx packets to be processed.
+ *
+ * This is the poll routine for rx part.
+ * It will process the packets maximux quota value.
+ *
+ * Return: number of packets received
+ */
+static int xcan_rx_poll(struct napi_struct *napi, int quota)
+{
+ struct net_device *ndev = napi->dev;
+ struct xcan_priv *priv = netdev_priv(ndev);
+ u32 isr, ier;
+ int work_done = 0;
+
+ isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
+ while ((isr & XCAN_IXR_RXNEMP_MASK) && (work_done < quota)) {
+ if (isr & XCAN_IXR_RXOK_MASK) {
+ priv->write_reg(priv, XCAN_ICR_OFFSET,
+ XCAN_IXR_RXOK_MASK);
+ if (xcan_rx(ndev) < 0)
+ return work_done;
+ work_done++;
+ } else {
+ priv->write_reg(priv, XCAN_ICR_OFFSET,
+ XCAN_IXR_RXNEMP_MASK);
+ break;
+ }
+ priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXNEMP_MASK);
+ isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
+ }
+
+ if (work_done < quota) {
+ napi_complete(napi);
+ ier = priv->read_reg(priv, XCAN_IER_OFFSET);
+ ier |= (XCAN_IXR_RXOK_MASK | XCAN_IXR_RXNEMP_MASK);
+ priv->write_reg(priv, XCAN_IER_OFFSET, ier);
+ }
+ return work_done;
+}
+
+/**
+ * xcan_tx_interrupt - Tx Done Isr
+ * @ndev: net_device pointer
+ */
+static void xcan_tx_interrupt(struct net_device *ndev)
+{
+ unsigned long flags;
+ struct xcan_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ u32 processed = 0, txpackets;
+
+ stats->tx_packets++;
+ netdev_dbg(ndev, "%s: waiting total:%d,current:%d\n", __func__,
+ priv->waiting_ech_skb_num, priv->waiting_ech_skb_index);
+
+ txpackets = priv->waiting_ech_skb_num;
+
+ if (txpackets) {
+ can_get_echo_skb(ndev, priv->waiting_ech_skb_index);
+ priv->waiting_ech_skb_index =
+ (priv->waiting_ech_skb_index + 1) %
+ priv->xcan_echo_skb_max_tx;
+ processed++;
+ txpackets--;
+ }
+
+ spin_lock_irqsave(&priv->ech_skb_lock, flags);
+ priv->waiting_ech_skb_num -= processed;
+ spin_unlock_irqrestore(&priv->ech_skb_lock, flags);
+
+ netdev_dbg(ndev, "%s: waiting total:%d,current:%d\n", __func__,
+ priv->waiting_ech_skb_num, priv->waiting_ech_skb_index);
+
+ netif_wake_queue(ndev);
+
+ can_led_event(ndev, CAN_LED_EVENT_TX);
+}
+
+/**
+ * xcan_interrupt - CAN Isr
+ * @irq: irq number
+ * @dev_id: device id poniter
+ *
+ * This is the xilinx CAN Isr. It checks for the type of interrupt
+ * and invokes the corresponding ISR.
+ *
+ * Return:
+ * IRQ_NONE - If CAN device is in sleep mode, IRQ_HANDLED otherwise
+ */
+static irqreturn_t xcan_interrupt(int irq, void *dev_id)
+{
+ struct net_device *ndev = (struct net_device *)dev_id;
+ struct xcan_priv *priv = netdev_priv(ndev);
+ u32 isr, ier;
+
+ /* Get the interrupt status from Xilinx CAN */
+ isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
+ if (!isr)
+ return IRQ_NONE;
+
+ netdev_dbg(ndev, "%s: isr:#x%08x, err:#x%08x\n", __func__,
+ isr, priv->read_reg(priv, XCAN_ESR_OFFSET));
+
+ /* Check for the type of interrupt and Processing it */
+ if (isr & (XCAN_IXR_SLP_MASK | XCAN_IXR_WKUP_MASK)) {
+ priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_SLP_MASK |
+ XCAN_IXR_WKUP_MASK));
+ xcan_state_interrupt(ndev, isr);
+ }
+
+ /* Check for Tx interrupt and Processing it */
+ if (isr & XCAN_IXR_TXOK_MASK) {
+ priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK);
+ xcan_tx_interrupt(ndev);
+ }
+
+ /* Check for the type of error interrupt and Processing it */
+ if (isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK |
+ XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK)) {
+ priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_ERROR_MASK |
+ XCAN_IXR_RXOFLW_MASK | XCAN_IXR_BSOFF_MASK |
+ XCAN_IXR_ARBLST_MASK));
+ xcan_err_interrupt(ndev, isr);
+ }
+
+ /* Check for the type of receive interrupt and Processing it */
+ if (isr & (XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK)) {
+ ier = priv->read_reg(priv, XCAN_IER_OFFSET);
+ ier &= ~(XCAN_IXR_RXNEMP_MASK | XCAN_IXR_RXOK_MASK);
+ priv->write_reg(priv, XCAN_IER_OFFSET, ier);
+ napi_schedule(&priv->napi);
+ }
+ return IRQ_HANDLED;
+}
+
+/**
+ * xcan_stop - Driver stop routine
+ * @ndev: Pointer to net_device structure
+ *
+ * This is the drivers stop routine. It will disable the
+ * interrupts and put the device into configuration mode.
+ */
+static void xcan_stop(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ u32 ier;
+
+ /* Disable interrupts and leave the can in configuration mode */
+ ier = priv->read_reg(priv, XCAN_IER_OFFSET);
+ ier &= ~XCAN_INTR_ALL;
+ priv->write_reg(priv, XCAN_IER_OFFSET, ier);
+ priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK);
+ priv->can.state = CAN_STATE_STOPPED;
+}
+
+/**
+ * xcan_open - Driver open routine
+ * @ndev: Pointer to net_device structure
+ *
+ * This is the driver open routine.
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_open(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = request_irq(ndev->irq, xcan_interrupt, priv->irq_flags,
+ ndev->name, (void *)ndev);
+ if (ret < 0) {
+ netdev_err(ndev, "Irq allocation for CAN failed\n");
+ return ret;
+ }
+
+ /* Set chip into reset mode */
+ ret = set_reset_mode(ndev);
+ if (ret < 0)
+ netdev_err(ndev, "mode resetting failed failed!\n");
+
+ /* Common open */
+ ret = open_candev(ndev);
+ if (ret)
+ return ret;
+
+ ret = xcan_start(ndev);
+ if (ret < 0)
+ netdev_err(ndev, "xcan_start failed!\n");
+
+
+ can_led_event(ndev, CAN_LED_EVENT_OPEN);
+ napi_enable(&priv->napi);
+ netif_start_queue(ndev);
+
+ return 0;
+}
+
+/**
+ * xcan_close - Driver close routine
+ * @ndev: Pointer to net_device structure
+ *
+ * Return: 0 always
+ */
+static int xcan_close(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+ napi_disable(&priv->napi);
+ xcan_stop(ndev);
+ free_irq(ndev->irq, ndev);
+ close_candev(ndev);
+
+ can_led_event(ndev, CAN_LED_EVENT_STOP);
+
+ return 0;
+}
+
+/**
+ * xcan_get_berr_counter - error counter routine
+ * @ndev: Pointer to net_device structure
+ * @bec: Pointer to can_berr_counter structure
+ *
+ * This is the driver error counter routine.
+ * Return: 0 always
+ */
+static int xcan_get_berr_counter(const struct net_device *ndev,
+ struct can_berr_counter *bec)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+
+ bec->txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK;
+ bec->rxerr = ((priv->read_reg(priv, XCAN_ECR_OFFSET) &
+ XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT);
+ return 0;
+}
+
+static const struct net_device_ops xcan_netdev_ops = {
+ .ndo_open = xcan_open,
+ .ndo_stop = xcan_close,
+ .ndo_start_xmit = xcan_start_xmit,
+};
+
+#ifdef CONFIG_PM_SLEEP
+/**
+ * xcan_suspend - Suspend method for the driver
+ * @_dev: Address of the platform_device structure
+ *
+ * Put the driver into low power mode.
+ * Return: 0 always
+ */
+static int xcan_suspend(struct device *_dev)
+{
+ struct platform_device *pdev = container_of(_dev,
+ struct platform_device, dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct xcan_priv *priv = netdev_priv(ndev);
+
+ if (netif_running(ndev)) {
+ netif_stop_queue(ndev);
+ netif_device_detach(ndev);
+ }
+
+ priv->write_reg(priv, XCAN_MSR_OFFSET, XCAN_MSR_SLEEP_MASK);
+ priv->can.state = CAN_STATE_SLEEPING;
+
+ clk_disable(priv->aperclk);
+ clk_disable(priv->devclk);
+
+ return 0;
+}
+
+/**
+ * xcan_resume - Resume from suspend
+ * @dev: Address of the platformdevice structure
+ *
+ * Resume operation after suspend.
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_resume(struct device *dev)
+{
+ struct platform_device *pdev = container_of(dev,
+ struct platform_device, dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct xcan_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = clk_enable(priv->aperclk);
+ if (ret) {
+ dev_err(dev, "Cannot enable clock.\n");
+ return ret;
+ }
+ ret = clk_enable(priv->devclk);
+ if (ret) {
+ dev_err(dev, "Cannot enable clock.\n");
+ return ret;
+ }
+
+ priv->write_reg(priv, XCAN_MSR_OFFSET, 0);
+ priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK);
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ if (netif_running(ndev)) {
+ netif_device_attach(ndev);
+ netif_start_queue(ndev);
+ }
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(xcan_dev_pm_ops, xcan_suspend, xcan_resume);
+
+/**
+ * xcan_probe - Platform registration call
+ * @pdev: Handle to the platform device structure
+ *
+ * This function does all the memory allocation and registration for the CAN
+ * device.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int xcan_probe(struct platform_device *pdev)
+{
+ struct resource *res; /* IO mem resources */
+ struct net_device *ndev;
+ struct xcan_priv *priv;
+ int ret, fifodep;
+
+ /* Create a CAN device instance */
+ ndev = alloc_candev(sizeof(struct xcan_priv), XCAN_ECHO_SKB_MAX);
+ if (!ndev)
+ return -ENOMEM;
+
+ priv = netdev_priv(ndev);
+ priv->dev = ndev;
+ priv->can.bittiming_const = &xcan_bittiming_const;
+ priv->can.do_set_bittiming = xcan_set_bittiming;
+ priv->can.do_set_mode = xcan_do_set_mode;
+ priv->can.do_get_berr_counter = xcan_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_BERR_REPORTING;
+
+ /* Get IRQ for the device */
+ ndev->irq = platform_get_irq(pdev, 0);
+
+ spin_lock_init(&priv->ech_skb_lock);
+ ndev->flags |= IFF_ECHO; /* We support local echo */
+
+ platform_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ ndev->netdev_ops = &xcan_netdev_ops;
+
+ /* Get the virtual base address for the device */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->reg_base)) {
+ ret = PTR_ERR(priv->reg_base);
+ goto err_free;
+ }
+ ndev->mem_start = res->start;
+ ndev->mem_end = res->end;
+
+ priv->write_reg = xcan_write_reg;
+ priv->read_reg = xcan_read_reg;
+
+ ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth",
+ &fifodep);
+ if (ret < 0)
+ goto err_free;
+ priv->xcan_echo_skb_max_tx = fifodep;
+
+ ret = of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth",
+ &fifodep);
+ if (ret < 0)
+ goto err_free;
+ priv->xcan_echo_skb_max_rx = fifodep;
+
+ /* Getting the CAN devclk info */
+ priv->devclk = devm_clk_get(&pdev->dev, "ref_clk");
+ if (IS_ERR(priv->devclk)) {
+ dev_err(&pdev->dev, "Device clock not found.\n");
+ ret = PTR_ERR(priv->devclk);
+ goto err_free;
+ }
+
+ /* Check for type of CAN device */
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "xlnx,zynq-can-1.00.a")) {
+ priv->aperclk = devm_clk_get(&pdev->dev, "aper_clk");
+ if (IS_ERR(priv->aperclk)) {
+ dev_err(&pdev->dev, "aper clock not found\n");
+ ret = PTR_ERR(priv->aperclk);
+ goto err_free;
+ }
+ } else {
+ priv->aperclk = priv->devclk;
+ }
+
+ ret = clk_prepare_enable(priv->devclk);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable device clock\n");
+ goto err_free;
+ }
+
+ ret = clk_prepare_enable(priv->aperclk);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable aper clock\n");
+ goto err_unprepar_disabledev;
+ }
+
+ priv->can.clock.freq = clk_get_rate(priv->devclk);
+
+ netif_napi_add(ndev, &priv->napi, xcan_rx_poll,
+ priv->xcan_echo_skb_max_rx);
+ ret = register_candev(ndev);
+ if (ret) {
+ dev_err(&pdev->dev, "fail to register failed (err=%d)\n", ret);
+ goto err_unprepar_disableaper;
+ }
+
+ devm_can_led_init(ndev);
+ dev_info(&pdev->dev,
+ "reg_base=0x%p irq=%d clock=%d, tx fifo depth:%d\n",
+ priv->reg_base, ndev->irq, priv->can.clock.freq,
+ priv->xcan_echo_skb_max_tx);
+
+ return 0;
+
+err_unprepar_disableaper:
+ clk_disable_unprepare(priv->aperclk);
+err_unprepar_disabledev:
+ clk_disable_unprepare(priv->devclk);
+err_free:
+ free_candev(ndev);
+
+ return ret;
+}
+
+/**
+ * xcan_remove - Unregister the device after releasing the resources
+ * @pdev: Handle to the platform device structure
+ *
+ * This function frees all the resources allocated to the device.
+ * Return: 0 always
+ */
+static int xcan_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct xcan_priv *priv = netdev_priv(ndev);
+
+ if (set_reset_mode(ndev) < 0)
+ netdev_err(ndev, "mode resetting failed!\n");
+
+ unregister_candev(ndev);
+ netif_napi_del(&priv->napi);
+ clk_disable_unprepare(priv->aperclk);
+ clk_disable_unprepare(priv->devclk);
+
+ free_candev(ndev);
+
+ return 0;
+}
+
+/* Match table for OF platform binding */
+static struct of_device_id xcan_of_match[] = {
+ { .compatible = "xlnx,zynq-can-1.00.a", },
+ { .compatible = "xlnx,axi-can-1.00.a", },
+ { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(of, xcan_of_match);
+
+static struct platform_driver xcan_driver = {
+ .probe = xcan_probe,
+ .remove = xcan_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .pm = &xcan_dev_pm_ops,
+ .of_match_table = xcan_of_match,
+ },
+};
+
+module_platform_driver(xcan_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Xilinx Inc");
+MODULE_DESCRIPTION("Xilinx CAN interface");
--
1.7.4
^ permalink raw reply related
* Re: [PATCH V2 5/6] vhost_net: poll vhost queue after marking DMA is done
From: Qin Chuanyu @ 2014-02-12 7:38 UTC (permalink / raw)
To: Jason Wang, virtualization, netdev, linux-kernel; +Cc: mst, kvm
In-Reply-To: <1377836962-49780-6-git-send-email-jasowang@redhat.com>
On 2013/8/30 12:29, Jason Wang wrote:
> We used to poll vhost queue before making DMA is done, this is racy if vhost
> thread were waked up before marking DMA is done which can result the signal to
> be missed. Fix this by always poll the vhost thread before DMA is done.
>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/vhost/net.c | 9 +++++----
> 1 files changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index ff60c2a..d09c17c 100644
> --- a/drivers/vhost/net.c
> +++ b/drivers/vhost/net.c
> @@ -308,6 +308,11 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success)
> struct vhost_virtqueue *vq = ubufs->vq;
> int cnt = atomic_read(&ubufs->kref.refcount);
>
> + /* set len to mark this desc buffers done DMA */
> + vq->heads[ubuf->desc].len = success ?
> + VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN;
> + vhost_net_ubuf_put(ubufs);
> +
> /*
> * Trigger polling thread if guest stopped submitting new buffers:
> * in this case, the refcount after decrement will eventually reach 1
> @@ -318,10 +323,6 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success)
> */
> if (cnt <= 2 || !(cnt % 16))
> vhost_poll_queue(&vq->poll);
> - /* set len to mark this desc buffers done DMA */
> - vq->heads[ubuf->desc].len = success ?
> - VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN;
> - vhost_net_ubuf_put(ubufs);
> }
>
> /* Expects to be always run from workqueue - which acts as
>
with this change, vq would lose protection that provided by ubufs->kref.
if another thread is waiting at vhost_net_ubuf_put_and_wait called by
vhost_net_release, then after vhost_net_ubuf_put, vq would been free
by vhost_net_release soon, vhost_poll_queue(&vq->poll) may cause NULL
pointer Exception.
another question is that vhost_zerocopy_callback is called by kfree_skb,
it may called in different thread context.
vhost_poll_queue is called decided by ubufs->kref.refcount, this may
cause there isn't any thread call vhost_poll_queue, but at least one is
needed. and this cause network break.
We could repeat it by using 8 netperf thread in guest to xmit tcp to its
host.
I think if using atomic_read to decide while do vhost_poll_queue or not,
at least a spink_lock is needed.
^ permalink raw reply
* Re: [PATCH] tun: use netif_receive_skb instead of netif_rx_ni
From: Jason Wang @ 2014-02-12 7:38 UTC (permalink / raw)
To: Eric Dumazet
Cc: Qin Chuanyu, davem, Michael S. Tsirkin, Anthony Liguori, KVM list,
netdev
In-Reply-To: <1392186384.1752.9.camel@edumazet-glaptop2.roam.corp.google.com>
On 02/12/2014 02:26 PM, Eric Dumazet wrote:
> On Wed, 2014-02-12 at 13:50 +0800, Jason Wang wrote:
>> On 02/12/2014 01:47 PM, Eric Dumazet wrote:
>>> On Wed, 2014-02-12 at 13:28 +0800, Jason Wang wrote:
>>>
>>>> A question: without NAPI weight, could this starve other net devices?
>>> Not really, as net devices are serviced by softirq handler.
>>>
>>>
>> Yes, then the issue is tun could be starved by other net devices.
> How this patch changes anything to this 'problem' ?
>
> netif_rx_ni() can only be called if your process is not preempted by
> other high prio tasks/softirqs.
>
> If this process is scheduled on a cpu, then disabling bh to process
> _one_ packet wont fundamentally change dynamic of the system.
>
After looking at the code for a while, I agree it won't be a great change.
Thanks
^ permalink raw reply
* Re: [PATCH] tun: use netif_receive_skb instead of netif_rx_ni
From: Jason Wang @ 2014-02-12 7:40 UTC (permalink / raw)
To: Qin Chuanyu, davem
Cc: Michael S. Tsirkin, Anthony Liguori, KVM list, netdev,
Eric Dumazet
In-Reply-To: <52FB18B8.4070401@huawei.com>
On 02/12/2014 02:46 PM, Qin Chuanyu wrote:
> On 2014/2/12 13:28, Jason Wang wrote:
>
>> A question: without NAPI weight, could this starve other net devices?
> tap xmit skb use thread context,the poll func of physical nic driver
> could be called in softirq context without change.
>
> I had test it by binding vhost thread and physic nic interrupt on the
> same vcpu, use netperf xmit udp, test model is VM1-Host1-Host2.
>
> if only VM1 xmit skb, the top show as below :
> Cpu1 :0.0%us, 95.0%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 5.0%si, 0.0%st
>
> then use host2 xmit skb to VM1, the top show as below :
> Cpu1 :0.0%us, 41.0%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 59.0%si, 0.0%st
>
> so I think there is no problem with this change.
Yes, I realize it was ok after Eric's comment.
Thanks
^ permalink raw reply
* [PATCH net-next] net: remove useless if check from register_netdevice()
From: Denis Kirjanov @ 2014-02-12 7:45 UTC (permalink / raw)
To: davem, netdev; +Cc: Denis Kirjanov
remove useless if check from register_netdevice()
Signed-off-by: Denis Kirjanov <kda@linux-powerpc.org>
---
net/core/dev.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index 4ad1b78..4be9a37 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5876,8 +5876,7 @@ int register_netdevice(struct net_device *dev)
if (dev->netdev_ops->ndo_init) {
ret = dev->netdev_ops->ndo_init(dev);
if (ret) {
- if (ret > 0)
- ret = -EIO;
+ ret = -EIO;
goto out;
}
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH net-next] ipv4: ip_forward: perform skb->pkt_type check at the beginning
From: Denis Kirjanov @ 2014-02-12 8:10 UTC (permalink / raw)
To: davem, netdev; +Cc: Denis Kirjanov
Packets which have L2 address different from ours should be
already filtered before entering into ip_forward().
Perform that check at the beginning to avoid processing such packets.
Signed-off-by: Denis Kirjanov <kda@linux-powerpc.org>
---
net/ipv4/ip_forward.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index e9f1217..1a07056 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -59,6 +59,10 @@ int ip_forward(struct sk_buff *skb)
struct rtable *rt; /* Route we use */
struct ip_options *opt = &(IPCB(skb)->opt);
+ /* that should never happen */
+ if (skb->pkt_type != PACKET_HOST)
+ goto drop;
+
if (skb_warn_if_lro(skb))
goto drop;
@@ -68,9 +72,6 @@ int ip_forward(struct sk_buff *skb)
if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
return NET_RX_SUCCESS;
- if (skb->pkt_type != PACKET_HOST)
- goto drop;
-
skb_forward_csum(skb);
/*
--
1.8.3.2
^ permalink raw reply related
* Re: [PATCH net-next] net: remove useless if check from register_netdevice()
From: Ding Tianhong @ 2014-02-12 8:20 UTC (permalink / raw)
To: Denis Kirjanov, davem, netdev
In-Reply-To: <1392191152-24182-1-git-send-email-kda@linux-powerpc.org>
On 2014/2/12 15:45, Denis Kirjanov wrote:
> remove useless if check from register_netdevice()
>
> Signed-off-by: Denis Kirjanov <kda@linux-powerpc.org>
> ---
> net/core/dev.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 4ad1b78..4be9a37 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -5876,8 +5876,7 @@ int register_netdevice(struct net_device *dev)
> if (dev->netdev_ops->ndo_init) {
> ret = dev->netdev_ops->ndo_init(dev);
> if (ret) {
> - if (ret > 0)
> - ret = -EIO;
> + ret = -EIO;
pls use checkpatch.pl to check the code.
Ding
> goto out;
> }
> }
>
^ permalink raw reply
* Re: [PATCH net-next] net: remove useless if check from register_netdevice()
From: Ding Tianhong @ 2014-02-12 8:24 UTC (permalink / raw)
To: Denis Kirjanov, davem, netdev
In-Reply-To: <1392191152-24182-1-git-send-email-kda@linux-powerpc.org>
On 2014/2/12 15:45, Denis Kirjanov wrote:
> remove useless if check from register_netdevice()
>
> Signed-off-by: Denis Kirjanov <kda@linux-powerpc.org>
> ---
> net/core/dev.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 4ad1b78..4be9a37 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -5876,8 +5876,7 @@ int register_netdevice(struct net_device *dev)
> if (dev->netdev_ops->ndo_init) {
> ret = dev->netdev_ops->ndo_init(dev);
> if (ret) {
> - if (ret > 0)
> - ret = -EIO;
> + ret = -EIO;
and:
some ndo_init() will return -ENOMEM, not only -EIO
> goto out;
> }
> }
>
^ permalink raw reply
* [PATCH net-next] tipc: explicitly include core.h in addr.h
From: andreas.bofjall @ 2014-02-12 8:34 UTC (permalink / raw)
To: netdev; +Cc: tipc-discussion, maloy, Andreas Bofjäll
From: Andreas Bofjäll <andreas.bofjall@ericsson.com>
The inline functions in addr.h uses tipc_own_addr which is exported by
core.h, but addr.h never actually includes it. It works because it is
explicitly included where this is used, but it looks a bit strange.
Include core.h in addr.h explicitly to make the dependency clearer.
Signed-off-by: Andreas Bofjäll <andreas.bofjall@ericsson.com>
Reviewed-by: Jon Maloy <jon.maloy@ericsson.com>
---
net/tipc/addr.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/tipc/addr.h b/net/tipc/addr.h
index 60b00ab..a74acf9 100644
--- a/net/tipc/addr.h
+++ b/net/tipc/addr.h
@@ -37,6 +37,8 @@
#ifndef _TIPC_ADDR_H
#define _TIPC_ADDR_H
+#include "core.h"
+
#define TIPC_ZONE_MASK 0xff000000u
#define TIPC_CLUSTER_MASK 0xfffff000u
--
1.8.5.2
^ permalink raw reply related
* Re: [PATCH net-next] net: remove useless if check from register_netdevice()
From: Denis Kirjanov @ 2014-02-12 8:47 UTC (permalink / raw)
To: Ding Tianhong; +Cc: davem, netdev
In-Reply-To: <52FB2FBF.7050907@huawei.com>
On 2/12/14, Ding Tianhong <dingtianhong@huawei.com> wrote:
> On 2014/2/12 15:45, Denis Kirjanov wrote:
>> remove useless if check from register_netdevice()
>>
>> Signed-off-by: Denis Kirjanov <kda@linux-powerpc.org>
>> ---
>> net/core/dev.c | 3 +--
>> 1 file changed, 1 insertion(+), 2 deletions(-)
>>
>> diff --git a/net/core/dev.c b/net/core/dev.c
>> index 4ad1b78..4be9a37 100644
>> --- a/net/core/dev.c
>> +++ b/net/core/dev.c
>> @@ -5876,8 +5876,7 @@ int register_netdevice(struct net_device *dev)
>> if (dev->netdev_ops->ndo_init) {
>> ret = dev->netdev_ops->ndo_init(dev);
>> if (ret) {
>> - if (ret > 0)
>> - ret = -EIO;
>> + ret = -EIO;
>
> and:
> some ndo_init() will return -ENOMEM, not only -EIO
>
>
>> goto out;
>> }
>> }
>>
Yes, I was thinking about that. The return code may contain everything.
Probably it's better to propagate return value back to
register_netdevice. On the other hand the return value -ENOTSUPP for
register_netdevice return value looks odd...
>
^ permalink raw reply
* Re: [PATCH V3] net/dt: Add support for overriding phy configuration from device tree
From: Gerlando Falauto @ 2014-02-12 8:57 UTC (permalink / raw)
To: Florian Fainelli
Cc: Matthew Garrett, netdev, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, Kishon Vijay Abraham I
In-Reply-To: <CAGVrzca7CV1SM0PfV2o=02Zd8z-65002kq6e-fhG6gWdkCadGA@mail.gmail.com>
Hi Florian,
On 02/11/2014 06:43 PM, Florian Fainelli wrote:
> Hi Gerlando,
>
> 2014-02-11 1:09 GMT-08:00 Gerlando Falauto <gerlando.falauto@keymile.com>:
>> Hi Florian,
>>
>> first of all, thank you for your answer.
>>
>>
>> On 02/10/2014 06:09 PM, Florian Fainelli wrote:
>>>
>>> Hi Gerlando,
>>>
>>> Le lundi 10 février 2014, 17:14:59 Gerlando Falauto a écrit :
>>>>
>>>> Hi,
>>>>
>>>> I'm currently trying to fix an issue for which this patch provides a
>>>> partial solution, so apologies in advance for jumping into the
>>>> discussion for my own purposes...
>>>>
>>>> On 02/04/2014 09:39 PM, Florian Fainelli wrote:> 2014-01-17 Matthew
>>>>
>>>> Garrett <matthew.garrett@nebula.com>:
>>>> >> Some hardware may be broken in interesting and board-specific ways,
>>>> such
>>>> >> that various bits of functionality don't work. This patch provides a
>>>> >> mechanism for overriding mii registers during init based on the
>>>>
>>>> contents of
>>>>
>>>> >> the device tree data, allowing board-specific fixups without having
>>>> to
>>>> >> pollute generic code.
>>>> >
>>>> > It would be good to explain exactly how your hardware is broken
>>>> > exactly. I really do not think that such a fine-grained setting where
>>>> > you could disable, e.g: 100BaseT_Full, but allow 100BaseT_Half to
>>>> > remain usable makes that much sense. In general, Gigabit might be
>>>> > badly broken, but 100 and 10Mbits/sec should work fine. How about the
>>>> > MASTER-SLAVE bit, is overriding it really required?
>>>> >
>>>> > Is not a PHY fixup registered for a specific OUI the solution you are
>>>> > looking for? I am also concerned that this creates PHY
>>>> troubleshooting
>>>> > issues much harder to debug than before as we may have no idea about
>>>> > how much information has been put in Device Tree to override that.
>>>> >
>>>> > Finally, how about making this more general just like the BCM87xx PHY
>>>> > driver, which is supplied value/reg pairs directly? There are 16
>>>> > common MII registers, and 16 others for vendor specific registers,
>>>> > this is just covering for about 2% of the possible changes.
>>>>
>>>> Good point. That would easily help me with my current issue, which
>>>> requires autoneg to be disabled to begin with (by clearing BMCR_ANENABLE
>>>> from register 0).
>>>
>>>
>>> Is there a point in time (e.g: after some specific initial configuration
>>> has
>>> been made) where BMCR_ANENABLE can be used?
>>
>>
>> What do you mean? In my case, for some HW-related reason (due to the PHY
>> counterpart I guess) autoneg needs to be disabled.
>> This is currently done by the bootloader code (which clears the bit).
>> What I'm looking for is some way for the kernel to either reinforce this
>> setting, or just take that into account and skip autoneg.
>> On top of that, there's a HW errata about that particular PHY, which
>> requires certain operations to be performed on the PHY as a workaround *WHEN
>> AUTONEG IS DISABLED*. That I'd implement on a PHY-specif driver.
>
> Ok.
>
>>
>>
>>>> This would not however fix it entirely (I tried a quick hardwired
>>>> implementation), as the whole PHY machinery would not take that into
>>>> account and would re-enable autoneg anyway.
>>>> I also tried changing the patch so that phydev->support gets updated
>>>
>>>
>>> There are multiple things that you could try doing here:
>>>
>>> - override the PHY state machine in your read_status callback to make sure
>>> that you always set phydev->autoneg set to AUTONEG_ENABLE
>>
>>
>> [you mean AUTONEG_DISABLE, right?]
>
> Right, I fat fingered here.
>
>> Uhm, but I don't want to implement a driver for that PHY that always
>> disables autoneg. I only want to disable autoneg for that particular board.
>> I figure I might register a fixup for that board, but that kindof makes
>> everything more complicated and less clear. Plus, what should be the
>> criterion to determine whether we're running on that particular hardware?
>
> of_machine_is_compatible() plus reading the specific PHY OUI should
> provide you with with an unique machine + PHY tuple. If your machine
> name is too generic.
Uhm, actually, my machine name ("model") is specific, but the compatible
string is indeed generic so this would mean adding an extra string
there. Not that it's a big issue, but it just seems too complicated and
hard to follow. After all, we wanted device tree in the first place to
get rid of board-sepcific files. To me, filtering by machine name looks
like a big step backwards, especially if it's all about a "pretty
standard feature" like disabling autoneg.
>
>>
>>
>>> - clear the SUPPORTED_Autoneg bits from phydev->supported right after PHY
>>> registration and before the call to phy_start()
>>
>>
>> I actually tried clearing it by tweaking the patch on this thread, but the
>> end result is that it does not produce any effect (see further comments
>> below). Only thing that seems to play a role here is explictly setting
>> phydev->autoneg = AUTONEG_DISABLE.
>>
>>
>>> - set the PHY_HAS_MAGICANEG bit in your PHY driver flag
>>
>>
>> Again, this seems to play no role whatsoever here:
>>
>> } else if (0 == phydev->link_timeout--) {
>> needs_aneg = 1;
>> /* If we have the magic_aneg bit,
>> * we try again */
>> if (phydev->drv->flags & PHY_HAS_MAGICANEG)
>> break;
>> }
>> break;
>> case PHY_NOLINK:
>>
>> This code might have made sense when it was written in 2006 -- back then,
>> the break statement was skipping some fallback code. But now it seems to do
>> nothing.
>>
>>
>>>
>>>>
>>>> (instead of phydev->advertising):
>>>> >> + if (!of_property_read_u32(np, override->prop, &tmp))
>>>> {
>>>> >> + if (tmp) {
>>>> >> + *val |= override->value;
>>>> >> + phydev->advertising |=
>>>>
>>>> override->supported;
>>>>
>>>> >> + } else {
>>>> >> + phydev->advertising &=
>>>>
>>>> ~(override->supported);
>>>>
>>>> >> + }
>>>> >> +
>>>> >> + *mask |= override->value;
>>>>
>>>> What I find weird is that the only way phydev->autoneg could ever be set
>>>> to disabled is from here (phy.c):
>>>>
>>>> static void phy_sanitize_settings(struct phy_device *phydev)
>>>> {
>>>> u32 features = phydev->supported;
>>>> int idx;
>>>>
>>>> /* Sanitize settings based on PHY capabilities */
>>>> if ((features & SUPPORTED_Autoneg) == 0)
>>>> phydev->autoneg = AUTONEG_DISABLE;
>>>>
>>>> which is in turn only called when phydev->autoneg is set to
>>>> AUTONEG_DISABLE to begin with:
>>>>
>>>> int phy_start_aneg(struct phy_device *phydev)
>>>> {
>>>> int err;
>>>>
>>>> mutex_lock(&phydev->lock);
>>>>
>>>> if (AUTONEG_DISABLE == phydev->autoneg)
>>>> phy_sanitize_settings(phydev);
>>>>
>>>> So could someone please help me figure out what I'm missing here?
>>>
>>>
>>> At first glance it looks like the PHY driver should be reading the phydev-
>>>>
>>>> autoneg value when the PHY driver config_aneg() callback is called to be
>>>
>>> allowed to set the forced speed and settings.
>>>
>>> The way phy_sanitize_settings() is coded does not make it return a mask of
>>> features, but only the forced supported speed and duplex. Then when the
>>> link
>>> is forced but we are having some issues getting a link status, libphy
>>> tries
>>> lower speeds and this function is used again to provide the next
>>> speed/duplex
>>> pair to try.
>>>
>>
>> What I was trying to say is that phy_sanitize_settings() is only called when
>> phydev->autoneg == AUTONEG_DISABLE, and in turn it's the only generic
>> function setting phydev->autoneg = AUTONEG_DISABLE.
>> So perhaps the condition should read:
>>
>> - if (AUTONEG_DISABLE == phydev->autoneg)
>> + if ((features & SUPPORTED_Autoneg) == 0)
>> phy_sanitize_settings(phydev);
>>
>> Or else, some other parts of the generic code should take care of setting it
>> to AUTONEG_DISABLE, depending on whether the feature is supported or not.
>> What I found weird is explicitly setting a value (phydev->autoneg =
>> AUTONEG_DISABLE), from a static function which is only called when that
>> condition is already true.
>
> I do not think that this change is correct either, let me cook a patch
> for you to allow disabling autoneg from the start.
Oh, OK, that would be great, thank you!
FWIW, I've already spent quite some time trying to overcome this -- my
understanding is that you somehow need to set phydev->autoneg to
AUTONEG_DISABLE at a very early stage (and that could of course be done
as a consequence of SUPPORTED_Autoneg being unset), otherwise the whole
software phy state machine and speed-matching algorithms will get confused.
>>
>> BTW, I feel like disabling autoneg from the start has never been a use case
>> before, am I right?
>
> Not really no, and that is because most hardware does not need quirks
> to work correctly.
To be honest with you, I'm not long experienced on MII/PHY, but I've
already seen two completely unrelated cases where autoneg needs to be
disabled in order for the hardware to work correctly. Of course I'm only
talking about in-board connections (e.g. not PHYs connected to an RJ-45
jack), still...
In this particular hardware configuration, not only does autoneg need to
be disabled in the first place (otherwise link won't work at all), but
the phy HW is also buggy so that when autoneg is disabled, it may still
occasionally not work (like 0.1% of the times).
Thank you so much!
Gerlando
^ permalink raw reply
* [PATCH net-next] socket: replace some printk with pr_*
From: Yang Yingliang @ 2014-02-12 9:09 UTC (permalink / raw)
To: netdev; +Cc: davem
Prefer pr_*(...) to printk(KERN_* ...).
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
---
net/socket.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/net/socket.c b/net/socket.c
index 879933a..840cffb 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -593,7 +593,7 @@ void sock_release(struct socket *sock)
}
if (rcu_dereference_protected(sock->wq, 1)->fasync_list)
- printk(KERN_ERR "sock_release: fasync list not empty!\n");
+ pr_err("%s: fasync list not empty!\n", __func__);
if (test_bit(SOCK_EXTERNALLY_ALLOCATED, &sock->flags))
return;
@@ -1265,8 +1265,8 @@ int __sock_create(struct net *net, int family, int type, int protocol,
static int warned;
if (!warned) {
warned = 1;
- printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n",
- current->comm);
+ pr_info("%s uses obsolete (PF_INET,SOCK_PACKET)\n",
+ current->comm);
}
family = PF_PACKET;
}
@@ -2595,8 +2595,7 @@ int sock_register(const struct net_proto_family *ops)
int err;
if (ops->family >= NPROTO) {
- printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family,
- NPROTO);
+ pr_crit("protocol %d >= NPROTO(%d)\n", ops->family, NPROTO);
return -ENOBUFS;
}
@@ -2610,7 +2609,7 @@ int sock_register(const struct net_proto_family *ops)
}
spin_unlock(&net_family_lock);
- printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family);
+ pr_info("NET: Registered protocol family %d\n", ops->family);
return err;
}
EXPORT_SYMBOL(sock_register);
@@ -2638,7 +2637,7 @@ void sock_unregister(int family)
synchronize_rcu();
- printk(KERN_INFO "NET: Unregistered protocol family %d\n", family);
+ pr_info("NET: Unregistered protocol family %d\n", family);
}
EXPORT_SYMBOL(sock_unregister);
--
1.8.0
^ permalink raw reply related
* [PATCH -next] gre: return more precise errno value when adding tunnel fails
From: Florian Westphal @ 2014-02-12 9:28 UTC (permalink / raw)
To: netdev; +Cc: Florian Westphal
Currently this always returns ENOBUFS, because the return value of
__ip_tunnel_create is discarded.
A more common failure is a duplicate name (EEXIST). Propagate the real
error code so userspace can display a more meaningful error message.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
net/ipv4/ip_tunnel.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 90ff957..ef43356 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -393,7 +393,7 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net,
fbt = netdev_priv(itn->fb_tunnel_dev);
dev = __ip_tunnel_create(net, itn->fb_tunnel_dev->rtnl_link_ops, parms);
if (IS_ERR(dev))
- return NULL;
+ return (void *) dev;
dev->mtu = ip_tunnel_bind_dev(dev);
@@ -732,9 +732,13 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type);
- if (!t && (cmd == SIOCADDTUNNEL))
+ if (!t && (cmd == SIOCADDTUNNEL)) {
t = ip_tunnel_create(net, itn, p);
-
+ if (IS_ERR(t)) {
+ err = PTR_ERR(t);
+ break;
+ }
+ }
if (dev != itn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
if (t != NULL) {
if (t->dev != dev) {
@@ -761,8 +765,9 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
if (t) {
err = 0;
ip_tunnel_update(itn, t, dev, p, true);
- } else
- err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
+ } else {
+ err = -ENOENT;
+ }
break;
case SIOCDELTUNNEL:
--
1.8.1.5
^ permalink raw reply related
* Re: [PATCH net] net: Clear local_df only if crossing namespace.
From: Nicolas Dichtel @ 2014-02-12 9:32 UTC (permalink / raw)
To: Pravin Shelar, David Miller, netdev, Templin, Fred L,
Steffen Klassert
In-Reply-To: <CALnjE+r5zUs0GKUESoum2YumjbfU2XKhDjjcoWUv2D8yiGEYkA@mail.gmail.com>
Le 12/02/2014 05:26, Pravin Shelar a écrit :
> On Mon, Feb 10, 2014 at 6:11 PM, Hannes Frederic Sowa
> <hannes@stressinduktion.org> wrote:
>> On Mon, Feb 10, 2014 at 01:00:14PM -0800, Pravin Shelar wrote:
>>> On Fri, Feb 7, 2014 at 4:58 PM, Hannes Frederic Sowa
>>> <hannes@stressinduktion.org> wrote:
>>>> May I know because of wich vport, vxlan or gre, you did this change?
>>>>
>>> It affects both gre and vxlan.
>>
>> Ok, thanks.
>>
>>>> I am feeling a bit uncomfortable handling remote and local packets that
>>>> differently on lower tunnel output (local_df is mostly set on locally
>>>> originating packets).
>>>
>>> For ip traffic it make sense to turn on local_df only for local
>>> traffic, since for remote case we can send icmp (frag-needed) back to
>>> source. No such thing exist for OVS tunnels. ICMP packet are not
>>> returned to source for the tunnels. That is why to be on safe side,
>>> local_df is turned on for tunnels in OVS.
>>
>> I have a proposal:
>>
>> I don't like it that much because of the many arguments. But I currently
>> don't see another easy solution. Maybe we should make bool xnet an enum and
>> test with bitops?
>>
>> I left the clearing of local_df in skb_scrub_packet as we need it for the
>> dev_forward_skb case and it should be done that in any case.
>>
>> This diff is slightly compile tested. ;)
>>
>> I can test and make proper submit if you agree.
>>
>> What do you think?
>>
>
> I am not sure why the caller can not just set skb->local_df before
> calling iptunnel_xmit() rather than passing extra arg to this
> function?
> There are not that many caller of this function.
The benefit is that it ensures that future callers will think about this point
;-)
Steffen is reworking vti code and will use skb_scrub_packet(), I CC'ed him in
case he has some comment about this change.
Regards,
Nicolas
^ permalink raw reply
* The kmemleak detector reports about leaked "struct net"
From: Andrey Wagin @ 2014-02-12 9:42 UTC (permalink / raw)
To: netdev
A kernel is compiled from Linus' tree without additional changes.
[root@jenkins ~]# uname -a
Linux jenkins.criu.org 3.14.0-rc2 #162 SMP Tue Feb 11 01:09:33 MSK
2014 x86_64 x86_64 x86_64 GNU/Linux
Sometimes I have found reports from the kmemleak detector about leaked
"struct net".
Here is a script to reproduce these leaks:
[root@jenkins ~]# cat test_net_ns.sh
ip net add test &&
ip link add name veth0 type veth peer name veth1 &&
ip link set dev veth1 netns test &&
ip net exec test ip link set up dev veth1 &&
ip link set up dev veth0 &&
brctl addif br0 veth0 &&
ip net exec test dhclient -4 veth1 -pf test.dhcp.pid -lf test.dhcp.lease &&
ip net exec test ip a
ip net exec test dhclient -r -pf test.dhcp.pid -lf test.dhcp.lease &&
ip net delete test &&
true || echo FAIL
This script creates a network namespace and a veth pair. One veth
device is attached to a bridge, another one is moved in namespace. The
dhclient gets ip address for the veth device in the test network
namespace. The final action is destroying the test network namespace.
[root@jenkins ~]# echo clear > /sys/kernel/debug/kmemleak
[root@jenkins ~]# bash -x test_net_ns.sh
+ ip net add test
+ ip link add name veth0 type veth peer name veth1
+ ip link set dev veth1 netns test
+ ip net exec test ip link set up dev veth1
+ ip link set up dev veth0
+ brctl addif br0 veth0
+ ip net exec test dhclient -4 veth1 -pf test.dhcp.pid -lf test.dhcp.lease
+ ip net exec test ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
23: veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast
state UP group default qlen 1000
link/ether ae:f9:75:20:9c:92 brd ff:ff:ff:ff:ff:ff
inet 10.30.24.229/16 brd 10.30.255.255 scope global dynamic veth1
valid_lft 3558sec preferred_lft 3558sec
inet6 fe80::acf9:75ff:fe20:9c92/64 scope link
valid_lft forever preferred_lft forever
+ ip net exec test ip r
default via 10.30.0.1 dev veth1
10.30.0.0/16 dev veth1 proto kernel scope link src 10.30.24.229
+ ip net exec test dhclient -r -pf test.dhcp.pid -lf test.dhcp.lease
+ ip net delete test
+ true
[root@jenkins ~]# echo scan > /sys/kernel/debug/kmemleak
[root@jenkins ~]# cat /sys/kernel/debug/kmemleak
[root@jenkins ~]# echo scan > /sys/kernel/debug/kmemleak
[root@jenkins ~]# cat /sys/kernel/debug/kmemleak
unreferenced object 0xffff88009bfc3c80 (size 128):
comm "ip", pid 25985, jiffies 4346037464 (age 4507.484s)
hex dump (first 32 bytes):
0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 b0 53 eb 0e 01 88 ff ff .........S......
backtrace:
[<ffffffff8176858e>] kmemleak_alloc+0x5e/0xc0
[<ffffffff811f6d3f>] __kmalloc+0x1bf/0x2e0
[<ffffffff81636351>] net_alloc_generic+0x21/0x30
[<ffffffff81636855>] copy_net_ns+0x45/0x160
[<ffffffff810b4c91>] create_new_namespaces+0x101/0x1b0
[<ffffffff810b4dc5>] unshare_nsproxy_namespaces+0x85/0xe0
[<ffffffff810810eb>] SyS_unshare+0x1ab/0x350
[<ffffffff8177bfe9>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff
unreferenced object 0xffff88006b3a92c0 (size 4416):
comm "ip", pid 25985, jiffies 4346037464 (age 4507.484s)
hex dump (first 32 bytes):
02 00 00 00 00 00 00 00 08 08 00 00 ad 4e ad de .............N..
ff ff ff ff 00 00 00 00 ff ff ff ff ff ff ff ff ................
backtrace:
[<ffffffff8176858e>] kmemleak_alloc+0x5e/0xc0
[<ffffffff811f5f47>] kmem_cache_alloc+0x217/0x2a0
[<ffffffff81636875>] copy_net_ns+0x65/0x160
[<ffffffff810b4c91>] create_new_namespaces+0x101/0x1b0
[<ffffffff810b4dc5>] unshare_nsproxy_namespaces+0x85/0xe0
[<ffffffff810810eb>] SyS_unshare+0x1ab/0x350
[<ffffffff8177bfe9>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff
[root@jenkins ~]# lsmod
Module Size Used by
veth 13604 0
binfmt_misc 17392 0
ip6table_filter 12815 0
ip6_tables 26677 1 ip6table_filter
tun 32328 0
netlink_diag 12658 0
af_packet_diag 12604 0
udp_diag 12794 0
tcp_diag 12591 0
inet_diag 18278 2 tcp_diag,udp_diag
unix_diag 12594 0
bridge 116990 0
stp 12989 1 bridge
llc 14094 2 stp,bridge
btrfs 933081 1
xor 21366 1 btrfs
raid6_pq 96781 1 btrfs
joydev 17642 0
microcode 19962 0
i2c_piix4 22148 0
virtio_net 28194 0
i2c_core 38545 1 i2c_piix4
virtio_balloon 13451 0
pcspkr 12718 0
virtio_blk 18030 6
virtio_pci 17713 0
virtio_ring 19923 4 virtio_blk,virtio_net,virtio_pci,virtio_balloon
virtio 14207 4 virtio_blk,virtio_net,virtio_pci,virtio_balloon
floppy 73436 0
^ permalink raw reply
* Re: [Patch net] macvlan: add NETIF_F_NETNS_LOCAL flag
From: Nicolas Dichtel @ 2014-02-12 9:47 UTC (permalink / raw)
To: Eric Dumazet, Hannes Frederic Sowa
Cc: Cong Wang, Cong Wang, netdev, Patrick McHardy, David S. Miller
In-Reply-To: <1392092120.6615.64.camel@edumazet-glaptop2.roam.corp.google.com>
Le 11/02/2014 05:15, Eric Dumazet a écrit :
> On Tue, 2014-02-11 at 03:40 +0100, Hannes Frederic Sowa wrote:
>
>> Setting up a macvlan and moving it into another namespace without moving
>> the parent device is a nice feature. I am not an administrator, so I don't
>> use that stuff often, but given you can easily spawn namespaces and put
>> applications into them, one of the easiest things to connect those to
>> local network without routing over veth and such is the macvlan interface.
>
> Exactly.
I also agree.
^ permalink raw reply
* [PATCH] netfilter: nft_meta: fix typo "CONFIG_NET_CLS_ROUTE"
From: Paul Bolle @ 2014-02-12 9:53 UTC (permalink / raw)
To: Pablo Neira Ayuso, Patrick McHardy, Jozsef Kadlecsik,
David S. Miller
Cc: Richard Weinberger, netfilter-devel, netfilter, coreteam, netdev,
linux-kernel
There are two checks for CONFIG_NET_CLS_ROUTE, but the corresponding
Kconfig symbol was dropped in v2.6.39. Since the code guards access to
dst_entry.tclassid it seems CONFIG_IP_ROUTE_CLASSID should be used
instead.
Signed-off-by: Paul Bolle <pebolle@tiscali.nl>
---
Untested! I don't use CONFIG_NF_TABLES in my .config (yet). Besides, I
would have no clue how to runtime test this.
And, yes, typo is stretching it a bit.
net/netfilter/nft_meta.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index e8254ad..425cf39 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -116,7 +116,7 @@ static void nft_meta_get_eval(const struct nft_expr *expr,
skb->sk->sk_socket->file->f_cred->fsgid);
read_unlock_bh(&skb->sk->sk_callback_lock);
break;
-#ifdef CONFIG_NET_CLS_ROUTE
+#ifdef CONFIG_IP_ROUTE_CLASSID
case NFT_META_RTCLASSID: {
const struct dst_entry *dst = skb_dst(skb);
@@ -199,7 +199,7 @@ static int nft_meta_init_validate_get(uint32_t key)
case NFT_META_OIFTYPE:
case NFT_META_SKUID:
case NFT_META_SKGID:
-#ifdef CONFIG_NET_CLS_ROUTE
+#ifdef CONFIG_IP_ROUTE_CLASSID
case NFT_META_RTCLASSID:
#endif
#ifdef CONFIG_NETWORK_SECMARK
--
1.8.5.3
^ permalink raw reply related
* Re: [Patch net] macvlan: add NETIF_F_NETNS_LOCAL flag
From: Nicolas Dichtel @ 2014-02-12 10:03 UTC (permalink / raw)
To: Eric Dumazet, Cong Wang
Cc: Hannes Frederic Sowa, Cong Wang, netdev, Patrick McHardy,
David S. Miller
In-Reply-To: <1392097099.6615.74.camel@edumazet-glaptop2.roam.corp.google.com>
Le 11/02/2014 06:38, Eric Dumazet a écrit :
> On Mon, 2014-02-10 at 21:37 -0800, Eric Dumazet wrote:
>
>>
>> Simple patch would be :
>>
>> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
>> index 048dc8d183aa..31bbba34fd1e 100644
>> --- a/net/core/rtnetlink.c
>> +++ b/net/core/rtnetlink.c
>> @@ -963,6 +963,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
>> nla_put_u32(skb, IFLA_NUM_RX_QUEUES, dev->num_rx_queues) ||
>> #endif
>> (dev->ifindex != dev->iflink &&
>> + __dev_get_by_index(dev_net(dev), dev->iflink) &&
>> nla_put_u32(skb, IFLA_LINK, dev->iflink)) ||
>> (upper_dev &&
>> nla_put_u32(skb, IFLA_MASTER, upper_dev->ifindex)) ||
>>
>
> Hmm, not enough.
>
> We probably need to keep a pointer to iflink net structure.
This is also used in ip tunnels, but when i/o device is not in the same netns
that the tunnel device, the userland can not interpret that IFLA_LINK attribute
(userland don't have necessary information to access another netns, maybe they
will be able to do it in the future ;-)).
The goal of your patch was to avoid filling this attribute when iflink is
into a netns != from dev_net(dev)?
If yes, I agree that we need to keep a pointer to the net structure of iflink.
This information is already available in ip tunnels (struct ip_tunnel->net,
struct ip6_tnl->net) but is not generic. Maybe we can move it to struct
net_device?
^ permalink raw reply
* Re: [PATCH V2 5/6] vhost_net: poll vhost queue after marking DMA is done
From: Jason Wang @ 2014-02-12 10:06 UTC (permalink / raw)
To: Qin Chuanyu, virtualization, netdev, linux-kernel; +Cc: kvm, mst
In-Reply-To: <52FB24EA.3060001@huawei.com>
On 02/12/2014 03:38 PM, Qin Chuanyu wrote:
> On 2013/8/30 12:29, Jason Wang wrote:
>> We used to poll vhost queue before making DMA is done, this is racy
>> if vhost
>> thread were waked up before marking DMA is done which can result the
>> signal to
>> be missed. Fix this by always poll the vhost thread before DMA is done.
>>
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>> ---
>> drivers/vhost/net.c | 9 +++++----
>> 1 files changed, 5 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
>> index ff60c2a..d09c17c 100644
>> --- a/drivers/vhost/net.c
>> +++ b/drivers/vhost/net.c
>> @@ -308,6 +308,11 @@ static void vhost_zerocopy_callback(struct
>> ubuf_info *ubuf, bool success)
>> struct vhost_virtqueue *vq = ubufs->vq;
>> int cnt = atomic_read(&ubufs->kref.refcount);
>>
>> + /* set len to mark this desc buffers done DMA */
>> + vq->heads[ubuf->desc].len = success ?
>> + VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN;
>> + vhost_net_ubuf_put(ubufs);
>> +
>> /*
>> * Trigger polling thread if guest stopped submitting new buffers:
>> * in this case, the refcount after decrement will eventually
>> reach 1
>> @@ -318,10 +323,6 @@ static void vhost_zerocopy_callback(struct
>> ubuf_info *ubuf, bool success)
>> */
>> if (cnt <= 2 || !(cnt % 16))
>> vhost_poll_queue(&vq->poll);
>> - /* set len to mark this desc buffers done DMA */
>> - vq->heads[ubuf->desc].len = success ?
>> - VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN;
>> - vhost_net_ubuf_put(ubufs);
>> }
>>
>> /* Expects to be always run from workqueue - which acts as
>>
> with this change, vq would lose protection that provided by ubufs->kref.
> if another thread is waiting at vhost_net_ubuf_put_and_wait called by
> vhost_net_release, then after vhost_net_ubuf_put, vq would been free
> by vhost_net_release soon, vhost_poll_queue(&vq->poll) may cause NULL
> pointer Exception.
>
Good catch.
> another question is that vhost_zerocopy_callback is called by kfree_skb,
> it may called in different thread context.
> vhost_poll_queue is called decided by ubufs->kref.refcount, this may
> cause there isn't any thread call vhost_poll_queue, but at least one
> is needed. and this cause network break.
> We could repeat it by using 8 netperf thread in guest to xmit tcp to
> its host.
>
> I think if using atomic_read to decide while do vhost_poll_queue or not,
> at least a spink_lock is needed.
Then you need another ref count to protect that spinlock? Care to send
patches?
Thanks
>
> --
> 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] USB2NET : SR9800 : One chip USB2.0 USB2NET SR9800 Device Driver Support
From: Thierry Reding @ 2014-02-12 10:12 UTC (permalink / raw)
To: liujunliang_ljl
Cc: davem, horms, joe, romieu, gregkh, netdev, linux-usb,
linux-kernel, sunhecheng
In-Reply-To: <1392010419-5217-1-git-send-email-liujunliang_ljl@163.com>
[-- Attachment #1: Type: text/plain, Size: 1269 bytes --]
On Mon, Feb 10, 2014 at 01:33:39PM +0800, liujunliang_ljl@163.com wrote:
> From: Liu Junliang <liujunliang_ljl@163.com>
>
>
> Signed-off-by: Liu Junliang <liujunliang_ljl@163.com>
> ---
> drivers/net/usb/Kconfig | 16 +
> drivers/net/usb/Makefile | 1 +
> drivers/net/usb/sr9800.c | 873 ++++++++++++++++++++++++++++++++++++++++++++++
> drivers/net/usb/sr9800.h | 202 +++++++++++
> 4 files changed, 1092 insertions(+), 0 deletions(-)
> create mode 100644 drivers/net/usb/sr9800.c
> create mode 100644 drivers/net/usb/sr9800.h
>
> diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
> index 47b0f73..2551bf6 100644
> --- a/drivers/net/usb/Kconfig
> +++ b/drivers/net/usb/Kconfig
> @@ -291,6 +291,22 @@ config USB_NET_SR9700
> This option adds support for CoreChip-sz SR9700 based USB 1.1
> 10/100 Ethernet adapters.
>
> +config USB_NET_SR9800
> + tristate "CoreChip-sz SR9800 based USB 2.0 10/100 ethernet devices"
> + depends on USB_USBNET
> + select CRC32
> + default y
Why is this selected by default? I can see that some of the other USB
network drivers are also selected by default, but not all of them. Is
there some rule of thumb as to which should default to y and which
shouldn't?
Thierry
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* pull-request: can-next 2014-02-12
From: Marc Kleine-Budde @ 2014-02-12 10:15 UTC (permalink / raw)
To: netdev; +Cc: David Miller, linux-can@vger.kernel.org, kernel@pengutronix.de
[-- Attachment #1: Type: text/plain, Size: 2769 bytes --]
Hello David,
this is a pull request of eight patches for net-next/master.
Florian Vaussard contributed a series that merged the sja1000 of_platform
into the platform driver. The of_platform driver is finally removed.
Stephane Grosjean supplied a patch to allocate CANFD skbs. In a patch
by Uwe Kleine-König another missing copyright information was added to
a userspace header. And a patch by Yoann DI RUZZA that adds listen only
mode to the at91_can driver.
regards,
Marc
---
The following changes since commit 77d143de75812596a58d126606f42d1214e09dde:
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml (2014-01-26 11:06:16 -0800)
are available in the git repository at:
git://gitorious.org/linux-can/linux-can-next.git tags/linux-can-next-for-3.15-20140212
for you to fetch changes up to 17a50ee4bd47bdba94546e0526fc9ce93dc77d5e:
can: at91_can: add listen only mode (2014-02-11 09:55:44 +0100)
----------------------------------------------------------------
linux-can-next-for-3.15-20140212
----------------------------------------------------------------
Florian Vaussard (5):
can: sja1000: convert printk to use netdev API
can: sja1000: platform: use devm_* APIs
can: sja1000: fuse of_platform into platform
Documentation: devicetree: sja1000: add reg-io-width binding
can: sja1000: of: add reg-io-width property for 8, 16 and 32-bit register access
Stephane Grosjean (1):
can: add ability to allocate CANFD frame in skb data
Uwe Kleine-König (1):
can: add explicit copyrights to can userspace header
Yoann DI RUZZA (1):
can: at91_can: add listen only mode
.../devicetree/bindings/net/can/sja1000.txt | 4 +
drivers/net/can/at91_can.c | 9 +-
drivers/net/can/dev.c | 24 +++
drivers/net/can/sja1000/Kconfig | 13 +-
drivers/net/can/sja1000/Makefile | 1 -
drivers/net/can/sja1000/sja1000.c | 3 +-
drivers/net/can/sja1000/sja1000_of_platform.c | 220 ---------------------
drivers/net/can/sja1000/sja1000_platform.c | 194 ++++++++++++------
include/linux/can/dev.h | 2 +
include/uapi/linux/can.h | 32 +++
10 files changed, 206 insertions(+), 296 deletions(-)
delete mode 100644 drivers/net/can/sja1000/sja1000_of_platform.c
--
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: 242 bytes --]
^ permalink raw reply
* [PATCH] can: kvaser_usb: check number of channels returned by HW
From: Marc Kleine-Budde @ 2014-02-12 10:35 UTC (permalink / raw)
To: netdev
Cc: davem, linux-can, kernel, Olivier Sobrie, linux-stable,
Marc Kleine-Budde
In-Reply-To: <1392201340-6909-1-git-send-email-mkl@pengutronix.de>
From: Olivier Sobrie <olivier@sobrie.be>
It is needed to check the number of channels returned by the HW because it
cannot be greater than MAX_NET_DEVICES otherwise it will crash.
Signed-off-by: Olivier Sobrie <olivier@sobrie.be>
Cc: linux-stable <stable@vger.kernel.org>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/kvaser_usb.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 6c859bb..e77d110 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -473,6 +473,8 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
return err;
dev->nchannels = msg.u.cardinfo.nchannels;
+ if (dev->nchannels > MAX_NET_DEVICES)
+ return -EINVAL;
return 0;
}
--
1.8.5.3
^ permalink raw reply related
* pull-request: can 2014-02-12
From: Marc Kleine-Budde @ 2014-02-12 10:35 UTC (permalink / raw)
To: netdev; +Cc: davem, linux-can, kernel
Hello David,
this is a pull request with one patch for net/master, for the current release
cycle. Olivier Sobrie noticed and fixed that the kvaser_usb driver doesn't
check the number of channels value from the hardware, which may result in
writing over the bounds of an array in the driver.
regards,
Marc
---
The following changes since commit 738b52bb9845da183b6ff46a8f685b56a63379d1:
Merge tag 'microblaze-3.14-rc3' of git://git.monstr.eu/linux-2.6-microblaze (2014-02-11 12:24:35 -0800)
are available in the git repository at:
git://gitorious.org/linux-can/linux-can.git tags/linux-can-fixes-for-3.14-20140212
for you to fetch changes up to 862474f8b46f6c1e600d4934e40ba40646c696ec:
can: kvaser_usb: check number of channels returned by HW (2014-02-12 10:42:02 +0100)
----------------------------------------------------------------
linux-can-fixes-for-3.14-20140212
----------------------------------------------------------------
Olivier Sobrie (1):
can: kvaser_usb: check number of channels returned by HW
drivers/net/can/usb/kvaser_usb.c | 2 ++
1 file changed, 2 insertions(+)
^ permalink raw reply
* [PATCH net-next] be2net patches
From: Somnath Kotur @ 2014-02-12 10:37 UTC (permalink / raw)
To: netdev; +Cc: davem, Somnath Kotur
Please apply.
Somnath Kotur (1):
be2net: This patch logs a kernel message when a HW
error(SLIPORT_ERROR in Lancer and UE in BEx/Skyhawk)
Vasundhara Volam (2):
be2net: Update copyright year
be2net: refactor multi-channel config code for Skyhawk-R chip
drivers/net/ethernet/emulex/benet/be.h | 14 ++-
drivers/net/ethernet/emulex/benet/be_cmds.c | 22 +++-
drivers/net/ethernet/emulex/benet/be_cmds.h | 38 ++++--
drivers/net/ethernet/emulex/benet/be_ethtool.c | 2 +-
drivers/net/ethernet/emulex/benet/be_hw.h | 6 +-
drivers/net/ethernet/emulex/benet/be_main.c | 171 +++++++++++++++---------
drivers/net/ethernet/emulex/benet/be_roce.c | 2 +-
drivers/net/ethernet/emulex/benet/be_roce.h | 2 +-
8 files changed, 176 insertions(+), 81 deletions(-)
^ permalink raw reply
* [PATCH 1/3] be2net: Log a kernel message when UE is detected in BE & Skyhawk
From: Somnath Kotur @ 2014-02-12 10:37 UTC (permalink / raw)
To: netdev; +Cc: davem, Somnath Kotur
This patch logs a kernel message when a HW error(SLIPORT_ERROR in Lancer and UE
in BEx/Skyhawk) is detected. The log message for BE3 was missing earlier.
This patch also refactors the code by segregating error-detection and reporting
code for Lancer and BEx/SH.
Signed-off-by: Somnath Kotur <somnath.kotur@emulex.com>
---
drivers/net/ethernet/emulex/benet/be_main.c | 82 +++++++++++++-------------
1 files changed, 41 insertions(+), 41 deletions(-)
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 04ac9c6..7057545 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -2423,6 +2423,9 @@ void be_detect_error(struct be_adapter *adapter)
u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0;
u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
u32 i;
+ bool error_detected = false;
+ struct device *dev = &adapter->pdev->dev;
+ struct net_device *netdev = adapter->netdev;
if (be_hw_error(adapter))
return;
@@ -2434,6 +2437,21 @@ void be_detect_error(struct be_adapter *adapter)
SLIPORT_ERROR1_OFFSET);
sliport_err2 = ioread32(adapter->db +
SLIPORT_ERROR2_OFFSET);
+ adapter->hw_error = true;
+ /* Do not log error messages if its a FW reset */
+ if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 &&
+ sliport_err2 == SLIPORT_ERROR_FW_RESET2) {
+ dev_info(dev, "Firmware update in progress\n");
+ } else {
+ error_detected = true;
+ dev_err(dev, "Error detected in the card\n");
+ dev_err(dev, "ERR: sliport status 0x%x\n",
+ sliport_status);
+ dev_err(dev, "ERR: sliport error1 0x%x\n",
+ sliport_err1);
+ dev_err(dev, "ERR: sliport error2 0x%x\n",
+ sliport_err2);
+ }
}
} else {
pci_read_config_dword(adapter->pdev,
@@ -2447,51 +2465,33 @@ void be_detect_error(struct be_adapter *adapter)
ue_lo = (ue_lo & ~ue_lo_mask);
ue_hi = (ue_hi & ~ue_hi_mask);
- }
-
- /* On certain platforms BE hardware can indicate spurious UEs.
- * Allow the h/w to stop working completely in case of a real UE.
- * Hence not setting the hw_error for UE detection.
- */
- if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
- adapter->hw_error = true;
- /* Do not log error messages if its a FW reset */
- if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 &&
- sliport_err2 == SLIPORT_ERROR_FW_RESET2) {
- dev_info(&adapter->pdev->dev,
- "Firmware update in progress\n");
- return;
- } else {
- dev_err(&adapter->pdev->dev,
- "Error detected in the card\n");
- }
- }
- if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
- dev_err(&adapter->pdev->dev,
- "ERR: sliport status 0x%x\n", sliport_status);
- dev_err(&adapter->pdev->dev,
- "ERR: sliport error1 0x%x\n", sliport_err1);
- dev_err(&adapter->pdev->dev,
- "ERR: sliport error2 0x%x\n", sliport_err2);
- }
-
- if (ue_lo) {
- for (i = 0; ue_lo; ue_lo >>= 1, i++) {
- if (ue_lo & 1)
- dev_err(&adapter->pdev->dev,
- "UE: %s bit set\n", ue_status_low_desc[i]);
- }
- }
+ /* On certain platforms BE hardware can indicate spurious UEs.
+ * Allow HW to stop working completely in case of a real UE.
+ * Hence not setting the hw_error for UE detection.
+ */
- if (ue_hi) {
- for (i = 0; ue_hi; ue_hi >>= 1, i++) {
- if (ue_hi & 1)
- dev_err(&adapter->pdev->dev,
- "UE: %s bit set\n", ue_status_hi_desc[i]);
+ if (ue_lo || ue_hi) {
+ error_detected = true;
+ dev_err(dev,
+ "Unrecoverable Error detected in the adapter");
+ dev_err(dev, "Please reboot server to recover");
+ if (skyhawk_chip(adapter))
+ adapter->hw_error = true;
+ for (i = 0; ue_lo; ue_lo >>= 1, i++) {
+ if (ue_lo & 1)
+ dev_err(dev, "UE: %s bit set\n",
+ ue_status_low_desc[i]);
+ }
+ for (i = 0; ue_hi; ue_hi >>= 1, i++) {
+ if (ue_hi & 1)
+ dev_err(dev, "UE: %s bit set\n",
+ ue_status_hi_desc[i]);
+ }
}
}
-
+ if (error_detected)
+ netif_carrier_off(netdev);
}
static void be_msix_disable(struct be_adapter *adapter)
--
1.5.6.1
^ permalink raw reply related
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