* questions about mpc82xx_ads and porting to other, similar, platform
From: Alexandros Kostopoulos @ 2007-07-13 8:51 UTC (permalink / raw)
To: linuxppc-dev
Hello all,
I am trying to port kernel 2.6.22.1 to my own platform, which incorporat=
es =
an mpc8275 chip. I'm using platform code for mpc82xx_ads as a template (=
is =
this right in the first place?). I have a couple of questions:
1. mpc82xx_ads.c uses init_scc_ioports function to initialize the scc =
uarts. However, this function is only used by the code in
arch/powerpc/sysdev/fsl_soc.c, and spefically in fs_enet_of_init(), whic=
h =
is used to initialize the ethernet driver and not the cpm_uart driver.
On the other hand, cpm_uart_of_init() function seems to be the one that =
=
initializes the uarts in cpm, and actually makes use of the device-id, =
model, rx-clock and tx-clock properties of the scc nodes in OF tree. So,=
=
AFAICT, init_scc_ioports should not be there, since it won't be actually=
=
called at all (although I have not actually tested this - I haven't yet =
=
managed to boot the kernel). Instead, cpm_uart_of_init should take care =
of =
everything, except for the pport initialization, which is done in u-boot=
=
anyway (at least in my case). Any thoughts on this?
2. I have also some questions regarding the device tree. Why are there t=
wo =
nodes regarding the interrupt controller in there? and in the top level =
=
node, what does this property means: reg =3D <f8200000 f8200004>; ?
Finally, in the memory node, the reg property defines a second mem regio=
n, =
(f4500000 f4500020). What is this? maybe a special memory mapped =
peripheral of this board? If I have a board with many mem configurations=
=
(e.g. it uses a DIMM SDRAM what can be changed), what value should I pla=
ce =
in the mem node? I have to change dts every time I insert a new DIMM?
any help would be greatly appreciated,
thank you in advance
Alex
^ permalink raw reply
* Re: Tickless Hz/hrtimers/etc. on PowerPC
From: Domen Puncer @ 2007-07-13 8:49 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: linuxppc-dev
In-Reply-To: <4696369A.2010200@ru.mvista.com>
On 12/07/07 18:11 +0400, Sergei Shtylyov wrote:
> Hello.
>
> Domen Puncer wrote:
>
> >>Does anyone have the definitive patchset to enable the tickless hz,
> >>some kind of hrtimer and the other related improvements in the
> >>PowerPC tree?
>
> >I use attached patches for tickless.
> >Order in which they're applied:
>
> >PowerPC_GENERIC_CLOCKEVENTS.patch
>
> That's my patch which used to have both description and signoff that I'm
> not seeing in the attached version...
Err, yes, sorry, I don't remember anymore where I picked them,
but I'm pretty sure I didn't go delete description and signoff
by hand.
>
> >PowerPC_GENERIC_TIME.linux-2.6.18-rc6_timeofday-arch-ppc_C6.patch
>
> This one should come first of all, I'd say...
> Note that it breaks TOD vsyscalls, so you need my patch that removes
> support for those for the time being (i.e. until Tony hopefully fixes this
> :-). Also, there was a patch implementing read_persistent_clock() and
> getting rid of the code setting xtime in time_init(). Attaching them
> both...
>
> >PowerPC_enable_HRT_and_dynticks_support.patch
>
> Again looks like my patch with description/signoff missing for whatever
> reason...
>
> >PowerPC_no_hz_fix.patch
>
> This has nothing to do with CONFIG_NO_HZ per se -- it fixes the
> compilation error introduced by John's patch.
>
> >tickless-enable.patch
>
> That one doesn't look quite right...
That's because I made it ;-)
It did the trick of enabling tickless though.
Domen
^ permalink raw reply
* Re: Tickless Hz/hrtimers/etc. on PowerPC
From: Benjamin Herrenschmidt @ 2007-07-13 8:34 UTC (permalink / raw)
To: Matt Sealey; +Cc: ppc-dev, Michael Neuling
In-Reply-To: <46968960.6090402@genesi-usa.com>
On Thu, 2007-07-12 at 21:04 +0100, Matt Sealey wrote:
> We already have some ~20 for Efika support on top of 2.6.22 including
> minor bugfixes and stuff, and the Gentoo genpatches stuff. I really
> want
> to get a good start on CFS, hrtimers, dynticks and so on though and
> see
> if we can push it to users and get out some decent testing and bug
> reports. I think it will help everyone if it is not just a feature
> which
> hits mainline after 6 months through supposed maturity (when a lack of
> bug reports may well also be down to lack of interest).
Why haven't you submited those patches ? The merge window for 2.6.23 is
open _now_
Ben
^ permalink raw reply
* Re: [PATCH 00/10] IB/ehca: Multiple Event Queues, MR/MW rework, large page MRs, fixes
From: Joachim Fenkes @ 2007-07-13 8:26 UTC (permalink / raw)
To: Roland Dreier
Cc: LKML, LinuxPPC-Dev, Christoph Raisch, OF-General, Stefan Roscher
In-Reply-To: <adawsx55ys3.fsf@cisco.com>
> > [09/10] fixes a lot of checkpatch.pl warnings
>
> Are these warnings from earlier patches in the series, or problems
> that already existed in the code? If they are coming from other
> patches in the series, please just fix the earlier patches before I
> merge them.
Nam did a diff -Nurp empty_dir ehca | checkpatch.pl and fixed all the
existing problems in the code. That's why this is such a big hunk -
we've been doing the pointer-typecast thing wrong for a long time,
for example.
Joachim
^ permalink raw reply
* boottime kernel relocation, what I missed?
From: meerkat @ 2007-07-13 7:17 UTC (permalink / raw)
To: linuxppc-embedded
Good day all,
For the first time I begin working on PPC, and on low level, and right start
from boot sequence, one issue puzzled me.
After bootstrap code (zImage) uncompressed the kernel vmLinux to physical
memory (say from addr 0),
it jumps to the kernel entry point, _start, using physically address.
At this time, the MMU is not yet setup to map the kernel virtual address
(which is statically linked against base address KERNELBASE) to the
physically address.
$ nm vmlinux |grep early_init
c038b8e0 T early_init
_start calls early_init before mmu is on to map the KERNEL_BASE to
physically address
The question is how "bl early_init" can branch to the early_init entry
point, properly, as early_init is still a virtual address?
Thanks
Jim
--
View this message in context: http://www.nabble.com/boottime-kernel-relocation%2C-what-I-missed--tf4072673.html#a11574529
Sent from the linuxppc-embedded mailing list archive at Nabble.com.
^ permalink raw reply
* Re: Weird oopses with 2.6.22-rc7
From: Christian Kujau @ 2007-07-13 6:43 UTC (permalink / raw)
To: Nathan Lynch; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20070712233719.GK17955@localdomain>
On Thu, 12 Jul 2007, Nathan Lynch wrote:
> Have you tried 2.6.22? Linus committed a utimensat-related oops fix
> right before releasing it:
Ah, this seem to have fixed http://lkml.org/lkml/2007/7/8/21 and really
looks promising, I'll try 2.6.22-git2 now.
thanks,
Christian.
--
BOFH excuse #208:
Your mail is being routed through Germany ... and they're censoring us.
^ permalink raw reply
* Re: [PATCH 3/4] pm: Handle HID0_SLEEP in the TLF_NAPPING hack.
From: Paul Mackerras @ 2007-07-13 6:34 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <20070712191301.GB31381@ld0162-tx32.am.freescale.net>
Scott Wood writes:
> The e300 core (and probably most other 6xx chips) can only come out of
> sleep mode with an interrupt. However, interrupts are logically disabled
> by the power management layer.
On powerbooks it's typically a hard reset rather than an interrupt.
Is it possible to use a hard reset on e300-based systems?
Also, if you use an interrupt, presumably the cpu has to do something
to clear the interrupt condition. What would that be?
Paul.
^ permalink raw reply
* Re: TEMAC driver available
From: Grant Likely @ 2007-07-13 5:40 UTC (permalink / raw)
To: David H. Lynch Jr.; +Cc: linuxppc-embedded
In-Reply-To: <4696FB46.3020103@dlasys.net>
On 7/12/07, David H. Lynch Jr. <dhlii@dlasys.net> wrote:
> I have finally been inspired to complete my TEMAC driver to an alpha
> state.
> It nearly required dynamite - I had a client application where the
> Xilinx/MV TEMAC
> just did not work.
>
> Anyway, the sucker is done and I guess I will post it as soon as I
> have leaned it up
> if there is any interest.
Wonderful; good news. I'd love to see it. Please send a patch as
soon as you can.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* can anyone help me to test my ac97 driver
From: silicom @ 2007-07-13 5:22 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 13110 bytes --]
Hi
I have a simple oss ac97 playback driver for xilinx ml403 and linux2.6.17 kernel,but when I test it with a *.wav file with sample rate 44.1k, there is much noisy, and I want to know whether there's problem with my ml403 board or ac97 driver,could anyone be kind to help me test it on your board or point out my problem?
thanks
below is my code "xilinx_ac97_adapter.c"
#include <linux/module.h>
#include <linux/version.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/sound.h>
#include <linux/slab.h>
#include <linux/soundcard.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/smp_lock.h>
#include <linux/sound.h>
#include <linux/ac97_codec.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/signal.h>
//#include <linux/wrapper.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
#include "xparameters.h"
#include "xac97_l.h"
#include "xio.h"
#define XILINX_AC97
#define DRIVER_VERSION "1.00a"
#define AC97_BASEADDR XPAR_OPB_AC97_CONTROLLER_REF_0_BASEADDR
#define AC97_HIGHADDR XPAR_OPB_AC97_CONTROLLER_REF_0_HIGHADDR
/* AC97 codec initialisation. */
static struct ac97_codec *xilinx_ac97_codec = NULL;
static int dev_audio = -1;
#define BUFFER_SIZE 32768
#define XILINX_AC97_PLAYBACK_INTERRUPT 7
struct xilinx_ac97_state {
struct semaphore open_sem; /* Device access */
struct semaphore sem; /* File access */
spinlock_t lock; /* State */
spinlock_t ac97_lock;
struct ac97_codec *ac97;
char *buffer;
int multichannel;
int dsp; /* OSS handle */
int trigger; /* mmap I/O trigger */
int halfFull;
// struct forte_channel play;
// struct forte_channel rec;
};
static struct xilinx_ac97_state *state;
static int halfEmpty;
static DECLARE_WAIT_QUEUE_HEAD(ac97_queue);
static int emptyTime;
static u16 xilinx_ac97_get(struct ac97_codec *dev, u8 reg);
static void xilinx_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
static void xilinx_ac97_codec_wait(struct ac97_codec *dev);
static irqreturn_t xilinx_ac97_interrupt(int irq, void * dev_id, struct pt_regs *regs)
{
disable_irq(XILINX_AC97_PLAYBACK_INTERRUPT);
halfEmpty = 1;
wake_up_interruptible(&ac97_queue);
return IRQ_HANDLED;
}
static u16 xilinx_ac97_get(struct ac97_codec *dev, u8 reg)
{
return XAC97_ReadReg((u32)dev->private_data, reg);
}
static void xilinx_ac97_set(struct ac97_codec *dev, u8 reg, u16 data) {
XAC97_WriteReg((u32)dev->private_data, reg, data);
}
static void xilinx_ac97_codec_wait(struct ac97_codec *dev) {
XAC97_AwaitCodecReady((u32)dev->private_data);
}
/* OSS /dev/mixer file operation methods */
static int xilinx_ac97_open_mixdev(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
if (xilinx_ac97_codec && xilinx_ac97_codec->dev_mixer == minor) {
file->private_data = xilinx_ac97_codec;
return 0;
}
return -ENODEV;
}
static int xilinx_ac97_ioctl_mixdev(struct inode *inode,
struct file *file,
unsigned int cmd, unsigned long arg)
{
struct ac97_codec *codec = (struct ac97_codec *) file->private_data;
return codec->mixer_ioctl(codec, cmd, arg);
}
static /*const */ struct file_operations xilinx_ac97_mixer_fops = {
owner:THIS_MODULE,
llseek:no_llseek,
ioctl:xilinx_ac97_ioctl_mixdev,
open:xilinx_ac97_open_mixdev,
};
static int xilinx_ac97_open(struct inode *inode, struct file *file)
{
u32 baseAddress;
if (!state)
BUG();
if (!xilinx_ac97_codec)
BUG();
baseAddress = (u32)xilinx_ac97_codec->private_data;
if (file->f_flags & O_NONBLOCK) {
if (down_trylock (&state->open_sem)) {
printk ("%s: returning -EAGAIN\n", __FUNCTION__);
return -EAGAIN;
}
}
else {
if (down_interruptible (&state->open_sem)) {
printk ("%s: returning -ERESTARTSYS\n", __FUNCTION__);
return -ERESTARTSYS;
}
}
file->private_data = state;
printk ("%s: dsp opened by %d\n", __FUNCTION__, current->pid);
state->buffer = (char *)kmalloc(BUFFER_SIZE, GFP_KERNEL);
/** Reset AC97 **/ //added by myself
XAC97_WriteReg(baseAddress, AC97_Reset, 0);
XAC97_Delay(1000);
/** Wait for the ready signal **/
XAC97_AwaitCodecReady(baseAddress);
XAC97_WriteReg(baseAddress, AC97_PCM_DAC_Rate0, AC97_PCM_RATE_48000_HZ);
XAC97_WriteReg(baseAddress, AC97_PCM_DAC_Rate1, AC97_PCM_RATE_48000_HZ);
/** Clear FIFOs **/
XAC97_ClearFifos(baseAddress);
XAC97_WriteReg(baseAddress, AC97_GeneralPurpose, 0x0000);
XAC97_WriteReg(baseAddress, AC97_SerialConfig, 0x7000);
/** Enable VRA Mode **/
XAC97_WriteReg(baseAddress, AC97_ExtendedAudioStat, AC97_EXTENDED_AUDIO_CONTROL_VRA);
if (file->f_mode & FMODE_WRITE) {
printk(KERN_INFO "setting volume\n");
/** Play Volume Settings **/
XAC97_WriteReg(baseAddress, AC97_MasterVol, AC97_VOL_MAX);
XAC97_WriteReg(baseAddress, AC97_AuxOutVol, AC97_VOL_MAX);
XAC97_WriteReg(baseAddress, AC97_MasterVolMono, AC97_VOL_MAX);
XAC97_WriteReg(baseAddress, AC97_PCBeepVol, AC97_VOL_MAX);
XAC97_WriteReg(baseAddress, AC97_PCMOutVol, AC97_VOL_MAX);
}
//firstly disable interrupt
disable_irq(XILINX_AC97_PLAYBACK_INTERRUPT);
if(request_irq(XILINX_AC97_PLAYBACK_INTERRUPT,xilinx_ac97_interrupt,SA_INTERRUPT,"ac97",NULL))
{
printk(KERN_ALERT "cannot register interrupt handler\n");
}
return 0;
}
static ssize_t
xilinx_ac97_write (struct file *file, const char *buffer, size_t bytes,
loff_t *ppos)
{
struct xilinx_ac97_state *state;
unsigned int i = 0;// sz = 0;
u32 baseAddress;
char* sound_ptr;
size_t words;
ssize_t ret;
int j;
if (!access_ok (VERIFY_READ, buffer, bytes))
return -EFAULT;
state = (struct xilinx_ac97_state *) file->private_data;
if (!state)
BUG();
if (!xilinx_ac97_codec)
BUG();
if (down_interruptible(&state->sem))
return -ERESTARTSYS;
baseAddress = (u32)xilinx_ac97_codec->private_data;
size_t buffer_size =(size_t)BUFFER_SIZE;
size_t tmp = bytes;
bytes = min(tmp,buffer_size);
if(XAC97_isInFIFOEmpty(baseAddress))
emptyTime++;//there's some time when playback FIFO is empty,I don't know how to fix it
if (copy_from_user(state->buffer, buffer, bytes)) {
ret = -EFAULT;
goto out;
}
words = bytes >> 1;
sound_ptr = (char *)state->buffer;
i = 0;
while(i < words) {
j = *sound_ptr;
sound_ptr++;
j |= (*sound_ptr)<<8;
if(!XAC97_isInFIFOFull(baseAddress))
XAC97_WriteFifo(baseAddress, j);
else
{
halfEmpty = 0;
enable_irq(XILINX_AC97_PLAYBACK_INTERRUPT);
wait_event_interruptible(ac97_queue,halfEmpty != 0);
XAC97_WriteFifo(baseAddress,j);
}
sound_ptr++;
i++;
j = 0;
}
ret = i << 1;
out:
up(&state->sem);
return ret;
}
static ssize_t
xilinx_ac97_read (struct file *file, const char *buffer, size_t bytes,
loff_t *ppos)
{
struct xilinx_ac97_state *state;
unsigned int i = 0;// sz = 0;
u32 baseAddress;
u32* sound_ptr;
size_t words;
if (ppos != &file->f_pos)
return -ESPIPE;
if (!access_ok (VERIFY_WRITE, buffer, bytes))
return -EFAULT;
state = (struct xilinx_ac97_state *) file->private_data;
if (!state)
BUG();
if (!xilinx_ac97_codec)
BUG();
baseAddress = (u32)xilinx_ac97_codec->private_data;
// Check if already opened for read?
// Compute the number of words to transfer.
words = bytes >> 2;
sound_ptr = (u32*)buffer;
i = 0;
while(i < words && !XAC97_isOutFIFOEmpty(baseAddress)) {
*sound_ptr = XAC97_mGetOutFifoData(baseAddress);
sound_ptr++;
i++;
}
// Return the number of bytes transferred.
return i << 2;
}
static int
xilinx_ac97_release (struct inode *inode, struct file *file)
{
u32 baseAddress;
kfree(state->buffer);
baseAddress = (u32)xilinx_ac97_codec->private_data;
XAC97_ClearFifos(baseAddress);
XAC97_SoftReset(baseAddress);
free_irq(XILINX_AC97_PLAYBACK_INTERRUPT,NULL);
up (&state->open_sem);
printk(KERN_ALERT "Empyt time is %d\n",emptyTime);
emptyTime = 0;
return 0;
}
static int
xilinx_ac97_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
int ival=0, rd, wr;//ret, count, rval=0;
struct xilinx_ac97_state *state;
u32 baseAddress = (u32)xilinx_ac97_codec->private_data;
state = (struct xilinx_ac97_state *)file->private_data;
if (file->f_mode & FMODE_WRITE)
wr = 1;
else
wr = 0;
if (file->f_mode & FMODE_READ)
rd = 1;
else
rd = 0;
switch(cmd){
default:break;
}
return -EINVAL;
}
static /*const */ struct file_operations xilinx_ac97_audio_fops = {
owner:THIS_MODULE,
llseek:no_llseek,
read:xilinx_ac97_read,
write:xilinx_ac97_write,
// poll:xilinx_ac97_poll,
ioctl:xilinx_ac97_ioctl,
// mmap:xilinx_ac97_mmap,
open:xilinx_ac97_open,
release:xilinx_ac97_release,
};
MODULE_AUTHOR("Xilinx");
MODULE_DESCRIPTION("Xilinx AC97 driver");
MODULE_LICENSE("GPL");
static int __init xilinx_ac97_init_module(void)
{
struct ac97_codec *codec;
u32 baseAddress;
printk(KERN_INFO "Xilinx AC97 Audio, version "
DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
baseAddress = (u32)ioremap(AC97_BASEADDR,AC97_HIGHADDR-AC97_BASEADDR);
printk(KERN_INFO "XAC97_HardReset\n");
XAC97_HardReset(baseAddress);
if ((codec = ac97_alloc_codec()) == NULL)
return -ENOMEM;
codec->private_data = (void *)baseAddress;
codec->id = 0;
codec->codec_read = xilinx_ac97_get;
codec->codec_write = xilinx_ac97_set;
codec->codec_wait = xilinx_ac97_codec_wait;
if (!ac97_probe_codec(codec)) {
printk(KERN_ERR "Failed to init Xilinx AC97");
kfree(codec);
return -ENODEV; /* it didn't work */
}
XAC97_InitAudio((u32)codec->private_data,0);
if ((codec->dev_mixer = register_sound_mixer(&xilinx_ac97_mixer_fops, -1)) < 0) {
printk(KERN_ERR "xilinx_ac97_audio: couldn't register mixer!\n");
kfree(codec);
return -ENODEV;
}
if ((dev_audio = register_sound_dsp(&xilinx_ac97_audio_fops, -1)) < 0) {
printk(KERN_ERR "xilinx_ac97_audio: couldn't register DSP device!\n");
unregister_sound_mixer(xilinx_ac97_codec->dev_mixer);
kfree(xilinx_ac97_codec);
return -ENODEV;
}
xilinx_ac97_codec = codec;
state = (struct xilinx_ac97_state *) kmalloc(sizeof(struct xilinx_ac97_state), GFP_KERNEL);
init_MUTEX(&state->open_sem);
init_MUTEX(&state->sem);
return 0;
}
static void __exit xilinx_ac97_cleanup_module(void)
{
unregister_sound_mixer(xilinx_ac97_codec->dev_mixer);
ac97_release_codec(xilinx_ac97_codec);
xilinx_ac97_codec = NULL;
unregister_sound_dsp(dev_audio);
dev_audio = -1;
}
module_init(xilinx_ac97_init_module);
module_exit(xilinx_ac97_cleanup_module);
/*
Local Variables:
c-basic-offset: 8
End:
*/
below is the test file "test_oss.c"
#include <fcntl.h>
#include <stdlib.h>
#include <linux/soundcard.h>
#include <sys/ioctl.h>
#define BUFFER_SIZE 1024
static int audio_fd;
void init_audio_device()
{
int fmts;
int init_channels;
int speed;
if ( (audio_fd = open("/dev/dsp", O_WRONLY)) == -1)
{
perror("open error\n");
printf("soundcard open error");
exit(1);
}
printf("successfully init soundcard\n\n");
}
int audio_close(void)
{
if (audio_fd)
{
close(audio_fd);
printf("the device has been closed!\n");
}
return 0;
}
int audio_play(char *buf, int len)
{
int temp;
temp = write(audio_fd, buf, len);
return temp;
}
int main()
{
init_audio_device();
int fd = open("/root/********.wav",O_RDONLY);
int len = 0;
char buffer[BUFFER_SIZE];
int i=0;
char tempt;
while(1)
{
len = read(fd,buffer,sizeof(buffer));
if(len == 0)
{
printf("reach the end\n");
break;
}
audio_play(buffer,len);
}
audio_close();
close(fd);
return 0;
}
in the write process,firstly check whether playback FIFO is full,if not, then send PCM data to FIFO;else sleep until FIFO half-empty interrupt,in the interrupt handler,wake up write process,then go on send data to playback FIFO until full.
[-- Attachment #2: Type: text/html, Size: 23187 bytes --]
^ permalink raw reply
* TEMAC driver available
From: David H. Lynch Jr. @ 2007-07-13 4:10 UTC (permalink / raw)
To: linuxppc-embedded
I have finally been inspired to complete my TEMAC driver to an alpha
state.
It nearly required dynamite - I had a client application where the
Xilinx/MV TEMAC
just did not work.
Anyway, the sucker is done and I guess I will post it as soon as I
have leaned it up
if there is any interest.
A brief description:
Might optionally (as in used to badly) support the LL_TEMAC.
Supports the more common PLB TEMAC ONLY in FIFO configurations.
Autonegotiates.
Is a reasonable approximation to a normal Linux network driver.
i.e. does not require xilinx_comon, or xilinx_edk or .....
Aside from hooks into the Linux build system is entirely
contained
in a single reasonably sized source.
Is extremely loosely based on older xilinx code from their
Webserver
sample application.
For someone that desparately wants to see it immediately you can
download
http://www.picocomputing.com/files/linux/linux-2.6-pico.tar.bz2
but that is a complete 2.6.22-rc4 kernel.org linux source with the
complete
Pico BSP
--
Dave Lynch DLA Systems
Software Development: Embedded Linux
717.627.3770 dhlii@dlasys.net http://www.dlasys.net
fax: 1.253.369.9244 Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.
"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
^ permalink raw reply
* Re: TEMAC MAC address
From: David H. Lynch Jr. @ 2007-07-13 3:57 UTC (permalink / raw)
To: Grant Likely; +Cc: Kevin Holland, Linux PPC Linux PPC
In-Reply-To: <fa686aa40707111311i42ed56bdiff24d2680b4a8297@mail.gmail.com>
Grant Likely wrote:
> On 7/11/07, Kevin Holland <KHollan@daktronics.com> wrote:
>
>> Grant,
>> How do I set the MAC address?
>>
>
> Badly, with an ugly hack. :-)
>
>
>> When my ML410 board boots its Hardware
>> address is set to 0. I looked through the message boards and can't seem
>> to find what Im looking for. Thanks for your help.
>>
>
> I set the mac addr with some Virtex specific code in
> arch/ppc/boot/simple/embed_config.c.
>
> BTW, Please at least CC: the mailing list when asking questions.
>
Pico cards pass the MAC address to linux via the board info struct -
doesn't uboot etc.
have a similar facility ?
Pico registered a block of MAC addresses, uses them as card serial
numbers and passes them via
board info.
--
Dave Lynch DLA Systems
Software Development: Embedded Linux
717.627.3770 dhlii@dlasys.net http://www.dlasys.net
fax: 1.253.369.9244 Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.
"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
^ permalink raw reply
* [PATCH] Update mpc7448hpc2 device tree to be compatible for tsi109 chip
From: Zang Roy-r61911 @ 2007-07-13 3:58 UTC (permalink / raw)
To: Kumar Gala, Paul Mackerras; +Cc: linuxppc-dev list
From: Roy Zang <tie-fei.zang@freescale.com>
Update mpc7448hpc2 device tree to be compatible for tsi109 chip.
Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
---
Based on previous patch
http://ozlabs.org/pipermail/linuxppc-dev/2007-July/038957.html
arch/powerpc/boot/dts/mpc7448hpc2.dts | 15 ++++++++-------
1 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc7448hpc2.dts b/arch/powerpc/boot/dts/mpc7448hpc2.dts
index f141ba2..45143f3 100644
--- a/arch/powerpc/boot/dts/mpc7448hpc2.dts
+++ b/arch/powerpc/boot/dts/mpc7448hpc2.dts
@@ -41,11 +41,12 @@
>;
};
- tsi108@c0000000 {
+ tsi109@c0000000 {
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
device_type = "tsi-bridge";
+ compatible = "tsi109-bridge", "tsi108-bridge";
ranges = <00000000 c0000000 00010000>;
reg = <c0000000 00010000>;
bus-frequency = <0>;
@@ -55,12 +56,12 @@
interrupts = <E 0>;
reg = <7000 400>;
device_type = "i2c";
- compatible = "tsi108-i2c";
+ compatible = "tsi109-i2c", "tsi108-i2c";
};
MDIO: mdio@6000 {
device_type = "mdio";
- compatible = "tsi108-mdio";
+ compatible = "tsi109-mdio", "tsi108-mdio";
reg = <6000 50>;
#address-cells = <1>;
#size-cells = <0>;
@@ -83,7 +84,7 @@
linux,network-index = <0>;
#size-cells = <0>;
device_type = "network";
- compatible = "tsi108-ethernet";
+ compatible = "tsi109-ethernet", "tsi108-ethernet";
reg = <6000 200>;
address = [ 00 06 D2 00 00 01 ];
interrupts = <10 2>;
@@ -97,7 +98,7 @@
#address-cells = <1>;
#size-cells = <0>;
device_type = "network";
- compatible = "tsi108-ethernet";
+ compatible = "tsi109-ethernet", "tsi108-ethernet";
reg = <6400 200>;
address = [ 00 06 D2 00 00 02 ];
interrupts = <11 2>;
@@ -136,7 +137,7 @@
big-endian;
};
pci@1000 {
- compatible = "tsi108-pci";
+ compatible = "tsi109-pci", "tsi108-pci";
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
@@ -190,7 +191,7 @@
};
};
chosen {
- linux,stdout-path = "/tsi108@c0000000/serial@7808";
+ linux,stdout-path = "/tsi109@c0000000/serial@7808";
};
};
--
1.5.1
^ permalink raw reply related
* Re: [PATCH] fix idr_get_new_above id alias bugs
From: Tejun Heo @ 2007-07-13 3:46 UTC (permalink / raw)
To: Andrew Morton
Cc: Kristian Hoegsberg, linux-kernel, openib-general, Stefan Roscher,
linuxppc-dev, raisch, Hoang-Nam Nguyen, jim.houston
In-Reply-To: <20070712143501.2c2cdf1f.akpm@linux-foundation.org>
Hello,
Andrew Morton wrote:
>> Hoang-Nam Nguyen reported a bug in idr_get_new_above()
>> which occurred with a starting id value like 0x3ffffffc.
>> His test module easily reproduced the problem. Thanks.
>>
>> The test revealed the following bugs:
>>
>> 1. Relying on shift operations which have undefined results
>> e.g.: 1 << n where n > word size. On i386 an integer shift
>> only uses the low 5 bits of the shift count.
>>
>> 2. An off by one error which prevented the top most layer
>> of the radix tree from being allocated. This meant that
>> sub_alloc() would allocate an entry in the existing portion
>> of the radix tree which aliased the requested address. When
>> it tried to allocate id 0x40000000, it might use the slot
>> belonging to id 0.
>>
>> 3. There was also a failure in the code which walked back up
>> the tree if an allocation failed. The normal case is to
>> descend the tree checking the starting id value against the
>> bitmap at each level. If the bit is set, we know that the
>> entire sub-tree is full and we can short cut the search.
>> We may still descend to the lowest level and find that the
>> portion of the id space we want is full. In this case we
>> need to walk back up the tree and continue the search.
>> The existing code just returned to the previous level and
>> continued. This resulted in an attempt to allocate an id
>> above 0x3ffffffc using the slot for id 0x3ffffc00 instead of
>> 0x40000000 which it then claimed to have allocated. The same
>> problem occurs with 0x3ff as the requested id value if it
>> is already in use.
The third one sounds like the bug I fixed. With it fixed, I verified
idr works correctly at least in the lower range of allocation by running
it parallelly with simple bitmap allocator but haven't tested higher
range like 0x3ffffffc.
--
tejun
^ permalink raw reply
* Re: [PATCH 0/5] Kconfig cleanup revisited
From: Mark A. Greer @ 2007-07-13 1:39 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, paulus
In-Reply-To: <20070712210156.973038514@arndb.de>
On Thu, Jul 12, 2007 at 11:01:56PM +0200, Arnd Bergmann wrote:
> Since this was brought up by Mark, here is a resend of the
> Kconfig cleanup patches that have not been merged so far,
> with updates for the comments I received.
>
> I stumbled over another bug in the process, and fear I have
> found a can of worms there (not opened yet): There are
> still many files under arch/powerpc that include headers
> from include/asm-ppc/. Most of these includes can simply
> be removed, but some are real bugs, where generic code still
> relies on board-specific macro definitions.
Hi Arnd,
I really like what you've done here, thanks.
The patches don't apply straight up so what other patches do these go
on top of?
Mark
^ permalink raw reply
* Re: [PATCH] [POWERPC] Move generic MPC82xx functions out of ADS-specific
From: Arnd Bergmann @ 2007-07-12 23:59 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: Laurent Pinchart, Vitaly Bordug
In-Reply-To: <200707121704.45373.laurent.pinchart@cse-semaphore.com>
On Thursday 12 July 2007, Laurent Pinchart wrote:
> > Ah, I missed that. =A0I'd just get rid of "Vendor" altogether, and incl=
ude
> > the vendor name in the machine name.
>=20
> Is there any standard/documentation regarding what show_cpuinfo should pr=
int ?=20
> Should it show CPU information only, or board information as well ? What=
=20
> about the memory size, clock settings, ... ? What are the meanings=20
> of "vendor" and "machine" ?
I guess the easiest would be to modify the common show_cpuinfo function
to fall back to just printing the model, if there is no specific function:
=2D-- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -175,6 +175,12 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "platform\t: %s\n", ppc_md.name);
if (ppc_md.show_cpuinfo !=3D NULL)
ppc_md.show_cpuinfo(m);
+ else {
+ struct device_node *root =3D of_find_node_by_path("/");
+ const char *model =3D of_get_property(root, "model", NULL);
+ seq_printf(m, "machine\t\t: %s\n", model);
+ of_node_put(root);
+ }
=20
return 0;
}
With that in place, we can probably get rid of half the platform
specific show_cpuinfo functions.
Arnd <><
^ permalink raw reply
* Re: [PATCH] fix showing xmon help
From: Michael Ellerman @ 2007-07-12 23:53 UTC (permalink / raw)
To: Ishizaki Kou; +Cc: linuxppc-dev, paulus
In-Reply-To: <20070712.165915.-1300535948.kouish@swc.toshiba.co.jp>
[-- Attachment #1: Type: text/plain, Size: 2289 bytes --]
On Thu, 2007-07-12 at 16:59 +0900, Ishizaki Kou wrote:
> In some configuration, xmon help string is larger than xmon output
> buffer. To show whole help string, this patch splits it into 2 parts.
>
> Signed-off-by: Kou Ishizaki <kou.ishizaki@toshiba.co.jp>
Nice catch! I've seen that a few times, but thought it was a flow
control problem on the console.
> Index: linux-powerpc-git/arch/powerpc/xmon/xmon.c
> ===================================================================
> RCS file: /home/public/cvs/linux-powerpc-git/arch/powerpc/xmon/xmon.c,v
> retrieving revision 1.1.1.7
> diff -u -p -r1.1.1.7 xmon.c
> --- linux-powerpc-git/arch/powerpc/xmon/xmon.c 11 Jul 2007 02:15:32 -0000 1.1.1.7
> +++ linux-powerpc-git/arch/powerpc/xmon/xmon.c 11 Jul 2007 10:08:41 -0000
> @@ -182,7 +182,7 @@ extern void xmon_save_regs(struct pt_reg
> || ('A' <= (c) && (c) <= 'Z'))
> #define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
>
> -static char *help_string = "\
> +static char *help_string1 = "\
> Commands:\n\
> b show breakpoints\n\
> bd set data breakpoint\n\
> @@ -210,7 +210,9 @@ Commands:\n\
> md compare two blocks of memory\n\
> ml locate a block of memory\n\
> mz zero a block of memory\n\
> - mi show information about memory allocation\n\
> + mi show information about memory allocation\n"
> +;
> +static char *help_string2 = "\
> p call a procedure\n\
> r print registers\n\
> s single step\n"
> @@ -833,7 +835,8 @@ cmds(struct pt_regs *excp)
> mdelay(2000);
> return cmd;
> case '?':
> - printf(help_string);
> + printf(help_string1);
> + printf(help_string2);
> break;
> case 'b':
> bpt_cmds();
I'm not sure I like the fix though, it's a bit of a kludge :)
We don't actually need to printf() the help string, so what'd be nicer
is to add an xmon_puts() to arch/powerpc/xmon/nonstdio.c which just
calls xmon_write(s, strlen(s)) and use that for printing the help
string.
cheers
--
Michael Ellerman
OzLabs, IBM Australia Development Lab
wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)
We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* [PATCH 2/2] Add support to OProfile for profiling Cell BE SPUs
From: Bob Nelson @ 2007-07-12 23:47 UTC (permalink / raw)
To: Andrew Morton; +Cc: linuxppc, oprofile, Philippe Elie
We would like this patch included in -mm and 2.6.23.
Subject: Add support to OProfile for profiling Cell BE SPUs
From: Maynard Johnson <mpjohn@us.ibm.com>
Bob Nelson <rrnelson@us.ibm.com>
This patch updates the existing arch/powerpc/oprofile/op_model_cell.c
to add in the SPU profiling capabilities. In addition, a 'cell'
subdirectory
was added to arch/powerpc/oprofile to hold Cell-specific SPU profiling
code.
Also incorporated several fixes from other patches. Check pointer
returned from kzalloc. Eliminated unnecessary cast. Better error
handling and cleanup in the related area. 64-bit unsigned long
parameter
was being demoted to 32-bit unsigned int and eventually promoted back to
unsigned long.
Signed-off-by: Carl Love <carll@us.ibm.com>
Signed-off-by: Maynard Johnson <mpjohn@us.ibm.com>
Signed-off-by: Bob Nelson <rrnelson@us.ibm.com>
Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Acked-by: Paul Mackerras <paulus@samba.org>
Index: powerpc.git/arch/powerpc/configs/cell_defconfig
===================================================================
--- powerpc.git.orig/arch/powerpc/configs/cell_defconfig
+++ powerpc.git/arch/powerpc/configs/cell_defconfig
@@ -1455,7 +1455,8 @@ CONFIG_HAS_DMA=y
# Instrumentation Support
#
CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
+CONFIG_OPROFILE=m
+CONFIG_OPROFILE_CELL=y
# CONFIG_KPROBES is not set
#
Index: powerpc.git/arch/powerpc/oprofile/cell/pr_util.h
===================================================================
--- /dev/null
+++ powerpc.git/arch/powerpc/oprofile/cell/pr_util.h
@@ -0,0 +1,90 @@
+ /*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef PR_UTIL_H
+#define PR_UTIL_H
+
+#include <linux/cpumask.h>
+#include <linux/oprofile.h>
+#include <asm/cell-pmu.h>
+#include <asm/spu.h>
+
+#include "../../platforms/cell/cbe_regs.h"
+
+static inline int number_of_online_nodes(void)
+{
+ u32 cpu; u32 tmp;
+ int nodes = 0;
+ for_each_online_cpu(cpu) {
+ tmp = cbe_cpu_to_node(cpu) + 1;
+ if (tmp > nodes)
+ nodes++;
+ }
+ return nodes;
+}
+
+/* Defines used for sync_start */
+#define SKIP_GENERIC_SYNC 0
+#define SYNC_START_ERROR -1
+#define DO_GENERIC_SYNC 1
+
+struct spu_overlay_info
+{
+ unsigned int vma;
+ unsigned int size;
+ unsigned int offset;
+ unsigned int buf;
+};
+
+struct vma_to_fileoffset_map
+{
+ struct vma_to_fileoffset_map *next;
+ unsigned int vma;
+ unsigned int size;
+ unsigned int offset;
+ unsigned int guard_ptr;
+ unsigned int guard_val;
+};
+
+/* The three functions below are for maintaining and accessing
+ * the vma-to-fileoffset map.
+ */
+struct vma_to_fileoffset_map *create_vma_map(const struct spu *spu,
+ u64 objectid);
+unsigned int vma_map_lookup(struct vma_to_fileoffset_map *map,
+ unsigned int vma, const struct spu *aSpu,
+ int *grd_val);
+void vma_map_free(struct vma_to_fileoffset_map *map);
+
+/*
+ * Entry point for SPU profiling.
+ * cycles_reset is the SPU_CYCLES count value specified by the user.
+ */
+int start_spu_profiling(unsigned int cycles_reset);
+
+void stop_spu_profiling(void);
+
+
+/* add the necessary profiling hooks */
+int spu_sync_start(void);
+
+/* remove the hooks */
+int spu_sync_stop(void);
+
+/* Record SPU program counter samples to the oprofile event buffer. */
+void spu_sync_buffer(int spu_num, unsigned int *samples,
+ int num_samples);
+
+void set_profiling_frequency(unsigned int freq_khz, unsigned int
cycles_reset);
+
+#endif /* PR_UTIL_H */
Index: powerpc.git/arch/powerpc/oprofile/cell/spu_profiler.c
===================================================================
--- /dev/null
+++ powerpc.git/arch/powerpc/oprofile/cell/spu_profiler.c
@@ -0,0 +1,223 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Authors: Maynard Johnson <maynardj@us.ibm.com>
+ * Carl Love <carll@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/hrtimer.h>
+#include <linux/smp.h>
+#include <linux/slab.h>
+#include <asm/cell-pmu.h>
+/*#include <linux/time.h>*/
+#include "pr_util.h"
+
+#define TRACE_ARRAY_SIZE 1024
+#define SCALE_SHIFT 14
+
+static u32 *samples;
+
+static int spu_prof_running;
+static unsigned int profiling_interval;
+
+extern int spu_prof_num_nodes;
+
+
+#define NUM_SPU_BITS_TRBUF 16
+#define SPUS_PER_TB_ENTRY 4
+#define SPUS_PER_NODE 8
+
+#define SPU_PC_MASK 0xFFFF
+
+static DEFINE_SPINLOCK(sample_array_lock);
+unsigned long sample_array_lock_flags;
+
+void set_profiling_frequency(unsigned int freq_khz, unsigned int
cycles_reset)
+{
+ unsigned long ns_per_cyc;
+ if (!freq_khz)
+ freq_khz = ppc_proc_freq/1000;
+
+ /* To calculate a timeout in nanoseconds, the basic
+ * formula is ns = cycles_reset * (NSEC_PER_SEC / cpu frequency).
+ * To avoid floating point math, we use the scale math
+ * technique as described in linux/jiffies.h. We use
+ * a scale factor of SCALE_SHIFT, which provides 4 decimal places
+ * of precision. This is close enough for the purpose at hand.
+ *
+ * The value of the timeout should be small enough that the hw
+ * trace buffer will not get more then about 1/3 full for the
+ * maximum user specified (the LFSR value) hw sampling frequency.
+ * This is to ensure the trace buffer will never fill even if the
+ * kernel thread scheduling varies under a heavy system load.
+ */
+
+ ns_per_cyc = (USEC_PER_SEC << SCALE_SHIFT)/freq_khz;
+ profiling_interval = (ns_per_cyc * cycles_reset) >> SCALE_SHIFT;
+
+}
+
+/*
+ * Extract SPU PC from trace buffer entry
+ */
+static void spu_pc_extract(int cpu, int entry)
+{
+ /* the trace buffer is 128 bits */
+ u64 trace_buffer[2];
+ u64 spu_mask;
+ int spu;
+
+ spu_mask = SPU_PC_MASK;
+
+ /* Each SPU PC is 16 bits; hence, four spus in each of
+ * the two 64-bit buffer entries that make up the
+ * 128-bit trace_buffer entry. Process two 64-bit values
+ * simultaneously.
+ * trace[0] SPU PC contents are: 0 1 2 3
+ * trace[1] SPU PC contents are: 4 5 6 7
+ */
+
+ cbe_read_trace_buffer(cpu, trace_buffer);
+
+ for (spu = SPUS_PER_TB_ENTRY-1; spu >= 0; spu--) {
+ /* spu PC trace entry is upper 16 bits of the
+ * 18 bit SPU program counter
+ */
+ samples[spu * TRACE_ARRAY_SIZE + entry]
+ = (spu_mask & trace_buffer[0]) << 2;
+ samples[(spu + SPUS_PER_TB_ENTRY) * TRACE_ARRAY_SIZE + entry]
+ = (spu_mask & trace_buffer[1]) << 2;
+
+ trace_buffer[0] = trace_buffer[0] >> NUM_SPU_BITS_TRBUF;
+ trace_buffer[1] = trace_buffer[1] >> NUM_SPU_BITS_TRBUF;
+ }
+}
+
+static int cell_spu_pc_collection(int cpu)
+{
+ u32 trace_addr;
+ int entry;
+
+ /* process the collected SPU PC for the node */
+
+ entry = 0;
+
+ trace_addr = cbe_read_pm(cpu, trace_address);
+ while (!(trace_addr & CBE_PM_TRACE_BUF_EMPTY)) {
+ /* there is data in the trace buffer to process */
+ spu_pc_extract(cpu, entry);
+
+ entry++;
+
+ if (entry >= TRACE_ARRAY_SIZE)
+ /* spu_samples is full */
+ break;
+
+ trace_addr = cbe_read_pm(cpu, trace_address);
+ }
+
+ return(entry);
+}
+
+
+static enum hrtimer_restart profile_spus(struct hrtimer *timer)
+{
+ ktime_t kt;
+ int cpu, node, k, num_samples, spu_num;
+
+ if (!spu_prof_running)
+ goto stop;
+
+ for_each_online_cpu(cpu) {
+ if (cbe_get_hw_thread_id(cpu))
+ continue;
+
+ node = cbe_cpu_to_node(cpu);
+
+ /* There should only be one kernel thread at a time processing
+ * the samples. In the very unlikely case that the processing
+ * is taking a very long time and multiple kernel threads are
+ * started to process the samples. Make sure only one kernel
+ * thread is working on the samples array at a time. The
+ * sample array must be loaded and then processed for a given
+ * cpu. The sample array is not per cpu.
+ */
+ spin_lock_irqsave(&sample_array_lock,
+ sample_array_lock_flags);
+ num_samples = cell_spu_pc_collection(cpu);
+
+ if (num_samples == 0) {
+ spin_unlock_irqrestore(&sample_array_lock,
+ sample_array_lock_flags);
+ continue;
+ }
+
+ for (k = 0; k < SPUS_PER_NODE; k++) {
+ spu_num = k + (node * SPUS_PER_NODE);
+ spu_sync_buffer(spu_num,
+ samples + (k * TRACE_ARRAY_SIZE),
+ num_samples);
+ }
+
+ spin_unlock_irqrestore(&sample_array_lock,
+ sample_array_lock_flags);
+
+ }
+ smp_wmb();
+
+ kt = ktime_set(0, profiling_interval);
+ if (!spu_prof_running)
+ goto stop;
+ hrtimer_forward(timer, timer->base->get_time(), kt);
+ return HRTIMER_RESTART;
+
+ stop:
+ printk(KERN_INFO "SPU_PROF: spu-prof timer ending\n");
+ return HRTIMER_NORESTART;
+}
+
+static struct hrtimer timer;
+/*
+ * Entry point for SPU profiling.
+ * NOTE: SPU profiling is done system-wide, not per-CPU.
+ *
+ * cycles_reset is the count value specified by the user when
+ * setting up OProfile to count SPU_CYCLES.
+ */
+int start_spu_profiling(unsigned int cycles_reset)
+{
+ ktime_t kt;
+
+ pr_debug("timer resolution: %lu\n", TICK_NSEC);
+ kt = ktime_set(0, profiling_interval);
+ hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ timer.expires = kt;
+ timer.function = profile_spus;
+
+ /* Allocate arrays for collecting SPU PC samples */
+ samples = kzalloc(SPUS_PER_NODE *
+ TRACE_ARRAY_SIZE * sizeof(u32), GFP_KERNEL);
+
+ if (!samples)
+ return -ENOMEM;
+
+ spu_prof_running = 1;
+ hrtimer_start(&timer, kt, HRTIMER_MODE_REL);
+
+ return 0;
+}
+
+void stop_spu_profiling(void)
+{
+ spu_prof_running = 0;
+ hrtimer_cancel(&timer);
+ kfree(samples);
+ pr_debug("SPU_PROF: stop_spu_profiling issued\n");
+}
Index: powerpc.git/arch/powerpc/oprofile/cell/spu_task_sync.c
===================================================================
--- /dev/null
+++ powerpc.git/arch/powerpc/oprofile/cell/spu_task_sync.c
@@ -0,0 +1,465 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* The purpose of this file is to handle SPU event task switching
+ * and to record SPU context information into the OProfile
+ * event buffer.
+ *
+ * Additionally, the spu_sync_buffer function is provided as a helper
+ * for recoding actual SPU program counter samples to the event buffer.
+ */
+#include <linux/dcookies.h>
+#include <linux/kref.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/numa.h>
+#include <linux/oprofile.h>
+#include <linux/spinlock.h>
+#include "pr_util.h"
+
+#define RELEASE_ALL 9999
+
+static DEFINE_SPINLOCK(buffer_lock);
+static DEFINE_SPINLOCK(cache_lock);
+static int num_spu_nodes;
+int spu_prof_num_nodes;
+int last_guard_val[MAX_NUMNODES * 8];
+
+/* Container for caching information about an active SPU task. */
+struct cached_info {
+ struct vma_to_fileoffset_map *map;
+ struct spu *the_spu; /* needed to access pointer to local_store */
+ struct kref cache_ref;
+};
+
+static struct cached_info *spu_info[MAX_NUMNODES * 8];
+
+static void destroy_cached_info(struct kref *kref)
+{
+ struct cached_info *info;
+
+ info = container_of(kref, struct cached_info, cache_ref);
+ vma_map_free(info->map);
+ kfree(info);
+ module_put(THIS_MODULE);
+}
+
+/* Return the cached_info for the passed SPU number.
+ * ATTENTION: Callers are responsible for obtaining the
+ * cache_lock if needed prior to invoking this function.
+ */
+static struct cached_info *get_cached_info(struct spu *the_spu, int
spu_num)
+{
+ struct kref *ref;
+ struct cached_info *ret_info;
+
+ if (spu_num >= num_spu_nodes) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: Invalid index %d into spu info cache\n",
+ __FUNCTION__, __LINE__, spu_num);
+ ret_info = NULL;
+ goto out;
+ }
+ if (!spu_info[spu_num] && the_spu) {
+ ref = spu_get_profile_private_kref(the_spu->ctx);
+ if (ref) {
+ spu_info[spu_num] = container_of(ref, struct cached_info,
cache_ref);
+ kref_get(&spu_info[spu_num]->cache_ref);
+ }
+ }
+
+ ret_info = spu_info[spu_num];
+ out:
+ return ret_info;
+}
+
+
+/* Looks for cached info for the passed spu. If not found, the
+ * cached info is created for the passed spu.
+ * Returns 0 for success; otherwise, -1 for error.
+ */
+static int
+prepare_cached_spu_info(struct spu *spu, unsigned long objectId)
+{
+ unsigned long flags;
+ struct vma_to_fileoffset_map *new_map;
+ int retval = 0;
+ struct cached_info *info;
+
+ /* We won't bother getting cache_lock here since
+ * don't do anything with the cached_info that's returned.
+ */
+ info = get_cached_info(spu, spu->number);
+
+ if (info) {
+ pr_debug("Found cached SPU info.\n");
+ goto out;
+ }
+
+ /* Create cached_info and set spu_info[spu->number] to point to it.
+ * spu->number is a system-wide value, not a per-node value.
+ */
+ info = kzalloc(sizeof(struct cached_info), GFP_KERNEL);
+ if (!info) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: create vma_map failed\n",
+ __FUNCTION__, __LINE__);
+ retval = -ENOMEM;
+ goto err_alloc;
+ }
+ new_map = create_vma_map(spu, objectId);
+ if (!new_map) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: create vma_map failed\n",
+ __FUNCTION__, __LINE__);
+ retval = -ENOMEM;
+ goto err_alloc;
+ }
+
+ pr_debug("Created vma_map\n");
+ info->map = new_map;
+ info->the_spu = spu;
+ kref_init(&info->cache_ref);
+ spin_lock_irqsave(&cache_lock, flags);
+ spu_info[spu->number] = info;
+ /* Increment count before passing off ref to SPUFS. */
+ kref_get(&info->cache_ref);
+
+ /* We increment the module refcount here since SPUFS is
+ * responsible for the final destruction of the cached_info,
+ * and it must be able to access the destroy_cached_info()
+ * function defined in the OProfile module. We decrement
+ * the module refcount in destroy_cached_info.
+ */
+ try_module_get(THIS_MODULE);
+ spu_set_profile_private_kref(spu->ctx, &info->cache_ref,
+ destroy_cached_info);
+ spin_unlock_irqrestore(&cache_lock, flags);
+ goto out;
+
+err_alloc:
+ kfree(info);
+out:
+ return retval;
+}
+
+/*
+ * NOTE: The caller is responsible for locking the
+ * cache_lock prior to calling this function.
+ */
+static int release_cached_info(int spu_index)
+{
+ int index, end;
+
+ if (spu_index == RELEASE_ALL) {
+ end = num_spu_nodes;
+ index = 0;
+ } else {
+ if (spu_index >= num_spu_nodes) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: "
+ "Invalid index %d into spu info cache\n",
+ __FUNCTION__, __LINE__, spu_index);
+ goto out;
+ }
+ end = spu_index + 1;
+ index = spu_index;
+ }
+ for (; index < end; index++) {
+ if (spu_info[index]) {
+ kref_put(&spu_info[index]->cache_ref,
+ destroy_cached_info);
+ spu_info[index] = NULL;
+ }
+ }
+
+out:
+ return 0;
+}
+
+/* The source code for fast_get_dcookie was "borrowed"
+ * from drivers/oprofile/buffer_sync.c.
+ */
+
+/* Optimisation. We can manage without taking the dcookie sem
+ * because we cannot reach this code without at least one
+ * dcookie user still being registered (namely, the reader
+ * of the event buffer).
+ */
+static inline unsigned long fast_get_dcookie(struct dentry *dentry,
+ struct vfsmount *vfsmnt)
+{
+ unsigned long cookie;
+
+ if (dentry->d_cookie)
+ return (unsigned long)dentry;
+ get_dcookie(dentry, vfsmnt, &cookie);
+ return cookie;
+}
+
+/* Look up the dcookie for the task's first VM_EXECUTABLE mapping,
+ * which corresponds loosely to "application name". Also, determine
+ * the offset for the SPU ELF object. If computed offset is
+ * non-zero, it implies an embedded SPU object; otherwise, it's a
+ * separate SPU binary, in which case we retrieve it's dcookie.
+ * For the embedded case, we must determine if SPU ELF is embedded
+ * in the executable application or another file (i.e., shared lib).
+ * If embedded in a shared lib, we must get the dcookie and return
+ * that to the caller.
+ */
+static unsigned long
+get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp,
+ unsigned long *spu_bin_dcookie,
+ unsigned long spu_ref)
+{
+ unsigned long app_cookie = 0;
+ unsigned int my_offset = 0;
+ struct file *app = NULL;
+ struct vm_area_struct *vma;
+ struct mm_struct *mm = spu->mm;
+
+ if (!mm)
+ goto out;
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if (!vma->vm_file)
+ continue;
+ if (!(vma->vm_flags & VM_EXECUTABLE))
+ continue;
+ app_cookie = fast_get_dcookie(vma->vm_file->f_dentry,
+ vma->vm_file->f_vfsmnt);
+ pr_debug("got dcookie for %s\n",
+ vma->vm_file->f_dentry->d_name.name);
+ app = vma->vm_file;
+ break;
+ }
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if (vma->vm_start > spu_ref || vma->vm_end <= spu_ref)
+ continue;
+ my_offset = spu_ref - vma->vm_start;
+ if (!vma->vm_file)
+ goto fail_no_image_cookie;
+
+ pr_debug("Found spu ELF at %X(object-id:%lx) for file %s\n",
+ my_offset, spu_ref,
+ vma->vm_file->f_dentry->d_name.name);
+ *offsetp = my_offset;
+ break;
+ }
+
+ *spu_bin_dcookie = fast_get_dcookie(vma->vm_file->f_dentry,
+ vma->vm_file->f_vfsmnt);
+ pr_debug("got dcookie for %s\n", vma->vm_file->f_dentry->d_name.name);
+
+out:
+ return app_cookie;
+
+fail_no_image_cookie:
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: Cannot find dcookie for SPU binary\n",
+ __FUNCTION__, __LINE__);
+ goto out;
+}
+
+
+
+/* This function finds or creates cached context information for the
+ * passed SPU and records SPU context information into the OProfile
+ * event buffer.
+ */
+static int process_context_switch(struct spu *spu, unsigned long
objectId)
+{
+ unsigned long flags;
+ int retval;
+ unsigned int offset = 0;
+ unsigned long spu_cookie = 0, app_dcookie;
+
+ retval = prepare_cached_spu_info(spu, objectId);
+ if (retval)
+ goto out;
+
+ /* Get dcookie first because a mutex_lock is taken in that
+ * code path, so interrupts must not be disabled.
+ */
+ app_dcookie = get_exec_dcookie_and_offset(spu, &offset, &spu_cookie,
objectId);
+ if (!app_dcookie || !spu_cookie) {
+ retval = -ENOENT;
+ goto out;
+ }
+
+ /* Record context info in event buffer */
+ spin_lock_irqsave(&buffer_lock, flags);
+ add_event_entry(ESCAPE_CODE);
+ add_event_entry(SPU_CTX_SWITCH_CODE);
+ add_event_entry(spu->number);
+ add_event_entry(spu->pid);
+ add_event_entry(spu->tgid);
+ add_event_entry(app_dcookie);
+ add_event_entry(spu_cookie);
+ add_event_entry(offset);
+ spin_unlock_irqrestore(&buffer_lock, flags);
+ smp_wmb();
+out:
+ return retval;
+}
+
+/*
+ * This function is invoked on either a bind_context or unbind_context.
+ * If called for an unbind_context, the val arg is 0; otherwise,
+ * it is the object-id value for the spu context.
+ * The data arg is of type 'struct spu *'.
+ */
+static int spu_active_notify(struct notifier_block *self, unsigned long
val,
+ void *data)
+{
+ int retval;
+ unsigned long flags;
+ struct spu *the_spu = data;
+
+ pr_debug("SPU event notification arrived\n");
+ if (!val) {
+ spin_lock_irqsave(&cache_lock, flags);
+ retval = release_cached_info(the_spu->number);
+ spin_unlock_irqrestore(&cache_lock, flags);
+ } else {
+ retval = process_context_switch(the_spu, val);
+ }
+ return retval;
+}
+
+static struct notifier_block spu_active = {
+ .notifier_call = spu_active_notify,
+};
+
+/* The main purpose of this function is to synchronize
+ * OProfile with SPUFS by registering to be notified of
+ * SPU task switches.
+ *
+ * NOTE: When profiling SPUs, we must ensure that only
+ * spu_sync_start is invoked and not the generic sync_start
+ * in drivers/oprofile/oprof.c. A return value of
+ * SKIP_GENERIC_SYNC or SYNC_START_ERROR will
+ * accomplish this.
+ */
+int spu_sync_start(void)
+{
+ int k;
+ int ret = SKIP_GENERIC_SYNC;
+ int register_ret;
+ unsigned long flags = 0;
+
+ spu_prof_num_nodes = number_of_online_nodes();
+ num_spu_nodes = spu_prof_num_nodes * 8;
+
+ spin_lock_irqsave(&buffer_lock, flags);
+ add_event_entry(ESCAPE_CODE);
+ add_event_entry(SPU_PROFILING_CODE);
+ add_event_entry(num_spu_nodes);
+ spin_unlock_irqrestore(&buffer_lock, flags);
+
+ /* Register for SPU events */
+ register_ret = spu_switch_event_register(&spu_active);
+ if (register_ret) {
+ ret = SYNC_START_ERROR;
+ goto out;
+ }
+
+ for (k = 0; k < (MAX_NUMNODES * 8); k++)
+ last_guard_val[k] = 0;
+ pr_debug("spu_sync_start -- running.\n");
+out:
+ return ret;
+}
+
+/* Record SPU program counter samples to the oprofile event buffer. */
+void spu_sync_buffer(int spu_num, unsigned int *samples,
+ int num_samples)
+{
+ unsigned long long file_offset;
+ unsigned long flags;
+ int i;
+ struct vma_to_fileoffset_map *map;
+ struct spu *the_spu;
+ unsigned long long spu_num_ll = spu_num;
+ unsigned long long spu_num_shifted = spu_num_ll << 32;
+ struct cached_info *c_info;
+
+ /* We need to obtain the cache_lock here because it's
+ * possible that after getting the cached_info, the SPU job
+ * corresponding to this cached_info may end, thus resulting
+ * in the destruction of the cached_info.
+ */
+ spin_lock_irqsave(&cache_lock, flags);
+ c_info = get_cached_info(NULL, spu_num);
+ if (!c_info) {
+ /* This legitimately happens when the SPU task ends before all
+ * samples are recorded.
+ * No big deal -- so we just drop a few samples.
+ */
+ pr_debug("SPU_PROF: No cached SPU contex "
+ "for SPU #%d. Dropping samples.\n", spu_num);
+ goto out;
+ }
+
+ map = c_info->map;
+ the_spu = c_info->the_spu;
+ spin_lock(&buffer_lock);
+ for (i = 0; i < num_samples; i++) {
+ unsigned int sample = *(samples+i);
+ int grd_val = 0;
+ file_offset = 0;
+ if (sample == 0)
+ continue;
+ file_offset = vma_map_lookup( map, sample, the_spu, &grd_val);
+
+ /* If overlays are used by this SPU application, the guard
+ * value is non-zero, indicating which overlay section is in
+ * use. We need to discard samples taken during the time
+ * period which an overlay occurs (i.e., guard value changes).
+ */
+ if (grd_val && grd_val != last_guard_val[spu_num]) {
+ last_guard_val[spu_num] = grd_val;
+ /* Drop the rest of the samples. */
+ break;
+ }
+
+ add_event_entry(file_offset | spu_num_shifted);
+ }
+ spin_unlock(&buffer_lock);
+out:
+ spin_unlock_irqrestore(&cache_lock, flags);
+}
+
+
+int spu_sync_stop(void)
+{
+ unsigned long flags = 0;
+ int ret = spu_switch_event_unregister(&spu_active);
+ if (ret) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: spu_switch_event_unregister returned %d\n",
+ __FUNCTION__, __LINE__, ret);
+ goto out;
+ }
+
+ spin_lock_irqsave(&cache_lock, flags);
+ ret = release_cached_info(RELEASE_ALL);
+ spin_unlock_irqrestore(&cache_lock, flags);
+out:
+ pr_debug("spu_sync_stop -- done.\n");
+ return ret;
+}
+
+
Index: powerpc.git/arch/powerpc/oprofile/cell/vma_map.c
===================================================================
--- /dev/null
+++ powerpc.git/arch/powerpc/oprofile/cell/vma_map.c
@@ -0,0 +1,287 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* The code in this source file is responsible for generating
+ * vma-to-fileOffset maps for both overlay and non-overlay SPU
+ * applications.
+ */
+
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/elf.h>
+#include "pr_util.h"
+
+
+void vma_map_free(struct vma_to_fileoffset_map *map)
+{
+ while (map) {
+ struct vma_to_fileoffset_map *next = map->next;
+ kfree(map);
+ map = next;
+ }
+}
+
+unsigned int
+vma_map_lookup(struct vma_to_fileoffset_map *map, unsigned int vma,
+ const struct spu *aSpu, int *grd_val)
+{
+ /*
+ * Default the offset to the physical address + a flag value.
+ * Addresses of dynamically generated code can't be found in the vma
+ * map. For those addresses the flagged value will be sent on to
+ * the user space tools so they can be reported rather than just
+ * thrown away.
+ */
+ u32 offset = 0x10000000 + vma;
+ u32 ovly_grd;
+
+ for (; map; map = map->next) {
+ if (vma < map->vma || vma >= map->vma + map->size)
+ continue;
+
+ if (map->guard_ptr) {
+ ovly_grd = *(u32 *)(aSpu->local_store + map->guard_ptr);
+ if (ovly_grd != map->guard_val)
+ continue;
+ *grd_val = ovly_grd;
+ }
+ offset = vma - map->vma + map->offset;
+ break;
+ }
+
+ return offset;
+}
+
+static struct vma_to_fileoffset_map *
+vma_map_add(struct vma_to_fileoffset_map *map, unsigned int vma,
+ unsigned int size, unsigned int offset, unsigned int guard_ptr,
+ unsigned int guard_val)
+{
+ struct vma_to_fileoffset_map *new =
+ kzalloc(sizeof(struct vma_to_fileoffset_map), GFP_KERNEL);
+ if (!new) {
+ printk(KERN_ERR "SPU_PROF: %s, line %d: malloc failed\n",
+ __FUNCTION__, __LINE__);
+ vma_map_free(map);
+ return NULL;
+ }
+
+ new->next = map;
+ new->vma = vma;
+ new->size = size;
+ new->offset = offset;
+ new->guard_ptr = guard_ptr;
+ new->guard_val = guard_val;
+
+ return new;
+}
+
+
+/* Parse SPE ELF header and generate a list of vma_maps.
+ * A pointer to the first vma_map in the generated list
+ * of vma_maps is returned. */
+struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu,
+ unsigned long spu_elf_start)
+{
+ static const unsigned char expected[EI_PAD] = {
+ [EI_MAG0] = ELFMAG0,
+ [EI_MAG1] = ELFMAG1,
+ [EI_MAG2] = ELFMAG2,
+ [EI_MAG3] = ELFMAG3,
+ [EI_CLASS] = ELFCLASS32,
+ [EI_DATA] = ELFDATA2MSB,
+ [EI_VERSION] = EV_CURRENT,
+ [EI_OSABI] = ELFOSABI_NONE
+ };
+
+ int grd_val;
+ struct vma_to_fileoffset_map *map = NULL;
+ struct spu_overlay_info ovly;
+ unsigned int overlay_tbl_offset = -1;
+ unsigned long phdr_start, shdr_start;
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr phdr;
+ Elf32_Shdr shdr, shdr_str;
+ Elf32_Sym sym;
+ int i, j;
+ char name[32];
+
+ unsigned int ovly_table_sym = 0;
+ unsigned int ovly_buf_table_sym = 0;
+ unsigned int ovly_table_end_sym = 0;
+ unsigned int ovly_buf_table_end_sym = 0;
+ unsigned long ovly_table;
+ unsigned int n_ovlys;
+
+ /* Get and validate ELF header. */
+
+ if (copy_from_user(&ehdr, (void *) spu_elf_start, sizeof (ehdr)))
+ goto fail;
+
+ if (memcmp(ehdr.e_ident, expected, EI_PAD) != 0) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: Unexpected e_ident parsing SPU ELF\n",
+ __FUNCTION__, __LINE__);
+ goto fail;
+ }
+ if (ehdr.e_machine != EM_SPU) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: Unexpected e_machine parsing SPU ELF\n",
+ __FUNCTION__, __LINE__);
+ goto fail;
+ }
+ if (ehdr.e_type != ET_EXEC) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: Unexpected e_type parsing SPU ELF\n",
+ __FUNCTION__, __LINE__);
+ goto fail;
+ }
+ phdr_start = spu_elf_start + ehdr.e_phoff;
+ shdr_start = spu_elf_start + ehdr.e_shoff;
+
+ /* Traverse program headers. */
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ if (copy_from_user(&phdr,
+ (void *) (phdr_start + i * sizeof(phdr)),
+ sizeof(phdr)))
+ goto fail;
+
+ if (phdr.p_type != PT_LOAD)
+ continue;
+ if (phdr.p_flags & (1 << 27))
+ continue;
+
+ map = vma_map_add(map, phdr.p_vaddr, phdr.p_memsz,
+ phdr.p_offset, 0, 0);
+ if (!map)
+ goto fail;
+ }
+
+ pr_debug("SPU_PROF: Created non-overlay maps\n");
+ /* Traverse section table and search for overlay-related symbols. */
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ if (copy_from_user(&shdr,
+ (void *) (shdr_start + i * sizeof(shdr)),
+ sizeof(shdr)))
+ goto fail;
+
+ if (shdr.sh_type != SHT_SYMTAB)
+ continue;
+ if (shdr.sh_entsize != sizeof (sym))
+ continue;
+
+ if (copy_from_user(&shdr_str,
+ (void *) (shdr_start + shdr.sh_link *
+ sizeof(shdr)),
+ sizeof(shdr)))
+ goto fail;
+
+ if (shdr_str.sh_type != SHT_STRTAB)
+ goto fail;;
+
+ for (j = 0; j < shdr.sh_size / sizeof (sym); j++) {
+ if (copy_from_user(&sym, (void *) (spu_elf_start +
+ shdr.sh_offset + j *
+ sizeof (sym)),
+ sizeof (sym)))
+ goto fail;
+
+ if (copy_from_user(name, (void *)
+ (spu_elf_start + shdr_str.sh_offset +
+ sym.st_name),
+ 20))
+ goto fail;
+
+ if (memcmp(name, "_ovly_table", 12) == 0)
+ ovly_table_sym = sym.st_value;
+ if (memcmp(name, "_ovly_buf_table", 16) == 0)
+ ovly_buf_table_sym = sym.st_value;
+ if (memcmp(name, "_ovly_table_end", 16) == 0)
+ ovly_table_end_sym = sym.st_value;
+ if (memcmp(name, "_ovly_buf_table_end", 20) == 0)
+ ovly_buf_table_end_sym = sym.st_value;
+ }
+ }
+
+ /* If we don't have overlays, we're done. */
+ if (ovly_table_sym == 0 || ovly_buf_table_sym == 0
+ || ovly_table_end_sym == 0 || ovly_buf_table_end_sym == 0) {
+ pr_debug("SPU_PROF: No overlay table found\n");
+ goto out;
+ } else {
+ pr_debug("SPU_PROF: Overlay table found\n");
+ }
+
+ /* The _ovly_table symbol represents a table with one entry
+ * per overlay section. The _ovly_buf_table symbol represents
+ * a table with one entry per overlay region.
+ * The struct spu_overlay_info gives the structure of the _ovly_table
+ * entries. The structure of _ovly_table_buf is simply one
+ * u32 word per entry.
+ */
+ overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym,
+ aSpu, &grd_val);
+ if (overlay_tbl_offset < 0) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: Error finding SPU overlay table\n",
+ __FUNCTION__, __LINE__);
+ goto fail;
+ }
+ ovly_table = spu_elf_start + overlay_tbl_offset;
+
+ n_ovlys = (ovly_table_end_sym -
+ ovly_table_sym) / sizeof (ovly);
+
+ /* Traverse overlay table. */
+ for (i = 0; i < n_ovlys; i++) {
+ if (copy_from_user(&ovly, (void *)
+ (ovly_table + i * sizeof (ovly)),
+ sizeof (ovly)))
+ goto fail;
+
+ /* The ovly.vma/size/offset arguments are analogous to the same
+ * arguments used above for non-overlay maps. The final two
+ * args are referred to as the guard pointer and the guard
+ * value.
+ * The guard pointer is an entry in the _ovly_buf_table,
+ * computed using ovly.buf as the index into the table. Since
+ * ovly.buf values begin at '1' to reference the first (or 0th)
+ * entry in the _ovly_buf_table, the computation subtracts 1
+ * from ovly.buf.
+ * The guard value is stored in the _ovly_buf_table entry and
+ * is an index (starting at 1) back to the _ovly_table entry
+ * that is pointing at this _ovly_buf_table entry. So, for
+ * example, for an overlay scenario with one overlay segment
+ * and two overlay sections:
+ * - Section 1 points to the first entry of the
+ * _ovly_buf_table, which contains a guard value
+ * of '1', referencing the first (index=0) entry of
+ * _ovly_table.
+ * - Section 2 points to the second entry of the
+ * _ovly_buf_table, which contains a guard value
+ * of '2', referencing the second (index=1) entry of
+ * _ovly_table.
+ */
+ map = vma_map_add(map, ovly.vma, ovly.size, ovly.offset,
+ ovly_buf_table_sym + (ovly.buf-1) * 4, i+1);
+ if (!map)
+ goto fail;
+ }
+ goto out;
+
+ fail:
+ map = NULL;
+ out:
+ return map;
+}
Index: powerpc.git/arch/powerpc/oprofile/common.c
===================================================================
--- powerpc.git.orig/arch/powerpc/oprofile/common.c
+++ powerpc.git/arch/powerpc/oprofile/common.c
@@ -29,6 +29,8 @@ static struct op_powerpc_model *model;
static struct op_counter_config ctr[OP_MAX_COUNTER];
static struct op_system_config sys;
+static int op_per_cpu_rc;
+
static void op_handle_interrupt(struct pt_regs *regs)
{
model->handle_interrupt(regs, ctr);
@@ -36,25 +38,41 @@ static void op_handle_interrupt(struct p
static void op_powerpc_cpu_setup(void *dummy)
{
- model->cpu_setup(ctr);
+ int ret;
+
+ ret = model->cpu_setup(ctr);
+
+ if (ret != 0)
+ op_per_cpu_rc = ret;
}
static int op_powerpc_setup(void)
{
int err;
+ op_per_cpu_rc = 0;
+
/* Grab the hardware */
err = reserve_pmc_hardware(op_handle_interrupt);
if (err)
return err;
/* Pre-compute the values to stuff in the hardware registers. */
- model->reg_setup(ctr, &sys, model->num_counters);
+ op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters);
- /* Configure the registers on all cpus. */
+ if (op_per_cpu_rc)
+ goto out;
+
+ /* Configure the registers on all cpus. If an error occurs on one
+ * of the cpus, op_per_cpu_rc will be set to the error */
on_each_cpu(op_powerpc_cpu_setup, NULL, 0, 1);
- return 0;
+out: if (op_per_cpu_rc) {
+ /* error on setup release the performance counter hardware */
+ release_pmc_hardware();
+ }
+
+ return op_per_cpu_rc;
}
static void op_powerpc_shutdown(void)
@@ -64,16 +82,29 @@ static void op_powerpc_shutdown(void)
static void op_powerpc_cpu_start(void *dummy)
{
- model->start(ctr);
+ /* If any of the cpus have return an error, set the
+ * global flag to the error so it can be returned
+ * to the generic OProfile caller.
+ */
+ int ret;
+
+ ret = model->start(ctr);
+ if (ret != 0)
+ op_per_cpu_rc = ret;
}
static int op_powerpc_start(void)
{
+ op_per_cpu_rc = 0;
+
if (model->global_start)
- model->global_start(ctr);
- if (model->start)
+ return model->global_start(ctr);
+ if (model->start) {
on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1);
- return 0;
+ return op_per_cpu_rc;
+ }
+ return -EIO; /* No start function is defined for this
+ power architecture */
}
static inline void op_powerpc_cpu_stop(void *dummy)
@@ -147,11 +178,13 @@ int __init oprofile_arch_init(struct opr
switch (cur_cpu_spec->oprofile_type) {
#ifdef CONFIG_PPC64
-#ifdef CONFIG_PPC_CELL_NATIVE
+#ifdef CONFIG_OPROFILE_CELL
case PPC_OPROFILE_CELL:
if (firmware_has_feature(FW_FEATURE_LPAR))
return -ENODEV;
model = &op_model_cell;
+ ops->sync_start = model->sync_start;
+ ops->sync_stop = model->sync_stop;
break;
#endif
case PPC_OPROFILE_RS64:
Index: powerpc.git/arch/powerpc/oprofile/Kconfig
===================================================================
--- powerpc.git.orig/arch/powerpc/oprofile/Kconfig
+++ powerpc.git/arch/powerpc/oprofile/Kconfig
@@ -15,3 +15,10 @@ config OPROFILE
If unsure, say N.
+config OPROFILE_CELL
+ bool "OProfile for Cell Broadband Engine"
+ depends on (SPU_FS = y && OPROFILE = m) || (SPU_FS = y && OPROFILE =
y) || (SPU_FS = m && OPROFILE = m)
+ default y
+ help
+ Profiling of Cell BE SPUs requires special support enabled
+ by this option.
Index: powerpc.git/arch/powerpc/oprofile/Makefile
===================================================================
--- powerpc.git.orig/arch/powerpc/oprofile/Makefile
+++ powerpc.git/arch/powerpc/oprofile/Makefile
@@ -11,7 +11,9 @@ DRIVER_OBJS := $(addprefix ../../../driv
timer_int.o )
oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
-oprofile-$(CONFIG_PPC_CELL_NATIVE) += op_model_cell.o
+oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \
+ cell/spu_profiler.o cell/vma_map.o \
+ cell/spu_task_sync.o
oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
op_model_pa6t.o
oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
oprofile-$(CONFIG_6xx) += op_model_7450.o
Index: powerpc.git/arch/powerpc/oprofile/op_model_cell.c
===================================================================
--- powerpc.git.orig/arch/powerpc/oprofile/op_model_cell.c
+++ powerpc.git/arch/powerpc/oprofile/op_model_cell.c
@@ -5,8 +5,8 @@
*
* Author: David Erb (djerb@us.ibm.com)
* Modifications:
- * Carl Love <carll@us.ibm.com>
- * Maynard Johnson <maynardj@us.ibm.com>
+ * Carl Love <carll@us.ibm.com>
+ * Maynard Johnson <maynardj@us.ibm.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -38,12 +38,25 @@
#include "../platforms/cell/interrupt.h"
#include "../platforms/cell/cbe_regs.h"
+#include "cell/pr_util.h"
+
+static void cell_global_stop_spu(void);
+
+/*
+ * spu_cycle_reset is the number of cycles between samples.
+ * This variable is used for SPU profiling and should ONLY be set
+ * at the beginning of cell_reg_setup; otherwise, it's read-only.
+ */
+static unsigned int spu_cycle_reset;
+
+#define NUM_SPUS_PER_NODE 8
+#define SPU_CYCLES_EVENT_NUM 2 /* event number for SPU_CYCLES */
#define PPU_CYCLES_EVENT_NUM 1 /* event number for CYCLES */
-#define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying
- * PPU_CYCLES event
- */
-#define CBE_COUNT_ALL_CYCLES 0x42800000 /* PPU cycle event specifier */
+#define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying
+ * PPU_CYCLES event
+ */
+#define CBE_COUNT_ALL_CYCLES 0x42800000 /* PPU cycle event specifier */
#define NUM_THREADS 2 /* number of physical threads in
* physical processor
@@ -51,6 +64,7 @@
#define NUM_TRACE_BUS_WORDS 4
#define NUM_INPUT_BUS_WORDS 2
+#define MAX_SPU_COUNT 0xFFFFFF /* maximum 24 bit LFSR value */
struct pmc_cntrl_data {
unsigned long vcntr;
@@ -62,11 +76,10 @@ struct pmc_cntrl_data {
/*
* ibm,cbe-perftools rtas parameters
*/
-
struct pm_signal {
u16 cpu; /* Processor to modify */
- u16 sub_unit; /* hw subunit this applies to (if applicable) */
- short int signal_group; /* Signal Group to Enable/Disable */
+ u16 sub_unit; /* hw subunit this applies to (if applicable)*/
+ short int signal_group; /* Signal Group to Enable/Disable */
u8 bus_word; /* Enable/Disable on this Trace/Trigger/Event
* Bus Word(s) (bitmask)
*/
@@ -112,21 +125,42 @@ static DEFINE_PER_CPU(unsigned long[NR_P
static struct pmc_cntrl_data pmc_cntrl[NUM_THREADS][NR_PHYS_CTRS];
-/* Interpetation of hdw_thread:
+/*
+ * The CELL profiling code makes rtas calls to setup the debug bus to
+ * route the performance signals. Additionally, SPU profiling requires
+ * a second rtas call to setup the hardware to capture the SPU PCs.
+ * The EIO error value is returned if the token lookups or the rtas
+ * call fail. The EIO error number is the best choice of the existing
+ * error numbers. The probability of rtas related error is very low.
But
+ * by returning EIO and printing additional information to dmsg the
user
+ * will know that OProfile did not start and dmesg will tell them why.
+ * OProfile does not support returning errors on Stop. Not a huge issue
+ * since failure to reset the debug bus or stop the SPU PC collection
is
+ * not a fatel issue. Chances are if the Stop failed, Start doesn't
work
+ * either.
+ */
+
+/*
+ * Interpetation of hdw_thread:
* 0 - even virtual cpus 0, 2, 4,...
* 1 - odd virtual cpus 1, 3, 5, ...
+ *
+ * FIXME: this is strictly wrong, we need to clean this up in a number
+ * of places. It works for now. -arnd
*/
static u32 hdw_thread;
static u32 virt_cntr_inter_mask;
static struct timer_list timer_virt_cntr;
-/* pm_signal needs to be global since it is initialized in
+/*
+ * pm_signal needs to be global since it is initialized in
* cell_reg_setup at the time when the necessary information
* is available.
*/
static struct pm_signal pm_signal[NR_PHYS_CTRS];
-static int pm_rtas_token;
+static int pm_rtas_token; /* token for debug bus setup call */
+static int spu_rtas_token; /* token for SPU cycle profiling */
static u32 reset_value[NR_PHYS_CTRS];
static int num_counters;
@@ -147,8 +181,8 @@ rtas_ibm_cbe_perftools(int subfunc, int
{
u64 paddr = __pa(address);
- return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc, passthru,
- paddr >> 32, paddr & 0xffffffff, length);
+ return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc,
+ passthru, paddr >> 32, paddr & 0xffffffff, length);
}
static void pm_rtas_reset_signals(u32 node)
@@ -156,12 +190,13 @@ static void pm_rtas_reset_signals(u32 no
int ret;
struct pm_signal pm_signal_local;
- /* The debug bus is being set to the passthru disable state.
- * However, the FW still expects atleast one legal signal routing
- * entry or it will return an error on the arguments. If we don't
- * supply a valid entry, we must ignore all return values. Ignoring
- * all return values means we might miss an error we should be
- * concerned about.
+ /*
+ * The debug bus is being set to the passthru disable state.
+ * However, the FW still expects atleast one legal signal routing
+ * entry or it will return an error on the arguments. If we don't
+ * supply a valid entry, we must ignore all return values. Ignoring
+ * all return values means we might miss an error we should be
+ * concerned about.
*/
/* fw expects physical cpu #. */
@@ -175,18 +210,24 @@ static void pm_rtas_reset_signals(u32 no
&pm_signal_local,
sizeof(struct pm_signal));
- if (ret)
+ if (unlikely(ret))
+ /*
+ * Not a fatal error. For Oprofile stop, the oprofile
+ * functions do not support returning an error for
+ * failure to stop OProfile.
+ */
printk(KERN_WARNING "%s: rtas returned: %d\n",
__FUNCTION__, ret);
}
-static void pm_rtas_activate_signals(u32 node, u32 count)
+static int pm_rtas_activate_signals(u32 node, u32 count)
{
int ret;
int i, j;
struct pm_signal pm_signal_local[NR_PHYS_CTRS];
- /* There is no debug setup required for the cycles event.
+ /*
+ * There is no debug setup required for the cycles event.
* Note that only events in the same group can be used.
* Otherwise, there will be conflicts in correctly routing
* the signals on the debug bus. It is the responsiblity
@@ -213,10 +254,14 @@ static void pm_rtas_activate_signals(u32
pm_signal_local,
i * sizeof(struct pm_signal));
- if (ret)
+ if (unlikely(ret)) {
printk(KERN_WARNING "%s: rtas returned: %d\n",
__FUNCTION__, ret);
+ return -EIO;
+ }
}
+
+ return 0;
}
/*
@@ -260,11 +305,12 @@ static void set_pm_event(u32 ctr, int ev
pm_regs.pm07_cntrl[ctr] |= PM07_CTR_POLARITY(polarity);
pm_regs.pm07_cntrl[ctr] |= PM07_CTR_INPUT_CONTROL(input_control);
- /* Some of the islands signal selection is based on 64 bit words.
+ /*
+ * Some of the islands signal selection is based on 64 bit words.
* The debug bus words are 32 bits, the input words to the performance
* counters are defined as 32 bits. Need to convert the 64 bit island
* specification to the appropriate 32 input bit and bus word for the
- * performance counter event selection. See the CELL Performance
+ * performance counter event selection. See the CELL Performance
* monitoring signals manual and the Perf cntr hardware descriptions
* for the details.
*/
@@ -298,6 +344,7 @@ static void set_pm_event(u32 ctr, int ev
input_bus[j] = i;
pm_regs.group_control |=
(i << (31 - i));
+
break;
}
}
@@ -309,7 +356,8 @@ out:
static void write_pm_cntrl(int cpu)
{
- /* Oprofile will use 32 bit counters, set bits 7:10 to 0
+ /*
+ * Oprofile will use 32 bit counters, set bits 7:10 to 0
* pmregs.pm_cntrl is a global
*/
@@ -326,7 +374,8 @@ static void write_pm_cntrl(int cpu)
if (pm_regs.pm_cntrl.freeze == 1)
val |= CBE_PM_FREEZE_ALL_CTRS;
- /* Routine set_count_mode must be called previously to set
+ /*
+ * Routine set_count_mode must be called previously to set
* the count mode based on the user selection of user and kernel.
*/
val |= CBE_PM_COUNT_MODE_SET(pm_regs.pm_cntrl.count_mode);
@@ -336,7 +385,8 @@ static void write_pm_cntrl(int cpu)
static inline void
set_count_mode(u32 kernel, u32 user)
{
- /* The user must specify user and kernel if they want them. If
+ /*
+ * The user must specify user and kernel if they want them. If
* neither is specified, OProfile will count in hypervisor mode.
* pm_regs.pm_cntrl is a global
*/
@@ -364,7 +414,7 @@ static inline void enable_ctr(u32 cpu, u
/*
* Oprofile is expected to collect data on all CPUs simultaneously.
- * However, there is one set of performance counters per node. There
are
+ * However, there is one set of performance counters per node. There
are
* two hardware threads or virtual CPUs on each node. Hence, OProfile
must
* multiplex in time the performance counter collection on the two
virtual
* CPUs. The multiplexing of the performance counters is done by this
@@ -377,19 +427,19 @@ static inline void enable_ctr(u32 cpu, u
* pair of per-cpu arrays is used for storing the previous and next
* pmc values for a given node.
* NOTE: We use the per-cpu variable to improve cache performance.
+ *
+ * This routine will alternate loading the virtual counters for
+ * virtual CPUs
*/
static void cell_virtual_cntr(unsigned long data)
{
- /* This routine will alternate loading the virtual counters for
- * virtual CPUs
- */
int i, prev_hdw_thread, next_hdw_thread;
u32 cpu;
unsigned long flags;
- /* Make sure that the interrupt_hander and
- * the virt counter are not both playing with
- * the counters on the same node.
+ /*
+ * Make sure that the interrupt_hander and the virt counter are
+ * not both playing with the counters on the same node.
*/
spin_lock_irqsave(&virt_cntr_lock, flags);
@@ -400,22 +450,25 @@ static void cell_virtual_cntr(unsigned l
hdw_thread = 1 ^ hdw_thread;
next_hdw_thread = hdw_thread;
- for (i = 0; i < num_counters; i++)
- /* There are some per thread events. Must do the
+ /*
+ * There are some per thread events. Must do the
* set event, for the thread that is being started
*/
+ for (i = 0; i < num_counters; i++)
set_pm_event(i,
pmc_cntrl[next_hdw_thread][i].evnts,
pmc_cntrl[next_hdw_thread][i].masks);
- /* The following is done only once per each node, but
+ /*
+ * The following is done only once per each node, but
* we need cpu #, not node #, to pass to the cbe_xxx functions.
*/
for_each_online_cpu(cpu) {
if (cbe_get_hw_thread_id(cpu))
continue;
- /* stop counters, save counter values, restore counts
+ /*
+ * stop counters, save counter values, restore counts
* for previous thread
*/
cbe_disable_pm(cpu);
@@ -428,7 +481,7 @@ static void cell_virtual_cntr(unsigned l
== 0xFFFFFFFF)
/* If the cntr value is 0xffffffff, we must
* reset that to 0xfffffff0 when the current
- * thread is restarted. This will generate a
+ * thread is restarted. This will generate a
* new interrupt and make sure that we never
* restore the counters to the max value. If
* the counters were restored to the max value,
@@ -444,13 +497,15 @@ static void cell_virtual_cntr(unsigned l
next_hdw_thread)[i]);
}
- /* Switch to the other thread. Change the interrupt
+ /*
+ * Switch to the other thread. Change the interrupt
* and control regs to be scheduled on the CPU
* corresponding to the thread to execute.
*/
for (i = 0; i < num_counters; i++) {
if (pmc_cntrl[next_hdw_thread][i].enabled) {
- /* There are some per thread events.
+ /*
+ * There are some per thread events.
* Must do the set event, enable_cntr
* for each cpu.
*/
@@ -482,17 +537,42 @@ static void start_virt_cntrs(void)
}
/* This function is called once for all cpus combined */
-static void
-cell_reg_setup(struct op_counter_config *ctr,
- struct op_system_config *sys, int num_ctrs)
+static int cell_reg_setup(struct op_counter_config *ctr,
+ struct op_system_config *sys, int num_ctrs)
{
int i, j, cpu;
+ spu_cycle_reset = 0;
+
+ if (ctr[0].event == SPU_CYCLES_EVENT_NUM) {
+ spu_cycle_reset = ctr[0].count;
+
+ /*
+ * Each node will need to make the rtas call to start
+ * and stop SPU profiling. Get the token once and store it.
+ */
+ spu_rtas_token = rtas_token("ibm,cbe-spu-perftools");
+
+ if (unlikely(spu_rtas_token == RTAS_UNKNOWN_SERVICE)) {
+ printk(KERN_ERR
+ "%s: rtas token ibm,cbe-spu-perftools unknown\n",
+ __FUNCTION__);
+ return -EIO;
+ }
+ }
pm_rtas_token = rtas_token("ibm,cbe-perftools");
- if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) {
- printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n",
+
+ /*
+ * For all events excetp PPU CYCLEs, each node will need to make
+ * the rtas cbe-perftools call to setup and reset the debug bus.
+ * Make the token lookup call once and store it in the global
+ * variable pm_rtas_token.
+ */
+ if (unlikely(pm_rtas_token == RTAS_UNKNOWN_SERVICE)) {
+ printk(KERN_ERR
+ "%s: rtas token ibm,cbe-perftools unknown\n",
__FUNCTION__);
- goto out;
+ return -EIO;
}
num_counters = num_ctrs;
@@ -520,7 +600,8 @@ cell_reg_setup(struct op_counter_config
per_cpu(pmc_values, j)[i] = 0;
}
- /* Setup the thread 1 events, map the thread 0 event to the
+ /*
+ * Setup the thread 1 events, map the thread 0 event to the
* equivalent thread 1 event.
*/
for (i = 0; i < num_ctrs; ++i) {
@@ -544,9 +625,10 @@ cell_reg_setup(struct op_counter_config
for (i = 0; i < NUM_INPUT_BUS_WORDS; i++)
input_bus[i] = 0xff;
- /* Our counters count up, and "count" refers to
+ /*
+ * Our counters count up, and "count" refers to
* how much before the next interrupt, and we interrupt
- * on overflow. So we calculate the starting value
+ * on overflow. So we calculate the starting value
* which will give us "count" until overflow.
* Then we set the events on the enabled counters.
*/
@@ -569,28 +651,27 @@ cell_reg_setup(struct op_counter_config
for (i = 0; i < num_counters; ++i) {
per_cpu(pmc_values, cpu)[i] = reset_value[i];
}
-out:
- ;
+
+ return 0;
}
+
+
/* This function is called once for each cpu */
-static void cell_cpu_setup(struct op_counter_config *cntr)
+static int cell_cpu_setup(struct op_counter_config *cntr)
{
u32 cpu = smp_processor_id();
u32 num_enabled = 0;
int i;
+ if (spu_cycle_reset)
+ return 0;
+
/* There is one performance monitor per processor chip (i.e. node),
* so we only need to perform this function once per node.
*/
if (cbe_get_hw_thread_id(cpu))
- goto out;
-
- if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) {
- printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n",
- __FUNCTION__);
- goto out;
- }
+ return 0;
/* Stop all counters */
cbe_disable_pm(cpu);
@@ -609,16 +690,286 @@ static void cell_cpu_setup(struct op_cou
}
}
- pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled);
+ /*
+ * The pm_rtas_activate_signals will return -EIO if the FW
+ * call failed.
+ */
+ return pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled);
+}
+
+#define ENTRIES 303
+#define MAXLFSR 0xFFFFFF
+
+/* precomputed table of 24 bit LFSR values */
+static int initial_lfsr[] = {
+ 8221349, 12579195, 5379618, 10097839, 7512963, 7519310, 3955098,
10753424,
+ 15507573, 7458917, 285419, 2641121, 9780088, 3915503, 6668768,
1548716,
+ 4885000, 8774424, 9650099, 2044357, 2304411, 9326253, 10332526,
4421547,
+ 3440748, 10179459, 13332843, 10375561, 1313462, 8375100, 5198480,
6071392,
+ 9341783, 1526887, 3985002, 1439429, 13923762, 7010104, 11969769,
4547026,
+ 2040072, 4025602, 3437678, 7939992, 11444177, 4496094, 9803157,
10745556,
+ 3671780, 4257846, 5662259, 13196905, 3237343, 12077182, 16222879,
7587769,
+ 14706824, 2184640, 12591135, 10420257, 7406075, 3648978, 11042541,
15906893,
+ 11914928, 4732944, 10695697, 12928164, 11980531, 4430912, 11939291,
2917017,
+ 6119256, 4172004, 9373765, 8410071, 14788383, 5047459, 5474428,
1737756,
+ 15967514, 13351758, 6691285, 8034329, 2856544, 14394753, 11310160,
12149558,
+ 7487528, 7542781, 15668898, 12525138, 12790975, 3707933, 9106617,
1965401,
+ 16219109, 12801644, 2443203, 4909502, 8762329, 3120803, 6360315,
9309720,
+ 15164599, 10844842, 4456529, 6667610, 14924259, 884312, 6234963,
3326042,
+ 15973422, 13919464, 5272099, 6414643, 3909029, 2764324, 5237926,
4774955,
+ 10445906, 4955302, 5203726, 10798229, 11443419, 2303395, 333836,
9646934,
+ 3464726, 4159182, 568492, 995747, 10318756, 13299332, 4836017,
8237783,
+ 3878992, 2581665, 11394667, 5672745, 14412947, 3159169, 9094251,
16467278,
+ 8671392, 15230076, 4843545, 7009238, 15504095, 1494895, 9627886,
14485051,
+ 8304291, 252817, 12421642, 16085736, 4774072, 2456177, 4160695,
15409741,
+ 4902868, 5793091, 13162925, 16039714, 782255, 11347835, 14884586,
366972,
+ 16308990, 11913488, 13390465, 2958444, 10340278, 1177858, 1319431,
10426302,
+ 2868597, 126119, 5784857, 5245324, 10903900, 16436004, 3389013,
1742384,
+ 14674502, 10279218, 8536112, 10364279, 6877778, 14051163, 1025130,
6072469,
+ 1988305, 8354440, 8216060, 16342977, 13112639, 3976679, 5913576,
8816697,
+ 6879995, 14043764, 3339515, 9364420, 15808858, 12261651, 2141560,
5636398,
+ 10345425, 10414756, 781725, 6155650, 4746914, 5078683, 7469001,
6799140,
+ 10156444, 9667150, 10116470, 4133858, 2121972, 1124204, 1003577,
1611214,
+ 14304602, 16221850, 13878465, 13577744, 3629235, 8772583, 10881308,
2410386,
+ 7300044, 5378855, 9301235, 12755149, 4977682, 8083074, 10327581,
6395087,
+ 9155434, 15501696, 7514362, 14520507, 15808945, 3244584, 4741962,
9658130,
+ 14336147, 8654727, 7969093, 15759799, 14029445, 5038459, 9894848,
8659300,
+ 13699287, 8834306, 10712885, 14753895, 10410465, 3373251, 309501,
9561475,
+ 5526688, 14647426, 14209836, 5339224, 207299, 14069911, 8722990,
2290950,
+ 3258216, 12505185, 6007317, 9218111, 14661019, 10537428, 11731949,
9027003,
+ 6641507, 9490160, 200241, 9720425, 16277895, 10816638, 1554761,
10431375,
+ 7467528, 6790302, 3429078, 14633753, 14428997, 11463204, 3576212,
2003426,
+ 6123687, 820520, 9992513, 15784513, 5778891, 6428165, 8388607
+};
+
+/*
+ * The hardware uses an LFSR counting sequence to determine when to
capture
+ * the SPU PCs. An LFSR sequence is like a puesdo random number
sequence
+ * where each number occurs once in the sequence but the sequence is
not in
+ * numerical order. The SPU PC capture is done when the LFSR sequence
reaches
+ * the last value in the sequence. Hence the user specified value N
+ * corresponds to the LFSR number that is N from the end of the
sequence.
+ *
+ * To avoid the time to compute the LFSR, a lookup table is used. The
24 bit
+ * LFSR sequence is broken into four ranges. The spacing of the
precomputed
+ * values is adjusted in each range so the error between the user
specifed
+ * number (N) of events between samples and the actual number of events
based
+ * on the precomputed value will be les then about 6.2%. Note, if the
user
+ * specifies N < 2^16, the LFSR value that is 2^16 from the end will be
used.
+ * This is to prevent the loss of samples because the trace buffer is
full.
+ *
+ * User specified N Step between Index in
+ * precomputed values precomputed
+ * table
+ * 0 to 2^16-1 ---- 0
+ * 2^16 to 2^16+2^19-1 2^12 1 to 128
+ * 2^16+2^19 to 2^16+2^19+2^22-1 2^15 129 to 256
+ * 2^16+2^19+2^22 to 2^24-1 2^18 257 to 302
+ *
+ *
+ * For example, the LFSR values in the second range are computed for
2^16,
+ * 2^16+2^12, ... , 2^19-2^16, 2^19 and stored in the table at indicies
+ * 1, 2,..., 127, 128.
+ *
+ * The 24 bit LFSR value for the nth number in the sequence can be
+ * calculated using the following code:
+ *
+ * #define size 24
+ * int calculate_lfsr(int n)
+ * {
+ * int i;
+ * unsigned int newlfsr0;
+ * unsigned int lfsr = 0xFFFFFF;
+ * unsigned int howmany = n;
+ *
+ * for (i = 2; i < howmany + 2; i++) {
+ * newlfsr0 = (((lfsr >> (size - 1 - 0)) & 1) ^
+ * ((lfsr >> (size - 1 - 1)) & 1) ^
+ * (((lfsr >> (size - 1 - 6)) & 1) ^
+ * ((lfsr >> (size - 1 - 23)) & 1)));
+ *
+ * lfsr >>= 1;
+ * lfsr = lfsr | (newlfsr0 << (size - 1));
+ * }
+ * return lfsr;
+ * }
+ */
+
+#define V2_16 (0x1 << 16)
+#define V2_19 (0x1 << 19)
+#define V2_22 (0x1 << 22)
+
+static int calculate_lfsr(int n)
+{
+ /*
+ * The ranges and steps are in powers of 2 so the calculations
+ * can be done using shifts rather then divide.
+ */
+ int index;
+
+ if ((n >> 16) == 0)
+ index = 0;
+ else if (((n - V2_16) >> 19) == 0)
+ index = ((n - V2_16) >> 12) + 1;
+ else if (((n - V2_16 - V2_19) >> 22) == 0)
+ index = ((n - V2_16 - V2_19) >> 15 ) + 1 + 128;
+ else if (((n - V2_16 - V2_19 - V2_22) >> 24) == 0)
+ index = ((n - V2_16 - V2_19 - V2_22) >> 18 ) + 1 + 256;
+ else
+ index = ENTRIES-1;
+
+ /* make sure index is valid */
+ if ((index > ENTRIES) || (index < 0))
+ index = ENTRIES-1;
+
+ return initial_lfsr[index];
+}
+
+static int pm_rtas_activate_spu_profiling(u32 node)
+{
+ int ret, i;
+ struct pm_signal pm_signal_local[NR_PHYS_CTRS];
+
+ /*
+ * Set up the rtas call to configure the debug bus to
+ * route the SPU PCs. Setup the pm_signal for each SPU
+ */
+ for (i = 0; i < NUM_SPUS_PER_NODE; i++) {
+ pm_signal_local[i].cpu = node;
+ pm_signal_local[i].signal_group = 41;
+ /* spu i on word (i/2) */
+ pm_signal_local[i].bus_word = 1 << i / 2;
+ /* spu i */
+ pm_signal_local[i].sub_unit = i;
+ pm_signal_local[i].bit = 63;
+ }
+
+ ret = rtas_ibm_cbe_perftools(SUBFUNC_ACTIVATE,
+ PASSTHRU_ENABLE, pm_signal_local,
+ (NUM_SPUS_PER_NODE
+ * sizeof(struct pm_signal)));
+
+ if (unlikely(ret)) {
+ printk(KERN_WARNING "%s: rtas returned: %d\n",
+ __FUNCTION__, ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_CPU_FREQ
+static int
+oprof_cpufreq_notify(struct notifier_block *nb, unsigned long val, void
*data)
+{
+ int ret = 0;
+ struct cpufreq_freqs *frq = data;
+ if ((val == CPUFREQ_PRECHANGE && frq->old < frq->new) ||
+ (val == CPUFREQ_POSTCHANGE && frq->old > frq->new) ||
+ (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE))
+ set_profiling_frequency(frq->new, spu_cycle_reset);
+ return ret;
+}
+
+static struct notifier_block cpu_freq_notifier_block = {
+ .notifier_call = oprof_cpufreq_notify
+};
+#endif
+
+static int cell_global_start_spu(struct op_counter_config *ctr)
+{
+ int subfunc;
+ unsigned int lfsr_value;
+ int cpu;
+ int ret;
+ int rtas_error;
+ unsigned int cpu_khzfreq = 0;
+
+ /* The SPU profiling uses time-based profiling based on
+ * cpu frequency, so if configured with the CPU_FREQ
+ * option, we should detect frequency changes and react
+ * accordingly.
+ */
+#ifdef CONFIG_CPU_FREQ
+ ret = cpufreq_register_notifier(&cpu_freq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ if (ret < 0)
+ /* this is not a fatal error */
+ printk(KERN_ERR "CPU freq change registration failed: %d\n",
+ ret);
+
+ else
+ cpu_khzfreq = cpufreq_quick_get(smp_processor_id());
+#endif
+
+ set_profiling_frequency(cpu_khzfreq, spu_cycle_reset);
+
+ for_each_online_cpu(cpu) {
+ if (cbe_get_hw_thread_id(cpu))
+ continue;
+
+ /*
+ * Setup SPU cycle-based profiling.
+ * Set perf_mon_control bit 0 to a zero before
+ * enabling spu collection hardware.
+ */
+ cbe_write_pm(cpu, pm_control, 0);
+
+ if (spu_cycle_reset > MAX_SPU_COUNT)
+ /* use largest possible value */
+ lfsr_value = calculate_lfsr(MAX_SPU_COUNT-1);
+ else
+ lfsr_value = calculate_lfsr(spu_cycle_reset);
+
+ /* must use a non zero value. Zero disables data collection. */
+ if (lfsr_value == 0)
+ lfsr_value = calculate_lfsr(1);
+
+ lfsr_value = lfsr_value << 8; /* shift lfsr to correct
+ * register location
+ */
+
+ /* debug bus setup */
+ ret = pm_rtas_activate_spu_profiling(cbe_cpu_to_node(cpu));
+
+ if (unlikely(ret)) {
+ rtas_error = ret;
+ goto out;
+ }
+
+
+ subfunc = 2; /* 2 - activate SPU tracing, 3 - deactivate */
+
+ /* start profiling */
+ ret = rtas_call(spu_rtas_token, 3, 1, NULL, subfunc,
+ cbe_cpu_to_node(cpu), lfsr_value);
+
+ if (unlikely(ret != 0)) {
+ printk(KERN_ERR
+ "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n",
+ __FUNCTION__, ret);
+ rtas_error = -EIO;
+ goto out;
+ }
+ }
+
+ rtas_error = start_spu_profiling(spu_cycle_reset);
+ if (rtas_error)
+ goto out_stop;
+
+ oprofile_running = 1;
+ return 0;
+
+out_stop:
+ cell_global_stop_spu(); /* clean up the PMU/debug bus */
out:
- ;
+ return rtas_error;
}
-static void cell_global_start(struct op_counter_config *ctr)
+static int cell_global_start_ppu(struct op_counter_config *ctr)
{
- u32 cpu;
+ u32 cpu, i;
u32 interrupt_mask = 0;
- u32 i;
/* This routine gets called once for the system.
* There is one performance monitor per node, so we
@@ -651,19 +1002,80 @@ static void cell_global_start(struct op_
oprofile_running = 1;
smp_wmb();
- /* NOTE: start_virt_cntrs will result in cell_virtual_cntr() being
- * executed which manipulates the PMU. We start the "virtual counter"
+ /*
+ * NOTE: start_virt_cntrs will result in cell_virtual_cntr() being
+ * executed which manipulates the PMU. We start the "virtual counter"
* here so that we do not need to synchronize access to the PMU in
* the above for-loop.
*/
start_virt_cntrs();
+
+ return 0;
}
-static void cell_global_stop(void)
+static int cell_global_start(struct op_counter_config *ctr)
+{
+ if (spu_cycle_reset) {
+ return cell_global_start_spu(ctr);
+ } else {
+ return cell_global_start_ppu(ctr);
+ }
+}
+
+/*
+ * Note the generic OProfile stop calls do not support returning
+ * an error on stop. Hence, will not return an error if the FW
+ * calls fail on stop. Failure to reset the debug bus is not an issue.
+ * Failure to disable the SPU profiling is not an issue. The FW calls
+ * to enable the performance counters and debug bus will work even if
+ * the hardware was not cleanly reset.
+ */
+static void cell_global_stop_spu(void)
+{
+ int subfunc, rtn_value;
+ unsigned int lfsr_value;
+ int cpu;
+
+ oprofile_running = 0;
+
+#ifdef CONFIG_CPU_FREQ
+ cpufreq_unregister_notifier(&cpu_freq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+
+ for_each_online_cpu(cpu) {
+ if (cbe_get_hw_thread_id(cpu))
+ continue;
+
+ subfunc = 3; /*
+ * 2 - activate SPU tracing,
+ * 3 - deactivate
+ */
+ lfsr_value = 0x8f100000;
+
+ rtn_value = rtas_call(spu_rtas_token, 3, 1, NULL,
+ subfunc, cbe_cpu_to_node(cpu),
+ lfsr_value);
+
+ if (unlikely(rtn_value != 0)) {
+ printk(KERN_ERR
+ "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n",
+ __FUNCTION__, rtn_value);
+ }
+
+ /* Deactivate the signals */
+ pm_rtas_reset_signals(cbe_cpu_to_node(cpu));
+ }
+
+ stop_spu_profiling();
+}
+
+static void cell_global_stop_ppu(void)
{
int cpu;
- /* This routine will be called once for the system.
+ /*
+ * This routine will be called once for the system.
* There is one performance monitor per node, so we
* only need to perform this function once per node.
*/
@@ -687,8 +1099,17 @@ static void cell_global_stop(void)
}
}
-static void
-cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config
*ctr)
+static void cell_global_stop(void)
+{
+ if (spu_cycle_reset) {
+ cell_global_stop_spu();
+ } else {
+ cell_global_stop_ppu();
+ }
+}
+
+static void cell_handle_interrupt(struct pt_regs *regs,
+ struct op_counter_config *ctr)
{
u32 cpu;
u64 pc;
@@ -699,13 +1120,15 @@ cell_handle_interrupt(struct pt_regs *re
cpu = smp_processor_id();
- /* Need to make sure the interrupt handler and the virt counter
+ /*
+ * Need to make sure the interrupt handler and the virt counter
* routine are not running at the same time. See the
* cell_virtual_cntr() routine for additional comments.
*/
spin_lock_irqsave(&virt_cntr_lock, flags);
- /* Need to disable and reenable the performance counters
+ /*
+ * Need to disable and reenable the performance counters
* to get the desired behavior from the hardware. This
* is hardware specific.
*/
@@ -714,7 +1137,8 @@ cell_handle_interrupt(struct pt_regs *re
interrupt_mask = cbe_get_and_clear_pm_interrupts(cpu);
- /* If the interrupt mask has been cleared, then the virt cntr
+ /*
+ * If the interrupt mask has been cleared, then the virt cntr
* has cleared the interrupt. When the thread that generated
* the interrupt is restored, the data count will be restored to
* 0xffffff0 to cause the interrupt to be regenerated.
@@ -732,18 +1156,20 @@ cell_handle_interrupt(struct pt_regs *re
}
}
- /* The counters were frozen by the interrupt.
+ /*
+ * The counters were frozen by the interrupt.
* Reenable the interrupt and restart the counters.
* If there was a race between the interrupt handler and
- * the virtual counter routine. The virutal counter
+ * the virtual counter routine. The virutal counter
* routine may have cleared the interrupts. Hence must
* use the virt_cntr_inter_mask to re-enable the interrupts.
*/
cbe_enable_pm_interrupts(cpu, hdw_thread,
virt_cntr_inter_mask);
- /* The writes to the various performance counters only writes
- * to a latch. The new values (interrupt setting bits, reset
+ /*
+ * The writes to the various performance counters only writes
+ * to a latch. The new values (interrupt setting bits, reset
* counter value etc.) are not copied to the actual registers
* until the performance monitor is enabled. In order to get
* this to work as desired, the permormance monitor needs to
@@ -755,10 +1181,33 @@ cell_handle_interrupt(struct pt_regs *re
spin_unlock_irqrestore(&virt_cntr_lock, flags);
}
+/*
+ * This function is called from the generic OProfile
+ * driver. When profiling PPUs, we need to do the
+ * generic sync start; otherwise, do spu_sync_start.
+ */
+static int cell_sync_start(void)
+{
+ if (spu_cycle_reset)
+ return spu_sync_start();
+ else
+ return DO_GENERIC_SYNC;
+}
+
+static int cell_sync_stop(void)
+{
+ if (spu_cycle_reset)
+ return spu_sync_stop();
+ else
+ return 1;
+}
+
struct op_powerpc_model op_model_cell = {
.reg_setup = cell_reg_setup,
.cpu_setup = cell_cpu_setup,
.global_start = cell_global_start,
.global_stop = cell_global_stop,
+ .sync_start = cell_sync_start,
+ .sync_stop = cell_sync_stop,
.handle_interrupt = cell_handle_interrupt,
};
Index: powerpc.git/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
--- powerpc.git.orig/arch/powerpc/platforms/cell/spufs/sched.c
+++ powerpc.git/arch/powerpc/platforms/cell/spufs/sched.c
@@ -264,6 +264,7 @@ static void spu_bind_context(struct spu
ctx->spu = spu;
ctx->ops = &spu_hw_ops;
spu->pid = current->pid;
+ spu->tgid = current->tgid;
spu_associate_mm(spu, ctx->owner);
spu->ibox_callback = spufs_ibox_callback;
spu->wbox_callback = spufs_wbox_callback;
@@ -304,6 +305,7 @@ static void spu_unbind_context(struct sp
spu->dma_callback = NULL;
spu_associate_mm(spu, NULL);
spu->pid = 0;
+ spu->tgid = 0;
ctx->ops = &spu_backing_ops;
ctx->spu = NULL;
spu->flags = 0;
@@ -590,7 +592,7 @@ void spu_deactivate(struct spu_context *
}
/**
- * spu_yield - yield a physical spu if others are waiting
+ * spu_yield - yield a physical spu if others are waiting
* @ctx: spu context to yield
*
* Check if there is a higher priority context waiting and if yes
Index: powerpc.git/drivers/oprofile/buffer_sync.c
===================================================================
--- powerpc.git.orig/drivers/oprofile/buffer_sync.c
+++ powerpc.git/drivers/oprofile/buffer_sync.c
@@ -26,8 +26,9 @@
#include <linux/profile.h>
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/oprofile.h>
#include <linux/sched.h>
-
+
#include "oprofile_stats.h"
#include "event_buffer.h"
#include "cpu_buffer.h"
Index: powerpc.git/drivers/oprofile/event_buffer.h
===================================================================
--- powerpc.git.orig/drivers/oprofile/event_buffer.h
+++ powerpc.git/drivers/oprofile/event_buffer.h
@@ -19,28 +19,10 @@ void free_event_buffer(void);
/* wake up the process sleeping on the event file */
void wake_up_buffer_waiter(void);
-
-/* Each escaped entry is prefixed by ESCAPE_CODE
- * then one of the following codes, then the
- * relevant data.
- */
-#define ESCAPE_CODE ~0UL
-#define CTX_SWITCH_CODE 1
-#define CPU_SWITCH_CODE 2
-#define COOKIE_SWITCH_CODE 3
-#define KERNEL_ENTER_SWITCH_CODE 4
-#define KERNEL_EXIT_SWITCH_CODE 5
-#define MODULE_LOADED_CODE 6
-#define CTX_TGID_CODE 7
-#define TRACE_BEGIN_CODE 8
-#define TRACE_END_CODE 9
-
+
#define INVALID_COOKIE ~0UL
#define NO_COOKIE 0UL
-/* add data to the event buffer */
-void add_event_entry(unsigned long data);
-
extern const struct file_operations event_buffer_fops;
/* mutex between sync_cpu_buffers() and the
Index: powerpc.git/drivers/oprofile/oprof.c
===================================================================
--- powerpc.git.orig/drivers/oprofile/oprof.c
+++ powerpc.git/drivers/oprofile/oprof.c
@@ -53,9 +53,24 @@ int oprofile_setup(void)
* us missing task deaths and eventually oopsing
* when trying to process the event buffer.
*/
+ if (oprofile_ops.sync_start) {
+ int sync_ret = oprofile_ops.sync_start();
+ switch (sync_ret) {
+ case 0:
+ goto post_sync;
+ case 1:
+ goto do_generic;
+ case -1:
+ goto out3;
+ default:
+ goto out3;
+ }
+ }
+do_generic:
if ((err = sync_start()))
goto out3;
+post_sync:
is_setup = 1;
mutex_unlock(&start_mutex);
return 0;
@@ -118,7 +133,20 @@ out:
void oprofile_shutdown(void)
{
mutex_lock(&start_mutex);
+ if (oprofile_ops.sync_stop) {
+ int sync_ret = oprofile_ops.sync_stop();
+ switch (sync_ret) {
+ case 0:
+ goto post_sync;
+ case 1:
+ goto do_generic;
+ default:
+ goto post_sync;
+ }
+ }
+do_generic:
sync_stop();
+post_sync:
if (oprofile_ops.shutdown)
oprofile_ops.shutdown();
is_setup = 0;
Index: powerpc.git/include/asm-powerpc/oprofile_impl.h
===================================================================
--- powerpc.git.orig/include/asm-powerpc/oprofile_impl.h
+++ powerpc.git/include/asm-powerpc/oprofile_impl.h
@@ -39,14 +39,16 @@ struct op_system_config {
/* Per-arch configuration */
struct op_powerpc_model {
- void (*reg_setup) (struct op_counter_config *,
+ int (*reg_setup) (struct op_counter_config *,
struct op_system_config *,
int num_counters);
- void (*cpu_setup) (struct op_counter_config *);
- void (*start) (struct op_counter_config *);
- void (*global_start) (struct op_counter_config *);
+ int (*cpu_setup) (struct op_counter_config *);
+ int (*start) (struct op_counter_config *);
+ int (*global_start) (struct op_counter_config *);
void (*stop) (void);
void (*global_stop) (void);
+ int (*sync_start)(void);
+ int (*sync_stop)(void);
void (*handle_interrupt) (struct pt_regs *,
struct op_counter_config *);
int num_counters;
Index: powerpc.git/include/asm-powerpc/spu.h
===================================================================
--- powerpc.git.orig/include/asm-powerpc/spu.h
+++ powerpc.git/include/asm-powerpc/spu.h
@@ -137,6 +137,7 @@ struct spu {
struct spu_runqueue *rq;
unsigned long long timestamp;
pid_t pid;
+ pid_t tgid;
int class_0_pending;
spinlock_t register_lock;
@@ -195,6 +196,20 @@ extern void spu_associate_mm(struct spu
struct mm_struct;
extern void spu_flush_all_slbs(struct mm_struct *mm);
+/* This interface allows a profiler (e.g., OProfile) to store a ref
+ * to spu context information that it creates. This caching technique
+ * avoids the need to recreate this information after a save/restore
operation.
+ *
+ * Assumes the caller has already incremented the ref count to
+ * profile_info; then spu_context_destroy must call kref_put
+ * on prof_info_kref.
+ */
+void spu_set_profile_private_kref(struct spu_context *ctx,
+ struct kref *prof_info_kref,
+ void ( * prof_info_release) (struct kref *kref));
+
+void *spu_get_profile_private_kref(struct spu_context *ctx);
+
/* system callbacks from the SPU */
struct spu_syscall_block {
u64 nr_ret;
Index: powerpc.git/include/linux/oprofile.h
===================================================================
--- powerpc.git.orig/include/linux/oprofile.h
+++ powerpc.git/include/linux/oprofile.h
@@ -17,6 +17,26 @@
#include <linux/spinlock.h>
#include <asm/atomic.h>
+/* Each escaped entry is prefixed by ESCAPE_CODE
+ * then one of the following codes, then the
+ * relevant data.
+ * These #defines live in this file so that arch-specific
+ * buffer sync'ing code can access them.
+ */
+#define ESCAPE_CODE ~0UL
+#define CTX_SWITCH_CODE 1
+#define CPU_SWITCH_CODE 2
+#define COOKIE_SWITCH_CODE 3
+#define KERNEL_ENTER_SWITCH_CODE 4
+#define KERNEL_EXIT_SWITCH_CODE 5
+#define MODULE_LOADED_CODE 6
+#define CTX_TGID_CODE 7
+#define TRACE_BEGIN_CODE 8
+#define TRACE_END_CODE 9
+#define XEN_ENTER_SWITCH_CODE 10
+#define SPU_PROFILING_CODE 11
+#define SPU_CTX_SWITCH_CODE 12
+
struct super_block;
struct dentry;
struct file_operations;
@@ -35,6 +55,14 @@ struct oprofile_operations {
int (*start)(void);
/* Stop delivering interrupts. */
void (*stop)(void);
+ /* Arch-specific buffer sync functions.
+ * Return value = 0: Success
+ * Return value = -1: Failure
+ * Return value = 1: Run generic sync function
+ */
+ int (*sync_start)(void);
+ int (*sync_stop)(void);
+
/* Initiate a stack backtrace. Optional. */
void (*backtrace)(struct pt_regs * const regs, unsigned int depth);
/* CPU identification string. */
@@ -56,6 +84,13 @@ int oprofile_arch_init(struct oprofile_o
void oprofile_arch_exit(void);
/**
+ * Add data to the event buffer.
+ * The data passed is free-form, but typically consists of
+ * file offsets, dcookies, context information, and ESCAPE codes.
+ */
+void add_event_entry(unsigned long data);
+
+/**
* Add a sample. This may be called from any context. Pass
* smp_processor_id() as cpu.
*/
Index: powerpc.git/arch/powerpc/kernel/time.c
===================================================================
--- powerpc.git.orig/arch/powerpc/kernel/time.c
+++ powerpc.git/arch/powerpc/kernel/time.c
@@ -121,6 +121,7 @@ extern struct timezone sys_tz;
static long timezone_offset;
unsigned long ppc_proc_freq;
+EXPORT_SYMBOL(ppc_proc_freq);
unsigned long ppc_tb_freq;
static u64 tb_last_jiffy __cacheline_aligned_in_smp;
Index: powerpc.git/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- powerpc.git.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ powerpc.git/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -94,6 +94,8 @@ struct spu_context {
struct list_head gang_list;
struct spu_gang *gang;
+ struct kref *prof_priv_kref;
+ void ( * prof_priv_release) (struct kref *kref);
/* owner thread */
pid_t tid;
Index: powerpc.git/arch/powerpc/platforms/cell/spufs/context.c
===================================================================
--- powerpc.git.orig/arch/powerpc/platforms/cell/spufs/context.c
+++ powerpc.git/arch/powerpc/platforms/cell/spufs/context.c
@@ -22,6 +22,7 @@
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <asm/atomic.h>
#include <asm/spu.h>
@@ -81,6 +82,8 @@ void destroy_spu_context(struct kref *kr
spu_fini_csa(&ctx->csa);
if (ctx->gang)
spu_gang_remove_ctx(ctx->gang, ctx);
+ if (ctx->prof_priv_kref)
+ kref_put(ctx->prof_priv_kref, ctx->prof_priv_release);
BUG_ON(!list_empty(&ctx->rq));
atomic_dec(&nr_spu_contexts);
kfree(ctx);
@@ -169,3 +172,20 @@ void spu_acquire_saved(struct spu_contex
if (ctx->state != SPU_STATE_SAVED)
spu_deactivate(ctx);
}
+
+void spu_set_profile_private_kref(struct spu_context *ctx,
+ struct kref *prof_info_kref,
+ void ( * prof_info_release) (struct kref *kref))
+{
+ ctx->prof_priv_kref = prof_info_kref;
+ ctx->prof_priv_release = prof_info_release;
+}
+EXPORT_SYMBOL_GPL(spu_set_profile_private_kref);
+
+void *spu_get_profile_private_kref(struct spu_context *ctx)
+{
+ return ctx->prof_priv_kref;
+}
+EXPORT_SYMBOL_GPL(spu_get_profile_private_kref);
+
+
Index: powerpc.git/include/linux/dcookies.h
===================================================================
--- powerpc.git.orig/include/linux/dcookies.h
+++ powerpc.git/include/linux/dcookies.h
@@ -12,6 +12,7 @@
#ifdef CONFIG_PROFILING
+#include <linux/dcache.h>
#include <linux/types.h>
struct dcookie_user;
Index: powerpc.git/include/linux/elf-em.h
===================================================================
--- powerpc.git.orig/include/linux/elf-em.h
+++ powerpc.git/include/linux/elf-em.h
@@ -20,7 +20,8 @@
#define EM_PARISC 15 /* HPPA */
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
#define EM_PPC 20 /* PowerPC */
-#define EM_PPC64 21 /* PowerPC64 */
+#define EM_PPC64 21 /* PowerPC64 */
+#define EM_SPU 23 /* Cell BE SPU */
#define EM_SH 42 /* SuperH */
#define EM_SPARCV9 43 /* SPARC v9 64-bit */
#define EM_IA_64 50 /* HP/Intel IA-64 */
Index: powerpc.git/arch/powerpc/oprofile/op_model_rs64.c
===================================================================
--- powerpc.git.orig/arch/powerpc/oprofile/op_model_rs64.c
+++ powerpc.git/arch/powerpc/oprofile/op_model_rs64.c
@@ -88,7 +88,7 @@ static unsigned long reset_value[OP_MAX_
static int num_counters;
-static void rs64_reg_setup(struct op_counter_config *ctr,
+static int rs64_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys,
int num_ctrs)
{
@@ -100,9 +100,10 @@ static void rs64_reg_setup(struct op_cou
reset_value[i] = 0x80000000UL - ctr[i].count;
/* XXX setup user and kernel profiling */
+ return 0;
}
-static void rs64_cpu_setup(struct op_counter_config *ctr)
+static int rs64_cpu_setup(struct op_counter_config *ctr)
{
unsigned int mmcr0;
@@ -125,9 +126,11 @@ static void rs64_cpu_setup(struct op_cou
mfspr(SPRN_MMCR0));
dbg("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(),
mfspr(SPRN_MMCR1));
+
+ return 0;
}
-static void rs64_start(struct op_counter_config *ctr)
+static int rs64_start(struct op_counter_config *ctr)
{
int i;
unsigned int mmcr0;
@@ -155,6 +158,7 @@ static void rs64_start(struct op_counter
mtspr(SPRN_MMCR0, mmcr0);
dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
+ return 0;
}
static void rs64_stop(void)
Index: powerpc.git/arch/powerpc/oprofile/op_model_power4.c
===================================================================
--- powerpc.git.orig/arch/powerpc/oprofile/op_model_power4.c
+++ powerpc.git/arch/powerpc/oprofile/op_model_power4.c
@@ -30,7 +30,7 @@ static u32 mmcr0_val;
static u64 mmcr1_val;
static u64 mmcra_val;
-static void power4_reg_setup(struct op_counter_config *ctr,
+static int power4_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys,
int num_ctrs)
{
@@ -58,6 +58,8 @@ static void power4_reg_setup(struct op_c
mmcr0_val &= ~MMCR0_PROBLEM_DISABLE;
else
mmcr0_val |= MMCR0_PROBLEM_DISABLE;
+
+ return 0;
}
extern void ppc64_enable_pmcs(void);
@@ -82,7 +84,7 @@ static inline int mmcra_must_set_sample(
return 0;
}
-static void power4_cpu_setup(struct op_counter_config *ctr)
+static int power4_cpu_setup(struct op_counter_config *ctr)
{
unsigned int mmcr0 = mmcr0_val;
unsigned long mmcra = mmcra_val;
@@ -109,9 +111,11 @@ static void power4_cpu_setup(struct op_c
mfspr(SPRN_MMCR1));
dbg("setup on cpu %d, mmcra %lx\n", smp_processor_id(),
mfspr(SPRN_MMCRA));
+
+ return 0;
}
-static void power4_start(struct op_counter_config *ctr)
+static int power4_start(struct op_counter_config *ctr)
{
int i;
unsigned int mmcr0;
@@ -146,6 +150,7 @@ static void power4_start(struct op_count
oprofile_running = 1;
dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
+ return 0;
}
static void power4_stop(void)
Index: powerpc.git/arch/powerpc/oprofile/op_model_7450.c
===================================================================
--- powerpc.git.orig/arch/powerpc/oprofile/op_model_7450.c
+++ powerpc.git/arch/powerpc/oprofile/op_model_7450.c
@@ -81,7 +81,7 @@ static void pmc_stop_ctrs(void)
/* Configures the counters on this CPU based on the global
* settings */
-static void fsl7450_cpu_setup(struct op_counter_config *ctr)
+static int fsl7450_cpu_setup(struct op_counter_config *ctr)
{
/* freeze all counters */
pmc_stop_ctrs();
@@ -89,12 +89,14 @@ static void fsl7450_cpu_setup(struct op_
mtspr(SPRN_MMCR0, mmcr0_val);
mtspr(SPRN_MMCR1, mmcr1_val);
mtspr(SPRN_MMCR2, mmcr2_val);
+
+ return 0;
}
#define NUM_CTRS 6
/* Configures the global settings for the countes on all CPUs. */
-static void fsl7450_reg_setup(struct op_counter_config *ctr,
+static int fsl7450_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys,
int num_ctrs)
{
@@ -126,10 +128,12 @@ static void fsl7450_reg_setup(struct op_
| mmcr1_event6(ctr[5].event);
mmcr2_val = 0;
+
+ return 0;
}
/* Sets the counters on this CPU to the chosen values, and starts them
*/
-static void fsl7450_start(struct op_counter_config *ctr)
+static int fsl7450_start(struct op_counter_config *ctr)
{
int i;
@@ -148,6 +152,8 @@ static void fsl7450_start(struct op_coun
pmc_start_ctrs();
oprofile_running = 1;
+
+ return 0;
}
/* Stop the counters on this CPU */
@@ -193,7 +199,7 @@ static void fsl7450_handle_interrupt(str
/* The freeze bit was set by the interrupt. */
/* Clear the freeze bit, and reenable the interrupt.
* The counters won't actually start until the rfi clears
- * the PMM bit */
+ * the PM/M bit */
pmc_start_ctrs();
}
Index: powerpc.git/arch/powerpc/oprofile/op_model_fsl_booke.c
===================================================================
--- powerpc.git.orig/arch/powerpc/oprofile/op_model_fsl_booke.c
+++ powerpc.git/arch/powerpc/oprofile/op_model_fsl_booke.c
@@ -244,7 +244,7 @@ static void dump_pmcs(void)
mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
}
-static void fsl_booke_cpu_setup(struct op_counter_config *ctr)
+static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
{
int i;
@@ -258,9 +258,11 @@ static void fsl_booke_cpu_setup(struct o
set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel);
}
+
+ return 0;
}
-static void fsl_booke_reg_setup(struct op_counter_config *ctr,
+static int fsl_booke_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys,
int num_ctrs)
{
@@ -276,9 +278,10 @@ static void fsl_booke_reg_setup(struct o
for (i = 0; i < num_counters; ++i)
reset_value[i] = 0x80000000UL - ctr[i].count;
+ return 0;
}
-static void fsl_booke_start(struct op_counter_config *ctr)
+static int fsl_booke_start(struct op_counter_config *ctr)
{
int i;
@@ -308,6 +311,8 @@ static void fsl_booke_start(struct op_co
pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(),
mfpmr(PMRN_PMGC0));
+
+ return 0;
}
static void fsl_booke_stop(void)
Index: powerpc.git/arch/powerpc/oprofile/op_model_pa6t.c
===================================================================
--- powerpc.git.orig/arch/powerpc/oprofile/op_model_pa6t.c
+++ powerpc.git/arch/powerpc/oprofile/op_model_pa6t.c
@@ -89,7 +89,7 @@ static inline void ctr_write(unsigned in
/* precompute the values to stuff in the hardware registers */
-static void pa6t_reg_setup(struct op_counter_config *ctr,
+static int pa6t_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys,
int num_ctrs)
{
@@ -135,10 +135,12 @@ static void pa6t_reg_setup(struct op_cou
pr_debug("reset_value for pmc%u inited to 0x%lx\n",
pmc, reset_value[pmc]);
}
+
+ return 0;
}
/* configure registers on this cpu */
-static void pa6t_cpu_setup(struct op_counter_config *ctr)
+static int pa6t_cpu_setup(struct op_counter_config *ctr)
{
u64 mmcr0 = mmcr0_val;
u64 mmcr1 = mmcr1_val;
@@ -154,9 +156,11 @@ static void pa6t_cpu_setup(struct op_cou
mfspr(SPRN_PA6T_MMCR0));
pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(),
mfspr(SPRN_PA6T_MMCR1));
+
+ return 0;
}
-static void pa6t_start(struct op_counter_config *ctr)
+static int pa6t_start(struct op_counter_config *ctr)
{
int i;
@@ -174,6 +178,8 @@ static void pa6t_start(struct op_counter
oprofile_running = 1;
pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+
+ return 0;
}
static void pa6t_stop(void)
^ permalink raw reply
* [PATCH 1/2] Enable SPU switch notification to detect currently active SPU tasks.
From: Bob Nelson @ 2007-07-12 23:45 UTC (permalink / raw)
To: Andrew Morton; +Cc: linuxppc, oprofile, Philippe Elie
We would like this patch included in -mm and in 2.6.23.
Subject: Enable SPU switch notification to detect currently active SPU
tasks.
From: Maynard Johnson <mpjohn@us.ibm.com>
This patch adds to the capability of spu_switch_event_register so that
the
caller is also notified of currently active SPU tasks. It also exports
spu_switch_event_register and spu_switch_event_unregister.
Signed-off-by: Maynard Johnson <mpjohn@us.ibm.com>
Signed-off-by: Carl Love <carll@us.ibm.com>
Signed-off-by: Bob Nelson <rrnelson@us.ibm.com>
Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Acked-by: Paul Mackerras <paulus@samba.org>
Index: powerpc.git/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
--- powerpc.git.orig/arch/powerpc/platforms/cell/spufs/sched.c
+++ powerpc.git/arch/powerpc/platforms/cell/spufs/sched.c
@@ -204,21 +204,47 @@ static void spu_remove_from_active_list(
static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier);
-static void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
+void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
{
blocking_notifier_call_chain(&spu_switch_notifier,
ctx ? ctx->object_id : 0, spu);
}
+static void notify_spus_active(void)
+{
+ int node;
+ /* Wake up the active spu_contexts. When the awakened processes
+ * see their "notify_active" flag is set, they will call
+ * spu_switch_notify();
+ */
+ for (node = 0; node < MAX_NUMNODES; node++) {
+ struct spu *spu;
+ mutex_lock(&spu_prio->active_mutex[node]);
+ list_for_each_entry(spu, &spu_prio->active_list[node], list) {
+ struct spu_context *ctx = spu->ctx;
+ set_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags);
+ mb();
+ wake_up_all(&ctx->stop_wq);
+ }
+ mutex_unlock(&spu_prio->active_mutex[node]);
+ }
+}
+
int spu_switch_event_register(struct notifier_block * n)
{
- return blocking_notifier_chain_register(&spu_switch_notifier, n);
+ int ret;
+ ret = blocking_notifier_chain_register(&spu_switch_notifier, n);
+ if (!ret)
+ notify_spus_active();
+ return ret;
}
+EXPORT_SYMBOL_GPL(spu_switch_event_register);
int spu_switch_event_unregister(struct notifier_block * n)
{
return blocking_notifier_chain_unregister(&spu_switch_notifier, n);
}
+EXPORT_SYMBOL_GPL(spu_switch_event_unregister);
/**
* spu_bind_context - bind spu context to physical spu
Index: powerpc.git/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- powerpc.git.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ powerpc.git/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -53,6 +53,11 @@ enum spuctx_execution_state {
SPUCTX_UTIL_MAX
};
+/* ctx->sched_flags */
+enum {
+ SPU_SCHED_NOTIFY_ACTIVE,
+};
+
struct spu_context {
struct spu *spu; /* pointer to a physical SPU */
struct spu_state csa; /* SPU context save area. */
@@ -231,6 +236,7 @@ void spu_acquire_saved(struct spu_contex
int spu_activate(struct spu_context *ctx, unsigned long flags);
void spu_deactivate(struct spu_context *ctx);
void spu_yield(struct spu_context *ctx);
+void spu_switch_notify(struct spu *spu, struct spu_context *ctx);
void spu_set_timeslice(struct spu_context *ctx);
void spu_update_sched_info(struct spu_context *ctx);
void __spu_update_sched_info(struct spu_context *ctx);
Index: powerpc.git/arch/powerpc/platforms/cell/spufs/run.c
===================================================================
--- powerpc.git.orig/arch/powerpc/platforms/cell/spufs/run.c
+++ powerpc.git/arch/powerpc/platforms/cell/spufs/run.c
@@ -18,15 +18,17 @@ void spufs_stop_callback(struct spu *spu
wake_up_all(&ctx->stop_wq);
}
-static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
+static inline int spu_stopped(struct spu_context *ctx, u32 *stat)
{
struct spu *spu;
u64 pte_fault;
*stat = ctx->ops->status_read(ctx);
- if (ctx->state != SPU_STATE_RUNNABLE)
- return 1;
+
spu = ctx->spu;
+ if (ctx->state != SPU_STATE_RUNNABLE ||
+ test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags))
+ return 1;
pte_fault = spu->dsisr &
(MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
return (!(*stat & SPU_STATUS_RUNNING) || pte_fault ||
spu->class_0_pending) ?
@@ -124,7 +126,7 @@ out:
return ret;
}
-static int spu_run_init(struct spu_context *ctx, u32 * npc)
+static int spu_run_init(struct spu_context *ctx, u32 *npc)
{
if (ctx->flags & SPU_CREATE_ISOLATE) {
unsigned long runcntl;
@@ -154,8 +156,8 @@ static int spu_run_init(struct spu_conte
return 0;
}
-static int spu_run_fini(struct spu_context *ctx, u32 * npc,
- u32 * status)
+static int spu_run_fini(struct spu_context *ctx, u32 *npc,
+ u32 *status)
{
int ret = 0;
@@ -293,6 +295,7 @@ long spufs_run_spu(struct file *file, st
u32 *npc, u32 *event)
{
int ret;
+ struct spu *spu;
u32 status;
if (mutex_lock_interruptible(&ctx->run_mutex))
@@ -326,8 +329,17 @@ long spufs_run_spu(struct file *file, st
do {
ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
+ spu = ctx->spu;
if (unlikely(ret))
break;
+ if (unlikely(test_bit(SPU_SCHED_NOTIFY_ACTIVE,
+ &ctx->sched_flags))) {
+ clear_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags);
+ if (!(status & SPU_STATUS_STOPPED_BY_STOP)) {
+ spu_switch_notify(spu, ctx);
+ continue;
+ }
+ }
if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
(status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
ret = spu_process_callback(ctx);
^ permalink raw reply
* Re: Weird oopses with 2.6.22-rc7
From: Nathan Lynch @ 2007-07-12 23:37 UTC (permalink / raw)
To: Christian Kujau; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <alpine.DEB.0.99.0707130016270.18512@sheep.housecafe.de>
Hello-
Christian Kujau wrote:
> Hi there,
>
> Since a few days I'm experiencing weird oopses on my iBook/G4 with
> ubuntu's 2.6.22-7-powerpc and also with a vanilla 2.6.22-rc7-git8.
>
> Now for the "weird" part: The oops happens when doing "make install" for
> a piece of software (xine-ui media player) as *root*. No kidding, it
> does NOT happen when I compile the software and do "make install" as a
> normal user. This is 100% reproducible, here're some technical infos
> before I go on describing whe I did:
>
> http://nerdbynature.de/bits/2.6.22-rc7-git8/
Here's the first oops from the "dmesg" file:
Unrecoverable FP Unavailable Exception 801 at efff20b0
Oops: Unrecoverable FP Unavailable Exception, sig: 6 [#1]
PREEMPT PowerMac
Modules linked in:
NIP: efff20b0 LR: c008dff4 CTR: efff20b0
REGS: ef7cbd90 TRAP: 0801 Not tainted
t8)
MSR: 00009032 <EE,ME,IR,DR> CR: 28028428 XER: 00000000
TASK = cfd9b800[1625] 'touch' THREAD: ef7ca000
GPR00: efff20b0 ef7cbe40 cfd9b800 ec049240 00000002 ef7cbea0 00000000 0ff29604
GPR08: 00000001 eff78d00 ef7ca000 00000000 28022422
NIP [efff20b0] 0xefff20b0
LR [c008dff4] permission+0x78/0x170
Call Trace:
[ef7cbe40] [00010942] 0x10942 (unreliable)
[ef7cbe60] [c00ac440] do_utimes+0x1cc/0x1f4
[ef7cbf10] [c00ac630] sys_utimensat+0xac/0x138
[ef7cbf40] [c00118ec] ret_from_syscall+0x0/0x38
> Any ideas which magic syscall could cause these oopses?
Have you tried 2.6.22? Linus committed a utimensat-related oops fix
right before releasing it:
http://git.kernel.org/gitweb.cgi?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=1e5de2837c166535f9bb4232bfe97ea1f9fc7a1c
^ permalink raw reply
* Weird oopses with 2.6.22-rc7
From: Christian Kujau @ 2007-07-12 22:37 UTC (permalink / raw)
To: linux-kernel; +Cc: linuxppc-dev
Hi there,
Since a few days I'm experiencing weird oopses on my iBook/G4 with
ubuntu's 2.6.22-7-powerpc and also with a vanilla 2.6.22-rc7-git8.
Now for the "weird" part: The oops happens when doing "make install" for
a piece of software (xine-ui media player) as *root*. No kidding, it
does NOT happen when I compile the software and do "make install" as a
normal user. This is 100% reproducible, here're some technical infos
before I go on describing whe I did:
http://nerdbynature.de/bits/2.6.22-rc7-git8/
I've compiled this software earlier, numerous times, always doing
"make" as a user and "sudo make install" afterwards to install to
/opt/xine. So when I now tried "make install" as a user I had to chown
/opt/xine to the user of course.
Even funnier: the dmesg output was captured when I was in
runlevel 1 - here "make install" (as root) did produce an oops too, but
the system did NOT panic. I typed "make install" a few times - always an
oops, but no panic (in runlevel 1).
The netconsole.log captured the panics as well, but the output is kinda
messy (as always), I'll try to reformat the logfile a bit...
When the Oopses started I checked memory (no memtest86 for ppc, but
userspace memtest found nothing) and the harddisk (dd'ing from the whole
disk) and fsck'ed the ext3 - not a single error. Also, all other
applications are running fine (X11, music, video and stuff),
the system is stable as usual.
I even moved the old target-directory (make install...) out of the way
and created a new one (new inode, new luck or so) - but to no avail.
"fsck.ext3 -D" to reindex the directories, still the Oopses just won't
go away. Searching the net for "Unrecoverable FP Unavailable Exception"
did not return much :(
Any ideas which magic syscall could cause these oopses?
Thanks,
Christian.
--
BOFH excuse #409:
The vulcan-death-grip ping has been applied.
^ permalink raw reply
* Help required for porting ISP1362 usb device driver
From: Vikram Kone @ 2007-07-12 22:57 UTC (permalink / raw)
To: linuxppc-dev, linuxppc-embedded
[-- Attachment #1.1: Type: text/plain, Size: 1692 bytes --]
Hi..
I'm a linux newbie and im working on porting the USB driver ISP1362 by
Philips on to my Freescale ppc board.
I dont know how to do this... so if any of you can tell me how to do this
step by step, i would be very grateful to you
Few details..
I'm running RHEL with kernel 2.4.21 on a PC (i386 machine)
Target Machine is MPC8548 CDS by Free scale (ppc architecture) running
kernel version 2.6.11
I do have a ppc tool chain, if that helps.....but i dont know how to use it
Thanks
P.S. I downloaded the deive driver and host controller drivers from
sourceforge.net and both of them seem to work for 2.6.6 kernel for i386 arch
..
P.P.S : Wolfgang ??!1 Can you help me out... I went through the archives on
the list and seems thatu answered many Qs on this driver. But i didnt find
any post specifcally for my problem..so

<http://www.cisco.com/global/EMEA/brand/signature/default/spacer.gif>
Vikram Kone
College Intern
EWTG GSBU
vkone@cisco.com
Phone :+1 408 853 8916
Mobile :+1 919 457 8792
Cisco Systems, Inc.
170 West Tasman Drive,
San Jose, CA 95134-1706
USA
www.cisco.com <http://www.cisco.com/>
<http://www.cisco.com/global/EMEA/brand/signature/default/footerHead.gif>
This e-mail may contain confidential and privileged material for the sole
use of the intended recipient. Any review, use, distribution or disclosure
by others is strictly prohibited. If you are not the intended recipient (or
authorized to receive for the recipient), please contact the sender by reply
e-mail and delete all copies of this message.
<http://www.cisco.com/global/EMEA/brand/signature/default/footer.gif>
[-- Attachment #1.2: Type: text/html, Size: 5947 bytes --]
[-- Attachment #2: spacer.gif --]
[-- Type: image/gif, Size: 51 bytes --]
[-- Attachment #3: footerHead.gif --]
[-- Type: image/gif, Size: 68 bytes --]
[-- Attachment #4: footer.gif --]
[-- Type: image/gif, Size: 347 bytes --]
^ permalink raw reply
* Help required on porting ISP1362 driver to ppc
From: Vikram Kone (vkone) @ 2007-07-12 22:56 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: linuxppc-dev
[-- Attachment #1.1: Type: text/plain, Size: 1458 bytes --]
Hi..
I'm a linux newbie and im working on porting the USB driver ISP1362 by Philips on to my Freescale ppc board.
I dont know how to do this... so if any of you can tell me how to do this step by step, i would be very grateful to you
Few details..
I'm running RHEL with kernel 2.4.21 on a PC (i386 machine)
Target Machine is MPC8548 CDS by Free scale (ppc architecture) running kernel version 2.6.11
I do have a ppc tool chain, if that helps.....but i dont know how to use it
Thanks
P.S. I downloaded the deive driver and host controller drivers from sourceforge.net and both of them seem to work for 2.6.6 kernel for i386 arch ..
P.P.S : Wolfgang ??!1 Can you help me out... I went through the archives on the list and seems thatu answered many Qs on this driver. But i didnt find any post specifcally for my problem..so

Vikram Kone
College Intern
EWTG GSBU
vkone@cisco.com
Phone :+1 408 853 8916
Mobile :+1 919 457 8792
Cisco Systems, Inc.
170 West Tasman Drive,
San Jose, CA 95134-1706
USA
www.cisco.com <http://www.cisco.com/>
This e-mail may contain confidential and privileged material for the sole use of the intended recipient. Any review, use, distribution or disclosure by others is strictly prohibited. If you are not the intended recipient (or authorized to receive for the recipient), please contact the sender by reply e-mail and delete all copies of this message.
[-- Attachment #1.2: Type: text/html, Size: 5947 bytes --]
[-- Attachment #2: spacer.gif --]
[-- Type: image/gif, Size: 51 bytes --]
[-- Attachment #3: footerHead.gif --]
[-- Type: image/gif, Size: 68 bytes --]
[-- Attachment #4: footer.gif --]
[-- Type: image/gif, Size: 347 bytes --]
^ permalink raw reply
* Re: XSysAce driver cant mount DOS part
From: Grant Likely @ 2007-07-12 22:51 UTC (permalink / raw)
To: Robertson, Joseph M.; +Cc: linuxppc-embedded
In-Reply-To: <939D37AEB47F1F49B88FAB6599B6023501A17209@hsv1dafpew02.das.gov.sanm.corp>
On 7/12/07, Robertson, Joseph M. <joseph.robertson@sanmina-sci.com> wrote:
> Hi,
>
> Ok this is surely enough to drive you nuts, but all I get is an error.
> How the heck do you debug patch? All I get is this.
>
> root@tocnet_ws_9:/mnt/public2/ecau/src/linux/linux-2.6.17.1#
> patch -p1 -un -i xsys.patch
> patch unexpectedly ends in middle of line
> patch: **** Only garbage was found in the patch input.
The Gmane web view mangles patches. You can use an NNTP client to
talk to gmane to get them without mangling.
But to keep things simple, I'll just email you the patch.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* Re: [PATCH] fix idr_get_new_above id alias bugs
From: Chuck Ebbert @ 2007-07-12 21:56 UTC (permalink / raw)
To: Andrew Morton
Cc: Tejun Heo, Kristian Hoegsberg, linux-kernel, openib-general,
Stefan Roscher, linuxppc-dev, raisch, Hoang-Nam Nguyen,
jim.houston
In-Reply-To: <20070712143501.2c2cdf1f.akpm@linux-foundation.org>
On 07/12/2007 05:35 PM, Andrew Morton wrote:
>>
>> With this patch, idr.c should work as advertised allocating id
>> values in the range 0...0x7fffffff. Andrew had speculated that
>> it should allow the full range 0...0xffffffff to be used. I was
>> tempted to make changes to allow this, but it would require changes
>> to API, e.g. making the starting id value and the return value
>> unsigned.
>
> Problem. There are a large number of IDR changes pending and this
> patch breaks in way which I am not at all confident in fixing.
>
> Originarily I'd just dump the earlier patches because bugfixes come
> first. But this time there's a very large dependency trail on the
> earlier patches (especially Tejun's extensive sysfs rework in Greg's
> driver tree) so the wreckage would be extensive.
>
> Also, it's possible that Tejun's changes already fixed some of the things
> which you fixed. Or added new bugs ;)
>
> Bottom line: a reworked patch against 2.6.22-rc6-mm1 would be muchly
> appreciated if poss, please.
>
> While you're there, it would be helpful if you could review all these
> pending IDR changes:
>
> ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.22-rc6/2.6.22-rc6-mm1/broken-out/gregkh-driver-ida-implement-idr-based-id-allocator.patch
> ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.22-rc6/2.6.22-rc6-mm1/broken-out/gregkh-driver-idr-fix-obscure-bug-in-allocation-path.patch
> ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.22-rc6/2.6.22-rc6-mm1/broken-out/gregkh-driver-idr-separate-out-idr_mark_full.patch
> ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.22-rc6/2.6.22-rc6-mm1/broken-out/lib-add-idr_for_each.patch
> ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.22-rc6/2.6.22-rc6-mm1/broken-out/lib-add-idr_for_each-fix.patch
> ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.22-rc6/2.6.22-rc6-mm1/broken-out/lib-add-idr_remove_all.patch
>
The first three just got merged into mainline...
^ permalink raw reply
* [PATCH 1/5] autoselect optimal -mcpu= flag by platform
From: Arnd Bergmann @ 2007-07-12 21:12 UTC (permalink / raw)
To: paulus; +Cc: linuxppc-dev
In-Reply-To: <20070712210156.973038514@arndb.de>
We can choose the -mcpu= gcc flags for compiling the kernel
based on the platform that we build for. In case of multiplatform
kernels, this chooses a setting for a common subset.
When using a platform type that can use different CPUs, a
new option CONFIG_PPC_CPU_SELECTION can be enabled to select
more specifically which CPUs the kernel will be able to
run on.
This replaces the CONFIG_POWER4_ONLY option with an much more
generic approach.
Also, when CONFIG_PPC_CPU_SELECTION is set, it is now possible
to select a CPU to tune for by means of the -mtune= option.
I tried to be very careful when coding the specific rules into
the Kconfig language, but it would be good to have a few
people sanity-checking them.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
updates include:
- lots of added help texts
- pass -mcpu=power3 instead of -mcpu=powerpc64 to work around a gcc bug
-
Index: linux-2.6/arch/powerpc/platforms/4xx/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/4xx/Kconfig
+++ linux-2.6/arch/powerpc/platforms/4xx/Kconfig
@@ -87,6 +87,7 @@ endmenu
# 40x specific CPU modules, selected based on the board above.
config NP405H
bool
+ select CPU_405
#depends on ASH
# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
@@ -94,6 +95,7 @@ config 403GCX
bool
#depends on OAK
select IBM405_ERR51
+ select CPU_403
config 405GP
bool
@@ -102,19 +104,23 @@ config 405GP
config 405EP
bool
+ select CPU_405
config 405GPR
bool
+ select CPU_405
config VIRTEX_II_PRO
bool
select IBM405_ERR77
select IBM405_ERR51
+ select CPU_405
config STB03xxx
bool
select IBM405_ERR77
select IBM405_ERR51
+ select CPU_405
# 40x errata/workaround config symbols, selected by the CPU models above
@@ -168,20 +174,25 @@ config 440EP
bool
select PPC_FPU
select IBM440EP_ERR42
+ select CPU_440
config 440GP
bool
select IBM_NEW_EMAC_ZMII
+ select CPU_440
config 440GX
bool
+ select CPU_440
config 440SP
bool
+ select CPU_440
config 440A
bool
depends on 440GX
+ select CPU_440
default y
# 44x errata/workaround config symbols, selected by the CPU models above
Index: linux-2.6/arch/powerpc/platforms/52xx/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/52xx/Kconfig
+++ linux-2.6/arch/powerpc/platforms/52xx/Kconfig
@@ -25,12 +25,14 @@ config PPC_EFIKA
select RTAS_PROC
select PPC_MPC52xx
select PPC_NATIVE
+ select CPU_603e
default n
config PPC_LITE5200
bool "Freescale Lite5200 Eval Board"
depends on PPC_MULTIPLATFORM && PPC32
select PPC_MPC5200
+ select CPU_603e
default n
Index: linux-2.6/arch/powerpc/platforms/82xx/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/82xx/Kconfig
+++ linux-2.6/arch/powerpc/platforms/82xx/Kconfig
@@ -10,6 +10,7 @@ config MPC82xx_ADS
select 8272
select 8260
select FSL_SOC
+ select CPU_603e
help
This option enables support for the MPC8272 ADS board
Index: linux-2.6/arch/powerpc/platforms/83xx/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/83xx/Kconfig
+++ linux-2.6/arch/powerpc/platforms/83xx/Kconfig
@@ -6,6 +6,7 @@ choice
config MPC8313_RDB
bool "Freescale MPC8313 RDB"
select DEFAULT_UIMAGE
+ select CPU_603e
help
This option enables support for the MPC8313 RDB board.
@@ -13,6 +14,7 @@ config MPC832x_MDS
bool "Freescale MPC832x MDS"
select DEFAULT_UIMAGE
select QUICC_ENGINE
+ select CPU_603e
help
This option enables support for the MPC832x MDS evaluation board.
@@ -20,12 +22,14 @@ config MPC832x_RDB
bool "Freescale MPC832x RDB"
select DEFAULT_UIMAGE
select QUICC_ENGINE
+ select CPU_603e
help
This option enables support for the MPC8323 RDB board.
config MPC834x_MDS
bool "Freescale MPC834x MDS"
select DEFAULT_UIMAGE
+ select CPU_603e
help
This option enables support for the MPC 834x MDS evaluation board.
@@ -37,6 +41,7 @@ config MPC834x_MDS
config MPC834x_ITX
bool "Freescale MPC834x ITX"
select DEFAULT_UIMAGE
+ select CPU_603e
help
This option enables support for the MPC 834x ITX evaluation board.
@@ -47,6 +52,7 @@ config MPC836x_MDS
bool "Freescale MPC836x MDS"
select DEFAULT_UIMAGE
select QUICC_ENGINE
+ select CPU_603e
help
This option enables support for the MPC836x MDS Processor Board.
Index: linux-2.6/arch/powerpc/platforms/86xx/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/86xx/Kconfig
+++ linux-2.6/arch/powerpc/platforms/86xx/Kconfig
@@ -7,6 +7,7 @@ config MPC8641_HPCN
bool "Freescale MPC8641 HPCN"
select PPC_I8259
select DEFAULT_UIMAGE
+ select CPU_7450
help
This option enables support for the MPC8641 HPCN board.
Index: linux-2.6/arch/powerpc/platforms/Kconfig.cputype
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/Kconfig.cputype
+++ linux-2.6/arch/powerpc/platforms/Kconfig.cputype
@@ -51,14 +51,352 @@ config E200
endchoice
-config POWER4_ONLY
- bool "Optimize for POWER4"
+config PPC_CPU_SELECTION
+ bool "Advanced CPU selection"
+ help
+ The kernel can be built for a range of CPU types, which it
+ normally determines automatically from the platform types that
+ have been enabled. In order to optimized leaving out support
+ for the older CPUs or selecting the exact -mtune= option that
+ is passed to gcc, you can further optimize the kernel for a
+ particular system.
+
+ Selecting this option will not cause changes directly, but will
+ reveal further options.
+
+ If unsure, say N.
+
+config CPU_DEFAULT
+ bool "Don't specify -mcpu= to gcc" if PPC_CPU_SELECTION
+ help
+ When this option is selected, gcc is called without
+ any specific -mcpu= argument, regardless of which
+ CPUs are enabled in the next options.
+
+config CPU_RS64
+ bool "RS64" if PPC_CPU_SELECTION
depends on PPC64
- default n
- ---help---
- Cause the compiler to optimize for POWER4/POWER5/PPC970 processors.
- The resulting binary will not work on POWER3 or RS64 processors
- when compiled with binutils 2.15 or later.
+ default y if PPC_PSERIES || PPC_ISERIES
+ help
+ Select this if you want to have support for the first
+ generation of 64 bit PowerPC CPUs used in the late
+ 1990s in IBM RS/6000 and AS/400 machines.
+
+config CPU_POWER3
+ bool "IBM Power3" if PPC_CPU_SELECTION
+ depends on PPC64
+ default y if PPC_PSERIES
+ help
+ Select this if you want to have support for the
+ Power3 chip used in IBM RS/6000 and early pSeries
+ machines.
+
+config CPU_POWER4
+ bool "IBM Power4" if PPC_CPU_SELECTION
+ depends on PPC64
+ default y if PPC_PSERIES || PPC_ISERIES
+ help
+ Select this if you want to have support for the Power 4
+ processor used in IBM pSeries and iSeries machines.
+
+config CPU_POWER5
+ bool "IBM Power5" if PPC_CPU_SELECTION
+ depends on PPC64
+ default y if PPC_PSERIES
+ help
+ Select this if you want to have support for the Power 5
+ processor used in IBM System p and System i machines.
+
+config CPU_POWER6
+ bool "IBM Power6" if PPC_CPU_SELECTION
+ depends on PPC64
+ default y if PPC_PSERIES
+ select ALTIVEC
+ help
+ Select this if you want to have support for the Power 6
+ processor used in the latest IBM System p and System i
+ machines.
+
+config CPU_970
+ bool "IBM PowerPC 970 (G5)" if PPC_CPU_SELECTION
+ depends on PPC64
+ default y if PPC_PSERIES
+ select ALTIVEC
+ help
+ Select this if you want to have support for the PowerPC 970
+ processor used in Apple Power Macintosh G5 and IBM JS2x blade
+ servers and other systems.
+
+config CPU_CELL
+ bool "Sony/Toshiba/IBM Cell Broadband Engine" if PPC_CPU_SELECTION
+ depends on PPC64
+ select ALTIVEC
+ help
+ Select this if you want to have support for the Cell Broadband
+ Engine processor used the Sony Playstation 3, the IBM QS2x
+ blade servers and other systems.
+
+config CPU_PA6T
+ bool "PA Semi PA6T-1682M" if PPC_CPU_SELECTION
+ depends on PPC64
+ select ALTIVEC
+ help
+ Select this if you want to have support for the PA6T-1682M
+ processor from PA Semi.
+
+config CPU_601
+ bool "PowerPC 601 (G1)" if PPC_CPU_SELECTION
+ depends on 6xx
+ default PPC_CHRP || PPC_PREP
+ help
+ Select this if you really wish to have support for ancient PowerPC
+ 601 processors used in very early Power Macintosh machines and
+ some CHRP boards.
+ Most people will want to disable this option to get better
+ performance on modern machines.
+
+config CPU_603e
+ bool "PowerPC 603e, 604, 604e, 52xx, 82xx, 83xx (G2)" if PPC_CPU_SELECTION
+ depends on 6xx
+ default PPC_CHRP || PPC_PREP || PPC_PMAC
+ help
+ The 603e processor line is the most widespread implementation of
+ the PowerPC ISA, so you most likely want to enable this if you are
+ building a kernel for multiple platforms.
+
+config CPU_750
+ bool "PowerPC 740, 750 (G3)" if PPC_CPU_SELECTION
+ depends on 6xx
+ default PPC_PMAC
+ help
+ Select this for the G3 PowerPC 750 processor used in Apple
+ Power Macintosh and a number of embedded boards.
+
+config CPU_7400
+ bool "PowerPC 7400, 7410 (G4)" if PPC_CPU_SELECTION
+ depends on 6xx
+ default PPC_PMAC
+ select ALTIVEC
+ help
+ Select this for the early G4 PowerPC 7400 processor used in
+ a few Apple Power Macintosh and other machines.
+
+config CPU_7450
+ bool "PowerPC 744x, 745x, 86xx (G4)" if PPC_CPU_SELECTION
+ depends on 6xx
+ default PPC_PMAC
+ select ALTIVEC
+ help
+ Select this for the later G4 PowerPC 7450 processor and its
+ derivatives used in most of the late Apple Power Macintosh
+ machines and some high-performance embedded boards.
+
+config CPU_8540
+ bool "Freescale e500v1 (MPC8540 compatible)" if PPC_CPU_SELECTION
+ depends on PPC_85xx
+ help
+ Select this for the older version 1 of the e500 core used in
+ the earlier MPC85xx processors.
+
+config CPU_8548
+ bool "Freescale e500v2 (MPC8548 compatible)" if PPC_CPU_SELECTION
+ depends on PPC_85xx
+ help
+ Select this for the newer version 2 of the e500 core that was
+ first used in the MPC8548 processor.
+ Some versions of gcc don't know about this yet, so you may
+ also have to enable 8540 to get the best performance with
+ your compiler.
+
+config CPU_403
+ bool "IBM 403" if PPC_CPU_SELECTION
+ depends on 40x
+ help
+ The PowerPC 403 core is used in the first generation Tivo and
+ some other old machines. Select this only if you are sure that
+ you want to run your kernel on one of these machines.
+
+config CPU_405
+ bool "IBM/AMCC 405" if PPC_CPU_SELECTION
+ depends on 40x
+ default y
+ help
+ Practically all PowerPC 40x based platforms supported by Linux use
+ a 405 core, so you should enable this option.
+
+config CPU_440
+ bool "IBM/AMCC 440" if PPC_CPU_SELECTION
+ depends on 44x
+ default y
+ help
+ If you are building for a PowerPC 440 based, you don't really
+ have a choice here, say Y.
+
+choice
+ prompt "Tune for processor type" if PPC_CPU_SELECTION
+ default TUNE_POWER4 if PPC64
+ default TUNE_DEFAULT
+ help
+ This will choose the gcc flag to use for the -mtune= parameter.
+ See the above list for a description of the invidual options.
+
+ If unsure, select TUNE_DEFAULT, gcc will tune for the oldest
+ CPU that the kernel supports in that case, which usually
+ gives reasonable results on newer CPUs as well.
+
+config TUNE_DEFAULT
+ bool "Don't specify -mtune= to gcc"
+
+config TUNE_RS64
+ bool "RS64"
+ depends on CPU_RS64
+
+config TUNE_POWER3
+ bool "IBM Power3"
+ depends on CPU_POWER3
+
+config TUNE_POWER4
+ bool "IBM Power4"
+ depends on CPU_POWER4
+
+config TUNE_POWER5
+ bool "IBM Power5"
+ depends on CPU_POWER5
+
+config TUNE_POWER6
+ bool "IBM Power6"
+ depends on CPU_POWER6
+
+config TUNE_970
+ bool "IBM PowerPC 970 (G5)"
+ depends on CPU_970
+
+config TUNE_CELL
+ bool "Sony/Toshiba/IBM Cell Broadband Engine"
+ depends on CPU_CELL
+
+config TUNE_PA6T
+ bool "PA Semi PA6T-1682M"
+ depends on CPU_PA6T
+
+config TUNE_601
+ bool "PowerPC 601 (G1)"
+ depends on CPU_601
+
+config TUNE_603e
+ bool "PowerPC 603e, 604, 604e, 52xx, 82xx, 83xx (G2)"
+ depends on CPU_603e
+
+config TUNE_750
+ bool "PowerPC 740/750 (G3)"
+ depends on CPU_750
+
+config TUNE_7400
+ bool "PowerPC 7400, 7410 (G4)"
+ depends on CPU_7400
+
+config TUNE_7450
+ bool "PowerPC 744x, 745x, 86xx (G4)"
+ depends on CPU_7450
+
+config TUNE_821
+ bool "Freescale MPC821"
+ depends on 8xx
+
+config TUNE_823
+ bool "Freescale MPC823"
+ depends on 8xx
+
+config TUNE_860
+ bool "Freescale MPC860"
+ depends on 8xx
+
+config TUNE_403
+ bool "IBM 403"
+ depends on CPU_403
+
+config TUNE_405
+ bool "IBM/AMCC 405"
+ depends on CPU_405
+
+config TUNE_440
+ bool "IBM/AMCC 440"
+ depends on CPU_440
+
+config TUNE_8540
+ bool "Freescale e500v1"
+ depends on CPU_8540
+
+config TUNE_8548
+ bool "Freescale e500v2"
+ depends on CPU_8548
+
+config TUNE_E200
+ bool "Freescale e200"
+ depends on E200
+
+endchoice
+
+config PPC_MCPU
+ string
+ default "" if CPU_DEFAULT
+ default "-mcpu=power3" if CPU_POWER3 || CPU_RS64
+ default "-mcpu=power4" if (CPU_POWER5 || CPU_POWER6) && (CPU_970 || CPU_CELL || CPU_PA6T)
+ default "-mcpu=power4" if CPU_POWER4
+ default "-mcpu=power5" if CPU_POWER5
+ default "-mcpu=power6" if CPU_POWER6
+ default "-mcpu=970" if CPU_970
+ default "-mcpu=cell" if CPU_CELL
+ default "-mcpu=pa6t" if CPU_PA6T
+ default "-mcpu=power3" if PPC64
+ default "-mcpu=powerpc" if CPU_601 && (CPU_603e || CPU_750 || CPU_7400 || CPU_7450)
+ default "-mcpu=601" if CPU_601
+ default "-mcpu=603e" if CPU_603e
+ default "-mcpu=750" if CPU_750
+ default "-mcpu=7400" if CPU_7400
+ default "-mcpu=7450" if CPU_7450
+ default "-mcpu=8540" if CPU_8540
+ default "-mcpu=8548" if CPU_8548
+ default "-mcpu=powerpc" if (CPU_403 && CPU_405)
+ default "-mcpu=powerpc" if (CPU_403 || CPU_405) && CPU_440
+ default "-mcpu=403" if CPU_403
+ default "-mcpu=405" if CPU_405
+ default "-mcpu=440" if CPU_440
+ default "-mcpu=860" if PPC_8xx
+ default "-mcpu=e200" if E200
+ default "-mcpu=powerpc"
+
+config PPC_MTUNE
+ string
+ default "" if TUNE_DEFAULT
+ default "-mtune=power3" if TUNE_POWER3
+ default "-mtune=rs64a" if TUNE_RS64
+ default "-mtune=power4" if TUNE_POWER4
+ default "-mtune=power5" if TUNE_POWER5
+ default "-mtune=power6" if TUNE_POWER6
+ default "-mtune=970" if TUNE_970
+ default "-mtune=cell" if TUNE_CELL
+ default "-mtune=pa6t" if TUNE_PA6T
+ default "-mtune=601" if TUNE_601
+ default "-mtune=603e" if TUNE_603e
+ default "-mtune=750" if TUNE_750
+ default "-mtune=7400" if TUNE_7400
+ default "-mtune=7450" if TUNE_7450
+ default "-mtune=8540" if TUNE_8540
+ default "-mtune=8548" if TUNE_8548
+ default "-mtune=403" if TUNE_403
+ default "-mtune=405" if TUNE_405
+ default "-mtune=440" if TUNE_440
+ default "-mtune=821" if TUNE_821
+ default "-mtune=823" if TUNE_823
+ default "-mtune=860" if TUNE_860
+ default "-mtune=e200" if TUNE_E200
+ default "-mtune=power4" if PPC64
+
+# The next three options should probably go away
+config POWER4_ONLY
+ def_bool y
+ depends on PPC64 && !CPU_POWER3 && !CPU_RS64
config POWER3
bool
Index: linux-2.6/arch/powerpc/platforms/cell/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/Kconfig
+++ linux-2.6/arch/powerpc/platforms/cell/Kconfig
@@ -20,6 +20,7 @@ config PPC_IBM_CELL_BLADE
select MMIO_NVRAM
select PPC_UDBG_16550
select UDBG_RTAS_CONSOLE
+ select CPU_CELL
menu "Cell Broadband Engine options"
depends on PPC_CELL
Index: linux-2.6/arch/powerpc/platforms/celleb/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/celleb/Kconfig
+++ linux-2.6/arch/powerpc/platforms/celleb/Kconfig
@@ -2,6 +2,7 @@ config PPC_CELLEB
bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
depends on PPC_MULTIPLATFORM && PPC64
select PPC_CELL
+ select CPU_CELL
select PPC_OF_PLATFORM_PCI
select HAS_TXX9_SERIAL
select PPC_UDBG_BEAT
Index: linux-2.6/arch/powerpc/platforms/embedded6xx/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/embedded6xx/Kconfig
+++ linux-2.6/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -8,6 +8,7 @@ config LINKSTATION
select FSL_SOC
select PPC_UDBG_16550 if SERIAL_8250
select DEFAULT_UIMAGE
+ select CPU_603e
help
Select LINKSTATION if configuring for one of PPC- (MPC8241)
based NAS systems from Buffalo Technology. So far only
@@ -20,6 +21,7 @@ config MPC7448HPC2
select TSI108_BRIDGE
select DEFAULT_UIMAGE
select PPC_UDBG_16550
+ select CPU_7450
help
Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga)
platform
@@ -29,6 +31,7 @@ config PPC_HOLLY
select TSI108_BRIDGE
select PPC_UDBG_16550
select WANT_DEVICE_TREE
+ select CPU_750
help
Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval
Board with TSI108/9 bridge (Hickory/Holly)
@@ -38,6 +41,7 @@ config PPC_PRPMC2800
select MV64X60
select NOT_COHERENT_CACHE
select WANT_DEVICE_TREE
+ select CPU_7450
help
This option enables support for the Motorola PrPMC2800 board
endchoice
Index: linux-2.6/arch/powerpc/platforms/maple/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/maple/Kconfig
+++ linux-2.6/arch/powerpc/platforms/maple/Kconfig
@@ -11,6 +11,7 @@ config PPC_MAPLE
select PPC_RTAS
select MMIO_NVRAM
select ATA_NONSTANDARD if ATA
+ select CPU_970
default n
help
This option enables support for the Maple 970FX Evaluation Board.
Index: linux-2.6/arch/powerpc/platforms/pasemi/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/pasemi/Kconfig
+++ linux-2.6/arch/powerpc/platforms/pasemi/Kconfig
@@ -6,6 +6,7 @@ config PPC_PASEMI
select PPC_UDBG_16550
select PPC_NATIVE
select EMBEDDED
+ select CPU_PA6T
help
This option enables support for PA Semi's PWRficient line
of SoC processors, including PA6T-1682M
Index: linux-2.6/arch/powerpc/platforms/powermac/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/powermac/Kconfig
+++ linux-2.6/arch/powerpc/platforms/powermac/Kconfig
@@ -16,6 +16,7 @@ config PPC_PMAC64
select MPIC_U3_HT_IRQS
select GENERIC_TBSYNC
select PPC_970_NAP
+ select CPU_970
default y
Index: linux-2.6/arch/powerpc/platforms/ps3/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/ps3/Kconfig
+++ linux-2.6/arch/powerpc/platforms/ps3/Kconfig
@@ -2,6 +2,7 @@ config PPC_PS3
bool "Sony PS3 (incomplete)"
depends on PPC_MULTIPLATFORM && PPC64
select PPC_CELL
+ select CPU_CELL
select USB_ARCH_HAS_OHCI
select USB_OHCI_LITTLE_ENDIAN
select USB_OHCI_BIG_ENDIAN_MMIO
Index: linux-2.6/arch/powerpc/Makefile
===================================================================
--- linux-2.6.orig/arch/powerpc/Makefile
+++ linux-2.6/arch/powerpc/Makefile
@@ -78,24 +78,23 @@ LINUXINCLUDE += $(LINUXINCLUDE-y)
CHECKFLAGS += -m$(SZ) -D__powerpc__ -D__powerpc$(SZ)__
+OPTFLAGS := $(call cc-option,$(CONFIG_PPC_MCPU)) $(call cc-option,$(CONFIG_PPC_MTUNE))
+
+# compilers older than 4.0.0 can only set -maltivec in 64 bit mode
+# when compiling for 970
ifeq ($(CONFIG_PPC64),y)
GCC_BROKEN_VEC := $(shell if [ $(call cc-version) -lt 0400 ] ; then echo "y"; fi)
-
ifeq ($(CONFIG_POWER4_ONLY),y)
ifeq ($(CONFIG_ALTIVEC),y)
ifeq ($(GCC_BROKEN_VEC),y)
- CFLAGS += $(call cc-option,-mcpu=970)
-else
- CFLAGS += $(call cc-option,-mcpu=power4)
+ OPTFLAGS := $(call cc-option,-mcpu=970) $(call cc-option,$(CONFIG_PPC_MTUNE))
endif
-else
- CFLAGS += $(call cc-option,-mcpu=power4)
endif
-else
- CFLAGS += $(call cc-option,-mtune=power4)
endif
endif
+CFLAGS += $(OPTFLAGS)
+
# No AltiVec instruction when building kernel
CFLAGS += $(call cc-option,-mno-altivec)
@@ -107,10 +106,6 @@ CFLAGS += $(call cc-option,-funit-at-a-t
# often slow when they are implemented at all
CFLAGS += -mno-string
-ifeq ($(CONFIG_6xx),y)
-CFLAGS += -mcpu=powerpc
-endif
-
cpu-as-$(CONFIG_4xx) += -Wa,-m405
cpu-as-$(CONFIG_6xx) += -Wa,-maltivec
cpu-as-$(CONFIG_POWER4) += -Wa,-maltivec
Index: linux-2.6/arch/powerpc/platforms/85xx/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/85xx/Kconfig
+++ linux-2.6/arch/powerpc/platforms/85xx/Kconfig
@@ -6,24 +6,28 @@ choice
config MPC8540_ADS
bool "Freescale MPC8540 ADS"
select DEFAULT_UIMAGE
+ select CPU_8540
help
This option enables support for the MPC 8540 ADS board
config MPC8560_ADS
bool "Freescale MPC8560 ADS"
select DEFAULT_UIMAGE
+ select CPU_8540
help
This option enables support for the MPC 8560 ADS board
config MPC85xx_CDS
bool "Freescale MPC85xx CDS"
select DEFAULT_UIMAGE
+ select CPU_8548
help
This option enables support for the MPC85xx CDS board
config MPC85xx_MDS
bool "Freescale MPC85xx MDS"
select DEFAULT_UIMAGE
+ select CPU_8548
# select QUICC_ENGINE
help
This option enables support for the MPC85xx MDS board
@@ -31,6 +35,7 @@ config MPC85xx_MDS
config MPC8544_DS
bool "Freescale MPC8544 DS"
select DEFAULT_UIMAGE
+ select CPU_8548
help
This option enables support for the MPC8544 DS board
--
^ 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