* [PATCH v2 2/3] ata: sata_mv: fix disk hotplug for Armada 370/XP SoCs
From: Simon Guinot @ 2014-01-31 10:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140126083210.2998ef12@skate>
On Sun, Jan 26, 2014 at 08:32:10AM +0100, Thomas Petazzoni wrote:
> Dear Simon Guinot,
Hi Thomas,
>
> On Tue, 14 Jan 2014 15:50:06 +0100, Simon Guinot wrote:
>
> > + if (hpriv->hp_flags & MV_HP_FIX_LP_PHY_CTL) {
> > + void __iomem *lp_phy_addr =
> > + mv_ap_base(link->ap) + LP_PHY_CTL;
> > + /*
> > + * Set PHY speed according to SControl speed.
> > + */
> > + if ((val & 0xf0) == 0x10)
> > + writelfl(0x7, lp_phy_addr);
> > + else
> > + writelfl(0x227, lp_phy_addr);
> > + }
>
> I think we could do a little bit better than these magical values.
>
> The datasheet says:
>
> * bits 12:9, PIN_PHY_GEN_RX. Value 0x0 => 1.5 Gbps, value 0x1 => 3 Gbps
> * bits 8:5, PIN_PHY_GEN_TX. Value 0x0 => 1.5 Gbps, value 0x1 => 3 Gbps
> * bit 2, PIN_PU_TX. Value 0x0 => Power down, value 0x1 => Power up.
> * bit 1, PIN_PU_RX. Value 0x0 => Power down, value 0x1 => Power up.
> * bit 0, PIN_PU_PLL. Value 0x0 => Power down, value 0x1 => Power up.
I missed this section in the datasheet...
>
> So maybe something like:
>
> #define PIN_PHY_GEN_1_5 0
> #define PIN_PHY_GEN_3 1
>
> #define PIN_PHY_GEN_RX(gen) ((gen) << 9)
> #define PIN_PHY_GEN_TX(gen) ((gen) << 5)
> #define PIN_PU_TX BIT(2)
> #define PIN_PU_RX BIT(1)
> #define PIN_PU_PLL BIT(0)
>
>
> u32 sata_gen;
>
> if ((val & 0xf0) == 0x10)
> sata_gen = PIN_PHY_GEN_1_5;
> else
> sata_gen = PIN_PHY_GEN_3;
>
> writelfl(PIN_PHY_GEN_RX(sata_gen) |
> PIN_PHY_GEN_TX(sata_gen) |
> PIN_PU_TX | PIN_PU_RX | PIN_PU_PLL,
> lp_phy_addr);
Yes, it is much more understandable.
>
>
> > + /*
> > + * To allow disk hotplug on Armada 370/XP SoCs, the PHY speed must be
> > + * updated in the LP_PHY_CTL register.
> > + */
> > + if (pdev->dev.of_node &&
> > + of_device_is_compatible(pdev->dev.of_node,
> > + "marvell,armada-370-xp-sata"))
>
> Testing whether pdev->dev.of_node is not NULL does not seems to be
> useful. A quick read of of_device_is_compatible() and the function it's
> calling seem to indicate that of_device_is_compatible will return false
> if the passed struct device_node * is NULL.
I see.
It seems to me, you already have a patch ready to send. Isn't it ?
Or do you want me to do the update ?
Simon
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140131/1e4dc2f0/attachment.sig>
^ permalink raw reply
* [PATCH 3/3] spi: switch to devm_spi_alloc_master
From: Maxime Ripard @ 2014-01-31 10:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391163792-21819-1-git-send-email-maxime.ripard@free-electrons.com>
Make the existing users of devm_spi_register_master use the
devm_spi_alloc_master function to avoid leaking memory.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/spi/spi-atmel.c | 8 +++-----
drivers/spi/spi-bcm2835.c | 15 +++++----------
drivers/spi/spi-bcm63xx-hsspi.c | 8 +++-----
drivers/spi/spi-bcm63xx.c | 16 ++++++----------
drivers/spi/spi-bfin-v3.c | 13 ++++---------
drivers/spi/spi-clps711x.c | 37 +++++++++++++++----------------------
drivers/spi/spi-coldfire-qspi.c | 15 +++++----------
drivers/spi/spi-dw.c | 6 ++----
drivers/spi/spi-ep93xx.c | 15 +++++----------
drivers/spi/spi-falcon.c | 5 ++---
drivers/spi/spi-mpc512x-psc.c | 19 ++++++++-----------
drivers/spi/spi-mxs.c | 9 +++------
drivers/spi/spi-octeon.c | 12 ++++--------
drivers/spi/spi-omap-100k.c | 16 +++++-----------
drivers/spi/spi-omap2-mcspi.c | 18 ++++++------------
drivers/spi/spi-orion.c | 10 +++-------
drivers/spi/spi-pl022.c | 3 +--
drivers/spi/spi-pxa2xx.c | 3 +--
drivers/spi/spi-rspi.c | 13 ++++---------
drivers/spi/spi-s3c64xx.c | 23 ++++++++---------------
drivers/spi/spi-sc18is602.c | 12 ++----------
drivers/spi/spi-sh-hspi.c | 7 ++-----
drivers/spi/spi-tegra114.c | 15 +++++----------
drivers/spi/spi-tegra20-sflash.c | 12 ++++--------
drivers/spi/spi-tegra20-slink.c | 15 +++++----------
drivers/spi/spi-ti-qspi.c | 32 +++++++++-----------------------
drivers/spi/spi-txx9.c | 3 +--
drivers/spi/spi-xcomm.c | 8 ++------
28 files changed, 123 insertions(+), 245 deletions(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index b0842f7..fdaa92f 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -1317,9 +1317,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
/* setup spi core then atmel-specific driver state */
ret = -ENOMEM;
- master = spi_alloc_master(&pdev->dev, sizeof(*as));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*as));
if (!master)
- goto out_free;
+ return ret;
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
@@ -1341,7 +1341,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
as->buffer = dma_alloc_coherent(&pdev->dev, BUFFER_SIZE,
&as->buffer_dma, GFP_KERNEL);
if (!as->buffer)
- goto out_free;
+ return ret;
spin_lock_init(&as->lock);
@@ -1420,8 +1420,6 @@ out_unmap_regs:
out_free_buffer:
dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
as->buffer_dma);
-out_free:
- spi_master_put(master);
return ret;
}
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 8a89dd1..ece406e 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -305,7 +305,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
struct resource *res;
int err;
- master = spi_alloc_master(&pdev->dev, sizeof(*bs));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*bs));
if (!master) {
dev_err(&pdev->dev, "spi_alloc_master() failed\n");
return -ENOMEM;
@@ -326,23 +326,19 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bs->regs = devm_ioremap_resource(&pdev->dev, res);
- 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 PTR_ERR(bs->clk);
}
bs->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
if (bs->irq <= 0) {
dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq);
- err = bs->irq ? bs->irq : -ENODEV;
- goto out_master_put;
+ return bs->irq ? bs->irq : -ENODEV;
}
clk_prepare_enable(bs->clk);
@@ -369,7 +365,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
out_clk_disable:
clk_disable_unprepare(bs->clk);
out_master_put:
- spi_master_put(master);
return err;
}
diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index b528f9f..df797cb 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -355,7 +355,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
if (ret)
return ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*bs));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*bs));
if (!master) {
ret = -ENOMEM;
goto out_disable_clk;
@@ -396,17 +396,15 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
pdev->name, bs);
if (ret)
- goto out_put_master;
+ goto out_disable_clk;
/* register and we are done */
ret = devm_spi_register_master(dev, master);
if (ret)
- goto out_put_master;
+ goto out_disable_clk;
return 0;
-out_put_master:
- spi_master_put(master);
out_disable_clk:
clk_disable_unprepare(clk);
return ret;
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 77286ae..dae739f 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -346,7 +346,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
return PTR_ERR(clk);
}
- master = spi_alloc_master(dev, sizeof(*bs));
+ master = devm_spi_alloc_master(dev, sizeof(*bs));
if (!master) {
dev_err(dev, "out of memory\n");
return -ENOMEM;
@@ -359,10 +359,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bs->regs = devm_ioremap_resource(&pdev->dev, r);
- if (IS_ERR(bs->regs)) {
- ret = PTR_ERR(bs->regs);
- goto out_err;
- }
+ if (IS_ERR(bs->regs))
+ return PTR_ERR(bs->regs);
bs->irq = irq;
bs->clk = clk;
@@ -372,7 +370,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
pdev->name, master);
if (ret) {
dev_err(dev, "unable to request irq\n");
- goto out_err;
+ return ret;
}
master->bus_num = pdata->bus_num;
@@ -393,13 +391,13 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
default:
dev_err(dev, "unsupported MSG_CTL width: %d\n",
bs->msg_ctl_width);
- goto out_err;
+ return ret;
}
/* Initialize hardware */
ret = clk_prepare_enable(bs->clk);
if (ret)
- goto out_err;
+ return ret;;
bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
@@ -417,8 +415,6 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
out_clk_disable:
clk_disable_unprepare(clk);
-out_err:
- spi_master_put(master);
return ret;
}
diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-bfin-v3.c
index 8f85988..140b066 100644
--- a/drivers/spi/spi-bfin-v3.c
+++ b/drivers/spi/spi-bfin-v3.c
@@ -807,7 +807,7 @@ static int bfin_spi_probe(struct platform_device *pdev)
rx_dma = res->start;
/* allocate master with space for drv_data */
- master = spi_alloc_master(dev, sizeof(*drv_data));
+ master = devm_spi_alloc_master(dev, sizeof(*drv_data));
if (!master) {
dev_err(dev, "can not alloc spi_master\n");
return -ENOMEM;
@@ -833,16 +833,14 @@ static int bfin_spi_probe(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
drv_data->regs = devm_ioremap_resource(dev, mem);
- if (IS_ERR(drv_data->regs)) {
- ret = PTR_ERR(drv_data->regs);
- goto err_put_master;
- }
+ if (IS_ERR(drv_data->regs))
+ return PTR_ERR(drv_data->regs);
/* request tx and rx dma */
ret = request_dma(tx_dma, "SPI_TX_DMA");
if (ret) {
dev_err(dev, "can not request SPI TX DMA channel\n");
- goto err_put_master;
+ return ret;
}
set_dma_callback(tx_dma, bfin_spi_tx_dma_isr, drv_data);
@@ -881,9 +879,6 @@ err_free_rx_dma:
free_dma(rx_dma);
err_free_tx_dma:
free_dma(tx_dma);
-err_put_master:
- spi_master_put(master);
-
return ret;
}
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
index 374ba4a..908c056 100644
--- a/drivers/spi/spi-clps711x.c
+++ b/drivers/spi/spi-clps711x.c
@@ -174,9 +174,9 @@ static int spi_clps711x_probe(struct platform_device *pdev)
return -EINVAL;
}
- master = spi_alloc_master(&pdev->dev,
- sizeof(struct spi_clps711x_data) +
- sizeof(int) * pdata->num_chipselect);
+ master = devm_spi_alloc_master(&pdev->dev,
+ sizeof(struct spi_clps711x_data) +
+ sizeof(int) * pdata->num_chipselect);
if (!master) {
dev_err(&pdev->dev, "SPI allocating memory error\n");
return -ENOMEM;
@@ -195,21 +195,18 @@ static int spi_clps711x_probe(struct platform_device *pdev)
hw->chipselect[i] = pdata->chipselect[i];
if (!gpio_is_valid(hw->chipselect[i])) {
dev_err(&pdev->dev, "Invalid CS GPIO %i\n", i);
- ret = -EINVAL;
- goto err_out;
+ return -EINVAL;
}
if (devm_gpio_request(&pdev->dev, hw->chipselect[i], NULL)) {
dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i);
- ret = -EINVAL;
- goto err_out;
+ return -EINVAL;
}
}
hw->spi_clk = devm_clk_get(&pdev->dev, "spi");
if (IS_ERR(hw->spi_clk)) {
dev_err(&pdev->dev, "Can't get clocks\n");
- ret = PTR_ERR(hw->spi_clk);
- goto err_out;
+ return PTR_ERR(hw->spi_clk);
}
hw->max_speed_hz = clk_get_rate(hw->spi_clk);
@@ -226,23 +223,19 @@ static int spi_clps711x_probe(struct platform_device *pdev)
dev_name(&pdev->dev), hw);
if (ret) {
dev_err(&pdev->dev, "Can't request IRQ\n");
- goto err_out;
+ return ret;
}
ret = devm_spi_register_master(&pdev->dev, master);
- if (!ret) {
- dev_info(&pdev->dev,
- "SPI bus driver initialized. Master clock %u Hz\n",
- hw->max_speed_hz);
- return 0;
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register master\n");
+ return ret;
}
-
- dev_err(&pdev->dev, "Failed to register master\n");
-
-err_out:
- spi_master_put(master);
-
- return ret;
+
+ dev_info(&pdev->dev,
+ "SPI bus driver initialized. Master clock %u Hz\n",
+ hw->max_speed_hz);
+ return 0;
}
static struct platform_driver clps711x_spi_driver = {
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index cabed8f..41f6c9c 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.c
@@ -388,7 +388,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
return -ENOENT;
}
- master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
if (master == NULL) {
dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
return -ENOMEM;
@@ -399,29 +399,26 @@ static int mcfqspi_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mcfqspi->iobase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(mcfqspi->iobase)) {
- status = PTR_ERR(mcfqspi->iobase);
- goto fail0;
+ return PTR_ERR(mcfqspi->iobase);
}
mcfqspi->irq = platform_get_irq(pdev, 0);
if (mcfqspi->irq < 0) {
dev_dbg(&pdev->dev, "platform_get_irq failed\n");
- status = -ENXIO;
- goto fail0;
+ return -ENXIO;
}
status = devm_request_irq(&pdev->dev, mcfqspi->irq, mcfqspi_irq_handler,
0, pdev->name, mcfqspi);
if (status) {
dev_dbg(&pdev->dev, "request_irq failed\n");
- goto fail0;
+ return status;
}
mcfqspi->clk = devm_clk_get(&pdev->dev, "qspi_clk");
if (IS_ERR(mcfqspi->clk)) {
dev_dbg(&pdev->dev, "clk_get failed\n");
- status = PTR_ERR(mcfqspi->clk);
- goto fail0;
+ return PTR_ERR(mcfqspi->clk);
}
clk_enable(mcfqspi->clk);
@@ -461,8 +458,6 @@ fail2:
mcfqspi_cs_teardown(mcfqspi);
fail1:
clk_disable(mcfqspi->clk);
-fail0:
- spi_master_put(master);
dev_dbg(&pdev->dev, "Coldfire QSPI probe failed\n");
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index bf98d63..bcb172c 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -783,7 +783,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
BUG_ON(dws == NULL);
- master = spi_alloc_master(dev, 0);
+ master = devm_spi_alloc_master(dev, 0);
if (!master)
return -ENOMEM;
@@ -799,7 +799,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
dws->name, dws);
if (ret < 0) {
dev_err(&master->dev, "can not get IRQ\n");
- goto err_free_master;
+ return ret;
}
master->mode_bits = SPI_CPOL | SPI_CPHA;
@@ -849,8 +849,6 @@ err_queue_alloc:
dws->dma_ops->dma_exit(dws);
err_diable_hw:
spi_enable_chip(dws, 0);
-err_free_master:
- spi_master_put(master);
return ret;
}
EXPORT_SYMBOL_GPL(dw_spi_add_host);
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index 1bfaed6..7177435 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -888,7 +888,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
return -ENODEV;
}
- master = spi_alloc_master(&pdev->dev, sizeof(*espi));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*espi));
if (!master)
return -ENOMEM;
@@ -907,8 +907,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
espi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(espi->clk)) {
dev_err(&pdev->dev, "unable to get spi clock\n");
- error = PTR_ERR(espi->clk);
- goto fail_release_master;
+ return PTR_ERR(espi->clk);
}
init_completion(&espi->wait);
@@ -924,16 +923,14 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
espi->sspdr_phys = res->start + SSPDR;
espi->regs_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(espi->regs_base)) {
- error = PTR_ERR(espi->regs_base);
- goto fail_release_master;
- }
+ if (IS_ERR(espi->regs_base))
+ return PTR_ERR(espi->regs_base);
error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt,
0, "ep93xx-spi", espi);
if (error) {
dev_err(&pdev->dev, "failed to request irq\n");
- goto fail_release_master;
+ return error;
}
if (info->use_dma && ep93xx_spi_setup_dma(espi))
@@ -955,8 +952,6 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
fail_free_dma:
ep93xx_spi_release_dma(espi);
-fail_release_master:
- spi_master_put(master);
return error;
}
diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c
index dd5bd46..a6aa66f 100644
--- a/drivers/spi/spi-falcon.c
+++ b/drivers/spi/spi-falcon.c
@@ -414,7 +414,7 @@ static int falcon_sflash_probe(struct platform_device *pdev)
return -ENODEV;
}
- master = spi_alloc_master(&pdev->dev, sizeof(*priv));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*priv));
if (!master)
return -ENOMEM;
@@ -434,8 +434,7 @@ static int falcon_sflash_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
ret = devm_spi_register_master(&pdev->dev, master);
- if (ret)
- spi_master_put(master);
+
return ret;
}
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 46d2313..f376595 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -479,7 +479,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
char clk_name[16];
struct clk *clk;
- master = spi_alloc_master(dev, sizeof *mps);
+ master = devm_spi_alloc_master(dev, sizeof *mps);
if (master == NULL)
return -ENOMEM;
@@ -507,8 +507,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
tempp = devm_ioremap(dev, regaddr, size);
if (!tempp) {
dev_err(dev, "could not ioremap I/O port range\n");
- ret = -EFAULT;
- goto free_master;
+ return -EFAULT;
}
mps->psc = tempp;
mps->fifo =
@@ -516,19 +515,19 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
ret = devm_request_irq(dev, mps->irq, mpc512x_psc_spi_isr, IRQF_SHARED,
"mpc512x-psc-spi", mps);
if (ret)
- goto free_master;
+ return ret;
init_completion(&mps->txisrdone);
psc_num = master->bus_num;
snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
clk = devm_clk_get(dev, clk_name);
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- goto free_master;
- }
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
ret = clk_prepare_enable(clk);
if (ret)
- goto free_master;
+ return ret;
+
mps->clk_mclk = clk;
mps->mclk_rate = clk_get_rate(clk);
@@ -544,8 +543,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
free_clock:
clk_disable_unprepare(mps->clk_mclk);
-free_master:
- spi_master_put(master);
return ret;
}
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 79e5aa2..2c63bed 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -489,7 +489,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
if (ret)
clk_freq = clk_freq_default;
- master = spi_alloc_master(&pdev->dev, sizeof(*spi));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*spi));
if (!master)
return -ENOMEM;
@@ -512,13 +512,12 @@ static int mxs_spi_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq_err, mxs_ssp_irq_handler, 0,
DRIVER_NAME, ssp);
if (ret)
- goto out_master_free;
+ return ret;
ssp->dmach = dma_request_slave_channel(&pdev->dev, "rx-tx");
if (!ssp->dmach) {
dev_err(ssp->dev, "Failed to request DMA\n");
- ret = -ENODEV;
- goto out_master_free;
+ return -ENODEV;
}
ret = clk_prepare_enable(ssp->clk);
@@ -545,8 +544,6 @@ out_disable_clk:
clk_disable_unprepare(ssp->clk);
out_dma_release:
dma_release_channel(ssp->dmach);
-out_master_free:
- spi_master_put(master);
return ret;
}
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c
index 67249a4..192ca3d 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-octeon.c
@@ -236,7 +236,7 @@ static int octeon_spi_probe(struct platform_device *pdev)
struct octeon_spi *p;
int err = -ENOENT;
- master = spi_alloc_master(&pdev->dev, sizeof(struct octeon_spi));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(struct octeon_spi));
if (!master)
return -ENOMEM;
p = spi_master_get_devdata(master);
@@ -246,13 +246,12 @@ static int octeon_spi_probe(struct platform_device *pdev)
if (res_mem == NULL) {
dev_err(&pdev->dev, "found no memory resource\n");
- err = -ENXIO;
- goto fail;
+ return -ENXIO;
}
if (!devm_request_mem_region(&pdev->dev, res_mem->start,
resource_size(res_mem), res_mem->name)) {
dev_err(&pdev->dev, "request_mem_region failed\n");
- goto fail;
+ return err;
}
p->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start,
resource_size(res_mem));
@@ -275,15 +274,12 @@ static int octeon_spi_probe(struct platform_device *pdev)
err = devm_spi_register_master(&pdev->dev, master);
if (err) {
dev_err(&pdev->dev, "register master failed: %d\n", err);
- goto fail;
+ return err;
}
dev_info(&pdev->dev, "OCTEON SPI bus driver\n");
return 0;
-fail:
- spi_master_put(master);
- return err;
}
static int octeon_spi_remove(struct platform_device *pdev)
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index 0d32054..4ceae27 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -411,7 +411,7 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
if (!pdev->id)
return -EINVAL;
- master = spi_alloc_master(&pdev->dev, sizeof *spi100k);
+ master = devm_spi_alloc_master(&pdev->dev, sizeof *spi100k);
if (master == NULL) {
dev_dbg(&pdev->dev, "master allocation failed\n");
return -ENOMEM;
@@ -446,28 +446,22 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
spi100k->ick = devm_clk_get(&pdev->dev, "ick");
if (IS_ERR(spi100k->ick)) {
dev_dbg(&pdev->dev, "can't get spi100k_ick\n");
- status = PTR_ERR(spi100k->ick);
- goto err;
+ return PTR_ERR(spi100k->ick);
}
spi100k->fck = devm_clk_get(&pdev->dev, "fck");
if (IS_ERR(spi100k->fck)) {
dev_dbg(&pdev->dev, "can't get spi100k_fck\n");
- status = PTR_ERR(spi100k->fck);
- goto err;
+ return PTR_ERR(spi100k->fck);
}
status = devm_spi_register_master(&pdev->dev, master);
if (status < 0)
- goto err;
+ return status;
spi100k->state = SPI_RUNNING;
- return status;
-
-err:
- spi_master_put(master);
- return status;
+ return 0;
}
static struct platform_driver omap1_spi100k_driver = {
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index a72127f..a4b105e 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -1297,7 +1297,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
struct device_node *node = pdev->dev.of_node;
const struct of_device_id *match;
- master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
+ master = devm_spi_alloc_master(&pdev->dev, sizeof *mcspi);
if (master == NULL) {
dev_dbg(&pdev->dev, "master allocation failed\n");
return -ENOMEM;
@@ -1337,20 +1337,16 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
regs_offset = pdata->regs_offset;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- status = -ENODEV;
- goto free_master;
- }
+ if (r == NULL)
+ return -ENODEV;
r->start += regs_offset;
r->end += regs_offset;
mcspi->phys = r->start;
mcspi->base = devm_ioremap_resource(&pdev->dev, r);
- if (IS_ERR(mcspi->base)) {
- status = PTR_ERR(mcspi->base);
- goto free_master;
- }
+ if (IS_ERR(mcspi->base))
+ return PTR_ERR(mcspi->base);
mcspi->dev = &pdev->dev;
@@ -1361,7 +1357,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
GFP_KERNEL);
if (mcspi->dma_channels == NULL)
- goto free_master;
+ return status;
for (i = 0; i < master->num_chipselect; i++) {
char *dma_rx_ch_name = mcspi->dma_channels[i].dma_rx_ch_name;
@@ -1423,8 +1419,6 @@ disable_pm:
pm_runtime_disable(&pdev->dev);
dma_chnl_free:
kfree(mcspi->dma_channels);
-free_master:
- spi_master_put(master);
return status;
}
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 7f2121f..1ca04af 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -407,7 +407,7 @@ static int orion_spi_probe(struct platform_device *pdev)
const u32 *iprop;
int size;
- master = spi_alloc_master(&pdev->dev, sizeof(*spi));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*spi));
if (master == NULL) {
dev_dbg(&pdev->dev, "master allocation failed\n");
return -ENOMEM;
@@ -435,10 +435,8 @@ static int orion_spi_probe(struct platform_device *pdev)
spi->master = master;
spi->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(spi->clk)) {
- status = PTR_ERR(spi->clk);
- goto out;
- }
+ if (IS_ERR(spi->clk))
+ return PTR_ERR(spi->clk);
clk_prepare(spi->clk);
clk_enable(spi->clk);
@@ -465,8 +463,6 @@ static int orion_spi_probe(struct platform_device *pdev)
out_rel_clk:
clk_disable_unprepare(spi->clk);
-out:
- spi_master_put(master);
return status;
}
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 2789b45..69e4d75 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -2095,7 +2095,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
}
/* Allocate master with space for data */
- master = spi_alloc_master(dev, sizeof(struct pl022));
+ master = devm_spi_alloc_master(dev, sizeof(struct pl022));
if (master == NULL) {
dev_err(&adev->dev, "probe - cannot alloc SPI master\n");
return -ENOMEM;
@@ -2259,7 +2259,6 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
amba_release_regions(adev);
err_no_ioregion:
err_no_gpio:
- spi_master_put(master);
return status;
}
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index c702fc5..51017e8 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -1117,7 +1117,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
}
/* Allocate master with space for drv_data and null dma buffer */
- master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
+ master = devm_spi_alloc_master(dev, sizeof(struct driver_data) + 16);
if (!master) {
dev_err(&pdev->dev, "cannot alloc spi_master\n");
pxa_ssp_free(ssp);
@@ -1224,7 +1224,6 @@ out_error_clock_enabled:
free_irq(ssp->irq, drv_data);
out_error_master_alloc:
- spi_master_put(master);
pxa_ssp_free(ssp);
return status;
}
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 28987d9..b69d06f 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -952,7 +952,7 @@ static int rspi_probe(struct platform_device *pdev)
return -ENODEV;
}
- master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
if (master == NULL) {
dev_err(&pdev->dev, "spi_alloc_master error.\n");
return -ENOMEM;
@@ -965,17 +965,14 @@ static int rspi_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rspi->addr = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(rspi->addr)) {
- ret = PTR_ERR(rspi->addr);
- goto error1;
- }
+ if (IS_ERR(rspi->addr))
+ return PTR_ERR(rspi->addr);
snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id);
rspi->clk = devm_clk_get(&pdev->dev, clk_name);
if (IS_ERR(rspi->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
- ret = PTR_ERR(rspi->clk);
- goto error1;
+ return PTR_ERR(rspi->clk);
}
clk_enable(rspi->clk);
@@ -1023,8 +1020,6 @@ error3:
rspi_release_dma(rspi);
error2:
clk_disable(rspi->clk);
-error1:
- spi_master_put(master);
return ret;
}
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index ae907dd..1772cba 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -1279,8 +1279,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
return irq;
}
- master = spi_alloc_master(&pdev->dev,
- sizeof(struct s3c64xx_spi_driver_data));
+ master = devm_spi_alloc_master(&pdev->dev,
+ sizeof(struct s3c64xx_spi_driver_data));
if (master == NULL) {
dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
return -ENOMEM;
@@ -1303,7 +1303,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n",
ret);
- goto err0;
+ return ret;
}
sdd->port_id = ret;
} else {
@@ -1349,29 +1349,24 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
master->auto_runtime_pm = true;
sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
- if (IS_ERR(sdd->regs)) {
- ret = PTR_ERR(sdd->regs);
- goto err0;
- }
+ if (IS_ERR(sdd->regs))
+ return PTR_ERR(sdd->regs);
if (sci->cfg_gpio && sci->cfg_gpio()) {
dev_err(&pdev->dev, "Unable to config gpio\n");
- ret = -EBUSY;
- goto err0;
+ return -EBUSY;
}
/* Setup clocks */
sdd->clk = devm_clk_get(&pdev->dev, "spi");
if (IS_ERR(sdd->clk)) {
dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n");
- ret = PTR_ERR(sdd->clk);
- goto err0;
+ return PTR_ERR(sdd->clk);
}
if (clk_prepare_enable(sdd->clk)) {
dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
- ret = -EBUSY;
- goto err0;
+ return -EBUSY;
}
sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr);
@@ -1428,8 +1423,6 @@ err3:
clk_disable_unprepare(sdd->src_clk);
err2:
clk_disable_unprepare(sdd->clk);
-err0:
- spi_master_put(master);
return ret;
}
diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c
index 121c2e1..64760ae 100644
--- a/drivers/spi/spi-sc18is602.c
+++ b/drivers/spi/spi-sc18is602.c
@@ -267,7 +267,7 @@ static int sc18is602_probe(struct i2c_client *client,
I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return -EINVAL;
- master = spi_alloc_master(dev, sizeof(struct sc18is602));
+ master = devm_spi_alloc_master(dev, sizeof(struct sc18is602));
if (!master)
return -ENOMEM;
@@ -310,15 +310,7 @@ static int sc18is602_probe(struct i2c_client *client,
master->transfer_one_message = sc18is602_transfer_one;
master->dev.of_node = np;
- error = devm_spi_register_master(dev, master);
- if (error)
- goto error_reg;
-
- return 0;
-
-error_reg:
- spi_master_put(master);
- return error;
+ return devm_spi_register_master(dev, master);
}
static const struct i2c_device_id sc18is602_id[] = {
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index 82d2f92..fe090a3 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -268,7 +268,7 @@ static int hspi_probe(struct platform_device *pdev)
return -EINVAL;
}
- master = spi_alloc_master(&pdev->dev, sizeof(*hspi));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*hspi));
if (!master) {
dev_err(&pdev->dev, "spi_alloc_master error.\n");
return -ENOMEM;
@@ -277,8 +277,7 @@ static int hspi_probe(struct platform_device *pdev)
clk = clk_get(NULL, "shyway_clk");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "shyway_clk is required\n");
- ret = -EINVAL;
- goto error0;
+ return -EINVAL;
}
hspi = spi_master_get_devdata(master);
@@ -316,8 +315,6 @@ static int hspi_probe(struct platform_device *pdev)
error1:
clk_put(clk);
- error0:
- spi_master_put(master);
return ret;
}
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 47b93cc..72076f6 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -1048,7 +1048,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
struct resource *r;
int ret, spi_irq;
- master = spi_alloc_master(&pdev->dev, sizeof(*tspi));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*tspi));
if (!master) {
dev_err(&pdev->dev, "master allocation failed\n");
return -ENOMEM;
@@ -1073,10 +1073,8 @@ static int tegra_spi_probe(struct platform_device *pdev)
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tspi->base = devm_ioremap_resource(&pdev->dev, r);
- if (IS_ERR(tspi->base)) {
- ret = PTR_ERR(tspi->base);
- goto exit_free_master;
- }
+ if (IS_ERR(tspi->base))
+ return PTR_ERR(tspi->base);
tspi->phys = r->start;
spi_irq = platform_get_irq(pdev, 0);
@@ -1087,14 +1085,13 @@ static int tegra_spi_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
tspi->irq);
- goto exit_free_master;
+ return ret;
}
tspi->clk = devm_clk_get(&pdev->dev, "spi");
if (IS_ERR(tspi->clk)) {
dev_err(&pdev->dev, "can not get clock\n");
- ret = PTR_ERR(tspi->clk);
- goto exit_free_irq;
+ return PTR_ERR(tspi->clk);
}
tspi->max_buf_size = SPI_FIFO_DEPTH << 2;
@@ -1152,8 +1149,6 @@ exit_rx_dma_free:
tegra_spi_deinit_dma_param(tspi, true);
exit_free_irq:
free_irq(spi_irq, tspi);
-exit_free_master:
- spi_master_put(master);
return ret;
}
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index af78c17..1638036 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -458,7 +458,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
return -ENODEV;
}
- master = spi_alloc_master(&pdev->dev, sizeof(*tsd));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*tsd));
if (!master) {
dev_err(&pdev->dev, "master allocation failed\n");
return -ENOMEM;
@@ -482,10 +482,8 @@ static int tegra_sflash_probe(struct platform_device *pdev)
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tsd->base = devm_ioremap_resource(&pdev->dev, r);
- if (IS_ERR(tsd->base)) {
- ret = PTR_ERR(tsd->base);
- goto exit_free_master;
- }
+ if (IS_ERR(tsd->base))
+ return PTR_ERR(tsd->base);
tsd->irq = platform_get_irq(pdev, 0);
ret = request_irq(tsd->irq, tegra_sflash_isr, 0,
@@ -493,7 +491,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
tsd->irq);
- goto exit_free_master;
+ return ret;
}
tsd->clk = devm_clk_get(&pdev->dev, NULL);
@@ -540,8 +538,6 @@ exit_pm_disable:
tegra_sflash_runtime_suspend(&pdev->dev);
exit_free_irq:
free_irq(tsd->irq, tsd);
-exit_free_master:
- spi_master_put(master);
return ret;
}
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index 3ce1de8..65e3f0d 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -1045,7 +1045,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
}
cdata = match->data;
- master = spi_alloc_master(&pdev->dev, sizeof(*tspi));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*tspi));
if (!master) {
dev_err(&pdev->dev, "master allocation failed\n");
return -ENOMEM;
@@ -1073,15 +1073,12 @@ static int tegra_slink_probe(struct platform_device *pdev)
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
dev_err(&pdev->dev, "No IO memory resource\n");
- ret = -ENODEV;
- goto exit_free_master;
+ return -ENODEV;
}
tspi->phys = r->start;
tspi->base = devm_ioremap_resource(&pdev->dev, r);
- if (IS_ERR(tspi->base)) {
- ret = PTR_ERR(tspi->base);
- goto exit_free_master;
- }
+ if (IS_ERR(tspi->base))
+ return PTR_ERR(tspi->base);
spi_irq = platform_get_irq(pdev, 0);
tspi->irq = spi_irq;
@@ -1091,7 +1088,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
tspi->irq);
- goto exit_free_master;
+ return ret;
}
tspi->clk = devm_clk_get(&pdev->dev, NULL);
@@ -1158,8 +1155,6 @@ exit_rx_dma_free:
tegra_slink_deinit_dma_param(tspi, true);
exit_free_irq:
free_irq(spi_irq, tspi);
-exit_free_master:
- spi_master_put(master);
return ret;
}
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
index 3d09265..61807ef 100644
--- a/drivers/spi/spi-ti-qspi.c
+++ b/drivers/spi/spi-ti-qspi.c
@@ -423,7 +423,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
u32 max_freq;
int ret = 0, num_cs, irq;
- master = spi_alloc_master(&pdev->dev, sizeof(*qspi));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(*qspi));
if (!master)
return -ENOMEM;
@@ -484,26 +484,20 @@ static int ti_qspi_probe(struct platform_device *pdev)
mutex_init(&qspi->list_lock);
qspi->base = devm_ioremap_resource(&pdev->dev, r);
- if (IS_ERR(qspi->base)) {
- ret = PTR_ERR(qspi->base);
- goto free_master;
- }
+ if (IS_ERR(qspi->base))
+ return PTR_ERR(qspi->base);
if (res_ctrl) {
qspi->ctrl_mod = true;
qspi->ctrl_base = devm_ioremap_resource(&pdev->dev, res_ctrl);
- if (IS_ERR(qspi->ctrl_base)) {
- ret = PTR_ERR(qspi->ctrl_base);
- goto free_master;
- }
+ if (IS_ERR(qspi->ctrl_base))
+ return PTR_ERR(qspi->ctrl_base);
}
if (res_mmap) {
qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap);
- if (IS_ERR(qspi->mmap_base)) {
- ret = PTR_ERR(qspi->mmap_base);
- goto free_master;
- }
+ if (IS_ERR(qspi->mmap_base))
+ return PTR_ERR(qspi->mmap_base);
}
ret = devm_request_irq(&pdev->dev, irq, ti_qspi_isr, 0,
@@ -511,7 +505,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
irq);
- goto free_master;
+ return ret;
}
qspi->fclk = devm_clk_get(&pdev->dev, "fck");
@@ -529,15 +523,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
qspi->spi_max_frequency = max_freq;
- ret = devm_spi_register_master(&pdev->dev, master);
- if (ret)
- goto free_master;
-
- return 0;
-
-free_master:
- spi_master_put(master);
- return ret;
+ return devm_spi_register_master(&pdev->dev, master);
}
static int ti_qspi_remove(struct platform_device *pdev)
diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c
index 6191ced..76307b7 100644
--- a/drivers/spi/spi-txx9.c
+++ b/drivers/spi/spi-txx9.c
@@ -337,7 +337,7 @@ static int txx9spi_probe(struct platform_device *dev)
u32 mcr;
int irq;
- master = spi_alloc_master(&dev->dev, sizeof(*c));
+ master = devm_spi_alloc_master(&dev->dev, sizeof(*c));
if (!master)
return ret;
c = spi_master_get_devdata(master);
@@ -416,7 +416,6 @@ exit:
destroy_workqueue(c->workqueue);
if (c->clk)
clk_disable(c->clk);
- spi_master_put(master);
return ret;
}
diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c
index 24c40b1..094119d 100644
--- a/drivers/spi/spi-xcomm.c
+++ b/drivers/spi/spi-xcomm.c
@@ -216,7 +216,7 @@ static int spi_xcomm_probe(struct i2c_client *i2c,
struct spi_master *master;
int ret;
- master = spi_alloc_master(&i2c->dev, sizeof(*spi_xcomm));
+ master = devm_spi_alloc_master(&i2c->dev, sizeof(*spi_xcomm));
if (!master)
return -ENOMEM;
@@ -231,11 +231,7 @@ static int spi_xcomm_probe(struct i2c_client *i2c,
master->dev.of_node = i2c->dev.of_node;
i2c_set_clientdata(i2c, master);
- ret = devm_spi_register_master(&i2c->dev, master);
- if (ret < 0)
- spi_master_put(master);
-
- return ret;
+ return devm_spi_register_master(&i2c->dev, master);
}
static const struct i2c_device_id spi_xcomm_ids[] = {
--
1.8.4.2
^ permalink raw reply related
* [PATCH 2/3] spi: core: Update the devm_spi_register_master documentation
From: Maxime Ripard @ 2014-01-31 10:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391163792-21819-1-git-send-email-maxime.ripard@free-electrons.com>
If the devm_spi_register_master function is used together with the
spi_alloc_master as advertised in the documentation, it will either lead to a
memory leak if spi_put_master is removed, or we will try to access an already
freed memory area during the unregistration function.
Advertise that you want to use the devm_spi_alloc_master function in such case.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/spi/spi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index eb728ec..dc577b7 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1444,7 +1444,7 @@ static void devm_spi_unregister(struct device *dev, void *res)
/**
* dev_spi_register_master - register managed SPI master controller
* @dev: device managing SPI master
- * @master: initialized master, originally from spi_alloc_master()
+ * @master: initialized master, originally from devm_spi_alloc_master()
* Context: can sleep
*
* Register a SPI device as with spi_register_master() which will
--
1.8.4.2
^ permalink raw reply related
* [PATCH 1/3] spi: core: Add devm_spi_alloc_master
From: Maxime Ripard @ 2014-01-31 10:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391163792-21819-1-git-send-email-maxime.ripard@free-electrons.com>
Using devm_spi_register_master leads to a memory leak on the spi_master
structure.
spi_alloc_master uses kzalloc to allocate the spi_master but the introduction
of devm_spi_register_master removed all the matching calls to spi_master_put,
leaking the spi_master structure.
Add a devm_spi_alloc_master to provide the intended behaviour.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/spi/spi.c | 36 ++++++++++++++++++++++++++++++++++++
include/linux/spi/spi.h | 2 ++
2 files changed, 38 insertions(+)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 63613a9..eb728ec 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1266,6 +1266,42 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
}
EXPORT_SYMBOL_GPL(spi_alloc_master);
+static void devm_spi_put(struct device *dev, void *res)
+{
+ spi_master_put(*(struct spi_master **)res);
+}
+
+/**
+ * devm_spi_alloc_master - allocate SPI master controller
+ * @dev: the controller, possibly using the platform_bus
+ * @size: how much zeroed driver-private data to allocate; the pointer to this
+ * memory is in the driver_data field of the returned device,
+ * accessible with spi_master_get_devdata().
+ * Context: can sleep
+ *
+ * Allocates a master controller as with spi_alloc_master() which will
+ * automatically be freed
+ */
+struct spi_master *devm_spi_alloc_master(struct device *dev, unsigned size)
+{
+ struct spi_master **ptr, *master;
+
+ ptr = devres_alloc(devm_spi_put, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ master = spi_alloc_master(dev, size);
+ if (master) {
+ *ptr = master;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return master;
+}
+EXPORT_SYMBOL_GPL(devm_spi_alloc_master);
+
#ifdef CONFIG_OF
static int of_spi_register_master(struct spi_master *master)
{
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index a1d4ca2..6fbdb2b 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -462,6 +462,8 @@ extern void spi_finalize_current_transfer(struct spi_master *master);
/* the spi driver core manages memory for the spi_master classdev */
extern struct spi_master *
spi_alloc_master(struct device *host, unsigned size);
+extern struct spi_master *
+devm_spi_alloc_master(struct device *host, unsigned size);
extern int spi_register_master(struct spi_master *master);
extern int devm_spi_register_master(struct device *dev,
--
1.8.4.2
^ permalink raw reply related
* [PATCH 0/3] spi: core: Introduce devm_spi_alloc_master
From: Maxime Ripard @ 2014-01-31 10:23 UTC (permalink / raw)
To: linux-arm-kernel
Hi!
This patchset introduces a devm_spi_alloc_master to the spi core. While most of
the drivers have a spi_master_put call in the probe, a lot of them using the
devm_spi_register_master function are missing it in the remove function,
leading to leaked resources.
Hence, we introduced a devm_spi_alloc_master, and converted the users of
devm_spi_register_master to use it.
Maxime Ripard (3):
spi: core: Add devm_spi_alloc_master
spi: core: Update the devm_spi_register_master documentation
spi: switch to devm_spi_alloc_master
drivers/spi/spi-atmel.c | 8 +++-----
drivers/spi/spi-bcm2835.c | 15 +++++----------
drivers/spi/spi-bcm63xx-hsspi.c | 8 +++-----
drivers/spi/spi-bcm63xx.c | 16 ++++++----------
drivers/spi/spi-bfin-v3.c | 13 ++++---------
drivers/spi/spi-clps711x.c | 37 +++++++++++++++----------------------
drivers/spi/spi-coldfire-qspi.c | 15 +++++----------
drivers/spi/spi-dw.c | 6 ++----
drivers/spi/spi-ep93xx.c | 15 +++++----------
drivers/spi/spi-falcon.c | 5 ++---
drivers/spi/spi-mpc512x-psc.c | 19 ++++++++-----------
drivers/spi/spi-mxs.c | 9 +++------
drivers/spi/spi-octeon.c | 12 ++++--------
drivers/spi/spi-omap-100k.c | 16 +++++-----------
drivers/spi/spi-omap2-mcspi.c | 18 ++++++------------
drivers/spi/spi-orion.c | 10 +++-------
drivers/spi/spi-pl022.c | 3 +--
drivers/spi/spi-pxa2xx.c | 3 +--
drivers/spi/spi-rspi.c | 13 ++++---------
drivers/spi/spi-s3c64xx.c | 23 ++++++++---------------
drivers/spi/spi-sc18is602.c | 12 ++----------
drivers/spi/spi-sh-hspi.c | 7 ++-----
drivers/spi/spi-tegra114.c | 15 +++++----------
drivers/spi/spi-tegra20-sflash.c | 12 ++++--------
drivers/spi/spi-tegra20-slink.c | 15 +++++----------
drivers/spi/spi-ti-qspi.c | 32 +++++++++-----------------------
drivers/spi/spi-txx9.c | 3 +--
drivers/spi/spi-xcomm.c | 8 ++------
drivers/spi/spi.c | 38 +++++++++++++++++++++++++++++++++++++-
include/linux/spi/spi.h | 2 ++
30 files changed, 162 insertions(+), 246 deletions(-)
--
1.8.4.2
^ permalink raw reply
* [PATCH v2 00/21] pinctrl: mvebu: restructure and remove hardcoded addresses from Dove pinctrl
From: Sebastian Hesselbarth @ 2014-01-31 10:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACRpkda5HRxpLWWizT_58SJ6Fb=TQpO=Y5yFThpZkUbUYmU8fg@mail.gmail.com>
On 01/31/14 11:17, Linus Walleij wrote:
> On Tue, Jan 28, 2014 at 1:39 AM, Sebastian Hesselbarth
> <sebastian.hesselbarth@gmail.com> wrote:
>
>> This patch set is one required step for Dove to hop into mach-mvebu.
>> Until now, pinctrl-dove was hardcoding some registers that do not
>> directly belong to MPP core registers. This is not compatible with
>> what we want for mach-mvebu.
>
> All this stuff is really nice, so if you can get Thomas to add his
> review-tag on this stuff and maybe have some Tested-by:s
> from other parties, I'd be happy to pull the end result to the
> pinctrl tree, or alternatively provide my ACK for you to take this
> through ARM SoC.
Luckily, we have a "pinctrl/mvebu" subfolder these patches will mess
with. I think it will be better to keep then all together and take
them through the MVEBU branch. This way we can have an eye on it and
base off subsequent patches without bothering you.
I'll come back to request your ACK as soon as we have sorted it out.
Sebastian
^ permalink raw reply
* [PATCH v2 09/21] pinctrl: mvebu: dove: provide generic mpp callbacks
From: Sebastian Hesselbarth @ 2014-01-31 10:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACRpkdYpGm-KAFqU5cpzbhrM1NaZJYtQa86wP7qJFrai2bDYbw@mail.gmail.com>
On 01/31/14 11:13, Linus Walleij wrote:
> On Tue, Jan 28, 2014 at 1:39 AM, Sebastian Hesselbarth
> <sebastian.hesselbarth@gmail.com> wrote:
>
>> We want to get rid of passing register addresses to common pinctrl
>> driver, so provide set/get callbacks for generic mpp pins.
>>
>> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
[...]
>> @@ -374,7 +398,7 @@ static struct mvebu_mpp_ctrl dove_mpp_controls[] = {
>> MPP_FUNC_CTRL(13, 13, "mpp13", dove_pmu_mpp_ctrl),
>> MPP_FUNC_CTRL(14, 14, "mpp14", dove_pmu_mpp_ctrl),
>> MPP_FUNC_CTRL(15, 15, "mpp15", dove_pmu_mpp_ctrl),
>> - MPP_REG_CTRL(16, 23),
>> + MPP_FUNC_CTRL(16, 23, NULL, dove_mpp_ctrl),
>
> What does this have to do with the rest of the patch?
>
> (Maybe I'm stupid, beware I'm just glancing over this stuff as I
> see the patch set is still in development.)
Not really, the driver is slightly misdesigned and this patches
try to clean this up a bit. I have prepared a v3 branch for the
MVEBU guys to have a look at first.
Short version: Thanks for trying to review this, but I guess your time
would be better spent on a soon to be posted v3.
Long version:
Not having a callback identifies each control as "generic mpp pins",
so by passing a callback we make them "SoC specific" as a preparation
to remove the common "generic mpp" set/get function.
Sebastian
^ permalink raw reply
* [PATCH v2 00/21] pinctrl: mvebu: restructure and remove hardcoded addresses from Dove pinctrl
From: Linus Walleij @ 2014-01-31 10:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390869573-27624-1-git-send-email-sebastian.hesselbarth@gmail.com>
On Tue, Jan 28, 2014 at 1:39 AM, Sebastian Hesselbarth
<sebastian.hesselbarth@gmail.com> wrote:
> This patch set is one required step for Dove to hop into mach-mvebu.
> Until now, pinctrl-dove was hardcoding some registers that do not
> directly belong to MPP core registers. This is not compatible with
> what we want for mach-mvebu.
All this stuff is really nice, so if you can get Thomas to add his
review-tag on this stuff and maybe have some Tested-by:s
from other parties, I'd be happy to pull the end result to the
pinctrl tree, or alternatively provide my ACK for you to take this
through ARM SoC.
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v2 09/21] pinctrl: mvebu: dove: provide generic mpp callbacks
From: Linus Walleij @ 2014-01-31 10:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390869573-27624-10-git-send-email-sebastian.hesselbarth@gmail.com>
On Tue, Jan 28, 2014 at 1:39 AM, Sebastian Hesselbarth
<sebastian.hesselbarth@gmail.com> wrote:
> We want to get rid of passing register addresses to common pinctrl
> driver, so provide set/get callbacks for generic mpp pins.
>
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
OK...
> +static int dove_mpp_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
> + unsigned long *config)
> +{
(...)
This is fine.
> @@ -374,7 +398,7 @@ static struct mvebu_mpp_ctrl dove_mpp_controls[] = {
> MPP_FUNC_CTRL(13, 13, "mpp13", dove_pmu_mpp_ctrl),
> MPP_FUNC_CTRL(14, 14, "mpp14", dove_pmu_mpp_ctrl),
> MPP_FUNC_CTRL(15, 15, "mpp15", dove_pmu_mpp_ctrl),
> - MPP_REG_CTRL(16, 23),
> + MPP_FUNC_CTRL(16, 23, NULL, dove_mpp_ctrl),
What does this have to do with the rest of the patch?
(Maybe I'm stupid, beware I'm just glancing over this stuff as I
see the patch set is still in development.)
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH resend 2/2] arm64: add support for kernel mode NEON in interrupt context
From: Ard Biesheuvel @ 2014-01-31 10:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391163196-27619-1-git-send-email-ard.biesheuvel@linaro.org>
This patch modifies kernel_neon_begin() and kernel_neon_end(), so
they may be called from any context. To address the case where only
a couple of registers are needed, kernel_neon_begin_partial(u32) is
introduced which takes as a parameter the number of bottom 'n' NEON
q-registers required. To mark the end of such a partial section, the
regular kernel_neon_end() should be used.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/include/asm/fpsimd.h | 17 ++++++++++++++
arch/arm64/include/asm/fpsimdmacros.h | 37 +++++++++++++++++++++++++++++
arch/arm64/include/asm/neon.h | 6 ++++-
arch/arm64/kernel/entry-fpsimd.S | 24 +++++++++++++++++++
arch/arm64/kernel/fpsimd.c | 44 +++++++++++++++++++++++------------
5 files changed, 112 insertions(+), 16 deletions(-)
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 609bc44ceb8d..dc9ef741c648 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -41,6 +41,19 @@ struct fpsimd_state {
unsigned int last_cpu;
};
+/*
+ * Struct for stacking the bottom 'n' FP/SIMD registers.
+ * Mainly intended for kernel use of v8 Crypto Extensions which only
+ * needs a few registers and may need to execute in atomic context.
+ */
+struct fpsimd_partial_state {
+ u32 num_regs;
+ u32 fpsr;
+ u32 fpcr;
+ __uint128_t vregs[32] __aligned(16);
+} __aligned(16);
+
+
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
/* Masks for extracting the FPSR and FPCR from the FPSCR */
#define VFP_FPSCR_STAT_MASK 0xf800009f
@@ -57,6 +70,10 @@ struct task_struct;
extern void fpsimd_save_state(struct fpsimd_state *state);
extern void fpsimd_load_state(struct fpsimd_state *state);
+extern void fpsimd_save_partial_state(struct fpsimd_partial_state *state,
+ u32 num_regs);
+extern void fpsimd_load_partial_state(struct fpsimd_partial_state *state);
+
extern void fpsimd_thread_switch(struct task_struct *next);
extern void fpsimd_flush_thread(void);
extern void fpsimd_reload_fpstate(void);
diff --git a/arch/arm64/include/asm/fpsimdmacros.h b/arch/arm64/include/asm/fpsimdmacros.h
index bbec599c96bd..42990a82c671 100644
--- a/arch/arm64/include/asm/fpsimdmacros.h
+++ b/arch/arm64/include/asm/fpsimdmacros.h
@@ -62,3 +62,40 @@
ldr w\tmpnr, [\state, #16 * 2 + 4]
msr fpcr, x\tmpnr
.endm
+
+.altmacro
+.macro q2op, op, q1, q2, state
+ \op q\q1, q\q2, [\state, # -16 * \q1 - 16]
+.endm
+
+.macro fpsimd_save_partial state, numnr, tmpnr1, tmpnr2
+ mrs x\tmpnr1, fpsr
+ str w\numnr, [\state]
+ mrs x\tmpnr2, fpcr
+ stp w\tmpnr1, w\tmpnr2, [\state, #4]
+ adr x\tmpnr1, 0f
+ add \state, \state, x\numnr, lsl #4
+ sub x\tmpnr1, x\tmpnr1, x\numnr, lsl #1
+ br x\tmpnr1
+ .irp qa, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0
+ qb = \qa + 1
+ q2op stp, \qa, %qb, \state
+ .endr
+0:
+.endm
+
+.macro fpsimd_restore_partial state, tmpnr1, tmpnr2
+ ldp w\tmpnr1, w\tmpnr2, [\state, #4]
+ msr fpsr, x\tmpnr1
+ msr fpcr, x\tmpnr2
+ adr x\tmpnr1, 0f
+ ldr w\tmpnr2, [\state]
+ add \state, \state, x\tmpnr2, lsl #4
+ sub x\tmpnr1, x\tmpnr1, x\tmpnr2, lsl #1
+ br x\tmpnr1
+ .irp qa, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0
+ qb = \qa + 1
+ q2op ldp, \qa, %qb, \state
+ .endr
+0:
+.endm
diff --git a/arch/arm64/include/asm/neon.h b/arch/arm64/include/asm/neon.h
index b0cc58a97780..13ce4cc18e26 100644
--- a/arch/arm64/include/asm/neon.h
+++ b/arch/arm64/include/asm/neon.h
@@ -8,7 +8,11 @@
* published by the Free Software Foundation.
*/
+#include <linux/types.h>
+
#define cpu_has_neon() (1)
-void kernel_neon_begin(void);
+#define kernel_neon_begin() kernel_neon_begin_partial(32)
+
+void kernel_neon_begin_partial(u32 num_regs);
void kernel_neon_end(void);
diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S
index 6a27cd6dbfa6..d358ccacfc00 100644
--- a/arch/arm64/kernel/entry-fpsimd.S
+++ b/arch/arm64/kernel/entry-fpsimd.S
@@ -41,3 +41,27 @@ ENTRY(fpsimd_load_state)
fpsimd_restore x0, 8
ret
ENDPROC(fpsimd_load_state)
+
+#ifdef CONFIG_KERNEL_MODE_NEON
+
+/*
+ * Save the bottom n FP registers.
+ *
+ * x0 - pointer to struct fpsimd_partial_state
+ */
+ENTRY(fpsimd_save_partial_state)
+ fpsimd_save_partial x0, 1, 8, 9
+ ret
+ENDPROC(fpsimd_load_partial_state)
+
+/*
+ * Load the bottom n FP registers.
+ *
+ * x0 - pointer to struct fpsimd_partial_state
+ */
+ENTRY(fpsimd_load_partial_state)
+ fpsimd_restore_partial x0, 8, 9
+ ret
+ENDPROC(fpsimd_load_partial_state)
+
+#endif
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 226a495e019c..970c2fa86530 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -144,30 +144,44 @@ void fpsimd_reload_fpstate(void)
#ifdef CONFIG_KERNEL_MODE_NEON
+static DEFINE_PER_CPU(struct fpsimd_partial_state, hardirq_fpsimdstate);
+static DEFINE_PER_CPU(struct fpsimd_partial_state, softirq_fpsimdstate);
+
/*
* Kernel-side NEON support functions
*/
-void kernel_neon_begin(void)
+void kernel_neon_begin_partial(u32 num_regs)
{
- /* Avoid using the NEON in interrupt context */
- BUG_ON(in_interrupt());
- preempt_disable();
-
- /*
- * Save the userland FPSIMD state if we have one and if we haven't done
- * so already. Clear fpsimd_last_task to indicate that there is no
- * longer userland context in the registers.
- */
- if (current->mm && !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE))
- fpsimd_save_state(¤t->thread.fpsimd_state);
- __get_cpu_var(fpsimd_last_task) = NULL;
+ if (in_interrupt()) {
+ struct fpsimd_partial_state *s = this_cpu_ptr(
+ in_irq() ? &hardirq_fpsimdstate : &softirq_fpsimdstate);
+ BUG_ON(num_regs > 32);
+ fpsimd_save_partial_state(s, roundup(num_regs, 2));
+ } else {
+ /*
+ * Save the userland FPSIMD state if we have one and if we
+ * haven't done so already. Clear fpsimd_last_task to indicate
+ * that there is no longer userland context in the registers.
+ */
+ preempt_disable();
+ if (current->mm &&
+ !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE))
+ fpsimd_save_state(¤t->thread.fpsimd_state);
+ __get_cpu_var(fpsimd_last_task) = NULL;
+ }
}
-EXPORT_SYMBOL(kernel_neon_begin);
+EXPORT_SYMBOL(kernel_neon_begin_partial);
void kernel_neon_end(void)
{
- preempt_enable();
+ if (in_interrupt()) {
+ struct fpsimd_partial_state *s = this_cpu_ptr(
+ in_irq() ? &hardirq_fpsimdstate : &softirq_fpsimdstate);
+ fpsimd_load_partial_state(s);
+ } else {
+ preempt_enable();
+ }
}
EXPORT_SYMBOL(kernel_neon_end);
--
1.8.3.2
^ permalink raw reply related
* [PATCH resend 1/2] arm64: defer reloading a task's FPSIMD state to userland resume
From: Ard Biesheuvel @ 2014-01-31 10:13 UTC (permalink / raw)
To: linux-arm-kernel
If a task gets scheduled out and back in again and nothing has touched
its FPSIMD state in the mean time, there is really no reason to reload
it from memory. Similarly, repeated calls to kernel_neon_begin() and
kernel_neon_end() will preserve and restore the FPSIMD state every time.
This patch defers the FPSIMD state restore to the last possible moment,
i.e., right before the task re-enters userland. If a task does not enter
userland at all (for any reason), the existing FPSIMD state is preserved
and may be reused by the owning task if it gets scheduled in again on the
same CPU.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/include/asm/fpsimd.h | 3 ++
arch/arm64/include/asm/thread_info.h | 4 +-
arch/arm64/kernel/entry.S | 2 +-
arch/arm64/kernel/fpsimd.c | 79 +++++++++++++++++++++++++++++++-----
arch/arm64/kernel/process.c | 3 +-
arch/arm64/kernel/signal.c | 3 ++
6 files changed, 81 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index c43b4ac13008..609bc44ceb8d 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -37,6 +37,8 @@ struct fpsimd_state {
u32 fpcr;
};
};
+ /* the id of the last cpu to have restored this state */
+ unsigned int last_cpu;
};
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
@@ -57,6 +59,7 @@ extern void fpsimd_load_state(struct fpsimd_state *state);
extern void fpsimd_thread_switch(struct task_struct *next);
extern void fpsimd_flush_thread(void);
+extern void fpsimd_reload_fpstate(void);
#endif
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 720e70b66ffd..4a1ca1cfb2f8 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -100,6 +100,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SIGPENDING 0
#define TIF_NEED_RESCHED 1
#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */
+#define TIF_FOREIGN_FPSTATE 3 /* CPU's FP state is not current's */
#define TIF_SYSCALL_TRACE 8
#define TIF_POLLING_NRFLAG 16
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
@@ -112,10 +113,11 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
+#define _TIF_FOREIGN_FPSTATE (1 << TIF_FOREIGN_FPSTATE)
#define _TIF_32BIT (1 << TIF_32BIT)
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
- _TIF_NOTIFY_RESUME)
+ _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE)
#endif /* __KERNEL__ */
#endif /* __ASM_THREAD_INFO_H */
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 39ac630d83de..80464e2fb1a5 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -576,7 +576,7 @@ fast_work_pending:
str x0, [sp, #S_X0] // returned x0
work_pending:
tbnz x1, #TIF_NEED_RESCHED, work_resched
- /* TIF_SIGPENDING or TIF_NOTIFY_RESUME case */
+ /* TIF_SIGPENDING, TIF_NOTIFY_RESUME or TIF_FOREIGN_FPSTATE case */
ldr x2, [sp, #S_PSTATE]
mov x0, sp // 'regs'
tst x2, #PSR_MODE_MASK // user mode regs?
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 4aef42a04bdc..226a495e019c 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -35,6 +35,23 @@
#define FPEXC_IDF (1 << 7)
/*
+ * In order to reduce the number of times the fpsimd state is needlessly saved
+ * and restored, keep track here of which task's userland owns the current state
+ * of the FPSIMD register file.
+ *
+ * This percpu variable points to the fpsimd_state.last_cpu field of the task
+ * whose FPSIMD state was most recently loaded onto this cpu. The last_cpu field
+ * itself contains the id of the cpu onto which the task's FPSIMD state was
+ * loaded most recently. So, to decide whether we can skip reloading the FPSIMD
+ * state, we need to check
+ * (a) whether this task was the last one to have its FPSIMD state loaded onto
+ * this cpu
+ * (b) whether this task may have manipulated its FPSIMD state on another cpu in
+ * the meantime
+ */
+static DEFINE_PER_CPU(unsigned int *, fpsimd_last_task);
+
+/*
* Trapped FP/ASIMD access.
*/
void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
@@ -72,18 +89,56 @@ void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
void fpsimd_thread_switch(struct task_struct *next)
{
- /* check if not kernel threads */
- if (current->mm)
+ /*
+ * The thread flag TIF_FOREIGN_FPSTATE conveys that the userland FPSIMD
+ * state belonging to the current task is not present in the registers
+ * but has (already) been saved to memory in order for the kernel to be
+ * able to go off and use the registers for something else. Therefore,
+ * we must not (re)save the register contents if this flag is set.
+ */
+ if (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE))
fpsimd_save_state(¤t->thread.fpsimd_state);
- if (next->mm)
- fpsimd_load_state(&next->thread.fpsimd_state);
+
+ if (next->mm) {
+ /*
+ * If we are switching to a task whose most recent userland NEON
+ * contents are already in the registers of *this* cpu, we can
+ * skip loading the state from memory. Otherwise, set the
+ * TIF_FOREIGN_FPSTATE flag so the state will be loaded upon the
+ * next entry of userland.
+ */
+ struct fpsimd_state *st = &next->thread.fpsimd_state;
+
+ if (__get_cpu_var(fpsimd_last_task) == &st->last_cpu
+ && st->last_cpu == smp_processor_id())
+ clear_ti_thread_flag(task_thread_info(next),
+ TIF_FOREIGN_FPSTATE);
+ else
+ set_ti_thread_flag(task_thread_info(next),
+ TIF_FOREIGN_FPSTATE);
+ }
}
void fpsimd_flush_thread(void)
{
- preempt_disable();
memset(¤t->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
- fpsimd_load_state(¤t->thread.fpsimd_state);
+ set_thread_flag(TIF_FOREIGN_FPSTATE);
+}
+
+void fpsimd_reload_fpstate(void)
+{
+ preempt_disable();
+ if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) {
+ /*
+ * We are entering userland and the userland context is not yet
+ * present in the registers.
+ */
+ struct fpsimd_state *st = ¤t->thread.fpsimd_state;
+
+ fpsimd_load_state(st);
+ __get_cpu_var(fpsimd_last_task) = &st->last_cpu;
+ st->last_cpu = smp_processor_id();
+ }
preempt_enable();
}
@@ -98,16 +153,20 @@ void kernel_neon_begin(void)
BUG_ON(in_interrupt());
preempt_disable();
- if (current->mm)
+ /*
+ * Save the userland FPSIMD state if we have one and if we haven't done
+ * so already. Clear fpsimd_last_task to indicate that there is no
+ * longer userland context in the registers.
+ */
+ if (current->mm && !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE))
fpsimd_save_state(¤t->thread.fpsimd_state);
+ __get_cpu_var(fpsimd_last_task) = NULL;
+
}
EXPORT_SYMBOL(kernel_neon_begin);
void kernel_neon_end(void)
{
- if (current->mm)
- fpsimd_load_state(¤t->thread.fpsimd_state);
-
preempt_enable();
}
EXPORT_SYMBOL(kernel_neon_end);
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 248a15db37f2..274316df860f 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -205,7 +205,8 @@ void release_thread(struct task_struct *dead_task)
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
- fpsimd_save_state(¤t->thread.fpsimd_state);
+ if (!test_thread_flag(TIF_FOREIGN_FPSTATE))
+ fpsimd_save_state(¤t->thread.fpsimd_state);
*dst = *src;
return 0;
}
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 890a591f75dd..0a9eccf4fc0f 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -416,4 +416,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
}
+
+ if (thread_flags & _TIF_FOREIGN_FPSTATE)
+ fpsimd_reload_fpstate();
}
--
1.8.3.2
^ permalink raw reply related
* iommu/arm-smmu: Regression (sleeping function called from invalid context)
From: Andreas Herrmann @ 2014-01-31 9:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140131084623.GN13543@alberich>
On Fri, Jan 31, 2014 at 09:46:23AM +0100, Andreas Herrmann wrote:
> On Fri, Jan 31, 2014 at 12:55:52AM +0100, Andreas Herrmann wrote:
> > Hi Will,
> >
> > Seems that commit a44a9791e778d9ccda50d5534028ed4057a9a45b
> > (iommu/arm-smmu: use mutex instead of spinlock for locking page tables)
> > introduced a regression.
> >
> > At least I've hit
> >
> > BUG: scheduling while atomic: ksoftirqd/0/3/0x00000100
> >...
>
> > BUG: sleeping function called from invalid context at mm/page_alloc.c:2679
> > in_atomic(): 1, irqs_disabled(): 128, pid: 0, name: swapper/0
> > CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.13.0-00016-g6e90346 #413
> > [<c0014740>] (unwind_backtrace+0x0/0xf8) from [<c00115b0>] (show_stack+0x10/0x14)
> > [<c00115b0>] (show_stack+0x10/0x14) from [<c057ea24>] (dump_stack+0x74/0xa8)
> > [<c057ea24>] (dump_stack+0x74/0xa8) from [<c00acc1c>] (__alloc_pages_nodemask+0x174/0x930)
> > [<c00acc1c>] (__alloc_pages_nodemask+0x174/0x930) from [<c042a250>] (arm_smmu_handle_mapping+0x470/0x66c)
> > [<c042a250>] (arm_smmu_handle_mapping+0x470/0x66c) from [<c0428e74>] (iommu_map+0xf0/0x148)
> > [<c0428e74>] (iommu_map+0xf0/0x148) from [<c001935c>] (__map_sg_chunk+0x198/0x2d4)
> >...
>
> > Maybe that was the reason why the offending commit was introduced(?).
> >
> > I think with the current code "atomic allocations" should be used when
> > IO page tables are created. With below patch I've not triggered above
> > errors.
>
> I think allocating memory with GFP_KERNEL in this dma-mapping path
> doesn't seem to be a good idea. What if the DMA operation for which we
> modify IO page tables was triggered to free pages (page cache, swap)?
I mean in case we run out of memory wouldn't we worsen the situation
by triggering additional IO (and thus DMA)? Whereas when we let the
mapping fail, the OS "just might have to wait a little bit" until
other DMA activities are completed, pages unmapped and iova freed. The
freed resources instantly can be used for further DMA activities.
Hmm, but maybe I need to rethink this (and look more closely into
page_alloc.c).
Andreas
^ permalink raw reply
* [PATCH v2 1/2] at91: gpio: use gpiolib API to mark a GPIO used as an IRQ
From: Nicolas Ferre @ 2014-01-31 8:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACRpkdZ4LxkRERfD-prZvJSOZyomgf8v8P+vLhb_+hrSkL8rzg@mail.gmail.com>
On 31/01/2014 08:55, Linus Walleij :
> On Thu, Jan 23, 2014 at 11:37 AM, Jean-Jacques Hiblot
> <jjhiblot@traphandler.com> wrote:
>
>> When an IRQ is started on a GPIO line, mark this GPIO as IRQ in
>> the gpiolib so we can keep track of the usage centrally.
>>
>> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
>
> Acked-by: Linus Walleij <linus.walleij@linaro.org>
>
> Nicolas, are you queueing this patch?
Yes, I will.
> I guess this custom GPIO implementation is going away with
> the transition to pinctrl else I'd requested that it be moved to
> drivers/gpio...
Absolutely. But I suspect it will still be around for some time...
Thanks for your review. Bye,
--
Nicolas Ferre
^ permalink raw reply
* [PATCH V3 3/8] SPEAr13xx: defconfig: Update
From: Mohit KUMAR DCG @ 2014-01-31 8:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201401301402.01842.arnd@arndb.de>
Hello Arnd,
> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd at arndb.de]
> Sent: Thursday, January 30, 2014 6:32 PM
> To: Mohit KUMAR DCG
> Cc: Pratyush ANAND; spear-devel; linux-arm-kernel at lists.infradead.org
> Subject: Re: [PATCH V3 3/8] SPEAr13xx: defconfig: Update
>
> On Thursday 30 January 2014, Mohit Kumar wrote:
> > Enable EABI, OEABI, VFP and NFS configs in default configuration file
> > for SPEAr13xx.
>
> Are you sure about OABI_COMPAT? That seems unusual.
- yes, this option is not required
>
> Also, please add all the options you need to multi_v7_defconfig and ensure
> that this configuration works with your hardware as well.
- OK, will do this and test with SPEAr1310.
Thanks
Mohit
^ permalink raw reply
* iommu/arm-smmu: Regression (sleeping function called from invalid context)
From: Andreas Herrmann @ 2014-01-31 8:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140130235552.GL13543@alberich>
On Fri, Jan 31, 2014 at 12:55:52AM +0100, Andreas Herrmann wrote:
> Hi Will,
>
> Seems that commit a44a9791e778d9ccda50d5534028ed4057a9a45b
> (iommu/arm-smmu: use mutex instead of spinlock for locking page tables)
> introduced a regression.
>
> At least I've hit
>
> BUG: scheduling while atomic: ksoftirqd/0/3/0x00000100
>...
> BUG: sleeping function called from invalid context at mm/page_alloc.c:2679
> in_atomic(): 1, irqs_disabled(): 128, pid: 0, name: swapper/0
> CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.13.0-00016-g6e90346 #413
> [<c0014740>] (unwind_backtrace+0x0/0xf8) from [<c00115b0>] (show_stack+0x10/0x14)
> [<c00115b0>] (show_stack+0x10/0x14) from [<c057ea24>] (dump_stack+0x74/0xa8)
> [<c057ea24>] (dump_stack+0x74/0xa8) from [<c00acc1c>] (__alloc_pages_nodemask+0x174/0x930)
> [<c00acc1c>] (__alloc_pages_nodemask+0x174/0x930) from [<c042a250>] (arm_smmu_handle_mapping+0x470/0x66c)
> [<c042a250>] (arm_smmu_handle_mapping+0x470/0x66c) from [<c0428e74>] (iommu_map+0xf0/0x148)
> [<c0428e74>] (iommu_map+0xf0/0x148) from [<c001935c>] (__map_sg_chunk+0x198/0x2d4)
>...
> Maybe that was the reason why the offending commit was introduced(?).
>
> I think with the current code "atomic allocations" should be used when
> IO page tables are created. With below patch I've not triggered above
> errors.
I think allocating memory with GFP_KERNEL in this dma-mapping path
doesn't seem to be a good idea. What if the DMA operation for which we
modify IO page tables was triggered to free pages (page cache, swap)?
Andreas
^ permalink raw reply
* [PATCH v2 RESEND] vt8500: pinctrl: Change devicetree data parsing
From: Linus Walleij @ 2014-01-31 8:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390467453-8841-1-git-send-email-linux@prisktech.co.nz>
On Thu, Jan 23, 2014 at 9:57 AM, Tony Prisk <linux@prisktech.co.nz> wrote:
> Due to an assumption in the VT8500 pinctrl driver, the value passed
> from devicetree for 'wm,pull' was not explicitly translated before
> being passed to pinconf.
>
> Since v3.10, changes to 'enum pin_config_param', PIN_CONFIG_BIAS_PULL_(UP/DOWN)
> no longer map 1-to-1 with the expected values in devicetree.
>
> This patch adds a small translation between the devicetree values (0..2)
> and the enum pin_config_param equivalent values.
>
> Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
> ---
> v2:
Patch applied to fixes and tagged for stable v3.10+
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v2 3/5] spi: sunxi: Add Allwinner A31 SPI controller driver
From: Maxime Ripard @ 2014-01-31 8:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGa+x854huSmiWmEv2EgOPUgZKcp3iitNaBvKXt8DiEj8msSVg@mail.gmail.com>
Hi Kevin,
On Thu, Jan 30, 2014 at 03:52:16PM -0800, Kevin Hilman wrote:
> On Wed, Jan 29, 2014 at 5:32 AM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > On Wed, Jan 29, 2014 at 12:25:20PM +0000, Mark Brown wrote:
> >> On Wed, Jan 29, 2014 at 12:10:48PM +0100, Maxime Ripard wrote:
> >>
> >> > +config SPI_SUN6I
> >> > + tristate "Allwinner A31 SPI controller"
> >> > + depends on ARCH_SUNXI || COMPILE_TEST
> >> > + select PM_RUNTIME
> >> > + help
> >> > + This enables using the SPI controller on the Allwinner A31 SoCs.
> >> > +
> >>
> >> A select of PM_RUNTIME is both surprising and odd - why is that there?
> >> The usual idiom is that the device starts out powered up (flagged using
> >> pm_runtime_set_active()) and then runtime PM then suspends it when it's
> >> compiled in. That way if for some reason people want to avoid runtime
> >> PM they can still use the device.
> >
> > Since pm_runtime_set_active and all the pm_runtime* callbacks in
> > general are defined to pretty much empty functions, how the
> > suspend/resume callbacks are called then? Obviously, we need them to
> > be run, hence why I added the select here, but now I'm seeing a
> > construct like what's following acceptable then?
>
> Even with your 'select', The runtime PM callbacks will never be called
> in the current driver. pm_runtime_enable() doesn't do any runtime PM
> transitions. It just allows transitions to happen when they're
> triggered by _get()/_put()/etc.
Actually, pm_runtime_get_sync is called by the SPI framework whenever
the device needs to be used. And pm_runtime_put whenever it's not used
anymore, so the callbacks are actually called.
>
> > pm_runtime_enable(&pdev->dev);
> > if (!pm_runtime_enabled(&pdev->dev))
> > sun6i_spi_runtime_resume(&pdev->dev);
>
> Similarily here, it's not the pm_runtime_enable that will fail when
> runtime PM is disabled (or not built-in), it's a pm_runtime_get_sync()
> that will fail.
In the case where pm_runtime is disabled, pm_runtime_enabled will only
return false, and hence the resume callback will be called. get_sync
will fail too when the framework will call it, but since the device is
already initialized, it's fine I guess.
> What you want is something like this in ->probe()
>
> sun6i_spi_runtime_resume();
> /* now, device is always activated whether or not runtime PM is enabled */
> pm_runtime_enable();
> pm_runtime_set_active(); /* tells runtime PM core device is
> already active */
> pm_runtime_get_sync();
>
> This 'get' will increase the usecount, but not actually call the
> callbacks because we told the RPM core that the device was already
> activated with _set_active().
>
> And then, in ->remove(), you'll want
>
> pm_runtime_put();
> pm_runtime_disable();
>
> And if runtime PM is not enabled in the kernel, then the device will
> be left on (which is kinda what you want if you didn't build runtime
> PM into the kernel.)
Yes, but that also mean that the device is actually on after the
probe, even if it's never going to be used. From what I got reading
the pm_runtime code, the suspend callback is called only whenever you
call _put, so the device will be suspended only after it's been used
the first time, right?
Wouldn't it be better if it was suspended by default, and just waken
up whenever the framework needs it?
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140131/489f461a/attachment.sig>
^ permalink raw reply
* device-tree: at91: irq and gpios: problem while requesting a gpio used as an interrupt source.
From: Linus Walleij @ 2014-01-31 8:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACh+v5Ot4ZwJrE_nJyJn-h-ZNrHfCk60c6KH_ErnFkD+u7atng@mail.gmail.com>
On Thu, Jan 23, 2014 at 2:16 PM, Jean-Jacques Hiblot
<jjhiblot@traphandler.com> wrote:
> I've been thinking hard on the gpio ownership and I'd like your
> opinion on the following assumptions:
>
> - a gpio used as an interrupt is always a gpio configured as an input.
> (corollary : a gpio used for interrupt cannot not be an ouput)
That is the assumption made by the core. Until the day someone
comes up with a weird usecase...
> - a gpio used as an input or interrupt only, could be safely accessed
> by multiple users.
Multiple consumers is the term we would use. But yes.
> - a gpio used as an output should be used as such by only one user.
> Still other users should be allowed to read its value.
Sounds reasonable.
> If those assumptions are true, I believe they can lead to a new
> exclusion scheme:
> - ouput is mutually exclusive with interrupt but not with input
> - only 1 ouput user at a time.
Logical conclusion from the above yes.
> It would do away with our sharing issue and more (chained interrupt
> handlers on gpio interrupt, read/interrupt access through sysfs to a
> gpio requested by a driver)
>
> And I believe that most of the infrastructure is in place to implement this :
> - direction flags in gpio_request_one
> - gpio_lock_as_irq/gpio_unlock_as_irq
So I think what I need to see is a proposed patch, whether it will
hit a particular driver or the gpiolib core, but either would probably
be interesting.
Pls keep linux-gpio and Alexandre on CC for this discussion.
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v2 2/2] at91: pinctrl: use gpiolib API to mark a GPIO used as an IRQ
From: Linus Walleij @ 2014-01-31 7:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390473478-5591-3-git-send-email-jjhiblot@traphandler.com>
On Thu, Jan 23, 2014 at 11:37 AM, Jean-Jacques Hiblot
<jjhiblot@traphandler.com> wrote:
> When an IRQ is started on a GPIO line, mark this GPIO as IRQ in
> the gpiolib so we can keep track of the usage centrally.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
Thanks!
Patch applied.
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v2 1/2] at91: gpio: use gpiolib API to mark a GPIO used as an IRQ
From: Linus Walleij @ 2014-01-31 7:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390473478-5591-2-git-send-email-jjhiblot@traphandler.com>
On Thu, Jan 23, 2014 at 11:37 AM, Jean-Jacques Hiblot
<jjhiblot@traphandler.com> wrote:
> When an IRQ is started on a GPIO line, mark this GPIO as IRQ in
> the gpiolib so we can keep track of the usage centrally.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Nicolas, are you queueing this patch?
I guess this custom GPIO implementation is going away with
the transition to pinctrl else I'd requested that it be moved to
drivers/gpio...
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v2] dma: Add Xilinx AXI Video Direct Memory Access Engine driver support
From: Srikanth Thokala @ 2014-01-31 6:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CA+mB=1Jwjn+KSO9yFr=LNVjk3khf0b-LLQamYf+nnSF4bODGPA@mail.gmail.com>
Hi Vinod,
On Mon, Jan 27, 2014 at 4:36 PM, Srikanth Thokala <sthokal@xilinx.com> wrote:
> Hi Vinod,
>
> On Sun, Jan 26, 2014 at 7:29 PM, Vinod Koul <vinod.koul@intel.com> wrote:
>> On Fri, Jan 24, 2014 at 02:24:27PM +0100, Lars-Peter Clausen wrote:
>>> On 01/24/2014 12:16 PM, Srikanth Thokala wrote:
>>> > Hi Lars,
>>> >
>>> > On Thu, Jan 23, 2014 at 4:55 PM, Lars-Peter Clausen <lars@metafoo.de> wrote:
>>> >> On 01/22/2014 05:52 PM, Srikanth Thokala wrote:
>>> >> [...]
>>> >>> +/**
>>> >>> + * xilinx_vdma_device_control - Configure DMA channel of the device
>>> >>> + * @dchan: DMA Channel pointer
>>> >>> + * @cmd: DMA control command
>>> >>> + * @arg: Channel configuration
>>> >>> + *
>>> >>> + * Return: '0' on success and failure value on error
>>> >>> + */
>>> >>> +static int xilinx_vdma_device_control(struct dma_chan *dchan,
>>> >>> + enum dma_ctrl_cmd cmd, unsigned long arg)
>>> >>> +{
>>> >>> + struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
>>> >>> +
>>> >>> + switch (cmd) {
>>> >>> + case DMA_TERMINATE_ALL:
>>> >>> + xilinx_vdma_terminate_all(chan);
>>> >>> + return 0;
>>> >>> + case DMA_SLAVE_CONFIG:
>>> >>> + return xilinx_vdma_slave_config(chan,
>>> >>> + (struct xilinx_vdma_config *)arg);
>>> >>
>>> >> You really shouldn't be overloading the generic API with your own semantics.
>>> >> DMA_SLAVE_CONFIG should take a dma_slave_config and nothing else.
>>> >
>>> > Ok. The driver needs few additional configuration from the slave
>>> > device like Vertical
>>> > Size, Horizontal Size, Stride etc., for the DMA transfers, in that case do you
>>> > suggest me to define a separate dma_ctrl_cmd like the one FSLDMA_EXTERNAL_START
>>> > defined for Freescale drivers?
>>>
>>> In my opinion it is not a good idea to have driver implement a generic API,
>>> but at the same time let the driver have custom semantics for those API
>>> calls. It's a bit like having a gpio driver that expects 23 and 42 as the
>>> values passed to gpio_set_value instead of 0 and 1. It completely defeats
>>> the purpose of a generic API, namely that you are able to write generic code
>>> that makes use of the API without having to know about which implementation
>>> API it is talking to. The dmaengine framework provides the
>>> dmaengine_prep_interleaved_dma() function to setup two dimensional
>>> transfers, e.g. take a look at sirf-dma.c or imx-dma.c.
>>
>> The question here i think would be waht this device supports? Is the hardware
>> capable of doing interleaved transfers, then would make sense.
>>
>> While we do try to get users use dma_slave_config, but there will always be
>> someone who have specfic params. If we can generalize then we might want to add
>> to the dma_slave_config as well
>
> There are many configuration parameters which are specific to IP and I
> would like to
> give an overview of some of parameteres here:
>
> 1) Park Mode ('cfg->park'): In Park mode, engine will park on frame
> referenced by
> 'cfg->park_frm', so user will have control on each frame in this mode.
>
> 2) Interrupt Coalesce ('cfg->coalesce'): Used for setting interrupt
> threshold. This value
> determines the number of frame buffers to process. To use this feature,
> 'cfg->frm_cnt_en' should be set.
>
> 3) Frame Synchronization Source ('cfg->ext_fsync'): Can be an
> external/internal frame
> synchronization source. Used to synchronize one channel (MM2S/S2MM) with
> another (S2MM/MM2S) channel.
>
> 4) Genlock Synchronization ('cfg->genlock'): Used to avoid mismatch rate between
> master and slave. In master mode (cfg->master), frames are not dropped and
> slave can drop frames to adjust to master frame rate.
>
> And in future, this Engine being a soft IP, we could expect some more additional
> parameters. Isn't a good idea to have a private member in dma_slave_config for
> sharing additional configuration between slave device and dma engine? Or a new
> dma_ctrl_cmd like FSLDMA_EXTERNAL_START?
Ping?
>
> Srikanth
>
>>
>> --
>> ~Vinod
>> --/EX
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* [PATCH v2] dma: Add Xilinx AXI Video Direct Memory Access Engine driver support
From: Srikanth Thokala @ 2014-01-31 6:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140128031324.GH10628@intel.com>
Hi Vinod,
On Tue, Jan 28, 2014 at 8:43 AM, Vinod Koul <vinod.koul@intel.com> wrote:
> On Mon, Jan 27, 2014 at 06:42:36PM +0530, Srikanth Thokala wrote:
>> Hi Lars/Vinod,
>> >> The question here i think would be waht this device supports? Is the hardware
>> >> capable of doing interleaved transfers, then would make sense.
>> >
>> > The hardware does 2D transfers. The parameters for a transfer are height,
>> > width and stride. That's only a subset of what interleaved transfers can be
>> > (xt->num_frames must be one for 2d transfers). But if I remember correctly
>> > there has been some discussion on this in the past and the result of that
>> > discussion was that using interleaved transfers for 2D transfers is
>> > preferred over adding a custom API for 2D transfers.
>>
>> I went through the prep_interleaved_dma API and I see only one descriptor
>> is prepared per API call (i.e. per frame). As our IP supports upto 16 frame
>> buffers (can be more in future), isn't it less efficient compared to the
>> prep_slave_sg where we get a single sg list and can prepare all the descriptors
>> (of non-contiguous buffers) in one go? Correct me, if am wrong and let me
>> know your opinions.
> Well the descriptor maybe one, but that can represent multiple frames, for
> example 16 as in your case. Can you read up the documentation of how multiple
> frames are passed. Pls see include/linux/dmaengine.h
>
> /**
> * Interleaved Transfer Request
> * ----------------------------
> * A chunk is collection of contiguous bytes to be transfered.
> * The gap(in bytes) between two chunks is called inter-chunk-gap(ICG).
> * ICGs may or maynot change between chunks.
> * A FRAME is the smallest series of contiguous {chunk,icg} pairs,
> * that when repeated an integral number of times, specifies the transfer.
> * A transfer template is specification of a Frame, the number of times
> * it is to be repeated and other per-transfer attributes.
> *
> * Practically, a client driver would have ready a template for each
> * type of transfer it is going to need during its lifetime and
> * set only 'src_start' and 'dst_start' before submitting the requests.
> *
> *
> * | Frame-1 | Frame-2 | ~ | Frame-'numf' |
> * |====....==.===...=...|====....==.===...=...| ~ |====....==.===...=...|
> *
> * == Chunk size
> * ... ICG
> */
Yes, it can handle multiple frames specified by 'numf' each of size
'frame_size * sgl[0].size'.
But, I see it only works if all the frames' memory is contiguous and
in this case we
can just increment 'src_start' by the total frame size 'numf' number
of times to fill in
for each HW descriptor (each frame is one HW descriptor). So, there
is no issue when the
memory is contiguous. If the frames are non contiguous, we have to
call this API for each
frame (hence for each descriptor), as the src_start for each frame is
different. Is it correct?
FYI: This hardware has an inbuilt Scatter-Gather engine.
Srikanth
>
> --
> ~Vinod
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* [PATCH v5 4/4] [media] exynos-scaler: Add DT bindings for SCALER driver
From: Shaik Ameer Basha @ 2014-01-31 6:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52E29051.3070906@samsung.com>
Hi Tomasz,
Thanks for the review.
Will consider all your comments in the next version of patch series.
Regards,
Shaik Ameer Basha
On Sat, Jan 25, 2014 at 1:09 AM, Tomasz Figa <t.figa@samsung.com> wrote:
> Hi Shaik,
>
>
> On 09.01.2014 04:28, Shaik Ameer Basha wrote:
>>
>> This patch adds the DT binding documentation for the
>> Exynos5420/5410 based SCALER device driver.
>>
>> Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
>> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
>> ---
>> .../devicetree/bindings/media/exynos5-scaler.txt | 22
>> ++++++++++++++++++++
>> 1 file changed, 22 insertions(+)
>> create mode 100644
>> Documentation/devicetree/bindings/media/exynos5-scaler.txt
>>
>> diff --git a/Documentation/devicetree/bindings/media/exynos5-scaler.txt
>> b/Documentation/devicetree/bindings/media/exynos5-scaler.txt
>> new file mode 100644
>> index 0000000..9328e7d
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/exynos5-scaler.txt
>> @@ -0,0 +1,22 @@
>> +* Samsung Exynos5 SCALER device
>> +
>> +SCALER is used for scaling, blending, color fill and color space
>> +conversion on EXYNOS[5420/5410] SoCs.
>> +
>> +Required properties:
>> +- compatible: should be "samsung,exynos5420-scaler" or
>> + "samsung,exynos5410-scaler"
>> +- reg: should contain SCALER physical address location and length
>> +- interrupts: should contain SCALER interrupt number
>
>
> s/number/specifier/
>
>
>> +- clocks: should contain the SCALER clock specifier, from the
>> + common clock bindings
>
>
> s/specifier/phandle and specifier pair for each clock listed in clock-names
> property/
>
> s/from/according to/
>
>
>> +- clock-names: should be "scaler"
>
>
> should contain exactly one entry:
> - "scaler" - IP bus clock.
>
> Also this patch should be first in the series to let the driver added in
> further patches use already present bindings.
>
> Best regards,
> Tomasz
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc"
> in
>
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2] ARM: iop32x: fix power off handling for the EM7210 board
From: Kevin Hilman @ 2014-01-31 6:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391005215-8520-1-git-send-email-linus.walleij@linaro.org>
Linus Walleij <linus.walleij@linaro.org> writes:
> This board was missed when converting all the others to proper
> abstracted GPIO handling. Fix it up the right way by requesting
> and driving GPIO line 0 high through gpiolib to power off the
> machine.
>
> Cc: Arnaud Patard <arnaud.patard@rtp-net.org>
> Reported-by: Arnd Bergmann <arnd@arndb.de>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Queueing for fixes (w/ack from Arnd.)
Kevin
^ permalink raw reply
* [PATCH] ARM: integrator: restore static map on the CP
From: Kevin Hilman @ 2014-01-31 6:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390568668-32270-1-git-send-email-linus.walleij@linaro.org>
Linus Walleij <linus.walleij@linaro.org> writes:
> Commit 78d1632183454dba46ca8295484a5e7603acdc18 deleted the
> static mappings of the core modules, but this static map is
> still needed on the Integrator/CP (not the Integrator/AP).
>
> Restore the static map on the Integrator/CP.
>
> Reported-by: Will Deacon <will.deacon@arm.com>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> ARM SoC folks: please apply this fix directly to ARM SoC
> if you're OK with it.
Queuing for fixes.
Kevin
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox