These are the patches I have queued for 2.6.20 for cell,
as I got them after the merge window closed.
They apply on the current powerpc.git with the bug fixes
applied that I sent earlier.
Please review for inclusion.
Arnd <><
From: Masato Noguchi <redacted>
SPRN_SDR1 and the SPE's MFC SDR are hypervisor resources and
are not accessible from a logical partition. This change adds an
access wrapper.
When running on bare H/W, the spufs needs to only set the SPE's MFC SDR
to the value of the PPE's SPRN_SDR1 once at SPE initialization, so this
change renames mfc_sdr_set() to mfc_sdr_setup() and moves the
access of SPRN_SDR1 into the mmio wrapper. It also removes the now
unneeded member mfc_sdr_RW from struct spu_priv1_collapsed.
Signed-off-by: Masato Noguchi <redacted>
Signed-off-by: Geoff Levand <redacted>
Signed-off-by: Arnd Bergmann <redacted>
--
Index: linux-2.6/arch/powerpc/platforms/cell/spu_base.c
===================================================================
From: Christian Krafft <redacted>
This patch adds a cpufreq backend driver to enable frequency scaling on cell.
Signed-off-by: Christian Krafft <redacted>
Signed-off-by: Arnd Bergmann <redacted>
Index: linux-2.6/arch/powerpc/platforms/cell/Kconfig
===================================================================
@@ -0,0 +1,248 @@+/*+*cpufreqdriverforthecellprocessor+*+*(C)CopyrightIBMDeutschlandEntwicklungGmbH2005+*+*Author:ChristianKrafft<krafft@de.ibm.com>+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation;eitherversion2,or(atyouroption)+*anylaterversion.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*+*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense+*alongwiththisprogram;ifnot,writetotheFreeSoftware+*Foundation,Inc.,675MassAve,Cambridge,MA02139,USA.+*/++#include<linux/cpufreq.h>+#include<linux/timer.h>++#include<asm/hw_irq.h>+#include<asm/io.h>+#include<asm/processor.h>+#include<asm/prom.h>+#include<asm/time.h>++#include"cbe_regs.h"++staticDEFINE_MUTEX(cbe_switch_mutex);+++/* the CBE supports an 8 step frequency scaling */+staticstructcpufreq_frequency_tablecbe_freqs[]={+{1,0},+{2,0},+{3,0},+{4,0},+{5,0},+{6,0},+{8,0},+{10,0},+{0,CPUFREQ_TABLE_END},+};++/* to write to MIC register */+staticu64MIC_Slow_Fast_Timer_table[]={+[0...7]=0x007fc00000000000ull,+};++/* more values for the MIC */+staticu64MIC_Slow_Next_Timer_table[]={+0x0000240000000000ull,+0x0000268000000000ull,+0x000029C000000000ull,+0x00002D0000000000ull,+0x0000300000000000ull,+0x0000334000000000ull,+0x000039C000000000ull,+0x00003FC000000000ull,+};++/*+*hardwarespecificfunctions+*/++staticintget_pmode(intcpu)+{+intret;+structcbe_pmd_regs__iomem*pmd_regs;++pmd_regs=cbe_get_cpu_pmd_regs(cpu);+ret=in_be64(&pmd_regs->pmsr)&0x07;++returnret;+}++staticintset_pmode(intcpu,unsignedintpmode)+{+structcbe_pmd_regs__iomem*pmd_regs;+structcbe_mic_tm_regs__iomem*mic_tm_regs;+u64flags;+u64value;++local_irq_save(flags);++mic_tm_regs=cbe_get_cpu_mic_tm_regs(cpu);+pmd_regs=cbe_get_cpu_pmd_regs(cpu);++pr_debug("pm register is mapped at %p\n",&pmd_regs->pmcr);+pr_debug("mic register is mapped at %p\n",&mic_tm_regs->slow_fast_timer_0);++out_be64(&mic_tm_regs->slow_fast_timer_0,MIC_Slow_Fast_Timer_table[pmode]);+out_be64(&mic_tm_regs->slow_fast_timer_1,MIC_Slow_Fast_Timer_table[pmode]);++out_be64(&mic_tm_regs->slow_next_timer_0,MIC_Slow_Next_Timer_table[pmode]);+out_be64(&mic_tm_regs->slow_next_timer_1,MIC_Slow_Next_Timer_table[pmode]);++value=in_be64(&pmd_regs->pmcr);+/* set bits to zero */+value&=0xFFFFFFFFFFFFFFF8ull;+/* set bits to next pmode */+value|=pmode;++out_be64(&pmd_regs->pmcr,value);++/* wait until new pmode appears in status register */+value=in_be64(&pmd_regs->pmsr)&0x07;+while(value!=pmode){+cpu_relax();+value=in_be64(&pmd_regs->pmsr)&0x07;+}++local_irq_restore(flags);++return0;+}++/*+*cpufreqfunctions+*/++staticintcbe_cpufreq_cpu_init(structcpufreq_policy*policy)+{+u32*max_freq;+inti,cur_pmode;+structdevice_node*cpu;++cpu=of_get_cpu_node(policy->cpu,NULL);++if(!cpu)+return-ENODEV;++pr_debug("init cpufreq on CPU %d\n",policy->cpu);++max_freq=(u32*)get_property(cpu,"clock-frequency",NULL);++if(!max_freq)+return-EINVAL;++// we need the freq in kHz+*max_freq/=1000;++pr_debug("max clock-frequency is at %u kHz\n",*max_freq);+pr_debug("initializing frequency table\n");++// initialize frequency table+for(i=0;cbe_freqs[i].frequency!=CPUFREQ_TABLE_END;i++){+cbe_freqs[i].frequency=*max_freq/cbe_freqs[i].index;+pr_debug("%d: %d\n",i,cbe_freqs[i].frequency);+}++policy->governor=CPUFREQ_DEFAULT_GOVERNOR;+/* if DEBUG is enabled set_pmode() measures the correct latency of a transition */+policy->cpuinfo.transition_latency=25000;++cur_pmode=get_pmode(policy->cpu);+pr_debug("current pmode is at %d\n",cur_pmode);++policy->cur=cbe_freqs[cur_pmode].frequency;++#ifdef CONFIG_SMP+policy->cpus=cpu_sibling_map[policy->cpu];+#endif++cpufreq_frequency_table_get_attr(cbe_freqs,policy->cpu);++/* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */+returncpufreq_frequency_table_cpuinfo(policy,cbe_freqs);+}++staticintcbe_cpufreq_cpu_exit(structcpufreq_policy*policy)+{+cpufreq_frequency_table_put_attr(policy->cpu);+return0;+}++staticintcbe_cpufreq_verify(structcpufreq_policy*policy)+{+returncpufreq_frequency_table_verify(policy,cbe_freqs);+}+++staticintcbe_cpufreq_target(structcpufreq_policy*policy,unsignedinttarget_freq,+unsignedintrelation)+{+intrc;+structcpufreq_freqsfreqs;+intcbe_pmode_new;++cpufreq_frequency_table_target(policy,+cbe_freqs,+target_freq,+relation,+&cbe_pmode_new);++freqs.old=policy->cur;+freqs.new=cbe_freqs[cbe_pmode_new].frequency;+freqs.cpu=policy->cpu;++mutex_lock(&cbe_switch_mutex);+cpufreq_notify_transition(&freqs,CPUFREQ_PRECHANGE);++pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",+policy->cpu,+cbe_freqs[cbe_pmode_new].frequency,+cbe_freqs[cbe_pmode_new].index);++rc=set_pmode(policy->cpu,cbe_pmode_new);+cpufreq_notify_transition(&freqs,CPUFREQ_POSTCHANGE);+mutex_unlock(&cbe_switch_mutex);++returnrc;+}++staticstructcpufreq_drivercbe_cpufreq_driver={+.verify=cbe_cpufreq_verify,+.target=cbe_cpufreq_target,+.init=cbe_cpufreq_cpu_init,+.exit=cbe_cpufreq_cpu_exit,+.name="cbe-cpufreq",+.owner=THIS_MODULE,+.flags=CPUFREQ_CONST_LOOPS,+};++/*+*moduleinitanddestoy+*/++staticint__initcbe_cpufreq_init(void)+{+returncpufreq_register_driver(&cbe_cpufreq_driver);+}++staticvoid__exitcbe_cpufreq_exit(void)+{+cpufreq_unregister_driver(&cbe_cpufreq_driver);+}++module_init(cbe_cpufreq_init);+module_exit(cbe_cpufreq_exit);++MODULE_LICENSE("GPL");+MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
@@ -139,7 +139,19 @@ CONFIG_RTAS_FLASH=y CONFIG_MMIO_NVRAM=y # CONFIG_PPC_MPC106 is not set # CONFIG_PPC_970_NAP is not set-# CONFIG_CPU_FREQ is not set+CONFIG_CPU_FREQ=y+CONFIG_CPU_FREQ_TABLE=y+CONFIG_CPU_FREQ_DEBUG=y+CONFIG_CPU_FREQ_STAT=y+# CONFIG_CPU_FREQ_STAT_DETAILS is not set+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y+CONFIG_CPU_FREQ_GOV_POWERSAVE=y+CONFIG_CPU_FREQ_GOV_USERSPACE=y+CONFIG_CPU_FREQ_GOV_ONDEMAND=y+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y+# CONFIG_CPU_FREQ_PMAC64 is not set # CONFIG_WANT_EARLY_SERIAL is not set # CONFIG_MPIC is not set
This moves the cell idle function to use the default cpu_idle
with a special power_save callback, like all other platforms
except iSeries already do.
It also makes it possible to disable this power_save function
with a new powerpc-specific boot option "powersave=off".
Signed-off-by: Arnd Bergmann <redacted>
Index: linux-2.6/arch/powerpc/kernel/idle.c
===================================================================
@@ -38,32 +38,16 @@#include"pervasive.h"#include"cbe_regs.h"-staticDEFINE_SPINLOCK(cbe_pervasive_lock);--staticvoid__initcbe_enable_pause_zero(void)+staticvoidcbe_power_save(void){-unsignedlongthread_switch_control;-unsignedlongtemp_register;-structcbe_pmd_regs__iomem*pregs;--spin_lock_irq(&cbe_pervasive_lock);-pregs=cbe_get_cpu_pmd_regs(smp_processor_id());-if(pregs==NULL)-gotoout;--pr_debug("Power Management: CPU %d\n",smp_processor_id());--/* Enable Pause(0) control bit */-temp_register=in_be64(&pregs->pmcr);--out_be64(&pregs->pmcr,-temp_register|CBE_PMD_PAUSE_ZERO_CONTROL);+unsignedlongctrl,thread_switch_control;+ctrl=mfspr(SPRN_CTRLF);/* Enable DEC and EE interrupt request */thread_switch_control=mfspr(SPRN_TSC_CELL);thread_switch_control|=TSC_CELL_EE_ENABLE|TSC_CELL_EE_BOOST;-switch((mfspr(SPRN_CTRLF)&CTRL_CT)){+switch(ctrl&CTRL_CT){caseCTRL_CT0:thread_switch_control|=TSC_CELL_DEC_ENABLE_0;break;
@@ -75,58 +59,21 @@ static void __init cbe_enable_pause_zero__FUNCTION__);break;}-mtspr(SPRN_TSC_CELL,thread_switch_control);-out:-spin_unlock_irq(&cbe_pervasive_lock);-}--staticvoidcbe_idle(void)-{-unsignedlongctrl;--/* Why do we do that on every idle ? Couldn't that be done once for-*allordowelosethestatesomeway?Also,thepmcr-*registersetting,thatcan'tbesetonceatboot?Wereallywant-*tomovethatawayinordertoimplementasimplepowersave+/*+*gointolowthreadpriority,mediumprioritywillbe+*restoredforusafterwake-up.*/-cbe_enable_pause_zero();+HMT_low();-while(1){-if(!need_resched()){-local_irq_disable();-while(!need_resched()){-/* go into low thread priority */-HMT_low();--/*-*atomicallydisablethreadexecution-*andrunlatch.-*ExternalandDecrementerexceptions-*arestillhandledwhenthethread-*isdisabledbutnowenterin-*cbe_system_reset_exception()-*/-ctrl=mfspr(SPRN_CTRLF);-ctrl&=~(CTRL_RUNLATCH|CTRL_TE);-mtspr(SPRN_CTRLT,ctrl);-}-/* restore thread prio */-HMT_medium();-local_irq_enable();-}--/*-*turnrunlatchonagainbeforeschedulingthe-*processwejustwokeup-*/-ppc64_runlatch_on();--preempt_enable_no_resched();-schedule();-preempt_disable();-}+/*+*atomicallydisablethreadexecutionandrunlatch.+*ExternalandDecrementerexceptionsarestillhandledwhenthe+*threadisdisabledbutnowenterincbe_system_reset_exception()+*/+ctrl&=~(CTRL_RUNLATCH|CTRL_TE);+mtspr(SPRN_CTRLT,ctrl);}staticintcbe_system_reset_exception(structpt_regs*regs)
@@ -158,9 +105,20 @@ static int cbe_system_reset_exception(stvoid__initcbe_pervasive_init(void){+intcpu;if(!cpu_has_feature(CPU_FTR_PAUSE_ZERO))return;-ppc_md.idle_loop=cbe_idle;+for_each_possible_cpu(cpu){+structcbe_pmd_regs__iomem*regs=cbe_get_cpu_pmd_regs(cpu);+if(!regs)+continue;++/* Enable Pause(0) control bit */+out_be64(®s->pmcr,in_be64(®s->pmcr)|+CBE_PMD_PAUSE_ZERO_CONTROL);+}++ppc_md.power_save=cbe_power_save;ppc_md.system_reset_exception=cbe_system_reset_exception;}--
From: Christian Krafft <redacted>
This patch adds a module that registers sysfs attributes to CPU and SPU
containing the temperature of the CBE.
They can be found under
/sys/devices/system/spu/cpuX/thermal/temperature[0|1]
/sys/devices/system/spu/spuX/thermal/temperature
The temperature is read from the on-chip temperature sensors.
Signed-off-by: Christian Krafft <redacted>
Signed-off-by: Arnd Bergmann <redacted>
Index: linux-2.6/arch/powerpc/platforms/cell/Kconfig
===================================================================
@@ -20,4 +20,9 @@ config CBE_RASbool"RAS features for bare metal Cell BE"defaulty+configCBE_THERM+tristate"CBE thermal support"+defaultm+depends onCBE_RAS+endmenu
@@ -0,0 +1,225 @@+/*+*thermalsupportforthecellprocessor+*+*(C)CopyrightIBMDeutschlandEntwicklungGmbH2005+*+*Author:ChristianKrafft<krafft@de.ibm.com>+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation;eitherversion2,or(atyouroption)+*anylaterversion.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*+*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense+*alongwiththisprogram;ifnot,writetotheFreeSoftware+*Foundation,Inc.,675MassAve,Cambridge,MA02139,USA.+*/++#include<linux/module.h>+#include<linux/sysdev.h>+#include<linux/kernel.h>+#include<linux/cpu.h>+#include<asm/spu.h>+#include<asm/io.h>+#include<asm/prom.h>++#include"cbe_regs.h"++staticstructcbe_pmd_regs__iomem*get_pmd_regs(structsys_device*sysdev)+{+structspu*spu;++spu=container_of(sysdev,structspu,sysdev);++returncbe_get_pmd_regs(spu->devnode);+}++/* returns the value for a given spu in a given register */+staticu8spu_read_register_value(structsys_device*sysdev,unionspe_reg__iomem*reg)+{+unsignedint*id;+unionspe_regvalue;+structspu*spu;++/* getting the id from the reg attribute will not work on future device-tree layouts+*infutureweshouldstoretheidtothespustructanduseithere*/+spu=container_of(sysdev,structspu,sysdev);+id=(unsignedint*)get_property(spu->devnode,"reg",NULL);+value.val=in_be64(®->val);++returnvalue.spe[*id];+}++staticssize_tspu_show_temp(structsys_device*sysdev,char*buf)+{+intvalue;+structcbe_pmd_regs__iomem*pmd_regs;++pmd_regs=get_pmd_regs(sysdev);++value=spu_read_register_value(sysdev,&pmd_regs->ts_ctsr1);+/* clear all other bits */+value&=0x3F;+/* temp is stored in steps of 2 degrees */+value*=2;+/* base temp is 65 degrees */+value+=65;++returnsprintf(buf,"%d\n",(int)value);+}++staticssize_tppe_show_temp(structsys_device*sysdev,char*buf,intpos)+{+structcbe_pmd_regs__iomem*pmd_regs;+u64value;++pmd_regs=cbe_get_cpu_pmd_regs(sysdev->id);+value=in_be64(&pmd_regs->ts_ctsr2);++/* access the corresponding byte */+value>>=pos;+/* clear all other bits */+value&=0x3F;+/* temp is stored in steps of 2 degrees */+value*=2;+/* base temp is 65 degrees */+value+=65;++returnsprintf(buf,"%d\n",(int)value);+}+++/* shows the temperature of the DTS on the PPE,+*locatednearthelinearthermalsensor*/+staticssize_tppe_show_temp0(structsys_device*sysdev,char*buf)+{+returnppe_show_temp(sysdev,buf,32);+}++/* shows the temperature of the second DTS on the PPE */+staticssize_tppe_show_temp1(structsys_device*sysdev,char*buf)+{+returnppe_show_temp(sysdev,buf,0);+}++staticstructsysdev_attributeattr_spu_temperature={+.attr={.name="temperature",.mode=0400},+.show=spu_show_temp,+};++staticstructattribute*spu_attributes[]={+&attr_spu_temperature.attr,+};++staticstructattribute_groupspu_attribute_group={+.name="thermal",+.attrs=spu_attributes,+};++staticstructsysdev_attributeattr_ppe_temperature0={+.attr={.name="temperature0",.mode=0400},+.show=ppe_show_temp0,+};++staticstructsysdev_attributeattr_ppe_temperature1={+.attr={.name="temperature1",.mode=0400},+.show=ppe_show_temp1,+};++staticstructattribute*ppe_attributes[]={+&attr_ppe_temperature0.attr,+&attr_ppe_temperature1.attr,+};++staticstructattribute_groupppe_attribute_group={+.name="thermal",+.attrs=ppe_attributes,+};++/*+*initializethrottlingwithdefaultvalues+*/+staticvoid__initinit_default_values(void)+{+intcpu;+structcbe_pmd_regs__iomem*pmd_regs;+structsys_device*sysdev;+unionppe_spe_regtpr;+unionspe_regstr1;+u64str2;+unionspe_regcr1;+u64cr2;++/* TPR defaults */+/* ppe+*1F-nofullstop+*08-dynamicthrottlingstartsifover80degrees+*03-dynamicthrottlingceasesifbelow70degrees*/+tpr.ppe=0x1F0803;+/* spe+*10-fullstoppedwhenover96degrees+*08-dynamicthrottlingstartsifover80degrees+*03-dynamicthrottlingceasesifbelow70degrees+*/+tpr.spe=0x100803;++/* STR defaults */+/* str1+*10-stop16of32cycles+*/+str1.val=0x1010101010101010ull;+/* str2+*10-stop16of32cycles+*/+str2=0x10;++/* CR defaults */+/* cr1+*4-normaloperation+*/+cr1.val=0x0404040404040404ull;+/* cr2+*4-normaloperation+*/+cr2=0x04;++for_each_possible_cpu(cpu){+pr_debug("processing cpu %d\n",cpu);+sysdev=get_cpu_sysdev(cpu);+pmd_regs=cbe_get_cpu_pmd_regs(sysdev->id);++out_be64(&pmd_regs->tm_str2,str2);+out_be64(&pmd_regs->tm_str1.val,str1.val);+out_be64(&pmd_regs->tm_tpr.val,tpr.val);+out_be64(&pmd_regs->tm_cr1.val,cr1.val);+out_be64(&pmd_regs->tm_cr2,cr2);+}+}+++staticint__initthermal_init(void)+{+init_default_values();++spu_add_sysdev_attr_group(&spu_attribute_group);+cpu_add_sysdev_attr_group(&ppe_attribute_group);++return0;+}+module_init(thermal_init);++staticvoid__exitthermal_exit(void)+{+spu_remove_sysdev_attr_group(&spu_attribute_group);+cpu_remove_sysdev_attr_group(&ppe_attribute_group);+}+module_exit(thermal_exit);++MODULE_LICENSE("GPL");+MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");+--
From: Mark Nutter <redacted>
This adds two new flags to spu_create:
SPU_CREATE_NONSCHED: create a context that is never moved
away from an SPE once it has started running. This flag
can only be used by tasks with the CAP_SYS_NICE capability.
SPU_CREATE_ISOLATED: create a nonschedulable context that
enters isolation mode upon first run. This requires the
SPU_CREATE_NONSCHED flag.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Arnd Bergmann <redacted>
---
Update: add psmap file.
arch/powerpc/platforms/cell/spufs/file.c | 22 ++++++++++++
arch/powerpc/platforms/cell/spufs/hw_ops.c | 5 ++
arch/powerpc/platforms/cell/spufs/inode.c | 17 +++++++++
arch/powerpc/platforms/cell/spufs/run.c | 10 ++++-
arch/powerpc/platforms/cell/spufs/spufs.h | 1
arch/powerpc/platforms/cell/spufs/switch.c | 50 +++++++++++++++++++++++++++--
include/asm-powerpc/spu.h | 5 ++
7 files changed, 103 insertions(+), 7 deletions(-)
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
@@ -1916,6 +1916,51 @@ static void save_lscsa(struct spu_state wait_spu_stopped(prev,spu);/* Step 57. */}+staticvoidforce_spu_isolate_exit(structspu*spu)+{+structspu_problem__iomem*prob=spu->problem;+structspu_priv2__iomem*priv2=spu->priv2;++/* Stop SPE execution and wait for completion. */+out_be32(&prob->spu_runcntl_RW,SPU_RUNCNTL_STOP);+iobarrier_rw();+POLL_WHILE_TRUE(in_be32(&prob->spu_status_R)&SPU_STATUS_RUNNING);++/* Restart SPE master runcntl. */+spu_mfc_sr1_set(spu,MFC_STATE1_MASTER_RUN_CONTROL_MASK);+iobarrier_w();++/* Initiate isolate exit request and wait for completion. */+out_be64(&priv2->spu_privcntl_RW,4LL);+iobarrier_w();+out_be32(&prob->spu_runcntl_RW,2);+iobarrier_rw();+POLL_WHILE_FALSE((in_be32(&prob->spu_status_R)+&SPU_STATUS_STOPPED_BY_STOP));++/* Reset load request to normal. */+out_be64(&priv2->spu_privcntl_RW,SPU_PRIVCNT_LOAD_REQUEST_NORMAL);+iobarrier_w();+}++/**+*stop_spu_isolate+*CheckSPUrun-controlstateandforceisolated+*exitfunctionasnecessary.+*/+staticvoidstop_spu_isolate(structspu*spu)+{+structspu_problem__iomem*prob=spu->problem;++if(in_be32(&prob->spu_status_R)&SPU_STATUS_ISOLATED_STATE){+/* The SPU is in isolated state; the only way+*togetitoutistoperformanisolated+*exit(clean)operation.+*/+force_spu_isolate_exit(spu);+}+}+staticvoidharvest(structspu_state*prev,structspu*spu){/*
From: Kevin Corry <redacted>
Many of the registers in the performance monitoring unit are write-only.
We need to save a "shadow" copy when we write to those registers so we
can retrieve the values if we need them later.
The new cbe_pmd_shadow_regs structure is added to the cbe_regs_map structure
so we have the appropriate per-node copies of these shadow values.
Signed-off-by: Kevin Corry <redacted>
Signed-off-by: Arnd Bergmann <redacted>
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_regs.c
===================================================================
From: Michael Ellerman <redacted>
This patch adds support for stopping, and restarting, spus
from xmon. We use the spu master runcntl bit to stop execution,
this is apparently the "right" way to control spu execution and
spufs will be changed in the future to use this bit.
Testing has shown that to restart execution we have to turn the
master runcntl bit on and also rewrite the spu runcntl bit, even
if it is already set to 1 (running).
Stopping spus is triggered by the xmon command 'ss' - "spus stop"
perhaps. Restarting them is triggered via 'sr'. Restart doesn't
start execution on spus unless they were running prior to being
stopped by xmon.
Walking the spu->full_list in xmon after a panic, would mean
corruption of any spu struct would make all the others
inaccessible. To avoid this, and also to make the next patch
easier, we cache pointers to all spus during boot.
We attempt to catch and recover from errors while stopping and
restarting the spus, but as with most xmon functionality there are
no guarantees that performing these operations won't crash xmon
itself.
Signed-off-by: Michael Ellerman <redacted>
Signed-off-by: Arnd Bergmann <redacted>
---
arch/powerpc/platforms/cell/spu_base.c | 4
arch/powerpc/xmon/xmon.c | 142 ++++++++++++++++++++++++++++++++-
include/asm-powerpc/xmon.h | 2
3 files changed, 146 insertions(+), 2 deletions(-)
Index: linux-2.6/arch/powerpc/platforms/cell/spu_base.c
===================================================================
@@ -209,8 +213,12 @@ Commands:\n\mishowinformationaboutmemoryallocation\n\pcallaprocedure\n\rprintregisters\n\-ssinglestep\n\-Sprintspecialregisters\n\+ssinglestep\n"+#ifdef CONFIG_PPC_CELL+" ss stop execution on all spus\n\+srrestoreexecutiononstoppedspus\n"+#endif+" S print special registers\n\tprintbacktrace\n\xexitmonitorandrecover\n\Xexitmonitoranddontrecover\n"
@@ -518,6 +526,7 @@ int xmon(struct pt_regs *excp)xmon_save_regs(®s);excp=®s;}+returnxmon_core(excp,0);}EXPORT_SYMBOL(xmon);
From: Christian Krafft <redacted>
This patch adds two functions to create and remove sysfs attributes and
attribute_group to all cpus. That allows to register sysfs attributes in
a subdirectory like: /sys/devices/system/cpu/cpuX/group_name/what_ever
This will be used by cbe_thermal to group all attributes dealing with
thermal support in one directory.
Signed-of-by: Christian Krafft [off-list ref]
Index: linux-2.6/arch/powerpc/kernel/sysfs.c
===================================================================
From: Michael Ellerman <redacted>
This patch adds a command to xmon for dumping information about
spu structs. The command is 'sf' for "spu fields" perhaps, and
takes the spu number as an argument. This is the same value as the
spu->number field, or the "phys-id" value of a context when it is
bound to a physical spu.
We try to catch memory errors as we dump each field, hopefully this
will make the command reasonably robust, but YMMV. If people see a
need we can easily add more fields to the dump in future.
Output looks something like this:
0:mon> sf 0
Dumping spu fields at address c00000001ffd9e80:
number = 0x0
name = spe
devnode->full_name = /cpus/PowerPC,BE@0/spes/spe@0
nid = 0x0
local_store_phys = 0x20000000000
local_store = 0xd0000800801e0000
ls_size = 0x0
isrc = 0x4
node = 0x0
flags = 0x0
dar = 0x0
dsisr = 0x0
class_0_pending = 0
irqs[0] = 0x16
irqs[1] = 0x17
irqs[2] = 0x24
slb_replace = 0x0
pid = 0
prio = 0
mm = 0x0000000000000000
ctx = 0x0000000000000000
rq = 0x0000000000000000
timestamp = 0x0000000000000000
problem_phys = 0x20000040000
problem = 0xd000080080220000
problem->spu_runcntl_RW = 0x0
problem->spu_status_R = 0x0
problem->spu_npc_RW = 0x0
priv1 = 0xd000080080240000
priv1->mfc_sr1_RW = 0x33
priv2 = 0xd000080080250000
Signed-off-by: Michael Ellerman <redacted>
Signed-off-by: Arnd Bergmann <redacted>
---
arch/powerpc/xmon/xmon.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 67 insertions(+), 1 deletion(-)
Index: linux-2.6/arch/powerpc/xmon/xmon.c
===================================================================
@@ -216,7 +216,8 @@ Commands:\n\ssinglestep\n"#ifdef CONFIG_PPC_CELL" ss stop execution on all spus\n\-srrestoreexecutiononstoppedspus\n"+srrestoreexecutiononstoppedspus\n\+sf#dumpspufieldsforspu#(inhex)\n"#endif" S print special registers\n\tprintbacktrace\n\
From: Kevin Corry <redacted>
Add routines for accessing the registers and counters in the performance
monitoring unit.
Signed-off-by: Kevin Corry <redacted>
Signed-off-by: Arnd Bergmann <redacted>
Index: linux-2.6/arch/powerpc/platforms/cell/Makefile
===================================================================
@@ -0,0 +1,328 @@+/*+*CellBroadbandEnginePerformanceMonitor+*+*(C)CopyrightIBMCorporation2001,2006+*+*Author:+*DavidErb(djerb@us.ibm.com)+*KevinCorry(kevcorry@us.ibm.com)+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation;eitherversion2,or(atyouroption)+*anylaterversion.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*+*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense+*alongwiththisprogram;ifnot,writetotheFreeSoftware+*Foundation,Inc.,675MassAve,Cambridge,MA02139,USA.+*/++#include<linux/types.h>+#include<asm/io.h>+#include<asm/machdep.h>+#include<asm/reg.h>+#include<asm/spu.h>++#include"cbe_regs.h"+#include"interrupt.h"+#include"pmu.h"++/*+*Whenwritingtowrite-onlymmioaddresses,saveashadowcopy.Allofthe+*registersare32-bit,butstoredintheupper-halfofa64-bitfieldin+*pmd_regs.+*/++#define WRITE_WO_MMIO(reg, x) \+do{\+u32_x=(x);\+structcbe_pmd_regs__iomem*pmd_regs;\+structcbe_pmd_shadow_regs*shadow_regs;\+pmd_regs=cbe_get_cpu_pmd_regs(cpu);\+shadow_regs=cbe_get_cpu_pmd_shadow_regs(cpu);\+out_be64(&(pmd_regs->reg),(((u64)_x)<<32));\+shadow_regs->reg=_x;\+}while(0)++#define READ_SHADOW_REG(val, reg) \+do{\+structcbe_pmd_shadow_regs*shadow_regs;\+shadow_regs=cbe_get_cpu_pmd_shadow_regs(cpu);\+(val)=shadow_regs->reg;\+}while(0)++#define READ_MMIO_UPPER32(val, reg) \+do{\+structcbe_pmd_regs__iomem*pmd_regs;\+pmd_regs=cbe_get_cpu_pmd_regs(cpu);\+(val)=(u32)(in_be64(&pmd_regs->reg)>>32);\+}while(0)++/*+*Physicalcounterregisters.+*Eachphysicalcountercanactasone32-bitcounterortwo16-bitcounters.+*/++u32cbe_read_phys_ctr(u32cpu,u32phys_ctr)+{+u32val_in_latch,val=0;++if(phys_ctr<NR_PHYS_CTRS){+READ_SHADOW_REG(val_in_latch,counter_value_in_latch);++/* Read the latch or the actual counter, whichever is newer. */+if(val_in_latch&(1<<phys_ctr)){+READ_SHADOW_REG(val,pm_ctr[phys_ctr]);+}else{+READ_MMIO_UPPER32(val,pm_ctr[phys_ctr]);+}+}++returnval;+}++voidcbe_write_phys_ctr(u32cpu,u32phys_ctr,u32val)+{+structcbe_pmd_shadow_regs*shadow_regs;+u32pm_ctrl;++if(phys_ctr<NR_PHYS_CTRS){+/* Writing to a counter only writes to a hardware latch.+*Thenewvalueisnotpropagatedtotheactualcounter+*untiltheperformancemonitorisenabled.+*/+WRITE_WO_MMIO(pm_ctr[phys_ctr],val);++pm_ctrl=cbe_read_pm(cpu,pm_control);+if(pm_ctrl&CBE_PM_ENABLE_PERF_MON){+/* The counters are already active, so we need to+*rewritethepm_controlregisterto"re-enable"+*thePMU.+*/+cbe_write_pm(cpu,pm_control,pm_ctrl);+}else{+shadow_regs=cbe_get_cpu_pmd_shadow_regs(cpu);+shadow_regs->counter_value_in_latch|=(1<<phys_ctr);+}+}+}++/*+*"Logical"counterregisters.+*Thesewillread/write16-bitsor32-bitsdependingonthe+*currentsizeofthecounter.Counters4-7arealways16-bit.+*/++u32cbe_read_ctr(u32cpu,u32ctr)+{+u32val;+u32phys_ctr=ctr&(NR_PHYS_CTRS-1);++val=cbe_read_phys_ctr(cpu,phys_ctr);++if(cbe_get_ctr_size(cpu,phys_ctr)==16)+val=(ctr<NR_PHYS_CTRS)?(val>>16):(val&0xffff);++returnval;+}++voidcbe_write_ctr(u32cpu,u32ctr,u32val)+{+u32phys_ctr;+u32phys_val;++phys_ctr=ctr&(NR_PHYS_CTRS-1);++if(cbe_get_ctr_size(cpu,phys_ctr)==16){+phys_val=cbe_read_phys_ctr(cpu,phys_ctr);++if(ctr<NR_PHYS_CTRS)+val=(val<<16)|(phys_val&0xffff);+else+val=(val&0xffff)|(phys_val&0xffff0000);+}++cbe_write_phys_ctr(cpu,phys_ctr,val);+}++/*+*Counter-controlregisters.+*Each"logical"counterhasacorrespondingcontrolregister.+*/++u32cbe_read_pm07_control(u32cpu,u32ctr)+{+u32pm07_control=0;++if(ctr<NR_CTRS)+READ_SHADOW_REG(pm07_control,pm07_control[ctr]);++returnpm07_control;+}++voidcbe_write_pm07_control(u32cpu,u32ctr,u32val)+{+if(ctr<NR_CTRS)+WRITE_WO_MMIO(pm07_control[ctr],val);+}++/*+*OtherPMUcontrolregisters.Mostofthesearewrite-only.+*/++u32cbe_read_pm(u32cpu,enumpm_reg_namereg)+{+u32val=0;++switch(reg){+casegroup_control:+READ_SHADOW_REG(val,group_control);+break;++casedebug_bus_control:+READ_SHADOW_REG(val,debug_bus_control);+break;++casetrace_address:+READ_MMIO_UPPER32(val,trace_address);+break;++caseext_tr_timer:+READ_SHADOW_REG(val,ext_tr_timer);+break;++casepm_status:+READ_MMIO_UPPER32(val,pm_status);+break;++casepm_control:+READ_SHADOW_REG(val,pm_control);+break;++casepm_interval:+READ_SHADOW_REG(val,pm_interval);+break;++casepm_start_stop:+READ_SHADOW_REG(val,pm_start_stop);+break;+}++returnval;+}++voidcbe_write_pm(u32cpu,enumpm_reg_namereg,u32val)+{+switch(reg){+casegroup_control:+WRITE_WO_MMIO(group_control,val);+break;++casedebug_bus_control:+WRITE_WO_MMIO(debug_bus_control,val);+break;++casetrace_address:+WRITE_WO_MMIO(trace_address,val);+break;++caseext_tr_timer:+WRITE_WO_MMIO(ext_tr_timer,val);+break;++casepm_status:+WRITE_WO_MMIO(pm_status,val);+break;++casepm_control:+WRITE_WO_MMIO(pm_control,val);+break;++casepm_interval:+WRITE_WO_MMIO(pm_interval,val);+break;++casepm_start_stop:+WRITE_WO_MMIO(pm_start_stop,val);+break;+}+}++/*+*Get/setthesizeofaphysicalcountertoeither16or32bits.+*/++u32cbe_get_ctr_size(u32cpu,u32phys_ctr)+{+u32pm_ctrl,size=0;++if(phys_ctr<NR_PHYS_CTRS){+pm_ctrl=cbe_read_pm(cpu,pm_control);+size=(pm_ctrl&CBE_PM_16BIT_CTR(phys_ctr))?16:32;+}++returnsize;+}++voidcbe_set_ctr_size(u32cpu,u32phys_ctr,u32ctr_size)+{+u32pm_ctrl;++if(phys_ctr<NR_PHYS_CTRS){+pm_ctrl=cbe_read_pm(cpu,pm_control);+switch(ctr_size){+case16:+pm_ctrl|=CBE_PM_16BIT_CTR(phys_ctr);+break;++case32:+pm_ctrl&=~CBE_PM_16BIT_CTR(phys_ctr);+break;+}+cbe_write_pm(cpu,pm_control,pm_ctrl);+}+}++/*+*Enable/disabletheentireperformancemonitoringunit.+*WhenweenablethePMU,allpendingwritestocountersgetcommitted.+*/++voidcbe_enable_pm(u32cpu)+{+structcbe_pmd_shadow_regs*shadow_regs;+u32pm_ctrl;++shadow_regs=cbe_get_cpu_pmd_shadow_regs(cpu);+shadow_regs->counter_value_in_latch=0;++pm_ctrl=cbe_read_pm(cpu,pm_control)|CBE_PM_ENABLE_PERF_MON;+cbe_write_pm(cpu,pm_control,pm_ctrl);+}++voidcbe_disable_pm(u32cpu)+{+u32pm_ctrl;+pm_ctrl=cbe_read_pm(cpu,pm_control)&~CBE_PM_ENABLE_PERF_MON;+cbe_write_pm(cpu,pm_control,pm_ctrl);+}++/*+*Readingfromthetrace_buffer.+*Thetracebufferistwo64-bitregisters.Readingfrom+*thesecondhalfautomaticallyincrementsthetrace_address.+*/++voidcbe_read_trace_buffer(u32cpu,u64*buf)+{+structcbe_pmd_regs__iomem*pmd_regs=cbe_get_cpu_pmd_regs(cpu);++*buf++=in_be64(&pmd_regs->trace_buffer_0_63);+*buf++=in_be64(&pmd_regs->trace_buffer_64_127);+}+
@@ -591,7 +590,6 @@ static int __init spu_map_interrupts_old/* Add the node number */isrc|=spu->node<<IIC_IRQ_NODE_SHIFT;-spu->isrc=isrc;/* Now map interrupts of all 3 classes */spu->irqs[0]=irq_create_mapping(NULL,IIC_IRQ_CLASS_0|isrc);
This patch adds general support for isolated mode SPE apps.
Isolated apps are started indirectly, by a dedicated loader "kernel".
This patch starts the loader when spe_create is invoked with the
ISOLATE flag. We do this at spe_create time to allow libspe to pass the
isolated app in before calling spe_run.
The loader is read from the device tree, at the location
"/spu-isolation/loader". If the loader is not present, an attempt to
start an isolated SPE binary will fail with -ENODEV.
Update: loader needs to be correctly aligned - copy to a kmalloced buf.
Update: remove workaround for systemsim/spurom 'L-bit' bug, which has
been fixed.
Update: don't write to runcntl on spu_run_init: SPU is already running.
Update: do spu_setup_isolated earlier
Tested on systemsim.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Arnd Bergmann <redacted>
---
arch/powerpc/platforms/cell/spu_base.c | 35 ++++++--
arch/powerpc/platforms/cell/spufs/inode.c | 117 ++++++++++++++++++++++++++++++
arch/powerpc/platforms/cell/spufs/run.c | 12 +--
3 files changed, 148 insertions(+), 16 deletions(-)
Index: linux-2.6/arch/powerpc/platforms/cell/spu_base.c
===================================================================
@@ -89,7 +89,30 @@ static int __spu_trap_data_seg(struct spprintk("%s: invalid access during switch!\n",__func__);return1;}-if(!mm||(REGION_ID(ea)!=USER_REGION_ID)){+esid=(ea&ESID_MASK)|SLB_ESID_V;++switch(REGION_ID(ea)){+caseUSER_REGION_ID:+#ifdef CONFIG_HUGETLB_PAGE+if(in_hugepage_area(mm->context,ea))+llp=mmu_psize_defs[mmu_huge_psize].sllp;+else+#endif+llp=mmu_psize_defs[mmu_virtual_psize].sllp;+vsid=(get_vsid(mm->context.id,ea)<<SLB_VSID_SHIFT)|+SLB_VSID_USER|llp;+break;+caseVMALLOC_REGION_ID:+llp=mmu_psize_defs[mmu_virtual_psize].sllp;+vsid=(get_kernel_vsid(ea)<<SLB_VSID_SHIFT)|+SLB_VSID_KERNEL|llp;+break;+caseKERNEL_REGION_ID:+llp=mmu_psize_defs[mmu_linear_psize].sllp;+vsid=(get_kernel_vsid(ea)<<SLB_VSID_SHIFT)|+SLB_VSID_KERNEL|llp;+break;+default:/* Future: support kernel segments so that drivers*canuseSPUs.*/
@@ -97,16 +120,6 @@ static int __spu_trap_data_seg(struct spreturn1;}-esid=(ea&ESID_MASK)|SLB_ESID_V;-#ifdef CONFIG_HUGETLB_PAGE-if(in_hugepage_area(mm->context,ea))-llp=mmu_psize_defs[mmu_huge_psize].sllp;-else-#endif-llp=mmu_psize_defs[mmu_virtual_psize].sllp;-vsid=(get_vsid(mm->context.id,ea)<<SLB_VSID_SHIFT)|-SLB_VSID_USER|llp;-out_be64(&priv2->slb_index_W,spu->slb_replace);out_be64(&priv2->slb_vsid_RW,vsid);out_be64(&priv2->slb_esid_RW,esid);
@@ -232,6 +235,89 @@ struct file_operations spufs_context_fop.fsync=simple_sync_file,};+staticintspu_setup_isolated(structspu_context*ctx)+{+intret;+u64__iomem*mfc_cntl;+u64sr1;+u32status;+unsignedlongtimeout;+constu32status_loading=SPU_STATUS_RUNNING+|SPU_STATUS_ISOLATED_STATE|SPU_STATUS_ISOLATED_LOAD_STATUS;++if(!isolated_loader)+return-ENODEV;++if((ret=spu_acquire_runnable(ctx))!=0)+returnret;++mfc_cntl=&ctx->spu->priv2->mfc_control_RW;++/* purge the MFC DMA queue to ensure no spurious accesses before we+*enterkernelmode*/+timeout=jiffies+HZ;+out_be64(mfc_cntl,MFC_CNTL_PURGE_DMA_REQUEST);+while((in_be64(mfc_cntl)&MFC_CNTL_PURGE_DMA_STATUS_MASK)+!=MFC_CNTL_PURGE_DMA_COMPLETE){+if(time_after(jiffies,timeout)){+printk(KERN_ERR"%s: timeout flushing MFC DMA queue\n",+__FUNCTION__);+ret=-EIO;+gotoout_unlock;+}+cond_resched();+}++/* put the SPE in kernel mode to allow access to the loader */+sr1=spu_mfc_sr1_get(ctx->spu);+sr1&=~MFC_STATE1_PROBLEM_STATE_MASK;+spu_mfc_sr1_set(ctx->spu,sr1);++/* start the loader */+ctx->ops->signal1_write(ctx,(unsignedlong)isolated_loader>>32);+ctx->ops->signal2_write(ctx,+(unsignedlong)isolated_loader&0xffffffff);++ctx->ops->runcntl_write(ctx,+SPU_RUNCNTL_RUNNABLE|SPU_RUNCNTL_ISOLATE);++ret=0;+timeout=jiffies+HZ;+while(((status=ctx->ops->status_read(ctx))&status_loading)==+status_loading){+if(time_after(jiffies,timeout)){+printk(KERN_ERR"%s: timeout waiting for loader\n",+__FUNCTION__);+ret=-EIO;+gotoout_drop_priv;+}+cond_resched();+}++if(!(status&SPU_STATUS_RUNNING)){+/* If isolated LOAD has failed: run SPU, we will get a stop-and+*signallater.*/+pr_debug("%s: isolated LOAD failed\n",__FUNCTION__);+ctx->ops->runcntl_write(ctx,SPU_RUNCNTL_RUNNABLE);+ret=-EACCES;++}elseif(!(status&SPU_STATUS_ISOLATED_STATE)){+/* This isn't allowed by the CBEA, but check anyway */+pr_debug("%s: SPU fell out of isolated mode?\n",__FUNCTION__);+ctx->ops->runcntl_write(ctx,SPU_RUNCNTL_STOP);+ret=-EINVAL;+}++out_drop_priv:+/* Finished accessing the loader. Drop kernel mode */+sr1|=MFC_STATE1_PROBLEM_STATE_MASK;+spu_mfc_sr1_set(ctx->spu,sr1);++out_unlock:+up_write(&ctx->state_sema);+returnret;+}+staticintspufs_mkdir(structinode*dir,structdentry*dentry,unsignedintflags,intmode)
@@ -56,12 +58,12 @@ static inline int spu_run_init(struct spif((ret=spu_acquire_runnable(ctx))!=0)returnret;-if(ctx->flags&SPU_CREATE_ISOLATE)-runcntl|=SPU_RUNCNTL_ISOLATE;-else+/* if we're in isolated mode, we would have started the SPU+*earlier,sodon'tdoitagainnow.*/+if(!(ctx->flags&SPU_CREATE_ISOLATE)){ctx->ops->npc_write(ctx,*npc);--ctx->ops->runcntl_write(ctx,runcntl);+ctx->ops->runcntl_write(ctx,runcntl);+}return0;}--
From: David Erb <redacted>
There are a few definitions that are required by subsequent patches,
so add them here.
The original patch is from David Erb, but is significantly cleaned
up by Kevon Corry.
Cc: Kevin Corry <redacted>
Signed-off-by: Arnd Bergmann <redacted>
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
===================================================================
@@ -42,6 +42,19 @@ static struct cbe_thread_mapstaticstructcbe_regs_map*cbe_find_map(structdevice_node*np){inti;+structdevice_node*tmp_np;++if(strcasecmp(np->type,"spe")==0){+if(np->data==NULL){+/* walk up path until cpu node was found */+tmp_np=np->parent;+while(tmp_np!=NULL&&strcasecmp(tmp_np->type,"cpu")!=0)+tmp_np=tmp_np->parent;++np->data=cbe_find_map(tmp_np);+}+returnnp->data;+}for(i=0;i<cbe_regs_map_count;i++)if(cbe_regs_maps[i].cpu_node==np)
@@ -54,9 +54,9 @@ static void __init cbe_enable_pause_zeropr_debug("Power Management: CPU %d\n",smp_processor_id());/* Enable Pause(0) control bit */-temp_register=in_be64(&pregs->pm_control);+temp_register=in_be64(&pregs->pmcr);-out_be64(&pregs->pm_control,+out_be64(&pregs->pmcr,temp_register|CBE_PMD_PAUSE_ZERO_CONTROL);/* Enable DEC and EE interrupt request */
@@ -87,7 +87,7 @@ static void cbe_idle(void)unsignedlongctrl;/* Why do we do that on every idle ? Couldn't that be done once for-*allordowelosethestatesomeway?Also,thepm_control+*allordowelosethestatesomeway?Also,thepmcr*registersetting,thatcan'tbesetonceatboot?Wereallywant*tomovethatawayinordertoimplementasimplepowersave*/--
From: Jeremy Kerr <redacted>
When in isolated mode, SPEs have access to an area of persistent
storage, which is per-SPE. In order for isolated-mode apps to
communicate arbitrary data through this storage, we need to ensure that
isolated physical SPEs can be reused for subsequent applications.
Add a file ("recycle") in a spethread dir to enable isolated-mode
recycling. By writing to this file, the kernel will reload the
isolated-mode loader kernel, allowing a new app to be run on the same
physical SPE.
This requires the spu_acquire_exclusive function to enforce exclusive
access to the SPE while the loader is initialised.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Arnd Bergmann <redacted>
---
Update: clarify locking, remove unnecessary yield, require >0 bytes
when writing to recycle file.
arch/powerpc/platforms/cell/spufs/context.c | 27 +++++++++++++++++++++++
arch/powerpc/platforms/cell/spufs/file.c | 32 ++++++++++++++++++++++++++++
arch/powerpc/platforms/cell/spufs/inode.c | 23 +++++++++++++-------
arch/powerpc/platforms/cell/spufs/spufs.h | 7 ++++++
4 files changed, 81 insertions(+), 8 deletions(-)
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/context.c
===================================================================
@@ -120,6 +120,33 @@ void spu_unmap_mappings(struct spu_conteunmap_mapping_range(ctx->signal2,0,0x4000,1);}+intspu_acquire_exclusive(structspu_context*ctx)+{+intret=0;++down_write(&ctx->state_sema);+/* ctx is about to be freed, can't acquire any more */+if(!ctx->owner){+ret=-EINVAL;+gotoout;+}++if(ctx->state==SPU_STATE_SAVED){+ret=spu_activate(ctx,0);+if(ret)+gotoout;+ctx->state=SPU_STATE_RUNNABLE;+}else{+/* We need to exclude userspace access to the context. */+spu_unmap_mappings(ctx);+}++out:+if(ret)+up_write(&ctx->state_sema);+returnret;+}+intspu_acquire_runnable(structspu_context*ctx){intret=0;
From: Christian Krafft <redacted>
In order to add sysfs attributes to all spu's, there is a
need for a list of all available spu's. Adding the device_node
makes also sense, as it is needed for proper register access.
This patch also adds two functions to create and remove sysfs
attributes and attribute_groups to all spus.
That allows to group spu attributes in a subdirectory like:
/sys/devices/system/spu/spuX/group_name/what_ever
This will be used by cbe_thermal to group all attributes dealing with
thermal support in one directory.
Signed-off-by: Christian Krafft <redacted>
Signed-off-by: Arnd Bergmann <redacted>
Index: linux-2.6/include/asm-powerpc/spu.h
===================================================================
You probably should check for errors on sysdev_create_file, clean up and
return an error number instead of always 0.
This is true for all the new functions here.
On Wednesday 25 October 2006 09:52, Heiko Carstens wrote:
You probably should check for errors on sysdev_create_file, clean up and
return an error number instead of always 0.
This is true for all the new functions here.
Right, thanks for the review.
Christian or I will take care of this.
Arnd <><
Which is a total PITA. If this is the case, then we should modify the
add calls to at least initialize enough fields before they can fail for
the remove calls not to crash. You don't want to keep track precisely of
what file was added and what not and test all of that in your exit code
path, it's just insane.
Ben.
On Thursday 26 October 2006 01:19, Benjamin Herrenschmidt wrote:
quoted
Will crash if cpu_add_sysdev_attr_group failed...
Which is a total PITA. If this is the case, then we should modify the
add calls to at least initialize enough fields before they can fail for
the remove calls not to crash. You don't want to keep track precisely of
what file was added and what not and test all of that in your exit code
path, it's just insane.
Heiko suggested that earlied in http://lkml.org/lkml/2006/10/9/22,
but Andrew didn't like it.
Currently, the worst is that sysfs_remove_file can be used
on a nonexisting file, but sysfs_remove_group cannot, which is
inconsistent. Either sysfs_remove_file should WARN_ON or
sysfs_remove_group should silently return, and I'd prefer the
latter, as it makes users simpler.
Arnd <><
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2006-10-26 09:19:44
On Thu, 2006-10-26 at 09:35 +0200, Arnd Bergmann wrote:
On Thursday 26 October 2006 01:19, Benjamin Herrenschmidt wrote:
quoted
quoted
Will crash if cpu_add_sysdev_attr_group failed...
Which is a total PITA. If this is the case, then we should modify the
add calls to at least initialize enough fields before they can fail for
the remove calls not to crash. You don't want to keep track precisely of
what file was added and what not and test all of that in your exit code
path, it's just insane.
Heiko suggested that earlied in http://lkml.org/lkml/2006/10/9/22,
but Andrew didn't like it.
Currently, the worst is that sysfs_remove_file can be used
on a nonexisting file, but sysfs_remove_group cannot, which is
inconsistent. Either sysfs_remove_file should WARN_ON or
sysfs_remove_group should silently return, and I'd prefer the
latter, as it makes users simpler.
We need to argue with Andrew then. I'll have a go tomorrow
Ben.