net: ti: icss-iep: Fix possible NULL pointer dereference for perout request
[ Upstream commit 7349c9e9979333abfce42da5f9025598083b59c9 ] The ICSS IEP driver tracks perout and pps enable state with flags. Currently when disabling pps and perout signals during icss_iep_exit(), results in NULL pointer dereference for perout. To fix the null pointer dereference issue, the icss_iep_perout_enable_hw function can be modified to directly clear the IEP CMP registers when disabling PPS or PEROUT, without referencing the ptp_perout_request structure, as its contents are irrelevant in this case. Fixes: 9b115361248d ("net: ti: icssg-prueth: Fix clearing of IEP_CMP_CFG registers during iep_init") Reported-by: Dan Carpenter <dan.carpenter@linaro.org> Closes: https://lore.kernel.org/all/7b1c7c36-363a-4085-b26c-4f210bee1df6@stanley.mountain/ Signed-off-by: Meghana Malladi <m-malladi@ti.com> Reviewed-by: Jacob Keller <jacob.e.keller@intel.com> Link: https://patch.msgid.link/20250415090543.717991-4-m-malladi@ti.com Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
8b9808b1f6
commit
7891619d21
@@ -482,6 +482,22 @@ static int icss_iep_perout_enable_hw(struct icss_iep *iep,
|
|||||||
int ret;
|
int ret;
|
||||||
u64 cmp;
|
u64 cmp;
|
||||||
|
|
||||||
|
if (!on) {
|
||||||
|
/* Disable CMP 1 */
|
||||||
|
regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
|
||||||
|
IEP_CMP_CFG_CMP_EN(1), 0);
|
||||||
|
|
||||||
|
/* clear CMP regs */
|
||||||
|
regmap_write(iep->map, ICSS_IEP_CMP1_REG0, 0);
|
||||||
|
if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
|
||||||
|
regmap_write(iep->map, ICSS_IEP_CMP1_REG1, 0);
|
||||||
|
|
||||||
|
/* Disable sync */
|
||||||
|
regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate width of the signal for PPS/PEROUT handling */
|
/* Calculate width of the signal for PPS/PEROUT handling */
|
||||||
ts.tv_sec = req->on.sec;
|
ts.tv_sec = req->on.sec;
|
||||||
ts.tv_nsec = req->on.nsec;
|
ts.tv_nsec = req->on.nsec;
|
||||||
@@ -500,64 +516,39 @@ static int icss_iep_perout_enable_hw(struct icss_iep *iep,
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (on) {
|
/* Configure CMP */
|
||||||
/* Configure CMP */
|
regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(cmp));
|
||||||
regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(cmp));
|
if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
|
||||||
if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
|
regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(cmp));
|
||||||
regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(cmp));
|
/* Configure SYNC, based on req on width */
|
||||||
/* Configure SYNC, based on req on width */
|
regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG,
|
||||||
regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG,
|
div_u64(ns_width, iep->def_inc));
|
||||||
div_u64(ns_width, iep->def_inc));
|
regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0);
|
||||||
regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0);
|
regmap_write(iep->map, ICSS_IEP_SYNC_START_REG,
|
||||||
regmap_write(iep->map, ICSS_IEP_SYNC_START_REG,
|
div_u64(ns_start, iep->def_inc));
|
||||||
div_u64(ns_start, iep->def_inc));
|
regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); /* one-shot mode */
|
||||||
regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); /* one-shot mode */
|
/* Enable CMP 1 */
|
||||||
/* Enable CMP 1 */
|
regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
|
||||||
regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
|
IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1));
|
||||||
IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1));
|
|
||||||
} else {
|
|
||||||
/* Disable CMP 1 */
|
|
||||||
regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
|
|
||||||
IEP_CMP_CFG_CMP_EN(1), 0);
|
|
||||||
|
|
||||||
/* clear regs */
|
|
||||||
regmap_write(iep->map, ICSS_IEP_CMP1_REG0, 0);
|
|
||||||
if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
|
|
||||||
regmap_write(iep->map, ICSS_IEP_CMP1_REG1, 0);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (on) {
|
u64 start_ns;
|
||||||
u64 start_ns;
|
|
||||||
|
|
||||||
iep->period = ((u64)req->period.sec * NSEC_PER_SEC) +
|
iep->period = ((u64)req->period.sec * NSEC_PER_SEC) +
|
||||||
req->period.nsec;
|
req->period.nsec;
|
||||||
start_ns = ((u64)req->period.sec * NSEC_PER_SEC)
|
start_ns = ((u64)req->period.sec * NSEC_PER_SEC)
|
||||||
+ req->period.nsec;
|
+ req->period.nsec;
|
||||||
icss_iep_update_to_next_boundary(iep, start_ns);
|
icss_iep_update_to_next_boundary(iep, start_ns);
|
||||||
|
|
||||||
regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG,
|
regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG,
|
||||||
div_u64(ns_width, iep->def_inc));
|
div_u64(ns_width, iep->def_inc));
|
||||||
regmap_write(iep->map, ICSS_IEP_SYNC_START_REG,
|
regmap_write(iep->map, ICSS_IEP_SYNC_START_REG,
|
||||||
div_u64(ns_start, iep->def_inc));
|
div_u64(ns_start, iep->def_inc));
|
||||||
/* Enable Sync in single shot mode */
|
/* Enable Sync in single shot mode */
|
||||||
regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG,
|
regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG,
|
||||||
IEP_SYNC_CTRL_SYNC_N_EN(0) | IEP_SYNC_CTRL_SYNC_EN);
|
IEP_SYNC_CTRL_SYNC_N_EN(0) | IEP_SYNC_CTRL_SYNC_EN);
|
||||||
/* Enable CMP 1 */
|
/* Enable CMP 1 */
|
||||||
regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
|
regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
|
||||||
IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1));
|
IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1));
|
||||||
} else {
|
|
||||||
/* Disable CMP 1 */
|
|
||||||
regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
|
|
||||||
IEP_CMP_CFG_CMP_EN(1), 0);
|
|
||||||
|
|
||||||
/* clear CMP regs */
|
|
||||||
regmap_write(iep->map, ICSS_IEP_CMP1_REG0, 0);
|
|
||||||
if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
|
|
||||||
regmap_write(iep->map, ICSS_IEP_CMP1_REG1, 0);
|
|
||||||
|
|
||||||
/* Disable sync */
|
|
||||||
regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -568,11 +559,21 @@ static int icss_iep_perout_enable(struct icss_iep *iep,
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!on)
|
||||||
|
goto disable;
|
||||||
|
|
||||||
/* Reject requests with unsupported flags */
|
/* Reject requests with unsupported flags */
|
||||||
if (req->flags & ~(PTP_PEROUT_DUTY_CYCLE |
|
if (req->flags & ~(PTP_PEROUT_DUTY_CYCLE |
|
||||||
PTP_PEROUT_PHASE))
|
PTP_PEROUT_PHASE))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
/* Set default "on" time (1ms) for the signal if not passed by the app */
|
||||||
|
if (!(req->flags & PTP_PEROUT_DUTY_CYCLE)) {
|
||||||
|
req->on.sec = 0;
|
||||||
|
req->on.nsec = NSEC_PER_MSEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
disable:
|
||||||
mutex_lock(&iep->ptp_clk_mutex);
|
mutex_lock(&iep->ptp_clk_mutex);
|
||||||
|
|
||||||
if (iep->pps_enabled) {
|
if (iep->pps_enabled) {
|
||||||
@@ -583,12 +584,6 @@ static int icss_iep_perout_enable(struct icss_iep *iep,
|
|||||||
if (iep->perout_enabled == !!on)
|
if (iep->perout_enabled == !!on)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
/* Set default "on" time (1ms) for the signal if not passed by the app */
|
|
||||||
if (!(req->flags & PTP_PEROUT_DUTY_CYCLE)) {
|
|
||||||
req->on.sec = 0;
|
|
||||||
req->on.nsec = NSEC_PER_MSEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = icss_iep_perout_enable_hw(iep, req, on);
|
ret = icss_iep_perout_enable_hw(iep, req, on);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
iep->perout_enabled = !!on;
|
iep->perout_enabled = !!on;
|
||||||
|
Reference in New Issue
Block a user