Skip to content

Commit 45e92a0

Browse files
EvenxfJiri Kosina
authored andcommitted
HID: Intel-thc-hid: Intel-thc: Introduce max input size control
This patch adds support for a new feature, named "Max Input Size Control", allowing driver to set a maximum input size for RxDMA. This enhancement aims to prevent RxDMA buffer overruns caused by data corruption on the I2C bus, thereby improving overall system stability. APIs added: - thc_i2c_set_rx_max_size(): Set the maximum input size for I2C RxDMA. - thc_i2c_rx_max_size_enable(): Enable or disable the max input size control. As this max input size control feature is only applicable to RxDMA and must remain disabled during SWDMA operations, it also involves a change in SWDMA code to record the max input size control feature state before SWDMA and restore the state after SWDMA. Signed-off-by: Even Xu <[email protected]> Tested-by: Chong Han <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 13dd609 commit 45e92a0

File tree

6 files changed

+119
-0
lines changed

6 files changed

+119
-0
lines changed

Documentation/hid/intel-thc-hid.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,20 @@ Control register.
188188
Reset line is controlled by BIOS (or EFI) through ACPI _RST method, driver needs to call this
189189
device ACPI _RST method to reset touch IC during initialization.
190190

191+
2.3 Max input size control
192+
--------------------------
193+
194+
This is a new feature introduced in Panther Lake platform, THC hardware allows driver to set
195+
a max input size for RxDMA. After this max size gets set and enabled, for every input report
196+
packet reading, THC hardware sequencer will first read incoming input packet size, then compare
197+
input packet size with the given max size:
198+
- if input packet size <= max size, THC continues using input packet size to finish the reading
199+
- if input packet size > max size, there is potential input data crash risk during
200+
transferring, THC will use max size instead of input packet size for reading
201+
202+
This feature is used to avoid data corruption which will cause RxDMA buffer overrun issue for
203+
I2C bus, and enhance whole system stability.
204+
191205
3. High level concept
192206
=====================
193207

drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,75 @@ int thc_i2c_subip_regs_restore(struct thc_device *dev)
15711571
}
15721572
EXPORT_SYMBOL_NS_GPL(thc_i2c_subip_regs_restore, "INTEL_THC");
15731573

1574+
/**
1575+
* thc_i2c_set_rx_max_size - Set I2C Rx transfer max input size
1576+
* @dev: The pointer of THC private device context
1577+
* @max_rx_size: Max input report packet size for input report
1578+
*
1579+
* Set @max_rx_size for I2C RxDMA max input size control feature.
1580+
*
1581+
* Return: 0 on success, other error codes on failure.
1582+
*/
1583+
int thc_i2c_set_rx_max_size(struct thc_device *dev, u32 max_rx_size)
1584+
{
1585+
u32 val;
1586+
int ret;
1587+
1588+
if (!dev)
1589+
return -EINVAL;
1590+
1591+
if (!max_rx_size)
1592+
return -EOPNOTSUPP;
1593+
1594+
ret = regmap_read(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, &val);
1595+
if (ret)
1596+
return ret;
1597+
1598+
val |= FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE, max_rx_size);
1599+
1600+
ret = regmap_write(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, val);
1601+
if (ret)
1602+
return ret;
1603+
1604+
dev->i2c_max_rx_size = max_rx_size;
1605+
1606+
return 0;
1607+
}
1608+
EXPORT_SYMBOL_NS_GPL(thc_i2c_set_rx_max_size, "INTEL_THC");
1609+
1610+
/**
1611+
* thc_i2c_rx_max_size_enable - Enable I2C Rx max input size control
1612+
* @dev: The pointer of THC private device context
1613+
* @enable: Enable max input size control or not
1614+
*
1615+
* Enable or disable I2C RxDMA max input size control feature.
1616+
* Max input size control only can be enabled after max input size
1617+
* was set by thc_i2c_set_rx_max_size().
1618+
*
1619+
* Return: 0 on success, other error codes on failure.
1620+
*/
1621+
int thc_i2c_rx_max_size_enable(struct thc_device *dev, bool enable)
1622+
{
1623+
u32 mask = THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE_EN;
1624+
u32 val = enable ? mask : 0;
1625+
int ret;
1626+
1627+
if (!dev)
1628+
return -EINVAL;
1629+
1630+
if (!dev->i2c_max_rx_size)
1631+
return -EOPNOTSUPP;
1632+
1633+
ret = regmap_write_bits(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, mask, val);
1634+
if (ret)
1635+
return ret;
1636+
1637+
dev->i2c_max_rx_size_en = enable;
1638+
1639+
return 0;
1640+
}
1641+
EXPORT_SYMBOL_NS_GPL(thc_i2c_rx_max_size_enable, "INTEL_THC");
1642+
15741643
MODULE_AUTHOR("Xinpeng Sun <[email protected]>");
15751644
MODULE_AUTHOR("Even Xu <[email protected]>");
15761645

drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ enum thc_int_type {
6262
* @swdma_done: Bool value that indicates if SWDMA sequence is done
6363
* @perf_limit: The delay between read operation and write operation
6464
* @i2c_subip_regs: The copy of THC I2C sub-system registers for resuming restore
65+
* @i2c_max_rx_size: I2C Rx transfer max input size
66+
* @i2c_max_rx_size_en: Bool value that indicates I2C max input size control enabled or not
6567
*/
6668
struct thc_device {
6769
struct device *dev;
@@ -81,6 +83,9 @@ struct thc_device {
8183
u32 perf_limit;
8284

8385
u32 *i2c_subip_regs;
86+
87+
u32 i2c_max_rx_size;
88+
bool i2c_max_rx_size_en;
8489
};
8590

8691
struct thc_device *thc_dev_init(struct device *device, void __iomem *mem_addr);
@@ -112,5 +117,7 @@ int thc_i2c_subip_init(struct thc_device *dev, const u32 target_address,
112117
const u32 speed, const u32 hcnt, const u32 lcnt);
113118
int thc_i2c_subip_regs_save(struct thc_device *dev);
114119
int thc_i2c_subip_regs_restore(struct thc_device *dev);
120+
int thc_i2c_set_rx_max_size(struct thc_device *dev, u32 max_rx_size);
121+
int thc_i2c_rx_max_size_enable(struct thc_device *dev, bool enable);
115122

116123
#endif /* _INTEL_THC_DEV_H_ */

drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,19 @@ static int thc_swdma_read_start(struct thc_device *dev, void *write_buff,
712712

713713
thc_reset_dma_settings(dev);
714714

715+
/*
716+
* Max input size control feature is only available for RxDMA, it must keep disabled
717+
* during SWDMA operation, and restore to previous state after SWDMA is done.
718+
* Max input size variables in THC device context track hardware state, and keep change
719+
* when feature state was changed, so those variables cannot be used to record feature
720+
* state after state was changed during SWDMA operation. Here have to use a temp variable
721+
* in DMA context to record feature state before SWDMA operation.
722+
*/
723+
if (dev->i2c_max_rx_size_en) {
724+
thc_i2c_rx_max_size_enable(dev, false);
725+
dev->dma_ctx->rx_max_size_en = true;
726+
}
727+
715728
mask = THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_WBC |
716729
THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_RX_DLEN_EN;
717730
val = FIELD_PREP(THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_WBC, write_len) |
@@ -754,6 +767,15 @@ static int thc_swdma_read_completion(struct thc_device *dev)
754767
if (ret)
755768
return ret;
756769

770+
/*
771+
* Restore max input size control feature to previous state after SWDMA if it was
772+
* enabled before SWDMA, and reset temp rx_max_size_en variable for next time.
773+
*/
774+
if (dev->dma_ctx->rx_max_size_en) {
775+
thc_i2c_rx_max_size_enable(dev, true);
776+
dev->dma_ctx->rx_max_size_en = false;
777+
}
778+
757779
thc_reset_dma_settings(dev);
758780

759781
dma_set_start_bit(dev, &dev->dma_ctx->dma_config[THC_RXDMA2]);

drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,14 @@ struct thc_dma_configuration {
121121
* struct thc_dma_context - THC DMA context
122122
* @thc_dma_configuration: Array of all THC Channel configures
123123
* @use_write_interrupts: Indicate TxDMA using interrupt or polling
124+
* @rx_max_size_en: Temp flag to indicate THC I2C Rx max input size control feature
125+
* enabled or not, only be used during SWDMA operation.
124126
*/
125127
struct thc_dma_context {
126128
struct thc_dma_configuration dma_config[MAX_THC_DMA_CHANNEL];
127129
u8 use_write_interrupts;
130+
131+
bool rx_max_size_en;
128132
};
129133

130134
struct thc_device;

drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,9 @@
399399
#define THC_M_PRT_SPI_ICRRD_OPCODE_SPI_DIO GENMASK(23, 16)
400400
#define THC_M_PRT_SPI_ICRRD_OPCODE_SPI_QIO GENMASK(15, 8)
401401

402+
#define THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE GENMASK(15, 0)
403+
#define THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE_EN BIT(31)
404+
402405
#define THC_M_PRT_INT_EN_SIPE BIT(0)
403406
#define THC_M_PRT_INT_EN_SBO BIT(1)
404407
#define THC_M_PRT_INT_EN_SIDR BIT(2)

0 commit comments

Comments
 (0)