All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Petar Stepanovic" <pstepanovic@axiado.com>
Cc: linux-usb@vger.kernel.org, devicetree@vger.kernel.org,
	robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v3 6/6] usb: gadget: udc: crg: Add core driver and build integration
Date: Tue, 20 Oct 2026 09:52:39 +0000	[thread overview]
Message-ID: <sashiko-outbox-178767@kernel.org> (raw)
In-Reply-To: <20261020-axiado-ax3000-usb-device-controller-v3-6-3012ecfc0a93@axiado.com>

Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
- [High] usb: gadget: crg: crg_udc_reset() clears ep->enabled before disconnect()
- [High] usb: gadget: crg: premature resetting clear and missing checks in crg_udc_reset()
- [Medium] usb: gadget: crg: premature IRQ and data init before ep setup in crg_udc_probe()
- [Medium] usb: gadget: crg: premature unlocked state reset in crg_udc_remove()
- [Medium] usb: gadget: crg: race in crg_udc_shutdown() on uccr->control and pullup_on
- [Medium] usb: gadget: udc: crg: 32-bit dma_addr_t shift overflow under COMPILE_TEST
- [Medium] usb: gadget: crg: crg_udc_issue_command() overwrites pending command when RUN is 0
- [Low] usb: gadget: udc: crg: deprecated SIMPLE_DEV_PM_OPS and missing pm_sleep_ptr()
--

commit 0ef71bda637190f9d2012396d35661e2929b2b80
Author: Petar Stepanovic <pstepanovic@axiado.com>

usb: gadget: udc: crg: Add core driver and build integration

This patch adds the core probe, remove, reset, and interrupt handling
functions for the Axiado AX3000/AX3005 UDC driver and wires the driver
into Kconfig and Makefile.

> diff --git a/drivers/usb/gadget/udc/crg/Kconfig b/drivers/usb/gadget/udc/crg/Kconfig
> new file mode 100644
> index 0000000000000..7167c4943389b
> --- /dev/null
> +++ b/drivers/usb/gadget/udc/crg/Kconfig
> @@ -0,0 +1,16 @@
> +# SPDX-License-Identifier: GPL-2.0
> +config USB_CRG_UDC
> +	tristate "Corigine / Axiado USB Device Controller"
> +	depends on USB_GADGET
> +	depends on HAS_DMA
> +	depends on ARCH_AXIADO || COMPILE_TEST

[Severity: Medium]
Can enabling COMPILE_TEST here break 32-bit builds where dma_addr_t is
32 bits wide (CONFIG_ARCH_DMA_ADDR_T_64BIT=n)?

In drivers/usb/gadget/udc/crg/crg-udc-gadget.c, crg_udc_ep_dequeue() and
crg_udc_handle_xfer_event() shift values cast to dma_addr_t left by 32 bits:

drivers/usb/gadget/udc/crg/crg-udc-gadget.c:crg_udc_ep_dequeue() {
	...
	dq_pt_addr = (dma_addr_t)deq_pt_lo | ((dma_addr_t)deq_pt_hi << 32);
	...
}

drivers/usb/gadget/udc/crg/crg-udc-gadget.c:crg_udc_handle_xfer_event() {
	...
		trb = crg_udc_tran_trb_dma_to_virt(
			udc_ep_ptr,
			(dma_addr_t)le32_to_cpu(event->dw0) |
				((dma_addr_t)le32_to_cpu(event->dw1) << 32));
	...
}

On 32-bit architectures without 64-bit dma_addr_t, shifting a 32-bit type
by 32 bits triggers -Wshift-count-overflow. Should those shifts cast to u64
first (like is_request_dequeued() and crg_udc_update_dequeue_pt() already
do)?

[ ... ]

> diff --git a/drivers/usb/gadget/udc/crg/crg-udc-core.c b/drivers/usb/gadget/udc/crg/crg-udc-core.c
> new file mode 100644
> index 0000000000000..80a4fc6a61e88
> --- /dev/null
> +++ b/drivers/usb/gadget/udc/crg/crg-udc-core.c
> @@ -0,0 +1,706 @@

[ ... ]

> +/*
> + * command related ops
> + */
> +int crg_udc_issue_command(struct crg_gadget_dev *crg_udc,
> +			  enum crg_cmd_type type, u32 param0, u32 param1)
> +{
> +	struct crg_uccr __iomem *uccr = crg_udc->uccr;
> +	u32 status;
> +	bool check_complete = false;
> +	u32 tmp;
> +
> +	/*
> +	 * The command state machine only runs while the controller itself is
> +	 * running. Once RUN is cleared (e.g. during udc_stop()/reset()), the
> +	 * hardware never processes queued commands, so ACTIVE never clears.
> +	 * Skip the busy/completion checks in that case instead of getting
> +	 * stuck on a command the hardware will never service.
> +	 */
> +	tmp = readl(&uccr->control);
> +	if (tmp & CRG_U3DC_CTRL_RUN)
> +		check_complete = true;
> +
> +	if (check_complete) {
> +		tmp = readl(&uccr->cmd_control);
> +		if (tmp & CRG_U3DC_CMD_CTRL_ACTIVE) {
> +			dev_err(crg_udc->dev,
> +				"previous command is not complete\n");
> +			return -EBUSY;
> +		}
> +	}
> +	/* Ensure that everything is written before issuing new command */
> +	dma_wmb();
> +
> +	writel(param0, &uccr->cmd_param0);
> +	writel(param1, &uccr->cmd_param1);
> +
> +	tmp = CRG_U3DC_CMD_CTRL_ACTIVE |
> +	      FIELD_PREP(CRG_U3DC_CMD_CTRL_TYPE_MASK, type);
> +	writel(tmp, &uccr->cmd_control);
> +
> +	if (!check_complete)
> +		return 0;

[Severity: Medium]
What happens when multiple commands are issued while CRG_U3DC_CTRL_RUN is 0,
or when a command is issued immediately after CRG_U3DC_CTRL_RUN is asserted?

Because the controller has a single set of command registers
(uccr->cmd_param0, uccr->cmd_param1, uccr->cmd_control) and the hardware
does not clear CRG_U3DC_CMD_CTRL_ACTIVE while CRG_U3DC_CTRL_RUN is 0:

1. crg_udc_init_ep0() issues CRG_CMD_INIT_EP0 while CRG_U3DC_CTRL_RUN is 0
   in crg_udc_probe(), crg_gadget_stop(), crg_udc_handle_port_status() on
   disconnect, and crg_gadget_handle_interrupt() on CRG_U3DC_STATUS_SYS_ERR,
   leaving CRG_CMD_INIT_EP0 pending in uccr->cmd_control. Similarly,
   crg_udc_set_pullup(crg_udc, false) in crg_gadget_pullup() and
   crg_udc_suspend() clears CRG_U3DC_CTRL_RUN while endpoints remain
   enabled.

2. If another command is issued before CRG_U3DC_CTRL_RUN is set (for
   example via crg_udc_ep_enable(), crg_udc_ep_dequeue() issuing
   CRG_CMD_STOP_EP followed by CRG_CMD_SET_TR_DQPTR, or crg_udc_ep_halt()
   issuing CRG_CMD_RESET_SEQNUM, CRG_CMD_CLEAR_HALT, and
   CRG_CMD_SET_TR_DQPTR back-to-back), check_complete is false and
   crg_udc_issue_command() overwrites the unserviced command in
   uccr->cmd_control.

3. When crg_udc_set_pullup(crg_udc, true) later sets CRG_U3DC_CTRL_RUN, it
   does not wait for a pending CRG_U3DC_CMD_CTRL_ACTIVE command to finish,
   so a command issued right after RUN is set can see
   CRG_U3DC_CMD_CTRL_ACTIVE still set and fail with -EBUSY.

Can this cause CRG_CMD_INIT_EP0 or endpoint commands to be lost or fail
with -EBUSY?

[ ... ]

> +static int crg_udc_probe(struct platform_device *pdev)
> +{

[ ... ]

> +	spin_lock_irqsave(&crg_udc->udc_lock, flags);
> +	ret = crg_udc_reset(crg_udc, &flags);
> +	spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
> +	if (ret)
> +		goto err_free_resources;
> +
> +	crg_udc_clear_portpm(crg_udc);
> +
> +	ret = crg_gadget_irq_init(pdev, crg_udc);
> +	if (ret)
> +		goto err_free_resources;
> +
> +	ret = crg_udc_reset_data_struct(crg_udc);
> +	if (ret) {
> +		dev_err(crg_udc->dev, "crg_udc_reset_data_struct error\n");
> +		goto err_free_resources;
> +	}
> +
> +	crg_udc_init_ep_info(crg_udc);
> +	ret = crg_udc_init_ep0(crg_udc);
> +	if (ret)
> +		goto err_free_resources;

[Severity: Medium]
Should crg_udc_init_ep_info(), crg_udc_reset_data_struct(), and
crg_udc_init_ep0() run before crg_gadget_irq_init(), with
crg_udc_init_ep_info() called before crg_udc_reset_data_struct()?

With the current ordering in crg_udc_probe():

1. crg_udc_reset_data_struct() runs before crg_udc_init_ep_info() has
   initialized crg_udc->udc_ep[0], and calls:

   crg_udc_reset_data_struct()
     -> crg_udc_alloc_request(&crg_udc->udc_ep[0].usb_ep, GFP_ATOMIC)
       -> trace_crg_udc_alloc_request(udc_ep, udc_req_ptr)

   where udc_ep[0].usb_ep.name, ops, and crg_udc are still NULL.

2. crg_gadget_irq_init() registers the shared IRQ (IRQF_SHARED |
   IRQF_ONESHOT) before crg_udc_reset_data_struct(), crg_udc_init_ep_info(),
   and crg_udc_init_ep0() have initialized the event rings, endpoint list
   heads, and EP0 transfer ring. Because crg_udc_common_irq() only checks
   uccr->status for CRG_U3DC_STATUS_EINT | CRG_U3DC_STATUS_SYS_ERR without
   checking CRG_U3DC_CTRL_INT_EN, an interrupt arriving in this window runs
   crg_gadget_handle_interrupt() under spin_lock_irqsave(&crg_udc->udc_lock,
   flags) while udc_ep[0].tran_ring_info.cpu_addr is still NULL, causing
   crg_udc_init_ep0() to call dma_alloc_coherent(..., GFP_KERNEL) while
   holding the spinlock:

drivers/usb/gadget/udc/crg/crg-udc-ep0.c:crg_udc_init_ep0() {
	...
	if (!udc_ep_ptr->tran_ring_info.cpu_addr) {
		...
		vaddr = dma_alloc_coherent(crg_udc->dev, len, &dma, GFP_KERNEL);
	...
}

> +
> +	crg_udc->udc_ep[0].desc = &crg_udc->ep0_desc;
> +
> +	ret = usb_add_gadget(&crg_udc->gadget);
> +	if (ret)
> +		goto err_free_resources;
> +
> +	return 0;
> +
> +err_free_resources:
> +	crg_udc_free_resources(crg_udc);
> +err_put_gadget:
> +	usb_put_gadget(&crg_udc->gadget);
> +	return ret;
> +}
> +
> +static void crg_udc_remove(struct platform_device *pdev)
> +{
> +	struct crg_gadget_dev *crg_udc = platform_get_drvdata(pdev);
> +	u32 tmp;
> +
> +	crg_udc->device_state = USB_STATE_ATTACHED;
> +	crg_udc_set_vbus_detect(crg_udc, false);
> +
> +	usb_del_gadget(&crg_udc->gadget);
> +	cancel_work_sync(&crg_udc->udc_reset_work);
> +	crg_udc_free_resources(crg_udc);

[Severity: Medium]
In crg_udc_remove(), why are crg_udc->device_state and VBUS detection
updated before usb_del_gadget(&crg_udc->gadget) and without holding
crg_udc->udc_lock?

While a gadget driver is bound and active, the controller and its interrupt
handler remain active until usb_del_gadget() unbinds the gadget driver and
invokes crg_gadget_stop() (which already sets crg_udc->device_state =
USB_STATE_ATTACHED and calls crg_udc_set_vbus_detect(crg_udc, false)).

Setting crg_udc->device_state = USB_STATE_ATTACHED before usb_del_gadget()
causes any concurrent crg_udc_handle_event() execution for
TRB_TYPE_EVT_TRANSFER to see crg_udc->device_state < USB_STATE_RECONNECTING
and drop in-flight transfer completion events:

drivers/usb/gadget/udc/crg/crg-udc-gadget.c:crg_udc_handle_event() {
	...
	case TRB_TYPE_EVT_TRANSFER:
		if (crg_udc->device_state < USB_STATE_RECONNECTING) {
			dev_err(crg_udc->dev,
				"Xfer compl event rcved when dev state=%d !\n",
				crg_udc->device_state);
			break;
		}

		ret = crg_udc_handle_xfer_event(crg_udc, event, flags);
	...
}

> +
> +	/* set controller host role */
> +	tmp = readl(crg_udc->mmio_virt_base + CRG_UDC_MODE_REG) & ~0x1;
> +	writel(tmp, crg_udc->mmio_virt_base + CRG_UDC_MODE_REG);
> +
> +	platform_set_drvdata(pdev, NULL);
> +	usb_put_gadget(&crg_udc->gadget);
> +}
> +
> +static void crg_udc_shutdown(struct platform_device *pdev)
> +{
> +	struct crg_gadget_dev *crg_udc = platform_get_drvdata(pdev);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&crg_udc->udc_lock, flags);
> +	crg_udc->device_state = USB_STATE_ATTACHED;
> +	crg_udc_set_pullup(crg_udc, false);
> +	spin_unlock_irqrestore(&crg_udc->udc_lock, flags);
> +	crg_udc_set_vbus_detect(crg_udc, false);
> +	if (crg_udc->uccr) {
> +		u32 val = readl(&crg_udc->uccr->control);
> +
> +		val &= ~CRG_U3DC_CTRL_INT_EN;
> +		writel(val, &crg_udc->uccr->control);
> +	}
> +	if (crg_udc->irq >= 0)
> +		synchronize_irq(crg_udc->irq);
> +}

[Severity: Medium]
Can crg_udc_shutdown() race with crg_gadget_handle_interrupt() and leave
the controller running with interrupts enabled?

In crg_udc_shutdown():
1. crg_udc_set_pullup(crg_udc, false) clears CRG_U3DC_CTRL_RUN, but
   crg_udc->pullup_on is not cleared.
2. &crg_udc->uccr->control is read-modify-written to clear
   CRG_U3DC_CTRL_INT_EN after dropping crg_udc->udc_lock and before
   synchronize_irq(crg_udc->irq).
3. If crg_udc_irq_thread() -> crg_gadget_handle_interrupt() is running
   concurrently (for instance, recovering from CRG_U3DC_STATUS_SYS_ERR where
   crg_udc_reset() drops and reacquires udc_lock), it observes
   crg_udc->pullup_on == true and calls crg_udc_set_pullup(crg_udc, true),
   which sets CRG_U3DC_CTRL_SYSERR_EN | CRG_U3DC_CTRL_INT_EN |
   CRG_U3DC_CTRL_RUN in uccr->control again.
4. crg_udc->udc_reset_work is not cancelled with cancel_work_sync().

Should crg_udc->pullup_on = false and the CRG_U3DC_CTRL_INT_EN clear be
done under crg_udc->udc_lock, followed by synchronize_irq() and
cancel_work_sync(&crg_udc->udc_reset_work)?

[ ... ]

> +static void crg_gadget_handle_interrupt(struct crg_gadget_dev *crg_udc)
> +{
> +	struct crg_uccr __iomem *uccr = crg_udc->uccr;
> +	unsigned long flags = 0;
> +	u32 tmp_status;
> +	int ret;
> +
> +	spin_lock_irqsave(&crg_udc->udc_lock, flags);
> +
> +	tmp_status = readl(&uccr->status);
> +
> +	if (tmp_status & CRG_U3DC_STATUS_SYS_ERR) {
> +		bool was_connected = crg_udc->connected;
> +
> +		dev_err(crg_udc->dev, "controller system error\n");
> +		writel(CRG_U3DC_STATUS_SYS_ERR, &uccr->status);
> +		ret = crg_udc_reset(crg_udc, &flags);
> +		if (!ret)
> +			ret = crg_udc_reset_data_struct(crg_udc);
> +		if (!ret)
> +			ret = crg_udc_init_ep0(crg_udc);
> +		if (ret)
> +			dev_err(crg_udc->dev,
> +				"failed to recover from controller error: %d\n",
> +				ret);
> +		crg_udc->gadget.speed = USB_SPEED_UNKNOWN;
> +		crg_udc->connected = 0;
> +		if (was_connected)
> +			crg_udc_notify_disconnect(crg_udc, &flags);

[Severity: High]
Does calling crg_udc_reset() before crg_udc_notify_disconnect() here
prevent gadget function drivers from cleaning up on disconnect?

In crg_udc_reset(), udc_ep_ptr->usb_ep.enabled is cleared to 0 for all
non-EP0 endpoints:

	for (i = 2; i < CRG_NUM_EP_CX; i++) {
		...
		udc_ep_ptr->ep_state = EP_STATE_DISABLED;
		udc_ep_ptr->usb_ep.enabled = 0;
	}

When crg_udc_notify_disconnect() then invokes
crg_udc->gadget_driver->disconnect() -> composite_disconnect() ->
reset_config(), function drivers whose ->disable() callbacks guard teardown
on ep->enabled (such as rndis_disable() checking rndis->notify->enabled, or
ecm_disable() and eem_disable() checking port.in_ep->enabled) see
enabled == 0 and return without calling rndis_uninit() or
gether_disconnect(). On subsequent re-enumeration, their ->set_alt()
callbacks also check in_ep->enabled before calling gether_disconnect(),
leaking the previous session's usb_request objects.

Should crg_udc_notify_disconnect() be called before crg_udc_reset(), matching
the disconnect path in crg_udc_handle_port_status()?

[ ... ]

> +int crg_udc_reset(struct crg_gadget_dev *crg_udc, unsigned long *flags)
> +{
> +	struct crg_uccr __iomem *uccr = crg_udc->uccr;
> +	u32 i, tmp;
> +	struct crg_udc_ep *udc_ep_ptr;
> +	u32 val;
> +
> +	val = readl(&uccr->control);
> +	val |= CRG_U3DC_CTRL_SWRST;
> +	writel(val, &uccr->control);
> +	crg_udc->resetting = true;
> +	spin_unlock_irqrestore(&crg_udc->udc_lock, *flags);
> +	/* Poll until SWRST clears; hardware reset takes up to 10 ms */
> +	if (readl_poll_timeout_atomic(&uccr->control, tmp,
> +			       !(tmp & CRG_U3DC_CTRL_SWRST), 10, 10000)) {
> +		spin_lock_irqsave(&crg_udc->udc_lock, *flags);
> +		crg_udc->resetting = false;
> +		dev_err(crg_udc->dev, "reset error\n");
> +		return -ETIMEDOUT;
> +	}
> +	spin_lock_irqsave(&crg_udc->udc_lock, *flags);
> +	crg_udc->resetting = false;
> +
> +	crg_udc_clear_portpm(crg_udc);
> +
> +	crg_udc->setup_status = WAIT_FOR_SETUP;
> +	/* Base on Figure 9-1, default USB_STATE is attached */
> +	crg_udc->device_state = USB_STATE_ATTACHED;
> +	crg_udc->dev_addr = 0;
> +
> +	/* Complete any reqs on EP1-EP15 queue */
> +	for (i = 2; i < CRG_NUM_EP_CX; i++) {
> +		udc_ep_ptr = &crg_udc->udc_ep[i];
> +
> +		if (udc_ep_ptr->desc) {
> +			udc_ep_ptr->desc = NULL;
> +			udc_ep_ptr->comp_desc = NULL;
> +			crg_udc_ep_nuke(udc_ep_ptr, -ESHUTDOWN);
> +		}
> +		udc_ep_ptr->tran_ring_full = false;
> +		udc_ep_ptr->ep_state = EP_STATE_DISABLED;
> +		/*
> +		 * This bypasses the generic usb_ep_disable() API, so the
> +		 * framework's own usb_ep.enabled bookkeeping needs to be
> +		 * cleared directly here too (crg_udc_reinit() already does
> +		 * this for the live bus-reset case). Otherwise a later
> +		 * usb_ep_enable() call for this endpoint short-circuits on
> +		 * the stale "already enabled" flag without ever calling our
> +		 * .enable callback, leaving desc/the ring never set up for
> +		 * the new session.
> +		 */
> +		udc_ep_ptr->usb_ep.enabled = 0;
> +	}
> +	crg_udc->num_enabled_eps = 0;
> +
> +	/* Complete any reqs on EP0 queue */
> +	udc_ep_ptr = &crg_udc->udc_ep[0];
> +	if (udc_ep_ptr->desc) {
> +		udc_ep_ptr->desc = NULL;
> +		udc_ep_ptr->comp_desc = NULL;
> +		crg_udc_ep_nuke(udc_ep_ptr, -ESHUTDOWN);
> +	}
> +
> +	return 0;
> +}

[Severity: High]
Can dropping crg_udc->udc_lock during crg_udc_reset() allow other threads or
completion callbacks to touch registers and ring doorbells while the
controller is mid-reset or before its rings and contexts are reinitialized?

There appear to be two windows here when crg_udc_reset() is called at
runtime (from crg_gadget_handle_interrupt(), crg_udc_handle_port_status(),
or crg_gadget_stop()):

1. While udc_lock is dropped polling for CRG_U3DC_CTRL_SWRST to clear, all
   endpoints still have desc != NULL and ep_state == EP_STATE_RUNNING, and
   only crg_udc_ep_queue() checks crg_udc->resetting. Concurrent calls to
   crg_udc_ep_dequeue(), crg_udc_ep_disable(), crg_udc_ep_enable(),
   crg_udc_ep_set_halt(), crg_udc_ep_set_wedge(), crg_gadget_pullup(),
   crg_gadget_wakeup(), crg_udc_suspend(), or crg_udc_resume() can acquire
   udc_lock and issue commands or write registers while SWRST is active.

2. crg_udc->resetting is set back to false immediately after SWRST clears,
   before the loop over udc_ep[2..CRG_NUM_EP_CX - 1] and udc_ep[0], and
   before the caller runs crg_udc_reset_data_struct() and
   crg_udc_init_ep0(). Inside the loop, crg_udc_ep_nuke() ->
   crg_udc_req_done() drops udc_lock around usb_gadget_giveback_request()
   while crg_udc->resetting is already false and remaining endpoints j > i
   (as well as udc_ep[0]) still have desc != NULL:

drivers/usb/gadget/udc/crg/crg-udc-gadget.c:crg_udc_ep_queue() {
	...
	if (udc_ep_ptr->desc != desc || !udc_req_ptr->usb_req.complete ||
	    !list_empty(&udc_req_ptr->queue) || crg_udc->resetting) {
	...
}

   A completion callback or another CPU waiting in crg_udc_ep_queue() for a
   later endpoint j > i (or EP0) will see both udc_ep_ptr->desc == desc and
   crg_udc->resetting == false, and will queue TRBs and ring the doorbell on
   a wiped controller before crg_udc_reset_data_struct() and
   crg_udc_init_ep0() have reprogrammed DCBAP, the event rings, and EP0.

> +
> +static const struct crg_udc_priv crg_udc_data = {
> +	.quirks = CRG_UDC_QUIRKS_DEFAULT,
> +};
> +
> +static const struct of_device_id of_crg_udc_match[] = {
> +	{ .compatible = "axiado,ax3000-udc", .data = &crg_udc_data },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, of_crg_udc_match);
> +
> +static SIMPLE_DEV_PM_OPS(crg_udc_pm_ops, crg_udc_suspend, crg_udc_resume);
> +
> +static struct platform_driver crg_udc_driver = {
> +	.probe = crg_udc_probe,
> +	.remove = crg_udc_remove,
> +	.shutdown = crg_udc_shutdown,
> +	.driver = {
> +		.name = KBUILD_MODNAME,
> +		.of_match_table = of_crg_udc_match,
> +		.pm = &crg_udc_pm_ops,
> +	},
> +};

[Severity: Low]
SIMPLE_DEV_PM_OPS() is deprecated in include/linux/pm.h. Could this use
DEFINE_SIMPLE_DEV_PM_OPS(crg_udc_pm_ops, crg_udc_suspend, crg_udc_resume)
with pm_sleep_ptr(&crg_udc_pm_ops) (and drop __maybe_unused from
crg_udc_suspend() and crg_udc_resume()) so the PM callbacks and ops struct
are omitted when CONFIG_PM_SLEEP is disabled?

[ ... ]

>
endasi

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-axiado-ax3000-usb-device-controller-v3-0-3012ecfc0a93@axiado.com?part=6

      reply	other threads:[~2026-10-20  9:52 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-20  7:18 [PATCH v3 0/6] Axiado AX3000 and AX3005 USB Device Controller (UDC) Petar Stepanovic
2026-10-20  7:18 ` [PATCH v3 1/6] dt-bindings: usb: gadget: udc: add Axiado AX3000 and AX3005 UDC Petar Stepanovic
2026-10-20  8:36   ` sashiko-bot
2026-10-20  7:18 ` [PATCH v3 2/6] usb: gadget: udc: crg: Add hardware definitions and structs Petar Stepanovic
2026-10-20  8:37   ` sashiko-bot
2026-10-20  7:18 ` [PATCH v3 3/6] usb: gadget: udc: crg: Add ring and transfer management Petar Stepanovic
2026-10-20  8:58   ` sashiko-bot
2026-10-20  7:18 ` [PATCH v3 4/6] usb: gadget: udc: crg: Add endpoint 0 handling Petar Stepanovic
2026-10-20 10:01   ` sashiko-bot
2026-10-20  7:18 ` [PATCH v3 5/6] usb: gadget: udc: crg: Add gadget and endpoint operations Petar Stepanovic
2026-10-20 10:01   ` sashiko-bot
2026-10-20  7:19 ` [PATCH v3 6/6] usb: gadget: udc: crg: Add core driver and build integration Petar Stepanovic
2026-10-20  9:52   ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-178767@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=pstepanovic@axiado.com \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.