* [PATCH v2 2/3] ARM: dts: sunxi: add support for Orange Pi Zero board
From: Maxime Ripard @ 2016-12-05 9:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205120021.0GBGtAl4@smtp3m.mail.yandex.net>
On Mon, Dec 05, 2016 at 04:59:44PM +0800, Icenowy Zheng wrote:
>
> 2016?12?5? 16:52? Maxime Ripard <maxime.ripard@free-electrons.com>???
> >
> > On Fri, Dec 02, 2016 at 10:22:30PM +0800, Icenowy Zheng wrote:
> > >
> > >
> > > 01.12.2016, 17:36, "Maxime Ripard" <maxime.ripard@free-electrons.com>:
> > > > On Mon, Nov 28, 2016 at 12:29:07AM +0000, Andr? Przywara wrote:
> > > >> ?> Something more interesting happened.
> > > >> ?>
> > > >> ?> Xunlong made a add-on board for Orange Pi Zero, which exposes the
> > > >> ?> two USB Controllers exported at expansion bus as USB Type-A
> > > >> ?> connectors.
> > > >> ?>
> > > >> ?> Also it exposes a analog A/V jack and a microphone.
> > > >> ?>
> > > >> ?> Should I enable {e,o}hci{2.3} in the device tree?
> > > >>
> > > >> ?Actually we should do this regardless of this extension board. The USB
> > > >> ?pins are not multiplexed and are exposed on user accessible pins (just
> > > >> ?not soldered, but that's a detail), so I think they qualify for DT
> > > >> ?enablement. And even if a user can't use them, it doesn't hurt to have
> > > >> ?them (since they are not multiplexed).
> > > >
> > > > My main concern about this is that we'll leave regulators enabled by
> > > > default, for a minority of users. And that minority will prevent to do
> > > > a proper power management when the times come since we'll have to keep
> > > > that behaviour forever.
> > >
> > > I think these users can add a 'fdt set /xxx/xxx status "disabled" ' .
> >
> > You can't ask that from the majority of users. These users will take
> > debian or fedora, install it, and expect everything to work
> > properly. I would make the opposite argument actually. If someone is
> > knowledgeable enough to solder the USB pins a connector, then (s)he'll
> > be able to make that u-boot call.
>
> Now (s)he do not need soldering.
>
> (S)he needs only paying $1.99 more to Xunlong to get the expansion
> board, and insert it on the OPi Zero.
Which is going to require an overlay anyway, so we could have the USB
bits in there too.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161205/194dd5d6/attachment.sig>
^ permalink raw reply
* [PATCH] ARM: dts: sunxi: Add num-cs for A20 spi nodes
From: Emmanuel Vadot @ 2016-12-05 9:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205092821.m2fmqxnzalcignly@lukather>
On Mon, 5 Dec 2016 10:28:21 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
> On Thu, Dec 01, 2016 at 11:24:14AM +0100, Emmanuel Vadot wrote:
> > > > > > If num-cs isn't present nothing prevent to start a transfer
> > > > > > with a non-valid CS pin, resulting in an error. num-cs are
> > > > > > default property especially made for this and a SPI driver
> > > > > > should try to get the property at probe/attach time.
> > > > >
> > > > > Yes, but as far as I know, our driver doesn't. I'm all in for
> > > > > having support for that in our driver, but without it, that
> > > > > patch is kind of useless.
> > > >
> > > > Yes the Linux driver doesn't use it but my upcoming one for FreeBSD
> > > > uses it. So it is not useless for downstream user of DTS.
> > >
> > > Ah, I didn't know this was for FreeBSD. So you started to use our DTs,
> > > or do you have some modifications to it? How does that work?
> >
> > Yes we use the DTS from linux from quite some times now. We're
> > currently synced with 4.7-ish. We either use them directly or
> > modify them according to our needs and driver support.
>
> Do you have a link to those modifications?
>
> Thanks,
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
Sure,
https://svnweb.freebsd.org/base/head/sys/boot/fdt/dts/arm/
--
Emmanuel Vadot <manu@bidouilliste.com> <manu@freebsd.org>
^ permalink raw reply
* [PATCH] arm/arm64: KVM: Check for properly initialized timer on init
From: Christoffer Dall @ 2016-12-05 9:32 UTC (permalink / raw)
To: linux-arm-kernel
When the arch timer code fails to initialize (for example because the
memory mapped timer doesn't work, which is currently seen with the AEM
model), then KVM just continues happily with a final result that KVM
eventually does a NULL pointer dereference of the uninitialized cycle
counter.
Check directly for this in the init path and give the user a reasonable
error in this case.
Cc: Shih-Wei Li <shihwei@cs.columbia.edu>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
virt/kvm/arm/arch_timer.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 27a1f63..5c12f53 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -425,6 +425,11 @@ int kvm_timer_hyp_init(void)
info = arch_timer_get_kvm_info();
timecounter = &info->timecounter;
+ if (!timecounter->cc) {
+ kvm_err("arch_timer: uninitialized timecounter\n");
+ return -ENODEV;
+ }
+
if (info->virtual_irq <= 0) {
kvm_err("kvm_arch_timer: invalid virtual timer IRQ: %d\n",
info->virtual_irq);
--
2.9.0
^ permalink raw reply related
* [PATCH v3 0/4] mm: fix the "counter.sh" failure for libhugetlbfs
From: Michal Hocko @ 2016-12-05 9:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480929431-22348-1-git-send-email-shijie.huang@arm.com>
On Mon 05-12-16 17:17:07, Huang Shijie wrote:
[...]
> 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 some functions are wrong:
> return_unused_surplus_pages()
> nr_overcommit_hugepages_store()
> hugetlb_overcommit_handler()
OK, so how is this any different from gigantic (1G) hugetlb pages on
x86_64? Do we need the same functionality or is it just 32MB not being
handled in the same way as 1G?
Thanks!
--
Michal Hocko
SUSE Labs
^ permalink raw reply
* [PATCH] ARM: dts: sunxi: Add num-cs for A20 spi nodes
From: Maxime Ripard @ 2016-12-05 9:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161201112414.62f9b351186115f62c8998a9@bidouilliste.com>
On Thu, Dec 01, 2016 at 11:24:14AM +0100, Emmanuel Vadot wrote:
> > > > > If num-cs isn't present nothing prevent to start a transfer
> > > > > with a non-valid CS pin, resulting in an error. num-cs are
> > > > > default property especially made for this and a SPI driver
> > > > > should try to get the property at probe/attach time.
> > > >
> > > > Yes, but as far as I know, our driver doesn't. I'm all in for
> > > > having support for that in our driver, but without it, that
> > > > patch is kind of useless.
> > >
> > > Yes the Linux driver doesn't use it but my upcoming one for FreeBSD
> > > uses it. So it is not useless for downstream user of DTS.
> >
> > Ah, I didn't know this was for FreeBSD. So you started to use our DTs,
> > or do you have some modifications to it? How does that work?
>
> Yes we use the DTS from linux from quite some times now. We're
> currently synced with 4.7-ish. We either use them directly or
> modify them according to our needs and driver support.
Do you have a link to those modifications?
Thanks,
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161205/7f666e1b/attachment-0001.sig>
^ permalink raw reply
* [PATCH v3 -next 1/2] ARM: sunxi: add support for H2+ SoC
From: Maxime Ripard @ 2016-12-05 9:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202150513.34691-1-icenowy@aosc.xyz>
On Fri, Dec 02, 2016 at 11:05:12PM +0800, Icenowy Zheng wrote:
> Allwinner H2+ is a quad-core Cortex-A7 SoC.
>
> It is very like H3, that they share the same SoC ID (0x1680), and H3
> memory maps as well as drivers works well on the SoC.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
Fixed the alphabetical order in the bindings doc, and applied.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161205/364dbd55/attachment.sig>
^ permalink raw reply
* [crypto] [marvell-cesa] Possible regression after Linux 4.7
From: Romain Perier @ 2016-12-05 9:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4573998d-6c5b-03e4-e1fa-7516d5a9e276@free-electrons.com>
Hello,
The issue is reproducible in STD mode too. We have found fixes.
Could you test these patches in STD mode please ?
cover letter:
https://www.mail-archive.com/linux-crypto at vger.kernel.org/msg22143.html
1/2: https://www.mail-archive.com/linux-crypto at vger.kernel.org/msg22142.html
2/2: https://www.mail-archive.com/linux-crypto at vger.kernel.org/msg22141.html
If you want to turn off DMA, open drivers/crypto/marvell/cesa.c and in
armada_xp_caps, change .has_tdma to false. (assuming that you test on a
armada 38x).
We're still investigating for regressions in DMA mode.
Have a nice day,
Romain
--
Romain Perier, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* [PATCH v3 4/4] mm: hugetlb: support gigantic surplus pages
From: Huang Shijie @ 2016-12-05 9:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480929431-22348-1-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 counter.sh is just a wrapper for counter.c, you can find them in:
https://github.com/libhugetlbfs/libhugetlbfs/blob/master/tests/counters.c
https://github.com/libhugetlbfs/libhugetlbfs/blob/master/tests/counters.sh
Please see the error log below:
............................................
........
quota.sh (32M: 64): PASS
counters.sh (32M: 64): FAIL mmap failed: Invalid argument
********** TEST SUMMARY
* 32M
* 32-bit 64-bit
* Total testcases: 0 87
* Skipped: 0 0
* PASS: 0 86
* FAIL: 0 1
* Killed by signal: 0 0
* Bad configuration: 0 0
* Expected FAIL: 0 0
* Unexpected PASS: 0 0
* Strange test result: 0 0
**********
............................................
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 does following things:
1) This patch changes the condition checks for:
return_unused_surplus_pages()
nr_overcommit_hugepages_store()
hugetlb_overcommit_handler()
2) This patch introduces two helper functions:
huge_nodemask() and __hugetlb_alloc_gigantic_page().
Please see the descritions in the two functions.
3) This patch uses __hugetlb_alloc_gigantic_page() 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.
After this patch, the counter.sh can pass for the gigantic page.
Signed-off-by: Huang Shijie <shijie.huang@arm.com>
---
include/linux/mempolicy.h | 8 +++++
mm/hugetlb.c | 77 +++++++++++++++++++++++++++++++++++++++++++----
mm/mempolicy.c | 44 +++++++++++++++++++++++++++
3 files changed, 123 insertions(+), 6 deletions(-)
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index 5f4d828..6539fbb 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -146,6 +146,8 @@ extern void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new,
enum mpol_rebind_step step);
extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new);
+extern bool huge_nodemask(struct vm_area_struct *vma,
+ unsigned long addr, nodemask_t *mask);
extern struct zonelist *huge_zonelist(struct vm_area_struct *vma,
unsigned long addr, gfp_t gfp_flags,
struct mempolicy **mpol, nodemask_t **nodemask);
@@ -269,6 +271,12 @@ static inline void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new)
{
}
+static inline bool huge_nodemask(struct vm_area_struct *vma,
+ unsigned long addr, nodemask_t *mask)
+{
+ return false;
+}
+
static inline struct zonelist *huge_zonelist(struct vm_area_struct *vma,
unsigned long addr, gfp_t gfp_flags,
struct mempolicy **mpol, nodemask_t **nodemask)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 1395bef..04440b8 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1506,6 +1506,69 @@ int dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
/*
* There are 3 ways this can get called:
+ *
+ * 1. When the NUMA is not enabled, use alloc_gigantic_page() to get
+ * the gigantic page.
+ *
+ * 2. The NUMA is enabled, but the vma is NULL.
+ * Initialize the @mask, and use alloc_fresh_gigantic_page() to get
+ * the gigantic page.
+ *
+ * 3. The NUMA is enabled, and the vma is valid.
+ * Use the @vma's memory policy.
+ * Get @mask by huge_nodemask(), and use alloc_fresh_gigantic_page()
+ * to get the gigantic page.
+ */
+static struct page *__hugetlb_alloc_gigantic_page(struct hstate *h,
+ struct vm_area_struct *vma, unsigned long addr, int nid)
+{
+ NODEMASK_ALLOC(nodemask_t, mask, GFP_KERNEL | __GFP_NORETRY);
+ struct page *page = NULL;
+
+ /* Not NUMA */
+ if (!IS_ENABLED(CONFIG_NUMA)) {
+ if (nid == NUMA_NO_NODE)
+ nid = numa_mem_id();
+
+ page = alloc_gigantic_page(nid, huge_page_order(h));
+ if (page)
+ prep_compound_gigantic_page(page, huge_page_order(h));
+ goto got_page;
+ }
+
+ /* NUMA && !vma */
+ if (!vma) {
+ /* First, check the mask */
+ if (!mask) {
+ mask = &node_states[N_MEMORY];
+ } else {
+ if (nid == NUMA_NO_NODE) {
+ if (!init_nodemask_of_mempolicy(mask)) {
+ NODEMASK_FREE(mask);
+ mask = &node_states[N_MEMORY];
+ }
+ } else {
+ init_nodemask_of_node(mask, nid);
+ }
+ }
+
+ page = alloc_fresh_gigantic_page(h, mask, false);
+ goto got_page;
+ }
+
+ /* NUMA && vma */
+ if (mask && huge_nodemask(vma, addr, mask))
+ page = alloc_fresh_gigantic_page(h, mask, false);
+
+got_page:
+ if (mask != &node_states[N_MEMORY])
+ NODEMASK_FREE(mask);
+
+ return page;
+}
+
+/*
+ * There are 3 ways this can get called:
* 1. With vma+addr: we use the VMA's memory policy
* 2. With !vma, but nid=NUMA_NO_NODE: We try to allocate a huge
* page from any node, and let the buddy allocator itself figure
@@ -1584,7 +1647,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;
/*
@@ -1629,7 +1692,10 @@ 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 = __hugetlb_alloc_gigantic_page(h, vma, addr, nid);
+ else
+ page = __hugetlb_alloc_buddy_huge_page(h, vma, addr, nid);
spin_lock(&hugetlb_lock);
if (page) {
@@ -1796,8 +1862,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);
@@ -2514,7 +2579,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);
@@ -2966,7 +3031,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;
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 6d3639e..3550a29 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1800,6 +1800,50 @@ static inline unsigned interleave_nid(struct mempolicy *pol,
#ifdef CONFIG_HUGETLBFS
/*
+ * huge_nodemask(@vma, @addr, @mask)
+ * @vma: virtual memory area whose policy is sought
+ * @addr: address in @vma
+ * @mask: should be a valid nodemask pointer, not NULL
+ *
+ * Return true if we can succeed in extracting the policy nodemask
+ * for 'bind' or 'interleave' policy into the argument @mask, or
+ * initializing the argument @mask to contain the single node for
+ * 'preferred' or 'local' policy.
+ */
+bool huge_nodemask(struct vm_area_struct *vma, unsigned long addr,
+ nodemask_t *mask)
+{
+ struct mempolicy *mpol;
+ bool ret = true;
+ int nid;
+
+ mpol = get_vma_policy(vma, addr);
+
+ switch (mpol->mode) {
+ case MPOL_PREFERRED:
+ if (mpol->flags & MPOL_F_LOCAL)
+ nid = numa_node_id();
+ else
+ nid = mpol->v.preferred_node;
+ init_nodemask_of_node(mask, nid);
+ break;
+
+ case MPOL_BIND:
+ /* Fall through */
+ case MPOL_INTERLEAVE:
+ *mask = mpol->v.nodes;
+ break;
+
+ default:
+ ret = false;
+ break;
+ }
+ mpol_cond_put(mpol);
+
+ return ret;
+}
+
+/*
* huge_zonelist(@vma, @addr, @gfp_flags, @mpol)
* @vma: virtual memory area whose policy is sought
* @addr: address in @vma for shared policy lookup and interleave policy
--
2.5.5
^ permalink raw reply related
* [PATCH v3 3/4] mm: hugetlb: change the return type for some functions
From: Huang Shijie @ 2016-12-05 9:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480929431-22348-1-git-send-email-shijie.huang@arm.com>
This patch changes the return type to "struct page*" for
alloc_fresh_gigantic_page()/alloc_fresh_huge_page().
This patch makes preparation for later patch.
Signed-off-by: Huang Shijie <shijie.huang@arm.com>
---
mm/hugetlb.c | 29 ++++++++++++++---------------
1 file changed, 14 insertions(+), 15 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index b7c73a1..1395bef 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1148,7 +1148,7 @@ static struct page *alloc_fresh_gigantic_page_node(struct hstate *h,
return page;
}
-static int alloc_fresh_gigantic_page(struct hstate *h,
+static struct page *alloc_fresh_gigantic_page(struct hstate *h,
nodemask_t *nodes_allowed, bool do_prep)
{
struct page *page = NULL;
@@ -1157,10 +1157,10 @@ static int alloc_fresh_gigantic_page(struct hstate *h,
for_each_node_mask_to_alloc(h, nr_nodes, node, nodes_allowed) {
page = alloc_fresh_gigantic_page_node(h, node, do_prep);
if (page)
- return 1;
+ return page;
}
- return 0;
+ return NULL;
}
static inline bool gigantic_page_supported(void) { return true; }
@@ -1173,8 +1173,8 @@ static inline bool gigantic_page_supported(void) { return false; }
static inline void free_gigantic_page(struct page *page, unsigned int order) { }
static inline void destroy_compound_gigantic_page(struct page *page,
unsigned int order) { }
-static inline int alloc_fresh_gigantic_page(struct hstate *h,
- nodemask_t *nodes_allowed, bool do_prep) { return 0; }
+static inline struct page *alloc_fresh_gigantic_page(struct hstate *h,
+ nodemask_t *nodes_allowed, bool do_prep) { return NULL; }
#endif
static void update_and_free_page(struct hstate *h, struct page *page)
@@ -1387,26 +1387,24 @@ static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid)
return page;
}
-static int alloc_fresh_huge_page(struct hstate *h, nodemask_t *nodes_allowed)
+static struct page *alloc_fresh_huge_page(struct hstate *h,
+ nodemask_t *nodes_allowed)
{
- struct page *page;
+ struct page *page = NULL;
int nr_nodes, node;
- int ret = 0;
for_each_node_mask_to_alloc(h, nr_nodes, node, nodes_allowed) {
page = alloc_fresh_huge_page_node(h, node);
- if (page) {
- ret = 1;
+ if (page)
break;
- }
}
- if (ret)
+ if (page)
count_vm_event(HTLB_BUDDY_PGALLOC);
else
count_vm_event(HTLB_BUDDY_PGALLOC_FAIL);
- return ret;
+ return page;
}
/*
@@ -2321,9 +2319,10 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
cond_resched();
if (hstate_is_gigantic(h))
- ret = alloc_fresh_gigantic_page(h, nodes_allowed, true);
+ ret = !!alloc_fresh_gigantic_page(h, nodes_allowed,
+ true);
else
- ret = alloc_fresh_huge_page(h, nodes_allowed);
+ ret = !!alloc_fresh_huge_page(h, nodes_allowed);
spin_lock(&hugetlb_lock);
if (!ret)
goto out;
--
2.5.5
^ permalink raw reply related
* [PATCH v3 2/4] mm: hugetlb: add a new parameter for some functions
From: Huang Shijie @ 2016-12-05 9:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480929431-22348-1-git-send-email-shijie.huang@arm.com>
This patch adds a new parameter, the "do_prep", for these functions:
alloc_fresh_gigantic_page_node()
alloc_fresh_gigantic_page()
The prep_new_huge_page() does some initialization for the new page.
But sometime, we do not need it to do so, such as in the surplus case
in later patch.
With this parameter, the prep_new_huge_page() can be called by needed:
If the "do_prep" is true, calls the prep_new_huge_page() in
the alloc_fresh_gigantic_page_node();
This patch makes preparation for the later patches.
Signed-off-by: Huang Shijie <shijie.huang@arm.com>
---
mm/hugetlb.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 5f4213d..b7c73a1 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1133,27 +1133,29 @@ static struct page *alloc_gigantic_page(int nid, unsigned int order)
static void prep_new_huge_page(struct hstate *h, struct page *page, int nid);
static void prep_compound_gigantic_page(struct page *page, unsigned int order);
-static struct page *alloc_fresh_gigantic_page_node(struct hstate *h, int nid)
+static struct page *alloc_fresh_gigantic_page_node(struct hstate *h,
+ int nid, bool do_prep)
{
struct page *page;
page = alloc_gigantic_page(nid, huge_page_order(h));
if (page) {
prep_compound_gigantic_page(page, huge_page_order(h));
- prep_new_huge_page(h, page, nid);
+ if (do_prep)
+ prep_new_huge_page(h, page, nid);
}
return page;
}
static int alloc_fresh_gigantic_page(struct hstate *h,
- nodemask_t *nodes_allowed)
+ nodemask_t *nodes_allowed, bool do_prep)
{
struct page *page = NULL;
int nr_nodes, node;
for_each_node_mask_to_alloc(h, nr_nodes, node, nodes_allowed) {
- page = alloc_fresh_gigantic_page_node(h, node);
+ page = alloc_fresh_gigantic_page_node(h, node, do_prep);
if (page)
return 1;
}
@@ -1172,7 +1174,7 @@ static inline void free_gigantic_page(struct page *page, unsigned int order) { }
static inline void destroy_compound_gigantic_page(struct page *page,
unsigned int order) { }
static inline int alloc_fresh_gigantic_page(struct hstate *h,
- nodemask_t *nodes_allowed) { return 0; }
+ nodemask_t *nodes_allowed, bool do_prep) { return 0; }
#endif
static void update_and_free_page(struct hstate *h, struct page *page)
@@ -2319,7 +2321,7 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
cond_resched();
if (hstate_is_gigantic(h))
- ret = alloc_fresh_gigantic_page(h, nodes_allowed);
+ ret = alloc_fresh_gigantic_page(h, nodes_allowed, true);
else
ret = alloc_fresh_huge_page(h, nodes_allowed);
spin_lock(&hugetlb_lock);
--
2.5.5
^ permalink raw reply related
* [PATCH v3 1/4] mm: hugetlb: rename some allocation functions
From: Huang Shijie @ 2016-12-05 9:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480929431-22348-1-git-send-email-shijie.huang@arm.com>
After a future patch, the __alloc_buddy_huge_page() will not necessarily
use the buddy allocator.
So this patch removes the "buddy" from these functions:
__alloc_buddy_huge_page -> __alloc_huge_page
__alloc_buddy_huge_page_no_mpol -> __alloc_huge_page_no_mpol
__alloc_buddy_huge_page_with_mpol -> __alloc_huge_page_with_mpol
This patch also adds the description for alloc_gigantic_page().
This patch makes preparation for the later patch.
Signed-off-by: Huang Shijie <shijie.huang@arm.com>
---
mm/hugetlb.c | 30 ++++++++++++++++++++----------
1 file changed, 20 insertions(+), 10 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 5f228cd..5f4213d 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1089,6 +1089,12 @@ static bool zone_spans_last_pfn(const struct zone *zone,
return zone_spans_pfn(zone, last_pfn);
}
+/*
+ * Allocate a gigantic page from @nid node.
+ *
+ * Scan the zones of @nid node, and try to allocate a number of contiguous
+ * pages (1 << order).
+ */
static struct page *alloc_gigantic_page(int nid, unsigned int order)
{
unsigned long nr_pages = 1 << order;
@@ -1157,6 +1163,10 @@ static int alloc_fresh_gigantic_page(struct hstate *h,
static inline bool gigantic_page_supported(void) { return true; }
#else
+static inline struct page *alloc_gigantic_page(int nid, unsigned int order)
+{
+ return NULL;
+}
static inline bool gigantic_page_supported(void) { return false; }
static inline void free_gigantic_page(struct page *page, unsigned int order) { }
static inline void destroy_compound_gigantic_page(struct page *page,
@@ -1568,7 +1578,7 @@ static struct page *__hugetlb_alloc_buddy_huge_page(struct hstate *h,
* For (2), we ignore 'vma' and 'addr' and use 'nid' exclusively. This
* implies that memory policies will not be taken in to account.
*/
-static struct page *__alloc_buddy_huge_page(struct hstate *h,
+static struct page *__alloc_huge_page(struct hstate *h,
struct vm_area_struct *vma, unsigned long addr, int nid)
{
struct page *page;
@@ -1649,21 +1659,21 @@ static struct page *__alloc_buddy_huge_page(struct hstate *h,
* anywhere.
*/
static
-struct page *__alloc_buddy_huge_page_no_mpol(struct hstate *h, int nid)
+struct page *__alloc_huge_page_no_mpol(struct hstate *h, int nid)
{
unsigned long addr = -1;
- return __alloc_buddy_huge_page(h, NULL, addr, nid);
+ return __alloc_huge_page(h, NULL, addr, nid);
}
/*
* Use the VMA's mpolicy to allocate a huge page from the buddy.
*/
static
-struct page *__alloc_buddy_huge_page_with_mpol(struct hstate *h,
+struct page *__alloc_huge_page_with_mpol(struct hstate *h,
struct vm_area_struct *vma, unsigned long addr)
{
- return __alloc_buddy_huge_page(h, vma, addr, NUMA_NO_NODE);
+ return __alloc_huge_page(h, vma, addr, NUMA_NO_NODE);
}
/*
@@ -1681,7 +1691,7 @@ struct page *alloc_huge_page_node(struct hstate *h, int nid)
spin_unlock(&hugetlb_lock);
if (!page)
- page = __alloc_buddy_huge_page_no_mpol(h, nid);
+ page = __alloc_huge_page_no_mpol(h, nid);
return page;
}
@@ -1711,7 +1721,7 @@ static int gather_surplus_pages(struct hstate *h, int delta)
retry:
spin_unlock(&hugetlb_lock);
for (i = 0; i < needed; i++) {
- page = __alloc_buddy_huge_page_no_mpol(h, NUMA_NO_NODE);
+ page = __alloc_huge_page_no_mpol(h, NUMA_NO_NODE);
if (!page) {
alloc_ok = false;
break;
@@ -2027,7 +2037,7 @@ struct page *alloc_huge_page(struct vm_area_struct *vma,
page = dequeue_huge_page_vma(h, vma, addr, avoid_reserve, gbl_chg);
if (!page) {
spin_unlock(&hugetlb_lock);
- page = __alloc_buddy_huge_page_with_mpol(h, vma, addr);
+ page = __alloc_huge_page_with_mpol(h, vma, addr);
if (!page)
goto out_uncharge_cgroup;
if (!avoid_reserve && vma_has_reserves(vma, gbl_chg)) {
@@ -2285,7 +2295,7 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
* First take pages out of surplus state. Then make up the
* remaining difference by allocating fresh huge pages.
*
- * We might race with __alloc_buddy_huge_page() here and be unable
+ * We might race with __alloc_huge_page() here and be unable
* to convert a surplus huge page to a normal huge page. That is
* not critical, though, it just means the overall size of the
* pool might be one hugepage larger than it needs to be, but
@@ -2331,7 +2341,7 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
* By placing pages into the surplus state independent of the
* overcommit value, we are allowing the surplus pool size to
* exceed overcommit. There are few sane options here. Since
- * __alloc_buddy_huge_page() is checking the global counter,
+ * __alloc_huge_page() is checking the global counter,
* though, we'll note that we're not allowed to exceed surplus
* and won't grow the pool anywhere else. Not until one of the
* sysctls are changed, or the surplus pages go out of use.
--
2.5.5
^ permalink raw reply related
* [PATCH v3 0/4] mm: fix the "counter.sh" failure for libhugetlbfs
From: Huang Shijie @ 2016-12-05 9:17 UTC (permalink / raw)
To: linux-arm-kernel
(1) Background
For the arm64, the hugetlb page size can be 32M (PMD + Contiguous bit).
In the 4K page environment, the max page order is 10 (max_order - 1),
so 32M page is the gigantic page.
The arm64 MMU supports a Contiguous bit which is a hint that the TTE
is one of a set of contiguous entries which can be cached in a single
TLB entry. Please refer to the arm64v8 mannul :
DDI0487A_f_armv8_arm.pdf (in page D4-1811)
(2) The bug
After I tested the libhugetlbfs, I found the test case "counter.sh"
will fail with the gigantic page (32M page in arm64 board).
The counter.sh is just a wrapper for counter.c.
You can find them in:
https://github.com/libhugetlbfs/libhugetlbfs/blob/master/tests/counters.c
https://github.com/libhugetlbfs/libhugetlbfs/blob/master/tests/counters.sh
The error log shows below:
----------------------------------------------------------
...........................................
LD_PRELOAD=libhugetlbfs.so shmoverride_unlinked (32M: 64): PASS
LD_PRELOAD=libhugetlbfs.so HUGETLB_SHM=yes shmoverride_unlinked (32M: 64): PASS
quota.sh (32M: 64): PASS
counters.sh (32M: 64): FAIL mmap failed: Invalid argument
********** TEST SUMMARY
* 32M
* 32-bit 64-bit
* Total testcases: 0 87
* Skipped: 0 0
* PASS: 0 86
* FAIL: 0 1
* Killed by signal: 0 0
* Bad configuration: 0 0
* Expected FAIL: 0 0
* Unexpected PASS: 0 0
* Strange test result: 0 0
**********
----------------------------------------------------------
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 some functions are wrong:
return_unused_surplus_pages()
nr_overcommit_hugepages_store()
hugetlb_overcommit_handler()
This patch set adds support for gigantic surplus hugetlb pages,
allowing the counter.sh unit test to pass.
Test this patch set with Juno-r1 board.
v2 -- > v3:
1.) In patch 2, change argument "no_init" to "do_prep"
2.) In patch 3, also change alloc_fresh_huge_page().
In the v2, this patch only changes the alloc_fresh_gigantic_page().
3.) Merge old patch #4,#5 into the last one.
4.) Follow Babka's suggestion, do the NULL check for @mask.
5.) others.
v1 -- > v2:
1.) fix the compiler error in X86.
2.) add new patches for NUMA.
The patch #2 ~ #5 are new patches.
Huang Shijie (4):
mm: hugetlb: rename some allocation functions
mm: hugetlb: add a new parameter for some functions
mm: hugetlb: change the return type for some functions
mm: hugetlb: support gigantic surplus pages
include/linux/mempolicy.h | 8 +++
mm/hugetlb.c | 146 +++++++++++++++++++++++++++++++++++-----------
mm/mempolicy.c | 44 ++++++++++++++
3 files changed, 163 insertions(+), 35 deletions(-)
--
2.5.5
^ permalink raw reply
* [linux-sunxi] [PATCH v3 -next 2/2] ARM: dts: sunxi: add support for Orange Pi Zero board
From: Maxime Ripard @ 2016-12-05 9:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161203162455.OlDm27ch@smtp3m.mail.yandex.net>
Hi Icenowy,
On Sat, Dec 03, 2016 at 09:24:19PM +0800, Icenowy Zheng wrote:
> <p dir="ltr"><br>
> 2016年12月3日 下午5:43于 Jernej Skrabec <jernej.skrabec at gmail.com>写道:<br>
> ><br>
> > Hi,<br>
> ><br>
> > Dne petek, 02. december 2016 17.42.04 UTC+1 je oseba Chen-Yu Tsai napisala:<br>
> >><br>
> >> Hi, <br>
> >><br>
> >> On Fri, Dec 2, 2016 at 11:05 PM, Icenowy Zheng <ice... at aosc.xyz> wrote: <br>
> >> > Orange Pi Zero is a board that came with the new Allwinner H2+ SoC and a <br>
> >> > SDIO Wi-Fi chip by Allwinner (XR819). <br>
> >> > <br>
> >> > Add a device tree file for it. <br>
> >> > <br>
> >> > Signed-off-by: Icenowy Zheng <ice... at aosc.xyz> <br>
Please make sure to disable the HTML replies, this is what your mail
looks like on a !HTML MUA :)
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161205/8617213b/attachment.sig>
^ permalink raw reply
* [PATCH v2 3/3] ARM: da850: fix da850_set_pll0rate()
From: Bartosz Golaszewski @ 2016-12-05 9:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <130825f1-5c8f-f6bc-1f27-929ff591a9c3@ti.com>
2016-12-05 9:45 GMT+01:00 Sekhar Nori <nsekhar@ti.com>:
> On Friday 02 December 2016 09:08 PM, Bartosz Golaszewski wrote:
>> This function is broken - its second argument is an index to the freq
>> table, not the requested clock rate in Hz. It leads to an oops when
>> called from clk_set_rate() since this argument isn't bounds checked
>> either.
>>
>> Fix it by iterating over the array of supported frequencies and
>> selecting a one that matches or returning -EINVAL for unsupported
>> rates.
>>
>> Also: update the davinci cpufreq driver. It's the only user of this
>> clock and currently it passes the cpufreq table index to
>> clk_set_rate(), which is confusing. Make it pass the requested clock
>> rate in Hz.
>>
>> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>> ---
>> arch/arm/mach-davinci/da850.c | 22 ++++++++++++++++++----
>> drivers/cpufreq/davinci-cpufreq.c | 2 +-
>> 2 files changed, 19 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
>> index a55101c..92e3303 100644
>> --- a/arch/arm/mach-davinci/da850.c
>> +++ b/arch/arm/mach-davinci/da850.c
>> @@ -1179,14 +1179,28 @@ static int da850_set_armrate(struct clk *clk, unsigned long index)
>> return clk_set_rate(pllclk, index);
>> }
>>
>> -static int da850_set_pll0rate(struct clk *clk, unsigned long index)
>> +static int da850_set_pll0rate(struct clk *clk, unsigned long rate)
>> {
>> - unsigned int prediv, mult, postdiv;
>> - struct da850_opp *opp;
>> struct pll_data *pll = clk->pll_data;
>> + struct cpufreq_frequency_table *freq;
>> + unsigned int prediv, mult, postdiv;
>> + struct da850_opp *opp = NULL;
>> int ret;
>>
>> - opp = (struct da850_opp *) cpufreq_info.freq_table[index].driver_data;
>> + for (freq = da850_freq_table;
>> + freq->frequency != CPUFREQ_TABLE_END; freq++) {
>> + /* requested_rate is in Hz, freq->frequency is in KHz */
>> + unsigned long freq_rate = freq->frequency * 1000;
>
> A small optimization here. Instead of multiplying potentially every
> frequency in the table by 1000, you could divide the incoming rate down
> to KHz. This will also avoid the need for 'freq_rate'. Should have
> noticed this earlier. Sorry about that.
>
> Thanks,
> Sekhar
I thought about it, but figured the multiplication would be safer. I
will change it if you prefer this version.
Best regards,
Bartosz Golaszewski
^ permalink raw reply
* [PATCH v2 1/3] ARM: da850: fix infinite loop in clk_set_rate()
From: Bartosz Golaszewski @ 2016-12-05 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <34f9e4c4-917e-0472-72af-96fbc7e0c6db@ti.com>
2016-12-05 9:38 GMT+01:00 Sekhar Nori <nsekhar@ti.com>:
> On Friday 02 December 2016 09:08 PM, Bartosz Golaszewski wrote:
>> The aemif clock is added twice to the lookup table in da850.c. This
>> breaks the children list of pll0_sysclk3 as we're using the same list
>> links in struct clk. When calling clk_set_rate(), we get stuck in
>> propagate_rate().
>>
>> Create a separate clock for nand, inheriting the rate of the aemif
>> clock and retrieve it in the davinci_nand module.
>>
>> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>> ---
>> arch/arm/mach-davinci/da850.c | 7 ++++++-
>> drivers/mtd/nand/davinci_nand.c | 2 +-
>> 2 files changed, 7 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
>> index e770c97..1fcc986 100644
>> --- a/arch/arm/mach-davinci/da850.c
>> +++ b/arch/arm/mach-davinci/da850.c
>> @@ -367,6 +367,11 @@ static struct clk aemif_clk = {
>> .flags = ALWAYS_ENABLED,
>> };
>>
>> +static struct clk nand_clk = {
>> + .name = "nand",
>> + .parent = &aemif_clk,
>> +};
>> +
>> static struct clk usb11_clk = {
>> .name = "usb11",
>> .parent = &pll0_sysclk4,
>> @@ -537,7 +542,7 @@ static struct clk_lookup da850_clks[] = {
>> CLK("da830-mmc.0", NULL, &mmcsd0_clk),
>> CLK("da830-mmc.1", NULL, &mmcsd1_clk),
>> CLK("ti-aemif", NULL, &aemif_clk),
>> - CLK(NULL, "aemif", &aemif_clk),
>> + CLK(NULL, "nand", &nand_clk),
>
> Why use a NULL device name here?
>
>> CLK("ohci-da8xx", "usb11", &usb11_clk),
>> CLK("musb-da8xx", "usb20", &usb20_clk),
>> CLK("spi_davinci.0", NULL, &spi0_clk),
>> diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
>> index 27fa8b8..5857d06 100644
>> --- a/drivers/mtd/nand/davinci_nand.c
>> +++ b/drivers/mtd/nand/davinci_nand.c
>> @@ -694,7 +694,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
>>
>> ret = -EINVAL;
>>
>> - info->clk = devm_clk_get(&pdev->dev, "aemif");
>> + info->clk = devm_clk_get(&pdev->dev, "nand");
>
> This driver is used by keystone devices too. So just changing the
> connection id will likely break them. Why do you need to change the
> connection id?
>
> Thanks,
> Sekhar
Thanks, I didn't know it.
I thought it would make the purpose of the clock more obvious. I'll
change it back to "aemif".
Best regards,
Bartosz Golaszewski
^ permalink raw reply
* [PATCH v2 2/3] ARM: dts: sunxi: add support for Orange Pi Zero board
From: Maxime Ripard @ 2016-12-05 9:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <324c8820-aeea-3fad-0e02-1bdb8f675677@arm.com>
On Fri, Dec 02, 2016 at 04:10:46PM +0000, Andre Przywara wrote:
> Hi,
>
> On 02/12/16 14:32, Icenowy Zheng wrote:
> >
> >
> > 02.12.2016, 22:30, "Hans de Goede" <hdegoede@redhat.com>:
> >> Hi,
> >>
> >> On 02-12-16 15:22, Icenowy Zheng wrote:
> >>> 01.12.2016, 17:36, "Maxime Ripard" <maxime.ripard@free-electrons.com>:
> >>>> On Mon, Nov 28, 2016 at 12:29:07AM +0000, Andr? Przywara wrote:
> >>>>> > Something more interesting happened.
> >>>>> >
> >>>>> > Xunlong made a add-on board for Orange Pi Zero, which exposes the
> >>>>> > two USB Controllers exported at expansion bus as USB Type-A
> >>>>> > connectors.
> >>>>> >
> >>>>> > Also it exposes a analog A/V jack and a microphone.
> >>>>> >
> >>>>> > Should I enable {e,o}hci{2.3} in the device tree?
> >>>>>
> >>>>> Actually we should do this regardless of this extension board. The USB
> >>>>> pins are not multiplexed and are exposed on user accessible pins (just
> >>>>> not soldered, but that's a detail), so I think they qualify for DT
> >>>>> enablement. And even if a user can't use them, it doesn't hurt to have
> >>>>> them (since they are not multiplexed).
> >>>>
> >>>> My main concern about this is that we'll leave regulators enabled by
> >>>> default, for a minority of users. And that minority will prevent to do
> >>>> a proper power management when the times come since we'll have to keep
> >>>> that behaviour forever.
> >>>
> >>> I think these users can add a 'fdt set /xxx/xxx status "disabled" ' .
> >>
> >> I don't think that will be necessary I'm pretty sure these extra usb
> >> ports do not have a regulator for the Vbus, they just hook directly
> >> to the 5V rail, can someone with a schematic check ?
> >
> > We seems to have still no schematics for the add-on board.
>
> From looking at the picture of that expansion board on the Aliexpress
> page and chasing the tracks, there is clearly no voltage regulator on
> there, it's just passive components. The 5V pin from the headers is
> routed forth and back between the two layers via some vias directly to
> the 5V pins of the USB sockets.
>
> > But something is sure is that there's no any regulator-related pins
> > on the add-on pinout. There's only USB DM and DP pins.
> >
> > So the Vbus must be directly connected to +5V.
>
> So yes, it is.
>
> But I think the question is moot anyways, since we don't provide DT
> support for that add-on board at that point anyways.
> One could imagine another board, though, which has regulators switched
> by GPIOs, but that would be their problem and they would have regulators
> specified in their specific DT snippet, then.
>
> So to summarize:
> - For that specific Orange Pi Zero board which we discuss the DT for
> there is no regulator support for the additional USB ports. Thus nothing
> we could turn off to save power.
> - A user could just take these USB brackets with pin headers that are so
> common in PCs to connect additional USB ports to the back of the box.
> One just needs to re-sort the pins, which is a matter of a minute.
> - As long as we don't provide any easy way of handling DT changes, we
> should enable the USB ports for the sake of the users of either those
> brackets or the expansion board. Any more sophisticated USB expansion
> board with regulators would need to amend the DT anyway.
I disagree with this. We already have different ways of changing the
DT at runtime, and even if we didn't I'd still disagree. Once you add
that, there's simply no going back. Saying "let's enable it and we'll
figure it out later" doesn't work, and is essentially a "enable it".
So what you're suggesting is to have those regulators enabled forever,
which might be the case on that board anyway, but definitely shouldn't
be policy.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161205/d728f143/attachment.sig>
^ permalink raw reply
* [PATCH v3 7/7] ARM: dts: stm32: add stm32 general purpose timer driver in DT
From: Lee Jones @ 2016-12-05 8:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <14837e15-07bb-39e5-b5b6-39a7dfb9130f@kernel.org>
On Sat, 03 Dec 2016, Jonathan Cameron wrote:
> On 02/12/16 13:22, Lee Jones wrote:
> > On Fri, 02 Dec 2016, Benjamin Gaignard wrote:
> >
> >> Add general purpose timers and it sub-nodes into DT for stm32f4.
> >> Define and enable pwm1 and pwm3 for stm32f469 discovery board
> >>
> >> version 3:
> >> - use "st,stm32-timer-trigger" in DT
> >>
> >> version 2:
> >> - use parameters to describe hardware capabilities
> >> - do not use references for pwm and iio timer subnodes
> >>
> >> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> >> ---
> >> arch/arm/boot/dts/stm32f429.dtsi | 333 +++++++++++++++++++++++++++++++++-
> >> arch/arm/boot/dts/stm32f469-disco.dts | 28 +++
> >> 2 files changed, 360 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> >> index bca491d..8c50d03 100644
> >> --- a/arch/arm/boot/dts/stm32f429.dtsi
> >> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> >> @@ -48,7 +48,7 @@
> >> #include "skeleton.dtsi"
> >> #include "armv7-m.dtsi"
> >> #include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
> >> -
> >> +#include <dt-bindings/iio/timer/st,stm32-timer-triggers.h>
> >> / {
> >> clocks {
> >> clk_hse: clk-hse {
> >> @@ -355,6 +355,21 @@
> >> slew-rate = <2>;
> >> };
> >> };
> >> +
> >> + pwm1_pins: pwm at 1 {
> >> + pins {
> >> + pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
> >> + <STM32F429_PB13_FUNC_TIM1_CH1N>,
> >> + <STM32F429_PB12_FUNC_TIM1_BKIN>;
> >> + };
> >> + };
> >> +
> >> + pwm3_pins: pwm at 3 {
> >> + pins {
> >> + pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
> >> + <STM32F429_PB5_FUNC_TIM3_CH2>;
> >> + };
> >> + };
> >> };
> >>
> >> rcc: rcc at 40023810 {
> >> @@ -426,6 +441,322 @@
> >> interrupts = <80>;
> >> clocks = <&rcc 0 38>;
> >> };
> >> +
> >> + gptimer1: gptimer1 at 40010000 {
> >
> > timer at xxxxxxx
> >
> > Node names should be generic and not numbered.
> >
> > I suggest that this isn't actually a timer either. Is contains a
> > timer (and a PWM), but in it's completeness it is not a timer per
> > say.
> That's just mean ;) At least suggest an alternative?
>
> stm32-gptimerish-magic?
Perfect! ;)
I already did:
https://lkml.org/lkml/2016/11/23/131
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40010000 0x400>;
> >> + clocks = <&rcc 0 160>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + pwm1 at 0 {
> >> + compatible = "st,stm32-pwm";
> >> + st,pwm-num-chan = <4>;
> >> + st,breakinput;
> >> + st,complementary;
> >> + status = "disabled";
> >> + };
> >> +
> >> + timer1 at 0 {
> >> + compatible = "st,stm32-timer-trigger";
> >> + interrupts = <27>;
> >> + st,input-triggers-names = TIM5_TRGO,
> >> + TIM2_TRGO,
> >> + TIM4_TRGO,
> >> + TIM3_TRGO;
> >
> > I'm still dubious with matching by strings.
> >
> > I'll take a look at the C code to see what the alternatives could be.
> >
> >> + st,output-triggers-names = TIM1_TRGO,
> >> + TIM1_CH1,
> >> + TIM1_CH2,
> >> + TIM1_CH3,
> >> + TIM1_CH4;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer2: gptimer2 at 40000000 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40000000 0x400>;
> >> + clocks = <&rcc 0 128>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + pwm2 at 0 {
> >> + compatible = "st,stm32-pwm";
> >> + st,pwm-num-chan = <4>;
> >> + st,32bits-counter;
> >> + status = "disabled";
> >> + };
> >> +
> >> + timer2 at 0 {
> >> + compatible = "st,stm32-timer-trigger";
> >> + interrupts = <28>;
> >> + st,input-triggers-names = TIM1_TRGO,
> >> + TIM8_TRGO,
> >> + TIM3_TRGO,
> >> + TIM4_TRGO;
> >> + st,output-triggers-names = TIM2_TRGO,
> >> + TIM2_CH1,
> >> + TIM2_CH2,
> >> + TIM2_CH3,
> >> + TIM2_CH4;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer3: gptimer3 at 40000400 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40000400 0x400>;
> >> + clocks = <&rcc 0 129>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + pwm3 at 0 {
> >> + compatible = "st,stm32-pwm";
> >> + st,pwm-num-chan = <4>;
> >> + status = "disabled";
> >> + };
> >> +
> >> + timer3 at 0 {
> >> + compatible = "st,stm32-timer-trigger";
> >> + interrupts = <29>;
> >> + st,input-triggers-names = TIM1_TRGO,
> >> + TIM8_TRGO,
> >> + TIM5_TRGO,
> >> + TIM4_TRGO;
> >> + st,output-triggers-names = TIM3_TRGO,
> >> + TIM3_CH1,
> >> + TIM3_CH2,
> >> + TIM3_CH3,
> >> + TIM3_CH4;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer4: gptimer4 at 40000800 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40000800 0x400>;
> >> + clocks = <&rcc 0 130>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + pwm4 at 0 {
> >> + compatible = "st,stm32-pwm";
> >> + st,pwm-num-chan = <4>;
> >> + status = "disabled";
> >> + };
> >> +
> >> + timer4 at 0 {
> >> + compatible = "st,stm32-timer-trigger";
> >> + interrupts = <30>;
> >> + st,input-triggers-names = TIM1_TRGO,
> >> + TIM2_TRGO,
> >> + TIM3_TRGO,
> >> + TIM8_TRGO;
> >> + st,output-triggers-names = TIM4_TRGO,
> >> + TIM4_CH1,
> >> + TIM4_CH2,
> >> + TIM4_CH3,
> >> + TIM4_CH4;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer5: gptimer5 at 40000C00 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40000C00 0x400>;
> >> + clocks = <&rcc 0 131>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + pwm5 at 0 {
> >> + compatible = "st,stm32-pwm";
> >> + st,pwm-num-chan = <4>;
> >> + st,32bits-counter;
> >> + status = "disabled";
> >> + };
> >> +
> >> + timer5 at 0 {
> >> + compatible = "st,stm32-timer-trigger";
> >> + interrupts = <50>;
> >> + st,input-triggers-names = TIM2_TRGO,
> >> + TIM3_TRGO,
> >> + TIM4_TRGO,
> >> + TIM8_TRGO;
> >> + st,output-triggers-names = TIM5_TRGO,
> >> + TIM5_CH1,
> >> + TIM5_CH2,
> >> + TIM5_CH3,
> >> + TIM5_CH4;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer6: gptimer6 at 40001000 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40001000 0x400>;
> >> + clocks = <&rcc 0 132>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + timer6 at 0 {
> >> + compatible = "st,stm32-timer-trigger";
> >> + interrupts = <54>;
> >> + st,output-triggers-names = TIM6_TRGO;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer7: gptimer7 at 40001400 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40001400 0x400>;
> >> + clocks = <&rcc 0 133>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + timer7 at 0 {
> >> + compatible = "st,stm32-timer-trigger";
> >> + interrupts = <55>;
> >> + st,output-triggers-names = TIM7_TRGO;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer8: gptimer8 at 40010400 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40010400 0x400>;
> >> + clocks = <&rcc 0 161>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + pwm8 at 0 {
> >> + compatible = "st,stm32-pwm";
> >> + st,pwm-num-chan = <4>;
> >> + st,complementary;
> >> + st,breakinput;
> >> + status = "disabled";
> >> + };
> >> +
> >> + timer8 at 0 {
> >> + compatible = "st,stm32-timer-trigger";
> >> + interrupts = <46>;
> >> + st,input-triggers-names = TIM1_TRGO,
> >> + TIM2_TRGO,
> >> + TIM4_TRGO,
> >> + TIM5_TRGO;
> >> + st,output-triggers-names = TIM8_TRGO,
> >> + TIM8_CH1,
> >> + TIM8_CH2,
> >> + TIM8_CH3,
> >> + TIM8_CH4;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer9: gptimer9 at 40014000 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40014000 0x400>;
> >> + clocks = <&rcc 0 176>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + pwm9 at 0 {
> >> + compatible = "st,stm32-pwm";
> >> + st,pwm-num-chan = <2>;
> >> + status = "disabled";
> >> + };
> >> +
> >> + timer9 at 0 {
> >> + compatible = "st,stm32-timer-trigger";
> >> + interrupts = <24>;
> >> + st,input-triggers-names = TIM2_TRGO,
> >> + TIM3_TRGO;
> >> + st,output-triggers-names = TIM9_TRGO,
> >> + TIM9_CH1,
> >> + TIM9_CH2;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer10: gptimer10 at 40014400 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40014400 0x400>;
> >> + clocks = <&rcc 0 177>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + pwm10 at 0 {
> >> + compatible = "st,stm32-pwm";
> >> + st,pwm-num-chan = <1>;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer11: gptimer11 at 40014800 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40014800 0x400>;
> >> + clocks = <&rcc 0 178>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + pwm11 at 0 {
> >> + compatible = "st,stm32-pwm";
> >> + st,pwm-num-chan = <1>;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer12: gptimer12 at 40001800 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40001800 0x400>;
> >> + clocks = <&rcc 0 134>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + pwm12 at 0 {
> >> + compatible = "st,stm32-pwm";
> >> + st,pwm-num-chan = <2>;
> >> + status = "disabled";
> >> + };
> >> +
> >> + timer12 at 0 {
> >> + compatible = "st,stm32-timer-trigger";
> >> + interrupts = <43>;
> >> + st,input-triggers-names = TIM4_TRGO,
> >> + TIM5_TRGO;
> >> + st,output-triggers-names = TIM12_TRGO,
> >> + TIM12_CH1,
> >> + TIM12_CH2;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer13: gptimer13 at 40001C00 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40001C00 0x400>;
> >> + clocks = <&rcc 0 135>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + pwm13 at 0 {
> >> + compatible = "st,stm32-pwm";
> >> + st,pwm-num-chan = <1>;
> >> + status = "disabled";
> >> + };
> >> + };
> >> +
> >> + gptimer14: gptimer14 at 40002000 {
> >> + compatible = "st,stm32-gptimer";
> >> + reg = <0x40002000 0x400>;
> >> + clocks = <&rcc 0 136>;
> >> + clock-names = "clk_int";
> >> + status = "disabled";
> >> +
> >> + pwm14 at 0 {
> >> + compatible = "st,stm32-pwm";
> >> + st,pwm-num-chan = <1>;
> >> + status = "disabled";
> >> + };
> >> + };
> >> };
> >> };
> >>
> >> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> >> index 8a163d7..df4ca7e 100644
> >> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> >> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> >> @@ -81,3 +81,31 @@
> >> &usart3 {
> >> status = "okay";
> >> };
> >> +
> >> +&gptimer1 {
> >> + status = "okay";
> >> +
> >> + pwm1 at 0 {
> >> + pinctrl-0 = <&pwm1_pins>;
> >> + pinctrl-names = "default";
> >> + status = "okay";
> >> + };
> >> +
> >> + timer1 at 0 {
> >> + status = "okay";
> >> + };
> >> +};
> >
> > This is a much *better* format than before.
> >
> > I still don't like the '&' syntax though.
> >
> >> +&gptimer3 {
> >> + status = "okay";
> >> +
> >> + pwm3 at 0 {
> >> + pinctrl-0 = <&pwm3_pins>;
> >> + pinctrl-names = "default";
> >> + status = "okay";
> >> + };
> >> +
> >> + timer3 at 0 {
> >> + status = "okay";
> >> + };
> >> +};
> >
>
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH v2] arm64: dts: zx: add pcu_domain node for zx296718
From: Shawn Guo @ 2016-12-05 8:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480925871-20855-1-git-send-email-baoyou.xie@linaro.org>
On Mon, Dec 05, 2016 at 04:17:51PM +0800, Baoyou Xie wrote:
> This patch adds the pcu_domain node, so it can be used
> by zte-soc's power domain driver.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
I'm fine with the patch itself, but I need to wait the driver and
bindings being accepted to apply it.
Shawn
> ---
> arch/arm64/boot/dts/zte/zx296718.dtsi | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/zte/zx296718.dtsi b/arch/arm64/boot/dts/zte/zx296718.dtsi
> index b44d1d1..1aa0587 100644
> --- a/arch/arm64/boot/dts/zte/zx296718.dtsi
> +++ b/arch/arm64/boot/dts/zte/zx296718.dtsi
> @@ -302,6 +302,11 @@
> reg = <0x116000 0x1000>;
> };
>
> + pcu_domain: pcu at 117000 {
> + compatible = "zte,zx296718-pcu";
> + reg = <0x00117000 0x1000>;
> + };
> +
> uart0: uart at 11f000 {
> compatible = "arm,pl011", "arm,primecell";
> arm,primecell-periphid = <0x001feffe>;
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH v2 2/3] ARM: dts: sunxi: add support for Orange Pi Zero board
From: Maxime Ripard @ 2016-12-05 8:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <11498641480688550@web2g.yandex.ru>
On Fri, Dec 02, 2016 at 10:22:30PM +0800, Icenowy Zheng wrote:
>
>
> 01.12.2016, 17:36, "Maxime Ripard" <maxime.ripard@free-electrons.com>:
> > On Mon, Nov 28, 2016 at 12:29:07AM +0000, Andr? Przywara wrote:
> >> ?> Something more interesting happened.
> >> ?>
> >> ?> Xunlong made a add-on board for Orange Pi Zero, which exposes the
> >> ?> two USB Controllers exported at expansion bus as USB Type-A
> >> ?> connectors.
> >> ?>
> >> ?> Also it exposes a analog A/V jack and a microphone.
> >> ?>
> >> ?> Should I enable {e,o}hci{2.3} in the device tree?
> >>
> >> ?Actually we should do this regardless of this extension board. The USB
> >> ?pins are not multiplexed and are exposed on user accessible pins (just
> >> ?not soldered, but that's a detail), so I think they qualify for DT
> >> ?enablement. And even if a user can't use them, it doesn't hurt to have
> >> ?them (since they are not multiplexed).
> >
> > My main concern about this is that we'll leave regulators enabled by
> > default, for a minority of users. And that minority will prevent to do
> > a proper power management when the times come since we'll have to keep
> > that behaviour forever.
>
> I think these users can add a 'fdt set /xxx/xxx status "disabled" ' .
You can't ask that from the majority of users. These users will take
debian or fedora, install it, and expect everything to work
properly. I would make the opposite argument actually. If someone is
knowledgeable enough to solder the USB pins a connector, then (s)he'll
be able to make that u-boot call.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161205/41c61333/attachment.sig>
^ permalink raw reply
* [PATCH v1 1/2] Add crypto driver support for some MediaTek chips
From: Corentin Labbe @ 2016-12-05 8:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480921284-45827-2-git-send-email-ryder.lee@mediatek.com>
Hello
I have two minor comment.
On Mon, Dec 05, 2016 at 03:01:23PM +0800, Ryder Lee wrote:
> This adds support for the MediaTek hardware accelerator on
> mt7623/mt2701/mt8521p SoC.
>
> This driver currently implement:
> - SHA1 and SHA2 family(HMAC) hash alogrithms.
There is a typo for algorithms.
[...]
> +/**
> + * struct mtk_desc - DMA descriptor
> + * @hdr: the descriptor control header
> + * @buf: DMA address of input buffer segment
> + * @ct: DMA address of command token that control operation flow
> + * @ct_hdr: the command token control header
> + * @tag: the user-defined field
> + * @tfm: DMA address of transform state
> + * @bound: align descriptors offset boundary
> + *
> + * Structure passed to the crypto engine to describe where source
> + * data needs to be fetched and how it needs to be processed.
> + */
> +struct mtk_desc {
> + u32 hdr;
> + u32 buf;
> + u32 ct;
> + u32 ct_hdr;
> + u32 tag;
> + u32 tfm;
> + u32 bound[2];
> +};
Do you have tested this descriptor with BE/LE kernel ?
Regards
Corentin Labbe
^ permalink raw reply
* [PATCH 2/2] arm: dts: sun8i: reuse the uart1 node of iNet D978 rev2 board
From: Maxime Ripard @ 2016-12-05 8:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161202151913.38892-2-icenowy@aosc.xyz>
On Fri, Dec 02, 2016 at 11:19:13PM +0800, Icenowy Zheng wrote:
> As a uart1 node is added into sun8i-reference-design-tablet.dtsi, simply
> use it in iNet D978 rev2 device tree.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
I'd like to see more consolidation before that change is needed. If we
find more boards using that, it will make sense, but for a single
board it's not worth it.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161205/4aa6d997/attachment.sig>
^ permalink raw reply
* [PATCH v2 3/3] ARM: da850: fix da850_set_pll0rate()
From: Sekhar Nori @ 2016-12-05 8:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480693134-31324-4-git-send-email-bgolaszewski@baylibre.com>
On Friday 02 December 2016 09:08 PM, Bartosz Golaszewski wrote:
> This function is broken - its second argument is an index to the freq
> table, not the requested clock rate in Hz. It leads to an oops when
> called from clk_set_rate() since this argument isn't bounds checked
> either.
>
> Fix it by iterating over the array of supported frequencies and
> selecting a one that matches or returning -EINVAL for unsupported
> rates.
>
> Also: update the davinci cpufreq driver. It's the only user of this
> clock and currently it passes the cpufreq table index to
> clk_set_rate(), which is confusing. Make it pass the requested clock
> rate in Hz.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
> arch/arm/mach-davinci/da850.c | 22 ++++++++++++++++++----
> drivers/cpufreq/davinci-cpufreq.c | 2 +-
> 2 files changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
> index a55101c..92e3303 100644
> --- a/arch/arm/mach-davinci/da850.c
> +++ b/arch/arm/mach-davinci/da850.c
> @@ -1179,14 +1179,28 @@ static int da850_set_armrate(struct clk *clk, unsigned long index)
> return clk_set_rate(pllclk, index);
> }
>
> -static int da850_set_pll0rate(struct clk *clk, unsigned long index)
> +static int da850_set_pll0rate(struct clk *clk, unsigned long rate)
> {
> - unsigned int prediv, mult, postdiv;
> - struct da850_opp *opp;
> struct pll_data *pll = clk->pll_data;
> + struct cpufreq_frequency_table *freq;
> + unsigned int prediv, mult, postdiv;
> + struct da850_opp *opp = NULL;
> int ret;
>
> - opp = (struct da850_opp *) cpufreq_info.freq_table[index].driver_data;
> + for (freq = da850_freq_table;
> + freq->frequency != CPUFREQ_TABLE_END; freq++) {
> + /* requested_rate is in Hz, freq->frequency is in KHz */
> + unsigned long freq_rate = freq->frequency * 1000;
A small optimization here. Instead of multiplying potentially every
frequency in the table by 1000, you could divide the incoming rate down
to KHz. This will also avoid the need for 'freq_rate'. Should have
noticed this earlier. Sorry about that.
Thanks,
Sekhar
^ permalink raw reply
* [PATCH v2 1/3] ARM: da850: fix infinite loop in clk_set_rate()
From: Sekhar Nori @ 2016-12-05 8:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480693134-31324-2-git-send-email-bgolaszewski@baylibre.com>
On Friday 02 December 2016 09:08 PM, Bartosz Golaszewski wrote:
> The aemif clock is added twice to the lookup table in da850.c. This
> breaks the children list of pll0_sysclk3 as we're using the same list
> links in struct clk. When calling clk_set_rate(), we get stuck in
> propagate_rate().
>
> Create a separate clock for nand, inheriting the rate of the aemif
> clock and retrieve it in the davinci_nand module.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
> arch/arm/mach-davinci/da850.c | 7 ++++++-
> drivers/mtd/nand/davinci_nand.c | 2 +-
> 2 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
> index e770c97..1fcc986 100644
> --- a/arch/arm/mach-davinci/da850.c
> +++ b/arch/arm/mach-davinci/da850.c
> @@ -367,6 +367,11 @@ static struct clk aemif_clk = {
> .flags = ALWAYS_ENABLED,
> };
>
> +static struct clk nand_clk = {
> + .name = "nand",
> + .parent = &aemif_clk,
> +};
> +
> static struct clk usb11_clk = {
> .name = "usb11",
> .parent = &pll0_sysclk4,
> @@ -537,7 +542,7 @@ static struct clk_lookup da850_clks[] = {
> CLK("da830-mmc.0", NULL, &mmcsd0_clk),
> CLK("da830-mmc.1", NULL, &mmcsd1_clk),
> CLK("ti-aemif", NULL, &aemif_clk),
> - CLK(NULL, "aemif", &aemif_clk),
> + CLK(NULL, "nand", &nand_clk),
Why use a NULL device name here?
> CLK("ohci-da8xx", "usb11", &usb11_clk),
> CLK("musb-da8xx", "usb20", &usb20_clk),
> CLK("spi_davinci.0", NULL, &spi0_clk),
> diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
> index 27fa8b8..5857d06 100644
> --- a/drivers/mtd/nand/davinci_nand.c
> +++ b/drivers/mtd/nand/davinci_nand.c
> @@ -694,7 +694,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
>
> ret = -EINVAL;
>
> - info->clk = devm_clk_get(&pdev->dev, "aemif");
> + info->clk = devm_clk_get(&pdev->dev, "nand");
This driver is used by keystone devices too. So just changing the
connection id will likely break them. Why do you need to change the
connection id?
Thanks,
Sekhar
^ permalink raw reply
* [PATCH v3 3/7] PWM: add pwm-stm32 DT bindings
From: Lee Jones @ 2016-12-05 8:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205065350.GA18069@ulmo.ba.sec>
On Mon, 05 Dec 2016, Thierry Reding wrote:
> On Fri, Dec 02, 2016 at 11:17:18AM +0100, Benjamin Gaignard wrote:
> > Define bindings for pwm-stm32
> >
> > version 2:
> > - use parameters instead of compatible of handle the hardware configuration
> >
> > Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> > ---
> > .../devicetree/bindings/pwm/pwm-stm32.txt | 38 ++++++++++++++++++++++
> > 1 file changed, 38 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/pwm/pwm-stm32.txt
> >
> > diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt
> > new file mode 100644
> > index 0000000..575b9fb
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt
> > @@ -0,0 +1,38 @@
> > +STMicroelectronics PWM driver bindings for STM32
>
> Technically this bindings describe devices, so "driver binding" is a
> somewhat odd wording. Perhaps:
>
> STMicroelectronics STM32 General Purpose Timer PWM bindings
>
> ?
>
> > +
> > +Must be a sub-node of STM32 general purpose timer driver
> > +Parent node properties are describe in ../mfd/stm32-general-purpose-timer.txt
>
> Again, "driver parent node" is odd. Perhaps:
>
> Must be a sub-node of an STM32 General Purpose Timer device tree
> node. See ../mfd/stm32-general-purpose-timer.txt for details about
> the parent node.
>
> ?
>
> > +Required parameters:
> > +- compatible: Must be "st,stm32-pwm"
> > +- pinctrl-names: Set to "default".
> > +- pinctrl-0: List of phandles pointing to pin configuration nodes
> > + for PWM module.
> > + For Pinctrl properties, please refer to [1].
>
> Your indentation and capitalization are inconsistent. Also, please refer
> to the pinctrl bindings by relative path and inline, rather than as a
> footnote reference.
>
> > +
> > +Optional parameters:
> > +- st,breakinput: Set if the hardware have break input capabilities
> > +- st,breakinput-polarity: Set break input polarity. Default is 0
> > + The value define the active polarity:
> > + - 0 (active LOW)
> > + - 1 (active HIGH)
>
> Could we fold these into a single property? If st,breakinput-polarity is
> not present it could simply mean that there is no break input, and if it
> is present you don't have to rely on a default.
>
> > +- st,pwm-num-chan: Number of available PWM channels. Default is 0.
>
> The pwm- prefix is rather redundant since the node is already named pwm.
> Why not simply st,channels? Or simply channels, since it's not really
> anything specific to this hardware.
>
> Come to think of it, might be worth having a discussion with our DT
> gurus about what their stance is on using the # as prefix for numbers
> (such as in #address-cells or #size-cells). This could be #channels to
> mark it more explicitly as representing a count.
Unfortunately that ship has sailed.
st,pwm-num-chan already exists (with your blessing). It's usually
suggested to reuse exiting properties when writing new bindings.
> > +- st,32bits-counter: Set if the hardware have a 32 bits counter
> > +- st,complementary: Set if the hardware have complementary output channels
>
> "hardware has" and also maybe mention explicitly that this is a boolean
> property. Otherwise people might be left wondering what it should be set
> to. Or maybe word this differently to imply that it's boolean:
>
> - st,32bits-counter: if present, the hardware has a 32 bit counter
> - st,complementary: if present, the hardware has a complementary
> output channel
>
> Thierry
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH v3 4/7] PWM: add pwm driver for stm32 plaftorm
From: Lee Jones @ 2016-12-05 8:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161205072357.GB18069@ulmo.ba.sec>
On Mon, 05 Dec 2016, Thierry Reding wrote:
> On Fri, Dec 02, 2016 at 11:17:19AM +0100, Benjamin Gaignard wrote:
> > This driver add support for pwm driver on stm32 platform.
>
> "adds". Also please use PWM in prose because it's an abbreviation.
>
> > The SoC have multiple instances of the hardware IP and each
> > of them could have small differences: number of channels,
> > complementary output, counter register size...
> > Use DT parameters to handle those differentes configuration
>
> "different configurations"
>
> >
> > version 2:
> > - only keep one comptatible
> > - use DT paramaters to discover hardware block configuration
>
> "parameters"
>
> >
> > Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> > ---
> > drivers/pwm/Kconfig | 8 ++
> > drivers/pwm/Makefile | 1 +
> > drivers/pwm/pwm-stm32.c | 285 ++++++++++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 294 insertions(+)
> > create mode 100644 drivers/pwm/pwm-stm32.c
> >
> > diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> > index bf01288..a89fdba 100644
> > --- a/drivers/pwm/Kconfig
> > +++ b/drivers/pwm/Kconfig
> > @@ -388,6 +388,14 @@ config PWM_STI
> > To compile this driver as a module, choose M here: the module
> > will be called pwm-sti.
> >
> > +config PWM_STM32
> > + bool "STMicroelectronics STM32 PWM"
> > + depends on ARCH_STM32
> > + depends on OF
> > + select MFD_STM32_GP_TIMER
>
> Should that be a "depends on"?
>
> > + help
> > + Generic PWM framework driver for STM32 SoCs.
> > +
> > config PWM_STMPE
> > bool "STMPE expander PWM export"
> > depends on MFD_STMPE
> > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> > index 1194c54..5aa9308 100644
> > --- a/drivers/pwm/Makefile
> > +++ b/drivers/pwm/Makefile
> > @@ -37,6 +37,7 @@ obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
> > obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
> > obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
> > obj-$(CONFIG_PWM_STI) += pwm-sti.o
> > +obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
> > obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o
> > obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o
> > obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
> > diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
> > new file mode 100644
> > index 0000000..a362f63
> > --- /dev/null
> > +++ b/drivers/pwm/pwm-stm32.c
> > @@ -0,0 +1,285 @@
> > +/*
> > + * Copyright (C) STMicroelectronics 2016
> > + * Author: Gerald Baeza <gerald.baeza@st.com>
>
> Could use a blank line between the above. Also, please use a single
> space after : for consistency.
>
> > + * License terms: GNU General Public License (GPL), version 2
>
> Here too.
>
> > + *
> > + * Inspired by timer-stm32.c from Maxime Coquelin
> > + * pwm-atmel.c from Bo Shen
> > + */
> > +
> > +#include <linux/of.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pwm.h>
>
> Please sort these alphabetically.
>
> > +
> > +#include <linux/mfd/stm32-gptimer.h>
> > +
> > +#define DRIVER_NAME "stm32-pwm"
> > +
> > +#define CAP_COMPLEMENTARY BIT(0)
> > +#define CAP_32BITS_COUNTER BIT(1)
> > +#define CAP_BREAKINPUT BIT(2)
> > +#define CAP_BREAKINPUT_POLARITY BIT(3)
>
> Just make these boolean. Makes the conditionals a lot simpler to read.
>
> > +
> > +struct stm32_pwm_dev {
>
> No need for the _dev suffix.
I usually like ddata (short for device data, which is what it is).
I'll be asking for the same in the MFD driver too.
> > + struct device *dev;
> > + struct clk *clk;
> > + struct regmap *regmap;
> > + struct pwm_chip chip;
>
> It's slightly more efficient to put this as first field because then
> to_stm32_pwm() becomes a no-op.
Niiiice!
> > + int caps;
> > + int npwm;
>
> unsigned int, please.
>
> > + u32 polarity;
>
> Maybe use a prefix here to stress that it is the polarity of the
> complementary output. Otherwise one might take it for the PWM signal's
> polarity that's already part of the PWM state.
>
> > +};
> > +
> > +#define to_stm32_pwm_dev(x) container_of(chip, struct stm32_pwm_dev, chip)
>
> Please turn this into a static inline.
>
> > +
> > +static u32 __active_channels(struct stm32_pwm_dev *pwm_dev)
>
> No need for a __ prefix.
>
> > +{
> > + u32 ccer;
> > +
> > + regmap_read(pwm_dev->regmap, TIM_CCER, &ccer);
> > +
> > + return ccer & TIM_CCER_CCXE;
> > +}
> > +
> > +static int write_ccrx(struct stm32_pwm_dev *dev, struct pwm_device *pwm,
> > + u32 ccr)
>
> u32 value, perhaps? I first mistook this to be a register offset.
>
> > +{
> > + switch (pwm->hwpwm) {
> > + case 0:
> > + return regmap_write(dev->regmap, TIM_CCR1, ccr);
> > + case 1:
> > + return regmap_write(dev->regmap, TIM_CCR2, ccr);
> > + case 2:
> > + return regmap_write(dev->regmap, TIM_CCR3, ccr);
> > + case 3:
> > + return regmap_write(dev->regmap, TIM_CCR4, ccr);
> > + }
> > + return -EINVAL;
> > +}
> > +
> > +static int stm32_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> > + int duty_ns, int period_ns)
>
> Please implement this as an atomic PWM driver, I don't want new drivers
> to use the legacy callbacks.
>
> > +{
> > + struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
>
> I think something like "stm", or "priv" would be more appropriate here.
> If you ever need access to a struct device, you'll be hard-pressed to
> find a good name for it.
See above.
> > + unsigned long long prd, div, dty;
> > + int prescaler = 0;
>
> If this can never be negative, please make it unsigned int.
>
> > + u32 max_arr = 0xFFFF, ccmr, mask, shift, bdtr;
> > +
> > + if (dev->caps & CAP_32BITS_COUNTER)
> > + max_arr = 0xFFFFFFFF;
>
> I prefer lower-case hexadecimal digits.
Even better to define the max values.
> > +
> > + /* Period and prescaler values depends of clock rate */
>
> "depend on"
>
> > + div = (unsigned long long)clk_get_rate(dev->clk) * period_ns;
> > +
> > + do_div(div, NSEC_PER_SEC);
> > + prd = div;
> > +
> > + while (div > max_arr) {
> > + prescaler++;
> > + div = prd;
> > + do_div(div, (prescaler + 1));
> > + }
> > + prd = div;
>
> Blank line after blocks, please.
... unless directly related to the block, which I think this is. It's
the '\n' *before* the block which confuses me.
> > + if (prescaler > MAX_TIM_PSC) {
> > + dev_err(chip->dev, "prescaler exceeds the maximum value\n");
> > + return -EINVAL;
> > + }
> > +
> > + /* All channels share the same prescaler and counter so
> > + * when two channels are active at the same we can't change them
> > + */
>
> This isn't proper block comment style. Also, please use all of the
> columns at your disposal.
>
> > + if (__active_channels(dev) & ~(1 << pwm->hwpwm * 4)) {
> > + u32 psc, arr;
> > +
> > + regmap_read(dev->regmap, TIM_PSC, &psc);
> > + regmap_read(dev->regmap, TIM_ARR, &arr);
> > +
> > + if ((psc != prescaler) || (arr != prd - 1))
> > + return -EINVAL;
>
> Maybe -EBUSY to differentiate from other error cases?
>
> > + }
> > +
> > + regmap_write(dev->regmap, TIM_PSC, prescaler);
> > + regmap_write(dev->regmap, TIM_ARR, prd - 1);
> > + regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
> > +
> > + /* Calculate the duty cycles */
> > + dty = prd * duty_ns;
> > + do_div(dty, period_ns);
> > +
> > + write_ccrx(dev, pwm, dty);
> > +
> > + /* Configure output mode */
> > + shift = (pwm->hwpwm & 0x1) * 8;
> > + ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift;
> > + mask = 0xFF << shift;
> > +
> > + if (pwm->hwpwm & 0x2)
>
> This looks as though TIM_CCMR1 is used for channels 0 and 1, while
> TIM_CCMR2 is used for channels 2 and 3. Wouldn't it be more natural to
> make the conditional above:
>
> if (pwm->hwpwm >= 2)
>
> ? Or perhaps better yet:
>
> if (pwm->hwpwm < 2)
> /* update TIM_CCMR1 */
> else
> /* update TIM_CCMR2 */
And please define the magic numbers.
*_MASK
*_SHIFT
> The other alternative, which might make the code slightly more readable,
> would be to get rid of all these conditionals by parameterizing the
> offsets per PWM channel. The PWM subsystem has a means of storing per-
> channel chip-specific data (see pwm_{set,get}_chip_data()). It might be
> a little overkill for this particular driver, given that the number of
> conditionals is fairly small.
>
> > + regmap_update_bits(dev->regmap, TIM_CCMR2, mask, ccmr);
> > + else
> > + regmap_update_bits(dev->regmap, TIM_CCMR1, mask, ccmr);
> > +
> > + if (!(dev->caps & CAP_BREAKINPUT))
> > + return 0;
>
> If you make these capabilities boolean, it becomes much more readable,
> especially for negations:
>
> if (!dev->has_breakinput)
+1
> > +
> > + bdtr = TIM_BDTR_MOE | TIM_BDTR_AOE;
> > +
> > + if (dev->caps & CAP_BREAKINPUT_POLARITY)
> > + bdtr |= TIM_BDTR_BKE;
> > +
> > + if (dev->polarity)
> > + bdtr |= TIM_BDTR_BKP;
> > +
> > + regmap_update_bits(dev->regmap, TIM_BDTR,
> > + TIM_BDTR_MOE | TIM_BDTR_AOE |
> > + TIM_BDTR_BKP | TIM_BDTR_BKE,
> > + bdtr);
> > +
> > + return 0;
> > +}
> > +
> > +static int stm32_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
> > + enum pwm_polarity polarity)
> > +{
> > + u32 mask;
> > + struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
> > +
> > + mask = TIM_CCER_CC1P << (pwm->hwpwm * 4);
> > + if (dev->caps & CAP_COMPLEMENTARY)
> > + mask |= TIM_CCER_CC1NP << (pwm->hwpwm * 4);
> > +
> > + regmap_update_bits(dev->regmap, TIM_CCER, mask,
> > + polarity == PWM_POLARITY_NORMAL ? 0 : mask);
> > +
> > + return 0;
> > +}
> > +
> > +static int stm32_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
> > +{
> > + u32 mask;
> > + struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
> > +
> > + clk_enable(dev->clk);
> > +
> > + /* Enable channel */
> > + mask = TIM_CCER_CC1E << (pwm->hwpwm * 4);
> > + if (dev->caps & CAP_COMPLEMENTARY)
> > + mask |= TIM_CCER_CC1NE << (pwm->hwpwm * 4);
> > +
> > + regmap_update_bits(dev->regmap, TIM_CCER, mask, mask);
> > +
> > + /* Make sure that registers are updated */
> > + regmap_update_bits(dev->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
> > +
> > + /* Enable controller */
> > + regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
> > +
> > + return 0;
> > +}
> > +
> > +static void stm32_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
> > +{
> > + u32 mask;
> > + struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
> > +
> > + /* Disable channel */
> > + mask = TIM_CCER_CC1E << (pwm->hwpwm * 4);
> > + if (dev->caps & CAP_COMPLEMENTARY)
> > + mask |= TIM_CCER_CC1NE << (pwm->hwpwm * 4);
> > +
> > + regmap_update_bits(dev->regmap, TIM_CCER, mask, 0);
> > +
> > + /* When all channels are disabled, we can disable the controller */
> > + if (!__active_channels(dev))
> > + regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_CEN, 0);
> > +
> > + clk_disable(dev->clk);
> > +}
>
> All of the above can be folded into the ->apply() hook for atomic PWM
> support.
>
> Also, in the above you use clk_enable() in the ->enable() callback and
> clk_disable() in ->disable(). If you need the clock to access registers
> you'll have to enabled it in the others as well because there are no
> guarantees that configuration will only happen between ->enable() and
> ->disable(). Atomic PWM simplifies this a bit, but you still need to be
> careful about when to enable the clock in your ->apply() hook.
>
> > +
> > +static const struct pwm_ops stm32pwm_ops = {
> > + .config = stm32_pwm_config,
> > + .set_polarity = stm32_pwm_set_polarity,
> > + .enable = stm32_pwm_enable,
> > + .disable = stm32_pwm_disable,
> > +};
>
> You need to set the .owner field as well.
>
> > +
> > +static int stm32_pwm_probe(struct platform_device *pdev)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct device_node *np = dev->of_node;
> > + struct stm32_gptimer_dev *mfd = dev_get_drvdata(pdev->dev.parent);
> > + struct stm32_pwm_dev *pwm;
pwm is okay. Please also consider using ddata for consistency across
the driver-set.
> > + int ret;
> > +
> > + pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL);
> > + if (!pwm)
> > + return -ENOMEM;
> > +
> > + pwm->regmap = mfd->regmap;
> > + pwm->clk = mfd->clk;
> > +
> > + if (!pwm->regmap || !pwm->clk)
> > + return -EINVAL;
> > +
> > + if (of_property_read_bool(np, "st,complementary"))
> > + pwm->caps |= CAP_COMPLEMENTARY;
> > +
> > + if (of_property_read_bool(np, "st,32bits-counter"))
> > + pwm->caps |= CAP_32BITS_COUNTER;
> > +
> > + if (of_property_read_bool(np, "st,breakinput"))
> > + pwm->caps |= CAP_BREAKINPUT;
> > +
> > + if (!of_property_read_u32(np, "st,breakinput-polarity", &pwm->polarity))
> > + pwm->caps |= CAP_BREAKINPUT_POLARITY;
> > +
> > + of_property_read_u32(np, "st,pwm-num-chan", &pwm->npwm);
> > +
> > + pwm->chip.base = -1;
> > + pwm->chip.dev = dev;
> > + pwm->chip.ops = &stm32pwm_ops;
> > + pwm->chip.npwm = pwm->npwm;
> > +
> > + ret = pwmchip_add(&pwm->chip);
> > + if (ret < 0)
> > + return ret;
> > +
> > + platform_set_drvdata(pdev, pwm);
> > +
> > + return 0;
> > +}
> > +
> > +static int stm32_pwm_remove(struct platform_device *pdev)
> > +{
> > + struct stm32_pwm_dev *pwm = platform_get_drvdata(pdev);
> > + int i;
>
> unsigned int, please.
>
> > +
> > + for (i = 0; i < pwm->npwm; i++)
> > + pwm_disable(&pwm->chip.pwms[i]);
> > +
> > + pwmchip_remove(&pwm->chip);
> > +
> > + return 0;
> > +}
> > +
> > +static const struct of_device_id stm32_pwm_of_match[] = {
> > + {
> > + .compatible = "st,stm32-pwm",
> > + },
>
> The above can be collapsed into a single line.
+1
> > +};
> > +MODULE_DEVICE_TABLE(of, stm32_pwm_of_match);
> > +
> > +static struct platform_driver stm32_pwm_driver = {
> > + .probe = stm32_pwm_probe,
> > + .remove = stm32_pwm_remove,
> > + .driver = {
> > + .name = DRIVER_NAME,
> > + .of_match_table = stm32_pwm_of_match,
> > + },
> > +};
>
> Please don't use tabs for padding within the structure definition since
> it doesn't align properly anyway.
+1
> > +module_platform_driver(stm32_pwm_driver);
> > +
> > +MODULE_ALIAS("platform:" DRIVER_NAME);
> > +MODULE_DESCRIPTION("STMicroelectronics STM32 PWM driver");
> > +MODULE_LICENSE("GPL");
>
> According to the header comment this should be "GPL v2".
+1
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ 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