LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* 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(&notif->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(&notif->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


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox