Merge tag 'usb-for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes: USB changes for v4.21 So it looks like folks are interested in dwc3 again. Almost 64% of the changes are in dwc3 this time around with some other bits in gadget functions and dwc2. There are two important parts here: a. removal of the waitqueue from dwc3's dequeue implementation, which will guarantee that gadget functions can dequeue from any context and; b. better method for starting isochronous transfers to avoid, as much as possible, missed isoc frames. Apart from these, we have the usual set of non-critical fixes and new features all over the place. * tag 'usb-for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb: (56 commits) usb: dwc2: Fix disable all EP's on disconnect usb: dwc3: gadget: Disable CSP for stream OUT ep usb: dwc2: disable power_down on Amlogic devices Revert "usb: dwc3: pci: Use devm functions to get the phy GPIOs" USB: gadget: udc: s3c2410_udc: convert to DEFINE_SHOW_ATTRIBUTE usb: mtu3: fix dbginfo in qmu_tx_zlp_error_handler usb: dwc3: trace: add missing break statement to make compiler happy usb: dwc3: gadget: Report isoc transfer frame number usb: gadget: Introduce frame_number to usb_request usb: renesas_usbhs: Use SIMPLE_DEV_PM_OPS macro usb: renesas_usbhs: Remove dummy runtime PM callbacks usb: dwc2: host: use hrtimer for NAK retries usb: mtu3: clear SOFTCONN when clear USB3_EN if work as HS mode usb: mtu3: enable SETUPENDISR interrupt usb: mtu3: fix the issue about SetFeature(U1/U2_Enable) usb: mtu3: enable hardware remote wakeup from L1 automatically usb: mtu3: remove QMU checksum usb/mtu3: power down device ip at setup usb: dwc2: Disable power down feature on Samsung SoCs usb: dwc3: Correct the logic for checking TRB full in __dwc3_prepare_one_trb() ...
This commit is contained in:
@@ -18,11 +18,15 @@
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/usb/ccid.h>
|
||||
#include <linux/usb/composite.h>
|
||||
#include <linux/usb/functionfs.h>
|
||||
|
||||
@@ -218,6 +222,8 @@ struct ffs_io_data {
|
||||
|
||||
struct usb_ep *ep;
|
||||
struct usb_request *req;
|
||||
struct sg_table sgt;
|
||||
bool use_sg;
|
||||
|
||||
struct ffs_data *ffs;
|
||||
};
|
||||
@@ -749,6 +755,65 @@ static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate a virtually contiguous buffer and create a scatterlist describing it
|
||||
* @sg_table - pointer to a place to be filled with sg_table contents
|
||||
* @size - required buffer size
|
||||
*/
|
||||
static void *ffs_build_sg_list(struct sg_table *sgt, size_t sz)
|
||||
{
|
||||
struct page **pages;
|
||||
void *vaddr, *ptr;
|
||||
unsigned int n_pages;
|
||||
int i;
|
||||
|
||||
vaddr = vmalloc(sz);
|
||||
if (!vaddr)
|
||||
return NULL;
|
||||
|
||||
n_pages = PAGE_ALIGN(sz) >> PAGE_SHIFT;
|
||||
pages = kvmalloc_array(n_pages, sizeof(struct page *), GFP_KERNEL);
|
||||
if (!pages) {
|
||||
vfree(vaddr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0, ptr = vaddr; i < n_pages; ++i, ptr += PAGE_SIZE)
|
||||
pages[i] = vmalloc_to_page(ptr);
|
||||
|
||||
if (sg_alloc_table_from_pages(sgt, pages, n_pages, 0, sz, GFP_KERNEL)) {
|
||||
kvfree(pages);
|
||||
vfree(vaddr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
kvfree(pages);
|
||||
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
static inline void *ffs_alloc_buffer(struct ffs_io_data *io_data,
|
||||
size_t data_len)
|
||||
{
|
||||
if (io_data->use_sg)
|
||||
return ffs_build_sg_list(&io_data->sgt, data_len);
|
||||
|
||||
return kmalloc(data_len, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static inline void ffs_free_buffer(struct ffs_io_data *io_data)
|
||||
{
|
||||
if (!io_data->buf)
|
||||
return;
|
||||
|
||||
if (io_data->use_sg) {
|
||||
sg_free_table(&io_data->sgt);
|
||||
vfree(io_data->buf);
|
||||
} else {
|
||||
kfree(io_data->buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void ffs_user_copy_worker(struct work_struct *work)
|
||||
{
|
||||
struct ffs_io_data *io_data = container_of(work, struct ffs_io_data,
|
||||
@@ -776,7 +841,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
|
||||
|
||||
if (io_data->read)
|
||||
kfree(io_data->to_free);
|
||||
kfree(io_data->buf);
|
||||
ffs_free_buffer(io_data);
|
||||
kfree(io_data);
|
||||
}
|
||||
|
||||
@@ -932,6 +997,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
||||
* earlier
|
||||
*/
|
||||
gadget = epfile->ffs->gadget;
|
||||
io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
|
||||
|
||||
spin_lock_irq(&epfile->ffs->eps_lock);
|
||||
/* In the meantime, endpoint got disabled or changed. */
|
||||
@@ -948,7 +1014,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
||||
data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
|
||||
spin_unlock_irq(&epfile->ffs->eps_lock);
|
||||
|
||||
data = kmalloc(data_len, GFP_KERNEL);
|
||||
data = ffs_alloc_buffer(io_data, data_len);
|
||||
if (unlikely(!data)) {
|
||||
ret = -ENOMEM;
|
||||
goto error_mutex;
|
||||
@@ -988,8 +1054,16 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
||||
bool interrupted = false;
|
||||
|
||||
req = ep->req;
|
||||
req->buf = data;
|
||||
req->length = data_len;
|
||||
if (io_data->use_sg) {
|
||||
req->buf = NULL;
|
||||
req->sg = io_data->sgt.sgl;
|
||||
req->num_sgs = io_data->sgt.nents;
|
||||
} else {
|
||||
req->buf = data;
|
||||
}
|
||||
req->length = data_len;
|
||||
|
||||
io_data->buf = data;
|
||||
|
||||
req->context = &done;
|
||||
req->complete = ffs_epfile_io_complete;
|
||||
@@ -1022,8 +1096,14 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
||||
} else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) {
|
||||
ret = -ENOMEM;
|
||||
} else {
|
||||
req->buf = data;
|
||||
req->length = data_len;
|
||||
if (io_data->use_sg) {
|
||||
req->buf = NULL;
|
||||
req->sg = io_data->sgt.sgl;
|
||||
req->num_sgs = io_data->sgt.nents;
|
||||
} else {
|
||||
req->buf = data;
|
||||
}
|
||||
req->length = data_len;
|
||||
|
||||
io_data->buf = data;
|
||||
io_data->ep = ep->ep;
|
||||
@@ -1052,7 +1132,7 @@ error_lock:
|
||||
error_mutex:
|
||||
mutex_unlock(&epfile->mutex);
|
||||
error:
|
||||
kfree(data);
|
||||
ffs_free_buffer(io_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1926,7 +2006,7 @@ typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity,
|
||||
|
||||
static int __must_check ffs_do_single_desc(char *data, unsigned len,
|
||||
ffs_entity_callback entity,
|
||||
void *priv)
|
||||
void *priv, int *current_class)
|
||||
{
|
||||
struct usb_descriptor_header *_ds = (void *)data;
|
||||
u8 length;
|
||||
@@ -1984,6 +2064,7 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len,
|
||||
__entity(INTERFACE, ds->bInterfaceNumber);
|
||||
if (ds->iInterface)
|
||||
__entity(STRING, ds->iInterface);
|
||||
*current_class = ds->bInterfaceClass;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1997,11 +2078,22 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len,
|
||||
}
|
||||
break;
|
||||
|
||||
case HID_DT_HID:
|
||||
pr_vdebug("hid descriptor\n");
|
||||
if (length != sizeof(struct hid_descriptor))
|
||||
goto inv_length;
|
||||
break;
|
||||
case USB_TYPE_CLASS | 0x01:
|
||||
if (*current_class == USB_INTERFACE_CLASS_HID) {
|
||||
pr_vdebug("hid descriptor\n");
|
||||
if (length != sizeof(struct hid_descriptor))
|
||||
goto inv_length;
|
||||
break;
|
||||
} else if (*current_class == USB_INTERFACE_CLASS_CCID) {
|
||||
pr_vdebug("ccid descriptor\n");
|
||||
if (length != sizeof(struct ccid_descriptor))
|
||||
goto inv_length;
|
||||
break;
|
||||
} else {
|
||||
pr_vdebug("unknown descriptor: %d for class %d\n",
|
||||
_ds->bDescriptorType, *current_class);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
case USB_DT_OTG:
|
||||
if (length != sizeof(struct usb_otg_descriptor))
|
||||
@@ -2058,6 +2150,7 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
|
||||
{
|
||||
const unsigned _len = len;
|
||||
unsigned long num = 0;
|
||||
int current_class = -1;
|
||||
|
||||
ENTER();
|
||||
|
||||
@@ -2078,7 +2171,8 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
|
||||
if (!data)
|
||||
return _len - len;
|
||||
|
||||
ret = ffs_do_single_desc(data, len, entity, priv);
|
||||
ret = ffs_do_single_desc(data, len, entity, priv,
|
||||
¤t_class);
|
||||
if (unlikely(ret < 0)) {
|
||||
pr_debug("%s returns %d\n", __func__, ret);
|
||||
return ret;
|
||||
|
@@ -102,7 +102,7 @@ static void uvc_buffer_queue(struct vb2_buffer *vb)
|
||||
spin_unlock_irqrestore(&queue->irqlock, flags);
|
||||
}
|
||||
|
||||
static struct vb2_ops uvc_queue_qops = {
|
||||
static const struct vb2_ops uvc_queue_qops = {
|
||||
.queue_setup = uvc_queue_setup,
|
||||
.buf_prepare = uvc_buffer_prepare,
|
||||
.buf_queue = uvc_buffer_queue,
|
||||
|
@@ -438,7 +438,7 @@ static int ast_vhub_udc_stop(struct usb_gadget *gadget)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_gadget_ops ast_vhub_udc_ops = {
|
||||
static const struct usb_gadget_ops ast_vhub_udc_ops = {
|
||||
.get_frame = ast_vhub_udc_get_frame,
|
||||
.wakeup = ast_vhub_udc_wakeup,
|
||||
.pullup = ast_vhub_udc_pullup,
|
||||
|
@@ -358,6 +358,7 @@ struct renesas_usb3 {
|
||||
bool extcon_host; /* check id and set EXTCON_USB_HOST */
|
||||
bool extcon_usb; /* check vbus and set EXTCON_USB */
|
||||
bool forced_b_device;
|
||||
bool start_to_connect;
|
||||
};
|
||||
|
||||
#define gadget_to_renesas_usb3(_gadget) \
|
||||
@@ -476,7 +477,8 @@ static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
|
||||
static void usb3_init_epc_registers(struct renesas_usb3 *usb3)
|
||||
{
|
||||
usb3_write(usb3, ~0, USB3_USB_INT_STA_1);
|
||||
usb3_enable_irq_1(usb3, USB_INT_1_VBUS_CNG);
|
||||
if (!usb3->workaround_for_vbus)
|
||||
usb3_enable_irq_1(usb3, USB_INT_1_VBUS_CNG);
|
||||
}
|
||||
|
||||
static bool usb3_wakeup_usb2_phy(struct renesas_usb3 *usb3)
|
||||
@@ -700,8 +702,7 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
|
||||
usb3_set_mode_by_role_sw(usb3, host);
|
||||
usb3_vbus_out(usb3, a_dev);
|
||||
/* for A-Peripheral or forced B-device mode */
|
||||
if ((!host && a_dev) ||
|
||||
(usb3->workaround_for_vbus && usb3->forced_b_device))
|
||||
if ((!host && a_dev) || usb3->start_to_connect)
|
||||
usb3_connect(usb3);
|
||||
spin_unlock_irqrestore(&usb3->lock, flags);
|
||||
}
|
||||
@@ -2432,7 +2433,11 @@ static ssize_t renesas_usb3_b_device_write(struct file *file,
|
||||
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!strncmp(buf, "1", 1))
|
||||
usb3->start_to_connect = false;
|
||||
if (usb3->workaround_for_vbus && usb3->forced_b_device &&
|
||||
!strncmp(buf, "2", 1))
|
||||
usb3->start_to_connect = true;
|
||||
else if (!strncmp(buf, "1", 1))
|
||||
usb3->forced_b_device = true;
|
||||
else
|
||||
usb3->forced_b_device = false;
|
||||
@@ -2440,7 +2445,7 @@ static ssize_t renesas_usb3_b_device_write(struct file *file,
|
||||
if (usb3->workaround_for_vbus)
|
||||
usb3_disconnect(usb3);
|
||||
|
||||
/* Let this driver call usb3_connect() anyway */
|
||||
/* Let this driver call usb3_connect() if needed */
|
||||
usb3_check_id(usb3);
|
||||
|
||||
return count;
|
||||
|
@@ -119,7 +119,7 @@ static void dprintk(int level, const char *fmt, ...)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
|
||||
static int s3c2410_udc_debugfs_show(struct seq_file *m, void *p)
|
||||
{
|
||||
u32 addr_reg, pwr_reg, ep_int_reg, usb_int_reg;
|
||||
u32 ep_int_en_reg, usb_int_en_reg, ep0_csr;
|
||||
@@ -168,20 +168,7 @@ static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c2410_udc_debugfs_fops_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
return single_open(file, s3c2410_udc_debugfs_seq_show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations s3c2410_udc_debugfs_fops = {
|
||||
.open = s3c2410_udc_debugfs_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(s3c2410_udc_debugfs);
|
||||
|
||||
/* io macros */
|
||||
|
||||
|
Reference in New Issue
Block a user