* [PATCH] dmaengine: cleanup with list_first_entry_or_null()
From: Vinod Koul @ 2016-09-14 13:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473703697-903-1-git-send-email-yamada.masahiro@socionext.com>
On Tue, Sep 13, 2016 at 03:08:17AM +0900, Masahiro Yamada wrote:
> The combo of list_empty() check and return list_first_entry()
> can be replaced with list_first_entry_or_null().
Applied, thanks
In future please do split this per driver, that helps..
--
~Vinod
^ permalink raw reply
* [PATCH v5 2/9] drivers: irqchip: Add STM32 external interrupts support
From: Alexandre Torgue @ 2016-09-14 13:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.20.1609141532510.6233@nanos>
On 09/14/2016 03:34 PM, Thomas Gleixner wrote:
> On Wed, 14 Sep 2016, Alexandre Torgue wrote:
>> On 09/14/2016 11:19 AM, Thomas Gleixner wrote:
>>>
>>> Now what really bugs me is that you do that at all. An interrupt which is
>>> freed must be masked already. Why is it unmasked in the first place?
>>
>> Honestly I don't know. When "devm_free_irq" is called to release virq, there
>> is no issue and interrupt is well masked. But, when I tried to use
>> "irq_dispose_mapping(virq)" I observed that .free is called (child and parent
>> domain) but interrupt is not masked.
>
> Well, you just used some function in some context which is not relevant to
> the normal operation. So adding that mask() is just paranoia for no value.
I agree. I just wanted to "force" a test for .free callback. If it not
relevant I'll remove ".free" callback of exti domain.
As a part of this series has already been taken by Linus (pinctrl part),
I will send a new series only for irqchip part (patches [1] and [2]). Do
you agree ?
Thanks
Alex
>
> Thanks,
>
> tglx
>
^ permalink raw reply
* [PATCH 1/2 v3] bus: mvebu-mbus: Provide stub function for mvebu_mbus_get_io_win_info()
From: Vinod Koul @ 2016-09-14 13:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <8760pyd41s.fsf@free-electrons.com>
On Wed, Sep 14, 2016 at 03:06:07PM +0200, Gregory CLEMENT wrote:
> Hi,
>
> On lun., sept. 05 2016, Stefan Roese <sr@denx.de> wrote:
>
> > This patch provides a stub function for mvebu_mbus_get_io_win_info(),
> > which will be used for all non-Orion (ARM32 MVEBU) platforms for
> > compile test coverage.
> >
> > On such platforms this function will return an error so that drivers
> > might detect a potential problem.
>
> Acked-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
>
> Vinod, if you happy with the second patch of the series you can apply
> both patches on your tree. It will allow to keep the bisactibility, and
> as I didn't have any commit modifying these file in my trees it won't
> generate merge conflict.
Okay, somehow I dont see this in my queue. Can you guys pls resend.
Thanks
--
~Vinod
^ permalink raw reply
* [PATCH 0/2] minor cleanups for IORT patch set
From: Hanjun Guo @ 2016-09-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
From: Hanjun Guo <hanjun.guo@linaro.org>
Minor cleanup for IORT patches and no functional change,
based on Marc's irq/irqchip-4.9 branch
Hanjun Guo (2):
ACPI: IORT: minor cleanup for iort_match_node_callback()
irqchip: gic-v3-its: keep the head file include in alphabetic order
drivers/acpi/arm64/iort.c | 10 +++-------
drivers/irqchip/irq-gic-v3-its.c | 3 +--
2 files changed, 4 insertions(+), 9 deletions(-)
--
1.7.12.4
^ permalink raw reply
* [PATCH 1/2] ACPI: IORT: minor cleanup for iort_match_node_callback()
From: Hanjun Guo @ 2016-09-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473860994-3996-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
Cleanup iort_match_node_callback() a little bit to reduce
some lines of code, aslo fix the indentation in iort_scan_node().
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/acpi/arm64/iort.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 6b81746..2032005 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -132,7 +132,7 @@ static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
if (iort_node->type == type &&
ACPI_SUCCESS(callback(iort_node, context)))
- return iort_node;
+ return iort_node;
iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
iort_node->length);
@@ -145,17 +145,15 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
void *context)
{
struct device *dev = context;
- acpi_status status;
+ acpi_status status = AE_NOT_FOUND;
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
struct acpi_iort_named_component *ncomp;
- if (!adev) {
- status = AE_NOT_FOUND;
+ if (!adev)
goto out;
- }
status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
if (ACPI_FAILURE(status)) {
@@ -181,8 +179,6 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
*/
status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
AE_OK : AE_NOT_FOUND;
- } else {
- status = AE_NOT_FOUND;
}
out:
return status;
--
1.7.12.4
^ permalink raw reply related
* [PATCH 2/2] irqchip: gic-v3-its: keep the head file include in alphabetic order
From: Hanjun Guo @ 2016-09-14 13:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473860994-3996-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
The head file is strictly in alphabetic order now, so let's
not be the rule breaker.
And acpi_iort.h includes acpi.h, remove acpi.h here.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/irqchip/irq-gic-v3-its.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 35c851c..b1ff440 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -15,13 +15,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/acpi.h>
+#include <linux/acpi_iort.h>
#include <linux/bitmap.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
-#include <linux/acpi_iort.h>
#include <linux/log2.h>
#include <linux/mm.h>
#include <linux/msi.h>
--
1.7.12.4
^ permalink raw reply related
* [PATCH] coresight: tmc: Cleanup operation mode handling
From: Suzuki K Poulose @ 2016-09-14 13:53 UTC (permalink / raw)
To: linux-arm-kernel
The mode of operation of the TMC tracked in drvdata->mode is defined
as a local_t type. This is always checked and modified under the
drvdata->spinlock and hence we don't need local_t for it and the
unnecessary synchronisation instructions that comes with it. This
change makes the code a bit more cleaner.
Also fixes the order in which we update the drvdata->mode to
CS_MODE_DISABLED. i.e, in tmc_disable_etX_sink we change the
mode to CS_MODE_DISABLED before invoking tmc_disable_etX_hw()
which in turn depends on the mode to decide whether to dump the
trace to a buffer.
Applies on mathieu's coresight/next tree [1]
https://git.linaro.org/kernel/coresight.git next
Reported-by: Venkatesh Vivekanandan <venkatesh.vivekanandan@broadcom.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
---
drivers/hwtracing/coresight/coresight-tmc-etf.c | 32 +++++++++++--------------
drivers/hwtracing/coresight/coresight-tmc-etr.c | 30 ++++++++++-------------
drivers/hwtracing/coresight/coresight-tmc.h | 2 +-
3 files changed, 28 insertions(+), 36 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index d6941ea..c51ce45 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -70,7 +70,7 @@ static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
* When operating in sysFS mode the content of the buffer needs to be
* read before the TMC is disabled.
*/
- if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
tmc_etb_dump_hw(drvdata);
tmc_disable_hw(drvdata);
@@ -108,7 +108,6 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 mode)
int ret = 0;
bool used = false;
char *buf = NULL;
- long val;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -138,13 +137,12 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 mode)
goto out;
}
- val = local_xchg(&drvdata->mode, mode);
/*
* In sysFS mode we can have multiple writers per sink. Since this
* sink is already enabled no memory is needed and the HW need not be
* touched.
*/
- if (val == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
goto out;
/*
@@ -163,6 +161,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 mode)
drvdata->buf = buf;
}
+ drvdata->mode = CS_MODE_SYSFS;
tmc_etb_enable_hw(drvdata);
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -180,7 +179,6 @@ out:
static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, u32 mode)
{
int ret = 0;
- long val;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -194,17 +192,17 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, u32 mode)
goto out;
}
- val = local_xchg(&drvdata->mode, mode);
/*
* In Perf mode there can be only one writer per sink. There
* is also no need to continue if the ETB/ETR is already operated
* from sysFS.
*/
- if (val != CS_MODE_DISABLED) {
+ if (drvdata->mode != CS_MODE_DISABLED) {
ret = -EINVAL;
goto out;
}
+ drvdata->mode = mode;
tmc_etb_enable_hw(drvdata);
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -227,7 +225,6 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
static void tmc_disable_etf_sink(struct coresight_device *csdev)
{
- long val;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -237,10 +234,11 @@ static void tmc_disable_etf_sink(struct coresight_device *csdev)
return;
}
- val = local_xchg(&drvdata->mode, CS_MODE_DISABLED);
/* Disable the TMC only if it needs to */
- if (val != CS_MODE_DISABLED)
+ if (drvdata->mode != CS_MODE_DISABLED) {
tmc_etb_disable_hw(drvdata);
+ drvdata->mode = CS_MODE_DISABLED;
+ }
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -260,7 +258,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
}
tmc_etf_enable_hw(drvdata);
- local_set(&drvdata->mode, CS_MODE_SYSFS);
+ drvdata->mode = CS_MODE_SYSFS;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_info(drvdata->dev, "TMC-ETF enabled\n");
@@ -279,8 +277,8 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
return;
}
+ drvdata->mode = CS_MODE_DISABLED;
tmc_etf_disable_hw(drvdata);
- local_set(&drvdata->mode, CS_MODE_DISABLED);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_info(drvdata->dev, "TMC disabled\n");
@@ -383,7 +381,7 @@ static void tmc_update_etf_buffer(struct coresight_device *csdev,
return;
/* This shouldn't happen */
- if (WARN_ON_ONCE(local_read(&drvdata->mode) != CS_MODE_PERF))
+ if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF))
return;
CS_UNLOCK(drvdata->base);
@@ -504,7 +502,6 @@ const struct coresight_ops tmc_etf_cs_ops = {
int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
{
- long val;
enum tmc_mode mode;
int ret = 0;
unsigned long flags;
@@ -528,9 +525,8 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
goto out;
}
- val = local_read(&drvdata->mode);
/* Don't interfere if operated from Perf */
- if (val == CS_MODE_PERF) {
+ if (drvdata->mode == CS_MODE_PERF) {
ret = -EINVAL;
goto out;
}
@@ -542,7 +538,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
}
/* Disable the TMC if need be */
- if (val == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
tmc_etb_disable_hw(drvdata);
drvdata->reading = true;
@@ -573,7 +569,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
}
/* Re-enable the TMC if need be */
- if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
+ if (drvdata->mode == CS_MODE_SYSFS) {
/*
* The trace run will continue with the same allocated trace
* buffer. As such zero-out the buffer so that we don't end
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 886ea83..cf2bf60 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -86,7 +86,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
* When operating in sysFS mode the content of the buffer needs to be
* read before the TMC is disabled.
*/
- if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
tmc_etr_dump_hw(drvdata);
tmc_disable_hw(drvdata);
@@ -97,7 +97,6 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 mode)
{
int ret = 0;
bool used = false;
- long val;
unsigned long flags;
void __iomem *vaddr = NULL;
dma_addr_t paddr;
@@ -134,13 +133,12 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 mode)
goto out;
}
- val = local_xchg(&drvdata->mode, mode);
/*
* In sysFS mode we can have multiple writers per sink. Since this
* sink is already enabled no memory is needed and the HW need not be
* touched.
*/
- if (val == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
goto out;
/*
@@ -157,6 +155,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 mode)
memset(drvdata->vaddr, 0, drvdata->size);
+ drvdata->mode = CS_MODE_SYSFS;
tmc_etr_enable_hw(drvdata);
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -174,7 +173,6 @@ out:
static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, u32 mode)
{
int ret = 0;
- long val;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -188,18 +186,18 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, u32 mode)
goto out;
}
- val = local_xchg(&drvdata->mode, mode);
/*
* In Perf mode there can be only one writer per sink. There
* is also no need to continue if the ETR is already operated
* from sysFS.
*/
- if (val != CS_MODE_DISABLED) {
+ if (drvdata->mode == CS_MODE_DISABLED) {
+ drvdata->mode = CS_MODE_PERF;
+ tmc_etr_enable_hw(drvdata);
+ } else {
ret = -EINVAL;
- goto out;
}
- tmc_etr_enable_hw(drvdata);
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -221,7 +219,6 @@ static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
static void tmc_disable_etr_sink(struct coresight_device *csdev)
{
- long val;
unsigned long flags;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -231,10 +228,11 @@ static void tmc_disable_etr_sink(struct coresight_device *csdev)
return;
}
- val = local_xchg(&drvdata->mode, CS_MODE_DISABLED);
/* Disable the TMC only if it needs to */
- if (val != CS_MODE_DISABLED)
+ if (drvdata->mode != CS_MODE_DISABLED) {
tmc_etr_disable_hw(drvdata);
+ drvdata->mode = CS_MODE_DISABLED;
+ }
spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -253,7 +251,6 @@ const struct coresight_ops tmc_etr_cs_ops = {
int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
{
int ret = 0;
- long val;
unsigned long flags;
/* config types are set a boot time and never change */
@@ -266,9 +263,8 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
goto out;
}
- val = local_read(&drvdata->mode);
/* Don't interfere if operated from Perf */
- if (val == CS_MODE_PERF) {
+ if (drvdata->mode == CS_MODE_PERF) {
ret = -EINVAL;
goto out;
}
@@ -280,7 +276,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
}
/* Disable the TMC if need be */
- if (val == CS_MODE_SYSFS)
+ if (drvdata->mode == CS_MODE_SYSFS)
tmc_etr_disable_hw(drvdata);
drvdata->reading = true;
@@ -303,7 +299,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
spin_lock_irqsave(&drvdata->spinlock, flags);
/* RE-enable the TMC if need be */
- if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
+ if (drvdata->mode == CS_MODE_SYSFS) {
/*
* The trace run will continue with the same allocated trace
* buffer. The trace buffer is cleared in tmc_etr_enable_hw(),
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 44b3ae3..51c0185 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -117,7 +117,7 @@ struct tmc_drvdata {
void __iomem *vaddr;
u32 size;
u32 len;
- local_t mode;
+ u32 mode;
enum tmc_config_type config_type;
enum tmc_mem_intf_width memwidth;
u32 trigger_cntr;
--
2.7.4
^ permalink raw reply related
* [RFC PATCH 9/9] ethernet: sun8i-emac: add pm_runtime support
From: LABBE Corentin @ 2016-09-14 14:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160912204451.GO9449@lukather>
On Mon, Sep 12, 2016 at 10:44:51PM +0200, Maxime Ripard wrote:
> Hi,
>
> On Fri, Sep 09, 2016 at 02:45:17PM +0200, Corentin Labbe wrote:
> > This patch add pm_runtime support to sun8i-emac.
> > For the moment, only basic support is added, (the device is marked as
> > used when net/open)
> >
> > Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
> > ---
> > drivers/net/ethernet/allwinner/sun8i-emac.c | 62 ++++++++++++++++++++++++++++-
> > 1 file changed, 60 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/allwinner/sun8i-emac.c b/drivers/net/ethernet/allwinner/sun8i-emac.c
> > index 1c4bc80..cce886e 100644
> > --- a/drivers/net/ethernet/allwinner/sun8i-emac.c
> > +++ b/drivers/net/ethernet/allwinner/sun8i-emac.c
> > @@ -9,7 +9,6 @@
> > * - MAC filtering
> > * - Jumbo frame
> > * - features rx-all (NETIF_F_RXALL_BIT)
> > - * - PM runtime
> > */
> > #include <linux/bitops.h>
> > #include <linux/clk.h>
> > @@ -27,6 +26,7 @@
> > #include <linux/pinctrl/consumer.h>
> > #include <linux/pinctrl/pinctrl.h>
> > #include <linux/platform_device.h>
> > +#include <linux/pm_runtime.h>
> > #include <linux/reset.h>
> > #include <linux/scatterlist.h>
> > #include <linux/skbuff.h>
> > @@ -1301,11 +1301,18 @@ static int sun8i_emac_open(struct net_device *ndev)
> > int err;
> > u32 v;
> >
> > + err = pm_runtime_get_sync(priv->dev);
> > + if (err) {
> > + pm_runtime_put_noidle(priv->dev);
> > + dev_err(priv->dev, "pm_runtime error: %d\n", err);
> > + return err;
> > + }
> > +
> > err = request_irq(priv->irq, sun8i_emac_dma_interrupt, 0,
> > dev_name(priv->dev), ndev);
> > if (err) {
> > dev_err(priv->dev, "Cannot request IRQ: %d\n", err);
> > - return err;
> > + goto err_runtime;
> > }
> >
> > /* Set interface mode (and configure internal PHY on H3) */
> > @@ -1395,6 +1402,8 @@ err_syscon:
> > sun8i_emac_unset_syscon(ndev);
> > err_irq:
> > free_irq(priv->irq, ndev);
> > +err_runtime:
> > + pm_runtime_put(priv->dev);
> > return err;
> > }
> >
> > @@ -1483,6 +1492,8 @@ static int sun8i_emac_stop(struct net_device *ndev)
> > dma_free_coherent(priv->dev, priv->nbdesc_tx * sizeof(struct dma_desc),
> > priv->dd_tx, priv->dd_tx_phy);
> >
> > + pm_runtime_put(priv->dev);
> > +
> > return 0;
> > }
> >
> > @@ -2210,6 +2221,8 @@ static int sun8i_emac_probe(struct platform_device *pdev)
> > goto probe_err;
> > }
> >
> > + pm_runtime_enable(priv->dev);
> > +
> > return 0;
> >
> > probe_err:
> > @@ -2221,6 +2234,8 @@ static int sun8i_emac_remove(struct platform_device *pdev)
> > {
> > struct net_device *ndev = platform_get_drvdata(pdev);
> >
> > + pm_runtime_disable(&pdev->dev);
> > +
> > unregister_netdev(ndev);
> > platform_set_drvdata(pdev, NULL);
> > free_netdev(ndev);
> > @@ -2228,6 +2243,47 @@ static int sun8i_emac_remove(struct platform_device *pdev)
> > return 0;
> > }
> >
> > +static int __maybe_unused sun8i_emac_suspend(struct platform_device *pdev, pm_message_t state)
> > +{
> > + struct net_device *ndev = platform_get_drvdata(pdev);
> > + struct sun8i_emac_priv *priv = netdev_priv(ndev);
> > +
> > + napi_disable(&priv->napi);
> > +
> > + if (netif_running(ndev))
> > + netif_device_detach(ndev);
> > +
> > + sun8i_emac_stop_tx(ndev);
> > + sun8i_emac_stop_rx(ndev);
> > +
> > + sun8i_emac_rx_clean(ndev);
> > + sun8i_emac_tx_clean(ndev);
> > +
> > + phy_stop(ndev->phydev);
> > +
> > + return 0;
> > +}
> > +
> > +static int __maybe_unused sun8i_emac_resume(struct platform_device *pdev)
> > +{
> > + struct net_device *ndev = platform_get_drvdata(pdev);
> > + struct sun8i_emac_priv *priv = netdev_priv(ndev);
> > +
> > + phy_start(ndev->phydev);
> > +
> > + sun8i_emac_start_tx(ndev);
> > + sun8i_emac_start_rx(ndev);
> > +
> > + if (netif_running(ndev))
> > + netif_device_attach(ndev);
> > +
> > + netif_start_queue(ndev);
> > +
> > + napi_enable(&priv->napi);
> > +
> > + return 0;
> > +}
>
> The main idea behind the runtime PM hooks is that they bring the
> device to a working state and shuts it down when it's not needed
> anymore.
>
I expect that the first part (all pm_runtime_xxx) of the patch bring that.
When the interface is not opened:
cat /sys/devices/platform/soc/1c30000.ethernet/power/runtime_status
suspended
> However, they shouldn't be called when the device is still in used, so
> all the mangling with NAPI, the phy and so on is irrelevant here, but
> the clocks, resets, for example, are.
>
I do the same as other ethernet driver for suspend/resume.
> > static const struct of_device_id sun8i_emac_of_match_table[] = {
> > { .compatible = "allwinner,sun8i-a83t-emac",
> > .data = &emac_variant_a83t },
> > @@ -2246,6 +2302,8 @@ static struct platform_driver sun8i_emac_driver = {
> > .name = "sun8i-emac",
> > .of_match_table = sun8i_emac_of_match_table,
> > },
> > + .suspend = sun8i_emac_suspend,
> > + .resume = sun8i_emac_resume,
>
> These are not the runtime PM hooks. How did you test that?
>
Anyway I didnt test suspend/resume so I will remove it until I successfully found how to hibernate my board.
Thanks
Regards
Corentin Labbe
^ permalink raw reply
* [PATCH 00/19] [RESEND] Remove STiH415 and STiH416 SoC platform support
From: Patrice Chotard @ 2016-09-14 14:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <7524458.uFhxDUCqEo@wuerfel>
Hi Peter, Arnd
On 09/14/2016 03:38 PM, Arnd Bergmann wrote:
> On Wednesday, September 14, 2016 2:27:38 PM CEST Peter Griffin wrote:
>> Resending due to incorrect Cc tags.
>>
>> ST have sent patches which remove clock support for these SoCs [1]
>> which once applied mean the platform will no longer boot.
>>
>> This series cleans up various STi platform drivers which have
>> support for these SoC's, by removing code, and updating the DT
>> documentation accordingly. Some drivers such as miphy365 and
>> stih41x-usb can be removed completely because the IP is only
>> found on these legacy SoC's.
>>
>> Once this series is applied, drm display driver, and ALSA SoC
>> are the main two remaining references to the legacy SoCs, other
>> than clocks which already have patches on the ML.
>
> It would be good to have a better explanation that "it's already
> broken by some other commit". Is this a platform that never shipped
> to end-users, or is it possible that someone out there actually
> has a machine with one of these SoCs?
This series is prematured as today STiH415/416 is not broken by any commit.
This series is depending on the merge of a ST's clock series not yet upstreamed.
(see https://patchwork.kernel.org/patch/9157571/)
STMicroelectronics expect to remove STiH415/416 in a near future from upstream kernel.
Patrice
>
> Arnd
>
^ permalink raw reply
* [PATCH V3 2/4] ARM64 LPC: LPC driver implementation on Hip06
From: kbuild test robot @ 2016-09-14 14:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473855354-150093-3-git-send-email-yuanzhichang@hisilicon.com>
Hi zhichang.yuan,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.8-rc6 next-20160914]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]
url: https://github.com/0day-ci/linux/commits/Zhichang-Yuan/ARM64-LPC-legacy-ISA-I-O-support/20160914-202858
config: openrisc-or1ksim_defconfig (attached as .config)
compiler: or32-linux-gcc (GCC) 4.5.1-or32-1.0rc1
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=openrisc
All errors (new ones prefixed by >>):
drivers/of/address.c: In function '__of_address_to_resource':
>> drivers/of/address.c:702:5: error: implicit declaration of function 'of_bus_pci_match'
vim +/of_bus_pci_match +702 drivers/of/address.c
696 return -EINVAL;
697 /*
698 * special processing for non-pci device gurantee the linux start pio
699 * is not ZERO. Otherwise, some drivers' initialization will fail.
700 */
701 if (!port && (!IS_ENABLED(CONFIG_OF_ADDRESS_PCI) ||
> 702 !of_bus_pci_match(dev)))
703 port += 1;
704
705 r->start = port;
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/octet-stream
Size: 7187 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160914/6b1ff665/attachment.obj>
^ permalink raw reply
* [PATCH V3 1/4] ARM64 LPC: Indirect ISA port IO introduced
From: zhichang.yuan @ 2016-09-14 14:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <8337589.pzGt0MZ9xn@wuerfel>
Hi, Arnd
On 2016/9/14 20:24, Arnd Bergmann wrote:
> On Wednesday, September 14, 2016 8:15:51 PM CEST Zhichang Yuan wrote:
>> From: "zhichang.yuan" <yuanzhichang@hisilicon.com>
>>
>> For arm64, there is no I/O space as other architectural platforms, such as
>> X86. Most I/O accesses are achieved based on MMIO. But for some arm64 SoCs,
>> such as Hip06, when accessing some legacy ISA devices connected to LPC, those
>> known port addresses are used to control the corresponding target devices, for
>> example, 0x2f8 is for UART, 0xe4 is for ipmi-bt. It is different from the
>> normal MMIO mode in using.
>>
>> To drive these devices, this patch introduces a method named indirect-IO.
>> In this method the in/out pair in arch/arm64/include/asm/io.h will be
>> redefined. When upper layer drivers call in/out with those known legacy port
>> addresses to access the peripherals, the hooking functions corrresponding to
>> those target peripherals will be called. Through this way, those upper layer
>> drivers which depend on in/out can run on Hip06 without any changes.
>>
>> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
>
> Looks ok overall, but I have a couple of comments for details.
>
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index bc3f00f..9579479 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -161,6 +161,12 @@ config ARCH_MMAP_RND_COMPAT_BITS_MIN
>> config ARCH_MMAP_RND_COMPAT_BITS_MAX
>> default 16
>>
>> +config ARM64_INDIRECT_PIO
>> + def_bool n
>
> 'def_bool n' is the same as the shorter and more common 'bool'.
Yes. Will modify as bool "access peripherals with legacy I/O port"
>
>> diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
>> index 9b6e408..d3acf1f 100644
>> --- a/arch/arm64/include/asm/io.h
>> +++ b/arch/arm64/include/asm/io.h
>> @@ -34,6 +34,10 @@
>>
>> #include <xen/xen.h>
>>
>> +#ifdef CONFIG_ARM64_INDIRECT_PIO
>> +#include <linux/extio.h>
>> +#endif
>
> No need to guard includes with an #ifdef.
If remove #ifdef here, extio.h should not contain any function external declarations whose definitions are in
extio.c compiled only when CONFIG_ARM64_INDIRECT_PIO is yes.
How about removing everything about the configure item "ARM64_INDIRECT_PIO"?
This will make the indirect-IO mechanism global on ARM64.
I worry about this mechanism is not so common, so using "ARM64_INDIRECT_PIO" make this feature optional.
>
>> +#define BUILDS_RW(bwl, type) \
>> +static inline void reads##bwl(const volatile void __iomem *addr, \
>> + void *buffer, unsigned int count) \
>> +{ \
>> + if (count) { \
>> + type *buf = buffer; \
>> + \
>> + do { \
>> + type x = __raw_read##bwl(addr); \
>> + *buf++ = x; \
>> + } while (--count); \
>> + } \
>> +} \
>> + \
>> +static inline void writes##bwl(volatile void __iomem *addr, \
>> + const void *buffer, unsigned int count) \
>> +{ \
>> + if (count) { \
>> + const type *buf = buffer; \
>> + \
>> + do { \
>> + __raw_write##bwl(*buf++, addr); \
>> + } while (--count); \
>> + } \
>> +}
>> +
>> +BUILDS_RW(b, u8)
>
> Why is this in here?
the readsb/writesb are defined in asm-generic/io.h which is included later, but the redefined insb/outsb need
to call them. Without these readsb/writesb definition before insb/outsb redefined, compile error occur.
It seems that copy all the definitions of "asm-generic/io.h" is not a good idea, so I move the definitions of
those function needed here....
Ok. I think your idea below defining in(s)/out(s) in a c file can solve this issue.
#ifdef CONFIG_ARM64_INDIRECT_PIO
#define inb inb
extern u8 inb(unsigned long addr);
#define outb outb
extern void outb(u8 value, unsigned long addr);
#define insb insb
extern void insb(unsigned long addr, void *buffer, unsigned int count);
#define outsb outsb
extern void outsb(unsigned long addr, const void *buffer, unsigned int count);
#endif
and definitions of all these functions are in extio.c :
u8 inb(unsigned long addr)
{
if (!arm64_extio_ops || arm64_extio_ops->start > addr ||
arm64_extio_ops->end < addr)
return readb(PCI_IOBASE + addr);
else
return arm64_extio_ops->pfin ?
arm64_extio_ops->pfin(arm64_extio_ops->devpara,
addr + arm64_extio_ops->ptoffset, NULL,
sizeof(u8), 1) : -1;
}
.....
>
>> @@ -149,6 +185,60 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
>> #define IO_SPACE_LIMIT (PCI_IO_SIZE - 1)
>> #define PCI_IOBASE ((void __iomem *)PCI_IO_START)
>>
>> +
>> +/*
>> + * redefine the in(s)b/out(s)b for indirect-IO.
>> + */
>> +#define inb inb
>> +static inline u8 inb(unsigned long addr)
>> +{
>> +#ifdef CONFIG_ARM64_INDIRECT_PIO
>> + if (arm64_extio_ops && arm64_extio_ops->start <= addr &&
>> + addr <= arm64_extio_ops->end)
>> + return extio_inb(addr);
>> +#endif
>> + return readb(PCI_IOBASE + addr);
>> +}
>> +
>
> Looks ok, but you only seem to do this for the 8-bit
> accessors, when it should be done for 16-bit and 32-bit
> ones as well for consistency.
Hip06 LPC only support 8-bit I/O operations on the designated port.
>
>> diff --git a/drivers/bus/extio.c b/drivers/bus/extio.c
>> new file mode 100644
>> index 0000000..1e7a9c5
>> --- /dev/null
>> +++ b/drivers/bus/extio.c
>> @@ -0,0 +1,66 @@
>
> This is in a globally visible directory
>
>> +
>> +struct extio_ops *arm64_extio_ops;
>
> But the identifier uses an architecture specific prefix. Either
> move the whole file into arch/arm64, or make the naming so that
> it can be used for everything.
I perfer to move the whole file into arch/arm64, extio.h will be moved to arch/arm64/include/asm;
>
>> +u8 __weak extio_inb(unsigned long addr)
>> +{
>> + return arm64_extio_ops->pfin ?
>> + arm64_extio_ops->pfin(arm64_extio_ops->devpara,
>> + addr + arm64_extio_ops->ptoffset, NULL,
>> + sizeof(u8), 1) : -1;
>> +}
>
> No need for the __weak attribute, just make sure that the
> code is always built-in when needed.
>
> Also, it doesn't seem necessary to have an extern function if
> all it does is call the one callback that you have already
> checked earlier. Either put it all into the inline
> definition in asm/io.h, or put it all into the extern
> version like this.
>
> #ifdef CONFIG_ARM64_INDIRECT_PIO /* otherwise use default from asm-generic */
> #define inb inb
> extern u8 inb(unsigned long addr);
> #endif
>
Yes. This is good!
Although the in(s)/out(s) are not inline anymore.
I had applied this way above.
> u8 inb(unsigned long addr)
> {
> if (arm64_extio_ops && arm64_extio_ops->start <= addr &&
> addr <= arm64_extio_ops->end)
> arm64_extio_ops->pfin(arm64_extio_ops->devpara,addr + arm64_extio_ops->ptoffset, NULL,sizeof(u8), 1) : -1;
> return extio_inb(addr);
> }
>
>> +#define inb inb
>> +static inline u8 inb(unsigned long addr)
>> +{
>> +#ifdef CONFIG_ARM64_INDIRECT_PIO
>> + if (arm64_extio_ops && arm64_extio_ops->start <= addr &&
>> + addr <= arm64_extio_ops->end)
>> + return extio_inb(addr);
>> +#endif
>> + return readb(PCI_IOBASE + addr);
>> +}
>
>> diff --git a/include/linux/extio.h b/include/linux/extio.h
>> new file mode 100644
>> index 0000000..08d1fca
>> --- /dev/null
>> +++ b/include/linux/extio.h
>> @@ -0,0 +1,49 @@
>> +/*
>> + * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
>> + * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
>> + * Author: Zou Rongrong <@huawei.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#ifndef __LINUX_EXTIO_H
>> +#define __LINUX_EXTIO_H
>> +
>> +
>> +typedef u64 (*inhook)(void *devobj, unsigned long ptaddr, void *inbuf,
>> + size_t dlen, unsigned int count);
>> +typedef void (*outhook)(void *devobj, unsigned long ptaddr,
>> + const void *outbuf, size_t dlen,
>> + unsigned int count);
>
> I would drop the typedef and just declare the types directly in the
> only place that references them.
>
Ok. Will apply it.
Thanks!
Zhichang
> Arnd
>
> .
>
^ permalink raw reply
* [RFC PATCH v2 00/11] ACPI platform MSI, interrupt producer/consumer and its example mbi-gen
From: Hanjun Guo @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
From: Hanjun Guo <hanjun.guo@linaro.org>
With platform msi support landed in the kernel, and the introduction
of IORT for GICv3 ITS (PCI MSI) [1], the framework for platform msi
is ready, this patch set add few patches to enable the ACPI platform
msi support.
For platform device connecting to ITS on arm platform, we have IORT
table with the named componant node to describe the mappings of paltform
device and ITS, so we can retrieve the dev id and find its parent
irqdomain (ITS) from IORT table (simlar with the ACPI ITS support).
With acpi platform msi supported, we add the ACPI support for irqchip
mbi-gen, which use this framework to form its stacked irqdomain, below
is the mbi-gen's topology in the system:
| ---------------| |------------------|
| | MSI | | wired interrupt(s)
| ITS |<-----------------| MBI-GEN |<----------------------------- IO device(s)
| | | |<----------------------------- IO device(s)
------------------ -------------------
So with ACPI platform MSI support, we can build the stacked domain for
mbi-gen which represented its mappings with the named componant in IORT,
but we still missing the connectings of devices to mbi-gen as in ACPI
world devices connect to main interrupt controller in MADT in default.
In ACPI 6.1, section 19.6.62, Interrupt Resource Descriptor Macro,
Interrupt (ResourceUsage, EdgeLevel, ActiveLevel, Shared,
ResourceSourceIndex, ResourceSource, DescriptorName)
{ InterruptList } => Buffer
For the arguement ResourceUsage and DescriptorName, which means:
ResourceUsage describes whether the device consumes the specified
interrupt ( ResourceConsumer ) or produces it for use by a child
device ( ResourceProducer ).
If nothing is specified, then ResourceConsumer is assumed.
DescriptorName evaluates to a name string which refers to the
entire resource descriptor.
So it can be used for devices connecting to a specific interrupt
prodcucer instead of the main interrupt controller in MADT, we can
define:
Interrupt(ResourceConsumer,..., "\_SB.IRQP") {12,14,....},
then get the interrupt producer with the full path name "\_SB.IRQP".
v2:
- Fix the bug of if multi Interrupt() resoures in single _PRS,
we need to calculate all the irq numbers (I missed it in previous
version);
- Rebased on Marc's irq/irqchip-4.9 branch and Lorenzo's v5
SMMu patches (also Robin's SMMu patches)
- Add patch irqchip: mbigen: promote mbigen init.
This is the RFC version 2 and we still needs to address:
- we need to deal with the device topology as:
NC (named componant) -> SMMU -> ITS.
Comments are warmly welcomed!
Thanks
Hanjun
Hanjun Guo (9):
irqchip: gicv3-its: platform-msi: refactor its_pmsi_prepare()
ACPI: platform-msi: retrieve dev id from IORT
irqchip: gicv3-its: platform-msi: refactor its_pmsi_init() to prepare
for ACPI
irqchip: gicv3-its: platform-msi: scan MADT to create platform msi
domain
ACPI: platform: setup MSI domain for ACPI based platform device
msi: platform: make platform_msi_create_device_domain() ACPI aware
ACPI: irq: introduce interrupt producer
irqchip: mbigen: Add ACPI support
irqchip: mbigen: promote mbigen init
Kefeng Wang (2):
irqchip: mbigen: drop module owner
irqchip: mbigen: introduce mbigen_of_create_domain()
drivers/acpi/arm64/iort.c | 31 ++++++-
drivers/acpi/gsi.c | 10 ++-
drivers/acpi/resource.c | 85 +++++++++++++------
drivers/base/platform-msi.c | 20 ++++-
drivers/base/platform.c | 2 +
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 107 ++++++++++++++++++------
drivers/irqchip/irq-mbigen.c | 115 ++++++++++++++++++++++----
include/acpi/acpi_bus.h | 1 +
include/linux/acpi_iort.h | 8 ++
include/linux/msi.h | 1 +
10 files changed, 305 insertions(+), 75 deletions(-)
--
1.7.12.4
^ permalink raw reply
* [RFC PATCH v2 01/11] irqchip: gicv3-its: platform-msi: refactor its_pmsi_prepare()
From: Hanjun Guo @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473862879-7769-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
Adding ACPI support for platform MSI, we need to retrieve the
dev id in ACPI way instead of device tree, we already have
a well formed function its_pmsi_prepare() to get the dev id
but it's OF dependent, so collect OF related code and put them
into a single function to make its_pmsi_prepare() more friendly
to ACPI later.
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index 470b4aa..3c94278 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -24,15 +24,11 @@ static struct irq_chip its_pmsi_irq_chip = {
.name = "ITS-pMSI",
};
-static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
- int nvec, msi_alloc_info_t *info)
+static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev,
+ u32 *dev_id)
{
- struct msi_domain_info *msi_info;
- u32 dev_id;
int ret, index = 0;
- msi_info = msi_get_domain_info(domain->parent);
-
/* Suck the DeviceID out of the msi-parent property */
do {
struct of_phandle_args args;
@@ -43,11 +39,24 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
if (args.np == irq_domain_get_of_node(domain)) {
if (WARN_ON(args.args_count != 1))
return -EINVAL;
- dev_id = args.args[0];
+ *dev_id = args.args[0];
break;
}
} while (!ret);
+ return ret;
+}
+
+static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
+ int nvec, msi_alloc_info_t *info)
+{
+ struct msi_domain_info *msi_info;
+ u32 dev_id;
+ int ret;
+
+ msi_info = msi_get_domain_info(domain->parent);
+
+ ret = of_pmsi_get_dev_id(domain, dev, &dev_id);
if (ret)
return ret;
--
1.7.12.4
^ permalink raw reply related
* [RFC PATCH v2 02/11] ACPI: platform-msi: retrieve dev id from IORT
From: Hanjun Guo @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473862879-7769-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
For devices connecting to ITS, it needs dev id to identify
itself, and this dev id is represented in the IORT table in
named componant node [1] for platform devices, so in this
patch we will scan the IORT to retrieve device's dev id.
Introduce iort_pmsi_get_dev_id() with pointer dev passed
in for that purpose.
[1]: https://static.docs.arm.com/den0049/b/DEN0049B_IO_Remapping_Table.pdf
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/acpi/arm64/iort.c | 26 ++++++++++++++++++++++++++
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 4 +++-
include/linux/acpi_iort.h | 8 ++++++++
3 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index cee82d4..13a1905 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -408,6 +408,32 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
}
/**
+ * iort_pmsi_get_dev_id() - Get the device id for a device
+ * @dev: The device for which the mapping is to be done.
+ * @dev_id: The device ID found.
+ *
+ * Returns: 0 for successful find a dev id, errors otherwise
+ */
+int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
+{
+ struct acpi_iort_node *node;
+
+ if (!iort_table)
+ return -ENODEV;
+
+ node = iort_find_dev_node(dev);
+ if (!node) {
+ dev_err(dev, "can't find related IORT node\n");
+ return -ENODEV;
+ }
+
+ if( !iort_node_get_id(node, dev_id, IORT_MSI_TYPE, 0))
+ return -ENODEV;
+
+ return 0;
+}
+
+/**
* iort_dev_find_its_id() - Find the ITS identifier for a device
* @dev: The device.
* @idx: Index of the ITS identifier list.
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index 3c94278..3646c23 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -16,6 +16,7 @@
*/
#include <linux/device.h>
+#include <linux/acpi_iort.h>
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/of_irq.h>
@@ -56,7 +57,8 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
msi_info = msi_get_domain_info(domain->parent);
- ret = of_pmsi_get_dev_id(domain, dev, &dev_id);
+ ret = dev->of_node ? of_pmsi_get_dev_id(domain, dev, &dev_id) :
+ iort_pmsi_get_dev_id(dev, &dev_id);
if (ret)
return ret;
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 167649a..bfaf75f 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -32,6 +32,7 @@ struct fwnode_handle *iort_find_domain_token(int trans_id);
#ifdef CONFIG_ACPI_IORT
void acpi_iort_init(void);
u32 iort_msi_map_rid(struct device *dev, u32 req_id);
+int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id);
struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id);
int iort_set_fwnode(struct acpi_iort_node *iort_node,
struct fwnode_handle *fwnode);
@@ -42,9 +43,16 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev);
static inline void acpi_iort_init(void) { }
static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
{ return req_id; }
+
static inline struct irq_domain *iort_get_device_domain(struct device *dev,
u32 req_id)
{ return NULL; }
+
+static inline int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
+{
+ return -ENODEV;
+}
+
static inline int iort_set_fwnode(struct acpi_iort_node *iort_node,
struct fwnode_handle *fwnode)
{ return -ENODEV; }
--
1.7.12.4
^ permalink raw reply related
* [RFC PATCH v2 03/11] irqchip: gicv3-its: platform-msi: refactor its_pmsi_init() to prepare for ACPI
From: Hanjun Guo @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473862879-7769-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
Introduce its_pmsi_init_one() to refactor the code to isolate
ACPI&DT common code to prepare for ACPI later.
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 45 ++++++++++++++++-----------
1 file changed, 27 insertions(+), 18 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index 3646c23..a80ecd7 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -84,34 +84,43 @@ static struct of_device_id its_device_id[] = {
{},
};
-static int __init its_pmsi_init(void)
+static int __init its_pmsi_init_one(struct fwnode_handle *fwnode,
+ const char *name)
{
- struct device_node *np;
struct irq_domain *parent;
+ parent = irq_find_matching_fwnode(fwnode, DOMAIN_BUS_NEXUS);
+ if (!parent || !msi_get_domain_info(parent)) {
+ pr_err("%s: unable to locate ITS domain\n", name);
+ return -ENXIO;
+ }
+
+ if (!platform_msi_create_irq_domain(fwnode, &its_pmsi_domain_info,
+ parent)) {
+ pr_err("%s: unable to create platform domain\n", name);
+ return -ENXIO;
+ }
+
+ pr_info("Platform MSI: %s domain created\n", name);
+ return 0;
+}
+
+static void __init its_pmsi_of_init(void)
+{
+ struct device_node *np;
+
for (np = of_find_matching_node(NULL, its_device_id); np;
np = of_find_matching_node(np, its_device_id)) {
if (!of_property_read_bool(np, "msi-controller"))
continue;
- parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS);
- if (!parent || !msi_get_domain_info(parent)) {
- pr_err("%s: unable to locate ITS domain\n",
- np->full_name);
- continue;
- }
-
- if (!platform_msi_create_irq_domain(of_node_to_fwnode(np),
- &its_pmsi_domain_info,
- parent)) {
- pr_err("%s: unable to create platform domain\n",
- np->full_name);
- continue;
- }
-
- pr_info("Platform MSI: %s domain created\n", np->full_name);
+ its_pmsi_init_one(of_node_to_fwnode(np), np->full_name);
}
+}
+static int __init its_pmsi_init(void)
+{
+ its_pmsi_of_init();
return 0;
}
early_initcall(its_pmsi_init);
--
1.7.12.4
^ permalink raw reply related
* [RFC PATCH v2 04/11] irqchip: gicv3-its: platform-msi: scan MADT to create platform msi domain
From: Hanjun Guo @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473862879-7769-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
With the introduction of its_pmsi_init_one(), we can add some code
on top for ACPI support of platform MSI.
We are scanning the MADT table to get the ITS entry(ies), then use
the information to create the platform msi domain for devices connect
to it, just like the PCI MSI for ITS did.
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/irqchip/irq-gic-v3-its-platform-msi.c | 37 +++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
index a80ecd7..e9dade9 100644
--- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/acpi_iort.h>
#include <linux/msi.h>
@@ -105,6 +106,41 @@ static int __init its_pmsi_init_one(struct fwnode_handle *fwnode,
return 0;
}
+#ifdef CONFIG_ACPI
+static int __init
+its_pmsi_parse_madt(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_translator *its_entry;
+ struct fwnode_handle *domain_handle;
+ const char *node_name;
+ int err = -ENXIO;
+
+ its_entry = (struct acpi_madt_generic_translator *)header;
+ node_name = kasprintf(GFP_KERNEL, "ITS at 0x%lx",
+ (long)its_entry->base_address);
+ domain_handle = iort_find_domain_token(its_entry->translation_id);
+ if (!domain_handle) {
+ pr_err("%s: Unable to locate ITS domain handle\n", node_name);
+ goto out;
+ }
+
+ err = its_pmsi_init_one(domain_handle, node_name);
+
+out:
+ kfree(node_name);
+ return err;
+}
+
+static void __init its_acpi_pmsi_init(void)
+{
+ acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+ its_pmsi_parse_madt, 0);
+}
+#else
+static inline void its_acpi_pmsi_init(void) { }
+#endif
+
static void __init its_pmsi_of_init(void)
{
struct device_node *np;
@@ -121,6 +157,7 @@ static void __init its_pmsi_of_init(void)
static int __init its_pmsi_init(void)
{
its_pmsi_of_init();
+ its_acpi_pmsi_init();
return 0;
}
early_initcall(its_pmsi_init);
--
1.7.12.4
^ permalink raw reply related
* [RFC PATCH v2 05/11] ACPI: platform: setup MSI domain for ACPI based platform device
From: Hanjun Guo @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473862879-7769-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
With the platform msi domain created, we can set up the msi domain
for a platform device when it's probed.
This patch introduces acpi_configure_msi_domain(), which retrieves
the domain from iort and set it to platform device.
As some platform devices such as an irqchip needs the msi irqdomain
to be the interrupt parent domain, we need to get irqdomain before
platform device is probed.
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Tomasz Nowicki <tn@semihalf.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/acpi/arm64/iort.c | 5 ++++-
drivers/base/platform-msi.c | 15 ++++++++++++++-
drivers/base/platform.c | 2 ++
include/linux/msi.h | 1 +
4 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 13a1905..bccd3cc 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -478,6 +478,7 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
{
struct fwnode_handle *handle;
int its_id;
+ enum irq_domain_bus_token bus_token;
if (iort_dev_find_its_id(dev, req_id, 0, &its_id))
return NULL;
@@ -486,7 +487,9 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
if (!handle)
return NULL;
- return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
+ bus_token = dev_is_pci(dev) ?
+ DOMAIN_BUS_PCI_MSI : DOMAIN_BUS_PLATFORM_MSI;
+ return irq_find_matching_fwnode(handle, bus_token);
}
static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c
index 279e539..f6eae18 100644
--- a/drivers/base/platform-msi.c
+++ b/drivers/base/platform-msi.c
@@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi_iort.h>
#include <linux/device.h>
-#include <linux/idr.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/msi.h>
@@ -416,3 +416,16 @@ int platform_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
return err;
}
+
+int acpi_configure_msi_domain(struct device *dev)
+{
+ struct irq_domain *d = NULL;
+
+ d = iort_get_device_domain(dev, 0);
+ if (d) {
+ dev_set_msi_domain(dev, d);
+ return 0;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 6482d47..ea01a37 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -24,6 +24,7 @@
#include <linux/pm_domain.h>
#include <linux/idr.h>
#include <linux/acpi.h>
+#include <linux/msi.h>
#include <linux/clk/clk-conf.h>
#include <linux/limits.h>
#include <linux/property.h>
@@ -500,6 +501,7 @@ struct platform_device *platform_device_register_full(
pdev->dev.parent = pdevinfo->parent;
pdev->dev.fwnode = pdevinfo->fwnode;
+ acpi_configure_msi_domain(&pdev->dev);
if (pdevinfo->dma_mask) {
/*
* This memory isn't freed when the device is put,
diff --git a/include/linux/msi.h b/include/linux/msi.h
index e8c81fb..1e93a78 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -308,6 +308,7 @@ int platform_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
void platform_msi_domain_free(struct irq_domain *domain, unsigned int virq,
unsigned int nvec);
void *platform_msi_get_host_data(struct irq_domain *domain);
+int acpi_configure_msi_domain(struct device *dev);
#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
--
1.7.12.4
^ permalink raw reply related
* [RFC PATCH v2 06/11] msi: platform: make platform_msi_create_device_domain() ACPI aware
From: Hanjun Guo @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473862879-7769-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
With the platform msi domain created for ITS, irqchip such as
mbi-gen connecting ITS, which needs ctreate its own irqdomain.
Fortunately with the platform msi support upstreamed by Marc,
we just need to add minor code to make it run properly.
platform_msi_create_device_domain() is almost ready for ACPI use
except of_node_to_fwnode() is for dt only, make it ACPI aware then
things will work in both DTS and ACPI.
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/base/platform-msi.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c
index f6eae18..9a550a8 100644
--- a/drivers/base/platform-msi.c
+++ b/drivers/base/platform-msi.c
@@ -338,16 +338,17 @@ platform_msi_create_device_domain(struct device *dev,
{
struct platform_msi_priv_data *data;
struct irq_domain *domain;
+ struct fwnode_handle *fwnode;
int err;
data = platform_msi_alloc_priv_data(dev, nvec, write_msi_msg);
if (IS_ERR(data))
return NULL;
+ fwnode = dev->of_node ? &dev->of_node->fwnode : dev->fwnode;
data->host_data = host_data;
domain = irq_domain_create_hierarchy(dev->msi_domain, 0, nvec,
- of_node_to_fwnode(dev->of_node),
- ops, data);
+ fwnode, ops, data);
if (!domain)
goto free_priv;
--
1.7.12.4
^ permalink raw reply related
* [RFC PATCH v2 07/11] ACPI: irq: introduce interrupt producer
From: Hanjun Guo @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473862879-7769-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
In ACPI 6.1 spec, section 19.6.62, Interrupt Resource Descriptor Macro,
Interrupt (ResourceUsage, EdgeLevel, ActiveLevel, Shared,
ResourceSourceIndex, ResourceSource, DescriptorName)
{ InterruptList } => Buffer
For the arguement ResourceUsage and DescriptorName, which means:
ResourceUsage describes whether the device consumes the specified
interrupt ( ResourceConsumer ) or produces it for use by a child
device ( ResourceProducer ).
If nothing is specified, then ResourceConsumer is assumed.
DescriptorName evaluates to a name string which refers to the
entire resource descriptor.
So it can be used for devices connecting to a specific interrupt
prodcucer instead of the main interrupt controller in MADT. In the
real world, we have irqchip such as mbi-gen which connecting to
a group of wired interrupts and then issue msi to the ITS, devices
connecting to such interrupt controller fit this scope.
For now the irq for ACPI only pointer to the main interrupt
controller's irqdomain, for devices not connecting to those
irqdomains, which need to present its irq parent, we can use
following ASL code to represent it:
Interrupt(ResourceConsumer,..., "\_SB.IRQP") {12,14,....}
then we can parse the interrupt producer with the full
path name "\_SB.IRQP".
In order to do that, we introduce a pointer interrupt_producer
in struct acpi_device, and fill it when scanning irq resources
for acpi device if it specifies the interrupt producer.
But for now when parsing the resources for acpi devices, we don't
pass the acpi device for acpi_walk_resoures() in drivers/acpi/resource.c,
so introduce a adev in struct res_proc_context to pass it as a context
to scan the interrupt resources, then finally pass to acpi_register_gsi()
to find its interrupt producer to get the virq from diffrent domains.
With steps above ready, rework acpi_register_gsi() to get other
interrupt producer if devices not connecting to main interrupt
controller.
Since we often pass NULL to acpi_register_gsi() and there is no interrupt
producer for devices connect to gicd on ARM or io-apic on X86, so it will
use the default irqdomain for those deivces and no functional changes to
those devices.
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: Agustin Vega-Frias <agustinv@codeaurora.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/acpi/gsi.c | 10 ++++--
drivers/acpi/resource.c | 85 ++++++++++++++++++++++++++++++++++---------------
include/acpi/acpi_bus.h | 1 +
3 files changed, 68 insertions(+), 28 deletions(-)
diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c
index ee9e0f2..29ee547 100644
--- a/drivers/acpi/gsi.c
+++ b/drivers/acpi/gsi.c
@@ -55,13 +55,19 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
int polarity)
{
struct irq_fwspec fwspec;
+ struct acpi_device *adev = dev ? to_acpi_device(dev) : NULL;
- if (WARN_ON(!acpi_gsi_domain_id)) {
+ if (adev && &adev->fwnode && adev->interrupt_producer)
+ /* devices in DSDT connecting to spefic interrupt producer */
+ fwspec.fwnode = adev->interrupt_producer;
+ else if (acpi_gsi_domain_id)
+ /* devices connecting to gicd in default */
+ fwspec.fwnode = acpi_gsi_domain_id;
+ else {
pr_warn("GSI: No registered irqchip, giving up\n");
return -EINVAL;
}
- fwspec.fwnode = acpi_gsi_domain_id;
fwspec.param[0] = gsi;
fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
fwspec.param_count = 2;
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index 56241eb..f1371cf 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -381,7 +381,7 @@ static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET;
}
-static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
+static void acpi_dev_get_irqresource(struct acpi_device *adev, struct resource *res, u32 gsi,
u8 triggering, u8 polarity, u8 shareable,
bool legacy)
{
@@ -415,7 +415,7 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
}
res->flags = acpi_dev_irq_flags(triggering, polarity, shareable);
- irq = acpi_register_gsi(NULL, gsi, triggering, polarity);
+ irq = acpi_register_gsi(&adev->dev, gsi, triggering, polarity);
if (irq >= 0) {
res->start = irq;
res->end = irq;
@@ -424,27 +424,9 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
}
}
-/**
- * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information.
- * @ares: Input ACPI resource object.
- * @index: Index into the array of GSIs represented by the resource.
- * @res: Output generic resource object.
- *
- * Check if the given ACPI resource object represents an interrupt resource
- * and @index does not exceed the resource's interrupt count (true is returned
- * in that case regardless of the results of the other checks)). If that's the
- * case, register the GSI corresponding to @index from the array of interrupts
- * represented by the resource and populate the generic resource object pointed
- * to by @res accordingly. If the registration of the GSI is not successful,
- * IORESOURCE_DISABLED will be set it that object's flags.
- *
- * Return:
- * 1) false with res->flags setting to zero: not the expected resource type
- * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource
- * 3) true: valid assigned resource
- */
-bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
- struct resource *res)
+static bool __acpi_dev_resource_interrupt(struct acpi_device *adev,
+ struct acpi_resource *ares, int index,
+ struct resource *res)
{
struct acpi_resource_irq *irq;
struct acpi_resource_extended_irq *ext_irq;
@@ -460,7 +442,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
acpi_dev_irqresource_disabled(res, 0);
return false;
}
- acpi_dev_get_irqresource(res, irq->interrupts[index],
+ acpi_dev_get_irqresource(adev, res, irq->interrupts[index],
irq->triggering, irq->polarity,
irq->sharable, true);
break;
@@ -470,7 +452,31 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
acpi_dev_irqresource_disabled(res, 0);
return false;
}
- acpi_dev_get_irqresource(res, ext_irq->interrupts[index],
+
+ /*
+ * It's a interrupt consumer device and connecting to specfic
+ * interrupt controller. For now, we only support connecting
+ * interrupts to one irq controller for a single device
+ */
+ if (ext_irq->producer_consumer == ACPI_CONSUMER
+ && ext_irq->resource_source.string_length != 0
+ && !adev->interrupt_producer) {
+ acpi_status status;
+ acpi_handle handle;
+ struct acpi_device *device;
+
+ status = acpi_get_handle(NULL, ext_irq->resource_source.string_ptr, &handle);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ device = acpi_bus_get_acpi_device(handle);
+ if (!device)
+ return false;
+
+ adev->interrupt_producer = &device->fwnode;
+ }
+
+ acpi_dev_get_irqresource(adev, res, ext_irq->interrupts[index],
ext_irq->triggering, ext_irq->polarity,
ext_irq->sharable, false);
break;
@@ -481,6 +487,31 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
return true;
}
+
+/**
+ * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information.
+ * @ares: Input ACPI resource object.
+ * @index: Index into the array of GSIs represented by the resource.
+ * @res: Output generic resource object.
+ *
+ * Check if the given ACPI resource object represents an interrupt resource
+ * and @index does not exceed the resource's interrupt count (true is returned
+ * in that case regardless of the results of the other checks)). If that's the
+ * case, register the GSI corresponding to @index from the array of interrupts
+ * represented by the resource and populate the generic resource object pointed
+ * to by @res accordingly. If the registration of the GSI is not successful,
+ * IORESOURCE_DISABLED will be set it that object's flags.
+ *
+ * Return:
+ * 1) false with res->flags setting to zero: not the expected resource type
+ * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource
+ * 3) true: valid assigned resource
+ */
+bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
+ struct resource *res)
+{
+ return __acpi_dev_resource_interrupt(NULL, ares, index, res);
+}
EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);
/**
@@ -499,6 +530,7 @@ struct res_proc_context {
void *preproc_data;
int count;
int error;
+ struct acpi_device *adev;
};
static acpi_status acpi_dev_new_resource_entry(struct resource_win *win,
@@ -546,7 +578,7 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
|| acpi_dev_resource_ext_address_space(ares, &win))
return acpi_dev_new_resource_entry(&win, c);
- for (i = 0; acpi_dev_resource_interrupt(ares, i, res); i++) {
+ for (i = 0; __acpi_dev_resource_interrupt(c->adev, ares, i, res); i++) {
acpi_status status;
status = acpi_dev_new_resource_entry(&win, c);
@@ -599,6 +631,7 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
c.preproc_data = preproc_data;
c.count = 0;
c.error = 0;
+ c.adev = adev;
status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
acpi_dev_process_resource, &c);
if (ACPI_FAILURE(status)) {
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 4242c31..5410d3b 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -355,6 +355,7 @@ struct acpi_device {
int device_type;
acpi_handle handle; /* no handle for fixed hardware */
struct fwnode_handle fwnode;
+ struct fwnode_handle *interrupt_producer;
struct acpi_device *parent;
struct list_head children;
struct list_head node;
--
1.7.12.4
^ permalink raw reply related
* [RFC PATCH v2 08/11] irqchip: mbigen: drop module owner
From: Hanjun Guo @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473862879-7769-1-git-send-email-guohanjun@huawei.com>
From: Kefeng Wang <wangkefeng.wang@huawei.com>
Module owner will be set by driver core, so drop it.
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ma Jun <majun258@huawei.com>
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/irqchip/irq-mbigen.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 03b79b0..c01ab41 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -293,7 +293,6 @@ MODULE_DEVICE_TABLE(of, mbigen_of_match);
static struct platform_driver mbigen_platform_driver = {
.driver = {
.name = "Hisilicon MBIGEN-V2",
- .owner = THIS_MODULE,
.of_match_table = mbigen_of_match,
},
.probe = mbigen_device_probe,
--
1.7.12.4
^ permalink raw reply related
* [RFC PATCH v2 09/11] irqchip: mbigen: introduce mbigen_of_create_domain()
From: Hanjun Guo @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473862879-7769-1-git-send-email-guohanjun@huawei.com>
From: Kefeng Wang <wangkefeng.wang@huawei.com>
Introduce mbigen_of_create_domain() to consolidate OF related
code and prepare for ACPI later.
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ma Jun <majun258@huawei.com>
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/irqchip/irq-mbigen.c | 42 +++++++++++++++++++++++++++---------------
1 file changed, 27 insertions(+), 15 deletions(-)
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index c01ab41..9484ea0 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -236,27 +236,15 @@ static struct irq_domain_ops mbigen_domain_ops = {
.free = irq_domain_free_irqs_common,
};
-static int mbigen_device_probe(struct platform_device *pdev)
+static int mbigen_of_create_domain(struct platform_device *pdev,
+ struct mbigen_device *mgn_chip)
{
- struct mbigen_device *mgn_chip;
+ struct device *parent;
struct platform_device *child;
struct irq_domain *domain;
struct device_node *np;
- struct device *parent;
- struct resource *res;
u32 num_pins;
- mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
- if (!mgn_chip)
- return -ENOMEM;
-
- mgn_chip->pdev = pdev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mgn_chip->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(mgn_chip->base))
- return PTR_ERR(mgn_chip->base);
-
for_each_child_of_node(pdev->dev.of_node, np) {
if (!of_property_read_bool(np, "interrupt-controller"))
continue;
@@ -280,6 +268,30 @@ static int mbigen_device_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ return 0;
+}
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+ struct mbigen_device *mgn_chip;
+ struct resource *res;
+ int err;
+
+ mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+ if (!mgn_chip)
+ return -ENOMEM;
+
+ mgn_chip->pdev = pdev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mgn_chip->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mgn_chip->base))
+ return PTR_ERR(mgn_chip->base);
+
+ err = mbigen_of_create_domain(pdev, mgn_chip);
+ if (err)
+ return err;
+
platform_set_drvdata(pdev, mgn_chip);
return 0;
}
--
1.7.12.4
^ permalink raw reply related
* [RFC PATCH v2 10/11] irqchip: mbigen: Add ACPI support
From: Hanjun Guo @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473862879-7769-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
With the preparation of platform msi support and interrupt producer
in DSDT, we can add mbigen ACPI support now.
We are using _PRS methd to indicate number of irq pins instead
of num_pins in DT.
For mbi-gen,
Device(MBI0) {
Name(_HID, "HISI0152")
Name(_UID, Zero)
Name(_CRS, ResourceTemplate() {
Memory32Fixed(ReadWrite, 0xa0080000, 0x10000)
})
Name (_PRS, ResourceTemplate() {
Interrupt(ResourceProducer,...) {12,14,....}
})
}
For devices,
Device(COM0) {
Name(_HID, "ACPIIDxx")
Name(_UID, Zero)
Name(_CRS, ResourceTemplate() {
Memory32Fixed(ReadWrite, 0xb0030000, 0x10000)
Interrupt(ResourceConsumer,..., "\_SB.MBI0") {12}
})
}
With the helpe of platform msi and interrupt producer, then devices
will get the virq from mbi-gen's irqdomain.
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ma Jun <majun258@huawei.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/irqchip/irq-mbigen.c | 70 ++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 67 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 9484ea0..ca6add1 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/irqchip.h>
#include <linux/module.h>
@@ -180,7 +181,7 @@ static int mbigen_domain_translate(struct irq_domain *d,
unsigned long *hwirq,
unsigned int *type)
{
- if (is_of_node(fwspec->fwnode)) {
+ if (is_of_node(fwspec->fwnode) || is_acpi_device_node(fwspec->fwnode)) {
if (fwspec->param_count != 2)
return -EINVAL;
@@ -271,6 +272,54 @@ static int mbigen_of_create_domain(struct platform_device *pdev,
return 0;
}
+#ifdef CONFIG_ACPI
+static acpi_status mbigen_acpi_process_resource(struct acpi_resource *ares,
+ void *context)
+{
+ struct acpi_resource_extended_irq *ext_irq;
+ u32 *num_irqs = context;
+
+ switch (ares->type) {
+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ ext_irq = &ares->data.extended_irq;
+ *num_irqs += ext_irq->interrupt_count;
+ break;
+ default:
+ break;
+ }
+
+ return AE_OK;
+}
+
+static int mbigen_acpi_create_domain(struct platform_device *pdev,
+ struct mbigen_device *mgn_chip)
+{
+ struct irq_domain *domain;
+ u32 num_msis = 0;
+ acpi_status status;
+
+ status = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), METHOD_NAME__PRS,
+ mbigen_acpi_process_resource, &num_msis);
+ if (ACPI_FAILURE(status) || num_msis == 0)
+ return -EINVAL;
+
+ domain = platform_msi_create_device_domain(&pdev->dev, num_msis,
+ mbigen_write_msg,
+ &mbigen_domain_ops,
+ mgn_chip);
+ if (!domain)
+ return -ENOMEM;
+
+ return 0;
+}
+#else
+static int mbigen_acpi_create_domain(struct platform_device *pdev,
+ struct mbigen_device *mgn_chip)
+{
+ return -ENODEV;
+}
+#endif
+
static int mbigen_device_probe(struct platform_device *pdev)
{
struct mbigen_device *mgn_chip;
@@ -288,9 +337,17 @@ static int mbigen_device_probe(struct platform_device *pdev)
if (IS_ERR(mgn_chip->base))
return PTR_ERR(mgn_chip->base);
- err = mbigen_of_create_domain(pdev, mgn_chip);
- if (err)
+ if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
+ err = mbigen_of_create_domain(pdev, mgn_chip);
+ else if (ACPI_COMPANION(&pdev->dev))
+ err = mbigen_acpi_create_domain(pdev, mgn_chip);
+ else
+ err = -EINVAL;
+
+ if (err) {
+ dev_err(&pdev->dev, "Failed to create mbi-gen@%p irqdomain", mgn_chip->base);
return err;
+ }
platform_set_drvdata(pdev, mgn_chip);
return 0;
@@ -302,10 +359,17 @@ static const struct of_device_id mbigen_of_match[] = {
};
MODULE_DEVICE_TABLE(of, mbigen_of_match);
+static const struct acpi_device_id mbigen_acpi_match[] = {
+ { "HISI0152", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, mbigen_acpi_match);
+
static struct platform_driver mbigen_platform_driver = {
.driver = {
.name = "Hisilicon MBIGEN-V2",
.of_match_table = mbigen_of_match,
+ .acpi_match_table = ACPI_PTR(mbigen_acpi_match),
},
.probe = mbigen_device_probe,
};
--
1.7.12.4
^ permalink raw reply related
* [RFC PATCH v2 11/11] irqchip: mbigen: promote mbigen init
From: Hanjun Guo @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1473862879-7769-1-git-send-email-guohanjun@huawei.com>
From: Hanjun Guo <hanjun.guo@linaro.org>
mbigen is an irqchip and it needs to be probed before
devices, same logic is used for SMMU and etc., let's
use arch_initcall instead of platform init for mbigen.
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ma Jun <majun258@huawei.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/irqchip/irq-mbigen.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index ca6add1..3a33de6 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -374,7 +374,11 @@ static struct platform_driver mbigen_platform_driver = {
.probe = mbigen_device_probe,
};
-module_platform_driver(mbigen_platform_driver);
+static __init int mbigen_init(void)
+{
+ return platform_driver_register(&mbigen_platform_driver);
+}
+arch_initcall(mbigen_init);
MODULE_AUTHOR("Jun Ma <majun258@huawei.com>");
MODULE_AUTHOR("Yun Wu <wuyun.wu@huawei.com>");
--
1.7.12.4
^ permalink raw reply related
* [PATCH v7.1 13/22] iommu/arm-smmu: Refactor mmu-masters handling
From: Robin Murphy @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <046d2d21f988d6ece916fc45b0af0804a7f200f2.1473695704.git.robin.murphy@arm.com>
To be able to support the generic bindings and handle of_xlate() calls,
we need to be able to associate SMMUs and stream IDs directly with
devices *before* allocating IOMMU groups. Furthermore, to support real
default domains with multi-device groups we also have to handle domain
attach on a per-device basis, as the "whole group at a time" assumption
fails to properly handle subsequent devices added to a group after the
first has already triggered default domain creation and attachment.
To that end, use the now-vacant dev->archdata.iommu field for easy
config and SMMU instance lookup, and unify config management by chopping
down the platform-device-specific tree and probing the "mmu-masters"
property on-demand instead. This may add a bit of one-off overhead to
initially adding a new device, but we're about to deprecate that binding
in favour of the inherently-more-efficient generic ones anyway.
For the sake of simplicity, this patch does temporarily regress the case
of aliasing PCI devices by losing the duplicate stream ID detection that
the previous per-group config had. Stay tuned, because we'll be back to
fix that in a better and more general way momentarily...
Tested-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
---
- Fix __find_legacy_master_phandle() to properly cope with more than
one SMMU using the legacy binding.
drivers/iommu/arm-smmu.c | 382 +++++++++++++----------------------------------
1 file changed, 107 insertions(+), 275 deletions(-)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 69b6cab65421..2023a77015a0 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -317,18 +317,13 @@ struct arm_smmu_smr {
};
struct arm_smmu_master_cfg {
+ struct arm_smmu_device *smmu;
int num_streamids;
u16 streamids[MAX_MASTER_STREAMIDS];
s16 smendx[MAX_MASTER_STREAMIDS];
};
#define INVALID_SMENDX -1
-struct arm_smmu_master {
- struct device_node *of_node;
- struct rb_node node;
- struct arm_smmu_master_cfg cfg;
-};
-
struct arm_smmu_device {
struct device *dev;
@@ -376,7 +371,6 @@ struct arm_smmu_device {
unsigned int *irqs;
struct list_head list;
- struct rb_root masters;
u32 cavium_id_base; /* Specific to Cavium */
};
@@ -415,12 +409,6 @@ struct arm_smmu_domain {
struct iommu_domain domain;
};
-struct arm_smmu_phandle_args {
- struct device_node *np;
- int args_count;
- uint32_t args[MAX_MASTER_STREAMIDS];
-};
-
static DEFINE_SPINLOCK(arm_smmu_devices_lock);
static LIST_HEAD(arm_smmu_devices);
@@ -462,132 +450,89 @@ static struct device_node *dev_get_dev_node(struct device *dev)
while (!pci_is_root_bus(bus))
bus = bus->parent;
- return bus->bridge->parent->of_node;
+ return of_node_get(bus->bridge->parent->of_node);
}
- return dev->of_node;
+ return of_node_get(dev->of_node);
}
-static struct arm_smmu_master *find_smmu_master(struct arm_smmu_device *smmu,
- struct device_node *dev_node)
+static int __arm_smmu_get_pci_sid(struct pci_dev *pdev, u16 alias, void *data)
{
- struct rb_node *node = smmu->masters.rb_node;
-
- while (node) {
- struct arm_smmu_master *master;
-
- master = container_of(node, struct arm_smmu_master, node);
-
- if (dev_node < master->of_node)
- node = node->rb_left;
- else if (dev_node > master->of_node)
- node = node->rb_right;
- else
- return master;
- }
-
- return NULL;
+ *((__be32 *)data) = cpu_to_be32(alias);
+ return 0; /* Continue walking */
}
-static struct arm_smmu_master_cfg *
-find_smmu_master_cfg(struct device *dev)
+static int __find_legacy_master_phandle(struct device *dev, void *data)
{
- struct arm_smmu_master_cfg *cfg = NULL;
- struct iommu_group *group = iommu_group_get(dev);
+ struct of_phandle_iterator *it = *(void **)data;
+ struct device_node *np = it->node;
+ int err;
- if (group) {
- cfg = iommu_group_get_iommudata(group);
- iommu_group_put(group);
- }
-
- return cfg;
-}
-
-static int insert_smmu_master(struct arm_smmu_device *smmu,
- struct arm_smmu_master *master)
-{
- struct rb_node **new, *parent;
-
- new = &smmu->masters.rb_node;
- parent = NULL;
- while (*new) {
- struct arm_smmu_master *this
- = container_of(*new, struct arm_smmu_master, node);
-
- parent = *new;
- if (master->of_node < this->of_node)
- new = &((*new)->rb_left);
- else if (master->of_node > this->of_node)
- new = &((*new)->rb_right);
- else
- return -EEXIST;
- }
-
- rb_link_node(&master->node, parent, new);
- rb_insert_color(&master->node, &smmu->masters);
- return 0;
-}
-
-static int register_smmu_master(struct arm_smmu_device *smmu,
- struct device *dev,
- struct arm_smmu_phandle_args *masterspec)
-{
- int i;
- struct arm_smmu_master *master;
-
- master = find_smmu_master(smmu, masterspec->np);
- if (master) {
- dev_err(dev,
- "rejecting multiple registrations for master device %s\n",
- masterspec->np->name);
- return -EBUSY;
- }
-
- if (masterspec->args_count > MAX_MASTER_STREAMIDS) {
- dev_err(dev,
- "reached maximum number (%d) of stream IDs for master device %s\n",
- MAX_MASTER_STREAMIDS, masterspec->np->name);
- return -ENOSPC;
- }
-
- master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL);
- if (!master)
- return -ENOMEM;
-
- master->of_node = masterspec->np;
- master->cfg.num_streamids = masterspec->args_count;
-
- for (i = 0; i < master->cfg.num_streamids; ++i) {
- u16 streamid = masterspec->args[i];
-
- if (!(smmu->features & ARM_SMMU_FEAT_STREAM_MATCH) &&
- (streamid >= smmu->num_mapping_groups)) {
- dev_err(dev,
- "stream ID for master device %s greater than maximum allowed (%d)\n",
- masterspec->np->name, smmu->num_mapping_groups);
- return -ERANGE;
+ of_for_each_phandle(it, err, dev->of_node, "mmu-masters",
+ "#stream-id-cells", 0)
+ if (it->node == np) {
+ *(void **)data = dev;
+ return 1;
}
- master->cfg.streamids[i] = streamid;
- master->cfg.smendx[i] = INVALID_SMENDX;
- }
- return insert_smmu_master(smmu, master);
+ it->node = np;
+ return err == -ENOENT ? 0 : err;
}
-static struct arm_smmu_device *find_smmu_for_device(struct device *dev)
+static int arm_smmu_register_legacy_master(struct device *dev)
{
struct arm_smmu_device *smmu;
- struct arm_smmu_master *master = NULL;
- struct device_node *dev_node = dev_get_dev_node(dev);
+ struct arm_smmu_master_cfg *cfg;
+ struct device_node *np;
+ struct of_phandle_iterator it;
+ void *data = ⁢
+ __be32 pci_sid;
+ int err;
+ np = dev_get_dev_node(dev);
+ if (!np || !of_find_property(np, "#stream-id-cells", NULL)) {
+ of_node_put(np);
+ return -ENODEV;
+ }
+
+ it.node = np;
spin_lock(&arm_smmu_devices_lock);
list_for_each_entry(smmu, &arm_smmu_devices, list) {
- master = find_smmu_master(smmu, dev_node);
- if (master)
+ err = __find_legacy_master_phandle(smmu->dev, &data);
+ if (err)
break;
}
spin_unlock(&arm_smmu_devices_lock);
+ of_node_put(np);
+ if (err == 0)
+ return -ENODEV;
+ if (err < 0)
+ return err;
- return master ? smmu : NULL;
+ if (it.cur_count > MAX_MASTER_STREAMIDS) {
+ dev_err(smmu->dev,
+ "reached maximum number (%d) of stream IDs for master device %s\n",
+ MAX_MASTER_STREAMIDS, dev_name(dev));
+ return -ENOSPC;
+ }
+ if (dev_is_pci(dev)) {
+ /* "mmu-masters" assumes Stream ID == Requester ID */
+ pci_for_each_dma_alias(to_pci_dev(dev), __arm_smmu_get_pci_sid,
+ &pci_sid);
+ it.cur = &pci_sid;
+ it.cur_count = 1;
+ }
+
+ cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ cfg->smmu = smmu;
+ dev->archdata.iommu = cfg;
+
+ while (it.cur_count--)
+ cfg->streamids[cfg->num_streamids++] = be32_to_cpup(it.cur++);
+
+ return 0;
}
static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end)
@@ -1119,8 +1064,7 @@ static void arm_smmu_free_smr(struct arm_smmu_device *smmu, int idx)
static void arm_smmu_write_smr(struct arm_smmu_device *smmu, int idx)
{
struct arm_smmu_smr *smr = smmu->smrs + idx;
- u32 reg = (smr->id & smmu->streamid_mask) << SMR_ID_SHIFT |
- (smr->mask & smmu->smr_mask_mask) << SMR_MASK_SHIFT;
+ u32 reg = smr->id << SMR_ID_SHIFT | smr->mask << SMR_MASK_SHIFT;
if (smr->valid)
reg |= SMR_VALID;
@@ -1189,9 +1133,9 @@ err_free_smrs:
return -ENOSPC;
}
-static void arm_smmu_master_free_smes(struct arm_smmu_device *smmu,
- struct arm_smmu_master_cfg *cfg)
+static void arm_smmu_master_free_smes(struct arm_smmu_master_cfg *cfg)
{
+ struct arm_smmu_device *smmu = cfg->smmu;
int i;
/*
@@ -1262,17 +1206,15 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
{
int ret;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
- struct arm_smmu_device *smmu;
- struct arm_smmu_master_cfg *cfg;
+ struct arm_smmu_master_cfg *cfg = dev->archdata.iommu;
- smmu = find_smmu_for_device(dev);
- if (!smmu) {
+ if (!cfg) {
dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n");
return -ENXIO;
}
/* Ensure that the domain is finalised */
- ret = arm_smmu_init_domain_context(domain, smmu);
+ ret = arm_smmu_init_domain_context(domain, cfg->smmu);
if (ret < 0)
return ret;
@@ -1280,18 +1222,14 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
* Sanity check the domain. We don't support domains across
* different SMMUs.
*/
- if (smmu_domain->smmu != smmu) {
+ if (smmu_domain->smmu != cfg->smmu) {
dev_err(dev,
"cannot attach to SMMU %s whilst already attached to domain on SMMU %s\n",
- dev_name(smmu_domain->smmu->dev), dev_name(smmu->dev));
+ dev_name(smmu_domain->smmu->dev), dev_name(cfg->smmu->dev));
return -EINVAL;
}
/* Looks ok, so add the device to the domain */
- cfg = find_smmu_master_cfg(dev);
- if (!cfg)
- return -ENODEV;
-
return arm_smmu_domain_add_master(smmu_domain, cfg);
}
@@ -1411,120 +1349,65 @@ static bool arm_smmu_capable(enum iommu_cap cap)
}
}
-static int __arm_smmu_get_pci_sid(struct pci_dev *pdev, u16 alias, void *data)
-{
- *((u16 *)data) = alias;
- return 0; /* Continue walking */
-}
-
-static void __arm_smmu_release_pci_iommudata(void *data)
-{
- kfree(data);
-}
-
-static int arm_smmu_init_pci_device(struct pci_dev *pdev,
- struct iommu_group *group)
-{
- struct arm_smmu_master_cfg *cfg;
- u16 sid;
- int i;
-
- cfg = iommu_group_get_iommudata(group);
- if (!cfg) {
- cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
- if (!cfg)
- return -ENOMEM;
-
- iommu_group_set_iommudata(group, cfg,
- __arm_smmu_release_pci_iommudata);
- }
-
- if (cfg->num_streamids >= MAX_MASTER_STREAMIDS)
- return -ENOSPC;
-
- /*
- * Assume Stream ID == Requester ID for now.
- * We need a way to describe the ID mappings in FDT.
- */
- pci_for_each_dma_alias(pdev, __arm_smmu_get_pci_sid, &sid);
- for (i = 0; i < cfg->num_streamids; ++i)
- if (cfg->streamids[i] == sid)
- break;
-
- /* Avoid duplicate SIDs, as this can lead to SMR conflicts */
- if (i == cfg->num_streamids) {
- cfg->streamids[i] = sid;
- cfg->smendx[i] = INVALID_SMENDX;
- cfg->num_streamids++;
- }
-
- return 0;
-}
-
-static int arm_smmu_init_platform_device(struct device *dev,
- struct iommu_group *group)
-{
- struct arm_smmu_device *smmu = find_smmu_for_device(dev);
- struct arm_smmu_master *master;
-
- if (!smmu)
- return -ENODEV;
-
- master = find_smmu_master(smmu, dev->of_node);
- if (!master)
- return -ENODEV;
-
- iommu_group_set_iommudata(group, &master->cfg, NULL);
-
- return 0;
-}
-
static int arm_smmu_add_device(struct device *dev)
{
+ struct arm_smmu_master_cfg *cfg;
struct iommu_group *group;
+ int i, ret;
+
+ ret = arm_smmu_register_legacy_master(dev);
+ cfg = dev->archdata.iommu;
+ if (ret)
+ goto out_free;
+
+ ret = -EINVAL;
+ for (i = 0; i < cfg->num_streamids; i++) {
+ u16 sid = cfg->streamids[i];
+
+ if (sid & ~cfg->smmu->streamid_mask) {
+ dev_err(dev, "stream ID 0x%x out of range for SMMU (0x%x)\n",
+ sid, cfg->smmu->streamid_mask);
+ goto out_free;
+ }
+ cfg->smendx[i] = INVALID_SMENDX;
+ }
group = iommu_group_get_for_dev(dev);
- if (IS_ERR(group))
- return PTR_ERR(group);
-
+ if (IS_ERR(group)) {
+ ret = PTR_ERR(group);
+ goto out_free;
+ }
iommu_group_put(group);
return 0;
+
+out_free:
+ kfree(cfg);
+ dev->archdata.iommu = NULL;
+ return ret;
}
static void arm_smmu_remove_device(struct device *dev)
{
- struct arm_smmu_device *smmu = find_smmu_for_device(dev);
- struct arm_smmu_master_cfg *cfg = find_smmu_master_cfg(dev);
+ struct arm_smmu_master_cfg *cfg = dev->archdata.iommu;
- if (smmu && cfg)
- arm_smmu_master_free_smes(smmu, cfg);
+ if (!cfg)
+ return;
+ arm_smmu_master_free_smes(cfg);
iommu_group_remove_device(dev);
+ kfree(cfg);
+ dev->archdata.iommu = NULL;
}
static struct iommu_group *arm_smmu_device_group(struct device *dev)
{
struct iommu_group *group;
- int ret;
if (dev_is_pci(dev))
group = pci_device_group(dev);
else
group = generic_device_group(dev);
- if (IS_ERR(group))
- return group;
-
- if (dev_is_pci(dev))
- ret = arm_smmu_init_pci_device(to_pci_dev(dev), group);
- else
- ret = arm_smmu_init_platform_device(dev, group);
-
- if (ret) {
- iommu_group_put(group);
- group = ERR_PTR(ret);
- }
-
return group;
}
@@ -1938,9 +1821,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
struct resource *res;
struct arm_smmu_device *smmu;
struct device *dev = &pdev->dev;
- struct rb_node *node;
- struct of_phandle_iterator it;
- struct arm_smmu_phandle_args *masterspec;
int num_irqs, i, err;
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
@@ -2001,37 +1881,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
if (err)
return err;
- i = 0;
- smmu->masters = RB_ROOT;
-
- err = -ENOMEM;
- /* No need to zero the memory for masterspec */
- masterspec = kmalloc(sizeof(*masterspec), GFP_KERNEL);
- if (!masterspec)
- goto out_put_masters;
-
- of_for_each_phandle(&it, err, dev->of_node,
- "mmu-masters", "#stream-id-cells", 0) {
- int count = of_phandle_iterator_args(&it, masterspec->args,
- MAX_MASTER_STREAMIDS);
- masterspec->np = of_node_get(it.node);
- masterspec->args_count = count;
-
- err = register_smmu_master(smmu, dev, masterspec);
- if (err) {
- dev_err(dev, "failed to add master %s\n",
- masterspec->np->name);
- kfree(masterspec);
- goto out_put_masters;
- }
-
- i++;
- }
-
- dev_notice(dev, "registered %d master devices\n", i);
-
- kfree(masterspec);
-
parse_driver_options(smmu);
if (smmu->version == ARM_SMMU_V2 &&
@@ -2039,8 +1888,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
dev_err(dev,
"found only %d context interrupt(s) but %d required\n",
smmu->num_context_irqs, smmu->num_context_banks);
- err = -ENODEV;
- goto out_put_masters;
+ return -ENODEV;
}
for (i = 0; i < smmu->num_global_irqs; ++i) {
@@ -2052,7 +1900,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
if (err) {
dev_err(dev, "failed to request global IRQ %d (%u)\n",
i, smmu->irqs[i]);
- goto out_put_masters;
+ return err;
}
}
@@ -2063,22 +1911,12 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
arm_smmu_device_reset(smmu);
return 0;
-
-out_put_masters:
- for (node = rb_first(&smmu->masters); node; node = rb_next(node)) {
- struct arm_smmu_master *master
- = container_of(node, struct arm_smmu_master, node);
- of_node_put(master->of_node);
- }
-
- return err;
}
static int arm_smmu_device_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct arm_smmu_device *curr, *smmu = NULL;
- struct rb_node *node;
spin_lock(&arm_smmu_devices_lock);
list_for_each_entry(curr, &arm_smmu_devices, list) {
@@ -2093,12 +1931,6 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
if (!smmu)
return -ENODEV;
- for (node = rb_first(&smmu->masters); node; node = rb_next(node)) {
- struct arm_smmu_master *master
- = container_of(node, struct arm_smmu_master, node);
- of_node_put(master->of_node);
- }
-
if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS))
dev_err(dev, "removing device with active domains!\n");
--
2.8.1.dirty
^ permalink raw reply related
* [PATCH 2/2] arm64: dts: marvell: enable MSI for PCIe on Armada 7K/8K
From: Gregory CLEMENT @ 2016-09-14 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1472744484-19132-3-git-send-email-thomas.petazzoni@free-electrons.com>
Hi Thomas,
On jeu., sept. 01 2016, Thomas Petazzoni <thomas.petazzoni@free-electrons.com> wrote:
> This commit adds a reference to the appropriate MSI controller in the
> description of the PCIe controllers on Marvel Armada 7K and 8K
> platforms.
Applied on mvebu/dt64
Thanks,
Gregory
>
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> ---
> arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi | 3 +++
> arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi | 3 +++
> 2 files changed, 6 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
> index ceb83b0..ff469e1 100644
> --- a/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
> +++ b/arch/arm64/boot/dts/marvell/armada-cp110-master.dtsi
> @@ -177,6 +177,7 @@
> #interrupt-cells = <1>;
> device_type = "pci";
> dma-coherent;
> + msi-parent = <&gic_v2m0>;
>
> bus-range = <0 0xff>;
> ranges =
> @@ -202,6 +203,7 @@
> #interrupt-cells = <1>;
> device_type = "pci";
> dma-coherent;
> + msi-parent = <&gic_v2m0>;
>
> bus-range = <0 0xff>;
> ranges =
> @@ -228,6 +230,7 @@
> #interrupt-cells = <1>;
> device_type = "pci";
> dma-coherent;
> + msi-parent = <&gic_v2m0>;
>
> bus-range = <0 0xff>;
> ranges =
> diff --git a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
> index 2d863f2..43cecf0 100644
> --- a/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
> +++ b/arch/arm64/boot/dts/marvell/armada-cp110-slave.dtsi
> @@ -177,6 +177,7 @@
> #interrupt-cells = <1>;
> device_type = "pci";
> dma-coherent;
> + msi-parent = <&gic_v2m0>;
>
> bus-range = <0 0xff>;
> ranges =
> @@ -202,6 +203,7 @@
> #interrupt-cells = <1>;
> device_type = "pci";
> dma-coherent;
> + msi-parent = <&gic_v2m0>;
>
> bus-range = <0 0xff>;
> ranges =
> @@ -228,6 +230,7 @@
> #interrupt-cells = <1>;
> device_type = "pci";
> dma-coherent;
> + msi-parent = <&gic_v2m0>;
>
> bus-range = <0 0xff>;
> ranges =
> --
> 2.7.4
>
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ 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