Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 17122
b: refs/heads/master
c: 8b3d666
h: refs/heads/master
v: v3
  • Loading branch information
Arnd Bergmann authored and Paul Mackerras committed Jan 9, 2006
1 parent 5617f2a commit f0aaf9a
Show file tree
Hide file tree
Showing 15 changed files with 1,681 additions and 324 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 05b841174c289ca62a6b42d883b8791d9ac3a4bd
refs/heads/master: 8b3d6663c6217e4f50cc3720935a96da9b984117
75 changes: 75 additions & 0 deletions trunk/arch/powerpc/platforms/cell/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,77 @@ void cell_show_cpuinfo(struct seq_file *m)
of_node_put(root);
}

#ifdef CONFIG_SPARSEMEM
static int __init find_spu_node_id(struct device_node *spe)
{
unsigned int *id;
#ifdef CONFIG_NUMA
struct device_node *cpu;
cpu = spe->parent->parent;
id = (unsigned int *)get_property(cpu, "node-id", NULL);
#else
id = NULL;
#endif
return id ? *id : 0;
}

static void __init cell_spuprop_present(struct device_node *spe,
const char *prop, int early)
{
struct address_prop {
unsigned long address;
unsigned int len;
} __attribute__((packed)) *p;
int proplen;

unsigned long start_pfn, end_pfn, pfn;
int node_id;

p = (void*)get_property(spe, prop, &proplen);
WARN_ON(proplen != sizeof (*p));

node_id = find_spu_node_id(spe);

start_pfn = p->address >> PAGE_SHIFT;
end_pfn = (p->address + p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;

/* We need to call memory_present *before* the call to sparse_init,
but we can initialize the page structs only *after* that call.
Thus, we're being called twice. */
if (early)
memory_present(node_id, start_pfn, end_pfn);
else {
/* As the pages backing SPU LS and I/O are outside the range
of regular memory, their page structs were not initialized
by free_area_init. Do it here instead. */
for (pfn = start_pfn; pfn < end_pfn; pfn++) {
struct page *page = pfn_to_page(pfn);
set_page_links(page, ZONE_DMA, node_id, pfn);
set_page_count(page, 0);
reset_page_mapcount(page);
SetPageReserved(page);
INIT_LIST_HEAD(&page->lru);
}
}
}

static void __init cell_spumem_init(int early)
{
struct device_node *node;
for (node = of_find_node_by_type(NULL, "spe");
node; node = of_find_node_by_type(node, "spe")) {
cell_spuprop_present(node, "local-store", early);
cell_spuprop_present(node, "problem", early);
cell_spuprop_present(node, "priv1", early);
cell_spuprop_present(node, "priv2", early);
}
}
#else
static void __init cell_spumem_init(int early)
{
}
#endif

static void cell_progress(char *s, unsigned short hex)
{
printk("*** %04x : %s\n", hex, s ? s : "");
Expand Down Expand Up @@ -99,6 +170,8 @@ static void __init cell_setup_arch(void)
#endif

mmio_nvram_init();

cell_spumem_init(0);
}

/*
Expand All @@ -114,6 +187,8 @@ static void __init cell_init_early(void)

ppc64_interrupt_controller = IC_CELL_PIC;

cell_spumem_init(1);

DBG(" <- cell_init_early()\n");
}

Expand Down
138 changes: 76 additions & 62 deletions trunk/arch/powerpc/platforms/cell/spu_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,51 +69,49 @@ static void spu_restart_dma(struct spu *spu)

static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
{
struct spu_priv2 __iomem *priv2;
struct mm_struct *mm;
struct spu_priv2 __iomem *priv2 = spu->priv2;
struct mm_struct *mm = spu->mm;
u64 esid, vsid;

pr_debug("%s\n", __FUNCTION__);

if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) {
/* SLBs are pre-loaded for context switch, so
* we should never get here!
*/
printk("%s: invalid access during switch!\n", __func__);
return 1;
}

if (REGION_ID(ea) != USER_REGION_ID) {
if (!mm || (REGION_ID(ea) != USER_REGION_ID)) {
/* Future: support kernel segments so that drivers
* can use SPUs.
*/
pr_debug("invalid region access at %016lx\n", ea);
return 1;
}

priv2 = spu->priv2;
mm = spu->mm;
esid = (ea & ESID_MASK) | SLB_ESID_V;
vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | SLB_VSID_USER;
if (in_hugepage_area(mm->context, ea))
vsid |= SLB_VSID_L;

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

spu->slb_replace++;
if (spu->slb_replace >= 8)
spu->slb_replace = 0;

out_be64(&priv2->slb_index_W, spu->slb_replace);
out_be64(&priv2->slb_vsid_RW,
(get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT)
| SLB_VSID_USER);
out_be64(&priv2->slb_esid_RW, (ea & ESID_MASK) | SLB_ESID_V);

spu_restart_dma(spu);

pr_debug("set slb %d context %lx, ea %016lx, vsid %016lx, esid %016lx\n",
spu->slb_replace, mm->context.id, ea,
(get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT)| SLB_VSID_USER,
(ea & ESID_MASK) | SLB_ESID_V);
return 0;
}

extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
static int __spu_trap_data_map(struct spu *spu, unsigned long ea)
static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
{
unsigned long dsisr;
struct spu_priv1 __iomem *priv1;

pr_debug("%s\n", __FUNCTION__);
priv1 = spu->priv1;
dsisr = in_be64(&priv1->mfc_dsisr_RW);

/* Handle kernel space hash faults immediately.
User hash faults need to be deferred to process context. */
Expand All @@ -129,14 +127,17 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea)
return 1;
}

spu->dar = ea;
spu->dsisr = dsisr;
mb();
wake_up(&spu->stop_wq);
return 0;
}

static int __spu_trap_mailbox(struct spu *spu)
{
wake_up_all(&spu->ibox_wq);
kill_fasync(&spu->ibox_fasync, SIGIO, POLLIN);
if (spu->ibox_callback)
spu->ibox_callback(spu);

/* atomically disable SPU mailbox interrupts */
spin_lock(&spu->register_lock);
Expand Down Expand Up @@ -171,8 +172,8 @@ static int __spu_trap_tag_group(struct spu *spu)

static int __spu_trap_spubox(struct spu *spu)
{
wake_up_all(&spu->wbox_wq);
kill_fasync(&spu->wbox_fasync, SIGIO, POLLOUT);
if (spu->wbox_callback)
spu->wbox_callback(spu);

/* atomically disable SPU mailbox interrupts */
spin_lock(&spu->register_lock);
Expand Down Expand Up @@ -220,17 +221,25 @@ static irqreturn_t
spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
{
struct spu *spu;
unsigned long stat, dar;
unsigned long stat, mask, dar, dsisr;

spu = data;
stat = in_be64(&spu->priv1->int_stat_class1_RW);

/* atomically read & clear class1 status. */
spin_lock(&spu->register_lock);
mask = in_be64(&spu->priv1->int_mask_class1_RW);
stat = in_be64(&spu->priv1->int_stat_class1_RW) & mask;
dar = in_be64(&spu->priv1->mfc_dar_RW);
dsisr = in_be64(&spu->priv1->mfc_dsisr_RW);
out_be64(&spu->priv1->mfc_dsisr_RW, 0UL);
out_be64(&spu->priv1->int_stat_class1_RW, stat);
spin_unlock(&spu->register_lock);

if (stat & 1) /* segment fault */
__spu_trap_data_seg(spu, dar);

if (stat & 2) { /* mapping fault */
__spu_trap_data_map(spu, dar);
__spu_trap_data_map(spu, dar, dsisr);
}

if (stat & 4) /* ls compare & suspend on get */
Expand All @@ -239,7 +248,6 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
if (stat & 8) /* ls compare & suspend on put */
;

out_be64(&spu->priv1->int_stat_class1_RW, stat);
return stat ? IRQ_HANDLED : IRQ_NONE;
}

Expand Down Expand Up @@ -396,24 +404,20 @@ EXPORT_SYMBOL(spu_alloc);
void spu_free(struct spu *spu)
{
down(&spu_mutex);
spu->ibox_fasync = NULL;
spu->wbox_fasync = NULL;
list_add_tail(&spu->list, &spu_list);
up(&spu_mutex);
}
EXPORT_SYMBOL(spu_free);

static int spu_handle_mm_fault(struct spu *spu)
{
struct spu_priv1 __iomem *priv1;
struct mm_struct *mm = spu->mm;
struct vm_area_struct *vma;
u64 ea, dsisr, is_write;
int ret;

priv1 = spu->priv1;
ea = in_be64(&priv1->mfc_dar_RW);
dsisr = in_be64(&priv1->mfc_dsisr_RW);
ea = spu->dar;
dsisr = spu->dsisr;
#if 0
if (!IS_VALID_EA(ea)) {
return -EFAULT;
Expand Down Expand Up @@ -476,15 +480,14 @@ static int spu_handle_mm_fault(struct spu *spu)

static int spu_handle_pte_fault(struct spu *spu)
{
struct spu_priv1 __iomem *priv1;
u64 ea, dsisr, access, error = 0UL;
int ret = 0;

priv1 = spu->priv1;
ea = in_be64(&priv1->mfc_dar_RW);
dsisr = in_be64(&priv1->mfc_dsisr_RW);
access = (_PAGE_PRESENT | _PAGE_USER);
ea = spu->dar;
dsisr = spu->dsisr;
if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
access = (_PAGE_PRESENT | _PAGE_USER);
access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
if (hash_page(ea, access, 0x300) != 0)
error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
}
Expand All @@ -495,40 +498,49 @@ static int spu_handle_pte_fault(struct spu *spu)
else
error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR;
}
if (!error)
spu->dar = 0UL;
spu->dsisr = 0UL;
if (!error) {
spu_restart_dma(spu);

} else {
__spu_trap_invalid_dma(spu);
}
return ret;
}

static inline int spu_pending(struct spu *spu, u32 * stat)
{
struct spu_problem __iomem *prob = spu->problem;
u64 pte_fault;

*stat = in_be32(&prob->spu_status_R);
pte_fault = spu->dsisr &
(MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
}

int spu_run(struct spu *spu)
{
struct spu_problem __iomem *prob;
struct spu_priv1 __iomem *priv1;
struct spu_priv2 __iomem *priv2;
unsigned long status;
u32 status;
int ret;

prob = spu->problem;
priv1 = spu->priv1;
priv2 = spu->priv2;

/* Let SPU run. */
spu->mm = current->mm;
eieio();
out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);

do {
ret = wait_event_interruptible(spu->stop_wq,
(!((status = in_be32(&prob->spu_status_R)) & 0x1))
|| (in_be64(&priv1->mfc_dsisr_RW) & MFC_DSISR_PTE_NOT_FOUND)
|| spu->class_0_pending);

if (status & SPU_STATUS_STOPPED_BY_STOP)
ret = -EAGAIN;
else if (status & SPU_STATUS_STOPPED_BY_HALT)
ret = -EIO;
else if (in_be64(&priv1->mfc_dsisr_RW) & MFC_DSISR_PTE_NOT_FOUND)
spu_pending(spu, &status));

if (spu->dsisr &
(MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))
ret = spu_handle_pte_fault(spu);

if (spu->class_0_pending)
Expand All @@ -537,7 +549,9 @@ int spu_run(struct spu *spu)
if (!ret && signal_pending(current))
ret = -ERESTARTSYS;

} while (!ret);
} while (!ret && !(status &
(SPU_STATUS_STOPPED_BY_STOP |
SPU_STATUS_STOPPED_BY_HALT)));

/* Ensure SPU is stopped. */
out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
Expand All @@ -549,8 +563,6 @@ int spu_run(struct spu *spu)
out_be64(&priv1->tlb_invalidate_entry_W, 0UL);
eieio();

spu->mm = NULL;

/* Check for SPU breakpoint. */
if (unlikely(current->ptrace & PT_PTRACED)) {
status = in_be32(&prob->spu_status_R);
Expand Down Expand Up @@ -669,19 +681,21 @@ static int __init create_spu(struct device_node *spe)
spu->stop_code = 0;
spu->slb_replace = 0;
spu->mm = NULL;
spu->ctx = NULL;
spu->rq = NULL;
spu->pid = 0;
spu->class_0_pending = 0;
spu->flags = 0UL;
spu->dar = 0UL;
spu->dsisr = 0UL;
spin_lock_init(&spu->register_lock);

out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
out_be64(&spu->priv1->mfc_sr1_RW, 0x33);

init_waitqueue_head(&spu->stop_wq);
init_waitqueue_head(&spu->wbox_wq);
init_waitqueue_head(&spu->ibox_wq);

spu->ibox_fasync = NULL;
spu->wbox_fasync = NULL;
spu->ibox_callback = NULL;
spu->wbox_callback = NULL;

down(&spu_mutex);
spu->number = number++;
Expand Down
Loading

0 comments on commit f0aaf9a

Please sign in to comment.