xics.c 20.2 KB
Newer Older
1 2
/*
 * arch/powerpc/platforms/pseries/xics.c
L
Linus Torvalds 已提交
3 4 5 6 7 8 9 10
 *
 * Copyright 2000 IBM Corporation.
 *
 *  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 of the License, or (at your option) any later version.
 */
11 12 13

#undef DEBUG

L
Linus Torvalds 已提交
14 15 16 17 18 19 20 21 22 23 24
#include <linux/types.h>
#include <linux/threads.h>
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
#include <linux/signal.h>
#include <linux/init.h>
#include <linux/gfp.h>
#include <linux/radix-tree.h>
#include <linux/cpu.h>
25

26
#include <asm/firmware.h>
L
Linus Torvalds 已提交
27 28 29 30 31 32 33
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/smp.h>
#include <asm/rtas.h>
#include <asm/hvcall.h>
#include <asm/machdep.h>
34
#include <asm/i8259.h>
L
Linus Torvalds 已提交
35

36
#include "xics.h"
37
#include "plpar_wrappers.h"
38

L
Linus Torvalds 已提交
39 40 41 42 43 44
#define XICS_IPI		2
#define XICS_IRQ_SPURIOUS	0

/* Want a priority other than 0.  Various HW issues require this. */
#define	DEFAULT_PRIORITY	5

45
/*
L
Linus Torvalds 已提交
46
 * Mark IPIs as higher priority so we can take them inside interrupts that
47
 * arent marked IRQF_DISABLED
L
Linus Torvalds 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
 */
#define IPI_PRIORITY		4

struct xics_ipl {
	union {
		u32 word;
		u8 bytes[4];
	} xirr_poll;
	union {
		u32 word;
		u8 bytes[4];
	} xirr;
	u32 dummy;
	union {
		u32 word;
		u8 bytes[4];
	} qirr;
};

static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS];

static unsigned int default_server = 0xFF;
A
Anton Blanchard 已提交
70 71
static unsigned int default_distrib_server = 0;
static unsigned int interrupt_server_size = 8;
L
Linus Torvalds 已提交
72

73 74
static struct irq_host *xics_host;

L
Linus Torvalds 已提交
75 76 77 78 79 80
/*
 * XICS only has a single IPI, so encode the messages per CPU
 */
struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;

/* RTAS service tokens */
A
Anton Blanchard 已提交
81 82 83 84
static int ibm_get_xive;
static int ibm_set_xive;
static int ibm_int_on;
static int ibm_int_off;
L
Linus Torvalds 已提交
85 86


87
/* Direct HW low level accessors */
L
Linus Torvalds 已提交
88 89


90
static inline unsigned int direct_xirr_info_get(int n_cpu)
L
Linus Torvalds 已提交
91 92 93 94
{
	return in_be32(&xics_per_cpu[n_cpu]->xirr.word);
}

95
static inline void direct_xirr_info_set(int n_cpu, int value)
L
Linus Torvalds 已提交
96 97 98 99
{
	out_be32(&xics_per_cpu[n_cpu]->xirr.word, value);
}

100
static inline void direct_cppr_info(int n_cpu, u8 value)
L
Linus Torvalds 已提交
101 102 103 104
{
	out_8(&xics_per_cpu[n_cpu]->xirr.bytes[0], value);
}

105
static inline void direct_qirr_info(int n_cpu, u8 value)
L
Linus Torvalds 已提交
106 107 108 109 110
{
	out_8(&xics_per_cpu[n_cpu]->qirr.bytes[0], value);
}


111
/* LPAR low level accessors */
L
Linus Torvalds 已提交
112 113


114
static inline unsigned int lpar_xirr_info_get(int n_cpu)
L
Linus Torvalds 已提交
115 116
{
	unsigned long lpar_rc;
117
	unsigned long return_value;
L
Linus Torvalds 已提交
118 119

	lpar_rc = plpar_xirr(&return_value);
120
	if (lpar_rc != H_SUCCESS)
121
		panic(" bad return code xirr - rc = %lx \n", lpar_rc);
122
	return (unsigned int)return_value;
L
Linus Torvalds 已提交
123 124
}

125
static inline void lpar_xirr_info_set(int n_cpu, int value)
L
Linus Torvalds 已提交
126 127 128 129 130
{
	unsigned long lpar_rc;
	unsigned long val64 = value & 0xffffffff;

	lpar_rc = plpar_eoi(val64);
131
	if (lpar_rc != H_SUCCESS)
L
Linus Torvalds 已提交
132
		panic("bad return code EOI - rc = %ld, value=%lx\n", lpar_rc,
133
		      val64);
L
Linus Torvalds 已提交
134 135
}

136
static inline void lpar_cppr_info(int n_cpu, u8 value)
L
Linus Torvalds 已提交
137 138 139 140
{
	unsigned long lpar_rc;

	lpar_rc = plpar_cppr(value);
141
	if (lpar_rc != H_SUCCESS)
142
		panic("bad return code cppr - rc = %lx\n", lpar_rc);
L
Linus Torvalds 已提交
143 144
}

145
static inline void lpar_qirr_info(int n_cpu , u8 value)
L
Linus Torvalds 已提交
146 147 148 149
{
	unsigned long lpar_rc;

	lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu), value);
150
	if (lpar_rc != H_SUCCESS)
151
		panic("bad return code qirr - rc = %lx\n", lpar_rc);
L
Linus Torvalds 已提交
152 153 154
}


155
/* High level handlers and init code */
L
Linus Torvalds 已提交
156 157 158


#ifdef CONFIG_SMP
159
static int get_irq_server(unsigned int virq)
L
Linus Torvalds 已提交
160 161 162
{
	unsigned int server;
	/* For the moment only implement delivery to all cpus or one cpu */
163
	cpumask_t cpumask = irq_desc[virq].affinity;
L
Linus Torvalds 已提交
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
	cpumask_t tmp = CPU_MASK_NONE;

	if (!distribute_irqs)
		return default_server;

	if (cpus_equal(cpumask, CPU_MASK_ALL)) {
		server = default_distrib_server;
	} else {
		cpus_and(tmp, cpu_online_map, cpumask);

		if (cpus_empty(tmp))
			server = default_distrib_server;
		else
			server = get_hard_smp_processor_id(first_cpu(tmp));
	}

	return server;

}
#else
184
static int get_irq_server(unsigned int virq)
L
Linus Torvalds 已提交
185 186 187 188 189
{
	return default_server;
}
#endif

190 191

static void xics_unmask_irq(unsigned int virq)
L
Linus Torvalds 已提交
192 193 194 195 196
{
	unsigned int irq;
	int call_status;
	unsigned int server;

197 198 199 200 201
	pr_debug("xics: unmask virq %d\n", virq);

	irq = (unsigned int)irq_map[virq].hwirq;
	pr_debug(" -> map to hwirq 0x%x\n", irq);
	if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
L
Linus Torvalds 已提交
202 203 204
		return;

	server = get_irq_server(virq);
205

L
Linus Torvalds 已提交
206 207 208
	call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
				DEFAULT_PRIORITY);
	if (call_status != 0) {
A
Anton Blanchard 已提交
209 210 211
		printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_set_xive "
		       "returned %d\n", irq, call_status);
		printk("set_xive %x, server %x\n", ibm_set_xive, server);
L
Linus Torvalds 已提交
212 213 214 215 216 217
		return;
	}

	/* Now unmask the interrupt (often a no-op) */
	call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq);
	if (call_status != 0) {
A
Anton Blanchard 已提交
218 219
		printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_int_on "
		       "returned %d\n", irq, call_status);
L
Linus Torvalds 已提交
220 221 222 223
		return;
	}
}

224
static void xics_mask_real_irq(unsigned int irq)
L
Linus Torvalds 已提交
225 226 227 228 229 230 231 232
{
	int call_status;

	if (irq == XICS_IPI)
		return;

	call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq);
	if (call_status != 0) {
A
Anton Blanchard 已提交
233 234
		printk(KERN_ERR "xics_disable_real_irq: irq=%u: "
		       "ibm_int_off returned %d\n", irq, call_status);
L
Linus Torvalds 已提交
235 236 237 238
		return;
	}

	/* Have to set XIVE to 0xff to be able to remove a slot */
239 240
	call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq,
				default_server, 0xff);
L
Linus Torvalds 已提交
241
	if (call_status != 0) {
A
Anton Blanchard 已提交
242 243
		printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)"
		       " returned %d\n", irq, call_status);
L
Linus Torvalds 已提交
244 245 246 247
		return;
	}
}

248
static void xics_mask_irq(unsigned int virq)
L
Linus Torvalds 已提交
249 250 251
{
	unsigned int irq;

252 253 254 255 256 257
	pr_debug("xics: mask virq %d\n", virq);

	irq = (unsigned int)irq_map[virq].hwirq;
	if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
		return;
	xics_mask_real_irq(irq);
258 259
}

260
static unsigned int xics_startup(unsigned int virq)
261 262 263
{
	unsigned int irq;

264 265 266
	/* force a reverse mapping of the interrupt so it gets in the cache */
	irq = (unsigned int)irq_map[virq].hwirq;
	irq_radix_revmap(xics_host, irq);
L
Linus Torvalds 已提交
267

268
	/* unmask it */
269 270 271 272
	xics_unmask_irq(virq);
	return 0;
}

273
static void xics_eoi_direct(unsigned int virq)
L
Linus Torvalds 已提交
274 275
{
	int cpu = smp_processor_id();
276
	unsigned int irq = (unsigned int)irq_map[virq].hwirq;
L
Linus Torvalds 已提交
277 278

	iosync();
279
	direct_xirr_info_set(cpu, (0xff << 24) | irq);
L
Linus Torvalds 已提交
280 281
}

282

283
static void xics_eoi_lpar(unsigned int virq)
L
Linus Torvalds 已提交
284 285
{
	int cpu = smp_processor_id();
286
	unsigned int irq = (unsigned int)irq_map[virq].hwirq;
L
Linus Torvalds 已提交
287

288
	iosync();
289
	lpar_xirr_info_set(cpu, (0xff << 24) | irq);
L
Linus Torvalds 已提交
290 291
}

292
static inline unsigned int xics_remap_irq(unsigned int vec)
L
Linus Torvalds 已提交
293
{
294
	unsigned int irq;
L
Linus Torvalds 已提交
295 296 297

	vec &= 0x00ffffff;

298 299
	if (vec == XICS_IRQ_SPURIOUS)
		return NO_IRQ;
300
	irq = irq_radix_revmap(xics_host, vec);
301
	if (likely(irq != NO_IRQ))
302
		return irq;
303 304 305 306 307

	printk(KERN_ERR "Interrupt %u (real) is invalid,"
	       " disabling it.\n", vec);
	xics_mask_real_irq(vec);
	return NO_IRQ;
L
Linus Torvalds 已提交
308 309
}

O
Olaf Hering 已提交
310
static unsigned int xics_get_irq_direct(void)
311 312
{
	unsigned int cpu = smp_processor_id();
L
Linus Torvalds 已提交
313

314 315 316
	return xics_remap_irq(direct_xirr_info_get(cpu));
}

O
Olaf Hering 已提交
317
static unsigned int xics_get_irq_lpar(void)
L
Linus Torvalds 已提交
318
{
319
	unsigned int cpu = smp_processor_id();
L
Linus Torvalds 已提交
320

321 322 323 324
	return xics_remap_irq(lpar_xirr_info_get(cpu));
}

#ifdef CONFIG_SMP
L
Linus Torvalds 已提交
325

326
static irqreturn_t xics_ipi_dispatch(int cpu)
327
{
L
Linus Torvalds 已提交
328 329 330 331 332 333
	WARN_ON(cpu_is_offline(cpu));

	while (xics_ipi_message[cpu].value) {
		if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION,
				       &xics_ipi_message[cpu].value)) {
			mb();
334
			smp_message_recv(PPC_MSG_CALL_FUNCTION);
L
Linus Torvalds 已提交
335 336 337 338
		}
		if (test_and_clear_bit(PPC_MSG_RESCHEDULE,
				       &xics_ipi_message[cpu].value)) {
			mb();
339
			smp_message_recv(PPC_MSG_RESCHEDULE);
L
Linus Torvalds 已提交
340 341 342 343 344
		}
#if 0
		if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK,
				       &xics_ipi_message[cpu].value)) {
			mb();
345
			smp_message_recv(PPC_MSG_MIGRATE_TASK);
L
Linus Torvalds 已提交
346 347
		}
#endif
348
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
L
Linus Torvalds 已提交
349 350 351
		if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
				       &xics_ipi_message[cpu].value)) {
			mb();
352
			smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
L
Linus Torvalds 已提交
353 354 355 356 357 358
		}
#endif
	}
	return IRQ_HANDLED;
}

359
static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id)
360 361 362 363 364
{
	int cpu = smp_processor_id();

	direct_qirr_info(cpu, 0xff);

365
	return xics_ipi_dispatch(cpu);
366 367
}

368
static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id)
369 370 371 372 373
{
	int cpu = smp_processor_id();

	lpar_qirr_info(cpu, 0xff);

374
	return xics_ipi_dispatch(cpu);
375 376
}

L
Linus Torvalds 已提交
377 378
void xics_cause_IPI(int cpu)
{
379 380 381 382
	if (firmware_has_feature(FW_FEATURE_LPAR))
		lpar_qirr_info(cpu, IPI_PRIORITY);
	else
		direct_qirr_info(cpu, IPI_PRIORITY);
L
Linus Torvalds 已提交
383
}
384

385
#endif /* CONFIG_SMP */
L
Linus Torvalds 已提交
386

387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
static void xics_set_cpu_priority(int cpu, unsigned char cppr)
{
	if (firmware_has_feature(FW_FEATURE_LPAR))
		lpar_cppr_info(cpu, cppr);
	else
		direct_cppr_info(cpu, cppr);
	iosync();
}

static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
{
	unsigned int irq;
	int status;
	int xics_status[2];
	unsigned long newmask;
	cpumask_t tmp = CPU_MASK_NONE;

404 405
	irq = (unsigned int)irq_map[virq].hwirq;
	if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
		return;

	status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);

	if (status) {
		printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive "
		       "returns %d\n", irq, status);
		return;
	}

	/* For the moment only implement delivery to all cpus or one cpu */
	if (cpus_equal(cpumask, CPU_MASK_ALL)) {
		newmask = default_distrib_server;
	} else {
		cpus_and(tmp, cpu_online_map, cpumask);
		if (cpus_empty(tmp))
			return;
		newmask = get_hard_smp_processor_id(first_cpu(tmp));
	}

	status = rtas_call(ibm_set_xive, 3, 1, NULL,
				irq, newmask, xics_status[1]);

	if (status) {
		printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive "
		       "returns %d\n", irq, status);
		return;
	}
}

436 437 438 439 440 441 442 443 444 445 446 447 448
void xics_setup_cpu(void)
{
	int cpu = smp_processor_id();

	xics_set_cpu_priority(cpu, 0xff);

	/*
	 * Put the calling processor into the GIQ.  This is really only
	 * necessary from a secondary thread as the OF start-cpu interface
	 * performs this function for us on primary threads.
	 *
	 * XXX: undo of teardown on kexec needs this too, as may hotplug
	 */
449
	rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
450 451 452 453
		(1UL << interrupt_server_size) - 1 - default_distrib_server, 1);
}


454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
static struct irq_chip xics_pic_direct = {
	.typename = " XICS     ",
	.startup = xics_startup,
	.mask = xics_mask_irq,
	.unmask = xics_unmask_irq,
	.eoi = xics_eoi_direct,
	.set_affinity = xics_set_affinity
};


static struct irq_chip xics_pic_lpar = {
	.typename = " XICS     ",
	.startup = xics_startup,
	.mask = xics_mask_irq,
	.unmask = xics_unmask_irq,
	.eoi = xics_eoi_lpar,
	.set_affinity = xics_set_affinity
};


474
static int xics_host_match(struct irq_host *h, struct device_node *node)
L
Linus Torvalds 已提交
475
{
476 477 478 479 480 481
	/* IBM machines have interrupt parents of various funky types for things
	 * like vdevices, events, etc... The trick we use here is to match
	 * everything here except the legacy 8259 which is compatible "chrp,iic"
	 */
	return !device_is_compatible(node, "chrp,iic");
}
L
Linus Torvalds 已提交
482

483
static int xics_host_map_direct(struct irq_host *h, unsigned int virq,
484
				irq_hw_number_t hw)
485
{
486
	pr_debug("xics: map_direct virq %d, hwirq 0x%lx\n", virq, hw);
487 488 489 490 491 492 493

	get_irq_desc(virq)->status |= IRQ_LEVEL;
	set_irq_chip_and_handler(virq, &xics_pic_direct, handle_fasteoi_irq);
	return 0;
}

static int xics_host_map_lpar(struct irq_host *h, unsigned int virq,
494
			      irq_hw_number_t hw)
495
{
496
	pr_debug("xics: map_direct virq %d, hwirq 0x%lx\n", virq, hw);
497 498 499 500 501 502 503 504 505 506 507 508 509 510

	get_irq_desc(virq)->status |= IRQ_LEVEL;
	set_irq_chip_and_handler(virq, &xics_pic_lpar, handle_fasteoi_irq);
	return 0;
}

static int xics_host_xlate(struct irq_host *h, struct device_node *ct,
			   u32 *intspec, unsigned int intsize,
			   irq_hw_number_t *out_hwirq, unsigned int *out_flags)

{
	/* Current xics implementation translates everything
	 * to level. It is not technically right for MSIs but this
	 * is irrelevant at this point. We might get smarter in the future
511
	 */
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
	*out_hwirq = intspec[0];
	*out_flags = IRQ_TYPE_LEVEL_LOW;

	return 0;
}

static struct irq_host_ops xics_host_direct_ops = {
	.match = xics_host_match,
	.map = xics_host_map_direct,
	.xlate = xics_host_xlate,
};

static struct irq_host_ops xics_host_lpar_ops = {
	.match = xics_host_match,
	.map = xics_host_map_lpar,
	.xlate = xics_host_xlate,
};

static void __init xics_init_host(void)
{
	struct irq_host_ops *ops;

	if (firmware_has_feature(FW_FEATURE_LPAR))
		ops = &xics_host_lpar_ops;
	else
		ops = &xics_host_direct_ops;
	xics_host = irq_alloc_host(IRQ_HOST_MAP_TREE, 0, ops,
				   XICS_IRQ_SPURIOUS);
	BUG_ON(xics_host == NULL);
	irq_set_default_host(xics_host);
542
}
L
Linus Torvalds 已提交
543

544 545
static void __init xics_map_one_cpu(int hw_id, unsigned long addr,
				     unsigned long size)
L
Linus Torvalds 已提交
546
{
547
#ifdef CONFIG_SMP
L
Linus Torvalds 已提交
548 549
	int i;

550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
	/* This may look gross but it's good enough for now, we don't quite
	 * have a hard -> linux processor id matching.
	 */
	for_each_possible_cpu(i) {
		if (!cpu_present(i))
			continue;
		if (hw_id == get_hard_smp_processor_id(i)) {
			xics_per_cpu[i] = ioremap(addr, size);
			return;
		}
	}
#else
	if (hw_id != 0)
		return;
	xics_per_cpu[0] = ioremap(addr, size);
#endif /* CONFIG_SMP */
}
L
Linus Torvalds 已提交
567

568 569 570 571
static void __init xics_init_one_node(struct device_node *np,
				      unsigned int *indx)
{
	unsigned int ilen;
572
	const u32 *ireg;
L
Linus Torvalds 已提交
573

574 575 576 577 578
	/* This code does the theorically broken assumption that the interrupt
	 * server numbers are the same as the hard CPU numbers.
	 * This happens to be the case so far but we are playing with fire...
	 * should be fixed one of these days. -BenH.
	 */
579
	ireg = of_get_property(np, "ibm,interrupt-server-ranges", NULL);
L
Linus Torvalds 已提交
580

581 582 583 584
	/* Do that ever happen ? we'll know soon enough... but even good'old
	 * f80 does have that property ..
	 */
	WARN_ON(ireg == NULL);
L
Linus Torvalds 已提交
585 586 587 588
	if (ireg) {
		/*
		 * set node starting index for this node
		 */
589
		*indx = *ireg;
L
Linus Torvalds 已提交
590
	}
591
	ireg = of_get_property(np, "reg", &ilen);
L
Linus Torvalds 已提交
592 593
	if (!ireg)
		panic("xics_init_IRQ: can't find interrupt reg property");
594

595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
	while (ilen >= (4 * sizeof(u32))) {
		unsigned long addr, size;

		/* XXX Use proper OF parsing code here !!! */
		addr = (unsigned long)*ireg++ << 32;
		ilen -= sizeof(u32);
		addr |= *ireg++;
		ilen -= sizeof(u32);
		size = (unsigned long)*ireg++ << 32;
		ilen -= sizeof(u32);
		size |= *ireg++;
		ilen -= sizeof(u32);
		xics_map_one_cpu(*indx, addr, size);
		(*indx)++;
	}
}


static void __init xics_setup_8259_cascade(void)
{
	struct device_node *np, *old, *found = NULL;
	int cascade, naddr;
617
	const u32 *addrp;
618 619 620 621 622 623 624 625 626 627
	unsigned long intack = 0;

	for_each_node_by_type(np, "interrupt-controller")
		if (device_is_compatible(np, "chrp,iic")) {
			found = np;
			break;
		}
	if (found == NULL) {
		printk(KERN_DEBUG "xics: no ISA interrupt controller\n");
		return;
L
Linus Torvalds 已提交
628
	}
629 630 631 632 633 634 635 636 637 638 639 640 641 642
	cascade = irq_of_parse_and_map(found, 0);
	if (cascade == NO_IRQ) {
		printk(KERN_ERR "xics: failed to map cascade interrupt");
		return;
	}
	pr_debug("xics: cascade mapped to irq %d\n", cascade);

	for (old = of_node_get(found); old != NULL ; old = np) {
		np = of_get_parent(old);
		of_node_put(old);
		if (np == NULL)
			break;
		if (strcmp(np->name, "pci") != 0)
			continue;
643
		addrp = of_get_property(np, "8259-interrupt-acknowledge", NULL);
644 645
		if (addrp == NULL)
			continue;
646
		naddr = of_n_addr_cells(np);
647 648 649 650 651 652 653 654 655 656
		intack = addrp[naddr-1];
		if (naddr > 1)
			intack |= ((unsigned long)addrp[naddr-2]) << 32;
	}
	if (intack)
		printk(KERN_DEBUG "xics: PCI 8259 intack at 0x%016lx\n", intack);
	i8259_init(found, intack);
	of_node_put(found);
	set_irq_chained_handler(cascade, pseries_8259_cascade);
}
L
Linus Torvalds 已提交
657

658 659 660 661 662 663 664 665 666
static struct device_node *cpuid_to_of_node(int cpu)
{
	struct device_node *np;
	u32 hcpuid = get_hard_smp_processor_id(cpu);

	for_each_node_by_type(np, "cpu") {
		int i, len;
		const u32 *intserv;

667 668
		intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
					&len);
669 670

		if (!intserv)
671
			intserv = of_get_property(np, "reg", &len);
672 673 674 675 676 677 678 679 680 681 682

		i = len / sizeof(u32);

		while (i--)
			if (intserv[i] == hcpuid)
				return np;
	}

	return NULL;
}

683 684
void __init xics_init_IRQ(void)
{
685
	int i, j;
686
	struct device_node *np;
687
	u32 ilen, indx = 0;
688
	const u32 *ireg, *isize;
689
	int found = 0;
690
	u32 hcpuid;
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708

	ppc64_boot_msg(0x20, "XICS Init");

	ibm_get_xive = rtas_token("ibm,get-xive");
	ibm_set_xive = rtas_token("ibm,set-xive");
	ibm_int_on  = rtas_token("ibm,int-on");
	ibm_int_off = rtas_token("ibm,int-off");

	for_each_node_by_type(np, "PowerPC-External-Interrupt-Presentation") {
		found = 1;
		if (firmware_has_feature(FW_FEATURE_LPAR))
			break;
		xics_init_one_node(np, &indx);
	}
	if (found == 0)
		return;

	xics_init_host();
L
Linus Torvalds 已提交
709 710

	/* Find the server numbers for the boot cpu. */
711 712
	np = cpuid_to_of_node(boot_cpuid);
	BUG_ON(!np);
713
	ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
	if (!ireg)
		goto skip_gserver_check;
	i = ilen / sizeof(int);
	hcpuid = get_hard_smp_processor_id(boot_cpuid);

	/* Global interrupt distribution server is specified in the last
	 * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
	 * entry fom this property for current boot cpu id and use it as
	 * default distribution server
	 */
	for (j = 0; j < i; j += 2) {
		if (ireg[j] == hcpuid) {
			default_server = hcpuid;
			default_distrib_server = ireg[j+1];

729
			isize = of_get_property(np,
L
Linus Torvalds 已提交
730
					"ibm,interrupt-server#-size", NULL);
731 732
			if (isize)
				interrupt_server_size = *isize;
L
Linus Torvalds 已提交
733 734
		}
	}
735
skip_gserver_check:
L
Linus Torvalds 已提交
736 737
	of_node_put(np);

738 739 740
	if (firmware_has_feature(FW_FEATURE_LPAR))
		ppc_md.get_irq = xics_get_irq_lpar;
	else
741
		ppc_md.get_irq = xics_get_irq_direct;
L
Linus Torvalds 已提交
742

743
	xics_setup_cpu();
L
Linus Torvalds 已提交
744

745
	xics_setup_8259_cascade();
L
Linus Torvalds 已提交
746

747
	ppc64_boot_msg(0x21, "XICS Done");
L
Linus Torvalds 已提交
748
}
749

L
Linus Torvalds 已提交
750 751 752 753

#ifdef CONFIG_SMP
void xics_request_IPIs(void)
{
754 755
	unsigned int ipi;

756
	ipi = irq_create_mapping(xics_host, XICS_IPI);
757
	BUG_ON(ipi == NO_IRQ);
L
Linus Torvalds 已提交
758

759 760 761 762
	/*
	 * IPIs are marked IRQF_DISABLED as they must run with irqs
	 * disabled
	 */
763
	set_irq_handler(ipi, handle_percpu_irq);
764
	if (firmware_has_feature(FW_FEATURE_LPAR))
765 766
		request_irq(ipi, xics_ipi_action_lpar, IRQF_DISABLED,
			    "IPI", NULL);
767
	else
768 769
		request_irq(ipi, xics_ipi_action_direct, IRQF_DISABLED,
			    "IPI", NULL);
L
Linus Torvalds 已提交
770
}
771
#endif /* CONFIG_SMP */
L
Linus Torvalds 已提交
772

773
void xics_teardown_cpu(int secondary)
774 775
{
	int cpu = smp_processor_id();
776 777
	unsigned int ipi;
	struct irq_desc *desc;
778

779
	xics_set_cpu_priority(cpu, 0);
780

781 782 783 784 785 786 787 788
	/*
	 * Clear IPI
	 */
	if (firmware_has_feature(FW_FEATURE_LPAR))
		lpar_qirr_info(cpu, 0xff);
	else
		direct_qirr_info(cpu, 0xff);

789 790 791 792 793 794 795
	/*
	 * we need to EOI the IPI if we got here from kexec down IPI
	 *
	 * probably need to check all the other interrupts too
	 * should we be flagging idle loop instead?
	 * or creating some task to be scheduled?
	 */
796 797 798 799 800

	ipi = irq_find_mapping(xics_host, XICS_IPI);
	if (ipi == XICS_IRQ_SPURIOUS)
		return;
	desc = get_irq_desc(ipi);
801
	if (desc->chip && desc->chip->eoi)
802
		desc->chip->eoi(ipi);
803

804
	/*
805 806
	 * Some machines need to have at least one cpu in the GIQ,
	 * so leave the master cpu in the group.
807
	 */
808
	if (secondary)
809
		rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
810 811
				   (1UL << interrupt_server_size) - 1 -
				   default_distrib_server, 0);
812 813
}

L
Linus Torvalds 已提交
814 815 816 817 818 819 820 821 822
#ifdef CONFIG_HOTPLUG_CPU

/* Interrupts are disabled. */
void xics_migrate_irqs_away(void)
{
	int status;
	unsigned int irq, virq, cpu = smp_processor_id();

	/* Reject any interrupt that was queued to us... */
823
	xics_set_cpu_priority(cpu, 0);
L
Linus Torvalds 已提交
824 825

	/* remove ourselves from the global interrupt queue */
826
	status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
L
Linus Torvalds 已提交
827 828 829 830
		(1UL << interrupt_server_size) - 1 - default_distrib_server, 0);
	WARN_ON(status < 0);

	/* Allow IPIs again... */
831
	xics_set_cpu_priority(cpu, DEFAULT_PRIORITY);
L
Linus Torvalds 已提交
832 833

	for_each_irq(virq) {
834
		struct irq_desc *desc;
L
Linus Torvalds 已提交
835 836 837 838
		int xics_status[2];
		unsigned long flags;

		/* We cant set affinity on ISA interrupts */
839
		if (virq < NUM_ISA_INTERRUPTS)
L
Linus Torvalds 已提交
840
			continue;
841 842 843
		if (irq_map[virq].host != xics_host)
			continue;
		irq = (unsigned int)irq_map[virq].hwirq;
L
Linus Torvalds 已提交
844
		/* We need to get IPIs still. */
845
		if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
L
Linus Torvalds 已提交
846
			continue;
847
		desc = get_irq_desc(virq);
L
Linus Torvalds 已提交
848 849

		/* We only need to migrate enabled IRQS */
850
		if (desc == NULL || desc->chip == NULL
L
Linus Torvalds 已提交
851
		    || desc->action == NULL
852
		    || desc->chip->set_affinity == NULL)
L
Linus Torvalds 已提交
853 854 855 856 857 858
			continue;

		spin_lock_irqsave(&desc->lock, flags);

		status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
		if (status) {
A
Anton Blanchard 已提交
859
			printk(KERN_ERR "migrate_irqs_away: irq=%u "
L
Linus Torvalds 已提交
860 861 862 863 864 865 866 867 868 869 870 871 872
					"ibm,get-xive returns %d\n",
					virq, status);
			goto unlock;
		}

		/*
		 * We only support delivery to all cpus or to one cpu.
		 * The irq has to be migrated only in the single cpu
		 * case.
		 */
		if (xics_status[0] != get_hard_smp_processor_id(cpu))
			goto unlock;

A
Anton Blanchard 已提交
873
		printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n",
L
Linus Torvalds 已提交
874 875 876
		       virq, cpu);

		/* Reset affinity to all cpus */
877
		desc->chip->set_affinity(virq, CPU_MASK_ALL);
878
		irq_desc[irq].affinity = CPU_MASK_ALL;
L
Linus Torvalds 已提交
879 880 881 882 883
unlock:
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}
#endif