* [PATCH V4] ASoC: fsl_ssi: refine ipg clock usage in this module
From: Shengjiu Wang @ 2014-09-16 2:13 UTC (permalink / raw)
To: timur, nicoleotsuka, Li.Xiubo, lgirdwood, broonie, perex, tiwai,
mpa
Cc: alsa-devel, linuxppc-dev, linux-kernel
Check if ipg clock is in clock-names property, then we can move the
ipg clock enable and disable operation to startup and shutdown, that
is only enable ipg clock when ssi is working and keep clock is disabled
when ssi is in idle.
But when the checking is failed, remain the clock control as before.
Tested-by: Markus Pargmann <mpa@pengutronix.de>
Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
---
v4 change log:
fix the code indent issue.
sound/soc/fsl/fsl_ssi.c | 53 ++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 45 insertions(+), 8 deletions(-)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 2fc3e66..16a1361 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -169,6 +169,7 @@ struct fsl_ssi_private {
u8 i2s_mode;
bool use_dma;
bool use_dual_fifo;
+ bool has_ipg_clk_name;
unsigned int fifo_depth;
struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
@@ -530,6 +531,11 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct fsl_ssi_private *ssi_private =
snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ int ret;
+
+ ret = clk_prepare_enable(ssi_private->clk);
+ if (ret)
+ return ret;
/* When using dual fifo mode, it is safer to ensure an even period
* size. If appearing to an odd number while DMA always starts its
@@ -544,6 +550,21 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
}
/**
+ * fsl_ssi_shutdown: shutdown the SSI
+ *
+ */
+static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct fsl_ssi_private *ssi_private =
+ snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+ clk_disable_unprepare(ssi_private->clk);
+
+}
+
+/**
* fsl_ssi_set_bclk - configure Digital Audio Interface bit clock
*
* Note: This function can be only called when using SSI as DAI master
@@ -1043,6 +1064,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
.startup = fsl_ssi_startup,
+ .shutdown = fsl_ssi_shutdown,
.hw_params = fsl_ssi_hw_params,
.hw_free = fsl_ssi_hw_free,
.set_fmt = fsl_ssi_set_dai_fmt,
@@ -1168,17 +1190,22 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
u32 dmas[4];
int ret;
- ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
+ if (ssi_private->has_ipg_clk_name)
+ ssi_private->clk = devm_clk_get(&pdev->dev, "ipg");
+ else
+ ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ssi_private->clk)) {
ret = PTR_ERR(ssi_private->clk);
dev_err(&pdev->dev, "could not get clock: %d\n", ret);
return ret;
}
- ret = clk_prepare_enable(ssi_private->clk);
- if (ret) {
- dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
- return ret;
+ if (!ssi_private->has_ipg_clk_name) {
+ ret = clk_prepare_enable(ssi_private->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+ return ret;
+ }
}
/* For those SLAVE implementations, we ingore non-baudclk cases
@@ -1236,8 +1263,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
return 0;
error_pcm:
- clk_disable_unprepare(ssi_private->clk);
+ if (!ssi_private->has_ipg_clk_name)
+ clk_disable_unprepare(ssi_private->clk);
return ret;
}
@@ -1246,7 +1274,8 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev,
{
if (!ssi_private->use_dma)
imx_pcm_fiq_exit(pdev);
- clk_disable_unprepare(ssi_private->clk);
+ if (!ssi_private->has_ipg_clk_name)
+ clk_disable_unprepare(ssi_private->clk);
}
static int fsl_ssi_probe(struct platform_device *pdev)
@@ -1321,8 +1350,16 @@ static int fsl_ssi_probe(struct platform_device *pdev)
return -ENOMEM;
}
- ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
+ ret = of_property_match_string(np, "clock-names", "ipg");
+ if (ret < 0) {
+ ssi_private->has_ipg_clk_name = false;
+ ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
&fsl_ssi_regconfig);
+ } else {
+ ssi_private->has_ipg_clk_name = true;
+ ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev,
+ "ipg", iomem, &fsl_ssi_regconfig);
+ }
if (IS_ERR(ssi_private->regs)) {
dev_err(&pdev->dev, "Failed to init register map\n");
return PTR_ERR(ssi_private->regs);
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH v1 21/21] PCI/MSI: Clean up unused MSI arch functions
From: Yijing Wang @ 2014-09-16 2:09 UTC (permalink / raw)
To: Lucas Stach
Cc: linux-mips, linux-ia64, linux-pci, Bharat.Bhushan, sparclinux,
linux-arch, linux-s390, Russell King, Joerg Roedel, x86,
Sebastian Ott, xen-devel, arnab.basu, Arnd Bergmann,
Konrad Rzeszutek Wilk, Chris Metcalf, Bjorn Helgaas,
Thomas Gleixner, linux-arm-kernel, Xinwei Hu, Tony Luck,
Ralf Baechle, iommu, Wuyun, linuxppc-dev, David S. Miller
In-Reply-To: <1410792430.3314.10.camel@pengutronix.de>
On 2014/9/15 22:47, Lucas Stach wrote:
> Am Freitag, den 05.09.2014, 18:10 +0800 schrieb Yijing Wang:
>> Now we use struct msi_chip in all platforms to configure
>> MSI/MSI-X. We can clean up the unused arch functions.
>>
>> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
>
> Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
Thanks!
>
>> ---
>> drivers/iommu/irq_remapping.c | 2 +-
>> drivers/pci/msi.c | 99 ++++++++++++++++-------------------------
>> include/linux/msi.h | 14 ------
>> 3 files changed, 39 insertions(+), 76 deletions(-)
>>
>> diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
>> index 99b1c0f..6e645f0 100644
>> --- a/drivers/iommu/irq_remapping.c
>> +++ b/drivers/iommu/irq_remapping.c
>> @@ -92,7 +92,7 @@ error:
>>
>> /*
>> * Restore altered MSI descriptor fields and prevent just destroyed
>> - * IRQs from tearing down again in default_teardown_msi_irqs()
>> + * IRQs from tearing down again in teardown_msi_irqs()
>> */
>> msidesc->irq = 0;
>> msidesc->nvec_used = 0;
>> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
>> index d78d637..e3e7f4f 100644
>> --- a/drivers/pci/msi.c
>> +++ b/drivers/pci/msi.c
>> @@ -34,50 +34,31 @@ struct msi_chip * __weak arch_find_msi_chip(struct pci_dev *dev)
>> return dev->bus->msi;
>> }
>>
>> -int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
>> -{
>> - struct msi_chip *chip = arch_find_msi_chip(dev);
>> - int err;
>> -
>> - if (!chip || !chip->setup_irq)
>> - return -EINVAL;
>> -
>> - err = chip->setup_irq(dev, desc);
>> - if (err < 0)
>> - return err;
>> -
>> - return 0;
>> -}
>> -
>> -void __weak arch_teardown_msi_irq(unsigned int irq)
>> -{
>> - struct msi_chip *chip = irq_get_chip_data(irq);
>> -
>> - if (!chip || !chip->teardown_irq)
>> - return;
>> -
>> - chip->teardown_irq(irq);
>> -}
>> -
>> -int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
>> +int setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
>> {
>> struct msi_desc *entry;
>> int ret;
>> struct msi_chip *chip;
>>
>> chip = arch_find_msi_chip(dev);
>> - if (chip && chip->setup_irqs)
>> + if (!chip)
>> + return -EINVAL;
>> +
>> + if (chip->setup_irqs)
>> return chip->setup_irqs(dev, nvec, type);
>>
>> /*
>> * If an architecture wants to support multiple MSI, it needs to
>> - * override arch_setup_msi_irqs()
>> + * implement chip->setup_irqs().
>> */
>> if (type == PCI_CAP_ID_MSI && nvec > 1)
>> return 1;
>>
>> + if (!chip->setup_irq)
>> + return -EINVAL;
>> +
>> list_for_each_entry(entry, &dev->msi_list, list) {
>> - ret = arch_setup_msi_irq(dev, entry);
>> + ret = chip->setup_irq(dev, entry);
>> if (ret < 0)
>> return ret;
>> if (ret > 0)
>> @@ -87,13 +68,20 @@ int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
>> return 0;
>> }
>>
>> -/*
>> - * We have a default implementation available as a separate non-weak
>> - * function, as it is used by the Xen x86 PCI code
>> - */
>> -void default_teardown_msi_irqs(struct pci_dev *dev)
>> +static void teardown_msi_irqs(struct pci_dev *dev)
>> {
>> struct msi_desc *entry;
>> + struct msi_chip *chip;
>> +
>> + chip = arch_find_msi_chip(dev);
>> + if (!chip)
>> + return;
>> +
>> + if (chip->teardown_irqs)
>> + return chip->teardown_irqs(dev);
>> +
>> + if (!chip->teardown_irq)
>> + return;
>>
>> list_for_each_entry(entry, &dev->msi_list, list) {
>> int i, nvec;
>> @@ -104,20 +92,10 @@ void default_teardown_msi_irqs(struct pci_dev *dev)
>> else
>> nvec = 1 << entry->msi_attrib.multiple;
>> for (i = 0; i < nvec; i++)
>> - arch_teardown_msi_irq(entry->irq + i);
>> + chip->teardown_irq(entry->irq + i);
>> }
>> }
>>
>> -void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
>> -{
>> - struct msi_chip *chip = arch_find_msi_chip(dev);
>> -
>> - if (chip && chip->teardown_irqs)
>> - return chip->teardown_irqs(dev);
>> -
>> - return default_teardown_msi_irqs(dev);
>> -}
>> -
>> static void default_restore_msi_irq(struct pci_dev *dev, int irq)
>> {
>> struct msi_desc *entry;
>> @@ -136,10 +114,18 @@ static void default_restore_msi_irq(struct pci_dev *dev, int irq)
>> write_msi_msg(irq, &entry->msg);
>> }
>>
>> -void __weak arch_restore_msi_irqs(struct pci_dev *dev)
>> +static void default_restore_msi_irqs(struct pci_dev *dev)
>> {
>> - struct msi_chip *chip = arch_find_msi_chip(dev);
>> + struct msi_desc *entry = NULL;
>> +
>> + list_for_each_entry(entry, &dev->msi_list, list) {
>> + default_restore_msi_irq(dev, entry->irq);
>> + }
>> +}
>>
>> +static void restore_msi_irqs(struct pci_dev *dev)
>> +{
>> + struct msi_chip *chip = arch_find_msi_chip(dev);
>> if (chip && chip->restore_irqs)
>> return chip->restore_irqs(dev);
>>
>> @@ -248,15 +234,6 @@ void unmask_msi_irq(struct irq_data *data)
>> msi_set_mask_bit(data, 0);
>> }
>>
>> -void default_restore_msi_irqs(struct pci_dev *dev)
>> -{
>> - struct msi_desc *entry;
>> -
>> - list_for_each_entry(entry, &dev->msi_list, list) {
>> - default_restore_msi_irq(dev, entry->irq);
>> - }
>> -}
>> -
>> void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
>> {
>> BUG_ON(entry->dev->current_state != PCI_D0);
>> @@ -360,7 +337,7 @@ static void free_msi_irqs(struct pci_dev *dev)
>> BUG_ON(irq_has_action(entry->irq + i));
>> }
>>
>> - arch_teardown_msi_irqs(dev);
>> + teardown_msi_irqs(dev);
>>
>> list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
>> if (entry->msi_attrib.is_msix) {
>> @@ -430,7 +407,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
>>
>> pci_intx_for_msi(dev, 0);
>> msi_set_enable(dev, 0);
>> - arch_restore_msi_irqs(dev);
>> + restore_msi_irqs(dev);
>>
>> pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
>> msi_mask_irq(entry, msi_mask(entry->msi_attrib.multi_cap),
>> @@ -453,7 +430,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
>> msix_clear_and_set_ctrl(dev, 0,
>> PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
>>
>> - arch_restore_msi_irqs(dev);
>> + restore_msi_irqs(dev);
>> list_for_each_entry(entry, &dev->msi_list, list) {
>> msix_mask_irq(entry, entry->masked);
>> }
>> @@ -624,7 +601,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
>> list_add_tail(&entry->list, &dev->msi_list);
>>
>> /* Configure MSI capability structure */
>> - ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
>> + ret = setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
>> if (ret) {
>> msi_mask_irq(entry, mask, ~mask);
>> free_msi_irqs(dev);
>> @@ -740,7 +717,7 @@ static int msix_capability_init(struct pci_dev *dev,
>> if (ret)
>> return ret;
>>
>> - ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
>> + ret = setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
>> if (ret)
>> goto out_avail;
>>
>> diff --git a/include/linux/msi.h b/include/linux/msi.h
>> index 92a51e7..d6e1f7c 100644
>> --- a/include/linux/msi.h
>> +++ b/include/linux/msi.h
>> @@ -51,20 +51,6 @@ struct msi_desc {
>> struct kobject kobj;
>> };
>>
>> -/*
>> - * The arch hooks to setup up msi irqs. Those functions are
>> - * implemented as weak symbols so that they /can/ be overriden by
>> - * architecture specific code if needed.
>> - */
>> -int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
>> -void arch_teardown_msi_irq(unsigned int irq);
>> -int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
>> -void arch_teardown_msi_irqs(struct pci_dev *dev);
>> -void arch_restore_msi_irqs(struct pci_dev *dev);
>> -
>> -void default_teardown_msi_irqs(struct pci_dev *dev);
>> -void default_restore_msi_irqs(struct pci_dev *dev);
>> -
>> struct msi_chip {
>> struct module *owner;
>> struct device *dev;
>
--
Thanks!
Yijing
^ permalink raw reply
* Re: [PATCH v1 06/21] PCI/MSI: Refactor struct msi_chip to make it become more common
From: Yijing Wang @ 2014-09-16 2:09 UTC (permalink / raw)
To: Lucas Stach
Cc: linux-mips, linux-ia64, linux-pci, Bharat.Bhushan, sparclinux,
linux-arch, linux-s390, Russell King, Joerg Roedel, x86,
Sebastian Ott, xen-devel, arnab.basu, Arnd Bergmann,
Konrad Rzeszutek Wilk, Chris Metcalf, Bjorn Helgaas,
Thomas Gleixner, linux-arm-kernel, Xinwei Hu, Tony Luck,
Ralf Baechle, iommu, Wuyun, linuxppc-dev, David S. Miller
In-Reply-To: <1410792261.3314.9.camel@pengutronix.de>
On 2014/9/15 22:44, Lucas Stach wrote:
> Am Freitag, den 05.09.2014, 18:09 +0800 schrieb Yijing Wang:
>> Now there are a lot of __weak arch functions in MSI code.
>> These functions make MSI driver complex. Thierry Reding Introduced
>> a new MSI chip framework to configure MSI/MSI-X irq in ARM. Use
>> the new MSI chip framework to refactor all other platform MSI
>> arch code to eliminate weak arch MSI functions. This patch add
>> .restore_irq() and .setup_irqs() to make it become more common.
>>
>> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
>
> This change looks good to me:
> Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
Thanks!
>
>> ---
>> drivers/pci/msi.c | 15 +++++++++++++++
>> include/linux/msi.h | 3 +++
>> 2 files changed, 18 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
>> index 539c11d..d78d637 100644
>> --- a/drivers/pci/msi.c
>> +++ b/drivers/pci/msi.c
>> @@ -63,6 +63,11 @@ int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
>> {
>> struct msi_desc *entry;
>> int ret;
>> + struct msi_chip *chip;
>> +
>> + chip = arch_find_msi_chip(dev);
>> + if (chip && chip->setup_irqs)
>> + return chip->setup_irqs(dev, nvec, type);
>>
>> /*
>> * If an architecture wants to support multiple MSI, it needs to
>> @@ -105,6 +110,11 @@ void default_teardown_msi_irqs(struct pci_dev *dev)
>>
>> void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
>> {
>> + struct msi_chip *chip = arch_find_msi_chip(dev);
>> +
>> + if (chip && chip->teardown_irqs)
>> + return chip->teardown_irqs(dev);
>> +
>> return default_teardown_msi_irqs(dev);
>> }
>>
>> @@ -128,6 +138,11 @@ static void default_restore_msi_irq(struct pci_dev *dev, int irq)
>>
>> void __weak arch_restore_msi_irqs(struct pci_dev *dev)
>> {
>> + struct msi_chip *chip = arch_find_msi_chip(dev);
>> +
>> + if (chip && chip->restore_irqs)
>> + return chip->restore_irqs(dev);
>> +
>> return default_restore_msi_irqs(dev);
>> }
>>
>> diff --git a/include/linux/msi.h b/include/linux/msi.h
>> index 5650848..92a51e7 100644
>> --- a/include/linux/msi.h
>> +++ b/include/linux/msi.h
>> @@ -72,7 +72,10 @@ struct msi_chip {
>> struct list_head list;
>>
>> int (*setup_irq)(struct pci_dev *dev, struct msi_desc *desc);
>> + int (*setup_irqs)(struct pci_dev *dev, int nvec, int type);
>> void (*teardown_irq)(unsigned int irq);
>> + void (*teardown_irqs)(struct pci_dev *dev);
>> + void (*restore_irqs)(struct pci_dev *dev);
>> };
>>
>> #endif /* LINUX_MSI_H */
>
--
Thanks!
Yijing
^ permalink raw reply
* Re: [PATCH v1 05/21] PCI/MSI: Introduce weak arch_find_msi_chip() to find MSI chip
From: Yijing Wang @ 2014-09-16 2:08 UTC (permalink / raw)
To: Lucas Stach
Cc: linux-mips, linux-ia64, linux-pci, Bharat.Bhushan, sparclinux,
linux-arch, linux-s390, Russell King, Joerg Roedel, x86,
Sebastian Ott, xen-devel, arnab.basu, Arnd Bergmann,
Konrad Rzeszutek Wilk, Chris Metcalf, Bjorn Helgaas,
Thomas Gleixner, linux-arm-kernel, Xinwei Hu, Tony Luck,
Ralf Baechle, iommu, Wuyun, linuxppc-dev, David S. Miller
In-Reply-To: <1410792154.3314.7.camel@pengutronix.de>
On 2014/9/15 22:42, Lucas Stach wrote:
> Am Freitag, den 05.09.2014, 18:09 +0800 schrieb Yijing Wang:
>> Introduce weak arch_find_msi_chip() to find the match msi_chip.
>> Currently, MSI chip associates pci bus to msi_chip. Because in
>> ARM platform, there may be more than one MSI controller in system.
>> Associate pci bus to msi_chip help pci device to find the match
>> msi_chip and setup MSI/MSI-X irq correctly. But in other platform,
>> like in x86. we only need one MSI chip, because all device use
>> the same MSI address/data and irq etc. So it's no need to associate
>> pci bus to MSI chip, just use a arch function, arch_find_msi_chip()
>> to return the MSI chip for simplicity. The default weak
>> arch_find_msi_chip() used in ARM platform, find the MSI chip
>> by pci bus.
>>
> Hm, while one weak function sounds much better than the plethora we have
> now, I wonder how much work it would be to associate the msi_chip with
> the pci bus on other arches the same way as done on ARM. This way we
> could kill this calling into arch specific functions which would make
> things a bit clearer to follow I think.
That's a heavy work to associate msi_chip with the pci_bus in all platforms,
And only in ARM platform, there are two or more different msi_chips which maybe
associate pci hostbridge or irq chip. In other platforms, only one MSI chip
exists at the same time. Another reason is I don't think associate the msi_chip
with pci bus is a good idea to make PCI device find its own msi_chip.
All PCI devices under the same PCI hostbridge should have the same msi_chip,
and now a property "msi-parent" is defined to help pci hostbridge to find its matched
msi_chip. I like to associate the msi_chip with a pci hostbridge. So we don't need to
add a lot of pcibios_add_bus() to do that.
I inspected all MSI chip drivers, and found there are two different relations between msi_chip and PCI hostbridge
1. MSI chip is a irq chip, like irq_armada_370_xp, PCI hostbridge platform device use "msi-parent" to find msi_chip by of_node.
2. MSI chip is integrated into PCI hostbridge, so msi_chip->dev is the PCI hostbridge platform device.
So long as we use PCI hostbridge platform device as the parent of PCI hostbridge, every PCI device under the hostbridge
can find the msi_chip by it.
All MSI chip drivers now except pci-mvebu have been passed the hostbridge platform dev as the parent.
pci_common_init_dev(pcie->dev, &hw);
^
Pseudo code like:
struct msi_chip *pcibios_find_msi_chip(struct pci_dev *dev)
{
struct pci_bus *root;
struct pci_host_bridge *bridge;
struct msi_chip *chip;
struct device_node *node, *msi_node;
/* First we find msi_chip by the phb of_node */ <-------- MSI chip is a irq chip
root = pci_find_root_bus(dev->bus);
node = pcibios_get_phb_of_node(root);
if (node) {
msi_node = of_parse_phandle(n, "msi-parent", 0);
of_node_put(node);
if (msi_node)
return of_pci_find_msi_chip_by_node(msi_node);
}
/* Some msi_chip are integrated into pci hostbridge,
* we find it by phb device pointer.
*/
if (bridge && bridge->dev.parent) { <-----------MSI chip is integrated into PCI hostbridge
down_read(&pci_msi_chip_sem);
list_for_each_entry(chip, &pci_msi_chip_list, list) {
if (chip->dev == bridge->dev.parent) {
up_read(pci_msi_chip_sem);
return chip;
}
}
up_read(&pci_msi_chip_sem);
}
return NULL;
}
Thanks!
Yijing.
>
> Regards,
> Lucas
>
>> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
>> ---
>> drivers/pci/msi.c | 7 ++++++-
>> 1 files changed, 6 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
>> index a77e7f7..539c11d 100644
>> --- a/drivers/pci/msi.c
>> +++ b/drivers/pci/msi.c
>> @@ -29,9 +29,14 @@ static int pci_msi_enable = 1;
>>
>> /* Arch hooks */
>>
>> +struct msi_chip * __weak arch_find_msi_chip(struct pci_dev *dev)
>> +{
>> + return dev->bus->msi;
>> +}
>> +
>> int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
>> {
>> - struct msi_chip *chip = dev->bus->msi;
>> + struct msi_chip *chip = arch_find_msi_chip(dev);
>> int err;
>>
>> if (!chip || !chip->setup_irq)
>
--
Thanks!
Yijing
^ permalink raw reply
* Re: [PATCH v1 03/21] MSI: Remove the redundant irq_set_chip_data()
From: Yijing Wang @ 2014-09-16 1:30 UTC (permalink / raw)
To: Lucas Stach
Cc: linux-mips, linux-ia64, linux-pci, Bharat.Bhushan, sparclinux,
linux-arch, linux-s390, Russell King, Joerg Roedel, x86,
Sebastian Ott, xen-devel, arnab.basu, Arnd Bergmann,
Konrad Rzeszutek Wilk, Chris Metcalf, Bjorn Helgaas,
Thomas Gleixner, linux-arm-kernel, Xinwei Hu, Tony Luck,
Ralf Baechle, iommu, Wuyun, linuxppc-dev, David S. Miller
In-Reply-To: <1410789648.3314.5.camel@pengutronix.de>
On 2014/9/15 22:00, Lucas Stach wrote:
> Am Freitag, den 05.09.2014, 18:09 +0800 schrieb Yijing Wang:
>> Currently, pcie-designware, pcie-rcar, pci-tegra drivers
>> use irq chip_data to save the msi_chip pointer. They
>> already call irq_set_chip_data() in their own MSI irq map
>> functions. So irq_set_chip_data() in arch_setup_msi_irq()
>> is useless.
>>
>> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
>> ---
>> drivers/pci/msi.c | 2 --
>> 1 files changed, 0 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
>> index f6cb317..d547f7f 100644
>> --- a/drivers/pci/msi.c
>> +++ b/drivers/pci/msi.c
>> @@ -41,8 +41,6 @@ int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
>> if (err < 0)
>> return err;
>>
>> - irq_set_chip_data(desc->irq, chip);
>> -
>> return 0;
>> }
>>
>
> arch_teardown_msi_irq() expects to find the msi_chip in the irq
> chip_data field. As this means drivers don't have any reasonable other
> possibility to stuff things into this field, I think it would make sense
> to do the cleanup the other way around: keep the irq_set_chip_data
> arch_setup_msi_irq() and rip it out of the individual drivers.
Hi Lucas, thanks for your review and comments!
irq_set_chip_data() should not be placed in MSI core functions, because other arch like x86,
use irq_data->chip_data to stores irq_cfg. So how to set the chip_data is arch dependent.
And this series is mainly to use MSI chip framework in all platforms.
Currently, only ARM platform MSI drivers use the chip_data to store msi_chip, and the drivers call
irq_set_chip_data() in their driver already. So I thought we should clean up it in MSI core code.
Thanks!
Yijing.
>
> Regards,
> Lucas
>
--
Thanks!
Yijing
^ permalink raw reply
* [PATCH 2/2] powerpc: Use CONFIG_ARCH_HAS_FAST_MULTIPLIER
From: Anton Blanchard @ 2014-09-16 0:49 UTC (permalink / raw)
To: benh, paulus, michael, torvalds; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20140916104749.35b84da8@kryten>
I ran some tests to compare hash_64 using shifts and multiplies.
The results:
POWER6: ~2x slower
POWER7: ~2x faster
POWER8: ~2x faster
Now we have a proper config option, select
CONFIG_ARCH_HAS_FAST_MULTIPLIER on POWER7 and POWER8.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
Index: b/arch/powerpc/platforms/Kconfig.cputype
===================================================================
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -116,10 +116,12 @@ config POWER6_CPU
config POWER7_CPU
bool "POWER7"
depends on PPC_BOOK3S_64
+ select ARCH_HAS_FAST_MULTIPLIER
config POWER8_CPU
bool "POWER8"
depends on PPC_BOOK3S_64
+ select ARCH_HAS_FAST_MULTIPLIER
config E5500_CPU
bool "Freescale e5500"
^ permalink raw reply
* [PATCH 1/2] powerpc: Add POWER8 CPU selection
From: Anton Blanchard @ 2014-09-16 0:47 UTC (permalink / raw)
To: benh, paulus, michael, torvalds; +Cc: linuxppc-dev, linux-kernel
This allows the user to build a kernel targeted at POWER8
(ie gcc -mcpu=power8).
Signed-off-by: Anton Blanchard <anton@samba.org>
---
Index: b/arch/powerpc/Makefile
===================================================================
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -135,6 +135,7 @@ CFLAGS-$(CONFIG_POWER4_CPU) += $(call cc
CFLAGS-$(CONFIG_POWER5_CPU) += $(call cc-option,-mcpu=power5)
CFLAGS-$(CONFIG_POWER6_CPU) += $(call cc-option,-mcpu=power6)
CFLAGS-$(CONFIG_POWER7_CPU) += $(call cc-option,-mcpu=power7)
+CFLAGS-$(CONFIG_POWER8_CPU) += $(call cc-option,-mcpu=power8)
# Altivec option not allowed with e500mc64 in GCC.
ifeq ($(CONFIG_ALTIVEC),y)
Index: b/arch/powerpc/platforms/Kconfig.cputype
===================================================================
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -117,6 +117,10 @@ config POWER7_CPU
bool "POWER7"
depends on PPC_BOOK3S_64
+config POWER8_CPU
+ bool "POWER8"
+ depends on PPC_BOOK3S_64
+
config E5500_CPU
bool "Freescale e5500"
depends on E500
^ permalink raw reply
* [PATCH 2/2] powerpc/pseries: fix bugs in RTAS mobility code
From: Cyril Bur @ 2014-09-16 0:25 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Cyril Bur
In-Reply-To: <1410827128-6876-1-git-send-email-cyril.bur@au1.ibm.com>
Running this code on a little endian machine has exposed some very unlikely
corner cases. Most of these oversights will lead to a buffer overflow.
Reworked some of the error pathes. It seems more sane to stop trying to parse
a buffer on errors. Attempting to continue opens up the possibility of
overflows and/or garbage reads.
Don't warn about failed allcations when the amount was taken from the buffer,
assume the value was incorrect, don't needlessly concern the user.
Signed-off-by: Cyril Bur <cyril.bur@au1.ibm.com>
---
arch/powerpc/platforms/pseries/mobility.c | 95 +++++++++++++++++++++----------
1 file changed, 64 insertions(+), 31 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
index 09bef23..00bd939 100644
--- a/arch/powerpc/platforms/pseries/mobility.c
+++ b/arch/powerpc/platforms/pseries/mobility.c
@@ -68,62 +68,45 @@ static int delete_dt_node(u32 phandle)
}
static int update_dt_property(struct device_node *dn, struct property **prop,
- const char *name, u32 vd, char *value)
+ const char *name, int length, char *value)
{
struct property *new_prop = *prop;
- int more = 0;
-
- /* A negative 'vd' value indicates that only part of the new property
- * value is contained in the buffer and we need to call
- * ibm,update-properties again to get the rest of the value.
- *
- * A negative value is also the two's compliment of the actual value.
- */
- if (vd & 0x80000000) {
- vd = ~vd + 1;
- more = 1;
- }
if (new_prop) {
/* partial property fixup */
- char *new_data = kzalloc(new_prop->length + vd, GFP_KERNEL);
+ char *new_data = kzalloc(new_prop->length + length, GFP_KERNEL | __GFP_NOWARN);
if (!new_data)
return -ENOMEM;
memcpy(new_data, new_prop->value, new_prop->length);
- memcpy(new_data + new_prop->length, value, vd);
+ memcpy(new_data + new_prop->length, value, length);
kfree(new_prop->value);
new_prop->value = new_data;
- new_prop->length += vd;
+ new_prop->length += length;
} else {
new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
if (!new_prop)
return -ENOMEM;
- new_prop->name = kstrdup(name, GFP_KERNEL);
+ new_prop->name = kstrdup(name, GFP_KERNEL | __GFP_NOWARN);
if (!new_prop->name) {
kfree(new_prop);
return -ENOMEM;
}
- new_prop->length = vd;
- new_prop->value = kzalloc(new_prop->length, GFP_KERNEL);
+ new_prop->length = length;
+ new_prop->value = kzalloc(new_prop->length, GFP_KERNEL | __GFP_NOWARN);
if (!new_prop->value) {
kfree(new_prop->name);
kfree(new_prop);
return -ENOMEM;
}
- memcpy(new_prop->value, value, vd);
+ memcpy(new_prop->value, value, length);
*prop = new_prop;
}
- if (!more) {
- of_update_property(dn, new_prop);
- *prop = NULL;
- }
-
return 0;
}
@@ -196,21 +179,52 @@ static int update_dt_node(u32 phandle, s32 scope)
break;
default:
+ /* A negative 'vd' value indicates that only part of the new property
+ * value is contained in the buffer and we need to call
+ * ibm,update-properties again to get the rest of the value.
+ *
+ * A negative value is also the two's compliment of the actual value.
+ */
+
rc = update_dt_property(dn, &prop, prop_name,
- vd, prop_data);
+ vd & 0x80000000 ? ~vd + 1 : vd, prop_data);
if (rc) {
- printk(KERN_ERR "Could not update %s"
- " property\n", prop_name);
+ printk(KERN_ERR "Could not update %s property\n",
+ prop_name);
+ /* Could try to continue but if the failure was for a section
+ * of a node it gets too easy to mess up the device tree.
+ * Plus, ENOMEM likely means we have bigger problems than a
+ * failed device tree update */
+ if (prop) {
+ kfree(prop->name);
+ kfree(prop->value);
+ kfree(prop);
+ prop = NULL;
+ }
+ i = upwa.nprops - 1; /* Break */
+ }
+
+ if (prop && !(vd & 0x80000000)) {
+ of_update_property(dn, prop);
+ prop = NULL;
}
+ prop_data += vd & 0x80000000 ? ~vd + 1 : vd;
+ }
- prop_data += vd;
+ if (prop_data - (char *)rtas_buf >= RTAS_DATA_BUF_SIZE) {
+ printk(KERN_ERR "Device tree property"
+ " length exceeds rtas buffer\n");
+ rc = -EOVERFLOW;
+ goto update_dt_node_err;
}
}
} while (rtas_rc == 1);
+ rc = rtas_rc;
of_node_put(dn);
+update_dt_node_err:
kfree(rtas_buf);
- return 0;
+ return rc;
}
static int add_dt_node(u32 parent_phandle, u32 drc_index)
@@ -264,9 +278,17 @@ int pseries_devicetree_update(s32 scope)
int node_count = node & NODE_COUNT_MASK;
for (i = 0; i < node_count; i++) {
- u32 phandle = be32_to_cpu(*data++);
+ u32 phandle;
u32 drc_index;
+ if (data + 1 - rtas_buf >= RTAS_DATA_BUF_SIZE) {
+ printk(KERN_ERR "Device tree property"
+ " length exceeds rtas buffer\n");
+ rc = -EOVERFLOW;
+ goto pseries_devicetree_update_err;
+ }
+ phandle = be32_to_cpu(*data++);
+
switch (action) {
case DELETE_DT_NODE:
delete_dt_node(phandle);
@@ -278,12 +300,23 @@ int pseries_devicetree_update(s32 scope)
drc_index = be32_to_cpu(*data++);
add_dt_node(phandle, drc_index);
break;
+ default:
+ /* Bogus action */
+ i = node_count - 1; /* Break */
+ data += node_count;
}
}
+ if (data - rtas_buf >= RTAS_DATA_BUF_SIZE) {
+ printk(KERN_ERR "Number of device tree update "
+ "nodes exceeds rtas buffer length\n");
+ rc = -EOVERFLOW;
+ goto pseries_devicetree_update_err;
+ }
node = be32_to_cpu(*data++);
}
} while (rc == 1);
+pseries_devicetree_update_err:
kfree(rtas_buf);
return rc;
}
--
1.9.1
^ permalink raw reply related
* [PATCH 1/2] powerpc/pseries: fix endian bugs in mobility RTAS calls
From: Cyril Bur @ 2014-09-16 0:25 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Cyril Bur
In-Reply-To: <1410827128-6876-1-git-send-email-cyril.bur@au1.ibm.com>
These calls use a buffer shared memory buffer to comunicate device tree
updates.
PAPR specifies that RTAS buffers are to be written in big endian.
Signed-off-by: Cyril Bur <cyril.bur@au1.ibm.com>
---
arch/powerpc/platforms/pseries/mobility.c | 50 ++++++++++++++++---------------
1 file changed, 26 insertions(+), 24 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
index e7cb6d4..09bef23 100644
--- a/arch/powerpc/platforms/pseries/mobility.c
+++ b/arch/powerpc/platforms/pseries/mobility.c
@@ -40,7 +40,7 @@ struct update_props_workarea {
#define MIGRATION_SCOPE (1)
-static int mobility_rtas_call(int token, char *buf, s32 scope)
+static int mobility_rtas_call(int token, __be32 *buf, s32 scope)
{
int rc;
@@ -129,14 +129,14 @@ static int update_dt_property(struct device_node *dn, struct property **prop,
static int update_dt_node(u32 phandle, s32 scope)
{
- struct update_props_workarea *upwa;
+ struct update_props_workarea upwa;
struct device_node *dn;
struct property *prop = NULL;
int i, rc, rtas_rc;
- char *prop_data;
- char *rtas_buf;
int update_properties_token;
+ char *prop_data;
u32 vd;
+ __be32 *rtas_buf;
update_properties_token = rtas_token("ibm,update-properties");
if (update_properties_token == RTAS_UNKNOWN_SERVICE)
@@ -152,16 +152,17 @@ static int update_dt_node(u32 phandle, s32 scope)
return -ENOENT;
}
- upwa = (struct update_props_workarea *)&rtas_buf[0];
- upwa->phandle = phandle;
-
+ *rtas_buf = cpu_to_be32(phandle);
do {
rtas_rc = mobility_rtas_call(update_properties_token, rtas_buf,
scope);
if (rtas_rc < 0)
break;
-
- prop_data = rtas_buf + sizeof(*upwa);
+ upwa.phandle = be32_to_cpu(*rtas_buf);
+ upwa.state = be32_to_cpu(*(rtas_buf + 1));
+ upwa.reserved = be64_to_cpu(*((__be64 *)(rtas_buf + 2)));
+ upwa.nprops = be32_to_cpu(*(rtas_buf + 4));
+ prop_data = ((char *)rtas_buf) + sizeof(upwa);
/* On the first call to ibm,update-properties for a node the
* the first property value descriptor contains an empty
@@ -169,18 +170,18 @@ static int update_dt_node(u32 phandle, s32 scope)
* and the property value is the node path being updated.
*/
if (*prop_data == 0) {
- prop_data++;
- vd = *(u32 *)prop_data;
+ prop_data += sizeof(u32);
+ vd = be32_to_cpu(*(__be32 *)prop_data);
prop_data += vd + sizeof(vd);
- upwa->nprops--;
+ upwa.nprops--;
}
- for (i = 0; i < upwa->nprops; i++) {
+ for (i = 0; i < upwa.nprops; i++) {
char *prop_name;
prop_name = prop_data;
prop_data += strlen(prop_name) + 1;
- vd = *(u32 *)prop_data;
+ vd = be32_to_cpu(*(__be32 *)prop_data);
prop_data += sizeof(vd);
switch (vd) {
@@ -236,10 +237,11 @@ static int add_dt_node(u32 parent_phandle, u32 drc_index)
int pseries_devicetree_update(s32 scope)
{
- char *rtas_buf;
- u32 *data;
+ __be32 *rtas_buf;
int update_nodes_token;
int rc;
+ __be32 *data;
+ u32 node;
update_nodes_token = rtas_token("ibm,update-nodes");
if (update_nodes_token == RTAS_UNKNOWN_SERVICE)
@@ -253,17 +255,16 @@ int pseries_devicetree_update(s32 scope)
rc = mobility_rtas_call(update_nodes_token, rtas_buf, scope);
if (rc && rc != 1)
break;
+ data = rtas_buf + 4;
+ node = be32_to_cpu(*data++);
- data = (u32 *)rtas_buf + 4;
- while (*data & NODE_ACTION_MASK) {
+ while (node & NODE_ACTION_MASK) {
int i;
- u32 action = *data & NODE_ACTION_MASK;
- int node_count = *data & NODE_COUNT_MASK;
-
- data++;
+ u32 action = node & NODE_ACTION_MASK;
+ int node_count = node & NODE_COUNT_MASK;
for (i = 0; i < node_count; i++) {
- u32 phandle = *data++;
+ u32 phandle = be32_to_cpu(*data++);
u32 drc_index;
switch (action) {
@@ -274,11 +275,12 @@ int pseries_devicetree_update(s32 scope)
update_dt_node(phandle, scope);
break;
case ADD_DT_NODE:
- drc_index = *data++;
+ drc_index = be32_to_cpu(*data++);
add_dt_node(phandle, drc_index);
break;
}
}
+ node = be32_to_cpu(*data++);
}
} while (rc == 1);
--
1.9.1
^ permalink raw reply related
* [PATCH 0/2] powerpc/pseries: RTAS mobility fixes
From: Cyril Bur @ 2014-09-16 0:25 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Cyril Bur
This patchset addresses endian issues and bugs in device tree update for
ibm,update-nodes and ibm,update-properties RTAS calls.
A subseqent patchset will deal with issues in device tree node addition
(ibm,configure-connector RTAS call) as well as more robust handling of
deleting critical device tree nodes.
Cyril Bur (2):
powerpc/pseries: fix endian bugs in mobility RTAS calls
powerpc/pseries: fix bugs in RTAS mobility code
arch/powerpc/platforms/pseries/mobility.c | 143 +++++++++++++++++++-----------
1 file changed, 89 insertions(+), 54 deletions(-)
--
1.9.1
^ permalink raw reply
* Re: [RFC PATCH] powerpc/numa: add ability to disable and debug topology updates
From: Nishanth Aravamudan @ 2014-09-15 23:54 UTC (permalink / raw)
To: Michael Ellerman; +Cc: Paul Mackerras, linuxppc-dev
In-Reply-To: <1410757536.32643.1.camel@concordia>
Hi Michael,
On 15.09.2014 [15:05:36 +1000], Michael Ellerman wrote:
> On Tue, 2014-09-09 at 13:09 -0700, Nishanth Aravamudan wrote:
> > We have hit a few customer issues with the topology update code (VPHN
> > and PRRN). It would be nice to be able to debug the notifications coming
> > from the hypervisor in both cases to the LPAR, as well as to disable
> > reacting to the notifications, to narrow down the source of the
> > problems. Add a basic level of such functionality, similar to the numa=
> > command-line parameter.
> >
> > Signed-off-by: Nishanth Aravamudan <nacc@linux.vnet.ibm.com>
> > ---
> > This is pretty rough, but has been useful in the field already. I'm not
> > sure if more information would be useful than this basic amount.
> >
> > diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
> > index 5ae8608ca9f5..6e3b9e3a2ab4 100644
> > --- a/Documentation/kernel-parameters.txt
> > +++ b/Documentation/kernel-parameters.txt
> > @@ -3370,6 +3370,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
> > e.g. base its process migration decisions on it.
> > Default is on.
> >
> > + topology_updates= [KNL, PPC, NUMA]
> > + Format: {off | debug}
> > + Specify if the kernel should ignore (off) or
> > + emit more information (debug) when the
> > + hypervisor sends NUMA topology updates to an
> > + LPAR.
>
> Boot-time parameters are kind of a pain, not least because they
> require a reboot to activate.
Thanks for the review, this is a good point. In the case we're
hitting, we're actually crashing at boot because of possibly dodgy
firmware data.
> Does it really need to be a boot param, or could it be a debugfs or
> sysctl flag? ie. do we need to disable it immediately at boot or would
> it be OK if it was /etc/rc.local or similar that turned it off ?
We need it off at boot, potentially. An LPAR does not indicate that it
will or will not respond to the events in any synchronous fashion, so
the hypervisor is free to send them to us whenever.
> It looks like arch_update_cpu_topology() is called quite early, from
> init_sched_domains(), but in that case I don't see how
> cpu_associativity_changes_mask can be non-zero, ie. we'll never do any
> work via that path.
Correct, that path is probably fine. But we can get these hypervisor
events fairly early in boot.
> As far as the debug goes, we could just use pr_debug() with
> CONFIG_DYNAMIC_DEBUG, it's not quite as easy to enable as a kernel
> parameter but for the odd bit of debugging it should be fine.
That's a good point, I wonder with that mechanism if we should perhaps
extend/remove other static debugging methods in favor of that (e.g.,
numa=debug)?
> I guess the downside there is you have to do some work before you know
> if you're printing anything out. More below ...
>
> > diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
> > index d7737a542fd7..72c5ad313cbe 100644
> > --- a/arch/powerpc/mm/numa.c
> > +++ b/arch/powerpc/mm/numa.c
> > @@ -1160,6 +1160,28 @@ static int __init early_numa(char *p)
> > }
> > early_param("numa", early_numa);
> >
> > +static int topology_updates_enabled = 1;
> > +static int topology_updates_debug = 0;
> > +
> > +static int __init early_topology_updates(char *p)
> > +{
> > + if (!p)
> > + return 0;
> > +
> > + if (strstr(p, "off")) {
> > + printk(KERN_INFO "Disabling topology updates\n");
> > + topology_updates_enabled = 0;
> > + }
>
> Can you add a:
> #define pr_fmt(fmt) "numa: " fmt
>
> At the top of the file and then use pr_xxx() for these?
Yes.
> > + if (strstr(p, "debug")) {
> > + printk(KERN_INFO "Enabling topology updates debug\n");
> > + topology_updates_debug = 1;
> > + }
> > +
> > + return 0;
> > +}
> > +early_param("topology_updates", early_topology_updates);
> > +
> > #ifdef CONFIG_MEMORY_HOTPLUG
> > /*
> > * Find the node associated with a hot added memory section for
> > @@ -1546,6 +1568,9 @@ int arch_update_cpu_topology(void)
> > struct device *dev;
> > int weight, new_nid, i = 0;
> >
> > + if (!topology_updates_enabled)
> > + return 0;
> > +
> > weight = cpumask_weight(&cpu_associativity_changes_mask);
> > if (!weight)
> > return 0;
> > @@ -1610,6 +1635,25 @@ int arch_update_cpu_topology(void)
> > *
> > * And for the similar reason, we will skip all the following updating.
> > */
>
> The comment should stay attached to the check below of updated_cpus, ie. this
> block should preceed the comment.
Yep.
> > + if (topology_updates_debug) {
> > + char *buf = kmalloc_array(NR_CPUS*5, sizeof(char), GFP_KERNEL);
> > + cpumask_scnprintf(buf, NR_CPUS*5, &updated_cpus);
> > + printk(KERN_DEBUG "Topology update for the following CPUs:\n");
> > + printk(KERN_DEBUG " %s\n", buf);
> > + printk(KERN_DEBUG "cpumask_weight(&updated_cpus)) = %u\n",
> > + cpumask_weight(&updated_cpus));
>
> Do we really need to print the cpumask? The same information is
> available below right, just in a more verbose form?
Yes, sorry, this is a "living" patch, and I haven't fully cleaned it up.
Will remove the cpumask bodge in v2.
> Assuming we can skip that we can just use pr_debug() for these I think
> and drop the debug flag. Or is this a super hot-path that I'm not
> aware of?
Not super hot, but when it breaks, your LPAR is unusable.
> > + if (cpumask_weight(&updated_cpus)) {
> > + for (ud = &updates[0]; ud; ud = ud->next) {
> > + printk(KERN_DEBUG "cpu %d moving from node %d "
> > + "to %d\n", ud->cpu,
> > + ud->old_nid, ud->new_nid);
> > + }
> > + }
> > + kfree(buf);
> > + }
> > +
> > if (!cpumask_weight(&updated_cpus))
> > goto out;
> >
> > @@ -1807,8 +1851,10 @@ static const struct file_operations topology_ops = {
> >
> > static int topology_update_init(void)
> > {
> > - start_topology_update();
> > - proc_create("powerpc/topology_updates", 0644, NULL, &topology_ops);
> > + if (topology_updates_enabled) {
> > + start_topology_update();
> > + proc_create("powerpc/topology_updates", 0644, NULL, &topology_ops);
> > + }
>
> It was already broken, but can you fix the (lack of) error handling
> here please?
Yep, will make it the first patch in the series.
-Nish
^ permalink raw reply
* [PATCH 5/5] pseries: Implement memory hotplug remove in the kernel
From: Nathan Fontenot @ 2014-09-15 20:33 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <54174B81.50504@linux.vnet.ibm.com>
This patch adds the ability to do memory hotplug remove in the kernel.
Currently the hotplug add/remove of memory is handled by the drmgr
command. The drmgr command performs the add/remove by performing
some work in user-space and making requests to the kernel to handle
other pieces. By moving all of the work to the kernel we can do the
add and remove faster, and provide a common place to do memory hotplug
for both the PowerVM and PowerKVM environments.
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/platforms/pseries/hotplug-memory.c | 140 +++++++++++++++++++++++
1 file changed, 139 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index b254773..160c424 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -193,7 +193,137 @@ static int pseries_remove_mem_node(struct device_node *np)
pseries_remove_memblock(base, lmb_size);
return 0;
}
+
+static int lmb_is_removable(struct of_drconf_cell *lmb)
+{
+ int i, scns_per_block;
+ int rc = 1;
+ unsigned long pfn, block_sz;
+ u64 phys_addr;
+
+ phys_addr = be64_to_cpu(lmb->base_addr);
+ block_sz = memory_block_size_bytes();
+ scns_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
+
+ for (i = 0; i < scns_per_block; i++) {
+ pfn = PFN_DOWN(phys_addr);
+ if (!pfn_present(pfn))
+ continue;
+
+ rc &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
+ phys_addr += MIN_MEMORY_BLOCK_SIZE;
+ }
+
+ return rc;
+}
+
+static int dlpar_add_one_lmb(struct of_drconf_cell *);
+
+static int dlpar_remove_one_lmb(struct of_drconf_cell *lmb)
+{
+ struct memory_block *mem_block;
+ unsigned long block_sz;
+ u64 phys_addr;
+ int nid, rc;
+
+ block_sz = memory_block_size_bytes();
+ phys_addr = be64_to_cpu(lmb->base_addr);
+ nid = memory_add_physaddr_to_nid(phys_addr);
+
+ if (!pfn_valid(phys_addr >> PAGE_SHIFT)) {
+ memblock_remove(phys_addr, block_sz);
+ return 0;
+ }
+
+ mem_block = lmb_to_memblock(lmb);
+ if (!mem_block)
+ return -EINVAL;
+
+ rc = device_offline(&mem_block->dev);
+ put_device(&mem_block->dev);
+ if (rc)
+ return rc;
+
+ remove_memory(nid, phys_addr, block_sz);
+ memblock_remove(phys_addr, block_sz);
+
+ return 0;
+}
+
+static int dlpar_memory_remove(struct pseries_hp_errorlog *hp_elog)
+{
+ struct of_drconf_cell *lmb;
+ struct device_node *dn;
+ struct property *prop;
+ int lmbs_to_remove, lmbs_removed = 0;
+ int i, entries;
+ int rc = -EINVAL;
+ uint32_t *p;
+
+ if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) {
+ lmbs_to_remove = be32_to_cpu(hp_elog->_drc_u.drc_count);
+ pr_info("Attempting to hot-remove %d LMB(s)\n", lmbs_to_remove);
+ } else {
+ lmbs_to_remove = 1;
+ pr_info("Attempting to hot-remove LMB, drc index %x\n",
+ be32_to_cpu(hp_elog->_drc_u.drc_index));
+ }
+
+ dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+ if (!dn)
+ return -EINVAL;
+
+ prop = dlpar_clone_drconf_property(dn);
+ if (!prop) {
+ of_node_put(dn);
+ return -EINVAL;
+ }
+
+ p = prop->value;
+ entries = be32_to_cpu(*p++);
+ lmb = (struct of_drconf_cell *)p;
+
+ for (i = 0; i < entries; i++, lmb++) {
+ u32 drc_index = be32_to_cpu(lmb->drc_index);
+
+ if (lmbs_to_remove == lmbs_removed)
+ break;
+
+ if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX
+ && lmb->drc_index != hp_elog->_drc_u.drc_index)
+ continue;
+
+ if (!(be32_to_cpu(lmb->flags) & DRCONF_MEM_ASSIGNED)
+ || !lmb_is_removable(lmb))
+ continue;
+
+ rc = dlpar_remove_one_lmb(lmb);
+ if (rc)
+ continue;
+
+ rc = dlpar_release_drc(drc_index);
+ if (rc) {
+ dlpar_add_one_lmb(lmb);
+ continue;
+ }
+
+ lmb->flags &= cpu_to_be32(~DRCONF_MEM_ASSIGNED);
+ lmbs_removed++;
+ pr_info("Memory at %llx (drc index %x) has been hot-removed\n",
+ be64_to_cpu(lmb->base_addr), drc_index);
+ }
+
+ if (lmbs_removed)
+ rc = of_update_property(dn, prop);
+ else
+ dlpar_free_drconf_property(prop);
+
+ of_node_put(dn);
+ return rc ? rc : lmbs_removed;
+}
+
#else
+
static inline int pseries_remove_memblock(unsigned long base,
unsigned int memblock_size)
{
@@ -203,6 +333,11 @@ static inline int pseries_remove_mem_node(struct device_node *np)
{
return 0;
}
+static inline int dlpar_memory_remove(struct pseries_hp_errorlog *hp_elog)
+{
+ return -EOPNOTSUPP;
+}
+
#endif /* CONFIG_MEMORY_HOTREMOVE */
static int dlpar_add_one_lmb(struct of_drconf_cell *lmb)
@@ -320,7 +455,7 @@ static int dlpar_memory_add(struct pseries_hp_errorlog *hp_elog)
int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
{
- int rc = 0;
+ int rc;
if (hp_elog->id_type != PSERIES_HP_ELOG_ID_DRC_COUNT
&& hp_elog->id_type != PSERIES_HP_ELOG_ID_DRC_INDEX)
@@ -332,6 +467,9 @@ int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
case PSERIES_HP_ELOG_ACTION_ADD:
rc = dlpar_memory_add(hp_elog);
break;
+ case PSERIES_HP_ELOG_ACTION_REMOVE:
+ rc = dlpar_memory_remove(hp_elog);
+ break;
default:
pr_err("Invalid action (%d) specified\n", hp_elog->action);
rc = -EINVAL;
^ permalink raw reply related
* [PATCH 4/5] pseries: Implement memory hotplug add in the kernel
From: Nathan Fontenot @ 2014-09-15 20:32 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <54174B81.50504@linux.vnet.ibm.com>
This patch adds the ability to do memory hotplug adding in the kernel.
Currently the hotplug add/remove of memory is handled by the drmgr
command. The drmgr command performs the add/remove by performing
some work in user-space and making requests to the kernel to handle
other pieces. By moving all of the work to the kernel we can do the
add and remove faster, and provide a common place to do memory hotplug
for both the PowerVM and PowerKVM environments.
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/platforms/pseries/hotplug-memory.c | 170 +++++++++++++++++++++++
1 file changed, 170 insertions(+)
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 0e60e15..b254773 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -17,6 +17,7 @@
#include <linux/vmalloc.h>
#include <linux/memory.h>
#include <linux/memory_hotplug.h>
+#include <linux/slab.h>
#include <asm/firmware.h>
#include <asm/machdep.h>
@@ -24,6 +25,8 @@
#include <asm/sparsemem.h>
#include <asm/rtas.h>
+#include "pseries.h"
+
DEFINE_MUTEX(dlpar_mem_mutex);
unsigned long pseries_memory_block_size(void)
@@ -69,6 +72,53 @@ unsigned long pseries_memory_block_size(void)
return memblock_size;
}
+static void dlpar_free_drconf_property(struct property *prop)
+{
+ kfree(prop->name);
+ kfree(prop->value);
+ kfree(prop);
+}
+
+static struct property *dlpar_clone_drconf_property(struct device_node *dn)
+{
+ struct property *prop, *new_prop;
+
+ prop = of_find_property(dn, "ibm,dynamic-memory", NULL);
+ if (!prop)
+ return NULL;
+
+ new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
+ if (!new_prop)
+ return NULL;
+
+ new_prop->name = kstrdup(prop->name, GFP_KERNEL);
+ new_prop->value = kmalloc(prop->length + 1, GFP_KERNEL);
+ if (!new_prop->name || !new_prop->value) {
+ dlpar_free_drconf_property(new_prop);
+ return NULL;
+ }
+
+ memcpy(new_prop->value, prop->value, prop->length);
+ new_prop->length = prop->length;
+ *(((char *)new_prop->value) + new_prop->length) = 0;
+
+ return new_prop;
+}
+
+static struct memory_block *lmb_to_memblock(struct of_drconf_cell *lmb)
+{
+ unsigned long section_nr;
+ struct mem_section *mem_sect;
+ struct memory_block *mem_block;
+ u64 phys_addr = be64_to_cpu(lmb->base_addr);
+
+ section_nr = pfn_to_section_nr(PFN_DOWN(phys_addr));
+ mem_sect = __nr_to_section(section_nr);
+
+ mem_block = find_memory_block(mem_sect);
+ return mem_block;
+}
+
#ifdef CONFIG_MEMORY_HOTREMOVE
static int pseries_remove_memory(u64 start, u64 size)
{
@@ -155,13 +205,133 @@ static inline int pseries_remove_mem_node(struct device_node *np)
}
#endif /* CONFIG_MEMORY_HOTREMOVE */
+static int dlpar_add_one_lmb(struct of_drconf_cell *lmb)
+{
+ struct memory_block *mem_block;
+ u64 phys_addr;
+ unsigned long pages_per_block;
+ unsigned long block_sz;
+ int nid, sections_per_block;
+ int rc;
+
+ phys_addr = be64_to_cpu(lmb->base_addr);
+ block_sz = memory_block_size_bytes();
+ sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
+ pages_per_block = PAGES_PER_SECTION * sections_per_block;
+
+ if (phys_addr & ((pages_per_block << PAGE_SHIFT) - 1))
+ return -EINVAL;
+
+ nid = memory_add_physaddr_to_nid(phys_addr);
+ rc = add_memory(nid, phys_addr, block_sz);
+ if (rc)
+ return rc;
+
+ rc = memblock_add(phys_addr, block_sz);
+ if (rc) {
+ remove_memory(nid, phys_addr, block_sz);
+ return rc;
+ }
+
+ mem_block = lmb_to_memblock(lmb);
+ if (!mem_block) {
+ remove_memory(nid, phys_addr, block_sz);
+ return -EINVAL;
+ }
+
+ rc = device_online(&mem_block->dev);
+ put_device(&mem_block->dev);
+ if (rc)
+ remove_memory(nid, phys_addr, block_sz);
+
+ return rc;
+}
+
+static int dlpar_memory_add(struct pseries_hp_errorlog *hp_elog)
+{
+ struct of_drconf_cell *lmb;
+ struct device_node *dn;
+ struct property *prop;
+ uint32_t entries, *p;
+ int i, lmbs_to_add;
+ int lmbs_added = 0;
+ int rc = -EINVAL;
+
+ if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) {
+ lmbs_to_add = be32_to_cpu(hp_elog->_drc_u.drc_count);
+ pr_info("Attempting to hot-add %d LMB(s)\n", lmbs_to_add);
+ } else {
+ lmbs_to_add = 1;
+ pr_info("Attempting to hot-add LMB, drc index %x\n",
+ be32_to_cpu(hp_elog->_drc_u.drc_index));
+ }
+
+ dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+ if (!dn)
+ return -EINVAL;
+
+ prop = dlpar_clone_drconf_property(dn);
+ if (!prop) {
+ of_node_put(dn);
+ return -EINVAL;
+ }
+
+ p = prop->value;
+ entries = be32_to_cpu(*p++);
+ lmb = (struct of_drconf_cell *)p;
+
+ for (i = 0; i < entries; i++, lmb++) {
+ u32 drc_index = be32_to_cpu(lmb->drc_index);
+
+ if (lmbs_to_add == lmbs_added)
+ break;
+
+ if (be32_to_cpu(lmb->flags) & DRCONF_MEM_ASSIGNED)
+ continue;
+
+ if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX
+ && lmb->drc_index != hp_elog->_drc_u.drc_index)
+ continue;
+
+ rc = dlpar_acquire_drc(drc_index);
+ if (rc)
+ continue;
+
+ rc = dlpar_add_one_lmb(lmb);
+ if (rc) {
+ dlpar_release_drc(drc_index);
+ continue;
+ }
+
+ lmb->flags |= cpu_to_be32(DRCONF_MEM_ASSIGNED);
+ lmbs_added++;
+ pr_info("Memory at %llx (drc index %x) has been hot-added\n",
+ be64_to_cpu(lmb->base_addr), drc_index);
+ }
+
+ if (lmbs_added)
+ rc = of_update_property(dn, prop);
+ else
+ dlpar_free_drconf_property(prop);
+
+ of_node_put(dn);
+ return rc ? rc : lmbs_added;
+}
+
int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
{
int rc = 0;
+ if (hp_elog->id_type != PSERIES_HP_ELOG_ID_DRC_COUNT
+ && hp_elog->id_type != PSERIES_HP_ELOG_ID_DRC_INDEX)
+ return -EINVAL;
+
mutex_lock(&dlpar_mem_mutex);
switch (hp_elog->action) {
+ case PSERIES_HP_ELOG_ACTION_ADD:
+ rc = dlpar_memory_add(hp_elog);
+ break;
default:
pr_err("Invalid action (%d) specified\n", hp_elog->action);
rc = -EINVAL;
^ permalink raw reply related
* [PATCH 3/5] pseries: Create device hotplug entry point
From: Nathan Fontenot @ 2014-09-15 20:31 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <54174B81.50504@linux.vnet.ibm.com>
For pseries system the kernel will be notified of hotplug requests in
the form of rtas hotplug events. This patch creates a common routine that
can handle these requests in both the PowerVM anbd PowerKVM environments,
handle_dlpar_errorlog(). This also creates the initial memory hotplug
request handling stub.
For PowerVM this patch also creates a new /proc file that the drmgr
command will use to write rtas hotplug events to.
For future PowerKVM handling the rtas check-exception code can pass
any rtas hotplug events received to handle_dlpar_errorlog().
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/platforms/pseries/dlpar.c | 63 +++++++++++++++++++++++
arch/powerpc/platforms/pseries/hotplug-memory.c | 22 ++++++++
arch/powerpc/platforms/pseries/pseries.h | 10 ++++
3 files changed, 94 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index a2450b8..574ec73 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -16,7 +16,9 @@
#include <linux/cpu.h>
#include <linux/slab.h>
#include <linux/of.h>
+#include <linux/proc_fs.h>
#include "offline_states.h"
+#include "pseries.h"
#include <asm/prom.h>
#include <asm/machdep.h>
@@ -530,13 +532,72 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count)
return count;
}
+#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
+
+static int handle_dlpar_errorlog(struct rtas_error_log *error_log)
+{
+ struct pseries_errorlog *pseries_log;
+ struct pseries_hp_errorlog *hp_elog;
+ int rc = -EINVAL;
+
+ pseries_log = get_pseries_errorlog(error_log,
+ PSERIES_ELOG_SECT_ID_HOTPLUG);
+ if (!pseries_log)
+ return rc;
+
+ hp_elog = (struct pseries_hp_errorlog *)pseries_log->data;
+ if (!hp_elog)
+ return rc;
+
+ switch (hp_elog->resource) {
+ case PSERIES_HP_ELOG_RESOURCE_MEM:
+ rc = dlpar_memory(hp_elog);
+ break;
+ }
+
+ return rc;
+}
+
+static ssize_t dlpar_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ char *event_buf;
+ int rc;
+
+ event_buf = kmalloc(count + 1, GFP_KERNEL);
+ if (!event_buf)
+ return -ENOMEM;
+
+ rc = copy_from_user(event_buf, buf, count);
+ if (rc) {
+ kfree(event_buf);
+ return rc;
+ }
+
+ rc = handle_dlpar_errorlog((struct rtas_error_log *)event_buf);
+ kfree(event_buf);
+ return rc ? rc : count;
+}
+
+static const struct file_operations dlpar_fops = {
+ .write = dlpar_write,
+ .llseek = noop_llseek,
+};
+
static int __init pseries_dlpar_init(void)
{
+ struct proc_dir_entry *proc_ent;
+
+ proc_ent = proc_create("powerpc/dlpar", S_IWUSR, NULL, &dlpar_fops);
+ if (proc_ent)
+ proc_set_size(proc_ent, 0);
+
+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
ppc_md.cpu_probe = dlpar_cpu_probe;
ppc_md.cpu_release = dlpar_cpu_release;
+#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
return 0;
}
machine_device_initcall(pseries, pseries_dlpar_init);
-#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 24abc5c..0e60e15 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -9,6 +9,8 @@
* 2 of the License, or (at your option) any later version.
*/
+#define pr_fmt(fmt) "pseries-hotplug: " fmt
+
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/memblock.h>
@@ -20,6 +22,9 @@
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/sparsemem.h>
+#include <asm/rtas.h>
+
+DEFINE_MUTEX(dlpar_mem_mutex);
unsigned long pseries_memory_block_size(void)
{
@@ -150,6 +155,23 @@ static inline int pseries_remove_mem_node(struct device_node *np)
}
#endif /* CONFIG_MEMORY_HOTREMOVE */
+int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
+{
+ int rc = 0;
+
+ mutex_lock(&dlpar_mem_mutex);
+
+ switch (hp_elog->action) {
+ default:
+ pr_err("Invalid action (%d) specified\n", hp_elog->action);
+ rc = -EINVAL;
+ break;
+ }
+
+ mutex_unlock(&dlpar_mem_mutex);
+ return rc;
+}
+
static int pseries_add_mem_node(struct device_node *np)
{
const char *type;
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index b94516b..28bd994 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -11,6 +11,7 @@
#define _PSERIES_PSERIES_H
#include <linux/interrupt.h>
+#include <asm/rtas.h>
struct device_node;
@@ -62,6 +63,15 @@ extern int dlpar_detach_node(struct device_node *);
extern int dlpar_acquire_drc(u32);
extern int dlpar_release_drc(u32);
+#ifdef CONFIG_MEMORY_HOTPLUG
+extern int dlpar_memory(struct pseries_hp_errorlog *);
+#else
+static inline int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
+{
+ return -ENOTSUPP;
+}
+#endif
+
/* PCI root bridge prepare function override for pseries */
struct pci_host_bridge;
int pseries_root_bridge_prepare(struct pci_host_bridge *bridge);
^ permalink raw reply related
* [PATCH 2/5] pseries: Export drc_[acquire|release]_drc() routines
From: Nathan Fontenot @ 2014-09-15 20:30 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <54174B81.50504@linux.vnet.ibm.com>
Export the routines to acquire and release a drc index.
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/platforms/pseries/pseries.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index 361add6..b94516b 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -59,6 +59,8 @@ extern void dlpar_free_cc_property(struct property *);
extern struct device_node *dlpar_configure_connector(u32, struct device_node *);
extern int dlpar_attach_node(struct device_node *);
extern int dlpar_detach_node(struct device_node *);
+extern int dlpar_acquire_drc(u32);
+extern int dlpar_release_drc(u32);
/* PCI root bridge prepare function override for pseries */
struct pci_host_bridge;
^ permalink raw reply related
* [PATCH 1/5] pseries: Define rtas hotplug event sections
From: Nathan Fontenot @ 2014-09-15 20:29 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <54174B81.50504@linux.vnet.ibm.com>
In order to handle device hotplug in the kernel on pseries the hotplug
notification will be communicated to the kernel in the form of a
rtas hotplug event. This patch adds the definition of rtas hotplug event
sections.
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/rtas.h | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index b390f55..a01879e 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -273,6 +273,7 @@ inline uint32_t rtas_ext_event_company_id(struct rtas_ext_event_log_v6 *ext_log)
#define PSERIES_ELOG_SECT_ID_MANUFACT_INFO (('M' << 8) | 'I')
#define PSERIES_ELOG_SECT_ID_CALL_HOME (('C' << 8) | 'H')
#define PSERIES_ELOG_SECT_ID_USER_DEF (('U' << 8) | 'D')
+#define PSERIES_ELOG_SECT_ID_HOTPLUG (('H' << 8) | 'P')
/* Vendor specific Platform Event Log Format, Version 6, section header */
struct pseries_errorlog {
@@ -296,6 +297,31 @@ inline uint16_t pseries_errorlog_length(struct pseries_errorlog *sect)
return be16_to_cpu(sect->length);
}
+/* RTAS pseries hotplug errorlog section */
+struct pseries_hp_errorlog {
+ uint8_t resource;
+ uint8_t action;
+ uint8_t id_type;
+ uint8_t reserved;
+ union {
+ __be32 drc_index;
+ __be32 drc_count;
+ char drc_name[1];
+ } _drc_u;
+};
+
+#define PSERIES_HP_ELOG_RESOURCE_CPU 1
+#define PSERIES_HP_ELOG_RESOURCE_MEM 2
+#define PSERIES_HP_ELOG_RESOURCE_SLOT 3
+#define PSERIES_HP_ELOG_RESOURCE_PHB 4
+
+#define PSERIES_HP_ELOG_ACTION_ADD 1
+#define PSERIES_HP_ELOG_ACTION_REMOVE 2
+
+#define PSERIES_HP_ELOG_ID_DRC_NAME 1
+#define PSERIES_HP_ELOG_ID_DRC_INDEX 2
+#define PSERIES_HP_ELOG_ID_DRC_COUNT 3
+
struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
uint16_t section_id);
^ permalink raw reply related
* [PATCH 0/5] pseries: Move memory hotplug to the kernel
From: Nathan Fontenot @ 2014-09-15 20:26 UTC (permalink / raw)
To: linuxppc-dev@lists.ozlabs.org
In order to better support device hotplug (cpu, memory, and pci) in the
PowerVM and PowerKVM environments, the handling of device hotplug
could be updated so that the act of hotplugging a device occurs entirely
in the kernel. This patch set begins to address this by moving
memory hotplug to the kernel. Patches to follow will do the same
for cpu and pci devices.
To provide background, the current handling of memory hotplug is
handled by the drmgr command. This command is invoked when memory
add/remove requests are made at the HMC and conveyed to a partition
through the RSCT framework. The drmgr command then performs parts
of the hotplug in user-space and makes requests to the kernel to perform
other pieces. This is not really ideal, we can do everything in the
kernel and do it faster.
In this patchset, hotplug events will now be communicated to the kernel
in the form of rtas hotplug events. For PowerKVM systems this is done
by qemu using the ras epow interrupt. For PowerVM systems the drmgr
command will be updated to create a rtas hotplug event and send it to
the kernel via a new /proc/powerpc/dlpar interface. Both of these
entry points for hotplug rtas events then call a common routine
for handling rtas hotplug events.
-Nathan
Patch 1/5
- Add definition of hotplug rtas event sections.
Patch 2/5
- export the dlpar_[acquire|release]drc() routines.
Patch 3/5
- Create the new /proc/powerpc/dlpar interface
Patch 4/5
- Implement memory hotplug add in the kernel.
Patch 5/5
- Implement memory hotplug remove in the kernel.
include/asm/rtas.h | 26 ++
platforms/pseries/dlpar.c | 63 ++++++-
platforms/pseries/hotplug-memory.c | 332 ++++++++++++++++++++++++++++++++++++-
platforms/pseries/pseries.h | 12 +
4 files changed, 431 insertions(+), 2 deletions(-)
^ permalink raw reply
* [PATCH v2] drivers: char: hw_random: printk replacement
From: Sudip Mukherjee @ 2014-09-15 15:01 UTC (permalink / raw)
To: Matt Mackall, Herbert Xu, Olof Johansson
Cc: linuxppc-dev, Sudip Mukherjee, linux-geode, linux-kernel
as pr_* macros are more preffered over printk, so printk replaced with corresponding pr_* macros
Signed-off-by: Sudip Mukherjee <sudip@vectorindia.org>
---
The replacement was done by a bash script to avoid copy paste error. The script is as follows :
OLD="printk(KERN_ERR \?"
OLD1="printk(KERN_NOTICE \?"
OLD2="printk(KERN_WARNING \?"
OLD3="printk(KERN_INFO \?"
NEW="pr_err("
NEW1="pr_notice("
NEW2="pr_warn("
NEW3="pr_info("
TFILE="/tmp/out.tmp.$$"
for f in *.c
do
sed -e "s/$OLD/$NEW/g" -e "s/$OLD1/$NEW1/g" -e "s/$OLD2/$NEW2/g" -e "s/$OLD3/$NEW3/g" "$f" > $TFILE && mv $TFILE "$f"
done
exception is intel-rng.c .
in v1 the build failed due to intel-rng.c .
it has been corrected and has been carefully build tested.
drivers/char/hw_random/amd-rng.c | 4 ++--
drivers/char/hw_random/geode-rng.c | 4 ++--
drivers/char/hw_random/intel-rng.c | 13 ++++++-------
drivers/char/hw_random/pasemi-rng.c | 2 +-
drivers/char/hw_random/pseries-rng.c | 2 +-
drivers/char/hw_random/via-rng.c | 8 ++++----
6 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index c6af038..48f6a83 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -142,10 +142,10 @@ found:
amd_rng.priv = (unsigned long)pmbase;
amd_pdev = pdev;
- printk(KERN_INFO "AMD768 RNG detected\n");
+ pr_info("AMD768 RNG detected\n");
err = hwrng_register(&amd_rng);
if (err) {
- printk(KERN_ERR PFX "RNG registering failed (%d)\n",
+ pr_err(PFX "RNG registering failed (%d)\n",
err);
release_region(pmbase + 0xF0, 8);
goto out;
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c
index 4c4d4e1..0d0579f 100644
--- a/drivers/char/hw_random/geode-rng.c
+++ b/drivers/char/hw_random/geode-rng.c
@@ -109,10 +109,10 @@ found:
goto out;
geode_rng.priv = (unsigned long)mem;
- printk(KERN_INFO "AMD Geode RNG detected\n");
+ pr_info("AMD Geode RNG detected\n");
err = hwrng_register(&geode_rng);
if (err) {
- printk(KERN_ERR PFX "RNG registering failed (%d)\n",
+ pr_err(PFX "RNG registering failed (%d)\n",
err);
goto err_unmap;
}
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index 86fe45c..290c880 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -199,7 +199,7 @@ static int intel_rng_init(struct hwrng *rng)
if ((hw_status & INTEL_RNG_ENABLED) == 0)
hw_status = hwstatus_set(mem, hw_status | INTEL_RNG_ENABLED);
if ((hw_status & INTEL_RNG_ENABLED) == 0) {
- printk(KERN_ERR PFX "cannot enable RNG, aborting\n");
+ pr_err(PFX "cannot enable RNG, aborting\n");
goto out;
}
err = 0;
@@ -216,7 +216,7 @@ static void intel_rng_cleanup(struct hwrng *rng)
if (hw_status & INTEL_RNG_ENABLED)
hwstatus_set(mem, hw_status & ~INTEL_RNG_ENABLED);
else
- printk(KERN_WARNING PFX "unusual: RNG already disabled\n");
+ pr_warn(PFX "unusual: RNG already disabled\n");
}
@@ -274,7 +274,7 @@ static int __init intel_rng_hw_init(void *_intel_rng_hw)
if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
(dvc != INTEL_FWH_DEVICE_CODE_8M &&
dvc != INTEL_FWH_DEVICE_CODE_4M)) {
- printk(KERN_NOTICE PFX "FWH not detected\n");
+ pr_notice(PFX "FWH not detected\n");
return -ENODEV;
}
@@ -306,7 +306,6 @@ static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw,
(BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
== BIOS_CNTL_LOCK_ENABLE_MASK) {
static __initdata /*const*/ char warning[] =
- KERN_WARNING
PFX "Firmware space is locked read-only. If you can't or\n"
PFX "don't want to disable this in firmware setup, and if\n"
PFX "you are certain that your system has a functional\n"
@@ -314,7 +313,7 @@ PFX "RNG, try using the 'no_fwh_detect' option.\n";
if (no_fwh_detect)
return -ENODEV;
- printk(warning);
+ pr_warn("%s", warning);
return -EBUSY;
}
@@ -392,10 +391,10 @@ fwh_done:
goto out;
}
- printk(KERN_INFO "Intel 82802 RNG detected\n");
+ pr_info("Intel 82802 RNG detected\n");
err = hwrng_register(&intel_rng);
if (err) {
- printk(KERN_ERR PFX "RNG registering failed (%d)\n",
+ pr_err(PFX "RNG registering failed (%d)\n",
err);
iounmap(mem);
}
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
index c66279b..c0347d1 100644
--- a/drivers/char/hw_random/pasemi-rng.c
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -113,7 +113,7 @@ static int rng_probe(struct platform_device *ofdev)
pasemi_rng.priv = (unsigned long)rng_regs;
- printk(KERN_INFO "Registering PA Semi RNG\n");
+ pr_info("Registering PA Semi RNG\n");
err = hwrng_register(&pasemi_rng);
diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c
index ab7ffde..6226aa0 100644
--- a/drivers/char/hw_random/pseries-rng.c
+++ b/drivers/char/hw_random/pseries-rng.c
@@ -86,7 +86,7 @@ static struct vio_driver pseries_rng_driver = {
static int __init rng_init(void)
{
- printk(KERN_INFO "Registering IBM pSeries RNG driver\n");
+ pr_info("Registering IBM pSeries RNG driver\n");
return vio_register_driver(&pseries_rng_driver);
}
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index de5a6dc..a3bebef 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -141,7 +141,7 @@ static int via_rng_init(struct hwrng *rng)
* register */
if ((c->x86 == 6) && (c->x86_model >= 0x0f)) {
if (!cpu_has_xstore_enabled) {
- printk(KERN_ERR PFX "can't enable hardware RNG "
+ pr_err(PFX "can't enable hardware RNG "
"if XSTORE is not enabled\n");
return -ENODEV;
}
@@ -180,7 +180,7 @@ static int via_rng_init(struct hwrng *rng)
unneeded */
rdmsr(MSR_VIA_RNG, lo, hi);
if ((lo & VIA_RNG_ENABLE) == 0) {
- printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n");
+ pr_err(PFX "cannot enable VIA C3 RNG, aborting\n");
return -ENODEV;
}
@@ -202,10 +202,10 @@ static int __init mod_init(void)
if (!cpu_has_xstore)
return -ENODEV;
- printk(KERN_INFO "VIA RNG detected\n");
+ pr_info("VIA RNG detected\n");
err = hwrng_register(&via_rng);
if (err) {
- printk(KERN_ERR PFX "RNG registering failed (%d)\n",
+ pr_err(PFX "RNG registering failed (%d)\n",
err);
goto out;
}
--
1.8.1.2
^ permalink raw reply related
* Re: [PATCH v1 21/21] PCI/MSI: Clean up unused MSI arch functions
From: Lucas Stach @ 2014-09-15 14:47 UTC (permalink / raw)
To: Yijing Wang
Cc: linux-mips, linux-ia64, linux-pci, Bharat.Bhushan, sparclinux,
linux-arch, linux-s390, Russell King, Joerg Roedel, x86,
Sebastian Ott, xen-devel, arnab.basu, Arnd Bergmann,
Konrad Rzeszutek Wilk, Chris Metcalf, Bjorn Helgaas,
Thomas Gleixner, linux-arm-kernel, Xinwei Hu, Tony Luck,
Ralf Baechle, iommu, Wuyun, linuxppc-dev, David S. Miller
In-Reply-To: <1409911806-10519-22-git-send-email-wangyijing@huawei.com>
Am Freitag, den 05.09.2014, 18:10 +0800 schrieb Yijing Wang:
> Now we use struct msi_chip in all platforms to configure
> MSI/MSI-X. We can clean up the unused arch functions.
>
> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
> ---
> drivers/iommu/irq_remapping.c | 2 +-
> drivers/pci/msi.c | 99 ++++++++++++++++-------------------------
> include/linux/msi.h | 14 ------
> 3 files changed, 39 insertions(+), 76 deletions(-)
>
> diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
> index 99b1c0f..6e645f0 100644
> --- a/drivers/iommu/irq_remapping.c
> +++ b/drivers/iommu/irq_remapping.c
> @@ -92,7 +92,7 @@ error:
>
> /*
> * Restore altered MSI descriptor fields and prevent just destroyed
> - * IRQs from tearing down again in default_teardown_msi_irqs()
> + * IRQs from tearing down again in teardown_msi_irqs()
> */
> msidesc->irq = 0;
> msidesc->nvec_used = 0;
> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
> index d78d637..e3e7f4f 100644
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -34,50 +34,31 @@ struct msi_chip * __weak arch_find_msi_chip(struct pci_dev *dev)
> return dev->bus->msi;
> }
>
> -int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
> -{
> - struct msi_chip *chip = arch_find_msi_chip(dev);
> - int err;
> -
> - if (!chip || !chip->setup_irq)
> - return -EINVAL;
> -
> - err = chip->setup_irq(dev, desc);
> - if (err < 0)
> - return err;
> -
> - return 0;
> -}
> -
> -void __weak arch_teardown_msi_irq(unsigned int irq)
> -{
> - struct msi_chip *chip = irq_get_chip_data(irq);
> -
> - if (!chip || !chip->teardown_irq)
> - return;
> -
> - chip->teardown_irq(irq);
> -}
> -
> -int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> +int setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> {
> struct msi_desc *entry;
> int ret;
> struct msi_chip *chip;
>
> chip = arch_find_msi_chip(dev);
> - if (chip && chip->setup_irqs)
> + if (!chip)
> + return -EINVAL;
> +
> + if (chip->setup_irqs)
> return chip->setup_irqs(dev, nvec, type);
>
> /*
> * If an architecture wants to support multiple MSI, it needs to
> - * override arch_setup_msi_irqs()
> + * implement chip->setup_irqs().
> */
> if (type == PCI_CAP_ID_MSI && nvec > 1)
> return 1;
>
> + if (!chip->setup_irq)
> + return -EINVAL;
> +
> list_for_each_entry(entry, &dev->msi_list, list) {
> - ret = arch_setup_msi_irq(dev, entry);
> + ret = chip->setup_irq(dev, entry);
> if (ret < 0)
> return ret;
> if (ret > 0)
> @@ -87,13 +68,20 @@ int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> return 0;
> }
>
> -/*
> - * We have a default implementation available as a separate non-weak
> - * function, as it is used by the Xen x86 PCI code
> - */
> -void default_teardown_msi_irqs(struct pci_dev *dev)
> +static void teardown_msi_irqs(struct pci_dev *dev)
> {
> struct msi_desc *entry;
> + struct msi_chip *chip;
> +
> + chip = arch_find_msi_chip(dev);
> + if (!chip)
> + return;
> +
> + if (chip->teardown_irqs)
> + return chip->teardown_irqs(dev);
> +
> + if (!chip->teardown_irq)
> + return;
>
> list_for_each_entry(entry, &dev->msi_list, list) {
> int i, nvec;
> @@ -104,20 +92,10 @@ void default_teardown_msi_irqs(struct pci_dev *dev)
> else
> nvec = 1 << entry->msi_attrib.multiple;
> for (i = 0; i < nvec; i++)
> - arch_teardown_msi_irq(entry->irq + i);
> + chip->teardown_irq(entry->irq + i);
> }
> }
>
> -void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
> -{
> - struct msi_chip *chip = arch_find_msi_chip(dev);
> -
> - if (chip && chip->teardown_irqs)
> - return chip->teardown_irqs(dev);
> -
> - return default_teardown_msi_irqs(dev);
> -}
> -
> static void default_restore_msi_irq(struct pci_dev *dev, int irq)
> {
> struct msi_desc *entry;
> @@ -136,10 +114,18 @@ static void default_restore_msi_irq(struct pci_dev *dev, int irq)
> write_msi_msg(irq, &entry->msg);
> }
>
> -void __weak arch_restore_msi_irqs(struct pci_dev *dev)
> +static void default_restore_msi_irqs(struct pci_dev *dev)
> {
> - struct msi_chip *chip = arch_find_msi_chip(dev);
> + struct msi_desc *entry = NULL;
> +
> + list_for_each_entry(entry, &dev->msi_list, list) {
> + default_restore_msi_irq(dev, entry->irq);
> + }
> +}
>
> +static void restore_msi_irqs(struct pci_dev *dev)
> +{
> + struct msi_chip *chip = arch_find_msi_chip(dev);
> if (chip && chip->restore_irqs)
> return chip->restore_irqs(dev);
>
> @@ -248,15 +234,6 @@ void unmask_msi_irq(struct irq_data *data)
> msi_set_mask_bit(data, 0);
> }
>
> -void default_restore_msi_irqs(struct pci_dev *dev)
> -{
> - struct msi_desc *entry;
> -
> - list_for_each_entry(entry, &dev->msi_list, list) {
> - default_restore_msi_irq(dev, entry->irq);
> - }
> -}
> -
> void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
> {
> BUG_ON(entry->dev->current_state != PCI_D0);
> @@ -360,7 +337,7 @@ static void free_msi_irqs(struct pci_dev *dev)
> BUG_ON(irq_has_action(entry->irq + i));
> }
>
> - arch_teardown_msi_irqs(dev);
> + teardown_msi_irqs(dev);
>
> list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
> if (entry->msi_attrib.is_msix) {
> @@ -430,7 +407,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
>
> pci_intx_for_msi(dev, 0);
> msi_set_enable(dev, 0);
> - arch_restore_msi_irqs(dev);
> + restore_msi_irqs(dev);
>
> pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
> msi_mask_irq(entry, msi_mask(entry->msi_attrib.multi_cap),
> @@ -453,7 +430,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
> msix_clear_and_set_ctrl(dev, 0,
> PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
>
> - arch_restore_msi_irqs(dev);
> + restore_msi_irqs(dev);
> list_for_each_entry(entry, &dev->msi_list, list) {
> msix_mask_irq(entry, entry->masked);
> }
> @@ -624,7 +601,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
> list_add_tail(&entry->list, &dev->msi_list);
>
> /* Configure MSI capability structure */
> - ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
> + ret = setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
> if (ret) {
> msi_mask_irq(entry, mask, ~mask);
> free_msi_irqs(dev);
> @@ -740,7 +717,7 @@ static int msix_capability_init(struct pci_dev *dev,
> if (ret)
> return ret;
>
> - ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
> + ret = setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
> if (ret)
> goto out_avail;
>
> diff --git a/include/linux/msi.h b/include/linux/msi.h
> index 92a51e7..d6e1f7c 100644
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -51,20 +51,6 @@ struct msi_desc {
> struct kobject kobj;
> };
>
> -/*
> - * The arch hooks to setup up msi irqs. Those functions are
> - * implemented as weak symbols so that they /can/ be overriden by
> - * architecture specific code if needed.
> - */
> -int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
> -void arch_teardown_msi_irq(unsigned int irq);
> -int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
> -void arch_teardown_msi_irqs(struct pci_dev *dev);
> -void arch_restore_msi_irqs(struct pci_dev *dev);
> -
> -void default_teardown_msi_irqs(struct pci_dev *dev);
> -void default_restore_msi_irqs(struct pci_dev *dev);
> -
> struct msi_chip {
> struct module *owner;
> struct device *dev;
--
Pengutronix e.K. | Lucas Stach |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Re: [PATCH v1 06/21] PCI/MSI: Refactor struct msi_chip to make it become more common
From: Lucas Stach @ 2014-09-15 14:44 UTC (permalink / raw)
To: Yijing Wang
Cc: linux-mips, linux-ia64, linux-pci, Bharat.Bhushan, sparclinux,
linux-arch, linux-s390, Russell King, Joerg Roedel, x86,
Sebastian Ott, xen-devel, arnab.basu, Arnd Bergmann,
Konrad Rzeszutek Wilk, Chris Metcalf, Bjorn Helgaas,
Thomas Gleixner, linux-arm-kernel, Xinwei Hu, Tony Luck,
Ralf Baechle, iommu, Wuyun, linuxppc-dev, David S. Miller
In-Reply-To: <1409911806-10519-7-git-send-email-wangyijing@huawei.com>
Am Freitag, den 05.09.2014, 18:09 +0800 schrieb Yijing Wang:
> Now there are a lot of __weak arch functions in MSI code.
> These functions make MSI driver complex. Thierry Reding Introduced
> a new MSI chip framework to configure MSI/MSI-X irq in ARM. Use
> the new MSI chip framework to refactor all other platform MSI
> arch code to eliminate weak arch MSI functions. This patch add
> .restore_irq() and .setup_irqs() to make it become more common.
>
> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
This change looks good to me:
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
> ---
> drivers/pci/msi.c | 15 +++++++++++++++
> include/linux/msi.h | 3 +++
> 2 files changed, 18 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
> index 539c11d..d78d637 100644
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -63,6 +63,11 @@ int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> {
> struct msi_desc *entry;
> int ret;
> + struct msi_chip *chip;
> +
> + chip = arch_find_msi_chip(dev);
> + if (chip && chip->setup_irqs)
> + return chip->setup_irqs(dev, nvec, type);
>
> /*
> * If an architecture wants to support multiple MSI, it needs to
> @@ -105,6 +110,11 @@ void default_teardown_msi_irqs(struct pci_dev *dev)
>
> void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
> {
> + struct msi_chip *chip = arch_find_msi_chip(dev);
> +
> + if (chip && chip->teardown_irqs)
> + return chip->teardown_irqs(dev);
> +
> return default_teardown_msi_irqs(dev);
> }
>
> @@ -128,6 +138,11 @@ static void default_restore_msi_irq(struct pci_dev *dev, int irq)
>
> void __weak arch_restore_msi_irqs(struct pci_dev *dev)
> {
> + struct msi_chip *chip = arch_find_msi_chip(dev);
> +
> + if (chip && chip->restore_irqs)
> + return chip->restore_irqs(dev);
> +
> return default_restore_msi_irqs(dev);
> }
>
> diff --git a/include/linux/msi.h b/include/linux/msi.h
> index 5650848..92a51e7 100644
> --- a/include/linux/msi.h
> +++ b/include/linux/msi.h
> @@ -72,7 +72,10 @@ struct msi_chip {
> struct list_head list;
>
> int (*setup_irq)(struct pci_dev *dev, struct msi_desc *desc);
> + int (*setup_irqs)(struct pci_dev *dev, int nvec, int type);
> void (*teardown_irq)(unsigned int irq);
> + void (*teardown_irqs)(struct pci_dev *dev);
> + void (*restore_irqs)(struct pci_dev *dev);
> };
>
> #endif /* LINUX_MSI_H */
--
Pengutronix e.K. | Lucas Stach |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Re: [PATCH v1 05/21] PCI/MSI: Introduce weak arch_find_msi_chip() to find MSI chip
From: Lucas Stach @ 2014-09-15 14:42 UTC (permalink / raw)
To: Yijing Wang
Cc: linux-mips, linux-ia64, linux-pci, Bharat.Bhushan, sparclinux,
linux-arch, linux-s390, Russell King, Joerg Roedel, x86,
Sebastian Ott, xen-devel, arnab.basu, Arnd Bergmann,
Konrad Rzeszutek Wilk, Chris Metcalf, Bjorn Helgaas,
Thomas Gleixner, linux-arm-kernel, Xinwei Hu, Tony Luck,
Ralf Baechle, iommu, Wuyun, linuxppc-dev, David S. Miller
In-Reply-To: <1409911806-10519-6-git-send-email-wangyijing@huawei.com>
Am Freitag, den 05.09.2014, 18:09 +0800 schrieb Yijing Wang:
> Introduce weak arch_find_msi_chip() to find the match msi_chip.
> Currently, MSI chip associates pci bus to msi_chip. Because in
> ARM platform, there may be more than one MSI controller in system.
> Associate pci bus to msi_chip help pci device to find the match
> msi_chip and setup MSI/MSI-X irq correctly. But in other platform,
> like in x86. we only need one MSI chip, because all device use
> the same MSI address/data and irq etc. So it's no need to associate
> pci bus to MSI chip, just use a arch function, arch_find_msi_chip()
> to return the MSI chip for simplicity. The default weak
> arch_find_msi_chip() used in ARM platform, find the MSI chip
> by pci bus.
>
Hm, while one weak function sounds much better than the plethora we have
now, I wonder how much work it would be to associate the msi_chip with
the pci bus on other arches the same way as done on ARM. This way we
could kill this calling into arch specific functions which would make
things a bit clearer to follow I think.
Regards,
Lucas
> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
> ---
> drivers/pci/msi.c | 7 ++++++-
> 1 files changed, 6 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
> index a77e7f7..539c11d 100644
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -29,9 +29,14 @@ static int pci_msi_enable = 1;
>
> /* Arch hooks */
>
> +struct msi_chip * __weak arch_find_msi_chip(struct pci_dev *dev)
> +{
> + return dev->bus->msi;
> +}
> +
> int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
> {
> - struct msi_chip *chip = dev->bus->msi;
> + struct msi_chip *chip = arch_find_msi_chip(dev);
> int err;
>
> if (!chip || !chip->setup_irq)
--
Pengutronix e.K. | Lucas Stach |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Re: [PATCH v1 03/21] MSI: Remove the redundant irq_set_chip_data()
From: Lucas Stach @ 2014-09-15 14:00 UTC (permalink / raw)
To: Yijing Wang
Cc: linux-mips, linux-ia64, linux-pci, Bharat.Bhushan, sparclinux,
linux-arch, linux-s390, Russell King, Joerg Roedel, x86,
Sebastian Ott, xen-devel, arnab.basu, Arnd Bergmann,
Konrad Rzeszutek Wilk, Chris Metcalf, Bjorn Helgaas,
Thomas Gleixner, linux-arm-kernel, Xinwei Hu, Tony Luck,
Ralf Baechle, iommu, Wuyun, linuxppc-dev, David S. Miller
In-Reply-To: <1409911806-10519-4-git-send-email-wangyijing@huawei.com>
Am Freitag, den 05.09.2014, 18:09 +0800 schrieb Yijing Wang:
> Currently, pcie-designware, pcie-rcar, pci-tegra drivers
> use irq chip_data to save the msi_chip pointer. They
> already call irq_set_chip_data() in their own MSI irq map
> functions. So irq_set_chip_data() in arch_setup_msi_irq()
> is useless.
>
> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
> ---
> drivers/pci/msi.c | 2 --
> 1 files changed, 0 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
> index f6cb317..d547f7f 100644
> --- a/drivers/pci/msi.c
> +++ b/drivers/pci/msi.c
> @@ -41,8 +41,6 @@ int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
> if (err < 0)
> return err;
>
> - irq_set_chip_data(desc->irq, chip);
> -
> return 0;
> }
>
arch_teardown_msi_irq() expects to find the msi_chip in the irq
chip_data field. As this means drivers don't have any reasonable other
possibility to stuff things into this field, I think it would make sense
to do the cleanup the other way around: keep the irq_set_chip_data
arch_setup_msi_irq() and rip it out of the individual drivers.
Regards,
Lucas
--
Pengutronix e.K. | Lucas Stach |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Re: [PATCH V3] ASoC: fsl_ssi: refine ipg clock usage in this module
From: Markus Pargmann @ 2014-09-15 13:52 UTC (permalink / raw)
To: Shengjiu Wang
Cc: alsa-devel, lgirdwood, tiwai, Li.Xiubo, timur, perex,
nicoleotsuka, broonie, linuxppc-dev, linux-kernel
In-Reply-To: <20140915103714.GB23877@audiosh1>
[-- Attachment #1: Type: text/plain, Size: 8013 bytes --]
On Mon, Sep 15, 2014 at 06:37:15PM +0800, Shengjiu Wang wrote:
> On Mon, Sep 15, 2014 at 12:32:13PM +0200, Markus Pargmann wrote:
> > On Mon, Sep 15, 2014 at 06:22:27PM +0800, Shengjiu Wang wrote:
> > > On Mon, Sep 15, 2014 at 12:05:41PM +0200, Markus Pargmann wrote:
> > > > On Fri, Sep 12, 2014 at 06:35:15PM +0800, Shengjiu Wang wrote:
> > > > > Check if ipg clock is in clock-names property, then we can move the
> > > > > ipg clock enable and disable operation to startup and shutdown, that
> > > > > is only enable ipg clock when ssi is working and keep clock is disabled
> > > > > when ssi is in idle.
> > > > > But when the checking is failed, remain the clock control as before.
> > > > >
> > > > > Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
> > > > > ---
> > > > > V3 change log:
> > > > > update patch according Nicolin and markus's comments
> > > > >
> > > > >
> > > > > sound/soc/fsl/fsl_ssi.c | 53 ++++++++++++++++++++++++++++++++++++++++-------
> > > > > 1 file changed, 45 insertions(+), 8 deletions(-)
> > > > >
> > > > > diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
> > > > > index 2fc3e66..6d1dfd5 100644
> > > > > --- a/sound/soc/fsl/fsl_ssi.c
> > > > > +++ b/sound/soc/fsl/fsl_ssi.c
> > > > > @@ -169,6 +169,7 @@ struct fsl_ssi_private {
> > > > > u8 i2s_mode;
> > > > > bool use_dma;
> > > > > bool use_dual_fifo;
> > > > > + bool has_ipg_clk_name;
> > > > > unsigned int fifo_depth;
> > > > > struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
> > > > >
> > > > > @@ -530,6 +531,11 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
> > > > > struct snd_soc_pcm_runtime *rtd = substream->private_data;
> > > > > struct fsl_ssi_private *ssi_private =
> > > > > snd_soc_dai_get_drvdata(rtd->cpu_dai);
> > > > > + int ret;
> > > > > +
> > > > > + ret = clk_prepare_enable(ssi_private->clk);
> > > > > + if (ret)
> > > > > + return ret;
> > > > >
> > > > > /* When using dual fifo mode, it is safer to ensure an even period
> > > > > * size. If appearing to an odd number while DMA always starts its
> > > > > @@ -544,6 +550,21 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
> > > > > }
> > > > >
> > > > > /**
> > > > > + * fsl_ssi_shutdown: shutdown the SSI
> > > > > + *
> > > > > + */
> > > > > +static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
> > > > > + struct snd_soc_dai *dai)
> > > > > +{
> > > > > + struct snd_soc_pcm_runtime *rtd = substream->private_data;
> > > > > + struct fsl_ssi_private *ssi_private =
> > > > > + snd_soc_dai_get_drvdata(rtd->cpu_dai);
> > > > > +
> > > > > + clk_disable_unprepare(ssi_private->clk);
> > > > > +
> > > > > +}
> > > > > +
> > > > > +/**
> > > > > * fsl_ssi_set_bclk - configure Digital Audio Interface bit clock
> > > > > *
> > > > > * Note: This function can be only called when using SSI as DAI master
> > > > > @@ -1043,6 +1064,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
> > > > >
> > > > > static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
> > > > > .startup = fsl_ssi_startup,
> > > > > + .shutdown = fsl_ssi_shutdown,
> > > > > .hw_params = fsl_ssi_hw_params,
> > > > > .hw_free = fsl_ssi_hw_free,
> > > > > .set_fmt = fsl_ssi_set_dai_fmt,
> > > > > @@ -1168,17 +1190,22 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
> > > > > u32 dmas[4];
> > > > > int ret;
> > > > >
> > > > > - ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
> > > > > + if (ssi_private->has_ipg_clk_name)
> > > > > + ssi_private->clk = devm_clk_get(&pdev->dev, "ipg");
> > > > > + else
> > > > > + ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
> > > > > if (IS_ERR(ssi_private->clk)) {
> > > > > ret = PTR_ERR(ssi_private->clk);
> > > > > dev_err(&pdev->dev, "could not get clock: %d\n", ret);
> > > > > return ret;
> > > > > }
> > > > >
> > > > > - ret = clk_prepare_enable(ssi_private->clk);
> > > > > - if (ret) {
> > > > > - dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
> > > > > - return ret;
> > > > > + if (!ssi_private->has_ipg_clk_name) {
> > > > > + ret = clk_prepare_enable(ssi_private->clk);
> > > > > + if (ret) {
> > > > > + dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
> > > > > + return ret;
> > > > > + }
> > > > > }
> > > > >
> > > > > /* For those SLAVE implementations, we ingore non-baudclk cases
> > > > > @@ -1236,8 +1263,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
> > > > > return 0;
> > > > >
> > > > > error_pcm:
> > > > > - clk_disable_unprepare(ssi_private->clk);
> > > > >
> > > > > + if (!ssi_private->has_ipg_clk_name)
> > > > > + clk_disable_unprepare(ssi_private->clk);
> > > > > return ret;
> > > > > }
> > > > >
> > > > > @@ -1246,7 +1274,8 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev,
> > > > > {
> > > > > if (!ssi_private->use_dma)
> > > > > imx_pcm_fiq_exit(pdev);
> > > > > - clk_disable_unprepare(ssi_private->clk);
> > > > > + if (!ssi_private->has_ipg_clk_name)
> > > > > + clk_disable_unprepare(ssi_private->clk);
> > > > > }
> > > > >
> > > > > static int fsl_ssi_probe(struct platform_device *pdev)
> > > > > @@ -1321,8 +1350,16 @@ static int fsl_ssi_probe(struct platform_device *pdev)
> > > > > return -ENOMEM;
> > > > > }
> > > > >
> > > > > - ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
> > > > > + ret = of_property_match_string(np, "clock-names", "ipg");
> > > > > + if (ret < 0) {
> > > > > + ssi_private->has_ipg_clk_name = false;
> > > > > + ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
> > > > > &fsl_ssi_regconfig);
> > > >
> > > > Sorry if I was unclear about that. My suggestion was to enable the clock
> > > > right here:
> > > > clk_prepare_enable(ssi_private->clk);
> > > >
> > > > Then you can remove ssi_private->has_ipg_clk_name and all
> > > > clk_prepare_enable() and clk_disable_unprepare() from above. Also you
> > > > can move the devm_clk_get() into this block.
> > > >
> > >
> > > ipg clock not only need to be enabled when accessing register, but also
> > > need to be enabled when ssi is working. So I add clk_enable in startup.
> > >
> > > > It seems you really want to implement this for devicetrees where the
> > > > "ipg" clock-name is missing, but I don't understand why? I really can't
> > > > see any benefit of adding all these clk_prepare_enable() calls for all
> > > > cornercases that may occure. For example the clocks for AC97 are still
> > > > missing in this version.
> > >
> > > When ipg clock-name is missing, I just remain the code logic as before.
> > > So AC97 case is same as before too.
> > > When have ipg clock-name, register it to regmap for accessing register,
> > > and enabling ipg clock in startup also is useful for AC97.
> > >
> > > I don't understand why you think clock for AC97 is still missing?
> >
> > Sorry got it all wrong, monday morning tiredness perhaps ;-).
> >
> > The patch looks good for me at the second look. I will test it later
> > today and give you feedback.
> >
> > Best regards,
> >
> > Markus
>
> Thank you very much. Your comments help me a lot. and wait your feedback.
Okay, I tested this patch on imx53-qsb with and without the "ipg"
clock-name. Both worked, so:
Tested-by: Markus Pargmann <mpa@pengutronix.de>
I noticed that checkpatch shows two minor style issues. It would be good
if you could fix them.
Best regards,
Markus
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH 1/4] powerpc/powernv: Add OPAL check token call
From: Benjamin Herrenschmidt @ 2014-09-15 12:24 UTC (permalink / raw)
To: Michael Ellerman; +Cc: Stewart Smith, Michael Neuling, linuxppc-dev
In-Reply-To: <1410750623.24738.9.camel@concordia>
On Mon, 2014-09-15 at 13:10 +1000, Michael Ellerman wrote:
> > +enum OpalCheckTokenStatus {
> > + OPAL_TOKEN_ABSENT = 0,
> > + OPAL_TOKEN_PRESENT = 1
> > +};
>
> I don't see this used anywhere?
>
> And NoCamelCase !
>
> Yes I know there's lots in that file, but I didn't merge that :)
The original OPAL APIs were like that and I chose to not "fix" them
because I've been aiming at reconciling the Linux and the FW versions
of the file, which I haven't had a chance to do yet (Cyril & Sam have
some WIP in that area afaik).
We could de-camelify them both but I'd rather do the reunification
first.
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH] cpuidle/powernv: Enter fastsleep on checking if deep idle states are allowed
From: Benjamin Herrenschmidt @ 2014-09-15 12:23 UTC (permalink / raw)
To: Preeti U Murthy; +Cc: mikey, linux-pm, rjw, linux-kernel, linuxppc-dev
In-Reply-To: <5416A8B0.8040603@linux.vnet.ibm.com>
On Mon, 2014-09-15 at 14:22 +0530, Preeti U Murthy wrote:
> > We were talking about getting rid of powersave_nap altogether, but I
> think we
> > decided we couldn't, I forget.
>
> Isn't this a helpful knob to disable cpuidle at runtime? Currently we
> check the value of powersave_nap before entering both nap and
> fastsleep.
It's useful when diagnosing some problems that can be caused by idle
states.
Cheers,
Ben.
^ 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