Skip to content

Commit 7aa83fb

Browse files
committed
drm/bridge: ti-sn65dsi86: Fix auxiliary bus lifetime
Memory for the "struct device" for any given device isn't supposed to be released until the device's release() is called. This is important because someone might be holding a kobject reference to the "struct device" and might try to access one of its members even after any other cleanup/uninitialization has happened. Code analysis of ti-sn65dsi86 shows that this isn't quite right. When the code was written, it was believed that we could rely on the fact that the child devices would all be freed before the parent devices and thus we didn't need to worry about a release() function. While I still believe that the parent's "struct device" is guaranteed to outlive the child's "struct device" (because the child holds a kobject reference to the parent), the parent's "devm" allocated memory is a different story. That appears to be freed much earlier. Let's make this better for ti-sn65dsi86 by allocating each auxiliary with kzalloc and then free that memory in the release(). Fixes: bf73537 ("drm/bridge: ti-sn65dsi86: Break GPIO and MIPI-to-eDP bridge into sub-drivers") Suggested-by: Stephen Boyd <[email protected]> Reviewed-by: Stephen Boyd <[email protected]> Signed-off-by: Douglas Anderson <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/20230613065812.v2.1.I24b838a5b4151fb32bccd6f36397998ea2df9fbb@changeid
1 parent db8b496 commit 7aa83fb

File tree

1 file changed

+22
-13
lines changed

1 file changed

+22
-13
lines changed

drivers/gpu/drm/bridge/ti-sn65dsi86.c

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,10 @@
170170
* @pwm_refclk_freq: Cache for the reference clock input to the PWM.
171171
*/
172172
struct ti_sn65dsi86 {
173-
struct auxiliary_device bridge_aux;
174-
struct auxiliary_device gpio_aux;
175-
struct auxiliary_device aux_aux;
176-
struct auxiliary_device pwm_aux;
173+
struct auxiliary_device *bridge_aux;
174+
struct auxiliary_device *gpio_aux;
175+
struct auxiliary_device *aux_aux;
176+
struct auxiliary_device *pwm_aux;
177177

178178
struct device *dev;
179179
struct regmap *regmap;
@@ -468,27 +468,34 @@ static void ti_sn65dsi86_delete_aux(void *data)
468468
auxiliary_device_delete(data);
469469
}
470470

471-
/*
472-
* AUX bus docs say that a non-NULL release is mandatory, but it makes no
473-
* sense for the model used here where all of the aux devices are allocated
474-
* in the single shared structure. We'll use this noop as a workaround.
475-
*/
476-
static void ti_sn65dsi86_noop(struct device *dev) {}
471+
static void ti_sn65dsi86_aux_device_release(struct device *dev)
472+
{
473+
struct auxiliary_device *aux = container_of(dev, struct auxiliary_device, dev);
474+
475+
kfree(aux);
476+
}
477477

478478
static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata,
479-
struct auxiliary_device *aux,
479+
struct auxiliary_device **aux_out,
480480
const char *name)
481481
{
482482
struct device *dev = pdata->dev;
483+
struct auxiliary_device *aux;
483484
int ret;
484485

486+
aux = kzalloc(sizeof(*aux), GFP_KERNEL);
487+
if (!aux)
488+
return -ENOMEM;
489+
485490
aux->name = name;
486491
aux->dev.parent = dev;
487-
aux->dev.release = ti_sn65dsi86_noop;
492+
aux->dev.release = ti_sn65dsi86_aux_device_release;
488493
device_set_of_node_from_dev(&aux->dev, dev);
489494
ret = auxiliary_device_init(aux);
490-
if (ret)
495+
if (ret) {
496+
kfree(aux);
491497
return ret;
498+
}
492499
ret = devm_add_action_or_reset(dev, ti_sn65dsi86_uninit_aux, aux);
493500
if (ret)
494501
return ret;
@@ -497,6 +504,8 @@ static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata,
497504
if (ret)
498505
return ret;
499506
ret = devm_add_action_or_reset(dev, ti_sn65dsi86_delete_aux, aux);
507+
if (!ret)
508+
*aux_out = aux;
500509

501510
return ret;
502511
}

0 commit comments

Comments
 (0)