Commit 564246fd authored by Tomoki Sekiyama's avatar Tomoki Sekiyama Committed by Mauro Carvalho Chehab

media: siano: Fix coherent memory allocation failure on arm64

On some architectures such as arm64, siano chip based TV-tuner
USB devices are not recognized correctly due to coherent memory
allocation failure with the following error:

[  663.556135] usbcore: deregistering interface driver smsusb
[  683.624809] smsusb:smsusb_probe: board id=18, interface number 0
[  683.633530] smsusb:smsusb_init_device: smscore_register_device(...) failed, rc -12
[  683.641501] smsusb:smsusb_probe: Device initialized with return code -12
[  683.652978] smsusb: probe of 1-1:1.0 failed with error -12

This is caused by dma_alloc_coherent(NULL, ...) returning NULL in
smscoreapi.c.

To fix this error, allocate the buffer memory for the USB devices
via kmalloc() and let the USB core do the DMA mapping and free.
Signed-off-by: default avatarTomoki Sekiyama <tomoki.sekiyama@gmail.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent e97c1907
...@@ -631,7 +631,8 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, ...@@ -631,7 +631,8 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
cb->p = buffer; cb->p = buffer;
cb->offset_in_common = buffer - (u8 *) common_buffer; cb->offset_in_common = buffer - (u8 *) common_buffer;
cb->phys = common_buffer_phys + cb->offset_in_common; if (common_buffer_phys)
cb->phys = common_buffer_phys + cb->offset_in_common;
return cb; return cb;
} }
...@@ -690,17 +691,21 @@ int smscore_register_device(struct smsdevice_params_t *params, ...@@ -690,17 +691,21 @@ int smscore_register_device(struct smsdevice_params_t *params,
/* alloc common buffer */ /* alloc common buffer */
dev->common_buffer_size = params->buffer_size * params->num_buffers; dev->common_buffer_size = params->buffer_size * params->num_buffers;
dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size, if (params->usb_device)
&dev->common_buffer_phys, buffer = kzalloc(dev->common_buffer_size, GFP_KERNEL);
GFP_KERNEL | GFP_DMA); else
if (!dev->common_buffer) { buffer = dma_alloc_coherent(params->device,
dev->common_buffer_size,
&dev->common_buffer_phys,
GFP_KERNEL | GFP_DMA);
if (!buffer) {
smscore_unregister_device(dev); smscore_unregister_device(dev);
return -ENOMEM; return -ENOMEM;
} }
dev->common_buffer = buffer;
/* prepare dma buffers */ /* prepare dma buffers */
for (buffer = dev->common_buffer; for (; dev->num_buffers < params->num_buffers;
dev->num_buffers < params->num_buffers;
dev->num_buffers++, buffer += params->buffer_size) { dev->num_buffers++, buffer += params->buffer_size) {
struct smscore_buffer_t *cb; struct smscore_buffer_t *cb;
...@@ -720,6 +725,7 @@ int smscore_register_device(struct smsdevice_params_t *params, ...@@ -720,6 +725,7 @@ int smscore_register_device(struct smsdevice_params_t *params,
dev->board_id = SMS_BOARD_UNKNOWN; dev->board_id = SMS_BOARD_UNKNOWN;
dev->context = params->context; dev->context = params->context;
dev->device = params->device; dev->device = params->device;
dev->usb_device = params->usb_device;
dev->setmode_handler = params->setmode_handler; dev->setmode_handler = params->setmode_handler;
dev->detectmode_handler = params->detectmode_handler; dev->detectmode_handler = params->detectmode_handler;
dev->sendrequest_handler = params->sendrequest_handler; dev->sendrequest_handler = params->sendrequest_handler;
...@@ -1231,10 +1237,15 @@ void smscore_unregister_device(struct smscore_device_t *coredev) ...@@ -1231,10 +1237,15 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
pr_debug("freed %d buffers\n", num_buffers); pr_debug("freed %d buffers\n", num_buffers);
if (coredev->common_buffer) if (coredev->common_buffer) {
dma_free_coherent(NULL, coredev->common_buffer_size, if (coredev->usb_device)
coredev->common_buffer, coredev->common_buffer_phys); kfree(coredev->common_buffer);
else
dma_free_coherent(coredev->device,
coredev->common_buffer_size,
coredev->common_buffer,
coredev->common_buffer_phys);
}
kfree(coredev->fw_buf); kfree(coredev->fw_buf);
list_del(&coredev->entry); list_del(&coredev->entry);
......
...@@ -134,6 +134,7 @@ struct smscore_buffer_t { ...@@ -134,6 +134,7 @@ struct smscore_buffer_t {
struct smsdevice_params_t { struct smsdevice_params_t {
struct device *device; struct device *device;
struct usb_device *usb_device;
int buffer_size; int buffer_size;
int num_buffers; int num_buffers;
...@@ -176,6 +177,7 @@ struct smscore_device_t { ...@@ -176,6 +177,7 @@ struct smscore_device_t {
void *context; void *context;
struct device *device; struct device *device;
struct usb_device *usb_device;
char devpath[32]; char devpath[32];
unsigned long device_flags; unsigned long device_flags;
......
...@@ -179,8 +179,7 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev, ...@@ -179,8 +179,7 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev,
smsusb_onresponse, smsusb_onresponse,
surb surb
); );
surb->urb.transfer_dma = surb->cb->phys; surb->urb.transfer_flags |= URB_FREE_BUFFER;
surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
return usb_submit_urb(&surb->urb, GFP_ATOMIC); return usb_submit_urb(&surb->urb, GFP_ATOMIC);
} }
...@@ -446,6 +445,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) ...@@ -446,6 +445,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
dev->in_ep, dev->out_ep); dev->in_ep, dev->out_ep);
params.device = &dev->udev->dev; params.device = &dev->udev->dev;
params.usb_device = dev->udev;
params.buffer_size = dev->buffer_size; params.buffer_size = dev->buffer_size;
params.num_buffers = MAX_BUFFERS; params.num_buffers = MAX_BUFFERS;
params.sendrequest_handler = smsusb_sendrequest; params.sendrequest_handler = smsusb_sendrequest;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment