xics.c 19.6 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 233
{
	int call_status;
	unsigned int server;

	if (irq == XICS_IPI)
		return;

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

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

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

253 254 255 256 257 258
	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);
259 260
}

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

265 266 267
	/* 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 已提交
268

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

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

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

283

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

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

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

	vec &= 0x00ffffff;

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

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

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

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

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

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

#ifdef CONFIG_SMP
L
Linus Torvalds 已提交
326

327
static irqreturn_t xics_ipi_dispatch(int cpu)
328
{
L
Linus Torvalds 已提交
329 330 331 332 333 334
	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();
335
			smp_message_recv(PPC_MSG_CALL_FUNCTION);
L
Linus Torvalds 已提交
336 337 338 339
		}
		if (test_and_clear_bit(PPC_MSG_RESCHEDULE,
				       &xics_ipi_message[cpu].value)) {
			mb();
340
			smp_message_recv(PPC_MSG_RESCHEDULE);
L
Linus Torvalds 已提交
341 342 343 344 345
		}
#if 0
		if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK,
				       &xics_ipi_message[cpu].value)) {
			mb();
346
			smp_message_recv(PPC_MSG_MIGRATE_TASK);
L
Linus Torvalds 已提交
347 348
		}
#endif
349
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
L
Linus Torvalds 已提交
350 351 352
		if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
				       &xics_ipi_message[cpu].value)) {
			mb();
353
			smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
L
Linus Torvalds 已提交
354 355 356 357 358 359
		}
#endif
	}
	return IRQ_HANDLED;
}

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

	direct_qirr_info(cpu, 0xff);

366
	return xics_ipi_dispatch(cpu);
367 368
}

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

	lpar_qirr_info(cpu, 0xff);

375
	return xics_ipi_dispatch(cpu);
376 377
}

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

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

388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
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;

405 406
	irq = (unsigned int)irq_map[virq].hwirq;
	if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
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 436
		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;
	}
}

437 438 439 440 441 442 443 444 445 446 447 448 449
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
	 */
450
	rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
451 452 453 454
		(1UL << interrupt_server_size) - 1 - default_distrib_server, 1);
}


455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
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
};


475
static int xics_host_match(struct irq_host *h, struct device_node *node)
L
Linus Torvalds 已提交
476
{
477 478 479 480 481 482
	/* 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 已提交
483

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

	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,
495
			      irq_hw_number_t hw)
496
{
497
	pr_debug("xics: map_direct virq %d, hwirq 0x%lx\n", virq, hw);
498 499 500 501 502 503 504 505 506 507 508 509 510 511

	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
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 542
	*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);
543
}
L
Linus Torvalds 已提交
544

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

551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
	/* 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 已提交
568

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

575 576 577 578 579
	/* 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.
	 */
580
	ireg = get_property(np, "ibm,interrupt-server-ranges", NULL);
L
Linus Torvalds 已提交
581

582 583 584 585
	/* 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 已提交
586 587 588 589
	if (ireg) {
		/*
		 * set node starting index for this node
		 */
590
		*indx = *ireg;
L
Linus Torvalds 已提交
591
	}
592
	ireg = get_property(np, "reg", &ilen);
L
Linus Torvalds 已提交
593 594
	if (!ireg)
		panic("xics_init_IRQ: can't find interrupt reg property");
595

596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
	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;
618
	const u32 *addrp;
619 620 621 622 623 624 625 626 627 628
	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 已提交
629
	}
630 631 632 633 634 635 636 637 638 639 640 641 642 643
	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;
644
		addrp = get_property(np, "8259-interrupt-acknowledge", NULL);
645 646 647 648 649 650 651 652 653 654 655 656 657
		if (addrp == NULL)
			continue;
		naddr = prom_n_addr_cells(np);
		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 已提交
658

659 660 661 662
void __init xics_init_IRQ(void)
{
	int i;
	struct device_node *np;
663 664
	u32 ilen, indx = 0;
	const u32 *ireg;
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
	int found = 0;

	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 已提交
684 685 686 687 688

	/* Find the server numbers for the boot cpu. */
	for (np = of_find_node_by_type(NULL, "cpu");
	     np;
	     np = of_find_node_by_type(np, "cpu")) {
689
		ireg = get_property(np, "reg", &ilen);
690
		if (ireg && ireg[0] == get_hard_smp_processor_id(boot_cpuid)) {
691 692
			ireg = get_property(np,
					"ibm,ppc-interrupt-gserver#s", &ilen);
L
Linus Torvalds 已提交
693 694 695
			i = ilen / sizeof(int);
			if (ireg && i > 0) {
				default_server = ireg[0];
696 697
				/* take last element */
				default_distrib_server = ireg[i-1];
L
Linus Torvalds 已提交
698
			}
699
			ireg = get_property(np,
L
Linus Torvalds 已提交
700 701 702 703 704 705 706 707
					"ibm,interrupt-server#-size", NULL);
			if (ireg)
				interrupt_server_size = *ireg;
			break;
		}
	}
	of_node_put(np);

708 709 710
	if (firmware_has_feature(FW_FEATURE_LPAR))
		ppc_md.get_irq = xics_get_irq_lpar;
	else
711
		ppc_md.get_irq = xics_get_irq_direct;
L
Linus Torvalds 已提交
712

713
	xics_setup_cpu();
L
Linus Torvalds 已提交
714

715
	xics_setup_8259_cascade();
L
Linus Torvalds 已提交
716

717
	ppc64_boot_msg(0x21, "XICS Done");
L
Linus Torvalds 已提交
718
}
719

L
Linus Torvalds 已提交
720 721 722 723

#ifdef CONFIG_SMP
void xics_request_IPIs(void)
{
724 725
	unsigned int ipi;

726
	ipi = irq_create_mapping(xics_host, XICS_IPI);
727
	BUG_ON(ipi == NO_IRQ);
L
Linus Torvalds 已提交
728

729 730 731 732
	/*
	 * IPIs are marked IRQF_DISABLED as they must run with irqs
	 * disabled
	 */
733
	set_irq_handler(ipi, handle_percpu_irq);
734
	if (firmware_has_feature(FW_FEATURE_LPAR))
735 736
		request_irq(ipi, xics_ipi_action_lpar, IRQF_DISABLED,
			    "IPI", NULL);
737
	else
738 739
		request_irq(ipi, xics_ipi_action_direct, IRQF_DISABLED,
			    "IPI", NULL);
L
Linus Torvalds 已提交
740
}
741
#endif /* CONFIG_SMP */
L
Linus Torvalds 已提交
742

743
void xics_teardown_cpu(int secondary)
744 745
{
	int cpu = smp_processor_id();
746 747
	unsigned int ipi;
	struct irq_desc *desc;
748

749
	xics_set_cpu_priority(cpu, 0);
750

751 752 753 754 755 756 757 758
	/*
	 * Clear IPI
	 */
	if (firmware_has_feature(FW_FEATURE_LPAR))
		lpar_qirr_info(cpu, 0xff);
	else
		direct_qirr_info(cpu, 0xff);

759 760 761 762 763 764 765
	/*
	 * 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?
	 */
766 767 768 769 770

	ipi = irq_find_mapping(xics_host, XICS_IPI);
	if (ipi == XICS_IRQ_SPURIOUS)
		return;
	desc = get_irq_desc(ipi);
771
	if (desc->chip && desc->chip->eoi)
772
		desc->chip->eoi(ipi);
773

774
	/*
775 776
	 * Some machines need to have at least one cpu in the GIQ,
	 * so leave the master cpu in the group.
777
	 */
778
	if (secondary)
779
		rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
780 781
				   (1UL << interrupt_server_size) - 1 -
				   default_distrib_server, 0);
782 783
}

L
Linus Torvalds 已提交
784 785 786 787 788 789 790 791 792
#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... */
793
	xics_set_cpu_priority(cpu, 0);
L
Linus Torvalds 已提交
794 795

	/* remove ourselves from the global interrupt queue */
796
	status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
L
Linus Torvalds 已提交
797 798 799 800
		(1UL << interrupt_server_size) - 1 - default_distrib_server, 0);
	WARN_ON(status < 0);

	/* Allow IPIs again... */
801
	xics_set_cpu_priority(cpu, DEFAULT_PRIORITY);
L
Linus Torvalds 已提交
802 803

	for_each_irq(virq) {
804
		struct irq_desc *desc;
L
Linus Torvalds 已提交
805 806 807 808
		int xics_status[2];
		unsigned long flags;

		/* We cant set affinity on ISA interrupts */
809
		if (virq < NUM_ISA_INTERRUPTS)
L
Linus Torvalds 已提交
810
			continue;
811 812 813
		if (irq_map[virq].host != xics_host)
			continue;
		irq = (unsigned int)irq_map[virq].hwirq;
L
Linus Torvalds 已提交
814
		/* We need to get IPIs still. */
815
		if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
L
Linus Torvalds 已提交
816
			continue;
817
		desc = get_irq_desc(virq);
L
Linus Torvalds 已提交
818 819

		/* We only need to migrate enabled IRQS */
820
		if (desc == NULL || desc->chip == NULL
L
Linus Torvalds 已提交
821
		    || desc->action == NULL
822
		    || desc->chip->set_affinity == NULL)
L
Linus Torvalds 已提交
823 824 825 826 827 828
			continue;

		spin_lock_irqsave(&desc->lock, flags);

		status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
		if (status) {
A
Anton Blanchard 已提交
829
			printk(KERN_ERR "migrate_irqs_away: irq=%u "
L
Linus Torvalds 已提交
830 831 832 833 834 835 836 837 838 839 840 841 842
					"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 已提交
843
		printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n",
L
Linus Torvalds 已提交
844 845 846
		       virq, cpu);

		/* Reset affinity to all cpus */
847
		desc->chip->set_affinity(virq, CPU_MASK_ALL);
848
		irq_desc[irq].affinity = CPU_MASK_ALL;
L
Linus Torvalds 已提交
849 850 851 852 853
unlock:
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}
#endif