Commit d6b42787 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull USB fixes from Greg KH:
 "Here are some small USB driver fixes and new device ids for 6.17-rc6.
  Included in here are:

   - new usb-serial driver device ids

   - dummy-hcd locking bugfix for rt-enabled systems (which is crazy,
     but people have odd testing requirements at times...)

   - xhci driver bugfixes for reported issues

   - typec driver bugfix

   - midi2 gadget driver bugfixes

   - usb core sysfs file regression fix from -rc1

  All of these, except for the last usb sysfs file fix, have been in
  linux-next with no reported issues. The sysfs fix was added to the
  tree on Friday, and is "obviously correct" and should not have any
  problems either, it just didn't have any time for linux-next to pick
  up (0-day had no problems with it)"

* tag 'usb-6.17-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  USB: core: remove the move buf action
  usb: gadget: midi2: Fix MIDI2 IN EP max packet size
  usb: gadget: midi2: Fix missing UMP group attributes initialization
  usb: typec: tcpm: properly deliver cable vdms to altmode drivers
  USB: gadget: dummy-hcd: Fix locking bug in RT-enabled kernels
  xhci: fix memory leak regression when freeing xhci vdev devices depth first
  xhci: dbc: Fix full DbC transfer ring after several reconnects
  xhci: dbc: decouple endpoint allocation from initialization
  USB: serial: option: add Telit Cinterion LE910C4-WWX new compositions
  USB: serial: option: add Telit Cinterion FN990A w/audio compositions
parents df86f912 9dfec4a5
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -119,11 +119,11 @@ ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf)
	guard(mutex)(&usb_dynids_lock);
	list_for_each_entry(dynid, &dynids->list, node)
		if (dynid->id.bInterfaceClass != 0)
			count += sysfs_emit_at(&buf[count], count, "%04x %04x %02x\n",
			count += sysfs_emit_at(buf, count, "%04x %04x %02x\n",
					   dynid->id.idVendor, dynid->id.idProduct,
					   dynid->id.bInterfaceClass);
		else
			count += sysfs_emit_at(&buf[count], count, "%04x %04x\n",
			count += sysfs_emit_at(buf, count, "%04x %04x\n",
					   dynid->id.idVendor, dynid->id.idProduct);
	return count;
}
+9 −2
Original line number Diff line number Diff line
@@ -1599,6 +1599,7 @@ static int f_midi2_create_card(struct f_midi2 *midi2)
			strscpy(fb->info.name, ump_fb_name(b),
				sizeof(fb->info.name));
		}
		snd_ump_update_group_attrs(ump);
	}

	for (i = 0; i < midi2->num_eps; i++) {
@@ -1736,9 +1737,12 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2,
	case USB_SPEED_HIGH:
		midi2_midi1_ep_out_desc.wMaxPacketSize = cpu_to_le16(512);
		midi2_midi1_ep_in_desc.wMaxPacketSize = cpu_to_le16(512);
		for (i = 0; i < midi2->num_eps; i++)
		for (i = 0; i < midi2->num_eps; i++) {
			midi2_midi2_ep_out_desc[i].wMaxPacketSize =
				cpu_to_le16(512);
			midi2_midi2_ep_in_desc[i].wMaxPacketSize =
				cpu_to_le16(512);
		}
		fallthrough;
	case USB_SPEED_FULL:
		midi1_in_eps = midi2_midi1_ep_in_descs;
@@ -1747,9 +1751,12 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2,
	case USB_SPEED_SUPER:
		midi2_midi1_ep_out_desc.wMaxPacketSize = cpu_to_le16(1024);
		midi2_midi1_ep_in_desc.wMaxPacketSize = cpu_to_le16(1024);
		for (i = 0; i < midi2->num_eps; i++)
		for (i = 0; i < midi2->num_eps; i++) {
			midi2_midi2_ep_out_desc[i].wMaxPacketSize =
				cpu_to_le16(1024);
			midi2_midi2_ep_in_desc[i].wMaxPacketSize =
				cpu_to_le16(1024);
		}
		midi1_in_eps = midi2_midi1_ep_in_ss_descs;
		midi1_out_eps = midi2_midi1_ep_out_ss_descs;
		break;
+4 −4
Original line number Diff line number Diff line
@@ -765,8 +765,7 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
	if (!dum->driver)
		return -ESHUTDOWN;

	local_irq_save(flags);
	spin_lock(&dum->lock);
	spin_lock_irqsave(&dum->lock, flags);
	list_for_each_entry(iter, &ep->queue, queue) {
		if (&iter->req != _req)
			continue;
@@ -776,15 +775,16 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
		retval = 0;
		break;
	}
	spin_unlock(&dum->lock);

	if (retval == 0) {
		dev_dbg(udc_dev(dum),
				"dequeued req %p from %s, len %d buf %p\n",
				req, _ep->name, _req->length, _req->buf);
		spin_unlock(&dum->lock);
		usb_gadget_giveback_request(_ep, _req);
		spin_lock(&dum->lock);
	}
	local_irq_restore(flags);
	spin_unlock_irqrestore(&dum->lock, flags);
	return retval;
}

+67 −27
Original line number Diff line number Diff line
@@ -101,29 +101,16 @@ static u32 xhci_dbc_populate_strings(struct dbc_str_descs *strings)
	return string_length;
}

static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length)
static void xhci_dbc_init_ep_contexts(struct xhci_dbc *dbc)
{
	struct dbc_info_context	*info;
	struct xhci_ep_ctx      *ep_ctx;
	u32			dev_info;
	dma_addr_t		deq, dma;
	unsigned int		max_burst;
	dma_addr_t		deq;

	if (!dbc)
		return;

	/* Populate info Context: */
	info			= (struct dbc_info_context *)dbc->ctx->bytes;
	dma			= dbc->string_dma;
	info->string0		= cpu_to_le64(dma);
	info->manufacturer	= cpu_to_le64(dma + DBC_MAX_STRING_LENGTH);
	info->product		= cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 2);
	info->serial		= cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 3);
	info->length		= cpu_to_le32(string_length);
	max_burst               = DBC_CTRL_MAXBURST(readl(&dbc->regs->control));

	/* Populate bulk out endpoint context: */
	ep_ctx                  = dbc_bulkout_ctx(dbc);
	max_burst		= DBC_CTRL_MAXBURST(readl(&dbc->regs->control));
	deq                     = dbc_bulkout_enq(dbc);
	ep_ctx->ep_info         = 0;
	ep_ctx->ep_info2        = dbc_epctx_info2(BULK_OUT_EP, 1024, max_burst);
@@ -135,6 +122,28 @@ static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length)
	ep_ctx->ep_info         = 0;
	ep_ctx->ep_info2        = dbc_epctx_info2(BULK_IN_EP, 1024, max_burst);
	ep_ctx->deq             = cpu_to_le64(deq | dbc->ring_in->cycle_state);
}

static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length)
{
	struct dbc_info_context	*info;
	u32			dev_info;
	dma_addr_t		dma;

	if (!dbc)
		return;

	/* Populate info Context: */
	info			= (struct dbc_info_context *)dbc->ctx->bytes;
	dma			= dbc->string_dma;
	info->string0		= cpu_to_le64(dma);
	info->manufacturer	= cpu_to_le64(dma + DBC_MAX_STRING_LENGTH);
	info->product		= cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 2);
	info->serial		= cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 3);
	info->length		= cpu_to_le32(string_length);

	/* Populate bulk in and out endpoint contexts: */
	xhci_dbc_init_ep_contexts(dbc);

	/* Set DbC context and info registers: */
	lo_hi_writeq(dbc->ctx->dma, &dbc->regs->dccp);
@@ -436,6 +445,42 @@ dbc_alloc_ctx(struct device *dev, gfp_t flags)
	return ctx;
}

static void xhci_dbc_ring_init(struct xhci_ring *ring)
{
	struct xhci_segment *seg = ring->first_seg;

	/* clear all trbs on ring in case of old ring */
	memset(seg->trbs, 0, TRB_SEGMENT_SIZE);

	/* Only event ring does not use link TRB */
	if (ring->type != TYPE_EVENT) {
		union xhci_trb *trb = &seg->trbs[TRBS_PER_SEGMENT - 1];

		trb->link.segment_ptr = cpu_to_le64(ring->first_seg->dma);
		trb->link.control = cpu_to_le32(LINK_TOGGLE | TRB_TYPE(TRB_LINK));
	}
	xhci_initialize_ring_info(ring);
}

static int xhci_dbc_reinit_ep_rings(struct xhci_dbc *dbc)
{
	struct xhci_ring *in_ring = dbc->eps[BULK_IN].ring;
	struct xhci_ring *out_ring = dbc->eps[BULK_OUT].ring;

	if (!in_ring || !out_ring || !dbc->ctx) {
		dev_warn(dbc->dev, "Can't re-init unallocated endpoints\n");
		return -ENODEV;
	}

	xhci_dbc_ring_init(in_ring);
	xhci_dbc_ring_init(out_ring);

	/* set ep context enqueue, dequeue, and cycle to initial values */
	xhci_dbc_init_ep_contexts(dbc);

	return 0;
}

static struct xhci_ring *
xhci_dbc_ring_alloc(struct device *dev, enum xhci_ring_type type, gfp_t flags)
{
@@ -464,15 +509,10 @@ xhci_dbc_ring_alloc(struct device *dev, enum xhci_ring_type type, gfp_t flags)

	seg->dma = dma;

	/* Only event ring does not use link TRB */
	if (type != TYPE_EVENT) {
		union xhci_trb *trb = &seg->trbs[TRBS_PER_SEGMENT - 1];

		trb->link.segment_ptr = cpu_to_le64(dma);
		trb->link.control = cpu_to_le32(LINK_TOGGLE | TRB_TYPE(TRB_LINK));
	}
	INIT_LIST_HEAD(&ring->td_list);
	xhci_initialize_ring_info(ring);

	xhci_dbc_ring_init(ring);

	return ring;
dma_fail:
	kfree(seg);
@@ -864,7 +904,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
			dev_info(dbc->dev, "DbC cable unplugged\n");
			dbc->state = DS_ENABLED;
			xhci_dbc_flush_requests(dbc);

			xhci_dbc_reinit_ep_rings(dbc);
			return EVT_DISC;
		}

@@ -874,7 +914,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
			writel(portsc, &dbc->regs->portsc);
			dbc->state = DS_ENABLED;
			xhci_dbc_flush_requests(dbc);

			xhci_dbc_reinit_ep_rings(dbc);
			return EVT_DISC;
		}

+1 −1
Original line number Diff line number Diff line
@@ -962,7 +962,7 @@ static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_i
out:
	/* we are now at a leaf device */
	xhci_debugfs_remove_slot(xhci, slot_id);
	xhci_free_virt_device(xhci, vdev, slot_id);
	xhci_free_virt_device(xhci, xhci->devs[slot_id], slot_id);
}

int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
Loading