Re: [PATCH v4] can: usb: IXXAT USB-to-CAN adapters drivers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello Wolfgang,

> > +	ret = ixxat_usb_snd_cmd(dev->udev, port, cmd, snd_size);
> > +	if (ret < 0)
> > +		goto fail;
> > +
> > +	ret = ixxat_usb_rcv_cmd(dev->udev, port, &cmd->res, rcv_size);
> > +	if (ret < 0)
> > +		goto fail;
> > +
> > +	ret = le32_to_cpu(cmd->res.code);
> 
> This pattern repeats five times or more. Could you not handle it by just
> one function?

I will add this in the next patch:

int ixxat_usb_snd_cmd(struct usb_device *dev, const u16 port, void *req,
		      const u16 req_size, void *res, const u16 res_size)
{
	int ret = ixxat_usb_snd_req(dev, port, req, req_size);
	struct ixxat_usb_dal_res *dal_res = res;

	if (ret < 0)
		goto fail;

	ret = ixxat_usb_rcv_res(dev, port, res, res_size);

	if (ret < 0)
		goto fail;

	ret = dal_res->code;

fail:
	return ret;
}

> > +MODULE_DESCRIPTION("CAN driver for IXXAT USB-to-CAN FD adapters");
> 
> The driver is also for non-FD adapters, right?

Yes, I will change it to this:

MODULE_DESCRIPTION("CAN driver for IXXAT USB-to-CAN / CAN FD adapters");

> > +int ixxat_usb_snd_cmd(struct usb_device *dev, const u16 port, void *buf,
> > +		      const u16 size)
> > +{
> > +	const int to = msecs_to_jiffies(IXXAT_USB_MSG_TIMEOUT);
> > +	const u8 rq = 0xff;
> > +	const u8 rt = USB_TYPE_VENDOR | USB_DIR_OUT;
> > +	int i;
> > +	int ret = 0;
> > +	int scp = usb_sndctrlpipe(dev, 0);
> > +
> > +	for (i = 0; i < IXXAT_USB_MAX_COM_REQ; ++i) {
> > +		ret = usb_control_msg(dev, scp, rq, rt, port, 0, buf, size, to);
> > +		if (ret < 0)
> > +			msleep(IXXAT_USB_MSG_CYCLE);
> > +		else
> > +			break;
> > +	}
> > +
> > +	if (ret < 0)
> > +		dev_info(&dev->dev, "Error %d: TX command failure\n", ret);
> 
> dev_info or dev_error?
> 
> > +
> > +	return ret;
> > +}

Oh, I changed this by mistake. It should be dev_error here and also in 
ixxat_usb_rcv_cmd.

> > +static int ixxat_usb_handle_error(struct ixxat_usb_device *dev,
> > +				  struct ixxat_can_msg *rx)
> > +{
> > +	struct net_device *netdev = dev->netdev;
> > +	struct can_frame *can_frame;
> > +	struct sk_buff *skb = alloc_can_err_skb(netdev, &can_frame);
> > +	u8 raw_error;
> > +
> > +	if (dev->adapter == &usb2can_cl1) {
> > +		raw_error = rx->cl1.data[0];
> > +		dev->bec.rxerr = rx->cl1.data[3];
> > +		dev->bec.txerr = rx->cl1.data[4];
> > +	} else {
> > +		raw_error = rx->cl2.data[0];
> > +		dev->bec.rxerr = rx->cl2.data[3];
> > +		dev->bec.txerr = rx->cl2.data[4];
> > +	}
> 
> Hm, do the lines avove make sense also if "dev->can.state ==
> CAN_STATE_BUS_OFF"?
>
> > +
> > +	if (dev->can.state == CAN_STATE_BUS_OFF)
> > +		return 0;
> > +
> > +	if (!skb)
> > +		return -ENOMEM;
> 
> Could you please do the "alloc_can_err_skb()" just before these two
> lines... otherwise the skb might not be freed.

I will fix this in the next patch.

> > +static void ixxat_usb_read_bulk(struct urb *urb)
> > +{
> > +	struct ixxat_usb_device *dev = urb->context;
> > +	const struct ixxat_usb_adapter *adapter = dev->adapter;
> > +	struct net_device *netdev = dev->netdev;
> > +	struct usb_device *udev = dev->udev;
> > +	int err;
> > +
> > +	if (!netif_device_present(netdev))
> > +		return;
> > +
> > +	switch (urb->status) {
> > +	case 0: /* success */
> > +		break;
> > +	case -EPROTO:
> > +	case -EILSEQ:
> > +	case -ENOENT:
> > +	case -ECONNRESET:
> > +	case -ESHUTDOWN:
> > +		return;
> > +	default:
> > +		netdev_err(netdev, "Rx urb aborted /(%d)\n", urb->status);
> > +		goto resubmit_urb;
> > +	}
> > +
> > +	if (urb->actual_length > 0)
> > +		if (dev->state & IXXAT_USB_STATE_STARTED)
> > +			err = ixxat_usb_decode_buf(urb);
> 
> "err" not handled!
>

ixxat_usb_decode_buf prints error messages if something fails and this is 
all we can do here. I will change ixxat_usb_decode_buf to a void function:

static void ixxat_usb_decode_buf(struct urb *urb)

> > +
> > +resubmit_urb:
> > +	usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, dev->ep_msg_in),
> > +			  urb->transfer_buffer, adapter->buffer_size_rx,
> > +			  ixxat_usb_read_bulk, dev);
> > +
> > +	usb_anchor_urb(urb, &dev->rx_submitted);
> > +	err = usb_submit_urb(urb, GFP_ATOMIC);
> > +	if (!err)
> > +		return;
> 
> Do you need "usb_unanchor_urb()" in case of return?

Wouldn't this stop the system from keeping track of the urb (and we won't 
get an ixxat_usb_read_bulk callback)?

> 
> > +
> > +	usb_unanchor_urb(urb);
> > +
> > +	if (err == -ENODEV)
> > +		netif_device_detach(netdev);
> > +	else
> > +		netdev_err(netdev,
> > +			   "Error %d: Failed to resubmit read bulk urb\n", err);
> > +}
> > +
> > +static void ixxat_usb_write_bulk(struct urb *urb)
> > +{
> > +	struct ixxat_tx_urb_context *context = urb->context;
> > +	struct ixxat_usb_device *dev;
> > +	struct net_device *netdev;
> > +
> > +	if (WARN_ON(!context))
> > +		return;
> > +
> > +	dev = context->dev;
> > +	netdev = dev->netdev;
> 
> Could be assigned after the if case below.
> 
> > +	atomic_dec(&dev->active_tx_urbs);
> > +
> > +	if (!netif_device_present(netdev))
> > +		return;

Only if we change the if case to this:

if (!netif_device_present(context->dev->netdev))

Is this what you suggest?

> > +     if (!urb->status) {
> > +             netdev->stats.tx_packets += context->count;
> > +             netdev->stats.tx_bytes += context->dlc;
> > +     } else {
> > +             netdev_err(netdev, "Error %d: Tx urb aborted\n", urb->status);
> > +     }
> > +
> > +     can_get_echo_skb(netdev, context->echo_index);
> > +     context->echo_index = IXXAT_USB_MAX_TX_URBS;
> > +
> > +     if (!urb->status)
> > +             netif_wake_queue(netdev);
> > +}

I found another flaw here. In the next patch I will move the
"atomic_dec(&dev->active_tx_urbs)" right afer the
"context->echo_index = IXXAT_USB_MAX_TX_URBS".
Otherwise it could happen that when the ixxat_usb_start_xmit function 
interrupts the ixxat_usb_write_bulk callback, the active_tx_urbs counter 
is decremented but the context isnt marked free yet.

> > +static void ixxat_usb_encode_msg(struct ixxat_usb_device *dev,
> > +				 struct sk_buff *skb, u8 *obuf,
> > +				 size_t *size)
> > +{
> > +	struct canfd_frame *cf = (struct canfd_frame *)skb->data;
> > +	struct ixxat_can_msg can_msg = {0};
> > +	struct ixxat_can_msg_base *msg_base = &can_msg.base;
> > +
> > +	if (cf->can_id & CAN_RTR_FLAG)
> > +		msg_base->flags |= IXXAT_USB_MSG_FLAGS_RTR;
> > +
> > +	if (cf->can_id & CAN_EFF_FLAG) {
> > +		msg_base->flags |= IXXAT_USB_MSG_FLAGS_EXT;
> > +		msg_base->msg_id = cf->can_id & CAN_EFF_MASK;
> > +	} else {
> > +		msg_base->msg_id = cf->can_id & CAN_SFF_MASK;
> > +	}
> > +
> > +	if (can_is_canfd_skb(skb)) {
> > +		msg_base->flags |= IXXAT_USB_FDMSG_FLAGS_EDL;
> > +
> > +		if (!(cf->can_id & CAN_RTR_FLAG) && (cf->flags & CANFD_BRS))
> > +			msg_base->flags |= IXXAT_USB_FDMSG_FLAGS_FDR;
> > +
> > +		msg_base->flags |= IXXAT_USB_ENCODE_DLC(can_len2dlc(cf->len));
> > +	} else {
> > +		msg_base->flags |= IXXAT_USB_ENCODE_DLC(cf->len);
> > +	}
> > +
> > +	le32_to_cpus(&msg_base->flags);
> > +	le32_to_cpus(&msg_base->msg_id);
> > +
> > +	msg_base->size = (u8)(sizeof(*msg_base) - 1);
> 
> To save two lines in the if case, why not:
> 
> 	msg_base->size = (u8)(sizeof(*msg_base) - 1 +  cf->len);
> 
> > +	if (dev->adapter == &usb2can_cl1) {
> > +		msg_base->size += (u8)(sizeof(can_msg.cl1) - CAN_MAX_DLEN);
> > +		msg_base->size += cf->len;
> > +		memcpy(can_msg.cl1.data, cf->data, cf->len);
> > +	} else {
> > +		msg_base->size += (u8)(sizeof(can_msg.cl2) - CANFD_MAX_DLEN);
> > +		msg_base->size += cf->len;
> > +		memcpy(can_msg.cl2.data, cf->data, cf->len);
> > +	}

I will fix this in the next patch.

> > +
> > +	*size = msg_base->size + 1;
> > +	memcpy(obuf, &can_msg, *size);
> > +	skb->data_len = *size;
> 
> Why do you modify the skb here?
> 
> > +}

This is not necessary. I will remove this in the next patch.

> > +static netdev_tx_t ixxat_usb_start_xmit(struct sk_buff *skb,
> > +					struct net_device *netdev)
> > +{
> > +	struct ixxat_usb_device *dev = netdev_priv(netdev);
> > +	struct ixxat_tx_urb_context *context = NULL;
> > +	struct net_device_stats *stats = &netdev->stats;
> > +	struct canfd_frame *cf = (struct canfd_frame *)skb->data;
> > +	struct urb *urb;
> > +	u8 *obuf;
> > +	int i;
> > +	int err;
> > +	size_t size = dev->adapter->buffer_size_tx;
> > +
> > +	if (can_dropped_invalid_skb(netdev, skb))
> > +		return NETDEV_TX_OK;
> > +
> > +	for (i = 0; i < IXXAT_USB_MAX_TX_URBS; i++) {
> > +		if (dev->tx_contexts[i].echo_index == IXXAT_USB_MAX_TX_URBS) {
> > +			context = dev->tx_contexts + i;
> > +			break;
> > +		}
> > +	}
> > +
> > +	if (WARN_ON_ONCE(!context))
> > +		return NETDEV_TX_BUSY;
> > +
> > +	urb = context->urb;
> > +	obuf = urb->transfer_buffer;
> > +
> > +	ixxat_usb_encode_msg(dev, skb, obuf, &size);
> > +
> > +	context->echo_index = i;
> > +	context->dlc = cf->len;
> > +	context->count = 1;
> > +
> > +	urb->transfer_buffer_length = size;
> > +	usb_anchor_urb(urb, &dev->tx_submitted);
> > +	can_put_echo_skb(skb, netdev, context->echo_index);
> > +	atomic_inc(&dev->active_tx_urbs);
> > +
> > +	err = usb_submit_urb(urb, GFP_ATOMIC);
> > +	if (unlikely(err)) {
> 
> You use "unlikely" just once!
> 
> > +		can_free_echo_skb(netdev, context->echo_index);
> > +		usb_unanchor_urb(urb);
> > +		atomic_dec(&dev->active_tx_urbs);
> > +
> > +		context->echo_index = IXXAT_USB_MAX_TX_URBS;
> > +
> > +		if (err == -ENODEV) {
> > +			netif_device_detach(netdev);
> > +		} else {
> > +			stats->tx_dropped++;
> > +			netdev_err(netdev,
> > +				   "Error %d: Submitting tx-urb failed\n", err);
> > +		}
> > +	} else {
> > +		if (atomic_read(&dev->active_tx_urbs) >= IXXAT_USB_MAX_TX_URBS)
> > +			netif_stop_queue(netdev);
> > +	}
> > +
> > +	return NETDEV_TX_OK;
> > +}

The "unlikely" macro isn't really necessary. Would you suggest to use it 
wherever a condition is unexpected or should we just remove it here?

> > +static int ixxat_usb_setup_tx_urbs(struct ixxat_usb_device *dev)
> > +{
> > +	int i;
> > +	int ret = 0;
> > +	const struct ixxat_usb_adapter *adapter = dev->adapter;
> > +	struct net_device *netdev = dev->netdev;
> > +	struct usb_device *udev = dev->udev;
> > +
> > +	for (i = 0; i < IXXAT_USB_MAX_TX_URBS; i++) {
> > +		struct ixxat_tx_urb_context *context;
> > +		struct urb *urb = NULL;
> > +		u8 *buf = NULL;
> 
> Preinitialisation not needed!

Will be fixed in the next patch.

Thank you very much for helping us to get the driver in proper shape!

Florian
--
To unsubscribe from this list: send the line "unsubscribe linux-can" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux