diff options
| -rw-r--r-- | drivers/net/can/flexcan.c | 18 | ||||
| -rw-r--r-- | drivers/net/can/usb/gs_usb.c | 2 | ||||
| -rw-r--r-- | drivers/net/can/usb/kvaser_usb.c | 69 | ||||
| -rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_ucan.h | 15 | ||||
| -rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 73 | 
5 files changed, 113 insertions, 64 deletions
| diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 80c46ad4cee4..ad0a7e8c2c2b 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -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); diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index 009acc8641fc..8b4d3e6875eb 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -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); diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index e97a08ce0b90..57611fd91229 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -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 @@ error:  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) { diff --git a/drivers/net/can/usb/peak_usb/pcan_ucan.h b/drivers/net/can/usb/peak_usb/pcan_ucan.h index 1ba7c25002e1..e8fc4952c6b0 100644 --- a/drivers/net/can/usb/peak_usb/pcan_ucan.h +++ b/drivers/net/can/usb/peak_usb/pcan_ucan.h @@ -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;  }; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index 0bac0f14edc3..a9221ad9f1a0 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -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,9 +791,9 @@ 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, -						 PCAN_UFD_FLTEXT_CALIBRATION); +		err = pcan_usb_fd_set_options(dev, 1, +					      PUCAN_OPTION_ERROR, +					      PCAN_UFD_FLTEXT_CALIBRATION);  	}  	pdev->usb_if->dev_opened_count++; @@ -806,9 +827,9 @@ 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_UFD_FLTEXT_CALIBRATION); +		pcan_usb_fd_set_options(dev, 0, +					PUCAN_OPTION_ERROR, +					PCAN_UFD_FLTEXT_CALIBRATION);  	pdev->usb_if->dev_opened_count--;  	return 0; @@ -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,9 +964,9 @@ 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_UFD_FLTEXT_CALIBRATION); +			pcan_usb_fd_set_options(dev, 0, +						PUCAN_OPTION_ERROR, +						PCAN_UFD_FLTEXT_CALIBRATION);  		/* tell USB adapter that the driver is being unloaded */  		pcan_usb_fd_drv_loaded(dev, 0); | 
