Message ID | 20240126103859.v3.1.Iacf5570a66b82b73ef03daa6557e2fc0db10266a@changeid |
---|---|
State | Superseded |
Headers | show |
Series | usb: typec: ucsi: Adding support for UCSI 3.0 | expand |
Hi Abhishek, On Fri, Jan 26, 2024 at 10:39 AM Abhishek Pandit-Subedi <abhishekpandit@chromium.org> wrote: > > Between UCSI 1.2 and UCSI 2.0, the size of the MESSAGE_IN region was > increased from 16 to 256. In order to avoid overflowing reads for older > systems, add a mechanism to use the read UCSI version to truncate read > sizes on UCSI v1.2. > > Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org> Please pick up review tags that you've received for previous versions (unless the patch has changed drastically). Reviewed-by: Prashant Malani <pmalani@chromium.org>
On Fri, Jan 26, 2024 at 10:39:07AM -0800, Abhishek Pandit-Subedi wrote: > Between UCSI 1.2 and UCSI 2.0, the size of the MESSAGE_IN region was > increased from 16 to 256. In order to avoid overflowing reads for older > systems, add a mechanism to use the read UCSI version to truncate read > sizes on UCSI v1.2. > > Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> > --- > Tested on 6.6 kernel. Dmesg output from this change: > [ 105.058162] ucsi_um_test ucsi_um_test_device.0: Registered UCSI > interface with version 3.0.0 > > > (no changes since v2) > > Changes in v2: > - Changed log message to DEBUG > > drivers/usb/typec/ucsi/ucsi.c | 26 ++++++++++++++++++++++++-- > drivers/usb/typec/ucsi/ucsi.h | 11 +++++++++++ > 2 files changed, 35 insertions(+), 2 deletions(-) > > diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c > index 5392ec698959..a35056ee3e96 100644 > --- a/drivers/usb/typec/ucsi/ucsi.c > +++ b/drivers/usb/typec/ucsi/ucsi.c > @@ -36,6 +36,19 @@ > */ > #define UCSI_SWAP_TIMEOUT_MS 5000 > > +static int ucsi_read_message_in(struct ucsi *ucsi, void *buf, > + size_t buf_size) > +{ > + /* > + * Below UCSI 2.0, MESSAGE_IN was limited to 16 bytes. Truncate the > + * reads here. > + */ > + if (ucsi->version <= UCSI_VERSION_1_2) > + buf_size = min_t(size_t, 16, buf_size); > + > + return ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, buf, buf_size); > +} > + > static int ucsi_acknowledge_command(struct ucsi *ucsi) > { > u64 ctrl; > @@ -72,7 +85,7 @@ static int ucsi_read_error(struct ucsi *ucsi) > if (ret < 0) > return ret; > > - ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, &error, sizeof(error)); > + ret = ucsi_read_message_in(ucsi, &error, sizeof(error)); > if (ret) > return ret; > > @@ -170,7 +183,7 @@ int ucsi_send_command(struct ucsi *ucsi, u64 command, > length = ret; > > if (data) { > - ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, data, size); > + ret = ucsi_read_message_in(ucsi, data, size); > if (ret) > goto out; > } > @@ -1556,6 +1569,15 @@ int ucsi_register(struct ucsi *ucsi) > if (!ucsi->version) > return -ENODEV; > > + /* > + * Version format is JJ.M.N (JJ = Major version, M = Minor version, > + * N = sub-minor version). > + */ > + dev_dbg(ucsi->dev, "Registered UCSI interface with version %x.%x.%x", > + UCSI_BCD_GET_MAJOR(ucsi->version), > + UCSI_BCD_GET_MINOR(ucsi->version), > + UCSI_BCD_GET_SUBMINOR(ucsi->version)); > + > queue_delayed_work(system_long_wq, &ucsi->work, 0); > > ucsi_debugfs_register(ucsi); > diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h > index 6478016d5cb8..bec920fa6b8a 100644 > --- a/drivers/usb/typec/ucsi/ucsi.h > +++ b/drivers/usb/typec/ucsi/ucsi.h > @@ -23,6 +23,17 @@ struct dentry; > #define UCSI_CONTROL 8 > #define UCSI_MESSAGE_IN 16 > #define UCSI_MESSAGE_OUT 32 > +#define UCSIv2_MESSAGE_OUT 272 > + > +/* UCSI versions */ > +#define UCSI_VERSION_1_2 0x0120 > +#define UCSI_VERSION_2_0 0x0200 > +#define UCSI_VERSION_2_1 0x0210 > +#define UCSI_VERSION_3_0 0x0300 > + > +#define UCSI_BCD_GET_MAJOR(_v_) (((_v_) >> 8) & 0xFF) > +#define UCSI_BCD_GET_MINOR(_v_) (((_v_) >> 4) & 0x0F) > +#define UCSI_BCD_GET_SUBMINOR(_v_) ((_v_) & 0x0F) > > /* Command Status and Connector Change Indication (CCI) bits */ > #define UCSI_CCI_CONNECTOR(_c_) (((_c_) & GENMASK(7, 1)) >> 1) > -- > 2.43.0.429.g432eaa2c6b-goog
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 5392ec698959..a35056ee3e96 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -36,6 +36,19 @@ */ #define UCSI_SWAP_TIMEOUT_MS 5000 +static int ucsi_read_message_in(struct ucsi *ucsi, void *buf, + size_t buf_size) +{ + /* + * Below UCSI 2.0, MESSAGE_IN was limited to 16 bytes. Truncate the + * reads here. + */ + if (ucsi->version <= UCSI_VERSION_1_2) + buf_size = min_t(size_t, 16, buf_size); + + return ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, buf, buf_size); +} + static int ucsi_acknowledge_command(struct ucsi *ucsi) { u64 ctrl; @@ -72,7 +85,7 @@ static int ucsi_read_error(struct ucsi *ucsi) if (ret < 0) return ret; - ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, &error, sizeof(error)); + ret = ucsi_read_message_in(ucsi, &error, sizeof(error)); if (ret) return ret; @@ -170,7 +183,7 @@ int ucsi_send_command(struct ucsi *ucsi, u64 command, length = ret; if (data) { - ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, data, size); + ret = ucsi_read_message_in(ucsi, data, size); if (ret) goto out; } @@ -1556,6 +1569,15 @@ int ucsi_register(struct ucsi *ucsi) if (!ucsi->version) return -ENODEV; + /* + * Version format is JJ.M.N (JJ = Major version, M = Minor version, + * N = sub-minor version). + */ + dev_dbg(ucsi->dev, "Registered UCSI interface with version %x.%x.%x", + UCSI_BCD_GET_MAJOR(ucsi->version), + UCSI_BCD_GET_MINOR(ucsi->version), + UCSI_BCD_GET_SUBMINOR(ucsi->version)); + queue_delayed_work(system_long_wq, &ucsi->work, 0); ucsi_debugfs_register(ucsi); diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 6478016d5cb8..bec920fa6b8a 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -23,6 +23,17 @@ struct dentry; #define UCSI_CONTROL 8 #define UCSI_MESSAGE_IN 16 #define UCSI_MESSAGE_OUT 32 +#define UCSIv2_MESSAGE_OUT 272 + +/* UCSI versions */ +#define UCSI_VERSION_1_2 0x0120 +#define UCSI_VERSION_2_0 0x0200 +#define UCSI_VERSION_2_1 0x0210 +#define UCSI_VERSION_3_0 0x0300 + +#define UCSI_BCD_GET_MAJOR(_v_) (((_v_) >> 8) & 0xFF) +#define UCSI_BCD_GET_MINOR(_v_) (((_v_) >> 4) & 0x0F) +#define UCSI_BCD_GET_SUBMINOR(_v_) ((_v_) & 0x0F) /* Command Status and Connector Change Indication (CCI) bits */ #define UCSI_CCI_CONNECTOR(_c_) (((_c_) & GENMASK(7, 1)) >> 1)
Between UCSI 1.2 and UCSI 2.0, the size of the MESSAGE_IN region was increased from 16 to 256. In order to avoid overflowing reads for older systems, add a mechanism to use the read UCSI version to truncate read sizes on UCSI v1.2. Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org> --- Tested on 6.6 kernel. Dmesg output from this change: [ 105.058162] ucsi_um_test ucsi_um_test_device.0: Registered UCSI interface with version 3.0.0 (no changes since v2) Changes in v2: - Changed log message to DEBUG drivers/usb/typec/ucsi/ucsi.c | 26 ++++++++++++++++++++++++-- drivers/usb/typec/ucsi/ucsi.h | 11 +++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-)