* Re: 3.16.6 build error: swsusp_booke.S:85: Error: invalid sprg number
From: Scott Wood @ 2014-03-20 4:52 UTC (permalink / raw)
To: John Donnelly; +Cc: linuxppc-dev
In-Reply-To: <CAGtOQbTgXnxEHfuqtQ-BwpsnY=J2WktMFTNXysfYw9-cYprstQ@mail.gmail.com>
On Wed, 2014-03-19 at 17:58 -0500, John Donnelly wrote:
> Platform: Freescale p4080--e500mc ,
>
>
> Suggestions welcome .
>
>
> /bin/sh arch/powerpc/kernel/systbl_chk.sh
> arch/powerpc/kernel/systbl_chk.i
> make -f scripts/Makefile.build obj=arch/powerpc/kernel/vdso32
> gcc -mbig-endian -m32 -Wp,-MD,arch/powerpc/kernel/.swsusp_booke.o.d
> -nostdinc -isystem /usr/lib/gcc/ppc64-redhat-linux/4.8.2/include
> -I/root/linux-3.13.6/arch/powerpc/include
> -Iarch/powerpc/include/generated -Iinclude
> -I/root/linux-3.13.6/arch/powerpc/include/uapi
> -Iarch/powerpc/include/generated/uapi
> -I/root/linux-3.13.6/include/uapi -Iinclude/generated/uapi
> -include /root/linux-3.13.6/include/linux/kconfig.h -D__KERNEL__
> -Iarch/powerpc -D__ASSEMBLY__ -Iarch/powerpc -gdwarf-2 -c
> -o arch/powerpc/kernel/swsusp_booke.o
> arch/powerpc/kernel/swsusp_booke.S
> arch/powerpc/kernel/swsusp_booke.S: Assembler messages:
> arch/powerpc/kernel/swsusp_booke.S:85: Error: invalid sprg number
> arch/powerpc/kernel/swsusp_booke.S:87: Error: invalid sprg number
>
You need commit b58a7bd6df7b61446b833a7c72f8a1f11066e0b0.
-Scott
^ permalink raw reply
* Re: Tasks stuck in futex code (in 3.14-rc6)
From: Srikar Dronamraju @ 2014-03-20 5:33 UTC (permalink / raw)
To: Peter Zijlstra
Cc: linuxppc-dev, LKML, davidlohr, paulus, tglx, Paul McKenney,
torvalds, mingo
In-Reply-To: <20140319170829.GD8557@laptop.programming.kicks-ass.net>
> > Joy,.. let me look at that with ppc in mind.
>
> OK; so while pretty much all the comments from that patch are utter
> nonsense (what was I thinking), I cannot actually find a real bug.
>
> But could you try the below which replaces a control dependency with a
> full barrier. The control flow is plenty convoluted that I think the
> control barrier isn't actually valid anymore and that might indeed
> explain the fail.
>
Unfortunately the patch didnt help. Still seeing tasks stuck
# ps -Ao pid,tt,user,fname,tmout,f,wchan | grep futex
14680 pts/0 root java - 0 futex_wait_queue_me
14797 pts/0 root java - 0 futex_wait_queue_me
# :> /var/log/messages
# echo t > /proc/sysrq-trigger
# grep futex_wait_queue_me /var/log/messages | wc -l
334
#
[ 6904.211478] Call Trace:
[ 6904.211481] [c000000fa1f1b4d0] [0000000000000020] 0x20 (unreliable)
[ 6904.211486] [c000000fa1f1b6a0] [c000000000015208] .__switch_to+0x1e8/0x330
[ 6904.211491] [c000000fa1f1b750] [c000000000702f00] .__schedule+0x360/0x8b0
[ 6904.211495] [c000000fa1f1b9d0] [c000000000147348] .futex_wait_queue_me+0xf8/0x1a0
[ 6904.211500] [c000000fa1f1ba60] [c0000000001486dc] .futex_wait+0x17c/0x2a0
[ 6904.211505] [c000000fa1f1bc10] [c00000000014a614] .do_futex+0x254/0xd80
[ 6904.211510] [c000000fa1f1bd60] [c00000000014b25c] .SyS_futex+0x11c/0x1d0
[ 6904.238874] [c000000fa1f1be30] [c00000000000a0fc] syscall_exit+0x0/0x7c
[ 6904.238879] java S 00003fff825f6044 0 14682 14076 0x00000080
Is there any other information that I provide that can help?
--
Thanks and Regards
Srikar Dronamraju
^ permalink raw reply
* Re: Tasks stuck in futex code (in 3.14-rc6)
From: Davidlohr Bueso @ 2014-03-20 5:56 UTC (permalink / raw)
To: Srikar Dronamraju
Cc: Peter Zijlstra, torvalds, LKML, paulus, tglx, Paul McKenney,
linuxppc-dev, mingo
In-Reply-To: <20140320053350.GB30295@linux.vnet.ibm.com>
On Thu, 2014-03-20 at 11:03 +0530, Srikar Dronamraju wrote:
> > > Joy,.. let me look at that with ppc in mind.
> >
> > OK; so while pretty much all the comments from that patch are utter
> > nonsense (what was I thinking), I cannot actually find a real bug.
> >
> > But could you try the below which replaces a control dependency with a
> > full barrier. The control flow is plenty convoluted that I think the
> > control barrier isn't actually valid anymore and that might indeed
> > explain the fail.
> >
>
> Unfortunately the patch didnt help. Still seeing tasks stuck
>
> # ps -Ao pid,tt,user,fname,tmout,f,wchan | grep futex
> 14680 pts/0 root java - 0 futex_wait_queue_me
> 14797 pts/0 root java - 0 futex_wait_queue_me
> # :> /var/log/messages
> # echo t > /proc/sysrq-trigger
> # grep futex_wait_queue_me /var/log/messages | wc -l
> 334
> #
>
> [ 6904.211478] Call Trace:
> [ 6904.211481] [c000000fa1f1b4d0] [0000000000000020] 0x20 (unreliable)
> [ 6904.211486] [c000000fa1f1b6a0] [c000000000015208] .__switch_to+0x1e8/0x330
> [ 6904.211491] [c000000fa1f1b750] [c000000000702f00] .__schedule+0x360/0x8b0
> [ 6904.211495] [c000000fa1f1b9d0] [c000000000147348] .futex_wait_queue_me+0xf8/0x1a0
> [ 6904.211500] [c000000fa1f1ba60] [c0000000001486dc] .futex_wait+0x17c/0x2a0
> [ 6904.211505] [c000000fa1f1bc10] [c00000000014a614] .do_futex+0x254/0xd80
> [ 6904.211510] [c000000fa1f1bd60] [c00000000014b25c] .SyS_futex+0x11c/0x1d0
> [ 6904.238874] [c000000fa1f1be30] [c00000000000a0fc] syscall_exit+0x0/0x7c
> [ 6904.238879] java S 00003fff825f6044 0 14682 14076 0x00000080
>
> Is there any other information that I provide that can help?
This problem suggests that we missed a wakeup for a task that was adding
itself to the queue in a wait path. And the only place that can happen
is with the hb spinlock check for any pending waiters. Just in case we
missed some assumption about checking the hash bucket spinlock as a way
of detecting any waiters (powerpc?), could you revert this commit and
try the original atomic operations variant:
https://lkml.org/lkml/2013/12/19/630
^ permalink raw reply
* RE: [PATCH] fix dmaengine_unmap failure.
From: Xuelin Shi @ 2014-03-20 6:34 UTC (permalink / raw)
To: Dan Williams; +Cc: Vinod Koul, dmaengine@vger.kernel.org, linuxppc-dev
In-Reply-To: <CAPcyv4imH14PuiZJwMw1B+UnxBgHzPAS22p4b171MrmKDBJM+Q@mail.gmail.com>
SGkgRGFuLA0KDQpJJ20gT0sgdG8gc2F2ZSBtZW1vcnkgaGVyZS4gSSdkIGxpa2UgdG8gc2VuZCB2
Mi4NCg0KVGhhbmtzLA0KWHVlbGluIFNoaQ0KDQotLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0K
RnJvbTogRGFuIFdpbGxpYW1zIFttYWlsdG86ZGFuLmoud2lsbGlhbXNAaW50ZWwuY29tXSANClNl
bnQ6IDIwMTTE6jPUwjE5yNUgMjM6NDQNClRvOiBTaGkgWHVlbGluLUIyOTIzNw0KQ2M6IFZpbm9k
IEtvdWw7IGxpbnV4cHBjLWRldjsgZG1hZW5naW5lQHZnZXIua2VybmVsLm9yZw0KU3ViamVjdDog
UmU6IFtQQVRDSF0gZml4IGRtYWVuZ2luZV91bm1hcCBmYWlsdXJlLg0KDQpPbiBUdWUsIE1hciAx
OCwgMjAxNCBhdCAxMTozOSBQTSwgWHVlbGluIFNoaSA8eHVlbGluLnNoaUBmcmVlc2NhbGUuY29t
PiB3cm90ZToNCj4gSGkgRGFuLA0KPg0KPiBJbiBhc3luY19tdWx0KC4uLikgb2YgYXN5bmNfcmFp
ZDZfcmVjb3YuYywgdGhlIGNvdW50IDMgaXMgdXNlZCB0byByZXF1ZXN0IGFuIHVubWFwLg0KPiBI
b3dldmVyIHRoZSB0b19jbnQgYW5kIGJpZGlfY250IGFyZSBib3RoIHNldCB0byAxIGFuZCBmcm9t
X2NudCB0byAwLg0KPiBUaGVuIHdoaWxlIHRyeWluZyB0byBkbyB1bm1hcCwgd2UgYXJlIGdldHRp
bmcgdGhlIHdyb25nICJ1bm1hcCIgZnJvbSBhIGRpZmZlcmVudCBtZW1wb29sLg0KPg0KPiBJbiB0
aGlzIHBhdGNoLCB0aGUgbWVtcG9vbCBpcyBhc3NvY2lhdGVkIHdpdGggdGhlIHVubWFwIHN0cnVj
dHVyZSBpbnN0ZWFkIG9mIGNvbXB1dGluZyBpdCBhZ2Fpbi4NCj4gQnkgdGhpcyB3YXksIGl0IGlz
IGd1YXJhbnRlZWQgdGhhdCB0aGUgdW5tYXAgaXMgdGhlIHNhbWUgd2hlbiB3ZSBnZXQgYW5kIHB1
dCB0aGUgdW5tYXAgZGF0YS4NCj4NCj4gQlRXOiB0aGUgbWVtcG9vbCBpcyBqdXN0IHVzZWQgdG8g
bWFuYWdlIHRoZSBzdHJ1Y3QgdW5tYXAsIG5vdCB0aGUgcGFnZXMuDQo+DQoNCkkgc2VlLCB3aGF0
IGFib3V0IGp1c3Qgc3RvcmluZyB0aGUgbWFwX2NudCBhdCBhbGxvY2F0aW9uIHRpbWU/ICBJdCBj
b3VsZCBiZSBhbm90aGVyIGJ5dGUgaW4gc3RydWN0IGRtYWVuZ2luZV91bm1hcF9kYXRhIHJhdGhl
ciB0aGFuIGFuIDggYnl0ZSBwb2ludGVyLg0KDQoNCg==
^ permalink raw reply
* [PATCH v2] fix dmaengine_unmap failure
From: xuelin.shi @ 2014-03-20 6:33 UTC (permalink / raw)
To: vinod.koul, dan.j.williams; +Cc: dmaengine, Xuelin Shi, linuxppc-dev
From: Xuelin Shi <xuelin.shi@freescale.com>
The count which is used to get_unmap_data maybe not the same as the
count computed in dmaengine_unmap which causes to free data in a
wrong pool.
This patch fixes this issue by keeping the map count with unmap_data
structure and use this count to get the pool.
Signed-off-by: Xuelin Shi <xuelin.shi@freescale.com>
---
change history:
v1: keep mempool pointer with unmap struct
v2: keep u8 map_cnt instead of mempool pointer to save mem.
drivers/dma/dmaengine.c | 2 ++
include/linux/dmaengine.h | 1 +
2 files changed, 3 insertions(+)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index ed610b4..a4068e2 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -1014,6 +1014,7 @@ static void dmaengine_unmap(struct kref *kref)
dma_unmap_page(dev, unmap->addr[i], unmap->len,
DMA_BIDIRECTIONAL);
}
+ cnt = unmap->map_cnt;
mempool_free(unmap, __get_unmap_pool(cnt)->pool);
}
@@ -1079,6 +1080,7 @@ dmaengine_get_unmap_data(struct device *dev, int nr, gfp_t flags)
memset(unmap, 0, sizeof(*unmap));
kref_init(&unmap->kref);
unmap->dev = dev;
+ unmap->map_cnt = nr;
return unmap;
}
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index c5c92d5..0a5f552 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -433,6 +433,7 @@ typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
typedef void (*dma_async_tx_callback)(void *dma_async_param);
struct dmaengine_unmap_data {
+ u8 map_cnt;
u8 to_cnt;
u8 from_cnt;
u8 bidi_cnt;
--
1.8.3.2
^ permalink raw reply related
* Re: Tasks stuck in futex code (in 3.14-rc6)
From: Peter Zijlstra @ 2014-03-20 7:23 UTC (permalink / raw)
To: Srikar Dronamraju
Cc: linuxppc-dev, LKML, davidlohr, paulus, tglx, Paul McKenney,
torvalds, mingo
In-Reply-To: <20140320053350.GB30295@linux.vnet.ibm.com>
On Thu, Mar 20, 2014 at 11:03:50AM +0530, Srikar Dronamraju wrote:
> > > Joy,.. let me look at that with ppc in mind.
> >
> > OK; so while pretty much all the comments from that patch are utter
> > nonsense (what was I thinking), I cannot actually find a real bug.
> >
> > But could you try the below which replaces a control dependency with a
> > full barrier. The control flow is plenty convoluted that I think the
> > control barrier isn't actually valid anymore and that might indeed
> > explain the fail.
> >
>
> Unfortunately the patch didnt help. Still seeing tasks stuck
Aww bugger. I'll be traveling tomorrow and today is wasted getting
ready. So unless Davidlohr has anything we'll need to scrap this change.
^ permalink raw reply
* Re: [v2, 2/2] powerpc/mpc85xx: add support for Keymile's kmcoge4 board
From: Valentin Longchamp @ 2014-03-20 8:42 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20140319230813.GA30481@home.buserror.net>
On 03/20/2014 12:08 AM, Scott Wood wrote:
> On Tue, Feb 11, 2014 at 12:50:07PM +0100, Valentin Longchamp wrote:
>> + reset_cpld@1,0 {
>> + interrupt-controller;
>> + #interrupt-cells = <2>;
>> + reg = <1 0 0x80>;
>> + interrupt-parent = <&mpic>;
>> + interrupts = <
>> + 4 1 0 0
>> + 5 1 0 0>;
>> + };
>> +
>> + chassis_mgmt@3,0 {
>> + interrupt-controller;
>> + #interrupt-cells = <2>;
>> + reg = <3 0 0x100>;
>> + interrupt-parent = <&mpic>;
>> + interrupts = <6 1 0 0>;
>> + };
>
> Dashes are preferred to underscores in device trees.
OK.
>
> More importantly, these nodes need proper compatibles and bindings. Once
> that's done, the name for the nodes should probably be
> "board_control@whatever" for both.
>
The first one can be board-ctrl. The second however manages things that are
beyond this board and important for other boards in the chassis, so I think
chassis-mgmt is correct.
For the binding/compatbiles issues: in the first discussion I had omitted these
nodes because these are not available (and honestly for such FPGAs I doubt they
will ever be mainlined). We discussed it and concluded that the DTS should
describe the HW and not the drivers available in the kernel so I have now added
them. Do you want me to add the compatible strings we use in our tree even
though there are no bindings ? Leave them as is ? Or drop them ?
Valentin
^ permalink raw reply
* [PATCH v2] fix wrong usage of dmaengine_unmap_put in async_xxx
From: xuelin.shi @ 2014-03-20 8:16 UTC (permalink / raw)
To: vinod.koul, dan.j.williams; +Cc: dmaengine, Xuelin Shi, linuxppc-dev
From: Xuelin Shi <xuelin.shi@freescale.com>
dmaengine_unmap_put does below two things:
a) unmap pages for srcs and dests
b) free unmap struct
The unmap struct data is generated but only initialized while
other some dma contions are met, like dma alignment etc.
If the unmap data is not initialized, call dmaengine_unmap_put
will unmap some random data in unmap->addr[...]
Also call dmaengine_get_unmap_data immediatally after generating tx
is not correct. Maybe the tx has not been finished by DMA hardware
yet but the srcs and dests are dma unmapped.
This patch fixed above two issues by:
a) only generates unmap struct data when other dma conditions are met.
b) eliminates dmaengine_unmap_put when tx is generated because tx knowes
the best time to unmap it (in interrupt processing).
Signed-off-by: Xuelin Shi <xuelin.shi@freescale.com>
---
change log:
v1: include change in async_memcpy, async_xor, async_pq
v2: add change in async_raid6_recov.c and fix some style issue
crypto/async_tx/async_memcpy.c | 80 ++++++++-------
crypto/async_tx/async_pq.c | 189 +++++++++++++++++++-----------------
crypto/async_tx/async_raid6_recov.c | 108 +++++++++++----------
crypto/async_tx/async_xor.c | 164 ++++++++++++++++---------------
4 files changed, 286 insertions(+), 255 deletions(-)
diff --git a/crypto/async_tx/async_memcpy.c b/crypto/async_tx/async_memcpy.c
index f8c0b8d..6546e87 100644
--- a/crypto/async_tx/async_memcpy.c
+++ b/crypto/async_tx/async_memcpy.c
@@ -51,11 +51,10 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
struct dma_device *device = chan ? chan->device : NULL;
struct dma_async_tx_descriptor *tx = NULL;
struct dmaengine_unmap_data *unmap = NULL;
+ void *dest_buf, *src_buf;
- if (device)
- unmap = dmaengine_get_unmap_data(device->dev, 2, GFP_NOIO);
-
- if (unmap && is_dma_copy_aligned(device, src_offset, dest_offset, len)) {
+ if (device &&
+ is_dma_copy_aligned(device, src_offset, dest_offset, len)) {
unsigned long dma_prep_flags = 0;
if (submit->cb_fn)
@@ -63,45 +62,56 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
if (submit->flags & ASYNC_TX_FENCE)
dma_prep_flags |= DMA_PREP_FENCE;
- unmap->to_cnt = 1;
- unmap->addr[0] = dma_map_page(device->dev, src, src_offset, len,
- DMA_TO_DEVICE);
- unmap->from_cnt = 1;
- unmap->addr[1] = dma_map_page(device->dev, dest, dest_offset, len,
- DMA_FROM_DEVICE);
- unmap->len = len;
-
- tx = device->device_prep_dma_memcpy(chan, unmap->addr[1],
- unmap->addr[0], len,
- dma_prep_flags);
+ unmap = dmaengine_get_unmap_data(device->dev, 2, GFP_NOIO);
+ if (unmap) {
+ unmap->to_cnt = 1;
+ unmap->addr[0] = dma_map_page(device->dev, src,
+ src_offset, len,
+ DMA_TO_DEVICE);
+ unmap->from_cnt = 1;
+ unmap->addr[1] = dma_map_page(device->dev, dest,
+ dest_offset, len,
+ DMA_FROM_DEVICE);
+ unmap->len = len;
+
+ tx = device->device_prep_dma_memcpy(chan,
+ unmap->addr[1],
+ unmap->addr[0],
+ len,
+ dma_prep_flags);
+ if (tx) {
+ pr_debug("%s: (async) len: %zu\n", __func__,
+ len);
+
+ dma_set_unmap(tx, unmap);
+ async_tx_submit(chan, tx, submit);
+ return tx;
+ }
+
+ /* could not get a descriptor, unmap and fall through to
+ * the synchronous path
+ */
+ dmaengine_unmap_put(unmap);
+ }
}
- if (tx) {
- pr_debug("%s: (async) len: %zu\n", __func__, len);
+ /* run the operation synchronously */
+ pr_debug("%s: (sync) len: %zu\n", __func__, len);
- dma_set_unmap(tx, unmap);
- async_tx_submit(chan, tx, submit);
- } else {
- void *dest_buf, *src_buf;
- pr_debug("%s: (sync) len: %zu\n", __func__, len);
+ /* wait for any prerequisite operations */
+ async_tx_quiesce(&submit->depend_tx);
- /* wait for any prerequisite operations */
- async_tx_quiesce(&submit->depend_tx);
+ dest_buf = kmap_atomic(dest) + dest_offset;
+ src_buf = kmap_atomic(src) + src_offset;
- dest_buf = kmap_atomic(dest) + dest_offset;
- src_buf = kmap_atomic(src) + src_offset;
+ memcpy(dest_buf, src_buf, len);
- memcpy(dest_buf, src_buf, len);
-
- kunmap_atomic(src_buf);
- kunmap_atomic(dest_buf);
-
- async_tx_sync_epilog(submit);
- }
+ kunmap_atomic(src_buf);
+ kunmap_atomic(dest_buf);
- dmaengine_unmap_put(unmap);
+ async_tx_sync_epilog(submit);
- return tx;
+ return NULL;
}
EXPORT_SYMBOL_GPL(async_memcpy);
diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c
index d05327c..f446cda 100644
--- a/crypto/async_tx/async_pq.c
+++ b/crypto/async_tx/async_pq.c
@@ -175,10 +175,7 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
BUG_ON(disks > 255 || !(P(blocks, disks) || Q(blocks, disks)));
- if (device)
- unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO);
-
- if (unmap &&
+ if (device &&
(src_cnt <= dma_maxpq(device, 0) ||
dma_maxpq(device, DMA_PREP_CONTINUE) > 0) &&
is_dma_pq_aligned(device, offset, 0, len)) {
@@ -194,46 +191,54 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
/* convert source addresses being careful to collapse 'empty'
* sources and update the coefficients accordingly
*/
- unmap->len = len;
- for (i = 0, j = 0; i < src_cnt; i++) {
- if (blocks[i] == NULL)
- continue;
- unmap->addr[j] = dma_map_page(device->dev, blocks[i], offset,
- len, DMA_TO_DEVICE);
- coefs[j] = raid6_gfexp[i];
- unmap->to_cnt++;
- j++;
- }
+ unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO);
+ if (unmap) {
+ unmap->len = len;
+ for (i = 0, j = 0; i < src_cnt; i++) {
+ if (blocks[i] == NULL)
+ continue;
+ unmap->addr[j] = dma_map_page(device->dev,
+ blocks[i],
+ offset,
+ len,
+ DMA_TO_DEVICE);
+ coefs[j] = raid6_gfexp[i];
+ unmap->to_cnt++;
+ j++;
+ }
- /*
- * DMAs use destinations as sources,
- * so use BIDIRECTIONAL mapping
- */
- unmap->bidi_cnt++;
- if (P(blocks, disks))
- unmap->addr[j++] = dma_map_page(device->dev, P(blocks, disks),
- offset, len, DMA_BIDIRECTIONAL);
- else {
- unmap->addr[j++] = 0;
- dma_flags |= DMA_PREP_PQ_DISABLE_P;
- }
+ /*
+ * DMAs use destinations as sources,
+ * so use BIDIRECTIONAL mapping
+ */
+ unmap->bidi_cnt++;
+ if (P(blocks, disks))
+ unmap->addr[j++] = dma_map_page(device->dev,
+ P(blocks, disks),
+ offset, len,
+ DMA_BIDIRECTIONAL);
+ else {
+ unmap->addr[j++] = 0;
+ dma_flags |= DMA_PREP_PQ_DISABLE_P;
+ }
- unmap->bidi_cnt++;
- if (Q(blocks, disks))
- unmap->addr[j++] = dma_map_page(device->dev, Q(blocks, disks),
- offset, len, DMA_BIDIRECTIONAL);
- else {
- unmap->addr[j++] = 0;
- dma_flags |= DMA_PREP_PQ_DISABLE_Q;
- }
+ unmap->bidi_cnt++;
+ if (Q(blocks, disks))
+ unmap->addr[j++] = dma_map_page(device->dev,
+ Q(blocks, disks),
+ offset, len,
+ DMA_BIDIRECTIONAL);
+ else {
+ unmap->addr[j++] = 0;
+ dma_flags |= DMA_PREP_PQ_DISABLE_Q;
+ }
- tx = do_async_gen_syndrome(chan, coefs, j, unmap, dma_flags, submit);
- dmaengine_unmap_put(unmap);
- return tx;
+ tx = do_async_gen_syndrome(chan, coefs, j, unmap,
+ dma_flags, submit);
+ return tx;
+ }
}
- dmaengine_unmap_put(unmap);
-
/* run the pq synchronously */
pr_debug("%s: (sync) disks: %d len: %zu\n", __func__, disks, len);
@@ -293,10 +298,7 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
BUG_ON(disks < 4);
- if (device)
- unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO);
-
- if (unmap && disks <= dma_maxpq(device, 0) &&
+ if (device && disks <= dma_maxpq(device, 0) &&
is_dma_pq_aligned(device, offset, 0, len)) {
struct device *dev = device->dev;
dma_addr_t pq[2];
@@ -305,58 +307,63 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
pr_debug("%s: (async) disks: %d len: %zu\n",
__func__, disks, len);
- unmap->len = len;
- for (i = 0; i < disks-2; i++)
- if (likely(blocks[i])) {
- unmap->addr[j] = dma_map_page(dev, blocks[i],
- offset, len,
+ unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO);
+ if (unmap) {
+ unmap->len = len;
+ for (i = 0; i < disks-2; i++)
+ if (likely(blocks[i])) {
+ unmap->addr[j] = dma_map_page(dev,
+ blocks[i],
+ offset,
+ len,
DMA_TO_DEVICE);
- coefs[j] = raid6_gfexp[i];
+ coefs[j] = raid6_gfexp[i];
+ unmap->to_cnt++;
+ src_cnt++;
+ j++;
+ }
+
+ if (!P(blocks, disks)) {
+ pq[0] = 0;
+ dma_flags |= DMA_PREP_PQ_DISABLE_P;
+ } else {
+ pq[0] = dma_map_page(dev, P(blocks, disks),
+ offset, len,
+ DMA_TO_DEVICE);
+ unmap->addr[j++] = pq[0];
+ unmap->to_cnt++;
+ }
+ if (!Q(blocks, disks)) {
+ pq[1] = 0;
+ dma_flags |= DMA_PREP_PQ_DISABLE_Q;
+ } else {
+ pq[1] = dma_map_page(dev, Q(blocks, disks),
+ offset, len,
+ DMA_TO_DEVICE);
+ unmap->addr[j++] = pq[1];
unmap->to_cnt++;
- src_cnt++;
- j++;
}
- if (!P(blocks, disks)) {
- pq[0] = 0;
- dma_flags |= DMA_PREP_PQ_DISABLE_P;
- } else {
- pq[0] = dma_map_page(dev, P(blocks, disks),
- offset, len,
- DMA_TO_DEVICE);
- unmap->addr[j++] = pq[0];
- unmap->to_cnt++;
- }
- if (!Q(blocks, disks)) {
- pq[1] = 0;
- dma_flags |= DMA_PREP_PQ_DISABLE_Q;
- } else {
- pq[1] = dma_map_page(dev, Q(blocks, disks),
- offset, len,
- DMA_TO_DEVICE);
- unmap->addr[j++] = pq[1];
- unmap->to_cnt++;
- }
-
- if (submit->flags & ASYNC_TX_FENCE)
- dma_flags |= DMA_PREP_FENCE;
- for (;;) {
- tx = device->device_prep_dma_pq_val(chan, pq,
- unmap->addr,
- src_cnt,
- coefs,
- len, pqres,
- dma_flags);
- if (likely(tx))
- break;
- async_tx_quiesce(&submit->depend_tx);
- dma_async_issue_pending(chan);
- }
+ if (submit->flags & ASYNC_TX_FENCE)
+ dma_flags |= DMA_PREP_FENCE;
+ for (;;) {
+ tx = device->device_prep_dma_pq_val(chan, pq,
+ unmap->addr,
+ src_cnt,
+ coefs,
+ len, pqres,
+ dma_flags);
+ if (likely(tx))
+ break;
+ async_tx_quiesce(&submit->depend_tx);
+ dma_async_issue_pending(chan);
+ }
- dma_set_unmap(tx, unmap);
- async_tx_submit(chan, tx, submit);
+ dma_set_unmap(tx, unmap);
+ async_tx_submit(chan, tx, submit);
- return tx;
+ return tx;
+ }
} else {
struct page *p_src = P(blocks, disks);
struct page *q_src = Q(blocks, disks);
@@ -411,9 +418,9 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
submit->cb_param = cb_param_orig;
submit->flags = flags_orig;
async_tx_sync_epilog(submit);
-
- return NULL;
}
+
+ return NULL;
}
EXPORT_SYMBOL_GPL(async_syndrome_val);
diff --git a/crypto/async_tx/async_raid6_recov.c b/crypto/async_tx/async_raid6_recov.c
index 934a849..c55d8f1 100644
--- a/crypto/async_tx/async_raid6_recov.c
+++ b/crypto/async_tx/async_raid6_recov.c
@@ -40,10 +40,7 @@ async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef,
u8 ax, bx;
u8 *a, *b, *c;
- if (dma)
- unmap = dmaengine_get_unmap_data(dma->dev, 3, GFP_NOIO);
-
- if (unmap) {
+ if (dma) {
struct device *dev = dma->dev;
dma_addr_t pq[2];
struct dma_async_tx_descriptor *tx;
@@ -51,29 +48,35 @@ async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef,
if (submit->flags & ASYNC_TX_FENCE)
dma_flags |= DMA_PREP_FENCE;
- unmap->addr[0] = dma_map_page(dev, srcs[0], 0, len, DMA_TO_DEVICE);
- unmap->addr[1] = dma_map_page(dev, srcs[1], 0, len, DMA_TO_DEVICE);
- unmap->to_cnt = 2;
-
- unmap->addr[2] = dma_map_page(dev, dest, 0, len, DMA_BIDIRECTIONAL);
- unmap->bidi_cnt = 1;
- /* engine only looks at Q, but expects it to follow P */
- pq[1] = unmap->addr[2];
-
- unmap->len = len;
- tx = dma->device_prep_dma_pq(chan, pq, unmap->addr, 2, coef,
- len, dma_flags);
- if (tx) {
- dma_set_unmap(tx, unmap);
- async_tx_submit(chan, tx, submit);
+
+ unmap = dmaengine_get_unmap_data(dma->dev, 3, GFP_NOIO);
+ if (unmap) {
+ unmap->addr[0] = dma_map_page(dev, srcs[0], 0, len,
+ DMA_TO_DEVICE);
+ unmap->addr[1] = dma_map_page(dev, srcs[1], 0, len,
+ DMA_TO_DEVICE);
+ unmap->to_cnt = 2;
+
+ unmap->addr[2] = dma_map_page(dev, dest, 0, len,
+ DMA_BIDIRECTIONAL);
+ unmap->bidi_cnt = 1;
+ /* engine only looks at Q, but expects it to follow P */
+ pq[1] = unmap->addr[2];
+
+ unmap->len = len;
+ tx = dma->device_prep_dma_pq(chan, pq, unmap->addr, 2,
+ coef, len, dma_flags);
+ if (tx) {
+ dma_set_unmap(tx, unmap);
+ async_tx_submit(chan, tx, submit);
+ return tx;
+ }
+
+ /* could not get a descriptor, unmap and fall through to
+ * the synchronous path
+ */
dmaengine_unmap_put(unmap);
- return tx;
}
-
- /* could not get a descriptor, unmap and fall through to
- * the synchronous path
- */
- dmaengine_unmap_put(unmap);
}
/* run the operation synchronously */
@@ -104,10 +107,7 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len,
const u8 *qmul; /* Q multiplier table */
u8 *d, *s;
- if (dma)
- unmap = dmaengine_get_unmap_data(dma->dev, 3, GFP_NOIO);
-
- if (unmap) {
+ if (dma) {
dma_addr_t dma_dest[2];
struct device *dev = dma->dev;
struct dma_async_tx_descriptor *tx;
@@ -115,31 +115,37 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len,
if (submit->flags & ASYNC_TX_FENCE)
dma_flags |= DMA_PREP_FENCE;
- unmap->addr[0] = dma_map_page(dev, src, 0, len, DMA_TO_DEVICE);
- unmap->to_cnt++;
- unmap->addr[1] = dma_map_page(dev, dest, 0, len, DMA_BIDIRECTIONAL);
- dma_dest[1] = unmap->addr[1];
- unmap->bidi_cnt++;
- unmap->len = len;
-
- /* this looks funny, but the engine looks for Q at
- * dma_dest[1] and ignores dma_dest[0] as a dest
- * due to DMA_PREP_PQ_DISABLE_P
- */
- tx = dma->device_prep_dma_pq(chan, dma_dest, unmap->addr,
- 1, &coef, len, dma_flags);
- if (tx) {
- dma_set_unmap(tx, unmap);
+ unmap = dmaengine_get_unmap_data(dma->dev, 3, GFP_NOIO);
+ if (unmap) {
+ unmap->addr[0] = dma_map_page(dev, src, 0, len,
+ DMA_TO_DEVICE);
+ unmap->to_cnt++;
+ unmap->addr[1] = dma_map_page(dev, dest, 0, len,
+ DMA_BIDIRECTIONAL);
+ dma_dest[1] = unmap->addr[1];
+ unmap->bidi_cnt++;
+ unmap->len = len;
+
+ /* this looks funny, but the engine looks for Q at
+ * dma_dest[1] and ignores dma_dest[0] as a dest
+ * due to DMA_PREP_PQ_DISABLE_P
+ */
+ tx = dma->device_prep_dma_pq(chan, dma_dest,
+ unmap->addr, 1, &coef,
+ len, dma_flags);
+
+ if (tx) {
+ dma_set_unmap(tx, unmap);
+ async_tx_submit(chan, tx, submit);
+ return tx;
+ }
+
+ /* could not get a descriptor, unmap and fall through to
+ * the synchronous path
+ */
dmaengine_unmap_put(unmap);
- async_tx_submit(chan, tx, submit);
- return tx;
}
-
- /* could not get a descriptor, unmap and fall through to
- * the synchronous path
- */
- dmaengine_unmap_put(unmap);
}
/* no channel available, or failed to allocate a descriptor, so
diff --git a/crypto/async_tx/async_xor.c b/crypto/async_tx/async_xor.c
index 3c562f5..019e469 100644
--- a/crypto/async_tx/async_xor.c
+++ b/crypto/async_tx/async_xor.c
@@ -182,55 +182,57 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
BUG_ON(src_cnt <= 1);
- if (device)
- unmap = dmaengine_get_unmap_data(device->dev, src_cnt+1, GFP_NOIO);
-
- if (unmap && is_dma_xor_aligned(device, offset, 0, len)) {
+ if (device && is_dma_xor_aligned(device, offset, 0, len)) {
struct dma_async_tx_descriptor *tx;
int i, j;
/* run the xor asynchronously */
pr_debug("%s (async): len: %zu\n", __func__, len);
- unmap->len = len;
- for (i = 0, j = 0; i < src_cnt; i++) {
- if (!src_list[i])
- continue;
- unmap->to_cnt++;
- unmap->addr[j++] = dma_map_page(device->dev, src_list[i],
- offset, len, DMA_TO_DEVICE);
- }
+ unmap = dmaengine_get_unmap_data(device->dev, src_cnt + 1,
+ GFP_NOIO);
+ if (unmap) {
+ unmap->len = len;
+ for (i = 0, j = 0; i < src_cnt; i++) {
+ if (!src_list[i])
+ continue;
+ unmap->to_cnt++;
+ unmap->addr[j++] = dma_map_page(device->dev,
+ src_list[i],
+ offset, len,
+ DMA_TO_DEVICE);
+ }
- /* map it bidirectional as it may be re-used as a source */
- unmap->addr[j] = dma_map_page(device->dev, dest, offset, len,
- DMA_BIDIRECTIONAL);
- unmap->bidi_cnt = 1;
-
- tx = do_async_xor(chan, unmap, submit);
- dmaengine_unmap_put(unmap);
- return tx;
- } else {
- dmaengine_unmap_put(unmap);
- /* run the xor synchronously */
- pr_debug("%s (sync): len: %zu\n", __func__, len);
- WARN_ONCE(chan, "%s: no space for dma address conversion\n",
- __func__);
-
- /* in the sync case the dest is an implied source
- * (assumes the dest is the first source)
- */
- if (submit->flags & ASYNC_TX_XOR_DROP_DST) {
- src_cnt--;
- src_list++;
+ /* map it bidirectional as it may be re-used
+ as a source */
+ unmap->addr[j] = dma_map_page(device->dev, dest, offset,
+ len, DMA_BIDIRECTIONAL);
+ unmap->bidi_cnt = 1;
+
+ tx = do_async_xor(chan, unmap, submit);
+ return tx;
}
+ }
- /* wait for any prerequisite operations */
- async_tx_quiesce(&submit->depend_tx);
+ /* run the xor synchronously */
+ pr_debug("%s (sync): len: %zu\n", __func__, len);
+ WARN_ONCE(chan, "%s: no space for dma address conversion\n",
+ __func__);
+
+ /* in the sync case the dest is an implied source
+ * (assumes the dest is the first source)
+ */
+ if (submit->flags & ASYNC_TX_XOR_DROP_DST) {
+ src_cnt--;
+ src_list++;
+ }
- do_sync_xor(dest, src_list, offset, src_cnt, len, submit);
+ /* wait for any prerequisite operations */
+ async_tx_quiesce(&submit->depend_tx);
- return NULL;
- }
+ do_sync_xor(dest, src_list, offset, src_cnt, len, submit);
+
+ return NULL;
}
EXPORT_SYMBOL_GPL(async_xor);
@@ -275,13 +277,11 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset,
struct dma_device *device = chan ? chan->device : NULL;
struct dma_async_tx_descriptor *tx = NULL;
struct dmaengine_unmap_data *unmap = NULL;
+ enum async_tx_flags flags_orig = submit->flags;
BUG_ON(src_cnt <= 1);
- if (device)
- unmap = dmaengine_get_unmap_data(device->dev, src_cnt, GFP_NOIO);
-
- if (unmap && src_cnt <= device->max_xor &&
+ if (device && src_cnt <= device->max_xor &&
is_dma_xor_aligned(device, offset, 0, len)) {
unsigned long dma_prep_flags = 0;
int i;
@@ -293,51 +293,59 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset,
if (submit->flags & ASYNC_TX_FENCE)
dma_prep_flags |= DMA_PREP_FENCE;
- for (i = 0; i < src_cnt; i++) {
- unmap->addr[i] = dma_map_page(device->dev, src_list[i],
- offset, len, DMA_TO_DEVICE);
- unmap->to_cnt++;
- }
- unmap->len = len;
-
- tx = device->device_prep_dma_xor_val(chan, unmap->addr, src_cnt,
- len, result,
- dma_prep_flags);
- if (unlikely(!tx)) {
- async_tx_quiesce(&submit->depend_tx);
-
- while (!tx) {
- dma_async_issue_pending(chan);
- tx = device->device_prep_dma_xor_val(chan,
- unmap->addr, src_cnt, len, result,
- dma_prep_flags);
+ unmap = dmaengine_get_unmap_data(device->dev, src_cnt,
+ GFP_NOIO);
+ if (unmap) {
+ for (i = 0; i < src_cnt; i++) {
+ unmap->addr[i] = dma_map_page(device->dev,
+ src_list[i],
+ offset, len,
+ DMA_TO_DEVICE);
+ unmap->to_cnt++;
+ }
+ unmap->len = len;
+
+ tx = device->device_prep_dma_xor_val(chan, unmap->addr,
+ src_cnt,
+ len, result,
+ dma_prep_flags);
+ if (unlikely(!tx)) {
+ async_tx_quiesce(&submit->depend_tx);
+
+ while (!tx) {
+ dma_async_issue_pending(chan);
+ tx = device->device_prep_dma_xor_val(
+ chan, unmap->addr,
+ src_cnt, len,
+ result, dma_prep_flags);
+ }
}
+ dma_set_unmap(tx, unmap);
+ async_tx_submit(chan, tx, submit);
+
+ return tx;
}
- dma_set_unmap(tx, unmap);
- async_tx_submit(chan, tx, submit);
- } else {
- enum async_tx_flags flags_orig = submit->flags;
+ }
- pr_debug("%s: (sync) len: %zu\n", __func__, len);
- WARN_ONCE(device && src_cnt <= device->max_xor,
- "%s: no space for dma address conversion\n",
- __func__);
+ /* run the xor_val synchronously */
+ pr_debug("%s: (sync) len: %zu\n", __func__, len);
+ WARN_ONCE(device && src_cnt <= device->max_xor,
+ "%s: no space for dma address conversion\n",
+ __func__);
- submit->flags |= ASYNC_TX_XOR_DROP_DST;
- submit->flags &= ~ASYNC_TX_ACK;
+ submit->flags |= ASYNC_TX_XOR_DROP_DST;
+ submit->flags &= ~ASYNC_TX_ACK;
- tx = async_xor(dest, src_list, offset, src_cnt, len, submit);
+ tx = async_xor(dest, src_list, offset, src_cnt, len, submit);
- async_tx_quiesce(&tx);
+ async_tx_quiesce(&tx);
- *result = !page_is_zero(dest, offset, len) << SUM_CHECK_P;
+ *result = !page_is_zero(dest, offset, len) << SUM_CHECK_P;
- async_tx_sync_epilog(submit);
- submit->flags = flags_orig;
- }
- dmaengine_unmap_put(unmap);
+ async_tx_sync_epilog(submit);
+ submit->flags = flags_orig;
- return tx;
+ return NULL;
}
EXPORT_SYMBOL_GPL(async_xor_val);
--
1.8.3.2
^ permalink raw reply related
* RE: [PATCH v2] fix wrong usage of dmaengine_unmap_put in async_xxx
From: Xuelin Shi @ 2014-03-20 9:53 UTC (permalink / raw)
To: Shevchenko, Andriy
Cc: Koul, Vinod, dmaengine@vger.kernel.org, Williams, Dan J,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1395308689.28803.323.camel@smile.fi.intel.com>
WWVzLCB0aGlzIHBhdGNoIGlzIHJ1biBieSBjaGVja3BhdGNoIGFuZCBmb3VuZCAwIGVycm9ycywg
MCB3YXJuaW5ncy4NCg0KLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCkZyb206IFNoZXZjaGVu
a28sIEFuZHJpeSBbbWFpbHRvOmFuZHJpeS5zaGV2Y2hlbmtvQGludGVsLmNvbV0gDQpTZW50OiAy
MDE05bm0M+aciDIw5pelIDE3OjQ1DQpUbzogU2hpIFh1ZWxpbi1CMjkyMzcNCkNjOiBLb3VsLCBW
aW5vZDsgV2lsbGlhbXMsIERhbiBKOyBkbWFlbmdpbmVAdmdlci5rZXJuZWwub3JnOyBsaW51eHBw
Yy1kZXZAbGlzdHMub3psYWJzLm9yZw0KU3ViamVjdDogUmU6IFtQQVRDSCB2Ml0gZml4IHdyb25n
IHVzYWdlIG9mIGRtYWVuZ2luZV91bm1hcF9wdXQgaW4gYXN5bmNfeHh4DQoNCk9uIFRodSwgMjAx
NC0wMy0yMCBhdCAxNjoxNiArMDgwMCwgeHVlbGluLnNoaUBmcmVlc2NhbGUuY29tIHdyb3RlOg0K
PiBGcm9tOiBYdWVsaW4gU2hpIDx4dWVsaW4uc2hpQGZyZWVzY2FsZS5jb20+DQo+IA0KPiBkbWFl
bmdpbmVfdW5tYXBfcHV0IGRvZXMgYmVsb3cgdHdvIHRoaW5nczoNCj4gYSkgdW5tYXAgcGFnZXMg
Zm9yIHNyY3MgYW5kIGRlc3RzDQo+IGIpIGZyZWUgdW5tYXAgc3RydWN0DQo+IA0KPiBUaGUgdW5t
YXAgc3RydWN0IGRhdGEgaXMgZ2VuZXJhdGVkIGJ1dCBvbmx5IGluaXRpYWxpemVkIHdoaWxlIG90
aGVyIA0KPiBzb21lIGRtYSBjb250aW9ucyBhcmUgbWV0LCBsaWtlIGRtYSBhbGlnbm1lbnQgZXRj
Lg0KPiBJZiB0aGUgdW5tYXAgZGF0YSBpcyBub3QgaW5pdGlhbGl6ZWQsIGNhbGwgZG1hZW5naW5l
X3VubWFwX3B1dCB3aWxsIA0KPiB1bm1hcCBzb21lIHJhbmRvbSBkYXRhIGluIHVubWFwLT5hZGRy
Wy4uLl0NCj4gDQo+IEFsc28gY2FsbCBkbWFlbmdpbmVfZ2V0X3VubWFwX2RhdGEgaW1tZWRpYXRh
bGx5IGFmdGVyIGdlbmVyYXRpbmcgdHggaXMgDQo+IG5vdCBjb3JyZWN0LiBNYXliZSB0aGUgdHgg
aGFzIG5vdCBiZWVuIGZpbmlzaGVkIGJ5IERNQSBoYXJkd2FyZSB5ZXQgDQo+IGJ1dCB0aGUgc3Jj
cyBhbmQgZGVzdHMgYXJlIGRtYSB1bm1hcHBlZC4NCj4gDQo+IFRoaXMgcGF0Y2ggZml4ZWQgYWJv
dmUgdHdvIGlzc3VlcyBieToNCj4gYSkgb25seSBnZW5lcmF0ZXMgdW5tYXAgc3RydWN0IGRhdGEg
d2hlbiBvdGhlciBkbWEgY29uZGl0aW9ucyBhcmUgbWV0Lg0KPiBiKSBlbGltaW5hdGVzIGRtYWVu
Z2luZV91bm1hcF9wdXQgd2hlbiB0eCBpcyBnZW5lcmF0ZWQgYmVjYXVzZSB0eCANCj4ga25vd2Vz
IHRoZSBiZXN0IHRpbWUgdG8gdW5tYXAgaXQgKGluIGludGVycnVwdCBwcm9jZXNzaW5nKS4NCg0K
SGF2ZSB5b3UgcnVuIGNoZWNrcGF0Y2gucGwgYWdhaW5zdCB0aGlzIG9uZT8NCg0KPiANCj4gU2ln
bmVkLW9mZi1ieTogWHVlbGluIFNoaSA8eHVlbGluLnNoaUBmcmVlc2NhbGUuY29tPg0KPiAtLS0N
Cj4gY2hhbmdlIGxvZzoNCj4gCXYxOiBpbmNsdWRlIGNoYW5nZSBpbiBhc3luY19tZW1jcHksIGFz
eW5jX3hvciwgYXN5bmNfcHENCj4gIAl2MjogYWRkIGNoYW5nZSBpbiBhc3luY19yYWlkNl9yZWNv
di5jIGFuZCBmaXggc29tZSBzdHlsZSBpc3N1ZQ0KPiANCj4gIGNyeXB0by9hc3luY190eC9hc3lu
Y19tZW1jcHkuYyAgICAgIHwgIDgwICsrKysrKysrLS0tLS0tLQ0KPiAgY3J5cHRvL2FzeW5jX3R4
L2FzeW5jX3BxLmMgICAgICAgICAgfCAxODkgKysrKysrKysrKysrKysrKysrKy0tLS0tLS0tLS0t
LS0tLS0tDQo+ICBjcnlwdG8vYXN5bmNfdHgvYXN5bmNfcmFpZDZfcmVjb3YuYyB8IDEwOCArKysr
KysrKysrKy0tLS0tLS0tLS0NCj4gIGNyeXB0by9hc3luY190eC9hc3luY194b3IuYyAgICAgICAg
IHwgMTY0ICsrKysrKysrKysrKysrKystLS0tLS0tLS0tLS0tLS0NCj4gIDQgZmlsZXMgY2hhbmdl
ZCwgMjg2IGluc2VydGlvbnMoKyksIDI1NSBkZWxldGlvbnMoLSkNCj4gDQo+IGRpZmYgLS1naXQg
YS9jcnlwdG8vYXN5bmNfdHgvYXN5bmNfbWVtY3B5LmMgDQo+IGIvY3J5cHRvL2FzeW5jX3R4L2Fz
eW5jX21lbWNweS5jIGluZGV4IGY4YzBiOGQuLjY1NDZlODcgMTAwNjQ0DQo+IC0tLSBhL2NyeXB0
by9hc3luY190eC9hc3luY19tZW1jcHkuYw0KPiArKysgYi9jcnlwdG8vYXN5bmNfdHgvYXN5bmNf
bWVtY3B5LmMNCj4gQEAgLTUxLDExICs1MSwxMCBAQCBhc3luY19tZW1jcHkoc3RydWN0IHBhZ2Ug
KmRlc3QsIHN0cnVjdCBwYWdlICpzcmMsIHVuc2lnbmVkIGludCBkZXN0X29mZnNldCwNCj4gIAlz
dHJ1Y3QgZG1hX2RldmljZSAqZGV2aWNlID0gY2hhbiA/IGNoYW4tPmRldmljZSA6IE5VTEw7DQo+
ICAJc3RydWN0IGRtYV9hc3luY190eF9kZXNjcmlwdG9yICp0eCA9IE5VTEw7DQo+ICAJc3RydWN0
IGRtYWVuZ2luZV91bm1hcF9kYXRhICp1bm1hcCA9IE5VTEw7DQo+ICsJdm9pZCAqZGVzdF9idWYs
ICpzcmNfYnVmOw0KPiAgDQo+IC0JaWYgKGRldmljZSkNCj4gLQkJdW5tYXAgPSBkbWFlbmdpbmVf
Z2V0X3VubWFwX2RhdGEoZGV2aWNlLT5kZXYsIDIsIEdGUF9OT0lPKTsNCj4gLQ0KPiAtCWlmICh1
bm1hcCAmJiBpc19kbWFfY29weV9hbGlnbmVkKGRldmljZSwgc3JjX29mZnNldCwgZGVzdF9vZmZz
ZXQsIGxlbikpIHsNCj4gKwlpZiAoZGV2aWNlICYmDQo+ICsJICAgIGlzX2RtYV9jb3B5X2FsaWdu
ZWQoZGV2aWNlLCBzcmNfb2Zmc2V0LCBkZXN0X29mZnNldCwgbGVuKSkgew0KPiAgCQl1bnNpZ25l
ZCBsb25nIGRtYV9wcmVwX2ZsYWdzID0gMDsNCj4gIA0KPiAgCQlpZiAoc3VibWl0LT5jYl9mbikN
Cj4gQEAgLTYzLDQ1ICs2Miw1NiBAQCBhc3luY19tZW1jcHkoc3RydWN0IHBhZ2UgKmRlc3QsIHN0
cnVjdCBwYWdlICpzcmMsIHVuc2lnbmVkIGludCBkZXN0X29mZnNldCwNCj4gIAkJaWYgKHN1Ym1p
dC0+ZmxhZ3MgJiBBU1lOQ19UWF9GRU5DRSkNCj4gIAkJCWRtYV9wcmVwX2ZsYWdzIHw9IERNQV9Q
UkVQX0ZFTkNFOw0KPiAgDQo+IC0JCXVubWFwLT50b19jbnQgPSAxOw0KPiAtCQl1bm1hcC0+YWRk
clswXSA9IGRtYV9tYXBfcGFnZShkZXZpY2UtPmRldiwgc3JjLCBzcmNfb2Zmc2V0LCBsZW4sDQo+
IC0JCQkJCSAgICAgIERNQV9UT19ERVZJQ0UpOw0KPiAtCQl1bm1hcC0+ZnJvbV9jbnQgPSAxOw0K
PiAtCQl1bm1hcC0+YWRkclsxXSA9IGRtYV9tYXBfcGFnZShkZXZpY2UtPmRldiwgZGVzdCwgZGVz
dF9vZmZzZXQsIGxlbiwNCj4gLQkJCQkJICAgICAgRE1BX0ZST01fREVWSUNFKTsNCj4gLQkJdW5t
YXAtPmxlbiA9IGxlbjsNCj4gLQ0KPiAtCQl0eCA9IGRldmljZS0+ZGV2aWNlX3ByZXBfZG1hX21l
bWNweShjaGFuLCB1bm1hcC0+YWRkclsxXSwNCj4gLQkJCQkJCSAgICB1bm1hcC0+YWRkclswXSwg
bGVuLA0KPiAtCQkJCQkJICAgIGRtYV9wcmVwX2ZsYWdzKTsNCj4gKwkJdW5tYXAgPSBkbWFlbmdp
bmVfZ2V0X3VubWFwX2RhdGEoZGV2aWNlLT5kZXYsIDIsIEdGUF9OT0lPKTsNCj4gKwkJaWYgKHVu
bWFwKSB7DQo+ICsJCQl1bm1hcC0+dG9fY250ID0gMTsNCj4gKwkJCXVubWFwLT5hZGRyWzBdID0g
ZG1hX21hcF9wYWdlKGRldmljZS0+ZGV2LCBzcmMsDQo+ICsJCQkJCQkgICAgICBzcmNfb2Zmc2V0
LCBsZW4sDQo+ICsJCQkJCQkgICAgICBETUFfVE9fREVWSUNFKTsNCj4gKwkJCXVubWFwLT5mcm9t
X2NudCA9IDE7DQo+ICsJCQl1bm1hcC0+YWRkclsxXSA9IGRtYV9tYXBfcGFnZShkZXZpY2UtPmRl
diwgZGVzdCwNCj4gKwkJCQkJCSAgICAgIGRlc3Rfb2Zmc2V0LCBsZW4sDQo+ICsJCQkJCQkgICAg
ICBETUFfRlJPTV9ERVZJQ0UpOw0KPiArCQkJdW5tYXAtPmxlbiA9IGxlbjsNCj4gKw0KPiArCQkJ
dHggPSBkZXZpY2UtPmRldmljZV9wcmVwX2RtYV9tZW1jcHkoY2hhbiwNCj4gKwkJCQkJCQkgICAg
dW5tYXAtPmFkZHJbMV0sDQo+ICsJCQkJCQkJICAgIHVubWFwLT5hZGRyWzBdLA0KPiArCQkJCQkJ
CSAgICBsZW4sDQo+ICsJCQkJCQkJICAgIGRtYV9wcmVwX2ZsYWdzKTsNCj4gKwkJCWlmICh0eCkg
ew0KPiArCQkJCXByX2RlYnVnKCIlczogKGFzeW5jKSBsZW46ICV6dVxuIiwgX19mdW5jX18sDQo+
ICsJCQkJCSBsZW4pOw0KPiArDQo+ICsJCQkJZG1hX3NldF91bm1hcCh0eCwgdW5tYXApOw0KPiAr
CQkJCWFzeW5jX3R4X3N1Ym1pdChjaGFuLCB0eCwgc3VibWl0KTsNCj4gKwkJCQlyZXR1cm4gdHg7
DQo+ICsJCQl9DQo+ICsNCj4gKwkJCS8qIGNvdWxkIG5vdCBnZXQgYSBkZXNjcmlwdG9yLCB1bm1h
cCBhbmQgZmFsbCB0aHJvdWdoIHRvDQo+ICsJCQkgKiB0aGUgc3luY2hyb25vdXMgcGF0aA0KPiAr
CQkJICovDQo+ICsJCQlkbWFlbmdpbmVfdW5tYXBfcHV0KHVubWFwKTsNCj4gKwkJfQ0KPiAgCX0N
Cj4gIA0KPiAtCWlmICh0eCkgew0KPiAtCQlwcl9kZWJ1ZygiJXM6IChhc3luYykgbGVuOiAlenVc
biIsIF9fZnVuY19fLCBsZW4pOw0KPiArCS8qIHJ1biB0aGUgb3BlcmF0aW9uIHN5bmNocm9ub3Vz
bHkgKi8NCj4gKwlwcl9kZWJ1ZygiJXM6IChzeW5jKSBsZW46ICV6dVxuIiwgX19mdW5jX18sIGxl
bik7DQo+ICANCj4gLQkJZG1hX3NldF91bm1hcCh0eCwgdW5tYXApOw0KPiAtCQlhc3luY190eF9z
dWJtaXQoY2hhbiwgdHgsIHN1Ym1pdCk7DQo+IC0JfSBlbHNlIHsNCj4gLQkJdm9pZCAqZGVzdF9i
dWYsICpzcmNfYnVmOw0KPiAtCQlwcl9kZWJ1ZygiJXM6IChzeW5jKSBsZW46ICV6dVxuIiwgX19m
dW5jX18sIGxlbik7DQo+ICsJLyogd2FpdCBmb3IgYW55IHByZXJlcXVpc2l0ZSBvcGVyYXRpb25z
ICovDQo+ICsJYXN5bmNfdHhfcXVpZXNjZSgmc3VibWl0LT5kZXBlbmRfdHgpOw0KPiAgDQo+IC0J
CS8qIHdhaXQgZm9yIGFueSBwcmVyZXF1aXNpdGUgb3BlcmF0aW9ucyAqLw0KPiAtCQlhc3luY190
eF9xdWllc2NlKCZzdWJtaXQtPmRlcGVuZF90eCk7DQo+ICsJZGVzdF9idWYgPSBrbWFwX2F0b21p
YyhkZXN0KSArIGRlc3Rfb2Zmc2V0Ow0KPiArCXNyY19idWYgPSBrbWFwX2F0b21pYyhzcmMpICsg
c3JjX29mZnNldDsNCj4gIA0KPiAtCQlkZXN0X2J1ZiA9IGttYXBfYXRvbWljKGRlc3QpICsgZGVz
dF9vZmZzZXQ7DQo+IC0JCXNyY19idWYgPSBrbWFwX2F0b21pYyhzcmMpICsgc3JjX29mZnNldDsN
Cj4gKwltZW1jcHkoZGVzdF9idWYsIHNyY19idWYsIGxlbik7DQo+ICANCj4gLQkJbWVtY3B5KGRl
c3RfYnVmLCBzcmNfYnVmLCBsZW4pOw0KPiAtDQo+IC0JCWt1bm1hcF9hdG9taWMoc3JjX2J1Zik7
DQo+IC0JCWt1bm1hcF9hdG9taWMoZGVzdF9idWYpOw0KPiAtDQo+IC0JCWFzeW5jX3R4X3N5bmNf
ZXBpbG9nKHN1Ym1pdCk7DQo+IC0JfQ0KPiArCWt1bm1hcF9hdG9taWMoc3JjX2J1Zik7DQo+ICsJ
a3VubWFwX2F0b21pYyhkZXN0X2J1Zik7DQo+ICANCj4gLQlkbWFlbmdpbmVfdW5tYXBfcHV0KHVu
bWFwKTsNCj4gKwlhc3luY190eF9zeW5jX2VwaWxvZyhzdWJtaXQpOw0KPiAgDQo+IC0JcmV0dXJu
IHR4Ow0KPiArCXJldHVybiBOVUxMOw0KPiAgfQ0KPiAgRVhQT1JUX1NZTUJPTF9HUEwoYXN5bmNf
bWVtY3B5KTsNCj4gIA0KPiBkaWZmIC0tZ2l0IGEvY3J5cHRvL2FzeW5jX3R4L2FzeW5jX3BxLmMg
Yi9jcnlwdG8vYXN5bmNfdHgvYXN5bmNfcHEuYyANCj4gaW5kZXggZDA1MzI3Yy4uZjQ0NmNkYSAx
MDA2NDQNCj4gLS0tIGEvY3J5cHRvL2FzeW5jX3R4L2FzeW5jX3BxLmMNCj4gKysrIGIvY3J5cHRv
L2FzeW5jX3R4L2FzeW5jX3BxLmMNCj4gQEAgLTE3NSwxMCArMTc1LDcgQEAgYXN5bmNfZ2VuX3N5
bmRyb21lKHN0cnVjdCBwYWdlICoqYmxvY2tzLCB1bnNpZ25lZCANCj4gaW50IG9mZnNldCwgaW50
IGRpc2tzLA0KPiAgDQo+ICAJQlVHX09OKGRpc2tzID4gMjU1IHx8ICEoUChibG9ja3MsIGRpc2tz
KSB8fCBRKGJsb2NrcywgZGlza3MpKSk7DQo+ICANCj4gLQlpZiAoZGV2aWNlKQ0KPiAtCQl1bm1h
cCA9IGRtYWVuZ2luZV9nZXRfdW5tYXBfZGF0YShkZXZpY2UtPmRldiwgZGlza3MsIEdGUF9OT0lP
KTsNCj4gLQ0KPiAtCWlmICh1bm1hcCAmJg0KPiArCWlmIChkZXZpY2UgJiYNCj4gIAkgICAgKHNy
Y19jbnQgPD0gZG1hX21heHBxKGRldmljZSwgMCkgfHwNCj4gIAkgICAgIGRtYV9tYXhwcShkZXZp
Y2UsIERNQV9QUkVQX0NPTlRJTlVFKSA+IDApICYmDQo+ICAJICAgIGlzX2RtYV9wcV9hbGlnbmVk
KGRldmljZSwgb2Zmc2V0LCAwLCBsZW4pKSB7IEBAIC0xOTQsNDYgKzE5MSw1NCANCj4gQEAgYXN5
bmNfZ2VuX3N5bmRyb21lKHN0cnVjdCBwYWdlICoqYmxvY2tzLCB1bnNpZ25lZCBpbnQgb2Zmc2V0
LCBpbnQgZGlza3MsDQo+ICAJCS8qIGNvbnZlcnQgc291cmNlIGFkZHJlc3NlcyBiZWluZyBjYXJl
ZnVsIHRvIGNvbGxhcHNlICdlbXB0eScNCj4gIAkJICogc291cmNlcyBhbmQgdXBkYXRlIHRoZSBj
b2VmZmljaWVudHMgYWNjb3JkaW5nbHkNCj4gIAkJICovDQo+IC0JCXVubWFwLT5sZW4gPSBsZW47
DQo+IC0JCWZvciAoaSA9IDAsIGogPSAwOyBpIDwgc3JjX2NudDsgaSsrKSB7DQo+IC0JCQlpZiAo
YmxvY2tzW2ldID09IE5VTEwpDQo+IC0JCQkJY29udGludWU7DQo+IC0JCQl1bm1hcC0+YWRkcltq
XSA9IGRtYV9tYXBfcGFnZShkZXZpY2UtPmRldiwgYmxvY2tzW2ldLCBvZmZzZXQsDQo+IC0JCQkJ
CQkgICAgICBsZW4sIERNQV9UT19ERVZJQ0UpOw0KPiAtCQkJY29lZnNbal0gPSByYWlkNl9nZmV4
cFtpXTsNCj4gLQkJCXVubWFwLT50b19jbnQrKzsNCj4gLQkJCWorKzsNCj4gLQkJfQ0KPiArCQl1
bm1hcCA9IGRtYWVuZ2luZV9nZXRfdW5tYXBfZGF0YShkZXZpY2UtPmRldiwgZGlza3MsIEdGUF9O
T0lPKTsNCj4gKwkJaWYgKHVubWFwKSB7DQo+ICsJCQl1bm1hcC0+bGVuID0gbGVuOw0KPiArCQkJ
Zm9yIChpID0gMCwgaiA9IDA7IGkgPCBzcmNfY250OyBpKyspIHsNCj4gKwkJCQlpZiAoYmxvY2tz
W2ldID09IE5VTEwpDQo+ICsJCQkJCWNvbnRpbnVlOw0KPiArCQkJCXVubWFwLT5hZGRyW2pdID0g
ZG1hX21hcF9wYWdlKGRldmljZS0+ZGV2LA0KPiArCQkJCQkJCSAgICAgIGJsb2Nrc1tpXSwNCj4g
KwkJCQkJCQkgICAgICBvZmZzZXQsDQo+ICsJCQkJCQkJICAgICAgbGVuLA0KPiArCQkJCQkJCSAg
ICAgIERNQV9UT19ERVZJQ0UpOw0KPiArCQkJCWNvZWZzW2pdID0gcmFpZDZfZ2ZleHBbaV07DQo+
ICsJCQkJdW5tYXAtPnRvX2NudCsrOw0KPiArCQkJCWorKzsNCj4gKwkJCX0NCj4gIA0KPiAtCQkv
Kg0KPiAtCQkgKiBETUFzIHVzZSBkZXN0aW5hdGlvbnMgYXMgc291cmNlcywNCj4gLQkJICogc28g
dXNlIEJJRElSRUNUSU9OQUwgbWFwcGluZw0KPiAtCQkgKi8NCj4gLQkJdW5tYXAtPmJpZGlfY250
Kys7DQo+IC0JCWlmIChQKGJsb2NrcywgZGlza3MpKQ0KPiAtCQkJdW5tYXAtPmFkZHJbaisrXSA9
IGRtYV9tYXBfcGFnZShkZXZpY2UtPmRldiwgUChibG9ja3MsIGRpc2tzKSwNCj4gLQkJCQkJCQlv
ZmZzZXQsIGxlbiwgRE1BX0JJRElSRUNUSU9OQUwpOw0KPiAtCQllbHNlIHsNCj4gLQkJCXVubWFw
LT5hZGRyW2orK10gPSAwOw0KPiAtCQkJZG1hX2ZsYWdzIHw9IERNQV9QUkVQX1BRX0RJU0FCTEVf
UDsNCj4gLQkJfQ0KPiArCQkJLyoNCj4gKwkJCSAqIERNQXMgdXNlIGRlc3RpbmF0aW9ucyBhcyBz
b3VyY2VzLA0KPiArCQkJICogc28gdXNlIEJJRElSRUNUSU9OQUwgbWFwcGluZw0KPiArCQkJICov
DQo+ICsJCQl1bm1hcC0+YmlkaV9jbnQrKzsNCj4gKwkJCWlmIChQKGJsb2NrcywgZGlza3MpKQ0K
PiArCQkJCXVubWFwLT5hZGRyW2orK10gPSBkbWFfbWFwX3BhZ2UoZGV2aWNlLT5kZXYsDQo+ICsJ
CQkJCQkJUChibG9ja3MsIGRpc2tzKSwNCj4gKwkJCQkJCQlvZmZzZXQsIGxlbiwNCj4gKwkJCQkJ
CQlETUFfQklESVJFQ1RJT05BTCk7DQo+ICsJCQllbHNlIHsNCj4gKwkJCQl1bm1hcC0+YWRkcltq
KytdID0gMDsNCj4gKwkJCQlkbWFfZmxhZ3MgfD0gRE1BX1BSRVBfUFFfRElTQUJMRV9QOw0KPiAr
CQkJfQ0KPiAgDQo+IC0JCXVubWFwLT5iaWRpX2NudCsrOw0KPiAtCQlpZiAoUShibG9ja3MsIGRp
c2tzKSkNCj4gLQkJCXVubWFwLT5hZGRyW2orK10gPSBkbWFfbWFwX3BhZ2UoZGV2aWNlLT5kZXYs
IFEoYmxvY2tzLCBkaXNrcyksDQo+IC0JCQkJCQkgICAgICAgb2Zmc2V0LCBsZW4sIERNQV9CSURJ
UkVDVElPTkFMKTsNCj4gLQkJZWxzZSB7DQo+IC0JCQl1bm1hcC0+YWRkcltqKytdID0gMDsNCj4g
LQkJCWRtYV9mbGFncyB8PSBETUFfUFJFUF9QUV9ESVNBQkxFX1E7DQo+IC0JCX0NCj4gKwkJCXVu
bWFwLT5iaWRpX2NudCsrOw0KPiArCQkJaWYgKFEoYmxvY2tzLCBkaXNrcykpDQo+ICsJCQkJdW5t
YXAtPmFkZHJbaisrXSA9IGRtYV9tYXBfcGFnZShkZXZpY2UtPmRldiwNCj4gKwkJCQkJCQlRKGJs
b2NrcywgZGlza3MpLA0KPiArCQkJCQkJCW9mZnNldCwgbGVuLA0KPiArCQkJCQkJCURNQV9CSURJ
UkVDVElPTkFMKTsNCj4gKwkJCWVsc2Ugew0KPiArCQkJCXVubWFwLT5hZGRyW2orK10gPSAwOw0K
PiArCQkJCWRtYV9mbGFncyB8PSBETUFfUFJFUF9QUV9ESVNBQkxFX1E7DQo+ICsJCQl9DQo+ICAN
Cj4gLQkJdHggPSBkb19hc3luY19nZW5fc3luZHJvbWUoY2hhbiwgY29lZnMsIGosIHVubWFwLCBk
bWFfZmxhZ3MsIHN1Ym1pdCk7DQo+IC0JCWRtYWVuZ2luZV91bm1hcF9wdXQodW5tYXApOw0KPiAt
CQlyZXR1cm4gdHg7DQo+ICsJCQl0eCA9IGRvX2FzeW5jX2dlbl9zeW5kcm9tZShjaGFuLCBjb2Vm
cywgaiwgdW5tYXAsDQo+ICsJCQkJCQkgICBkbWFfZmxhZ3MsIHN1Ym1pdCk7DQo+ICsJCQlyZXR1
cm4gdHg7DQo+ICsJCX0NCj4gIAl9DQo+ICANCj4gLQlkbWFlbmdpbmVfdW5tYXBfcHV0KHVubWFw
KTsNCj4gLQ0KPiAgCS8qIHJ1biB0aGUgcHEgc3luY2hyb25vdXNseSAqLw0KPiAgCXByX2RlYnVn
KCIlczogKHN5bmMpIGRpc2tzOiAlZCBsZW46ICV6dVxuIiwgX19mdW5jX18sIGRpc2tzLCBsZW4p
Ow0KPiAgDQo+IEBAIC0yOTMsMTAgKzI5OCw3IEBAIGFzeW5jX3N5bmRyb21lX3ZhbChzdHJ1Y3Qg
cGFnZSAqKmJsb2NrcywgdW5zaWduZWQgDQo+IGludCBvZmZzZXQsIGludCBkaXNrcywNCj4gIA0K
PiAgCUJVR19PTihkaXNrcyA8IDQpOw0KPiAgDQo+IC0JaWYgKGRldmljZSkNCj4gLQkJdW5tYXAg
PSBkbWFlbmdpbmVfZ2V0X3VubWFwX2RhdGEoZGV2aWNlLT5kZXYsIGRpc2tzLCBHRlBfTk9JTyk7
DQo+IC0NCj4gLQlpZiAodW5tYXAgJiYgZGlza3MgPD0gZG1hX21heHBxKGRldmljZSwgMCkgJiYN
Cj4gKwlpZiAoZGV2aWNlICYmIGRpc2tzIDw9IGRtYV9tYXhwcShkZXZpY2UsIDApICYmDQo+ICAJ
ICAgIGlzX2RtYV9wcV9hbGlnbmVkKGRldmljZSwgb2Zmc2V0LCAwLCBsZW4pKSB7DQo+ICAJCXN0
cnVjdCBkZXZpY2UgKmRldiA9IGRldmljZS0+ZGV2Ow0KPiAgCQlkbWFfYWRkcl90IHBxWzJdOw0K
PiBAQCAtMzA1LDU4ICszMDcsNjMgQEAgYXN5bmNfc3luZHJvbWVfdmFsKHN0cnVjdCBwYWdlICoq
YmxvY2tzLCB1bnNpZ25lZCBpbnQgb2Zmc2V0LCBpbnQgZGlza3MsDQo+ICAJCXByX2RlYnVnKCIl
czogKGFzeW5jKSBkaXNrczogJWQgbGVuOiAlenVcbiIsDQo+ICAJCQkgX19mdW5jX18sIGRpc2tz
LCBsZW4pOw0KPiAgDQo+IC0JCXVubWFwLT5sZW4gPSBsZW47DQo+IC0JCWZvciAoaSA9IDA7IGkg
PCBkaXNrcy0yOyBpKyspDQo+IC0JCQlpZiAobGlrZWx5KGJsb2Nrc1tpXSkpIHsNCj4gLQkJCQl1
bm1hcC0+YWRkcltqXSA9IGRtYV9tYXBfcGFnZShkZXYsIGJsb2Nrc1tpXSwNCj4gLQkJCQkJCQkg
ICAgICBvZmZzZXQsIGxlbiwNCj4gKwkJdW5tYXAgPSBkbWFlbmdpbmVfZ2V0X3VubWFwX2RhdGEo
ZGV2aWNlLT5kZXYsIGRpc2tzLCBHRlBfTk9JTyk7DQo+ICsJCWlmICh1bm1hcCkgew0KPiArCQkJ
dW5tYXAtPmxlbiA9IGxlbjsNCj4gKwkJCWZvciAoaSA9IDA7IGkgPCBkaXNrcy0yOyBpKyspDQo+
ICsJCQkJaWYgKGxpa2VseShibG9ja3NbaV0pKSB7DQo+ICsJCQkJCXVubWFwLT5hZGRyW2pdID0g
ZG1hX21hcF9wYWdlKGRldiwNCj4gKwkJCQkJCQkgICAgICBibG9ja3NbaV0sDQo+ICsJCQkJCQkJ
ICAgICAgb2Zmc2V0LA0KPiArCQkJCQkJCSAgICAgIGxlbiwNCj4gIAkJCQkJCQkgICAgICBETUFf
VE9fREVWSUNFKTsNCj4gLQkJCQljb2Vmc1tqXSA9IHJhaWQ2X2dmZXhwW2ldOw0KPiArCQkJCQlj
b2Vmc1tqXSA9IHJhaWQ2X2dmZXhwW2ldOw0KPiArCQkJCQl1bm1hcC0+dG9fY250Kys7DQo+ICsJ
CQkJCXNyY19jbnQrKzsNCj4gKwkJCQkJaisrOw0KPiArCQkJCX0NCj4gKw0KPiArCQkJaWYgKCFQ
KGJsb2NrcywgZGlza3MpKSB7DQo+ICsJCQkJcHFbMF0gPSAwOw0KPiArCQkJCWRtYV9mbGFncyB8
PSBETUFfUFJFUF9QUV9ESVNBQkxFX1A7DQo+ICsJCQl9IGVsc2Ugew0KPiArCQkJCXBxWzBdID0g
ZG1hX21hcF9wYWdlKGRldiwgUChibG9ja3MsIGRpc2tzKSwNCj4gKwkJCQkJCSAgICAgb2Zmc2V0
LCBsZW4sDQo+ICsJCQkJCQkgICAgIERNQV9UT19ERVZJQ0UpOw0KPiArCQkJCXVubWFwLT5hZGRy
W2orK10gPSBwcVswXTsNCj4gKwkJCQl1bm1hcC0+dG9fY250Kys7DQo+ICsJCQl9DQo+ICsJCQlp
ZiAoIVEoYmxvY2tzLCBkaXNrcykpIHsNCj4gKwkJCQlwcVsxXSA9IDA7DQo+ICsJCQkJZG1hX2Zs
YWdzIHw9IERNQV9QUkVQX1BRX0RJU0FCTEVfUTsNCj4gKwkJCX0gZWxzZSB7DQo+ICsJCQkJcHFb
MV0gPSBkbWFfbWFwX3BhZ2UoZGV2LCBRKGJsb2NrcywgZGlza3MpLA0KPiArCQkJCQkJICAgICBv
ZmZzZXQsIGxlbiwNCj4gKwkJCQkJCSAgICAgRE1BX1RPX0RFVklDRSk7DQo+ICsJCQkJdW5tYXAt
PmFkZHJbaisrXSA9IHBxWzFdOw0KPiAgCQkJCXVubWFwLT50b19jbnQrKzsNCj4gLQkJCQlzcmNf
Y250Kys7DQo+IC0JCQkJaisrOw0KPiAgCQkJfQ0KPiAgDQo+IC0JCWlmICghUChibG9ja3MsIGRp
c2tzKSkgew0KPiAtCQkJcHFbMF0gPSAwOw0KPiAtCQkJZG1hX2ZsYWdzIHw9IERNQV9QUkVQX1BR
X0RJU0FCTEVfUDsNCj4gLQkJfSBlbHNlIHsNCj4gLQkJCXBxWzBdID0gZG1hX21hcF9wYWdlKGRl
diwgUChibG9ja3MsIGRpc2tzKSwNCj4gLQkJCQkJICAgICBvZmZzZXQsIGxlbiwNCj4gLQkJCQkJ
ICAgICBETUFfVE9fREVWSUNFKTsNCj4gLQkJCXVubWFwLT5hZGRyW2orK10gPSBwcVswXTsNCj4g
LQkJCXVubWFwLT50b19jbnQrKzsNCj4gLQkJfQ0KPiAtCQlpZiAoIVEoYmxvY2tzLCBkaXNrcykp
IHsNCj4gLQkJCXBxWzFdID0gMDsNCj4gLQkJCWRtYV9mbGFncyB8PSBETUFfUFJFUF9QUV9ESVNB
QkxFX1E7DQo+IC0JCX0gZWxzZSB7DQo+IC0JCQlwcVsxXSA9IGRtYV9tYXBfcGFnZShkZXYsIFEo
YmxvY2tzLCBkaXNrcyksDQo+IC0JCQkJCSAgICAgb2Zmc2V0LCBsZW4sDQo+IC0JCQkJCSAgICAg
RE1BX1RPX0RFVklDRSk7DQo+IC0JCQl1bm1hcC0+YWRkcltqKytdID0gcHFbMV07DQo+IC0JCQl1
bm1hcC0+dG9fY250Kys7DQo+IC0JCX0NCj4gLQ0KPiAtCQlpZiAoc3VibWl0LT5mbGFncyAmIEFT
WU5DX1RYX0ZFTkNFKQ0KPiAtCQkJZG1hX2ZsYWdzIHw9IERNQV9QUkVQX0ZFTkNFOw0KPiAtCQlm
b3IgKDs7KSB7DQo+IC0JCQl0eCA9IGRldmljZS0+ZGV2aWNlX3ByZXBfZG1hX3BxX3ZhbChjaGFu
LCBwcSwNCj4gLQkJCQkJCQkgICAgdW5tYXAtPmFkZHIsDQo+IC0JCQkJCQkJICAgIHNyY19jbnQs
DQo+IC0JCQkJCQkJICAgIGNvZWZzLA0KPiAtCQkJCQkJCSAgICBsZW4sIHBxcmVzLA0KPiAtCQkJ
CQkJCSAgICBkbWFfZmxhZ3MpOw0KPiAtCQkJaWYgKGxpa2VseSh0eCkpDQo+IC0JCQkJYnJlYWs7
DQo+IC0JCQlhc3luY190eF9xdWllc2NlKCZzdWJtaXQtPmRlcGVuZF90eCk7DQo+IC0JCQlkbWFf
YXN5bmNfaXNzdWVfcGVuZGluZyhjaGFuKTsNCj4gLQkJfQ0KPiArCQkJaWYgKHN1Ym1pdC0+Zmxh
Z3MgJiBBU1lOQ19UWF9GRU5DRSkNCj4gKwkJCQlkbWFfZmxhZ3MgfD0gRE1BX1BSRVBfRkVOQ0U7
DQo+ICsJCQlmb3IgKDs7KSB7DQo+ICsJCQkJdHggPSBkZXZpY2UtPmRldmljZV9wcmVwX2RtYV9w
cV92YWwoY2hhbiwgcHEsDQo+ICsJCQkJCQkJCSAgICB1bm1hcC0+YWRkciwNCj4gKwkJCQkJCQkJ
ICAgIHNyY19jbnQsDQo+ICsJCQkJCQkJCSAgICBjb2VmcywNCj4gKwkJCQkJCQkJICAgIGxlbiwg
cHFyZXMsDQo+ICsJCQkJCQkJCSAgICBkbWFfZmxhZ3MpOw0KPiArCQkJCWlmIChsaWtlbHkodHgp
KQ0KPiArCQkJCQlicmVhazsNCj4gKwkJCQlhc3luY190eF9xdWllc2NlKCZzdWJtaXQtPmRlcGVu
ZF90eCk7DQo+ICsJCQkJZG1hX2FzeW5jX2lzc3VlX3BlbmRpbmcoY2hhbik7DQo+ICsJCQl9DQo+
ICANCj4gLQkJZG1hX3NldF91bm1hcCh0eCwgdW5tYXApOw0KPiAtCQlhc3luY190eF9zdWJtaXQo
Y2hhbiwgdHgsIHN1Ym1pdCk7DQo+ICsJCQlkbWFfc2V0X3VubWFwKHR4LCB1bm1hcCk7DQo+ICsJ
CQlhc3luY190eF9zdWJtaXQoY2hhbiwgdHgsIHN1Ym1pdCk7DQo+ICANCj4gLQkJcmV0dXJuIHR4
Ow0KPiArCQkJcmV0dXJuIHR4Ow0KPiArCQl9DQo+ICAJfSBlbHNlIHsNCj4gIAkJc3RydWN0IHBh
Z2UgKnBfc3JjID0gUChibG9ja3MsIGRpc2tzKTsNCj4gIAkJc3RydWN0IHBhZ2UgKnFfc3JjID0g
UShibG9ja3MsIGRpc2tzKTsgQEAgLTQxMSw5ICs0MTgsOSBAQCANCj4gYXN5bmNfc3luZHJvbWVf
dmFsKHN0cnVjdCBwYWdlICoqYmxvY2tzLCB1bnNpZ25lZCBpbnQgb2Zmc2V0LCBpbnQgZGlza3Ms
DQo+ICAJCXN1Ym1pdC0+Y2JfcGFyYW0gPSBjYl9wYXJhbV9vcmlnOw0KPiAgCQlzdWJtaXQtPmZs
YWdzID0gZmxhZ3Nfb3JpZzsNCj4gIAkJYXN5bmNfdHhfc3luY19lcGlsb2coc3VibWl0KTsNCj4g
LQ0KPiAtCQlyZXR1cm4gTlVMTDsNCj4gIAl9DQo+ICsNCj4gKwlyZXR1cm4gTlVMTDsNCj4gIH0N
Cj4gIEVYUE9SVF9TWU1CT0xfR1BMKGFzeW5jX3N5bmRyb21lX3ZhbCk7DQo+ICANCj4gZGlmZiAt
LWdpdCBhL2NyeXB0by9hc3luY190eC9hc3luY19yYWlkNl9yZWNvdi5jIA0KPiBiL2NyeXB0by9h
c3luY190eC9hc3luY19yYWlkNl9yZWNvdi5jDQo+IGluZGV4IDkzNGE4NDkuLmM1NWQ4ZjEgMTAw
NjQ0DQo+IC0tLSBhL2NyeXB0by9hc3luY190eC9hc3luY19yYWlkNl9yZWNvdi5jDQo+ICsrKyBi
L2NyeXB0by9hc3luY190eC9hc3luY19yYWlkNl9yZWNvdi5jDQo+IEBAIC00MCwxMCArNDAsNyBA
QCBhc3luY19zdW1fcHJvZHVjdChzdHJ1Y3QgcGFnZSAqZGVzdCwgc3RydWN0IHBhZ2UgKipzcmNz
LCB1bnNpZ25lZCBjaGFyICpjb2VmLA0KPiAgCXU4IGF4LCBieDsNCj4gIAl1OCAqYSwgKmIsICpj
Ow0KPiAgDQo+IC0JaWYgKGRtYSkNCj4gLQkJdW5tYXAgPSBkbWFlbmdpbmVfZ2V0X3VubWFwX2Rh
dGEoZG1hLT5kZXYsIDMsIEdGUF9OT0lPKTsNCj4gLQ0KPiAtCWlmICh1bm1hcCkgew0KPiArCWlm
IChkbWEpIHsNCj4gIAkJc3RydWN0IGRldmljZSAqZGV2ID0gZG1hLT5kZXY7DQo+ICAJCWRtYV9h
ZGRyX3QgcHFbMl07DQo+ICAJCXN0cnVjdCBkbWFfYXN5bmNfdHhfZGVzY3JpcHRvciAqdHg7IEBA
IC01MSwyOSArNDgsMzUgQEAgDQo+IGFzeW5jX3N1bV9wcm9kdWN0KHN0cnVjdCBwYWdlICpkZXN0
LCBzdHJ1Y3QgcGFnZSAqKnNyY3MsIHVuc2lnbmVkIGNoYXIgDQo+ICpjb2VmLA0KPiAgDQo+ICAJ
CWlmIChzdWJtaXQtPmZsYWdzICYgQVNZTkNfVFhfRkVOQ0UpDQo+ICAJCQlkbWFfZmxhZ3MgfD0g
RE1BX1BSRVBfRkVOQ0U7DQo+IC0JCXVubWFwLT5hZGRyWzBdID0gZG1hX21hcF9wYWdlKGRldiwg
c3Jjc1swXSwgMCwgbGVuLCBETUFfVE9fREVWSUNFKTsNCj4gLQkJdW5tYXAtPmFkZHJbMV0gPSBk
bWFfbWFwX3BhZ2UoZGV2LCBzcmNzWzFdLCAwLCBsZW4sIERNQV9UT19ERVZJQ0UpOw0KPiAtCQl1
bm1hcC0+dG9fY250ID0gMjsNCj4gLQ0KPiAtCQl1bm1hcC0+YWRkclsyXSA9IGRtYV9tYXBfcGFn
ZShkZXYsIGRlc3QsIDAsIGxlbiwgRE1BX0JJRElSRUNUSU9OQUwpOw0KPiAtCQl1bm1hcC0+Ymlk
aV9jbnQgPSAxOw0KPiAtCQkvKiBlbmdpbmUgb25seSBsb29rcyBhdCBRLCBidXQgZXhwZWN0cyBp
dCB0byBmb2xsb3cgUCAqLw0KPiAtCQlwcVsxXSA9IHVubWFwLT5hZGRyWzJdOw0KPiAtDQo+IC0J
CXVubWFwLT5sZW4gPSBsZW47DQo+IC0JCXR4ID0gZG1hLT5kZXZpY2VfcHJlcF9kbWFfcHEoY2hh
biwgcHEsIHVubWFwLT5hZGRyLCAyLCBjb2VmLA0KPiAtCQkJCQkgICAgIGxlbiwgZG1hX2ZsYWdz
KTsNCj4gLQkJaWYgKHR4KSB7DQo+IC0JCQlkbWFfc2V0X3VubWFwKHR4LCB1bm1hcCk7DQo+IC0J
CQlhc3luY190eF9zdWJtaXQoY2hhbiwgdHgsIHN1Ym1pdCk7DQo+ICsNCj4gKwkJdW5tYXAgPSBk
bWFlbmdpbmVfZ2V0X3VubWFwX2RhdGEoZG1hLT5kZXYsIDMsIEdGUF9OT0lPKTsNCj4gKwkJaWYg
KHVubWFwKSB7DQo+ICsJCQl1bm1hcC0+YWRkclswXSA9IGRtYV9tYXBfcGFnZShkZXYsIHNyY3Nb
MF0sIDAsIGxlbiwNCj4gKwkJCQkJCSAgICAgIERNQV9UT19ERVZJQ0UpOw0KPiArCQkJdW5tYXAt
PmFkZHJbMV0gPSBkbWFfbWFwX3BhZ2UoZGV2LCBzcmNzWzFdLCAwLCBsZW4sDQo+ICsJCQkJCQkg
ICAgICBETUFfVE9fREVWSUNFKTsNCj4gKwkJCXVubWFwLT50b19jbnQgPSAyOw0KPiArDQo+ICsJ
CQl1bm1hcC0+YWRkclsyXSA9IGRtYV9tYXBfcGFnZShkZXYsIGRlc3QsIDAsIGxlbiwNCj4gKwkJ
CQkJCSAgICAgIERNQV9CSURJUkVDVElPTkFMKTsNCj4gKwkJCXVubWFwLT5iaWRpX2NudCA9IDE7
DQo+ICsJCQkvKiBlbmdpbmUgb25seSBsb29rcyBhdCBRLCBidXQgZXhwZWN0cyBpdCB0byBmb2xs
b3cgUCAqLw0KPiArCQkJcHFbMV0gPSB1bm1hcC0+YWRkclsyXTsNCj4gKw0KPiArCQkJdW5tYXAt
PmxlbiA9IGxlbjsNCj4gKwkJCXR4ID0gZG1hLT5kZXZpY2VfcHJlcF9kbWFfcHEoY2hhbiwgcHEs
IHVubWFwLT5hZGRyLCAyLA0KPiArCQkJCQkJICAgICBjb2VmLCBsZW4sIGRtYV9mbGFncyk7DQo+
ICsJCQlpZiAodHgpIHsNCj4gKwkJCQlkbWFfc2V0X3VubWFwKHR4LCB1bm1hcCk7DQo+ICsJCQkJ
YXN5bmNfdHhfc3VibWl0KGNoYW4sIHR4LCBzdWJtaXQpOw0KPiArCQkJCXJldHVybiB0eDsNCj4g
KwkJCX0NCj4gKw0KPiArCQkJLyogY291bGQgbm90IGdldCBhIGRlc2NyaXB0b3IsIHVubWFwIGFu
ZCBmYWxsIHRocm91Z2ggdG8NCj4gKwkJCSAqIHRoZSBzeW5jaHJvbm91cyBwYXRoDQo+ICsJCQkg
Ki8NCj4gIAkJCWRtYWVuZ2luZV91bm1hcF9wdXQodW5tYXApOw0KPiAtCQkJcmV0dXJuIHR4Ow0K
PiAgCQl9DQo+IC0NCj4gLQkJLyogY291bGQgbm90IGdldCBhIGRlc2NyaXB0b3IsIHVubWFwIGFu
ZCBmYWxsIHRocm91Z2ggdG8NCj4gLQkJICogdGhlIHN5bmNocm9ub3VzIHBhdGgNCj4gLQkJICov
DQo+IC0JCWRtYWVuZ2luZV91bm1hcF9wdXQodW5tYXApOw0KPiAgCX0NCj4gIA0KPiAgCS8qIHJ1
biB0aGUgb3BlcmF0aW9uIHN5bmNocm9ub3VzbHkgKi8gQEAgLTEwNCwxMCArMTA3LDcgQEAgDQo+
IGFzeW5jX211bHQoc3RydWN0IHBhZ2UgKmRlc3QsIHN0cnVjdCBwYWdlICpzcmMsIHU4IGNvZWYs
IHNpemVfdCBsZW4sDQo+ICAJY29uc3QgdTggKnFtdWw7IC8qIFEgbXVsdGlwbGllciB0YWJsZSAq
Lw0KPiAgCXU4ICpkLCAqczsNCj4gIA0KPiAtCWlmIChkbWEpDQo+IC0JCXVubWFwID0gZG1hZW5n
aW5lX2dldF91bm1hcF9kYXRhKGRtYS0+ZGV2LCAzLCBHRlBfTk9JTyk7DQo+IC0NCj4gLQlpZiAo
dW5tYXApIHsNCj4gKwlpZiAoZG1hKSB7DQo+ICAJCWRtYV9hZGRyX3QgZG1hX2Rlc3RbMl07DQo+
ICAJCXN0cnVjdCBkZXZpY2UgKmRldiA9IGRtYS0+ZGV2Ow0KPiAgCQlzdHJ1Y3QgZG1hX2FzeW5j
X3R4X2Rlc2NyaXB0b3IgKnR4OyBAQCAtMTE1LDMxICsxMTUsMzcgQEAgDQo+IGFzeW5jX211bHQo
c3RydWN0IHBhZ2UgKmRlc3QsIHN0cnVjdCBwYWdlICpzcmMsIHU4IGNvZWYsIHNpemVfdCBsZW4s
DQo+ICANCj4gIAkJaWYgKHN1Ym1pdC0+ZmxhZ3MgJiBBU1lOQ19UWF9GRU5DRSkNCj4gIAkJCWRt
YV9mbGFncyB8PSBETUFfUFJFUF9GRU5DRTsNCj4gLQkJdW5tYXAtPmFkZHJbMF0gPSBkbWFfbWFw
X3BhZ2UoZGV2LCBzcmMsIDAsIGxlbiwgRE1BX1RPX0RFVklDRSk7DQo+IC0JCXVubWFwLT50b19j
bnQrKzsNCj4gLQkJdW5tYXAtPmFkZHJbMV0gPSBkbWFfbWFwX3BhZ2UoZGV2LCBkZXN0LCAwLCBs
ZW4sIERNQV9CSURJUkVDVElPTkFMKTsNCj4gLQkJZG1hX2Rlc3RbMV0gPSB1bm1hcC0+YWRkclsx
XTsNCj4gLQkJdW5tYXAtPmJpZGlfY250Kys7DQo+IC0JCXVubWFwLT5sZW4gPSBsZW47DQo+IC0N
Cj4gLQkJLyogdGhpcyBsb29rcyBmdW5ueSwgYnV0IHRoZSBlbmdpbmUgbG9va3MgZm9yIFEgYXQN
Cj4gLQkJICogZG1hX2Rlc3RbMV0gYW5kIGlnbm9yZXMgZG1hX2Rlc3RbMF0gYXMgYSBkZXN0DQo+
IC0JCSAqIGR1ZSB0byBETUFfUFJFUF9QUV9ESVNBQkxFX1ANCj4gLQkJICovDQo+IC0JCXR4ID0g
ZG1hLT5kZXZpY2VfcHJlcF9kbWFfcHEoY2hhbiwgZG1hX2Rlc3QsIHVubWFwLT5hZGRyLA0KPiAt
CQkJCQkgICAgIDEsICZjb2VmLCBsZW4sIGRtYV9mbGFncyk7DQo+ICANCj4gLQkJaWYgKHR4KSB7
DQo+IC0JCQlkbWFfc2V0X3VubWFwKHR4LCB1bm1hcCk7DQo+ICsJCXVubWFwID0gZG1hZW5naW5l
X2dldF91bm1hcF9kYXRhKGRtYS0+ZGV2LCAzLCBHRlBfTk9JTyk7DQo+ICsJCWlmICh1bm1hcCkg
ew0KPiArCQkJdW5tYXAtPmFkZHJbMF0gPSBkbWFfbWFwX3BhZ2UoZGV2LCBzcmMsIDAsIGxlbiwN
Cj4gKwkJCQkJCSAgICAgIERNQV9UT19ERVZJQ0UpOw0KPiArCQkJdW5tYXAtPnRvX2NudCsrOw0K
PiArCQkJdW5tYXAtPmFkZHJbMV0gPSBkbWFfbWFwX3BhZ2UoZGV2LCBkZXN0LCAwLCBsZW4sDQo+
ICsJCQkJCQkgICAgICBETUFfQklESVJFQ1RJT05BTCk7DQo+ICsJCQlkbWFfZGVzdFsxXSA9IHVu
bWFwLT5hZGRyWzFdOw0KPiArCQkJdW5tYXAtPmJpZGlfY250Kys7DQo+ICsJCQl1bm1hcC0+bGVu
ID0gbGVuOw0KPiArDQo+ICsJCQkvKiB0aGlzIGxvb2tzIGZ1bm55LCBidXQgdGhlIGVuZ2luZSBs
b29rcyBmb3IgUSBhdA0KPiArCQkJICogZG1hX2Rlc3RbMV0gYW5kIGlnbm9yZXMgZG1hX2Rlc3Rb
MF0gYXMgYSBkZXN0DQo+ICsJCQkgKiBkdWUgdG8gRE1BX1BSRVBfUFFfRElTQUJMRV9QDQo+ICsJ
CQkgKi8NCj4gKwkJCXR4ID0gZG1hLT5kZXZpY2VfcHJlcF9kbWFfcHEoY2hhbiwgZG1hX2Rlc3Qs
DQo+ICsJCQkJCQkgICAgIHVubWFwLT5hZGRyLCAxLCAmY29lZiwNCj4gKwkJCQkJCSAgICAgbGVu
LCBkbWFfZmxhZ3MpOw0KPiArDQo+ICsJCQlpZiAodHgpIHsNCj4gKwkJCQlkbWFfc2V0X3VubWFw
KHR4LCB1bm1hcCk7DQo+ICsJCQkJYXN5bmNfdHhfc3VibWl0KGNoYW4sIHR4LCBzdWJtaXQpOw0K
PiArCQkJCXJldHVybiB0eDsNCj4gKwkJCX0NCj4gKw0KPiArCQkJLyogY291bGQgbm90IGdldCBh
IGRlc2NyaXB0b3IsIHVubWFwIGFuZCBmYWxsIHRocm91Z2ggdG8NCj4gKwkJCSAqIHRoZSBzeW5j
aHJvbm91cyBwYXRoDQo+ICsJCQkgKi8NCj4gIAkJCWRtYWVuZ2luZV91bm1hcF9wdXQodW5tYXAp
Ow0KPiAtCQkJYXN5bmNfdHhfc3VibWl0KGNoYW4sIHR4LCBzdWJtaXQpOw0KPiAtCQkJcmV0dXJu
IHR4Ow0KPiAgCQl9DQo+IC0NCj4gLQkJLyogY291bGQgbm90IGdldCBhIGRlc2NyaXB0b3IsIHVu
bWFwIGFuZCBmYWxsIHRocm91Z2ggdG8NCj4gLQkJICogdGhlIHN5bmNocm9ub3VzIHBhdGgNCj4g
LQkJICovDQo+IC0JCWRtYWVuZ2luZV91bm1hcF9wdXQodW5tYXApOw0KPiAgCX0NCj4gIA0KPiAg
CS8qIG5vIGNoYW5uZWwgYXZhaWxhYmxlLCBvciBmYWlsZWQgdG8gYWxsb2NhdGUgYSBkZXNjcmlw
dG9yLCBzbyBkaWZmIA0KPiAtLWdpdCBhL2NyeXB0by9hc3luY190eC9hc3luY194b3IuYyBiL2Ny
eXB0by9hc3luY190eC9hc3luY194b3IuYyANCj4gaW5kZXggM2M1NjJmNS4uMDE5ZTQ2OSAxMDA2
NDQNCj4gLS0tIGEvY3J5cHRvL2FzeW5jX3R4L2FzeW5jX3hvci5jDQo+ICsrKyBiL2NyeXB0by9h
c3luY190eC9hc3luY194b3IuYw0KPiBAQCAtMTgyLDU1ICsxODIsNTcgQEAgYXN5bmNfeG9yKHN0
cnVjdCBwYWdlICpkZXN0LCBzdHJ1Y3QgcGFnZSANCj4gKipzcmNfbGlzdCwgdW5zaWduZWQgaW50
IG9mZnNldCwNCj4gIA0KPiAgCUJVR19PTihzcmNfY250IDw9IDEpOw0KPiAgDQo+IC0JaWYgKGRl
dmljZSkNCj4gLQkJdW5tYXAgPSBkbWFlbmdpbmVfZ2V0X3VubWFwX2RhdGEoZGV2aWNlLT5kZXYs
IHNyY19jbnQrMSwgR0ZQX05PSU8pOw0KPiAtDQo+IC0JaWYgKHVubWFwICYmIGlzX2RtYV94b3Jf
YWxpZ25lZChkZXZpY2UsIG9mZnNldCwgMCwgbGVuKSkgew0KPiArCWlmIChkZXZpY2UgJiYgaXNf
ZG1hX3hvcl9hbGlnbmVkKGRldmljZSwgb2Zmc2V0LCAwLCBsZW4pKSB7DQo+ICAJCXN0cnVjdCBk
bWFfYXN5bmNfdHhfZGVzY3JpcHRvciAqdHg7DQo+ICAJCWludCBpLCBqOw0KPiAgDQo+ICAJCS8q
IHJ1biB0aGUgeG9yIGFzeW5jaHJvbm91c2x5ICovDQo+ICAJCXByX2RlYnVnKCIlcyAoYXN5bmMp
OiBsZW46ICV6dVxuIiwgX19mdW5jX18sIGxlbik7DQo+ICANCj4gLQkJdW5tYXAtPmxlbiA9IGxl
bjsNCj4gLQkJZm9yIChpID0gMCwgaiA9IDA7IGkgPCBzcmNfY250OyBpKyspIHsNCj4gLQkJCWlm
ICghc3JjX2xpc3RbaV0pDQo+IC0JCQkJY29udGludWU7DQo+IC0JCQl1bm1hcC0+dG9fY250Kys7
DQo+IC0JCQl1bm1hcC0+YWRkcltqKytdID0gZG1hX21hcF9wYWdlKGRldmljZS0+ZGV2LCBzcmNf
bGlzdFtpXSwNCj4gLQkJCQkJCQlvZmZzZXQsIGxlbiwgRE1BX1RPX0RFVklDRSk7DQo+IC0JCX0N
Cj4gKwkJdW5tYXAgPSBkbWFlbmdpbmVfZ2V0X3VubWFwX2RhdGEoZGV2aWNlLT5kZXYsIHNyY19j
bnQgKyAxLA0KPiArCQkJCQkJIEdGUF9OT0lPKTsNCj4gKwkJaWYgKHVubWFwKSB7DQo+ICsJCQl1
bm1hcC0+bGVuID0gbGVuOw0KPiArCQkJZm9yIChpID0gMCwgaiA9IDA7IGkgPCBzcmNfY250OyBp
KyspIHsNCj4gKwkJCQlpZiAoIXNyY19saXN0W2ldKQ0KPiArCQkJCQljb250aW51ZTsNCj4gKwkJ
CQl1bm1hcC0+dG9fY250Kys7DQo+ICsJCQkJdW5tYXAtPmFkZHJbaisrXSA9IGRtYV9tYXBfcGFn
ZShkZXZpY2UtPmRldiwNCj4gKwkJCQkJCQkJc3JjX2xpc3RbaV0sDQo+ICsJCQkJCQkJCW9mZnNl
dCwgbGVuLA0KPiArCQkJCQkJCQlETUFfVE9fREVWSUNFKTsNCj4gKwkJCX0NCj4gIA0KPiAtCQkv
KiBtYXAgaXQgYmlkaXJlY3Rpb25hbCBhcyBpdCBtYXkgYmUgcmUtdXNlZCBhcyBhIHNvdXJjZSAq
Lw0KPiAtCQl1bm1hcC0+YWRkcltqXSA9IGRtYV9tYXBfcGFnZShkZXZpY2UtPmRldiwgZGVzdCwg
b2Zmc2V0LCBsZW4sDQo+IC0JCQkJCSAgICAgIERNQV9CSURJUkVDVElPTkFMKTsNCj4gLQkJdW5t
YXAtPmJpZGlfY250ID0gMTsNCj4gLQ0KPiAtCQl0eCA9IGRvX2FzeW5jX3hvcihjaGFuLCB1bm1h
cCwgc3VibWl0KTsNCj4gLQkJZG1hZW5naW5lX3VubWFwX3B1dCh1bm1hcCk7DQo+IC0JCXJldHVy
biB0eDsNCj4gLQl9IGVsc2Ugew0KPiAtCQlkbWFlbmdpbmVfdW5tYXBfcHV0KHVubWFwKTsNCj4g
LQkJLyogcnVuIHRoZSB4b3Igc3luY2hyb25vdXNseSAqLw0KPiAtCQlwcl9kZWJ1ZygiJXMgKHN5
bmMpOiBsZW46ICV6dVxuIiwgX19mdW5jX18sIGxlbik7DQo+IC0JCVdBUk5fT05DRShjaGFuLCAi
JXM6IG5vIHNwYWNlIGZvciBkbWEgYWRkcmVzcyBjb252ZXJzaW9uXG4iLA0KPiAtCQkJICBfX2Z1
bmNfXyk7DQo+IC0NCj4gLQkJLyogaW4gdGhlIHN5bmMgY2FzZSB0aGUgZGVzdCBpcyBhbiBpbXBs
aWVkIHNvdXJjZQ0KPiAtCQkgKiAoYXNzdW1lcyB0aGUgZGVzdCBpcyB0aGUgZmlyc3Qgc291cmNl
KQ0KPiAtCQkgKi8NCj4gLQkJaWYgKHN1Ym1pdC0+ZmxhZ3MgJiBBU1lOQ19UWF9YT1JfRFJPUF9E
U1QpIHsNCj4gLQkJCXNyY19jbnQtLTsNCj4gLQkJCXNyY19saXN0Kys7DQo+ICsJCQkvKiBtYXAg
aXQgYmlkaXJlY3Rpb25hbCBhcyBpdCBtYXkgYmUgcmUtdXNlZA0KPiArCQkJICAgYXMgYSBzb3Vy
Y2UgKi8NCj4gKwkJCXVubWFwLT5hZGRyW2pdID0gZG1hX21hcF9wYWdlKGRldmljZS0+ZGV2LCBk
ZXN0LCBvZmZzZXQsDQo+ICsJCQkJCQkgICAgICBsZW4sIERNQV9CSURJUkVDVElPTkFMKTsNCj4g
KwkJCXVubWFwLT5iaWRpX2NudCA9IDE7DQo+ICsNCj4gKwkJCXR4ID0gZG9fYXN5bmNfeG9yKGNo
YW4sIHVubWFwLCBzdWJtaXQpOw0KPiArCQkJcmV0dXJuIHR4Ow0KPiAgCQl9DQo+ICsJfQ0KPiAg
DQo+IC0JCS8qIHdhaXQgZm9yIGFueSBwcmVyZXF1aXNpdGUgb3BlcmF0aW9ucyAqLw0KPiAtCQlh
c3luY190eF9xdWllc2NlKCZzdWJtaXQtPmRlcGVuZF90eCk7DQo+ICsJLyogcnVuIHRoZSB4b3Ig
c3luY2hyb25vdXNseSAqLw0KPiArCXByX2RlYnVnKCIlcyAoc3luYyk6IGxlbjogJXp1XG4iLCBf
X2Z1bmNfXywgbGVuKTsNCj4gKwlXQVJOX09OQ0UoY2hhbiwgIiVzOiBubyBzcGFjZSBmb3IgZG1h
IGFkZHJlc3MgY29udmVyc2lvblxuIiwNCj4gKwkJICBfX2Z1bmNfXyk7DQo+ICsNCj4gKwkvKiBp
biB0aGUgc3luYyBjYXNlIHRoZSBkZXN0IGlzIGFuIGltcGxpZWQgc291cmNlDQo+ICsJICogKGFz
c3VtZXMgdGhlIGRlc3QgaXMgdGhlIGZpcnN0IHNvdXJjZSkNCj4gKwkgKi8NCj4gKwlpZiAoc3Vi
bWl0LT5mbGFncyAmIEFTWU5DX1RYX1hPUl9EUk9QX0RTVCkgew0KPiArCQlzcmNfY250LS07DQo+
ICsJCXNyY19saXN0Kys7DQo+ICsJfQ0KPiAgDQo+IC0JCWRvX3N5bmNfeG9yKGRlc3QsIHNyY19s
aXN0LCBvZmZzZXQsIHNyY19jbnQsIGxlbiwgc3VibWl0KTsNCj4gKwkvKiB3YWl0IGZvciBhbnkg
cHJlcmVxdWlzaXRlIG9wZXJhdGlvbnMgKi8NCj4gKwlhc3luY190eF9xdWllc2NlKCZzdWJtaXQt
PmRlcGVuZF90eCk7DQo+ICANCj4gLQkJcmV0dXJuIE5VTEw7DQo+IC0JfQ0KPiArCWRvX3N5bmNf
eG9yKGRlc3QsIHNyY19saXN0LCBvZmZzZXQsIHNyY19jbnQsIGxlbiwgc3VibWl0KTsNCj4gKw0K
PiArCXJldHVybiBOVUxMOw0KPiAgfQ0KPiAgRVhQT1JUX1NZTUJPTF9HUEwoYXN5bmNfeG9yKTsN
Cj4gIA0KPiBAQCAtMjc1LDEzICsyNzcsMTEgQEAgYXN5bmNfeG9yX3ZhbChzdHJ1Y3QgcGFnZSAq
ZGVzdCwgc3RydWN0IHBhZ2UgKipzcmNfbGlzdCwgdW5zaWduZWQgaW50IG9mZnNldCwNCj4gIAlz
dHJ1Y3QgZG1hX2RldmljZSAqZGV2aWNlID0gY2hhbiA/IGNoYW4tPmRldmljZSA6IE5VTEw7DQo+
ICAJc3RydWN0IGRtYV9hc3luY190eF9kZXNjcmlwdG9yICp0eCA9IE5VTEw7DQo+ICAJc3RydWN0
IGRtYWVuZ2luZV91bm1hcF9kYXRhICp1bm1hcCA9IE5VTEw7DQo+ICsJZW51bSBhc3luY190eF9m
bGFncyBmbGFnc19vcmlnID0gc3VibWl0LT5mbGFnczsNCj4gIA0KPiAgCUJVR19PTihzcmNfY250
IDw9IDEpOw0KPiAgDQo+IC0JaWYgKGRldmljZSkNCj4gLQkJdW5tYXAgPSBkbWFlbmdpbmVfZ2V0
X3VubWFwX2RhdGEoZGV2aWNlLT5kZXYsIHNyY19jbnQsIEdGUF9OT0lPKTsNCj4gLQ0KPiAtCWlm
ICh1bm1hcCAmJiBzcmNfY250IDw9IGRldmljZS0+bWF4X3hvciAmJg0KPiArCWlmIChkZXZpY2Ug
JiYgc3JjX2NudCA8PSBkZXZpY2UtPm1heF94b3IgJiYNCj4gIAkgICAgaXNfZG1hX3hvcl9hbGln
bmVkKGRldmljZSwgb2Zmc2V0LCAwLCBsZW4pKSB7DQo+ICAJCXVuc2lnbmVkIGxvbmcgZG1hX3By
ZXBfZmxhZ3MgPSAwOw0KPiAgCQlpbnQgaTsNCj4gQEAgLTI5Myw1MSArMjkzLDU5IEBAIGFzeW5j
X3hvcl92YWwoc3RydWN0IHBhZ2UgKmRlc3QsIHN0cnVjdCBwYWdlICoqc3JjX2xpc3QsIHVuc2ln
bmVkIGludCBvZmZzZXQsDQo+ICAJCWlmIChzdWJtaXQtPmZsYWdzICYgQVNZTkNfVFhfRkVOQ0Up
DQo+ICAJCQlkbWFfcHJlcF9mbGFncyB8PSBETUFfUFJFUF9GRU5DRTsNCj4gIA0KPiAtCQlmb3Ig
KGkgPSAwOyBpIDwgc3JjX2NudDsgaSsrKSB7DQo+IC0JCQl1bm1hcC0+YWRkcltpXSA9IGRtYV9t
YXBfcGFnZShkZXZpY2UtPmRldiwgc3JjX2xpc3RbaV0sDQo+IC0JCQkJCQkgICAgICBvZmZzZXQs
IGxlbiwgRE1BX1RPX0RFVklDRSk7DQo+IC0JCQl1bm1hcC0+dG9fY250Kys7DQo+IC0JCX0NCj4g
LQkJdW5tYXAtPmxlbiA9IGxlbjsNCj4gLQ0KPiAtCQl0eCA9IGRldmljZS0+ZGV2aWNlX3ByZXBf
ZG1hX3hvcl92YWwoY2hhbiwgdW5tYXAtPmFkZHIsIHNyY19jbnQsDQo+IC0JCQkJCQkgICAgIGxl
biwgcmVzdWx0LA0KPiAtCQkJCQkJICAgICBkbWFfcHJlcF9mbGFncyk7DQo+IC0JCWlmICh1bmxp
a2VseSghdHgpKSB7DQo+IC0JCQlhc3luY190eF9xdWllc2NlKCZzdWJtaXQtPmRlcGVuZF90eCk7
DQo+IC0NCj4gLQkJCXdoaWxlICghdHgpIHsNCj4gLQkJCQlkbWFfYXN5bmNfaXNzdWVfcGVuZGlu
ZyhjaGFuKTsNCj4gLQkJCQl0eCA9IGRldmljZS0+ZGV2aWNlX3ByZXBfZG1hX3hvcl92YWwoY2hh
biwNCj4gLQkJCQkJdW5tYXAtPmFkZHIsIHNyY19jbnQsIGxlbiwgcmVzdWx0LA0KPiAtCQkJCQlk
bWFfcHJlcF9mbGFncyk7DQo+ICsJCXVubWFwID0gZG1hZW5naW5lX2dldF91bm1hcF9kYXRhKGRl
dmljZS0+ZGV2LCBzcmNfY250LA0KPiArCQkJCQkJIEdGUF9OT0lPKTsNCj4gKwkJaWYgKHVubWFw
KSB7DQo+ICsJCQlmb3IgKGkgPSAwOyBpIDwgc3JjX2NudDsgaSsrKSB7DQo+ICsJCQkJdW5tYXAt
PmFkZHJbaV0gPSBkbWFfbWFwX3BhZ2UoZGV2aWNlLT5kZXYsDQo+ICsJCQkJCQkJICAgICAgc3Jj
X2xpc3RbaV0sDQo+ICsJCQkJCQkJICAgICAgb2Zmc2V0LCBsZW4sDQo+ICsJCQkJCQkJICAgICAg
RE1BX1RPX0RFVklDRSk7DQo+ICsJCQkJdW5tYXAtPnRvX2NudCsrOw0KPiArCQkJfQ0KPiArCQkJ
dW5tYXAtPmxlbiA9IGxlbjsNCj4gKw0KPiArCQkJdHggPSBkZXZpY2UtPmRldmljZV9wcmVwX2Rt
YV94b3JfdmFsKGNoYW4sIHVubWFwLT5hZGRyLA0KPiArCQkJCQkJCSAgICAgc3JjX2NudCwNCj4g
KwkJCQkJCQkgICAgIGxlbiwgcmVzdWx0LA0KPiArCQkJCQkJCSAgICAgZG1hX3ByZXBfZmxhZ3Mp
Ow0KPiArCQkJaWYgKHVubGlrZWx5KCF0eCkpIHsNCj4gKwkJCQlhc3luY190eF9xdWllc2NlKCZz
dWJtaXQtPmRlcGVuZF90eCk7DQo+ICsNCj4gKwkJCQl3aGlsZSAoIXR4KSB7DQo+ICsJCQkJCWRt
YV9hc3luY19pc3N1ZV9wZW5kaW5nKGNoYW4pOw0KPiArCQkJCQl0eCA9IGRldmljZS0+ZGV2aWNl
X3ByZXBfZG1hX3hvcl92YWwoDQo+ICsJCQkJCQkJY2hhbiwgdW5tYXAtPmFkZHIsDQo+ICsJCQkJ
CQkJc3JjX2NudCwgbGVuLA0KPiArCQkJCQkJCXJlc3VsdCwgZG1hX3ByZXBfZmxhZ3MpOw0KPiAr
CQkJCX0NCj4gIAkJCX0NCj4gKwkJCWRtYV9zZXRfdW5tYXAodHgsIHVubWFwKTsNCj4gKwkJCWFz
eW5jX3R4X3N1Ym1pdChjaGFuLCB0eCwgc3VibWl0KTsNCj4gKw0KPiArCQkJcmV0dXJuIHR4Ow0K
PiAgCQl9DQo+IC0JCWRtYV9zZXRfdW5tYXAodHgsIHVubWFwKTsNCj4gLQkJYXN5bmNfdHhfc3Vi
bWl0KGNoYW4sIHR4LCBzdWJtaXQpOw0KPiAtCX0gZWxzZSB7DQo+IC0JCWVudW0gYXN5bmNfdHhf
ZmxhZ3MgZmxhZ3Nfb3JpZyA9IHN1Ym1pdC0+ZmxhZ3M7DQo+ICsJfQ0KPiAgDQo+IC0JCXByX2Rl
YnVnKCIlczogKHN5bmMpIGxlbjogJXp1XG4iLCBfX2Z1bmNfXywgbGVuKTsNCj4gLQkJV0FSTl9P
TkNFKGRldmljZSAmJiBzcmNfY250IDw9IGRldmljZS0+bWF4X3hvciwNCj4gLQkJCSAgIiVzOiBu
byBzcGFjZSBmb3IgZG1hIGFkZHJlc3MgY29udmVyc2lvblxuIiwNCj4gLQkJCSAgX19mdW5jX18p
Ow0KPiArCS8qIHJ1biB0aGUgeG9yX3ZhbCBzeW5jaHJvbm91c2x5ICovDQo+ICsJcHJfZGVidWco
IiVzOiAoc3luYykgbGVuOiAlenVcbiIsIF9fZnVuY19fLCBsZW4pOw0KPiArCVdBUk5fT05DRShk
ZXZpY2UgJiYgc3JjX2NudCA8PSBkZXZpY2UtPm1heF94b3IsDQo+ICsJCSAgIiVzOiBubyBzcGFj
ZSBmb3IgZG1hIGFkZHJlc3MgY29udmVyc2lvblxuIiwNCj4gKwkJICBfX2Z1bmNfXyk7DQo+ICAN
Cj4gLQkJc3VibWl0LT5mbGFncyB8PSBBU1lOQ19UWF9YT1JfRFJPUF9EU1Q7DQo+IC0JCXN1Ym1p
dC0+ZmxhZ3MgJj0gfkFTWU5DX1RYX0FDSzsNCj4gKwlzdWJtaXQtPmZsYWdzIHw9IEFTWU5DX1RY
X1hPUl9EUk9QX0RTVDsNCj4gKwlzdWJtaXQtPmZsYWdzICY9IH5BU1lOQ19UWF9BQ0s7DQo+ICAN
Cj4gLQkJdHggPSBhc3luY194b3IoZGVzdCwgc3JjX2xpc3QsIG9mZnNldCwgc3JjX2NudCwgbGVu
LCBzdWJtaXQpOw0KPiArCXR4ID0gYXN5bmNfeG9yKGRlc3QsIHNyY19saXN0LCBvZmZzZXQsIHNy
Y19jbnQsIGxlbiwgc3VibWl0KTsNCj4gIA0KPiAtCQlhc3luY190eF9xdWllc2NlKCZ0eCk7DQo+
ICsJYXN5bmNfdHhfcXVpZXNjZSgmdHgpOw0KPiAgDQo+IC0JCSpyZXN1bHQgPSAhcGFnZV9pc196
ZXJvKGRlc3QsIG9mZnNldCwgbGVuKSA8PCBTVU1fQ0hFQ0tfUDsNCj4gKwkqcmVzdWx0ID0gIXBh
Z2VfaXNfemVybyhkZXN0LCBvZmZzZXQsIGxlbikgPDwgU1VNX0NIRUNLX1A7DQo+ICANCj4gLQkJ
YXN5bmNfdHhfc3luY19lcGlsb2coc3VibWl0KTsNCj4gLQkJc3VibWl0LT5mbGFncyA9IGZsYWdz
X29yaWc7DQo+IC0JfQ0KPiAtCWRtYWVuZ2luZV91bm1hcF9wdXQodW5tYXApOw0KPiArCWFzeW5j
X3R4X3N5bmNfZXBpbG9nKHN1Ym1pdCk7DQo+ICsJc3VibWl0LT5mbGFncyA9IGZsYWdzX29yaWc7
DQo+ICANCj4gLQlyZXR1cm4gdHg7DQo+ICsJcmV0dXJuIE5VTEw7DQo+ICB9DQo+ICBFWFBPUlRf
U1lNQk9MX0dQTChhc3luY194b3JfdmFsKTsNCj4gIA0KDQoNCi0tDQpBbmR5IFNoZXZjaGVua28g
PGFuZHJpeS5zaGV2Y2hlbmtvQGludGVsLmNvbT4gSW50ZWwgRmlubGFuZCBPeQ0KLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tDQpJbnRlbCBGaW5sYW5kIE95DQpSZWdpc3RlcmVkIEFkZHJlc3M6IFBMIDI4MSwgMDAxODEg
SGVsc2lua2kgQnVzaW5lc3MgSWRlbnRpdHkgQ29kZTogMDM1NzYwNiAtIDQgRG9taWNpbGVkIGlu
IEhlbHNpbmtpIA0KDQpUaGlzIGUtbWFpbCBhbmQgYW55IGF0dGFjaG1lbnRzIG1heSBjb250YWlu
IGNvbmZpZGVudGlhbCBtYXRlcmlhbCBmb3IgdGhlIHNvbGUgdXNlIG9mIHRoZSBpbnRlbmRlZCBy
ZWNpcGllbnQocykuIEFueSByZXZpZXcgb3IgZGlzdHJpYnV0aW9uIGJ5IG90aGVycyBpcyBzdHJp
Y3RseSBwcm9oaWJpdGVkLiBJZiB5b3UgYXJlIG5vdCB0aGUgaW50ZW5kZWQgcmVjaXBpZW50LCBw
bGVhc2UgY29udGFjdCB0aGUgc2VuZGVyIGFuZCBkZWxldGUgYWxsIGNvcGllcy4NCg==
^ permalink raw reply
* Re: Tasks stuck in futex code (in 3.14-rc6)
From: Srikar Dronamraju @ 2014-03-20 10:08 UTC (permalink / raw)
To: Davidlohr Bueso
Cc: Peter Zijlstra, linuxppc-dev, LKML, paulus, tglx, Paul McKenney,
torvalds, mingo
In-Reply-To: <1395295019.2612.11.camel@buesod1.americas.hpqcorp.net>
> This problem suggests that we missed a wakeup for a task that was adding
> itself to the queue in a wait path. And the only place that can happen
> is with the hb spinlock check for any pending waiters. Just in case we
> missed some assumption about checking the hash bucket spinlock as a way
> of detecting any waiters (powerpc?), could you revert this commit and
> try the original atomic operations variant:
>
> https://lkml.org/lkml/2013/12/19/630
I think the above url and the commit id that I reverted i.e
git://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=b0c29f79ecea0b6fbcefc999
are the same.
Or am I missing something?
--
Thanks and Regards
Srikar Dronamraju
^ permalink raw reply
* Re: EDAC PCIe errors when scannning the bus
From: Valentin Longchamp @ 2014-03-20 10:44 UTC (permalink / raw)
To: Johannes Thumshirn
Cc: linux-pci@vger.kernel.org, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20140319155404.GA2045@jtlinux>
Hello Johannes,
On 03/19/2014 04:54 PM, Johannes Thumshirn wrote:
> On Wed, Mar 19, 2014 at 01:46:37PM +0100, Valentin Longchamp wrote:
>> Hello,
>>
>> We have a board that is based on Freescale's P2041 SoC. The boards has 2 PCIe
>> buses with this topology:
>>
>> PCIe 0 <---> PEX8505 switch <---> 4 network devices
>> PCIE 2 <---> FPGA
>>
>> On 3.10.33 + a subset of the Freescale SDK 1.4 patches, both PCIe buses work
>> well and we are able to use the devices on them.
>>
>> For each bus, I however keep getting EDAC PCIe errors at the very first stage of
>> bus enumeration (please see the attached kernel log, with some debug output from
>> arch/powerpc/kernel/pci-common.c and drivers/pci/probe.c) for both buses.
>>
>> My current "understanding" of the situation is such: since PCI_PROBE_NORMAL is
>> used, pcibios_scan_phb() calls pci_scan_child_bus() that does a pci_scan_slot()
>> on the bus for 32 slots. The first pci_scan_slot() is successful and it
>> discovers the P2041's PCIe Controller. All the 31 other pci_scan_slot() calls
>> generate an EDAC PCIe error, that is triggered by the configuration read
>> transaction to read an hypothetical vendor ID of a device on the bus. This is
>> relevant with that is reported by the EDAC error handler (all the 31 are the same):
>>
>>> PCIE error(s) detected
>>> PCIE ERR_DR register: 0x00020000
>>
>> ICCA bit is set: Access to an illegal configuration space from
>> PEX_CONFIG_ADDR/PEX_CONFIG_DATA was detected.
>>
>>> PCIE ERR_CAP_STAT register: 0x80000001
>>
>> To is set: Transaction originated from PEX_CONFIG_ADDR/PEX_CONFIG_DATA.
>>
>>> PCIE ERR_CAP_R0 register: 0x00000800
>>
>> FMT: 0b00, TYPE: 0b00100 (Config read I guess)
>>
>>> PCIE ERR_CAP_R1 register: 0x00000000
>>> PCIE ERR_CAP_R2 register: 0x00000000
>>> PCIE ERR_CAP_R3 register: 0x00000000
>>
>> Afterwards, pci_scan_child_bus() calls pcibios_fixup_bus (that maybe helps ?).
>> From here, since the P2041's PCIe Controller is a bridge, pci_scan_bridge is
>> called for this bus and all the devices are detected without having any
>> configuration transaction causing EDAC errors.
>>
>> Has someone already observed such a behavior ? Why do these initial transaction
>> generate an error ? What would be a possible fix to avoid these transaction
>> errors for these 31 (unneded ?) pci_scan_slot() calls on the initial bus ?
>>
>
> I've encountered similar problems on a P4080 based design (mine has additional
> machine checks that cause an oops). I haven't solved it yet, so I unfortunately
> can't offer you a fix. But I was told there are some errata workarounds that
> more or less could have an impact on PCIe behavior. Could you show me the output
> of U-Boot's errata command?
Here is the output for the errata command:
> => errata
> Work-around for Erratum CPU-A003999 enabled
> Work-around for Erratum DDR-A003473 enabled
> Work-around for Erratum ESDHC111 enabled
> Work-around for Erratum DDR-A003 enabled
> Work-around for Erratum A004510 enabled
> Work-around for Erratum SRIO-A004034 enabled
> Work-around for Erratum A004849 is not enabled
> Work-around for Erratum A004580 is not enabled
> Work-around for Erratum USB14 enabled
>
> Especially if the workarounds for A-004580 and A-004849 are in place.
>
So both are not enabled, I am going to fix that. Surprisingly, A-004580 is not
defined for the P2041 in u-boot even though it is also present in the P2041's
errata sheet, I had to enable it myself.
However, I expect that enabling the workarounds for these 2 Errata are good for
the system but it will not solve the PCIe EDAC problem.
Thank you for the input.
Valentin
^ permalink raw reply
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
From: Kevin Hao @ 2014-03-20 11:47 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, Chenhui Zhao, Jason.Jin, linux-kernel
In-Reply-To: <1395184734.12479.250.camel@snotra.buserror.net>
[-- Attachment #1: Type: text/plain, Size: 6168 bytes --]
On Tue, Mar 18, 2014 at 06:18:54PM -0500, Scott Wood wrote:
> > The sequence "write, readback, sync" will guarantee this according to the manual.
>
> If you're referring to the section you quoted above, the manual does not
> say that. It only talks about when accesses "to memory regions affected
> by the configuration register write" can be safely made.
To guarantee that the results of any sequence of writes to configuration
registers are in effect, the final configuration register write should be
immediately followed by a read of the same register, and that should be
followed by a SYNC instruction. Then accesses can safely be made to memory
regions affected by the configuration register write.
According to the above description in t4240 RM manual (2.6.1 Accessing CCSR
Memory from the Local Processor), that the writing to configuration register
takes effect is a prerequisite for the memory access to the affected regions.
>
> > If we just want to
> > order the delay loop after the load, the following sequence should be enough:
> > store to CCSR_DDR_SDRAM_CFG_2
> > load from CCSR_DDR_SDRAM_CFG_2
> > isync or sync
> > delay loop
> >
> > Why do we need the 'date dependency' here? According to the e6500 manual, the
> > instructions can execute out of order, but complete in order. So I am really
> > wondering why we need to order the load and the following delay loop if there
> > is no intention to order the storage access?
>
> The data (not date) dependency means that the twi will not execute until
> after the load instruction returns data (thus, after the device has
> responded to the load). The twi, being a flow control instruction
> rather than a storage instruction, should be fully ordered by isync.
>
> From the isync description in the ISA: "Except as described in the
> preceding sentence, the isync instruction may complete before storage
> accesses associated with instructions preceding the
> isync instruction have been performed."
>
> I don't know if that really applies to loads (as opposed to stores), and
> it probably doesn't apply to guarded loads, but I feel safer leaving the
> twi in.
>
> As for sync instead of isync, I see nothing to indicate that it would be
> adequate (though it may be that the only reason there needed to be a
> delay loop in the first place was the lack of a readback/sync before
> doing other I/O, in which case this is moot).
OK, so the intention of 'twi, isync' following the load is not to order the
following storage access, but order the following delay loop instructions,
right? But according to the e6500 manual, the instructions complete in order.
The following is the definition of 'complete':
Complete—An instruction is eligible to complete after it finishes executing
and makes its results available for subsequent instructions. Instructions
must complete in order from the bottom two entries of the
completion queue (CQ). The completion unit coordinates how instructions (which
may have executed out of order) affect architected registers to ensure the
appearance of serial execution. This guarantees that the completed instruction
and all previous instructions can cause no exceptions. An instruction completes
when it is retired, that is, deleted from the CQ.
So the following delay loop instructions should never complete before the
complete of the load instruction. After the complete of load instruction,
the data should already been updated to the architecture register. So we can
guarantee that the load instruction get the data (the device has responded to
the load) before the complete of the following delay loop instructions, why do
we need the additional 'twi, isync'? Then for a case like this (which don't
need order the following storage access), I think the following sequence should
be enough:
write to configuration register
read back
delay loop
> I mean that I do not understand why it says, "the load on which the
> Branch depends is performed before any loads caused by instructions
> following the isync" rather than "the Load on which the Branch depends
> is performed before any instructions following the isync".
When we talk about the 'performed' here, we should only mean the effect of
storage access. The following is the definition of 'performed':
performed
A load or instruction fetch by a processor or mech-
anism (P1) is performed with respect to any pro-
cessor or mechanism (P2) when the value to be
returned by the load or instruction fetch can no
longer be changed by a store by P2. A store by P1
is performed with respect to P2 when a load by P2
from the location accessed by the store will return
the value stored (or a value stored subsequently).
An instruction cache block invalidation by P1 is
performed with respect to P2 when an instruction
fetch by P2 will not be satisfied from the copy of
the block that existed in its instruction cache when
the instruction causing the invalidation was exe-
cuted, and similarly for a data cache block invalida-
tion.
The preceding definitions apply regardless of
whether P1 and P2 are the same entity.
>
> > > > So if we want to order all the storage access as well
> > > > as execution synchronization, we should choose sync here.
> > >
> > > Do we need execution synchronization or context synchronization?
> >
> > There is no context-altering instruction here, so I think an execution
> > synchronizing instruction should be enough here.
>
> Is the ISA ever explicit about what constitutes "context"?
The following is the definition of context-altering instruction:
An instruction that alters the context in which data
addresses or instruction addresses are interpreted, or
in which instructions are executed or data accesses are
performed, is called a context-altering instruction.
So the context should be:
- in which data addresses or instruction addresses are interpreted
- in which instructions are executed
- in which data accesses are performed
Thanks,
Kevin
[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply
* RE: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
From: David Laight @ 2014-03-20 11:59 UTC (permalink / raw)
To: 'Kevin Hao', Scott Wood
Cc: linuxppc-dev@lists.ozlabs.org, Chenhui Zhao,
Jason.Jin@freescale.com, linux-kernel@vger.kernel.org
In-Reply-To: <20140320114735.GD10182@pek-khao-d1.corp.ad.wrs.com>
RnJvbTogS2V2aW4gSGFvDQo+IFNlbnQ6IDIwIE1hcmNoIDIwMTQgMTE6NDgNCj4gVG86IFNjb3R0
IFdvb2QNCj4gQ2M6IGxpbnV4cHBjLWRldkBsaXN0cy5vemxhYnMub3JnOyBDaGVuaHVpIFpoYW87
IEphc29uLkppbkBmcmVlc2NhbGUuY29tOyBsaW51eC1rZXJuZWxAdmdlci5rZXJuZWwub3JnDQo+
IFN1YmplY3Q6IFJlOiBbUEFUQ0ggOS85XSBwb3dlcnBjL3BtOiBzdXBwb3J0IGRlZXAgc2xlZXAg
ZmVhdHVyZSBvbiBUMTA0MA0KPiANCj4gT24gVHVlLCBNYXIgMTgsIDIwMTQgYXQgMDY6MTg6NTRQ
TSAtMDUwMCwgU2NvdHQgV29vZCB3cm90ZToNCj4gPiA+ICBUaGUgc2VxdWVuY2UgIndyaXRlLCBy
ZWFkYmFjaywgc3luYyIgd2lsbCBndWFyYW50ZWUgdGhpcyBhY2NvcmRpbmcgdG8gdGhlIG1hbnVh
bC4NCj4gPg0KPiA+IElmIHlvdSdyZSByZWZlcnJpbmcgdG8gdGhlIHNlY3Rpb24geW91IHF1b3Rl
ZCBhYm92ZSwgdGhlIG1hbnVhbCBkb2VzIG5vdA0KPiA+IHNheSB0aGF0LiAgSXQgb25seSB0YWxr
cyBhYm91dCB3aGVuIGFjY2Vzc2VzICJ0byBtZW1vcnkgcmVnaW9ucyBhZmZlY3RlZA0KPiA+IGJ5
IHRoZSBjb25maWd1cmF0aW9uIHJlZ2lzdGVyIHdyaXRlIiBjYW4gYmUgc2FmZWx5IG1hZGUuDQo+
IA0KPiAgIFRvIGd1YXJhbnRlZSB0aGF0IHRoZSByZXN1bHRzIG9mIGFueSBzZXF1ZW5jZSBvZiB3
cml0ZXMgdG8gY29uZmlndXJhdGlvbg0KPiAgIHJlZ2lzdGVycyBhcmUgaW4gZWZmZWN0LCB0aGUg
ZmluYWwgY29uZmlndXJhdGlvbiByZWdpc3RlciB3cml0ZSBzaG91bGQgYmUNCj4gICBpbW1lZGlh
dGVseSBmb2xsb3dlZCBieSBhIHJlYWQgb2YgdGhlIHNhbWUgcmVnaXN0ZXIsIGFuZCB0aGF0IHNo
b3VsZCBiZQ0KPiAgIGZvbGxvd2VkIGJ5IGEgU1lOQyBpbnN0cnVjdGlvbi4gVGhlbiBhY2Nlc3Nl
cyBjYW4gc2FmZWx5IGJlIG1hZGUgdG8gbWVtb3J5DQo+ICAgcmVnaW9ucyBhZmZlY3RlZCBieSB0
aGUgY29uZmlndXJhdGlvbiByZWdpc3RlciB3cml0ZS4NCg0KVGhhdCBzb3J0IG9mIHNlcXVlbmNl
IGlzIG5lZWQgdG8gZm9yY2UgdGhlIG9wZXJhdGlvbnMgdGhyb3VnaCBhbnkNCmV4dGVybmFsIGJ1
cyAtIGFmdGVyIHRoZSBjcHUgaXRzZWxmIGhhcyBpc3N1ZWQgdGhlIGJ1cyBjeWNsZXMuDQpNb3N0
bHkgcmVxdWlyZWQgYmVjYXVzZSB3cml0ZXMgYXJlIG9mdGVuICdwb3N0ZWQnIChpZSBhZGRyZXNz
IGFuZCBkYXRhDQpsYXRjaGVkLCBhbmQgdGhlbiBwZXJmb3JtZWQgc3luY2hyb25vdXNseSkuDQoN
Cj4gQWNjb3JkaW5nIHRvIHRoZSBhYm92ZSBkZXNjcmlwdGlvbiBpbiB0NDI0MCBSTSBtYW51YWwg
KDIuNi4xIEFjY2Vzc2luZyBDQ1NSDQo+IE1lbW9yeSBmcm9tIHRoZSBMb2NhbCBQcm9jZXNzb3Ip
LCB0aGF0IHRoZSB3cml0aW5nIHRvIGNvbmZpZ3VyYXRpb24gcmVnaXN0ZXINCj4gdGFrZXMgZWZm
ZWN0IGlzIGEgcHJlcmVxdWlzaXRlIGZvciB0aGUgbWVtb3J5IGFjY2VzcyB0byB0aGUgYWZmZWN0
ZWQgcmVnaW9ucy4NCi4uLg0KPiBPSywgc28gdGhlIGludGVudGlvbiBvZiAndHdpLCBpc3luYycg
Zm9sbG93aW5nIHRoZSBsb2FkIGlzIG5vdCB0byBvcmRlciB0aGUNCj4gZm9sbG93aW5nIHN0b3Jh
Z2UgYWNjZXNzLCBidXQgb3JkZXIgdGhlIGZvbGxvd2luZyBkZWxheSBsb29wIGluc3RydWN0aW9u
cywNCj4gcmlnaHQNCg0KSSB0cmllZCB0byB3b3JrIG91dCB3aGF0IHRoZSAndHdpLCBpc3luYycg
aW5zdHJ1Y3Rpb25zIHdlcmUgZm9yIChpbiBpbl9sZTMyKCkpLg0KVGhlIGJlc3QgSSBjb3VsZCBj
b21lIHVwIHdpdGggd2FzIHRvIGVuc3VyZSBhIHN5bmNocm9ub3VzIGJ1cy1mYXVsdC4NCkJ1dCBi
dXMgZmF1bHRzIGFyZSBwcm9iYWJseSBvbmx5IGV4cGVjdGVkIGR1cmluZyBkZXZpY2UgcHJvYmlu
ZyAtIG5vdA0Kbm9ybWFsIG9wZXJhdGlvbiwgYW5kIHRoZSBpbnN0cnVjdGlvbnMgd2lsbCBoYXZl
IGEgc2lnbmlmaWNhbnQgY29zdC4NCg0KQWRkaXRpb25hbGx5IGluX2xlMzIoKSBhbmQgb3V0X2xl
MzIoKSBib3RoIHN0YXJ0IHdpdGggYSAnc3luYycgaW5zdHJ1Y3Rpb24uDQpJbiBtYW55IGNhc2Vz
IHRoYXQgaXNuJ3QgbmVlZGVkIGVpdGhlciAtIGFuIGV4cGxpY2l0IGlvc3luYygpIGNhbiBiZQ0K
dXNlZCBhZnRlciBncm91cHMgb2YgaW5zdHJ1Y3Rpb25zLg0KDQoJRGF2aWQNCg0KDQo=
^ permalink raw reply
* [PATCH v3 0/5] powernv: Enable Dynamic Frequency
From: Gautham R. Shenoy @ 2014-03-20 12:10 UTC (permalink / raw)
To: linuxppc-dev, linux-pm; +Cc: Gautham R. Shenoy
From: "Gautham R. Shenoy" <ego@linux.vnet.ibm.com>
Hi,
This is the v3 of the consolidated patchset consisting
patches for enabling cpufreq on IBM POWERNV platforms
along with some enhancements. I have incorporated the review
for v2 (which can be found at [1]).
- This patchset contains code for the platform driver to support CPU
frequency scaling on IBM POWERNV platforms.
- In addition to the standard control and status files exposed by the
cpufreq core, the patchset exposes the nominal frequency through the
file named "cpuinfo_nominal_freq".
The changes from from v2:
- Updated the changelog for "powernv: cpufreq driver for powernv platform"
to record the fact that policy->cpus must be populated with a sibling mask
that includes even the offlined siblings.
- Dropped the patch named
"powernv:cpufreq: Create a powernv_cpu_to_core_mask() helper"
since the driver->get() method can use cpu_sibling_mask().
- Updated "powernv:cpufreq: Implement the driver->get() method" to
use cpu_sibling_mask() in powernv_cpufreq_get()
The patchset is based against commit 4907cdca7210c5895311bddcf05a4c85b67d8566
of the mainline tree.
[1]: https://lists.ozlabs.org/pipermail/linuxppc-dev/2014-March/115861.html
Gautham R. Shenoy (3):
powernv:cpufreq: Create pstate_id_to_freq() helper
powernv:cpufreq: Export nominal frequency via sysfs.
powernv:cpufreq: Implement the driver->get() method
Srivatsa S. Bhat (1):
powernv,cpufreq:Add per-core locking to serialize frequency
transitions
Vaidyanathan Srinivasan (1):
powernv: cpufreq driver for powernv platform
arch/powerpc/include/asm/reg.h | 4 +
arch/powerpc/platforms/powernv/Kconfig | 1 +
drivers/cpufreq/Kconfig | 1 +
drivers/cpufreq/Kconfig.powerpc | 13 ++
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/powernv-cpufreq.c | 375 +++++++++++++++++++++++++++++++++
6 files changed, 395 insertions(+)
create mode 100644 drivers/cpufreq/powernv-cpufreq.c
--
1.8.3.1
^ permalink raw reply
* [PATCH v3 1/5] powernv: cpufreq driver for powernv platform
From: Gautham R. Shenoy @ 2014-03-20 12:10 UTC (permalink / raw)
To: linuxppc-dev, linux-pm
Cc: Anton Blanchard, Srivatsa S. Bhat, Gautham R. Shenoy
In-Reply-To: <1395317460-14811-1-git-send-email-ego@linux.vnet.ibm.com>
From: Vaidyanathan Srinivasan <svaidy@linux.vnet.ibm.com>
Backend driver to dynamically set voltage and frequency on
IBM POWER non-virtualized platforms. Power management SPRs
are used to set the required PState.
This driver works in conjunction with cpufreq governors
like 'ondemand' to provide a demand based frequency and
voltage setting on IBM POWER non-virtualized platforms.
PState table is obtained from OPAL v3 firmware through device
tree.
powernv_cpufreq back-end driver would parse the relevant device-tree
nodes and initialise the cpufreq subsystem on powernv platform.
The policy->cpus needs to be populated in a hotplug-invariant manner
instead of using cpu_sibling_mask() which varies with cpu-hotplug. This
is because the cpufreq core code copies this content into policy->related_cpus
mask which is should not vary on cpu-hotplug.
[Change log updated by ego@linux.vnet.ibm.com]
Signed-off-by: Vaidyanathan Srinivasan <svaidy@linux.vnet.ibm.com>
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/reg.h | 4 +
arch/powerpc/platforms/powernv/Kconfig | 1 +
drivers/cpufreq/Kconfig | 1 +
drivers/cpufreq/Kconfig.powerpc | 13 ++
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/powernv-cpufreq.c | 277 +++++++++++++++++++++++++++++++++
6 files changed, 297 insertions(+)
create mode 100644 drivers/cpufreq/powernv-cpufreq.c
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 90c06ec..84f92ca 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -271,6 +271,10 @@
#define SPRN_HSRR1 0x13B /* Hypervisor Save/Restore 1 */
#define SPRN_IC 0x350 /* Virtual Instruction Count */
#define SPRN_VTB 0x351 /* Virtual Time Base */
+#define SPRN_PMICR 0x354 /* Power Management Idle Control Reg */
+#define SPRN_PMSR 0x355 /* Power Management Status Reg */
+#define SPRN_PMCR 0x374 /* Power Management Control Register */
+
/* HFSCR and FSCR bit numbers are the same */
#define FSCR_TAR_LG 8 /* Enable Target Address Register */
#define FSCR_EBB_LG 7 /* Enable Event Based Branching */
diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig
index 895e8a2..1fe12b1 100644
--- a/arch/powerpc/platforms/powernv/Kconfig
+++ b/arch/powerpc/platforms/powernv/Kconfig
@@ -11,6 +11,7 @@ config PPC_POWERNV
select PPC_UDBG_16550
select PPC_SCOM
select ARCH_RANDOM
+ select CPU_FREQ
default y
config PPC_POWERNV_RTAS
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 4b029c0..4ba1632 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -48,6 +48,7 @@ config CPU_FREQ_STAT_DETAILS
choice
prompt "Default CPUFreq governor"
default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ
+ default CPU_FREQ_DEFAULT_GOV_ONDEMAND if POWERNV_CPUFREQ
default CPU_FREQ_DEFAULT_GOV_PERFORMANCE
help
This option sets which CPUFreq governor shall be loaded at
diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
index ca0021a..93f8689 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -54,3 +54,16 @@ config PPC_PASEMI_CPUFREQ
help
This adds the support for frequency switching on PA Semi
PWRficient processors.
+
+config POWERNV_CPUFREQ
+ tristate "CPU frequency scaling for IBM POWERNV platform"
+ depends on PPC_POWERNV
+ select CPU_FREQ_GOV_PERFORMANCE
+ select CPU_FREQ_GOV_POWERSAVE
+ select CPU_FREQ_GOV_USERSPACE
+ select CPU_FREQ_GOV_ONDEMAND
+ select CPU_FREQ_GOV_CONSERVATIVE
+ default y
+ help
+ This adds support for CPU frequency switching on IBM POWERNV
+ platform
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 7494565..0dbb963 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_PPC_CORENET_CPUFREQ) += ppc-corenet-cpufreq.o
obj-$(CONFIG_CPU_FREQ_PMAC) += pmac32-cpufreq.o
obj-$(CONFIG_CPU_FREQ_PMAC64) += pmac64-cpufreq.o
obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += pasemi-cpufreq.o
+obj-$(CONFIG_POWERNV_CPUFREQ) += powernv-cpufreq.o
##################################################################################
# Other platform drivers
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
new file mode 100644
index 0000000..ab1551f
--- /dev/null
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -0,0 +1,277 @@
+/*
+ * POWERNV cpufreq driver for the IBM POWER processors
+ *
+ * (C) Copyright IBM 2014
+ *
+ * Author: Vaidyanathan Srinivasan <svaidy at linux.vnet.ibm.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "powernv-cpufreq: " fmt
+
+#include <linux/module.h>
+#include <linux/cpufreq.h>
+#include <linux/of.h>
+#include <asm/cputhreads.h>
+
+/* FIXME: Make this per-core */
+static DEFINE_MUTEX(freq_switch_mutex);
+
+#define POWERNV_MAX_PSTATES 256
+
+static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
+static int powernv_pstate_ids[POWERNV_MAX_PSTATES+1];
+
+/*
+ * Initialize the freq table based on data obtained
+ * from the firmware passed via device-tree
+ */
+
+static int init_powernv_pstates(void)
+{
+ struct device_node *power_mgt;
+ int nr_pstates = 0;
+ int pstate_min, pstate_max, pstate_nominal;
+ const __be32 *pstate_ids, *pstate_freqs;
+ int i;
+ u32 len_ids, len_freqs;
+
+ power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
+ if (!power_mgt) {
+ pr_warn("power-mgt node not found\n");
+ return -ENODEV;
+ }
+
+ if (of_property_read_u32(power_mgt, "ibm,pstate-min", &pstate_min)) {
+ pr_warn("ibm,pstate-min node not found\n");
+ return -ENODEV;
+ }
+
+ if (of_property_read_u32(power_mgt, "ibm,pstate-max", &pstate_max)) {
+ pr_warn("ibm,pstate-max node not found\n");
+ return -ENODEV;
+ }
+
+ if (of_property_read_u32(power_mgt, "ibm,pstate-nominal",
+ &pstate_nominal)) {
+ pr_warn("ibm,pstate-nominal not found\n");
+ return -ENODEV;
+ }
+ pr_info("cpufreq pstate min %d nominal %d max %d\n", pstate_min,
+ pstate_nominal, pstate_max);
+
+ pstate_ids = of_get_property(power_mgt, "ibm,pstate-ids", &len_ids);
+ if (!pstate_ids) {
+ pr_warn("ibm,pstate-ids not found\n");
+ return -ENODEV;
+ }
+
+ pstate_freqs = of_get_property(power_mgt, "ibm,pstate-frequencies-mhz",
+ &len_freqs);
+ if (!pstate_freqs) {
+ pr_warn("ibm,pstate-frequencies-mhz not found\n");
+ return -ENODEV;
+ }
+
+ WARN_ON(len_ids != len_freqs);
+ nr_pstates = min(len_ids, len_freqs) / sizeof(u32);
+ WARN_ON(!nr_pstates);
+
+ pr_debug("NR PStates %d\n", nr_pstates);
+ for (i = 0; i < nr_pstates; i++) {
+ u32 id = be32_to_cpu(pstate_ids[i]);
+ u32 freq = be32_to_cpu(pstate_freqs[i]);
+
+ pr_debug("PState id %d freq %d MHz\n", id, freq);
+ powernv_freqs[i].driver_data = i;
+ powernv_freqs[i].frequency = freq * 1000; /* kHz */
+ powernv_pstate_ids[i] = id;
+ }
+ /* End of list marker entry */
+ powernv_freqs[i].driver_data = 0;
+ powernv_freqs[i].frequency = CPUFREQ_TABLE_END;
+
+ /* Print frequency table */
+ for (i = 0; powernv_freqs[i].frequency != CPUFREQ_TABLE_END; i++)
+ pr_debug("%d: %d\n", i, powernv_freqs[i].frequency);
+
+ return 0;
+}
+
+static struct freq_attr *powernv_cpu_freq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+/* Helper routines */
+
+/* Access helpers to power mgt SPR */
+
+static inline unsigned long get_pmspr(unsigned long sprn)
+{
+ switch (sprn) {
+ case SPRN_PMCR:
+ return mfspr(SPRN_PMCR);
+
+ case SPRN_PMICR:
+ return mfspr(SPRN_PMICR);
+
+ case SPRN_PMSR:
+ return mfspr(SPRN_PMSR);
+ }
+ BUG();
+}
+
+static inline void set_pmspr(unsigned long sprn, unsigned long val)
+{
+ switch (sprn) {
+ case SPRN_PMCR:
+ mtspr(SPRN_PMCR, val);
+ return;
+
+ case SPRN_PMICR:
+ mtspr(SPRN_PMICR, val);
+ return;
+
+ case SPRN_PMSR:
+ mtspr(SPRN_PMSR, val);
+ return;
+ }
+ BUG();
+}
+
+static void set_pstate(void *pstate)
+{
+ unsigned long val;
+ unsigned long pstate_ul = *(unsigned long *) pstate;
+
+ val = get_pmspr(SPRN_PMCR);
+ val = val & 0x0000ffffffffffffULL;
+ /* Set both global(bits 56..63) and local(bits 48..55) PStates */
+ val = val | (pstate_ul << 56) | (pstate_ul << 48);
+ pr_debug("Setting cpu %d pmcr to %016lX\n", smp_processor_id(), val);
+ set_pmspr(SPRN_PMCR, val);
+}
+
+static int powernv_set_freq(cpumask_var_t cpus, unsigned int new_index)
+{
+ unsigned long val = (unsigned long) powernv_pstate_ids[new_index];
+
+ /*
+ * Use smp_call_function to send IPI and execute the
+ * mtspr on target cpu. We could do that without IPI
+ * if current CPU is within policy->cpus (core)
+ */
+
+ val = val & 0xFF;
+ smp_call_function_any(cpus, set_pstate, &val, 1);
+ return 0;
+}
+
+static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ int base, i;
+
+#ifdef CONFIG_SMP
+ base = cpu_first_thread_sibling(policy->cpu);
+
+ for (i = 0; i < threads_per_core; i++)
+ cpumask_set_cpu(base + i, policy->cpus);
+#endif
+ policy->cpuinfo.transition_latency = 25000;
+
+ policy->cur = powernv_freqs[0].frequency;
+ cpufreq_frequency_table_get_attr(powernv_freqs, policy->cpu);
+ return cpufreq_frequency_table_cpuinfo(policy, powernv_freqs);
+}
+
+static int powernv_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ return 0;
+}
+
+static int powernv_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, powernv_freqs);
+}
+
+static int powernv_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ int rc;
+ struct cpufreq_freqs freqs;
+ unsigned int new_index;
+
+ cpufreq_frequency_table_target(policy, powernv_freqs, target_freq,
+ relation, &new_index);
+
+ freqs.old = policy->cur;
+ freqs.new = powernv_freqs[new_index].frequency;
+ freqs.cpu = policy->cpu;
+
+ mutex_lock(&freq_switch_mutex);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+
+ pr_debug("setting frequency for cpu %d to %d kHz index %d pstate %d",
+ policy->cpu,
+ powernv_freqs[new_index].frequency,
+ new_index,
+ powernv_pstate_ids[new_index]);
+
+ rc = powernv_set_freq(policy->cpus, new_index);
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ mutex_unlock(&freq_switch_mutex);
+
+ return rc;
+}
+
+static struct cpufreq_driver powernv_cpufreq_driver = {
+ .verify = powernv_cpufreq_verify,
+ .target = powernv_cpufreq_target,
+ .init = powernv_cpufreq_cpu_init,
+ .exit = powernv_cpufreq_cpu_exit,
+ .name = "powernv-cpufreq",
+ .flags = CPUFREQ_CONST_LOOPS,
+ .attr = powernv_cpu_freq_attr,
+};
+
+static int __init powernv_cpufreq_init(void)
+{
+ int rc = 0;
+
+ /* Discover pstates from device tree and init */
+
+ rc = init_powernv_pstates();
+
+ if (rc) {
+ pr_info("powernv-cpufreq disabled\n");
+ return rc;
+ }
+
+ rc = cpufreq_register_driver(&powernv_cpufreq_driver);
+ return rc;
+}
+
+static void __exit powernv_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&powernv_cpufreq_driver);
+}
+
+module_init(powernv_cpufreq_init);
+module_exit(powernv_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vaidyanathan Srinivasan <svaidy at linux.vnet.ibm.com>");
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 2/5] powernv, cpufreq:Add per-core locking to serialize frequency transitions
From: Gautham R. Shenoy @ 2014-03-20 12:10 UTC (permalink / raw)
To: linuxppc-dev, linux-pm; +Cc: Srivatsa S. Bhat, Gautham R. Shenoy
In-Reply-To: <1395317460-14811-1-git-send-email-ego@linux.vnet.ibm.com>
From: "Srivatsa S. Bhat" <srivatsa.bhat@linux.vnet.ibm.com>
On POWER systems, the CPU frequency is controlled at a core-level and
hence we need to serialize so that only one of the threads in the core
switches the core's frequency at a time.
Using a global mutex lock would needlessly serialize _all_ frequency
transitions in the system (across all cores). So introduce per-core
locking to enable finer-grained synchronization and thereby enhance
the speed and responsiveness of the cpufreq driver to varying workload
demands.
The design of per-core locking is very simple and straight-forward: we
first define a Per-CPU lock and use the ones that belongs to the first
thread sibling of the core.
cpu_first_thread_sibling() macro is used to find the *common* lock for
all thread siblings belonging to a core.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: Vaidyanathan Srinivasan <svaidy@linux.vnet.ibm.com>
Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
---
drivers/cpufreq/powernv-cpufreq.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
index ab1551f..66dae0d 100644
--- a/drivers/cpufreq/powernv-cpufreq.c
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -24,8 +24,15 @@
#include <linux/of.h>
#include <asm/cputhreads.h>
-/* FIXME: Make this per-core */
-static DEFINE_MUTEX(freq_switch_mutex);
+/* Per-Core locking for frequency transitions */
+static DEFINE_PER_CPU(struct mutex, freq_switch_lock);
+
+#define lock_core_freq(cpu) \
+ mutex_lock(&per_cpu(freq_switch_lock,\
+ cpu_first_thread_sibling(cpu)));
+#define unlock_core_freq(cpu) \
+ mutex_unlock(&per_cpu(freq_switch_lock,\
+ cpu_first_thread_sibling(cpu)));
#define POWERNV_MAX_PSTATES 256
@@ -221,7 +228,7 @@ static int powernv_cpufreq_target(struct cpufreq_policy *policy,
freqs.new = powernv_freqs[new_index].frequency;
freqs.cpu = policy->cpu;
- mutex_lock(&freq_switch_mutex);
+ lock_core_freq(policy->cpu);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
pr_debug("setting frequency for cpu %d to %d kHz index %d pstate %d",
@@ -233,7 +240,7 @@ static int powernv_cpufreq_target(struct cpufreq_policy *policy,
rc = powernv_set_freq(policy->cpus, new_index);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
- mutex_unlock(&freq_switch_mutex);
+ unlock_core_freq(policy->cpu);
return rc;
}
@@ -250,7 +257,7 @@ static struct cpufreq_driver powernv_cpufreq_driver = {
static int __init powernv_cpufreq_init(void)
{
- int rc = 0;
+ int cpu, rc = 0;
/* Discover pstates from device tree and init */
@@ -260,6 +267,10 @@ static int __init powernv_cpufreq_init(void)
pr_info("powernv-cpufreq disabled\n");
return rc;
}
+ /* Init per-core mutex */
+ for_each_possible_cpu(cpu) {
+ mutex_init(&per_cpu(freq_switch_lock, cpu));
+ }
rc = cpufreq_register_driver(&powernv_cpufreq_driver);
return rc;
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 3/5] powernv:cpufreq: Create pstate_id_to_freq() helper
From: Gautham R. Shenoy @ 2014-03-20 12:10 UTC (permalink / raw)
To: linuxppc-dev, linux-pm; +Cc: Gautham R. Shenoy
In-Reply-To: <1395317460-14811-1-git-send-email-ego@linux.vnet.ibm.com>
From: "Gautham R. Shenoy" <ego@linux.vnet.ibm.com>
Create a helper routine that can return the cpu-frequency for the
corresponding pstate_id.
Also, cache the values of the pstate_max, pstate_min and
pstate_nominal and nr_pstates in a static structure so that they can
be reused in the future to perform any validations.
Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
---
drivers/cpufreq/powernv-cpufreq.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
index 66dae0d..e7b0292 100644
--- a/drivers/cpufreq/powernv-cpufreq.c
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -39,6 +39,14 @@ static DEFINE_PER_CPU(struct mutex, freq_switch_lock);
static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
static int powernv_pstate_ids[POWERNV_MAX_PSTATES+1];
+struct powernv_pstate_info {
+ int pstate_min_id;
+ int pstate_max_id;
+ int pstate_nominal_id;
+ int nr_pstates;
+};
+static struct powernv_pstate_info powernv_pstate_info;
+
/*
* Initialize the freq table based on data obtained
* from the firmware passed via device-tree
@@ -112,9 +120,28 @@ static int init_powernv_pstates(void)
for (i = 0; powernv_freqs[i].frequency != CPUFREQ_TABLE_END; i++)
pr_debug("%d: %d\n", i, powernv_freqs[i].frequency);
+ powernv_pstate_info.pstate_min_id = pstate_min;
+ powernv_pstate_info.pstate_max_id = pstate_max;
+ powernv_pstate_info.pstate_nominal_id = pstate_nominal;
+ powernv_pstate_info.nr_pstates = nr_pstates;
+
return 0;
}
+/**
+ * Returns the cpu frequency corresponding to the pstate_id.
+ */
+static unsigned int pstate_id_to_freq(int pstate_id)
+{
+ int i;
+
+ i = powernv_pstate_info.pstate_max_id - pstate_id;
+
+ BUG_ON(i >= powernv_pstate_info.nr_pstates || i < 0);
+ WARN_ON(powernv_pstate_ids[i] != pstate_id);
+ return powernv_freqs[i].frequency;
+}
+
static struct freq_attr *powernv_cpu_freq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 4/5] powernv:cpufreq: Export nominal frequency via sysfs.
From: Gautham R. Shenoy @ 2014-03-20 12:10 UTC (permalink / raw)
To: linuxppc-dev, linux-pm; +Cc: Gautham R. Shenoy
In-Reply-To: <1395317460-14811-1-git-send-email-ego@linux.vnet.ibm.com>
From: "Gautham R. Shenoy" <ego@linux.vnet.ibm.com>
Create a driver attribute named cpuinfo_nominal_freq which
creates a sysfs read-only file named cpuinfo_nominal_freq. Export
the frequency corresponding to the nominal_pstate through this
interface.
Nominal frequency is the highest non-turbo frequency for the
platform. This is generally used for setting governor policies from
user space for optimal energy efficiency.
Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
---
drivers/cpufreq/powernv-cpufreq.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
index e7b0292..46bee8a 100644
--- a/drivers/cpufreq/powernv-cpufreq.c
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -142,8 +142,30 @@ static unsigned int pstate_id_to_freq(int pstate_id)
return powernv_freqs[i].frequency;
}
+/**
+ * show_cpuinfo_nominal_freq - Show the nominal CPU frequency as indicated by
+ * the firmware
+ */
+static ssize_t show_cpuinfo_nominal_freq(struct cpufreq_policy *policy,
+ char *buf)
+{
+ int nominal_freq;
+ nominal_freq = pstate_id_to_freq(powernv_pstate_info.pstate_nominal_id);
+ return sprintf(buf, "%u\n", nominal_freq);
+}
+
+
+struct freq_attr cpufreq_freq_attr_cpuinfo_nominal_freq = {
+ .attr = { .name = "cpuinfo_nominal_freq",
+ .mode = 0444,
+ },
+ .show = show_cpuinfo_nominal_freq,
+};
+
+
static struct freq_attr *powernv_cpu_freq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+ &cpufreq_freq_attr_cpuinfo_nominal_freq,
NULL,
};
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 5/5] powernv:cpufreq: Implement the driver->get() method
From: Gautham R. Shenoy @ 2014-03-20 12:11 UTC (permalink / raw)
To: linuxppc-dev, linux-pm; +Cc: Gautham R. Shenoy
In-Reply-To: <1395317460-14811-1-git-send-email-ego@linux.vnet.ibm.com>
From: "Gautham R. Shenoy" <ego@linux.vnet.ibm.com>
The current frequency of a cpu is reported through the sysfs file
cpuinfo_cur_freq. This requires the driver to implement a
"->get(unsigned int cpu)" method which will return the current
operating frequency.
Implement a function named powernv_cpufreq_get() which reads the local
pstate from the PMSR and returns the corresponding frequency.
Set the powernv_cpufreq_driver.get hook to powernv_cpufreq_get().
Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
---
drivers/cpufreq/powernv-cpufreq.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
index 46bee8a..ef6ed8c 100644
--- a/drivers/cpufreq/powernv-cpufreq.c
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -206,6 +206,43 @@ static inline void set_pmspr(unsigned long sprn, unsigned long val)
BUG();
}
+/*
+ * Computes the current frequency on this cpu
+ * and stores the result in *ret_freq.
+ */
+static void powernv_read_cpu_freq(void *ret_freq)
+{
+ unsigned long pmspr_val;
+ s8 local_pstate_id;
+ int *cur_freq, freq, pstate_id;
+
+ cur_freq = (int *)ret_freq;
+ pmspr_val = get_pmspr(SPRN_PMSR);
+
+ /* The local pstate id corresponds bits 48..55 in the PMSR.
+ * Note: Watch out for the sign! */
+ local_pstate_id = (pmspr_val >> 48) & 0xFF;
+ pstate_id = local_pstate_id;
+
+ freq = pstate_id_to_freq(pstate_id);
+ pr_debug("cpu %d pmsr %lx pstate_id %d frequency %d \n",
+ smp_processor_id(), pmspr_val, pstate_id, freq);
+ *cur_freq = freq;
+}
+
+/*
+ * Returns the cpu frequency as reported by the firmware for 'cpu'.
+ * This value is reported through the sysfs file cpuinfo_cur_freq.
+ */
+unsigned int powernv_cpufreq_get(unsigned int cpu)
+{
+ int ret_freq;
+
+ smp_call_function_any(cpu_sibling_mask(cpu), powernv_read_cpu_freq,
+ &ret_freq, 1);
+ return ret_freq;
+}
+
static void set_pstate(void *pstate)
{
unsigned long val;
@@ -297,6 +334,7 @@ static int powernv_cpufreq_target(struct cpufreq_policy *policy,
static struct cpufreq_driver powernv_cpufreq_driver = {
.verify = powernv_cpufreq_verify,
.target = powernv_cpufreq_target,
+ .get = powernv_cpufreq_get,
.init = powernv_cpufreq_cpu_init,
.exit = powernv_cpufreq_cpu_exit,
.name = "powernv-cpufreq",
--
1.8.3.1
^ permalink raw reply related
* [PATCH] powerpc: Fix KVM hang with CONFIG_KVM_XICS=n
From: Anton Blanchard @ 2014-03-20 13:03 UTC (permalink / raw)
To: paulus, benh, Andreas Schwab, Alexander Graf; +Cc: linuxppc-dev
I noticed KVM is broken when KVM in-kernel XICS emulation
(CONFIG_KVM_XICS) is disabled.
The problem was introduced in 48eaef05 (KVM: PPC: Book3S HV: use
xics_wake_cpu only when defined). It used CONFIG_KVM_XICS to wrap
xics_wake_cpu, where CONFIG_PPC_ICP_NATIVE should have been
used.
Signed-off-by: Anton Blanchard <anton@samba.org>
Cc: stable@vger.kernel.org
---
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 17fc949..7a25d92 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -86,7 +86,7 @@ static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu)
/* CPU points to the first thread of the core */
if (cpu != me && cpu >= 0 && cpu < nr_cpu_ids) {
-#ifdef CONFIG_KVM_XICS
+#ifdef CONFIG_PPC_ICP_NATIVE
int real_cpu = cpu + vcpu->arch.ptid;
if (paca[real_cpu].kvm_hstate.xics_phys)
xics_wake_cpu(real_cpu);
@@ -1360,9 +1360,7 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu)
smp_wmb();
#if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP)
if (cpu != smp_processor_id()) {
-#ifdef CONFIG_KVM_XICS
xics_wake_cpu(cpu);
-#endif
if (vcpu->arch.ptid)
++vc->n_woken;
}
^ permalink raw reply related
* [PATCH RFC v10 0/6] MPC512x DMA slave s/g support, OF DMA lookup
From: Alexander Popov @ 2014-03-20 14:47 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Andy Shevchenko,
Alexander Popov, linuxppc-dev, dmaengine
Cc: devicetree
2013/7/14 Gerhard Sittig <gsi@denx.de>:
> this series
> - introduces slave s/g support (that's support for DMA transfers which
> involve peripherals in contrast to mem-to-mem transfers)
> - adds device tree based lookup support for DMA channels
> - combines floating patches and related feedback which already covered
> several aspects of what the suggested LPB driver needs, to demonstrate
> how integration might be done
> - carries Q&D SD card support to enable another DMA client during test,
> while this patch needs to get dropped upon pickup
Changes in v2:
> - re-order mpc8308 related code paths for improved readability, no
> change in behaviour, introduction of symbolic channel names here
> already
> - squash 'execute() start condition' and 'terminate all' into the
> introduction of 'slave s/g prep' and 'device control' support; refuse
> s/g lists with more than one item since slave support is operational
> yet proper s/g support is missing (can get addressed later)
> - always start transfers from software on MPC8308 as there are no
> external request lines for peripheral flow control
> - drop dt-bindings header file and symbolic channel names in OF nodes
Changes in v3 and v4:
Part 1/5:
- use #define instead of enum since individual channels don't require
special handling.
Part 2/5:
- add a flag "will_access_peripheral" to DMA transfer descriptor
according recommendations of Gerhard Sittig.
This flag is set in mpc_dma_prep_memcpy() and mpc_dma_prep_slave_sg()
and is evaluated in mpc_dma_execute() to choose a type of start for
the transfer.
- prevent descriptors of transfers which involve peripherals from
being chained together;
each of such transfers needs hardware initiated start.
- add locking while working with struct mpc_dma_chan
according recommendations of Lars-Peter Clausen.
- remove default nbytes value. Client kernel modules must set
src_maxburst and dst_maxburst fields of struct dma_slave_config (dmaengine.h).
Changes in v5:
Part 2/5:
- add and improve comments;
- improve the code moving transfer descriptors from 'queued' to 'active' list
in mpc_dma_execute();
- allow mpc_dma_prep_slave_sg() to run with non-empty 'active' list;
- take 'mdesc' back to 'free' list in case of error in mpc_dma_prep_slave_sg();
- improve checks of the transfer parameters;
- provide the default value for 'maxburst' in mpc_dma_device_control().
Changes in v6:
Part 2/5:
- remove doubtful comment;
- fix coding style issues;
- set default value for 'maxburst' to 1 which applies to most cases;
Part 3/5:
- use dma_get_slave_channel() instead of dma_request_channel()
in new function of_dma_xlate_by_chan_id() according recommendations of
Arnd Bergmann;
Part 4/5:
- set DMA_PRIVATE flag for MPC512x DMA controller since its driver relies on
of_dma_xlate_by_chan_id() which doesn't use dma_request_channel()
any more; (removed in v7)
- resolve little patch conflict;
Part 5/5:
- resolve little patch conflict;
Changes in v7:
Part 2:
- improve comment;
Part 4:
- split in two separate patches. Part 4/6 contains device tree
binding document and in part 5/6 MPC512x DMA controller is registered
for device tree channel lookup;
- remove setting DMA_PRIVATE flag for MPC512x DMA controller from part 5/6;
Changes in v8:
Part 2:
- improve comments;
- fix style issues;
Part 6:
- remove since it has become obsolete;
Changes in v9:
A new patch (part 3/6) is added to this series according the
feedback of Andy Shevchenko.
Part 2/6:
- keep style of the comments;
- use is_slave_direction() instead of manual checks;
- remove redundant else branches of the conditions;
- make mpc_dma_device_control() return -ENXIO for unknown command;
Part 6/6:
- change according the new part 3/6;
- fix style issues;
Changes in v10:
Part 2/6:
- don't use direction field of dma_slave_config in mpc_dma_device_control()
but store settings in mpc_dma_chan for both DMA_DEV_TO_MEM and
DMA_MEM_TO_DEV cases; then retrieve the needed values in
mpc_dma_prep_slave_sg();
- fix style issue and put 2014 instead of 2013;
Part 3/6:
- fix mpc_dma_probe() error path and mpc_dma_remove(): manually free IRQs and
dispose IRQ mappings before devm_* takes care of other resources;
Part 6/6:
- change according the new part 3/6;
- fix style issue;
> known issues:
> - it's yet to get confirmed whether MPC8308 can use slave support or
> whether the DMA controller's driver shall actively reject it, the
> information that's available so far suggests that peripheral transfers
> to IP bus attached I/O is useful and shall not get blocked right away
- adding support for transfers which don't increment the RAM address or
do increment the peripheral "port's" address is easy with
this implementation; but which options of the common API
should be used for specifying such transfers?
2014/02/13 Gerhard Sittig <gsi@denx.de>:
> - The MPC512x DMA completely lacks a binding document, so one
> should get added.
> - The MPC8308 hardware is similar and can re-use the MPC512x
> binding, which should be stated.
> - The Linux implementation currently has no OF based channel
> lookup support, so '#dma-cells' is "a future feature". I guess
> the binding can and should already discuss the feature,
> regardless of whether all implementations support it.
Alexander Popov (5):
dma: mpc512x: reorder mpc8308 specific instructions
dma: mpc512x: add support for peripheral transfers
dma: mpc512x: fix freeing resources in mpc_dma_probe() and
mpc_dma_remove()
dma: of: Add common xlate function for matching by channel id
dma: mpc512x: register for device tree channel lookup
Gerhard Sittig (1):
dma: mpc512x: add device tree binding document
.../devicetree/bindings/dma/mpc512x-dma.txt | 55 ++++
arch/powerpc/boot/dts/mpc5121.dtsi | 1 +
drivers/dma/mpc512x_dma.c | 345 ++++++++++++++++++---
drivers/dma/of-dma.c | 35 +++
include/linux/of_dma.h | 4 +
5 files changed, 402 insertions(+), 38 deletions(-)
create mode 100644 Documentation/devicetree/bindings/dma/mpc512x-dma.txt
--
1.8.4.2
^ permalink raw reply
* [PATCH RFC v10 1/6] dma: mpc512x: reorder mpc8308 specific instructions
From: Alexander Popov @ 2014-03-20 14:47 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Andy Shevchenko,
Alexander Popov, linuxppc-dev, dmaengine
In-Reply-To: <1395326878-25243-1-git-send-email-a13xp0p0v88@gmail.com>
Concentrate the specific code for MPC8308 in the 'if' branch
and handle MPC512x in the 'else' branch.
This modification only reorders instructions but doesn't change behaviour.
Signed-off-by: Alexander Popov <a13xp0p0v88@gmail.com>
Acked-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Gerhard Sittig <gsi@denx.de>
---
drivers/dma/mpc512x_dma.c | 42 +++++++++++++++++++++++++-----------------
1 file changed, 25 insertions(+), 17 deletions(-)
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 448750d..2ce248b 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -52,9 +52,17 @@
#define MPC_DMA_DESCRIPTORS 64
/* Macro definitions */
-#define MPC_DMA_CHANNELS 64
#define MPC_DMA_TCD_OFFSET 0x1000
+/*
+ * Maximum channel counts for individual hardware variants
+ * and the maximum channel count over all supported controllers,
+ * used for data structure size
+ */
+#define MPC8308_DMACHAN_MAX 16
+#define MPC512x_DMACHAN_MAX 64
+#define MPC_DMA_CHANNELS 64
+
/* Arbitration mode of group and channel */
#define MPC_DMA_DMACR_EDCG (1 << 31)
#define MPC_DMA_DMACR_ERGA (1 << 3)
@@ -710,10 +718,10 @@ static int mpc_dma_probe(struct platform_device *op)
dma = &mdma->dma;
dma->dev = dev;
- if (!mdma->is_mpc8308)
- dma->chancnt = MPC_DMA_CHANNELS;
+ if (mdma->is_mpc8308)
+ dma->chancnt = MPC8308_DMACHAN_MAX;
else
- dma->chancnt = 16; /* MPC8308 DMA has only 16 channels */
+ dma->chancnt = MPC512x_DMACHAN_MAX;
dma->device_alloc_chan_resources = mpc_dma_alloc_chan_resources;
dma->device_free_chan_resources = mpc_dma_free_chan_resources;
dma->device_issue_pending = mpc_dma_issue_pending;
@@ -747,7 +755,19 @@ static int mpc_dma_probe(struct platform_device *op)
* - Round-robin group arbitration,
* - Round-robin channel arbitration.
*/
- if (!mdma->is_mpc8308) {
+ if (mdma->is_mpc8308) {
+ /* MPC8308 has 16 channels and lacks some registers */
+ out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_ERCA);
+
+ /* enable snooping */
+ out_be32(&mdma->regs->dmagpor, MPC_DMA_DMAGPOR_SNOOP_ENABLE);
+ /* Disable error interrupts */
+ out_be32(&mdma->regs->dmaeeil, 0);
+
+ /* Clear interrupts status */
+ out_be32(&mdma->regs->dmaintl, 0xFFFF);
+ out_be32(&mdma->regs->dmaerrl, 0xFFFF);
+ } else {
out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG |
MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA);
@@ -768,18 +788,6 @@ static int mpc_dma_probe(struct platform_device *op)
/* Route interrupts to IPIC */
out_be32(&mdma->regs->dmaihsa, 0);
out_be32(&mdma->regs->dmailsa, 0);
- } else {
- /* MPC8308 has 16 channels and lacks some registers */
- out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_ERCA);
-
- /* enable snooping */
- out_be32(&mdma->regs->dmagpor, MPC_DMA_DMAGPOR_SNOOP_ENABLE);
- /* Disable error interrupts */
- out_be32(&mdma->regs->dmaeeil, 0);
-
- /* Clear interrupts status */
- out_be32(&mdma->regs->dmaintl, 0xFFFF);
- out_be32(&mdma->regs->dmaerrl, 0xFFFF);
}
/* Register DMA engine */
--
1.8.4.2
^ permalink raw reply related
* [PATCH RFC v10 2/6] dma: mpc512x: add support for peripheral transfers
From: Alexander Popov @ 2014-03-20 14:47 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Andy Shevchenko,
Alexander Popov, linuxppc-dev, dmaengine
In-Reply-To: <1395326878-25243-1-git-send-email-a13xp0p0v88@gmail.com>
Introduce support for slave s/g transfer preparation and the associated
device control callback in the MPC512x DMA controller driver, which adds
support for data transfers between memory and peripheral I/O to the
previously supported mem-to-mem transfers.
Signed-off-by: Alexander Popov <a13xp0p0v88@gmail.com>
---
drivers/dma/mpc512x_dma.c | 239 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 234 insertions(+), 5 deletions(-)
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 2ce248b..68231d9 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -2,6 +2,7 @@
* Copyright (C) Freescale Semicondutor, Inc. 2007, 2008.
* Copyright (C) Semihalf 2009
* Copyright (C) Ilya Yanok, Emcraft Systems 2010
+ * Copyright (C) Alexander Popov, Promcontroller 2014
*
* Written by Piotr Ziecik <kosmo@semihalf.com>. Hardware description
* (defines, structures and comments) was taken from MPC5121 DMA driver
@@ -29,8 +30,17 @@
*/
/*
- * This is initial version of MPC5121 DMA driver. Only memory to memory
- * transfers are supported (tested using dmatest module).
+ * MPC512x and MPC8308 DMA driver. It supports
+ * memory to memory data transfers (tested using dmatest module) and
+ * data transfers between memory and peripheral I/O memory
+ * by means of slave s/g with these limitations:
+ * - chunked transfers (transfers with more than one part) are refused
+ * as long as proper support for scatter/gather is missing;
+ * - transfers on MPC8308 always start from software as this SoC appears
+ * not to have external request lines for peripheral flow control;
+ * - minimal memory <-> I/O memory transfer chunk is 4 bytes and consequently
+ * source and destination addresses must be 4-byte aligned
+ * and transfer size must be aligned on (4 * maxburst) boundary;
*/
#include <linux/module.h>
@@ -189,6 +199,7 @@ struct mpc_dma_desc {
dma_addr_t tcd_paddr;
int error;
struct list_head node;
+ int will_access_peripheral;
};
struct mpc_dma_chan {
@@ -201,6 +212,12 @@ struct mpc_dma_chan {
struct mpc_dma_tcd *tcd;
dma_addr_t tcd_paddr;
+ /* Settings for access to peripheral FIFO */
+ dma_addr_t src_per_paddr;
+ u32 src_tcd_nunits;
+ dma_addr_t dst_per_paddr;
+ u32 dst_tcd_nunits;
+
/* Lock for this structure */
spinlock_t lock;
};
@@ -251,8 +268,23 @@ static void mpc_dma_execute(struct mpc_dma_chan *mchan)
struct mpc_dma_desc *mdesc;
int cid = mchan->chan.chan_id;
- /* Move all queued descriptors to active list */
- list_splice_tail_init(&mchan->queued, &mchan->active);
+ while (!list_empty(&mchan->queued)) {
+ mdesc = list_first_entry(&mchan->queued,
+ struct mpc_dma_desc, node);
+ /*
+ * Grab either several mem-to-mem transfer descriptors
+ * or one peripheral transfer descriptor,
+ * don't mix mem-to-mem and peripheral transfer descriptors
+ * within the same 'active' list.
+ */
+ if (mdesc->will_access_peripheral) {
+ if (list_empty(&mchan->active))
+ list_move_tail(&mdesc->node, &mchan->active);
+ break;
+ } else {
+ list_move_tail(&mdesc->node, &mchan->active);
+ }
+ }
/* Chain descriptors into one transaction */
list_for_each_entry(mdesc, &mchan->active, node) {
@@ -278,7 +310,17 @@ static void mpc_dma_execute(struct mpc_dma_chan *mchan)
if (first != prev)
mdma->tcd[cid].e_sg = 1;
- out_8(&mdma->regs->dmassrt, cid);
+
+ if (mdma->is_mpc8308) {
+ /* MPC8308, no request lines, software initiated start */
+ out_8(&mdma->regs->dmassrt, cid);
+ } else if (first->will_access_peripheral) {
+ /* Peripherals involved, start by external request signal */
+ out_8(&mdma->regs->dmaserq, cid);
+ } else {
+ /* Memory to memory transfer, software initiated start */
+ out_8(&mdma->regs->dmassrt, cid);
+ }
}
/* Handle interrupt on one half of DMA controller (32 channels) */
@@ -596,6 +638,7 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
}
mdesc->error = 0;
+ mdesc->will_access_peripheral = 0;
tcd = mdesc->tcd;
/* Prepare Transfer Control Descriptor for this transaction */
@@ -643,6 +686,189 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
return &mdesc->desc;
}
+static struct dma_async_tx_descriptor *
+mpc_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+ struct mpc_dma_desc *mdesc = NULL;
+ dma_addr_t per_paddr;
+ u32 tcd_nunits;
+ struct mpc_dma_tcd *tcd;
+ unsigned long iflags;
+ struct scatterlist *sg;
+ size_t len;
+ int iter, i;
+
+ /* Currently there is no proper support for scatter/gather */
+ if (sg_len != 1)
+ return NULL;
+
+ if (!is_slave_direction(direction))
+ return NULL;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ spin_lock_irqsave(&mchan->lock, iflags);
+
+ mdesc = list_first_entry(&mchan->free,
+ struct mpc_dma_desc, node);
+ if (!mdesc) {
+ spin_unlock_irqrestore(&mchan->lock, iflags);
+ /* Try to free completed descriptors */
+ mpc_dma_process_completed(mdma);
+ return NULL;
+ }
+
+ list_del(&mdesc->node);
+
+ if (direction == DMA_DEV_TO_MEM) {
+ per_paddr = mchan->src_per_paddr;
+ tcd_nunits = mchan->src_tcd_nunits;
+ } else {
+ per_paddr = mchan->dst_per_paddr;
+ tcd_nunits = mchan->dst_tcd_nunits;
+ }
+
+ spin_unlock_irqrestore(&mchan->lock, iflags);
+
+ if (per_paddr == 0 || tcd_nunits == 0)
+ goto err_prep;
+
+ mdesc->error = 0;
+ mdesc->will_access_peripheral = 1;
+
+ /* Prepare Transfer Control Descriptor for this transaction */
+ tcd = mdesc->tcd;
+
+ memset(tcd, 0, sizeof(struct mpc_dma_tcd));
+
+ if (!IS_ALIGNED(sg_dma_address(sg), 4))
+ goto err_prep;
+
+ if (direction == DMA_DEV_TO_MEM) {
+ tcd->saddr = per_paddr;
+ tcd->daddr = sg_dma_address(sg);
+ tcd->soff = 0;
+ tcd->doff = 4;
+ } else {
+ tcd->saddr = sg_dma_address(sg);
+ tcd->daddr = per_paddr;
+ tcd->soff = 4;
+ tcd->doff = 0;
+ }
+
+ tcd->ssize = MPC_DMA_TSIZE_4;
+ tcd->dsize = MPC_DMA_TSIZE_4;
+
+ len = sg_dma_len(sg);
+ tcd->nbytes = tcd_nunits * 4;
+ if (!IS_ALIGNED(len, tcd->nbytes))
+ goto err_prep;
+
+ iter = len / tcd->nbytes;
+ if (iter >= 1 << 15) {
+ /* len is too big */
+ goto err_prep;
+ }
+ /* citer_linkch contains the high bits of iter */
+ tcd->biter = iter & 0x1ff;
+ tcd->biter_linkch = iter >> 9;
+ tcd->citer = tcd->biter;
+ tcd->citer_linkch = tcd->biter_linkch;
+
+ tcd->e_sg = 0;
+ tcd->d_req = 1;
+
+ /* Place descriptor in prepared list */
+ spin_lock_irqsave(&mchan->lock, iflags);
+ list_add_tail(&mdesc->node, &mchan->prepared);
+ spin_unlock_irqrestore(&mchan->lock, iflags);
+ }
+
+ return &mdesc->desc;
+
+err_prep:
+ /* Put the descriptor back */
+ spin_lock_irqsave(&mchan->lock, iflags);
+ list_add_tail(&mdesc->node, &mchan->free);
+ spin_unlock_irqrestore(&mchan->lock, iflags);
+
+ return NULL;
+}
+
+static int mpc_dma_device_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct mpc_dma_chan *mchan;
+ struct mpc_dma *mdma;
+ struct dma_slave_config *cfg;
+ unsigned long flags;
+
+ mchan = dma_chan_to_mpc_dma_chan(chan);
+ switch (cmd) {
+ case DMA_TERMINATE_ALL:
+ /* Disable channel requests */
+ mdma = dma_chan_to_mpc_dma(chan);
+
+ spin_lock_irqsave(&mchan->lock, flags);
+
+ out_8(&mdma->regs->dmacerq, chan->chan_id);
+ list_splice_tail_init(&mchan->prepared, &mchan->free);
+ list_splice_tail_init(&mchan->queued, &mchan->free);
+ list_splice_tail_init(&mchan->active, &mchan->free);
+
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ return 0;
+ case DMA_SLAVE_CONFIG:
+ /*
+ * Constraints:
+ * - only transfers between a peripheral device and
+ * memory are supported;
+ * - minimal transfer chunk is 4 bytes and consequently
+ * source and destination addresses must be 4-byte aligned
+ * and transfer size must be aligned on (4 * maxburst)
+ * boundary;
+ * - during the transfer RAM address is being incremented by
+ * the size of minimal transfer chunk;
+ * - peripheral port's address is constant during the transfer.
+ */
+
+ cfg = (void *)arg;
+
+ if (cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES ||
+ cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES ||
+ !IS_ALIGNED(cfg->src_addr, 4) ||
+ !IS_ALIGNED(cfg->dst_addr, 4)) {
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&mchan->lock, flags);
+
+ mchan->src_per_paddr = cfg->src_addr;
+ mchan->src_tcd_nunits = cfg->src_maxburst;
+ mchan->dst_per_paddr = cfg->dst_addr;
+ mchan->dst_tcd_nunits = cfg->dst_maxburst;
+
+ /* Apply defaults */
+ if (mchan->src_tcd_nunits == 0)
+ mchan->src_tcd_nunits = 1;
+ if (mchan->dst_tcd_nunits == 0)
+ mchan->dst_tcd_nunits = 1;
+
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ return 0;
+ default:
+ /* Unknown command */
+ break;
+ }
+
+ return -ENXIO;
+}
+
static int mpc_dma_probe(struct platform_device *op)
{
struct device_node *dn = op->dev.of_node;
@@ -727,9 +953,12 @@ static int mpc_dma_probe(struct platform_device *op)
dma->device_issue_pending = mpc_dma_issue_pending;
dma->device_tx_status = mpc_dma_tx_status;
dma->device_prep_dma_memcpy = mpc_dma_prep_memcpy;
+ dma->device_prep_slave_sg = mpc_dma_prep_slave_sg;
+ dma->device_control = mpc_dma_device_control;
INIT_LIST_HEAD(&dma->channels);
dma_cap_set(DMA_MEMCPY, dma->cap_mask);
+ dma_cap_set(DMA_SLAVE, dma->cap_mask);
for (i = 0; i < dma->chancnt; i++) {
mchan = &mdma->channels[i];
--
1.8.4.2
^ permalink raw reply related
* [PATCH RFC v10 3/6] dma: mpc512x: fix freeing resources in mpc_dma_probe() and mpc_dma_remove()
From: Alexander Popov @ 2014-03-20 14:47 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Andy Shevchenko,
Alexander Popov, linuxppc-dev, dmaengine
In-Reply-To: <1395326878-25243-1-git-send-email-a13xp0p0v88@gmail.com>
Fix mpc_dma_probe() error path and mpc_dma_remove(): manually free IRQs and
dispose IRQ mappings before devm_* takes care of other resources.
Moreover replace devm_request_irq() with request_irq() since there is no need
to use it because the original code always frees IRQ manually with
devm_free_irq(). Replace devm_free_irq() with free_irq() accordingly.
Signed-off-by: Alexander Popov <a13xp0p0v88@gmail.com>
---
drivers/dma/mpc512x_dma.c | 55 ++++++++++++++++++++++++++++++++---------------
1 file changed, 38 insertions(+), 17 deletions(-)
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 68231d9..1b90b3b 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -883,13 +883,15 @@ static int mpc_dma_probe(struct platform_device *op)
mdma = devm_kzalloc(dev, sizeof(struct mpc_dma), GFP_KERNEL);
if (!mdma) {
dev_err(dev, "Memory exhausted!\n");
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto err;
}
mdma->irq = irq_of_parse_and_map(dn, 0);
if (mdma->irq == NO_IRQ) {
dev_err(dev, "Error mapping IRQ!\n");
- return -EINVAL;
+ retval = -EINVAL;
+ goto err;
}
if (of_device_is_compatible(dn, "fsl,mpc8308-dma")) {
@@ -897,14 +899,15 @@ static int mpc_dma_probe(struct platform_device *op)
mdma->irq2 = irq_of_parse_and_map(dn, 1);
if (mdma->irq2 == NO_IRQ) {
dev_err(dev, "Error mapping IRQ!\n");
- return -EINVAL;
+ retval = -EINVAL;
+ goto err_dispose1;
}
}
retval = of_address_to_resource(dn, 0, &res);
if (retval) {
dev_err(dev, "Error parsing memory region!\n");
- return retval;
+ goto err_dispose2;
}
regs_start = res.start;
@@ -912,31 +915,34 @@ static int mpc_dma_probe(struct platform_device *op)
if (!devm_request_mem_region(dev, regs_start, regs_size, DRV_NAME)) {
dev_err(dev, "Error requesting memory region!\n");
- return -EBUSY;
+ retval = -EBUSY;
+ goto err_dispose2;
}
mdma->regs = devm_ioremap(dev, regs_start, regs_size);
if (!mdma->regs) {
dev_err(dev, "Error mapping memory region!\n");
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto err_dispose2;
}
mdma->tcd = (struct mpc_dma_tcd *)((u8 *)(mdma->regs)
+ MPC_DMA_TCD_OFFSET);
- retval = devm_request_irq(dev, mdma->irq, &mpc_dma_irq, 0, DRV_NAME,
- mdma);
+ retval = request_irq(mdma->irq, &mpc_dma_irq, 0, DRV_NAME, mdma);
if (retval) {
dev_err(dev, "Error requesting IRQ!\n");
- return -EINVAL;
+ retval = -EINVAL;
+ goto err_dispose2;
}
if (mdma->is_mpc8308) {
- retval = devm_request_irq(dev, mdma->irq2, &mpc_dma_irq, 0,
- DRV_NAME, mdma);
+ retval = request_irq(mdma->irq2, &mpc_dma_irq, 0,
+ DRV_NAME, mdma);
if (retval) {
dev_err(dev, "Error requesting IRQ2!\n");
- return -EINVAL;
+ retval = -EINVAL;
+ goto err_free1;
}
}
@@ -1022,12 +1028,23 @@ static int mpc_dma_probe(struct platform_device *op)
/* Register DMA engine */
dev_set_drvdata(dev, mdma);
retval = dma_async_device_register(dma);
- if (retval) {
- devm_free_irq(dev, mdma->irq, mdma);
- irq_dispose_mapping(mdma->irq);
- }
+ if (retval)
+ goto err_free2;
return retval;
+
+err_free2:
+ if (mdma->is_mpc8308)
+ free_irq(mdma->irq2, mdma);
+err_free1:
+ free_irq(mdma->irq, mdma);
+err_dispose2:
+ if (mdma->is_mpc8308)
+ irq_dispose_mapping(mdma->irq2);
+err_dispose1:
+ irq_dispose_mapping(mdma->irq);
+err:
+ return retval;
}
static int mpc_dma_remove(struct platform_device *op)
@@ -1036,7 +1053,11 @@ static int mpc_dma_remove(struct platform_device *op)
struct mpc_dma *mdma = dev_get_drvdata(dev);
dma_async_device_unregister(&mdma->dma);
- devm_free_irq(dev, mdma->irq, mdma);
+ if (mdma->is_mpc8308) {
+ free_irq(mdma->irq2, mdma);
+ irq_dispose_mapping(mdma->irq2);
+ }
+ free_irq(mdma->irq, mdma);
irq_dispose_mapping(mdma->irq);
return 0;
--
1.8.4.2
^ permalink raw reply related
* [PATCH RFC v10 4/6] dma: of: Add common xlate function for matching by channel id
From: Alexander Popov @ 2014-03-20 14:47 UTC (permalink / raw)
To: Gerhard Sittig, Dan Williams, Vinod Koul, Lars-Peter Clausen,
Arnd Bergmann, Anatolij Gustschin, Andy Shevchenko,
Alexander Popov, linuxppc-dev, dmaengine
Cc: devicetree
In-Reply-To: <1395326878-25243-1-git-send-email-a13xp0p0v88@gmail.com>
This patch adds a new common OF dma xlate callback function which will match a
channel by it's id. The binding expects one integer argument which it will use to
lookup the channel by the id.
Unlike of_dma_simple_xlate this function is able to handle a system with
multiple DMA controllers. When registering the of dma provider with
of_dma_controller_register a pointer to the dma_device struct which is
associated with the dt node needs to passed as the data parameter.
New function will use this pointer to match only channels which belong to the
specified DMA controller.
Signed-off-by: Alexander Popov <a13xp0p0v88@gmail.com>
---
drivers/dma/of-dma.c | 35 +++++++++++++++++++++++++++++++++++
include/linux/of_dma.h | 4 ++++
2 files changed, 39 insertions(+)
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index e8fe9dc..d5fbeaa 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -218,3 +218,38 @@ struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
&dma_spec->args[0]);
}
EXPORT_SYMBOL_GPL(of_dma_simple_xlate);
+
+/**
+ * of_dma_xlate_by_chan_id - Translate dt property to DMA channel by channel id
+ * @dma_spec: pointer to DMA specifier as found in the device tree
+ * @of_dma: pointer to DMA controller data
+ *
+ * This function can be used as the of xlate callback for DMA driver which wants
+ * to match the channel based on the channel id. When using this xlate function
+ * the #dma-cells propety of the DMA controller dt node needs to be set to 1.
+ * The data parameter of of_dma_controller_register must be a pointer to the
+ * dma_device struct the function should match upon.
+ *
+ * Returns pointer to appropriate dma channel on success or NULL on error.
+ */
+struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct dma_device *dev = ofdma->of_dma_data;
+ struct dma_chan *chan, *candidate = NULL;
+
+ if (!dev || dma_spec->args_count != 1)
+ return NULL;
+
+ list_for_each_entry(chan, &dev->channels, device_node)
+ if (chan->chan_id == dma_spec->args[0]) {
+ candidate = chan;
+ break;
+ }
+
+ if (!candidate)
+ return NULL;
+
+ return dma_get_slave_channel(candidate);
+}
+EXPORT_SYMBOL_GPL(of_dma_xlate_by_chan_id);
diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
index ae36298..56bc026 100644
--- a/include/linux/of_dma.h
+++ b/include/linux/of_dma.h
@@ -41,6 +41,8 @@ extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
const char *name);
extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma);
+extern struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma);
#else
static inline int of_dma_controller_register(struct device_node *np,
struct dma_chan *(*of_dma_xlate)
@@ -66,6 +68,8 @@ static inline struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_s
return NULL;
}
+#define of_dma_xlate_by_chan_id NULL
+
#endif
#endif /* __LINUX_OF_DMA_H */
--
1.8.4.2
^ permalink raw reply related
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