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@xxxxxxxxxxxx> Reviewed-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > --- > 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 -- heikki