spu_base.c 17.9 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

#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/wait.h>
31 32
#include <linux/mm.h>
#include <linux/io.h>
33
#include <linux/mutex.h>
34
#include <linux/linux_logo.h>
35
#include <asm/spu.h>
36
#include <asm/spu_priv1.h>
37
#include <asm/spu_csa.h>
38
#include <asm/xmon.h>
39
#include <asm/prom.h>
40

41
const struct spu_management_ops *spu_management_ops;
42 43
EXPORT_SYMBOL_GPL(spu_management_ops);

44
const struct spu_priv1_ops *spu_priv1_ops;
45
EXPORT_SYMBOL_GPL(spu_priv1_ops);
46

47 48
struct cbe_spu_info cbe_spu_info[MAX_NUMNODES];
EXPORT_SYMBOL_GPL(cbe_spu_info);
49

50 51 52 53 54 55 56
/*
 * 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);

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
/*
 * Protects cbe_spu_info and spu->number.
 */
static DEFINE_SPINLOCK(spu_lock);

/*
 * List of all spus in the system.
 *
 * This list is iterated by callers from irq context and callers that
 * want to sleep.  Thus modifications need to be done with both
 * spu_full_list_lock and spu_full_list_mutex held, while iterating
 * through it requires either of these locks.
 *
 * In addition spu_full_list_lock protects all assignmens to
 * spu->mm.
 */
static LIST_HEAD(spu_full_list);
static DEFINE_SPINLOCK(spu_full_list_lock);
static DEFINE_MUTEX(spu_full_list_mutex);
76

77 78 79 80
struct spu_slb {
	u64 esid, vsid;
};

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
void spu_invalidate_slbs(struct spu *spu)
{
	struct spu_priv2 __iomem *priv2 = spu->priv2;

	if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK)
		out_be64(&priv2->slb_invalidate_all_W, 0UL);
}
EXPORT_SYMBOL_GPL(spu_invalidate_slbs);

/* This is called by the MM core when a segment size is changed, to
 * request a flush of all the SPEs using a given mm
 */
void spu_flush_all_slbs(struct mm_struct *mm)
{
	struct spu *spu;
	unsigned long flags;

98
	spin_lock_irqsave(&spu_full_list_lock, flags);
99 100 101 102
	list_for_each_entry(spu, &spu_full_list, full_list) {
		if (spu->mm == mm)
			spu_invalidate_slbs(spu);
	}
103
	spin_unlock_irqrestore(&spu_full_list_lock, flags);
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
}

/* The hack below stinks... try to do something better one of
 * these days... Does it even work properly with NR_CPUS == 1 ?
 */
static inline void mm_needs_global_tlbie(struct mm_struct *mm)
{
	int nr = (NR_CPUS > 1) ? NR_CPUS : NR_CPUS + 1;

	/* Global TLBIE broadcast required with SPEs. */
	__cpus_setall(&mm->cpu_vm_mask, nr);
}

void spu_associate_mm(struct spu *spu, struct mm_struct *mm)
{
	unsigned long flags;

121
	spin_lock_irqsave(&spu_full_list_lock, flags);
122
	spu->mm = mm;
123
	spin_unlock_irqrestore(&spu_full_list_lock, flags);
124 125 126 127 128
	if (mm)
		mm_needs_global_tlbie(mm);
}
EXPORT_SYMBOL_GPL(spu_associate_mm);

129 130 131
static int __spu_trap_invalid_dma(struct spu *spu)
{
	pr_debug("%s\n", __FUNCTION__);
132
	spu->dma_callback(spu, SPE_EVENT_INVALID_DMA);
133 134 135 136 137 138
	return 0;
}

static int __spu_trap_dma_align(struct spu *spu)
{
	pr_debug("%s\n", __FUNCTION__);
139
	spu->dma_callback(spu, SPE_EVENT_DMA_ALIGNMENT);
140 141 142 143 144 145
	return 0;
}

static int __spu_trap_error(struct spu *spu)
{
	pr_debug("%s\n", __FUNCTION__);
146
	spu->dma_callback(spu, SPE_EVENT_SPE_ERROR);
147 148 149 150 151 152
	return 0;
}

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

154
	if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags))
155
		out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
156 157
}

158 159 160 161 162 163 164 165 166 167 168 169
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);
}

170 171
static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
{
172
	struct mm_struct *mm = spu->mm;
173
	struct spu_slb slb;
174
	int psize;
175 176 177

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

178
	if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
179 180 181
		/* SLBs are pre-loaded for context switch, so
		 * we should never get here!
		 */
182 183 184
		printk("%s: invalid access during switch!\n", __func__);
		return 1;
	}
185
	slb.esid = (ea & ESID_MASK) | SLB_ESID_V;
186 187 188

	switch(REGION_ID(ea)) {
	case USER_REGION_ID:
189 190 191 192
#ifdef CONFIG_PPC_MM_SLICES
		psize = get_slice_psize(mm, ea);
#else
		psize = mm->context.user_psize;
193
#endif
194 195
		slb.vsid = (get_vsid(mm->context.id, ea, MMU_SEGSIZE_256M)
				<< SLB_VSID_SHIFT) | SLB_VSID_USER;
196 197
		break;
	case VMALLOC_REGION_ID:
198 199 200 201
		if (ea < VMALLOC_END)
			psize = mmu_vmalloc_psize;
		else
			psize = mmu_io_psize;
202 203
		slb.vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M)
				<< SLB_VSID_SHIFT) | SLB_VSID_KERNEL;
204 205
		break;
	case KERNEL_REGION_ID:
206
		psize = mmu_linear_psize;
207 208
		slb.vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M)
				<< SLB_VSID_SHIFT) | SLB_VSID_KERNEL;
209 210
		break;
	default:
211 212 213
		/* Future: support kernel segments so that drivers
		 * can use SPUs.
		 */
214 215 216
		pr_debug("invalid region access at %016lx\n", ea);
		return 1;
	}
217
	slb.vsid |= mmu_psize_defs[psize].sllp;
218

219
	spu_load_slb(spu, spu->slb_replace, &slb);
220 221

	spu->slb_replace++;
222 223 224 225
	if (spu->slb_replace >= 8)
		spu->slb_replace = 0;

	spu_restart_dma(spu);
226
	spu->stats.slb_flt++;
227 228 229
	return 0;
}

230
extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
231
static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
232
{
233
	pr_debug("%s, %lx, %lx\n", __FUNCTION__, dsisr, ea);
234

235 236 237 238 239 240 241 242 243
	/* 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;
	}

244
	if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
245 246 247
		printk("%s: invalid access during switch!\n", __func__);
		return 1;
	}
248

249 250 251
	spu->dar = ea;
	spu->dsisr = dsisr;
	mb();
252
	spu->stop_callback(spu);
253 254 255
	return 0;
}

256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
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;
}

/**
 * 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.
 */
void spu_setup_kernel_slbs(struct spu *spu, struct spu_lscsa *lscsa, void *code)
{
	struct spu_slb code_slb, lscsa_slb;

	__spu_kernel_slb(lscsa, &lscsa_slb);
	__spu_kernel_slb(code, &code_slb);

	spu_load_slb(spu, 0, &lscsa_slb);
	if (lscsa_slb.esid != code_slb.esid)
		spu_load_slb(spu, 1, &code_slb);
}
EXPORT_SYMBOL_GPL(spu_setup_kernel_slbs);

288
static irqreturn_t
289
spu_irq_class_0(int irq, void *data)
290 291
{
	struct spu *spu;
292
	unsigned long stat, mask;
293 294

	spu = data;
295 296 297 298 299 300 301 302 303

	mask = spu_int_mask_get(spu, 0);
	stat = spu_int_stat_get(spu, 0);
	stat &= mask;

	spin_lock(&spu->register_lock);
	spu->class_0_pending |= stat;
	spin_unlock(&spu->register_lock);

304
	spu->stop_callback(spu);
305

306 307
	spu_int_stat_clear(spu, 0, stat);

308 309 310
	return IRQ_HANDLED;
}

311
int
312 313
spu_irq_class_0_bottom(struct spu *spu)
{
314
	unsigned long flags;
315
	unsigned long stat;
316

317
	spin_lock_irqsave(&spu->register_lock, flags);
318 319
	stat = spu->class_0_pending;
	spu->class_0_pending = 0;
320

321
	if (stat & 1) /* invalid DMA alignment */
322 323
		__spu_trap_dma_align(spu);

324 325 326
	if (stat & 2) /* invalid MFC DMA */
		__spu_trap_invalid_dma(spu);

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

330
	spin_unlock_irqrestore(&spu->register_lock, flags);
331 332

	return (stat & 0x7) ? -EIO : 0;
333
}
334
EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom);
335 336

static irqreturn_t
337
spu_irq_class_1(int irq, void *data)
338 339
{
	struct spu *spu;
340
	unsigned long stat, mask, dar, dsisr;
341 342

	spu = data;
343 344 345

	/* atomically read & clear class1 status. */
	spin_lock(&spu->register_lock);
346 347 348 349
	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);
350
	if (stat & 2) /* mapping fault */
351 352
		spu_mfc_dsisr_set(spu, 0ul);
	spu_int_stat_clear(spu, 1, stat);
353
	spin_unlock(&spu->register_lock);
354 355
	pr_debug("%s: %lx %lx %lx %lx\n", __FUNCTION__, mask, stat,
			dar, dsisr);
356 357 358 359 360

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

	if (stat & 2) { /* mapping fault */
361
		__spu_trap_data_map(spu, dar, dsisr);
362 363 364 365 366 367 368 369 370 371 372 373
	}

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

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

	return stat ? IRQ_HANDLED : IRQ_NONE;
}

static irqreturn_t
374
spu_irq_class_2(int irq, void *data)
375 376 377
{
	struct spu *spu;
	unsigned long stat;
378
	unsigned long mask;
379 380

	spu = data;
381
	spin_lock(&spu->register_lock);
382 383
	stat = spu_int_stat_get(spu, 2);
	mask = spu_int_mask_get(spu, 2);
384 385 386 387 388 389 390 391 392 393 394
	/* ignore interrupts we're not waiting for */
	stat &= mask;
	/*
	 * mailbox interrupts (0x1 and 0x10) are level triggered.
	 * mask them now before acknowledging.
	 */
	if (stat & 0x11)
		spu_int_mask_and(spu, 2, ~(stat & 0x11));
	/* acknowledge all interrupts before the callbacks */
	spu_int_stat_clear(spu, 2, stat);
	spin_unlock(&spu->register_lock);
395

396
	pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask);
397 398

	if (stat & 1)  /* PPC core mailbox */
399
		spu->ibox_callback(spu);
400 401

	if (stat & 2) /* SPU stop-and-signal */
402
		spu->stop_callback(spu);
403 404

	if (stat & 4) /* SPU halted */
405
		spu->stop_callback(spu);
406 407

	if (stat & 8) /* DMA tag group complete */
408
		spu->mfc_callback(spu);
409 410

	if (stat & 0x10) /* SPU mailbox threshold */
411
		spu->wbox_callback(spu);
412

413
	spu->stats.class2_intr++;
414 415 416
	return stat ? IRQ_HANDLED : IRQ_NONE;
}

417
static int spu_request_irqs(struct spu *spu)
418
{
419
	int ret = 0;
420

421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
	if (spu->irqs[0] != NO_IRQ) {
		snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0",
			 spu->number);
		ret = request_irq(spu->irqs[0], spu_irq_class_0,
				  IRQF_DISABLED,
				  spu->irq_c0, spu);
		if (ret)
			goto bail0;
	}
	if (spu->irqs[1] != NO_IRQ) {
		snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1",
			 spu->number);
		ret = request_irq(spu->irqs[1], spu_irq_class_1,
				  IRQF_DISABLED,
				  spu->irq_c1, spu);
		if (ret)
			goto bail1;
	}
	if (spu->irqs[2] != NO_IRQ) {
		snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2",
			 spu->number);
		ret = request_irq(spu->irqs[2], spu_irq_class_2,
				  IRQF_DISABLED,
				  spu->irq_c2, spu);
		if (ret)
			goto bail2;
	}
	return 0;
449

450 451 452 453 454 455 456
bail2:
	if (spu->irqs[1] != NO_IRQ)
		free_irq(spu->irqs[1], spu);
bail1:
	if (spu->irqs[0] != NO_IRQ)
		free_irq(spu->irqs[0], spu);
bail0:
457 458 459
	return ret;
}

460
static void spu_free_irqs(struct spu *spu)
461
{
462 463 464 465 466 467
	if (spu->irqs[0] != NO_IRQ)
		free_irq(spu->irqs[0], spu);
	if (spu->irqs[1] != NO_IRQ)
		free_irq(spu->irqs[1], spu);
	if (spu->irqs[2] != NO_IRQ)
		free_irq(spu->irqs[2], spu);
468 469
}

470
void spu_init_channels(struct spu *spu)
471 472 473 474 475 476 477 478 479 480 481 482
{
	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, },
	};
483
	struct spu_priv2 __iomem *priv2;
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
	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);
	}
}
503
EXPORT_SYMBOL_GPL(spu_init_channels);
504

505 506 507 508 509 510 511 512 513
static int spu_shutdown(struct sys_device *sysdev)
{
	struct spu *spu = container_of(sysdev, struct spu, sysdev);

	spu_free_irqs(spu);
	spu_destroy_spu(spu);
	return 0;
}

514
static struct sysdev_class spu_sysdev_class = {
515 516
	set_kset_name("spu"),
	.shutdown = spu_shutdown,
517 518
};

519 520 521 522
int spu_add_sysdev_attr(struct sysdev_attribute *attr)
{
	struct spu *spu;

523
	mutex_lock(&spu_full_list_mutex);
524 525
	list_for_each_entry(spu, &spu_full_list, full_list)
		sysdev_create_file(&spu->sysdev, attr);
526
	mutex_unlock(&spu_full_list_mutex);
527 528 529 530 531 532 533 534 535

	return 0;
}
EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);

int spu_add_sysdev_attr_group(struct attribute_group *attrs)
{
	struct spu *spu;

536
	mutex_lock(&spu_full_list_mutex);
537 538
	list_for_each_entry(spu, &spu_full_list, full_list)
		sysfs_create_group(&spu->sysdev.kobj, attrs);
539
	mutex_unlock(&spu_full_list_mutex);
540 541 542 543 544 545 546 547 548 549

	return 0;
}
EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);


void spu_remove_sysdev_attr(struct sysdev_attribute *attr)
{
	struct spu *spu;

550
	mutex_lock(&spu_full_list_mutex);
551 552
	list_for_each_entry(spu, &spu_full_list, full_list)
		sysdev_remove_file(&spu->sysdev, attr);
553
	mutex_unlock(&spu_full_list_mutex);
554 555 556 557 558 559 560
}
EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr);

void spu_remove_sysdev_attr_group(struct attribute_group *attrs)
{
	struct spu *spu;

561
	mutex_lock(&spu_full_list_mutex);
562 563
	list_for_each_entry(spu, &spu_full_list, full_list)
		sysfs_remove_group(&spu->sysdev.kobj, attrs);
564
	mutex_unlock(&spu_full_list_mutex);
565 566 567
}
EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group);

568 569 570 571 572 573 574 575 576 577 578 579 580
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;
	}

581
	sysfs_add_device_to_node(&spu->sysdev, spu->node);
582 583 584 585

	return 0;
}

586
static int __init create_spu(void *data)
587 588 589 590
{
	struct spu *spu;
	int ret;
	static int number;
591
	unsigned long flags;
592
	struct timespec ts;
593 594

	ret = -ENOMEM;
595
	spu = kzalloc(sizeof (*spu), GFP_KERNEL);
596 597 598
	if (!spu)
		goto out;

599 600
	spu->alloc_state = SPU_FREE;

601
	spin_lock_init(&spu->register_lock);
602
	spin_lock(&spu_lock);
603
	spu->number = number++;
604
	spin_unlock(&spu_lock);
605 606

	ret = spu_create_spu(spu, data);
607

608 609 610
	if (ret)
		goto out_free;

611
	spu_mfc_sdr_setup(spu);
612
	spu_mfc_sr1_set(spu, 0x33);
613 614
	ret = spu_request_irqs(spu);
	if (ret)
615
		goto out_destroy;
616

617 618 619 620
	ret = spu_create_sysdev(spu);
	if (ret)
		goto out_free_irqs;

621
	mutex_lock(&cbe_spu_info[spu->node].list_mutex);
622 623
	list_add(&spu->cbe_list, &cbe_spu_info[spu->node].spus);
	cbe_spu_info[spu->node].n_spus++;
624
	mutex_unlock(&cbe_spu_info[spu->node].list_mutex);
625 626 627

	mutex_lock(&spu_full_list_mutex);
	spin_lock_irqsave(&spu_full_list_lock, flags);
628
	list_add(&spu->full_list, &spu_full_list);
629 630
	spin_unlock_irqrestore(&spu_full_list_lock, flags);
	mutex_unlock(&spu_full_list_mutex);
631

632 633 634
	spu->stats.util_state = SPU_UTIL_IDLE_LOADED;
	ktime_get_ts(&ts);
	spu->stats.tstamp = timespec_to_ns(&ts);
635

636 637
	INIT_LIST_HEAD(&spu->aff_list);

638 639
	goto out;

640 641
out_free_irqs:
	spu_free_irqs(spu);
642 643
out_destroy:
	spu_destroy_spu(spu);
644 645 646 647 648 649
out_free:
	kfree(spu);
out:
	return ret;
}

650 651 652 653 654 655 656
static const char *spu_state_names[] = {
	"user", "system", "iowait", "idle"
};

static unsigned long long spu_acct_time(struct spu *spu,
		enum spu_utilization_state state)
{
657
	struct timespec ts;
658 659
	unsigned long long time = spu->stats.times[state];

660 661 662 663 664 665 666 667 668
	/*
	 * If the spu is idle or the context is stopped, utilization
	 * statistics are not updated.  Apply the time delta from the
	 * last recorded state of the spu.
	 */
	if (spu->stats.util_state == state) {
		ktime_get_ts(&ts);
		time += timespec_to_ns(&ts) - spu->stats.tstamp;
	}
669

670
	return time / NSEC_PER_MSEC;
671 672 673 674 675 676 677 678 679
}


static ssize_t spu_stat_show(struct sys_device *sysdev, char *buf)
{
	struct spu *spu = container_of(sysdev, struct spu, sysdev);

	return sprintf(buf, "%s %llu %llu %llu %llu "
		      "%llu %llu %llu %llu %llu %llu %llu %llu\n",
680
		spu_state_names[spu->stats.util_state],
681 682 683
		spu_acct_time(spu, SPU_UTIL_USER),
		spu_acct_time(spu, SPU_UTIL_SYSTEM),
		spu_acct_time(spu, SPU_UTIL_IOWAIT),
684
		spu_acct_time(spu, SPU_UTIL_IDLE_LOADED),
685 686 687 688 689 690 691 692 693 694 695 696
		spu->stats.vol_ctx_switch,
		spu->stats.invol_ctx_switch,
		spu->stats.slb_flt,
		spu->stats.hash_flt,
		spu->stats.min_flt,
		spu->stats.maj_flt,
		spu->stats.class2_intr,
		spu->stats.libassist);
}

static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL);

697 698
static int __init init_spu_base(void)
{
699
	int i, ret = 0;
700

701
	for (i = 0; i < MAX_NUMNODES; i++) {
702
		mutex_init(&cbe_spu_info[i].list_mutex);
703 704
		INIT_LIST_HEAD(&cbe_spu_info[i].spus);
	}
705

706
	if (!spu_management_ops)
707
		goto out;
708

709 710 711
	/* create sysdev class for spus */
	ret = sysdev_class_register(&spu_sysdev_class);
	if (ret)
712
		goto out;
713

714 715
	ret = spu_enumerate_spus(create_spu);

716
	if (ret < 0) {
717 718
		printk(KERN_WARNING "%s: Error initializing spus\n",
			__FUNCTION__);
719
		goto out_unregister_sysdev_class;
720
	}
721

722 723 724 725 726 727 728 729 730 731 732 733
	if (ret > 0) {
		/*
		 * We cannot put the forward declaration in
		 * <linux/linux_logo.h> because of conflicting session type
		 * conflicts for const and __initdata with different compiler
		 * versions
		 */
		extern const struct linux_logo logo_spe_clut224;

		fb_append_extra_logo(&logo_spe_clut224, ret);
	}

734
	mutex_lock(&spu_full_list_mutex);
735
	xmon_register_spus(&spu_full_list);
736
	crash_register_spus(&spu_full_list);
737
	mutex_unlock(&spu_full_list_mutex);
738 739
	spu_add_sysdev_attr(&attr_stat);

740
	spu_init_affinity();
741

742 743 744 745 746
	return 0;

 out_unregister_sysdev_class:
	sysdev_class_unregister(&spu_sysdev_class);
 out:
747 748 749 750 751 752
	return ret;
}
module_init(init_spu_base);

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