Skip to content

Commit

Permalink
Merge branch 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kerne…
Browse files Browse the repository at this point in the history
…l/git/arnd/cell-2.6 into for-2.6.25
  • Loading branch information
Paul Mackerras committed Dec 20, 2007
2 parents f91266e + 1e77103 commit 2c0b713
Show file tree
Hide file tree
Showing 14 changed files with 170 additions and 75 deletions.
20 changes: 11 additions & 9 deletions arch/powerpc/oprofile/op_model_cell.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ static unsigned int spu_cycle_reset;
#define NUM_THREADS 2 /* number of physical threads in
* physical processor
*/
#define NUM_TRACE_BUS_WORDS 4
#define NUM_DEBUG_BUS_WORDS 4
#define NUM_INPUT_BUS_WORDS 2

#define MAX_SPU_COUNT 0xFFFFFF /* maximum 24 bit LFSR value */
Expand Down Expand Up @@ -169,7 +169,6 @@ static DEFINE_SPINLOCK(virt_cntr_lock);

static u32 ctr_enabled;

static unsigned char trace_bus[NUM_TRACE_BUS_WORDS];
static unsigned char input_bus[NUM_INPUT_BUS_WORDS];

/*
Expand Down Expand Up @@ -298,7 +297,7 @@ static void set_pm_event(u32 ctr, int event, u32 unit_mask)

p->signal_group = event / 100;
p->bus_word = bus_word;
p->sub_unit = (unit_mask & 0x0000f000) >> 12;
p->sub_unit = GET_SUB_UNIT(unit_mask);

pm_regs.pm07_cntrl[ctr] = 0;
pm_regs.pm07_cntrl[ctr] |= PM07_CTR_COUNT_CYCLES(count_cycles);
Expand Down Expand Up @@ -334,16 +333,16 @@ static void set_pm_event(u32 ctr, int event, u32 unit_mask)
p->bit = signal_bit;
}

for (i = 0; i < NUM_TRACE_BUS_WORDS; i++) {
for (i = 0; i < NUM_DEBUG_BUS_WORDS; i++) {
if (bus_word & (1 << i)) {
pm_regs.debug_bus_control |=
(bus_type << (31 - (2 * i) + 1));
(bus_type << (30 - (2 * i)));

for (j = 0; j < NUM_INPUT_BUS_WORDS; j++) {
if (input_bus[j] == 0xff) {
input_bus[j] = i;
pm_regs.group_control |=
(i << (31 - i));
(i << (30 - (2 * j)));

break;
}
Expand Down Expand Up @@ -450,6 +449,12 @@ static void cell_virtual_cntr(unsigned long data)
hdw_thread = 1 ^ hdw_thread;
next_hdw_thread = hdw_thread;

pm_regs.group_control = 0;
pm_regs.debug_bus_control = 0;

for (i = 0; i < NUM_INPUT_BUS_WORDS; i++)
input_bus[i] = 0xff;

/*
* There are some per thread events. Must do the
* set event, for the thread that is being started
Expand Down Expand Up @@ -619,9 +624,6 @@ static int cell_reg_setup(struct op_counter_config *ctr,
pmc_cntrl[1][i].vcntr = i;
}

for (i = 0; i < NUM_TRACE_BUS_WORDS; i++)
trace_bus[i] = 0xff;

for (i = 0; i < NUM_INPUT_BUS_WORDS; i++)
input_bus[i] = 0xff;

Expand Down
3 changes: 2 additions & 1 deletion arch/powerpc/platforms/cell/cbe_cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
*/

#include <linux/cpufreq.h>
#include <linux/of_platform.h>

#include <asm/machdep.h>
#include <asm/of_platform.h>
#include <asm/prom.h>
#include <asm/cell-regs.h>
#include "cbe_cpufreq.h"
Expand Down
3 changes: 2 additions & 1 deletion arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <asm/of_platform.h>
#include <linux/of_platform.h>

#include <asm/processor.h>
#include <asm/prom.h>
#include <asm/pmi.h>
Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/platforms/cell/cbe_regs.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
#include <linux/percpu.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>

#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/ptrace.h>
#include <asm/of_device.h>
#include <asm/of_platform.h>
#include <asm/cell-regs.h>

/*
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/platforms/cell/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/of_platform.h>

#include <asm/prom.h>
#include <asm/iommu.h>
#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <asm/udbg.h>
#include <asm/of_platform.h>
#include <asm/lmb.h>
#include <asm/firmware.h>
#include <asm/cell-regs.h>
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/platforms/cell/pmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ u32 cbe_read_pm(u32 cpu, enum pm_reg_name reg)
break;

case pm_interval:
READ_SHADOW_REG(val, pm_interval);
READ_MMIO_UPPER32(val, pm_interval);
break;

case pm_start_stop:
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/platforms/cell/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <linux/console.h>
#include <linux/mutex.h>
#include <linux/memory_hotplug.h>
#include <linux/of_platform.h>

#include <asm/mmu.h>
#include <asm/processor.h>
Expand All @@ -51,7 +52,6 @@
#include <asm/spu_priv1.h>
#include <asm/udbg.h>
#include <asm/mpic.h>
#include <asm/of_platform.h>
#include <asm/cell-regs.h>

#include "interrupt.h"
Expand Down
141 changes: 125 additions & 16 deletions arch/powerpc/platforms/cell/spu_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <linux/linux_logo.h>
#include <asm/spu.h>
#include <asm/spu_priv1.h>
#include <asm/spu_csa.h>
#include <asm/xmon.h>
#include <asm/prom.h>

Expand All @@ -46,6 +47,13 @@ EXPORT_SYMBOL_GPL(spu_priv1_ops);
struct cbe_spu_info cbe_spu_info[MAX_NUMNODES];
EXPORT_SYMBOL_GPL(cbe_spu_info);

/*
* The spufs fault-handling code needs to call force_sig_info to raise signals
* on DMA errors. Export it here to avoid general kernel-wide access to this
* function
*/
EXPORT_SYMBOL_GPL(force_sig_info);

/*
* Protects cbe_spu_info and spu->number.
*/
Expand All @@ -66,6 +74,10 @@ static LIST_HEAD(spu_full_list);
static DEFINE_SPINLOCK(spu_full_list_lock);
static DEFINE_MUTEX(spu_full_list_mutex);

struct spu_slb {
u64 esid, vsid;
};

void spu_invalidate_slbs(struct spu *spu)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
Expand Down Expand Up @@ -114,6 +126,12 @@ void spu_associate_mm(struct spu *spu, struct mm_struct *mm)
}
EXPORT_SYMBOL_GPL(spu_associate_mm);

int spu_64k_pages_available(void)
{
return mmu_psize_defs[MMU_PAGE_64K].shift != 0;
}
EXPORT_SYMBOL_GPL(spu_64k_pages_available);

static int __spu_trap_invalid_dma(struct spu *spu)
{
pr_debug("%s\n", __FUNCTION__);
Expand Down Expand Up @@ -143,11 +161,22 @@ static void spu_restart_dma(struct spu *spu)
out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
}

static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
static inline void spu_load_slb(struct spu *spu, int slbe, struct spu_slb *slb)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;

pr_debug("%s: adding SLB[%d] 0x%016lx 0x%016lx\n",
__func__, slbe, slb->vsid, slb->esid);

out_be64(&priv2->slb_index_W, slbe);
out_be64(&priv2->slb_vsid_RW, slb->vsid);
out_be64(&priv2->slb_esid_RW, slb->esid);
}

static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
{
struct mm_struct *mm = spu->mm;
u64 esid, vsid, llp;
struct spu_slb slb;
int psize;

pr_debug("%s\n", __FUNCTION__);
Expand All @@ -159,7 +188,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
printk("%s: invalid access during switch!\n", __func__);
return 1;
}
esid = (ea & ESID_MASK) | SLB_ESID_V;
slb.esid = (ea & ESID_MASK) | SLB_ESID_V;

switch(REGION_ID(ea)) {
case USER_REGION_ID:
Expand All @@ -168,21 +197,21 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
#else
psize = mm->context.user_psize;
#endif
vsid = (get_vsid(mm->context.id, ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) |
SLB_VSID_USER;
slb.vsid = (get_vsid(mm->context.id, ea, MMU_SEGSIZE_256M)
<< SLB_VSID_SHIFT) | SLB_VSID_USER;
break;
case VMALLOC_REGION_ID:
if (ea < VMALLOC_END)
psize = mmu_vmalloc_psize;
else
psize = mmu_io_psize;
vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) |
SLB_VSID_KERNEL;
slb.vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M)
<< SLB_VSID_SHIFT) | SLB_VSID_KERNEL;
break;
case KERNEL_REGION_ID:
psize = mmu_linear_psize;
vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) |
SLB_VSID_KERNEL;
slb.vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M)
<< SLB_VSID_SHIFT) | SLB_VSID_KERNEL;
break;
default:
/* Future: support kernel segments so that drivers
Expand All @@ -191,11 +220,9 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
pr_debug("invalid region access at %016lx\n", ea);
return 1;
}
llp = mmu_psize_defs[psize].sllp;
slb.vsid |= mmu_psize_defs[psize].sllp;

out_be64(&priv2->slb_index_W, spu->slb_replace);
out_be64(&priv2->slb_vsid_RW, vsid | llp);
out_be64(&priv2->slb_esid_RW, esid);
spu_load_slb(spu, spu->slb_replace, &slb);

spu->slb_replace++;
if (spu->slb_replace >= 8)
Expand Down Expand Up @@ -232,6 +259,74 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
return 0;
}

static void __spu_kernel_slb(void *addr, struct spu_slb *slb)
{
unsigned long ea = (unsigned long)addr;
u64 llp;

if (REGION_ID(ea) == KERNEL_REGION_ID)
llp = mmu_psize_defs[mmu_linear_psize].sllp;
else
llp = mmu_psize_defs[mmu_virtual_psize].sllp;

slb->vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) |
SLB_VSID_KERNEL | llp;
slb->esid = (ea & ESID_MASK) | SLB_ESID_V;
}

/**
* Given an array of @nr_slbs SLB entries, @slbs, return non-zero if the
* address @new_addr is present.
*/
static inline int __slb_present(struct spu_slb *slbs, int nr_slbs,
void *new_addr)
{
unsigned long ea = (unsigned long)new_addr;
int i;

for (i = 0; i < nr_slbs; i++)
if (!((slbs[i].esid ^ ea) & ESID_MASK))
return 1;

return 0;
}

/**
* Setup the SPU kernel SLBs, in preparation for a context save/restore. We
* need to map both the context save area, and the save/restore code.
*
* Because the lscsa and code may cross segment boundaires, we check to see
* if mappings are required for the start and end of each range. We currently
* assume that the mappings are smaller that one segment - if not, something
* is seriously wrong.
*/
void spu_setup_kernel_slbs(struct spu *spu, struct spu_lscsa *lscsa,
void *code, int code_size)
{
struct spu_slb slbs[4];
int i, nr_slbs = 0;
/* start and end addresses of both mappings */
void *addrs[] = {
lscsa, (void *)lscsa + sizeof(*lscsa) - 1,
code, code + code_size - 1
};

/* check the set of addresses, and create a new entry in the slbs array
* if there isn't already a SLB for that address */
for (i = 0; i < ARRAY_SIZE(addrs); i++) {
if (__slb_present(slbs, nr_slbs, addrs[i]))
continue;

__spu_kernel_slb(addrs[i], &slbs[nr_slbs]);
nr_slbs++;
}

/* Add the set of SLBs */
for (i = 0; i < nr_slbs; i++)
spu_load_slb(spu, i, &slbs[i]);
}
EXPORT_SYMBOL_GPL(spu_setup_kernel_slbs);

static irqreturn_t
spu_irq_class_0(int irq, void *data)
{
Expand Down Expand Up @@ -479,13 +574,27 @@ EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);
int spu_add_sysdev_attr_group(struct attribute_group *attrs)
{
struct spu *spu;
int rc = 0;

mutex_lock(&spu_full_list_mutex);
list_for_each_entry(spu, &spu_full_list, full_list)
sysfs_create_group(&spu->sysdev.kobj, attrs);
list_for_each_entry(spu, &spu_full_list, full_list) {
rc = sysfs_create_group(&spu->sysdev.kobj, attrs);

/* we're in trouble here, but try unwinding anyway */
if (rc) {
printk(KERN_ERR "%s: can't create sysfs group '%s'\n",
__func__, attrs->name);

list_for_each_entry_continue_reverse(spu,
&spu_full_list, full_list)
sysfs_remove_group(&spu->sysdev.kobj, attrs);
break;
}
}

mutex_unlock(&spu_full_list_mutex);

return 0;
return rc;
}
EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);

Expand Down
Loading

0 comments on commit 2c0b713

Please sign in to comment.