* Re: AltiVec in the kernel
From: Kumar Gala @ 2006-07-18 13:53 UTC (permalink / raw)
To: matt; +Cc: linuxppc-dev list, Paul Mackerras
In-Reply-To: <004c01c6aa68$6f580d00$99dfdfdf@bakuhatsu.net>
On Jul 18, 2006, at 7:48 AM, Matt Sealey wrote:
>
> Once upon a time we were all told this wouldn't work for some reason,
> but a lot of documentation now hints that it does actually work and
> for instance there is a RAID5/6 driver (for G5) which uses AltiVec
> in a kernel context.
Using Altivec generally in the kernel is still something that is not
recommended. The key to using it is in disabling preemption, this
ensures that when the code is done the Altivec register state is back
to how the kernel found it.
preempt_disable();
enable_kernel_altivec();
raid6_altivec$#_gen_syndrome_real(disks, bytes, ptrs);
preempt_enable();
> But I didn't find any definitive documentation on how one goes about
> it. The largest clue I found was in Documentation/cpu_features.txt:
>
> #ifdef CONFIG_ALTIVEC
> BEGIN_FTR_SECTION
> mfspr r22,SPRN_VRSAVE /* if G4, save vrsave register value */
> stw r22,THREAD_VRSAVE(r23)
> END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
> #endif /* CONFIG_ALTIVEC */
>
> So we can use AltiVec by implementing this kind of wrapper around
> kernel functions which may use AltiVec?
>
> In the code above is there ANY significance of r22 and r23 other
> than that they are fairly high up and probably marked as "will
> be trashed" by all the relevant ABIs and so?
I'd guess those were the registers used by the code this was snipped
from.
> Just curious, as I would like to investigate writing some docs at
> least on this (in article fashion) to go with PPCZone, Libfreevec
> and so on. I think there is a problem here in that simply developers
> who may be interested in doing this kind of optimized code do not
> know where to start (and we are thinking from a point of view of
> also teaching sessions too, like we did at FTF Frankfurt 2004, so
> after we teach them what AltiVec is etc. we demonstrate application
> AND kernel functionality and the quirks associated with it).
I'm pretty sure Paul looked into using AltiVec for memory operations
in the kernel and didn't see a significant benefit to it.
- kumar
^ permalink raw reply
* RE: AltiVec in the kernel
From: Matt Sealey @ 2006-07-18 15:10 UTC (permalink / raw)
To: 'Kumar Gala'
Cc: 'linuxppc-dev list', 'Paul Mackerras'
In-Reply-To: <E40C6B7A-F2E8-4DB8-97D3-2CFF88C1D90A@kernel.crashing.org>
> -----Original Message-----
> From: Kumar Gala [mailto:galak@kernel.crashing.org]
> Sent: Tuesday, July 18, 2006 8:53 AM
> To: matt@genesi-usa.com
> Cc: linuxppc-dev list; Paul Mackerras
> Subject: Re: AltiVec in the kernel
>
>
> On Jul 18, 2006, at 7:48 AM, Matt Sealey wrote:
>
> > for instance there is a RAID5/6 driver (for G5) which uses
> > AltiVec in a kernel context.
>
> Using Altivec generally in the kernel is still something that
> is not recommended. The key to using it is in disabling
> preemption, this ensures that when the code is done the
> Altivec register state is back to how the kernel found it.
>
> preempt_disable();
> enable_kernel_altivec();
>
> raid6_altivec$#_gen_syndrome_real(disks, bytes, ptrs);
>
> preempt_enable();
Why isn't it recommended?
For instance on FreeBSD and other operating systems they have
designed the functionality in there as it would be a feature
people would want to use. QNX uses AltiVec to perform the
context switch and message passing and keep latency down.
Restricting AltiVec to userspace code (applications..) really
means you are barely ever using it. Kernel functions and
drivers are called every second of every day.. it's about
making AltiVec really used and not having the unit sit twiddling
it's thumbs until you REALLY NEED TO DECODE A JPEG VERY FAST.
There are thousands of things it could be doing. One example
could be.. in-kernel compression and encryption subroutines.
> > teach them what AltiVec is etc. we demonstrate application
> > AND kernel functionality and the quirks associated with it).
>
> I'm pretty sure Paul looked into using AltiVec for memory
> operations in the kernel and didn't see a significant benefit to it.
We had our own guy look at it and he presented some significant
performance improvements. One problem was, though, that the best
improvement in theory came from a function which needed to be
called very early in kernel boot, well before AltiVec was
enabled, and everything else is marginal at best (1.n times
improvement, but it is still 0.n more than 1.0). I am not clear
on this and cannot find my discussion on the subject in my logs
and email backups, so. I will leave it for now.
There is also plenty of example code (libmotovec, Freescale
Application Notes) which improve things like TCP checksumming
and so on using AltiVec. These patches are even used in EEMBC
benchmarks to boost the scores.
There is also plenty of examples of userspace code (as before,
checksumming, encryption, compression/decompression) which has
been improved. libfreevec includes some changes to the zlib
window functions. For example the kernel includes an MD5, SHA,
zlib compression framework.. mostly ported userspace code and
standard libraries. Would these not be candidates? The development
and speed improvements are even capable of being tested in
userspace (and this is a GREAT teaching aid also; show how to
improve some userspace app. Then show the differences it needed
to go into the kernel. Benchmark both. Detail result.)
I think there are thousands of places where AltiVec could be
used - even sparingly - to provide good performance improvements.
>From your reply I suspect that these would be places which do
not rely on the effects preemption has on performance (i.e.
you trade preemption for AltiVec and gain).
I don't think people investigate it too much because the first
thing they hit is lack of documentation, and then "well we don't
really recommend it". I think this makes Linux the worst OS a
developer would want to run on a G4 and G5, then? :D
--
Matt Sealey <matt@genesi-usa.com>
Manager, Genesi, Developer Relations
^ permalink raw reply
* Re: [PATCH] Add USB to MPC8349 PB platform support
From: Dan Malek @ 2006-07-18 15:19 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, linux-usb-devel
In-Reply-To: <41AD230F-91E8-442A-B9F9-9892D14BEF12@kernel.crashing.org>
On Jul 18, 2006, at 9:52 AM, Kumar Gala wrote:
> ..... I'm concerned about where to draw the line because of all
> the ways a user can configure the MDS board.
IMHO, you choose one configuration that works and
make that the board port. If someone wants to change
it later, it would be a good exercise for them to learn
how to do such things From years of working with these
things I'll suggest that it's not worthwhile to make this
so complicated that you think it's going to be everything
for anyone. It's not the way people use these boards.
The best thing we should do is clearly document
one board configuration and have the Linux configuration
that matches. It's horribly misleading to present a board
that is infinitely configurable and implying you can
find a Linux configuration to match. They are guaranteed
to find something that doesn't work on their first
attempt, and then all of the "broken this" and "broken
that" finger pointing starts :-)
Thanks.
-- Dan
^ permalink raw reply
* Re: [PATCH] Add USB to MPC8349 PB platform support
From: Wolfgang Denk @ 2006-07-18 15:53 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, linux-usb-devel
In-Reply-To: <41AD230F-91E8-442A-B9F9-9892D14BEF12@kernel.crashing.org>
In message <41AD230F-91E8-442A-B9F9-9892D14BEF12@kernel.crashing.org> you wrote:
>
> I'm talking about opening the door to a ton of options, not that we
> have them now. For example, your patch doesnt handle the USB PHYs if
If you really assume that all this has to be handled in so many
configuration options then it probably makes not much difference if
you do this in the kernel or in any boot loader - you're just
shifting effort and responsibility to somebody else. I agree with
Dan's argumentation.
Best regards,
Wolfgang Denk
--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Chapter 1 -- The story so far:
In the beginning the Universe was created. This has made a lot of
people very angry and been widely regarded as a bad move.
^ permalink raw reply
* Re: AltiVec in the kernel
From: Paul Mackerras @ 2006-07-18 17:43 UTC (permalink / raw)
To: matt; +Cc: linuxppc-dev
In-Reply-To: <004c01c6aa68$6f580d00$99dfdfdf@bakuhatsu.net>
Matt Sealey writes:
> Once upon a time we were all told this wouldn't work for some reason,
> but a lot of documentation now hints that it does actually work and
> for instance there is a RAID5/6 driver (for G5) which uses AltiVec
> in a kernel context.
It's possible, with some restrictions, basically the same restrictions
on using floating point in the kernel.
Kernel use of altivec interacts with the lazy altivec context switch
that we do on UP kernels, and the fact that the kernel context switch
doesn't save/restore the altivec state. That means that before using
altivec in the kernel you may have to save away the altivec state, and
you have to make sure you don't sleep or get preempted while using
altivec.
> But I didn't find any definitive documentation on how one goes about
> it. The largest clue I found was in Documentation/cpu_features.txt:
>
> #ifdef CONFIG_ALTIVEC
> BEGIN_FTR_SECTION
> mfspr r22,SPRN_VRSAVE /* if G4, save vrsave register value */
> stw r22,THREAD_VRSAVE(r23)
> END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
> #endif /* CONFIG_ALTIVEC */
>
> So we can use AltiVec by implementing this kind of wrapper around
> kernel functions which may use AltiVec?
No, that's irrelevant; that just has to do with the VRSAVE register,
not the altivec state. In fact VRSAVE isn't actually even part of the
altivec state.
> In the code above is there ANY significance of r22 and r23 other
> than that they are fairly high up and probably marked as "will
> be trashed" by all the relevant ABIs and so?
I hope we do a bit better than "probably" ... :) No, there is no
particular significance to the choice of r22 and r23. If you read the
code you will see that those registers are saved at the beginning of
the context switch routine and restored (from the new process's stack)
at the end.
Paul.
^ permalink raw reply
* RE: AltiVec in the kernel
From: Paul Mackerras @ 2006-07-18 17:56 UTC (permalink / raw)
To: matt; +Cc: 'linuxppc-dev list'
In-Reply-To: <005701c6aa7c$632a48e0$99dfdfdf@bakuhatsu.net>
Matt Sealey writes:
> Why isn't it recommended?
Because the overhead of saving away the user altivec state and
restoring it can easily overwhelm any advantage you get from using
altivec.
> We had our own guy look at it and he presented some significant
> performance improvements. One problem was, though, that the best
> improvement in theory came from a function which needed to be
> called very early in kernel boot, well before AltiVec was
> enabled, and everything else is marginal at best (1.n times
> improvement, but it is still 0.n more than 1.0). I am not clear
> on this and cannot find my discussion on the subject in my logs
> and email backups, so. I will leave it for now.
I tried using altivec for memory copies, and while I was able to show
an improvement in speed of copying stuff that was hot in the cache,
there was no overall improvement in the context of everything else the
kernel does. In other words, the things being copied were generally
not hot in the cache, and the CPU was able to saturate the memory
bandwidth using ordinary loads and stores.
> There is also plenty of example code (libmotovec, Freescale
> Application Notes) which improve things like TCP checksumming
> and so on using AltiVec. These patches are even used in EEMBC
> benchmarks to boost the scores.
TCP checksumming is simple enough that it is limited by memory
bandwidth rather than computation speed. This is another example
where you can show an improvement on a microbenchmark because the data
is hot in the cache, but the improvement doesn't translate into any
real improvement in a real application.
> There is also plenty of examples of userspace code (as before,
> checksumming, encryption, compression/decompression) which has
> been improved. libfreevec includes some changes to the zlib
> window functions. For example the kernel includes an MD5, SHA,
> zlib compression framework.. mostly ported userspace code and
> standard libraries. Would these not be candidates?
A lot of compression and encryption algorithms, by their very nature,
are very difficult to parallelize enough to get any significant
improvement from altivec. I looked at SHA1 for instance, and the
sequential dependencies in the computation are such that it is
practically impossible to find a way to do 4 things in parallel. The
sequential dependencies are of course a critical part of the way that
SHA1 ensures that a small change in any part of the input data results
in substantial changes in every byte of the output.
> I think there are thousands of places where AltiVec could be
> used - even sparingly - to provide good performance improvements.
I think that there are actually very few places in the kernel where we
are doing something which is parallelizable, sufficiently
compute-intensive, and not bound by memory bandwidth, to be worth
using altivec.
Paul.
^ permalink raw reply
* RE: AltiVec in the kernel
From: Benjamin Herrenschmidt @ 2006-07-18 18:39 UTC (permalink / raw)
To: matt; +Cc: 'linuxppc-dev list', 'Paul Mackerras'
In-Reply-To: <005701c6aa7c$632a48e0$99dfdfdf@bakuhatsu.net>
> I don't think people investigate it too much because the first
> thing they hit is lack of documentation, and then "well we don't
> really recommend it". I think this makes Linux the worst OS a
> developer would want to run on a G4 and G5, then? :D
It's not recommended for the same reason the FPU isn't used in the
kernel and x86 doesn't use SSE / MMX there neither except in a few
places where it does make sense like the RAID code. It's possible that
it might be interesting to do it for some of the crypto modules as well
and we certainly welcome any patch using altivec to improve some other
aspect of the kernel provided that it does indeed... improve
performances :)
Part of the problem is the cost of enabling/disabling it and
saving/restoring the vector registers that get clobbered when using it.
Essentially, the kernel entry only saves and restores GPRs. Not FPRs,
not VRs. This is done to keep the cost of kernel entry low. Which means
that at any given point in time, the altivec and FPU units contain
whatever context last used by userland. If the kernel wants to use it
for it's own, in thus needs to flush that context to the thread struct
(which also means that the unit will be disabled on the way back to
userland and re-faulted in when used again). That's what
enable_kernel_altivec() does (and the similar enable_kernel_fp()). This
cannot happen at interrupt time though and you shouldn't be holding
locks thus it may be a problem with some of the crypto stuffs as I think
they can be used in some weird code path. It's also important that no
scheduling happen until you are done with the unit, which is why you
have to disable preemption, since otherwise, the unit could be re-used
by userland behind your back.
Another alternative which can work at interrupt time, but requires a bit
of assembly hackery, is to manually enable MSR:VEC (if not already set)
and save and restore all the altivec registers modified by the code.
Ben.
^ permalink raw reply
* [PATCH 5/5] add MAINTAINERS entry for snd-aoa
From: Johannes Berg @ 2006-07-18 17:28 UTC (permalink / raw)
To: linuxppc-dev; +Cc: alsa-devel
In-Reply-To: <20060718172841.046446000@sipsolutions.net>
This adds me into the MAINTAINERS file for the AOA driver.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
--- linux-2.6-fetch.orig/MAINTAINERS 2006-07-18 13:39:52.543476868 +0200
+++ linux-2.6-fetch/MAINTAINERS 2006-07-18 13:57:27.843476868 +0200
@@ -292,6 +292,13 @@ L: info-linux@geode.amd.com
W: http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
S: Supported
+AOA (Apple Onboard Audio) ALSA DRIVER
+P: Johannes Berg
+M: johannes@sipsolutions.net
+L: linuxppc-dev@ozlabs.org
+L: alsa-devel@alsa-project.org
+S: Maintained
+
APM DRIVER
P: Stephen Rothwell
M: sfr@canb.auug.org.au
--
^ permalink raw reply
* [PATCH 1/5] aoa: feature gpio layer: fix IRQ access
From: Johannes Berg @ 2006-07-18 17:28 UTC (permalink / raw)
To: linuxppc-dev; +Cc: alsa-devel
In-Reply-To: <20060718172841.046446000@sipsolutions.net>
The IRQ rework caused some hiccups here, in some cases we call
get_irq without a device node. This patch makes it catch that
case and return NO_IRQ when it happens, along with changing the
place where the irq is checked to check for NO_IRQ instead of -1.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
--- linux-2.6-fetch.orig/sound/aoa/core/snd-aoa-gpio-feature.c 2006-07-16 22:10:02.467630929 +0200
+++ linux-2.6-fetch/sound/aoa/core/snd-aoa-gpio-feature.c 2006-07-16 22:13:41.891630929 +0200
@@ -112,7 +112,10 @@ static struct device_node *get_gpio(char
static void get_irq(struct device_node * np, int *irqptr)
{
- *irqptr = irq_of_parse_and_map(np, 0);
+ if (np)
+ *irqptr = irq_of_parse_and_map(np, 0);
+ else
+ *irqptr = NO_IRQ;
}
/* 0x4 is outenable, 0x1 is out, thus 4 or 5 */
@@ -322,7 +325,7 @@ static int ftr_set_notify(struct gpio_ru
return -EINVAL;
}
- if (irq == -1)
+ if (irq == NO_IRQ)
return -ENODEV;
mutex_lock(¬if->mutex);
--
^ permalink raw reply
* [PATCH 0/5] powerpc sound, some more patches
From: Johannes Berg @ 2006-07-18 17:28 UTC (permalink / raw)
To: linuxppc-dev; +Cc: alsa-devel
Here's a new and hopefully final round of patches fixing problems with my
new snd-aoa driver. There are fixes for the PPC Mac Mini as well as for a
problem with snd-powermac that I had noticed.
^ permalink raw reply
* [PATCH 3/5] make snd-powermac load even when it cant bind the device
From: Johannes Berg @ 2006-07-18 17:28 UTC (permalink / raw)
To: linuxppc-dev; +Cc: alsa-devel
In-Reply-To: <20060718172841.046446000@sipsolutions.net>
This patch makes snd-powermac load when it can't bind the device right
away. That's the expected behaviour for hotplugging, but fixes an
important problem I was seeing with doing a modprobe snd-powermac with
a version that refuses loading on machines with layout-id: snd-powermac
would create a bunch of uevents and then refuse to load, the uevents
causing udev to reload it again, ad eternum.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
--- linux-2.6-fetch.orig/sound/ppc/powermac.c 2006-07-18 18:16:53.633476868 +0200
+++ linux-2.6-fetch/sound/ppc/powermac.c 2006-07-18 18:40:39.243476868 +0200
@@ -181,21 +181,14 @@ static int __init alsa_card_pmac_init(vo
if ((err = platform_driver_register(&snd_pmac_driver)) < 0)
return err;
device = platform_device_register_simple(SND_PMAC_DRIVER, -1, NULL, 0);
- if (!IS_ERR(device)) {
- if (platform_get_drvdata(device))
- return 0;
- platform_device_unregister(device);
- err = -ENODEV;
- } else
- err = PTR_ERR(device);
- platform_driver_unregister(&snd_pmac_driver);
- return err;
+ return 0;
}
static void __exit alsa_card_pmac_exit(void)
{
- platform_device_unregister(device);
+ if (!IS_ERR(device))
+ platform_device_unregister(device);
platform_driver_unregister(&snd_pmac_driver);
}
--
^ permalink raw reply
* [PATCH 4/5] aoa: platform function gpio: ignore errors from functions that dont exist
From: Johannes Berg @ 2006-07-18 17:28 UTC (permalink / raw)
To: linuxppc-dev; +Cc: alsa-devel
In-Reply-To: <20060718172841.046446000@sipsolutions.net>
Sometimes we simply want to turn off or on everything, and when recently a
warning was added when a certain platform function can't be called, this
triggered all the time in those cases. This patch shows the warning only if
the error was different from the function not existing.
The alternative would be to not even try calling the function when it
doesn't exist by first checking which exist and then only calling those that
do, but that adds complexity that isn't necessary.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
--- linux-2.6-fetch.orig/sound/aoa/core/snd-aoa-gpio-pmf.c 2006-07-18 19:24:30.273476868 +0200
+++ linux-2.6-fetch/sound/aoa/core/snd-aoa-gpio-pmf.c 2006-07-18 19:24:55.103476868 +0200
@@ -18,7 +18,7 @@ static void pmf_gpio_set_##name(struct g
\
if (unlikely(!rt)) return; \
rc = pmf_call_function(rt->node, #name "-mute", &args); \
- if (rc) \
+ if (rc && rc != -ENODEV) \
printk(KERN_WARNING "pmf_gpio_set_" #name \
" failed, rc: %d\n", rc); \
rt->implementation_private &= ~(1<<bit); \
--
^ permalink raw reply
* [PATCH 2/5] aoa: fix toonie codec
From: Johannes Berg @ 2006-07-18 17:28 UTC (permalink / raw)
To: linuxppc-dev; +Cc: alsa-devel
In-Reply-To: <20060718172841.046446000@sipsolutions.net>
This patch fixes the toonie codec to be actually usable.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
--- linux-2.6-fetch.orig/sound/aoa/codecs/snd-aoa-codec-toonie.c 2006-07-18 11:40:32.363476868 +0200
+++ linux-2.6-fetch/sound/aoa/codecs/snd-aoa-codec-toonie.c 2006-07-18 11:52:29.783476868 +0200
@@ -51,6 +51,13 @@ static struct transfer_info toonie_trans
{}
};
+static int toonie_usable(struct codec_info_item *cii,
+ struct transfer_info *ti,
+ struct transfer_info *out)
+{
+ return 1;
+}
+
#ifdef CONFIG_PM
static int toonie_suspend(struct codec_info_item *cii, pm_message_t state)
{
@@ -69,6 +76,7 @@ static struct codec_info toonie_codec_in
.sysclock_factor = 256,
.bus_factor = 64,
.owner = THIS_MODULE,
+ .usable = toonie_usable,
#ifdef CONFIG_PM
.suspend = toonie_suspend,
.resume = toonie_resume,
@@ -79,19 +87,20 @@ static int toonie_init_codec(struct aoa_
{
struct toonie *toonie = codec_to_toonie(codec);
+ /* nothing connected? what a joke! */
+ if (toonie->codec.connected != 1)
+ return -ENOTCONN;
+
if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, toonie, &ops)) {
printk(KERN_ERR PFX "failed to create toonie snd device!\n");
return -ENODEV;
}
- /* nothing connected? what a joke! */
- if (toonie->codec.connected != 1)
- return -ENOTCONN;
-
if (toonie->codec.soundbus_dev->attach_codec(toonie->codec.soundbus_dev,
aoa_get_card(),
&toonie_codec_info, toonie)) {
printk(KERN_ERR PFX "error creating toonie pcm\n");
+ snd_device_free(aoa_get_card(), toonie);
return -ENODEV;
}
--
^ permalink raw reply
* Re: [PATCH 1/5] aoa: feature gpio layer: fix IRQ access
From: Benjamin Herrenschmidt @ 2006-07-18 18:45 UTC (permalink / raw)
To: Johannes Berg; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <20060718173012.532719000@sipsolutions.net>
On Tue, 2006-07-18 at 19:28 +0200, Johannes Berg wrote:
> plain text document attachment (aoa-get-irq-fix.patch)
> The IRQ rework caused some hiccups here, in some cases we call
> get_irq without a device node. This patch makes it catch that
> case and return NO_IRQ when it happens, along with changing the
> place where the irq is checked to check for NO_IRQ instead of -1.
>
> Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>
> --- linux-2.6-fetch.orig/sound/aoa/core/snd-aoa-gpio-feature.c 2006-07-16 22:10:02.467630929 +0200
> +++ linux-2.6-fetch/sound/aoa/core/snd-aoa-gpio-feature.c 2006-07-16 22:13:41.891630929 +0200
> @@ -112,7 +112,10 @@ static struct device_node *get_gpio(char
>
> static void get_irq(struct device_node * np, int *irqptr)
> {
> - *irqptr = irq_of_parse_and_map(np, 0);
> + if (np)
> + *irqptr = irq_of_parse_and_map(np, 0);
> + else
> + *irqptr = NO_IRQ;
> }
>
> /* 0x4 is outenable, 0x1 is out, thus 4 or 5 */
> @@ -322,7 +325,7 @@ static int ftr_set_notify(struct gpio_ru
> return -EINVAL;
> }
>
> - if (irq == -1)
> + if (irq == NO_IRQ)
> return -ENODEV;
>
> mutex_lock(¬if->mutex);
>
> --
^ permalink raw reply
* Re: [PATCH] panic_on_oops: remove ssleep()
From: Horms @ 2006-07-18 19:13 UTC (permalink / raw)
To: Andrew Morton
Cc: chris, tony.luck, linux-ia64, discuss, ak, linux-kernel,
linuxppc-dev, paulus, anton, rmk
In-Reply-To: <20060717172341.6d49f109.akpm@osdl.org>
On Mon, Jul 17, 2006 at 05:23:41PM -0700, Andrew Morton wrote:
> On Mon, 17 Jul 2006 19:10:59 -0400
> Horms <horms@verge.net.au> wrote:
>
> > On Tue, Jul 18, 2006 at 12:27:51AM +0200, Andi Kleen wrote:
> > > On Monday 17 July 2006 18:17, Horms wrote:
> > > ...
> > > Keeping the delay might be actually useful so that you can see the panic
> > > before system reboots when reboot on panic is enabled. I would just use a loop
> > > of mdelays(1) with touch_nmi_watchdog/touch_softirq_watchdog()s
> > > inbetween.
> >
> > Ok, I will look into making that happen. I agree that the pause is
> > quite useful.
>
> It's kind-of already implemented, via pause_on_oops. Perhaps doing
> something like
>
> if (panic_on_oops)
> pause_on_oops = max(pause_on_oops, 5*HZ);
>
> would be sufficient.
Thanks, that may well be sufficient. And I assume that it is nicely out
of the arch-dependant code in die(). I will poke around a bit more.
--
Horms
H: http://www.vergenet.net/~horms/
W: http://www.valinux.co.jp/en/
^ permalink raw reply
* Re: [PATCH] panic_on_oops: remove ssleep()
From: Horms @ 2006-07-18 19:15 UTC (permalink / raw)
To: Chuck Ebbert
Cc: Andrew Morton, Chris Zankel, Tony Luck, linux-ia64, discuss,
Andi Kleen, linux-kernel, linuxppc-dev, Paul Mackerras,
Anton Blanchard, Russell King
In-Reply-To: <200607172126_MC3-1-C544-E35A@compuserve.com>
On Mon, Jul 17, 2006 at 09:22:17PM -0400, Chuck Ebbert wrote:
> In-Reply-To: <31687.FP.7244@verge.net.au>
>
> On Mon, 17 Jul 2006 12:17:20 -0400, Horms wrote:
>
> > This patch is part of an effort to unify the panic_on_oops behaviour
> > across all architectures that implement it.
> >
> > It was pointed out to me by Andi Kleen that if an oops has occured
> > in interrupt context, then calling sleep() in the oops path will only cause
> > a panic, and that it would be really better for it not to be in the path at
> > all.
>
> i386 already checks in_interrupt() and panics immediately:
Very good point. I guess that needs to be moved to after
panic_on_oops() if the change that Andi suggests works out.
--
Horms
H: http://www.vergenet.net/~horms/
W: http://www.valinux.co.jp/en/
^ permalink raw reply
* [PATCH 0/3] powerpc: Instrument Hypervisor Calls
From: Mike Kravetz @ 2006-07-18 20:47 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
A small update from the last version. By popular demand, both
wall time (mftb) and cpu cycles(PURR) are collected for each call.
It is interesting to see these two values side by side in the
output files.
--
Mike
^ permalink raw reply
* [PATCH 1/3] powerpc: Instrument Hypervisor Calls: merge headers
From: Mike Kravetz @ 2006-07-18 20:48 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20060718204723.GA6104@w-mikek2.ibm.com>
Move all the Hypervisor call definitions to to a single header file.
--
Signed-off-by: Mike Kravetz <kravetz@us.ibm.com>
diff -Naupr linux-2.6.17.6/drivers/net/ibmveth.h linux-2.6.17.6.work/drivers/net/ibmveth.h
--- linux-2.6.17.6/drivers/net/ibmveth.h 2006-07-15 19:00:43.000000000 +0000
+++ linux-2.6.17.6.work/drivers/net/ibmveth.h 2006-07-18 19:33:47.000000000 +0000
@@ -41,16 +41,6 @@
#define IbmVethMcastRemoveFilter 0x2UL
#define IbmVethMcastClearFilterTable 0x3UL
-/* hcall numbers */
-#define H_VIO_SIGNAL 0x104
-#define H_REGISTER_LOGICAL_LAN 0x114
-#define H_FREE_LOGICAL_LAN 0x118
-#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
-#define H_SEND_LOGICAL_LAN 0x120
-#define H_MULTICAST_CTRL 0x130
-#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
-#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
-
/* hcall macros */
#define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac)
diff -Naupr linux-2.6.17.6/include/asm-powerpc/hvcall.h linux-2.6.17.6.work/include/asm-powerpc/hvcall.h
--- linux-2.6.17.6/include/asm-powerpc/hvcall.h 2006-07-15 19:00:43.000000000 +0000
+++ linux-2.6.17.6.work/include/asm-powerpc/hvcall.h 2006-07-18 19:33:47.000000000 +0000
@@ -155,9 +155,15 @@
#define H_VIO_SIGNAL 0x104
#define H_SEND_CRQ 0x108
#define H_COPY_RDMA 0x110
+#define H_REGISTER_LOGICAL_LAN 0x114
+#define H_FREE_LOGICAL_LAN 0x118
+#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
+#define H_SEND_LOGICAL_LAN 0x120
+#define H_MULTICAST_CTRL 0x130
#define H_SET_XDABR 0x134
#define H_STUFF_TCE 0x138
#define H_PUT_TCE_INDIRECT 0x13C
+#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
#define H_VTERM_PARTNER_INFO 0x150
#define H_REGISTER_VTERM 0x154
#define H_FREE_VTERM 0x158
@@ -187,11 +193,14 @@
#define H_GET_HCA_INFO 0x1B8
#define H_GET_PERF_COUNT 0x1BC
#define H_MANAGE_TRACE 0x1C0
+#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
#define H_QUERY_INT_STATE 0x1E4
#define H_POLL_PENDING 0x1D8
#define H_JOIN 0x298
#define H_ENABLE_CRQ 0x2B0
+#define MAX_HCALL_OPCODES (H_ENABLE_CRQ >> 2)
+
#ifndef __ASSEMBLY__
/* plpar_hcall() -- Generic call interface using above opcodes
^ permalink raw reply
* [PATCH 2/3] powerpc: Instrument Hypervisor Calls: add wrappers
From: Mike Kravetz @ 2006-07-18 20:49 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20060718204723.GA6104@w-mikek2.ibm.com>
Add wrappers which perform the actual hypervisor call instrumentation.
--
Signed-off-by: Mike Kravetz <kravetz@us.ibm.com>
diff -Naupr linux-2.6.17.6/arch/powerpc/Kconfig.debug linux-2.6.17.6.work/arch/powerpc/Kconfig.debug
--- linux-2.6.17.6/arch/powerpc/Kconfig.debug 2006-07-15 19:00:43.000000000 +0000
+++ linux-2.6.17.6.work/arch/powerpc/Kconfig.debug 2006-07-18 19:56:20.000000000 +0000
@@ -18,6 +18,20 @@ config DEBUG_STACK_USAGE
This option will slow down process creation somewhat.
+config HCALL_STATS
+ bool "Hypervisor call instrumentation"
+ depends on PPC_PSERIES && DEBUG_FS
+ help
+ Adds code to keep track of the number of hypervisor calls made and
+ the amount of time spent in hypervisor calls: both wall time (based
+ on time base) and cpu time (based on PURR). A directory named
+ hcall_inst is added at the root of the debugfs filesystem. Within
+ the hcall_inst directory are files that contain CPU specific call
+ statistics.
+
+ This option will add a small amount of overhead to all hypervisor
+ calls.
+
config DEBUGGER
bool "Enable debugger hooks"
depends on DEBUG_KERNEL
diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/Makefile linux-2.6.17.6.work/arch/powerpc/platforms/pseries/Makefile
--- linux-2.6.17.6/arch/powerpc/platforms/pseries/Makefile 2006-07-15 19:00:43.000000000 +0000
+++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/Makefile 2006-07-18 19:56:20.000000000 +0000
@@ -9,3 +9,4 @@ obj-$(CONFIG_EEH) += eeh.o eeh_cache.o e
obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
obj-$(CONFIG_HVCS) += hvcserver.o
+obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o
diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall.S linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall.S
--- linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall.S 2006-07-15 19:00:43.000000000 +0000
+++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall.S 2006-07-18 19:56:20.000000000 +0000
@@ -11,7 +11,35 @@
#include <asm/hvcall.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
-
+
+/*
+ * If hcall statistics are desired, all routines are wrapped with code
+ * that does the statistic gathering.
+ */
+#ifndef CONFIG_HCALL_STATS
+#define PLPAR_HCALL plpar_hcall
+#define PLPAR_HCALL_NORETS plpar_hcall_norets
+#define PLPAR_HCALL_8ARG_2RET plpar_hcall_8arg_2ret
+#define PLPAR_HCALL_4OUT plpar_hcall_4out
+#define PLPAR_HCALL_7ARG_7RET plpar_hcall_7arg_7ret
+#define PLPAR_HCALL_9ARG_9RET plpar_hcall_9arg_9ret
+#else
+#define PLPAR_HCALL plpar_hcall_base
+#define PLPAR_HCALL_NORETS plpar_hcall_norets_base
+#define PLPAR_HCALL_8ARG_2RET plpar_hcall_8arg_2ret_base
+#define PLPAR_HCALL_4OUT plpar_hcall_4out_base
+#define PLPAR_HCALL_7ARG_7RET plpar_hcall_7arg_7ret_base
+#define PLPAR_HCALL_9ARG_9RET plpar_hcall_9arg_9ret_base
+
+/*
+ * A special 'indirect' call to a C based wrapper if statistics are desired.
+ * See plpar_hcall_norets_C function header for more details.
+ */
+_GLOBAL(plpar_hcall_norets)
+ b plpar_hcall_norets_C
+
+#endif
+
#define STK_PARM(i) (48 + ((i)-3)*8)
.text
@@ -25,7 +53,7 @@
unsigned long *out2, R9
unsigned long *out3); R10
*/
-_GLOBAL(plpar_hcall)
+_GLOBAL(PLPAR_HCALL)
HMT_MEDIUM
mfcr r0
@@ -52,7 +80,7 @@ _GLOBAL(plpar_hcall)
/* Simple interface with no output values (other than status) */
-_GLOBAL(plpar_hcall_norets)
+_GLOBAL(PLPAR_HCALL_NORETS)
HMT_MEDIUM
mfcr r0
@@ -76,7 +104,7 @@ _GLOBAL(plpar_hcall_norets)
unsigned long arg8, 112(R1)
unsigned long *out1); 120(R1)
*/
-_GLOBAL(plpar_hcall_8arg_2ret)
+_GLOBAL(PLPAR_HCALL_8ARG_2RET)
HMT_MEDIUM
mfcr r0
@@ -102,7 +130,7 @@ _GLOBAL(plpar_hcall_8arg_2ret)
unsigned long *out3, R10
unsigned long *out4); 112(R1)
*/
-_GLOBAL(plpar_hcall_4out)
+_GLOBAL(PLPAR_HCALL_4OUT)
HMT_MEDIUM
mfcr r0
@@ -144,7 +172,7 @@ _GLOBAL(plpar_hcall_4out)
unsigned long *out6, 102(R1)
unsigned long *out7); 100(R1)
*/
-_GLOBAL(plpar_hcall_7arg_7ret)
+_GLOBAL(PLPAR_HCALL_7ARG_7RET)
HMT_MEDIUM
mfcr r0
@@ -193,7 +221,7 @@ _GLOBAL(plpar_hcall_7arg_7ret)
unsigned long *out8, 94(R1)
unsigned long *out9, 92(R1)
*/
-_GLOBAL(plpar_hcall_9arg_9ret)
+_GLOBAL(PLPAR_HCALL_9ARG_9RET)
HMT_MEDIUM
mfcr r0
diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall_inst.c linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall_inst.c
--- linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall_inst.c 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall_inst.c 2006-07-18 19:57:44.000000000 +0000
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2006 Mike Kravetz IBM Corporation
+ *
+ * Hypervisor Call Instrumentation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/percpu.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/cpumask.h>
+#include <asm/hvcall.h>
+#include <asm/firmware.h>
+
+DEFINE_PER_CPU(struct hcall_stats[MAX_HCALL_OPCODES+1], hcall_stats);
+
+/*
+ * Common update of the per-CPU/per-hcall statistics
+ */
+static inline void update_stats(unsigned long opcode,
+ unsigned long t_tb_before,
+ unsigned long t_cpu_before)
+{
+ unsigned long op_index = opcode >> 2;
+ struct hcall_stats *hs = &__get_cpu_var(hcall_stats[op_index]);
+
+ hs->tb_total += (mftb() - t_tb_before);
+ hs->cpu_total += (mfspr(SPRN_PURR) - t_cpu_before);
+ hs->num_calls++;
+}
+
+/*
+ * plpar_hcall wrapper
+ */
+long plpar_hcall(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3)
+{
+ long rc;
+ unsigned long t_tb_before, t_cpu_before;
+
+ t_tb_before = mftb();
+ t_cpu_before = mfspr(SPRN_PURR);
+ rc = plpar_hcall_base(opcode, arg1, arg2, arg3, arg4, out1, out2, out3);
+
+ update_stats(opcode, t_tb_before, t_cpu_before);
+ return rc;
+}
+
+/*
+ * A C based wrapper for plpar_hcall_norets
+ * The wrapper for plpar_hcall_norets is a special case because the function
+ * takes a variable number of arguments. It is almost impossible to write a
+ * wrapper for a function that takes a variable number of arguments in C.
+ * Therefore, there is an assembly routine in hvCall.S that simply branches
+ * to this C wrapper. This 'indirection' takes care of the variable arguments
+ * issue. This C wrapper has a fixed maximum number of arguments.
+ */
+long plpar_hcall_norets_C(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6)
+{
+ long rc;
+ unsigned long t_tb_before, t_cpu_before;
+
+ t_tb_before = mftb();
+ t_cpu_before = mfspr(SPRN_PURR);
+ rc = plpar_hcall_norets_base(opcode, arg1, arg2, arg3, arg4, arg5,
+ arg6);
+
+ update_stats(opcode, t_tb_before, t_cpu_before);
+ return rc;
+}
+
+/*
+ * plpar_hcall_8arg_2ret wrapper
+ */
+long plpar_hcall_8arg_2ret(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long arg8,
+ unsigned long *out1)
+{
+ long rc;
+ unsigned long t_tb_before, t_cpu_before;
+
+ t_tb_before = mftb();
+ t_cpu_before = mfspr(SPRN_PURR);
+ rc = plpar_hcall_8arg_2ret_base(opcode, arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, out1);
+
+ update_stats(opcode, t_tb_before, t_cpu_before);
+ return rc;
+}
+
+/*
+ * plpar_hcall_4out wrapper
+ */
+long plpar_hcall_4out(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3,
+ unsigned long *out4)
+{
+ long rc;
+ unsigned long t_tb_before, t_cpu_before;
+
+ t_tb_before = mftb();
+ t_cpu_before = mfspr(SPRN_PURR);
+ rc = plpar_hcall_4out_base(opcode, arg1, arg2, arg3, arg4, out1,
+ out2, out3, out4);
+
+ update_stats(opcode, t_tb_before, t_cpu_before);
+ return rc;
+}
+
+/*
+ * plpar_hcall_7arg_7ret wrapper
+ */
+long plpar_hcall_7arg_7ret(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3,
+ unsigned long *out4,
+ unsigned long *out5,
+ unsigned long *out6,
+ unsigned long *out7)
+{
+ long rc;
+ unsigned long t_tb_before, t_cpu_before;
+
+ t_tb_before = mftb();
+ t_cpu_before = mfspr(SPRN_PURR);
+ rc = plpar_hcall_7arg_7ret_base(opcode, arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, out1, out2, out3, out4,
+ out5, out6, out7);
+
+ update_stats(opcode, t_tb_before, t_cpu_before);
+ return rc;
+}
+
+/*
+ * plpar_hcall_9arg_9ret wrapper
+ */
+long plpar_hcall_9arg_9ret(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long arg8,
+ unsigned long arg9,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3,
+ unsigned long *out4,
+ unsigned long *out5,
+ unsigned long *out6,
+ unsigned long *out7,
+ unsigned long *out8,
+ unsigned long *out9)
+{
+ long rc;
+ unsigned long t_tb_before, t_cpu_before;
+
+ t_tb_before = mftb();
+ t_cpu_before = mfspr(SPRN_PURR);
+ rc = plpar_hcall_9arg_9ret_base(opcode, arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, arg9, out1, out2,
+ out3, out4, out5, out6, out7, out8,
+ out9);
+
+ update_stats(opcode, t_tb_before, t_cpu_before);
+ return rc;
+}
diff -Naupr linux-2.6.17.6/include/asm-powerpc/hvcall.h linux-2.6.17.6.work/include/asm-powerpc/hvcall.h
--- linux-2.6.17.6/include/asm-powerpc/hvcall.h 2006-07-18 19:35:00.000000000 +0000
+++ linux-2.6.17.6.work/include/asm-powerpc/hvcall.h 2006-07-18 19:56:20.000000000 +0000
@@ -292,6 +292,87 @@ long plpar_hcall_9arg_9ret(unsigned long
unsigned long *out8,
unsigned long *out9);
+
+/* For hcall instrumentation. One structure per-hcall, per-CPU */
+struct hcall_stats {
+ unsigned long num_calls; /* number of calls (on this CPU) */
+ unsigned long tb_total; /* total wall time (mftb) of calls. */
+ unsigned long cpu_total; /* total cpu time (PURR) of calls. */
+};
+
+/* If Hypervisor call instrumentation is enabled, the assembly routine
+ * names are changed from 'plpar_hcall*' to 'plpar_hcall*_base' and
+ * 'plpar_hcall*' routines become instrumented wrappers. The following
+ * are declarations for the renamed 'plpar_hcall*_base' routines.
+ */
+long plpar_hcall_base (unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3);
+
+long plpar_hcall_norets_base(unsigned long opcode, ...);
+
+long plpar_hcall_8arg_2ret_base(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long arg8,
+ unsigned long *out1);
+
+long plpar_hcall_4out_base(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3,
+ unsigned long *out4);
+
+long plpar_hcall_7arg_7ret_base(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3,
+ unsigned long *out4,
+ unsigned long *out5,
+ unsigned long *out6,
+ unsigned long *out7);
+
+long plpar_hcall_9arg_9ret_base(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long arg8,
+ unsigned long arg9,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3,
+ unsigned long *out4,
+ unsigned long *out5,
+ unsigned long *out6,
+ unsigned long *out7,
+ unsigned long *out8,
+ unsigned long *out9);
+
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_HVCALL_H */
^ permalink raw reply
* [PATCH 3/3] powerpc: Instrument Hypervisor Calls: add debugfs files
From: Mike Kravetz @ 2006-07-18 20:50 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20060718204723.GA6104@w-mikek2.ibm.com>
Make statistics available via files in debugfs.
--
Signed-off-by: Mike Kravetz <kravetz@us.ibm.com>
diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall_inst.c linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall_inst.c
--- linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall_inst.c 2006-07-18 20:02:21.000000000 +0000
+++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall_inst.c 2006-07-18 20:03:32.000000000 +0000
@@ -214,3 +214,96 @@ long plpar_hcall_9arg_9ret(unsigned long
update_stats(opcode, t_tb_before, t_cpu_before);
return rc;
}
+
+/*
+ * Routines for displaying the statistics in debugfs
+ */
+static void *hc_start(struct seq_file *m, loff_t *pos)
+{
+ if ((int)*pos < MAX_HCALL_OPCODES)
+ return (void *)(unsigned long)(*pos + 1);
+
+ return NULL;
+}
+
+static void *hc_next(struct seq_file *m, void *p, loff_t * pos)
+{
+ ++*pos;
+
+ return hc_start(m, pos);
+}
+
+static void hc_stop(struct seq_file *m, void *p)
+{
+}
+
+static int hc_show(struct seq_file *m, void *p)
+{
+ unsigned long h_num = (unsigned long)p;
+ struct hcall_stats *hs = (struct hcall_stats *)m->private;
+
+ if (hs[h_num].num_calls)
+ seq_printf(m, "%lu %lu %lu %lu\n", h_num<<2,
+ hs[h_num].num_calls,
+ hs[h_num].tb_total,
+ hs[h_num].cpu_total);
+
+ return 0;
+}
+
+static struct seq_operations hcall_inst_seq_ops = {
+ .start = hc_start,
+ .next = hc_next,
+ .stop = hc_stop,
+ .show = hc_show
+};
+
+static int hcall_inst_seq_open(struct inode *inode, struct file *file)
+{
+ int rc;
+ struct seq_file *seq;
+
+ rc = seq_open(file, &hcall_inst_seq_ops);
+ seq = file->private_data;
+ seq->private = file->f_dentry->d_inode->u.generic_ip;
+
+ return rc;
+}
+
+static struct file_operations hcall_inst_seq_fops = {
+ .open = hcall_inst_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+#define HCALL_ROOT_DIR "hcall_inst"
+#define CPU_NAME_BUF_SIZE 32
+
+static int __init hcall_inst_init(void)
+{
+ struct dentry *hcall_root;
+ struct dentry *hcall_file;
+ char cpu_name_buf[CPU_NAME_BUF_SIZE];
+ int cpu;
+
+ if (!firmware_has_feature(FW_FEATURE_LPAR))
+ return 0;
+
+ hcall_root = debugfs_create_dir(HCALL_ROOT_DIR, NULL);
+ if (!hcall_root)
+ return -ENOMEM;
+
+ for_each_cpu(cpu) {
+ snprintf(cpu_name_buf, CPU_NAME_BUF_SIZE, "cpu%d", cpu);
+ hcall_file = debugfs_create_file(cpu_name_buf, S_IRUGO,
+ hcall_root,
+ per_cpu(hcall_stats, cpu),
+ &hcall_inst_seq_fops);
+ if (!hcall_file)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+__initcall(hcall_inst_init);
^ permalink raw reply
* Re: [PATCH 0/3] powerpc: Instrument Hypervisor Calls
From: Paul Mackerras @ 2006-07-18 21:00 UTC (permalink / raw)
To: Mike Kravetz; +Cc: linuxppc-dev
In-Reply-To: <20060718204723.GA6104@w-mikek2.ibm.com>
Mike Kravetz writes:
> A small update from the last version. By popular demand, both
> wall time (mftb) and cpu cycles(PURR) are collected for each call.
> It is interesting to see these two values side by side in the
> output files.
Did you see the patch from Anton that I posted a week or so ago, which
reduces the number of plpar_hcall_* functions? I'd rather the
instrumentation stuff was based on that.
My other comment is this: wouldn't it actually turn out simpler if we
read the timebase (and PURR, if we really want to do that too) in the
assembly code that implements plpar_hcall_*?
Paul.
^ permalink raw reply
* Re: [PATCH 0/3] powerpc: Instrument Hypervisor Calls
From: Mike Kravetz @ 2006-07-18 21:29 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20060718204723.GA6104@w-mikek2.ibm.com>
On Tue, Jul 18, 2006 at 01:47:23PM -0700, Mike Kravetz wrote:
> A small update from the last version. By popular demand, both
> wall time (mftb) and cpu cycles(PURR) are collected for each call.
> It is interesting to see these two values side by side in the
> output files.
Arnd asked on IRC, so I thought others may be interested in a
sample output file. Remember, there is one file per CPU. All
values are decimal. First number is hcall # (in decimal), second
is number of calls, third is total time (mftb) and fourth is cpu
time (PURR). Note that 'total times' are still in cycles and
can be converted to another format in user space.
[elm3b125]/sys/kernel/debug/hcall_inst >cat cpu0
4 140651 21538230 14456409
8 130064 11855094 9459178
24 14259 1496316 986702
32 1809 354584 315399
84 103 27196 17763
88 1046 108106 109322
100 2596 251229 205154
104 1 1040 1061
108 2208 320491 242708
116 2669 1030894 713272
220 2 532 510
224 130662 47508588184 169383891
228 5 2689902 4622
260 3018 261893 230753
--
Mike
^ permalink raw reply
* [PATCH] clean up pseries hcall interfaces
From: Anton Blanchard @ 2006-07-18 22:01 UTC (permalink / raw)
To: linuxppc-dev; +Cc: paulus
Our pseries hcall interfaces are out of control:
plpar_hcall_norets
plpar_hcall
plpar_hcall_8arg_2ret
plpar_hcall_4out
plpar_hcall_7arg_7ret
plpar_hcall_9arg_9ret
Create 3 interfaces to cover all cases:
plpar_hcall_norets: 7 arguments no returns
plpar_hcall: 6 arguments 4 returns
plpar_hcall9: 9 arguments 9 returns
There are only 2 cases in the kernel that need plpar_hcall9, hopefully
we can keep it that way.
Pass in a buffer to stash return parameters so we avoid the &dummy1,
&dummy2 madness.
Signed-off-by: Anton Blanchard <anton@samba.org>
--
Index: build/arch/powerpc/kernel/lparcfg.c
===================================================================
--- build.orig/arch/powerpc/kernel/lparcfg.c 2006-07-18 04:20:13.000000000 +1000
+++ build/arch/powerpc/kernel/lparcfg.c 2006-07-18 04:24:08.000000000 +1000
@@ -183,8 +183,14 @@ static unsigned int h_get_ppp(unsigned l
unsigned long *resource)
{
unsigned long rc;
- rc = plpar_hcall_4out(H_GET_PPP, 0, 0, 0, 0, entitled, unallocated,
- aggregation, resource);
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_GET_PPP, retbuf);
+
+ *entitled = retbuf[0];
+ *unallocated = retbuf[1];
+ *aggregation = retbuf[2];
+ *resource = retbuf[3];
log_plpar_hcall_return(rc, "H_GET_PPP");
@@ -194,8 +200,12 @@ static unsigned int h_get_ppp(unsigned l
static void h_pic(unsigned long *pool_idle_time, unsigned long *num_procs)
{
unsigned long rc;
- unsigned long dummy;
- rc = plpar_hcall(H_PIC, 0, 0, 0, 0, pool_idle_time, num_procs, &dummy);
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_PIC, retbuf);
+
+ *pool_idle_time = retbuf[0];
+ *num_procs = retbuf[1];
if (rc != H_AUTHORITY)
log_plpar_hcall_return(rc, "H_PIC");
Index: build/arch/powerpc/kernel/rtas.c
===================================================================
--- build.orig/arch/powerpc/kernel/rtas.c 2006-07-18 04:20:13.000000000 +1000
+++ build/arch/powerpc/kernel/rtas.c 2006-07-18 04:24:08.000000000 +1000
@@ -666,15 +666,14 @@ static int rtas_ibm_suspend_me(struct rt
int i;
long state;
long rc;
- unsigned long dummy;
-
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
struct rtas_suspend_me_data data;
/* Make sure the state is valid */
- rc = plpar_hcall(H_VASI_STATE,
- ((u64)args->args[0] << 32) | args->args[1],
- 0, 0, 0,
- &state, &dummy, &dummy);
+ rc = plpar_hcall(H_VASI_STATE, retbuf,
+ ((u64)args->args[0] << 32) | args->args[1]);
+
+ state = retbuf[0];
if (rc) {
printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned %ld\n",rc);
Index: build/arch/powerpc/platforms/pseries/hvCall.S
===================================================================
--- build.orig/arch/powerpc/platforms/pseries/hvCall.S 2006-07-18 04:20:13.000000000 +1000
+++ build/arch/powerpc/platforms/pseries/hvCall.S 2006-07-19 06:59:32.000000000 +1000
@@ -1,7 +1,6 @@
/*
* This file contains the generic code to perform a call to the
* pSeries LPAR hypervisor.
- * NOTE: this file will go away when we move to inline this work.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -16,42 +15,6 @@
.text
-/* long plpar_hcall(unsigned long opcode, R3
- unsigned long arg1, R4
- unsigned long arg2, R5
- unsigned long arg3, R6
- unsigned long arg4, R7
- unsigned long *out1, R8
- unsigned long *out2, R9
- unsigned long *out3); R10
- */
-_GLOBAL(plpar_hcall)
- HMT_MEDIUM
-
- mfcr r0
-
- std r8,STK_PARM(r8)(r1) /* Save out ptrs */
- std r9,STK_PARM(r9)(r1)
- std r10,STK_PARM(r10)(r1)
-
- stw r0,8(r1)
-
- HVSC /* invoke the hypervisor */
-
- lwz r0,8(r1)
-
- ld r8,STK_PARM(r8)(r1) /* Fetch r4-r6 ret args */
- ld r9,STK_PARM(r9)(r1)
- ld r10,STK_PARM(r10)(r1)
- std r4,0(r8)
- std r5,0(r9)
- std r6,0(r10)
-
- mtcrf 0xff,r0
- blr /* return r3 = status */
-
-
-/* Simple interface with no output values (other than status) */
_GLOBAL(plpar_hcall_norets)
HMT_MEDIUM
@@ -64,164 +27,64 @@ _GLOBAL(plpar_hcall_norets)
mtcrf 0xff,r0
blr /* return r3 = status */
-
-/* long plpar_hcall_8arg_2ret(unsigned long opcode, R3
- unsigned long arg1, R4
- unsigned long arg2, R5
- unsigned long arg3, R6
- unsigned long arg4, R7
- unsigned long arg5, R8
- unsigned long arg6, R9
- unsigned long arg7, R10
- unsigned long arg8, 112(R1)
- unsigned long *out1); 120(R1)
- */
-_GLOBAL(plpar_hcall_8arg_2ret)
+_GLOBAL(plpar_hcall)
HMT_MEDIUM
mfcr r0
- ld r11,STK_PARM(r11)(r1) /* put arg8 in R11 */
stw r0,8(r1)
- HVSC /* invoke the hypervisor */
-
- lwz r0,8(r1)
- ld r10,STK_PARM(r12)(r1) /* Fetch r4 ret arg */
- std r4,0(r10)
- mtcrf 0xff,r0
- blr /* return r3 = status */
-
-
-/* long plpar_hcall_4out(unsigned long opcode, R3
- unsigned long arg1, R4
- unsigned long arg2, R5
- unsigned long arg3, R6
- unsigned long arg4, R7
- unsigned long *out1, R8
- unsigned long *out2, R9
- unsigned long *out3, R10
- unsigned long *out4); 112(R1)
- */
-_GLOBAL(plpar_hcall_4out)
- HMT_MEDIUM
-
- mfcr r0
- stw r0,8(r1)
+ std r4,STK_PARM(r4)(r1) /* Save ret buffer */
- std r8,STK_PARM(r8)(r1) /* Save out ptrs */
- std r9,STK_PARM(r9)(r1)
- std r10,STK_PARM(r10)(r1)
+ mr r4,r5
+ mr r5,r6
+ mr r6,r7
+ mr r7,r8
+ mr r8,r9
+ mr r9,r10
HVSC /* invoke the hypervisor */
- lwz r0,8(r1)
-
- ld r8,STK_PARM(r8)(r1) /* Fetch r4-r7 ret args */
- ld r9,STK_PARM(r9)(r1)
- ld r10,STK_PARM(r10)(r1)
- ld r11,STK_PARM(r11)(r1)
- std r4,0(r8)
- std r5,0(r9)
- std r6,0(r10)
- std r7,0(r11)
-
- mtcrf 0xff,r0
- blr /* return r3 = status */
-
-/* plpar_hcall_7arg_7ret(unsigned long opcode, R3
- unsigned long arg1, R4
- unsigned long arg2, R5
- unsigned long arg3, R6
- unsigned long arg4, R7
- unsigned long arg5, R8
- unsigned long arg6, R9
- unsigned long arg7, R10
- unsigned long *out1, 112(R1)
- unsigned long *out2, 110(R1)
- unsigned long *out3, 108(R1)
- unsigned long *out4, 106(R1)
- unsigned long *out5, 104(R1)
- unsigned long *out6, 102(R1)
- unsigned long *out7); 100(R1)
-*/
-_GLOBAL(plpar_hcall_7arg_7ret)
- HMT_MEDIUM
-
- mfcr r0
- stw r0,8(r1)
-
- HVSC /* invoke the hypervisor */
+ ld r12,STK_PARM(r4)(r1)
+ std r4, 0(r12)
+ std r5, 8(r12)
+ std r6, 16(r12)
+ std r7, 24(r12)
lwz r0,8(r1)
-
- ld r11,STK_PARM(r11)(r1) /* Fetch r4 ret arg */
- std r4,0(r11)
- ld r11,STK_PARM(r12)(r1) /* Fetch r5 ret arg */
- std r5,0(r11)
- ld r11,STK_PARM(r13)(r1) /* Fetch r6 ret arg */
- std r6,0(r11)
- ld r11,STK_PARM(r14)(r1) /* Fetch r7 ret arg */
- std r7,0(r11)
- ld r11,STK_PARM(r15)(r1) /* Fetch r8 ret arg */
- std r8,0(r11)
- ld r11,STK_PARM(r16)(r1) /* Fetch r9 ret arg */
- std r9,0(r11)
- ld r11,STK_PARM(r17)(r1) /* Fetch r10 ret arg */
- std r10,0(r11)
-
mtcrf 0xff,r0
blr /* return r3 = status */
-/* plpar_hcall_9arg_9ret(unsigned long opcode, R3
- unsigned long arg1, R4
- unsigned long arg2, R5
- unsigned long arg3, R6
- unsigned long arg4, R7
- unsigned long arg5, R8
- unsigned long arg6, R9
- unsigned long arg7, R10
- unsigned long arg8, 112(R1)
- unsigned long arg9, 110(R1)
- unsigned long *out1, 108(R1)
- unsigned long *out2, 106(R1)
- unsigned long *out3, 104(R1)
- unsigned long *out4, 102(R1)
- unsigned long *out5, 100(R1)
- unsigned long *out6, 98(R1)
- unsigned long *out7); 96(R1)
- unsigned long *out8, 94(R1)
- unsigned long *out9, 92(R1)
-*/
-_GLOBAL(plpar_hcall_9arg_9ret)
+_GLOBAL(plpar_hcall9)
HMT_MEDIUM
mfcr r0
stw r0,8(r1)
- ld r11,STK_PARM(r11)(r1) /* put arg8 in R11 */
- ld r12,STK_PARM(r12)(r1) /* put arg9 in R12 */
+ std r4,STK_PARM(r4)(r1) /* Save ret buffer */
+
+ mr r4,r5
+ mr r5,r6
+ mr r6,r7
+ mr r7,r8
+ mr r8,r9
+ mr r9,r10
+ ld r10,STK_PARM(r11)(r1) /* put arg7 in R10 */
+ ld r11,STK_PARM(r12)(r1) /* put arg8 in R11 */
+ ld r12,STK_PARM(r13)(r1) /* put arg9 in R12 */
HVSC /* invoke the hypervisor */
- ld r0,STK_PARM(r13)(r1) /* Fetch r4 ret arg */
- stdx r4,r0,r0
- ld r0,STK_PARM(r14)(r1) /* Fetch r5 ret arg */
- stdx r5,r0,r0
- ld r0,STK_PARM(r15)(r1) /* Fetch r6 ret arg */
- stdx r6,r0,r0
- ld r0,STK_PARM(r16)(r1) /* Fetch r7 ret arg */
- stdx r7,r0,r0
- ld r0,STK_PARM(r17)(r1) /* Fetch r8 ret arg */
- stdx r8,r0,r0
- ld r0,STK_PARM(r18)(r1) /* Fetch r9 ret arg */
- stdx r9,r0,r0
- ld r0,STK_PARM(r19)(r1) /* Fetch r10 ret arg */
- stdx r10,r0,r0
- ld r0,STK_PARM(r20)(r1) /* Fetch r11 ret arg */
- stdx r11,r0,r0
- ld r0,STK_PARM(r21)(r1) /* Fetch r12 ret arg */
- stdx r12,r0,r0
+ ld r12,STK_PARM(r4)(r1)
+ std r4, 0(r12)
+ std r5, 8(r12)
+ std r6, 16(r12)
+ std r7, 24(r12)
+ std r8, 32(r12)
+ std r9, 40(r12)
+ std r10,48(r12)
+ std r11,56(r12)
+ std r12,64(r12)
lwz r0,8(r1)
mtcrf 0xff,r0
Index: build/arch/powerpc/platforms/pseries/hvconsole.c
===================================================================
--- build.orig/arch/powerpc/platforms/pseries/hvconsole.c 2006-07-18 04:20:13.000000000 +1000
+++ build/arch/powerpc/platforms/pseries/hvconsole.c 2006-07-18 04:24:08.000000000 +1000
@@ -27,6 +27,7 @@
#include <linux/module.h>
#include <asm/hvcall.h>
#include <asm/hvconsole.h>
+#include "plpar_wrappers.h"
/**
* hvc_get_chars - retrieve characters from firmware for denoted vterm adatper
@@ -40,9 +41,9 @@ int hvc_get_chars(uint32_t vtermno, char
{
unsigned long got;
- if (plpar_hcall(H_GET_TERM_CHAR, vtermno, 0, 0, 0, &got,
- (unsigned long *)buf, (unsigned long *)buf+1) == H_SUCCESS)
+ if (plpar_get_term_char(vtermno, &got, buf) == H_SUCCESS)
return got;
+
return 0;
}
Index: build/arch/powerpc/platforms/pseries/lpar.c
===================================================================
--- build.orig/arch/powerpc/platforms/pseries/lpar.c 2006-07-18 04:20:13.000000000 +1000
+++ build/arch/powerpc/platforms/pseries/lpar.c 2006-07-18 04:24:08.000000000 +1000
@@ -48,13 +48,11 @@
#define DBG_LOW(fmt...) do { } while(0)
#endif
-/* in pSeries_hvCall.S */
+/* in hvCall.S */
EXPORT_SYMBOL(plpar_hcall);
-EXPORT_SYMBOL(plpar_hcall_4out);
+EXPORT_SYMBOL(plpar_hcall9);
EXPORT_SYMBOL(plpar_hcall_norets);
-EXPORT_SYMBOL(plpar_hcall_8arg_2ret);
-EXPORT_SYMBOL(plpar_hcall_7arg_7ret);
-EXPORT_SYMBOL(plpar_hcall_9arg_9ret);
+
extern void pSeries_find_serial_port(void);
@@ -277,7 +275,6 @@ long pSeries_lpar_hpte_insert(unsigned l
unsigned long flags;
unsigned long slot;
unsigned long hpte_v, hpte_r;
- unsigned long dummy0, dummy1;
if (!(vflags & HPTE_V_BOLTED))
DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, "
@@ -302,8 +299,7 @@ long pSeries_lpar_hpte_insert(unsigned l
if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
hpte_r &= ~_PAGE_COHERENT;
- lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, hpte_v,
- hpte_r, &slot, &dummy0, &dummy1);
+ lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot);
if (unlikely(lpar_rc == H_PTEG_FULL)) {
if (!(vflags & HPTE_V_BOLTED))
DBG_LOW(" full\n");
Index: build/arch/powerpc/platforms/pseries/plpar_wrappers.h
===================================================================
--- build.orig/arch/powerpc/platforms/pseries/plpar_wrappers.h 2006-07-18 04:20:13.000000000 +1000
+++ build/arch/powerpc/platforms/pseries/plpar_wrappers.h 2006-07-18 04:27:14.000000000 +1000
@@ -5,20 +5,17 @@
static inline long poll_pending(void)
{
- unsigned long dummy;
- return plpar_hcall(H_POLL_PENDING, 0, 0, 0, 0, &dummy, &dummy, &dummy);
+ return plpar_hcall_norets(H_POLL_PENDING);
}
static inline long prod_processor(void)
{
- plpar_hcall_norets(H_PROD);
- return 0;
+ return plpar_hcall_norets(H_PROD);
}
static inline long cede_processor(void)
{
- plpar_hcall_norets(H_CEDE);
- return 0;
+ return plpar_hcall_norets(H_CEDE);
}
static inline long vpa_call(unsigned long flags, unsigned long cpu,
@@ -42,21 +39,47 @@ static inline long register_vpa(unsigned
extern void vpa_init(int cpu);
+static inline long plpar_pte_enter(unsigned long flags,
+ unsigned long hpte_group, unsigned long hpte_v,
+ unsigned long hpte_r, unsigned long *slot)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_ENTER, retbuf, flags, hpte_group, hpte_v, hpte_r);
+
+ *slot = retbuf[0];
+
+ return rc;
+}
+
static inline long plpar_pte_remove(unsigned long flags, unsigned long ptex,
unsigned long avpn, unsigned long *old_pteh_ret,
unsigned long *old_ptel_ret)
{
- unsigned long dummy;
- return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0, old_pteh_ret,
- old_ptel_ret, &dummy);
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_REMOVE, retbuf, flags, ptex, avpn);
+
+ *old_pteh_ret = retbuf[0];
+ *old_ptel_ret = retbuf[1];
+
+ return rc;
}
static inline long plpar_pte_read(unsigned long flags, unsigned long ptex,
unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
{
- unsigned long dummy;
- return plpar_hcall(H_READ, flags, ptex, 0, 0, old_pteh_ret,
- old_ptel_ret, &dummy);
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_READ, retbuf, flags, ptex);
+
+ *old_pteh_ret = retbuf[0];
+ *old_ptel_ret = retbuf[1];
+
+ return rc;
}
static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex,
@@ -68,9 +91,14 @@ static inline long plpar_pte_protect(uns
static inline long plpar_tce_get(unsigned long liobn, unsigned long ioba,
unsigned long *tce_ret)
{
- unsigned long dummy;
- return plpar_hcall(H_GET_TCE, liobn, ioba, 0, 0, tce_ret, &dummy,
- &dummy);
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_GET_TCE, retbuf, liobn, ioba);
+
+ *tce_ret = retbuf[0];
+
+ return rc;
}
static inline long plpar_tce_put(unsigned long liobn, unsigned long ioba,
@@ -94,9 +122,17 @@ static inline long plpar_tce_stuff(unsig
static inline long plpar_get_term_char(unsigned long termno,
unsigned long *len_ret, char *buf_ret)
{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
unsigned long *lbuf = (unsigned long *)buf_ret; /* TODO: alignment? */
- return plpar_hcall(H_GET_TERM_CHAR, termno, 0, 0, 0, len_ret,
- lbuf + 0, lbuf + 1);
+
+ rc = plpar_hcall(H_GET_TERM_CHAR, retbuf, termno);
+
+ *len_ret = retbuf[0];
+ lbuf[0] = retbuf[1];
+ lbuf[1] = retbuf[2];
+
+ return rc;
}
static inline long plpar_put_term_char(unsigned long termno, unsigned long len,
@@ -107,4 +143,31 @@ static inline long plpar_put_term_char(u
lbuf[1]);
}
+static inline long plpar_eoi(unsigned long xirr)
+{
+ return plpar_hcall_norets(H_EOI, xirr);
+}
+
+static inline long plpar_cppr(unsigned long cppr)
+{
+ return plpar_hcall_norets(H_CPPR, cppr);
+}
+
+static inline long plpar_ipi(unsigned long servernum, unsigned long mfrr)
+{
+ return plpar_hcall_norets(H_IPI, servernum, mfrr);
+}
+
+static inline long plpar_xirr(unsigned long *xirr_ret)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_XIRR, retbuf);
+
+ *xirr_ret = retbuf[0];
+
+ return rc;
+}
+
#endif /* _PSERIES_PLPAR_WRAPPERS_H */
Index: build/arch/powerpc/platforms/pseries/xics.c
===================================================================
--- build.orig/arch/powerpc/platforms/pseries/xics.c 2006-07-18 04:21:59.000000000 +1000
+++ build/arch/powerpc/platforms/pseries/xics.c 2006-07-18 04:25:58.000000000 +1000
@@ -34,6 +34,7 @@
#include <asm/i8259.h>
#include "xics.h"
+#include "plpar_wrappers.h"
#define XICS_IPI 2
#define XICS_IRQ_SPURIOUS 0
@@ -110,27 +111,6 @@ static inline void direct_qirr_info(int
/* LPAR low level accessors */
-static inline long plpar_eoi(unsigned long xirr)
-{
- return plpar_hcall_norets(H_EOI, xirr);
-}
-
-static inline long plpar_cppr(unsigned long cppr)
-{
- return plpar_hcall_norets(H_CPPR, cppr);
-}
-
-static inline long plpar_ipi(unsigned long servernum, unsigned long mfrr)
-{
- return plpar_hcall_norets(H_IPI, servernum, mfrr);
-}
-
-static inline long plpar_xirr(unsigned long *xirr_ret)
-{
- unsigned long dummy;
- return plpar_hcall(H_XIRR, 0, 0, 0, 0, xirr_ret, &dummy, &dummy);
-}
-
static inline unsigned int lpar_xirr_info_get(int n_cpu)
{
unsigned long lpar_rc;
Index: build/drivers/net/ibmveth.c
===================================================================
--- build.orig/drivers/net/ibmveth.c 2006-07-18 04:20:13.000000000 +1000
+++ build/drivers/net/ibmveth.c 2006-07-18 04:24:08.000000000 +1000
@@ -702,7 +702,8 @@ static int ibmveth_start_xmit(struct sk_
desc[3].desc,
desc[4].desc,
desc[5].desc,
- correlator);
+ correlator,
+ &correlator);
} while ((lpar_rc == H_BUSY) && (retry_count--));
if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) {
Index: build/drivers/net/ibmveth.h
===================================================================
--- build.orig/drivers/net/ibmveth.h 2006-07-18 04:20:13.000000000 +1000
+++ build/drivers/net/ibmveth.h 2006-07-19 06:55:56.000000000 +1000
@@ -61,8 +61,21 @@
#define h_add_logical_lan_buffer(ua, buf) \
plpar_hcall_norets(H_ADD_LOGICAL_LAN_BUFFER, ua, buf)
-#define h_send_logical_lan(ua, buf1, buf2, buf3, buf4, buf5, buf6, correlator) \
- plpar_hcall_8arg_2ret(H_SEND_LOGICAL_LAN, ua, buf1, buf2, buf3, buf4, buf5, buf6, correlator, &correlator)
+static inline long h_send_logical_lan(unsigned long unit_address,
+ unsigned long desc1, unsigned long desc2, unsigned long desc3,
+ unsigned long desc4, unsigned long desc5, unsigned long desc6,
+ unsigned long corellator_in, unsigned long *corellator_out)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
+
+ rc = plpar_hcall9(H_SEND_LOGICAL_LAN, retbuf, unit_address, desc1,
+ desc2, desc3, desc4, desc5, desc6, corellator_in);
+
+ *corellator_out = retbuf[0];
+
+ return rc;
+}
#define h_multicast_ctrl(ua, cmd, mac) \
plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac)
Index: build/include/asm-powerpc/hvcall.h
===================================================================
--- build.orig/include/asm-powerpc/hvcall.h 2006-07-18 04:20:13.000000000 +1000
+++ build/include/asm-powerpc/hvcall.h 2006-07-19 07:16:14.000000000 +1000
@@ -204,94 +204,39 @@
#ifndef __ASSEMBLY__
-/* plpar_hcall() -- Generic call interface using above opcodes
+/**
+ * plpar_hcall_norets: - Make a pseries hypervisor call with no return arguments
+ * @opcode: The hypervisor call to make.
*
- * The actual call interface is a hypervisor call instruction with
- * the opcode in R3 and input args in R4-R7.
- * Status is returned in R3 with variable output values in R4-R11.
- * Only H_PTE_READ with H_READ_4 uses R6-R11 so we ignore it for now
- * and return only two out args which MUST ALWAYS BE PROVIDED.
- */
-long plpar_hcall(unsigned long opcode,
- unsigned long arg1,
- unsigned long arg2,
- unsigned long arg3,
- unsigned long arg4,
- unsigned long *out1,
- unsigned long *out2,
- unsigned long *out3);
-
-/* Same as plpar_hcall but for those opcodes that return no values
- * other than status. Slightly more efficient.
+ * This call supports up to 7 arguments and only returns the status of
+ * the hcall. Use this version where possible, its slightly faster than
+ * the other plpar_hcalls.
*/
long plpar_hcall_norets(unsigned long opcode, ...);
-/*
- * Special hcall interface for ibmveth support.
- * Takes 8 input parms. Returns a rc and stores the
- * R4 return value in *out1.
- */
-long plpar_hcall_8arg_2ret(unsigned long opcode,
- unsigned long arg1,
- unsigned long arg2,
- unsigned long arg3,
- unsigned long arg4,
- unsigned long arg5,
- unsigned long arg6,
- unsigned long arg7,
- unsigned long arg8,
- unsigned long *out1);
-
-/* plpar_hcall_4out()
+/**
+ * plpar_hcall: - Make a pseries hypervisor call
+ * @opcode: The hypervisor call to make.
+ * @retbuf: Buffer to store up to 4 return arguments in.
*
- * same as plpar_hcall except with 4 output arguments.
+ * This call supports up to 6 arguments and 4 return arguments. Use
+ * PLPAR_HCALL_BUFSIZE to size the return argument buffer.
*
+ * Used for all but the craziest of phyp interfaces (see plpar_hcall9)
*/
-long plpar_hcall_4out(unsigned long opcode,
- unsigned long arg1,
- unsigned long arg2,
- unsigned long arg3,
- unsigned long arg4,
- unsigned long *out1,
- unsigned long *out2,
- unsigned long *out3,
- unsigned long *out4);
+#define PLPAR_HCALL_BUFSIZE 4
+long plpar_hcall(unsigned long opcode, unsigned long *retbuf, ...);
-long plpar_hcall_7arg_7ret(unsigned long opcode,
- unsigned long arg1,
- unsigned long arg2,
- unsigned long arg3,
- unsigned long arg4,
- unsigned long arg5,
- unsigned long arg6,
- unsigned long arg7,
- unsigned long *out1,
- unsigned long *out2,
- unsigned long *out3,
- unsigned long *out4,
- unsigned long *out5,
- unsigned long *out6,
- unsigned long *out7);
-
-long plpar_hcall_9arg_9ret(unsigned long opcode,
- unsigned long arg1,
- unsigned long arg2,
- unsigned long arg3,
- unsigned long arg4,
- unsigned long arg5,
- unsigned long arg6,
- unsigned long arg7,
- unsigned long arg8,
- unsigned long arg9,
- unsigned long *out1,
- unsigned long *out2,
- unsigned long *out3,
- unsigned long *out4,
- unsigned long *out5,
- unsigned long *out6,
- unsigned long *out7,
- unsigned long *out8,
- unsigned long *out9);
+/**
+ * plpar_hcall9: - Make a pseries hypervisor call with up to 9 return arguments
+ * @opcode: The hypervisor call to make.
+ * @retbuf: Buffer to store up to 9 return arguments in.
+ *
+ * This call supports up to 9 arguments and 9 return arguments. Use
+ * PLPAR_HCALL9_BUFSIZE to size the return argument buffer.
+ */
+#define PLPAR_HCALL9_BUFSIZE 9
+long plpar_hcall9(unsigned long opcode, unsigned long *retbuf, ...);
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
^ permalink raw reply
* Re: [PATCH 2/3] powerpc: Instrument Hypervisor Calls: add wrappers
From: Olof Johansson @ 2006-07-18 22:34 UTC (permalink / raw)
To: Mike Kravetz; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <20060718204946.GC6104@w-mikek2.ibm.com>
On Tue, Jul 18, 2006 at 01:49:46PM -0700, Mike Kravetz wrote:
> Add wrappers which perform the actual hypervisor call instrumentation.
> --
> Signed-off-by: Mike Kravetz <kravetz@us.ibm.com>
NACK.
As I said before, SPRN_PURR doesn't exist on all architecture versions
that supports hypervisor mode. Try booting on a JS20/21 or a POWER4
machine in LPAR mode and you'll see. (Unfortunately I don't have access
to any such hardware myself, so I can't send you oops output to show it).
-Olof
> diff -Naupr linux-2.6.17.6/arch/powerpc/Kconfig.debug linux-2.6.17.6.work/arch/powerpc/Kconfig.debug
> --- linux-2.6.17.6/arch/powerpc/Kconfig.debug 2006-07-15 19:00:43.000000000 +0000
> +++ linux-2.6.17.6.work/arch/powerpc/Kconfig.debug 2006-07-18 19:56:20.000000000 +0000
> @@ -18,6 +18,20 @@ config DEBUG_STACK_USAGE
>
> This option will slow down process creation somewhat.
>
> +config HCALL_STATS
> + bool "Hypervisor call instrumentation"
> + depends on PPC_PSERIES && DEBUG_FS
> + help
> + Adds code to keep track of the number of hypervisor calls made and
> + the amount of time spent in hypervisor calls: both wall time (based
> + on time base) and cpu time (based on PURR). A directory named
> + hcall_inst is added at the root of the debugfs filesystem. Within
> + the hcall_inst directory are files that contain CPU specific call
> + statistics.
> +
> + This option will add a small amount of overhead to all hypervisor
> + calls.
> +
> config DEBUGGER
> bool "Enable debugger hooks"
> depends on DEBUG_KERNEL
> diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/Makefile linux-2.6.17.6.work/arch/powerpc/platforms/pseries/Makefile
> --- linux-2.6.17.6/arch/powerpc/platforms/pseries/Makefile 2006-07-15 19:00:43.000000000 +0000
> +++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/Makefile 2006-07-18 19:56:20.000000000 +0000
> @@ -9,3 +9,4 @@ obj-$(CONFIG_EEH) += eeh.o eeh_cache.o e
>
> obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
> obj-$(CONFIG_HVCS) += hvcserver.o
> +obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o
> diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall.S linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall.S
> --- linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall.S 2006-07-15 19:00:43.000000000 +0000
> +++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall.S 2006-07-18 19:56:20.000000000 +0000
> @@ -11,7 +11,35 @@
> #include <asm/hvcall.h>
> #include <asm/processor.h>
> #include <asm/ppc_asm.h>
> -
> +
> +/*
> + * If hcall statistics are desired, all routines are wrapped with code
> + * that does the statistic gathering.
> + */
> +#ifndef CONFIG_HCALL_STATS
> +#define PLPAR_HCALL plpar_hcall
> +#define PLPAR_HCALL_NORETS plpar_hcall_norets
> +#define PLPAR_HCALL_8ARG_2RET plpar_hcall_8arg_2ret
> +#define PLPAR_HCALL_4OUT plpar_hcall_4out
> +#define PLPAR_HCALL_7ARG_7RET plpar_hcall_7arg_7ret
> +#define PLPAR_HCALL_9ARG_9RET plpar_hcall_9arg_9ret
> +#else
> +#define PLPAR_HCALL plpar_hcall_base
> +#define PLPAR_HCALL_NORETS plpar_hcall_norets_base
> +#define PLPAR_HCALL_8ARG_2RET plpar_hcall_8arg_2ret_base
> +#define PLPAR_HCALL_4OUT plpar_hcall_4out_base
> +#define PLPAR_HCALL_7ARG_7RET plpar_hcall_7arg_7ret_base
> +#define PLPAR_HCALL_9ARG_9RET plpar_hcall_9arg_9ret_base
> +
> +/*
> + * A special 'indirect' call to a C based wrapper if statistics are desired.
> + * See plpar_hcall_norets_C function header for more details.
> + */
> +_GLOBAL(plpar_hcall_norets)
> + b plpar_hcall_norets_C
> +
> +#endif
> +
> #define STK_PARM(i) (48 + ((i)-3)*8)
>
> .text
> @@ -25,7 +53,7 @@
> unsigned long *out2, R9
> unsigned long *out3); R10
> */
> -_GLOBAL(plpar_hcall)
> +_GLOBAL(PLPAR_HCALL)
> HMT_MEDIUM
>
> mfcr r0
> @@ -52,7 +80,7 @@ _GLOBAL(plpar_hcall)
>
>
> /* Simple interface with no output values (other than status) */
> -_GLOBAL(plpar_hcall_norets)
> +_GLOBAL(PLPAR_HCALL_NORETS)
> HMT_MEDIUM
>
> mfcr r0
> @@ -76,7 +104,7 @@ _GLOBAL(plpar_hcall_norets)
> unsigned long arg8, 112(R1)
> unsigned long *out1); 120(R1)
> */
> -_GLOBAL(plpar_hcall_8arg_2ret)
> +_GLOBAL(PLPAR_HCALL_8ARG_2RET)
> HMT_MEDIUM
>
> mfcr r0
> @@ -102,7 +130,7 @@ _GLOBAL(plpar_hcall_8arg_2ret)
> unsigned long *out3, R10
> unsigned long *out4); 112(R1)
> */
> -_GLOBAL(plpar_hcall_4out)
> +_GLOBAL(PLPAR_HCALL_4OUT)
> HMT_MEDIUM
>
> mfcr r0
> @@ -144,7 +172,7 @@ _GLOBAL(plpar_hcall_4out)
> unsigned long *out6, 102(R1)
> unsigned long *out7); 100(R1)
> */
> -_GLOBAL(plpar_hcall_7arg_7ret)
> +_GLOBAL(PLPAR_HCALL_7ARG_7RET)
> HMT_MEDIUM
>
> mfcr r0
> @@ -193,7 +221,7 @@ _GLOBAL(plpar_hcall_7arg_7ret)
> unsigned long *out8, 94(R1)
> unsigned long *out9, 92(R1)
> */
> -_GLOBAL(plpar_hcall_9arg_9ret)
> +_GLOBAL(PLPAR_HCALL_9ARG_9RET)
> HMT_MEDIUM
>
> mfcr r0
> diff -Naupr linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall_inst.c linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall_inst.c
> --- linux-2.6.17.6/arch/powerpc/platforms/pseries/hvCall_inst.c 1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.17.6.work/arch/powerpc/platforms/pseries/hvCall_inst.c 2006-07-18 19:57:44.000000000 +0000
> @@ -0,0 +1,216 @@
> +/*
> + * Copyright (C) 2006 Mike Kravetz IBM Corporation
> + *
> + * Hypervisor Call Instrumentation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/percpu.h>
> +#include <linux/debugfs.h>
> +#include <linux/seq_file.h>
> +#include <linux/cpumask.h>
> +#include <asm/hvcall.h>
> +#include <asm/firmware.h>
> +
> +DEFINE_PER_CPU(struct hcall_stats[MAX_HCALL_OPCODES+1], hcall_stats);
> +
> +/*
> + * Common update of the per-CPU/per-hcall statistics
> + */
> +static inline void update_stats(unsigned long opcode,
> + unsigned long t_tb_before,
> + unsigned long t_cpu_before)
> +{
> + unsigned long op_index = opcode >> 2;
> + struct hcall_stats *hs = &__get_cpu_var(hcall_stats[op_index]);
> +
> + hs->tb_total += (mftb() - t_tb_before);
> + hs->cpu_total += (mfspr(SPRN_PURR) - t_cpu_before);
> + hs->num_calls++;
> +}
> +
> +/*
> + * plpar_hcall wrapper
> + */
> +long plpar_hcall(unsigned long opcode,
> + unsigned long arg1,
> + unsigned long arg2,
> + unsigned long arg3,
> + unsigned long arg4,
> + unsigned long *out1,
> + unsigned long *out2,
> + unsigned long *out3)
> +{
> + long rc;
> + unsigned long t_tb_before, t_cpu_before;
> +
> + t_tb_before = mftb();
> + t_cpu_before = mfspr(SPRN_PURR);
> + rc = plpar_hcall_base(opcode, arg1, arg2, arg3, arg4, out1, out2, out3);
> +
> + update_stats(opcode, t_tb_before, t_cpu_before);
> + return rc;
> +}
> +
> +/*
> + * A C based wrapper for plpar_hcall_norets
> + * The wrapper for plpar_hcall_norets is a special case because the function
> + * takes a variable number of arguments. It is almost impossible to write a
> + * wrapper for a function that takes a variable number of arguments in C.
> + * Therefore, there is an assembly routine in hvCall.S that simply branches
> + * to this C wrapper. This 'indirection' takes care of the variable arguments
> + * issue. This C wrapper has a fixed maximum number of arguments.
> + */
> +long plpar_hcall_norets_C(unsigned long opcode,
> + unsigned long arg1,
> + unsigned long arg2,
> + unsigned long arg3,
> + unsigned long arg4,
> + unsigned long arg5,
> + unsigned long arg6)
> +{
> + long rc;
> + unsigned long t_tb_before, t_cpu_before;
> +
> + t_tb_before = mftb();
> + t_cpu_before = mfspr(SPRN_PURR);
> + rc = plpar_hcall_norets_base(opcode, arg1, arg2, arg3, arg4, arg5,
> + arg6);
> +
> + update_stats(opcode, t_tb_before, t_cpu_before);
> + return rc;
> +}
> +
> +/*
> + * plpar_hcall_8arg_2ret wrapper
> + */
> +long plpar_hcall_8arg_2ret(unsigned long opcode,
> + unsigned long arg1,
> + unsigned long arg2,
> + unsigned long arg3,
> + unsigned long arg4,
> + unsigned long arg5,
> + unsigned long arg6,
> + unsigned long arg7,
> + unsigned long arg8,
> + unsigned long *out1)
> +{
> + long rc;
> + unsigned long t_tb_before, t_cpu_before;
> +
> + t_tb_before = mftb();
> + t_cpu_before = mfspr(SPRN_PURR);
> + rc = plpar_hcall_8arg_2ret_base(opcode, arg1, arg2, arg3, arg4, arg5,
> + arg6, arg7, arg8, out1);
> +
> + update_stats(opcode, t_tb_before, t_cpu_before);
> + return rc;
> +}
> +
> +/*
> + * plpar_hcall_4out wrapper
> + */
> +long plpar_hcall_4out(unsigned long opcode,
> + unsigned long arg1,
> + unsigned long arg2,
> + unsigned long arg3,
> + unsigned long arg4,
> + unsigned long *out1,
> + unsigned long *out2,
> + unsigned long *out3,
> + unsigned long *out4)
> +{
> + long rc;
> + unsigned long t_tb_before, t_cpu_before;
> +
> + t_tb_before = mftb();
> + t_cpu_before = mfspr(SPRN_PURR);
> + rc = plpar_hcall_4out_base(opcode, arg1, arg2, arg3, arg4, out1,
> + out2, out3, out4);
> +
> + update_stats(opcode, t_tb_before, t_cpu_before);
> + return rc;
> +}
> +
> +/*
> + * plpar_hcall_7arg_7ret wrapper
> + */
> +long plpar_hcall_7arg_7ret(unsigned long opcode,
> + unsigned long arg1,
> + unsigned long arg2,
> + unsigned long arg3,
> + unsigned long arg4,
> + unsigned long arg5,
> + unsigned long arg6,
> + unsigned long arg7,
> + unsigned long *out1,
> + unsigned long *out2,
> + unsigned long *out3,
> + unsigned long *out4,
> + unsigned long *out5,
> + unsigned long *out6,
> + unsigned long *out7)
> +{
> + long rc;
> + unsigned long t_tb_before, t_cpu_before;
> +
> + t_tb_before = mftb();
> + t_cpu_before = mfspr(SPRN_PURR);
> + rc = plpar_hcall_7arg_7ret_base(opcode, arg1, arg2, arg3, arg4, arg5,
> + arg6, arg7, out1, out2, out3, out4,
> + out5, out6, out7);
> +
> + update_stats(opcode, t_tb_before, t_cpu_before);
> + return rc;
> +}
> +
> +/*
> + * plpar_hcall_9arg_9ret wrapper
> + */
> +long plpar_hcall_9arg_9ret(unsigned long opcode,
> + unsigned long arg1,
> + unsigned long arg2,
> + unsigned long arg3,
> + unsigned long arg4,
> + unsigned long arg5,
> + unsigned long arg6,
> + unsigned long arg7,
> + unsigned long arg8,
> + unsigned long arg9,
> + unsigned long *out1,
> + unsigned long *out2,
> + unsigned long *out3,
> + unsigned long *out4,
> + unsigned long *out5,
> + unsigned long *out6,
> + unsigned long *out7,
> + unsigned long *out8,
> + unsigned long *out9)
> +{
> + long rc;
> + unsigned long t_tb_before, t_cpu_before;
> +
> + t_tb_before = mftb();
> + t_cpu_before = mfspr(SPRN_PURR);
> + rc = plpar_hcall_9arg_9ret_base(opcode, arg1, arg2, arg3, arg4, arg5,
> + arg6, arg7, arg8, arg9, out1, out2,
> + out3, out4, out5, out6, out7, out8,
> + out9);
> +
> + update_stats(opcode, t_tb_before, t_cpu_before);
> + return rc;
> +}
> diff -Naupr linux-2.6.17.6/include/asm-powerpc/hvcall.h linux-2.6.17.6.work/include/asm-powerpc/hvcall.h
> --- linux-2.6.17.6/include/asm-powerpc/hvcall.h 2006-07-18 19:35:00.000000000 +0000
> +++ linux-2.6.17.6.work/include/asm-powerpc/hvcall.h 2006-07-18 19:56:20.000000000 +0000
> @@ -292,6 +292,87 @@ long plpar_hcall_9arg_9ret(unsigned long
> unsigned long *out8,
> unsigned long *out9);
>
> +
> +/* For hcall instrumentation. One structure per-hcall, per-CPU */
> +struct hcall_stats {
> + unsigned long num_calls; /* number of calls (on this CPU) */
> + unsigned long tb_total; /* total wall time (mftb) of calls. */
> + unsigned long cpu_total; /* total cpu time (PURR) of calls. */
> +};
> +
> +/* If Hypervisor call instrumentation is enabled, the assembly routine
> + * names are changed from 'plpar_hcall*' to 'plpar_hcall*_base' and
> + * 'plpar_hcall*' routines become instrumented wrappers. The following
> + * are declarations for the renamed 'plpar_hcall*_base' routines.
> + */
> +long plpar_hcall_base (unsigned long opcode,
> + unsigned long arg1,
> + unsigned long arg2,
> + unsigned long arg3,
> + unsigned long arg4,
> + unsigned long *out1,
> + unsigned long *out2,
> + unsigned long *out3);
> +
> +long plpar_hcall_norets_base(unsigned long opcode, ...);
> +
> +long plpar_hcall_8arg_2ret_base(unsigned long opcode,
> + unsigned long arg1,
> + unsigned long arg2,
> + unsigned long arg3,
> + unsigned long arg4,
> + unsigned long arg5,
> + unsigned long arg6,
> + unsigned long arg7,
> + unsigned long arg8,
> + unsigned long *out1);
> +
> +long plpar_hcall_4out_base(unsigned long opcode,
> + unsigned long arg1,
> + unsigned long arg2,
> + unsigned long arg3,
> + unsigned long arg4,
> + unsigned long *out1,
> + unsigned long *out2,
> + unsigned long *out3,
> + unsigned long *out4);
> +
> +long plpar_hcall_7arg_7ret_base(unsigned long opcode,
> + unsigned long arg1,
> + unsigned long arg2,
> + unsigned long arg3,
> + unsigned long arg4,
> + unsigned long arg5,
> + unsigned long arg6,
> + unsigned long arg7,
> + unsigned long *out1,
> + unsigned long *out2,
> + unsigned long *out3,
> + unsigned long *out4,
> + unsigned long *out5,
> + unsigned long *out6,
> + unsigned long *out7);
> +
> +long plpar_hcall_9arg_9ret_base(unsigned long opcode,
> + unsigned long arg1,
> + unsigned long arg2,
> + unsigned long arg3,
> + unsigned long arg4,
> + unsigned long arg5,
> + unsigned long arg6,
> + unsigned long arg7,
> + unsigned long arg8,
> + unsigned long arg9,
> + unsigned long *out1,
> + unsigned long *out2,
> + unsigned long *out3,
> + unsigned long *out4,
> + unsigned long *out5,
> + unsigned long *out6,
> + unsigned long *out7,
> + unsigned long *out8,
> + unsigned long *out9);
> +
> #endif /* __ASSEMBLY__ */
> #endif /* __KERNEL__ */
> #endif /* _ASM_POWERPC_HVCALL_H */
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [PATCH 0/3] powerpc: Instrument Hypervisor Calls
From: Olof Johansson @ 2006-07-18 22:38 UTC (permalink / raw)
To: Mike Kravetz; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <20060718212913.GB3091@w-mikek2.ibm.com>
On Tue, Jul 18, 2006 at 02:29:13PM -0700, Mike Kravetz wrote:
> 88 1046 108106 109322
[...]
> 104 1 1040 1061
Heh. Shouldn't PURR/TB be <= 1 at all times? :-) I bet this is because
they're not sampled at exactly the same time, etc.
Maybe recoding it to assembly so you can do mftb and mfspr right after
each other, and do the arithmetics/stores later could help. Inline asm
might be sufficient.
-Olof
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox