brintos

brintos / linux-shallow public Read only

0
0
Text · 15.2 KiB · 1888ca1 Raw
508 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces.4 *5 * File es581_4.c: Adds support to ETAS ES581.4.6 *7 * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.8 * Copyright (c) 2020 ETAS K.K.. All rights reserved.9 * Copyright (c) 2020-2022 Vincent Mailhol <mailhol.vincent@wanadoo.fr>10 */11 12#include <linux/unaligned.h>13#include <linux/kernel.h>14#include <linux/units.h>15 16#include "es58x_core.h"17#include "es581_4.h"18 19/**20 * es581_4_sizeof_rx_tx_msg() - Calculate the actual length of the21 *	structure of a rx or tx message.22 * @msg: message of variable length, must have a dlc field.23 *24 * Even if RTR frames have actually no payload, the ES58X devices25 * still expect it. Must be a macro in order to accept several types26 * (struct es581_4_tx_can_msg and struct es581_4_rx_can_msg) as an27 * input.28 *29 * Return: length of the message.30 */31#define es581_4_sizeof_rx_tx_msg(msg)				\32	offsetof(typeof(msg), data[can_cc_dlc2len((msg).dlc)])33 34static u16 es581_4_get_msg_len(const union es58x_urb_cmd *urb_cmd)35{36	return get_unaligned_le16(&urb_cmd->es581_4_urb_cmd.msg_len);37}38 39static int es581_4_echo_msg(struct es58x_device *es58x_dev,40			    const struct es581_4_urb_cmd *es581_4_urb_cmd)41{42	struct net_device *netdev;43	const struct es581_4_bulk_echo_msg *bulk_echo_msg;44	const struct es581_4_echo_msg *echo_msg;45	u64 *tstamps = es58x_dev->timestamps;46	u16 msg_len;47	u32 first_packet_idx, packet_idx;48	unsigned int dropped = 0;49	int i, num_element, ret;50 51	bulk_echo_msg = &es581_4_urb_cmd->bulk_echo_msg;52	msg_len = get_unaligned_le16(&es581_4_urb_cmd->msg_len) -53	    sizeof(bulk_echo_msg->channel_no);54	num_element = es58x_msg_num_element(es58x_dev->dev,55					    bulk_echo_msg->echo_msg, msg_len);56	if (num_element <= 0)57		return num_element;58 59	ret = es58x_get_netdev(es58x_dev, bulk_echo_msg->channel_no,60			       ES581_4_CHANNEL_IDX_OFFSET, &netdev);61	if (ret)62		return ret;63 64	echo_msg = &bulk_echo_msg->echo_msg[0];65	first_packet_idx = get_unaligned_le32(&echo_msg->packet_idx);66	packet_idx = first_packet_idx;67	for (i = 0; i < num_element; i++) {68		u32 tmp_idx;69 70		echo_msg = &bulk_echo_msg->echo_msg[i];71		tmp_idx = get_unaligned_le32(&echo_msg->packet_idx);72		if (tmp_idx == packet_idx - 1) {73			if (net_ratelimit())74				netdev_warn(netdev,75					    "Received echo packet idx %u twice\n",76					    packet_idx - 1);77			dropped++;78			continue;79		}80		if (tmp_idx != packet_idx) {81			netdev_err(netdev, "Echo packet idx jumped from %u to %u\n",82				   packet_idx - 1, echo_msg->packet_idx);83			return -EBADMSG;84		}85 86		tstamps[i] = get_unaligned_le64(&echo_msg->timestamp);87		packet_idx++;88	}89 90	netdev->stats.tx_dropped += dropped;91	return es58x_can_get_echo_skb(netdev, first_packet_idx,92				      tstamps, num_element - dropped);93}94 95static int es581_4_rx_can_msg(struct es58x_device *es58x_dev,96			      const struct es581_4_urb_cmd *es581_4_urb_cmd,97			      u16 msg_len)98{99	const struct device *dev = es58x_dev->dev;100	struct net_device *netdev;101	int pkts, num_element, channel_no, ret;102 103	num_element = es58x_msg_num_element(dev, es581_4_urb_cmd->rx_can_msg,104					    msg_len);105	if (num_element <= 0)106		return num_element;107 108	channel_no = es581_4_urb_cmd->rx_can_msg[0].channel_no;109	ret = es58x_get_netdev(es58x_dev, channel_no,110			       ES581_4_CHANNEL_IDX_OFFSET, &netdev);111	if (ret)112		return ret;113 114	if (!netif_running(netdev)) {115		if (net_ratelimit())116			netdev_info(netdev,117				    "%s: %s is down, dropping %d rx packets\n",118				    __func__, netdev->name, num_element);119		netdev->stats.rx_dropped += num_element;120		return 0;121	}122 123	for (pkts = 0; pkts < num_element; pkts++) {124		const struct es581_4_rx_can_msg *rx_can_msg =125		    &es581_4_urb_cmd->rx_can_msg[pkts];126		u64 tstamp = get_unaligned_le64(&rx_can_msg->timestamp);127		canid_t can_id = get_unaligned_le32(&rx_can_msg->can_id);128 129		if (channel_no != rx_can_msg->channel_no)130			return -EBADMSG;131 132		ret = es58x_rx_can_msg(netdev, tstamp, rx_can_msg->data,133				       can_id, rx_can_msg->flags,134				       rx_can_msg->dlc);135		if (ret)136			break;137	}138 139	return ret;140}141 142static int es581_4_rx_err_msg(struct es58x_device *es58x_dev,143			      const struct es581_4_rx_err_msg *rx_err_msg)144{145	struct net_device *netdev;146	enum es58x_err error = get_unaligned_le32(&rx_err_msg->error);147	int ret;148 149	ret = es58x_get_netdev(es58x_dev, rx_err_msg->channel_no,150			       ES581_4_CHANNEL_IDX_OFFSET, &netdev);151	if (ret)152		return ret;153 154	return es58x_rx_err_msg(netdev, error, 0,155				get_unaligned_le64(&rx_err_msg->timestamp));156}157 158static int es581_4_rx_event_msg(struct es58x_device *es58x_dev,159				const struct es581_4_rx_event_msg *rx_event_msg)160{161	struct net_device *netdev;162	enum es58x_event event = get_unaligned_le32(&rx_event_msg->event);163	int ret;164 165	ret = es58x_get_netdev(es58x_dev, rx_event_msg->channel_no,166			       ES581_4_CHANNEL_IDX_OFFSET, &netdev);167	if (ret)168		return ret;169 170	return es58x_rx_err_msg(netdev, 0, event,171				get_unaligned_le64(&rx_event_msg->timestamp));172}173 174static int es581_4_rx_cmd_ret_u32(struct es58x_device *es58x_dev,175				  const struct es581_4_urb_cmd *es581_4_urb_cmd,176				  enum es58x_ret_type ret_type)177{178	struct net_device *netdev;179	const struct es581_4_rx_cmd_ret *rx_cmd_ret;180	u16 msg_len = get_unaligned_le16(&es581_4_urb_cmd->msg_len);181	int ret;182 183	ret = es58x_check_msg_len(es58x_dev->dev,184				  es581_4_urb_cmd->rx_cmd_ret, msg_len);185	if (ret)186		return ret;187 188	rx_cmd_ret = &es581_4_urb_cmd->rx_cmd_ret;189 190	ret = es58x_get_netdev(es58x_dev, rx_cmd_ret->channel_no,191			       ES581_4_CHANNEL_IDX_OFFSET, &netdev);192	if (ret)193		return ret;194 195	return es58x_rx_cmd_ret_u32(netdev, ret_type,196				    get_unaligned_le32(&rx_cmd_ret->rx_cmd_ret_le32));197}198 199static int es581_4_tx_ack_msg(struct es58x_device *es58x_dev,200			      const struct es581_4_urb_cmd *es581_4_urb_cmd)201{202	struct net_device *netdev;203	const struct es581_4_tx_ack_msg *tx_ack_msg;204	u16 msg_len = get_unaligned_le16(&es581_4_urb_cmd->msg_len);205	int ret;206 207	tx_ack_msg = &es581_4_urb_cmd->tx_ack_msg;208	ret = es58x_check_msg_len(es58x_dev->dev, *tx_ack_msg, msg_len);209	if (ret)210		return ret;211 212	if (tx_ack_msg->rx_cmd_ret_u8 != ES58X_RET_U8_OK)213		return es58x_rx_cmd_ret_u8(es58x_dev->dev,214					   ES58X_RET_TYPE_TX_MSG,215					   tx_ack_msg->rx_cmd_ret_u8);216 217	ret = es58x_get_netdev(es58x_dev, tx_ack_msg->channel_no,218			       ES581_4_CHANNEL_IDX_OFFSET, &netdev);219	if (ret)220		return ret;221 222	return es58x_tx_ack_msg(netdev,223				get_unaligned_le16(&tx_ack_msg->tx_free_entries),224				ES58X_RET_U32_OK);225}226 227static int es581_4_dispatch_rx_cmd(struct es58x_device *es58x_dev,228				   const struct es581_4_urb_cmd *es581_4_urb_cmd)229{230	const struct device *dev = es58x_dev->dev;231	u16 msg_len = get_unaligned_le16(&es581_4_urb_cmd->msg_len);232	enum es581_4_rx_type rx_type = es581_4_urb_cmd->rx_can_msg[0].rx_type;233	int ret = 0;234 235	switch (rx_type) {236	case ES581_4_RX_TYPE_MESSAGE:237		return es581_4_rx_can_msg(es58x_dev, es581_4_urb_cmd, msg_len);238 239	case ES581_4_RX_TYPE_ERROR:240		ret = es58x_check_msg_len(dev, es581_4_urb_cmd->rx_err_msg,241					  msg_len);242		if (ret < 0)243			return ret;244		return es581_4_rx_err_msg(es58x_dev,245					  &es581_4_urb_cmd->rx_err_msg);246 247	case ES581_4_RX_TYPE_EVENT:248		ret = es58x_check_msg_len(dev, es581_4_urb_cmd->rx_event_msg,249					  msg_len);250		if (ret < 0)251			return ret;252		return es581_4_rx_event_msg(es58x_dev,253					    &es581_4_urb_cmd->rx_event_msg);254 255	default:256		dev_err(dev, "%s: Unknown rx_type 0x%02X\n", __func__, rx_type);257		return -EBADRQC;258	}259}260 261static int es581_4_handle_urb_cmd(struct es58x_device *es58x_dev,262				  const union es58x_urb_cmd *urb_cmd)263{264	const struct es581_4_urb_cmd *es581_4_urb_cmd;265	struct device *dev = es58x_dev->dev;266	u16 msg_len = es581_4_get_msg_len(urb_cmd);267	int ret;268 269	es581_4_urb_cmd = &urb_cmd->es581_4_urb_cmd;270 271	if (es581_4_urb_cmd->cmd_type != ES581_4_CAN_COMMAND_TYPE) {272		dev_err(dev, "%s: Unknown command type (0x%02X)\n",273			__func__, es581_4_urb_cmd->cmd_type);274		return -EBADRQC;275	}276 277	switch ((enum es581_4_cmd_id)es581_4_urb_cmd->cmd_id) {278	case ES581_4_CMD_ID_SET_BITTIMING:279		return es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,280					      ES58X_RET_TYPE_SET_BITTIMING);281 282	case ES581_4_CMD_ID_ENABLE_CHANNEL:283		return es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,284					      ES58X_RET_TYPE_ENABLE_CHANNEL);285 286	case ES581_4_CMD_ID_TX_MSG:287		return es581_4_tx_ack_msg(es58x_dev, es581_4_urb_cmd);288 289	case ES581_4_CMD_ID_RX_MSG:290		return es581_4_dispatch_rx_cmd(es58x_dev, es581_4_urb_cmd);291 292	case ES581_4_CMD_ID_RESET_RX:293		ret = es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,294					     ES58X_RET_TYPE_RESET_RX);295		return ret;296 297	case ES581_4_CMD_ID_RESET_TX:298		ret = es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,299					     ES58X_RET_TYPE_RESET_TX);300		return ret;301 302	case ES581_4_CMD_ID_DISABLE_CHANNEL:303		return es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,304					      ES58X_RET_TYPE_DISABLE_CHANNEL);305 306	case ES581_4_CMD_ID_TIMESTAMP:307		ret = es58x_check_msg_len(dev, es581_4_urb_cmd->timestamp,308					  msg_len);309		if (ret < 0)310			return ret;311		es58x_rx_timestamp(es58x_dev,312				   get_unaligned_le64(&es581_4_urb_cmd->timestamp));313		return 0;314 315	case ES581_4_CMD_ID_ECHO:316		return es581_4_echo_msg(es58x_dev, es581_4_urb_cmd);317 318	case ES581_4_CMD_ID_DEVICE_ERR:319		ret = es58x_check_msg_len(dev, es581_4_urb_cmd->rx_cmd_ret_u8,320					  msg_len);321		if (ret)322			return ret;323		return es58x_rx_cmd_ret_u8(dev, ES58X_RET_TYPE_DEVICE_ERR,324					   es581_4_urb_cmd->rx_cmd_ret_u8);325 326	default:327		dev_warn(dev, "%s: Unexpected command ID: 0x%02X\n",328			 __func__, es581_4_urb_cmd->cmd_id);329		return -EBADRQC;330	}331}332 333static void es581_4_fill_urb_header(union es58x_urb_cmd *urb_cmd, u8 cmd_type,334				    u8 cmd_id, u8 channel_idx, u16 msg_len)335{336	struct es581_4_urb_cmd *es581_4_urb_cmd = &urb_cmd->es581_4_urb_cmd;337 338	es581_4_urb_cmd->SOF = cpu_to_le16(es581_4_param.tx_start_of_frame);339	es581_4_urb_cmd->cmd_type = cmd_type;340	es581_4_urb_cmd->cmd_id = cmd_id;341	es581_4_urb_cmd->msg_len = cpu_to_le16(msg_len);342}343 344static int es581_4_tx_can_msg(struct es58x_priv *priv,345			      const struct sk_buff *skb)346{347	struct es58x_device *es58x_dev = priv->es58x_dev;348	union es58x_urb_cmd *urb_cmd = priv->tx_urb->transfer_buffer;349	struct es581_4_urb_cmd *es581_4_urb_cmd = &urb_cmd->es581_4_urb_cmd;350	struct can_frame *cf = (struct can_frame *)skb->data;351	struct es581_4_tx_can_msg *tx_can_msg;352	u16 msg_len;353	int ret;354 355	if (can_is_canfd_skb(skb))356		return -EMSGSIZE;357 358	if (priv->tx_can_msg_cnt == 0) {359		msg_len = sizeof(es581_4_urb_cmd->bulk_tx_can_msg.num_can_msg);360		es581_4_fill_urb_header(urb_cmd, ES581_4_CAN_COMMAND_TYPE,361					ES581_4_CMD_ID_TX_MSG,362					priv->channel_idx, msg_len);363		es581_4_urb_cmd->bulk_tx_can_msg.num_can_msg = 0;364	} else {365		msg_len = es581_4_get_msg_len(urb_cmd);366	}367 368	ret = es58x_check_msg_max_len(es58x_dev->dev,369				      es581_4_urb_cmd->bulk_tx_can_msg,370				      msg_len + sizeof(*tx_can_msg));371	if (ret)372		return ret;373 374	/* Fill message contents. */375	tx_can_msg = (typeof(tx_can_msg))&es581_4_urb_cmd->raw_msg[msg_len];376	put_unaligned_le32(es58x_get_raw_can_id(cf), &tx_can_msg->can_id);377	put_unaligned_le32(priv->tx_head, &tx_can_msg->packet_idx);378	put_unaligned_le16((u16)es58x_get_flags(skb), &tx_can_msg->flags);379	tx_can_msg->channel_no = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET;380	tx_can_msg->dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);381 382	memcpy(tx_can_msg->data, cf->data, cf->len);383 384	/* Calculate new sizes. */385	es581_4_urb_cmd->bulk_tx_can_msg.num_can_msg++;386	msg_len += es581_4_sizeof_rx_tx_msg(*tx_can_msg);387	priv->tx_urb->transfer_buffer_length = es58x_get_urb_cmd_len(es58x_dev,388								     msg_len);389	es581_4_urb_cmd->msg_len = cpu_to_le16(msg_len);390 391	return 0;392}393 394static int es581_4_set_bittiming(struct es58x_priv *priv)395{396	struct es581_4_tx_conf_msg tx_conf_msg = { 0 };397	struct can_bittiming *bt = &priv->can.bittiming;398 399	tx_conf_msg.bitrate = cpu_to_le32(bt->bitrate);400	/* bt->sample_point is in tenth of percent. Convert it to percent. */401	tx_conf_msg.sample_point = cpu_to_le32(bt->sample_point / 10U);402	tx_conf_msg.samples_per_bit = cpu_to_le32(ES58X_SAMPLES_PER_BIT_ONE);403	tx_conf_msg.bit_time = cpu_to_le32(can_bit_time(bt));404	tx_conf_msg.sjw = cpu_to_le32(bt->sjw);405	tx_conf_msg.sync_edge = cpu_to_le32(ES58X_SYNC_EDGE_SINGLE);406	tx_conf_msg.physical_layer =407	    cpu_to_le32(ES58X_PHYSICAL_LAYER_HIGH_SPEED);408	tx_conf_msg.echo_mode = cpu_to_le32(ES58X_ECHO_ON);409	tx_conf_msg.channel_no = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET;410 411	return es58x_send_msg(priv->es58x_dev, ES581_4_CAN_COMMAND_TYPE,412			      ES581_4_CMD_ID_SET_BITTIMING, &tx_conf_msg,413			      sizeof(tx_conf_msg), priv->channel_idx);414}415 416static int es581_4_enable_channel(struct es58x_priv *priv)417{418	int ret;419	u8 msg = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET;420 421	ret = es581_4_set_bittiming(priv);422	if (ret)423		return ret;424 425	return es58x_send_msg(priv->es58x_dev, ES581_4_CAN_COMMAND_TYPE,426			      ES581_4_CMD_ID_ENABLE_CHANNEL, &msg, sizeof(msg),427			      priv->channel_idx);428}429 430static int es581_4_disable_channel(struct es58x_priv *priv)431{432	u8 msg = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET;433 434	return es58x_send_msg(priv->es58x_dev, ES581_4_CAN_COMMAND_TYPE,435			      ES581_4_CMD_ID_DISABLE_CHANNEL, &msg, sizeof(msg),436			      priv->channel_idx);437}438 439static int es581_4_reset_device(struct es58x_device *es58x_dev)440{441	return es58x_send_msg(es58x_dev, ES581_4_CAN_COMMAND_TYPE,442			      ES581_4_CMD_ID_RESET_DEVICE,443			      ES58X_EMPTY_MSG, 0, ES58X_CHANNEL_IDX_NA);444}445 446static int es581_4_get_timestamp(struct es58x_device *es58x_dev)447{448	return es58x_send_msg(es58x_dev, ES581_4_CAN_COMMAND_TYPE,449			      ES581_4_CMD_ID_TIMESTAMP,450			      ES58X_EMPTY_MSG, 0, ES58X_CHANNEL_IDX_NA);451}452 453/* Nominal bittiming constants for ES581.4 as specified in the454 * microcontroller datasheet: "Stellaris(R) LM3S5B91 Microcontroller"455 * table 17-4 "CAN Protocol Ranges" from Texas Instruments.456 */457static const struct can_bittiming_const es581_4_bittiming_const = {458	.name = "ES581.4",459	.tseg1_min = 1,460	.tseg1_max = 8,461	.tseg2_min = 1,462	.tseg2_max = 8,463	.sjw_max = 4,464	.brp_min = 1,465	.brp_max = 128,466	.brp_inc = 1467};468 469const struct es58x_parameters es581_4_param = {470	.bittiming_const = &es581_4_bittiming_const,471	.data_bittiming_const = NULL,472	.tdc_const = NULL,473	.bitrate_max = 1 * MEGA /* BPS */,474	.clock = {.freq = 50 * MEGA /* Hz */},475	.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC,476	.tx_start_of_frame = 0xAFAF,477	.rx_start_of_frame = 0xFAFA,478	.tx_urb_cmd_max_len = ES581_4_TX_URB_CMD_MAX_LEN,479	.rx_urb_cmd_max_len = ES581_4_RX_URB_CMD_MAX_LEN,480	/* Size of internal device TX queue is 330.481	 *482	 * However, we witnessed some ES58X_ERR_PROT_CRC errors from483	 * the device and thus, echo_skb_max was lowered to the484	 * empirical value of 75 which seems stable and then rounded485	 * down to become a power of two.486	 *487	 * Root cause of those ES58X_ERR_PROT_CRC errors is still488	 * unclear.489	 */490	.fifo_mask = 63, /* echo_skb_max = 64 */491	.dql_min_limit = CAN_FRAME_LEN_MAX * 50, /* Empirical value. */492	.tx_bulk_max = ES581_4_TX_BULK_MAX,493	.urb_cmd_header_len = ES581_4_URB_CMD_HEADER_LEN,494	.rx_urb_max = ES58X_RX_URBS_MAX,495	.tx_urb_max = ES58X_TX_URBS_MAX496};497 498const struct es58x_operators es581_4_ops = {499	.get_msg_len = es581_4_get_msg_len,500	.handle_urb_cmd = es581_4_handle_urb_cmd,501	.fill_urb_header = es581_4_fill_urb_header,502	.tx_can_msg = es581_4_tx_can_msg,503	.enable_channel = es581_4_enable_channel,504	.disable_channel = es581_4_disable_channel,505	.reset_device = es581_4_reset_device,506	.get_timestamp = es581_4_get_timestamp507};508