spu_base.c 17.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * Low-level SPU handling
 *
 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
 *
 * Author: Arnd Bergmann <arndb@de.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, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

23
#undef DEBUG
24 25 26 27 28 29 30 31 32 33 34

#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/wait.h>

#include <asm/io.h>
#include <asm/prom.h>
35
#include <linux/mutex.h>
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
#include <asm/spu.h>
#include <asm/mmu_context.h>

#include "interrupt.h"

static int __spu_trap_invalid_dma(struct spu *spu)
{
	pr_debug("%s\n", __FUNCTION__);
	force_sig(SIGBUS, /* info, */ current);
	return 0;
}

static int __spu_trap_dma_align(struct spu *spu)
{
	pr_debug("%s\n", __FUNCTION__);
	force_sig(SIGBUS, /* info, */ current);
	return 0;
}

static int __spu_trap_error(struct spu *spu)
{
	pr_debug("%s\n", __FUNCTION__);
	force_sig(SIGILL, /* info, */ current);
	return 0;
}

static void spu_restart_dma(struct spu *spu)
{
	struct spu_priv2 __iomem *priv2 = spu->priv2;
65

66
	if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags))
67
		out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
68 69 70 71
}

static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
{
72 73
	struct spu_priv2 __iomem *priv2 = spu->priv2;
	struct mm_struct *mm = spu->mm;
74
	u64 esid, vsid, llp;
75 76 77

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

78
	if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
79 80 81
		/* SLBs are pre-loaded for context switch, so
		 * we should never get here!
		 */
82 83 84
		printk("%s: invalid access during switch!\n", __func__);
		return 1;
	}
85 86 87 88
	if (!mm || (REGION_ID(ea) != USER_REGION_ID)) {
		/* Future: support kernel segments so that drivers
		 * can use SPUs.
		 */
89 90 91 92
		pr_debug("invalid region access at %016lx\n", ea);
		return 1;
	}

93
	esid = (ea & ESID_MASK) | SLB_ESID_V;
94
#ifdef CONFIG_HUGETLB_PAGE
95
	if (in_hugepage_area(mm->context, ea))
96 97 98 99 100 101
		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;
102

103 104 105 106 107
	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++;
108 109 110 111 112 113 114 115
	if (spu->slb_replace >= 8)
		spu->slb_replace = 0;

	spu_restart_dma(spu);

	return 0;
}

116
extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
117
static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
118
{
119
	pr_debug("%s, %lx, %lx\n", __FUNCTION__, dsisr, ea);
120

121 122 123 124 125 126 127 128 129
	/* Handle kernel space hash faults immediately.
	   User hash faults need to be deferred to process context. */
	if ((dsisr & MFC_DSISR_PTE_NOT_FOUND)
	    && REGION_ID(ea) != USER_REGION_ID
	    && hash_page(ea, _PAGE_PRESENT, 0x300) == 0) {
		spu_restart_dma(spu);
		return 0;
	}

130
	if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
131 132 133
		printk("%s: invalid access during switch!\n", __func__);
		return 1;
	}
134

135 136 137
	spu->dar = ea;
	spu->dsisr = dsisr;
	mb();
138 139
	if (spu->stop_callback)
		spu->stop_callback(spu);
140 141 142 143 144
	return 0;
}

static int __spu_trap_mailbox(struct spu *spu)
{
145 146
	if (spu->ibox_callback)
		spu->ibox_callback(spu);
147 148 149

	/* atomically disable SPU mailbox interrupts */
	spin_lock(&spu->register_lock);
150
	spu_int_mask_and(spu, 2, ~0x1);
151 152 153 154 155 156 157 158
	spin_unlock(&spu->register_lock);
	return 0;
}

static int __spu_trap_stop(struct spu *spu)
{
	pr_debug("%s\n", __FUNCTION__);
	spu->stop_code = in_be32(&spu->problem->spu_status_R);
159 160
	if (spu->stop_callback)
		spu->stop_callback(spu);
161 162 163 164 165 166 167
	return 0;
}

static int __spu_trap_halt(struct spu *spu)
{
	pr_debug("%s\n", __FUNCTION__);
	spu->stop_code = in_be32(&spu->problem->spu_status_R);
168 169
	if (spu->stop_callback)
		spu->stop_callback(spu);
170 171 172 173 174 175
	return 0;
}

static int __spu_trap_tag_group(struct spu *spu)
{
	pr_debug("%s\n", __FUNCTION__);
176
	spu->mfc_callback(spu);
177 178 179 180 181
	return 0;
}

static int __spu_trap_spubox(struct spu *spu)
{
182 183
	if (spu->wbox_callback)
		spu->wbox_callback(spu);
184 185 186

	/* atomically disable SPU mailbox interrupts */
	spin_lock(&spu->register_lock);
187
	spu_int_mask_and(spu, 2, ~0x10);
188 189 190 191 192 193 194 195 196 197 198
	spin_unlock(&spu->register_lock);
	return 0;
}

static irqreturn_t
spu_irq_class_0(int irq, void *data, struct pt_regs *regs)
{
	struct spu *spu;

	spu = data;
	spu->class_0_pending = 1;
199 200
	if (spu->stop_callback)
		spu->stop_callback(spu);
201 202 203 204

	return IRQ_HANDLED;
}

205
int
206 207
spu_irq_class_0_bottom(struct spu *spu)
{
208
	unsigned long stat, mask;
209 210 211

	spu->class_0_pending = 0;

212 213
	mask = spu_int_mask_get(spu, 0);
	stat = spu_int_stat_get(spu, 0);
214

215 216
	stat &= mask;

217 218 219 220 221 222 223 224 225
	if (stat & 1) /* invalid MFC DMA */
		__spu_trap_invalid_dma(spu);

	if (stat & 2) /* invalid DMA alignment */
		__spu_trap_dma_align(spu);

	if (stat & 4) /* error on SPU */
		__spu_trap_error(spu);

226
	spu_int_stat_clear(spu, 0, stat);
227 228

	return (stat & 0x7) ? -EIO : 0;
229
}
230
EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom);
231 232 233 234 235

static irqreturn_t
spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
{
	struct spu *spu;
236
	unsigned long stat, mask, dar, dsisr;
237 238

	spu = data;
239 240 241

	/* atomically read & clear class1 status. */
	spin_lock(&spu->register_lock);
242 243 244 245
	mask  = spu_int_mask_get(spu, 1);
	stat  = spu_int_stat_get(spu, 1) & mask;
	dar   = spu_mfc_dar_get(spu);
	dsisr = spu_mfc_dsisr_get(spu);
246
	if (stat & 2) /* mapping fault */
247 248
		spu_mfc_dsisr_set(spu, 0ul);
	spu_int_stat_clear(spu, 1, stat);
249
	spin_unlock(&spu->register_lock);
250 251
	pr_debug("%s: %lx %lx %lx %lx\n", __FUNCTION__, mask, stat,
			dar, dsisr);
252 253 254 255 256

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

	if (stat & 2) { /* mapping fault */
257
		__spu_trap_data_map(spu, dar, dsisr);
258 259 260 261 262 263 264 265 266 267
	}

	if (stat & 4) /* ls compare & suspend on get */
		;

	if (stat & 8) /* ls compare & suspend on put */
		;

	return stat ? IRQ_HANDLED : IRQ_NONE;
}
268
EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom);
269 270 271 272 273 274

static irqreturn_t
spu_irq_class_2(int irq, void *data, struct pt_regs *regs)
{
	struct spu *spu;
	unsigned long stat;
275
	unsigned long mask;
276 277

	spu = data;
278 279
	stat = spu_int_stat_get(spu, 2);
	mask = spu_int_mask_get(spu, 2);
280

281
	pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask);
282

283
	stat &= mask;
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299

	if (stat & 1)  /* PPC core mailbox */
		__spu_trap_mailbox(spu);

	if (stat & 2) /* SPU stop-and-signal */
		__spu_trap_stop(spu);

	if (stat & 4) /* SPU halted */
		__spu_trap_halt(spu);

	if (stat & 8) /* DMA tag group complete */
		__spu_trap_tag_group(spu);

	if (stat & 0x10) /* SPU mailbox threshold */
		__spu_trap_spubox(spu);

300
	spu_int_stat_clear(spu, 2, stat);
301 302 303 304 305 306 307 308 309 310 311 312 313
	return stat ? IRQ_HANDLED : IRQ_NONE;
}

static int
spu_request_irqs(struct spu *spu)
{
	int ret;
	int irq_base;

	irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET;

	snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0", spu->number);
	ret = request_irq(irq_base + spu->isrc,
314
		 spu_irq_class_0, SA_INTERRUPT, spu->irq_c0, spu);
315 316 317 318 319
	if (ret)
		goto out;

	snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number);
	ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc,
320
		 spu_irq_class_1, SA_INTERRUPT, spu->irq_c1, spu);
321 322 323 324 325
	if (ret)
		goto out1;

	snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number);
	ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc,
326
		 spu_irq_class_2, SA_INTERRUPT, spu->irq_c2, spu);
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
	if (ret)
		goto out2;
	goto out;

out2:
	free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu);
out1:
	free_irq(irq_base + spu->isrc, spu);
out:
	return ret;
}

static void
spu_free_irqs(struct spu *spu)
{
	int irq_base;

	irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET;

	free_irq(irq_base + spu->isrc, spu);
	free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu);
	free_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc, spu);
}

static LIST_HEAD(spu_list);
352
static DEFINE_MUTEX(spu_mutex);
353 354 355 356 357 358 359 360 361 362 363 364 365 366

static void spu_init_channels(struct spu *spu)
{
	static const struct {
		 unsigned channel;
		 unsigned count;
	} zero_list[] = {
		{ 0x00, 1, }, { 0x01, 1, }, { 0x03, 1, }, { 0x04, 1, },
		{ 0x18, 1, }, { 0x19, 1, }, { 0x1b, 1, }, { 0x1d, 1, },
	}, count_list[] = {
		{ 0x00, 0, }, { 0x03, 0, }, { 0x04, 0, }, { 0x15, 16, },
		{ 0x17, 1, }, { 0x18, 0, }, { 0x19, 0, }, { 0x1b, 0, },
		{ 0x1c, 1, }, { 0x1d, 0, }, { 0x1e, 1, },
	};
367
	struct spu_priv2 __iomem *priv2;
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
	int i;

	priv2 = spu->priv2;

	/* initialize all channel data to zero */
	for (i = 0; i < ARRAY_SIZE(zero_list); i++) {
		int count;

		out_be64(&priv2->spu_chnlcntptr_RW, zero_list[i].channel);
		for (count = 0; count < zero_list[i].count; count++)
			out_be64(&priv2->spu_chnldata_RW, 0);
	}

	/* initialize channel counts to meaningful values */
	for (i = 0; i < ARRAY_SIZE(count_list); i++) {
		out_be64(&priv2->spu_chnlcntptr_RW, count_list[i].channel);
		out_be64(&priv2->spu_chnlcnt_RW, count_list[i].count);
	}
}

struct spu *spu_alloc(void)
{
	struct spu *spu;

392
	mutex_lock(&spu_mutex);
393 394 395 396 397 398 399 400
	if (!list_empty(&spu_list)) {
		spu = list_entry(spu_list.next, struct spu, list);
		list_del_init(&spu->list);
		pr_debug("Got SPU %x %d\n", spu->isrc, spu->number);
	} else {
		pr_debug("No SPU left\n");
		spu = NULL;
	}
401
	mutex_unlock(&spu_mutex);
402

403
	if (spu)
404 405 406 407
		spu_init_channels(spu);

	return spu;
}
408
EXPORT_SYMBOL_GPL(spu_alloc);
409 410 411

void spu_free(struct spu *spu)
{
412
	mutex_lock(&spu_mutex);
413
	list_add_tail(&spu->list, &spu_list);
414
	mutex_unlock(&spu_mutex);
415
}
416
EXPORT_SYMBOL_GPL(spu_free);
417 418 419 420 421 422 423 424

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

425 426
	ea = spu->dar;
	dsisr = spu->dsisr;
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
#if 0
	if (!IS_VALID_EA(ea)) {
		return -EFAULT;
	}
#endif /* XXX */
	if (mm == NULL) {
		return -EFAULT;
	}
	if (mm->pgd == NULL) {
		return -EFAULT;
	}

	down_read(&mm->mmap_sem);
	vma = find_vma(mm, ea);
	if (!vma)
		goto bad_area;
	if (vma->vm_start <= ea)
		goto good_area;
	if (!(vma->vm_flags & VM_GROWSDOWN))
		goto bad_area;
#if 0
	if (expand_stack(vma, ea))
		goto bad_area;
#endif /* XXX */
good_area:
	is_write = dsisr & MFC_DSISR_ACCESS_PUT;
	if (is_write) {
		if (!(vma->vm_flags & VM_WRITE))
			goto bad_area;
	} else {
		if (dsisr & MFC_DSISR_ACCESS_DENIED)
			goto bad_area;
		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
			goto bad_area;
	}
	ret = 0;
	switch (handle_mm_fault(mm, vma, ea, is_write)) {
	case VM_FAULT_MINOR:
		current->min_flt++;
		break;
	case VM_FAULT_MAJOR:
		current->maj_flt++;
		break;
	case VM_FAULT_SIGBUS:
		ret = -EFAULT;
		goto bad_area;
	case VM_FAULT_OOM:
		ret = -ENOMEM;
		goto bad_area;
	default:
		BUG();
	}
	up_read(&mm->mmap_sem);
	return ret;

bad_area:
	up_read(&mm->mmap_sem);
	return -EFAULT;
}

487
int spu_irq_class_1_bottom(struct spu *spu)
488 489 490 491
{
	u64 ea, dsisr, access, error = 0UL;
	int ret = 0;

492 493
	ea = spu->dar;
	dsisr = spu->dsisr;
494
	if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) {
495 496
		u64 flags;

497 498
		access = (_PAGE_PRESENT | _PAGE_USER);
		access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
499
		local_irq_save(flags);
500 501
		if (hash_page(ea, access, 0x300) != 0)
			error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
502
		local_irq_restore(flags);
503
	}
504
	if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) {
505 506 507 508 509
		if ((ret = spu_handle_mm_fault(spu)) != 0)
			error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
		else
			error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR;
	}
510 511 512
	spu->dar = 0UL;
	spu->dsisr = 0UL;
	if (!error) {
513
		spu_restart_dma(spu);
514 515 516
	} else {
		__spu_trap_invalid_dma(spu);
	}
517 518 519
	return ret;
}

520 521 522 523 524 525 526 527
void spu_irq_setaffinity(struct spu *spu, int cpu)
{
	u64 target = iic_get_target_id(cpu);
	u64 route = target << 48 | target << 32 | target << 16;
	spu_int_route_set(spu, route);
}
EXPORT_SYMBOL_GPL(spu_irq_setaffinity);

528 529 530 531 532 533 534 535 536
static int __init find_spu_node_id(struct device_node *spe)
{
	unsigned int *id;
	struct device_node *cpu;
	cpu = spe->parent->parent;
	id = (unsigned int *)get_property(cpu, "node-id", NULL);
	return id ? *id : 0;
}

537 538
static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe,
		const char *prop)
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
{
	static DEFINE_MUTEX(add_spumem_mutex);

	struct address_prop {
		unsigned long address;
		unsigned int len;
	} __attribute__((packed)) *p;
	int proplen;

	unsigned long start_pfn, nr_pages;
	struct pglist_data *pgdata;
	struct zone *zone;
	int ret;

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

	start_pfn = p->address >> PAGE_SHIFT;
	nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;

559
	pgdata = NODE_DATA(spu->nid);
560 561 562 563 564 565 566 567 568 569
	zone = pgdata->node_zones;

	/* XXX rethink locking here */
	mutex_lock(&add_spumem_mutex);
	ret = __add_pages(zone, start_pfn, nr_pages);
	mutex_unlock(&add_spumem_mutex);

	return ret;
}

570 571
static void __iomem * __init map_spe_prop(struct spu *spu,
		struct device_node *n, const char *name)
572 573 574 575 576 577 578 579
{
	struct address_prop {
		unsigned long address;
		unsigned int len;
	} __attribute__((packed)) *prop;

	void *p;
	int proplen;
580 581
	void* ret = NULL;
	int err = 0;
582 583 584 585 586 587 588

	p = get_property(n, name, &proplen);
	if (proplen != sizeof (struct address_prop))
		return NULL;

	prop = p;

589
	err = cell_spuprop_present(spu, n, name);
590 591 592 593 594 595 596
	if (err && (err != -EEXIST))
		goto out;

	ret = ioremap(prop->address, prop->len);

 out:
	return ret;
597 598 599 600 601 602 603 604 605 606
}

static void spu_unmap(struct spu *spu)
{
	iounmap(spu->priv2);
	iounmap(spu->priv1);
	iounmap(spu->problem);
	iounmap((u8 __iomem *)spu->local_store);
}

607
static int __init spu_map_device(struct spu *spu, struct device_node *node)
608 609 610 611 612
{
	char *prop;
	int ret;

	ret = -ENODEV;
613
	prop = get_property(node, "isrc", NULL);
614 615 616 617
	if (!prop)
		goto out;
	spu->isrc = *(unsigned int *)prop;

618
	spu->name = get_property(node, "name", NULL);
619 620 621
	if (!spu->name)
		goto out;

622
	prop = get_property(node, "local-store", NULL);
623 624 625 626 627
	if (!prop)
		goto out;
	spu->local_store_phys = *(unsigned long *)prop;

	/* we use local store as ram, not io memory */
628 629
	spu->local_store = (void __force *)
		map_spe_prop(spu, node, "local-store");
630 631 632
	if (!spu->local_store)
		goto out;

633
	prop = get_property(node, "problem", NULL);
634 635 636 637
	if (!prop)
		goto out_unmap;
	spu->problem_phys = *(unsigned long *)prop;

638
	spu->problem= map_spe_prop(spu, node, "problem");
639 640 641
	if (!spu->problem)
		goto out_unmap;

642
	spu->priv1= map_spe_prop(spu, node, "priv1");
643
	/* priv1 is not available on a hypervisor */
644

645
	spu->priv2= map_spe_prop(spu, node, "priv2");
646 647 648 649 650 651 652 653 654 655 656
	if (!spu->priv2)
		goto out_unmap;
	ret = 0;
	goto out;

out_unmap:
	spu_unmap(spu);
out:
	return ret;
}

657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
struct sysdev_class spu_sysdev_class = {
	set_kset_name("spu")
};

static ssize_t spu_show_isrc(struct sys_device *sysdev, char *buf)
{
	struct spu *spu = container_of(sysdev, struct spu, sysdev);
	return sprintf(buf, "%d\n", spu->isrc);

}
static SYSDEV_ATTR(isrc, 0400, spu_show_isrc, NULL);

extern int attach_sysdev_to_node(struct sys_device *dev, int nid);

static int spu_create_sysdev(struct spu *spu)
{
	int ret;

	spu->sysdev.id = spu->number;
	spu->sysdev.cls = &spu_sysdev_class;
	ret = sysdev_register(&spu->sysdev);
	if (ret) {
		printk(KERN_ERR "Can't register SPU %d with sysfs\n",
				spu->number);
		return ret;
	}

	sysdev_create_file(&spu->sysdev, &attr_isrc);
	sysfs_add_device_to_node(&spu->sysdev, spu->nid);

	return 0;
}

static void spu_destroy_sysdev(struct spu *spu)
{
	sysdev_remove_file(&spu->sysdev, &attr_isrc);
	sysfs_remove_device_from_node(&spu->sysdev, spu->nid);
	sysdev_unregister(&spu->sysdev);
}

697 698 699 700 701 702 703
static int __init create_spu(struct device_node *spe)
{
	struct spu *spu;
	int ret;
	static int number;

	ret = -ENOMEM;
704
	spu = kzalloc(sizeof (*spu), GFP_KERNEL);
705 706 707 708 709 710 711 712
	if (!spu)
		goto out;

	ret = spu_map_device(spu, spe);
	if (ret)
		goto out_free;

	spu->node = find_spu_node_id(spe);
713 714 715
	spu->nid = of_node_to_nid(spe);
	if (spu->nid == -1)
		spu->nid = 0;
716
	spin_lock_init(&spu->register_lock);
717 718
	spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
	spu_mfc_sr1_set(spu, 0x33);
719
	mutex_lock(&spu_mutex);
720

721 722 723 724 725
	spu->number = number++;
	ret = spu_request_irqs(spu);
	if (ret)
		goto out_unmap;

726 727 728 729
	ret = spu_create_sysdev(spu);
	if (ret)
		goto out_free_irqs;

730
	list_add(&spu->list, &spu_list);
731
	mutex_unlock(&spu_mutex);
732 733 734 735 736 737

	pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",
		spu->name, spu->isrc, spu->local_store,
		spu->problem, spu->priv1, spu->priv2, spu->number);
	goto out;

738 739 740
out_free_irqs:
	spu_free_irqs(spu);

741
out_unmap:
742
	mutex_unlock(&spu_mutex);
743 744 745 746 747 748 749 750 751 752 753
	spu_unmap(spu);
out_free:
	kfree(spu);
out:
	return ret;
}

static void destroy_spu(struct spu *spu)
{
	list_del_init(&spu->list);

754
	spu_destroy_sysdev(spu);
755 756 757 758 759 760 761 762
	spu_free_irqs(spu);
	spu_unmap(spu);
	kfree(spu);
}

static void cleanup_spu_base(void)
{
	struct spu *spu, *tmp;
763
	mutex_lock(&spu_mutex);
764 765
	list_for_each_entry_safe(spu, tmp, &spu_list, list)
		destroy_spu(spu);
766
	mutex_unlock(&spu_mutex);
767
	sysdev_class_unregister(&spu_sysdev_class);
768 769 770 771 772 773 774 775
}
module_exit(cleanup_spu_base);

static int __init init_spu_base(void)
{
	struct device_node *node;
	int ret;

776 777 778 779 780
	/* create sysdev class for spus */
	ret = sysdev_class_register(&spu_sysdev_class);
	if (ret)
		return ret;

781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
	ret = -ENODEV;
	for (node = of_find_node_by_type(NULL, "spe");
			node; node = of_find_node_by_type(node, "spe")) {
		ret = create_spu(node);
		if (ret) {
			printk(KERN_WARNING "%s: Error initializing %s\n",
				__FUNCTION__, node->name);
			cleanup_spu_base();
			break;
		}
	}
	/* in some old firmware versions, the spe is called 'spc', so we
	   look for that as well */
	for (node = of_find_node_by_type(NULL, "spc");
			node; node = of_find_node_by_type(node, "spc")) {
		ret = create_spu(node);
		if (ret) {
			printk(KERN_WARNING "%s: Error initializing %s\n",
				__FUNCTION__, node->name);
			cleanup_spu_base();
			break;
		}
	}
	return ret;
}
module_init(init_spu_base);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");