cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

usb_urb.c (9226B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* usb-urb.c is part of the DVB USB library.
      3 *
      4 * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
      5 * see dvb-usb-init.c for copyright information.
      6 *
      7 * This file keeps functions for initializing and handling the
      8 * BULK and ISOC USB data transfers in a generic way.
      9 * Can be used for DVB-only and also, that's the plan, for
     10 * Hybrid USB devices (analog and DVB).
     11 */
     12#include "dvb_usb_common.h"
     13
     14/* URB stuff for streaming */
     15
     16int usb_urb_reconfig(struct usb_data_stream *stream,
     17		struct usb_data_stream_properties *props);
     18
     19static void usb_urb_complete(struct urb *urb)
     20{
     21	struct usb_data_stream *stream = urb->context;
     22	int ptype = usb_pipetype(urb->pipe);
     23	int i;
     24	u8 *b;
     25
     26	dev_dbg_ratelimited(&stream->udev->dev,
     27			"%s: %s urb completed status=%d length=%d/%d pack_num=%d errors=%d\n",
     28			__func__, ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
     29			urb->status, urb->actual_length,
     30			urb->transfer_buffer_length,
     31			urb->number_of_packets, urb->error_count);
     32
     33	switch (urb->status) {
     34	case 0:         /* success */
     35	case -ETIMEDOUT:    /* NAK */
     36		break;
     37	case -ECONNRESET:   /* kill */
     38	case -ENOENT:
     39	case -ESHUTDOWN:
     40		return;
     41	default:        /* error */
     42		dev_dbg_ratelimited(&stream->udev->dev,
     43				"%s: urb completion failed=%d\n",
     44				__func__, urb->status);
     45		break;
     46	}
     47
     48	b = (u8 *) urb->transfer_buffer;
     49	switch (ptype) {
     50	case PIPE_ISOCHRONOUS:
     51		for (i = 0; i < urb->number_of_packets; i++) {
     52			if (urb->iso_frame_desc[i].status != 0)
     53				dev_dbg(&stream->udev->dev,
     54						"%s: iso frame descriptor has an error=%d\n",
     55						__func__,
     56						urb->iso_frame_desc[i].status);
     57			else if (urb->iso_frame_desc[i].actual_length > 0)
     58				stream->complete(stream,
     59					b + urb->iso_frame_desc[i].offset,
     60					urb->iso_frame_desc[i].actual_length);
     61
     62			urb->iso_frame_desc[i].status = 0;
     63			urb->iso_frame_desc[i].actual_length = 0;
     64		}
     65		break;
     66	case PIPE_BULK:
     67		if (urb->actual_length > 0)
     68			stream->complete(stream, b, urb->actual_length);
     69		break;
     70	default:
     71		dev_err(&stream->udev->dev,
     72				"%s: unknown endpoint type in completion handler\n",
     73				KBUILD_MODNAME);
     74		return;
     75	}
     76	usb_submit_urb(urb, GFP_ATOMIC);
     77}
     78
     79int usb_urb_killv2(struct usb_data_stream *stream)
     80{
     81	int i;
     82	for (i = 0; i < stream->urbs_submitted; i++) {
     83		dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i);
     84		/* stop the URB */
     85		usb_kill_urb(stream->urb_list[i]);
     86	}
     87	stream->urbs_submitted = 0;
     88	return 0;
     89}
     90
     91int usb_urb_submitv2(struct usb_data_stream *stream,
     92		struct usb_data_stream_properties *props)
     93{
     94	int i, ret;
     95
     96	if (props) {
     97		ret = usb_urb_reconfig(stream, props);
     98		if (ret < 0)
     99			return ret;
    100	}
    101
    102	for (i = 0; i < stream->urbs_initialized; i++) {
    103		dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i);
    104		ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC);
    105		if (ret) {
    106			dev_err(&stream->udev->dev,
    107					"%s: could not submit urb no. %d - get them all back\n",
    108					KBUILD_MODNAME, i);
    109			usb_urb_killv2(stream);
    110			return ret;
    111		}
    112		stream->urbs_submitted++;
    113	}
    114	return 0;
    115}
    116
    117static int usb_urb_free_urbs(struct usb_data_stream *stream)
    118{
    119	int i;
    120
    121	usb_urb_killv2(stream);
    122
    123	for (i = stream->urbs_initialized - 1; i >= 0; i--) {
    124		if (stream->urb_list[i]) {
    125			dev_dbg(&stream->udev->dev, "%s: free urb=%d\n",
    126					__func__, i);
    127			/* free the URBs */
    128			usb_free_urb(stream->urb_list[i]);
    129		}
    130	}
    131	stream->urbs_initialized = 0;
    132
    133	return 0;
    134}
    135
    136static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream)
    137{
    138	int i, j;
    139
    140	/* allocate the URBs */
    141	for (i = 0; i < stream->props.count; i++) {
    142		dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
    143		stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
    144		if (!stream->urb_list[i]) {
    145			dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
    146			for (j = 0; j < i; j++)
    147				usb_free_urb(stream->urb_list[j]);
    148			return -ENOMEM;
    149		}
    150		usb_fill_bulk_urb(stream->urb_list[i],
    151				stream->udev,
    152				usb_rcvbulkpipe(stream->udev,
    153						stream->props.endpoint),
    154				stream->buf_list[i],
    155				stream->props.u.bulk.buffersize,
    156				usb_urb_complete, stream);
    157
    158		stream->urbs_initialized++;
    159	}
    160	return 0;
    161}
    162
    163static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream)
    164{
    165	int i, j;
    166
    167	/* allocate the URBs */
    168	for (i = 0; i < stream->props.count; i++) {
    169		struct urb *urb;
    170		int frame_offset = 0;
    171		dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
    172		stream->urb_list[i] = usb_alloc_urb(
    173				stream->props.u.isoc.framesperurb, GFP_ATOMIC);
    174		if (!stream->urb_list[i]) {
    175			dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
    176			for (j = 0; j < i; j++)
    177				usb_free_urb(stream->urb_list[j]);
    178			return -ENOMEM;
    179		}
    180
    181		urb = stream->urb_list[i];
    182
    183		urb->dev = stream->udev;
    184		urb->context = stream;
    185		urb->complete = usb_urb_complete;
    186		urb->pipe = usb_rcvisocpipe(stream->udev,
    187				stream->props.endpoint);
    188		urb->transfer_flags = URB_ISO_ASAP;
    189		urb->interval = stream->props.u.isoc.interval;
    190		urb->number_of_packets = stream->props.u.isoc.framesperurb;
    191		urb->transfer_buffer_length = stream->props.u.isoc.framesize *
    192				stream->props.u.isoc.framesperurb;
    193		urb->transfer_buffer = stream->buf_list[i];
    194
    195		for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
    196			urb->iso_frame_desc[j].offset = frame_offset;
    197			urb->iso_frame_desc[j].length =
    198					stream->props.u.isoc.framesize;
    199			frame_offset += stream->props.u.isoc.framesize;
    200		}
    201
    202		stream->urbs_initialized++;
    203	}
    204	return 0;
    205}
    206
    207static int usb_free_stream_buffers(struct usb_data_stream *stream)
    208{
    209	if (stream->state & USB_STATE_URB_BUF) {
    210		while (stream->buf_num) {
    211			stream->buf_num--;
    212			kfree(stream->buf_list[stream->buf_num]);
    213		}
    214	}
    215
    216	stream->state &= ~USB_STATE_URB_BUF;
    217
    218	return 0;
    219}
    220
    221static int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num,
    222				    unsigned long size)
    223{
    224	stream->buf_num = 0;
    225	stream->buf_size = size;
    226
    227	dev_dbg(&stream->udev->dev,
    228			"%s: all in all I will use %lu bytes for streaming\n",
    229			__func__,  num * size);
    230
    231	for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
    232		stream->buf_list[stream->buf_num] = kzalloc(size, GFP_ATOMIC);
    233		if (!stream->buf_list[stream->buf_num]) {
    234			dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n",
    235					__func__, stream->buf_num);
    236			usb_free_stream_buffers(stream);
    237			return -ENOMEM;
    238		}
    239
    240		dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
    241				__func__, stream->buf_num,
    242				stream->buf_list[stream->buf_num],
    243				(long long)stream->dma_addr[stream->buf_num]);
    244		stream->state |= USB_STATE_URB_BUF;
    245	}
    246
    247	return 0;
    248}
    249
    250int usb_urb_reconfig(struct usb_data_stream *stream,
    251		struct usb_data_stream_properties *props)
    252{
    253	int buf_size;
    254
    255	if (!props)
    256		return 0;
    257
    258	/* check allocated buffers are large enough for the request */
    259	if (props->type == USB_BULK) {
    260		buf_size = stream->props.u.bulk.buffersize;
    261	} else if (props->type == USB_ISOC) {
    262		buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb;
    263	} else {
    264		dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n",
    265				KBUILD_MODNAME, props->type);
    266		return -EINVAL;
    267	}
    268
    269	if (stream->buf_num < props->count || stream->buf_size < buf_size) {
    270		dev_err(&stream->udev->dev,
    271				"%s: cannot reconfigure as allocated buffers are too small\n",
    272				KBUILD_MODNAME);
    273		return -EINVAL;
    274	}
    275
    276	/* check if all fields are same */
    277	if (stream->props.type == props->type &&
    278			stream->props.count == props->count &&
    279			stream->props.endpoint == props->endpoint) {
    280		if (props->type == USB_BULK &&
    281				props->u.bulk.buffersize ==
    282				stream->props.u.bulk.buffersize)
    283			return 0;
    284		else if (props->type == USB_ISOC &&
    285				props->u.isoc.framesperurb ==
    286				stream->props.u.isoc.framesperurb &&
    287				props->u.isoc.framesize ==
    288				stream->props.u.isoc.framesize &&
    289				props->u.isoc.interval ==
    290				stream->props.u.isoc.interval)
    291			return 0;
    292	}
    293
    294	dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__);
    295
    296	usb_urb_free_urbs(stream);
    297	memcpy(&stream->props, props, sizeof(*props));
    298	if (props->type == USB_BULK)
    299		return usb_urb_alloc_bulk_urbs(stream);
    300	else if (props->type == USB_ISOC)
    301		return usb_urb_alloc_isoc_urbs(stream);
    302
    303	return 0;
    304}
    305
    306int usb_urb_initv2(struct usb_data_stream *stream,
    307		const struct usb_data_stream_properties *props)
    308{
    309	int ret;
    310
    311	if (!stream || !props)
    312		return -EINVAL;
    313
    314	memcpy(&stream->props, props, sizeof(*props));
    315
    316	if (!stream->complete) {
    317		dev_err(&stream->udev->dev,
    318				"%s: there is no data callback - this doesn't make sense\n",
    319				KBUILD_MODNAME);
    320		return -EINVAL;
    321	}
    322
    323	switch (stream->props.type) {
    324	case USB_BULK:
    325		ret = usb_alloc_stream_buffers(stream, stream->props.count,
    326				stream->props.u.bulk.buffersize);
    327		if (ret < 0)
    328			return ret;
    329
    330		return usb_urb_alloc_bulk_urbs(stream);
    331	case USB_ISOC:
    332		ret = usb_alloc_stream_buffers(stream, stream->props.count,
    333				stream->props.u.isoc.framesize *
    334				stream->props.u.isoc.framesperurb);
    335		if (ret < 0)
    336			return ret;
    337
    338		return usb_urb_alloc_isoc_urbs(stream);
    339	default:
    340		dev_err(&stream->udev->dev,
    341				"%s: unknown urb-type for data transfer\n",
    342				KBUILD_MODNAME);
    343		return -EINVAL;
    344	}
    345}
    346
    347int usb_urb_exitv2(struct usb_data_stream *stream)
    348{
    349	usb_urb_free_urbs(stream);
    350	usb_free_stream_buffers(stream);
    351
    352	return 0;
    353}