Skip to content

Commit

Permalink
net: ti: icss-iep: Fix possible NULL pointer dereference for perout r…
Browse files Browse the repository at this point in the history
…equest

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: 9b11536 ("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>
  • Loading branch information
Meghana Malladi authored and Paolo Abeni committed Apr 17, 2025
1 parent 8ed2fa6 commit 7349c9e
Showing 1 changed file with 58 additions and 63 deletions.
121 changes: 58 additions & 63 deletions drivers/net/ethernet/ti/icssg/icss_iep.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,22 @@ static int icss_iep_perout_enable_hw(struct icss_iep *iep,
int ret;
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 */
ts.tv_sec = req->on.sec;
ts.tv_nsec = req->on.nsec;
Expand All @@ -430,64 +446,39 @@ static int icss_iep_perout_enable_hw(struct icss_iep *iep,
if (ret)
return ret;

if (on) {
/* Configure CMP */
regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(cmp));
if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(cmp));
/* Configure SYNC, based on req on width */
regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG,
div_u64(ns_width, iep->def_inc));
regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0);
regmap_write(iep->map, ICSS_IEP_SYNC_START_REG,
div_u64(ns_start, iep->def_inc));
regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); /* one-shot mode */
/* Enable CMP 1 */
regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
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);
}
/* Configure CMP */
regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(cmp));
if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(cmp));
/* Configure SYNC, based on req on width */
regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG,
div_u64(ns_width, iep->def_inc));
regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0);
regmap_write(iep->map, ICSS_IEP_SYNC_START_REG,
div_u64(ns_start, iep->def_inc));
regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); /* one-shot mode */
/* Enable CMP 1 */
regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1));
} else {
if (on) {
u64 start_ns;

iep->period = ((u64)req->period.sec * NSEC_PER_SEC) +
req->period.nsec;
start_ns = ((u64)req->period.sec * NSEC_PER_SEC)
+ req->period.nsec;
icss_iep_update_to_next_boundary(iep, start_ns);

regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG,
div_u64(ns_width, iep->def_inc));
regmap_write(iep->map, ICSS_IEP_SYNC_START_REG,
div_u64(ns_start, iep->def_inc));
/* Enable Sync in single shot mode */
regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG,
IEP_SYNC_CTRL_SYNC_N_EN(0) | IEP_SYNC_CTRL_SYNC_EN);
/* Enable CMP 1 */
regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
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);
}
u64 start_ns;

iep->period = ((u64)req->period.sec * NSEC_PER_SEC) +
req->period.nsec;
start_ns = ((u64)req->period.sec * NSEC_PER_SEC)
+ req->period.nsec;
icss_iep_update_to_next_boundary(iep, start_ns);

regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG,
div_u64(ns_width, iep->def_inc));
regmap_write(iep->map, ICSS_IEP_SYNC_START_REG,
div_u64(ns_start, iep->def_inc));
/* Enable Sync in single shot mode */
regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG,
IEP_SYNC_CTRL_SYNC_N_EN(0) | IEP_SYNC_CTRL_SYNC_EN);
/* Enable CMP 1 */
regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1));
}

return 0;
Expand All @@ -498,11 +489,21 @@ static int icss_iep_perout_enable(struct icss_iep *iep,
{
int ret = 0;

if (!on)
goto disable;

/* Reject requests with unsupported flags */
if (req->flags & ~(PTP_PEROUT_DUTY_CYCLE |
PTP_PEROUT_PHASE))
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);

if (iep->pps_enabled) {
Expand All @@ -513,12 +514,6 @@ static int icss_iep_perout_enable(struct icss_iep *iep,
if (iep->perout_enabled == !!on)
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);
if (!ret)
iep->perout_enabled = !!on;
Expand Down

0 comments on commit 7349c9e

Please sign in to comment.