1
0
mirror of https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2026-01-11 17:10:13 +00:00

USB fixes for 6.19-rc3

Here are some small USB fixes, and bunch of reverts for 6.19-rc3.
 Included in here are:
   - reverts of some typec ucsi driver changes that had a lot of
     regression reports after -rc1.  Let's just revert it all for now and
     it will come back in a way that is better tested.
   - other typec bugfixes
   - usb-storage quirk fixups
   - dwc3 driver fix
   - other minor USB fixes for reported problems.
 
 All of these have passed 0-day testing and individual testing.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCaVElGw8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ylMeQCgzsZZNX7AtfUXlHkFENzlKFyAYZEAn0Nl01xd
 BBKmE3GqGMWsVIJ2T0AI
 =cjZ8
 -----END PGP SIGNATURE-----

Merge tag 'usb-6.19-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are some small USB fixes, and bunch of reverts for 6.19-rc3.
  Included in here are:

   - reverts of some typec ucsi driver changes that had a lot of
     regression reports after -rc1. Let's just revert it all for now and
     it will come back in a way that is better tested.

   - other typec bugfixes

   - usb-storage quirk fixups

   - dwc3 driver fix

   - other minor USB fixes for reported problems.

  All of these have passed 0-day testing and individual testing"

* tag 'usb-6.19-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (22 commits)
  Revert "usb: typec: ucsi: Update UCSI structure to have message in and message out fields"
  Revert "usb: typec: ucsi: Add support for message out data structure"
  Revert "usb: typec: ucsi: Enable debugfs for message_out data structure"
  Revert "usb: typec: ucsi: Add support for SET_PDOS command"
  Revert "usb: typec: ucsi: Fix null pointer dereference in ucsi_sync_control_common"
  Revert "usb: typec: ucsi: Get connector status after enable notifications"
  usb: ohci-nxp: clean up probe error labels
  usb: gadget: lpc32xx_udc: clean up probe error labels
  usb: ohci-nxp: fix device leak on probe failure
  usb: phy: isp1301: fix non-OF device reference imbalance
  usb: gadget: lpc32xx_udc: fix clock imbalance in error path
  usb: typec: ucsi: Get connector status after enable notifications
  usb: usb-storage: Maintain minimal modifications to the bcdDevice range.
  usb: dwc3: of-simple: fix clock resource leak in dwc3_of_simple_probe
  usb: typec: ucsi: Fix null pointer dereference in ucsi_sync_control_common
  USB: lpc32xx_udc: Fix error handling in probe
  usb: typec: altmodes/displayport: Drop the device reference in dp_altmode_probe()
  usb: phy: fsl-usb: Fix use-after-free in delayed work during device removal
  usb: renesas_usbhs: Fix a resource leak in usbhs_pipe_malloc()
  usb: typec: ucsi: huawei-gaokin: add DRM dependency
  ...
This commit is contained in:
Linus Torvalds 2025-12-28 10:21:47 -08:00
commit c875a6c324
20 changed files with 130 additions and 207 deletions

View File

@ -70,11 +70,11 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
simple->num_clocks = ret; simple->num_clocks = ret;
ret = clk_bulk_prepare_enable(simple->num_clocks, simple->clks); ret = clk_bulk_prepare_enable(simple->num_clocks, simple->clks);
if (ret) if (ret)
goto err_resetc_assert; goto err_clk_put_all;
ret = of_platform_populate(np, NULL, NULL, dev); ret = of_platform_populate(np, NULL, NULL, dev);
if (ret) if (ret)
goto err_clk_put; goto err_clk_disable;
pm_runtime_set_active(dev); pm_runtime_set_active(dev);
pm_runtime_enable(dev); pm_runtime_enable(dev);
@ -82,8 +82,9 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
return 0; return 0;
err_clk_put: err_clk_disable:
clk_bulk_disable_unprepare(simple->num_clocks, simple->clks); clk_bulk_disable_unprepare(simple->num_clocks, simple->clks);
err_clk_put_all:
clk_bulk_put_all(simple->num_clocks, simple->clks); clk_bulk_put_all(simple->num_clocks, simple->clks);
err_resetc_assert: err_resetc_assert:

View File

@ -4826,7 +4826,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
if (!dwc->gadget) if (!dwc->gadget)
return; return;
dwc3_enable_susphy(dwc, false); dwc3_enable_susphy(dwc, true);
usb_del_gadget(dwc->gadget); usb_del_gadget(dwc->gadget);
dwc3_gadget_free_endpoints(dwc); dwc3_gadget_free_endpoints(dwc);
usb_put_gadget(dwc->gadget); usb_put_gadget(dwc->gadget);

View File

@ -227,7 +227,7 @@ void dwc3_host_exit(struct dwc3 *dwc)
if (dwc->sys_wakeup) if (dwc->sys_wakeup)
device_init_wakeup(&dwc->xhci->dev, false); device_init_wakeup(&dwc->xhci->dev, false);
dwc3_enable_susphy(dwc, false); dwc3_enable_susphy(dwc, true);
platform_device_unregister(dwc->xhci); platform_device_unregister(dwc->xhci);
dwc->xhci = NULL; dwc->xhci = NULL;
} }

View File

@ -3020,7 +3020,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; pdev->dev.dma_mask = &lpc32xx_usbd_dmamask;
retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
if (retval) if (retval)
return retval; goto err_put_client;
udc->board = &lpc32xx_usbddata; udc->board = &lpc32xx_usbddata;
@ -3038,28 +3038,32 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
/* Get IRQs */ /* Get IRQs */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
udc->udp_irq[i] = platform_get_irq(pdev, i); udc->udp_irq[i] = platform_get_irq(pdev, i);
if (udc->udp_irq[i] < 0) if (udc->udp_irq[i] < 0) {
return udc->udp_irq[i]; retval = udc->udp_irq[i];
goto err_put_client;
}
} }
udc->udp_baseaddr = devm_platform_ioremap_resource(pdev, 0); udc->udp_baseaddr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(udc->udp_baseaddr)) { if (IS_ERR(udc->udp_baseaddr)) {
dev_err(udc->dev, "IO map failure\n"); dev_err(udc->dev, "IO map failure\n");
return PTR_ERR(udc->udp_baseaddr); retval = PTR_ERR(udc->udp_baseaddr);
goto err_put_client;
} }
/* Get USB device clock */ /* Get USB device clock */
udc->usb_slv_clk = devm_clk_get(&pdev->dev, NULL); udc->usb_slv_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(udc->usb_slv_clk)) { if (IS_ERR(udc->usb_slv_clk)) {
dev_err(udc->dev, "failed to acquire USB device clock\n"); dev_err(udc->dev, "failed to acquire USB device clock\n");
return PTR_ERR(udc->usb_slv_clk); retval = PTR_ERR(udc->usb_slv_clk);
goto err_put_client;
} }
/* Enable USB device clock */ /* Enable USB device clock */
retval = clk_prepare_enable(udc->usb_slv_clk); retval = clk_prepare_enable(udc->usb_slv_clk);
if (retval < 0) { if (retval < 0) {
dev_err(udc->dev, "failed to start USB device clock\n"); dev_err(udc->dev, "failed to start USB device clock\n");
return retval; goto err_put_client;
} }
/* Setup deferred workqueue data */ /* Setup deferred workqueue data */
@ -3080,7 +3084,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
if (!udc->udca_v_base) { if (!udc->udca_v_base) {
dev_err(udc->dev, "error getting UDCA region\n"); dev_err(udc->dev, "error getting UDCA region\n");
retval = -ENOMEM; retval = -ENOMEM;
goto i2c_fail; goto err_disable_clk;
} }
udc->udca_p_base = dma_handle; udc->udca_p_base = dma_handle;
dev_dbg(udc->dev, "DMA buffer(0x%x bytes), P:0x%08x, V:0x%p\n", dev_dbg(udc->dev, "DMA buffer(0x%x bytes), P:0x%08x, V:0x%p\n",
@ -3093,7 +3097,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
if (!udc->dd_cache) { if (!udc->dd_cache) {
dev_err(udc->dev, "error getting DD DMA region\n"); dev_err(udc->dev, "error getting DD DMA region\n");
retval = -ENOMEM; retval = -ENOMEM;
goto dma_alloc_fail; goto err_free_dma;
} }
/* Clear USB peripheral and initialize gadget endpoints */ /* Clear USB peripheral and initialize gadget endpoints */
@ -3107,14 +3111,14 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
if (retval < 0) { if (retval < 0) {
dev_err(udc->dev, "LP request irq %d failed\n", dev_err(udc->dev, "LP request irq %d failed\n",
udc->udp_irq[IRQ_USB_LP]); udc->udp_irq[IRQ_USB_LP]);
goto irq_req_fail; goto err_destroy_pool;
} }
retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_HP], retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_HP],
lpc32xx_usb_hp_irq, 0, "udc_hp", udc); lpc32xx_usb_hp_irq, 0, "udc_hp", udc);
if (retval < 0) { if (retval < 0) {
dev_err(udc->dev, "HP request irq %d failed\n", dev_err(udc->dev, "HP request irq %d failed\n",
udc->udp_irq[IRQ_USB_HP]); udc->udp_irq[IRQ_USB_HP]);
goto irq_req_fail; goto err_destroy_pool;
} }
retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_DEVDMA], retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_DEVDMA],
@ -3122,7 +3126,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
if (retval < 0) { if (retval < 0) {
dev_err(udc->dev, "DEV request irq %d failed\n", dev_err(udc->dev, "DEV request irq %d failed\n",
udc->udp_irq[IRQ_USB_DEVDMA]); udc->udp_irq[IRQ_USB_DEVDMA]);
goto irq_req_fail; goto err_destroy_pool;
} }
/* The transceiver interrupt is used for VBUS detection and will /* The transceiver interrupt is used for VBUS detection and will
@ -3133,7 +3137,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
if (retval < 0) { if (retval < 0) {
dev_err(udc->dev, "VBUS request irq %d failed\n", dev_err(udc->dev, "VBUS request irq %d failed\n",
udc->udp_irq[IRQ_USB_ATX]); udc->udp_irq[IRQ_USB_ATX]);
goto irq_req_fail; goto err_destroy_pool;
} }
/* Initialize wait queue */ /* Initialize wait queue */
@ -3142,7 +3146,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
retval = usb_add_gadget_udc(dev, &udc->gadget); retval = usb_add_gadget_udc(dev, &udc->gadget);
if (retval < 0) if (retval < 0)
goto add_gadget_fail; goto err_destroy_pool;
dev_set_drvdata(dev, udc); dev_set_drvdata(dev, udc);
device_init_wakeup(dev, 1); device_init_wakeup(dev, 1);
@ -3154,14 +3158,16 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
dev_info(udc->dev, "%s version %s\n", driver_name, DRIVER_VERSION); dev_info(udc->dev, "%s version %s\n", driver_name, DRIVER_VERSION);
return 0; return 0;
add_gadget_fail: err_destroy_pool:
irq_req_fail:
dma_pool_destroy(udc->dd_cache); dma_pool_destroy(udc->dd_cache);
dma_alloc_fail: err_free_dma:
dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
udc->udca_v_base, udc->udca_p_base); udc->udca_v_base, udc->udca_p_base);
i2c_fail: err_disable_clk:
clk_disable_unprepare(udc->usb_slv_clk); clk_disable_unprepare(udc->usb_slv_clk);
err_put_client:
put_device(&udc->isp1301_i2c_client->dev);
dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval);
return retval; return retval;
@ -3190,6 +3196,8 @@ static void lpc32xx_udc_remove(struct platform_device *pdev)
udc->udca_v_base, udc->udca_p_base); udc->udca_v_base, udc->udca_p_base);
clk_disable_unprepare(udc->usb_slv_clk); clk_disable_unprepare(udc->usb_slv_clk);
put_device(&udc->isp1301_i2c_client->dev);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM

View File

@ -169,13 +169,13 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev)
ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (ret) if (ret)
goto fail_disable; goto err_put_client;
dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name); dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name);
if (usb_disabled()) { if (usb_disabled()) {
dev_err(&pdev->dev, "USB is disabled\n"); dev_err(&pdev->dev, "USB is disabled\n");
ret = -ENODEV; ret = -ENODEV;
goto fail_disable; goto err_put_client;
} }
/* Enable USB host clock */ /* Enable USB host clock */
@ -183,7 +183,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev)
if (IS_ERR(usb_host_clk)) { if (IS_ERR(usb_host_clk)) {
dev_err(&pdev->dev, "failed to acquire and start USB OHCI clock\n"); dev_err(&pdev->dev, "failed to acquire and start USB OHCI clock\n");
ret = PTR_ERR(usb_host_clk); ret = PTR_ERR(usb_host_clk);
goto fail_disable; goto err_put_client;
} }
isp1301_configure(); isp1301_configure();
@ -192,13 +192,13 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev)
if (!hcd) { if (!hcd) {
dev_err(&pdev->dev, "Failed to allocate HC buffer\n"); dev_err(&pdev->dev, "Failed to allocate HC buffer\n");
ret = -ENOMEM; ret = -ENOMEM;
goto fail_disable; goto err_put_client;
} }
hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(hcd->regs)) { if (IS_ERR(hcd->regs)) {
ret = PTR_ERR(hcd->regs); ret = PTR_ERR(hcd->regs);
goto fail_resource; goto err_put_hcd;
} }
hcd->rsrc_start = res->start; hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res); hcd->rsrc_len = resource_size(res);
@ -206,7 +206,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
ret = -ENXIO; ret = -ENXIO;
goto fail_resource; goto err_put_hcd;
} }
ohci_nxp_start_hc(); ohci_nxp_start_hc();
@ -220,9 +220,10 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev)
} }
ohci_nxp_stop_hc(); ohci_nxp_stop_hc();
fail_resource: err_put_hcd:
usb_put_hcd(hcd); usb_put_hcd(hcd);
fail_disable: err_put_client:
put_device(&isp1301_i2c_client->dev);
isp1301_i2c_client = NULL; isp1301_i2c_client = NULL;
return ret; return ret;
} }
@ -234,6 +235,7 @@ static void ohci_hcd_nxp_remove(struct platform_device *pdev)
usb_remove_hcd(hcd); usb_remove_hcd(hcd);
ohci_nxp_stop_hc(); ohci_nxp_stop_hc();
usb_put_hcd(hcd); usb_put_hcd(hcd);
put_device(&isp1301_i2c_client->dev);
isp1301_i2c_client = NULL; isp1301_i2c_client = NULL;
} }

View File

@ -554,7 +554,7 @@ static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc)
* Hang up the TTY. This wakes up any blocked * Hang up the TTY. This wakes up any blocked
* writers and causes subsequent writes to fail. * writers and causes subsequent writes to fail.
*/ */
tty_vhangup(port->port.tty); tty_port_tty_vhangup(&port->port);
tty_unregister_device(dbc_tty_driver, port->minor); tty_unregister_device(dbc_tty_driver, port->minor);
xhci_dbc_tty_exit_port(port); xhci_dbc_tty_exit_port(port);

View File

@ -988,6 +988,7 @@ static void fsl_otg_remove(struct platform_device *pdev)
{ {
struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
disable_delayed_work_sync(&fsl_otg_dev->otg_event);
usb_remove_phy(&fsl_otg_dev->phy); usb_remove_phy(&fsl_otg_dev->phy);
free_irq(fsl_otg_dev->irq, fsl_otg_dev); free_irq(fsl_otg_dev->irq, fsl_otg_dev);

View File

@ -149,7 +149,12 @@ struct i2c_client *isp1301_get_client(struct device_node *node)
return client; return client;
/* non-DT: only one ISP1301 chip supported */ /* non-DT: only one ISP1301 chip supported */
return isp1301_i2c_client; if (isp1301_i2c_client) {
get_device(&isp1301_i2c_client->dev);
return isp1301_i2c_client;
}
return NULL;
} }
EXPORT_SYMBOL_GPL(isp1301_get_client); EXPORT_SYMBOL_GPL(isp1301_get_client);

View File

@ -713,11 +713,13 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv,
/* make sure pipe is not busy */ /* make sure pipe is not busy */
ret = usbhsp_pipe_barrier(pipe); ret = usbhsp_pipe_barrier(pipe);
if (ret < 0) { if (ret < 0) {
usbhsp_put_pipe(pipe);
dev_err(dev, "pipe setup failed %d\n", usbhs_pipe_number(pipe)); dev_err(dev, "pipe setup failed %d\n", usbhs_pipe_number(pipe));
return NULL; return NULL;
} }
if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, &pipecfg)) { if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, &pipecfg)) {
usbhsp_put_pipe(pipe);
dev_err(dev, "can't setup pipe\n"); dev_err(dev, "can't setup pipe\n");
return NULL; return NULL;
} }

View File

@ -98,7 +98,7 @@ UNUSUAL_DEV(0x125f, 0xa94a, 0x0160, 0x0160,
US_FL_NO_ATA_1X), US_FL_NO_ATA_1X),
/* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */ /* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
UNUSUAL_DEV(0x13fd, 0x3940, 0x0309, 0x0309, UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x0309,
"Initio Corporation", "Initio Corporation",
"INIC-3069", "INIC-3069",
USB_SC_DEVICE, USB_PR_DEVICE, NULL, USB_SC_DEVICE, USB_PR_DEVICE, NULL,

View File

@ -766,12 +766,16 @@ int dp_altmode_probe(struct typec_altmode *alt)
if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) & if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) &
DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) && DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) &&
!(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) & !(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) &
DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo))) DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo))) {
typec_altmode_put_plug(plug);
return -ENODEV; return -ENODEV;
}
dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL); dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL);
if (!dp) if (!dp) {
typec_altmode_put_plug(plug);
return -ENOMEM; return -ENOMEM;
}
INIT_WORK(&dp->work, dp_altmode_work); INIT_WORK(&dp->work, dp_altmode_work);
mutex_init(&dp->lock); mutex_init(&dp->lock);

View File

@ -96,6 +96,7 @@ config UCSI_LENOVO_YOGA_C630
config UCSI_HUAWEI_GAOKUN config UCSI_HUAWEI_GAOKUN
tristate "UCSI Interface Driver for Huawei Matebook E Go" tristate "UCSI Interface Driver for Huawei Matebook E Go"
depends on EC_HUAWEI_GAOKUN depends on EC_HUAWEI_GAOKUN
depends on DRM || !DRM
select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF
help help
This driver enables UCSI support on the Huawei Matebook E Go tablet, This driver enables UCSI support on the Huawei Matebook E Go tablet,

View File

@ -105,12 +105,13 @@ static int cros_ucsi_async_control(struct ucsi *ucsi, u64 cmd)
return 0; return 0;
} }
static int cros_ucsi_sync_control(struct ucsi *ucsi, u64 cmd, u32 *cci) static int cros_ucsi_sync_control(struct ucsi *ucsi, u64 cmd, u32 *cci,
void *data, size_t size)
{ {
struct cros_ucsi_data *udata = ucsi_get_drvdata(ucsi); struct cros_ucsi_data *udata = ucsi_get_drvdata(ucsi);
int ret; int ret;
ret = ucsi_sync_control_common(ucsi, cmd, cci); ret = ucsi_sync_control_common(ucsi, cmd, cci, data, size);
switch (ret) { switch (ret) {
case -EBUSY: case -EBUSY:
/* EC may return -EBUSY if CCI.busy is set. /* EC may return -EBUSY if CCI.busy is set.

View File

@ -37,9 +37,7 @@ static int ucsi_cmd(void *data, u64 val)
case UCSI_SET_USB: case UCSI_SET_USB:
case UCSI_SET_POWER_LEVEL: case UCSI_SET_POWER_LEVEL:
case UCSI_READ_POWER_LEVEL: case UCSI_READ_POWER_LEVEL:
case UCSI_SET_PDOS: ret = ucsi_send_command(ucsi, val, NULL, 0);
ucsi->message_in_size = 0;
ret = ucsi_send_command(ucsi, val);
break; break;
case UCSI_GET_CAPABILITY: case UCSI_GET_CAPABILITY:
case UCSI_GET_CONNECTOR_CAPABILITY: case UCSI_GET_CONNECTOR_CAPABILITY:
@ -54,9 +52,9 @@ static int ucsi_cmd(void *data, u64 val)
case UCSI_GET_ATTENTION_VDO: case UCSI_GET_ATTENTION_VDO:
case UCSI_GET_CAM_CS: case UCSI_GET_CAM_CS:
case UCSI_GET_LPM_PPM_INFO: case UCSI_GET_LPM_PPM_INFO:
ucsi->message_in_size = sizeof(ucsi->debugfs->response); ret = ucsi_send_command(ucsi, val,
ret = ucsi_send_command(ucsi, val); &ucsi->debugfs->response,
memcpy(&ucsi->debugfs->response, ucsi->message_in, sizeof(ucsi->debugfs->response)); sizeof(ucsi->debugfs->response));
break; break;
default: default:
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
@ -111,30 +109,6 @@ static int ucsi_vbus_volt_show(struct seq_file *m, void *v)
} }
DEFINE_SHOW_ATTRIBUTE(ucsi_vbus_volt); DEFINE_SHOW_ATTRIBUTE(ucsi_vbus_volt);
static ssize_t ucsi_message_out_write(struct file *file,
const char __user *data, size_t count, loff_t *ppos)
{
struct ucsi *ucsi = file->private_data;
int ret;
char *buf __free(kfree) = memdup_user_nul(data, count);
if (IS_ERR(buf))
return PTR_ERR(buf);
ucsi->message_out_size = min(count / 2, UCSI_MAX_MESSAGE_OUT_LENGTH);
ret = hex2bin(ucsi->message_out, buf, ucsi->message_out_size);
if (ret)
return ret;
return count;
}
static const struct file_operations ucsi_message_out_fops = {
.open = simple_open,
.write = ucsi_message_out_write,
.llseek = generic_file_llseek,
};
void ucsi_debugfs_register(struct ucsi *ucsi) void ucsi_debugfs_register(struct ucsi *ucsi)
{ {
ucsi->debugfs = kzalloc(sizeof(*ucsi->debugfs), GFP_KERNEL); ucsi->debugfs = kzalloc(sizeof(*ucsi->debugfs), GFP_KERNEL);
@ -147,8 +121,6 @@ void ucsi_debugfs_register(struct ucsi *ucsi)
debugfs_create_file("peak_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_peak_curr_fops); debugfs_create_file("peak_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_peak_curr_fops);
debugfs_create_file("avg_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_avg_curr_fops); debugfs_create_file("avg_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_avg_curr_fops);
debugfs_create_file("vbus_voltage", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_vbus_volt_fops); debugfs_create_file("vbus_voltage", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_vbus_volt_fops);
debugfs_create_file("message_out", 0200, ucsi->debugfs->dentry, ucsi,
&ucsi_message_out_fops);
} }
void ucsi_debugfs_unregister(struct ucsi *ucsi) void ucsi_debugfs_unregister(struct ucsi *ucsi)

View File

@ -67,14 +67,11 @@ static int ucsi_displayport_enter(struct typec_altmode *alt, u32 *vdo)
} }
command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(dp->con->num); command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(dp->con->num);
ucsi->message_in_size = sizeof(cur); ret = ucsi_send_command(ucsi, command, &cur, sizeof(cur));
ret = ucsi_send_command(ucsi, command);
if (ret < 0) { if (ret < 0) {
if (ucsi->version > 0x0100) if (ucsi->version > 0x0100)
goto err_unlock; goto err_unlock;
cur = 0xff; cur = 0xff;
} else {
memcpy(&cur, ucsi->message_in, ucsi->message_in_size);
} }
if (cur != 0xff) { if (cur != 0xff) {
@ -129,8 +126,7 @@ static int ucsi_displayport_exit(struct typec_altmode *alt)
} }
command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 0, dp->offset, 0); command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 0, dp->offset, 0);
dp->con->ucsi->message_in_size = 0; ret = ucsi_send_command(dp->con->ucsi, command, NULL, 0);
ret = ucsi_send_command(dp->con->ucsi, command);
if (ret < 0) if (ret < 0)
goto out_unlock; goto out_unlock;
@ -197,8 +193,7 @@ static int ucsi_displayport_configure(struct ucsi_dp *dp)
command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, pins); command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, pins);
dp->con->ucsi->message_in_size = 0; return ucsi_send_command(dp->con->ucsi, command, NULL, 0);
return ucsi_send_command(dp->con->ucsi, command);
} }
static int ucsi_displayport_vdm(struct typec_altmode *alt, static int ucsi_displayport_vdm(struct typec_altmode *alt,

View File

@ -55,7 +55,8 @@ void ucsi_notify_common(struct ucsi *ucsi, u32 cci)
} }
EXPORT_SYMBOL_GPL(ucsi_notify_common); EXPORT_SYMBOL_GPL(ucsi_notify_common);
int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci) int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci,
void *data, size_t size)
{ {
bool ack = UCSI_COMMAND(command) == UCSI_ACK_CC_CI; bool ack = UCSI_COMMAND(command) == UCSI_ACK_CC_CI;
int ret; int ret;
@ -67,20 +68,6 @@ int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci)
reinit_completion(&ucsi->complete); reinit_completion(&ucsi->complete);
if (ucsi->message_out_size > 0) {
if (!ucsi->ops->write_message_out) {
ucsi->message_out_size = 0;
ret = -EOPNOTSUPP;
goto out_clear_bit;
}
ret = ucsi->ops->write_message_out(ucsi, ucsi->message_out,
ucsi->message_out_size);
ucsi->message_out_size = 0;
if (ret)
goto out_clear_bit;
}
ret = ucsi->ops->async_control(ucsi, command); ret = ucsi->ops->async_control(ucsi, command);
if (ret) if (ret)
goto out_clear_bit; goto out_clear_bit;
@ -97,10 +84,9 @@ out_clear_bit:
if (!ret && cci) if (!ret && cci)
ret = ucsi->ops->read_cci(ucsi, cci); ret = ucsi->ops->read_cci(ucsi, cci);
if (!ret && ucsi->message_in_size > 0 && if (!ret && data &&
(*cci & UCSI_CCI_COMMAND_COMPLETE)) (*cci & UCSI_CCI_COMMAND_COMPLETE))
ret = ucsi->ops->read_message_in(ucsi, ucsi->message_in, ret = ucsi->ops->read_message_in(ucsi, data, size);
ucsi->message_in_size);
return ret; return ret;
} }
@ -117,25 +103,23 @@ static int ucsi_acknowledge(struct ucsi *ucsi, bool conn_ack)
ctrl |= UCSI_ACK_CONNECTOR_CHANGE; ctrl |= UCSI_ACK_CONNECTOR_CHANGE;
} }
ucsi->message_in_size = 0; return ucsi->ops->sync_control(ucsi, ctrl, NULL, NULL, 0);
return ucsi->ops->sync_control(ucsi, ctrl, NULL);
} }
static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci, bool conn_ack) static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci,
void *data, size_t size, bool conn_ack)
{ {
int ret, err; int ret, err;
*cci = 0; *cci = 0;
if (ucsi->message_in_size > UCSI_MAX_DATA_LENGTH(ucsi)) if (size > UCSI_MAX_DATA_LENGTH(ucsi))
return -EINVAL; return -EINVAL;
ret = ucsi->ops->sync_control(ucsi, command, cci); ret = ucsi->ops->sync_control(ucsi, command, cci, data, size);
if (*cci & UCSI_CCI_BUSY) { if (*cci & UCSI_CCI_BUSY)
ucsi->message_in_size = 0; return ucsi_run_command(ucsi, UCSI_CANCEL, cci, NULL, 0, false) ?: -EBUSY;
return ucsi_run_command(ucsi, UCSI_CANCEL, cci, false) ?: -EBUSY;
}
if (ret) if (ret)
return ret; return ret;
@ -167,13 +151,10 @@ static int ucsi_read_error(struct ucsi *ucsi, u8 connector_num)
int ret; int ret;
command = UCSI_GET_ERROR_STATUS | UCSI_CONNECTOR_NUMBER(connector_num); command = UCSI_GET_ERROR_STATUS | UCSI_CONNECTOR_NUMBER(connector_num);
ucsi->message_in_size = sizeof(error); ret = ucsi_run_command(ucsi, command, &cci, &error, sizeof(error), false);
ret = ucsi_run_command(ucsi, command, &cci, false);
if (ret < 0) if (ret < 0)
return ret; return ret;
memcpy(&error, ucsi->message_in, sizeof(error));
switch (error) { switch (error) {
case UCSI_ERROR_INCOMPATIBLE_PARTNER: case UCSI_ERROR_INCOMPATIBLE_PARTNER:
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -219,7 +200,8 @@ static int ucsi_read_error(struct ucsi *ucsi, u8 connector_num)
return -EIO; return -EIO;
} }
static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, bool conn_ack) static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd,
void *data, size_t size, bool conn_ack)
{ {
u8 connector_num; u8 connector_num;
u32 cci; u32 cci;
@ -247,7 +229,7 @@ static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, bool conn_ack)
mutex_lock(&ucsi->ppm_lock); mutex_lock(&ucsi->ppm_lock);
ret = ucsi_run_command(ucsi, cmd, &cci, conn_ack); ret = ucsi_run_command(ucsi, cmd, &cci, data, size, conn_ack);
if (cci & UCSI_CCI_ERROR) if (cci & UCSI_CCI_ERROR)
ret = ucsi_read_error(ucsi, connector_num); ret = ucsi_read_error(ucsi, connector_num);
@ -256,9 +238,10 @@ static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, bool conn_ack)
return ret; return ret;
} }
int ucsi_send_command(struct ucsi *ucsi, u64 command) int ucsi_send_command(struct ucsi *ucsi, u64 command,
void *data, size_t size)
{ {
return ucsi_send_command_common(ucsi, command, false); return ucsi_send_command_common(ucsi, command, data, size, false);
} }
EXPORT_SYMBOL_GPL(ucsi_send_command); EXPORT_SYMBOL_GPL(ucsi_send_command);
@ -336,8 +319,7 @@ void ucsi_altmode_update_active(struct ucsi_connector *con)
int i; int i;
command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(con->num); command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(con->num);
con->ucsi->message_in_size = sizeof(cur); ret = ucsi_send_command(con->ucsi, command, &cur, sizeof(cur));
ret = ucsi_send_command(con->ucsi, command);
if (ret < 0) { if (ret < 0) {
if (con->ucsi->version > 0x0100) { if (con->ucsi->version > 0x0100) {
dev_err(con->ucsi->dev, dev_err(con->ucsi->dev,
@ -345,8 +327,6 @@ void ucsi_altmode_update_active(struct ucsi_connector *con)
return; return;
} }
cur = 0xff; cur = 0xff;
} else {
memcpy(&cur, con->ucsi->message_in, sizeof(cur));
} }
if (cur < UCSI_MAX_ALTMODES) if (cur < UCSI_MAX_ALTMODES)
@ -530,8 +510,7 @@ ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient)
command |= UCSI_GET_ALTMODE_RECIPIENT(recipient); command |= UCSI_GET_ALTMODE_RECIPIENT(recipient);
command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num); command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num);
command |= UCSI_GET_ALTMODE_OFFSET(i); command |= UCSI_GET_ALTMODE_OFFSET(i);
ucsi->message_in_size = sizeof(alt); len = ucsi_send_command(con->ucsi, command, &alt, sizeof(alt));
len = ucsi_send_command(con->ucsi, command);
/* /*
* We are collecting all altmodes first and then registering. * We are collecting all altmodes first and then registering.
* Some type-C device will return zero length data beyond last * Some type-C device will return zero length data beyond last
@ -540,8 +519,6 @@ ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient)
if (len < 0) if (len < 0)
return len; return len;
memcpy(&alt, ucsi->message_in, sizeof(alt));
/* We got all altmodes, now break out and register them */ /* We got all altmodes, now break out and register them */
if (!len || !alt.svid) if (!len || !alt.svid)
break; break;
@ -609,15 +586,12 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient)
command |= UCSI_GET_ALTMODE_RECIPIENT(recipient); command |= UCSI_GET_ALTMODE_RECIPIENT(recipient);
command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num); command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num);
command |= UCSI_GET_ALTMODE_OFFSET(i); command |= UCSI_GET_ALTMODE_OFFSET(i);
con->ucsi->message_in_size = sizeof(alt); len = ucsi_send_command(con->ucsi, command, alt, sizeof(alt));
len = ucsi_send_command(con->ucsi, command);
if (len == -EBUSY) if (len == -EBUSY)
continue; continue;
if (len <= 0) if (len <= 0)
return len; return len;
memcpy(&alt, con->ucsi->message_in, sizeof(alt));
/* /*
* This code is requesting one alt mode at a time, but some PPMs * This code is requesting one alt mode at a time, but some PPMs
* may still return two. If that happens both alt modes need be * may still return two. If that happens both alt modes need be
@ -685,9 +659,7 @@ static int ucsi_get_connector_status(struct ucsi_connector *con, bool conn_ack)
UCSI_MAX_DATA_LENGTH(con->ucsi)); UCSI_MAX_DATA_LENGTH(con->ucsi));
int ret; int ret;
con->ucsi->message_in_size = size; ret = ucsi_send_command_common(con->ucsi, command, &con->status, size, conn_ack);
ret = ucsi_send_command_common(con->ucsi, command, conn_ack);
memcpy(&con->status, con->ucsi->message_in, size);
return ret < 0 ? ret : 0; return ret < 0 ? ret : 0;
} }
@ -710,9 +682,8 @@ static int ucsi_read_pdos(struct ucsi_connector *con,
command |= UCSI_GET_PDOS_PDO_OFFSET(offset); command |= UCSI_GET_PDOS_PDO_OFFSET(offset);
command |= UCSI_GET_PDOS_NUM_PDOS(num_pdos - 1); command |= UCSI_GET_PDOS_NUM_PDOS(num_pdos - 1);
command |= is_source(role) ? UCSI_GET_PDOS_SRC_PDOS : 0; command |= is_source(role) ? UCSI_GET_PDOS_SRC_PDOS : 0;
ucsi->message_in_size = num_pdos * sizeof(u32); ret = ucsi_send_command(ucsi, command, pdos + offset,
ret = ucsi_send_command(ucsi, command); num_pdos * sizeof(u32));
memcpy(pdos + offset, ucsi->message_in, num_pdos * sizeof(u32));
if (ret < 0 && ret != -ETIMEDOUT) if (ret < 0 && ret != -ETIMEDOUT)
dev_err(ucsi->dev, "UCSI_GET_PDOS failed (%d)\n", ret); dev_err(ucsi->dev, "UCSI_GET_PDOS failed (%d)\n", ret);
@ -799,9 +770,7 @@ static int ucsi_get_pd_message(struct ucsi_connector *con, u8 recipient,
command |= UCSI_GET_PD_MESSAGE_BYTES(len); command |= UCSI_GET_PD_MESSAGE_BYTES(len);
command |= UCSI_GET_PD_MESSAGE_TYPE(type); command |= UCSI_GET_PD_MESSAGE_TYPE(type);
con->ucsi->message_in_size = len; ret = ucsi_send_command(con->ucsi, command, data + offset, len);
ret = ucsi_send_command(con->ucsi, command);
memcpy(data + offset, con->ucsi->message_in, len);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
@ -966,9 +935,7 @@ static int ucsi_register_cable(struct ucsi_connector *con)
int ret; int ret;
command = UCSI_GET_CABLE_PROPERTY | UCSI_CONNECTOR_NUMBER(con->num); command = UCSI_GET_CABLE_PROPERTY | UCSI_CONNECTOR_NUMBER(con->num);
con->ucsi->message_in_size = sizeof(cable_prop); ret = ucsi_send_command(con->ucsi, command, &cable_prop, sizeof(cable_prop));
ret = ucsi_send_command(con->ucsi, command);
memcpy(&cable_prop, con->ucsi->message_in, sizeof(cable_prop));
if (ret < 0) { if (ret < 0) {
dev_err(con->ucsi->dev, "GET_CABLE_PROPERTY failed (%d)\n", ret); dev_err(con->ucsi->dev, "GET_CABLE_PROPERTY failed (%d)\n", ret);
return ret; return ret;
@ -1029,9 +996,7 @@ static int ucsi_check_connector_capability(struct ucsi_connector *con)
return 0; return 0;
command = UCSI_GET_CONNECTOR_CAPABILITY | UCSI_CONNECTOR_NUMBER(con->num); command = UCSI_GET_CONNECTOR_CAPABILITY | UCSI_CONNECTOR_NUMBER(con->num);
con->ucsi->message_in_size = sizeof(con->cap); ret = ucsi_send_command(con->ucsi, command, &con->cap, sizeof(con->cap));
ret = ucsi_send_command(con->ucsi, command);
memcpy(&con->cap, con->ucsi->message_in, sizeof(con->cap));
if (ret < 0) { if (ret < 0) {
dev_err(con->ucsi->dev, "GET_CONNECTOR_CAPABILITY failed (%d)\n", ret); dev_err(con->ucsi->dev, "GET_CONNECTOR_CAPABILITY failed (%d)\n", ret);
return ret; return ret;
@ -1415,8 +1380,7 @@ static int ucsi_reset_connector(struct ucsi_connector *con, bool hard)
else if (con->ucsi->version >= UCSI_VERSION_2_0) else if (con->ucsi->version >= UCSI_VERSION_2_0)
command |= hard ? 0 : UCSI_CONNECTOR_RESET_DATA_VER_2_0; command |= hard ? 0 : UCSI_CONNECTOR_RESET_DATA_VER_2_0;
con->ucsi->message_in_size = 0; return ucsi_send_command(con->ucsi, command, NULL, 0);
return ucsi_send_command(con->ucsi, command);
} }
static int ucsi_reset_ppm(struct ucsi *ucsi) static int ucsi_reset_ppm(struct ucsi *ucsi)
@ -1497,8 +1461,7 @@ static int ucsi_role_cmd(struct ucsi_connector *con, u64 command)
{ {
int ret; int ret;
con->ucsi->message_in_size = 0; ret = ucsi_send_command(con->ucsi, command, NULL, 0);
ret = ucsi_send_command(con->ucsi, command);
if (ret == -ETIMEDOUT) { if (ret == -ETIMEDOUT) {
u64 c; u64 c;
@ -1506,8 +1469,7 @@ static int ucsi_role_cmd(struct ucsi_connector *con, u64 command)
ucsi_reset_ppm(con->ucsi); ucsi_reset_ppm(con->ucsi);
c = UCSI_SET_NOTIFICATION_ENABLE | con->ucsi->ntfy; c = UCSI_SET_NOTIFICATION_ENABLE | con->ucsi->ntfy;
con->ucsi->message_in_size = 0; ucsi_send_command(con->ucsi, c, NULL, 0);
ucsi_send_command(con->ucsi, c);
ucsi_reset_connector(con, true); ucsi_reset_connector(con, true);
} }
@ -1660,13 +1622,10 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
/* Get connector capability */ /* Get connector capability */
command = UCSI_GET_CONNECTOR_CAPABILITY; command = UCSI_GET_CONNECTOR_CAPABILITY;
command |= UCSI_CONNECTOR_NUMBER(con->num); command |= UCSI_CONNECTOR_NUMBER(con->num);
ucsi->message_in_size = sizeof(con->cap); ret = ucsi_send_command(ucsi, command, &con->cap, sizeof(con->cap));
ret = ucsi_send_command(ucsi, command);
if (ret < 0) if (ret < 0)
goto out_unlock; goto out_unlock;
memcpy(&con->cap, ucsi->message_in, sizeof(con->cap));
if (UCSI_CONCAP(con, OPMODE_DRP)) if (UCSI_CONCAP(con, OPMODE_DRP))
cap->data = TYPEC_PORT_DRD; cap->data = TYPEC_PORT_DRD;
else if (UCSI_CONCAP(con, OPMODE_DFP)) else if (UCSI_CONCAP(con, OPMODE_DFP))
@ -1863,20 +1822,17 @@ static int ucsi_init(struct ucsi *ucsi)
/* Enable basic notifications */ /* Enable basic notifications */
ntfy = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR; ntfy = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR;
command = UCSI_SET_NOTIFICATION_ENABLE | ntfy; command = UCSI_SET_NOTIFICATION_ENABLE | ntfy;
ucsi->message_in_size = 0; ret = ucsi_send_command(ucsi, command, NULL, 0);
ret = ucsi_send_command(ucsi, command);
if (ret < 0) if (ret < 0)
goto err_reset; goto err_reset;
/* Get PPM capabilities */ /* Get PPM capabilities */
command = UCSI_GET_CAPABILITY; command = UCSI_GET_CAPABILITY;
ucsi->message_in_size = BITS_TO_BYTES(UCSI_GET_CAPABILITY_SIZE); ret = ucsi_send_command(ucsi, command, &ucsi->cap,
ret = ucsi_send_command(ucsi, command); BITS_TO_BYTES(UCSI_GET_CAPABILITY_SIZE));
if (ret < 0) if (ret < 0)
goto err_reset; goto err_reset;
memcpy(&ucsi->cap, ucsi->message_in, BITS_TO_BYTES(UCSI_GET_CAPABILITY_SIZE));
if (!ucsi->cap.num_connectors) { if (!ucsi->cap.num_connectors) {
ret = -ENODEV; ret = -ENODEV;
goto err_reset; goto err_reset;
@ -1906,8 +1862,7 @@ static int ucsi_init(struct ucsi *ucsi)
/* Enable all supported notifications */ /* Enable all supported notifications */
ntfy = ucsi_get_supported_notifications(ucsi); ntfy = ucsi_get_supported_notifications(ucsi);
command = UCSI_SET_NOTIFICATION_ENABLE | ntfy; command = UCSI_SET_NOTIFICATION_ENABLE | ntfy;
ucsi->message_in_size = 0; ret = ucsi_send_command(ucsi, command, NULL, 0);
ret = ucsi_send_command(ucsi, command);
if (ret < 0) if (ret < 0)
goto err_unregister; goto err_unregister;
@ -1958,8 +1913,7 @@ static void ucsi_resume_work(struct work_struct *work)
/* Restore UCSI notification enable mask after system resume */ /* Restore UCSI notification enable mask after system resume */
command = UCSI_SET_NOTIFICATION_ENABLE | ucsi->ntfy; command = UCSI_SET_NOTIFICATION_ENABLE | ucsi->ntfy;
ucsi->message_in_size = 0; ret = ucsi_send_command(ucsi, command, NULL, 0);
ret = ucsi_send_command(ucsi, command);
if (ret < 0) { if (ret < 0) {
dev_err(ucsi->dev, "failed to re-enable notifications (%d)\n", ret); dev_err(ucsi->dev, "failed to re-enable notifications (%d)\n", ret);
return; return;

View File

@ -29,10 +29,6 @@ struct dentry;
#define UCSI_MESSAGE_OUT 32 #define UCSI_MESSAGE_OUT 32
#define UCSIv2_MESSAGE_OUT 272 #define UCSIv2_MESSAGE_OUT 272
/* Define maximum lengths for message buffers */
#define UCSI_MAX_MESSAGE_IN_LENGTH 256
#define UCSI_MAX_MESSAGE_OUT_LENGTH 256
/* UCSI versions */ /* UCSI versions */
#define UCSI_VERSION_1_0 0x0100 #define UCSI_VERSION_1_0 0x0100
#define UCSI_VERSION_1_1 0x0110 #define UCSI_VERSION_1_1 0x0110
@ -69,7 +65,6 @@ struct dentry;
* @read_cci: Read CCI register * @read_cci: Read CCI register
* @poll_cci: Read CCI register while polling with notifications disabled * @poll_cci: Read CCI register while polling with notifications disabled
* @read_message_in: Read message data from UCSI * @read_message_in: Read message data from UCSI
* @write_message_out: Write message data to UCSI
* @sync_control: Blocking control operation * @sync_control: Blocking control operation
* @async_control: Non-blocking control operation * @async_control: Non-blocking control operation
* @update_altmodes: Squashes duplicate DP altmodes * @update_altmodes: Squashes duplicate DP altmodes
@ -85,8 +80,8 @@ struct ucsi_operations {
int (*read_cci)(struct ucsi *ucsi, u32 *cci); int (*read_cci)(struct ucsi *ucsi, u32 *cci);
int (*poll_cci)(struct ucsi *ucsi, u32 *cci); int (*poll_cci)(struct ucsi *ucsi, u32 *cci);
int (*read_message_in)(struct ucsi *ucsi, void *val, size_t val_len); int (*read_message_in)(struct ucsi *ucsi, void *val, size_t val_len);
int (*write_message_out)(struct ucsi *ucsi, void *data, size_t data_len); int (*sync_control)(struct ucsi *ucsi, u64 command, u32 *cci,
int (*sync_control)(struct ucsi *ucsi, u64 command, u32 *cci); void *data, size_t size);
int (*async_control)(struct ucsi *ucsi, u64 command); int (*async_control)(struct ucsi *ucsi, u64 command);
bool (*update_altmodes)(struct ucsi *ucsi, u8 recipient, bool (*update_altmodes)(struct ucsi *ucsi, u8 recipient,
struct ucsi_altmode *orig, struct ucsi_altmode *orig,
@ -137,7 +132,6 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num);
#define UCSI_GET_PD_MESSAGE 0x15 #define UCSI_GET_PD_MESSAGE 0x15
#define UCSI_GET_CAM_CS 0x18 #define UCSI_GET_CAM_CS 0x18
#define UCSI_SET_SINK_PATH 0x1c #define UCSI_SET_SINK_PATH 0x1c
#define UCSI_SET_PDOS 0x1d
#define UCSI_READ_POWER_LEVEL 0x1e #define UCSI_READ_POWER_LEVEL 0x1e
#define UCSI_SET_USB 0x21 #define UCSI_SET_USB 0x21
#define UCSI_GET_LPM_PPM_INFO 0x22 #define UCSI_GET_LPM_PPM_INFO 0x22
@ -499,12 +493,6 @@ struct ucsi {
unsigned long quirks; unsigned long quirks;
#define UCSI_NO_PARTNER_PDOS BIT(0) /* Don't read partner's PDOs */ #define UCSI_NO_PARTNER_PDOS BIT(0) /* Don't read partner's PDOs */
#define UCSI_DELAY_DEVICE_PDOS BIT(1) /* Reading PDOs fails until the parter is in PD mode */ #define UCSI_DELAY_DEVICE_PDOS BIT(1) /* Reading PDOs fails until the parter is in PD mode */
/* Fixed-size buffers for incoming and outgoing messages */
u8 message_in[UCSI_MAX_MESSAGE_IN_LENGTH];
size_t message_in_size;
u8 message_out[UCSI_MAX_MESSAGE_OUT_LENGTH];
size_t message_out_size;
}; };
#define UCSI_MAX_DATA_LENGTH(u) (((u)->version < UCSI_VERSION_2_0) ? 0x10 : 0xff) #define UCSI_MAX_DATA_LENGTH(u) (((u)->version < UCSI_VERSION_2_0) ? 0x10 : 0xff)
@ -567,13 +555,15 @@ struct ucsi_connector {
struct usb_pd_identity cable_identity; struct usb_pd_identity cable_identity;
}; };
int ucsi_send_command(struct ucsi *ucsi, u64 command); int ucsi_send_command(struct ucsi *ucsi, u64 command,
void *retval, size_t size);
void ucsi_altmode_update_active(struct ucsi_connector *con); void ucsi_altmode_update_active(struct ucsi_connector *con);
int ucsi_resume(struct ucsi *ucsi); int ucsi_resume(struct ucsi *ucsi);
void ucsi_notify_common(struct ucsi *ucsi, u32 cci); void ucsi_notify_common(struct ucsi *ucsi, u32 cci);
int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci); int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci,
void *data, size_t size);
#if IS_ENABLED(CONFIG_POWER_SUPPLY) #if IS_ENABLED(CONFIG_POWER_SUPPLY)
int ucsi_register_port_psy(struct ucsi_connector *con); int ucsi_register_port_psy(struct ucsi_connector *con);

View File

@ -86,21 +86,6 @@ static int ucsi_acpi_read_message_in(struct ucsi *ucsi, void *val, size_t val_le
return 0; return 0;
} }
static int ucsi_acpi_write_message_out(struct ucsi *ucsi, void *data, size_t data_len)
{
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
if (!data || !data_len)
return -EINVAL;
if (ucsi->version <= UCSI_VERSION_1_2)
memcpy(ua->base + UCSI_MESSAGE_OUT, data, data_len);
else
memcpy(ua->base + UCSIv2_MESSAGE_OUT, data, data_len);
return 0;
}
static int ucsi_acpi_async_control(struct ucsi *ucsi, u64 command) static int ucsi_acpi_async_control(struct ucsi *ucsi, u64 command)
{ {
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
@ -116,19 +101,19 @@ static const struct ucsi_operations ucsi_acpi_ops = {
.read_cci = ucsi_acpi_read_cci, .read_cci = ucsi_acpi_read_cci,
.poll_cci = ucsi_acpi_poll_cci, .poll_cci = ucsi_acpi_poll_cci,
.read_message_in = ucsi_acpi_read_message_in, .read_message_in = ucsi_acpi_read_message_in,
.write_message_out = ucsi_acpi_write_message_out,
.sync_control = ucsi_sync_control_common, .sync_control = ucsi_sync_control_common,
.async_control = ucsi_acpi_async_control .async_control = ucsi_acpi_async_control
}; };
static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command, u32 *cci) static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command, u32 *cci,
void *val, size_t len)
{ {
u16 bogus_change = UCSI_CONSTAT_POWER_LEVEL_CHANGE | u16 bogus_change = UCSI_CONSTAT_POWER_LEVEL_CHANGE |
UCSI_CONSTAT_PDOS_CHANGE; UCSI_CONSTAT_PDOS_CHANGE;
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
int ret; int ret;
ret = ucsi_sync_control_common(ucsi, command, cci); ret = ucsi_sync_control_common(ucsi, command, cci, val, len);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -140,8 +125,8 @@ static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command, u32 *cci)
if (UCSI_COMMAND(ua->cmd) == UCSI_GET_CONNECTOR_STATUS && if (UCSI_COMMAND(ua->cmd) == UCSI_GET_CONNECTOR_STATUS &&
ua->check_bogus_event) { ua->check_bogus_event) {
/* Clear the bogus change */ /* Clear the bogus change */
if (*(u16 *)ucsi->message_in == bogus_change) if (*(u16 *)val == bogus_change)
*(u16 *)ucsi->message_in = 0; *(u16 *)val = 0;
ua->check_bogus_event = false; ua->check_bogus_event = false;
} }

View File

@ -606,7 +606,8 @@ static int ucsi_ccg_async_control(struct ucsi *ucsi, u64 command)
return ccg_write(uc, reg, (u8 *)&command, sizeof(command)); return ccg_write(uc, reg, (u8 *)&command, sizeof(command));
} }
static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci) static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci,
void *data, size_t size)
{ {
struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi); struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi);
struct ucsi_connector *con; struct ucsi_connector *con;
@ -628,16 +629,16 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci)
ucsi_ccg_update_set_new_cam_cmd(uc, con, &command); ucsi_ccg_update_set_new_cam_cmd(uc, con, &command);
} }
ret = ucsi_sync_control_common(ucsi, command, cci); ret = ucsi_sync_control_common(ucsi, command, cci, data, size);
switch (UCSI_COMMAND(command)) { switch (UCSI_COMMAND(command)) {
case UCSI_GET_CURRENT_CAM: case UCSI_GET_CURRENT_CAM:
if (uc->has_multiple_dp) if (uc->has_multiple_dp)
ucsi_ccg_update_get_current_cam_cmd(uc, (u8 *)ucsi->message_in); ucsi_ccg_update_get_current_cam_cmd(uc, (u8 *)data);
break; break;
case UCSI_GET_ALTERNATE_MODES: case UCSI_GET_ALTERNATE_MODES:
if (UCSI_ALTMODE_RECIPIENT(command) == UCSI_RECIPIENT_SOP) { if (UCSI_ALTMODE_RECIPIENT(command) == UCSI_RECIPIENT_SOP) {
struct ucsi_altmode *alt = (struct ucsi_altmode *)ucsi->message_in; struct ucsi_altmode *alt = data;
if (alt[0].svid == USB_TYPEC_NVIDIA_VLINK_SID) if (alt[0].svid == USB_TYPEC_NVIDIA_VLINK_SID)
ucsi_ccg_nvidia_altmode(uc, alt, command); ucsi_ccg_nvidia_altmode(uc, alt, command);
@ -645,7 +646,7 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci)
break; break;
case UCSI_GET_CAPABILITY: case UCSI_GET_CAPABILITY:
if (uc->fw_build == CCG_FW_BUILD_NVIDIA_TEGRA) { if (uc->fw_build == CCG_FW_BUILD_NVIDIA_TEGRA) {
struct ucsi_capability *cap = (struct ucsi_capability *)ucsi->message_in; struct ucsi_capability *cap = data;
cap->features &= ~UCSI_CAP_ALT_MODE_DETAILS; cap->features &= ~UCSI_CAP_ALT_MODE_DETAILS;
} }

View File

@ -88,7 +88,8 @@ static int yoga_c630_ucsi_async_control(struct ucsi *ucsi, u64 command)
static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi, static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi,
u64 command, u64 command,
u32 *cci) u32 *cci,
void *data, size_t size)
{ {
int ret; int ret;
@ -106,8 +107,8 @@ static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi,
}; };
dev_dbg(ucsi->dev, "faking DP altmode for con1\n"); dev_dbg(ucsi->dev, "faking DP altmode for con1\n");
memset(ucsi->message_in, 0, ucsi->message_in_size); memset(data, 0, size);
memcpy(ucsi->message_in, &alt, min(sizeof(alt), ucsi->message_in_size)); memcpy(data, &alt, min(sizeof(alt), size));
*cci = UCSI_CCI_COMMAND_COMPLETE | UCSI_SET_CCI_LENGTH(sizeof(alt)); *cci = UCSI_CCI_COMMAND_COMPLETE | UCSI_SET_CCI_LENGTH(sizeof(alt));
return 0; return 0;
} }
@ -120,18 +121,18 @@ static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi,
if (UCSI_COMMAND(command) == UCSI_GET_ALTERNATE_MODES && if (UCSI_COMMAND(command) == UCSI_GET_ALTERNATE_MODES &&
UCSI_GET_ALTMODE_GET_CONNECTOR_NUMBER(command) == 2) { UCSI_GET_ALTMODE_GET_CONNECTOR_NUMBER(command) == 2) {
dev_dbg(ucsi->dev, "ignoring altmodes for con2\n"); dev_dbg(ucsi->dev, "ignoring altmodes for con2\n");
memset(ucsi->message_in, 0, ucsi->message_in_size); memset(data, 0, size);
*cci = UCSI_CCI_COMMAND_COMPLETE; *cci = UCSI_CCI_COMMAND_COMPLETE;
return 0; return 0;
} }
ret = ucsi_sync_control_common(ucsi, command, cci); ret = ucsi_sync_control_common(ucsi, command, cci, data, size);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* UCSI_GET_CURRENT_CAM is off-by-one on all ports */ /* UCSI_GET_CURRENT_CAM is off-by-one on all ports */
if (UCSI_COMMAND(command) == UCSI_GET_CURRENT_CAM && ucsi->message_in_size > 0) if (UCSI_COMMAND(command) == UCSI_GET_CURRENT_CAM && data)
ucsi->message_in[0]--; ((u8 *)data)[0]--;
return ret; return ret;
} }