Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pwm: sti: Reduce number of allocations and drop usage of chip_data

Instead of using one allocation per capture channel, use a single one. Also
store it in driver data instead of chip data.

This has several advantages:

- driver data isn't cleared when pwm_put() is called
- Reduces memory fragmentation

Also register the pwm chip only after the per capture channel data is
initialized as the capture callback relies on this initialization and it
might be called even before pwmchip_add() returns.

It would be still better to have struct sti_pwm_compat_data and the
per-channel data struct sti_cpt_ddata in a single memory chunk, but that's
not easily possible because the number of capture channels isn't known yet
when the driver data struct is allocated.

Fixes: e926b12c611c ("pwm: Clear chip_data in pwm_put()")
Reported-by: George Stark <gnstark@sberdevices.ru>
Fixes: c97267ae831d ("pwm: sti: Add PWM capture callback")
Link: https://lore.kernel.org/r/20230705080650.2353391-7-u.kleine-koenig@pengutronix.de
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>

authored by

Uwe Kleine-König and committed by
Thierry Reding
2d6812b4 ec63391a

+14 -15
+14 -15
drivers/pwm/pwm-sti.c
··· 79 79 unsigned int cpt_num_devs; 80 80 unsigned int max_pwm_cnt; 81 81 unsigned int max_prescale; 82 + struct sti_cpt_ddata *ddata; 82 83 }; 83 84 84 85 struct sti_pwm_chip { ··· 315 314 { 316 315 struct sti_pwm_chip *pc = to_sti_pwmchip(chip); 317 316 struct sti_pwm_compat_data *cdata = pc->cdata; 318 - struct sti_cpt_ddata *ddata = pwm_get_chip_data(pwm); 317 + struct sti_cpt_ddata *ddata = &cdata->ddata[pwm->hwpwm]; 319 318 struct device *dev = pc->dev; 320 319 unsigned int effective_ticks; 321 320 unsigned long long high, low; ··· 440 439 while (cpt_int_stat) { 441 440 devicenum = ffs(cpt_int_stat) - 1; 442 441 443 - ddata = pwm_get_chip_data(&pc->chip.pwms[devicenum]); 442 + ddata = &pc->cdata->ddata[devicenum]; 444 443 445 444 /* 446 445 * Capture input: ··· 638 637 dev_err(dev, "failed to prepare clock\n"); 639 638 return ret; 640 639 } 640 + 641 + cdata->ddata = devm_kzalloc(dev, cdata->cpt_num_devs * sizeof(*cdata->ddata), GFP_KERNEL); 642 + if (!cdata->ddata) 643 + return -ENOMEM; 641 644 } 642 645 643 646 pc->chip.dev = dev; 644 647 pc->chip.ops = &sti_pwm_ops; 645 648 pc->chip.npwm = pc->cdata->pwm_num_devs; 646 649 650 + for (i = 0; i < cdata->cpt_num_devs; i++) { 651 + struct sti_cpt_ddata *ddata = &cdata->ddata[i]; 652 + 653 + init_waitqueue_head(&ddata->wait); 654 + mutex_init(&ddata->lock); 655 + } 656 + 647 657 ret = pwmchip_add(&pc->chip); 648 658 if (ret < 0) { 649 659 clk_unprepare(pc->pwm_clk); 650 660 clk_unprepare(pc->cpt_clk); 651 661 return ret; 652 - } 653 - 654 - for (i = 0; i < cdata->cpt_num_devs; i++) { 655 - struct sti_cpt_ddata *ddata; 656 - 657 - ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); 658 - if (!ddata) 659 - return -ENOMEM; 660 - 661 - init_waitqueue_head(&ddata->wait); 662 - mutex_init(&ddata->lock); 663 - 664 - pwm_set_chip_data(&pc->chip.pwms[i], ddata); 665 662 } 666 663 667 664 platform_set_drvdata(pdev, pc);