intc.c 23.3 KB
Newer Older
1 2 3
/*
 * Shared interrupt handling code for IPR and INTC2 types of IRQs.
 *
M
Magnus Damm 已提交
4
 * Copyright (C) 2007, 2008 Magnus Damm
P
Paul Mundt 已提交
5
 * Copyright (C) 2009 Paul Mundt
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * Based on intc2.c and ipr.c
 *
 * Copyright (C) 1999  Niibe Yutaka & Takeshi Yaegashi
 * Copyright (C) 2000  Kazumoto Kojima
 * Copyright (C) 2001  David J. Mckay (david.mckay@st.com)
 * Copyright (C) 2003  Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
 * Copyright (C) 2005, 2006  Paul Mundt
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/interrupt.h>
24
#include <linux/sh_intc.h>
M
Magnus Damm 已提交
25 26
#include <linux/sysdev.h>
#include <linux/list.h>
P
Paul Mundt 已提交
27
#include <linux/topology.h>
P
Paul Mundt 已提交
28
#include <linux/bitmap.h>
M
Magnus Damm 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
	((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
	 ((addr_e) << 16) | ((addr_d << 24)))

#define _INTC_SHIFT(h) (h & 0x1f)
#define _INTC_WIDTH(h) ((h >> 5) & 0xf)
#define _INTC_FN(h) ((h >> 9) & 0xf)
#define _INTC_MODE(h) ((h >> 13) & 0x7)
#define _INTC_ADDR_E(h) ((h >> 16) & 0xff)
#define _INTC_ADDR_D(h) ((h >> 24) & 0xff)

struct intc_handle_int {
	unsigned int irq;
	unsigned long handle;
};
45

M
Magnus Damm 已提交
46
struct intc_desc_int {
M
Magnus Damm 已提交
47 48
	struct list_head list;
	struct sys_device sysdev;
49
	pm_message_t state;
M
Magnus Damm 已提交
50
	unsigned long *reg;
M
Magnus Damm 已提交
51 52 53
#ifdef CONFIG_SMP
	unsigned long *smp;
#endif
M
Magnus Damm 已提交
54 55 56 57 58 59 60
	unsigned int nr_reg;
	struct intc_handle_int *prio;
	unsigned int nr_prio;
	struct intc_handle_int *sense;
	unsigned int nr_sense;
	struct irq_chip chip;
};
61

M
Magnus Damm 已提交
62 63
static LIST_HEAD(intc_list);

P
Paul Mundt 已提交
64 65 66 67 68 69 70 71 72 73 74 75 76 77
/*
 * The intc_irq_map provides a global map of bound IRQ vectors for a
 * given platform. Allocation of IRQs are either static through the CPU
 * vector map, or dynamic in the case of board mux vectors or MSI.
 *
 * As this is a central point for all IRQ controllers on the system,
 * each of the available sources are mapped out here. This combined with
 * sparseirq makes it quite trivial to keep the vector map tightly packed
 * when dynamically creating IRQs, as well as tying in to otherwise
 * unused irq_desc positions in the sparse array.
 */
static DECLARE_BITMAP(intc_irq_map, NR_IRQS);
static DEFINE_SPINLOCK(vector_lock);

M
Magnus Damm 已提交
78 79 80 81 82 83 84 85 86 87
#ifdef CONFIG_SMP
#define IS_SMP(x) x.smp
#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
#else
#define IS_SMP(x) 0
#define INTC_REG(d, x, c) (d->reg[(x)])
#define SMP_NR(d, x) 1
#endif

M
Magnus Damm 已提交
88
static unsigned int intc_prio_level[NR_IRQS]; /* for now */
M
Magnus Damm 已提交
89
static unsigned long ack_handle[NR_IRQS];
90

M
Magnus Damm 已提交
91
static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
92 93
{
	struct irq_chip *chip = get_irq_chip(irq);
94
	return container_of(chip, struct intc_desc_int, chip);
95 96 97 98
}

static inline unsigned int set_field(unsigned int value,
				     unsigned int field_value,
M
Magnus Damm 已提交
99
				     unsigned int handle)
100
{
M
Magnus Damm 已提交
101 102 103
	unsigned int width = _INTC_WIDTH(handle);
	unsigned int shift = _INTC_SHIFT(handle);

104 105 106 107 108
	value &= ~(((1 << width) - 1) << shift);
	value |= field_value << shift;
	return value;
}

M
Magnus Damm 已提交
109
static void write_8(unsigned long addr, unsigned long h, unsigned long data)
110
{
111
	__raw_writeb(set_field(0, data, h), addr);
112
	(void)__raw_readb(addr);	/* Defeat write posting */
113 114
}

M
Magnus Damm 已提交
115
static void write_16(unsigned long addr, unsigned long h, unsigned long data)
116
{
117
	__raw_writew(set_field(0, data, h), addr);
118
	(void)__raw_readw(addr);	/* Defeat write posting */
119 120
}

M
Magnus Damm 已提交
121
static void write_32(unsigned long addr, unsigned long h, unsigned long data)
122
{
123
	__raw_writel(set_field(0, data, h), addr);
124
	(void)__raw_readl(addr);	/* Defeat write posting */
125 126
}

M
Magnus Damm 已提交
127
static void modify_8(unsigned long addr, unsigned long h, unsigned long data)
128
{
M
Magnus Damm 已提交
129 130
	unsigned long flags;
	local_irq_save(flags);
131
	__raw_writeb(set_field(__raw_readb(addr), data, h), addr);
132
	(void)__raw_readb(addr);	/* Defeat write posting */
M
Magnus Damm 已提交
133
	local_irq_restore(flags);
134 135
}

M
Magnus Damm 已提交
136
static void modify_16(unsigned long addr, unsigned long h, unsigned long data)
137
{
M
Magnus Damm 已提交
138 139
	unsigned long flags;
	local_irq_save(flags);
140
	__raw_writew(set_field(__raw_readw(addr), data, h), addr);
141
	(void)__raw_readw(addr);	/* Defeat write posting */
M
Magnus Damm 已提交
142
	local_irq_restore(flags);
143 144
}

M
Magnus Damm 已提交
145
static void modify_32(unsigned long addr, unsigned long h, unsigned long data)
146
{
M
Magnus Damm 已提交
147 148
	unsigned long flags;
	local_irq_save(flags);
149
	__raw_writel(set_field(__raw_readl(addr), data, h), addr);
150
	(void)__raw_readl(addr);	/* Defeat write posting */
M
Magnus Damm 已提交
151
	local_irq_restore(flags);
152 153
}

M
Magnus Damm 已提交
154 155 156 157 158 159 160 161 162 163 164 165
enum {	REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 };

static void (*intc_reg_fns[])(unsigned long addr,
			      unsigned long h,
			      unsigned long data) = {
	[REG_FN_WRITE_BASE + 0] = write_8,
	[REG_FN_WRITE_BASE + 1] = write_16,
	[REG_FN_WRITE_BASE + 3] = write_32,
	[REG_FN_MODIFY_BASE + 0] = modify_8,
	[REG_FN_MODIFY_BASE + 1] = modify_16,
	[REG_FN_MODIFY_BASE + 3] = modify_32,
};
166

M
Magnus Damm 已提交
167 168 169 170 171 172
enum {	MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
	MODE_MASK_REG,       /* Bit(s) set -> interrupt disabled */
	MODE_DUAL_REG,       /* Two registers, set bit to enable / disable */
	MODE_PRIO_REG,       /* Priority value written to enable interrupt */
	MODE_PCLR_REG,       /* Above plus all bits set to disable interrupt */
};
173

M
Magnus Damm 已提交
174 175 176 177 178 179
static void intc_mode_field(unsigned long addr,
			    unsigned long handle,
			    void (*fn)(unsigned long,
				       unsigned long,
				       unsigned long),
			    unsigned int irq)
180
{
M
Magnus Damm 已提交
181
	fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
182 183
}

M
Magnus Damm 已提交
184 185 186 187 188 189
static void intc_mode_zero(unsigned long addr,
			   unsigned long handle,
			   void (*fn)(unsigned long,
				       unsigned long,
				       unsigned long),
			   unsigned int irq)
190
{
M
Magnus Damm 已提交
191
	fn(addr, handle, 0);
192 193
}

M
Magnus Damm 已提交
194 195 196 197 198 199
static void intc_mode_prio(unsigned long addr,
			   unsigned long handle,
			   void (*fn)(unsigned long,
				       unsigned long,
				       unsigned long),
			   unsigned int irq)
200
{
M
Magnus Damm 已提交
201
	fn(addr, handle, intc_prio_level[irq]);
202 203
}

M
Magnus Damm 已提交
204 205 206 207 208 209 210 211 212 213 214 215
static void (*intc_enable_fns[])(unsigned long addr,
				 unsigned long handle,
				 void (*fn)(unsigned long,
					    unsigned long,
					    unsigned long),
				 unsigned int irq) = {
	[MODE_ENABLE_REG] = intc_mode_field,
	[MODE_MASK_REG] = intc_mode_zero,
	[MODE_DUAL_REG] = intc_mode_field,
	[MODE_PRIO_REG] = intc_mode_prio,
	[MODE_PCLR_REG] = intc_mode_prio,
};
216

M
Magnus Damm 已提交
217 218 219 220 221 222 223 224 225 226 227 228
static void (*intc_disable_fns[])(unsigned long addr,
				  unsigned long handle,
				  void (*fn)(unsigned long,
					     unsigned long,
					     unsigned long),
				  unsigned int irq) = {
	[MODE_ENABLE_REG] = intc_mode_zero,
	[MODE_MASK_REG] = intc_mode_field,
	[MODE_DUAL_REG] = intc_mode_field,
	[MODE_PRIO_REG] = intc_mode_zero,
	[MODE_PCLR_REG] = intc_mode_field,
};
229

M
Magnus Damm 已提交
230
static inline void _intc_enable(unsigned int irq, unsigned long handle)
231
{
M
Magnus Damm 已提交
232
	struct intc_desc_int *d = get_intc_desc(irq);
M
Magnus Damm 已提交
233 234
	unsigned long addr;
	unsigned int cpu;
235

M
Magnus Damm 已提交
236 237 238 239 240
	for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
		addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
		intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
						    [_INTC_FN(handle)], irq);
	}
241 242
}

243 244
static void intc_enable(unsigned int irq)
{
M
Magnus Damm 已提交
245
	_intc_enable(irq, (unsigned long)get_irq_chip_data(irq));
246 247 248 249
}

static void intc_disable(unsigned int irq)
{
M
Magnus Damm 已提交
250
	struct intc_desc_int *d = get_intc_desc(irq);
M
Magnus Damm 已提交
251
	unsigned long handle = (unsigned long) get_irq_chip_data(irq);
M
Magnus Damm 已提交
252 253
	unsigned long addr;
	unsigned int cpu;
254

M
Magnus Damm 已提交
255 256 257 258 259
	for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
		addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
		intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
						     [_INTC_FN(handle)], irq);
	}
260 261
}

M
Magnus Damm 已提交
262 263 264 265 266
static int intc_set_wake(unsigned int irq, unsigned int on)
{
	return 0; /* allow wakeup, but setup hardware in intc_suspend() */
}

M
Magnus Damm 已提交
267 268 269 270 271 272 273 274 275 276 277 278
static void intc_mask_ack(unsigned int irq)
{
	struct intc_desc_int *d = get_intc_desc(irq);
	unsigned long handle = ack_handle[irq];
	unsigned long addr;

	intc_disable(irq);

	/* read register and write zero only to the assocaited bit */

	if (handle) {
		addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
279 280
		switch (_INTC_FN(handle)) {
		case REG_FN_MODIFY_BASE + 0:	/* 8bit */
281 282
			__raw_readb(addr);
			__raw_writeb(0xff ^ set_field(0, 1, handle), addr);
283 284
			break;
		case REG_FN_MODIFY_BASE + 1:	/* 16bit */
285 286
			__raw_readw(addr);
			__raw_writew(0xffff ^ set_field(0, 1, handle), addr);
287 288
			break;
		case REG_FN_MODIFY_BASE + 3:	/* 32bit */
289 290
			__raw_readl(addr);
			__raw_writel(0xffffffff ^ set_field(0, 1, handle), addr);
291 292 293 294 295
			break;
		default:
			BUG();
			break;
		}
M
Magnus Damm 已提交
296 297 298
	}
}

M
Magnus Damm 已提交
299 300 301
static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
					     unsigned int nr_hp,
					     unsigned int irq)
302
{
M
Magnus Damm 已提交
303 304
	int i;

305 306 307 308 309 310 311 312 313 314 315 316
	/* this doesn't scale well, but...
	 *
	 * this function should only be used for cerain uncommon
	 * operations such as intc_set_priority() and intc_set_sense()
	 * and in those rare cases performance doesn't matter that much.
	 * keeping the memory footprint low is more important.
	 *
	 * one rather simple way to speed this up and still keep the
	 * memory footprint down is to make sure the array is sorted
	 * and then perform a bisect to lookup the irq.
	 */

M
Magnus Damm 已提交
317 318 319 320 321 322
	for (i = 0; i < nr_hp; i++) {
		if ((hp + i)->irq != irq)
			continue;

		return hp + i;
	}
323

M
Magnus Damm 已提交
324
	return NULL;
325 326
}

M
Magnus Damm 已提交
327
int intc_set_priority(unsigned int irq, unsigned int prio)
328
{
M
Magnus Damm 已提交
329 330 331 332 333 334 335 336
	struct intc_desc_int *d = get_intc_desc(irq);
	struct intc_handle_int *ihp;

	if (!intc_prio_level[irq] || prio <= 1)
		return -EINVAL;

	ihp = intc_find_irq(d->prio, d->nr_prio, irq);
	if (ihp) {
337
		if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
M
Magnus Damm 已提交
338
			return -EINVAL;
339

M
Magnus Damm 已提交
340 341 342 343 344 345 346 347
		intc_prio_level[irq] = prio;

		/*
		 * only set secondary masking method directly
		 * primary masking method is using intc_prio_level[irq]
		 * priority level will be set during next enable()
		 */

348
		if (_INTC_FN(ihp->handle) != REG_FN_ERR)
M
Magnus Damm 已提交
349 350 351
			_intc_enable(irq, ihp->handle);
	}
	return 0;
352 353 354 355 356 357 358 359
}

#define VALID(x) (x | 0x80)

static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
	[IRQ_TYPE_EDGE_FALLING] = VALID(0),
	[IRQ_TYPE_EDGE_RISING] = VALID(1),
	[IRQ_TYPE_LEVEL_LOW] = VALID(2),
360 361 362 363
	/* SH7706, SH7707 and SH7709 do not support high level triggered */
#if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \
    !defined(CONFIG_CPU_SUBTYPE_SH7707) && \
    !defined(CONFIG_CPU_SUBTYPE_SH7709)
364
	[IRQ_TYPE_LEVEL_HIGH] = VALID(3),
365
#endif
366 367 368 369
};

static int intc_set_sense(unsigned int irq, unsigned int type)
{
M
Magnus Damm 已提交
370
	struct intc_desc_int *d = get_intc_desc(irq);
371
	unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
M
Magnus Damm 已提交
372 373
	struct intc_handle_int *ihp;
	unsigned long addr;
374

M
Magnus Damm 已提交
375
	if (!value)
376 377
		return -EINVAL;

M
Magnus Damm 已提交
378 379
	ihp = intc_find_irq(d->sense, d->nr_sense, irq);
	if (ihp) {
M
Magnus Damm 已提交
380
		addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
M
Magnus Damm 已提交
381
		intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
382
	}
M
Magnus Damm 已提交
383
	return 0;
384 385
}

M
Magnus Damm 已提交
386 387
static unsigned int __init intc_get_reg(struct intc_desc_int *d,
				 unsigned long address)
388
{
M
Magnus Damm 已提交
389
	unsigned int k;
390

M
Magnus Damm 已提交
391 392 393
	for (k = 0; k < d->nr_reg; k++) {
		if (d->reg[k] == address)
			return k;
394 395 396
	}

	BUG();
M
Magnus Damm 已提交
397
	return 0;
398 399
}

M
Magnus Damm 已提交
400 401
static intc_enum __init intc_grp_id(struct intc_desc *desc,
				    intc_enum enum_id)
M
Magnus Damm 已提交
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
{
	struct intc_group *g = desc->groups;
	unsigned int i, j;

	for (i = 0; g && enum_id && i < desc->nr_groups; i++) {
		g = desc->groups + i;

		for (j = 0; g->enum_ids[j]; j++) {
			if (g->enum_ids[j] != enum_id)
				continue;

			return g->enum_id;
		}
	}

	return 0;
}

420
static unsigned int __init intc_mask_data(struct intc_desc *desc,
M
Magnus Damm 已提交
421
					  struct intc_desc_int *d,
M
Magnus Damm 已提交
422
					  intc_enum enum_id, int do_grps)
423
{
M
Magnus Damm 已提交
424
	struct intc_mask_reg *mr = desc->mask_regs;
M
Magnus Damm 已提交
425 426
	unsigned int i, j, fn, mode;
	unsigned long reg_e, reg_d;
427

M
Magnus Damm 已提交
428 429
	for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) {
		mr = desc->mask_regs + i;
430 431 432 433 434

		for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
			if (mr->enum_ids[j] != enum_id)
				continue;

M
Magnus Damm 已提交
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
			if (mr->set_reg && mr->clr_reg) {
				fn = REG_FN_WRITE_BASE;
				mode = MODE_DUAL_REG;
				reg_e = mr->clr_reg;
				reg_d = mr->set_reg;
			} else {
				fn = REG_FN_MODIFY_BASE;
				if (mr->set_reg) {
					mode = MODE_ENABLE_REG;
					reg_e = mr->set_reg;
					reg_d = mr->set_reg;
				} else {
					mode = MODE_MASK_REG;
					reg_e = mr->clr_reg;
					reg_d = mr->clr_reg;
				}
451 452
			}

M
Magnus Damm 已提交
453 454 455 456 457 458
			fn += (mr->reg_width >> 3) - 1;
			return _INTC_MK(fn, mode,
					intc_get_reg(d, reg_e),
					intc_get_reg(d, reg_d),
					1,
					(mr->reg_width - 1) - j);
459 460 461
		}
	}

M
Magnus Damm 已提交
462
	if (do_grps)
M
Magnus Damm 已提交
463
		return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0);
M
Magnus Damm 已提交
464

465 466 467 468
	return 0;
}

static unsigned int __init intc_prio_data(struct intc_desc *desc,
M
Magnus Damm 已提交
469
					  struct intc_desc_int *d,
M
Magnus Damm 已提交
470
					  intc_enum enum_id, int do_grps)
471
{
M
Magnus Damm 已提交
472
	struct intc_prio_reg *pr = desc->prio_regs;
M
Magnus Damm 已提交
473 474
	unsigned int i, j, fn, mode, bit;
	unsigned long reg_e, reg_d;
475

M
Magnus Damm 已提交
476 477
	for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) {
		pr = desc->prio_regs + i;
478 479 480 481 482

		for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) {
			if (pr->enum_ids[j] != enum_id)
				continue;

M
Magnus Damm 已提交
483 484 485 486 487 488 489 490 491 492 493 494 495
			if (pr->set_reg && pr->clr_reg) {
				fn = REG_FN_WRITE_BASE;
				mode = MODE_PCLR_REG;
				reg_e = pr->set_reg;
				reg_d = pr->clr_reg;
			} else {
				fn = REG_FN_MODIFY_BASE;
				mode = MODE_PRIO_REG;
				if (!pr->set_reg)
					BUG();
				reg_e = pr->set_reg;
				reg_d = pr->set_reg;
			}
496

M
Magnus Damm 已提交
497
			fn += (pr->reg_width >> 3) - 1;
498

499 500 501
			BUG_ON((j + 1) * pr->field_width > pr->reg_width);

			bit = pr->reg_width - ((j + 1) * pr->field_width);
502

M
Magnus Damm 已提交
503 504 505 506
			return _INTC_MK(fn, mode,
					intc_get_reg(d, reg_e),
					intc_get_reg(d, reg_d),
					pr->field_width, bit);
507 508 509
		}
	}

M
Magnus Damm 已提交
510
	if (do_grps)
M
Magnus Damm 已提交
511 512 513 514 515
		return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0);

	return 0;
}

M
Magnus Damm 已提交
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 543 544 545 546 547
static unsigned int __init intc_ack_data(struct intc_desc *desc,
					  struct intc_desc_int *d,
					  intc_enum enum_id)
{
	struct intc_mask_reg *mr = desc->ack_regs;
	unsigned int i, j, fn, mode;
	unsigned long reg_e, reg_d;

	for (i = 0; mr && enum_id && i < desc->nr_ack_regs; i++) {
		mr = desc->ack_regs + i;

		for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
			if (mr->enum_ids[j] != enum_id)
				continue;

			fn = REG_FN_MODIFY_BASE;
			mode = MODE_ENABLE_REG;
			reg_e = mr->set_reg;
			reg_d = mr->set_reg;

			fn += (mr->reg_width >> 3) - 1;
			return _INTC_MK(fn, mode,
					intc_get_reg(d, reg_e),
					intc_get_reg(d, reg_d),
					1,
					(mr->reg_width - 1) - j);
		}
	}

	return 0;
}

M
Magnus Damm 已提交
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
static unsigned int __init intc_sense_data(struct intc_desc *desc,
					   struct intc_desc_int *d,
					   intc_enum enum_id)
{
	struct intc_sense_reg *sr = desc->sense_regs;
	unsigned int i, j, fn, bit;

	for (i = 0; sr && enum_id && i < desc->nr_sense_regs; i++) {
		sr = desc->sense_regs + i;

		for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
			if (sr->enum_ids[j] != enum_id)
				continue;

			fn = REG_FN_MODIFY_BASE;
			fn += (sr->reg_width >> 3) - 1;

565 566 567
			BUG_ON((j + 1) * sr->field_width > sr->reg_width);

			bit = sr->reg_width - ((j + 1) * sr->field_width);
M
Magnus Damm 已提交
568 569 570 571 572

			return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg),
					0, sr->field_width, bit);
		}
	}
M
Magnus Damm 已提交
573

574 575 576
	return 0;
}

M
Magnus Damm 已提交
577 578 579
static void __init intc_register_irq(struct intc_desc *desc,
				     struct intc_desc_int *d,
				     intc_enum enum_id,
580 581
				     unsigned int irq)
{
582
	struct intc_handle_int *hp;
M
Magnus Damm 已提交
583 584
	unsigned int data[2], primary;

P
Paul Mundt 已提交
585 586 587 588 589
	/*
	 * Register the IRQ position with the global IRQ map
	 */
	set_bit(irq, intc_irq_map);

M
Magnus Damm 已提交
590 591 592 593 594 595
	/* Prefer single interrupt source bitmap over other combinations:
	 * 1. bitmap, single interrupt source
	 * 2. priority, single interrupt source
	 * 3. bitmap, multiple interrupt sources (groups)
	 * 4. priority, multiple interrupt sources (groups)
	 */
596

M
Magnus Damm 已提交
597 598
	data[0] = intc_mask_data(desc, d, enum_id, 0);
	data[1] = intc_prio_data(desc, d, enum_id, 0);
M
Magnus Damm 已提交
599 600 601 602 603

	primary = 0;
	if (!data[0] && data[1])
		primary = 1;

604
	if (!data[0] && !data[1])
605 606
		pr_warning("intc: missing unique irq mask for "
			   "irq %d (vect 0x%04x)\n", irq, irq2evt(irq));
607

M
Magnus Damm 已提交
608 609
	data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
	data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
M
Magnus Damm 已提交
610 611 612 613 614

	if (!data[primary])
		primary ^= 1;

	BUG_ON(!data[primary]); /* must have primary masking method */
615 616

	disable_irq_nosync(irq);
M
Magnus Damm 已提交
617
	set_irq_chip_and_handler_name(irq, &d->chip,
618
				      handle_level_irq, "level");
M
Magnus Damm 已提交
619
	set_irq_chip_data(irq, (void *)data[primary]);
620

621 622 623 624
	/* set priority level
	 * - this needs to be at least 2 for 5-bit priorities on 7780
	 */
	intc_prio_level[irq] = 2;
M
Magnus Damm 已提交
625

M
Magnus Damm 已提交
626 627
	/* enable secondary masking method if present */
	if (data[!primary])
M
Magnus Damm 已提交
628 629 630 631
		_intc_enable(irq, data[!primary]);

	/* add irq to d->prio list if priority is available */
	if (data[1]) {
632 633 634 635 636 637 638 639 640 641 642 643 644
		hp = d->prio + d->nr_prio;
		hp->irq = irq;
		hp->handle = data[1];

		if (primary) {
			/*
			 * only secondary priority should access registers, so
			 * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
			 */

			hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
			hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
		}
M
Magnus Damm 已提交
645 646 647 648 649 650 651 652 653 654
		d->nr_prio++;
	}

	/* add irq to d->sense list if sense is available */
	data[0] = intc_sense_data(desc, d, enum_id);
	if (data[0]) {
		(d->sense + d->nr_sense)->irq = irq;
		(d->sense + d->nr_sense)->handle = data[0];
		d->nr_sense++;
	}
655 656

	/* irq should be disabled by default */
M
Magnus Damm 已提交
657
	d->chip.mask(irq);
M
Magnus Damm 已提交
658 659 660

	if (desc->ack_regs)
		ack_handle[irq] = intc_ack_data(desc, d, enum_id);
661 662
}

M
Magnus Damm 已提交
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
static unsigned int __init save_reg(struct intc_desc_int *d,
				    unsigned int cnt,
				    unsigned long value,
				    unsigned int smp)
{
	if (value) {
		d->reg[cnt] = value;
#ifdef CONFIG_SMP
		d->smp[cnt] = smp;
#endif
		return 1;
	}

	return 0;
}

679
static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
680
{
681
	generic_handle_irq((unsigned int)get_irq_data(irq));
682
}
M
Magnus Damm 已提交
683

684 685
void __init register_intc_controller(struct intc_desc *desc)
{
P
Paul Mundt 已提交
686
	unsigned int i, k, smp;
M
Magnus Damm 已提交
687 688
	struct intc_desc_int *d;

689
	d = kzalloc(sizeof(*d), GFP_NOWAIT);
M
Magnus Damm 已提交
690

M
Magnus Damm 已提交
691 692 693
	INIT_LIST_HEAD(&d->list);
	list_add(&d->list, &intc_list);

M
Magnus Damm 已提交
694 695 696
	d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0;
	d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0;
	d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0;
M
Magnus Damm 已提交
697
	d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0;
698

699
	d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
M
Magnus Damm 已提交
700
#ifdef CONFIG_SMP
701
	d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
M
Magnus Damm 已提交
702
#endif
M
Magnus Damm 已提交
703 704 705 706
	k = 0;

	if (desc->mask_regs) {
		for (i = 0; i < desc->nr_mask_regs; i++) {
M
Magnus Damm 已提交
707 708 709
			smp = IS_SMP(desc->mask_regs[i]);
			k += save_reg(d, k, desc->mask_regs[i].set_reg, smp);
			k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp);
M
Magnus Damm 已提交
710 711 712 713
		}
	}

	if (desc->prio_regs) {
714
		d->prio = kzalloc(desc->nr_vectors * sizeof(*d->prio), GFP_NOWAIT);
M
Magnus Damm 已提交
715 716

		for (i = 0; i < desc->nr_prio_regs; i++) {
M
Magnus Damm 已提交
717 718 719
			smp = IS_SMP(desc->prio_regs[i]);
			k += save_reg(d, k, desc->prio_regs[i].set_reg, smp);
			k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp);
M
Magnus Damm 已提交
720 721 722 723
		}
	}

	if (desc->sense_regs) {
724
		d->sense = kzalloc(desc->nr_vectors * sizeof(*d->sense), GFP_NOWAIT);
M
Magnus Damm 已提交
725 726

		for (i = 0; i < desc->nr_sense_regs; i++) {
M
Magnus Damm 已提交
727
			k += save_reg(d, k, desc->sense_regs[i].reg, 0);
M
Magnus Damm 已提交
728 729 730 731 732 733 734
		}
	}

	d->chip.name = desc->name;
	d->chip.mask = intc_disable;
	d->chip.unmask = intc_enable;
	d->chip.mask_ack = intc_disable;
735 736 737
	d->chip.enable = intc_enable;
	d->chip.disable = intc_disable;
	d->chip.shutdown = intc_disable;
M
Magnus Damm 已提交
738
	d->chip.set_type = intc_set_sense;
M
Magnus Damm 已提交
739
	d->chip.set_wake = intc_set_wake;
740

M
Magnus Damm 已提交
741 742 743 744 745 746 747 748 749
	if (desc->ack_regs) {
		for (i = 0; i < desc->nr_ack_regs; i++)
			k += save_reg(d, k, desc->ack_regs[i].set_reg, 0);

		d->chip.mask_ack = intc_mask_ack;
	}

	BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */

750
	/* register the vectors one by one */
751 752
	for (i = 0; i < desc->nr_vectors; i++) {
		struct intc_vect *vect = desc->vectors + i;
753 754
		unsigned int irq = evt2irq(vect->vect);
		struct irq_desc *irq_desc;
P
Paul Mundt 已提交
755

756 757 758
		if (!vect->enum_id)
			continue;

P
Paul Mundt 已提交
759
		irq_desc = irq_to_desc_alloc_node(irq, numa_node_id());
760
		if (unlikely(!irq_desc)) {
761
			pr_info("can't get irq_desc for %d\n", irq);
762 763 764 765
			continue;
		}

		intc_register_irq(desc, d, vect->enum_id, irq);
766 767 768 769 770 771 772 773

		for (k = i + 1; k < desc->nr_vectors; k++) {
			struct intc_vect *vect2 = desc->vectors + k;
			unsigned int irq2 = evt2irq(vect2->vect);

			if (vect->enum_id != vect2->enum_id)
				continue;

774 775 776 777 778 779 780 781 782 783 784
			/*
			 * In the case of multi-evt handling and sparse
			 * IRQ support, each vector still needs to have
			 * its own backing irq_desc.
			 */
			irq_desc = irq_to_desc_alloc_node(irq2, numa_node_id());
			if (unlikely(!irq_desc)) {
				pr_info("can't get irq_desc for %d\n", irq2);
				continue;
			}

785 786 787 788 789 790 791
			vect2->enum_id = 0;

			/* redirect this interrupts to the first one */
			set_irq_chip_and_handler_name(irq2, &d->chip,
					intc_redirect_irq, "redirect");
			set_irq_data(irq2, (void *)irq);
		}
792 793
	}
}
M
Magnus Damm 已提交
794 795 796 797 798 799 800 801 802 803

static int intc_suspend(struct sys_device *dev, pm_message_t state)
{
	struct intc_desc_int *d;
	struct irq_desc *desc;
	int irq;

	/* get intc controller associated with this sysdev */
	d = container_of(dev, struct intc_desc_int, sysdev);

804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
	switch (state.event) {
	case PM_EVENT_ON:
		if (d->state.event != PM_EVENT_FREEZE)
			break;
		for_each_irq_desc(irq, desc) {
			if (desc->chip != &d->chip)
				continue;
			if (desc->status & IRQ_DISABLED)
				intc_disable(irq);
			else
				intc_enable(irq);
		}
		break;
	case PM_EVENT_FREEZE:
		/* nothing has to be done */
		break;
	case PM_EVENT_SUSPEND:
		/* enable wakeup irqs belonging to this intc controller */
		for_each_irq_desc(irq, desc) {
			if ((desc->status & IRQ_WAKEUP) && (desc->chip == &d->chip))
				intc_enable(irq);
		}
		break;
M
Magnus Damm 已提交
827
	}
828
	d->state = state;
M
Magnus Damm 已提交
829 830 831 832

	return 0;
}

833 834 835 836 837
static int intc_resume(struct sys_device *dev)
{
	return intc_suspend(dev, PMSG_ON);
}

M
Magnus Damm 已提交
838 839 840
static struct sysdev_class intc_sysdev_class = {
	.name = "intc",
	.suspend = intc_suspend,
841
	.resume = intc_resume,
M
Magnus Damm 已提交
842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
};

/* register this intc as sysdev to allow suspend/resume */
static int __init register_intc_sysdevs(void)
{
	struct intc_desc_int *d;
	int error;
	int id = 0;

	error = sysdev_class_register(&intc_sysdev_class);
	if (!error) {
		list_for_each_entry(d, &intc_list, list) {
			d->sysdev.id = id;
			d->sysdev.cls = &intc_sysdev_class;
			error = sysdev_register(&d->sysdev);
			if (error)
				break;
			id++;
		}
	}

	if (error)
		pr_warning("intc: sysdev registration error\n");

	return error;
}
device_initcall(register_intc_sysdevs);
P
Paul Mundt 已提交
869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930

/*
 * Dynamic IRQ allocation and deallocation
 */
static unsigned int create_irq_on_node(unsigned int irq_want, int node)
{
	unsigned int irq = 0, new;
	unsigned long flags;
	struct irq_desc *desc;

	spin_lock_irqsave(&vector_lock, flags);

	/*
	 * First try the wanted IRQ, then scan.
	 */
	if (test_and_set_bit(irq_want, intc_irq_map)) {
		new = find_first_zero_bit(intc_irq_map, nr_irqs);
		if (unlikely(new == nr_irqs))
			goto out_unlock;

		desc = irq_to_desc_alloc_node(new, node);
		if (unlikely(!desc)) {
			pr_info("can't get irq_desc for %d\n", new);
			goto out_unlock;
		}

		desc = move_irq_desc(desc, node);
		__set_bit(new, intc_irq_map);
		irq = new;
	}

out_unlock:
	spin_unlock_irqrestore(&vector_lock, flags);

	if (irq > 0)
		dynamic_irq_init(irq);

	return irq;
}

int create_irq(void)
{
	int nid = cpu_to_node(smp_processor_id());
	int irq;

	irq = create_irq_on_node(NR_IRQS_LEGACY, nid);
	if (irq == 0)
		irq = -1;

	return irq;
}

void destroy_irq(unsigned int irq)
{
	unsigned long flags;

	dynamic_irq_cleanup(irq);

	spin_lock_irqsave(&vector_lock, flags);
	__clear_bit(irq, intc_irq_map);
	spin_unlock_irqrestore(&vector_lock, flags);
}
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955

int reserve_irq_vector(unsigned int irq)
{
	unsigned long flags;
	int ret = 0;

	spin_lock_irqsave(&vector_lock, flags);
	if (test_and_set_bit(irq, intc_irq_map))
		ret = -EBUSY;
	spin_unlock_irqrestore(&vector_lock, flags);

	return ret;
}

void reserve_irq_legacy(void)
{
	unsigned long flags;
	int i, j;

	spin_lock_irqsave(&vector_lock, flags);
	j = find_first_bit(intc_irq_map, nr_irqs);
	for (i = 0; i < j; i++)
		__set_bit(i, intc_irq_map);
	spin_unlock_irqrestore(&vector_lock, flags);
}