* [PATCH 2/2] mm: hugetlb: support gigantic surplus pages
From: Huang Shijie @ 2016-11-09 7:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161108202742.57ed120d@thinkpad>
On Tue, Nov 08, 2016 at 08:27:42PM +0100, Gerald Schaefer wrote:
> On Tue, 8 Nov 2016 17:17:28 +0800
> Huang Shijie <shijie.huang@arm.com> wrote:
>
> > > I will look at the lockdep issue.
> > I tested the new patch (will be sent out later) on the arm64 platform,
> > and I did not meet the lockdep issue when I enabled the lockdep.
> > The following is my config:
> >
> > CONFIG_LOCKD=y
> > CONFIG_LOCKD_V4=y
> > CONFIG_LOCKUP_DETECTOR=y
> > # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
> > CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
> > CONFIG_DEBUG_SPINLOCK=y
> > CONFIG_DEBUG_LOCK_ALLOC=y
> > CONFIG_PROVE_LOCKING=y
> > CONFIG_LOCKDEP=y
> > CONFIG_LOCK_STAT=y
> > CONFIG_DEBUG_LOCKDEP=y
> > CONFIG_DEBUG_LOCKING_API_SELFTESTS=y
> >
> > So do I miss something?
>
> Those options should be OK. Meanwhile I looked into this a little more,
> and the problematic line/lock is spin_lock_irqsave(&z->lock, flags) at
> the top of alloc_gigantic_page(). From the lockdep trace we see that
> it is triggered by an mmap(), and then hugetlb_acct_memory() ->
> __alloc_huge_page() -> alloc_gigantic_page().
>
> However, in between those functions (inside gather_surplus_pages())
> a NUMA_NO_NODE node id comes into play. And this finally results in
> alloc_gigantic_page() being called with NUMA_NO_NODE as nid (which is
> -1), and NODE_DATA(nid)->node_zones will then reach into Nirvana.
Thanks for pointing this.
I sent out the new patch just now. Could you please try it again?
I added a NUMA_NO_NODE check in the alloc_gigantic_page();
thanks
Huang Shijie
^ permalink raw reply
* [PATCH v2 2/2] mm: hugetlb: support gigantic surplus pages
From: Huang Shijie @ 2016-11-09 7:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478141499-13825-3-git-send-email-shijie.huang@arm.com>
When testing the gigantic page whose order is too large for the buddy
allocator, the libhugetlbfs test case "counter.sh" will fail.
The failure is caused by:
1) kernel fails to allocate a gigantic page for the surplus case.
And the gather_surplus_pages() will return NULL in the end.
2) The condition checks for "over-commit" is wrong.
This patch adds code to allocate the gigantic page in the
__alloc_huge_page(). After this patch, gather_surplus_pages()
can return a gigantic page for the surplus case.
This patch changes the condition checks for:
return_unused_surplus_pages()
nr_overcommit_hugepages_store()
hugetlb_overcommit_handler()
This patch also set @nid with proper value when NUMA_NO_NODE is
passed to alloc_gigantic_page().
After this patch, the counter.sh can pass for the gigantic page.
Acked-by: Steve Capper <steve.capper@arm.com>
Signed-off-by: Huang Shijie <shijie.huang@arm.com>
---
1. fix the wrong check in hugetlb_overcommit_handler();
2. try to fix the s390 issue.
---
mm/hugetlb.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 9fdfc24..5dbfd62 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1095,6 +1095,9 @@ static struct page *alloc_gigantic_page(int nid, unsigned int order)
unsigned long ret, pfn, flags;
struct zone *z;
+ if (nid == NUMA_NO_NODE)
+ nid = numa_mem_id();
+
z = NODE_DATA(nid)->node_zones;
for (; z - NODE_DATA(nid)->node_zones < MAX_NR_ZONES; z++) {
spin_lock_irqsave(&z->lock, flags);
@@ -1578,7 +1581,7 @@ static struct page *__alloc_huge_page(struct hstate *h,
struct page *page;
unsigned int r_nid;
- if (hstate_is_gigantic(h))
+ if (hstate_is_gigantic(h) && !gigantic_page_supported())
return NULL;
/*
@@ -1623,7 +1626,13 @@ static struct page *__alloc_huge_page(struct hstate *h,
}
spin_unlock(&hugetlb_lock);
- page = __hugetlb_alloc_buddy_huge_page(h, vma, addr, nid);
+ if (hstate_is_gigantic(h)) {
+ page = alloc_gigantic_page(nid, huge_page_order(h));
+ if (page)
+ prep_compound_gigantic_page(page, huge_page_order(h));
+ } else {
+ page = __hugetlb_alloc_buddy_huge_page(h, vma, addr, nid);
+ }
spin_lock(&hugetlb_lock);
if (page) {
@@ -1790,8 +1799,7 @@ static void return_unused_surplus_pages(struct hstate *h,
/* Uncommit the reservation */
h->resv_huge_pages -= unused_resv_pages;
- /* Cannot return gigantic pages currently */
- if (hstate_is_gigantic(h))
+ if (hstate_is_gigantic(h) && !gigantic_page_supported())
return;
nr_pages = min(unused_resv_pages, h->surplus_huge_pages);
@@ -2443,7 +2451,7 @@ static ssize_t nr_overcommit_hugepages_store(struct kobject *kobj,
unsigned long input;
struct hstate *h = kobj_to_hstate(kobj, NULL);
- if (hstate_is_gigantic(h))
+ if (hstate_is_gigantic(h) && !gigantic_page_supported())
return -EINVAL;
err = kstrtoul(buf, 10, &input);
@@ -2884,7 +2892,7 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write,
tmp = h->nr_overcommit_huge_pages;
- if (write && hstate_is_gigantic(h))
+ if (write && hstate_is_gigantic(h) && !gigantic_page_supported())
return -EINVAL;
table->data = &tmp;
--
2.1.4
^ permalink raw reply related
* [PATCH V3 0/8] IOMMU probe deferral support
From: Sricharan @ 2016-11-09 6:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <9f36244f-62d4-08e3-d64a-2b04ad4dc2e0@arm.com>
Hi Robin,
>On 04/11/16 15:16, Sricharan wrote:
>> Hi Robin,
>>
>>>>> Yikes, on second look, that definitely shouldn't be happening.
>>>>> Everything below is probably the resulting fallout.
>>>>
>>>> [ 40.206703] vfio-pci 0000:08:00.0: Failed to setup iommu ops
>>>>
>>>> I think the above print which says "failed to setup iommu_ops"
>>>> because the call ops->add_device failed in of_pci_iommu_configure
>>>> is the reason for the failure, in my case i simply do not get this even with
>>>> your scripts. ops->add_device succeeds in the rebind as well. So still
>>>> checking what could be happening in your case.
>>>
>>> I was looking at your code base from [1].The ops->add_device
>>> callback from of_pci_iommu_configure on the rebind is the
>>> one which is causing the failure. But not able to spot out
>>>from code which point is causing the failure. It would be very helpful
>>> if i can know which is the return value from the add_device callback
>>> or point inside add_device callback which fails in your setup.
>>>
>>>
>>> [1] git://linux-arm.org/linux-rm iommu/misc
>>
>> With little more try, i saw an issue where i had an failure
>> similar to what you reported. The issue happens when multiple
>> devices fall in to same group due to matching sids. I ended up
>> doing a fix like below and it would be nice to verify if it is the same
>> that we are seeing in your setup and if the fix makes a difference ?
>>
>> From: Sricharan R <sricharan@codeaurora.org>
>> Date: Fri, 4 Nov 2016 20:28:49 +0530
>> Subject: [PATCH] iommu/arm-smmu: Fix group's reference counting
>>
>> iommu_group_get_for_dev which gets called in the add_device
>> callback, increases the reference count of the iommu_group,
>> so we do an iommu_group_put after that. iommu_group_get_for_dev
>> inturn calls device_group callback and in the case of arm-smmu
>> we call generic_device_group/pci_device_group which takes
>> care of increasing the group's reference. But when we return
>> an already existing group(when multiple devices have same group)
>> the reference is not incremented, resulting in issues when the
>> remove_device callback for the devices is invoked.
>> Fixing the same here.
>
>Bah, yes, this does look like my fault - after flip-flopping between
>about 3 different ways to keep refcounts for the S2CR entries, none of
>which would quite work, I ripped it all out but apparently still got
>things wrong, oh well. Thanks for figuring it out.
>
>On the probe-deferral angle, whilst it's useful to have uncovered this
>bug, I don't think we should actually be calling remove_device() from
>DMA teardown. I think it's preferable from a user perspective if group
>numbering remains stable, rather than changing depending on the order in
>which they unbind/rebind VFIO drivers. I'm really keen to try and get
>this in shape for 4.10, so I've taken the liberty of hacking up my own
>branch (iommu/defer) based on v3 - would you mind taking a look at the
>two "iommu/of:" commits to see what you think? (Ignore the PCI changes
>to your later patches - that was an experiment which didn't really work out)
Ok, will take a look at this now and respond more on this.
>
>> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
>> ---
>> drivers/iommu/arm-smmu.c | 4 +++-
>> 1 file changed, 3 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
>> index 71ce4b6..a1d0b3c 100644
>> --- a/drivers/iommu/arm-smmu.c
>> +++ b/drivers/iommu/arm-smmu.c
>> @@ -1516,8 +1516,10 @@ static struct iommu_group *arm_smmu_device_group(struct device *dev)
>> group = smmu->s2crs[idx].group;
>> }
>>
>> - if (group)
>> + if (group) {
>> + iommu_group_get_by_id(iommu_group_id(group));
>> return group;
>
>This might as well just be inline, i.e.:
>
> return iommu_group_get_by_id(iommu_group_id(group));
>
>It's a shame we have to go all round the houses when we have the group
>right there, but this is probably the most expedient fix. I guess we can
>extend the API with some sort of iommu_group_get(group) overload in
>future if we really want to.
>
ok, i can send this fix separately then. Otherwise, Will was suggesting on the
other thread that there should probably be a separate API to increment
the group refcount or get the group from the existing aliasing device.
As per me adding the api, looks like another option or post the above ?
Regards,
Sricharan
^ permalink raw reply
* [PATCH 3/3 v4] ARM: dts: Add gyro and accel to APQ8060 Dragonboard
From: Bjorn Andersson @ 2016-11-09 5:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478508284-10847-3-git-send-email-linus.walleij@linaro.org>
On Mon 07 Nov 00:44 PST 2016, Linus Walleij wrote:
> This adds the MPU-3050 gyroscope and the KXSD9 accelerometer to
> the Qualcomm APQ8060 Dragonboard. The KXSD9 is mounted beyond the
> MPU-3050 and appear as a subdevice beyond it. We set up the
> required GPIO and interrupt lines to make the devices work.
>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> ChangeLog v3->v4:
> - Use interrupts-extended
> - Add Bjorn's ACK.
Looks like it didn't make it to the message after all, but Andy is using
patchworks, so here we go again :)
Acked-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Regards,
Bjorn
> ChangeLog v2->v3:
> - Move the interrupt to the pm8058 alias to reflect the two patches
> properly specifying the PMIC as interrupt parent.
> ChangeLog v1->v2:
> - Use the new I2C mux gate bindings from Peter Rosin (merged to
> the I2C subsystem)
> ---
> arch/arm/boot/dts/qcom-apq8060-dragonboard.dts | 52 ++++++++++++++++++++++++++
> 1 file changed, 52 insertions(+)
>
> diff --git a/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts b/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts
> index ea660ffa03ea..39d9e6ddefed 100644
> --- a/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts
> +++ b/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts
> @@ -220,6 +220,14 @@
> function = "ebi2";
> };
> };
> +
> + /* Interrupt line for the KXSD9 accelerometer */
> + dragon_kxsd9_gpios: kxsd9 {
> + irq {
> + pins = "gpio57"; /* IRQ line */
> + bias-pull-up;
> + };
> + };
> };
>
> qcom,ssbi at 500000 {
> @@ -272,6 +280,15 @@
> power-source = <PM8058_GPIO_S3>;
> };
> };
> + dragon_mpu3050_gpios: mpu3050-gpios {
> + pinconf {
> + pins = "gpio17";
> + function = "normal";
> + input-enable;
> + bias-disable;
> + power-source = <PM8058_GPIO_S3>;
> + };
> + };
> dragon_sdcc3_gpios: sdcc3-gpios {
> pinconf {
> pins = "gpio22";
> @@ -389,6 +406,41 @@
> vddd-supply = <&pm8058_lvs0>; // 1.8V
> vdda-supply = <&pm8058_l14>; // 2.85V
> };
> + mpu3050 at 68 {
> + compatible = "invensense,mpu3050";
> + reg = <0x68>;
> + /*
> + * GPIO17 has interrupt 208 on the
> + * PM8058, it is pulled high by a 10k
> + * resistor to VLOGIC so needs to be
> + * active low/falling edge.
> + */
> + interrupts-extended = <&pm8058 208 IRQ_TYPE_EDGE_FALLING>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&dragon_mpu3050_gpios>;
> + vlogic-supply = <&pm8058_lvs0>; // 1.8V
> + vdd-supply = <&pm8058_l14>; // 2.85V
> +
> + /*
> + * The MPU-3050 acts as a hub for the
> + * accelerometer.
> + */
> + i2c-gate {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + kxsd9 at 18 {
> + compatible = "kionix,kxsd9";
> + reg = <0x18>;
> + interrupt-parent = <&tlmm>;
> + interrupts = <57 IRQ_TYPE_EDGE_FALLING>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&dragon_kxsd9_gpios>;
> + iovdd-supply = <&pm8058_lvs0>; // 1.8V
> + vdd-supply = <&pm8058_l14>; // 2.85V
> + };
> + };
> + };
> };
> };
>
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH v1 03/11] drivers: soc: hisi: Add support for Hisilicon Djtag driver
From: Anurup M @ 2016-11-09 4:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4657586.c5MJoh65Ux@wuerfel>
On Tuesday 08 November 2016 08:38 PM, Arnd Bergmann wrote:
> On Tuesday, November 8, 2016 7:16:30 PM CET Anurup M wrote:
>>>>>> If these are backwards compatible, just mark them as compatible in DT,
>>>>>> e.g. hip06 can use
>>>>>>
>>>>>> compatible = "hisilicon,hip06-cpu-djtag-v1", "hisilicon,hip05-cpu-djtag-v1";
>>>>>>
>>>>>> so you can tell the difference if you need to, but the driver only has to
>>>>>> list the oldest one here.
>>>>>>
>>>>>> What is the difference between the cpu and io djtag interfaces?
>>>> On some chips like hip06, the djtag version is different for IO die.
>>> In what way? The driver doesn't seem to care about the difference.
>> There is a difference in djtag version of CPU and IO die (in some chips).
>> For ex: in hip06 djtag for CPU is v1 and for IO is v2.
>> so they use different readwrite handlers djtag_readwrite_(v1/2).
>>
>> + /* for hip06(D03) cpu die */
>> + { .compatible = "hisilicon,hip06-cpu-djtag-v1",
>> + .data = (void *)djtag_readwrite_v1 },
>> + /* for hip06(D03) io die */
>> + { .compatible = "hisilicon,hip06-io-djtag-v2",
>> + .data = (void *)djtag_readwrite_v2 },
>>
>>
>> For the same djtag version, there is no difference in handling in the
>> driver.
> Right, but my point was about the compatibility with the older chips
> using the same IP block, marking the ones as compatible that actually
> use the same interface.
>
> I also see that the compatible strings have the version included in
> them, and you can probably drop them by requiring them only in the
> fallback:
>
> compatible = "hisilicon,hip05-cpu-djtag", "hisilicon,djtag-v1";
> compatible = "hisilicon,hip05-io-djtag", "hisilicon,djtag-v1";
> compatible = "hisilicon,hip06-cpu-djtag", "hisilicon,djtag-v1";
> compatible = "hisilicon,hip06-io-djtag", "hisilicon,djtag-v2";
> compatible = "hisilicon,hip07-cpu-djtag", "hisilicon,djtag-v2";
> compatible = "hisilicon,hip07-io-djtag", "hisilicon,djtag-v2";
>
> We want to have the first entry be as specific as possible, but
> the last (second) entry is the one that can be used by the driver
> for matching. When a future hip08/hip09/... chip uses an existing
> interface, you then don't have to update the driver.
Thanks. I had a similar thought on this. So as I have the version string
in the
second entry "-v(1/2)".
I can use it in driver for matching. So i think I will change it as below.
Please correct me if my understanding is wrong.
static const struct of_device_id djtag_of_match[] = {
- /* for hip05(D02) cpu die */
- { .compatible = "hisilicon,hip05-cpu-djtag-v1",
+ /* for hisi djtag-v1 cpu die */
+ { .compatible = "hisilicon,hisi-cpu-djtag-v1",
.data = djtag_readwrite_v1 },
- /* for hip05(D02) io die */
- { .compatible = "hisilicon,hip05-io-djtag-v1",
+ /* for hisi djtag-v1 io die */
+ { .compatible = "hisilicon,hisi-io-djtag-v1",
.data = djtag_readwrite_v1 },
- /* for hip06(D03) cpu die */
- { .compatible = "hisilicon,hip06-cpu-djtag-v1",
- .data = djtag_readwrite_v1 },
- /* for hip06(D03) io die */
- { .compatible = "hisilicon,hip06-io-djtag-v2",
- .data = djtag_readwrite_v2 },
- /* for hip07(D05) cpu die */
- { .compatible = "hisilicon,hip07-cpu-djtag-v2",
+ /* for hisi djtag-v2 cpu die */
+ { .compatible = "hisilicon,hisi-cpu-djtag-v2",
.data = djtag_readwrite_v2 },
- /* for hip07(D05) io die */
- { .compatible = "hisilicon,hip07-io-djtag-v2",
+ /* for hisi djtag-v2 io die */
+ { .compatible = "hisilicon,hisi-io-djtag-v2",
.data = (djtag_readwrite_v2 },
{},
};
Thanks,
Anurup
> Arnd
^ permalink raw reply
* [PATCH v6] PM/devfreq: add suspend frequency support
From: Lin Huang @ 2016-11-09 3:37 UTC (permalink / raw)
To: linux-arm-kernel
Add suspend frequency support and if needed set it to
the frequency obtained from the suspend opp (can be defined
using opp-v2 bindings and is optional).
Signed-off-by: Lin Huang <hl@rock-chips.com>
---
Changes in v2:
- use update_devfreq() instead devfreq_update_status()
Changes in v3:
- fix build error
Changes in v4:
- move dev_pm_opp_get_suspend_opp() to devfreq_add_device()
Changes in v5:
- delete devfreq_opp_get_suspend_opp() in devfreq.h
Changes in v6:
- return to use stop_polling check suspend status
drivers/devfreq/devfreq.c | 14 +++++++++++---
drivers/devfreq/governor_simpleondemand.c | 9 +++++++++
include/linux/devfreq.h | 1 +
3 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index da72d97..cfa64a0 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -359,9 +359,11 @@ void devfreq_monitor_suspend(struct devfreq *devfreq)
mutex_unlock(&devfreq->lock);
return;
}
-
- devfreq_update_status(devfreq, devfreq->previous_freq);
devfreq->stop_polling = true;
+ if (devfreq->suspend_freq)
+ update_devfreq(devfreq);
+ else
+ devfreq_update_status(devfreq, devfreq->previous_freq);
mutex_unlock(&devfreq->lock);
cancel_delayed_work_sync(&devfreq->work);
}
@@ -390,7 +392,6 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
devfreq->last_stat_updated = jiffies;
devfreq->stop_polling = false;
-
if (devfreq->profile->get_cur_freq &&
!devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq))
devfreq->previous_freq = freq;
@@ -524,6 +525,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
struct devfreq *devfreq;
struct devfreq_governor *governor;
int err = 0;
+ struct dev_pm_opp *suspend_opp;
if (!dev || !profile || !governor_name) {
dev_err(dev, "%s: Invalid parameters.\n", __func__);
@@ -558,6 +560,12 @@ struct devfreq *devfreq_add_device(struct device *dev,
devfreq->data = data;
devfreq->nb.notifier_call = devfreq_notifier_call;
+ rcu_read_lock();
+ suspend_opp = dev_pm_opp_get_suspend_opp(dev);
+ if (suspend_opp)
+ devfreq->suspend_freq = dev_pm_opp_get_freq(suspend_opp);
+ rcu_read_unlock();
+
if (!devfreq->profile->max_state && !devfreq->profile->freq_table) {
mutex_unlock(&devfreq->lock);
devfreq_set_freq_table(devfreq);
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c
index ae72ba5..b82f089 100644
--- a/drivers/devfreq/governor_simpleondemand.c
+++ b/drivers/devfreq/governor_simpleondemand.c
@@ -29,6 +29,15 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
struct devfreq_simple_ondemand_data *data = df->data;
unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX;
+ /*
+ * if devfreq in suspend status and have suspend_freq,
+ * the frequency need to set to suspend_freq
+ */
+ if (df->stop_polling) {
+ *freq = df->suspend_freq;
+ return 0;
+ }
+
err = devfreq_update_stats(df);
if (err)
return err;
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 98c6993..517e394 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -172,6 +172,7 @@ struct devfreq {
struct delayed_work work;
unsigned long previous_freq;
+ unsigned long suspend_freq;
struct devfreq_dev_status last_status;
void *data; /* private data for governors */
--
2.6.6
^ permalink raw reply related
* [v16, 7/7] mmc: sdhci-of-esdhc: fix host version for T4240-R1.0-R2.0
From: Yangbo Lu @ 2016-11-09 3:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478661252-42439-1-git-send-email-yangbo.lu@nxp.com>
The eSDHC of T4240-R1.0-R2.0 has incorrect vender version and spec version.
Acturally the right version numbers should be VVN=0x13 and SVN = 0x1.
This patch adds the GUTS driver support for eSDHC driver to match SoC.
And fix host version to avoid that incorrect version numbers break down
the ADMA data transfer.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: Scott Wood <oss@buserror.net>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
Changes for v2:
- Got SVR through iomap instead of dts
Changes for v3:
- Managed GUTS through syscon instead of iomap in eSDHC driver
Changes for v4:
- Got SVR by GUTS driver instead of SYSCON
Changes for v5:
- Changed to get SVR through API fsl_guts_get_svr()
- Combined patch 4, patch 5 and patch 6 into one
Changes for v6:
- Added 'Acked-by: Ulf Hansson'
Changes for v7:
- None
Changes for v8:
- Added 'Acked-by: Scott Wood'
Changes for v9:
- None
Changes for v10:
- None
Changes for v11:
- Changed to use soc_device_match
Changes for v12:
- Matched soc through .family field instead of .soc_id
Changes for v13:
- None
Changes for v14:
- None
Changes for v15:
- None
Changes for v16:
- Added 'Acked-by: Arnd'
---
drivers/mmc/host/Kconfig | 1 +
drivers/mmc/host/sdhci-of-esdhc.c | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5cf7eba..4128a3c 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -144,6 +144,7 @@ config MMC_SDHCI_OF_ESDHC
depends on MMC_SDHCI_PLTFM
depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE
select MMC_SDHCI_IO_ACCESSORS
+ select FSL_GUTS
help
This selects the Freescale eSDHC controller support.
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index fb71c86..57bdb9e 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -18,6 +18,7 @@
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/sys_soc.h>
#include <linux/mmc/host.h>
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
@@ -28,6 +29,7 @@
struct sdhci_esdhc {
u8 vendor_ver;
u8 spec_ver;
+ bool quirk_incorrect_hostver;
};
/**
@@ -73,6 +75,8 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host,
static u16 esdhc_readw_fixup(struct sdhci_host *host,
int spec_reg, u32 value)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
u16 ret;
int shift = (spec_reg & 0x2) * 8;
@@ -80,6 +84,12 @@ static u16 esdhc_readw_fixup(struct sdhci_host *host,
ret = value & 0xffff;
else
ret = (value >> shift) & 0xffff;
+ /* Workaround for T4240-R1.0-R2.0 eSDHC which has incorrect
+ * vendor version and spec version information.
+ */
+ if ((spec_reg == SDHCI_HOST_VERSION) &&
+ (esdhc->quirk_incorrect_hostver))
+ ret = (VENDOR_V_23 << SDHCI_VENDOR_VER_SHIFT) | SDHCI_SPEC_200;
return ret;
}
@@ -558,6 +568,12 @@ static const struct sdhci_pltfm_data sdhci_esdhc_le_pdata = {
.ops = &sdhci_esdhc_le_ops,
};
+static struct soc_device_attribute soc_incorrect_hostver[] = {
+ { .family = "QorIQ T4240", .revision = "1.0", },
+ { .family = "QorIQ T4240", .revision = "2.0", },
+ { },
+};
+
static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host;
@@ -571,6 +587,10 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >>
SDHCI_VENDOR_VER_SHIFT;
esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK;
+ if (soc_device_match(soc_incorrect_hostver))
+ esdhc->quirk_incorrect_hostver = true;
+ else
+ esdhc->quirk_incorrect_hostver = false;
}
static int sdhci_esdhc_probe(struct platform_device *pdev)
--
2.1.0.27.g96db324
^ permalink raw reply related
* [v16, 6/7] base: soc: Check for NULL SoC device attributes
From: Yangbo Lu @ 2016-11-09 3:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478661252-42439-1-git-send-email-yangbo.lu@nxp.com>
From: Geert Uytterhoeven <geert+renesas@glider.be>
If soc_device_match() is used to check the value of a specific
attribute that is not present for the current SoC, the kernel crashes
with a NULL pointer dereference.
Fix this by explicitly checking for the absence of a needed property,
and considering this a non-match.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
Changes for v16:
- Added this patch
---
drivers/base/soc.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
index 0c5cf87..0e701e2 100644
--- a/drivers/base/soc.c
+++ b/drivers/base/soc.c
@@ -167,19 +167,23 @@ static int soc_device_match_one(struct device *dev, void *arg)
const struct soc_device_attribute *match = arg;
if (match->machine &&
- !glob_match(match->machine, soc_dev->attr->machine))
+ (!soc_dev->attr->machine ||
+ !glob_match(match->machine, soc_dev->attr->machine)))
return 0;
if (match->family &&
- !glob_match(match->family, soc_dev->attr->family))
+ (!soc_dev->attr->family ||
+ !glob_match(match->family, soc_dev->attr->family)))
return 0;
if (match->revision &&
- !glob_match(match->revision, soc_dev->attr->revision))
+ (!soc_dev->attr->revision ||
+ !glob_match(match->revision, soc_dev->attr->revision)))
return 0;
if (match->soc_id &&
- !glob_match(match->soc_id, soc_dev->attr->soc_id))
+ (!soc_dev->attr->soc_id ||
+ !glob_match(match->soc_id, soc_dev->attr->soc_id)))
return 0;
return 1;
--
2.1.0.27.g96db324
^ permalink raw reply related
* [v16, 5/7] base: soc: introduce soc_device_match() interface
From: Yangbo Lu @ 2016-11-09 3:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478661252-42439-1-git-send-email-yangbo.lu@nxp.com>
From: Arnd Bergmann <arnd@arndb.de>
We keep running into cases where device drivers want to know the exact
version of the a SoC they are currently running on. In the past, this has
usually been done through a vendor specific API that can be called by a
driver, or by directly accessing some kind of version register that is
not part of the device itself but that belongs to a global register area
of the chip.
Common reasons for doing this include:
- A machine is not using devicetree or similar for passing data about
on-chip devices, but just announces their presence using boot-time
platform devices, and the machine code itself does not care about the
revision.
- There is existing firmware or boot loaders with existing DT binaries
with generic compatible strings that do not identify the particular
revision of each device, but the driver knows which SoC revisions
include which part.
- A prerelease version of a chip has some quirks and we are using the same
version of the bootloader and the DT blob on both the prerelease and the
final version. An update of the DT binding seems inappropriate because
that would involve maintaining multiple copies of the dts and/or
bootloader.
This patch introduces the soc_device_match() interface that is meant to
work like of_match_node() but instead of identifying the version of a
device, it identifies the SoC itself using a vendor-agnostic interface.
Unlike of_match_node(), we do not do an exact string compare but instead
use glob_match() to allow wildcards in strings.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
Changes for v11:
- Added this patch for soc match
Changes for v12:
- Corrected the author
- Rewrited soc_device_match with while loop
Changes for v13:
- Added ack from Greg
Changes for v14:
- None
Changes for v15:
- None
Changes for v16:
- None
---
drivers/base/Kconfig | 1 +
drivers/base/soc.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/sys_soc.h | 3 +++
3 files changed, 70 insertions(+)
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index d02e7c0..2abea87 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -237,6 +237,7 @@ config GENERIC_CPU_AUTOPROBE
config SOC_BUS
bool
+ select GLOB
source "drivers/base/regmap/Kconfig"
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
index b63f23e..0c5cf87 100644
--- a/drivers/base/soc.c
+++ b/drivers/base/soc.c
@@ -13,6 +13,7 @@
#include <linux/spinlock.h>
#include <linux/sys_soc.h>
#include <linux/err.h>
+#include <linux/glob.h>
static DEFINE_IDA(soc_ida);
@@ -159,3 +160,68 @@ static int __init soc_bus_register(void)
return bus_register(&soc_bus_type);
}
core_initcall(soc_bus_register);
+
+static int soc_device_match_one(struct device *dev, void *arg)
+{
+ struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+ const struct soc_device_attribute *match = arg;
+
+ if (match->machine &&
+ !glob_match(match->machine, soc_dev->attr->machine))
+ return 0;
+
+ if (match->family &&
+ !glob_match(match->family, soc_dev->attr->family))
+ return 0;
+
+ if (match->revision &&
+ !glob_match(match->revision, soc_dev->attr->revision))
+ return 0;
+
+ if (match->soc_id &&
+ !glob_match(match->soc_id, soc_dev->attr->soc_id))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * soc_device_match - identify the SoC in the machine
+ * @matches: zero-terminated array of possible matches
+ *
+ * returns the first matching entry of the argument array, or NULL
+ * if none of them match.
+ *
+ * This function is meant as a helper in place of of_match_node()
+ * in cases where either no device tree is available or the information
+ * in a device node is insufficient to identify a particular variant
+ * by its compatible strings or other properties. For new devices,
+ * the DT binding should always provide unique compatible strings
+ * that allow the use of of_match_node() instead.
+ *
+ * The calling function can use the .data entry of the
+ * soc_device_attribute to pass a structure or function pointer for
+ * each entry.
+ */
+const struct soc_device_attribute *soc_device_match(
+ const struct soc_device_attribute *matches)
+{
+ int ret = 0;
+
+ if (!matches)
+ return NULL;
+
+ while (!ret) {
+ if (!(matches->machine || matches->family ||
+ matches->revision || matches->soc_id))
+ break;
+ ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
+ soc_device_match_one);
+ if (!ret)
+ matches++;
+ else
+ return matches;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(soc_device_match);
diff --git a/include/linux/sys_soc.h b/include/linux/sys_soc.h
index 2739ccb..9f5eb06 100644
--- a/include/linux/sys_soc.h
+++ b/include/linux/sys_soc.h
@@ -13,6 +13,7 @@ struct soc_device_attribute {
const char *family;
const char *revision;
const char *soc_id;
+ const void *data;
};
/**
@@ -34,4 +35,6 @@ void soc_device_unregister(struct soc_device *soc_dev);
*/
struct device *soc_device_to_device(struct soc_device *soc);
+const struct soc_device_attribute *soc_device_match(
+ const struct soc_device_attribute *matches);
#endif /* __SOC_BUS_H */
--
2.1.0.27.g96db324
^ permalink raw reply related
* [v16, 4/7] MAINTAINERS: add entry for Freescale SoC drivers
From: Yangbo Lu @ 2016-11-09 3:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478661252-42439-1-git-send-email-yangbo.lu@nxp.com>
Add maintainer entry for Freescale SoC drivers including
the QE library and the GUTS driver now. Also add maintainer
for QE library.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Acked-by: Scott Wood <oss@buserror.net>
Acked-by: Qiang Zhao <qiang.zhao@nxp.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
Changes for v8:
- Added this patch
Changes for v9:
- Added linux-arm mail list
- Removed GUTS driver entry
Changes for v10:
- Changed 'DRIVER' to 'DRIVERS'
- Added 'Acked-by' of Scott and Qiang
Changes for v11:
- None
Changes for v12:
- None
Changes for v13:
- None
Changes for v14:
- None
Changes for v15:
- None
Changes for v16:
- Added 'Acked-by: Arnd'
---
MAINTAINERS | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 9be761f..e1a8835 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5045,9 +5045,18 @@ S: Maintained
F: drivers/net/ethernet/freescale/fman
F: Documentation/devicetree/bindings/powerpc/fsl/fman.txt
+FREESCALE SOC DRIVERS
+M: Scott Wood <oss@buserror.net>
+L: linuxppc-dev at lists.ozlabs.org
+L: linux-arm-kernel at lists.infradead.org
+S: Maintained
+F: drivers/soc/fsl/
+F: include/linux/fsl/
+
FREESCALE QUICC ENGINE LIBRARY
+M: Qiang Zhao <qiang.zhao@nxp.com>
L: linuxppc-dev at lists.ozlabs.org
-S: Orphan
+S: Maintained
F: drivers/soc/fsl/qe/
F: include/soc/fsl/*qe*.h
F: include/soc/fsl/*ucc*.h
--
2.1.0.27.g96db324
^ permalink raw reply related
* [v16, 3/7] soc: fsl: add GUTS driver for QorIQ platforms
From: Yangbo Lu @ 2016-11-09 3:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478661252-42439-1-git-send-email-yangbo.lu@nxp.com>
The global utilities block controls power management, I/O device
enabling, power-onreset(POR) configuration monitoring, alternate
function selection for multiplexed signals,and clock control.
This patch adds a driver to manage and access global utilities block.
Initially only reading SVR and registering soc device are supported.
Other guts accesses, such as reading RCW, should eventually be moved
into this driver as well.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
Changes for v4:
- Added this patch
Changes for v5:
- Modified copyright info
- Changed MODULE_LICENSE to GPL
- Changed EXPORT_SYMBOL_GPL to EXPORT_SYMBOL
- Made FSL_GUTS user-invisible
- Added a complete compatible list for GUTS
- Stored guts info in file-scope variable
- Added mfspr() getting SVR
- Redefined GUTS APIs
- Called fsl_guts_init rather than using platform driver
- Removed useless parentheses
- Removed useless 'extern' key words
Changes for v6:
- Made guts thread safe in fsl_guts_init
Changes for v7:
- Removed 'ifdef' for function declaration in guts.h
Changes for v8:
- Fixes lines longer than 80 characters checkpatch issue
- Added 'Acked-by: Scott Wood'
Changes for v9:
- None
Changes for v10:
- None
Changes for v11:
- Changed to platform driver
Changes for v12:
- Removed "signed-off-by: Scott"
- Defined fsl_soc_die_attr struct array instead of
soc_device_attribute
- Re-designed soc_device_attribute for QorIQ SoC
- Other minor fixes
Changes for v13:
- Rebased
- Removed text after 'bool' in Kconfig
- Removed ARCH ifdefs
- Added more bits for ls1021a mask
- Used devm
Changes for v14:
- Used devm_ioremap_resource
Changes for v15:
- Fixed error code for devm_ioremap_resource
Changes for v16:
- Removed header file svr.h and calculated REV_MAJ/MIN in this driver
- Added 'Acked-by: Arnd'
---
drivers/soc/Kconfig | 3 +-
drivers/soc/fsl/Kconfig | 18 ++++
drivers/soc/fsl/Makefile | 1 +
drivers/soc/fsl/guts.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/fsl/guts.h | 125 +++++++++++++++----------
5 files changed, 333 insertions(+), 50 deletions(-)
create mode 100644 drivers/soc/fsl/Kconfig
create mode 100644 drivers/soc/fsl/guts.c
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index e6e90e8..f31bceb 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -1,8 +1,7 @@
menu "SOC (System On Chip) specific Drivers"
source "drivers/soc/bcm/Kconfig"
-source "drivers/soc/fsl/qbman/Kconfig"
-source "drivers/soc/fsl/qe/Kconfig"
+source "drivers/soc/fsl/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/qcom/Kconfig"
source "drivers/soc/rockchip/Kconfig"
diff --git a/drivers/soc/fsl/Kconfig b/drivers/soc/fsl/Kconfig
new file mode 100644
index 0000000..7a9fb9b
--- /dev/null
+++ b/drivers/soc/fsl/Kconfig
@@ -0,0 +1,18 @@
+#
+# Freescale SOC drivers
+#
+
+source "drivers/soc/fsl/qbman/Kconfig"
+source "drivers/soc/fsl/qe/Kconfig"
+
+config FSL_GUTS
+ bool
+ select SOC_BUS
+ help
+ The global utilities block controls power management, I/O device
+ enabling, power-onreset(POR) configuration monitoring, alternate
+ function selection for multiplexed signals,and clock control.
+ This driver is to manage and access global utilities block.
+ Initially only reading SVR and registering soc device are supported.
+ Other guts accesses, such as reading RCW, should eventually be moved
+ into this driver as well.
diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile
index 75e1f53..44b3beb 100644
--- a/drivers/soc/fsl/Makefile
+++ b/drivers/soc/fsl/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_FSL_DPAA) += qbman/
obj-$(CONFIG_QUICC_ENGINE) += qe/
obj-$(CONFIG_CPM) += qe/
+obj-$(CONFIG_FSL_GUTS) += guts.o
diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c
new file mode 100644
index 0000000..0ac8826
--- /dev/null
+++ b/drivers/soc/fsl/guts.c
@@ -0,0 +1,236 @@
+/*
+ * Freescale QorIQ Platforms GUTS Driver
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_fdt.h>
+#include <linux/sys_soc.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/fsl/guts.h>
+
+struct guts {
+ struct ccsr_guts __iomem *regs;
+ bool little_endian;
+};
+
+struct fsl_soc_die_attr {
+ char *die;
+ u32 svr;
+ u32 mask;
+};
+
+static struct guts *guts;
+static struct soc_device_attribute soc_dev_attr;
+static struct soc_device *soc_dev;
+
+
+/* SoC die attribute definition for QorIQ platform */
+static const struct fsl_soc_die_attr fsl_soc_die[] = {
+ /*
+ * Power Architecture-based SoCs T Series
+ */
+
+ /* Die: T4240, SoC: T4240/T4160/T4080 */
+ { .die = "T4240",
+ .svr = 0x82400000,
+ .mask = 0xfff00000,
+ },
+ /* Die: T1040, SoC: T1040/T1020/T1042/T1022 */
+ { .die = "T1040",
+ .svr = 0x85200000,
+ .mask = 0xfff00000,
+ },
+ /* Die: T2080, SoC: T2080/T2081 */
+ { .die = "T2080",
+ .svr = 0x85300000,
+ .mask = 0xfff00000,
+ },
+ /* Die: T1024, SoC: T1024/T1014/T1023/T1013 */
+ { .die = "T1024",
+ .svr = 0x85400000,
+ .mask = 0xfff00000,
+ },
+
+ /*
+ * ARM-based SoCs LS Series
+ */
+
+ /* Die: LS1043A, SoC: LS1043A/LS1023A */
+ { .die = "LS1043A",
+ .svr = 0x87920000,
+ .mask = 0xffff0000,
+ },
+ /* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */
+ { .die = "LS2080A",
+ .svr = 0x87010000,
+ .mask = 0xff3f0000,
+ },
+ /* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */
+ { .die = "LS1088A",
+ .svr = 0x87030000,
+ .mask = 0xff3f0000,
+ },
+ /* Die: LS1012A, SoC: LS1012A */
+ { .die = "LS1012A",
+ .svr = 0x87040000,
+ .mask = 0xffff0000,
+ },
+ /* Die: LS1046A, SoC: LS1046A/LS1026A */
+ { .die = "LS1046A",
+ .svr = 0x87070000,
+ .mask = 0xffff0000,
+ },
+ /* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */
+ { .die = "LS2088A",
+ .svr = 0x87090000,
+ .mask = 0xff3f0000,
+ },
+ /* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */
+ { .die = "LS1021A",
+ .svr = 0x87000000,
+ .mask = 0xfff70000,
+ },
+ { },
+};
+
+static const struct fsl_soc_die_attr *fsl_soc_die_match(
+ u32 svr, const struct fsl_soc_die_attr *matches)
+{
+ while (matches->svr) {
+ if (matches->svr == (svr & matches->mask))
+ return matches;
+ matches++;
+ };
+ return NULL;
+}
+
+u32 fsl_guts_get_svr(void)
+{
+ u32 svr = 0;
+
+ if (!guts || !guts->regs)
+ return svr;
+
+ if (guts->little_endian)
+ svr = ioread32(&guts->regs->svr);
+ else
+ svr = ioread32be(&guts->regs->svr);
+
+ return svr;
+}
+EXPORT_SYMBOL(fsl_guts_get_svr);
+
+static int fsl_guts_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ const struct fsl_soc_die_attr *soc_die;
+ const char *machine;
+ u32 svr;
+
+ /* Initialize guts */
+ guts = devm_kzalloc(dev, sizeof(*guts), GFP_KERNEL);
+ if (!guts)
+ return -ENOMEM;
+
+ guts->little_endian = of_property_read_bool(np, "little-endian");
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ guts->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(guts->regs))
+ return PTR_ERR(guts->regs);
+
+ /* Register soc device */
+ machine = of_flat_dt_get_machine_name();
+ if (machine)
+ soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
+
+ svr = fsl_guts_get_svr();
+ soc_die = fsl_soc_die_match(svr, fsl_soc_die);
+ if (soc_die) {
+ soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
+ "QorIQ %s", soc_die->die);
+ } else {
+ soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, "QorIQ");
+ }
+ soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL,
+ "svr:0x%08x", svr);
+ soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
+ (svr >> 4) & 0xf, svr & 0xf);
+
+ soc_dev = soc_device_register(&soc_dev_attr);
+ if (IS_ERR(soc_dev))
+ return PTR_ERR(soc_dev);
+
+ pr_info("Machine: %s\n", soc_dev_attr.machine);
+ pr_info("SoC family: %s\n", soc_dev_attr.family);
+ pr_info("SoC ID: %s, Revision: %s\n",
+ soc_dev_attr.soc_id, soc_dev_attr.revision);
+ return 0;
+}
+
+static int fsl_guts_remove(struct platform_device *dev)
+{
+ soc_device_unregister(soc_dev);
+ return 0;
+}
+
+/*
+ * Table for matching compatible strings, for device tree
+ * guts node, for Freescale QorIQ SOCs.
+ */
+static const struct of_device_id fsl_guts_of_match[] = {
+ { .compatible = "fsl,qoriq-device-config-1.0", },
+ { .compatible = "fsl,qoriq-device-config-2.0", },
+ { .compatible = "fsl,p1010-guts", },
+ { .compatible = "fsl,p1020-guts", },
+ { .compatible = "fsl,p1021-guts", },
+ { .compatible = "fsl,p1022-guts", },
+ { .compatible = "fsl,p1023-guts", },
+ { .compatible = "fsl,p2020-guts", },
+ { .compatible = "fsl,bsc9131-guts", },
+ { .compatible = "fsl,bsc9132-guts", },
+ { .compatible = "fsl,mpc8536-guts", },
+ { .compatible = "fsl,mpc8544-guts", },
+ { .compatible = "fsl,mpc8548-guts", },
+ { .compatible = "fsl,mpc8568-guts", },
+ { .compatible = "fsl,mpc8569-guts", },
+ { .compatible = "fsl,mpc8572-guts", },
+ { .compatible = "fsl,ls1021a-dcfg", },
+ { .compatible = "fsl,ls1043a-dcfg", },
+ { .compatible = "fsl,ls2080a-dcfg", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_guts_of_match);
+
+static struct platform_driver fsl_guts_driver = {
+ .driver = {
+ .name = "fsl-guts",
+ .of_match_table = fsl_guts_of_match,
+ },
+ .probe = fsl_guts_probe,
+ .remove = fsl_guts_remove,
+};
+
+static int __init fsl_guts_init(void)
+{
+ return platform_driver_register(&fsl_guts_driver);
+}
+core_initcall(fsl_guts_init);
+
+static void __exit fsl_guts_exit(void)
+{
+ platform_driver_unregister(&fsl_guts_driver);
+}
+module_exit(fsl_guts_exit);
diff --git a/include/linux/fsl/guts.h b/include/linux/fsl/guts.h
index 649e917..3efa3b8 100644
--- a/include/linux/fsl/guts.h
+++ b/include/linux/fsl/guts.h
@@ -29,83 +29,112 @@
* #ifdefs.
*/
struct ccsr_guts {
- __be32 porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */
- __be32 porbmsr; /* 0x.0004 - POR Boot Mode Status Register */
- __be32 porimpscr; /* 0x.0008 - POR I/O Impedance Status and Control Register */
- __be32 pordevsr; /* 0x.000c - POR I/O Device Status Register */
- __be32 pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */
- __be32 pordevsr2; /* 0x.0014 - POR device status register 2 */
+ u32 porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */
+ u32 porbmsr; /* 0x.0004 - POR Boot Mode Status Register */
+ u32 porimpscr; /* 0x.0008 - POR I/O Impedance Status and
+ * Control Register
+ */
+ u32 pordevsr; /* 0x.000c - POR I/O Device Status Register */
+ u32 pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */
+ u32 pordevsr2; /* 0x.0014 - POR device status register 2 */
u8 res018[0x20 - 0x18];
- __be32 porcir; /* 0x.0020 - POR Configuration Information Register */
+ u32 porcir; /* 0x.0020 - POR Configuration Information
+ * Register
+ */
u8 res024[0x30 - 0x24];
- __be32 gpiocr; /* 0x.0030 - GPIO Control Register */
+ u32 gpiocr; /* 0x.0030 - GPIO Control Register */
u8 res034[0x40 - 0x34];
- __be32 gpoutdr; /* 0x.0040 - General-Purpose Output Data Register */
+ u32 gpoutdr; /* 0x.0040 - General-Purpose Output Data
+ * Register
+ */
u8 res044[0x50 - 0x44];
- __be32 gpindr; /* 0x.0050 - General-Purpose Input Data Register */
+ u32 gpindr; /* 0x.0050 - General-Purpose Input Data
+ * Register
+ */
u8 res054[0x60 - 0x54];
- __be32 pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex Control */
- __be32 pmuxcr2; /* 0x.0064 - Alternate function signal multiplex control 2 */
- __be32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */
+ u32 pmuxcr; /* 0x.0060 - Alternate Function Signal
+ * Multiplex Control
+ */
+ u32 pmuxcr2; /* 0x.0064 - Alternate function signal
+ * multiplex control 2
+ */
+ u32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */
u8 res06c[0x70 - 0x6c];
- __be32 devdisr; /* 0x.0070 - Device Disable Control */
+ u32 devdisr; /* 0x.0070 - Device Disable Control */
#define CCSR_GUTS_DEVDISR_TB1 0x00001000
#define CCSR_GUTS_DEVDISR_TB0 0x00004000
- __be32 devdisr2; /* 0x.0074 - Device Disable Control 2 */
+ u32 devdisr2; /* 0x.0074 - Device Disable Control 2 */
u8 res078[0x7c - 0x78];
- __be32 pmjcr; /* 0x.007c - 4 Power Management Jog Control Register */
- __be32 powmgtcsr; /* 0x.0080 - Power Management Status and Control Register */
- __be32 pmrccr; /* 0x.0084 - Power Management Reset Counter Configuration Register */
- __be32 pmpdccr; /* 0x.0088 - Power Management Power Down Counter Configuration Register */
- __be32 pmcdr; /* 0x.008c - 4Power management clock disable register */
- __be32 mcpsumr; /* 0x.0090 - Machine Check Summary Register */
- __be32 rstrscr; /* 0x.0094 - Reset Request Status and Control Register */
- __be32 ectrstcr; /* 0x.0098 - Exception reset control register */
- __be32 autorstsr; /* 0x.009c - Automatic reset status register */
- __be32 pvr; /* 0x.00a0 - Processor Version Register */
- __be32 svr; /* 0x.00a4 - System Version Register */
+ u32 pmjcr; /* 0x.007c - 4 Power Management Jog Control
+ * Register
+ */
+ u32 powmgtcsr; /* 0x.0080 - Power Management Status and
+ * Control Register
+ */
+ u32 pmrccr; /* 0x.0084 - Power Management Reset Counter
+ * Configuration Register
+ */
+ u32 pmpdccr; /* 0x.0088 - Power Management Power Down Counter
+ * Configuration Register
+ */
+ u32 pmcdr; /* 0x.008c - 4Power management clock disable
+ * register
+ */
+ u32 mcpsumr; /* 0x.0090 - Machine Check Summary Register */
+ u32 rstrscr; /* 0x.0094 - Reset Request Status and
+ * Control Register
+ */
+ u32 ectrstcr; /* 0x.0098 - Exception reset control register */
+ u32 autorstsr; /* 0x.009c - Automatic reset status register */
+ u32 pvr; /* 0x.00a0 - Processor Version Register */
+ u32 svr; /* 0x.00a4 - System Version Register */
u8 res0a8[0xb0 - 0xa8];
- __be32 rstcr; /* 0x.00b0 - Reset Control Register */
+ u32 rstcr; /* 0x.00b0 - Reset Control Register */
u8 res0b4[0xc0 - 0xb4];
- __be32 iovselsr; /* 0x.00c0 - I/O voltage select status register
+ u32 iovselsr; /* 0x.00c0 - I/O voltage select status register
Called 'elbcvselcr' on 86xx SOCs */
u8 res0c4[0x100 - 0xc4];
- __be32 rcwsr[16]; /* 0x.0100 - Reset Control Word Status registers
+ u32 rcwsr[16]; /* 0x.0100 - Reset Control Word Status registers
There are 16 registers */
u8 res140[0x224 - 0x140];
- __be32 iodelay1; /* 0x.0224 - IO delay control register 1 */
- __be32 iodelay2; /* 0x.0228 - IO delay control register 2 */
+ u32 iodelay1; /* 0x.0224 - IO delay control register 1 */
+ u32 iodelay2; /* 0x.0228 - IO delay control register 2 */
u8 res22c[0x604 - 0x22c];
- __be32 pamubypenr; /* 0x.604 - PAMU bypass enable register */
+ u32 pamubypenr; /* 0x.604 - PAMU bypass enable register */
u8 res608[0x800 - 0x608];
- __be32 clkdvdr; /* 0x.0800 - Clock Divide Register */
+ u32 clkdvdr; /* 0x.0800 - Clock Divide Register */
u8 res804[0x900 - 0x804];
- __be32 ircr; /* 0x.0900 - Infrared Control Register */
+ u32 ircr; /* 0x.0900 - Infrared Control Register */
u8 res904[0x908 - 0x904];
- __be32 dmacr; /* 0x.0908 - DMA Control Register */
+ u32 dmacr; /* 0x.0908 - DMA Control Register */
u8 res90c[0x914 - 0x90c];
- __be32 elbccr; /* 0x.0914 - eLBC Control Register */
+ u32 elbccr; /* 0x.0914 - eLBC Control Register */
u8 res918[0xb20 - 0x918];
- __be32 ddr1clkdr; /* 0x.0b20 - DDR1 Clock Disable Register */
- __be32 ddr2clkdr; /* 0x.0b24 - DDR2 Clock Disable Register */
- __be32 ddrclkdr; /* 0x.0b28 - DDR Clock Disable Register */
+ u32 ddr1clkdr; /* 0x.0b20 - DDR1 Clock Disable Register */
+ u32 ddr2clkdr; /* 0x.0b24 - DDR2 Clock Disable Register */
+ u32 ddrclkdr; /* 0x.0b28 - DDR Clock Disable Register */
u8 resb2c[0xe00 - 0xb2c];
- __be32 clkocr; /* 0x.0e00 - Clock Out Select Register */
+ u32 clkocr; /* 0x.0e00 - Clock Out Select Register */
u8 rese04[0xe10 - 0xe04];
- __be32 ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */
+ u32 ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */
u8 rese14[0xe20 - 0xe14];
- __be32 lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */
- __be32 cpfor; /* 0x.0e24 - L2 charge pump fuse override register */
+ u32 lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */
+ u32 cpfor; /* 0x.0e24 - L2 charge pump fuse override
+ * register
+ */
u8 rese28[0xf04 - 0xe28];
- __be32 srds1cr0; /* 0x.0f04 - SerDes1 Control Register 0 */
- __be32 srds1cr1; /* 0x.0f08 - SerDes1 Control Register 0 */
+ u32 srds1cr0; /* 0x.0f04 - SerDes1 Control Register 0 */
+ u32 srds1cr1; /* 0x.0f08 - SerDes1 Control Register 0 */
u8 resf0c[0xf2c - 0xf0c];
- __be32 itcr; /* 0x.0f2c - Internal transaction control register */
+ u32 itcr; /* 0x.0f2c - Internal transaction control
+ * register
+ */
u8 resf30[0xf40 - 0xf30];
- __be32 srds2cr0; /* 0x.0f40 - SerDes2 Control Register 0 */
- __be32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */
+ u32 srds2cr0; /* 0x.0f40 - SerDes2 Control Register 0 */
+ u32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */
} __attribute__ ((packed));
+u32 fsl_guts_get_svr(void);
/* Alternate function signal multiplex control */
#define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x))
--
2.1.0.27.g96db324
^ permalink raw reply related
* [v16, 2/7] dt: bindings: move guts devicetree doc out of powerpc directory
From: Yangbo Lu @ 2016-11-09 3:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478661252-42439-1-git-send-email-yangbo.lu@nxp.com>
Move guts devicetree doc to Documentation/devicetree/bindings/soc/fsl/
since it's used by not only PowerPC but also ARM. And add a specification
for 'little-endian' property.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
Acked-by: Scott Wood <oss@buserror.net>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
Changes for v4:
- Added this patch
Changes for v5:
- Modified the description for little-endian property
Changes for v6:
- None
Changes for v7:
- None
Changes for v8:
- Added 'Acked-by: Scott Wood'
- Added 'Acked-by: Rob Herring'
Changes for v9:
- None
Changes for v10:
- None
Changes for v11:
- None
Changes for v12:
- None
Changes for v13:
- None
Changes for v14:
- None
Changes for v15:
- None
Changes for v16:
- Added 'Acked-by: Arnd'
---
Documentation/devicetree/bindings/{powerpc => soc}/fsl/guts.txt | 3 +++
1 file changed, 3 insertions(+)
rename Documentation/devicetree/bindings/{powerpc => soc}/fsl/guts.txt (91%)
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/guts.txt b/Documentation/devicetree/bindings/soc/fsl/guts.txt
similarity index 91%
rename from Documentation/devicetree/bindings/powerpc/fsl/guts.txt
rename to Documentation/devicetree/bindings/soc/fsl/guts.txt
index b71b203..07adca9 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/guts.txt
+++ b/Documentation/devicetree/bindings/soc/fsl/guts.txt
@@ -25,6 +25,9 @@ Recommended properties:
- fsl,liodn-bits : Indicates the number of defined bits in the LIODN
registers, for those SOCs that have a PAMU device.
+ - little-endian : Indicates that the global utilities block is little
+ endian. The default is big endian.
+
Examples:
global-utilities at e0000 { /* global utilities block */
compatible = "fsl,mpc8548-guts";
--
2.1.0.27.g96db324
^ permalink raw reply related
* [v16, 1/7] ARM64: dts: ls2080a: add device configuration node
From: Yangbo Lu @ 2016-11-09 3:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478661252-42439-1-git-send-email-yangbo.lu@nxp.com>
Add the dts node for device configuration unit that provides
general purpose configuration and status for the device.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Acked-by: Scott Wood <oss@buserror.net>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
Changes for v5:
- Added this patch
Changes for v6:
- None
Changes for v7:
- None
Changes for v8:
- Added 'Acked-by: Scott Wood'
Changes for v9:
- None
Changes for v10:
- None
Changes for v11:
- None
Changes for v12:
- None
Changes for v13:
- None
Changes for v14:
- None
Changes for v15:
- None
Changes for v16:
- Added 'Acked-by: Arnd'
---
arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
index 7f0dc13..d058e56 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
@@ -216,6 +216,12 @@
clocks = <&sysclk>;
};
+ dcfg: dcfg at 1e00000 {
+ compatible = "fsl,ls2080a-dcfg", "syscon";
+ reg = <0x0 0x1e00000 0x0 0x10000>;
+ little-endian;
+ };
+
serial0: serial at 21c0500 {
compatible = "fsl,ns16550", "ns16550a";
reg = <0x0 0x21c0500 0x0 0x100>;
--
2.1.0.27.g96db324
^ permalink raw reply related
* [v16, 0/7] Fix eSDHC host version register bug
From: Yangbo Lu @ 2016-11-09 3:14 UTC (permalink / raw)
To: linux-arm-kernel
This patchset is used to fix a host version register bug in the T4240-R1.0-R2.0
eSDHC controller. To match the SoC version and revision, 15 previous version
patchsets had tried many methods but all of them were rejected by reviewers.
Such as
- dts compatible method
- syscon method
- ifdef PPC method
- GUTS driver getting SVR method
Anrd suggested a soc_device_match method in v10, and this is the only available
method left now. This v11 patchset introduces the soc_device_match interface in
soc driver.
The first four patches of Yangbo are to add the GUTS driver. This is used to
register a soc device which contain soc version and revision information.
The other three patches introduce the soc_device_match method in soc driver
and apply it on esdhc driver to fix this bug.
---
Changes for v15:
- Dropped patch 'dt: bindings: update Freescale DCFG compatible'
since the work had been done by below patch on ShawnGuo's linux tree.
'dt-bindings: fsl: add LS1043A/LS1046A/LS2080A compatible for SCFG
and DCFG'
- Fixed error code issue in guts driver
Changes for v16:
- Dropped patch 'powerpc/fsl: move mpc85xx.h to include/linux/fsl'
- Added a bug-fix patch from Geert
---
Arnd Bergmann (1):
base: soc: introduce soc_device_match() interface
Geert Uytterhoeven (1):
base: soc: Check for NULL SoC device attributes
Yangbo Lu (5):
ARM64: dts: ls2080a: add device configuration node
dt: bindings: move guts devicetree doc out of powerpc directory
soc: fsl: add GUTS driver for QorIQ platforms
MAINTAINERS: add entry for Freescale SoC drivers
mmc: sdhci-of-esdhc: fix host version for T4240-R1.0-R2.0
.../bindings/{powerpc => soc}/fsl/guts.txt | 3 +
MAINTAINERS | 11 +-
arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi | 6 +
drivers/base/Kconfig | 1 +
drivers/base/soc.c | 70 ++++++
drivers/mmc/host/Kconfig | 1 +
drivers/mmc/host/sdhci-of-esdhc.c | 20 ++
drivers/soc/Kconfig | 3 +-
drivers/soc/fsl/Kconfig | 18 ++
drivers/soc/fsl/Makefile | 1 +
drivers/soc/fsl/guts.c | 236 +++++++++++++++++++++
include/linux/fsl/guts.h | 125 ++++++-----
include/linux/sys_soc.h | 3 +
13 files changed, 447 insertions(+), 51 deletions(-)
rename Documentation/devicetree/bindings/{powerpc => soc}/fsl/guts.txt (91%)
create mode 100644 drivers/soc/fsl/Kconfig
create mode 100644 drivers/soc/fsl/guts.c
--
2.1.0.27.g96db324
^ permalink raw reply
* Summary of LPC guest MSI discussion in Santa Fe
From: Don Dutile @ 2016-11-09 2:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161108163508.1bcae0c2@t450s.home>
On 11/08/2016 06:35 PM, Alex Williamson wrote:
> On Tue, 8 Nov 2016 21:29:22 +0100
> Christoffer Dall <christoffer.dall@linaro.org> wrote:
>
>> Hi Will,
>>
>> On Tue, Nov 08, 2016 at 02:45:59AM +0000, Will Deacon wrote:
>>> Hi all,
>>>
>>> I figured this was a reasonable post to piggy-back on for the LPC minutes
>>> relating to guest MSIs on arm64.
>>>
>>> On Thu, Nov 03, 2016 at 10:02:05PM -0600, Alex Williamson wrote:
>>>> We can always have QEMU reject hot-adding the device if the reserved
>>>> region overlaps existing guest RAM, but I don't even really see how we
>>>> advise users to give them a reasonable chance of avoiding that
>>>> possibility. Apparently there are also ARM platforms where MSI pages
>>>> cannot be remapped to support the previous programmable user/VM
>>>> address, is it even worthwhile to support those platforms? Does that
>>>> decision influence whether user programmable MSI reserved regions are
>>>> really a second class citizen to fixed reserved regions? I expect
>>>> we'll be talking about this tomorrow morning, but I certainly haven't
>>>> come up with any viable solutions to this. Thanks,
>>>
>>> At LPC last week, we discussed guest MSIs on arm64 as part of the PCI
>>> microconference. I presented some slides to illustrate some of the issues
>>> we're trying to solve:
>>>
>>> http://www.willdeacon.ukfsn.org/bitbucket/lpc-16/msi-in-guest-arm64.pdf
>>>
>>> Punit took some notes (thanks!) on the etherpad here:
>>>
>>> https://etherpad.openstack.org/p/LPC2016_PCI
>>>
>>> although the discussion was pretty lively and jumped about, so I've had
>>> to go from memory where the notes didn't capture everything that was
>>> said.
>>>
>>> To summarise, arm64 platforms differ in their handling of MSIs when compared
>>> to x86:
>>>
>>> 1. The physical memory map is not standardised (Jon pointed out that
>>> this is something that was realised late on)
>>> 2. MSIs are usually treated the same as DMA writes, in that they must be
>>> mapped by the SMMU page tables so that they target a physical MSI
>>> doorbell
>>> 3. On some platforms, MSIs bypass the SMMU entirely (e.g. due to an MSI
>>> doorbell built into the PCI RC)
>>> 4. Platforms typically have some set of addresses that abort before
>>> reaching the SMMU (e.g. because the PCI identifies them as P2P).
>>>
>>> All of this means that userspace (QEMU) needs to identify the memory
>>> regions corresponding to points (3) and (4) and ensure that they are
>>> not allocated in the guest physical (IPA) space. For platforms that can
>>> remap the MSI doorbell as in (2), then some space also needs to be
>>> allocated for that.
>>>
>>> Rather than treat these as separate problems, a better interface is to
>>> tell userspace about a set of reserved regions, and have this include
>>> the MSI doorbell, irrespective of whether or not it can be remapped.
>>
>> Is my understanding correct, that you need to tell userspace about the
>> location of the doorbell (in the IOVA space) in case (2), because even
>> though the configuration of the device is handled by the (host) kernel
>> through trapping of the BARs, we have to avoid the VFIO user programming
>> the device to create other DMA transactions to this particular address,
>> since that will obviously conflict and either not produce the desired
>> DMA transactions or result in unintended weird interrupts?
>
> Correct, if the MSI doorbell IOVA range overlaps RAM in the VM, then
> it's potentially a DMA target and we'll get bogus data on DMA read from
> the device, and lose data and potentially trigger spurious interrupts on
> DMA write from the device. Thanks,
>
> Alex
>
That's b/c the MSI doorbells are not positioned *above* the SMMU, i.e.,
they address match before the SMMU checks are done. if
all DMA addrs had to go through SMMU first, then the DMA access could
be ignored/rejected.
For bare-metal, memory can't be put in the same place as MSI addrs, or
DMA could never reach it. So, only a virt issue, unless the VMs mem address
range mimic the host layout.
- Don
^ permalink raw reply
* [PATCH] arm/arm64: KVM: clean up useless code in kvm_timer_enable
From: Longpeng(Mike) @ 2016-11-09 2:50 UTC (permalink / raw)
To: linux-arm-kernel
1) Since commit:41a54482 changed timer enabled variable to per-vcpu,
the correlative comment in kvm_timer_enable is useless now.
2) After the kvm module init successfully, the timecounter is always
non-null, so we can remove the checking of timercounter.
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
---
virt/kvm/arm/arch_timer.c | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 27a1f63..17b8fa5 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -498,17 +498,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
if (ret)
return ret;
-
- /*
- * There is a potential race here between VCPUs starting for the first
- * time, which may be enabling the timer multiple times. That doesn't
- * hurt though, because we're just setting a variable to the same
- * variable that it already was. The important thing is that all
- * VCPUs have the enabled variable set, before entering the guest, if
- * the arch timers are enabled.
- */
- if (timecounter)
- timer->enabled = 1;
+ timer->enabled = 1;
return 0;
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH] ARM: dts: imx7d-pinfunc: fix UART pinmux defines
From: Stefan Agner @ 2016-11-09 2:44 UTC (permalink / raw)
To: linux-arm-kernel
The UART pinmux defines for the pins which are part of the LPSR
pinmux controller are wrong: Output signals configure the input
sel value and the pinmux defines allow not to distinguish between
DCE/DTE mode. Follow the usual pattern using DTE/DCE as part of
the define to denote the two UART configuration options.
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
There is a similar patch downstream named:
"MLK-10662: arm: imx7d-pinfunc: fix uart input sel option value"
Tested using UART5 on a Colibri iMX7.
--
Stefan
arch/arm/boot/dts/imx7d-pinfunc.h | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/arch/arm/boot/dts/imx7d-pinfunc.h b/arch/arm/boot/dts/imx7d-pinfunc.h
index 3f9f0d9..7bc3c00 100644
--- a/arch/arm/boot/dts/imx7d-pinfunc.h
+++ b/arch/arm/boot/dts/imx7d-pinfunc.h
@@ -43,26 +43,30 @@
#define MX7D_PAD_GPIO1_IO04__GPIO1_IO4 0x0010 0x0040 0x0000 0x0 0x0
#define MX7D_PAD_GPIO1_IO04__USB_OTG1_OC 0x0010 0x0040 0x072C 0x1 0x1
#define MX7D_PAD_GPIO1_IO04__FLEXTIMER1_CH4 0x0010 0x0040 0x0594 0x2 0x1
-#define MX7D_PAD_GPIO1_IO04__UART5_CTS_B 0x0010 0x0040 0x0710 0x3 0x4
+#define MX7D_PAD_GPIO1_IO04__UART5_DCE_CTS 0x0010 0x0040 0x0000 0x3 0x0
+#define MX7D_PAD_GPIO1_IO04__UART5_DTE_RTS 0x0010 0x0040 0x0710 0x3 0x4
#define MX7D_PAD_GPIO1_IO04__I2C1_SCL 0x0010 0x0040 0x05D4 0x4 0x2
#define MX7D_PAD_GPIO1_IO04__OBSERVE3_OUT 0x0010 0x0040 0x0000 0x6 0x0
#define MX7D_PAD_GPIO1_IO05__GPIO1_IO5 0x0014 0x0044 0x0000 0x0 0x0
#define MX7D_PAD_GPIO1_IO05__USB_OTG1_PWR 0x0014 0x0044 0x0000 0x1 0x0
#define MX7D_PAD_GPIO1_IO05__FLEXTIMER1_CH5 0x0014 0x0044 0x0598 0x2 0x1
-#define MX7D_PAD_GPIO1_IO05__UART5_RTS_B 0x0014 0x0044 0x0710 0x3 0x5
+#define MX7D_PAD_GPIO1_IO05__UART5_DCE_RTS 0x0014 0x0044 0x0710 0x3 0x5
+#define MX7D_PAD_GPIO1_IO05__UART5_DTE_CTS 0x0014 0x0044 0x0000 0x3 0x0
#define MX7D_PAD_GPIO1_IO05__I2C1_SDA 0x0014 0x0044 0x05D8 0x4 0x2
#define MX7D_PAD_GPIO1_IO05__OBSERVE4_OUT 0x0014 0x0044 0x0000 0x6 0x0
#define MX7D_PAD_GPIO1_IO06__GPIO1_IO6 0x0018 0x0048 0x0000 0x0 0x0
#define MX7D_PAD_GPIO1_IO06__USB_OTG2_OC 0x0018 0x0048 0x0728 0x1 0x1
#define MX7D_PAD_GPIO1_IO06__FLEXTIMER1_CH6 0x0018 0x0048 0x059C 0x2 0x1
-#define MX7D_PAD_GPIO1_IO06__UART5_RX_DATA 0x0018 0x0048 0x0714 0x3 0x4
+#define MX7D_PAD_GPIO1_IO06__UART5_DCE_RX 0x0018 0x0048 0x0714 0x3 0x4
+#define MX7D_PAD_GPIO1_IO06__UART5_DTE_TX 0x0018 0x0048 0x0000 0x3 0x0
#define MX7D_PAD_GPIO1_IO06__I2C2_SCL 0x0018 0x0048 0x05DC 0x4 0x2
#define MX7D_PAD_GPIO1_IO06__CCM_WAIT 0x0018 0x0048 0x0000 0x5 0x0
#define MX7D_PAD_GPIO1_IO06__KPP_ROW4 0x0018 0x0048 0x0624 0x6 0x1
#define MX7D_PAD_GPIO1_IO07__GPIO1_IO7 0x001C 0x004C 0x0000 0x0 0x0
#define MX7D_PAD_GPIO1_IO07__USB_OTG2_PWR 0x001C 0x004C 0x0000 0x1 0x0
#define MX7D_PAD_GPIO1_IO07__FLEXTIMER1_CH7 0x001C 0x004C 0x05A0 0x2 0x1
-#define MX7D_PAD_GPIO1_IO07__UART5_TX_DATA 0x001C 0x004C 0x0714 0x3 0x5
+#define MX7D_PAD_GPIO1_IO07__UART5_DCE_TX 0x001C 0x004C 0x0000 0x3 0x0
+#define MX7D_PAD_GPIO1_IO07__UART5_DTE_RX 0x001C 0x004C 0x0714 0x3 0x5
#define MX7D_PAD_GPIO1_IO07__I2C2_SDA 0x001C 0x004C 0x05E0 0x4 0x2
#define MX7D_PAD_GPIO1_IO07__CCM_STOP 0x001C 0x004C 0x0000 0x5 0x0
#define MX7D_PAD_GPIO1_IO07__KPP_COL4 0x001C 0x004C 0x0604 0x6 0x1
--
2.10.2
^ permalink raw reply related
* RE: [PATCH v4] PM/devfreq: add suspend frequency support
From: MyungJoo Ham @ 2016-11-09 1:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CGME20161108091840epcas3p21af60a1b0a4867306366633427567dc3@epcas3p2.samsung.com>
> Add suspend frequency support and if needed set it to
> the frequency obtained from the suspend opp (can be defined
> using opp-v2 bindings and is optional).
>
> Signed-off-by: Lin Huang <hl@rock-chips.com>
> ---
> Changes in v2:
> - use update_devfreq() instead devfreq_update_status()
> Changes in v3:
> - fix build error
> Changes in v4:
> - move dev_pm_opp_get_suspend_opp() to devfreq_add_device()
>
> drivers/devfreq/devfreq.c | 15 +++++++++++++--
> drivers/devfreq/governor_simpleondemand.c | 9 +++++++++
> include/linux/devfreq.h | 9 +++++++++
> 3 files changed, 31 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index bf3ea76..d9d56e1 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -363,7 +363,10 @@ void devfreq_monitor_suspend(struct devfreq *devfreq)
> mutex_unlock(&devfreq->lock);
> return;
> }
> -
> + if (devfreq->suspend_freq) {
> + update_devfreq(devfreq);
> + devfreq->suspend_flag = true;
+ } else {
+ devfreq_update_status(devfreq, devfreq->previous_freq);
+ }
- devfreq_update_status(devfreq, devfreq->previous_freq);
update_devfreq() calls devfreq_update_status.
So let's call it only when update_devfreq is not called.
> devfreq->stop_polling = true;
> mutex_unlock(&devfreq->lock);
> @@ -394,7 +397,8 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
>
> devfreq->last_stat_updated = jiffies;
> devfreq->stop_polling = false;
> -
> + if (devfreq->suspend_freq)
> + devfreq->suspend_flag = false;
> if (devfreq->profile->get_cur_freq &&
> !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq))
> devfreq->previous_freq = freq;
> @@ -528,6 +532,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
> struct devfreq *devfreq;
> struct devfreq_governor *governor;
> int err = 0;
> + struct dev_pm_opp *suspend_opp;
>
> if (!dev || !profile || !governor_name) {
> dev_err(dev, "%s: Invalid parameters.\n", __func__);
> @@ -563,6 +568,12 @@ struct devfreq *devfreq_add_device(struct device *dev,
> devfreq->data = data;
> devfreq->nb.notifier_call = devfreq_notifier_call;
>
> + rcu_read_lock();
> + suspend_opp = dev_pm_opp_get_suspend_opp(dev);
> + if (suspend_opp)
> + devfreq->suspend_freq = dev_pm_opp_get_freq(suspend_opp);
> + rcu_read_unlock();
> +
> if (!devfreq->profile->max_state && !devfreq->profile->freq_table) {
> mutex_unlock(&devfreq->lock);
> devfreq_set_freq_table(devfreq);
> diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c
> index ae72ba5..84b3ce1 100644
> --- a/drivers/devfreq/governor_simpleondemand.c
> +++ b/drivers/devfreq/governor_simpleondemand.c
> @@ -29,6 +29,15 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
> struct devfreq_simple_ondemand_data *data = df->data;
> unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX;
>
> + /*
> + * if devfreq in suspend status and have suspend_freq,
> + * the frequency need to set to suspend_freq
> + */
> + if (df->suspend_flag) {
> + *freq = df->suspend_freq;
> + return 0;
> + }
> +
If this is because of the case when devfreq_simple_ondemand_func() is called
before cancel_delayed_work_sync() in devfreq_monitor_suspend() and
after update_devfreq() in devfreq_monitor_suspend(),
you can use devfreq->stop_polling (and move devfreq->stop_polling = true; a bit earlier).
You do not need to introduce yet another variable, suspend_flag, in the devfreq struct.
The semantics of "stop_polling" fits the purpose well enough.
> err = devfreq_update_stats(df);
> if (err)
> return err;
> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> index 2de4e2e..c463ae1 100644
> --- a/include/linux/devfreq.h
> +++ b/include/linux/devfreq.h
> @@ -172,6 +172,7 @@ struct devfreq {
> struct delayed_work work;
>
> unsigned long previous_freq;
> + unsigned long suspend_freq;
> struct devfreq_dev_status last_status;
>
> void *data; /* private data for governors */
> @@ -179,6 +180,7 @@ struct devfreq {
> unsigned long min_freq;
> unsigned long max_freq;
> bool stop_polling;
> + bool suspend_flag;
>
> /* information for device frequency transition */
> unsigned int total_trans;
> @@ -214,6 +216,8 @@ extern int devfreq_resume_device(struct devfreq *devfreq);
> /* Helper functions for devfreq user device driver with OPP. */
> extern struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
> unsigned long *freq, u32 flags);
> +extern void devfreq_opp_get_suspend_opp(struct device *dev,
> + struct devfreq *devfreq);
No more required.
> extern int devfreq_register_opp_notifier(struct device *dev,
> struct devfreq *devfreq);
> extern int devfreq_unregister_opp_notifier(struct device *dev,
> @@ -348,6 +352,11 @@ static inline struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
> return ERR_PTR(-EINVAL);
> }
>
> +static inline void devfreq_opp_get_suspend_opp(struct device *dev,
> + struct devfreq *devfreq)
> +{
> +}
> +
No more required.
> static inline int devfreq_register_opp_notifier(struct device *dev,
> struct devfreq *devfreq)
> {
> --
> 2.6.6
>
>
>
^ permalink raw reply
* [PATCH v2 0/2] arm64: fix the bugs found in the hugetlb test
From: Huang Shijie @ 2016-11-09 1:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161108163642.GE20591@arm.com>
Hi Will & Catalin,
On Tue, Nov 08, 2016 at 04:36:43PM +0000, Will Deacon wrote:
> On Tue, Nov 08, 2016 at 02:09:09PM +0000, Catalin Marinas wrote:
> > On Tue, Nov 08, 2016 at 01:44:37PM +0800, Huang Shijie wrote:
> > > (3) The test result in the Softiron and Juno-r1 boards:
> > >
> > > This detail test result shows below (both the "make func" & "make stress"):
> > >
> > > 4KB granule:
> > >
> > > 1.1) PTE + Contiguous bit : 4K x 16 = 64K (per huge page size)
> > > Test result : PASS
> > >
> > > 1.2) PMD : 2M x 1 = 2M (per huge page size)
> > > Test result : PASS
> > >
> > > 1.3) PMD + Contiguous bit : 2M x 16 = 32M (per huge page size)
> > > Test result : PASS
> > >
> > > 64KB granule:
> > >
> > > 3.1) PTE + Contiguous bit : 64K x 32 = 2M (per huge page size)
> > > Test result : PASS
> > >
> > > 3.2) PMD + Contiguous bit : 512M x 32 = 16G (per huge page size)
> > > Test result : no hardware to support this test
> >
> > Don't we have support for single (non-contiguous) PMD huge page with 64K
> > pages (512M per huge page)? I gave it a try and it seems to work (though
> > without your patches applied ;)).
Yes, it should be okay. This patch set does not affect the the single
PMD huge page.
> >
> > > Huang Shijie (2):
> > > arm64: hugetlb: remove the wrong pmd check in find_num_contig()
> > > arm64: hugetlb: fix the wrong address for several functions
> >
> > For these patches:
> >
> > Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Thanks you, Catalin.
> >
> > I'm not sure whether Will plans to push them into 4.9. AFAICT, the
> > contiguous huge pages never worked properly, so we may not count it as a
> > regression but a new feature. If Will doesn't take them, I'll queue the
> > patches for 4.10.
>
> Right, given that it's never worked and the failure only seems to crop up
> in synthetic testing, I think you can queue these for 4.10.
Okay. Thank for queue them for 4.10.
Thanks
Huang Shijie
^ permalink raw reply
* [PATCH v2 1/3] ARM: dts: imx6qdl-apalis: Do not rely on DDC I2C bus bitbang for HDMI
From: Stefan Agner @ 2016-11-09 0:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161108173315.GA16082@Sanchayan-Arch.localdomain>
On 2016-11-08 09:33, maitysanchayan at gmail.com wrote:
> Hello Shawn,
>
> On 16-10-22 15:43:04, Vladimir Zapolskiy wrote:
>> Hi Shawn,
>>
>> On 10/22/2016 06:25 AM, Shawn Guo wrote:
>> > On Mon, Sep 19, 2016 at 10:41:51AM +0530, Sanchayan Maity wrote:
>> > > Remove the use of DDC I2C bus bitbang to support reading of EDID
>> > > and rely on support from internal HDMI I2C master controller instead.
>> > > As a result remove the device tree property ddc-i2c-bus.
>> > >
>> > > Signed-off-by: Sanchayan Maity <maitysanchayan@gmail.com>
>> >
>> > I think that the dw-hdmi i2c support [1] is a prerequisite of this
>> > patch. I do not see it lands on v4.9-rc1. Or am I missing something?
>> >
>> > Shawn
>> >
>> > [1] https://patchwork.kernel.org/patch/9296883/
>> >
>>
>> I'm adding Philipp to Cc, since he is the last one who tested the change
>> and helped me to push the change to the mainline:
>>
>> https://lists.freedesktop.org/archives/dri-devel/2016-September/118569.html
>>
>> The problem is that there is no official DW HDMI bridge maintainer, may be
>> you can review the change, and if you find it satisfactory push it through
>> ARM/iMX tree.
>
> Shawn, is it okay if that patch goes through your ARM/iMX tree?
I don't think it makes sense that the DRM bridge changes go through
Shawn's tree. Dave should merge Philipps pull request...
--
Stefan
^ permalink raw reply
* [PATCH] ARM: socfpga_defconfig: enable FS configs to support Angstrom filesystem
From: Dinh Nguyen @ 2016-11-09 0:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2911351.Izg0zkPBzd@wuerfel>
On Tue, Nov 8, 2016 at 4:57 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday, November 8, 2016 4:47:50 PM CET Dinh Nguyen wrote:
>> Enables:
>>
>> CONFIG_AUTOFS4_FS=y
>> CONFIG_NFSD=y
>> CONFIG_NFS_V3_ACL=y
>> CONFIG_NFSD_V3_ACL=y
>> CONFIG_NFSD_V4=y
>>
>> Signed-off-by: Matthew Gerlach <mgerlach@opensource.altera.com>
>> Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
>>
>
> No objections to the patch, but the changelog should not state what
> the patch clearly shows already but instead it should explain why
> you do this.
>
> The subject line mentions "to support Angstrom filesystem", but
> it's not clear (at least not to me) what that filesystem is.
>
Thanks for the review Arnd. I'll update with a better changelog message.
Dinh
^ permalink raw reply
* [PATCH v7 1/3] input: touchscreen: TOUCHSCREEN_SUN4I depends on !SUN4I_GPADC
From: Dmitry Torokhov @ 2016-11-09 0:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161103101601.24529-2-quentin.schulz@free-electrons.com>
On Thu, Nov 03, 2016 at 11:15:59AM +0100, Quentin Schulz wrote:
> SUN4I_GPADC and TOUCHSCREEN_SUN4I are incompatible (both are drivers
> for Allwinner SoCs' ADC). This makes sure TOUCHSCREEN_SUN4I isn't
> enabled while SUN4I_GPADC is enabled.
>
> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Please merge with SUN4I_GPADC driver patch.
> ---
>
> added in v7
>
> drivers/input/touchscreen/Kconfig | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> index efca013..c618cb9 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -1120,6 +1120,7 @@ config TOUCHSCREEN_SUN4I
> depends on ARCH_SUNXI || COMPILE_TEST
> depends on HWMON
> depends on THERMAL || !THERMAL_OF
> + depends on !SUN4I_GPADC
> help
> This selects support for the resistive touchscreen controller
> found on Allwinner sunxi SoCs.
> --
> 2.9.3
>
--
Dmitry
^ permalink raw reply
* [PATCH v15 2/4] reset: mediatek: Add MT2701 reset driver
From: Stephen Boyd @ 2016-11-09 0:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478245388-1412-3-git-send-email-erin.lo@mediatek.com>
On 11/04, Erin Lo wrote:
> From: Shunli Wang <shunli.wang@mediatek.com>
>
> In infrasys and perifsys, there are many reset
> control bits for kinds of modules. These bits are
> used as actual reset controllers to be registered
> into kernel's generic reset controller framework.
>
> Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
> Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
> Signed-off-by: Erin Lo <erin.lo@mediatek.com>
> Tested-by: John Crispin <blogic@openwrt.org>
> Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
> ---
Applied to clk-next
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH v15 1/4] clk: mediatek: Add MT2701 clock support
From: Stephen Boyd @ 2016-11-09 0:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478245388-1412-2-git-send-email-erin.lo@mediatek.com>
On 11/04, Erin Lo wrote:
> From: Shunli Wang <shunli.wang@mediatek.com>
>
> Add MT2701 clock support, include topckgen, apmixedsys,
> infracfg, pericfg and subsystem clocks.
>
> Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
> Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
> Signed-off-by: Erin Lo <erin.lo@mediatek.com>
> Tested-by: John Crispin <blogic@openwrt.org>
> ---
Applied to clk-next
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* [PATCH v4 1/5] arm64: perf: Basic uncore counter support for Cavium ThunderX SOC
From: Will Deacon @ 2016-11-08 23:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <73173d6ad2430eead5e9da40564a90a60961b6d9.1477741719.git.jglauber@cavium.com>
Hi Jan,
Thanks for posting an updated series. I have a few minor comments, which
we can hopefully address in time for 4.10.
Also, have you run the perf fuzzer with this series applied?
https://github.com/deater/perf_event_tests
(build the tests and look under the fuzzer/ directory for the tool)
On Sat, Oct 29, 2016 at 01:55:29PM +0200, Jan Glauber wrote:
> Provide "uncore" facilities for different non-CPU performance
> counter units.
>
> The uncore PMUs can be found under /sys/bus/event_source/devices.
> All counters are exported via sysfs in the corresponding events
> files under the PMU directory so the perf tool can list the event names.
>
> There are some points that are special in this implementation:
>
> 1) The PMU detection relies on PCI device detection. If a
> matching PCI device is found the PMU is created. The code can deal
> with multiple units of the same type, e.g. more than one memory
> controller.
>
> 2) Counters are summarized across different units of the same type
> on one NUMA node but not across NUMA nodes.
> For instance L2C TAD 0..7 are presented as a single counter
> (adding the values from TAD 0 to 7). Although losing the ability
> to read a single value the merged values are easier to use.
>
> 3) The counters are not CPU related. A random CPU is picked regardless
> of the NUMA node. There is a small performance penalty for accessing
> counters on a remote note but reading a performance counter is a
> slow operation anyway.
>
> Signed-off-by: Jan Glauber <jglauber@cavium.com>
> ---
> drivers/perf/Kconfig | 13 ++
> drivers/perf/Makefile | 1 +
> drivers/perf/uncore/Makefile | 1 +
> drivers/perf/uncore/uncore_cavium.c | 351 ++++++++++++++++++++++++++++++++++++
> drivers/perf/uncore/uncore_cavium.h | 71 ++++++++
We already have "uncore" PMUs under drivers/perf, so I'd prefer that we
renamed this a bit to reflect better what's going on. How about:
drivers/perf/cavium/
and then
drivers/perf/cavium/uncore_thunder.[ch]
?
> include/linux/cpuhotplug.h | 1 +
> 6 files changed, 438 insertions(+)
> create mode 100644 drivers/perf/uncore/Makefile
> create mode 100644 drivers/perf/uncore/uncore_cavium.c
> create mode 100644 drivers/perf/uncore/uncore_cavium.h
>
> diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
> index 4d5c5f9..3266c87 100644
> --- a/drivers/perf/Kconfig
> +++ b/drivers/perf/Kconfig
> @@ -19,4 +19,17 @@ config XGENE_PMU
> help
> Say y if you want to use APM X-Gene SoC performance monitors.
>
> +config UNCORE_PMU
> + bool
This isn't needed.
> +
> +config UNCORE_PMU_CAVIUM
> + depends on PERF_EVENTS && NUMA && ARM64
> + bool "Cavium uncore PMU support"
Please mentioned Thunder somewhere, since that's the SoC being supported.
> + select UNCORE_PMU
> + default y
> + help
> + Say y if you want to access performance counters of subsystems
> + on a Cavium SOC like cache controller, memory controller or
> + processor interconnect.
> +
> endmenu
> diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
> index b116e98..d6c02c9 100644
> --- a/drivers/perf/Makefile
> +++ b/drivers/perf/Makefile
> @@ -1,2 +1,3 @@
> obj-$(CONFIG_ARM_PMU) += arm_pmu.o
> obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
> +obj-y += uncore/
> diff --git a/drivers/perf/uncore/Makefile b/drivers/perf/uncore/Makefile
> new file mode 100644
> index 0000000..6130e18
> --- /dev/null
> +++ b/drivers/perf/uncore/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_UNCORE_PMU_CAVIUM) += uncore_cavium.o
> diff --git a/drivers/perf/uncore/uncore_cavium.c b/drivers/perf/uncore/uncore_cavium.c
> new file mode 100644
> index 0000000..a7b4277
> --- /dev/null
> +++ b/drivers/perf/uncore/uncore_cavium.c
> @@ -0,0 +1,351 @@
> +/*
> + * Cavium Thunder uncore PMU support.
> + *
> + * Copyright (C) 2015,2016 Cavium Inc.
> + * Author: Jan Glauber <jan.glauber@cavium.com>
> + */
> +
> +#include <linux/cpufeature.h>
> +#include <linux/numa.h>
> +#include <linux/slab.h>
> +
> +#include "uncore_cavium.h"
> +
> +/*
> + * Some notes about the various counters supported by this "uncore" PMU
> + * and the design:
> + *
> + * All counters are 64 bit long.
> + * There are no overflow interrupts.
> + * Counters are summarized per node/socket.
> + * Most devices appear as separate PCI devices per socket with the exception
> + * of OCX TLK which appears as one PCI device per socket and contains several
> + * units with counters that are merged.
> + * Some counters are selected via a control register (L2C TAD) and read by
> + * a number of counter registers, others (L2C CBC, LMC & OCX TLK) have
> + * one dedicated counter per event.
> + * Some counters are not stoppable (L2C CBC & LMC).
> + * Some counters are read-only (LMC).
> + * All counters belong to PCI devices, the devices may have additional
> + * drivers but we assume we are the only user of the counter registers.
> + * We map the whole PCI BAR so we must be careful to forbid access to
> + * addresses that contain neither counters nor counter control registers.
> + */
> +
> +void thunder_uncore_read(struct perf_event *event)
> +{
Rather than have a bunch of global symbols that are called from the
individual drivers, why don't you pass a struct of function pointers to
their respective init functions and keep the internals private?
> + struct thunder_uncore *uncore = to_uncore(event->pmu);
> + struct hw_perf_event *hwc = &event->hw;
> + struct thunder_uncore_node *node;
> + struct thunder_uncore_unit *unit;
> + u64 prev, delta, new = 0;
> +
> + node = get_node(hwc->config, uncore);
> +
> + /* read counter values from all units on the node */
> + list_for_each_entry(unit, &node->unit_list, entry)
> + new += readq(hwc->event_base + unit->map);
> +
> + prev = local64_read(&hwc->prev_count);
> + local64_set(&hwc->prev_count, new);
> + delta = new - prev;
> + local64_add(delta, &event->count);
> +}
> +
> +int thunder_uncore_add(struct perf_event *event, int flags, u64 config_base,
> + u64 event_base)
> +{
> + struct thunder_uncore *uncore = to_uncore(event->pmu);
> + struct hw_perf_event *hwc = &event->hw;
> + struct thunder_uncore_node *node;
> + int id;
> +
> + node = get_node(hwc->config, uncore);
> + id = get_id(hwc->config);
> +
> + if (!cmpxchg(&node->events[id], NULL, event))
> + hwc->idx = id;
Does this need to be a full-fat cmpxchg? Who are you racing with?
> +
> + if (hwc->idx == -1)
> + return -EBUSY;
This would be much clearer as an else statement after the cmpxchg.
> +
> + hwc->config_base = config_base;
> + hwc->event_base = event_base;
> + hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
> +
> + if (flags & PERF_EF_START)
> + uncore->pmu.start(event, PERF_EF_RELOAD);
> +
> + return 0;
> +}
> +
> +void thunder_uncore_del(struct perf_event *event, int flags)
> +{
> + struct thunder_uncore *uncore = to_uncore(event->pmu);
> + struct hw_perf_event *hwc = &event->hw;
> + struct thunder_uncore_node *node;
> + int i;
> +
> + event->pmu->stop(event, PERF_EF_UPDATE);
> +
> + /*
> + * For programmable counters we need to check where we installed it.
> + * To keep this function generic always test the more complicated
> + * case (free running counters won't need the loop).
> + */
> + node = get_node(hwc->config, uncore);
> + for (i = 0; i < node->num_counters; i++) {
> + if (cmpxchg(&node->events[i], event, NULL) == event)
> + break;
> + }
> + hwc->idx = -1;
> +}
> +
> +void thunder_uncore_start(struct perf_event *event, int flags)
> +{
> + struct thunder_uncore *uncore = to_uncore(event->pmu);
> + struct hw_perf_event *hwc = &event->hw;
> + struct thunder_uncore_node *node;
> + struct thunder_uncore_unit *unit;
> + u64 new = 0;
> +
> + /* read counter values from all units on the node */
> + node = get_node(hwc->config, uncore);
> + list_for_each_entry(unit, &node->unit_list, entry)
> + new += readq(hwc->event_base + unit->map);
> + local64_set(&hwc->prev_count, new);
> +
> + hwc->state = 0;
> + perf_event_update_userpage(event);
> +}
> +
> +void thunder_uncore_stop(struct perf_event *event, int flags)
> +{
> + struct hw_perf_event *hwc = &event->hw;
> +
> + hwc->state |= PERF_HES_STOPPED;
> +
> + if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
> + thunder_uncore_read(event);
> + hwc->state |= PERF_HES_UPTODATE;
> + }
> +}
> +
> +int thunder_uncore_event_init(struct perf_event *event)
> +{
> + struct hw_perf_event *hwc = &event->hw;
> + struct thunder_uncore_node *node;
> + struct thunder_uncore *uncore;
> +
> + if (event->attr.type != event->pmu->type)
> + return -ENOENT;
> +
> + /* we do not support sampling */
> + if (is_sampling_event(event))
> + return -EINVAL;
> +
> + /* counters do not have these bits */
> + if (event->attr.exclude_user ||
> + event->attr.exclude_kernel ||
> + event->attr.exclude_host ||
> + event->attr.exclude_guest ||
> + event->attr.exclude_hv ||
> + event->attr.exclude_idle)
> + return -EINVAL;
> +
> + uncore = to_uncore(event->pmu);
> + if (!uncore)
> + return -ENODEV;
> + if (!uncore->event_valid(event->attr.config & UNCORE_EVENT_ID_MASK))
> + return -EINVAL;
> +
> + /* check NUMA node */
> + node = get_node(event->attr.config, uncore);
> + if (!node) {
> + pr_debug("Invalid NUMA node selected\n");
> + return -EINVAL;
> + }
> +
> + hwc->config = event->attr.config;
> + hwc->idx = -1;
> + return 0;
> +}
> +
> +static ssize_t thunder_uncore_attr_show_cpumask(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct pmu *pmu = dev_get_drvdata(dev);
> + struct thunder_uncore *uncore =
> + container_of(pmu, struct thunder_uncore, pmu);
> +
> + return cpumap_print_to_pagebuf(true, buf, &uncore->active_mask);
> +}
> +static DEVICE_ATTR(cpumask, S_IRUGO, thunder_uncore_attr_show_cpumask, NULL);
> +
> +static struct attribute *thunder_uncore_attrs[] = {
> + &dev_attr_cpumask.attr,
> + NULL,
> +};
> +
> +struct attribute_group thunder_uncore_attr_group = {
> + .attrs = thunder_uncore_attrs,
> +};
> +
> +ssize_t thunder_events_sysfs_show(struct device *dev,
> + struct device_attribute *attr,
> + char *page)
> +{
> + struct perf_pmu_events_attr *pmu_attr =
> + container_of(attr, struct perf_pmu_events_attr, attr);
> +
> + if (pmu_attr->event_str)
> + return sprintf(page, "%s", pmu_attr->event_str);
> +
> + return 0;
> +}
> +
> +/* node attribute depending on number of NUMA nodes */
> +static ssize_t node_show(struct device *dev, struct device_attribute *attr,
> + char *page)
> +{
> + if (NODES_SHIFT)
> + return sprintf(page, "config:16-%d\n", 16 + NODES_SHIFT - 1);
If NODES_SHIFT is 1, you'll end up with "config:16-16", which might confuse
userspace.
> + else
> + return sprintf(page, "config:16\n");
> +}
> +
> +struct device_attribute format_attr_node = __ATTR_RO(node);
> +
> +/*
> + * Thunder uncore events are independent from CPUs. Provide a cpumask
> + * nevertheless to prevent perf from adding the event per-cpu and just
> + * set the mask to one online CPU. Use the same cpumask for all uncore
> + * devices.
> + *
> + * There is a performance penalty for accessing a device from a CPU on
> + * another socket, but we do not care (yet).
> + */
> +static int thunder_uncore_offline_cpu(unsigned int old_cpu, struct hlist_node *node)
> +{
> + struct thunder_uncore *uncore = hlist_entry_safe(node, struct thunder_uncore, node);
Why _safe?
> + int new_cpu;
> +
> + if (!cpumask_test_and_clear_cpu(old_cpu, &uncore->active_mask))
> + return 0;
> + new_cpu = cpumask_any_but(cpu_online_mask, old_cpu);
> + if (new_cpu >= nr_cpu_ids)
> + return 0;
> + perf_pmu_migrate_context(&uncore->pmu, old_cpu, new_cpu);
> + cpumask_set_cpu(new_cpu, &uncore->active_mask);
> + return 0;
> +}
> +
> +static struct thunder_uncore_node * __init alloc_node(struct thunder_uncore *uncore,
> + int node_id, int counters)
> +{
> + struct thunder_uncore_node *node;
> +
> + node = kzalloc(sizeof(*node), GFP_KERNEL);
> + if (!node)
> + return NULL;
> + node->num_counters = counters;
> + INIT_LIST_HEAD(&node->unit_list);
> + return node;
> +}
> +
> +int __init thunder_uncore_setup(struct thunder_uncore *uncore, int device_id,
> + struct pmu *pmu, int counters)
> +{
> + unsigned int vendor_id = PCI_VENDOR_ID_CAVIUM;
> + struct thunder_uncore_unit *unit, *tmp;
> + struct thunder_uncore_node *node;
> + struct pci_dev *pdev = NULL;
> + int ret, node_id, found = 0;
> +
> + /* detect PCI devices */
> + while ((pdev = pci_get_device(vendor_id, device_id, pdev))) {
Redundant brackets?
> + if (!pdev)
> + break;
Redundant check?
> + node_id = dev_to_node(&pdev->dev);
> +
> + /* allocate node if necessary */
> + if (!uncore->nodes[node_id])
> + uncore->nodes[node_id] = alloc_node(uncore, node_id, counters);
> +
> + node = uncore->nodes[node_id];
> + if (!node) {
> + ret = -ENOMEM;
> + goto fail;
> + }
> +
> + unit = kzalloc(sizeof(*unit), GFP_KERNEL);
> + if (!unit) {
> + ret = -ENOMEM;
> + goto fail;
> + }
> +
> + unit->pdev = pdev;
> + unit->map = ioremap(pci_resource_start(pdev, 0),
> + pci_resource_len(pdev, 0));
> + list_add(&unit->entry, &node->unit_list);
> + node->nr_units++;
> + found++;
> + }
> +
> + if (!found)
> + return -ENODEV;
> +
> + cpuhp_state_add_instance_nocalls(CPUHP_AP_UNCORE_CAVIUM_ONLINE,
> + &uncore->node);
> +
> + /*
> + * perf PMU is CPU dependent in difference to our uncore devices.
> + * Just pick a CPU and migrate away if it goes offline.
> + */
> + cpumask_set_cpu(smp_processor_id(), &uncore->active_mask);
> +
> + uncore->pmu = *pmu;
> + ret = perf_pmu_register(&uncore->pmu, uncore->pmu.name, -1);
> + if (ret)
> + goto fail;
> +
> + return 0;
> +
> +fail:
> + node_id = 0;
> + while (uncore->nodes[node_id]) {
> + node = uncore->nodes[node_id];
> +
> + list_for_each_entry_safe(unit, tmp, &node->unit_list, entry) {
Why do you need the _safe variant?
Will
^ 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