* [Buildroot] [PATCH] dtv-scan-tables: rename file to have only ASCII characters
From: Thomas Petazzoni @ 2016-11-14 21:12 UTC (permalink / raw)
To: buildroot
In-Reply-To: <20161114211024.GC3399@free.fr>
Hello,
On Mon, 14 Nov 2016 22:10:24 +0100, Yann E. MORIN wrote:
> At first, I was not very happy about this, because the filename is also
> displayed to the user, so it would make sense to keep localised names.
>
> However, you are right that there is no standard way to encode
> filenames, so this is not very reliable to depend on the filename to
> provide a user-visible representation of the city/country/... Instead,
> the location should be encoded in the file itself, possibly using the
> filename as a ascii-only fallback.
There are already many many other files that should have non-ASCII
characters to accurately represent the name of the city or region, but
that don't have them. From the commit log of the patch I just sent
upstream:
- pl-Wroclaw should be written pl-Wroc?aw
- se-Laxsjo should be written se-Laxsj?
- de-Dusseldorf should be written de-D?sseldorf
- vn-Thaibinh should be written vn-Th?i_B?nh
> > + mv $(TARGET_DIR)/usr/share/dvb/dvb-t/pl-Krosno_Sucha* \
> > + $(TARGET_DIR)/usr/share/dvb/dvb-t/pl-Krosno_Sucha_Gora
>
> Can't you do that in a post-extrat or post-patch hook?
Sure, v2 coming.
Thanks,
Thomas
--
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* Re: [PATCH v2] tile: handle __ro_after_init like parisc does
From: Kees Cook @ 2016-11-14 21:12 UTC (permalink / raw)
To: Chris Metcalf; +Cc: Heiko Carstens, Martin Schwidefsky, LKML
In-Reply-To: <1479155369-18074-1-git-send-email-cmetcalf@mellanox.com>
On Mon, Nov 14, 2016 at 12:29 PM, Chris Metcalf <cmetcalf@mellanox.com> wrote:
> The tile architecture already marks RO_DATA as read-only in
> the kernel, so grouping RO_AFTER_INIT_DATA with RO_DATA, as is
> done by default, means the kernel faults in init when it tries
> to write to RO_AFTER_INIT_DATA. For now, just arrange that
> __ro_after_init is handled like __write_once, i.e. __read_mostly.
>
> Signed-off-by: Chris Metcalf <cmetcalf@mellanox.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
At some point here, I want to collect all the arch maintainers and
discuss the options for correctly reflecting the three data
memory-protection needs we have:
- always read-only
- read-only after init
- read-only except during rare updates
(The latter one doesn't exist all yet...)
x86, arm, and arm64 use mark_rodata_ro() after init finishes, so they
don't technically implement "always read-only". parisc, tile, powerpc,
others have "always read-only", but disable read-only-after-init since
they don't use mark_rodata_ro(). I think s390 has recently implemented
both, but I have to double-check...
-Kees
> ---
> arch/tile/include/asm/cache.h | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/arch/tile/include/asm/cache.h b/arch/tile/include/asm/cache.h
> index 6160761d5f61..4810e48dbbbf 100644
> --- a/arch/tile/include/asm/cache.h
> +++ b/arch/tile/include/asm/cache.h
> @@ -61,4 +61,7 @@
> */
> #define __write_once __read_mostly
>
> +/* __ro_after_init is the generic name for the tile arch __write_once. */
> +#define __ro_after_init __read_mostly
> +
> #endif /* _ASM_TILE_CACHE_H */
> --
> 2.7.2
>
--
Kees Cook
Nexus Security
^ permalink raw reply
* [Buildroot] Buildroot error
From: Michael Brainerd @ 2016-11-14 21:11 UTC (permalink / raw)
To: buildroot
I have a build error that I am unable to find documentation to debug the issue.
See attached build error text, and .config file.
My host is:
$> uname -a
Linux mikeb-23-q214 4.4.0-47-generic #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
$>
CONFIDENTIALITY NOTICE
This e-mail message, including any attachments, may contain confidential information which is intended only for the use of the intended recipient(s). Any unauthorized review, use, disclosure, distribution, dissemination or action taken in reliance upon this information by persons or entities other than the intended recipient is prohibited. If you are not the intended recipient and this message has been addressed to you in error, please promptly notify the sender by email reply and destroy all copies of the message and any attachments.
EXPORT CONTROL NOTICE
This document and attachments may contain technical data as defined in the International Traffic In Arms Regulations (ITAR) 22 CFR 120.10 or the Export Administration Regulations (EAR) 15 CFR Parts 730 ? 780 . Export of this material may be controlled by these regulations and may not be exported or transferred to non-U.S. persons without prior written approval from the U.S. government.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.busybox.net/pipermail/buildroot/attachments/20161114/36617573/attachment.html>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: Build_errors.txt
URL: <http://lists.busybox.net/pipermail/buildroot/attachments/20161114/36617573/attachment.txt>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dot_config
Type: application/octet-stream
Size: 58995 bytes
Desc: dot_config
URL: <http://lists.busybox.net/pipermail/buildroot/attachments/20161114/36617573/attachment.obj>
^ permalink raw reply
* [PATCH] ext4: avoid lockdep warning when inheriting encryption context
From: Eric Biggers @ 2016-11-14 21:03 UTC (permalink / raw)
To: linux-ext4
Cc: Theodore Ts'o, Andreas Dilger, Jaegeuk Kim, Jan Kara,
Eric Biggers
On a lockdep-enabled kernel, xfstests generic/027 fails due to a lockdep
warning when run on ext4 mounted with -o test_dummy_encryption:
xfs_io/4594 is trying to acquire lock:
(jbd2_handle
){++++.+}, at:
[<ffffffff813096ef>] jbd2_log_wait_commit+0x5/0x11b
but task is already holding lock:
(jbd2_handle
){++++.+}, at:
[<ffffffff813000de>] start_this_handle+0x354/0x3d8
The abbreviated call stack is:
[<ffffffff813096ef>] ? jbd2_log_wait_commit+0x5/0x11b
[<ffffffff8130972a>] jbd2_log_wait_commit+0x40/0x11b
[<ffffffff813096ef>] ? jbd2_log_wait_commit+0x5/0x11b
[<ffffffff8130987b>] ? __jbd2_journal_force_commit+0x76/0xa6
[<ffffffff81309896>] __jbd2_journal_force_commit+0x91/0xa6
[<ffffffff813098b9>] jbd2_journal_force_commit_nested+0xe/0x18
[<ffffffff812a6049>] ext4_should_retry_alloc+0x72/0x79
[<ffffffff812f0c1f>] ext4_xattr_set+0xef/0x11f
[<ffffffff812cc35b>] ext4_set_context+0x3a/0x16b
[<ffffffff81258123>] fscrypt_inherit_context+0xe3/0x103
[<ffffffff812ab611>] __ext4_new_inode+0x12dc/0x153a
[<ffffffff812bd371>] ext4_create+0xb7/0x161
When a file is created in an encrypted directory, ext4_set_context() is
called to set an encryption context on the new file. This calls
ext4_xattr_set(), which contains a retry loop where the journal is
forced to commit if an ENOSPC error is encountered.
If the task actually were to wait for the journal to commit in this
case, then it would deadlock because a handle remains open from
__ext4_new_inode(), so the running transaction can't be committed yet.
Fortunately, __jbd2_journal_force_commit() avoids the deadlock by not
allowing the running transaction to be committed while the current task
has it open. However, the above lockdep warning is still triggered.
Fix the problem by passing the handle through the 'fs_data' argument to
ext4_set_context(), then using ext4_xattr_set_handle() instead of
ext4_xattr_set(). And in the case where no journal handle is specified
and ext4_set_context() has to open one, add an ENOSPC retry loop since
in that case it is the outermost transaction.
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
fs/ext4/ialloc.c | 3 +--
fs/ext4/super.c | 32 ++++++++++++++++++++++----------
2 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 170421e..f543281 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -1115,8 +1115,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
}
if (encrypt) {
- /* give pointer to avoid set_context with journal ops. */
- err = fscrypt_inherit_context(dir, inode, &encrypt, true);
+ err = fscrypt_inherit_context(dir, inode, handle, true);
if (err)
goto fail_free_drop;
}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index ff6f3ab..22d50cb 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1114,14 +1114,22 @@ static int ext4_prepare_context(struct inode *inode)
static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
void *fs_data)
{
- handle_t *handle;
- int res, res2;
+ handle_t *handle = fs_data;
+ int res, res2, retries = 0;
- /* fs_data is null when internally used. */
- if (fs_data) {
- res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
- EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx,
- len, 0);
+ /*
+ * If a journal handle was specified, then the encryption context is
+ * being set on a new inode via inheritance and is part of a larger
+ * transaction to create the inode. Otherwise the encryption context is
+ * being set on an existing inode in its own transaction. Only in the
+ * latter case should the "retry on ENOSPC" logic be used.
+ */
+
+ if (handle) {
+ res = ext4_xattr_set_handle(handle, inode,
+ EXT4_XATTR_INDEX_ENCRYPTION,
+ EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
+ ctx, len, 0);
if (!res) {
ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
ext4_clear_inode_state(inode,
@@ -1130,14 +1138,15 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
return res;
}
+retry:
handle = ext4_journal_start(inode, EXT4_HT_MISC,
ext4_jbd2_credits_xattr(inode));
if (IS_ERR(handle))
return PTR_ERR(handle);
- res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
- EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx,
- len, 0);
+ res = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_ENCRYPTION,
+ EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
+ ctx, len, 0);
if (!res) {
ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
res = ext4_mark_inode_dirty(handle, inode);
@@ -1145,6 +1154,9 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
EXT4_ERROR_INODE(inode, "Failed to mark inode dirty");
}
res2 = ext4_journal_stop(handle);
+
+ if (res == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
if (!res)
res = res2;
return res;
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* Re: [meta-networking][PATCH] iscsi-initiator-utils: Update SRC_URI and homepage
From: Martin Jansa @ 2016-11-14 21:10 UTC (permalink / raw)
To: openembedded-devel
In-Reply-To: <1479156633-20878-1-git-send-email-joe_macdonald@mentor.com>
Github archives are regenerated from time to time, please use the tag and
git fetcher.
On Mon, Nov 14, 2016 at 9:50 PM, Joe MacDonald <joe_macdonald@mentor.com>
wrote:
> open-iscsi.org is defunct, the new home is at open-iscsi.com, update the
> SRC_URI and homepage accordingly.
>
> Signed-off-by: Joe MacDonald <joe_macdonald@mentor.com>
> ---
> ...utils_2.0-873.bb => iscsi-initiator-utils_2.0.873.bb} | 16
> +++++++++-------
> 1 file changed, 9 insertions(+), 7 deletions(-)
> rename meta-networking/recipes-daemons/iscsi-initiator-utils/{
> iscsi-initiator-utils_2.0-873.bb => iscsi-initiator-utils_2.0.873.bb}
> (90%)
>
> diff --git a/meta-networking/recipes-daemons/iscsi-initiator-utils/
> iscsi-initiator-utils_2.0-873.bb b/meta-networking/recipes-
> daemons/iscsi-initiator-utils/iscsi-initiator-utils_2.0.873.bb
> similarity index 90%
> rename from meta-networking/recipes-daemons/iscsi-initiator-utils/
> iscsi-initiator-utils_2.0-873.bb
> rename to meta-networking/recipes-daemons/iscsi-initiator-utils/
> iscsi-initiator-utils_2.0.873.bb
> index 4b13155..d540085 100644
> --- a/meta-networking/recipes-daemons/iscsi-initiator-utils/
> iscsi-initiator-utils_2.0-873.bb
> +++ b/meta-networking/recipes-daemons/iscsi-initiator-utils/
> iscsi-initiator-utils_2.0.873.bb
> @@ -4,16 +4,17 @@ independent, multi-platform implementation of RFC3720.
> The iscsi package \
> provides the server daemon for the iSCSI protocol, as well as the utility
> \
> programs used to manage it. iSCSI is a protocol for distributed \
> disk access using SCSI commands sent over Internet Protocol networks."
> -HOMEPAGE = "http://www.open-iscsi.org/"
> +HOMEPAGE = "http://www.open-iscsi.com/"
> LICENSE = "GPLv2 & LGPLv2.1"
> SECTION = "net"
> DEPENDS = "openssl flex-native bison-native"
>
> -LIC_FILES_CHKSUM = \
> - "file://COPYING;md5=393a5ca445f6965873eca0259a17f833 \
> - file://utils/open-isns/COPYING;md5=
> 7fbc338309ac38fefcd64b04bb903e34"
> +LIC_FILES_CHKSUM = "\
> + file://COPYING;md5=393a5ca445f6965873eca0259a17f833 \
> + file://utils/open-isns/COPYING;md5=7fbc338309ac38fefcd64b04bb903e34 \
> + "
>
> -SRC_URI = "http://www.open-iscsi.org/bits/open-iscsi-${PV}.tar.gz \
> +SRC_URI = "https://github.com/open-iscsi/open-iscsi/archive/${PV}.tar.gz
> \
> file://iscsi-initiator-utils-use-var-for-config.patch \
> file://iscsi-initiator-utils-dont-use-static.patch \
> file://initd.debian \
> @@ -23,8 +24,9 @@ SRC_URI = "http://www.open-iscsi.org/
> bits/open-iscsi-${PV}.tar.gz \
> file://iscsi-initiator-targets.service \
> file://set_initiatorname \
> "
> -SRC_URI[md5sum] = "8b8316d7c9469149a6cc6234478347f7"
> -SRC_URI[sha256sum] = "7dd9f2f97da417560349a8da44ea4f
> cfe98bfd5ef284240a2cc4ff8e88ac7cd9"
> +SRC_URI[md5sum] = "77ef4d5f5aceb4c7f0bef743fa7fc05c"
> +SRC_URI[sha256sum] = "c51f6fad45afb7c059f10776de721c
> 6d5fd0336ff927daacea6a7e0a3ad02f18"
> +
>
> S = "${WORKDIR}/open-iscsi-${PV}"
>
> --
> 1.9.1
>
> --
> _______________________________________________
> Openembedded-devel mailing list
> Openembedded-devel@lists.openembedded.org
> http://lists.openembedded.org/mailman/listinfo/openembedded-devel
>
^ permalink raw reply
* Re: [RFC/PATCH 0/2] git diff <(command1) <(command2)
From: Junio C Hamano @ 2016-11-14 21:10 UTC (permalink / raw)
To: Michael J Gruber
Cc: Johannes Schindelin, Jacob Keller, Dennis Kaarsemaker,
Git mailing list
In-Reply-To: <a3db4c55-550c-f2e8-83b8-46c2be86f7da@drmicha.warpmail.net>
Michael J Gruber <git@drmicha.warpmail.net> writes:
> Junio C Hamano venit, vidit, dixit 14.11.2016 19:01:
>> Michael J Gruber <git@drmicha.warpmail.net> writes:
>>
>>> *My* idea of --no-index was for it to behave as similar to the
>>> --index-version as possible, regarding formatting etc., and to be a good
>>> substitute for ordinary diff. The proposed patch achieves exactly that -
>> ...
> It's not clear to me what you are saying here - 1/2 makes git diff
> follow symbolic links, yes, just like ordinary diff.
Yes, which can be seen as deviating from your earlier "as similar to
the --index version as possible" goal, which I think was where Dscho's
complaint comes from.
I _think_ the no-index mode was primarily for those who want to use
our diff as a replacement for GNU and other diffs, and from that
point of view, I'd favour not doing the "comparing symbolic link?
We'll show the difference between the link contents, not target"
under no-index mode myself. That is a lot closer to the diff other
people implemented, not ours. Hence the knee-jerk reaction I gave
in
http://public-inbox.org/git/xmqqinrt1zcx.fsf@gitster.mtv.corp.google.com
^ permalink raw reply
* [Buildroot] [PATCH] dtv-scan-tables: rename file to have only ASCII characters
From: Yann E. MORIN @ 2016-11-14 21:10 UTC (permalink / raw)
To: buildroot
In-Reply-To: <1479156903-486-1-git-send-email-thomas.petazzoni@free-electrons.com>
Thomas, All,
On 2016-11-14 21:55 +0100, Thomas Petazzoni spake thusly:
> Since the bump of dtv-scan-tables to version
> ceb11833b35f05813b1f0397a60e0f3b99430aab in commit
> b1c8794d8ac0eb3895d13ae91d8e912ec469a105, one file contains non-ASCII
> characters, which causes encoding issues tvheadend. Since no other
> file in the dtv-scan-tables code base contains files with non-ASCII
> characters (despite having files named after cities in various
> countries that definitely do have non-ASCII characters), we rename
> this file so that it is named with only ASCII characters.
>
> This fixes the build of tvheadend, which was failing when the host
> Python interpreter was python3, due to a file name encoding issue.
>
> Fixes:
>
> http://autobuild.buildroot.net/results/1ae8bee297edb089535a2fb6ec724ebf7976888d/
> (tvheadend)
>
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
At first, I was not very happy about this, because the filename is also
displayed to the user, so it would make sense to keep localised names.
However, you are right that there is no standard way to encode
filenames, so this is not very reliable to depend on the filename to
provide a user-visible representation of the city/country/... Instead,
the location should be encoded in the file itself, possibly using the
filename as a ascii-only fallback.
I'll take on me to reach to upstream to discuss this with them.
However, I still ahve a little comment about this patch...
> ---
> Note: we will separately submit a patch to the upstream
> dtv-scan-tables project to rename the problematic file.
> ---
> package/dtv-scan-tables/dtv-scan-tables.mk | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/package/dtv-scan-tables/dtv-scan-tables.mk b/package/dtv-scan-tables/dtv-scan-tables.mk
> index 8ef42b9..2be0eb5 100644
> --- a/package/dtv-scan-tables/dtv-scan-tables.mk
> +++ b/package/dtv-scan-tables/dtv-scan-tables.mk
> @@ -17,11 +17,16 @@ DTV_SCAN_TABLES_SITE_METHOD = git
> DTV_SCAN_TABLES_LICENSE = GPLv2, LGPLv2.1
> DTV_SCAN_TABLES_LICENSE_FILES = COPYING COPYING.LGPL
>
> +# In order to avoid issues with file name encodings, we rename the
> +# only dtv-scan-tables file that has non-ASCII characters to have a
> +# name using only ASCII characters (pl-Krosno_Sucha_Gora)
> define DTV_SCAN_TABLES_INSTALL_TARGET_CMDS
> for f in atsc dvb-c dvb-s dvb-t; do \
> $(INSTALL) -d -m 0755 $(TARGET_DIR)/usr/share/dvb/$$f; \
> $(INSTALL) $(@D)/$$f/* $(TARGET_DIR)/usr/share/dvb/$$f; \
> done
> + mv $(TARGET_DIR)/usr/share/dvb/dvb-t/pl-Krosno_Sucha* \
> + $(TARGET_DIR)/usr/share/dvb/dvb-t/pl-Krosno_Sucha_Gora
Can't you do that in a post-extrat or post-patch hook?
Regards,
Yann E. MORIN.
> endef
>
> $(eval $(generic-package))
> --
> 2.7.4
>
--
.-----------------.--------------------.------------------.--------------------.
| Yann E. MORIN | Real-Time Embedded | /"\ ASCII RIBBON | Erics' conspiracy: |
| +33 662 376 056 | Software Designer | \ / CAMPAIGN | ___ |
| +33 223 225 172 `------------.-------: X AGAINST | \e/ There is no |
| http://ymorin.is-a-geek.org/ | _/*\_ | / \ HTML MAIL | v conspiracy. |
'------------------------------^-------^------------------^--------------------'
^ permalink raw reply
* Re: Announcing btrfs-dedupe
From: Zygo Blaxell @ 2016-11-14 21:10 UTC (permalink / raw)
To: Austin S. Hemmelgarn; +Cc: James Pharaoh, Mark Fasheh, linux-btrfs
In-Reply-To: <4389716b-8082-ef89-7efc-60c2ae6b7db6@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 4307 bytes --]
On Mon, Nov 14, 2016 at 02:56:51PM -0500, Austin S. Hemmelgarn wrote:
> On 2016-11-14 14:51, Zygo Blaxell wrote:
> >Deduplicating an extent that may might be concurrently modified during the
> >dedup is a reasonable userspace request. In the general case there's
> >no way for userspace to ensure that it's not happening.
> I'm not even talking about the locking, I'm talking about the data
> comparison that the ioctl does to ensure they are the same before
> deduplicating them, and specifically that protecting against userspace just
> passing in two random extents that happen to be the same size but not
> contain the same data (because deduplication _should_ reject such a
> situation, that's what the clone ioctl is for).
If I'm deduping a VM image, and the virtual host is writing to said image
(which is likely since an incremental dedup will be intentionally doing
dedup over recently active data sets), the extent I just compared in
userspace might be different by the time the kernel sees it.
This is an important reason why the whole lock/read/compare/replace step
is an atomic operation from userspace's PoV.
The read also saves having to confirm a short/weak hash isn't a collision.
The RAM savings from using weak hashes (~48 bits) are a huge performance
win.
The locking overhead is very small compared to the reading overhead,
and (in the absence of bugs) it will only block concurrent writes to the
same offset range in the src/dst inodes (based on a read of the code...I
don't know if there's also an inode-level or backref-level barrier that
expands the locking scope).
I'm not sure the ioctl is well designed for simply throwing random
data at it, especially not entire files (it can't handle files over
16MB anyway). It will read more data than it has to compared to a
block-by-block comparison from userspace with prefetches or a pair of
IO threads. If userspace reads both copies of the data just before
issuing the extent-same call, the kernel will read the data from cache
reasonably quickly.
> The locking is perfectly reasonable and shouldn't contribute that much to
> the overhead (unless you're being crazy and deduplicating thousands of tiny
> blocks of data).
Why is deduplicating thousands of blocks of data crazy? I already
deduplicate four orders of magnitude more than that per week.
> >That said, some optimization is possible (although there are good reasons
> >not to bother with optimization in the kernel):
> >
> > - VFS could recognize when it has two separate references to
> > the same physical extent and not re-read the same data twice
> > (but that requires teaching VFS how to do CoW in general, and is
> > hard for political reasons on top of the obvious technical ones).
> >
> > - the extent-same ioctl could check to see which extents
> > are referenced by the src and dst ranges, and return success
> > immediately without reading data if they are the same (but
> > userspace should already know this, or it's wasting a huge amount
> > of time before it even calls the kernel).
> >
> >>TBH, even though it's kind of annoying from a performance perspective, it's
> >>a rather nice safety net to have. For example, one of the cases where I do
> >>deduplication is a couple of directories where each directory is an
> >>overlapping partial subset of one large tree which I keep elsewhere. In
> >>this case, I can tell just by filename exactly what files might be
> >>duplicates, so the ioctl's check lets me just call the ioctl on all
> >>potential duplicates (after checking size, no point in wasting time if the
> >>files obviously aren't duplicates), and have it figure out whether or not
> >>they can be deduplicated.
> >>>
> >>>In any case, I'm considering some digging into the filesystem structures
> >>>to see if I can work this out myself before i do any deduplication. I'm
> >>>fairly sure this should be relatively simple to work out, at least well
> >>>enough for my purposes.
> >>Sadly, there's no way to avoid doing so right now.
> >>
> >>--
> >>To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> >>the body of a message to majordomo@vger.kernel.org
> >>More majordomo info at http://vger.kernel.org/majordomo-info.html
>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply
* RFC: Enable delayed responses to Git clean/smudge filter requests
From: Lars Schneider @ 2016-11-14 21:09 UTC (permalink / raw)
To: Git Mailing List
Hi,
Git always performs a clean/smudge filter on files in sequential order.
Sometimes a filter operation can take a noticeable amount of time.
This blocks the entire Git process.
I would like to give a filter process the possibility to answer Git with
"I got your request, I am processing it, ask me for the result later!".
I see the following way to realize this:
In unpack-trees.c:check_updates() [1] we loop through the cache
entries and "ask me later" could be an acceptable return value of the
checkout_entry() call. The loop could run until all entries returned
success or error.
The filter machinery is triggered in various other places in Git and
all places that want to support "ask me later" would need to be patched
accordingly.
--
Do you think this could be a viable approach?
Do you see a better way?
Thanks,
Lars
[1] https://github.com/git/git/blob/3ab228137f980ff72dbdf5064a877d07bec76df9/unpack-trees.c#L267
^ permalink raw reply
* [U-Boot] [PATCH v3 0/4] serial: pxa: kconfig and optional driver model integration
From: Marek Vasut @ 2016-11-14 21:09 UTC (permalink / raw)
To: u-boot
In-Reply-To: <1479156028-30553-1-git-send-email-marcel.ziswiler@toradex.com>
On 11/14/2016 09:40 PM, Marcel Ziswiler wrote:
> This series integrates both Kconfig as well as optional driver model
> support for the PXA serial driver. As I do not have any of the other
> hardware available for testing for now I only transitioned the
> Colibri PXA270 to actually make use of DM_SERIAL. As space on this
> mostly NOR based hardware is rather constrained I decided against
> also integrating device tree support for now but rather use olde
> platform data. Your input on this is more than welcome.
>
> Changes in v3:
> - Add Marek's reviewed-by.
> - Drop spurious newline.
> - Add Marek's reviewed-by.
Applied all four, thanks!
--
Best regards,
Marek Vasut
^ permalink raw reply
* Re: dm-crypt accepts '+' in the key
From: Mikulas Patocka @ 2016-11-14 21:09 UTC (permalink / raw)
To: Alexey Dobriyan
Cc: Milan Broz, Ondrej Kozina, Mike Snitzer, dm-devel, linux-kernel
In-Reply-To: <20161114003631.GA1304@avx2>
On Mon, 14 Nov 2016, Alexey Dobriyan wrote:
> On Sun, Nov 13, 2016 at 03:45:27PM +0100, Milan Broz wrote:
> > On 11/12/2016 09:20 PM, Mikulas Patocka wrote:
> > > Hi
> > >
> > > dm-crypt uses the function kstrtou8 to decode the encryption key. kstrtou8
> > > calls kstrtoull and kstrtoull skips the first character if it is '+'.
> > >
> > > Consequently, it is possible to load keys with '+' in it. For example,
> > > this is possible:
> > >
> > > dmsetup create cr --table "0 131072 crypt aes-cbc-essiv:sha256 +0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0 0 /dev/debian/tmptest 0"
> > >
> > > Should this be fixed in dm-crypt or in kstrtou8? A fix in kstrtou8 could
> > > be more appropriate, but we don't know how many other kernel parts depend
> > > on this "skip plus" behavior...
> >
> > I would way it should be checked in both places...
> > For dmcrypt, it should validate input here and should
> > not accept anything in key field in dm table that is not in hexa representation.
> >
> > (Is this regression since code switched from simple_strtoul to kstrtou8
> > or this bug was there always?)
>
> Well, before kernel would silently parse anything broken as "0".
dm-crypt already validates that there are exactly two characters passed to
kstrtou8 or simple_strtoul.
> But since it is base-16, "0[xX]" will be accepted before every byte.
Yes, the old dm-crypt code that used simple_strtoul accepted "0x" in a key
(and parsed it as zero byte). It didn't accept "+" or "-".
> dm-crypt should parse key by hand, frankly.
Mikulas
^ permalink raw reply
* Re: [PATCH 3.2 144/152] firewire: net: guard against rx buffer overflows
From: Stefan Richter @ 2016-11-14 21:09 UTC (permalink / raw)
To: Ben Hutchings; +Cc: linux-kernel, stable, akpm, Eyal Itkin
In-Reply-To: <lsq.1479082447.664241533@decadent.org.uk>
On Nov 14 Ben Hutchings wrote:
> 3.2.84-rc1 review patch. If anyone has any objections, please let me know.
>
> ------------------
>
> From: Stefan Richter <stefanr@s5r6.in-berlin.de>
>
> commit 667121ace9dbafb368618dbabcf07901c962ddac upstream.
[...]
> [bwh: Backported to 3.2: fwnet_receive_broadcast() never matches IPv6 packets]
> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Backport looks correct to me; thanks.
--
Stefan Richter
-======----- =-== -===-
http://arcgraph.de/sr/
^ permalink raw reply
* [Qemu-devel] [kvm-unit-tests PATCH v6 11/11] arm/arm64: gic: don't just use zero
From: Andrew Jones @ 2016-11-14 21:08 UTC (permalink / raw)
To: kvm, kvmarm, qemu-devel, qemu-arm
Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
marc.zyngier, eric.auger, christoffer.dall
In-Reply-To: <1479157719-31021-1-git-send-email-drjones@redhat.com>
Allow user to select who sends ipis and with which irq,
rather than just always sending irq=0 from cpu0.
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v6:
- make sender/irq names more future-proof [drew]
- sanity check inputs [drew]
- introduce check_sender/irq and bad_sender/irq to more
cleanly do checks [drew]
- default sender and irq to 1, instead of still zero [drew]
v4: improve structure and make sure spurious checking is
done even when the sender isn't cpu0
v2: actually check that the irq received was the irq sent,
and (for gicv2) that the sender is the expected one.
---
arm/gic.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 99 insertions(+), 25 deletions(-)
diff --git a/arm/gic.c b/arm/gic.c
index d954a3775c26..638b8b140c96 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -11,6 +11,7 @@
* This work is licensed under the terms of the GNU LGPL, version 2.
*/
#include <libcflat.h>
+#include <util.h>
#include <asm/setup.h>
#include <asm/processor.h>
#include <asm/gic.h>
@@ -28,6 +29,8 @@ struct gic {
static struct gic *gic;
static int acked[NR_CPUS], spurious[NR_CPUS];
+static int bad_sender[NR_CPUS], bad_irq[NR_CPUS];
+static int cmdl_sender = 1, cmdl_irq = 1;
static cpumask_t ready;
static void nr_cpu_check(int nr)
@@ -43,10 +46,23 @@ static void wait_on_ready(void)
cpu_relax();
}
+static void stats_reset(void)
+{
+ int i;
+
+ for (i = 0; i < nr_cpus; ++i) {
+ acked[i] = 0;
+ bad_sender[i] = -1;
+ bad_irq[i] = -1;
+ }
+ smp_wmb();
+}
+
static void check_acked(cpumask_t *mask)
{
int missing = 0, extra = 0, unexpected = 0;
int nr_pass, cpu, i;
+ bool bad = false;
/* Wait up to 5s for all interrupts to be delivered */
for (i = 0; i < 50; ++i) {
@@ -56,9 +72,21 @@ static void check_acked(cpumask_t *mask)
smp_rmb();
nr_pass += cpumask_test_cpu(cpu, mask) ?
acked[cpu] == 1 : acked[cpu] == 0;
+
+ if (bad_sender[cpu] != -1) {
+ printf("cpu%d received IPI from wrong sender %d\n",
+ cpu, bad_sender[cpu]);
+ bad = true;
+ }
+
+ if (bad_irq[cpu] != -1) {
+ printf("cpu%d received wrong irq %d\n",
+ cpu, bad_irq[cpu]);
+ bad = true;
+ }
}
if (nr_pass == nr_cpus) {
- report("Completed in %d ms", true, ++i * 100);
+ report("Completed in %d ms", !bad, ++i * 100);
return;
}
}
@@ -91,6 +119,22 @@ static void check_spurious(void)
}
}
+static void check_ipi_sender(u32 irqstat)
+{
+ if (gic_version() == 2) {
+ int src = (irqstat >> 10) & 7;
+
+ if (src != cmdl_sender)
+ bad_sender[smp_processor_id()] = src;
+ }
+}
+
+static void check_irqnr(u32 irqnr)
+{
+ if (irqnr != (u32)cmdl_irq)
+ bad_irq[smp_processor_id()] = irqnr;
+}
+
static void ipi_handler(struct pt_regs *regs __unused)
{
u32 irqstat = gic_read_iar();
@@ -98,8 +142,10 @@ static void ipi_handler(struct pt_regs *regs __unused)
if (irqnr != GICC_INT_SPURIOUS) {
gic_write_eoir(irqstat);
- smp_rmb(); /* pairs with wmb in ipi_test functions */
+ smp_rmb(); /* pairs with wmb in stats_reset */
++acked[smp_processor_id()];
+ check_ipi_sender(irqstat);
+ check_irqnr(irqnr);
smp_wmb(); /* pairs with rmb in check_acked */
} else {
++spurious[smp_processor_id()];
@@ -109,19 +155,19 @@ static void ipi_handler(struct pt_regs *regs __unused)
static void gicv2_ipi_send_self(void)
{
- writel(2 << 24, gicv2_dist_base() + GICD_SGIR);
+ writel(2 << 24 | cmdl_irq, gicv2_dist_base() + GICD_SGIR);
}
-static void gicv2_ipi_send_tlist(cpumask_t *mask, int irq __unused)
+static void gicv2_ipi_send_tlist(cpumask_t *mask, int irq)
{
u8 tlist = (u8)cpumask_bits(mask)[0];
- writel(tlist << 16, gicv2_dist_base() + GICD_SGIR);
+ writel(tlist << 16 | irq, gicv2_dist_base() + GICD_SGIR);
}
static void gicv2_ipi_send_broadcast(void)
{
- writel(1 << 24, gicv2_dist_base() + GICD_SGIR);
+ writel(1 << 24 | cmdl_irq, gicv2_dist_base() + GICD_SGIR);
}
static void gicv3_ipi_send_self(void)
@@ -130,12 +176,12 @@ static void gicv3_ipi_send_self(void)
cpumask_clear(&mask);
cpumask_set_cpu(smp_processor_id(), &mask);
- gicv3_ipi_send_tlist(&mask, 0);
+ gicv3_ipi_send_tlist(&mask, cmdl_irq);
}
static void gicv3_ipi_send_broadcast(void)
{
- gicv3_write_sgi1r(1ULL << 40);
+ gicv3_write_sgi1r(1ULL << 40 | cmdl_irq << 24);
isb();
}
@@ -144,10 +190,9 @@ static void ipi_test_self(void)
cpumask_t mask;
report_prefix_push("self");
- memset(acked, 0, sizeof(acked));
- smp_wmb();
+ stats_reset();
cpumask_clear(&mask);
- cpumask_set_cpu(0, &mask);
+ cpumask_set_cpu(smp_processor_id(), &mask);
gic->ipi.send_self();
check_acked(&mask);
report_prefix_pop();
@@ -159,20 +204,18 @@ static void ipi_test_smp(void)
int i;
report_prefix_push("target-list");
- memset(acked, 0, sizeof(acked));
- smp_wmb();
+ stats_reset();
cpumask_copy(&mask, &cpu_present_mask);
- for (i = 0; i < nr_cpus; i += 2)
+ for (i = smp_processor_id() & 1; i < nr_cpus; i += 2)
cpumask_clear_cpu(i, &mask);
- gic->ipi.send_tlist(&mask, 0);
+ gic->ipi.send_tlist(&mask, cmdl_irq);
check_acked(&mask);
report_prefix_pop();
report_prefix_push("broadcast");
- memset(acked, 0, sizeof(acked));
- smp_wmb();
+ stats_reset();
cpumask_copy(&mask, &cpu_present_mask);
- cpumask_clear_cpu(0, &mask);
+ cpumask_clear_cpu(smp_processor_id(), &mask);
gic->ipi.send_broadcast();
check_acked(&mask);
report_prefix_pop();
@@ -189,6 +232,16 @@ static void ipi_enable(void)
local_irq_enable();
}
+static void ipi_send(void)
+{
+ ipi_enable();
+ wait_on_ready();
+ ipi_test_self();
+ ipi_test_smp();
+ check_spurious();
+ exit(report_summary());
+}
+
static void ipi_recv(void)
{
ipi_enable();
@@ -197,6 +250,14 @@ static void ipi_recv(void)
wfi();
}
+static void ipi_test(void)
+{
+ if (smp_processor_id() == cmdl_sender)
+ ipi_send();
+ else
+ ipi_recv();
+}
+
static struct gic gicv2 = {
.ipi = {
.send_self = gicv2_ipi_send_self,
@@ -242,21 +303,34 @@ int main(int argc, char **argv)
report_prefix_pop();
} else if (strcmp(argv[1], "ipi") == 0) {
+ int off, i = 1;
+ long val;
report_prefix_push(argv[1]);
nr_cpu_check(2);
+ while (--argc != 1) {
+ off = parse_keyval(argv[++i], &val);
+ if (off == -1)
+ continue;
+ argv[i][off] = '\0';
+ if (strcmp(argv[i], "sender") == 0) {
+ if (val >= nr_cpus)
+ report_abort("invalid sender %d, nr_cpus=%d", val, nr_cpus);
+ cmdl_sender = val;
+ } else if (strcmp(argv[i], "irq") == 0) {
+ if (val > 15)
+ report_abort("irq (SGI) must be < 16");
+ cmdl_irq = val;
+ }
+ }
+
for_each_present_cpu(cpu) {
if (cpu == 0)
continue;
- smp_boot_secondary(cpu, ipi_recv);
+ smp_boot_secondary(cpu, ipi_test);
}
- ipi_enable();
- wait_on_ready();
- ipi_test_self();
- ipi_test_smp();
- check_spurious();
- report_prefix_pop();
+ ipi_test();
} else {
report_abort("Unknown subtest '%s'", argv[1]);
--
2.7.4
^ permalink raw reply related
* [Qemu-devel] [kvm-unit-tests PATCH v6 10/11] arm/arm64: gicv3: add an IPI test
From: Andrew Jones @ 2016-11-14 21:08 UTC (permalink / raw)
To: kvm, kvmarm, qemu-devel, qemu-arm
Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
marc.zyngier, eric.auger, christoffer.dall
In-Reply-To: <1479157719-31021-1-git-send-email-drjones@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v6: move most gicv2/gicv3 wrappers to common code [Alex]
v5:
- fix copy+paste error in gicv3_write_eoir [drew]
- use modern register names [Andre]
v4:
- heavily comment gicv3_ipi_send_tlist() [Eric]
- changes needed for gicv2 iar/irqstat fix to other patch
v2:
- use IRM for gicv3 broadcast
---
arm/gic.c | 97 +++++++++++++++++++++++++-----
arm/unittests.cfg | 6 ++
lib/arm/asm/arch_gicv3.h | 23 +++++++
lib/arm/asm/gic-v3.h | 10 +++-
lib/arm/asm/gic.h | 60 +++++++++++++++++++
lib/arm/gic.c | 145 ++++++++++++++++++++++++++++++++++++++++++---
lib/arm64/asm/arch_gicv3.h | 22 +++++++
7 files changed, 338 insertions(+), 25 deletions(-)
diff --git a/arm/gic.c b/arm/gic.c
index b42c2b1ca1e1..d954a3775c26 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -3,6 +3,8 @@
*
* GICv2
* + test sending/receiving IPIs
+ * GICv3
+ * + test sending/receiving IPIs
*
* Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
*
@@ -16,7 +18,15 @@
#include <asm/barrier.h>
#include <asm/io.h>
-static int gic_version;
+struct gic {
+ struct {
+ void (*send_self)(void);
+ void (*send_tlist)(cpumask_t *mask, int irq);
+ void (*send_broadcast)(void);
+ } ipi;
+};
+
+static struct gic *gic;
static int acked[NR_CPUS], spurious[NR_CPUS];
static cpumask_t ready;
@@ -83,11 +93,11 @@ static void check_spurious(void)
static void ipi_handler(struct pt_regs *regs __unused)
{
- u32 irqstat = readl(gicv2_cpu_base() + GICC_IAR);
- u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+ u32 irqstat = gic_read_iar();
+ u32 irqnr = gic_iar_irqnr(irqstat);
if (irqnr != GICC_INT_SPURIOUS) {
- writel(irqstat, gicv2_cpu_base() + GICC_EOIR);
+ gic_write_eoir(irqstat);
smp_rmb(); /* pairs with wmb in ipi_test functions */
++acked[smp_processor_id()];
smp_wmb(); /* pairs with rmb in check_acked */
@@ -97,6 +107,38 @@ static void ipi_handler(struct pt_regs *regs __unused)
}
}
+static void gicv2_ipi_send_self(void)
+{
+ writel(2 << 24, gicv2_dist_base() + GICD_SGIR);
+}
+
+static void gicv2_ipi_send_tlist(cpumask_t *mask, int irq __unused)
+{
+ u8 tlist = (u8)cpumask_bits(mask)[0];
+
+ writel(tlist << 16, gicv2_dist_base() + GICD_SGIR);
+}
+
+static void gicv2_ipi_send_broadcast(void)
+{
+ writel(1 << 24, gicv2_dist_base() + GICD_SGIR);
+}
+
+static void gicv3_ipi_send_self(void)
+{
+ cpumask_t mask;
+
+ cpumask_clear(&mask);
+ cpumask_set_cpu(smp_processor_id(), &mask);
+ gicv3_ipi_send_tlist(&mask, 0);
+}
+
+static void gicv3_ipi_send_broadcast(void)
+{
+ gicv3_write_sgi1r(1ULL << 40);
+ isb();
+}
+
static void ipi_test_self(void)
{
cpumask_t mask;
@@ -106,7 +148,7 @@ static void ipi_test_self(void)
smp_wmb();
cpumask_clear(&mask);
cpumask_set_cpu(0, &mask);
- writel(2 << 24, gicv2_dist_base() + GICD_SGIR);
+ gic->ipi.send_self();
check_acked(&mask);
report_prefix_pop();
}
@@ -114,14 +156,15 @@ static void ipi_test_self(void)
static void ipi_test_smp(void)
{
cpumask_t mask;
- unsigned long tlist;
+ int i;
report_prefix_push("target-list");
memset(acked, 0, sizeof(acked));
smp_wmb();
- tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
- cpumask_bits(&mask)[0] = tlist;
- writel((u8)tlist << 16, gicv2_dist_base() + GICD_SGIR);
+ cpumask_copy(&mask, &cpu_present_mask);
+ for (i = 0; i < nr_cpus; i += 2)
+ cpumask_clear_cpu(i, &mask);
+ gic->ipi.send_tlist(&mask, 0);
check_acked(&mask);
report_prefix_pop();
@@ -130,14 +173,14 @@ static void ipi_test_smp(void)
smp_wmb();
cpumask_copy(&mask, &cpu_present_mask);
cpumask_clear_cpu(0, &mask);
- writel(1 << 24, gicv2_dist_base() + GICD_SGIR);
+ gic->ipi.send_broadcast();
check_acked(&mask);
report_prefix_pop();
}
static void ipi_enable(void)
{
- gicv2_enable_defaults();
+ gic_enable_defaults();
#ifdef __arm__
install_exception_handler(EXCPTN_IRQ, ipi_handler);
#else
@@ -154,18 +197,42 @@ static void ipi_recv(void)
wfi();
}
+static struct gic gicv2 = {
+ .ipi = {
+ .send_self = gicv2_ipi_send_self,
+ .send_tlist = gicv2_ipi_send_tlist,
+ .send_broadcast = gicv2_ipi_send_broadcast,
+ },
+};
+
+static struct gic gicv3 = {
+ .ipi = {
+ .send_self = gicv3_ipi_send_self,
+ .send_tlist = gicv3_ipi_send_tlist,
+ .send_broadcast = gicv3_ipi_send_broadcast,
+ },
+};
+
int main(int argc, char **argv)
{
char pfx[8];
int cpu;
- gic_version = gic_init();
- if (!gic_version)
- report_abort("No gic present!");
+ if (!gic_init())
+ report_abort("No supported gic present!");
- snprintf(pfx, sizeof(pfx), "gicv%d", gic_version);
+ snprintf(pfx, sizeof(pfx), "gicv%d", gic_version());
report_prefix_push(pfx);
+ switch (gic_version()) {
+ case 2:
+ gic = &gicv2;
+ break;
+ case 3:
+ gic = &gicv3;
+ break;
+ }
+
if (argc < 2) {
report_prefix_push("ipi");
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index e631c35e2bbb..c7392c747f98 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -66,3 +66,9 @@ file = gic.flat
smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
extra_params = -machine gic-version=2 -append 'ipi'
groups = gic
+
+[gicv3-ipi]
+file = gic.flat
+smp = $MAX_SMP
+extra_params = -machine gic-version=3 -append 'ipi'
+groups = gic
diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h
index 276577452a14..b47cd2e0090b 100644
--- a/lib/arm/asm/arch_gicv3.h
+++ b/lib/arm/asm/arch_gicv3.h
@@ -16,10 +16,28 @@
#define __stringify xstr
#define __ACCESS_CP15(CRn, Op1, CRm, Op2) p15, Op1, %0, CRn, CRm, Op2
+#define __ACCESS_CP15_64(Op1, CRm) p15, Op1, %Q0, %R0, CRm
+#define ICC_EOIR1 __ACCESS_CP15(c12, 0, c12, 1)
+#define ICC_IAR1 __ACCESS_CP15(c12, 0, c12, 0)
+#define ICC_SGI1R __ACCESS_CP15_64(0, c12)
#define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0)
#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7)
+static inline void gicv3_write_eoir(u32 irq)
+{
+ asm volatile("mcr " __stringify(ICC_EOIR1) : : "r" (irq));
+ isb();
+}
+
+static inline u32 gicv3_read_iar(void)
+{
+ u32 irqstat;
+ asm volatile("mrc " __stringify(ICC_IAR1) : "=r" (irqstat));
+ dsb(sy);
+ return irqstat;
+}
+
static inline void gicv3_write_pmr(u32 val)
{
asm volatile("mcr " __stringify(ICC_PMR) : : "r" (val));
@@ -31,6 +49,11 @@ static inline void gicv3_write_grpen1(u32 val)
isb();
}
+static inline void gicv3_write_sgi1r(u64 val)
+{
+ asm volatile("mcrr " __stringify(ICC_SGI1R) : : "r" (val));
+}
+
/*
* We may access GICR_TYPER and GITS_TYPER by reading both the TYPER
* offset and the following offset (+ 4) and then combining them to
diff --git a/lib/arm/asm/gic-v3.h b/lib/arm/asm/gic-v3.h
index 73ade4681d21..43f9ffce56de 100644
--- a/lib/arm/asm/gic-v3.h
+++ b/lib/arm/asm/gic-v3.h
@@ -33,12 +33,19 @@
#define GICR_ISENABLER0 GICD_ISENABLER
#define GICR_IPRIORITYR0 GICD_IPRIORITYR
+#define ICC_SGI1R_AFFINITY_1_SHIFT 16
+#define ICC_SGI1R_AFFINITY_2_SHIFT 32
+#define ICC_SGI1R_AFFINITY_3_SHIFT 48
+#define MPIDR_TO_SGI_AFFINITY(cluster_id, level) \
+ (MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT)
+
#include <asm/arch_gicv3.h>
#ifndef __ASSEMBLY__
#include <asm/setup.h>
-#include <asm/smp.h>
#include <asm/processor.h>
+#include <asm/cpumask.h>
+#include <asm/smp.h>
#include <asm/io.h>
struct gicv3_data {
@@ -55,6 +62,7 @@ extern struct gicv3_data gicv3_data;
extern int gicv3_init(void);
extern void gicv3_enable_defaults(void);
extern void gicv3_set_redist_base(size_t stride);
+extern void gicv3_ipi_send_tlist(cpumask_t *mask, int irq);
static inline void gicv3_do_wait_for_rwp(void *base)
{
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index 21511997f2a9..c2267b6b3937 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -42,5 +42,65 @@
*/
extern int gic_init(void);
+/*
+ * gic_common_ops collects some functions that we provide unit
+ * tests that don't care which gic version they're using.
+ */
+struct gic_common_ops {
+ int gic_version;
+ u32 (*read_iar)(void);
+ u32 (*iar_irqnr)(u32 iar);
+ void (*write_eoir)(u32 irqstat);
+ void (*ipi_send)(int cpu, int irq);
+};
+
+extern struct gic_common_ops *gic_common_ops;
+
+static inline int gic_version(void)
+{
+ assert(gic_common_ops);
+ return gic_common_ops->gic_version;
+}
+
+static inline u32 gic_read_iar(void)
+{
+ assert(gic_common_ops && gic_common_ops->read_iar);
+ return gic_common_ops->read_iar();
+}
+
+static inline u32 gic_iar_irqnr(u32 iar)
+{
+ assert(gic_common_ops && gic_common_ops->iar_irqnr);
+ return gic_common_ops->iar_irqnr(iar);
+}
+
+static inline void gic_write_eoir(u32 irqstat)
+{
+ assert(gic_common_ops && gic_common_ops->write_eoir);
+ gic_common_ops->write_eoir(irqstat);
+}
+
+static inline void gic_ipi_send(int cpu, int irq)
+{
+ assert(gic_common_ops && gic_common_ops->ipi_send);
+ gic_common_ops->ipi_send(cpu, irq);
+}
+
+static inline void gic_enable_defaults(void)
+{
+ switch (gic_version()) {
+ case 2:
+ gicv2_enable_defaults();
+ break;
+ case 3:
+ gicv3_enable_defaults();
+ break;
+ default:
+ printf("%s: Unknown gic version %d\n", __func__,
+ gic_version());
+ abort();
+ }
+}
+
#endif /* !__ASSEMBLY__ */
#endif /* _ASMARM_GIC_H_ */
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
index d703ad96a37e..4f67363e073b 100644
--- a/lib/arm/gic.c
+++ b/lib/arm/gic.c
@@ -56,15 +56,6 @@ int gicv3_init(void)
&gicv3_data.redist_base[0]);
}
-int gic_init(void)
-{
- if (gicv2_init())
- return 2;
- else if (gicv3_init())
- return 3;
- return 0;
-}
-
void gicv2_enable_defaults(void)
{
void *dist = gicv2_dist_base();
@@ -85,6 +76,28 @@ void gicv2_enable_defaults(void)
writel(GICC_ENABLE, cpu_base + GICC_CTLR);
}
+static u32 gicv2_read_iar(void)
+{
+ return readl(gicv2_cpu_base() + GICC_IAR);
+}
+
+static u32 gicv2_iar_irqnr(u32 iar)
+{
+ return iar & GICC_IAR_INT_ID_MASK;
+}
+
+static void gicv2_write_eoir(u32 irqstat)
+{
+ writel(irqstat, gicv2_cpu_base() + GICC_EOIR);
+}
+
+static void gicv2_ipi_send(int cpu, int irq)
+{
+ assert(cpu < 8);
+ assert(irq < 16);
+ writel(1 << (cpu + 16) | irq, gicv2_dist_base() + GICD_SGIR);
+}
+
void gicv3_set_redist_base(size_t stride)
{
u32 aff = mpidr_compress(get_mpidr());
@@ -138,3 +151,117 @@ void gicv3_enable_defaults(void)
gicv3_write_pmr(GICC_INT_PRI_THRESHOLD);
gicv3_write_grpen1(1);
}
+
+static u32 gicv3_iar_irqnr(u32 iar)
+{
+ return iar;
+}
+
+void gicv3_ipi_send_tlist(cpumask_t *mask, int irq)
+{
+ u16 tlist;
+ int cpu;
+
+ assert(irq < 16);
+
+ /*
+ * For each cpu in the mask collect its peers, which are also in
+ * the mask, in order to form target lists.
+ */
+ for_each_cpu(cpu, mask) {
+ u64 mpidr = cpus[cpu], sgi1r;
+ u64 cluster_id;
+
+ /*
+ * GICv3 can send IPIs to up 16 peer cpus with a single
+ * write to ICC_SGI1R_EL1 (using the target list). Peers
+ * are cpus that have nearly identical MPIDRs, the only
+ * difference being Aff0. The matching upper affinity
+ * levels form the cluster ID.
+ */
+ cluster_id = mpidr & ~0xffUL;
+ tlist = 0;
+
+ /*
+ * Sort of open code for_each_cpu in order to have a
+ * nested for_each_cpu loop.
+ */
+ while (cpu < nr_cpus) {
+ if ((mpidr & 0xff) >= 16) {
+ printf("cpu%d MPIDR:aff0 is %d (>= 16)!\n",
+ cpu, (int)(mpidr & 0xff));
+ break;
+ }
+
+ tlist |= 1 << (mpidr & 0xf);
+
+ cpu = cpumask_next(cpu, mask);
+ if (cpu >= nr_cpus)
+ break;
+
+ mpidr = cpus[cpu];
+
+ if (cluster_id != (mpidr & ~0xffUL)) {
+ /*
+ * The next cpu isn't in our cluster. Roll
+ * back the cpu index allowing the outer
+ * for_each_cpu to find it again with
+ * cpumask_next
+ */
+ --cpu;
+ break;
+ }
+ }
+
+ /* Send the IPIs for the target list of this cluster */
+ sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3) |
+ MPIDR_TO_SGI_AFFINITY(cluster_id, 2) |
+ irq << 24 |
+ MPIDR_TO_SGI_AFFINITY(cluster_id, 1) |
+ tlist);
+
+ gicv3_write_sgi1r(sgi1r);
+ }
+
+ /* Force the above writes to ICC_SGI1R_EL1 to be executed */
+ isb();
+}
+
+static void gicv3_ipi_send(int cpu, int irq)
+{
+ cpumask_t mask;
+
+ cpumask_clear(&mask);
+ cpumask_set_cpu(cpu, &mask);
+ gicv3_ipi_send_tlist(&mask, irq);
+}
+
+static struct gic_common_ops gicv2_common_ops = {
+ .gic_version = 2,
+ .read_iar = gicv2_read_iar,
+ .iar_irqnr = gicv2_iar_irqnr,
+ .write_eoir = gicv2_write_eoir,
+ .ipi_send = gicv2_ipi_send,
+};
+
+static struct gic_common_ops gicv3_common_ops = {
+ .gic_version = 3,
+ .read_iar = gicv3_read_iar,
+ .iar_irqnr = gicv3_iar_irqnr,
+ .write_eoir = gicv3_write_eoir,
+ .ipi_send = gicv3_ipi_send,
+};
+
+struct gic_common_ops *gic_common_ops;
+
+int gic_init(void)
+{
+ if (gicv2_init()) {
+ gic_common_ops = &gicv2_common_ops;
+ return 2;
+ } else if (gicv3_init()) {
+ gic_common_ops = &gicv3_common_ops;
+ return 3;
+ }
+ return 0;
+}
diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h
index 6d353567f56a..874775828016 100644
--- a/lib/arm64/asm/arch_gicv3.h
+++ b/lib/arm64/asm/arch_gicv3.h
@@ -10,6 +10,9 @@
#include <asm/sysreg.h>
+#define ICC_EOIR1_EL1 sys_reg(3, 0, 12, 12, 1)
+#define ICC_IAR1_EL1 sys_reg(3, 0, 12, 12, 0)
+#define ICC_SGI1R_EL1 sys_reg(3, 0, 12, 11, 5)
#define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0)
#define ICC_GRPEN1_EL1 sys_reg(3, 0, 12, 12, 7)
@@ -27,6 +30,20 @@
* sets the GP register's most significant bits to 0 with an explicit cast.
*/
+static inline void gicv3_write_eoir(u32 irq)
+{
+ asm volatile("msr_s " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq));
+ isb();
+}
+
+static inline u32 gicv3_read_iar(void)
+{
+ u64 irqstat;
+ asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat));
+ dsb(sy);
+ return (u64)irqstat;
+}
+
static inline void gicv3_write_pmr(u32 val)
{
asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" ((u64)val));
@@ -38,6 +55,11 @@ static inline void gicv3_write_grpen1(u32 val)
isb();
}
+static inline void gicv3_write_sgi1r(u64 val)
+{
+ asm volatile("msr_s " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val));
+}
+
#define gicv3_read_typer(c) readq(c)
#endif /* __ASSEMBLY__ */
--
2.7.4
^ permalink raw reply related
* [Qemu-devel] [kvm-unit-tests PATCH v6 09/11] arm/arm64: add initial gicv3 support
From: Andrew Jones @ 2016-11-14 21:08 UTC (permalink / raw)
To: kvm, kvmarm, qemu-devel, qemu-arm
Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
marc.zyngier, eric.auger, christoffer.dall
In-Reply-To: <1479157719-31021-1-git-send-email-drjones@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v6:
- added comments [Alex]
- added stride parameter to gicv3_set_redist_base [Andre]
- redist-wait s/rwp/uwp/ and comment [Andre]
- removed unnecessary wait-for-rwps [Andre]
v5: use modern register names [Andre]
v4:
- only take defines from kernel we need now [Andre]
- simplify enable by not caring if we reinit the distributor [drew]
v2:
- configure irqs as NS GRP1
---
lib/arm/asm/arch_gicv3.h | 47 ++++++++++++++++++++
lib/arm/asm/gic-v3.h | 104 +++++++++++++++++++++++++++++++++++++++++++++
lib/arm/asm/gic.h | 5 ++-
lib/arm/gic.c | 64 ++++++++++++++++++++++++++++
lib/arm64/asm/arch_gicv3.h | 44 +++++++++++++++++++
lib/arm64/asm/gic-v3.h | 1 +
lib/arm64/asm/sysreg.h | 44 +++++++++++++++++++
7 files changed, 308 insertions(+), 1 deletion(-)
create mode 100644 lib/arm/asm/arch_gicv3.h
create mode 100644 lib/arm/asm/gic-v3.h
create mode 100644 lib/arm64/asm/arch_gicv3.h
create mode 100644 lib/arm64/asm/gic-v3.h
create mode 100644 lib/arm64/asm/sysreg.h
diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h
new file mode 100644
index 000000000000..276577452a14
--- /dev/null
+++ b/lib/arm/asm/arch_gicv3.h
@@ -0,0 +1,47 @@
+/*
+ * All ripped off from arch/arm/include/asm/arch_gicv3.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM_ARCH_GICV3_H_
+#define _ASMARM_ARCH_GICV3_H_
+
+#ifndef __ASSEMBLY__
+#include <libcflat.h>
+#include <asm/barrier.h>
+#include <asm/io.h>
+
+#define __stringify xstr
+
+#define __ACCESS_CP15(CRn, Op1, CRm, Op2) p15, Op1, %0, CRn, CRm, Op2
+
+#define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0)
+#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7)
+
+static inline void gicv3_write_pmr(u32 val)
+{
+ asm volatile("mcr " __stringify(ICC_PMR) : : "r" (val));
+}
+
+static inline void gicv3_write_grpen1(u32 val)
+{
+ asm volatile("mcr " __stringify(ICC_IGRPEN1) : : "r" (val));
+ isb();
+}
+
+/*
+ * We may access GICR_TYPER and GITS_TYPER by reading both the TYPER
+ * offset and the following offset (+ 4) and then combining them to
+ * form a 64-bit address.
+ */
+static inline u64 gicv3_read_typer(const volatile void __iomem *addr)
+{
+ u64 val = readl(addr);
+ val |= (u64)readl(addr + 4) << 32;
+ return val;
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_ARCH_GICV3_H_ */
diff --git a/lib/arm/asm/gic-v3.h b/lib/arm/asm/gic-v3.h
new file mode 100644
index 000000000000..73ade4681d21
--- /dev/null
+++ b/lib/arm/asm/gic-v3.h
@@ -0,0 +1,104 @@
+/*
+ * All GIC* defines are lifted from include/linux/irqchip/arm-gic-v3.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM_GIC_V3_H_
+#define _ASMARM_GIC_V3_H_
+
+#ifndef _ASMARM_GIC_H_
+#error Do not directly include <asm/gic-v3.h>. Include <asm/gic.h>
+#endif
+
+/*
+ * Distributor registers
+ *
+ * We expect to be run in Non-secure mode, thus we define the
+ * group1 enable bits with respect to that view.
+ */
+#define GICD_CTLR_RWP (1U << 31)
+#define GICD_CTLR_ARE_NS (1U << 4)
+#define GICD_CTLR_ENABLE_G1A (1U << 1)
+#define GICD_CTLR_ENABLE_G1 (1U << 0)
+
+/* Re-Distributor registers, offsets from RD_base */
+#define GICR_TYPER 0x0008
+
+#define GICR_TYPER_LAST (1U << 4)
+
+/* Re-Distributor registers, offsets from SGI_base */
+#define GICR_IGROUPR0 GICD_IGROUPR
+#define GICR_ISENABLER0 GICD_ISENABLER
+#define GICR_IPRIORITYR0 GICD_IPRIORITYR
+
+#include <asm/arch_gicv3.h>
+
+#ifndef __ASSEMBLY__
+#include <asm/setup.h>
+#include <asm/smp.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+struct gicv3_data {
+ void *dist_base;
+ void *redist_base[NR_CPUS];
+ unsigned int irq_nr;
+};
+extern struct gicv3_data gicv3_data;
+
+#define gicv3_dist_base() (gicv3_data.dist_base)
+#define gicv3_redist_base() (gicv3_data.redist_base[smp_processor_id()])
+#define gicv3_sgi_base() (gicv3_data.redist_base[smp_processor_id()] + SZ_64K)
+
+extern int gicv3_init(void);
+extern void gicv3_enable_defaults(void);
+extern void gicv3_set_redist_base(size_t stride);
+
+static inline void gicv3_do_wait_for_rwp(void *base)
+{
+ int count = 100000; /* 1s */
+
+ while (readl(base + GICD_CTLR) & GICD_CTLR_RWP) {
+ if (!--count) {
+ printf("GICv3: RWP timeout!\n");
+ abort();
+ }
+ cpu_relax();
+ udelay(10);
+ };
+}
+
+static inline void gicv3_dist_wait_for_rwp(void)
+{
+ gicv3_do_wait_for_rwp(gicv3_dist_base());
+}
+
+static inline void gicv3_redist_wait_for_uwp(void)
+{
+ /*
+ * We can build on gic_do_wait_for_rwp, which uses GICD_ registers
+ * because GICD_CTLR == GICR_CTLR and GICD_CTLR_RWP == GICR_CTLR_UWP
+ */
+ gicv3_do_wait_for_rwp(gicv3_redist_base());
+}
+
+static inline u32 mpidr_compress(u64 mpidr)
+{
+ u64 compressed = mpidr & MPIDR_HWID_BITMASK;
+
+ compressed = (((compressed >> 32) & 0xff) << 24) | compressed;
+ return compressed;
+}
+
+static inline u64 mpidr_uncompress(u32 compressed)
+{
+ u64 mpidr = ((u64)compressed >> 24) << 32;
+
+ mpidr |= compressed & MPIDR_HWID_BITMASK;
+ return mpidr;
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_GIC_V3_H_ */
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index d816b96e46b4..21511997f2a9 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -6,11 +6,11 @@
#ifndef _ASMARM_GIC_H_
#define _ASMARM_GIC_H_
-#include <asm/gic-v2.h>
/* Distributor registers */
#define GICD_CTLR 0x0000
#define GICD_TYPER 0x0004
+#define GICD_IGROUPR 0x0080
#define GICD_ISENABLER 0x0100
#define GICD_IPRIORITYR 0x0400
#define GICD_SGIR 0x0f00
@@ -28,6 +28,9 @@
#define GICC_INT_PRI_THRESHOLD 0xf0
#define GICC_INT_SPURIOUS 0x3ff
+#include <asm/gic-v2.h>
+#include <asm/gic-v3.h>
+
#ifndef __ASSEMBLY__
/*
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
index d655105e058b..d703ad96a37e 100644
--- a/lib/arm/gic.c
+++ b/lib/arm/gic.c
@@ -8,9 +8,11 @@
#include <asm/io.h>
struct gicv2_data gicv2_data;
+struct gicv3_data gicv3_data;
/*
* Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
+ * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
*/
static bool
gic_get_dt_bases(const char *compatible, void **base1, void **base2)
@@ -48,10 +50,18 @@ int gicv2_init(void)
&gicv2_data.dist_base, &gicv2_data.cpu_base);
}
+int gicv3_init(void)
+{
+ return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base,
+ &gicv3_data.redist_base[0]);
+}
+
int gic_init(void)
{
if (gicv2_init())
return 2;
+ else if (gicv3_init())
+ return 3;
return 0;
}
@@ -74,3 +84,57 @@ void gicv2_enable_defaults(void)
writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
writel(GICC_ENABLE, cpu_base + GICC_CTLR);
}
+
+void gicv3_set_redist_base(size_t stride)
+{
+ u32 aff = mpidr_compress(get_mpidr());
+ void *ptr = gicv3_data.redist_base[0];
+ u64 typer;
+
+ do {
+ typer = gicv3_read_typer(ptr + GICR_TYPER);
+ if ((typer >> 32) == aff) {
+ gicv3_redist_base() = ptr;
+ return;
+ }
+ ptr += stride; /* skip RD_base, SGI_base, etc. */
+ } while (!(typer & GICR_TYPER_LAST));
+
+ /* should never reach here */
+ assert(0);
+}
+
+void gicv3_enable_defaults(void)
+{
+ void *dist = gicv3_dist_base();
+ void *sgi_base;
+ unsigned int i;
+
+ gicv3_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
+ if (gicv3_data.irq_nr > 1020)
+ gicv3_data.irq_nr = 1020;
+
+ writel(0, dist + GICD_CTLR);
+ gicv3_dist_wait_for_rwp();
+
+ writel(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
+ dist + GICD_CTLR);
+ gicv3_dist_wait_for_rwp();
+
+ for (i = 0; i < gicv3_data.irq_nr; i += 4)
+ writel(~0, dist + GICD_IGROUPR + i);
+
+ if (!gicv3_redist_base())
+ gicv3_set_redist_base(SZ_64K * 2);
+ sgi_base = gicv3_sgi_base();
+
+ writel(~0, sgi_base + GICR_IGROUPR0);
+
+ for (i = 0; i < 16; i += 4)
+ writel(GICD_INT_DEF_PRI_X4, sgi_base + GICR_IPRIORITYR0 + i);
+
+ writel(GICD_INT_EN_SET_SGI, sgi_base + GICR_ISENABLER0);
+
+ gicv3_write_pmr(GICC_INT_PRI_THRESHOLD);
+ gicv3_write_grpen1(1);
+}
diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h
new file mode 100644
index 000000000000..6d353567f56a
--- /dev/null
+++ b/lib/arm64/asm/arch_gicv3.h
@@ -0,0 +1,44 @@
+/*
+ * All ripped off from arch/arm64/include/asm/arch_gicv3.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM64_ARCH_GICV3_H_
+#define _ASMARM64_ARCH_GICV3_H_
+
+#include <asm/sysreg.h>
+
+#define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0)
+#define ICC_GRPEN1_EL1 sys_reg(3, 0, 12, 12, 7)
+
+#ifndef __ASSEMBLY__
+
+#include <libcflat.h>
+#include <asm/barrier.h>
+
+#define __stringify xstr
+
+/*
+ * Low-level accessors
+ *
+ * These system registers are 32 bits, but we make sure that the compiler
+ * sets the GP register's most significant bits to 0 with an explicit cast.
+ */
+
+static inline void gicv3_write_pmr(u32 val)
+{
+ asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" ((u64)val));
+}
+
+static inline void gicv3_write_grpen1(u32 val)
+{
+ asm volatile("msr_s " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val));
+ isb();
+}
+
+#define gicv3_read_typer(c) readq(c)
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASMARM64_ARCH_GICV3_H_ */
diff --git a/lib/arm64/asm/gic-v3.h b/lib/arm64/asm/gic-v3.h
new file mode 100644
index 000000000000..8ee5d4d9c181
--- /dev/null
+++ b/lib/arm64/asm/gic-v3.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic-v3.h"
diff --git a/lib/arm64/asm/sysreg.h b/lib/arm64/asm/sysreg.h
new file mode 100644
index 000000000000..544a46cb8cc5
--- /dev/null
+++ b/lib/arm64/asm/sysreg.h
@@ -0,0 +1,44 @@
+/*
+ * Ripped off from arch/arm64/include/asm/sysreg.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM64_SYSREG_H_
+#define _ASMARM64_SYSREG_H_
+
+#define sys_reg(op0, op1, crn, crm, op2) \
+ ((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5))
+
+#ifdef __ASSEMBLY__
+ .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
+ .equ .L__reg_num_x\num, \num
+ .endr
+ .equ .L__reg_num_xzr, 31
+
+ .macro mrs_s, rt, sreg
+ .inst 0xd5200000|(\sreg)|(.L__reg_num_\rt)
+ .endm
+
+ .macro msr_s, sreg, rt
+ .inst 0xd5000000|(\sreg)|(.L__reg_num_\rt)
+ .endm
+#else
+asm(
+" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n"
+" .equ .L__reg_num_x\\num, \\num\n"
+" .endr\n"
+" .equ .L__reg_num_xzr, 31\n"
+"\n"
+" .macro mrs_s, rt, sreg\n"
+" .inst 0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n"
+" .endm\n"
+"\n"
+" .macro msr_s, sreg, rt\n"
+" .inst 0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n"
+" .endm\n"
+);
+#endif
+
+#endif /* _ASMARM64_SYSREG_H_ */
--
2.7.4
^ permalink raw reply related
* [kvm-unit-tests PATCH v6 09/11] arm/arm64: add initial gicv3 support
From: Andrew Jones @ 2016-11-14 21:08 UTC (permalink / raw)
To: kvm, kvmarm, qemu-devel, qemu-arm
Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
marc.zyngier, eric.auger, christoffer.dall
In-Reply-To: <1479157719-31021-1-git-send-email-drjones@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v6:
- added comments [Alex]
- added stride parameter to gicv3_set_redist_base [Andre]
- redist-wait s/rwp/uwp/ and comment [Andre]
- removed unnecessary wait-for-rwps [Andre]
v5: use modern register names [Andre]
v4:
- only take defines from kernel we need now [Andre]
- simplify enable by not caring if we reinit the distributor [drew]
v2:
- configure irqs as NS GRP1
---
lib/arm/asm/arch_gicv3.h | 47 ++++++++++++++++++++
lib/arm/asm/gic-v3.h | 104 +++++++++++++++++++++++++++++++++++++++++++++
lib/arm/asm/gic.h | 5 ++-
lib/arm/gic.c | 64 ++++++++++++++++++++++++++++
lib/arm64/asm/arch_gicv3.h | 44 +++++++++++++++++++
lib/arm64/asm/gic-v3.h | 1 +
lib/arm64/asm/sysreg.h | 44 +++++++++++++++++++
7 files changed, 308 insertions(+), 1 deletion(-)
create mode 100644 lib/arm/asm/arch_gicv3.h
create mode 100644 lib/arm/asm/gic-v3.h
create mode 100644 lib/arm64/asm/arch_gicv3.h
create mode 100644 lib/arm64/asm/gic-v3.h
create mode 100644 lib/arm64/asm/sysreg.h
diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h
new file mode 100644
index 000000000000..276577452a14
--- /dev/null
+++ b/lib/arm/asm/arch_gicv3.h
@@ -0,0 +1,47 @@
+/*
+ * All ripped off from arch/arm/include/asm/arch_gicv3.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM_ARCH_GICV3_H_
+#define _ASMARM_ARCH_GICV3_H_
+
+#ifndef __ASSEMBLY__
+#include <libcflat.h>
+#include <asm/barrier.h>
+#include <asm/io.h>
+
+#define __stringify xstr
+
+#define __ACCESS_CP15(CRn, Op1, CRm, Op2) p15, Op1, %0, CRn, CRm, Op2
+
+#define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0)
+#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7)
+
+static inline void gicv3_write_pmr(u32 val)
+{
+ asm volatile("mcr " __stringify(ICC_PMR) : : "r" (val));
+}
+
+static inline void gicv3_write_grpen1(u32 val)
+{
+ asm volatile("mcr " __stringify(ICC_IGRPEN1) : : "r" (val));
+ isb();
+}
+
+/*
+ * We may access GICR_TYPER and GITS_TYPER by reading both the TYPER
+ * offset and the following offset (+ 4) and then combining them to
+ * form a 64-bit address.
+ */
+static inline u64 gicv3_read_typer(const volatile void __iomem *addr)
+{
+ u64 val = readl(addr);
+ val |= (u64)readl(addr + 4) << 32;
+ return val;
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_ARCH_GICV3_H_ */
diff --git a/lib/arm/asm/gic-v3.h b/lib/arm/asm/gic-v3.h
new file mode 100644
index 000000000000..73ade4681d21
--- /dev/null
+++ b/lib/arm/asm/gic-v3.h
@@ -0,0 +1,104 @@
+/*
+ * All GIC* defines are lifted from include/linux/irqchip/arm-gic-v3.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM_GIC_V3_H_
+#define _ASMARM_GIC_V3_H_
+
+#ifndef _ASMARM_GIC_H_
+#error Do not directly include <asm/gic-v3.h>. Include <asm/gic.h>
+#endif
+
+/*
+ * Distributor registers
+ *
+ * We expect to be run in Non-secure mode, thus we define the
+ * group1 enable bits with respect to that view.
+ */
+#define GICD_CTLR_RWP (1U << 31)
+#define GICD_CTLR_ARE_NS (1U << 4)
+#define GICD_CTLR_ENABLE_G1A (1U << 1)
+#define GICD_CTLR_ENABLE_G1 (1U << 0)
+
+/* Re-Distributor registers, offsets from RD_base */
+#define GICR_TYPER 0x0008
+
+#define GICR_TYPER_LAST (1U << 4)
+
+/* Re-Distributor registers, offsets from SGI_base */
+#define GICR_IGROUPR0 GICD_IGROUPR
+#define GICR_ISENABLER0 GICD_ISENABLER
+#define GICR_IPRIORITYR0 GICD_IPRIORITYR
+
+#include <asm/arch_gicv3.h>
+
+#ifndef __ASSEMBLY__
+#include <asm/setup.h>
+#include <asm/smp.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+struct gicv3_data {
+ void *dist_base;
+ void *redist_base[NR_CPUS];
+ unsigned int irq_nr;
+};
+extern struct gicv3_data gicv3_data;
+
+#define gicv3_dist_base() (gicv3_data.dist_base)
+#define gicv3_redist_base() (gicv3_data.redist_base[smp_processor_id()])
+#define gicv3_sgi_base() (gicv3_data.redist_base[smp_processor_id()] + SZ_64K)
+
+extern int gicv3_init(void);
+extern void gicv3_enable_defaults(void);
+extern void gicv3_set_redist_base(size_t stride);
+
+static inline void gicv3_do_wait_for_rwp(void *base)
+{
+ int count = 100000; /* 1s */
+
+ while (readl(base + GICD_CTLR) & GICD_CTLR_RWP) {
+ if (!--count) {
+ printf("GICv3: RWP timeout!\n");
+ abort();
+ }
+ cpu_relax();
+ udelay(10);
+ };
+}
+
+static inline void gicv3_dist_wait_for_rwp(void)
+{
+ gicv3_do_wait_for_rwp(gicv3_dist_base());
+}
+
+static inline void gicv3_redist_wait_for_uwp(void)
+{
+ /*
+ * We can build on gic_do_wait_for_rwp, which uses GICD_ registers
+ * because GICD_CTLR == GICR_CTLR and GICD_CTLR_RWP == GICR_CTLR_UWP
+ */
+ gicv3_do_wait_for_rwp(gicv3_redist_base());
+}
+
+static inline u32 mpidr_compress(u64 mpidr)
+{
+ u64 compressed = mpidr & MPIDR_HWID_BITMASK;
+
+ compressed = (((compressed >> 32) & 0xff) << 24) | compressed;
+ return compressed;
+}
+
+static inline u64 mpidr_uncompress(u32 compressed)
+{
+ u64 mpidr = ((u64)compressed >> 24) << 32;
+
+ mpidr |= compressed & MPIDR_HWID_BITMASK;
+ return mpidr;
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_GIC_V3_H_ */
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index d816b96e46b4..21511997f2a9 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -6,11 +6,11 @@
#ifndef _ASMARM_GIC_H_
#define _ASMARM_GIC_H_
-#include <asm/gic-v2.h>
/* Distributor registers */
#define GICD_CTLR 0x0000
#define GICD_TYPER 0x0004
+#define GICD_IGROUPR 0x0080
#define GICD_ISENABLER 0x0100
#define GICD_IPRIORITYR 0x0400
#define GICD_SGIR 0x0f00
@@ -28,6 +28,9 @@
#define GICC_INT_PRI_THRESHOLD 0xf0
#define GICC_INT_SPURIOUS 0x3ff
+#include <asm/gic-v2.h>
+#include <asm/gic-v3.h>
+
#ifndef __ASSEMBLY__
/*
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
index d655105e058b..d703ad96a37e 100644
--- a/lib/arm/gic.c
+++ b/lib/arm/gic.c
@@ -8,9 +8,11 @@
#include <asm/io.h>
struct gicv2_data gicv2_data;
+struct gicv3_data gicv3_data;
/*
* Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
+ * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
*/
static bool
gic_get_dt_bases(const char *compatible, void **base1, void **base2)
@@ -48,10 +50,18 @@ int gicv2_init(void)
&gicv2_data.dist_base, &gicv2_data.cpu_base);
}
+int gicv3_init(void)
+{
+ return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base,
+ &gicv3_data.redist_base[0]);
+}
+
int gic_init(void)
{
if (gicv2_init())
return 2;
+ else if (gicv3_init())
+ return 3;
return 0;
}
@@ -74,3 +84,57 @@ void gicv2_enable_defaults(void)
writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
writel(GICC_ENABLE, cpu_base + GICC_CTLR);
}
+
+void gicv3_set_redist_base(size_t stride)
+{
+ u32 aff = mpidr_compress(get_mpidr());
+ void *ptr = gicv3_data.redist_base[0];
+ u64 typer;
+
+ do {
+ typer = gicv3_read_typer(ptr + GICR_TYPER);
+ if ((typer >> 32) == aff) {
+ gicv3_redist_base() = ptr;
+ return;
+ }
+ ptr += stride; /* skip RD_base, SGI_base, etc. */
+ } while (!(typer & GICR_TYPER_LAST));
+
+ /* should never reach here */
+ assert(0);
+}
+
+void gicv3_enable_defaults(void)
+{
+ void *dist = gicv3_dist_base();
+ void *sgi_base;
+ unsigned int i;
+
+ gicv3_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
+ if (gicv3_data.irq_nr > 1020)
+ gicv3_data.irq_nr = 1020;
+
+ writel(0, dist + GICD_CTLR);
+ gicv3_dist_wait_for_rwp();
+
+ writel(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
+ dist + GICD_CTLR);
+ gicv3_dist_wait_for_rwp();
+
+ for (i = 0; i < gicv3_data.irq_nr; i += 4)
+ writel(~0, dist + GICD_IGROUPR + i);
+
+ if (!gicv3_redist_base())
+ gicv3_set_redist_base(SZ_64K * 2);
+ sgi_base = gicv3_sgi_base();
+
+ writel(~0, sgi_base + GICR_IGROUPR0);
+
+ for (i = 0; i < 16; i += 4)
+ writel(GICD_INT_DEF_PRI_X4, sgi_base + GICR_IPRIORITYR0 + i);
+
+ writel(GICD_INT_EN_SET_SGI, sgi_base + GICR_ISENABLER0);
+
+ gicv3_write_pmr(GICC_INT_PRI_THRESHOLD);
+ gicv3_write_grpen1(1);
+}
diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h
new file mode 100644
index 000000000000..6d353567f56a
--- /dev/null
+++ b/lib/arm64/asm/arch_gicv3.h
@@ -0,0 +1,44 @@
+/*
+ * All ripped off from arch/arm64/include/asm/arch_gicv3.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM64_ARCH_GICV3_H_
+#define _ASMARM64_ARCH_GICV3_H_
+
+#include <asm/sysreg.h>
+
+#define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0)
+#define ICC_GRPEN1_EL1 sys_reg(3, 0, 12, 12, 7)
+
+#ifndef __ASSEMBLY__
+
+#include <libcflat.h>
+#include <asm/barrier.h>
+
+#define __stringify xstr
+
+/*
+ * Low-level accessors
+ *
+ * These system registers are 32 bits, but we make sure that the compiler
+ * sets the GP register's most significant bits to 0 with an explicit cast.
+ */
+
+static inline void gicv3_write_pmr(u32 val)
+{
+ asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" ((u64)val));
+}
+
+static inline void gicv3_write_grpen1(u32 val)
+{
+ asm volatile("msr_s " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val));
+ isb();
+}
+
+#define gicv3_read_typer(c) readq(c)
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASMARM64_ARCH_GICV3_H_ */
diff --git a/lib/arm64/asm/gic-v3.h b/lib/arm64/asm/gic-v3.h
new file mode 100644
index 000000000000..8ee5d4d9c181
--- /dev/null
+++ b/lib/arm64/asm/gic-v3.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic-v3.h"
diff --git a/lib/arm64/asm/sysreg.h b/lib/arm64/asm/sysreg.h
new file mode 100644
index 000000000000..544a46cb8cc5
--- /dev/null
+++ b/lib/arm64/asm/sysreg.h
@@ -0,0 +1,44 @@
+/*
+ * Ripped off from arch/arm64/include/asm/sysreg.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM64_SYSREG_H_
+#define _ASMARM64_SYSREG_H_
+
+#define sys_reg(op0, op1, crn, crm, op2) \
+ ((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5))
+
+#ifdef __ASSEMBLY__
+ .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
+ .equ .L__reg_num_x\num, \num
+ .endr
+ .equ .L__reg_num_xzr, 31
+
+ .macro mrs_s, rt, sreg
+ .inst 0xd5200000|(\sreg)|(.L__reg_num_\rt)
+ .endm
+
+ .macro msr_s, sreg, rt
+ .inst 0xd5000000|(\sreg)|(.L__reg_num_\rt)
+ .endm
+#else
+asm(
+" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n"
+" .equ .L__reg_num_x\\num, \\num\n"
+" .endr\n"
+" .equ .L__reg_num_xzr, 31\n"
+"\n"
+" .macro mrs_s, rt, sreg\n"
+" .inst 0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n"
+" .endm\n"
+"\n"
+" .macro msr_s, sreg, rt\n"
+" .inst 0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n"
+" .endm\n"
+);
+#endif
+
+#endif /* _ASMARM64_SYSREG_H_ */
--
2.7.4
^ permalink raw reply related
* [kvm-unit-tests PATCH v6 11/11] arm/arm64: gic: don't just use zero
From: Andrew Jones @ 2016-11-14 21:08 UTC (permalink / raw)
To: kvm, kvmarm, qemu-devel, qemu-arm
Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
marc.zyngier, eric.auger, christoffer.dall
In-Reply-To: <1479157719-31021-1-git-send-email-drjones@redhat.com>
Allow user to select who sends ipis and with which irq,
rather than just always sending irq=0 from cpu0.
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v6:
- make sender/irq names more future-proof [drew]
- sanity check inputs [drew]
- introduce check_sender/irq and bad_sender/irq to more
cleanly do checks [drew]
- default sender and irq to 1, instead of still zero [drew]
v4: improve structure and make sure spurious checking is
done even when the sender isn't cpu0
v2: actually check that the irq received was the irq sent,
and (for gicv2) that the sender is the expected one.
---
arm/gic.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 99 insertions(+), 25 deletions(-)
diff --git a/arm/gic.c b/arm/gic.c
index d954a3775c26..638b8b140c96 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -11,6 +11,7 @@
* This work is licensed under the terms of the GNU LGPL, version 2.
*/
#include <libcflat.h>
+#include <util.h>
#include <asm/setup.h>
#include <asm/processor.h>
#include <asm/gic.h>
@@ -28,6 +29,8 @@ struct gic {
static struct gic *gic;
static int acked[NR_CPUS], spurious[NR_CPUS];
+static int bad_sender[NR_CPUS], bad_irq[NR_CPUS];
+static int cmdl_sender = 1, cmdl_irq = 1;
static cpumask_t ready;
static void nr_cpu_check(int nr)
@@ -43,10 +46,23 @@ static void wait_on_ready(void)
cpu_relax();
}
+static void stats_reset(void)
+{
+ int i;
+
+ for (i = 0; i < nr_cpus; ++i) {
+ acked[i] = 0;
+ bad_sender[i] = -1;
+ bad_irq[i] = -1;
+ }
+ smp_wmb();
+}
+
static void check_acked(cpumask_t *mask)
{
int missing = 0, extra = 0, unexpected = 0;
int nr_pass, cpu, i;
+ bool bad = false;
/* Wait up to 5s for all interrupts to be delivered */
for (i = 0; i < 50; ++i) {
@@ -56,9 +72,21 @@ static void check_acked(cpumask_t *mask)
smp_rmb();
nr_pass += cpumask_test_cpu(cpu, mask) ?
acked[cpu] == 1 : acked[cpu] == 0;
+
+ if (bad_sender[cpu] != -1) {
+ printf("cpu%d received IPI from wrong sender %d\n",
+ cpu, bad_sender[cpu]);
+ bad = true;
+ }
+
+ if (bad_irq[cpu] != -1) {
+ printf("cpu%d received wrong irq %d\n",
+ cpu, bad_irq[cpu]);
+ bad = true;
+ }
}
if (nr_pass == nr_cpus) {
- report("Completed in %d ms", true, ++i * 100);
+ report("Completed in %d ms", !bad, ++i * 100);
return;
}
}
@@ -91,6 +119,22 @@ static void check_spurious(void)
}
}
+static void check_ipi_sender(u32 irqstat)
+{
+ if (gic_version() == 2) {
+ int src = (irqstat >> 10) & 7;
+
+ if (src != cmdl_sender)
+ bad_sender[smp_processor_id()] = src;
+ }
+}
+
+static void check_irqnr(u32 irqnr)
+{
+ if (irqnr != (u32)cmdl_irq)
+ bad_irq[smp_processor_id()] = irqnr;
+}
+
static void ipi_handler(struct pt_regs *regs __unused)
{
u32 irqstat = gic_read_iar();
@@ -98,8 +142,10 @@ static void ipi_handler(struct pt_regs *regs __unused)
if (irqnr != GICC_INT_SPURIOUS) {
gic_write_eoir(irqstat);
- smp_rmb(); /* pairs with wmb in ipi_test functions */
+ smp_rmb(); /* pairs with wmb in stats_reset */
++acked[smp_processor_id()];
+ check_ipi_sender(irqstat);
+ check_irqnr(irqnr);
smp_wmb(); /* pairs with rmb in check_acked */
} else {
++spurious[smp_processor_id()];
@@ -109,19 +155,19 @@ static void ipi_handler(struct pt_regs *regs __unused)
static void gicv2_ipi_send_self(void)
{
- writel(2 << 24, gicv2_dist_base() + GICD_SGIR);
+ writel(2 << 24 | cmdl_irq, gicv2_dist_base() + GICD_SGIR);
}
-static void gicv2_ipi_send_tlist(cpumask_t *mask, int irq __unused)
+static void gicv2_ipi_send_tlist(cpumask_t *mask, int irq)
{
u8 tlist = (u8)cpumask_bits(mask)[0];
- writel(tlist << 16, gicv2_dist_base() + GICD_SGIR);
+ writel(tlist << 16 | irq, gicv2_dist_base() + GICD_SGIR);
}
static void gicv2_ipi_send_broadcast(void)
{
- writel(1 << 24, gicv2_dist_base() + GICD_SGIR);
+ writel(1 << 24 | cmdl_irq, gicv2_dist_base() + GICD_SGIR);
}
static void gicv3_ipi_send_self(void)
@@ -130,12 +176,12 @@ static void gicv3_ipi_send_self(void)
cpumask_clear(&mask);
cpumask_set_cpu(smp_processor_id(), &mask);
- gicv3_ipi_send_tlist(&mask, 0);
+ gicv3_ipi_send_tlist(&mask, cmdl_irq);
}
static void gicv3_ipi_send_broadcast(void)
{
- gicv3_write_sgi1r(1ULL << 40);
+ gicv3_write_sgi1r(1ULL << 40 | cmdl_irq << 24);
isb();
}
@@ -144,10 +190,9 @@ static void ipi_test_self(void)
cpumask_t mask;
report_prefix_push("self");
- memset(acked, 0, sizeof(acked));
- smp_wmb();
+ stats_reset();
cpumask_clear(&mask);
- cpumask_set_cpu(0, &mask);
+ cpumask_set_cpu(smp_processor_id(), &mask);
gic->ipi.send_self();
check_acked(&mask);
report_prefix_pop();
@@ -159,20 +204,18 @@ static void ipi_test_smp(void)
int i;
report_prefix_push("target-list");
- memset(acked, 0, sizeof(acked));
- smp_wmb();
+ stats_reset();
cpumask_copy(&mask, &cpu_present_mask);
- for (i = 0; i < nr_cpus; i += 2)
+ for (i = smp_processor_id() & 1; i < nr_cpus; i += 2)
cpumask_clear_cpu(i, &mask);
- gic->ipi.send_tlist(&mask, 0);
+ gic->ipi.send_tlist(&mask, cmdl_irq);
check_acked(&mask);
report_prefix_pop();
report_prefix_push("broadcast");
- memset(acked, 0, sizeof(acked));
- smp_wmb();
+ stats_reset();
cpumask_copy(&mask, &cpu_present_mask);
- cpumask_clear_cpu(0, &mask);
+ cpumask_clear_cpu(smp_processor_id(), &mask);
gic->ipi.send_broadcast();
check_acked(&mask);
report_prefix_pop();
@@ -189,6 +232,16 @@ static void ipi_enable(void)
local_irq_enable();
}
+static void ipi_send(void)
+{
+ ipi_enable();
+ wait_on_ready();
+ ipi_test_self();
+ ipi_test_smp();
+ check_spurious();
+ exit(report_summary());
+}
+
static void ipi_recv(void)
{
ipi_enable();
@@ -197,6 +250,14 @@ static void ipi_recv(void)
wfi();
}
+static void ipi_test(void)
+{
+ if (smp_processor_id() == cmdl_sender)
+ ipi_send();
+ else
+ ipi_recv();
+}
+
static struct gic gicv2 = {
.ipi = {
.send_self = gicv2_ipi_send_self,
@@ -242,21 +303,34 @@ int main(int argc, char **argv)
report_prefix_pop();
} else if (strcmp(argv[1], "ipi") == 0) {
+ int off, i = 1;
+ long val;
report_prefix_push(argv[1]);
nr_cpu_check(2);
+ while (--argc != 1) {
+ off = parse_keyval(argv[++i], &val);
+ if (off == -1)
+ continue;
+ argv[i][off] = '\0';
+ if (strcmp(argv[i], "sender") == 0) {
+ if (val >= nr_cpus)
+ report_abort("invalid sender %d, nr_cpus=%d", val, nr_cpus);
+ cmdl_sender = val;
+ } else if (strcmp(argv[i], "irq") == 0) {
+ if (val > 15)
+ report_abort("irq (SGI) must be < 16");
+ cmdl_irq = val;
+ }
+ }
+
for_each_present_cpu(cpu) {
if (cpu == 0)
continue;
- smp_boot_secondary(cpu, ipi_recv);
+ smp_boot_secondary(cpu, ipi_test);
}
- ipi_enable();
- wait_on_ready();
- ipi_test_self();
- ipi_test_smp();
- check_spurious();
- report_prefix_pop();
+ ipi_test();
} else {
report_abort("Unknown subtest '%s'", argv[1]);
--
2.7.4
^ permalink raw reply related
* [Qemu-devel] [kvm-unit-tests PATCH v6 07/11] arm/arm64: gicv2: add an IPI test
From: Andrew Jones @ 2016-11-14 21:08 UTC (permalink / raw)
To: kvm, kvmarm, qemu-devel, qemu-arm
Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
marc.zyngier, eric.auger, christoffer.dall
In-Reply-To: <1479157719-31021-1-git-send-email-drjones@redhat.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v6: move the spurious check to its own check_ function [drew]
v5: use modern registers [Andre]
v4: properly mask irqnr in ipi_handler
v2: add more details in the output if a test fails,
report spurious interrupts if we get them
---
arm/Makefile.common | 8 +--
arm/gic.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++
arm/unittests.cfg | 8 +++
lib/arm/asm/gic-v2.h | 2 +
lib/arm/asm/gic.h | 4 ++
5 files changed, 217 insertions(+), 4 deletions(-)
create mode 100644 arm/gic.c
diff --git a/arm/Makefile.common b/arm/Makefile.common
index 6f56015c43c4..2fe7aeeca6d4 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -9,10 +9,10 @@ ifeq ($(LOADADDR),)
LOADADDR = 0x40000000
endif
-tests-common = \
- $(TEST_DIR)/selftest.flat \
- $(TEST_DIR)/spinlock-test.flat \
- $(TEST_DIR)/pci-test.flat
+tests-common = $(TEST_DIR)/selftest.flat
+tests-common += $(TEST_DIR)/spinlock-test.flat
+tests-common += $(TEST_DIR)/pci-test.flat
+tests-common += $(TEST_DIR)/gic.flat
all: test_cases
diff --git a/arm/gic.c b/arm/gic.c
new file mode 100644
index 000000000000..b42c2b1ca1e1
--- /dev/null
+++ b/arm/gic.c
@@ -0,0 +1,199 @@
+/*
+ * GIC tests
+ *
+ * GICv2
+ * + test sending/receiving IPIs
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <libcflat.h>
+#include <asm/setup.h>
+#include <asm/processor.h>
+#include <asm/gic.h>
+#include <asm/smp.h>
+#include <asm/barrier.h>
+#include <asm/io.h>
+
+static int gic_version;
+static int acked[NR_CPUS], spurious[NR_CPUS];
+static cpumask_t ready;
+
+static void nr_cpu_check(int nr)
+{
+ if (nr_cpus < nr)
+ report_abort("At least %d cpus required", nr);
+}
+
+static void wait_on_ready(void)
+{
+ cpumask_set_cpu(smp_processor_id(), &ready);
+ while (!cpumask_full(&ready))
+ cpu_relax();
+}
+
+static void check_acked(cpumask_t *mask)
+{
+ int missing = 0, extra = 0, unexpected = 0;
+ int nr_pass, cpu, i;
+
+ /* Wait up to 5s for all interrupts to be delivered */
+ for (i = 0; i < 50; ++i) {
+ mdelay(100);
+ nr_pass = 0;
+ for_each_present_cpu(cpu) {
+ smp_rmb();
+ nr_pass += cpumask_test_cpu(cpu, mask) ?
+ acked[cpu] == 1 : acked[cpu] == 0;
+ }
+ if (nr_pass == nr_cpus) {
+ report("Completed in %d ms", true, ++i * 100);
+ return;
+ }
+ }
+
+ for_each_present_cpu(cpu) {
+ if (cpumask_test_cpu(cpu, mask)) {
+ if (!acked[cpu])
+ ++missing;
+ else if (acked[cpu] > 1)
+ ++extra;
+ } else {
+ if (acked[cpu])
+ ++unexpected;
+ }
+ }
+
+ report("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d",
+ false, missing, extra, unexpected);
+}
+
+static void check_spurious(void)
+{
+ int cpu;
+
+ smp_rmb();
+ for_each_present_cpu(cpu) {
+ if (spurious[cpu])
+ printf("ipi: WARN: cpu%d got %d spurious interrupts\n",
+ spurious[cpu], smp_processor_id());
+ }
+}
+
+static void ipi_handler(struct pt_regs *regs __unused)
+{
+ u32 irqstat = readl(gicv2_cpu_base() + GICC_IAR);
+ u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+
+ if (irqnr != GICC_INT_SPURIOUS) {
+ writel(irqstat, gicv2_cpu_base() + GICC_EOIR);
+ smp_rmb(); /* pairs with wmb in ipi_test functions */
+ ++acked[smp_processor_id()];
+ smp_wmb(); /* pairs with rmb in check_acked */
+ } else {
+ ++spurious[smp_processor_id()];
+ smp_wmb();
+ }
+}
+
+static void ipi_test_self(void)
+{
+ cpumask_t mask;
+
+ report_prefix_push("self");
+ memset(acked, 0, sizeof(acked));
+ smp_wmb();
+ cpumask_clear(&mask);
+ cpumask_set_cpu(0, &mask);
+ writel(2 << 24, gicv2_dist_base() + GICD_SGIR);
+ check_acked(&mask);
+ report_prefix_pop();
+}
+
+static void ipi_test_smp(void)
+{
+ cpumask_t mask;
+ unsigned long tlist;
+
+ report_prefix_push("target-list");
+ memset(acked, 0, sizeof(acked));
+ smp_wmb();
+ tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
+ cpumask_bits(&mask)[0] = tlist;
+ writel((u8)tlist << 16, gicv2_dist_base() + GICD_SGIR);
+ check_acked(&mask);
+ report_prefix_pop();
+
+ report_prefix_push("broadcast");
+ memset(acked, 0, sizeof(acked));
+ smp_wmb();
+ cpumask_copy(&mask, &cpu_present_mask);
+ cpumask_clear_cpu(0, &mask);
+ writel(1 << 24, gicv2_dist_base() + GICD_SGIR);
+ check_acked(&mask);
+ report_prefix_pop();
+}
+
+static void ipi_enable(void)
+{
+ gicv2_enable_defaults();
+#ifdef __arm__
+ install_exception_handler(EXCPTN_IRQ, ipi_handler);
+#else
+ install_irq_handler(EL1H_IRQ, ipi_handler);
+#endif
+ local_irq_enable();
+}
+
+static void ipi_recv(void)
+{
+ ipi_enable();
+ cpumask_set_cpu(smp_processor_id(), &ready);
+ while (1)
+ wfi();
+}
+
+int main(int argc, char **argv)
+{
+ char pfx[8];
+ int cpu;
+
+ gic_version = gic_init();
+ if (!gic_version)
+ report_abort("No gic present!");
+
+ snprintf(pfx, sizeof(pfx), "gicv%d", gic_version);
+ report_prefix_push(pfx);
+
+ if (argc < 2) {
+
+ report_prefix_push("ipi");
+ ipi_enable();
+ ipi_test_self();
+ check_spurious();
+ report_prefix_pop();
+
+ } else if (strcmp(argv[1], "ipi") == 0) {
+
+ report_prefix_push(argv[1]);
+ nr_cpu_check(2);
+
+ for_each_present_cpu(cpu) {
+ if (cpu == 0)
+ continue;
+ smp_boot_secondary(cpu, ipi_recv);
+ }
+ ipi_enable();
+ wait_on_ready();
+ ipi_test_self();
+ ipi_test_smp();
+ check_spurious();
+ report_prefix_pop();
+
+ } else {
+ report_abort("Unknown subtest '%s'", argv[1]);
+ }
+
+ return report_summary();
+}
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index ae32a42a91c3..e631c35e2bbb 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -55,6 +55,14 @@ smp = $MAX_SMP
extra_params = -append 'smp'
groups = selftest
+# pci-testdev
[pci-test]
file = pci-test.flat
groups = pci
+
+# Test GIC emulation
+[gicv2-ipi]
+file = gic.flat
+smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
+extra_params = -machine gic-version=2 -append 'ipi'
+groups = gic
diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
index c2d5fecd4886..8b3f7ed6790c 100644
--- a/lib/arm/asm/gic-v2.h
+++ b/lib/arm/asm/gic-v2.h
@@ -13,7 +13,9 @@
#endif
#define GICD_ENABLE 0x1
+
#define GICC_ENABLE 0x1
+#define GICC_IAR_INT_ID_MASK 0x3ff
#ifndef __ASSEMBLY__
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index e3580bd1d42d..d816b96e46b4 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -13,6 +13,7 @@
#define GICD_TYPER 0x0004
#define GICD_ISENABLER 0x0100
#define GICD_IPRIORITYR 0x0400
+#define GICD_SGIR 0x0f00
#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32)
#define GICD_INT_EN_SET_SGI 0x0000ffff
@@ -21,8 +22,11 @@
/* CPU interface registers */
#define GICC_CTLR 0x0000
#define GICC_PMR 0x0004
+#define GICC_IAR 0x000c
+#define GICC_EOIR 0x0010
#define GICC_INT_PRI_THRESHOLD 0xf0
+#define GICC_INT_SPURIOUS 0x3ff
#ifndef __ASSEMBLY__
--
2.7.4
^ permalink raw reply related
* [Qemu-devel] [kvm-unit-tests PATCH v6 08/11] libcflat: add IS_ALIGNED() macro, and page sizes
From: Andrew Jones @ 2016-11-14 21:08 UTC (permalink / raw)
To: kvm, kvmarm, qemu-devel, qemu-arm
Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
marc.zyngier, eric.auger, christoffer.dall, Peter Xu
In-Reply-To: <1479157719-31021-1-git-send-email-drjones@redhat.com>
From: Peter Xu <peterx@redhat.com>
These macros will be useful to do page alignment checks.
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
[drew: also added SZ_64K and changed to shifts]
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v6: change to shifts [Alex]
---
lib/libcflat.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/lib/libcflat.h b/lib/libcflat.h
index 82005f5d014f..244e40a724be 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -33,6 +33,12 @@
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
#define __ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1)
#define ALIGN(x, a) __ALIGN((x), (a))
+#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0)
+
+#define SZ_4K (1 << 12)
+#define SZ_64K (1 << 16)
+#define SZ_2M (1 << 21)
+#define SZ_1G (1 << 30)
typedef uint8_t u8;
typedef int8_t s8;
--
2.7.4
^ permalink raw reply related
* [Qemu-devel] [kvm-unit-tests PATCH v6 06/11] arm/arm64: add initial gicv2 support
From: Andrew Jones @ 2016-11-14 21:08 UTC (permalink / raw)
To: kvm, kvmarm, qemu-devel, qemu-arm
Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
marc.zyngier, eric.auger, christoffer.dall
In-Reply-To: <1479157719-31021-1-git-send-email-drjones@redhat.com>
Add some gicv2 support. This just adds init and enable
functions, allowing unit tests to start messing with it.
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v6: added comments (register offset headers) [Alex]
v5: share/use only the modern register names [Andre]
v4:
- only take defines from kernel we need now [Andre]
- moved defines to asm/gic.h so they'll be shared with v3 [drew]
- simplify enable by not caring if we reinit the distributor [drew]
- init all GICD_INT_DEF_PRI_X4 registers [Eric]
---
arm/Makefile.common | 1 +
lib/arm/asm/gic-v2.h | 34 ++++++++++++++++++++++
lib/arm/asm/gic.h | 39 ++++++++++++++++++++++++++
lib/arm/gic.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
lib/arm64/asm/gic-v2.h | 1 +
lib/arm64/asm/gic.h | 1 +
6 files changed, 152 insertions(+)
create mode 100644 lib/arm/asm/gic-v2.h
create mode 100644 lib/arm/asm/gic.h
create mode 100644 lib/arm/gic.c
create mode 100644 lib/arm64/asm/gic-v2.h
create mode 100644 lib/arm64/asm/gic.h
diff --git a/arm/Makefile.common b/arm/Makefile.common
index f37b5c2a3de4..6f56015c43c4 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -46,6 +46,7 @@ cflatobjs += lib/arm/mmu.o
cflatobjs += lib/arm/bitops.o
cflatobjs += lib/arm/psci.o
cflatobjs += lib/arm/smp.o
+cflatobjs += lib/arm/gic.o
libeabi = lib/arm/libeabi.a
eabiobjs = lib/arm/eabi_compat.o
diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
new file mode 100644
index 000000000000..c2d5fecd4886
--- /dev/null
+++ b/lib/arm/asm/gic-v2.h
@@ -0,0 +1,34 @@
+/*
+ * All GIC* defines are lifted from include/linux/irqchip/arm-gic.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM_GIC_V2_H_
+#define _ASMARM_GIC_V2_H_
+
+#ifndef _ASMARM_GIC_H_
+#error Do not directly include <asm/gic-v2.h>. Include <asm/gic.h>
+#endif
+
+#define GICD_ENABLE 0x1
+#define GICC_ENABLE 0x1
+
+#ifndef __ASSEMBLY__
+
+struct gicv2_data {
+ void *dist_base;
+ void *cpu_base;
+ unsigned int irq_nr;
+};
+extern struct gicv2_data gicv2_data;
+
+#define gicv2_dist_base() (gicv2_data.dist_base)
+#define gicv2_cpu_base() (gicv2_data.cpu_base)
+
+extern int gicv2_init(void);
+extern void gicv2_enable_defaults(void);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_GIC_V2_H_ */
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
new file mode 100644
index 000000000000..e3580bd1d42d
--- /dev/null
+++ b/lib/arm/asm/gic.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM_GIC_H_
+#define _ASMARM_GIC_H_
+
+#include <asm/gic-v2.h>
+
+/* Distributor registers */
+#define GICD_CTLR 0x0000
+#define GICD_TYPER 0x0004
+#define GICD_ISENABLER 0x0100
+#define GICD_IPRIORITYR 0x0400
+
+#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32)
+#define GICD_INT_EN_SET_SGI 0x0000ffff
+#define GICD_INT_DEF_PRI_X4 0xa0a0a0a0
+
+/* CPU interface registers */
+#define GICC_CTLR 0x0000
+#define GICC_PMR 0x0004
+
+#define GICC_INT_PRI_THRESHOLD 0xf0
+
+#ifndef __ASSEMBLY__
+
+/*
+ * gic_init will try to find all known gics, and then
+ * initialize the gic data for the one found.
+ * returns
+ * 0 : no gic was found
+ * > 0 : the gic version of the gic found
+ */
+extern int gic_init(void);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_GIC_H_ */
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
new file mode 100644
index 000000000000..d655105e058b
--- /dev/null
+++ b/lib/arm/gic.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <devicetree.h>
+#include <asm/gic.h>
+#include <asm/io.h>
+
+struct gicv2_data gicv2_data;
+
+/*
+ * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
+ */
+static bool
+gic_get_dt_bases(const char *compatible, void **base1, void **base2)
+{
+ struct dt_pbus_reg reg;
+ struct dt_device gic;
+ struct dt_bus bus;
+ int node, ret;
+
+ dt_bus_init_defaults(&bus);
+ dt_device_init(&gic, &bus, NULL);
+
+ node = dt_device_find_compatible(&gic, compatible);
+ assert(node >= 0 || node == -FDT_ERR_NOTFOUND);
+
+ if (node == -FDT_ERR_NOTFOUND)
+ return false;
+
+ dt_device_bind_node(&gic, node);
+
+ ret = dt_pbus_translate(&gic, 0, ®);
+ assert(ret == 0);
+ *base1 = ioremap(reg.addr, reg.size);
+
+ ret = dt_pbus_translate(&gic, 1, ®);
+ assert(ret == 0);
+ *base2 = ioremap(reg.addr, reg.size);
+
+ return true;
+}
+
+int gicv2_init(void)
+{
+ return gic_get_dt_bases("arm,cortex-a15-gic",
+ &gicv2_data.dist_base, &gicv2_data.cpu_base);
+}
+
+int gic_init(void)
+{
+ if (gicv2_init())
+ return 2;
+ return 0;
+}
+
+void gicv2_enable_defaults(void)
+{
+ void *dist = gicv2_dist_base();
+ void *cpu_base = gicv2_cpu_base();
+ unsigned int i;
+
+ gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
+ if (gicv2_data.irq_nr > 1020)
+ gicv2_data.irq_nr = 1020;
+
+ for (i = 0; i < gicv2_data.irq_nr; i += 4)
+ writel(GICD_INT_DEF_PRI_X4, dist + GICD_IPRIORITYR + i);
+
+ writel(GICD_INT_EN_SET_SGI, dist + GICD_ISENABLER + 0);
+ writel(GICD_ENABLE, dist + GICD_CTLR);
+
+ writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
+ writel(GICC_ENABLE, cpu_base + GICC_CTLR);
+}
diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h
new file mode 100644
index 000000000000..52226624a209
--- /dev/null
+++ b/lib/arm64/asm/gic-v2.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic-v2.h"
diff --git a/lib/arm64/asm/gic.h b/lib/arm64/asm/gic.h
new file mode 100644
index 000000000000..e5eb302a31b4
--- /dev/null
+++ b/lib/arm64/asm/gic.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic.h"
--
2.7.4
^ permalink raw reply related
* [kvm-unit-tests PATCH v6 08/11] libcflat: add IS_ALIGNED() macro, and page sizes
From: Andrew Jones @ 2016-11-14 21:08 UTC (permalink / raw)
To: kvm, kvmarm, qemu-devel, qemu-arm
Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
marc.zyngier, eric.auger, christoffer.dall, Peter Xu
In-Reply-To: <1479157719-31021-1-git-send-email-drjones@redhat.com>
From: Peter Xu <peterx@redhat.com>
These macros will be useful to do page alignment checks.
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
[drew: also added SZ_64K and changed to shifts]
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v6: change to shifts [Alex]
---
lib/libcflat.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/lib/libcflat.h b/lib/libcflat.h
index 82005f5d014f..244e40a724be 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -33,6 +33,12 @@
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
#define __ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1)
#define ALIGN(x, a) __ALIGN((x), (a))
+#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0)
+
+#define SZ_4K (1 << 12)
+#define SZ_64K (1 << 16)
+#define SZ_2M (1 << 21)
+#define SZ_1G (1 << 30)
typedef uint8_t u8;
typedef int8_t s8;
--
2.7.4
^ permalink raw reply related
* [kvm-unit-tests PATCH v6 07/11] arm/arm64: gicv2: add an IPI test
From: Andrew Jones @ 2016-11-14 21:08 UTC (permalink / raw)
To: kvm, kvmarm, qemu-devel, qemu-arm
Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
marc.zyngier, eric.auger, christoffer.dall
In-Reply-To: <1479157719-31021-1-git-send-email-drjones@redhat.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v6: move the spurious check to its own check_ function [drew]
v5: use modern registers [Andre]
v4: properly mask irqnr in ipi_handler
v2: add more details in the output if a test fails,
report spurious interrupts if we get them
---
arm/Makefile.common | 8 +--
arm/gic.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++
arm/unittests.cfg | 8 +++
lib/arm/asm/gic-v2.h | 2 +
lib/arm/asm/gic.h | 4 ++
5 files changed, 217 insertions(+), 4 deletions(-)
create mode 100644 arm/gic.c
diff --git a/arm/Makefile.common b/arm/Makefile.common
index 6f56015c43c4..2fe7aeeca6d4 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -9,10 +9,10 @@ ifeq ($(LOADADDR),)
LOADADDR = 0x40000000
endif
-tests-common = \
- $(TEST_DIR)/selftest.flat \
- $(TEST_DIR)/spinlock-test.flat \
- $(TEST_DIR)/pci-test.flat
+tests-common = $(TEST_DIR)/selftest.flat
+tests-common += $(TEST_DIR)/spinlock-test.flat
+tests-common += $(TEST_DIR)/pci-test.flat
+tests-common += $(TEST_DIR)/gic.flat
all: test_cases
diff --git a/arm/gic.c b/arm/gic.c
new file mode 100644
index 000000000000..b42c2b1ca1e1
--- /dev/null
+++ b/arm/gic.c
@@ -0,0 +1,199 @@
+/*
+ * GIC tests
+ *
+ * GICv2
+ * + test sending/receiving IPIs
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <libcflat.h>
+#include <asm/setup.h>
+#include <asm/processor.h>
+#include <asm/gic.h>
+#include <asm/smp.h>
+#include <asm/barrier.h>
+#include <asm/io.h>
+
+static int gic_version;
+static int acked[NR_CPUS], spurious[NR_CPUS];
+static cpumask_t ready;
+
+static void nr_cpu_check(int nr)
+{
+ if (nr_cpus < nr)
+ report_abort("At least %d cpus required", nr);
+}
+
+static void wait_on_ready(void)
+{
+ cpumask_set_cpu(smp_processor_id(), &ready);
+ while (!cpumask_full(&ready))
+ cpu_relax();
+}
+
+static void check_acked(cpumask_t *mask)
+{
+ int missing = 0, extra = 0, unexpected = 0;
+ int nr_pass, cpu, i;
+
+ /* Wait up to 5s for all interrupts to be delivered */
+ for (i = 0; i < 50; ++i) {
+ mdelay(100);
+ nr_pass = 0;
+ for_each_present_cpu(cpu) {
+ smp_rmb();
+ nr_pass += cpumask_test_cpu(cpu, mask) ?
+ acked[cpu] == 1 : acked[cpu] == 0;
+ }
+ if (nr_pass == nr_cpus) {
+ report("Completed in %d ms", true, ++i * 100);
+ return;
+ }
+ }
+
+ for_each_present_cpu(cpu) {
+ if (cpumask_test_cpu(cpu, mask)) {
+ if (!acked[cpu])
+ ++missing;
+ else if (acked[cpu] > 1)
+ ++extra;
+ } else {
+ if (acked[cpu])
+ ++unexpected;
+ }
+ }
+
+ report("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d",
+ false, missing, extra, unexpected);
+}
+
+static void check_spurious(void)
+{
+ int cpu;
+
+ smp_rmb();
+ for_each_present_cpu(cpu) {
+ if (spurious[cpu])
+ printf("ipi: WARN: cpu%d got %d spurious interrupts\n",
+ spurious[cpu], smp_processor_id());
+ }
+}
+
+static void ipi_handler(struct pt_regs *regs __unused)
+{
+ u32 irqstat = readl(gicv2_cpu_base() + GICC_IAR);
+ u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+
+ if (irqnr != GICC_INT_SPURIOUS) {
+ writel(irqstat, gicv2_cpu_base() + GICC_EOIR);
+ smp_rmb(); /* pairs with wmb in ipi_test functions */
+ ++acked[smp_processor_id()];
+ smp_wmb(); /* pairs with rmb in check_acked */
+ } else {
+ ++spurious[smp_processor_id()];
+ smp_wmb();
+ }
+}
+
+static void ipi_test_self(void)
+{
+ cpumask_t mask;
+
+ report_prefix_push("self");
+ memset(acked, 0, sizeof(acked));
+ smp_wmb();
+ cpumask_clear(&mask);
+ cpumask_set_cpu(0, &mask);
+ writel(2 << 24, gicv2_dist_base() + GICD_SGIR);
+ check_acked(&mask);
+ report_prefix_pop();
+}
+
+static void ipi_test_smp(void)
+{
+ cpumask_t mask;
+ unsigned long tlist;
+
+ report_prefix_push("target-list");
+ memset(acked, 0, sizeof(acked));
+ smp_wmb();
+ tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
+ cpumask_bits(&mask)[0] = tlist;
+ writel((u8)tlist << 16, gicv2_dist_base() + GICD_SGIR);
+ check_acked(&mask);
+ report_prefix_pop();
+
+ report_prefix_push("broadcast");
+ memset(acked, 0, sizeof(acked));
+ smp_wmb();
+ cpumask_copy(&mask, &cpu_present_mask);
+ cpumask_clear_cpu(0, &mask);
+ writel(1 << 24, gicv2_dist_base() + GICD_SGIR);
+ check_acked(&mask);
+ report_prefix_pop();
+}
+
+static void ipi_enable(void)
+{
+ gicv2_enable_defaults();
+#ifdef __arm__
+ install_exception_handler(EXCPTN_IRQ, ipi_handler);
+#else
+ install_irq_handler(EL1H_IRQ, ipi_handler);
+#endif
+ local_irq_enable();
+}
+
+static void ipi_recv(void)
+{
+ ipi_enable();
+ cpumask_set_cpu(smp_processor_id(), &ready);
+ while (1)
+ wfi();
+}
+
+int main(int argc, char **argv)
+{
+ char pfx[8];
+ int cpu;
+
+ gic_version = gic_init();
+ if (!gic_version)
+ report_abort("No gic present!");
+
+ snprintf(pfx, sizeof(pfx), "gicv%d", gic_version);
+ report_prefix_push(pfx);
+
+ if (argc < 2) {
+
+ report_prefix_push("ipi");
+ ipi_enable();
+ ipi_test_self();
+ check_spurious();
+ report_prefix_pop();
+
+ } else if (strcmp(argv[1], "ipi") == 0) {
+
+ report_prefix_push(argv[1]);
+ nr_cpu_check(2);
+
+ for_each_present_cpu(cpu) {
+ if (cpu == 0)
+ continue;
+ smp_boot_secondary(cpu, ipi_recv);
+ }
+ ipi_enable();
+ wait_on_ready();
+ ipi_test_self();
+ ipi_test_smp();
+ check_spurious();
+ report_prefix_pop();
+
+ } else {
+ report_abort("Unknown subtest '%s'", argv[1]);
+ }
+
+ return report_summary();
+}
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index ae32a42a91c3..e631c35e2bbb 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -55,6 +55,14 @@ smp = $MAX_SMP
extra_params = -append 'smp'
groups = selftest
+# pci-testdev
[pci-test]
file = pci-test.flat
groups = pci
+
+# Test GIC emulation
+[gicv2-ipi]
+file = gic.flat
+smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
+extra_params = -machine gic-version=2 -append 'ipi'
+groups = gic
diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
index c2d5fecd4886..8b3f7ed6790c 100644
--- a/lib/arm/asm/gic-v2.h
+++ b/lib/arm/asm/gic-v2.h
@@ -13,7 +13,9 @@
#endif
#define GICD_ENABLE 0x1
+
#define GICC_ENABLE 0x1
+#define GICC_IAR_INT_ID_MASK 0x3ff
#ifndef __ASSEMBLY__
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index e3580bd1d42d..d816b96e46b4 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -13,6 +13,7 @@
#define GICD_TYPER 0x0004
#define GICD_ISENABLER 0x0100
#define GICD_IPRIORITYR 0x0400
+#define GICD_SGIR 0x0f00
#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32)
#define GICD_INT_EN_SET_SGI 0x0000ffff
@@ -21,8 +22,11 @@
/* CPU interface registers */
#define GICC_CTLR 0x0000
#define GICC_PMR 0x0004
+#define GICC_IAR 0x000c
+#define GICC_EOIR 0x0010
#define GICC_INT_PRI_THRESHOLD 0xf0
+#define GICC_INT_SPURIOUS 0x3ff
#ifndef __ASSEMBLY__
--
2.7.4
^ permalink raw reply related
* [Qemu-devel] [kvm-unit-tests PATCH v6 04/11] arm/arm64: add some delay routines
From: Andrew Jones @ 2016-11-14 21:08 UTC (permalink / raw)
To: kvm, kvmarm, qemu-devel, qemu-arm
Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
marc.zyngier, eric.auger, christoffer.dall
In-Reply-To: <1479157719-31021-1-git-send-email-drjones@redhat.com>
Allow a thread to wait some specified amount of time. Can
specify in cycles, usecs, and msecs.
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
lib/arm/asm/processor.h | 19 +++++++++++++++++++
lib/arm/processor.c | 15 +++++++++++++++
lib/arm64/asm/processor.h | 19 +++++++++++++++++++
lib/arm64/processor.c | 15 +++++++++++++++
4 files changed, 68 insertions(+)
diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index ecf5bbe1824a..bc46d1f980ee 100644
--- a/lib/arm/asm/processor.h
+++ b/lib/arm/asm/processor.h
@@ -5,7 +5,9 @@
*
* This work is licensed under the terms of the GNU LGPL, version 2.
*/
+#include <libcflat.h>
#include <asm/ptrace.h>
+#include <asm/barrier.h>
enum vector {
EXCPTN_RST,
@@ -51,4 +53,21 @@ extern int mpidr_to_cpu(unsigned long mpidr);
extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
extern bool is_user(void);
+static inline u64 get_cntvct(void)
+{
+ u64 vct;
+ isb();
+ asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (vct));
+ return vct;
+}
+
+extern void delay(u64 cycles);
+extern void udelay(unsigned long usecs);
+
+static inline void mdelay(unsigned long msecs)
+{
+ while (msecs--)
+ udelay(1000);
+}
+
#endif /* _ASMARM_PROCESSOR_H_ */
diff --git a/lib/arm/processor.c b/lib/arm/processor.c
index 54fdb87ef019..c2ee360df688 100644
--- a/lib/arm/processor.c
+++ b/lib/arm/processor.c
@@ -9,6 +9,7 @@
#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/thread_info.h>
+#include <asm/barrier.h>
static const char *processor_modes[] = {
"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" ,
@@ -141,3 +142,17 @@ bool is_user(void)
{
return current_thread_info()->flags & TIF_USER_MODE;
}
+
+void delay(u64 cycles)
+{
+ u64 start = get_cntvct();
+ while ((get_cntvct() - start) < cycles)
+ cpu_relax();
+}
+
+void udelay(unsigned long usec)
+{
+ unsigned int frq;
+ asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (frq));
+ delay((u64)usec * frq / 1000000);
+}
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 7e448dc81a6a..94f7ce35b65c 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -17,8 +17,10 @@
#define SCTLR_EL1_M (1 << 0)
#ifndef __ASSEMBLY__
+#include <libcflat.h>
#include <asm/ptrace.h>
#include <asm/esr.h>
+#include <asm/barrier.h>
enum vector {
EL1T_SYNC,
@@ -89,5 +91,22 @@ extern int mpidr_to_cpu(unsigned long mpidr);
extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
extern bool is_user(void);
+static inline u64 get_cntvct(void)
+{
+ u64 vct;
+ isb();
+ asm volatile("mrs %0, cntvct_el0" : "=r" (vct));
+ return vct;
+}
+
+extern void delay(u64 cycles);
+extern void udelay(unsigned long usecs);
+
+static inline void mdelay(unsigned long msecs)
+{
+ while (msecs--)
+ udelay(1000);
+}
+
#endif /* !__ASSEMBLY__ */
#endif /* _ASMARM64_PROCESSOR_H_ */
diff --git a/lib/arm64/processor.c b/lib/arm64/processor.c
index deeab4ec9c8a..50fa835c6f1e 100644
--- a/lib/arm64/processor.c
+++ b/lib/arm64/processor.c
@@ -9,6 +9,7 @@
#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/thread_info.h>
+#include <asm/barrier.h>
static const char *vector_names[] = {
"el1t_sync",
@@ -253,3 +254,17 @@ bool is_user(void)
{
return current_thread_info()->flags & TIF_USER_MODE;
}
+
+void delay(u64 cycles)
+{
+ u64 start = get_cntvct();
+ while ((get_cntvct() - start) < cycles)
+ cpu_relax();
+}
+
+void udelay(unsigned long usec)
+{
+ unsigned int frq;
+ asm volatile("mrs %0, cntfrq_el0" : "=r" (frq));
+ delay((u64)usec * frq / 1000000);
+}
--
2.7.4
^ permalink raw reply related
* [Qemu-devel] [kvm-unit-tests PATCH v6 05/11] arm/arm64: irq enable/disable
From: Andrew Jones @ 2016-11-14 21:08 UTC (permalink / raw)
To: kvm, kvmarm, qemu-devel, qemu-arm
Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
marc.zyngier, eric.auger, christoffer.dall
In-Reply-To: <1479157719-31021-1-git-send-email-drjones@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
lib/arm/asm/processor.h | 10 ++++++++++
lib/arm64/asm/processor.h | 10 ++++++++++
2 files changed, 20 insertions(+)
diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index bc46d1f980ee..959ecda5dced 100644
--- a/lib/arm/asm/processor.h
+++ b/lib/arm/asm/processor.h
@@ -35,6 +35,16 @@ static inline unsigned long current_cpsr(void)
#define current_mode() (current_cpsr() & MODE_MASK)
+static inline void local_irq_enable(void)
+{
+ asm volatile("cpsie i" : : : "memory", "cc");
+}
+
+static inline void local_irq_disable(void)
+{
+ asm volatile("cpsid i" : : : "memory", "cc");
+}
+
static inline unsigned long get_mpidr(void)
{
unsigned long mpidr;
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 94f7ce35b65c..d54a4ed1c187 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -68,6 +68,16 @@ static inline unsigned long current_level(void)
return el & 0xc;
}
+static inline void local_irq_enable(void)
+{
+ asm volatile("msr daifclr, #2" : : : "memory");
+}
+
+static inline void local_irq_disable(void)
+{
+ asm volatile("msr daifset, #2" : : : "memory");
+}
+
#define DEFINE_GET_SYSREG(reg, type) \
static inline type get_##reg(void) \
{ \
--
2.7.4
^ permalink raw reply related
* [U-Boot] [PATCH RESEND 6/9] eeprom: Add DS2431 support
From: Maxime Ripard @ 2016-11-14 21:09 UTC (permalink / raw)
To: u-boot
In-Reply-To: <CAPnjgZ3z7PwmisfXvfyJeE8iU-Zvzn8d7uHbT4o2TxVJOhRDow@mail.gmail.com>
On Mon, Nov 14, 2016 at 01:44:42PM -0700, Simon Glass wrote:
> Hi Maxime,
>
> On 14 November 2016 at 13:12, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > On Mon, Nov 14, 2016 at 10:14:57AM -0500, Tom Rini wrote:
> >> On Mon, Nov 14, 2016 at 02:42:59PM +0100, Maxime Ripard wrote:
> >> > Hi,
> >> >
> >> > On Fri, Nov 11, 2016 at 11:16:39AM -0800, Moritz Fischer wrote:
> >> > > > +U_BOOT_DRIVER(ds2431) = {
> >> > > > + .name = "ds2431",
> >> > > > + .id = UCLASS_EEPROM,
> >> > > > + .ops = &ds2431_ops,
> >> > >
> >> > > Do you want to add a .flags = DM_UC_FLAG_SEQ_ALIAS here?
> >> >
> >> > I don't know. I was kind of wondering why U-Boot relies on aliases so
> >> > much, especially when the Linux DT maintainers are saying that aliases
> >> > should be avoided entirely, and we'll won't be able to upstream those
> >> > changes.
> >>
> >> Bah. Do you have a pointer to some discussion about this handy?
> >
> > Rob said this multiple times, but here is an example:
> > http://lkml.iu.edu/hypermail/linux/kernel/1609.1/00653.html
>
> Well that's not really an explanation!
Don't shoot the messenger :)
I think I found some other discussion where they discuss it at length:
https://patchwork.kernel.org/patch/9133903/
The interesting part is when Rob Herring is involved.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161114/6a3164b2/attachment.sig>
^ 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.