* Re: [PATCH v2] pack-objects: fix performance issues on packing large deltas
From: Junio C Hamano @ 2018-07-23 18:04 UTC (permalink / raw)
To: Nguyễn Thái Ngọc Duy; +Cc: git, Elijah Newren, Jeff King
In-Reply-To: <20180722080421.12887-1-pclouds@gmail.com>
Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:
> Access to e->delta_size_ (and by extension
> pack->delta_size[e - pack->objects]) is unprotected as before, the
> thread scheduler in pack-objects must make sure "e" is never updated
> by two different threads.
OK. Do we need to worry about "e" (e.g. "e->delta_size_valid")
being accessed while/before it is set by another thread?
oe_delta_size() makes unprotected accesses to .delta_size_ and
pack->delta_size[e - pack->objects], so we apparently do not, and
oe_set_delta_size() only protects the allocation call and does not
prevent a reader in oe_delta_size() from first reading the _valid
field, noticing that it is 0 as initialized, and goes on to read the
pack->delta_size[] slot for the entry, while the writer is setting
the size to .delta_size_ field and flipping _valid bit, without ever
storing the size in the pack->delta_size[] array.
> @@ -130,6 +131,7 @@ struct packing_data {
> uint32_t index_size;
>
> unsigned int *in_pack_pos;
> + unsigned long *delta_size;
>
> /*
> * Only one of these can be non-NULL and they have different
> @@ -140,10 +142,29 @@ struct packing_data {
> struct packed_git **in_pack_by_idx;
> struct packed_git **in_pack;
>
> +#ifndef NO_PTHREADS
> + pthread_mutex_t lock;
I am wondering if we want the variable to say what data it is
protecting from simultaneous accesses, or leave it as generic so
that any new caller that wants to lock any (new) thing that is
associated with a packing_data structure can grab it for other
purposes. The design of this patch clearly is the latter, which is
OK for now, I think.
> @@ -332,18 +353,34 @@ static inline unsigned long oe_delta_size(struct packing_data *pack,
> {
> if (e->delta_size_valid)
> return e->delta_size_;
> - return oe_size(pack, e);
> +
> + /*
> + * pack->detla_size[] can't be NULL because oe_set_delta_size()
> + * must have been called when a new delta is saved with
> + * oe_set_delta().
> + * If oe_delta() returns NULL (i.e. default state, which means
> + * delta_size_valid is also false), then the caller must never
> + * call oe_delta_size().
> + */
> + return pack->delta_size[e - pack->objects];
> }
>
> static inline void oe_set_delta_size(struct packing_data *pack,
> struct object_entry *e,
> unsigned long size)
> {
> - e->delta_size_ = size;
> - e->delta_size_valid = e->delta_size_ == size;
> - if (!e->delta_size_valid && size != oe_size(pack, e))
> - BUG("this can only happen in check_object() "
> - "where delta size is the same as entry size");
> + if (size < pack->oe_delta_size_limit) {
> + e->delta_size_ = size;
> + e->delta_size_valid = 1;
> + } else {
> + packing_data_lock(pack);
> + if (!pack->delta_size)
> + ALLOC_ARRAY(pack->delta_size, pack->nr_alloc);
> + packing_data_unlock(pack);
> +
> + pack->delta_size[e - pack->objects] = size;
> + e->delta_size_valid = 0;
> + }
> }
^ permalink raw reply
* Re: [PATCH 2/2] media: usb: pwc: Don't use coherent DMA buffers for ISO transfer
From: Matwey V. Kornilov @ 2018-07-23 17:04 UTC (permalink / raw)
To: Tomasz Figa
Cc: Alan Stern, Ezequiel Garcia, Hans de Goede, Hans Verkuil,
Mauro Carvalho Chehab, Laurent Pinchart, Steven Rostedt, mingo,
Mike Isely, Bhumika Goyal, Colin King, Linux Media Mailing List,
Linux Kernel Mailing List, Kieran Bingham, keiichiw
In-Reply-To: <CAJs94EaXpiHaJS0M7SxUtmjNAL869sPe9XpC1rorHgJOum-Oog@mail.gmail.com>
2018-07-20 14:57 GMT+03:00 Matwey V. Kornilov <matwey@sai.msu.ru>:
> 2018-07-20 14:33 GMT+03:00 Tomasz Figa <tfiga@chromium.org>:
>> On Fri, Jul 20, 2018 at 8:23 PM Matwey V. Kornilov <matwey@sai.msu.ru> wrote:
>>>
>>> 2018-07-20 13:55 GMT+03:00 Tomasz Figa <tfiga@chromium.org>:
>>> > On Wed, Jul 18, 2018 at 5:51 AM Alan Stern <stern@rowland.harvard.edu> wrote:
>>> >>
>>> >> On Tue, 17 Jul 2018, Ezequiel Garcia wrote:
>>> >>
>>> >> > Hi Matwey,
>>> >> >
>>> >> > First of all, sorry for the delay.
>>> >> >
>>> >> > Adding Alan and Hans. Guys, do you have any feedback here?
>>> >>
>>> >> ...
>>> >>
>>> >> > > > So, what is the benefit of using consistent
>>> >> > > > for these URBs, as opposed to streaming?
>>> >> > >
>>> >> > > I don't know, I think there is no real benefit and all we see is a
>>> >> > > consequence of copy-pasta when some webcam drivers were inspired by
>>> >> > > others and development priparily was going at x86 platforms.
>>> >> >
>>> >> > You are probably right about the copy-pasta.
>>> >> >
>>> >> > > It would
>>> >> > > be great if somebody corrected me here. DMA Coherence is quite strong
>>> >> > > property and I cannot figure out how can it help when streaming video.
>>> >> > > The CPU host always reads from the buffer and never writes to.
>>> >> > > Hardware perepherial always writes to and never reads from. Moreover,
>>> >> > > buffer access is mutually exclusive and separated in time by Interrupt
>>> >> > > fireing and URB starting (when we reuse existing URB for new request).
>>> >> > > Only single one memory barrier is really required here.
>>> >> > >
>>> >> >
>>> >> > Yeah, and not setting URB_NO_TRANSFER_DMA_MAP makes the USB core
>>> >> > create DMA mappings and use the streaming API. Which makes more
>>> >> > sense in hardware without hardware coherency.
>>> >>
>>> >> As far as I know, the _only_ advantage to using coherent DMA in this
>>> >> situation is that you then do not have to pay the overhead of
>>> >> constantly setting up and tearing down the streaming mappings. So it
>>> >> depends very much on the platform: If coherent buffers are cached then
>>> >> it's a slight win and otherwise it's a big lose.
>>> >
>>> > Isn't it about usb_alloc_coherent() being backed by DMA coherent API
>>> > (dma_alloc_coherent/attrs()) and ending up allocating uncached (or
>>> > write-combine) memory for devices with non-coherent DMAs? I'm not sure
>>>
>>> Yes, this is what exactly happens at armv7l platforms.
>>
>> Okay, thanks. So this seems to be exactly the same thing that is
>> happening in the UVC driver. There is quite a bit of random accesses
>> to extract some header fields and then a big memcpy into VB2 buffer to
>> assemble final frame.
>>
>> If we don't want to pay the cost of creating and destroying the
>> streaming mapping, we could map (dma_map_single()) once, set
>> transfer_dma of URB and URB_NO_TRANSFER_DMA_MAP and then just
>> synchronize the caches (dma_sync_single()) before submitting/after
>> completing the URB.
>
> Thank you. Now it is becoming clearer to me. Please allow me some time
> to try to sketch the implementation.
I've tried to strategies:
1) Use dma_unmap and dma_map inside the handler (I suppose this is
similar to how USB core does when there is no URB_NO_TRANSFER_DMA_MAP)
2) Use sync_cpu and sync_device inside the handler (and dma_map only
once at memory allocation)
It is interesting that dma_unmap/dma_map pair leads to the lower
overhead (+1us) than sync_cpu/sync_device (+2us) at x86_64 platform.
At armv7l platform using dma_unmap/dma_map leads to ~50 usec in the
handler, and sync_cpu/sync_device - ~65 usec.
However, I am not sure is it mandatory to call
dma_sync_single_for_device for FROM_DEVICE direction?
>
>>
>> Best regards,
>> Tomasz
>>
>
>
>
> --
> With best regards,
> Matwey V. Kornilov.
> Sternberg Astronomical Institute, Lomonosov Moscow State University, Russia
> 119234, Moscow, Universitetsky pr-k 13, +7 (495) 9392382
--
With best regards,
Matwey V. Kornilov.
Sternberg Astronomical Institute, Lomonosov Moscow State University, Russia
119234, Moscow, Universitetsky pr-k 13, +7 (495) 9392382
^ permalink raw reply
* Re: [PATCH] i2c: davinci: Avoid zero value of CLKH
From: Wolfram Sang @ 2018-07-23 18:07 UTC (permalink / raw)
To: Alexander Sverdlin; +Cc: Sekhar Nori, linux-i2c, linux-arm-kernel, Kevin Hilman
In-Reply-To: <20180713152017.2207-1-alexander.sverdlin@nokia.com>
[-- Attachment #1.1: Type: text/plain, Size: 521 bytes --]
On Fri, Jul 13, 2018 at 05:20:17PM +0200, Alexander Sverdlin wrote:
> If CLKH is set to 0 I2C clock is not generated at all, so avoid this value
> and stretch the clock in this case.
>
> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
Applied to for-current, thanks!
I did not add stable because Alexander told me this is very likely not
to be observed on HW out there. But TI people are investigating more.
I suggest they resend this patch to stable if they see fit. D'accord
everyone?
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] i2c: davinci: Avoid zero value of CLKH
From: Wolfram Sang @ 2018-07-23 18:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180713152017.2207-1-alexander.sverdlin@nokia.com>
On Fri, Jul 13, 2018 at 05:20:17PM +0200, Alexander Sverdlin wrote:
> If CLKH is set to 0 I2C clock is not generated at all, so avoid this value
> and stretch the clock in this case.
>
> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
Applied to for-current, thanks!
I did not add stable because Alexander told me this is very likely not
to be observed on HW out there. But TI people are investigating more.
I suggest they resend this patch to stable if they see fit. D'accord
everyone?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180723/8ea58ced/attachment.sig>
^ permalink raw reply
* [PATCH] media: dw2102: Fix memleak on sequence of probes
From: Anton Vasilyev @ 2018-07-23 17:04 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Anton Vasilyev, Jonathan Corbet, Enrico Mioso, Bhumika Goyal,
Sean Young, linux-media, linux-kernel, ldv-project
Each call to dw2102_probe() allocates memory by kmemdup for structures
p1100, s660, p7500 and s421, but there is no their deallocation.
dvb_usb_device_init() copies the corresponding structure into
dvb_usb_device->props, so there is no use of original structure after
dvb_usb_device_init().
The patch moves structures from global scope to local and adds their
deallocation.
Found by Linux Driver Verification project (linuxtesting.org).
Signed-off-by: Anton Vasilyev <vasilyev@ispras.ru>
---
drivers/media/usb/dvb-usb/dw2102.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index 0d4fdd34a710..9ce8b4d79d1f 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -2101,14 +2101,12 @@ static struct dvb_usb_device_properties s6x0_properties = {
}
};
-static struct dvb_usb_device_properties *p1100;
static const struct dvb_usb_device_description d1100 = {
"Prof 1100 USB ",
{&dw2102_table[PROF_1100], NULL},
{NULL},
};
-static struct dvb_usb_device_properties *s660;
static const struct dvb_usb_device_description d660 = {
"TeVii S660 USB",
{&dw2102_table[TEVII_S660], NULL},
@@ -2127,14 +2125,12 @@ static const struct dvb_usb_device_description d480_2 = {
{NULL},
};
-static struct dvb_usb_device_properties *p7500;
static const struct dvb_usb_device_description d7500 = {
"Prof 7500 USB DVB-S2",
{&dw2102_table[PROF_7500], NULL},
{NULL},
};
-static struct dvb_usb_device_properties *s421;
static const struct dvb_usb_device_description d421 = {
"TeVii S421 PCI",
{&dw2102_table[TEVII_S421], NULL},
@@ -2334,6 +2330,11 @@ static int dw2102_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
int retval = -ENOMEM;
+ struct dvb_usb_device_properties *p1100;
+ struct dvb_usb_device_properties *s660;
+ struct dvb_usb_device_properties *p7500;
+ struct dvb_usb_device_properties *s421;
+
p1100 = kmemdup(&s6x0_properties,
sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
if (!p1100)
@@ -2402,8 +2403,16 @@ static int dw2102_probe(struct usb_interface *intf,
0 == dvb_usb_device_init(intf, &t220_properties,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &tt_s2_4600_properties,
- THIS_MODULE, NULL, adapter_nr))
+ THIS_MODULE, NULL, adapter_nr)) {
+
+ /* clean up copied properties */
+ kfree(s421);
+ kfree(p7500);
+ kfree(s660);
+ kfree(p1100);
+
return 0;
+ }
retval = -ENODEV;
kfree(s421);
--
2.18.0
^ permalink raw reply related
* Re: [PATCH net-next] wan/fsl_ucc_hdlc: use IS_ERR_VALUE() to check return value of qe_muram_alloc
From: David Miller @ 2018-07-23 18:07 UTC (permalink / raw)
To: yuehaibing; +Cc: qiang.zhao, linux-kernel, netdev, linuxppc-dev
In-Reply-To: <20180723141233.19948-1-yuehaibing@huawei.com>
From: YueHaibing <yuehaibing@huawei.com>
Date: Mon, 23 Jul 2018 22:12:33 +0800
> qe_muram_alloc return a unsigned long integer,which should not
> compared with zero. check it using IS_ERR_VALUE() to fix this.
>
> Fixes: c19b6d246a35 ("drivers/net: support hdlc function for QE-UCC")
> Signed-off-by: YueHaibing <yuehaibing@huawei.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH v2 1/4] i2c: imx: Fix reinit_completion() use
From: Wolfram Sang @ 2018-07-23 18:08 UTC (permalink / raw)
To: Esben Haabendal
Cc: linux-i2c, Wolfram Sang, Uwe Kleine-König, Rob Herring,
Mark Rutland, Yuan Yao, Esben Haabendal, Phil Reid, Lucas Stach,
Linus Walleij, Peter Rosin, Fabio Estevam, linux-kernel
In-Reply-To: <20180709094304.8814-2-esben.haabendal@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 607 bytes --]
On Mon, Jul 09, 2018 at 11:43:01AM +0200, Esben Haabendal wrote:
> From: Esben Haabendal <eha@deif.com>
>
> Make sure to call reinit_completion() before dma is started to avoid race
> condition where reinit_completion() is called after complete() and before
> wait_for_completion_timeout().
>
> Signed-off-by: Esben Haabendal <eha@deif.com>
> Fixes: ce1a78840ff7 ("i2c: imx: add DMA support for freescale i2c driver")
> Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Applied to for-current and added stable, thanks!
Uwe, do you have comments for the other patches, too?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH 1/2] t3507: add a testcase showing failure with sparse checkout
From: Eric Sunshine @ 2018-07-23 18:09 UTC (permalink / raw)
To: Ben Peart; +Cc: Elijah Newren, Git List, Junio C Hamano, Ben Peart, kewillf
In-Reply-To: <b56598a1-e543-500a-a39b-cee07fe1e533@gmail.com>
On Mon, Jul 23, 2018 at 9:12 AM Ben Peart <peartben@gmail.com> wrote:
> On 7/21/2018 3:21 AM, Eric Sunshine wrote:
> > On Sat, Jul 21, 2018 at 2:34 AM Elijah Newren <newren@gmail.com> wrote:
> >> + rm .git/info/sparse-checkout
> >
> > Should this cleanup be done by test_when_finished()?
>
> I think trying to use test_when_finished() for this really degrades the
> readability of the test. See below:
>
> test_expect_success 'failed cherry-pick with sparse-checkout' '
> pristine_detach initial &&
> test_config core.sparsecheckout true &&
> echo /unrelated >.git/info/sparse-checkout &&
> git read-tree --reset -u HEAD &&
> test_when_finished "echo \"/*\" >.git/info/sparse-checkout && git
> read-tree --reset -u HEAD && rm .git/info/sparse-checkout" &&
> test_must_fail git cherry-pick -Xours picked>actual &&
> test_i18ngrep ! "Changes not staged for commit:" actual
> '
>
> Given it takes multiple commands, I'd prefer to keep the setup and
> cleanup of the sparse checkout settings symmetrical.
Some observations:
The test_when_finished() ought to be called before the initial
git-read-tree, otherwise you risk leaving a .git/info/sparse-checkout
sitting around if git-read-tree fails.
The tear-down code could be moved to a function, in which case,
test_when_finished() would simply call that function.
Multi-line quoted strings are valid, so you don't need to string out
all the tear-down steps on a single line like that, and instead spread
them across multiple lines to improve readability.
test_when_finished() doesn't expect just a single quoted string as
argument. In fact, it can take many (unquoted) arguments, which also
allows you to spread the tear-down steps over multiple lines to
improve readability.
Multiple test_when_finished() invocations are allowed, so you could
spread out the tear-down commands that way (though they'd have to be
in reverse order, which would be bad for readability in this case,
thus not recommended).
Correctness ought to trump readability, not the other way around.
So, one possibility, which seems pretty readable to me:
test_expect_failure 'failed cherry-pick with sparse-checkout' '
pristine_detach initial &&
test_config core.sparseCheckout true &&
test_when_finished "
echo \"/*\" >.git/info/sparse-checkout
git read-tree --reset -u HEAD
rm .git/info/sparse-checkout" &&
echo /unrelated >.git/info/sparse-checkout &&
git read-tree --reset -u HEAD &&
test_must_fail git cherry-pick -Xours picked>actual &&
test_i18ngrep ! "Changes not staged for commit:" actual &&
'
Notice that I dropped the internal &&-chain in test_when_finish() to
ensure that the final 'rm' is invoked even if the cleanup
git-read-tree fails (though all bets are probably off, anyhow, if it
does fail).
^ permalink raw reply
* Re: [PATCH] btrfs: fix size_t format string
From: Randy Dunlap @ 2018-07-23 17:07 UTC (permalink / raw)
To: dsterba, Arnd Bergmann, Chris Mason, Josef Bacik, David Sterba,
Qu Wenruo, Nikolay Borisov, Su Yue, linux-btrfs, linux-kernel
In-Reply-To: <20180717150400.GA3126@twin.jikos.cz>
On 07/17/2018 08:04 AM, David Sterba wrote:
> On Tue, Jul 17, 2018 at 03:52:27PM +0200, Arnd Bergmann wrote:
>> The newly added check_block_group_item() function causes a build warning
>> on 32-bit architectures:
>>
>> fs/btrfs/tree-checker.c: In function 'check_block_group_item':
>> fs/btrfs/tree-checker.c:404:41: error: format '%lu' expects argument of type 'long unsigned int', but argument 6 has type 'unsigned int' [-Werror=format=]
>>
>> The type of a sizeof() expression is size_t, which is correctly printed
>> using the %zu format string.
>>
>> Fixes: 9dc16aad5660 ("btrfs: tree-checker: Verify block_group_item")
>
> Folded to the commit, thanks.
>
Hi David,
Where did this patch end up? linux-next-20180723 is still showing this
format warning.
thanks,
--
~Randy
^ permalink raw reply
* [PATCH i2c-next] i2c: aspeed: Handle master/slave combined irq events properly
From: James Feist @ 2018-07-23 18:10 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <20180723174808.4007-1-jae.hyun.yoo@linux.intel.com>
On 07/23/2018 10:48 AM, Jae Hyun Yoo wrote:
> In most of cases, interrupt bits are set one by one but there are
> also a lot of other cases that Aspeed I2C IP sends multiple
> interrupt bits with combining master and slave events using a
> single interrupt call. It happens much in multi-master environment
much more
> than single-master. For an example, when master is waiting for a
> NORMAL_STOP interrupt in its MASTER_STOP state, SLAVE_MATCH and
> RX_DONE interrupts could come along with the NORMAL_STOP in case of
> an another master immediately sends data just after acquiring the
> bus. In this case, the NORMAL_STOP interrupt should be handled
> by master_irq and the SLAVE_MATCH and RX_DONE interrupts should be
> handled by slave_irq. This commit modifies irq hadling logic to
> handle the master/slave combined events properly.
>
> Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
> ---
> drivers/i2c/busses/i2c-aspeed.c | 137 ++++++++++++++++++--------------
> 1 file changed, 76 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
> index efb89422d496..24d43f143a55 100644
> --- a/drivers/i2c/busses/i2c-aspeed.c
> +++ b/drivers/i2c/busses/i2c-aspeed.c
> @@ -82,6 +82,11 @@
> #define ASPEED_I2CD_INTR_RX_DONE BIT(2)
> #define ASPEED_I2CD_INTR_TX_NAK BIT(1)
> #define ASPEED_I2CD_INTR_TX_ACK BIT(0)
> +#define ASPEED_I2CD_INTR_ERRORS \
> + (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
> + ASPEED_I2CD_INTR_SCL_TIMEOUT | \
> + ASPEED_I2CD_INTR_ABNORMAL | \
> + ASPEED_I2CD_INTR_ARBIT_LOSS)
> #define ASPEED_I2CD_INTR_ALL \
> (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
> ASPEED_I2CD_INTR_BUS_RECOVER_DONE | \
> @@ -150,6 +155,7 @@ struct aspeed_i2c_bus {
> int cmd_err;
> /* Protected only by i2c_lock_bus */
> int master_xfer_result;
> + u32 irq_status;
> #if IS_ENABLED(CONFIG_I2C_SLAVE)
> struct i2c_client *slave;
> enum aspeed_i2c_slave_state slave_state;
> @@ -229,36 +235,30 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
> #if IS_ENABLED(CONFIG_I2C_SLAVE)
> static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
> {
> - u32 command, irq_status, status_ack = 0;
> + u32 command, status_ack = 0;
> struct i2c_client *slave = bus->slave;
> - bool irq_handled = true;
> u8 value;
>
> - if (!slave) {
> - irq_handled = false;
> - goto out;
> - }
> + if (!slave)
> + return false;
>
> command = readl(bus->base + ASPEED_I2C_CMD_REG);
> - irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
>
> /* Slave was requested, restart state machine. */
> - if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
> status_ack |= ASPEED_I2CD_INTR_SLAVE_MATCH;
> bus->slave_state = ASPEED_I2C_SLAVE_START;
> }
>
> /* Slave is not currently active, irq was for someone else. */
> - if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) {
> - irq_handled = false;
> - goto out;
> - }
> + if (bus->slave_state == ASPEED_I2C_SLAVE_STOP)
> + return false;
>
> dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
> - irq_status, command);
> + bus->irq_status, command);
>
> /* Slave was sent something. */
> - if (irq_status & ASPEED_I2CD_INTR_RX_DONE) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_RX_DONE) {
> value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
> /* Handle address frame. */
> if (bus->slave_state == ASPEED_I2C_SLAVE_START) {
> @@ -273,28 +273,29 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
> }
>
> /* Slave was asked to stop. */
> - if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
> status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
> bus->slave_state = ASPEED_I2C_SLAVE_STOP;
> }
> - if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_TX_NAK) {
> status_ack |= ASPEED_I2CD_INTR_TX_NAK;
> bus->slave_state = ASPEED_I2C_SLAVE_STOP;
> }
> + if (bus->irq_status & ASPEED_I2CD_INTR_TX_ACK) {
> + status_ack |= ASPEED_I2CD_INTR_TX_ACK;
> + }
>
> switch (bus->slave_state) {
> case ASPEED_I2C_SLAVE_READ_REQUESTED:
> - if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
> + if (bus->irq_status & ASPEED_I2CD_INTR_TX_ACK)
> dev_err(bus->dev, "Unexpected ACK on read request.\n");
> bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
> -
> i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
> writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
> writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
> break;
> case ASPEED_I2C_SLAVE_READ_PROCESSED:
> - status_ack |= ASPEED_I2CD_INTR_TX_ACK;
> - if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
> + if (!(bus->irq_status & ASPEED_I2CD_INTR_TX_ACK))
> dev_err(bus->dev,
> "Expected ACK after processed read.\n");
> i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
> @@ -317,14 +318,8 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
> break;
> }
>
> - if (status_ack != irq_status)
> - dev_err(bus->dev,
> - "irq handled != irq. expected %x, but was %x\n",
> - irq_status, status_ack);
> - writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG);
> -
> -out:
> - return irq_handled;
> + bus->irq_status ^= status_ack;
> + return !bus->irq_status;
> }
> #endif /* CONFIG_I2C_SLAVE */
>
> @@ -382,19 +377,19 @@ static int aspeed_i2c_is_irq_error(u32 irq_status)
>
> static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> {
> - u32 irq_status, status_ack = 0, command = 0;
> + u32 status_ack = 0, command = 0;
> struct i2c_msg *msg;
> u8 recv_byte;
> int ret;
>
> - irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
> - /* Ack all interrupt bits. */
> - writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG);
> -
> - if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
> bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
> status_ack |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
> goto out_complete;
> + } else {
> + /* Master is not currently active, irq was for someone else. */
> + if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE)
> + goto out_no_complete;
> }
>
> /*
> @@ -402,20 +397,23 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> * should clear the command queue effectively taking us back to the
> * INACTIVE state.
> */
> - ret = aspeed_i2c_is_irq_error(irq_status);
> - if (ret < 0) {
> + ret = aspeed_i2c_is_irq_error(bus->irq_status);
> + if (ret) {
> dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
> - irq_status);
> + bus->irq_status);
> bus->cmd_err = ret;
> bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
> + status_ack |= (bus->irq_status & ASPEED_I2CD_INTR_ERRORS);
> goto out_complete;
> }
>
> /* We are in an invalid state; reset bus to a known state. */
> if (!bus->msgs) {
> - dev_err(bus->dev, "bus in unknown state\n");
> + dev_err(bus->dev, "bus in unknown state irq_status: 0x%x\n",
> + bus->irq_status);
> bus->cmd_err = -EIO;
> - if (bus->master_state != ASPEED_I2C_MASTER_STOP)
> + if (bus->master_state != ASPEED_I2C_MASTER_STOP &&
> + bus->master_state != ASPEED_I2C_MASTER_INACTIVE)
> aspeed_i2c_do_stop(bus);
> goto out_no_complete;
> }
> @@ -427,8 +425,14 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> * then update the state and handle the new state below.
> */
> if (bus->master_state == ASPEED_I2C_MASTER_START) {
> - if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
> - pr_devel("no slave present at %02x\n", msg->addr);
> + if (unlikely(!(bus->irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
> + if (unlikely(!(bus->irq_status &
> + ASPEED_I2CD_INTR_TX_NAK))) {
> + bus->cmd_err = -ENXIO;
> + bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
> + goto out_complete;
> + }
> + pr_devel("no slave present at %02x", msg->addr);
Missing line feed character
> status_ack |= ASPEED_I2CD_INTR_TX_NAK;
> bus->cmd_err = -ENXIO;
> aspeed_i2c_do_stop(bus);
> @@ -447,11 +451,12 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
>
> switch (bus->master_state) {
> case ASPEED_I2C_MASTER_TX:
> - if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
> + if (unlikely(bus->irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
> dev_dbg(bus->dev, "slave NACKed TX\n");
> status_ack |= ASPEED_I2CD_INTR_TX_NAK;
> goto error_and_stop;
> - } else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
> + } else if (unlikely(!(bus->irq_status &
> + ASPEED_I2CD_INTR_TX_ACK))) {
> dev_err(bus->dev, "slave failed to ACK TX\n");
> goto error_and_stop;
> }
> @@ -470,11 +475,11 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> goto out_no_complete;
> case ASPEED_I2C_MASTER_RX_FIRST:
> /* RX may not have completed yet (only address cycle) */
> - if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE))
> + if (!(bus->irq_status & ASPEED_I2CD_INTR_RX_DONE))
> goto out_no_complete;
> /* fallthrough intended */
> case ASPEED_I2C_MASTER_RX:
> - if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
> + if (unlikely(!(bus->irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
> dev_err(bus->dev, "master failed to RX\n");
> goto error_and_stop;
> }
> @@ -505,8 +510,11 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> }
> goto out_no_complete;
> case ASPEED_I2C_MASTER_STOP:
> - if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) {
> - dev_err(bus->dev, "master failed to STOP\n");
> + if (unlikely(!(bus->irq_status &
> + ASPEED_I2CD_INTR_NORMAL_STOP))) {
> + dev_err(bus->dev,
> + "master failed to STOP irq_status:0x%x\n",
> + bus->irq_status);
> bus->cmd_err = -EIO;
> /* Do not STOP as we have already tried. */
> } else {
> @@ -518,7 +526,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> case ASPEED_I2C_MASTER_INACTIVE:
> dev_err(bus->dev,
> "master received interrupt 0x%08x, but is inactive\n",
> - irq_status);
> + bus->irq_status);
> bus->cmd_err = -EIO;
> /* Do not STOP as we should be inactive. */
> goto out_complete;
> @@ -540,33 +548,40 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> bus->master_xfer_result = bus->msgs_index + 1;
> complete(&bus->cmd_complete);
> out_no_complete:
> - if (irq_status != status_ack)
> - dev_err(bus->dev,
> - "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
> - irq_status, status_ack);
> - return !!irq_status;
> + bus->irq_status ^= status_ack;
> + return !bus->irq_status;
> }
>
> static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
> {
> struct aspeed_i2c_bus *bus = dev_id;
> - bool ret;
> + u32 irq_received;
>
> spin_lock(&bus->lock);
> + irq_received = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
> + bus->irq_status = irq_received;
>
> #if IS_ENABLED(CONFIG_I2C_SLAVE)
> - if (aspeed_i2c_slave_irq(bus)) {
> - dev_dbg(bus->dev, "irq handled by slave.\n");
> - ret = true;
> - goto out;
> + if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
> + if (!aspeed_i2c_master_irq(bus))
> + aspeed_i2c_slave_irq(bus);
> + } else {
> + if (!aspeed_i2c_slave_irq(bus))
> + aspeed_i2c_master_irq(bus);
> }
> +#else
> + aspeed_i2c_master_irq(bus);
> #endif /* CONFIG_I2C_SLAVE */
>
> - ret = aspeed_i2c_master_irq(bus);
> + if (bus->irq_status)
> + dev_err(bus->dev,
> + "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
> + irq_received, irq_received ^ bus->irq_status);
>
> -out:
> + /* Ack all interrupt bits. */
> + writel(irq_received, bus->base + ASPEED_I2C_INTR_STS_REG);
> spin_unlock(&bus->lock);
> - return ret ? IRQ_HANDLED : IRQ_NONE;
> + return bus->irq_status ? IRQ_NONE : IRQ_HANDLED;
> }
>
> static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
>
^ permalink raw reply
* Re: [PATCH i2c-next] i2c: aspeed: Handle master/slave combined irq events properly
From: James Feist @ 2018-07-23 18:10 UTC (permalink / raw)
To: Jae Hyun Yoo, Brendan Higgins, Benjamin Herrenschmidt,
Joel Stanley, Andrew Jeffery, linux-i2c, openbmc,
linux-arm-kernel, linux-aspeed, linux-kernel
Cc: Vernon Mauery, Jarkko Nikula
In-Reply-To: <20180723174808.4007-1-jae.hyun.yoo@linux.intel.com>
On 07/23/2018 10:48 AM, Jae Hyun Yoo wrote:
> In most of cases, interrupt bits are set one by one but there are
> also a lot of other cases that Aspeed I2C IP sends multiple
> interrupt bits with combining master and slave events using a
> single interrupt call. It happens much in multi-master environment
much more
> than single-master. For an example, when master is waiting for a
> NORMAL_STOP interrupt in its MASTER_STOP state, SLAVE_MATCH and
> RX_DONE interrupts could come along with the NORMAL_STOP in case of
> an another master immediately sends data just after acquiring the
> bus. In this case, the NORMAL_STOP interrupt should be handled
> by master_irq and the SLAVE_MATCH and RX_DONE interrupts should be
> handled by slave_irq. This commit modifies irq hadling logic to
> handle the master/slave combined events properly.
>
> Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
> ---
> drivers/i2c/busses/i2c-aspeed.c | 137 ++++++++++++++++++--------------
> 1 file changed, 76 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
> index efb89422d496..24d43f143a55 100644
> --- a/drivers/i2c/busses/i2c-aspeed.c
> +++ b/drivers/i2c/busses/i2c-aspeed.c
> @@ -82,6 +82,11 @@
> #define ASPEED_I2CD_INTR_RX_DONE BIT(2)
> #define ASPEED_I2CD_INTR_TX_NAK BIT(1)
> #define ASPEED_I2CD_INTR_TX_ACK BIT(0)
> +#define ASPEED_I2CD_INTR_ERRORS \
> + (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
> + ASPEED_I2CD_INTR_SCL_TIMEOUT | \
> + ASPEED_I2CD_INTR_ABNORMAL | \
> + ASPEED_I2CD_INTR_ARBIT_LOSS)
> #define ASPEED_I2CD_INTR_ALL \
> (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
> ASPEED_I2CD_INTR_BUS_RECOVER_DONE | \
> @@ -150,6 +155,7 @@ struct aspeed_i2c_bus {
> int cmd_err;
> /* Protected only by i2c_lock_bus */
> int master_xfer_result;
> + u32 irq_status;
> #if IS_ENABLED(CONFIG_I2C_SLAVE)
> struct i2c_client *slave;
> enum aspeed_i2c_slave_state slave_state;
> @@ -229,36 +235,30 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
> #if IS_ENABLED(CONFIG_I2C_SLAVE)
> static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
> {
> - u32 command, irq_status, status_ack = 0;
> + u32 command, status_ack = 0;
> struct i2c_client *slave = bus->slave;
> - bool irq_handled = true;
> u8 value;
>
> - if (!slave) {
> - irq_handled = false;
> - goto out;
> - }
> + if (!slave)
> + return false;
>
> command = readl(bus->base + ASPEED_I2C_CMD_REG);
> - irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
>
> /* Slave was requested, restart state machine. */
> - if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
> status_ack |= ASPEED_I2CD_INTR_SLAVE_MATCH;
> bus->slave_state = ASPEED_I2C_SLAVE_START;
> }
>
> /* Slave is not currently active, irq was for someone else. */
> - if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) {
> - irq_handled = false;
> - goto out;
> - }
> + if (bus->slave_state == ASPEED_I2C_SLAVE_STOP)
> + return false;
>
> dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
> - irq_status, command);
> + bus->irq_status, command);
>
> /* Slave was sent something. */
> - if (irq_status & ASPEED_I2CD_INTR_RX_DONE) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_RX_DONE) {
> value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
> /* Handle address frame. */
> if (bus->slave_state == ASPEED_I2C_SLAVE_START) {
> @@ -273,28 +273,29 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
> }
>
> /* Slave was asked to stop. */
> - if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
> status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
> bus->slave_state = ASPEED_I2C_SLAVE_STOP;
> }
> - if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_TX_NAK) {
> status_ack |= ASPEED_I2CD_INTR_TX_NAK;
> bus->slave_state = ASPEED_I2C_SLAVE_STOP;
> }
> + if (bus->irq_status & ASPEED_I2CD_INTR_TX_ACK) {
> + status_ack |= ASPEED_I2CD_INTR_TX_ACK;
> + }
>
> switch (bus->slave_state) {
> case ASPEED_I2C_SLAVE_READ_REQUESTED:
> - if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
> + if (bus->irq_status & ASPEED_I2CD_INTR_TX_ACK)
> dev_err(bus->dev, "Unexpected ACK on read request.\n");
> bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
> -
> i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
> writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
> writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
> break;
> case ASPEED_I2C_SLAVE_READ_PROCESSED:
> - status_ack |= ASPEED_I2CD_INTR_TX_ACK;
> - if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
> + if (!(bus->irq_status & ASPEED_I2CD_INTR_TX_ACK))
> dev_err(bus->dev,
> "Expected ACK after processed read.\n");
> i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
> @@ -317,14 +318,8 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
> break;
> }
>
> - if (status_ack != irq_status)
> - dev_err(bus->dev,
> - "irq handled != irq. expected %x, but was %x\n",
> - irq_status, status_ack);
> - writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG);
> -
> -out:
> - return irq_handled;
> + bus->irq_status ^= status_ack;
> + return !bus->irq_status;
> }
> #endif /* CONFIG_I2C_SLAVE */
>
> @@ -382,19 +377,19 @@ static int aspeed_i2c_is_irq_error(u32 irq_status)
>
> static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> {
> - u32 irq_status, status_ack = 0, command = 0;
> + u32 status_ack = 0, command = 0;
> struct i2c_msg *msg;
> u8 recv_byte;
> int ret;
>
> - irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
> - /* Ack all interrupt bits. */
> - writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG);
> -
> - if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
> bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
> status_ack |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
> goto out_complete;
> + } else {
> + /* Master is not currently active, irq was for someone else. */
> + if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE)
> + goto out_no_complete;
> }
>
> /*
> @@ -402,20 +397,23 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> * should clear the command queue effectively taking us back to the
> * INACTIVE state.
> */
> - ret = aspeed_i2c_is_irq_error(irq_status);
> - if (ret < 0) {
> + ret = aspeed_i2c_is_irq_error(bus->irq_status);
> + if (ret) {
> dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
> - irq_status);
> + bus->irq_status);
> bus->cmd_err = ret;
> bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
> + status_ack |= (bus->irq_status & ASPEED_I2CD_INTR_ERRORS);
> goto out_complete;
> }
>
> /* We are in an invalid state; reset bus to a known state. */
> if (!bus->msgs) {
> - dev_err(bus->dev, "bus in unknown state\n");
> + dev_err(bus->dev, "bus in unknown state irq_status: 0x%x\n",
> + bus->irq_status);
> bus->cmd_err = -EIO;
> - if (bus->master_state != ASPEED_I2C_MASTER_STOP)
> + if (bus->master_state != ASPEED_I2C_MASTER_STOP &&
> + bus->master_state != ASPEED_I2C_MASTER_INACTIVE)
> aspeed_i2c_do_stop(bus);
> goto out_no_complete;
> }
> @@ -427,8 +425,14 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> * then update the state and handle the new state below.
> */
> if (bus->master_state == ASPEED_I2C_MASTER_START) {
> - if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
> - pr_devel("no slave present at %02x\n", msg->addr);
> + if (unlikely(!(bus->irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
> + if (unlikely(!(bus->irq_status &
> + ASPEED_I2CD_INTR_TX_NAK))) {
> + bus->cmd_err = -ENXIO;
> + bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
> + goto out_complete;
> + }
> + pr_devel("no slave present at %02x", msg->addr);
Missing line feed character
> status_ack |= ASPEED_I2CD_INTR_TX_NAK;
> bus->cmd_err = -ENXIO;
> aspeed_i2c_do_stop(bus);
> @@ -447,11 +451,12 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
>
> switch (bus->master_state) {
> case ASPEED_I2C_MASTER_TX:
> - if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
> + if (unlikely(bus->irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
> dev_dbg(bus->dev, "slave NACKed TX\n");
> status_ack |= ASPEED_I2CD_INTR_TX_NAK;
> goto error_and_stop;
> - } else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
> + } else if (unlikely(!(bus->irq_status &
> + ASPEED_I2CD_INTR_TX_ACK))) {
> dev_err(bus->dev, "slave failed to ACK TX\n");
> goto error_and_stop;
> }
> @@ -470,11 +475,11 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> goto out_no_complete;
> case ASPEED_I2C_MASTER_RX_FIRST:
> /* RX may not have completed yet (only address cycle) */
> - if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE))
> + if (!(bus->irq_status & ASPEED_I2CD_INTR_RX_DONE))
> goto out_no_complete;
> /* fallthrough intended */
> case ASPEED_I2C_MASTER_RX:
> - if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
> + if (unlikely(!(bus->irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
> dev_err(bus->dev, "master failed to RX\n");
> goto error_and_stop;
> }
> @@ -505,8 +510,11 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> }
> goto out_no_complete;
> case ASPEED_I2C_MASTER_STOP:
> - if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) {
> - dev_err(bus->dev, "master failed to STOP\n");
> + if (unlikely(!(bus->irq_status &
> + ASPEED_I2CD_INTR_NORMAL_STOP))) {
> + dev_err(bus->dev,
> + "master failed to STOP irq_status:0x%x\n",
> + bus->irq_status);
> bus->cmd_err = -EIO;
> /* Do not STOP as we have already tried. */
> } else {
> @@ -518,7 +526,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> case ASPEED_I2C_MASTER_INACTIVE:
> dev_err(bus->dev,
> "master received interrupt 0x%08x, but is inactive\n",
> - irq_status);
> + bus->irq_status);
> bus->cmd_err = -EIO;
> /* Do not STOP as we should be inactive. */
> goto out_complete;
> @@ -540,33 +548,40 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> bus->master_xfer_result = bus->msgs_index + 1;
> complete(&bus->cmd_complete);
> out_no_complete:
> - if (irq_status != status_ack)
> - dev_err(bus->dev,
> - "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
> - irq_status, status_ack);
> - return !!irq_status;
> + bus->irq_status ^= status_ack;
> + return !bus->irq_status;
> }
>
> static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
> {
> struct aspeed_i2c_bus *bus = dev_id;
> - bool ret;
> + u32 irq_received;
>
> spin_lock(&bus->lock);
> + irq_received = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
> + bus->irq_status = irq_received;
>
> #if IS_ENABLED(CONFIG_I2C_SLAVE)
> - if (aspeed_i2c_slave_irq(bus)) {
> - dev_dbg(bus->dev, "irq handled by slave.\n");
> - ret = true;
> - goto out;
> + if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
> + if (!aspeed_i2c_master_irq(bus))
> + aspeed_i2c_slave_irq(bus);
> + } else {
> + if (!aspeed_i2c_slave_irq(bus))
> + aspeed_i2c_master_irq(bus);
> }
> +#else
> + aspeed_i2c_master_irq(bus);
> #endif /* CONFIG_I2C_SLAVE */
>
> - ret = aspeed_i2c_master_irq(bus);
> + if (bus->irq_status)
> + dev_err(bus->dev,
> + "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
> + irq_received, irq_received ^ bus->irq_status);
>
> -out:
> + /* Ack all interrupt bits. */
> + writel(irq_received, bus->base + ASPEED_I2C_INTR_STS_REG);
> spin_unlock(&bus->lock);
> - return ret ? IRQ_HANDLED : IRQ_NONE;
> + return bus->irq_status ? IRQ_NONE : IRQ_HANDLED;
> }
>
> static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
>
^ permalink raw reply
* [PATCH i2c-next] i2c: aspeed: Handle master/slave combined irq events properly
From: James Feist @ 2018-07-23 18:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180723174808.4007-1-jae.hyun.yoo@linux.intel.com>
On 07/23/2018 10:48 AM, Jae Hyun Yoo wrote:
> In most of cases, interrupt bits are set one by one but there are
> also a lot of other cases that Aspeed I2C IP sends multiple
> interrupt bits with combining master and slave events using a
> single interrupt call. It happens much in multi-master environment
much more
> than single-master. For an example, when master is waiting for a
> NORMAL_STOP interrupt in its MASTER_STOP state, SLAVE_MATCH and
> RX_DONE interrupts could come along with the NORMAL_STOP in case of
> an another master immediately sends data just after acquiring the
> bus. In this case, the NORMAL_STOP interrupt should be handled
> by master_irq and the SLAVE_MATCH and RX_DONE interrupts should be
> handled by slave_irq. This commit modifies irq hadling logic to
> handle the master/slave combined events properly.
>
> Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
> ---
> drivers/i2c/busses/i2c-aspeed.c | 137 ++++++++++++++++++--------------
> 1 file changed, 76 insertions(+), 61 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
> index efb89422d496..24d43f143a55 100644
> --- a/drivers/i2c/busses/i2c-aspeed.c
> +++ b/drivers/i2c/busses/i2c-aspeed.c
> @@ -82,6 +82,11 @@
> #define ASPEED_I2CD_INTR_RX_DONE BIT(2)
> #define ASPEED_I2CD_INTR_TX_NAK BIT(1)
> #define ASPEED_I2CD_INTR_TX_ACK BIT(0)
> +#define ASPEED_I2CD_INTR_ERRORS \
> + (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
> + ASPEED_I2CD_INTR_SCL_TIMEOUT | \
> + ASPEED_I2CD_INTR_ABNORMAL | \
> + ASPEED_I2CD_INTR_ARBIT_LOSS)
> #define ASPEED_I2CD_INTR_ALL \
> (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
> ASPEED_I2CD_INTR_BUS_RECOVER_DONE | \
> @@ -150,6 +155,7 @@ struct aspeed_i2c_bus {
> int cmd_err;
> /* Protected only by i2c_lock_bus */
> int master_xfer_result;
> + u32 irq_status;
> #if IS_ENABLED(CONFIG_I2C_SLAVE)
> struct i2c_client *slave;
> enum aspeed_i2c_slave_state slave_state;
> @@ -229,36 +235,30 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
> #if IS_ENABLED(CONFIG_I2C_SLAVE)
> static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
> {
> - u32 command, irq_status, status_ack = 0;
> + u32 command, status_ack = 0;
> struct i2c_client *slave = bus->slave;
> - bool irq_handled = true;
> u8 value;
>
> - if (!slave) {
> - irq_handled = false;
> - goto out;
> - }
> + if (!slave)
> + return false;
>
> command = readl(bus->base + ASPEED_I2C_CMD_REG);
> - irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
>
> /* Slave was requested, restart state machine. */
> - if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
> status_ack |= ASPEED_I2CD_INTR_SLAVE_MATCH;
> bus->slave_state = ASPEED_I2C_SLAVE_START;
> }
>
> /* Slave is not currently active, irq was for someone else. */
> - if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) {
> - irq_handled = false;
> - goto out;
> - }
> + if (bus->slave_state == ASPEED_I2C_SLAVE_STOP)
> + return false;
>
> dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
> - irq_status, command);
> + bus->irq_status, command);
>
> /* Slave was sent something. */
> - if (irq_status & ASPEED_I2CD_INTR_RX_DONE) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_RX_DONE) {
> value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
> /* Handle address frame. */
> if (bus->slave_state == ASPEED_I2C_SLAVE_START) {
> @@ -273,28 +273,29 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
> }
>
> /* Slave was asked to stop. */
> - if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
> status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
> bus->slave_state = ASPEED_I2C_SLAVE_STOP;
> }
> - if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_TX_NAK) {
> status_ack |= ASPEED_I2CD_INTR_TX_NAK;
> bus->slave_state = ASPEED_I2C_SLAVE_STOP;
> }
> + if (bus->irq_status & ASPEED_I2CD_INTR_TX_ACK) {
> + status_ack |= ASPEED_I2CD_INTR_TX_ACK;
> + }
>
> switch (bus->slave_state) {
> case ASPEED_I2C_SLAVE_READ_REQUESTED:
> - if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
> + if (bus->irq_status & ASPEED_I2CD_INTR_TX_ACK)
> dev_err(bus->dev, "Unexpected ACK on read request.\n");
> bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
> -
> i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
> writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
> writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
> break;
> case ASPEED_I2C_SLAVE_READ_PROCESSED:
> - status_ack |= ASPEED_I2CD_INTR_TX_ACK;
> - if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
> + if (!(bus->irq_status & ASPEED_I2CD_INTR_TX_ACK))
> dev_err(bus->dev,
> "Expected ACK after processed read.\n");
> i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
> @@ -317,14 +318,8 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
> break;
> }
>
> - if (status_ack != irq_status)
> - dev_err(bus->dev,
> - "irq handled != irq. expected %x, but was %x\n",
> - irq_status, status_ack);
> - writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG);
> -
> -out:
> - return irq_handled;
> + bus->irq_status ^= status_ack;
> + return !bus->irq_status;
> }
> #endif /* CONFIG_I2C_SLAVE */
>
> @@ -382,19 +377,19 @@ static int aspeed_i2c_is_irq_error(u32 irq_status)
>
> static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> {
> - u32 irq_status, status_ack = 0, command = 0;
> + u32 status_ack = 0, command = 0;
> struct i2c_msg *msg;
> u8 recv_byte;
> int ret;
>
> - irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
> - /* Ack all interrupt bits. */
> - writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG);
> -
> - if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
> + if (bus->irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
> bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
> status_ack |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
> goto out_complete;
> + } else {
> + /* Master is not currently active, irq was for someone else. */
> + if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE)
> + goto out_no_complete;
> }
>
> /*
> @@ -402,20 +397,23 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> * should clear the command queue effectively taking us back to the
> * INACTIVE state.
> */
> - ret = aspeed_i2c_is_irq_error(irq_status);
> - if (ret < 0) {
> + ret = aspeed_i2c_is_irq_error(bus->irq_status);
> + if (ret) {
> dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
> - irq_status);
> + bus->irq_status);
> bus->cmd_err = ret;
> bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
> + status_ack |= (bus->irq_status & ASPEED_I2CD_INTR_ERRORS);
> goto out_complete;
> }
>
> /* We are in an invalid state; reset bus to a known state. */
> if (!bus->msgs) {
> - dev_err(bus->dev, "bus in unknown state\n");
> + dev_err(bus->dev, "bus in unknown state irq_status: 0x%x\n",
> + bus->irq_status);
> bus->cmd_err = -EIO;
> - if (bus->master_state != ASPEED_I2C_MASTER_STOP)
> + if (bus->master_state != ASPEED_I2C_MASTER_STOP &&
> + bus->master_state != ASPEED_I2C_MASTER_INACTIVE)
> aspeed_i2c_do_stop(bus);
> goto out_no_complete;
> }
> @@ -427,8 +425,14 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> * then update the state and handle the new state below.
> */
> if (bus->master_state == ASPEED_I2C_MASTER_START) {
> - if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
> - pr_devel("no slave present at %02x\n", msg->addr);
> + if (unlikely(!(bus->irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
> + if (unlikely(!(bus->irq_status &
> + ASPEED_I2CD_INTR_TX_NAK))) {
> + bus->cmd_err = -ENXIO;
> + bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
> + goto out_complete;
> + }
> + pr_devel("no slave present at %02x", msg->addr);
Missing line feed character
> status_ack |= ASPEED_I2CD_INTR_TX_NAK;
> bus->cmd_err = -ENXIO;
> aspeed_i2c_do_stop(bus);
> @@ -447,11 +451,12 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
>
> switch (bus->master_state) {
> case ASPEED_I2C_MASTER_TX:
> - if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
> + if (unlikely(bus->irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
> dev_dbg(bus->dev, "slave NACKed TX\n");
> status_ack |= ASPEED_I2CD_INTR_TX_NAK;
> goto error_and_stop;
> - } else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
> + } else if (unlikely(!(bus->irq_status &
> + ASPEED_I2CD_INTR_TX_ACK))) {
> dev_err(bus->dev, "slave failed to ACK TX\n");
> goto error_and_stop;
> }
> @@ -470,11 +475,11 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> goto out_no_complete;
> case ASPEED_I2C_MASTER_RX_FIRST:
> /* RX may not have completed yet (only address cycle) */
> - if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE))
> + if (!(bus->irq_status & ASPEED_I2CD_INTR_RX_DONE))
> goto out_no_complete;
> /* fallthrough intended */
> case ASPEED_I2C_MASTER_RX:
> - if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
> + if (unlikely(!(bus->irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
> dev_err(bus->dev, "master failed to RX\n");
> goto error_and_stop;
> }
> @@ -505,8 +510,11 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> }
> goto out_no_complete;
> case ASPEED_I2C_MASTER_STOP:
> - if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) {
> - dev_err(bus->dev, "master failed to STOP\n");
> + if (unlikely(!(bus->irq_status &
> + ASPEED_I2CD_INTR_NORMAL_STOP))) {
> + dev_err(bus->dev,
> + "master failed to STOP irq_status:0x%x\n",
> + bus->irq_status);
> bus->cmd_err = -EIO;
> /* Do not STOP as we have already tried. */
> } else {
> @@ -518,7 +526,7 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> case ASPEED_I2C_MASTER_INACTIVE:
> dev_err(bus->dev,
> "master received interrupt 0x%08x, but is inactive\n",
> - irq_status);
> + bus->irq_status);
> bus->cmd_err = -EIO;
> /* Do not STOP as we should be inactive. */
> goto out_complete;
> @@ -540,33 +548,40 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
> bus->master_xfer_result = bus->msgs_index + 1;
> complete(&bus->cmd_complete);
> out_no_complete:
> - if (irq_status != status_ack)
> - dev_err(bus->dev,
> - "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
> - irq_status, status_ack);
> - return !!irq_status;
> + bus->irq_status ^= status_ack;
> + return !bus->irq_status;
> }
>
> static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
> {
> struct aspeed_i2c_bus *bus = dev_id;
> - bool ret;
> + u32 irq_received;
>
> spin_lock(&bus->lock);
> + irq_received = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
> + bus->irq_status = irq_received;
>
> #if IS_ENABLED(CONFIG_I2C_SLAVE)
> - if (aspeed_i2c_slave_irq(bus)) {
> - dev_dbg(bus->dev, "irq handled by slave.\n");
> - ret = true;
> - goto out;
> + if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
> + if (!aspeed_i2c_master_irq(bus))
> + aspeed_i2c_slave_irq(bus);
> + } else {
> + if (!aspeed_i2c_slave_irq(bus))
> + aspeed_i2c_master_irq(bus);
> }
> +#else
> + aspeed_i2c_master_irq(bus);
> #endif /* CONFIG_I2C_SLAVE */
>
> - ret = aspeed_i2c_master_irq(bus);
> + if (bus->irq_status)
> + dev_err(bus->dev,
> + "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
> + irq_received, irq_received ^ bus->irq_status);
>
> -out:
> + /* Ack all interrupt bits. */
> + writel(irq_received, bus->base + ASPEED_I2C_INTR_STS_REG);
> spin_unlock(&bus->lock);
> - return ret ? IRQ_HANDLED : IRQ_NONE;
> + return bus->irq_status ? IRQ_NONE : IRQ_HANDLED;
> }
>
> static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
>
^ permalink raw reply
* Re: [PATCH v2 1/2] common/qat: add sgl header
From: De Lara Guarch, Pablo @ 2018-07-23 18:10 UTC (permalink / raw)
To: Trahe, Fiona, dev@dpdk.org; +Cc: Jozwiak, TomaszX
In-Reply-To: <1532351135-10064-1-git-send-email-fiona.trahe@intel.com>
> -----Original Message-----
> From: Trahe, Fiona
> Sent: Monday, July 23, 2018 2:06 PM
> To: dev@dpdk.org
> Cc: De Lara Guarch, Pablo <pablo.de.lara.guarch@intel.com>; Trahe, Fiona
> <fiona.trahe@intel.com>; Jozwiak, TomaszX <tomaszx.jozwiak@intel.com>
> Subject: [PATCH v2 1/2] common/qat: add sgl header
>
> This patch refactors the sgl struct so it includes a flexible array of flat buffers as
> sym and compress PMDs can have different size sgls.
>
> Signed-off-by: Tomasz Jozwiak <tomaszx.jozwiak@intel.com>
> Signed-off-by: Fiona Trahe <fiona.trahe@intel.com>
Applied to dpdk-next-crypto.
Thanks,
Pablo
^ permalink raw reply
* Re: [PATCH] IB/mlx5: avoid binding a new mpi unit to the same devices repeatedly
From: Daniel Jurgens @ 2018-07-23 18:11 UTC (permalink / raw)
To: Qing Huang, Or Gerlitz, Parav Pandit
Cc: Linux Kernel, RDMA mailing list, Jason Gunthorpe, Doug Ledford,
Leon Romanovsky, gerald.gibson
In-Reply-To: <556984ea-c35f-197d-0e45-16272da3f604@oracle.com>
On 7/23/2018 10:36 AM, Qing Huang wrote:
>
> Hi Daniel/Parav,
>
> Have you got a chance to review this patch? Thanks!
Hi Qing, sorry for the delay, I just got back to the office today. I don't agree with the proposed fix, I provided an alternative suggestion below.
>
>>> Or.
>>>
>>>> Reported-by: Gerald Gibson <gerald.gibson@oracle.com>
>>>> Signed-off-by: Qing Huang <qing.huang@oracle.com>
>>>> ---
>>>> drivers/infiniband/hw/mlx5/main.c | 3 ++-
>>>> 1 file changed, 2 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
>>>> index b3ba9a2..1ddd1d3 100644
>>>> --- a/drivers/infiniband/hw/mlx5/main.c
>>>> +++ b/drivers/infiniband/hw/mlx5/main.c
>>>> @@ -6068,7 +6068,8 @@ static void *mlx5_ib_add_slave_port(struct mlx5_core_dev *mdev, u8 port_num)
>>>>
>>>> mutex_lock(&mlx5_ib_multiport_mutex);
>>>> list_for_each_entry(dev, &mlx5_ib_dev_list, ib_dev_list) {
>>>> - if (dev->sys_image_guid == mpi->sys_image_guid)
>>>> + if (dev->sys_image_guid == mpi->sys_image_guid &&
>>>> + !dev->port[mlx5_core_native_port_num(mdev) - 1].mp.mpi)
You shouldn't check the mpi field that without holding the lock in the mp structure. Prefer you change the print from a warning in mlx5_ib_bind_slave_port to a debug message.
>>>> bound = mlx5_ib_bind_slave_port(dev, mpi);
>>>>
>>>> if (bound) {
>>>> --
>>>> 2.9.3
>>>>
>>>> --
>>>> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
>>>> the body of a message to majordomo@vger.kernel.org
>>>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: next-20180723 build: 2 failures 11 warnings (next-20180723)
From: Mark Brown @ 2018-07-23 18:11 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon
Cc: linaro-kernel, khilman, kernel-build-reports, linux-next,
matthew.hart, linux-arm-kernel
In-Reply-To: <E1fheAy-0003tU-Dq@optimist>
[-- Attachment #1.1: Type: text/plain, Size: 779 bytes --]
On Mon, Jul 23, 2018 at 05:59:12PM +0100, Build bot for Mark Brown wrote:
Today's -next fails to build an arm64 allmodconfig with:
> arm64-allmodconfig
> ERROR: "__sync_icache_dcache" [drivers/xen/xen-privcmd.ko] undefined!
using
aarch64-linux-gnu-gcc (Linaro GCC 5.3-2016.05) 5.3.1 20160412
however it builds perfectly fine with
aarch64-linux-gnu-gcc (Linaro GCC 6.2-2016.11) 6.2.1 20161016
which honestly seems like a sensible and worthwhile upgrade at this
point anyway given that it's a year and a half old so I'm going to do
that for my builder (perhaps even jump on a newer version) but it seemed
worth highlighting in case this is considered undesirable. A similar
issue is hitting on KernelCI, we should probably look at upgrading the
toolchain there too.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* next-20180723 build: 2 failures 11 warnings (next-20180723)
From: Mark Brown @ 2018-07-23 18:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <E1fheAy-0003tU-Dq@optimist>
On Mon, Jul 23, 2018 at 05:59:12PM +0100, Build bot for Mark Brown wrote:
Today's -next fails to build an arm64 allmodconfig with:
> arm64-allmodconfig
> ERROR: "__sync_icache_dcache" [drivers/xen/xen-privcmd.ko] undefined!
using
aarch64-linux-gnu-gcc (Linaro GCC 5.3-2016.05) 5.3.1 20160412
however it builds perfectly fine with
aarch64-linux-gnu-gcc (Linaro GCC 6.2-2016.11) 6.2.1 20161016
which honestly seems like a sensible and worthwhile upgrade at this
point anyway given that it's a year and a half old so I'm going to do
that for my builder (perhaps even jump on a newer version) but it seemed
worth highlighting in case this is considered undesirable. A similar
issue is hitting on KernelCI, we should probably look at upgrading the
toolchain there too.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180723/f22badc9/attachment-0001.sig>
^ permalink raw reply
* Re: [PATCH 1/2] t3507: add a testcase showing failure with sparse checkout
From: Junio C Hamano @ 2018-07-23 18:12 UTC (permalink / raw)
To: Ben Peart; +Cc: Elijah Newren, git, benpeart, kewillf
In-Reply-To: <5250481c-f6a1-0784-28e7-f34a9d6d3c93@gmail.com>
Ben Peart <peartben@gmail.com> writes:
> On 7/21/2018 2:34 AM, Elijah Newren wrote:
>> From: Ben Peart <peartben@gmail.com>
>>
>> Signed-off-by: Elijah Newren <newren@gmail.com>
>> ---
>> Testcase provided by Ben, so committing with him as the author. Just need
>> a sign off from him.
>
> Thanks Elijah, consider it
>
> Signed-off-by: Ben Peart <Ben.Peart@microsoft.com>
>
Thanks; I'll also tweak the in-body From: line while applying to
match the Sign-off.
^ permalink raw reply
* Re: [PATCH 1/2] Add sw2_sw4 voltage table to cpcap regulator.
From: Mark Brown @ 2018-07-23 18:13 UTC (permalink / raw)
To: Peter Geis
Cc: lgirdwood, robh+dt, mark.rutland, linux-kernel, devicetree,
linux-tegra
In-Reply-To: <e411faa3-7d42-710f-a18a-a4fdd764b60a@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 505 bytes --]
On Mon, Jul 23, 2018 at 01:58:26PM -0400, Peter Geis wrote:
> SW2 and SW4 use a shared table to provide voltage to the cpu core and
> devices on Tegra hardware.
> Added this table to the cpcap regulator driver as the first step to
> supporting this device on Tegra.
This also doesn't apply against current code (though it does now parse
OK), please check and resend - make sure you don't have other out of
tree changes and are using an up to date kernel (ideally my regulator
for-next branch) as a base.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH i2c-next] i2c: aspeed: Handle master/slave combined irq events properly
From: Jae Hyun Yoo @ 2018-07-23 18:13 UTC (permalink / raw)
To: linux-aspeed
In-Reply-To: <58d31319-83c0-969b-e3fd-4273818929fc@linux.intel.com>
Thanks James for the review. Please see my inline answers.
On 7/23/2018 11:10 AM, James Feist wrote:
> On 07/23/2018 10:48 AM, Jae Hyun Yoo wrote:
>> In most of cases, interrupt bits are set one by one but there are
>> also a lot of other cases that Aspeed I2C IP sends multiple
>> interrupt bits with combining master and slave events using a
>> single interrupt call. It happens much in multi-master environment
>
> much more
>
Thanks! Will fix it.
>> than single-master. For an example, when master is waiting for a
>> NORMAL_STOP interrupt in its MASTER_STOP state, SLAVE_MATCH and
>> RX_DONE interrupts could come along with the NORMAL_STOP in case of
>> an another master immediately sends data just after acquiring the
>> bus. In this case, the NORMAL_STOP interrupt should be handled
>> by master_irq and the SLAVE_MATCH and RX_DONE interrupts should be
>> handled by slave_irq. This commit modifies irq hadling logic to
>> handle the master/slave combined events properly.
>>
>> Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
>> ---
>> ? drivers/i2c/busses/i2c-aspeed.c | 137 ++++++++++++++++++--------------
>> ? 1 file changed, 76 insertions(+), 61 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-aspeed.c
>> b/drivers/i2c/busses/i2c-aspeed.c
>> index efb89422d496..24d43f143a55 100644
>> --- a/drivers/i2c/busses/i2c-aspeed.c
>> +++ b/drivers/i2c/busses/i2c-aspeed.c
>> @@ -82,6 +82,11 @@
>> ? #define ASPEED_I2CD_INTR_RX_DONE??????????? BIT(2)
>> ? #define ASPEED_I2CD_INTR_TX_NAK??????????????? BIT(1)
>> ? #define ASPEED_I2CD_INTR_TX_ACK??????????????? BIT(0)
>> +#define ASPEED_I2CD_INTR_ERRORS?????????????????????????????? \
>> +??????? (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT |?????????????????? \
>> +???????? ASPEED_I2CD_INTR_SCL_TIMEOUT |?????????????????????? \
>> +???????? ASPEED_I2CD_INTR_ABNORMAL |?????????????????????? \
>> +???????? ASPEED_I2CD_INTR_ARBIT_LOSS)
>> ? #define ASPEED_I2CD_INTR_ALL?????????????????????????????? \
>> ????????? (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT |?????????????????? \
>> ?????????? ASPEED_I2CD_INTR_BUS_RECOVER_DONE |?????????????????? \
>> @@ -150,6 +155,7 @@ struct aspeed_i2c_bus {
>> ????? int??????????????? cmd_err;
>> ????? /* Protected only by i2c_lock_bus */
>> ????? int??????????????? master_xfer_result;
>> +??? u32??????????????? irq_status;
>> ? #if IS_ENABLED(CONFIG_I2C_SLAVE)
>> ????? struct i2c_client??????? *slave;
>> ????? enum aspeed_i2c_slave_state??? slave_state;
>> @@ -229,36 +235,30 @@ static int aspeed_i2c_recover_bus(struct
>> aspeed_i2c_bus *bus)
>> ? #if IS_ENABLED(CONFIG_I2C_SLAVE)
>> ? static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
>> ? {
>> -??? u32 command, irq_status, status_ack = 0;
>> +??? u32 command, status_ack = 0;
>> ????? struct i2c_client *slave = bus->slave;
>> -??? bool irq_handled = true;
>> ????? u8 value;
>> -??? if (!slave) {
>> -??????? irq_handled = false;
>> -??????? goto out;
>> -??? }
>> +??? if (!slave)
>> +??????? return false;
>> ????? command = readl(bus->base + ASPEED_I2C_CMD_REG);
>> -??? irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
>> ????? /* Slave was requested, restart state machine. */
>> -??? if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
>> +??? if (bus->irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
>> ????????? status_ack |= ASPEED_I2CD_INTR_SLAVE_MATCH;
>> ????????? bus->slave_state = ASPEED_I2C_SLAVE_START;
>> ????? }
>> ????? /* Slave is not currently active, irq was for someone else. */
>> -??? if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) {
>> -??????? irq_handled = false;
>> -??????? goto out;
>> -??? }
>> +??? if (bus->slave_state == ASPEED_I2C_SLAVE_STOP)
>> +??????? return false;
>> ????? dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
>> -??????? irq_status, command);
>> +??????? bus->irq_status, command);
>> ????? /* Slave was sent something. */
>> -??? if (irq_status & ASPEED_I2CD_INTR_RX_DONE) {
>> +??? if (bus->irq_status & ASPEED_I2CD_INTR_RX_DONE) {
>> ????????? value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
>> ????????? /* Handle address frame. */
>> ????????? if (bus->slave_state == ASPEED_I2C_SLAVE_START) {
>> @@ -273,28 +273,29 @@ static bool aspeed_i2c_slave_irq(struct
>> aspeed_i2c_bus *bus)
>> ????? }
>> ????? /* Slave was asked to stop. */
>> -??? if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
>> +??? if (bus->irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
>> ????????? status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
>> ????????? bus->slave_state = ASPEED_I2C_SLAVE_STOP;
>> ????? }
>> -??? if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
>> +??? if (bus->irq_status & ASPEED_I2CD_INTR_TX_NAK) {
>> ????????? status_ack |= ASPEED_I2CD_INTR_TX_NAK;
>> ????????? bus->slave_state = ASPEED_I2C_SLAVE_STOP;
>> ????? }
>> +??? if (bus->irq_status & ASPEED_I2CD_INTR_TX_ACK) {
>> +??????? status_ack |= ASPEED_I2CD_INTR_TX_ACK;
>> +??? }
>> ????? switch (bus->slave_state) {
>> ????? case ASPEED_I2C_SLAVE_READ_REQUESTED:
>> -??????? if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
>> +??????? if (bus->irq_status & ASPEED_I2CD_INTR_TX_ACK)
>> ????????????? dev_err(bus->dev, "Unexpected ACK on read request.\n");
>> ????????? bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
>> -
>> ????????? i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
>> ????????? writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
>> ????????? writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
>> ????????? break;
>> ????? case ASPEED_I2C_SLAVE_READ_PROCESSED:
>> -??????? status_ack |= ASPEED_I2CD_INTR_TX_ACK;
>> -??????? if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
>> +??????? if (!(bus->irq_status & ASPEED_I2CD_INTR_TX_ACK))
>> ????????????? dev_err(bus->dev,
>> ????????????????? "Expected ACK after processed read.\n");
>> ????????? i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
>> @@ -317,14 +318,8 @@ static bool aspeed_i2c_slave_irq(struct
>> aspeed_i2c_bus *bus)
>> ????????? break;
>> ????? }
>> -??? if (status_ack != irq_status)
>> -??????? dev_err(bus->dev,
>> -??????????? "irq handled != irq. expected %x, but was %x\n",
>> -??????????? irq_status, status_ack);
>> -??? writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG);
>> -
>> -out:
>> -??? return irq_handled;
>> +??? bus->irq_status ^= status_ack;
>> +??? return !bus->irq_status;
>> ? }
>> ? #endif /* CONFIG_I2C_SLAVE */
>> @@ -382,19 +377,19 @@ static int aspeed_i2c_is_irq_error(u32 irq_status)
>> ? static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
>> ? {
>> -??? u32 irq_status, status_ack = 0, command = 0;
>> +??? u32 status_ack = 0, command = 0;
>> ????? struct i2c_msg *msg;
>> ????? u8 recv_byte;
>> ????? int ret;
>> -??? irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
>> -??? /* Ack all interrupt bits. */
>> -??? writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG);
>> -
>> -??? if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
>> +??? if (bus->irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
>> ????????? bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
>> ????????? status_ack |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
>> ????????? goto out_complete;
>> +??? } else {
>> +??????? /* Master is not currently active, irq was for someone else. */
>> +??????? if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE)
>> +??????????? goto out_no_complete;
>> ????? }
>> ????? /*
>> @@ -402,20 +397,23 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ?????? * should clear the command queue effectively taking us back to the
>> ?????? * INACTIVE state.
>> ?????? */
>> -??? ret = aspeed_i2c_is_irq_error(irq_status);
>> -??? if (ret < 0) {
>> +??? ret = aspeed_i2c_is_irq_error(bus->irq_status);
>> +??? if (ret) {
>> ????????? dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
>> -??????????? irq_status);
>> +??????????? bus->irq_status);
>> ????????? bus->cmd_err = ret;
>> ????????? bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
>> +??????? status_ack |= (bus->irq_status & ASPEED_I2CD_INTR_ERRORS);
>> ????????? goto out_complete;
>> ????? }
>> ????? /* We are in an invalid state; reset bus to a known state. */
>> ????? if (!bus->msgs) {
>> -??????? dev_err(bus->dev, "bus in unknown state\n");
>> +??????? dev_err(bus->dev, "bus in unknown state irq_status: 0x%x\n",
>> +??????????? bus->irq_status);
>> ????????? bus->cmd_err = -EIO;
>> -??????? if (bus->master_state != ASPEED_I2C_MASTER_STOP)
>> +??????? if (bus->master_state != ASPEED_I2C_MASTER_STOP &&
>> +??????????? bus->master_state != ASPEED_I2C_MASTER_INACTIVE)
>> ????????????? aspeed_i2c_do_stop(bus);
>> ????????? goto out_no_complete;
>> ????? }
>> @@ -427,8 +425,14 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ?????? * then update the state and handle the new state below.
>> ?????? */
>> ????? if (bus->master_state == ASPEED_I2C_MASTER_START) {
>> -??????? if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
>> -??????????? pr_devel("no slave present at %02x\n", msg->addr);
>> +??????? if (unlikely(!(bus->irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
>> +??????????? if (unlikely(!(bus->irq_status &
>> +???????????????????? ASPEED_I2CD_INTR_TX_NAK))) {
>> +??????????????? bus->cmd_err = -ENXIO;
>> +??????????????? bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
>> +??????????????? goto out_complete;
>> +??????????? }
>> +??????????? pr_devel("no slave present at %02x", msg->addr);
> Missing line feed character
Thanks for your pointing it out. Will add '\n' at the end of the
message.
>> ????????????? status_ack |= ASPEED_I2CD_INTR_TX_NAK;
>> ????????????? bus->cmd_err = -ENXIO;
>> ????????????? aspeed_i2c_do_stop(bus);
>> @@ -447,11 +451,12 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ????? switch (bus->master_state) {
>> ????? case ASPEED_I2C_MASTER_TX:
>> -??????? if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
>> +??????? if (unlikely(bus->irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
>> ????????????? dev_dbg(bus->dev, "slave NACKed TX\n");
>> ????????????? status_ack |= ASPEED_I2CD_INTR_TX_NAK;
>> ????????????? goto error_and_stop;
>> -??????? } else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
>> +??????? } else if (unlikely(!(bus->irq_status &
>> +????????????????????? ASPEED_I2CD_INTR_TX_ACK))) {
>> ????????????? dev_err(bus->dev, "slave failed to ACK TX\n");
>> ????????????? goto error_and_stop;
>> ????????? }
>> @@ -470,11 +475,11 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ????????? goto out_no_complete;
>> ????? case ASPEED_I2C_MASTER_RX_FIRST:
>> ????????? /* RX may not have completed yet (only address cycle) */
>> -??????? if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE))
>> +??????? if (!(bus->irq_status & ASPEED_I2CD_INTR_RX_DONE))
>> ????????????? goto out_no_complete;
>> ????????? /* fallthrough intended */
>> ????? case ASPEED_I2C_MASTER_RX:
>> -??????? if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
>> +??????? if (unlikely(!(bus->irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
>> ????????????? dev_err(bus->dev, "master failed to RX\n");
>> ????????????? goto error_and_stop;
>> ????????? }
>> @@ -505,8 +510,11 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ????????? }
>> ????????? goto out_no_complete;
>> ????? case ASPEED_I2C_MASTER_STOP:
>> -??????? if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) {
>> -??????????? dev_err(bus->dev, "master failed to STOP\n");
>> +??????? if (unlikely(!(bus->irq_status &
>> +?????????????????? ASPEED_I2CD_INTR_NORMAL_STOP))) {
>> +??????????? dev_err(bus->dev,
>> +??????????????? "master failed to STOP irq_status:0x%x\n",
>> +??????????????? bus->irq_status);
>> ????????????? bus->cmd_err = -EIO;
>> ????????????? /* Do not STOP as we have already tried. */
>> ????????? } else {
>> @@ -518,7 +526,7 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ????? case ASPEED_I2C_MASTER_INACTIVE:
>> ????????? dev_err(bus->dev,
>> ????????????? "master received interrupt 0x%08x, but is inactive\n",
>> -??????????? irq_status);
>> +??????????? bus->irq_status);
>> ????????? bus->cmd_err = -EIO;
>> ????????? /* Do not STOP as we should be inactive. */
>> ????????? goto out_complete;
>> @@ -540,33 +548,40 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ????????? bus->master_xfer_result = bus->msgs_index + 1;
>> ????? complete(&bus->cmd_complete);
>> ? out_no_complete:
>> -??? if (irq_status != status_ack)
>> -??????? dev_err(bus->dev,
>> -??????????? "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
>> -??????????? irq_status, status_ack);
>> -??? return !!irq_status;
>> +??? bus->irq_status ^= status_ack;
>> +??? return !bus->irq_status;
>> ? }
>> ? static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
>> ? {
>> ????? struct aspeed_i2c_bus *bus = dev_id;
>> -??? bool ret;
>> +??? u32 irq_received;
>> ????? spin_lock(&bus->lock);
>> +??? irq_received = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
>> +??? bus->irq_status = irq_received;
>> ? #if IS_ENABLED(CONFIG_I2C_SLAVE)
>> -??? if (aspeed_i2c_slave_irq(bus)) {
>> -??????? dev_dbg(bus->dev, "irq handled by slave.\n");
>> -??????? ret = true;
>> -??????? goto out;
>> +??? if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
>> +??????? if (!aspeed_i2c_master_irq(bus))
>> +??????????? aspeed_i2c_slave_irq(bus);
>> +??? } else {
>> +??????? if (!aspeed_i2c_slave_irq(bus))
>> +??????????? aspeed_i2c_master_irq(bus);
>> ????? }
>> +#else
>> +??? aspeed_i2c_master_irq(bus);
>> ? #endif /* CONFIG_I2C_SLAVE */
>> -??? ret = aspeed_i2c_master_irq(bus);
>> +??? if (bus->irq_status)
>> +??????? dev_err(bus->dev,
>> +??????????? "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
>> +??????????? irq_received, irq_received ^ bus->irq_status);
>> -out:
>> +??? /* Ack all interrupt bits. */
>> +??? writel(irq_received, bus->base + ASPEED_I2C_INTR_STS_REG);
>> ????? spin_unlock(&bus->lock);
>> -??? return ret ? IRQ_HANDLED : IRQ_NONE;
>> +??? return bus->irq_status ? IRQ_NONE : IRQ_HANDLED;
>> ? }
>> ? static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
>>
^ permalink raw reply
* Re: [PATCH i2c-next] i2c: aspeed: Handle master/slave combined irq events properly
From: Jae Hyun Yoo @ 2018-07-23 18:13 UTC (permalink / raw)
To: James Feist, Brendan Higgins, Benjamin Herrenschmidt,
Joel Stanley, Andrew Jeffery, linux-i2c, openbmc,
linux-arm-kernel, linux-aspeed, linux-kernel
Cc: Vernon Mauery, Jarkko Nikula
In-Reply-To: <58d31319-83c0-969b-e3fd-4273818929fc@linux.intel.com>
Thanks James for the review. Please see my inline answers.
On 7/23/2018 11:10 AM, James Feist wrote:
> On 07/23/2018 10:48 AM, Jae Hyun Yoo wrote:
>> In most of cases, interrupt bits are set one by one but there are
>> also a lot of other cases that Aspeed I2C IP sends multiple
>> interrupt bits with combining master and slave events using a
>> single interrupt call. It happens much in multi-master environment
>
> much more
>
Thanks! Will fix it.
>> than single-master. For an example, when master is waiting for a
>> NORMAL_STOP interrupt in its MASTER_STOP state, SLAVE_MATCH and
>> RX_DONE interrupts could come along with the NORMAL_STOP in case of
>> an another master immediately sends data just after acquiring the
>> bus. In this case, the NORMAL_STOP interrupt should be handled
>> by master_irq and the SLAVE_MATCH and RX_DONE interrupts should be
>> handled by slave_irq. This commit modifies irq hadling logic to
>> handle the master/slave combined events properly.
>>
>> Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
>> ---
>> drivers/i2c/busses/i2c-aspeed.c | 137 ++++++++++++++++++--------------
>> 1 file changed, 76 insertions(+), 61 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-aspeed.c
>> b/drivers/i2c/busses/i2c-aspeed.c
>> index efb89422d496..24d43f143a55 100644
>> --- a/drivers/i2c/busses/i2c-aspeed.c
>> +++ b/drivers/i2c/busses/i2c-aspeed.c
>> @@ -82,6 +82,11 @@
>> #define ASPEED_I2CD_INTR_RX_DONE BIT(2)
>> #define ASPEED_I2CD_INTR_TX_NAK BIT(1)
>> #define ASPEED_I2CD_INTR_TX_ACK BIT(0)
>> +#define ASPEED_I2CD_INTR_ERRORS \
>> + (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
>> + ASPEED_I2CD_INTR_SCL_TIMEOUT | \
>> + ASPEED_I2CD_INTR_ABNORMAL | \
>> + ASPEED_I2CD_INTR_ARBIT_LOSS)
>> #define ASPEED_I2CD_INTR_ALL \
>> (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
>> ASPEED_I2CD_INTR_BUS_RECOVER_DONE | \
>> @@ -150,6 +155,7 @@ struct aspeed_i2c_bus {
>> int cmd_err;
>> /* Protected only by i2c_lock_bus */
>> int master_xfer_result;
>> + u32 irq_status;
>> #if IS_ENABLED(CONFIG_I2C_SLAVE)
>> struct i2c_client *slave;
>> enum aspeed_i2c_slave_state slave_state;
>> @@ -229,36 +235,30 @@ static int aspeed_i2c_recover_bus(struct
>> aspeed_i2c_bus *bus)
>> #if IS_ENABLED(CONFIG_I2C_SLAVE)
>> static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
>> {
>> - u32 command, irq_status, status_ack = 0;
>> + u32 command, status_ack = 0;
>> struct i2c_client *slave = bus->slave;
>> - bool irq_handled = true;
>> u8 value;
>> - if (!slave) {
>> - irq_handled = false;
>> - goto out;
>> - }
>> + if (!slave)
>> + return false;
>> command = readl(bus->base + ASPEED_I2C_CMD_REG);
>> - irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
>> /* Slave was requested, restart state machine. */
>> - if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
>> + if (bus->irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
>> status_ack |= ASPEED_I2CD_INTR_SLAVE_MATCH;
>> bus->slave_state = ASPEED_I2C_SLAVE_START;
>> }
>> /* Slave is not currently active, irq was for someone else. */
>> - if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) {
>> - irq_handled = false;
>> - goto out;
>> - }
>> + if (bus->slave_state == ASPEED_I2C_SLAVE_STOP)
>> + return false;
>> dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
>> - irq_status, command);
>> + bus->irq_status, command);
>> /* Slave was sent something. */
>> - if (irq_status & ASPEED_I2CD_INTR_RX_DONE) {
>> + if (bus->irq_status & ASPEED_I2CD_INTR_RX_DONE) {
>> value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
>> /* Handle address frame. */
>> if (bus->slave_state == ASPEED_I2C_SLAVE_START) {
>> @@ -273,28 +273,29 @@ static bool aspeed_i2c_slave_irq(struct
>> aspeed_i2c_bus *bus)
>> }
>> /* Slave was asked to stop. */
>> - if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
>> + if (bus->irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
>> status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
>> bus->slave_state = ASPEED_I2C_SLAVE_STOP;
>> }
>> - if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
>> + if (bus->irq_status & ASPEED_I2CD_INTR_TX_NAK) {
>> status_ack |= ASPEED_I2CD_INTR_TX_NAK;
>> bus->slave_state = ASPEED_I2C_SLAVE_STOP;
>> }
>> + if (bus->irq_status & ASPEED_I2CD_INTR_TX_ACK) {
>> + status_ack |= ASPEED_I2CD_INTR_TX_ACK;
>> + }
>> switch (bus->slave_state) {
>> case ASPEED_I2C_SLAVE_READ_REQUESTED:
>> - if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
>> + if (bus->irq_status & ASPEED_I2CD_INTR_TX_ACK)
>> dev_err(bus->dev, "Unexpected ACK on read request.\n");
>> bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
>> -
>> i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
>> writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
>> writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
>> break;
>> case ASPEED_I2C_SLAVE_READ_PROCESSED:
>> - status_ack |= ASPEED_I2CD_INTR_TX_ACK;
>> - if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
>> + if (!(bus->irq_status & ASPEED_I2CD_INTR_TX_ACK))
>> dev_err(bus->dev,
>> "Expected ACK after processed read.\n");
>> i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
>> @@ -317,14 +318,8 @@ static bool aspeed_i2c_slave_irq(struct
>> aspeed_i2c_bus *bus)
>> break;
>> }
>> - if (status_ack != irq_status)
>> - dev_err(bus->dev,
>> - "irq handled != irq. expected %x, but was %x\n",
>> - irq_status, status_ack);
>> - writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG);
>> -
>> -out:
>> - return irq_handled;
>> + bus->irq_status ^= status_ack;
>> + return !bus->irq_status;
>> }
>> #endif /* CONFIG_I2C_SLAVE */
>> @@ -382,19 +377,19 @@ static int aspeed_i2c_is_irq_error(u32 irq_status)
>> static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
>> {
>> - u32 irq_status, status_ack = 0, command = 0;
>> + u32 status_ack = 0, command = 0;
>> struct i2c_msg *msg;
>> u8 recv_byte;
>> int ret;
>> - irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
>> - /* Ack all interrupt bits. */
>> - writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG);
>> -
>> - if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
>> + if (bus->irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
>> bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
>> status_ack |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
>> goto out_complete;
>> + } else {
>> + /* Master is not currently active, irq was for someone else. */
>> + if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE)
>> + goto out_no_complete;
>> }
>> /*
>> @@ -402,20 +397,23 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> * should clear the command queue effectively taking us back to the
>> * INACTIVE state.
>> */
>> - ret = aspeed_i2c_is_irq_error(irq_status);
>> - if (ret < 0) {
>> + ret = aspeed_i2c_is_irq_error(bus->irq_status);
>> + if (ret) {
>> dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
>> - irq_status);
>> + bus->irq_status);
>> bus->cmd_err = ret;
>> bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
>> + status_ack |= (bus->irq_status & ASPEED_I2CD_INTR_ERRORS);
>> goto out_complete;
>> }
>> /* We are in an invalid state; reset bus to a known state. */
>> if (!bus->msgs) {
>> - dev_err(bus->dev, "bus in unknown state\n");
>> + dev_err(bus->dev, "bus in unknown state irq_status: 0x%x\n",
>> + bus->irq_status);
>> bus->cmd_err = -EIO;
>> - if (bus->master_state != ASPEED_I2C_MASTER_STOP)
>> + if (bus->master_state != ASPEED_I2C_MASTER_STOP &&
>> + bus->master_state != ASPEED_I2C_MASTER_INACTIVE)
>> aspeed_i2c_do_stop(bus);
>> goto out_no_complete;
>> }
>> @@ -427,8 +425,14 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> * then update the state and handle the new state below.
>> */
>> if (bus->master_state == ASPEED_I2C_MASTER_START) {
>> - if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
>> - pr_devel("no slave present at %02x\n", msg->addr);
>> + if (unlikely(!(bus->irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
>> + if (unlikely(!(bus->irq_status &
>> + ASPEED_I2CD_INTR_TX_NAK))) {
>> + bus->cmd_err = -ENXIO;
>> + bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
>> + goto out_complete;
>> + }
>> + pr_devel("no slave present at %02x", msg->addr);
> Missing line feed character
Thanks for your pointing it out. Will add '\n' at the end of the
message.
>> status_ack |= ASPEED_I2CD_INTR_TX_NAK;
>> bus->cmd_err = -ENXIO;
>> aspeed_i2c_do_stop(bus);
>> @@ -447,11 +451,12 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> switch (bus->master_state) {
>> case ASPEED_I2C_MASTER_TX:
>> - if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
>> + if (unlikely(bus->irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
>> dev_dbg(bus->dev, "slave NACKed TX\n");
>> status_ack |= ASPEED_I2CD_INTR_TX_NAK;
>> goto error_and_stop;
>> - } else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
>> + } else if (unlikely(!(bus->irq_status &
>> + ASPEED_I2CD_INTR_TX_ACK))) {
>> dev_err(bus->dev, "slave failed to ACK TX\n");
>> goto error_and_stop;
>> }
>> @@ -470,11 +475,11 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> goto out_no_complete;
>> case ASPEED_I2C_MASTER_RX_FIRST:
>> /* RX may not have completed yet (only address cycle) */
>> - if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE))
>> + if (!(bus->irq_status & ASPEED_I2CD_INTR_RX_DONE))
>> goto out_no_complete;
>> /* fallthrough intended */
>> case ASPEED_I2C_MASTER_RX:
>> - if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
>> + if (unlikely(!(bus->irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
>> dev_err(bus->dev, "master failed to RX\n");
>> goto error_and_stop;
>> }
>> @@ -505,8 +510,11 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> }
>> goto out_no_complete;
>> case ASPEED_I2C_MASTER_STOP:
>> - if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) {
>> - dev_err(bus->dev, "master failed to STOP\n");
>> + if (unlikely(!(bus->irq_status &
>> + ASPEED_I2CD_INTR_NORMAL_STOP))) {
>> + dev_err(bus->dev,
>> + "master failed to STOP irq_status:0x%x\n",
>> + bus->irq_status);
>> bus->cmd_err = -EIO;
>> /* Do not STOP as we have already tried. */
>> } else {
>> @@ -518,7 +526,7 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> case ASPEED_I2C_MASTER_INACTIVE:
>> dev_err(bus->dev,
>> "master received interrupt 0x%08x, but is inactive\n",
>> - irq_status);
>> + bus->irq_status);
>> bus->cmd_err = -EIO;
>> /* Do not STOP as we should be inactive. */
>> goto out_complete;
>> @@ -540,33 +548,40 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> bus->master_xfer_result = bus->msgs_index + 1;
>> complete(&bus->cmd_complete);
>> out_no_complete:
>> - if (irq_status != status_ack)
>> - dev_err(bus->dev,
>> - "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
>> - irq_status, status_ack);
>> - return !!irq_status;
>> + bus->irq_status ^= status_ack;
>> + return !bus->irq_status;
>> }
>> static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
>> {
>> struct aspeed_i2c_bus *bus = dev_id;
>> - bool ret;
>> + u32 irq_received;
>> spin_lock(&bus->lock);
>> + irq_received = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
>> + bus->irq_status = irq_received;
>> #if IS_ENABLED(CONFIG_I2C_SLAVE)
>> - if (aspeed_i2c_slave_irq(bus)) {
>> - dev_dbg(bus->dev, "irq handled by slave.\n");
>> - ret = true;
>> - goto out;
>> + if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
>> + if (!aspeed_i2c_master_irq(bus))
>> + aspeed_i2c_slave_irq(bus);
>> + } else {
>> + if (!aspeed_i2c_slave_irq(bus))
>> + aspeed_i2c_master_irq(bus);
>> }
>> +#else
>> + aspeed_i2c_master_irq(bus);
>> #endif /* CONFIG_I2C_SLAVE */
>> - ret = aspeed_i2c_master_irq(bus);
>> + if (bus->irq_status)
>> + dev_err(bus->dev,
>> + "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
>> + irq_received, irq_received ^ bus->irq_status);
>> -out:
>> + /* Ack all interrupt bits. */
>> + writel(irq_received, bus->base + ASPEED_I2C_INTR_STS_REG);
>> spin_unlock(&bus->lock);
>> - return ret ? IRQ_HANDLED : IRQ_NONE;
>> + return bus->irq_status ? IRQ_NONE : IRQ_HANDLED;
>> }
>> static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
>>
^ permalink raw reply
* [PATCH i2c-next] i2c: aspeed: Handle master/slave combined irq events properly
From: Jae Hyun Yoo @ 2018-07-23 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <58d31319-83c0-969b-e3fd-4273818929fc@linux.intel.com>
Thanks James for the review. Please see my inline answers.
On 7/23/2018 11:10 AM, James Feist wrote:
> On 07/23/2018 10:48 AM, Jae Hyun Yoo wrote:
>> In most of cases, interrupt bits are set one by one but there are
>> also a lot of other cases that Aspeed I2C IP sends multiple
>> interrupt bits with combining master and slave events using a
>> single interrupt call. It happens much in multi-master environment
>
> much more
>
Thanks! Will fix it.
>> than single-master. For an example, when master is waiting for a
>> NORMAL_STOP interrupt in its MASTER_STOP state, SLAVE_MATCH and
>> RX_DONE interrupts could come along with the NORMAL_STOP in case of
>> an another master immediately sends data just after acquiring the
>> bus. In this case, the NORMAL_STOP interrupt should be handled
>> by master_irq and the SLAVE_MATCH and RX_DONE interrupts should be
>> handled by slave_irq. This commit modifies irq hadling logic to
>> handle the master/slave combined events properly.
>>
>> Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
>> ---
>> ? drivers/i2c/busses/i2c-aspeed.c | 137 ++++++++++++++++++--------------
>> ? 1 file changed, 76 insertions(+), 61 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-aspeed.c
>> b/drivers/i2c/busses/i2c-aspeed.c
>> index efb89422d496..24d43f143a55 100644
>> --- a/drivers/i2c/busses/i2c-aspeed.c
>> +++ b/drivers/i2c/busses/i2c-aspeed.c
>> @@ -82,6 +82,11 @@
>> ? #define ASPEED_I2CD_INTR_RX_DONE??????????? BIT(2)
>> ? #define ASPEED_I2CD_INTR_TX_NAK??????????????? BIT(1)
>> ? #define ASPEED_I2CD_INTR_TX_ACK??????????????? BIT(0)
>> +#define ASPEED_I2CD_INTR_ERRORS?????????????????????????????? \
>> +??????? (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT |?????????????????? \
>> +???????? ASPEED_I2CD_INTR_SCL_TIMEOUT |?????????????????????? \
>> +???????? ASPEED_I2CD_INTR_ABNORMAL |?????????????????????? \
>> +???????? ASPEED_I2CD_INTR_ARBIT_LOSS)
>> ? #define ASPEED_I2CD_INTR_ALL?????????????????????????????? \
>> ????????? (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT |?????????????????? \
>> ?????????? ASPEED_I2CD_INTR_BUS_RECOVER_DONE |?????????????????? \
>> @@ -150,6 +155,7 @@ struct aspeed_i2c_bus {
>> ????? int??????????????? cmd_err;
>> ????? /* Protected only by i2c_lock_bus */
>> ????? int??????????????? master_xfer_result;
>> +??? u32??????????????? irq_status;
>> ? #if IS_ENABLED(CONFIG_I2C_SLAVE)
>> ????? struct i2c_client??????? *slave;
>> ????? enum aspeed_i2c_slave_state??? slave_state;
>> @@ -229,36 +235,30 @@ static int aspeed_i2c_recover_bus(struct
>> aspeed_i2c_bus *bus)
>> ? #if IS_ENABLED(CONFIG_I2C_SLAVE)
>> ? static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
>> ? {
>> -??? u32 command, irq_status, status_ack = 0;
>> +??? u32 command, status_ack = 0;
>> ????? struct i2c_client *slave = bus->slave;
>> -??? bool irq_handled = true;
>> ????? u8 value;
>> -??? if (!slave) {
>> -??????? irq_handled = false;
>> -??????? goto out;
>> -??? }
>> +??? if (!slave)
>> +??????? return false;
>> ????? command = readl(bus->base + ASPEED_I2C_CMD_REG);
>> -??? irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
>> ????? /* Slave was requested, restart state machine. */
>> -??? if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
>> +??? if (bus->irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
>> ????????? status_ack |= ASPEED_I2CD_INTR_SLAVE_MATCH;
>> ????????? bus->slave_state = ASPEED_I2C_SLAVE_START;
>> ????? }
>> ????? /* Slave is not currently active, irq was for someone else. */
>> -??? if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) {
>> -??????? irq_handled = false;
>> -??????? goto out;
>> -??? }
>> +??? if (bus->slave_state == ASPEED_I2C_SLAVE_STOP)
>> +??????? return false;
>> ????? dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
>> -??????? irq_status, command);
>> +??????? bus->irq_status, command);
>> ????? /* Slave was sent something. */
>> -??? if (irq_status & ASPEED_I2CD_INTR_RX_DONE) {
>> +??? if (bus->irq_status & ASPEED_I2CD_INTR_RX_DONE) {
>> ????????? value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
>> ????????? /* Handle address frame. */
>> ????????? if (bus->slave_state == ASPEED_I2C_SLAVE_START) {
>> @@ -273,28 +273,29 @@ static bool aspeed_i2c_slave_irq(struct
>> aspeed_i2c_bus *bus)
>> ????? }
>> ????? /* Slave was asked to stop. */
>> -??? if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
>> +??? if (bus->irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
>> ????????? status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
>> ????????? bus->slave_state = ASPEED_I2C_SLAVE_STOP;
>> ????? }
>> -??? if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
>> +??? if (bus->irq_status & ASPEED_I2CD_INTR_TX_NAK) {
>> ????????? status_ack |= ASPEED_I2CD_INTR_TX_NAK;
>> ????????? bus->slave_state = ASPEED_I2C_SLAVE_STOP;
>> ????? }
>> +??? if (bus->irq_status & ASPEED_I2CD_INTR_TX_ACK) {
>> +??????? status_ack |= ASPEED_I2CD_INTR_TX_ACK;
>> +??? }
>> ????? switch (bus->slave_state) {
>> ????? case ASPEED_I2C_SLAVE_READ_REQUESTED:
>> -??????? if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
>> +??????? if (bus->irq_status & ASPEED_I2CD_INTR_TX_ACK)
>> ????????????? dev_err(bus->dev, "Unexpected ACK on read request.\n");
>> ????????? bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
>> -
>> ????????? i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
>> ????????? writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
>> ????????? writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
>> ????????? break;
>> ????? case ASPEED_I2C_SLAVE_READ_PROCESSED:
>> -??????? status_ack |= ASPEED_I2CD_INTR_TX_ACK;
>> -??????? if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
>> +??????? if (!(bus->irq_status & ASPEED_I2CD_INTR_TX_ACK))
>> ????????????? dev_err(bus->dev,
>> ????????????????? "Expected ACK after processed read.\n");
>> ????????? i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
>> @@ -317,14 +318,8 @@ static bool aspeed_i2c_slave_irq(struct
>> aspeed_i2c_bus *bus)
>> ????????? break;
>> ????? }
>> -??? if (status_ack != irq_status)
>> -??????? dev_err(bus->dev,
>> -??????????? "irq handled != irq. expected %x, but was %x\n",
>> -??????????? irq_status, status_ack);
>> -??? writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG);
>> -
>> -out:
>> -??? return irq_handled;
>> +??? bus->irq_status ^= status_ack;
>> +??? return !bus->irq_status;
>> ? }
>> ? #endif /* CONFIG_I2C_SLAVE */
>> @@ -382,19 +377,19 @@ static int aspeed_i2c_is_irq_error(u32 irq_status)
>> ? static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
>> ? {
>> -??? u32 irq_status, status_ack = 0, command = 0;
>> +??? u32 status_ack = 0, command = 0;
>> ????? struct i2c_msg *msg;
>> ????? u8 recv_byte;
>> ????? int ret;
>> -??? irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
>> -??? /* Ack all interrupt bits. */
>> -??? writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG);
>> -
>> -??? if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
>> +??? if (bus->irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
>> ????????? bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
>> ????????? status_ack |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
>> ????????? goto out_complete;
>> +??? } else {
>> +??????? /* Master is not currently active, irq was for someone else. */
>> +??????? if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE)
>> +??????????? goto out_no_complete;
>> ????? }
>> ????? /*
>> @@ -402,20 +397,23 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ?????? * should clear the command queue effectively taking us back to the
>> ?????? * INACTIVE state.
>> ?????? */
>> -??? ret = aspeed_i2c_is_irq_error(irq_status);
>> -??? if (ret < 0) {
>> +??? ret = aspeed_i2c_is_irq_error(bus->irq_status);
>> +??? if (ret) {
>> ????????? dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
>> -??????????? irq_status);
>> +??????????? bus->irq_status);
>> ????????? bus->cmd_err = ret;
>> ????????? bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
>> +??????? status_ack |= (bus->irq_status & ASPEED_I2CD_INTR_ERRORS);
>> ????????? goto out_complete;
>> ????? }
>> ????? /* We are in an invalid state; reset bus to a known state. */
>> ????? if (!bus->msgs) {
>> -??????? dev_err(bus->dev, "bus in unknown state\n");
>> +??????? dev_err(bus->dev, "bus in unknown state irq_status: 0x%x\n",
>> +??????????? bus->irq_status);
>> ????????? bus->cmd_err = -EIO;
>> -??????? if (bus->master_state != ASPEED_I2C_MASTER_STOP)
>> +??????? if (bus->master_state != ASPEED_I2C_MASTER_STOP &&
>> +??????????? bus->master_state != ASPEED_I2C_MASTER_INACTIVE)
>> ????????????? aspeed_i2c_do_stop(bus);
>> ????????? goto out_no_complete;
>> ????? }
>> @@ -427,8 +425,14 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ?????? * then update the state and handle the new state below.
>> ?????? */
>> ????? if (bus->master_state == ASPEED_I2C_MASTER_START) {
>> -??????? if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
>> -??????????? pr_devel("no slave present at %02x\n", msg->addr);
>> +??????? if (unlikely(!(bus->irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
>> +??????????? if (unlikely(!(bus->irq_status &
>> +???????????????????? ASPEED_I2CD_INTR_TX_NAK))) {
>> +??????????????? bus->cmd_err = -ENXIO;
>> +??????????????? bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
>> +??????????????? goto out_complete;
>> +??????????? }
>> +??????????? pr_devel("no slave present at %02x", msg->addr);
> Missing line feed character
Thanks for your pointing it out. Will add '\n' at the end of the
message.
>> ????????????? status_ack |= ASPEED_I2CD_INTR_TX_NAK;
>> ????????????? bus->cmd_err = -ENXIO;
>> ????????????? aspeed_i2c_do_stop(bus);
>> @@ -447,11 +451,12 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ????? switch (bus->master_state) {
>> ????? case ASPEED_I2C_MASTER_TX:
>> -??????? if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
>> +??????? if (unlikely(bus->irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
>> ????????????? dev_dbg(bus->dev, "slave NACKed TX\n");
>> ????????????? status_ack |= ASPEED_I2CD_INTR_TX_NAK;
>> ????????????? goto error_and_stop;
>> -??????? } else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
>> +??????? } else if (unlikely(!(bus->irq_status &
>> +????????????????????? ASPEED_I2CD_INTR_TX_ACK))) {
>> ????????????? dev_err(bus->dev, "slave failed to ACK TX\n");
>> ????????????? goto error_and_stop;
>> ????????? }
>> @@ -470,11 +475,11 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ????????? goto out_no_complete;
>> ????? case ASPEED_I2C_MASTER_RX_FIRST:
>> ????????? /* RX may not have completed yet (only address cycle) */
>> -??????? if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE))
>> +??????? if (!(bus->irq_status & ASPEED_I2CD_INTR_RX_DONE))
>> ????????????? goto out_no_complete;
>> ????????? /* fallthrough intended */
>> ????? case ASPEED_I2C_MASTER_RX:
>> -??????? if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
>> +??????? if (unlikely(!(bus->irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
>> ????????????? dev_err(bus->dev, "master failed to RX\n");
>> ????????????? goto error_and_stop;
>> ????????? }
>> @@ -505,8 +510,11 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ????????? }
>> ????????? goto out_no_complete;
>> ????? case ASPEED_I2C_MASTER_STOP:
>> -??????? if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) {
>> -??????????? dev_err(bus->dev, "master failed to STOP\n");
>> +??????? if (unlikely(!(bus->irq_status &
>> +?????????????????? ASPEED_I2CD_INTR_NORMAL_STOP))) {
>> +??????????? dev_err(bus->dev,
>> +??????????????? "master failed to STOP irq_status:0x%x\n",
>> +??????????????? bus->irq_status);
>> ????????????? bus->cmd_err = -EIO;
>> ????????????? /* Do not STOP as we have already tried. */
>> ????????? } else {
>> @@ -518,7 +526,7 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ????? case ASPEED_I2C_MASTER_INACTIVE:
>> ????????? dev_err(bus->dev,
>> ????????????? "master received interrupt 0x%08x, but is inactive\n",
>> -??????????? irq_status);
>> +??????????? bus->irq_status);
>> ????????? bus->cmd_err = -EIO;
>> ????????? /* Do not STOP as we should be inactive. */
>> ????????? goto out_complete;
>> @@ -540,33 +548,40 @@ static bool aspeed_i2c_master_irq(struct
>> aspeed_i2c_bus *bus)
>> ????????? bus->master_xfer_result = bus->msgs_index + 1;
>> ????? complete(&bus->cmd_complete);
>> ? out_no_complete:
>> -??? if (irq_status != status_ack)
>> -??????? dev_err(bus->dev,
>> -??????????? "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
>> -??????????? irq_status, status_ack);
>> -??? return !!irq_status;
>> +??? bus->irq_status ^= status_ack;
>> +??? return !bus->irq_status;
>> ? }
>> ? static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
>> ? {
>> ????? struct aspeed_i2c_bus *bus = dev_id;
>> -??? bool ret;
>> +??? u32 irq_received;
>> ????? spin_lock(&bus->lock);
>> +??? irq_received = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
>> +??? bus->irq_status = irq_received;
>> ? #if IS_ENABLED(CONFIG_I2C_SLAVE)
>> -??? if (aspeed_i2c_slave_irq(bus)) {
>> -??????? dev_dbg(bus->dev, "irq handled by slave.\n");
>> -??????? ret = true;
>> -??????? goto out;
>> +??? if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
>> +??????? if (!aspeed_i2c_master_irq(bus))
>> +??????????? aspeed_i2c_slave_irq(bus);
>> +??? } else {
>> +??????? if (!aspeed_i2c_slave_irq(bus))
>> +??????????? aspeed_i2c_master_irq(bus);
>> ????? }
>> +#else
>> +??? aspeed_i2c_master_irq(bus);
>> ? #endif /* CONFIG_I2C_SLAVE */
>> -??? ret = aspeed_i2c_master_irq(bus);
>> +??? if (bus->irq_status)
>> +??????? dev_err(bus->dev,
>> +??????????? "irq handled != irq. expected 0x%08x, but was 0x%08x\n",
>> +??????????? irq_received, irq_received ^ bus->irq_status);
>> -out:
>> +??? /* Ack all interrupt bits. */
>> +??? writel(irq_received, bus->base + ASPEED_I2C_INTR_STS_REG);
>> ????? spin_unlock(&bus->lock);
>> -??? return ret ? IRQ_HANDLED : IRQ_NONE;
>> +??? return bus->irq_status ? IRQ_NONE : IRQ_HANDLED;
>> ? }
>> ? static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
>>
^ permalink raw reply
* Re: [PATCHv3 2/2] mtd: m25p80: restore the status of SPI flash when exiting
From: Brian Norris @ 2018-07-23 18:13 UTC (permalink / raw)
To: Zhiqiang Hou
Cc: linux-mtd, linux-kernel, dwmw2, boris.brezillon, marek.vasut,
richard, cyrille.pitchen
In-Reply-To: <20171206025342.7266-3-Zhiqiang.Hou@nxp.com>
Hello,
I noticed this got merged, but I wanted to put my 2 cents in here:
On Wed, Dec 06, 2017 at 10:53:42AM +0800, Zhiqiang Hou wrote:
> From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
>
> Restore the status to be compatible with legacy devices.
> Take Freescale eSPI boot for example, it copies (in 3 Byte
> addressing mode) the RCW and bootloader images from SPI flash
> without firing a reset signal previously, so the reboot command
> will fail without reseting the addressing mode of SPI flash.
> This patch implement .shutdown function to restore the status
> in reboot process, and add the same operation to the .remove
> function.
We have previously rejected this patch multiple times, because the above
comment demonstrates a broken product. You cannot guarantee that all
reboots will invoke the .shutdown() method -- what about crashes? What
about watchdog resets? IIUC, those will hit the same broken behavior,
and have unexepcted behavior in your bootloader.
I suppose one could argue for doing this in remove(), but AIUI you're
just papering over system bugs by introducing the shutdown() function
here. Thus, I'd prefer we drop the shutdown() method to avoid misleading
other users of this driver.
Brian
> Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
> ---
> V3:
> - Modified the commit to make this patch specific.
>
> drivers/mtd/devices/m25p80.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
> index dbe6a1de2bb8..a4e18f6aaa33 100644
> --- a/drivers/mtd/devices/m25p80.c
> +++ b/drivers/mtd/devices/m25p80.c
> @@ -307,10 +307,18 @@ static int m25p_remove(struct spi_device *spi)
> {
> struct m25p *flash = spi_get_drvdata(spi);
>
> + spi_nor_restore(&flash->spi_nor);
> +
> /* Clean up MTD stuff. */
> return mtd_device_unregister(&flash->spi_nor.mtd);
> }
>
> +static void m25p_shutdown(struct spi_device *spi)
> +{
> + struct m25p *flash = spi_get_drvdata(spi);
> +
> + spi_nor_restore(&flash->spi_nor);
> +}
> /*
> * Do NOT add to this array without reading the following:
> *
> @@ -386,6 +394,7 @@ static struct spi_driver m25p80_driver = {
> .id_table = m25p_ids,
> .probe = m25p_probe,
> .remove = m25p_remove,
> + .shutdown = m25p_shutdown,
>
> /* REVISIT: many of these chips have deep power-down modes, which
> * should clearly be entered on suspend() to minimize power use.
> --
> 2.14.1
>
^ permalink raw reply
* Re: [PATCH v6 8/8] fetch-pack: implement ref-in-want
From: Duy Nguyen @ 2018-07-23 18:13 UTC (permalink / raw)
To: Brandon Williams
Cc: Git Mailing List, Jonathan Tan, Junio C Hamano, Stefan Beller,
Jonathan Nieder
In-Reply-To: <20180723175318.GB25435@google.com>
On Mon, Jul 23, 2018 at 7:53 PM Brandon Williams <bmwill@google.com> wrote:
>
> On 07/22, Duy Nguyen wrote:
> > On Thu, Jun 28, 2018 at 12:33 AM Brandon Williams <bmwill@google.com> wrote:
> > > +static void receive_wanted_refs(struct packet_reader *reader, struct ref *refs)
> > > +{
> > > + process_section_header(reader, "wanted-refs", 0);
> > > + while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
> > > + struct object_id oid;
> > > + const char *end;
> > > + struct ref *r = NULL;
> > > +
> > > + if (parse_oid_hex(reader->line, &oid, &end) || *end++ != ' ')
> > > + die("expected wanted-ref, got '%s'", reader->line);
> >
> > Could you do a follow and wrap all these strings in _() since this one
> > is already in 'next'?
>
> What criteria is used to determine if something should be translated?
> To me, this looks like a wire-protocol error which would benefit from
> not being translated because it would be easier to grep for if it
> occurs. That and if a user sees this sort of error I don't think that
> they could really do anything about it anyway.
Devs are users too and for me, even if I can read English just fine, I
prefer fully translated interface, not a mix of non-English and
English. Users can still google around and find out about wanted-ref
(at least linux users 10 years ago did). If they show up here asking
for support, we can ask them to translate back if needed (or look into
.po files). We have the same problem anyway if their bug reports
contain other non-English strings.
Besides drawing the line "benefit from (not) being translated" varies
from one developer to another. I think it's just easier and more
consistent to stick to "if it's not machine-readable (or really meant
for devs, like BUG()), translate it" and leave it to translators to
decide.
--
Duy
^ permalink raw reply
* In-Band Firmware Update
From: Patrick Venture @ 2018-07-23 18:13 UTC (permalink / raw)
To: OpenBMC Maillist
I've started to implement the host-tool outside of google3, and
started splitting up the OEM handler that corresponds with it.
However, firstly, I've submitted the design for the protocol for
review, please let me know if you're interested and I'll add you to
the review. IIRC, there was at least one interested party outside of
us.
Patrick
^ permalink raw reply
* Re: [PATCH] fetch-pack: mark die strings for translation
From: Stefan Beller @ 2018-07-23 18:14 UTC (permalink / raw)
To: Brandon Williams; +Cc: git
In-Reply-To: <20180723175635.31323-1-bmwill@google.com>
On Mon, Jul 23, 2018 at 10:56 AM Brandon Williams <bmwill@google.com> wrote:
>
fetch-pack is listed as a plumbing command, which means its prime consumer
is supposedly a machine; But fetch-pack is also used by git-fetch that
is invoked
by a human, who prefers translations.
.. goes reads code...
This translates protocol v2 messages, and p0 messages are translated already,
so this just aligns the new protocol to the old protocol w.r.t. i18n.
Sounds good,
Thanks,
Stefan
[ This message is a gentle hint for better commit messages. ;-) ]
> Signed-off-by: Brandon Williams <bmwill@google.com>
> ---
> fetch-pack.c | 16 ++++++++--------
> 1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/fetch-pack.c b/fetch-pack.c
> index 0b4a9f288f..51abee6181 100644
> --- a/fetch-pack.c
> +++ b/fetch-pack.c
> @@ -1245,13 +1245,13 @@ static int process_section_header(struct packet_reader *reader,
> int ret;
>
> if (packet_reader_peek(reader) != PACKET_READ_NORMAL)
> - die("error reading section header '%s'", section);
> + die(_("error reading section header '%s'"), section);
>
> ret = !strcmp(reader->line, section);
>
> if (!peek) {
> if (!ret)
> - die("expected '%s', received '%s'",
> + die(_("expected '%s', received '%s'"),
> section, reader->line);
> packet_reader_read(reader);
> }
> @@ -1289,12 +1289,12 @@ static int process_acks(struct packet_reader *reader, struct oidset *common)
> continue;
> }
>
> - die("unexpected acknowledgment line: '%s'", reader->line);
> + die(_("unexpected acknowledgment line: '%s'"), reader->line);
> }
>
> if (reader->status != PACKET_READ_FLUSH &&
> reader->status != PACKET_READ_DELIM)
> - die("error processing acks: %d", reader->status);
> + die(_("error processing acks: %d"), reader->status);
>
> /* return 0 if no common, 1 if there are common, or 2 if ready */
> return received_ready ? 2 : (received_ack ? 1 : 0);
> @@ -1331,7 +1331,7 @@ static void receive_shallow_info(struct fetch_pack_args *args,
>
> if (reader->status != PACKET_READ_FLUSH &&
> reader->status != PACKET_READ_DELIM)
> - die("error processing shallow info: %d", reader->status);
> + die(_("error processing shallow info: %d"), reader->status);
>
> setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL);
> args->deepen = 1;
> @@ -1346,7 +1346,7 @@ static void receive_wanted_refs(struct packet_reader *reader, struct ref *refs)
> struct ref *r = NULL;
>
> if (parse_oid_hex(reader->line, &oid, &end) || *end++ != ' ')
> - die("expected wanted-ref, got '%s'", reader->line);
> + die(_("expected wanted-ref, got '%s'"), reader->line);
>
> for (r = refs; r; r = r->next) {
> if (!strcmp(end, r->name)) {
> @@ -1356,11 +1356,11 @@ static void receive_wanted_refs(struct packet_reader *reader, struct ref *refs)
> }
>
> if (!r)
> - die("unexpected wanted-ref: '%s'", reader->line);
> + die(_("unexpected wanted-ref: '%s'"), reader->line);
> }
>
> if (reader->status != PACKET_READ_DELIM)
> - die("error processing wanted refs: %d", reader->status);
> + die(_("error processing wanted refs: %d"), reader->status);
> }
>
> enum fetch_state {
> --
> 2.18.0.233.g985f88cf7e-goog
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.