spu_base.c 19.2 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 <linux/syscore_ops.h>
36
#include <asm/spu.h>
37
#include <asm/spu_priv1.h>
38
#include <asm/spu_csa.h>
39
#include <asm/xmon.h>
40
#include <asm/prom.h>
41
#include <asm/kexec.h>
42

43
const struct spu_management_ops *spu_management_ops;
44 45
EXPORT_SYMBOL_GPL(spu_management_ops);

46
const struct spu_priv1_ops *spu_priv1_ops;
47
EXPORT_SYMBOL_GPL(spu_priv1_ops);
48

49 50
struct cbe_spu_info cbe_spu_info[MAX_NUMNODES];
EXPORT_SYMBOL_GPL(cbe_spu_info);
51

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

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
/*
 * 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);
78

79 80 81
void spu_invalidate_slbs(struct spu *spu)
{
	struct spu_priv2 __iomem *priv2 = spu->priv2;
82
	unsigned long flags;
83

84
	spin_lock_irqsave(&spu->register_lock, flags);
85 86
	if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK)
		out_be64(&priv2->slb_invalidate_all_W, 0UL);
87
	spin_unlock_irqrestore(&spu->register_lock, flags);
88 89 90 91 92 93 94 95 96 97 98
}
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;

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

/* 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. */
115
	bitmap_fill(cpumask_bits(mm_cpumask(mm)), nr);
116 117 118 119 120 121
}

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

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

130 131 132 133 134 135
int spu_64k_pages_available(void)
{
	return mmu_psize_defs[MMU_PAGE_64K].shift != 0;
}
EXPORT_SYMBOL_GPL(spu_64k_pages_available);

136 137 138
static void spu_restart_dma(struct spu *spu)
{
	struct spu_priv2 __iomem *priv2 = spu->priv2;
139

140
	if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags))
141
		out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
142 143 144 145
	else {
		set_bit(SPU_CONTEXT_FAULT_PENDING, &spu->flags);
		mb();
	}
146 147
}

148
static inline void spu_load_slb(struct spu *spu, int slbe, struct copro_slb *slb)
149 150 151
{
	struct spu_priv2 __iomem *priv2 = spu->priv2;

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

	out_be64(&priv2->slb_index_W, slbe);
156 157 158
	/* set invalid before writing vsid */
	out_be64(&priv2->slb_esid_RW, 0);
	/* now it's safe to write the vsid */
159
	out_be64(&priv2->slb_vsid_RW, slb->vsid);
160
	/* setting the new esid makes the entry valid again */
161 162 163
	out_be64(&priv2->slb_esid_RW, slb->esid);
}

164 165
static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
{
166 167 168 169 170 171
	struct copro_slb slb;
	int ret;

	ret = copro_calculate_slb(spu->mm, ea, &slb);
	if (ret)
		return ret;
172

173
	spu_load_slb(spu, spu->slb_replace, &slb);
174 175

	spu->slb_replace++;
176 177 178 179
	if (spu->slb_replace >= 8)
		spu->slb_replace = 0;

	spu_restart_dma(spu);
180
	spu->stats.slb_flt++;
181 182 183
	return 0;
}

184 185
extern int hash_page(unsigned long ea, unsigned long access,
		     unsigned long trap, unsigned long dsisr); //XXX
186
static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
187
{
188 189
	int ret;

190
	pr_debug("%s, %llx, %lx\n", __func__, dsisr, ea);
191

192 193 194 195 196 197 198 199
	/*
	 * 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)) {

		spin_unlock(&spu->register_lock);
200
		ret = hash_page(ea, _PAGE_PRESENT, 0x300, dsisr);
201 202 203 204 205 206
		spin_lock(&spu->register_lock);

		if (!ret) {
			spu_restart_dma(spu);
			return 0;
		}
207 208
	}

209 210 211 212
	spu->class_1_dar = ea;
	spu->class_1_dsisr = dsisr;

	spu->stop_callback(spu, 1);
213

214 215
	spu->class_1_dar = 0;
	spu->class_1_dsisr = 0;
216

217 218 219
	return 0;
}

220
static void __spu_kernel_slb(void *addr, struct copro_slb *slb)
221 222 223 224 225 226 227 228 229 230 231 232 233 234
{
	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;
}

235 236 237 238
/**
 * Given an array of @nr_slbs SLB entries, @slbs, return non-zero if the
 * address @new_addr is present.
 */
239
static inline int __slb_present(struct copro_slb *slbs, int nr_slbs,
240 241 242 243 244 245 246 247 248 249 250 251
		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;
}

252 253 254
/**
 * 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.
255 256 257 258 259
 *
 * 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.
260
 */
261 262
void spu_setup_kernel_slbs(struct spu *spu, struct spu_lscsa *lscsa,
		void *code, int code_size)
263
{
264
	struct copro_slb slbs[4];
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
	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++;
	}
281

282
	spin_lock_irq(&spu->register_lock);
283 284 285
	/* Add the set of SLBs */
	for (i = 0; i < nr_slbs; i++)
		spu_load_slb(spu, i, &slbs[i]);
286
	spin_unlock_irq(&spu->register_lock);
287 288 289
}
EXPORT_SYMBOL_GPL(spu_setup_kernel_slbs);

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

	spu = data;
297

298
	spin_lock(&spu->register_lock);
299
	mask = spu_int_mask_get(spu, 0);
300
	stat = spu_int_stat_get(spu, 0) & mask;
301 302

	spu->class_0_pending |= stat;
303 304 305 306
	spu->class_0_dar = spu_mfc_dar_get(spu);
	spu->stop_callback(spu, 0);
	spu->class_0_pending = 0;
	spu->class_0_dar = 0;
307

308
	spu_int_stat_clear(spu, 0, stat);
309
	spin_unlock(&spu->register_lock);
310

311 312 313 314
	return IRQ_HANDLED;
}

static irqreturn_t
315
spu_irq_class_1(int irq, void *data)
316 317
{
	struct spu *spu;
318
	unsigned long stat, mask, dar, dsisr;
319 320

	spu = data;
321 322 323

	/* atomically read & clear class1 status. */
	spin_lock(&spu->register_lock);
324 325 326 327
	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);
328
	if (stat & CLASS1_STORAGE_FAULT_INTR)
329 330
		spu_mfc_dsisr_set(spu, 0ul);
	spu_int_stat_clear(spu, 1, stat);
331

332
	pr_debug("%s: %lx %lx %lx %lx\n", __func__, mask, stat,
333 334
			dar, dsisr);

335 336 337
	if (stat & CLASS1_SEGMENT_FAULT_INTR)
		__spu_trap_data_seg(spu, dar);

338
	if (stat & CLASS1_STORAGE_FAULT_INTR)
339
		__spu_trap_data_map(spu, dar, dsisr);
340

341
	if (stat & CLASS1_LS_COMPARE_SUSPEND_ON_GET_INTR)
342 343
		;

344
	if (stat & CLASS1_LS_COMPARE_SUSPEND_ON_PUT_INTR)
345 346
		;

347 348 349
	spu->class_1_dsisr = 0;
	spu->class_1_dar = 0;

350 351
	spin_unlock(&spu->register_lock);

352 353 354 355
	return stat ? IRQ_HANDLED : IRQ_NONE;
}

static irqreturn_t
356
spu_irq_class_2(int irq, void *data)
357 358 359
{
	struct spu *spu;
	unsigned long stat;
360
	unsigned long mask;
361 362
	const int mailbox_intrs =
		CLASS2_MAILBOX_THRESHOLD_INTR | CLASS2_MAILBOX_INTR;
363 364

	spu = data;
365
	spin_lock(&spu->register_lock);
366 367
	stat = spu_int_stat_get(spu, 2);
	mask = spu_int_mask_get(spu, 2);
368 369
	/* ignore interrupts we're not waiting for */
	stat &= mask;
370 371 372 373
	/* mailbox interrupts are level triggered. mask them now before
	 * acknowledging */
	if (stat & mailbox_intrs)
		spu_int_mask_and(spu, 2, ~(stat & mailbox_intrs));
374 375
	/* acknowledge all interrupts before the callbacks */
	spu_int_stat_clear(spu, 2, stat);
376

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

379
	if (stat & CLASS2_MAILBOX_INTR)
380
		spu->ibox_callback(spu);
381

382
	if (stat & CLASS2_SPU_STOP_INTR)
383
		spu->stop_callback(spu, 2);
384

385
	if (stat & CLASS2_SPU_HALT_INTR)
386
		spu->stop_callback(spu, 2);
387

388
	if (stat & CLASS2_SPU_DMA_TAG_GROUP_COMPLETE_INTR)
389
		spu->mfc_callback(spu);
390

391
	if (stat & CLASS2_MAILBOX_THRESHOLD_INTR)
392
		spu->wbox_callback(spu);
393

394
	spu->stats.class2_intr++;
395 396 397

	spin_unlock(&spu->register_lock);

398 399 400
	return stat ? IRQ_HANDLED : IRQ_NONE;
}

401
static int spu_request_irqs(struct spu *spu)
402
{
403
	int ret = 0;
404

405 406 407 408
	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,
Y
Yong Zhang 已提交
409
				  0, spu->irq_c0, spu);
410 411 412 413 414 415 416
		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,
Y
Yong Zhang 已提交
417
				  0, spu->irq_c1, spu);
418 419 420 421 422 423 424
		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,
Y
Yong Zhang 已提交
425
				  0, spu->irq_c2, spu);
426 427 428 429
		if (ret)
			goto bail2;
	}
	return 0;
430

431 432 433 434 435 436 437
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:
438 439 440
	return ret;
}

441
static void spu_free_irqs(struct spu *spu)
442
{
443 444 445 446 447 448
	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);
449 450
}

451
void spu_init_channels(struct spu *spu)
452 453 454 455 456 457 458 459 460 461 462 463
{
	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, },
	};
464
	struct spu_priv2 __iomem *priv2;
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
	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);
	}
}
484
EXPORT_SYMBOL_GPL(spu_init_channels);
485

486
static struct bus_type spu_subsys = {
487
	.name = "spu",
488
	.dev_name = "spu",
489 490
};

491
int spu_add_dev_attr(struct device_attribute *attr)
492 493 494
{
	struct spu *spu;

495
	mutex_lock(&spu_full_list_mutex);
496
	list_for_each_entry(spu, &spu_full_list, full_list)
497
		device_create_file(&spu->dev, attr);
498
	mutex_unlock(&spu_full_list_mutex);
499 500 501

	return 0;
}
502
EXPORT_SYMBOL_GPL(spu_add_dev_attr);
503

504
int spu_add_dev_attr_group(struct attribute_group *attrs)
505 506
{
	struct spu *spu;
507
	int rc = 0;
508

509
	mutex_lock(&spu_full_list_mutex);
510
	list_for_each_entry(spu, &spu_full_list, full_list) {
511
		rc = sysfs_create_group(&spu->dev.kobj, attrs);
512 513 514 515 516 517 518 519

		/* 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)
520
				sysfs_remove_group(&spu->dev.kobj, attrs);
521 522 523 524
			break;
		}
	}

525
	mutex_unlock(&spu_full_list_mutex);
526

527
	return rc;
528
}
529
EXPORT_SYMBOL_GPL(spu_add_dev_attr_group);
530 531


532
void spu_remove_dev_attr(struct device_attribute *attr)
533 534 535
{
	struct spu *spu;

536
	mutex_lock(&spu_full_list_mutex);
537
	list_for_each_entry(spu, &spu_full_list, full_list)
538
		device_remove_file(&spu->dev, attr);
539
	mutex_unlock(&spu_full_list_mutex);
540
}
541
EXPORT_SYMBOL_GPL(spu_remove_dev_attr);
542

543
void spu_remove_dev_attr_group(struct attribute_group *attrs)
544 545 546
{
	struct spu *spu;

547
	mutex_lock(&spu_full_list_mutex);
548
	list_for_each_entry(spu, &spu_full_list, full_list)
549
		sysfs_remove_group(&spu->dev.kobj, attrs);
550
	mutex_unlock(&spu_full_list_mutex);
551
}
552
EXPORT_SYMBOL_GPL(spu_remove_dev_attr_group);
553

554
static int spu_create_dev(struct spu *spu)
555 556 557
{
	int ret;

558 559 560
	spu->dev.id = spu->number;
	spu->dev.bus = &spu_subsys;
	ret = device_register(&spu->dev);
561 562 563 564 565 566
	if (ret) {
		printk(KERN_ERR "Can't register SPU %d with sysfs\n",
				spu->number);
		return ret;
	}

567
	sysfs_add_device_to_node(&spu->dev, spu->node);
568 569 570 571

	return 0;
}

572
static int __init create_spu(void *data)
573 574 575 576
{
	struct spu *spu;
	int ret;
	static int number;
577
	unsigned long flags;
578 579

	ret = -ENOMEM;
580
	spu = kzalloc(sizeof (*spu), GFP_KERNEL);
581 582 583
	if (!spu)
		goto out;

584 585
	spu->alloc_state = SPU_FREE;

586
	spin_lock_init(&spu->register_lock);
587
	spin_lock(&spu_lock);
588
	spu->number = number++;
589
	spin_unlock(&spu_lock);
590 591

	ret = spu_create_spu(spu, data);
592

593 594 595
	if (ret)
		goto out_free;

596
	spu_mfc_sdr_setup(spu);
597
	spu_mfc_sr1_set(spu, 0x33);
598 599
	ret = spu_request_irqs(spu);
	if (ret)
600
		goto out_destroy;
601

602
	ret = spu_create_dev(spu);
603 604 605
	if (ret)
		goto out_free_irqs;

606
	mutex_lock(&cbe_spu_info[spu->node].list_mutex);
607 608
	list_add(&spu->cbe_list, &cbe_spu_info[spu->node].spus);
	cbe_spu_info[spu->node].n_spus++;
609
	mutex_unlock(&cbe_spu_info[spu->node].list_mutex);
610 611 612

	mutex_lock(&spu_full_list_mutex);
	spin_lock_irqsave(&spu_full_list_lock, flags);
613
	list_add(&spu->full_list, &spu_full_list);
614 615
	spin_unlock_irqrestore(&spu_full_list_lock, flags);
	mutex_unlock(&spu_full_list_mutex);
616

617
	spu->stats.util_state = SPU_UTIL_IDLE_LOADED;
618
	spu->stats.tstamp = ktime_get_ns();
619

620 621
	INIT_LIST_HEAD(&spu->aff_list);

622 623
	goto out;

624 625
out_free_irqs:
	spu_free_irqs(spu);
626 627
out_destroy:
	spu_destroy_spu(spu);
628 629 630 631 632 633
out_free:
	kfree(spu);
out:
	return ret;
}

634 635 636 637 638 639 640 641 642
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)
{
	unsigned long long time = spu->stats.times[state];

643 644 645 646 647
	/*
	 * 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.
	 */
648 649
	if (spu->stats.util_state == state)
		time += ktime_get_ns() - spu->stats.tstamp;
650

651
	return time / NSEC_PER_MSEC;
652 653 654
}


655 656
static ssize_t spu_stat_show(struct device *dev,
				struct device_attribute *attr, char *buf)
657
{
658
	struct spu *spu = container_of(dev, struct spu, dev);
659 660 661

	return sprintf(buf, "%s %llu %llu %llu %llu "
		      "%llu %llu %llu %llu %llu %llu %llu %llu\n",
662
		spu_state_names[spu->stats.util_state],
663 664 665
		spu_acct_time(spu, SPU_UTIL_USER),
		spu_acct_time(spu, SPU_UTIL_SYSTEM),
		spu_acct_time(spu, SPU_UTIL_IOWAIT),
666
		spu_acct_time(spu, SPU_UTIL_IDLE_LOADED),
667 668 669 670 671 672 673 674 675 676
		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);
}

677
static DEVICE_ATTR(stat, 0444, spu_stat_show, NULL);
678

679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
#ifdef CONFIG_KEXEC

struct crash_spu_info {
	struct spu *spu;
	u32 saved_spu_runcntl_RW;
	u32 saved_spu_status_R;
	u32 saved_spu_npc_RW;
	u64 saved_mfc_sr1_RW;
	u64 saved_mfc_dar;
	u64 saved_mfc_dsisr;
};

#define CRASH_NUM_SPUS	16	/* Enough for current hardware */
static struct crash_spu_info crash_spu_info[CRASH_NUM_SPUS];

static void crash_kexec_stop_spus(void)
{
	struct spu *spu;
	int i;
	u64 tmp;

	for (i = 0; i < CRASH_NUM_SPUS; i++) {
		if (!crash_spu_info[i].spu)
			continue;

		spu = crash_spu_info[i].spu;

		crash_spu_info[i].saved_spu_runcntl_RW =
			in_be32(&spu->problem->spu_runcntl_RW);
		crash_spu_info[i].saved_spu_status_R =
			in_be32(&spu->problem->spu_status_R);
		crash_spu_info[i].saved_spu_npc_RW =
			in_be32(&spu->problem->spu_npc_RW);

		crash_spu_info[i].saved_mfc_dar    = spu_mfc_dar_get(spu);
		crash_spu_info[i].saved_mfc_dsisr  = spu_mfc_dsisr_get(spu);
		tmp = spu_mfc_sr1_get(spu);
		crash_spu_info[i].saved_mfc_sr1_RW = tmp;

		tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
		spu_mfc_sr1_set(spu, tmp);

		__delay(200);
	}
}

static void crash_register_spus(struct list_head *list)
{
	struct spu *spu;
	int ret;

	list_for_each_entry(spu, list, full_list) {
		if (WARN_ON(spu->number >= CRASH_NUM_SPUS))
			continue;

		crash_spu_info[spu->number].spu = spu;
	}

	ret = crash_shutdown_register(&crash_kexec_stop_spus);
	if (ret)
		printk(KERN_ERR "Could not register SPU crash handler");
}

#else
static inline void crash_register_spus(struct list_head *list)
{
}
#endif

748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
static void spu_shutdown(void)
{
	struct spu *spu;

	mutex_lock(&spu_full_list_mutex);
	list_for_each_entry(spu, &spu_full_list, full_list) {
		spu_free_irqs(spu);
		spu_destroy_spu(spu);
	}
	mutex_unlock(&spu_full_list_mutex);
}

static struct syscore_ops spu_syscore_ops = {
	.shutdown = spu_shutdown,
};

764 765
static int __init init_spu_base(void)
{
766
	int i, ret = 0;
767

768
	for (i = 0; i < MAX_NUMNODES; i++) {
769
		mutex_init(&cbe_spu_info[i].list_mutex);
770 771
		INIT_LIST_HEAD(&cbe_spu_info[i].spus);
	}
772

773
	if (!spu_management_ops)
774
		goto out;
775

776 777
	/* create system subsystem for spus */
	ret = subsys_system_register(&spu_subsys, NULL);
778
	if (ret)
779
		goto out;
780

781 782
	ret = spu_enumerate_spus(create_spu);

783
	if (ret < 0) {
784
		printk(KERN_WARNING "%s: Error initializing spus\n",
785
			__func__);
786
		goto out_unregister_subsys;
787
	}
788

789
	if (ret > 0)
790 791
		fb_append_extra_logo(&logo_spe_clut224, ret);

792
	mutex_lock(&spu_full_list_mutex);
793
	xmon_register_spus(&spu_full_list);
794
	crash_register_spus(&spu_full_list);
795
	mutex_unlock(&spu_full_list_mutex);
796
	spu_add_dev_attr(&dev_attr_stat);
797
	register_syscore_ops(&spu_syscore_ops);
798

799
	spu_init_affinity();
800

801 802
	return 0;

803 804
 out_unregister_subsys:
	bus_unregister(&spu_subsys);
805
 out:
806 807 808 809 810 811
	return ret;
}
module_init(init_spu_base);

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