Re: [PATCH 09/26] dibusb: don't do DMA on stack

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

 



On Fri,  7 Oct 2016 14:24:19 -0300
Mauro Carvalho Chehab <mchehab@xxxxxxxxxxxxxxxx> wrote:

> The USB control messages require DMA to work. We cannot pass
> a stack-allocated buffer, as it is not warranted that the
> stack would be into a DMA enabled area.
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab@xxxxxxxxxxxxxxxx>
> ---
>  drivers/media/usb/dvb-usb/dibusb-common.c | 106
> +++++++++++++++++++++---------
> drivers/media/usb/dvb-usb/dibusb.h        |   5 ++ 2 files changed,
> 81 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c
> b/drivers/media/usb/dvb-usb/dibusb-common.c index
> 4b08c2a47ae2..76b26dc7339c 100644 ---
> a/drivers/media/usb/dvb-usb/dibusb-common.c +++
> b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -12,9 +12,6 @@
>  #include <linux/kconfig.h>
>  #include "dibusb.h"
>  
> -/* Max transfer size done by I2C transfer functions */
> -#define MAX_XFER_SIZE  64
> -
>  static int debug;
>  module_param(debug, int, 0644);
>  MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))."
> DVB_USB_DEBUG_STATUS); @@ -63,72 +60,109 @@
> EXPORT_SYMBOL(dibusb_pid_filter_ctrl); 
>  int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff)
>  {
> -	u8 b[3];
> +	u8 *b;
>  	int ret;
> +
> +	b = kmalloc(3, GFP_KERNEL);
> +	if (!b)
> +		return -ENOMEM;
> +
>  	b[0] = DIBUSB_REQ_SET_IOCTL;
>  	b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
>  	b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP :
> DIBUSB_IOCTL_POWER_SLEEP;
> -	ret = dvb_usb_generic_write(d,b,3);
> +
> +	ret = dvb_usb_generic_write(d, b, 3);
> +
> +	kfree(b);
> +
>  	msleep(10);
> +
>  	return ret;
>  }
>  EXPORT_SYMBOL(dibusb_power_ctrl);
>  
>  int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
>  {
> -	u8 b[3] = { 0 };
> +	struct dibusb_state *st = adap->priv;
>  	int ret;
>  
>  	if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0)
>  		return ret;
>  
>  	if (onoff) {
> -		b[0] = DIBUSB_REQ_SET_STREAMING_MODE;
> -		b[1] = 0x00;
> -		if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0)
> +		st->data[0] = DIBUSB_REQ_SET_STREAMING_MODE;
> +		st->data[1] = 0x00;
> +		ret = dvb_usb_generic_write(adap->dev, st->data, 2);
> +		if (ret  < 0)
>  			return ret;
>  	}
>  
> -	b[0] = DIBUSB_REQ_SET_IOCTL;
> -	b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM :
> DIBUSB_IOCTL_CMD_DISABLE_STREAM;
> -	return dvb_usb_generic_write(adap->dev,b,3);
> +	st->data[0] = DIBUSB_REQ_SET_IOCTL;
> +	st->data[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM :
> DIBUSB_IOCTL_CMD_DISABLE_STREAM;
> +	return dvb_usb_generic_write(adap->dev, st->data, 3);
>  }
>  EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
>  
>  int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff)
>  {
> -	if (onoff) {
> -		u8 b[3] = { DIBUSB_REQ_SET_IOCTL,
> DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP };
> -		return dvb_usb_generic_write(d,b,3);
> -	} else
> +	u8 *b;
> +	int ret;
> +
> +	if (!onoff)
>  		return 0;
> +
> +	b = kmalloc(3, GFP_KERNEL);
> +	if (!b)
> +		return -ENOMEM;
> +
> +	b[0] = DIBUSB_REQ_SET_IOCTL;
> +	b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
> +	b[2] = DIBUSB_IOCTL_POWER_WAKEUP;
> +
> +	ret = dvb_usb_generic_write(d, b, 3);
> +
> +	kfree(b);
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(dibusb2_0_power_ctrl);
>  
>  static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr,
>  			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
>  {
> -	u8 sndbuf[MAX_XFER_SIZE]; /* lead(1) devaddr,direction(1)
> addr(2) data(wlen) (len(2) (when reading)) */
> +	u8 *sndbuf;
> +	int ret, wo, len;
> +
>  	/* write only ? */
> -	int wo = (rbuf == NULL || rlen == 0),
> -		len = 2 + wlen + (wo ? 0 : 2);
> +	wo = (rbuf == NULL || rlen == 0);
>  
> -	if (4 + wlen > sizeof(sndbuf)) {
> +	len = 2 + wlen + (wo ? 0 : 2);
> +
> +	sndbuf = kmalloc(MAX_XFER_SIZE, GFP_KERNEL);
> +	if (!sndbuf)
> +		return -ENOMEM;
> +
> +	if (4 + wlen > MAX_XFER_SIZE) {
>  		warn("i2c wr: len=%d is too big!\n", wlen);
> -		return -EOPNOTSUPP;
> +		ret = -EOPNOTSUPP;
> +		goto ret;
>  	}
>  
>  	sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
>  	sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
>  
> -	memcpy(&sndbuf[2],wbuf,wlen);
> +	memcpy(&sndbuf[2], wbuf, wlen);
>  
>  	if (!wo) {
> -		sndbuf[wlen+2] = (rlen >> 8) & 0xff;
> -		sndbuf[wlen+3] = rlen & 0xff;
> +		sndbuf[wlen + 2] = (rlen >> 8) & 0xff;
> +		sndbuf[wlen + 3] = rlen & 0xff;
>  	}
>  
> -	return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0);
> +	ret = dvb_usb_generic_rw(d, sndbuf, len, rbuf, rlen, 0);
> +
> +ret:
> +	kfree(sndbuf);
> +	return ret;
>  }
>  
>  /*
> @@ -320,11 +354,23 @@ EXPORT_SYMBOL(rc_map_dibusb_table);
>  
>  int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
>  {
> -	u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE;
> -	dvb_usb_generic_rw(d,&cmd,1,key,5,0);
> -	dvb_usb_nec_rc_key_to_event(d,key,event,state);
> -	if (key[0] != 0)
> -		deb_info("key: %*ph\n", 5, key);
> +	u8 *buf;
> +
> +	buf = kmalloc(5, GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	buf[0] = DIBUSB_REQ_POLL_REMOTE;
> +
> +	dvb_usb_generic_rw(d, buf, 1, buf, 5, 0);
> +
> +	dvb_usb_nec_rc_key_to_event(d, buf, event, state);
> +
> +	if (buf[0] != 0)
> +		deb_info("key: %*ph\n", 5, buf);
> +
> +	kfree(buf);
> +
>  	return 0;
>  }
>  EXPORT_SYMBOL(dibusb_rc_query);
> diff --git a/drivers/media/usb/dvb-usb/dibusb.h
> b/drivers/media/usb/dvb-usb/dibusb.h index 3f82163d8ab8..42e9750393e5
> 100644 --- a/drivers/media/usb/dvb-usb/dibusb.h
> +++ b/drivers/media/usb/dvb-usb/dibusb.h
> @@ -96,10 +96,15 @@
>  #define DIBUSB_IOCTL_CMD_ENABLE_STREAM	0x01
>  #define DIBUSB_IOCTL_CMD_DISABLE_STREAM	0x02
>  
> +/* Max transfer size done by I2C transfer functions */
> +#define MAX_XFER_SIZE  64
> +
>  struct dibusb_state {
>  	struct dib_fe_xfer_ops ops;
>  	int mt2060_present;
>  	u8 tuner_addr;
> +
> +	unsigned char data[MAX_XFER_SIZE];
>  };
>  
>  struct dibusb_device_state {

Reviewed-By: Patrick Boettcher <patrick.boettcher@xxxxxxxxx>
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux