spi: Fixes for v5.10
This is a relatively large set of fixes, the bulk of it being a series from Lukas Wunner which fixes confusion with the lifetime of driver data allocated along with the SPI controller structure that's been created as part of the conversion to devm APIs. The simplest fix, explained in detail in Lukas' commit message, is to move to a devm_ function for allocation of the controller and hence driver data in order to push the free of that after anything tries to reference the driver data in the remove path. This results in a relatively large diff due to the addition of a new function but isn't particularly complex. There's also a fix from sven van Asbroeck which fixes yet more fallout from the conflicts between the various different places one can configure the polarity of GPIOs in modern systems. Otherwise everything is fairly small and driver specific. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAl+2qqsACgkQJNaLcl1U h9DN/gf+P85QtRuWq8hGt9cEywwvPXdYEifxlJuevO+RIzyrI7y6hc2AqmQ/ek2Q kRU39CVLzrm+P8GRX/K6wL8sSQmBVJSt25aWwYKiygidh4eFqmDKC5y/yQY+VIoW /MvFpdFOENDbAjRRK3l5x9BdwXsNPadjl7Ts2FGyjsBOOEWdXf9fApXju7oVHGki oDc35Z5o1DdwTdTD5B/uKP2VmevbrEmBceGZttaSUjyO4kJ9ehe+kJ1DuBu9QrTN GDu/J7oijbtYYfRi6DeMjVfUvvNK9c+6TQay91j0c6ZNW5TuYkZ0XS1vbpjwshQg wWPxA+uQ4YelNgRQ4H+PhzOKo0zv4A== =oG9R -----END PGP SIGNATURE----- Merge tag 'spi-fix-v5.10-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi fixes from Mark Brown: "This is a relatively large set of fixes, the bulk of it being a series from Lukas Wunner which fixes confusion with the lifetime of driver data allocated along with the SPI controller structure that's been created as part of the conversion to devm APIs. The simplest fix, explained in detail in Lukas' commit message, is to move to a devm_ function for allocation of the controller and hence driver data in order to push the free of that after anything tries to reference the driver data in the remove path. This results in a relatively large diff due to the addition of a new function but isn't particularly complex. There's also a fix from Sven van Asbroeck which fixes yet more fallout from the conflicts between the various different places one can configure the polarity of GPIOs in modern systems. Otherwise everything is fairly small and driver specific" * tag 'spi-fix-v5.10-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: spi: npcm-fiu: Don't leak SPI master in probe error path spi: dw: Set transfer handler before unmasking the IRQs spi: cadence-quadspi: Fix error return code in cqspi_probe spi: bcm2835aux: Restore err assignment in bcm2835aux_spi_probe spi: lpspi: Fix use-after-free on unbind spi: bcm-qspi: Fix use-after-free on unbind spi: bcm2835aux: Fix use-after-free on unbind spi: bcm2835: Fix use-after-free on unbind spi: Introduce device-managed SPI controller allocation spi: fsi: Fix transfer returning without finalizing message spi: fix client driver breakages when using GPIO descriptors
This commit is contained in:
commit
fee3c824ed
@ -1327,7 +1327,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
||||
|
||||
data = of_id->data;
|
||||
|
||||
master = spi_alloc_master(dev, sizeof(struct bcm_qspi));
|
||||
master = devm_spi_alloc_master(dev, sizeof(struct bcm_qspi));
|
||||
if (!master) {
|
||||
dev_err(dev, "error allocating spi_master\n");
|
||||
return -ENOMEM;
|
||||
@ -1367,21 +1367,17 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
||||
|
||||
if (res) {
|
||||
qspi->base[MSPI] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(qspi->base[MSPI])) {
|
||||
ret = PTR_ERR(qspi->base[MSPI]);
|
||||
goto qspi_resource_err;
|
||||
}
|
||||
if (IS_ERR(qspi->base[MSPI]))
|
||||
return PTR_ERR(qspi->base[MSPI]);
|
||||
} else {
|
||||
goto qspi_resource_err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bspi");
|
||||
if (res) {
|
||||
qspi->base[BSPI] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(qspi->base[BSPI])) {
|
||||
ret = PTR_ERR(qspi->base[BSPI]);
|
||||
goto qspi_resource_err;
|
||||
}
|
||||
if (IS_ERR(qspi->base[BSPI]))
|
||||
return PTR_ERR(qspi->base[BSPI]);
|
||||
qspi->bspi_mode = true;
|
||||
} else {
|
||||
qspi->bspi_mode = false;
|
||||
@ -1392,18 +1388,14 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cs_reg");
|
||||
if (res) {
|
||||
qspi->base[CHIP_SELECT] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(qspi->base[CHIP_SELECT])) {
|
||||
ret = PTR_ERR(qspi->base[CHIP_SELECT]);
|
||||
goto qspi_resource_err;
|
||||
}
|
||||
if (IS_ERR(qspi->base[CHIP_SELECT]))
|
||||
return PTR_ERR(qspi->base[CHIP_SELECT]);
|
||||
}
|
||||
|
||||
qspi->dev_ids = kcalloc(num_irqs, sizeof(struct bcm_qspi_dev_id),
|
||||
GFP_KERNEL);
|
||||
if (!qspi->dev_ids) {
|
||||
ret = -ENOMEM;
|
||||
goto qspi_resource_err;
|
||||
}
|
||||
if (!qspi->dev_ids)
|
||||
return -ENOMEM;
|
||||
|
||||
for (val = 0; val < num_irqs; val++) {
|
||||
irq = -1;
|
||||
@ -1484,7 +1476,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
||||
qspi->xfer_mode.addrlen = -1;
|
||||
qspi->xfer_mode.hp = -1;
|
||||
|
||||
ret = devm_spi_register_master(&pdev->dev, master);
|
||||
ret = spi_register_master(master);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't register master\n");
|
||||
goto qspi_reg_err;
|
||||
@ -1497,8 +1489,6 @@ qspi_reg_err:
|
||||
clk_disable_unprepare(qspi->clk);
|
||||
qspi_probe_err:
|
||||
kfree(qspi->dev_ids);
|
||||
qspi_resource_err:
|
||||
spi_master_put(master);
|
||||
return ret;
|
||||
}
|
||||
/* probe function to be called by SoC specific platform driver probe */
|
||||
@ -1508,10 +1498,10 @@ int bcm_qspi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm_qspi *qspi = platform_get_drvdata(pdev);
|
||||
|
||||
spi_unregister_master(qspi->master);
|
||||
bcm_qspi_hw_uninit(qspi);
|
||||
clk_disable_unprepare(qspi->clk);
|
||||
kfree(qspi->dev_ids);
|
||||
spi_unregister_master(qspi->master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1278,7 +1278,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
|
||||
struct bcm2835_spi *bs;
|
||||
int err;
|
||||
|
||||
ctlr = spi_alloc_master(&pdev->dev, ALIGN(sizeof(*bs),
|
||||
ctlr = devm_spi_alloc_master(&pdev->dev, ALIGN(sizeof(*bs),
|
||||
dma_get_cache_alignment()));
|
||||
if (!ctlr)
|
||||
return -ENOMEM;
|
||||
@ -1299,23 +1299,17 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
|
||||
bs->ctlr = ctlr;
|
||||
|
||||
bs->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(bs->regs)) {
|
||||
err = PTR_ERR(bs->regs);
|
||||
goto out_controller_put;
|
||||
}
|
||||
if (IS_ERR(bs->regs))
|
||||
return PTR_ERR(bs->regs);
|
||||
|
||||
bs->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(bs->clk)) {
|
||||
err = dev_err_probe(&pdev->dev, PTR_ERR(bs->clk),
|
||||
"could not get clk\n");
|
||||
goto out_controller_put;
|
||||
}
|
||||
if (IS_ERR(bs->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(bs->clk),
|
||||
"could not get clk\n");
|
||||
|
||||
bs->irq = platform_get_irq(pdev, 0);
|
||||
if (bs->irq <= 0) {
|
||||
err = bs->irq ? bs->irq : -ENODEV;
|
||||
goto out_controller_put;
|
||||
}
|
||||
if (bs->irq <= 0)
|
||||
return bs->irq ? bs->irq : -ENODEV;
|
||||
|
||||
clk_prepare_enable(bs->clk);
|
||||
|
||||
@ -1349,8 +1343,6 @@ out_dma_release:
|
||||
bcm2835_dma_release(ctlr, bs);
|
||||
out_clk_disable:
|
||||
clk_disable_unprepare(bs->clk);
|
||||
out_controller_put:
|
||||
spi_controller_put(ctlr);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -494,7 +494,7 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
|
||||
unsigned long clk_hz;
|
||||
int err;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*bs));
|
||||
master = devm_spi_alloc_master(&pdev->dev, sizeof(*bs));
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -524,29 +524,25 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
|
||||
|
||||
/* the main area */
|
||||
bs->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(bs->regs)) {
|
||||
err = PTR_ERR(bs->regs);
|
||||
goto out_master_put;
|
||||
}
|
||||
if (IS_ERR(bs->regs))
|
||||
return PTR_ERR(bs->regs);
|
||||
|
||||
bs->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(bs->clk)) {
|
||||
err = PTR_ERR(bs->clk);
|
||||
dev_err(&pdev->dev, "could not get clk: %d\n", err);
|
||||
goto out_master_put;
|
||||
return err;
|
||||
}
|
||||
|
||||
bs->irq = platform_get_irq(pdev, 0);
|
||||
if (bs->irq <= 0) {
|
||||
err = bs->irq ? bs->irq : -ENODEV;
|
||||
goto out_master_put;
|
||||
}
|
||||
if (bs->irq <= 0)
|
||||
return bs->irq ? bs->irq : -ENODEV;
|
||||
|
||||
/* this also enables the HW block */
|
||||
err = clk_prepare_enable(bs->clk);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "could not prepare clock: %d\n", err);
|
||||
goto out_master_put;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* just checking if the clock returns a sane value */
|
||||
@ -581,8 +577,6 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
|
||||
|
||||
out_clk_disable:
|
||||
clk_disable_unprepare(bs->clk);
|
||||
out_master_put:
|
||||
spi_master_put(master);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1260,12 +1260,14 @@ static int cqspi_probe(struct platform_device *pdev)
|
||||
/* Obtain QSPI reset control */
|
||||
rstc = devm_reset_control_get_optional_exclusive(dev, "qspi");
|
||||
if (IS_ERR(rstc)) {
|
||||
ret = PTR_ERR(rstc);
|
||||
dev_err(dev, "Cannot get QSPI reset.\n");
|
||||
goto probe_reset_failed;
|
||||
}
|
||||
|
||||
rstc_ocp = devm_reset_control_get_optional_exclusive(dev, "qspi-ocp");
|
||||
if (IS_ERR(rstc_ocp)) {
|
||||
ret = PTR_ERR(rstc_ocp);
|
||||
dev_err(dev, "Cannot get QSPI OCP reset.\n");
|
||||
goto probe_reset_failed;
|
||||
}
|
||||
|
@ -357,11 +357,11 @@ static void dw_spi_irq_setup(struct dw_spi *dws)
|
||||
dw_writel(dws, DW_SPI_TXFTLR, level);
|
||||
dw_writel(dws, DW_SPI_RXFTLR, level - 1);
|
||||
|
||||
dws->transfer_handler = dw_spi_transfer_handler;
|
||||
|
||||
imask = SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI |
|
||||
SPI_INT_RXFI;
|
||||
spi_umask_intr(dws, imask);
|
||||
|
||||
dws->transfer_handler = dw_spi_transfer_handler;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -477,7 +477,7 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr,
|
||||
|
||||
rc = fsi_spi_check_mux(ctx->fsi, ctx->dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto error;
|
||||
|
||||
list_for_each_entry(transfer, &mesg->transfers, transfer_list) {
|
||||
struct fsi_spi_sequence seq;
|
||||
|
@ -938,9 +938,6 @@ static int fsl_lpspi_remove(struct platform_device *pdev)
|
||||
spi_controller_get_devdata(controller);
|
||||
|
||||
pm_runtime_disable(fsl_lpspi->dev);
|
||||
|
||||
spi_master_put(controller);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -679,7 +679,7 @@ static int npcm_fiu_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int id;
|
||||
|
||||
ctrl = spi_alloc_master(dev, sizeof(*fiu));
|
||||
ctrl = devm_spi_alloc_master(dev, sizeof(*fiu));
|
||||
if (!ctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -812,18 +812,16 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
|
||||
enable = !enable;
|
||||
|
||||
if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio)) {
|
||||
/*
|
||||
* Honour the SPI_NO_CS flag and invert the enable line, as
|
||||
* active low is default for SPI. Execution paths that handle
|
||||
* polarity inversion in gpiolib (such as device tree) will
|
||||
* enforce active high using the SPI_CS_HIGH resulting in a
|
||||
* double inversion through the code above.
|
||||
*/
|
||||
if (!(spi->mode & SPI_NO_CS)) {
|
||||
if (spi->cs_gpiod)
|
||||
/* polarity handled by gpiolib */
|
||||
gpiod_set_value_cansleep(spi->cs_gpiod,
|
||||
!enable);
|
||||
enable1);
|
||||
else
|
||||
/*
|
||||
* invert the enable line, as active low is
|
||||
* default for SPI.
|
||||
*/
|
||||
gpio_set_value_cansleep(spi->cs_gpio, !enable);
|
||||
}
|
||||
/* Some SPI masters need both GPIO CS & slave_select */
|
||||
@ -1992,15 +1990,6 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
|
||||
}
|
||||
spi->chip_select = value;
|
||||
|
||||
/*
|
||||
* For descriptors associated with the device, polarity inversion is
|
||||
* handled in the gpiolib, so all gpio chip selects are "active high"
|
||||
* in the logical sense, the gpiolib will invert the line if need be.
|
||||
*/
|
||||
if ((ctlr->use_gpio_descriptors) && ctlr->cs_gpiods &&
|
||||
ctlr->cs_gpiods[spi->chip_select])
|
||||
spi->mode |= SPI_CS_HIGH;
|
||||
|
||||
/* Device speed */
|
||||
if (!of_property_read_u32(nc, "spi-max-frequency", &value))
|
||||
spi->max_speed_hz = value;
|
||||
@ -2453,6 +2442,49 @@ struct spi_controller *__spi_alloc_controller(struct device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__spi_alloc_controller);
|
||||
|
||||
static void devm_spi_release_controller(struct device *dev, void *ctlr)
|
||||
{
|
||||
spi_controller_put(*(struct spi_controller **)ctlr);
|
||||
}
|
||||
|
||||
/**
|
||||
* __devm_spi_alloc_controller - resource-managed __spi_alloc_controller()
|
||||
* @dev: physical device of SPI controller
|
||||
* @size: how much zeroed driver-private data to allocate
|
||||
* @slave: whether to allocate an SPI master (false) or SPI slave (true)
|
||||
* Context: can sleep
|
||||
*
|
||||
* Allocate an SPI controller and automatically release a reference on it
|
||||
* when @dev is unbound from its driver. Drivers are thus relieved from
|
||||
* having to call spi_controller_put().
|
||||
*
|
||||
* The arguments to this function are identical to __spi_alloc_controller().
|
||||
*
|
||||
* Return: the SPI controller structure on success, else NULL.
|
||||
*/
|
||||
struct spi_controller *__devm_spi_alloc_controller(struct device *dev,
|
||||
unsigned int size,
|
||||
bool slave)
|
||||
{
|
||||
struct spi_controller **ptr, *ctlr;
|
||||
|
||||
ptr = devres_alloc(devm_spi_release_controller, sizeof(*ptr),
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
|
||||
ctlr = __spi_alloc_controller(dev, size, slave);
|
||||
if (ctlr) {
|
||||
*ptr = ctlr;
|
||||
devres_add(dev, ptr);
|
||||
} else {
|
||||
devres_free(ptr);
|
||||
}
|
||||
|
||||
return ctlr;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__devm_spi_alloc_controller);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int of_spi_get_gpio_numbers(struct spi_controller *ctlr)
|
||||
{
|
||||
@ -2789,6 +2821,11 @@ int devm_spi_register_controller(struct device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_spi_register_controller);
|
||||
|
||||
static int devm_spi_match_controller(struct device *dev, void *res, void *ctlr)
|
||||
{
|
||||
return *(struct spi_controller **)res == ctlr;
|
||||
}
|
||||
|
||||
static int __unregister(struct device *dev, void *null)
|
||||
{
|
||||
spi_unregister_device(to_spi_device(dev));
|
||||
@ -2830,7 +2867,15 @@ void spi_unregister_controller(struct spi_controller *ctlr)
|
||||
list_del(&ctlr->list);
|
||||
mutex_unlock(&board_lock);
|
||||
|
||||
device_unregister(&ctlr->dev);
|
||||
device_del(&ctlr->dev);
|
||||
|
||||
/* Release the last reference on the controller if its driver
|
||||
* has not yet been converted to devm_spi_alloc_master/slave().
|
||||
*/
|
||||
if (!devres_find(ctlr->dev.parent, devm_spi_release_controller,
|
||||
devm_spi_match_controller, ctlr))
|
||||
put_device(&ctlr->dev);
|
||||
|
||||
/* free bus id */
|
||||
mutex_lock(&board_lock);
|
||||
if (found == ctlr)
|
||||
|
@ -734,6 +734,25 @@ static inline struct spi_controller *spi_alloc_slave(struct device *host,
|
||||
return __spi_alloc_controller(host, size, true);
|
||||
}
|
||||
|
||||
struct spi_controller *__devm_spi_alloc_controller(struct device *dev,
|
||||
unsigned int size,
|
||||
bool slave);
|
||||
|
||||
static inline struct spi_controller *devm_spi_alloc_master(struct device *dev,
|
||||
unsigned int size)
|
||||
{
|
||||
return __devm_spi_alloc_controller(dev, size, false);
|
||||
}
|
||||
|
||||
static inline struct spi_controller *devm_spi_alloc_slave(struct device *dev,
|
||||
unsigned int size)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_SPI_SLAVE))
|
||||
return NULL;
|
||||
|
||||
return __devm_spi_alloc_controller(dev, size, true);
|
||||
}
|
||||
|
||||
extern int spi_register_controller(struct spi_controller *ctlr);
|
||||
extern int devm_spi_register_controller(struct device *dev,
|
||||
struct spi_controller *ctlr);
|
||||
|
Loading…
x
Reference in New Issue
Block a user