Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ef70aab authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'linux-can-fixes-for-4.0-20150322' of...

Merge tag 'linux-can-fixes-for-4.0-20150322' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can



Marc Kleine-Budde says:

====================
pull-request: can 2015-03-22

this is a pull-request of 7 patches for net/master.

Ahmed S. Darwish fixes another two problems in the kvaser_usb driver. A patch
by Colin Ian King for the gs_usb driver adds a missing check for kzalloc
allocation failures. Two patches by Stephane Grosjean for the peak_usb driver
add missing support for ISO / non-ISO mode switching. Andri Yngvason
contributes a patch to fix the state handling in the flexcan driver. The last
patch by Andreas Werner for the flexcan driver add missing EPROBE_DEFER
handling for the transceiver regulator.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 90a5a895 555828ef
Loading
Loading
Loading
Loading
+11 −7
Original line number Diff line number Diff line
@@ -592,13 +592,12 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
		rx_state = unlikely(reg_esr & FLEXCAN_ESR_RX_WRN) ?
			   CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE;
		new_state = max(tx_state, rx_state);
	} else if (unlikely(flt == FLEXCAN_ESR_FLT_CONF_PASSIVE)) {
	} else {
		__flexcan_get_berr_counter(dev, &bec);
		new_state = CAN_STATE_ERROR_PASSIVE;
		new_state = flt == FLEXCAN_ESR_FLT_CONF_PASSIVE ?
			    CAN_STATE_ERROR_PASSIVE : CAN_STATE_BUS_OFF;
		rx_state = bec.rxerr >= bec.txerr ? new_state : 0;
		tx_state = bec.rxerr <= bec.txerr ? new_state : 0;
	} else {
		new_state = CAN_STATE_BUS_OFF;
	}

	/* state hasn't changed */
@@ -1158,12 +1157,19 @@ static int flexcan_probe(struct platform_device *pdev)
	const struct flexcan_devtype_data *devtype_data;
	struct net_device *dev;
	struct flexcan_priv *priv;
	struct regulator *reg_xceiver;
	struct resource *mem;
	struct clk *clk_ipg = NULL, *clk_per = NULL;
	void __iomem *base;
	int err, irq;
	u32 clock_freq = 0;

	reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
	if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER)
		return -EPROBE_DEFER;
	else if (IS_ERR(reg_xceiver))
		reg_xceiver = NULL;

	if (pdev->dev.of_node)
		of_property_read_u32(pdev->dev.of_node,
						"clock-frequency", &clock_freq);
@@ -1224,9 +1230,7 @@ static int flexcan_probe(struct platform_device *pdev)
	priv->pdata = dev_get_platdata(&pdev->dev);
	priv->devtype_data = devtype_data;

	priv->reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
	if (IS_ERR(priv->reg_xceiver))
		priv->reg_xceiver = NULL;
	priv->reg_xceiver = reg_xceiver;

	netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT);

+2 −0
Original line number Diff line number Diff line
@@ -901,6 +901,8 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *
	}

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev)
		return -ENOMEM;
	init_usb_anchor(&dev->rx_submitted);

	atomic_set(&dev->active_channels, 0);
+42 −27
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>

#define MAX_TX_URBS			16
#define MAX_RX_URBS			4
#define START_TIMEOUT			1000 /* msecs */
#define STOP_TIMEOUT			1000 /* msecs */
@@ -443,6 +442,7 @@ struct kvaser_usb_error_summary {
	};
};

/* Context for an outstanding, not yet ACKed, transmission */
struct kvaser_usb_tx_urb_context {
	struct kvaser_usb_net_priv *priv;
	u32 echo_index;
@@ -456,8 +456,13 @@ struct kvaser_usb {
	struct usb_endpoint_descriptor *bulk_in, *bulk_out;
	struct usb_anchor rx_submitted;

	/* @max_tx_urbs: Firmware-reported maximum number of oustanding,
	 * not yet ACKed, transmissions on this device. This value is
	 * also used as a sentinel for marking free tx contexts.
	 */
	u32 fw_version;
	unsigned int nchannels;
	unsigned int max_tx_urbs;
	enum kvaser_usb_family family;

	bool rxinitdone;
@@ -467,19 +472,18 @@ struct kvaser_usb {

struct kvaser_usb_net_priv {
	struct can_priv can;

	spinlock_t tx_contexts_lock;
	int active_tx_contexts;
	struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS];

	struct usb_anchor tx_submitted;
	struct completion start_comp, stop_comp;
	struct can_berr_counter bec;

	struct kvaser_usb *dev;
	struct net_device *netdev;
	int channel;

	struct can_berr_counter bec;
	struct completion start_comp, stop_comp;
	struct usb_anchor tx_submitted;

	spinlock_t tx_contexts_lock;
	int active_tx_contexts;
	struct kvaser_usb_tx_urb_context tx_contexts[];
};

static const struct usb_device_id kvaser_usb_table[] = {
@@ -592,8 +596,8 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
			 * for further details.
			 */
			if (tmp->len == 0) {
				pos = round_up(pos,
					       dev->bulk_in->wMaxPacketSize);
				pos = round_up(pos, le16_to_cpu(dev->bulk_in->
								wMaxPacketSize));
				continue;
			}

@@ -657,9 +661,13 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
	switch (dev->family) {
	case KVASER_LEAF:
		dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version);
		dev->max_tx_urbs =
			le16_to_cpu(msg.u.leaf.softinfo.max_outstanding_tx);
		break;
	case KVASER_USBCAN:
		dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version);
		dev->max_tx_urbs =
			le16_to_cpu(msg.u.usbcan.softinfo.max_outstanding_tx);
		break;
	}

@@ -715,7 +723,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,

	stats = &priv->netdev->stats;

	context = &priv->tx_contexts[tid % MAX_TX_URBS];
	context = &priv->tx_contexts[tid % dev->max_tx_urbs];

	/* Sometimes the state change doesn't come after a bus-off event */
	if (priv->can.restart_ms &&
@@ -744,7 +752,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
	spin_lock_irqsave(&priv->tx_contexts_lock, flags);

	can_get_echo_skb(priv->netdev, context->echo_index);
	context->echo_index = MAX_TX_URBS;
	context->echo_index = dev->max_tx_urbs;
	--priv->active_tx_contexts;
	netif_wake_queue(priv->netdev);

@@ -1329,7 +1337,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
		 * number of events in case of a heavy rx load on the bus.
		 */
		if (msg->len == 0) {
			pos = round_up(pos, dev->bulk_in->wMaxPacketSize);
			pos = round_up(pos, le16_to_cpu(dev->bulk_in->
							wMaxPacketSize));
			continue;
		}

@@ -1512,11 +1521,13 @@ static int kvaser_usb_open(struct net_device *netdev)

static void kvaser_usb_reset_tx_urb_contexts(struct kvaser_usb_net_priv *priv)
{
	int i;
	int i, max_tx_urbs;

	max_tx_urbs = priv->dev->max_tx_urbs;

	priv->active_tx_contexts = 0;
	for (i = 0; i < MAX_TX_URBS; i++)
		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
	for (i = 0; i < max_tx_urbs; i++)
		priv->tx_contexts[i].echo_index = max_tx_urbs;
}

/* This method might sleep. Do not call it in the atomic context
@@ -1702,14 +1713,14 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
		*msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME;

	spin_lock_irqsave(&priv->tx_contexts_lock, flags);
	for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
		if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
	for (i = 0; i < dev->max_tx_urbs; i++) {
		if (priv->tx_contexts[i].echo_index == dev->max_tx_urbs) {
			context = &priv->tx_contexts[i];

			context->echo_index = i;
			can_put_echo_skb(skb, netdev, context->echo_index);
			++priv->active_tx_contexts;
			if (priv->active_tx_contexts >= MAX_TX_URBS)
			if (priv->active_tx_contexts >= dev->max_tx_urbs)
				netif_stop_queue(netdev);

			break;
@@ -1743,7 +1754,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
		spin_lock_irqsave(&priv->tx_contexts_lock, flags);

		can_free_echo_skb(netdev, context->echo_index);
		context->echo_index = MAX_TX_URBS;
		context->echo_index = dev->max_tx_urbs;
		--priv->active_tx_contexts;
		netif_wake_queue(netdev);

@@ -1881,7 +1892,9 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
	if (err)
		return err;

	netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
	netdev = alloc_candev(sizeof(*priv) +
			      dev->max_tx_urbs * sizeof(*priv->tx_contexts),
			      dev->max_tx_urbs);
	if (!netdev) {
		dev_err(&intf->dev, "Cannot alloc candev\n");
		return -ENOMEM;
@@ -2009,6 +2022,13 @@ static int kvaser_usb_probe(struct usb_interface *intf,
		return err;
	}

	dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
		((dev->fw_version >> 24) & 0xff),
		((dev->fw_version >> 16) & 0xff),
		(dev->fw_version & 0xffff));

	dev_dbg(&intf->dev, "Max oustanding tx = %d URBs\n", dev->max_tx_urbs);

	err = kvaser_usb_get_card_info(dev);
	if (err) {
		dev_err(&intf->dev,
@@ -2016,11 +2036,6 @@ static int kvaser_usb_probe(struct usb_interface *intf,
		return err;
	}

	dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
		((dev->fw_version >> 24) & 0xff),
		((dev->fw_version >> 16) & 0xff),
		(dev->fw_version & 0xffff));

	for (i = 0; i < dev->nchannels; i++) {
		err = kvaser_usb_init_one(intf, id, i);
		if (err) {
+8 −7
Original line number Diff line number Diff line
@@ -26,8 +26,8 @@
#define PUCAN_CMD_FILTER_STD		0x008
#define PUCAN_CMD_TX_ABORT		0x009
#define PUCAN_CMD_WR_ERR_CNT		0x00a
#define PUCAN_CMD_RX_FRAME_ENABLE	0x00b
#define PUCAN_CMD_RX_FRAME_DISABLE	0x00c
#define PUCAN_CMD_SET_EN_OPTION		0x00b
#define PUCAN_CMD_CLR_DIS_OPTION	0x00c
#define PUCAN_CMD_END_OF_COLLECTION	0x3ff

/* uCAN received messages list */
@@ -101,14 +101,15 @@ struct __packed pucan_wr_err_cnt {
	u16	unused;
};

/* uCAN RX_FRAME_ENABLE command fields */
#define PUCAN_FLTEXT_ERROR		0x0001
#define PUCAN_FLTEXT_BUSLOAD		0x0002
/* uCAN SET_EN/CLR_DIS _OPTION command fields */
#define PUCAN_OPTION_ERROR		0x0001
#define PUCAN_OPTION_BUSLOAD		0x0002
#define PUCAN_OPTION_CANDFDISO		0x0004

struct __packed pucan_filter_ext {
struct __packed pucan_options {
	__le16	opcode_channel;

	__le16	ext_mask;
	__le16	options;
	u32	unused;
};

+50 −23
Original line number Diff line number Diff line
@@ -110,13 +110,13 @@ struct __packed pcan_ufd_led {
	u8	unused[5];
};

/* Extended usage of uCAN commands CMD_RX_FRAME_xxxABLE for PCAN-USB Pro FD */
/* Extended usage of uCAN commands CMD_xxx_xx_OPTION for PCAN-USB Pro FD */
#define PCAN_UFD_FLTEXT_CALIBRATION	0x8000

struct __packed pcan_ufd_filter_ext {
struct __packed pcan_ufd_options {
	__le16	opcode_channel;

	__le16	ext_mask;
	__le16	ucan_mask;
	u16	unused;
	__le16	usb_mask;
};
@@ -251,6 +251,27 @@ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf)
	/* moves the pointer forward */
	pc += sizeof(struct pucan_wr_err_cnt);

	/* add command to switch from ISO to non-ISO mode, if fw allows it */
	if (dev->can.ctrlmode_supported & CAN_CTRLMODE_FD_NON_ISO) {
		struct pucan_options *puo = (struct pucan_options *)pc;

		puo->opcode_channel =
			(dev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) ?
			pucan_cmd_opcode_channel(dev,
						 PUCAN_CMD_CLR_DIS_OPTION) :
			pucan_cmd_opcode_channel(dev, PUCAN_CMD_SET_EN_OPTION);

		puo->options = cpu_to_le16(PUCAN_OPTION_CANDFDISO);

		/* to be sure that no other extended bits will be taken into
		 * account
		 */
		puo->unused = 0;

		/* moves the pointer forward */
		pc += sizeof(struct pucan_options);
	}

	/* next, go back to operational mode */
	cmd = (struct pucan_command *)pc;
	cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
@@ -321,21 +342,21 @@ static int pcan_usb_fd_set_filter_std(struct peak_usb_device *dev, int idx,
	return pcan_usb_fd_send_cmd(dev, cmd);
}

/* set/unset notifications filter:
/* set/unset options
 *
 *	onoff	sets(1)/unset(0) notifications
 *	mask	each bit defines a kind of notification to set/unset
 *	onoff	set(1)/unset(0) options
 *	mask	each bit defines a kind of options to set/unset
 */
static int pcan_usb_fd_set_filter_ext(struct peak_usb_device *dev,
				      bool onoff, u16 ext_mask, u16 usb_mask)
static int pcan_usb_fd_set_options(struct peak_usb_device *dev,
				   bool onoff, u16 ucan_mask, u16 usb_mask)
{
	struct pcan_ufd_filter_ext *cmd = pcan_usb_fd_cmd_buffer(dev);
	struct pcan_ufd_options *cmd = pcan_usb_fd_cmd_buffer(dev);

	cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
					(onoff) ? PUCAN_CMD_RX_FRAME_ENABLE :
						  PUCAN_CMD_RX_FRAME_DISABLE);
					(onoff) ? PUCAN_CMD_SET_EN_OPTION :
						  PUCAN_CMD_CLR_DIS_OPTION);

	cmd->ext_mask = cpu_to_le16(ext_mask);
	cmd->ucan_mask = cpu_to_le16(ucan_mask);
	cmd->usb_mask = cpu_to_le16(usb_mask);

	/* send the command */
@@ -770,8 +791,8 @@ static int pcan_usb_fd_start(struct peak_usb_device *dev)
				       &pcan_usb_pro_fd);

		/* enable USB calibration messages */
		err = pcan_usb_fd_set_filter_ext(dev, 1,
						 PUCAN_FLTEXT_ERROR,
		err = pcan_usb_fd_set_options(dev, 1,
					      PUCAN_OPTION_ERROR,
					      PCAN_UFD_FLTEXT_CALIBRATION);
	}

@@ -806,8 +827,8 @@ static int pcan_usb_fd_stop(struct peak_usb_device *dev)

	/* turn off special msgs for that interface if no other dev opened */
	if (pdev->usb_if->dev_opened_count == 1)
		pcan_usb_fd_set_filter_ext(dev, 0,
					   PUCAN_FLTEXT_ERROR,
		pcan_usb_fd_set_options(dev, 0,
					PUCAN_OPTION_ERROR,
					PCAN_UFD_FLTEXT_CALIBRATION);
	pdev->usb_if->dev_opened_count--;

@@ -860,8 +881,14 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
			 pdev->usb_if->fw_info.fw_version[2],
			 dev->adapter->ctrl_count);

		/* the currently supported hw is non-ISO */
		dev->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO;
		/* check for ability to switch between ISO/non-ISO modes */
		if (pdev->usb_if->fw_info.fw_version[0] >= 2) {
			/* firmware >= 2.x supports ISO/non-ISO switching */
			dev->can.ctrlmode_supported |= CAN_CTRLMODE_FD_NON_ISO;
		} else {
			/* firmware < 2.x only supports fixed(!) non-ISO */
			dev->can.ctrlmode |= CAN_CTRLMODE_FD_NON_ISO;
		}

		/* tell the hardware the can driver is running */
		err = pcan_usb_fd_drv_loaded(dev, 1);
@@ -937,8 +964,8 @@ static void pcan_usb_fd_exit(struct peak_usb_device *dev)
	if (dev->ctrl_idx == 0) {
		/* turn off calibration message if any device were opened */
		if (pdev->usb_if->dev_opened_count > 0)
			pcan_usb_fd_set_filter_ext(dev, 0,
						   PUCAN_FLTEXT_ERROR,
			pcan_usb_fd_set_options(dev, 0,
						PUCAN_OPTION_ERROR,
						PCAN_UFD_FLTEXT_CALIBRATION);

		/* tell USB adapter that the driver is being unloaded */