Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: typec: ucsi: Get connector status after enable notifications

Originally, the notification for connector change will be enabled after
the first read of the connector status. Therefore, if the event happens
during this window, it will be missing and make the status unsynced.

Get the connector status only after enabling the notification for
connector change to ensure the status is synced.

Fixes: c1b0bc2dabfa ("usb: typec: Add support for UCSI interface")
Cc: stable <stable@kernel.org>
Tested-by: Kenneth R. Crudup <kenny@panix.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Hsin-Te Yuan <yuanhsinte@chromium.org>
Link: https://patch.msgid.link/20251218-ucsi-v7-1-aea83e83fb12@chromium.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Hsin-Te Yuan and committed by
Greg Kroah-Hartman
5106dbab 0831269b

+74 -59
+74 -59
drivers/usb/typec/ucsi/ucsi.c
··· 1624 1624 return NULL; 1625 1625 } 1626 1626 1627 + static void ucsi_init_port(struct ucsi *ucsi, struct ucsi_connector *con) 1628 + { 1629 + enum usb_role u_role = USB_ROLE_NONE; 1630 + int ret; 1631 + 1632 + /* Get the status */ 1633 + ret = ucsi_get_connector_status(con, false); 1634 + if (ret) { 1635 + dev_err(ucsi->dev, "con%d: failed to get status\n", con->num); 1636 + return; 1637 + } 1638 + 1639 + if (ucsi->ops->connector_status) 1640 + ucsi->ops->connector_status(con); 1641 + 1642 + switch (UCSI_CONSTAT(con, PARTNER_TYPE)) { 1643 + case UCSI_CONSTAT_PARTNER_TYPE_UFP: 1644 + case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: 1645 + u_role = USB_ROLE_HOST; 1646 + fallthrough; 1647 + case UCSI_CONSTAT_PARTNER_TYPE_CABLE: 1648 + typec_set_data_role(con->port, TYPEC_HOST); 1649 + break; 1650 + case UCSI_CONSTAT_PARTNER_TYPE_DFP: 1651 + u_role = USB_ROLE_DEVICE; 1652 + typec_set_data_role(con->port, TYPEC_DEVICE); 1653 + break; 1654 + default: 1655 + break; 1656 + } 1657 + 1658 + /* Check if there is already something connected */ 1659 + if (UCSI_CONSTAT(con, CONNECTED)) { 1660 + typec_set_pwr_role(con->port, UCSI_CONSTAT(con, PWR_DIR)); 1661 + ucsi_register_partner(con); 1662 + ucsi_pwr_opmode_change(con); 1663 + ucsi_orientation(con); 1664 + ucsi_port_psy_changed(con); 1665 + if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE) 1666 + ucsi_get_partner_identity(con); 1667 + if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS) 1668 + ucsi_check_cable(con); 1669 + } 1670 + 1671 + /* Only notify USB controller if partner supports USB data */ 1672 + if (!(UCSI_CONSTAT(con, PARTNER_FLAG_USB))) 1673 + u_role = USB_ROLE_NONE; 1674 + 1675 + ret = usb_role_switch_set_role(con->usb_role_sw, u_role); 1676 + if (ret) 1677 + dev_err(ucsi->dev, "con:%d: failed to set usb role:%d\n", 1678 + con->num, u_role); 1679 + 1680 + if (con->partner && UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) { 1681 + ucsi_register_device_pdos(con); 1682 + ucsi_get_src_pdos(con); 1683 + ucsi_check_altmodes(con); 1684 + ucsi_check_connector_capability(con); 1685 + } 1686 + } 1687 + 1627 1688 static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) 1628 1689 { 1629 1690 struct typec_capability *cap = &con->typec_cap; 1630 1691 enum typec_accessory *accessory = cap->accessory; 1631 - enum usb_role u_role = USB_ROLE_NONE; 1632 1692 u64 command; 1633 1693 char *name; 1634 1694 int ret; ··· 1787 1727 dev_err(ucsi->dev, "con%d: failed to register alt modes\n", 1788 1728 con->num); 1789 1729 goto out; 1790 - } 1791 - 1792 - /* Get the status */ 1793 - ret = ucsi_get_connector_status(con, false); 1794 - if (ret) { 1795 - dev_err(ucsi->dev, "con%d: failed to get status\n", con->num); 1796 - goto out; 1797 - } 1798 - 1799 - if (ucsi->ops->connector_status) 1800 - ucsi->ops->connector_status(con); 1801 - 1802 - switch (UCSI_CONSTAT(con, PARTNER_TYPE)) { 1803 - case UCSI_CONSTAT_PARTNER_TYPE_UFP: 1804 - case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: 1805 - u_role = USB_ROLE_HOST; 1806 - fallthrough; 1807 - case UCSI_CONSTAT_PARTNER_TYPE_CABLE: 1808 - typec_set_data_role(con->port, TYPEC_HOST); 1809 - break; 1810 - case UCSI_CONSTAT_PARTNER_TYPE_DFP: 1811 - u_role = USB_ROLE_DEVICE; 1812 - typec_set_data_role(con->port, TYPEC_DEVICE); 1813 - break; 1814 - default: 1815 - break; 1816 - } 1817 - 1818 - /* Check if there is already something connected */ 1819 - if (UCSI_CONSTAT(con, CONNECTED)) { 1820 - typec_set_pwr_role(con->port, UCSI_CONSTAT(con, PWR_DIR)); 1821 - ucsi_register_partner(con); 1822 - ucsi_pwr_opmode_change(con); 1823 - ucsi_orientation(con); 1824 - ucsi_port_psy_changed(con); 1825 - if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE) 1826 - ucsi_get_partner_identity(con); 1827 - if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS) 1828 - ucsi_check_cable(con); 1829 - } 1830 - 1831 - /* Only notify USB controller if partner supports USB data */ 1832 - if (!(UCSI_CONSTAT(con, PARTNER_FLAG_USB))) 1833 - u_role = USB_ROLE_NONE; 1834 - 1835 - ret = usb_role_switch_set_role(con->usb_role_sw, u_role); 1836 - if (ret) { 1837 - dev_err(ucsi->dev, "con:%d: failed to set usb role:%d\n", 1838 - con->num, u_role); 1839 - ret = 0; 1840 - } 1841 - 1842 - if (con->partner && UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) { 1843 - ucsi_register_device_pdos(con); 1844 - ucsi_get_src_pdos(con); 1845 - ucsi_check_altmodes(con); 1846 - ucsi_check_connector_capability(con); 1847 1730 } 1848 1731 1849 1732 trace_ucsi_register_port(con->num, con); ··· 1906 1903 goto err_unregister; 1907 1904 } 1908 1905 1906 + /* Delay other interactions with each connector until ucsi_init_port is done */ 1907 + for (i = 0; i < ucsi->cap.num_connectors; i++) 1908 + mutex_lock(&connector[i].lock); 1909 + 1909 1910 /* Enable all supported notifications */ 1910 1911 ntfy = ucsi_get_supported_notifications(ucsi); 1911 1912 command = UCSI_SET_NOTIFICATION_ENABLE | ntfy; 1912 1913 ucsi->message_in_size = 0; 1913 1914 ret = ucsi_send_command(ucsi, command); 1914 - if (ret < 0) 1915 + if (ret < 0) { 1916 + for (i = 0; i < ucsi->cap.num_connectors; i++) 1917 + mutex_unlock(&connector[i].lock); 1915 1918 goto err_unregister; 1919 + } 1916 1920 1917 1921 ucsi->connector = connector; 1918 1922 ucsi->ntfy = ntfy; 1923 + 1924 + for (i = 0; i < ucsi->cap.num_connectors; i++) { 1925 + ucsi_init_port(ucsi, &connector[i]); 1926 + mutex_unlock(&connector[i].lock); 1927 + } 1919 1928 1920 1929 mutex_lock(&ucsi->ppm_lock); 1921 1930 ret = ucsi->ops->read_cci(ucsi, &cci);