intc.c 26.1 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 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
static void (*intc_enable_noprio_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_field,
	[MODE_PCLR_REG] = intc_mode_field,
};

static void intc_enable_disable(struct intc_desc_int *d,
				unsigned long handle, int do_enable)
{
	unsigned long addr;
	unsigned int cpu;
	void (*fn)(unsigned long, unsigned long,
		   void (*)(unsigned long, unsigned long, unsigned long),
		   unsigned int);

	if (do_enable) {
		for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
			addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
			fn = intc_enable_noprio_fns[_INTC_MODE(handle)];
			fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
		}
	} else {
		for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
			addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
			fn = intc_disable_fns[_INTC_MODE(handle)];
			fn(addr, handle, intc_reg_fns[_INTC_FN(handle)], 0);
		}
	}
}

M
Magnus Damm 已提交
299 300 301 302 303
static int intc_set_wake(unsigned int irq, unsigned int on)
{
	return 0; /* allow wakeup, but setup hardware in intc_suspend() */
}

M
Magnus Damm 已提交
304 305 306 307 308 309 310 311 312 313 314 315
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);
316 317
		switch (_INTC_FN(handle)) {
		case REG_FN_MODIFY_BASE + 0:	/* 8bit */
318 319
			__raw_readb(addr);
			__raw_writeb(0xff ^ set_field(0, 1, handle), addr);
320 321
			break;
		case REG_FN_MODIFY_BASE + 1:	/* 16bit */
322 323
			__raw_readw(addr);
			__raw_writew(0xffff ^ set_field(0, 1, handle), addr);
324 325
			break;
		case REG_FN_MODIFY_BASE + 3:	/* 32bit */
326 327
			__raw_readl(addr);
			__raw_writel(0xffffffff ^ set_field(0, 1, handle), addr);
328 329 330 331 332
			break;
		default:
			BUG();
			break;
		}
M
Magnus Damm 已提交
333 334 335
	}
}

M
Magnus Damm 已提交
336 337 338
static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
					     unsigned int nr_hp,
					     unsigned int irq)
339
{
M
Magnus Damm 已提交
340 341
	int i;

342 343 344 345 346 347 348 349 350 351 352 353
	/* 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 已提交
354 355 356 357 358 359
	for (i = 0; i < nr_hp; i++) {
		if ((hp + i)->irq != irq)
			continue;

		return hp + i;
	}
360

M
Magnus Damm 已提交
361
	return NULL;
362 363
}

M
Magnus Damm 已提交
364
int intc_set_priority(unsigned int irq, unsigned int prio)
365
{
M
Magnus Damm 已提交
366 367 368 369 370 371 372 373
	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) {
374
		if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
M
Magnus Damm 已提交
375
			return -EINVAL;
376

M
Magnus Damm 已提交
377 378 379 380 381 382 383 384
		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()
		 */

385
		if (_INTC_FN(ihp->handle) != REG_FN_ERR)
M
Magnus Damm 已提交
386 387 388
			_intc_enable(irq, ihp->handle);
	}
	return 0;
389 390 391 392 393 394 395 396
}

#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),
397 398 399 400
	/* 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)
401
	[IRQ_TYPE_LEVEL_HIGH] = VALID(3),
402
#endif
403 404 405 406
};

static int intc_set_sense(unsigned int irq, unsigned int type)
{
M
Magnus Damm 已提交
407
	struct intc_desc_int *d = get_intc_desc(irq);
408
	unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
M
Magnus Damm 已提交
409 410
	struct intc_handle_int *ihp;
	unsigned long addr;
411

M
Magnus Damm 已提交
412
	if (!value)
413 414
		return -EINVAL;

M
Magnus Damm 已提交
415 416
	ihp = intc_find_irq(d->sense, d->nr_sense, irq);
	if (ihp) {
M
Magnus Damm 已提交
417
		addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
M
Magnus Damm 已提交
418
		intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
419
	}
M
Magnus Damm 已提交
420
	return 0;
421 422
}

M
Magnus Damm 已提交
423 424
static unsigned int __init intc_get_reg(struct intc_desc_int *d,
				 unsigned long address)
425
{
M
Magnus Damm 已提交
426
	unsigned int k;
427

M
Magnus Damm 已提交
428 429 430
	for (k = 0; k < d->nr_reg; k++) {
		if (d->reg[k] == address)
			return k;
431 432 433
	}

	BUG();
M
Magnus Damm 已提交
434
	return 0;
435 436
}

M
Magnus Damm 已提交
437 438
static intc_enum __init intc_grp_id(struct intc_desc *desc,
				    intc_enum enum_id)
M
Magnus Damm 已提交
439
{
440
	struct intc_group *g = desc->hw.groups;
M
Magnus Damm 已提交
441 442
	unsigned int i, j;

443 444
	for (i = 0; g && enum_id && i < desc->hw.nr_groups; i++) {
		g = desc->hw.groups + i;
M
Magnus Damm 已提交
445 446 447 448 449 450 451 452 453 454 455 456

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

			return g->enum_id;
		}
	}

	return 0;
}

M
Magnus Damm 已提交
457 458 459 460 461
static unsigned int __init _intc_mask_data(struct intc_desc *desc,
					   struct intc_desc_int *d,
					   intc_enum enum_id,
					   unsigned int *reg_idx,
					   unsigned int *fld_idx)
462
{
463
	struct intc_mask_reg *mr = desc->hw.mask_regs;
M
Magnus Damm 已提交
464
	unsigned int fn, mode;
M
Magnus Damm 已提交
465
	unsigned long reg_e, reg_d;
466

M
Magnus Damm 已提交
467 468
	while (mr && enum_id && *reg_idx < desc->hw.nr_mask_regs) {
		mr = desc->hw.mask_regs + *reg_idx;
469

M
Magnus Damm 已提交
470 471
		for (; *fld_idx < ARRAY_SIZE(mr->enum_ids); (*fld_idx)++) {
			if (mr->enum_ids[*fld_idx] != enum_id)
472 473
				continue;

M
Magnus Damm 已提交
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
			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;
				}
490 491
			}

M
Magnus Damm 已提交
492 493 494 495 496
			fn += (mr->reg_width >> 3) - 1;
			return _INTC_MK(fn, mode,
					intc_get_reg(d, reg_e),
					intc_get_reg(d, reg_d),
					1,
M
Magnus Damm 已提交
497
					(mr->reg_width - 1) - *fld_idx);
498
		}
M
Magnus Damm 已提交
499 500 501

		*fld_idx = 0;
		(*reg_idx)++;
502 503
	}

M
Magnus Damm 已提交
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
	return 0;
}

static unsigned int __init intc_mask_data(struct intc_desc *desc,
					  struct intc_desc_int *d,
					  intc_enum enum_id, int do_grps)
{
	unsigned int i = 0;
	unsigned int j = 0;
	unsigned int ret;

	ret = _intc_mask_data(desc, d, enum_id, &i, &j);
	if (ret)
		return ret;

M
Magnus Damm 已提交
519
	if (do_grps)
M
Magnus Damm 已提交
520
		return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0);
M
Magnus Damm 已提交
521

522 523 524
	return 0;
}

M
Magnus Damm 已提交
525 526 527 528 529
static unsigned int __init _intc_prio_data(struct intc_desc *desc,
					   struct intc_desc_int *d,
					   intc_enum enum_id,
					   unsigned int *reg_idx,
					   unsigned int *fld_idx)
530
{
531
	struct intc_prio_reg *pr = desc->hw.prio_regs;
M
Magnus Damm 已提交
532
	unsigned int fn, n, mode, bit;
M
Magnus Damm 已提交
533
	unsigned long reg_e, reg_d;
534

M
Magnus Damm 已提交
535 536
	while (pr && enum_id && *reg_idx < desc->hw.nr_prio_regs) {
		pr = desc->hw.prio_regs + *reg_idx;
537

M
Magnus Damm 已提交
538 539
		for (; *fld_idx < ARRAY_SIZE(pr->enum_ids); (*fld_idx)++) {
			if (pr->enum_ids[*fld_idx] != enum_id)
540 541
				continue;

M
Magnus Damm 已提交
542 543 544 545 546 547 548 549 550 551 552 553 554
			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;
			}
555

M
Magnus Damm 已提交
556
			fn += (pr->reg_width >> 3) - 1;
M
Magnus Damm 已提交
557
			n = *fld_idx + 1;
558

M
Magnus Damm 已提交
559
			BUG_ON(n * pr->field_width > pr->reg_width);
560

M
Magnus Damm 已提交
561
			bit = pr->reg_width - (n * pr->field_width);
562

M
Magnus Damm 已提交
563 564 565 566
			return _INTC_MK(fn, mode,
					intc_get_reg(d, reg_e),
					intc_get_reg(d, reg_d),
					pr->field_width, bit);
567
		}
M
Magnus Damm 已提交
568 569 570

		*fld_idx = 0;
		(*reg_idx)++;
571 572
	}

M
Magnus Damm 已提交
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
	return 0;
}

static unsigned int __init intc_prio_data(struct intc_desc *desc,
					  struct intc_desc_int *d,
					  intc_enum enum_id, int do_grps)
{
	unsigned int i = 0;
	unsigned int j = 0;
	unsigned int ret;

	ret = _intc_prio_data(desc, d, enum_id, &i, &j);
	if (ret)
		return ret;

M
Magnus Damm 已提交
588
	if (do_grps)
M
Magnus Damm 已提交
589 590 591 592 593
		return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0);

	return 0;
}

M
Magnus Damm 已提交
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
static void __init intc_enable_disable_enum(struct intc_desc *desc,
					    struct intc_desc_int *d,
					    intc_enum enum_id, int enable)
{
	unsigned int i, j, data;

	/* go through and enable/disable all mask bits */
	i = j = 0;
	do {
		data = _intc_mask_data(desc, d, enum_id, &i, &j);
		if (data)
			intc_enable_disable(d, data, enable);
		j++;
	} while (data);

	/* go through and enable/disable all priority fields */
	i = j = 0;
	do {
		data = _intc_prio_data(desc, d, enum_id, &i, &j);
		if (data)
			intc_enable_disable(d, data, enable);

		j++;
	} while (data);
}

M
Magnus Damm 已提交
620 621 622 623
static unsigned int __init intc_ack_data(struct intc_desc *desc,
					  struct intc_desc_int *d,
					  intc_enum enum_id)
{
624
	struct intc_mask_reg *mr = desc->hw.ack_regs;
M
Magnus Damm 已提交
625 626 627
	unsigned int i, j, fn, mode;
	unsigned long reg_e, reg_d;

628 629
	for (i = 0; mr && enum_id && i < desc->hw.nr_ack_regs; i++) {
		mr = desc->hw.ack_regs + i;
M
Magnus Damm 已提交
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651

		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 已提交
652 653 654 655
static unsigned int __init intc_sense_data(struct intc_desc *desc,
					   struct intc_desc_int *d,
					   intc_enum enum_id)
{
656
	struct intc_sense_reg *sr = desc->hw.sense_regs;
M
Magnus Damm 已提交
657 658
	unsigned int i, j, fn, bit;

659 660
	for (i = 0; sr && enum_id && i < desc->hw.nr_sense_regs; i++) {
		sr = desc->hw.sense_regs + i;
M
Magnus Damm 已提交
661 662 663 664 665 666 667 668

		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;

669 670 671
			BUG_ON((j + 1) * sr->field_width > sr->reg_width);

			bit = sr->reg_width - ((j + 1) * sr->field_width);
M
Magnus Damm 已提交
672 673 674 675 676

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

678 679 680
	return 0;
}

M
Magnus Damm 已提交
681 682 683
static void __init intc_register_irq(struct intc_desc *desc,
				     struct intc_desc_int *d,
				     intc_enum enum_id,
684 685
				     unsigned int irq)
{
686
	struct intc_handle_int *hp;
M
Magnus Damm 已提交
687 688
	unsigned int data[2], primary;

P
Paul Mundt 已提交
689 690 691 692 693
	/*
	 * Register the IRQ position with the global IRQ map
	 */
	set_bit(irq, intc_irq_map);

M
Magnus Damm 已提交
694 695 696 697 698 699
	/* 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)
	 */
700

M
Magnus Damm 已提交
701 702
	data[0] = intc_mask_data(desc, d, enum_id, 0);
	data[1] = intc_prio_data(desc, d, enum_id, 0);
M
Magnus Damm 已提交
703 704 705 706 707

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

708
	if (!data[0] && !data[1])
709 710
		pr_warning("intc: missing unique irq mask for "
			   "irq %d (vect 0x%04x)\n", irq, irq2evt(irq));
711

M
Magnus Damm 已提交
712 713
	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 已提交
714 715 716 717 718

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

	BUG_ON(!data[primary]); /* must have primary masking method */
719 720

	disable_irq_nosync(irq);
M
Magnus Damm 已提交
721
	set_irq_chip_and_handler_name(irq, &d->chip,
722
				      handle_level_irq, "level");
M
Magnus Damm 已提交
723
	set_irq_chip_data(irq, (void *)data[primary]);
724

725 726 727 728
	/* set priority level
	 * - this needs to be at least 2 for 5-bit priorities on 7780
	 */
	intc_prio_level[irq] = 2;
M
Magnus Damm 已提交
729

M
Magnus Damm 已提交
730 731
	/* enable secondary masking method if present */
	if (data[!primary])
M
Magnus Damm 已提交
732 733 734 735
		_intc_enable(irq, data[!primary]);

	/* add irq to d->prio list if priority is available */
	if (data[1]) {
736 737 738 739 740 741 742 743 744 745 746 747 748
		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 已提交
749 750 751 752 753 754 755 756 757 758
		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++;
	}
759 760

	/* irq should be disabled by default */
M
Magnus Damm 已提交
761
	d->chip.mask(irq);
M
Magnus Damm 已提交
762

763
	if (desc->hw.ack_regs)
M
Magnus Damm 已提交
764
		ack_handle[irq] = intc_ack_data(desc, d, enum_id);
765 766
}

M
Magnus Damm 已提交
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
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;
}

783
static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
784
{
785
	generic_handle_irq((unsigned int)get_irq_data(irq));
786
}
M
Magnus Damm 已提交
787

788 789
void __init register_intc_controller(struct intc_desc *desc)
{
P
Paul Mundt 已提交
790
	unsigned int i, k, smp;
791
	struct intc_hw_desc *hw = &desc->hw;
M
Magnus Damm 已提交
792 793
	struct intc_desc_int *d;

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

M
Magnus Damm 已提交
796 797 798
	INIT_LIST_HEAD(&d->list);
	list_add(&d->list, &intc_list);

799 800 801 802
	d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
	d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
	d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
	d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
803

804
	d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
M
Magnus Damm 已提交
805
#ifdef CONFIG_SMP
806
	d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
M
Magnus Damm 已提交
807
#endif
M
Magnus Damm 已提交
808 809
	k = 0;

810 811 812 813 814
	if (hw->mask_regs) {
		for (i = 0; i < hw->nr_mask_regs; i++) {
			smp = IS_SMP(hw->mask_regs[i]);
			k += save_reg(d, k, hw->mask_regs[i].set_reg, smp);
			k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp);
M
Magnus Damm 已提交
815 816 817
		}
	}

818 819 820
	if (hw->prio_regs) {
		d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
				  GFP_NOWAIT);
M
Magnus Damm 已提交
821

822 823 824 825
		for (i = 0; i < hw->nr_prio_regs; i++) {
			smp = IS_SMP(hw->prio_regs[i]);
			k += save_reg(d, k, hw->prio_regs[i].set_reg, smp);
			k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp);
M
Magnus Damm 已提交
826 827 828
		}
	}

829 830 831
	if (hw->sense_regs) {
		d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
				   GFP_NOWAIT);
M
Magnus Damm 已提交
832

833 834
		for (i = 0; i < hw->nr_sense_regs; i++)
			k += save_reg(d, k, hw->sense_regs[i].reg, 0);
M
Magnus Damm 已提交
835 836 837 838 839 840
	}

	d->chip.name = desc->name;
	d->chip.mask = intc_disable;
	d->chip.unmask = intc_enable;
	d->chip.mask_ack = intc_disable;
841 842 843
	d->chip.enable = intc_enable;
	d->chip.disable = intc_disable;
	d->chip.shutdown = intc_disable;
M
Magnus Damm 已提交
844
	d->chip.set_type = intc_set_sense;
M
Magnus Damm 已提交
845
	d->chip.set_wake = intc_set_wake;
846

847 848 849
	if (hw->ack_regs) {
		for (i = 0; i < hw->nr_ack_regs; i++)
			k += save_reg(d, k, hw->ack_regs[i].set_reg, 0);
M
Magnus Damm 已提交
850 851 852 853

		d->chip.mask_ack = intc_mask_ack;
	}

M
Magnus Damm 已提交
854 855 856 857 858

	/* disable bits matching force_enable before registering irqs */
	if (desc->force_enable)
		intc_enable_disable_enum(desc, d, desc->force_enable, 0);

M
Magnus Damm 已提交
859 860
	BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */

861
	/* register the vectors one by one */
862 863
	for (i = 0; i < hw->nr_vectors; i++) {
		struct intc_vect *vect = hw->vectors + i;
864 865
		unsigned int irq = evt2irq(vect->vect);
		struct irq_desc *irq_desc;
P
Paul Mundt 已提交
866

867 868 869
		if (!vect->enum_id)
			continue;

P
Paul Mundt 已提交
870
		irq_desc = irq_to_desc_alloc_node(irq, numa_node_id());
871
		if (unlikely(!irq_desc)) {
872
			pr_info("can't get irq_desc for %d\n", irq);
873 874 875 876
			continue;
		}

		intc_register_irq(desc, d, vect->enum_id, irq);
877

878 879
		for (k = i + 1; k < hw->nr_vectors; k++) {
			struct intc_vect *vect2 = hw->vectors + k;
880 881 882 883 884
			unsigned int irq2 = evt2irq(vect2->vect);

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

885 886 887 888 889 890 891 892 893 894 895
			/*
			 * 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;
			}

896 897 898
			vect2->enum_id = 0;

			/* redirect this interrupts to the first one */
899 900
			set_irq_chained_handler(irq2, intc_redirect_irq);
			set_irq_chip(irq2, &d->chip);
901 902
			set_irq_data(irq2, (void *)irq);
		}
903
	}
M
Magnus Damm 已提交
904 905 906 907

	/* enable bits matching force_enable after registering irqs */
	if (desc->force_enable)
		intc_enable_disable_enum(desc, d, desc->force_enable, 1);
908
}
M
Magnus Damm 已提交
909 910 911 912 913 914 915 916 917 918

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);

919 920 921 922 923
	switch (state.event) {
	case PM_EVENT_ON:
		if (d->state.event != PM_EVENT_FREEZE)
			break;
		for_each_irq_desc(irq, desc) {
924
			if (desc->handle_irq == intc_redirect_irq)
P
Paul Mundt 已提交
925
				continue;
926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
			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 已提交
944
	}
945
	d->state = state;
M
Magnus Damm 已提交
946 947 948 949

	return 0;
}

950 951 952 953 954
static int intc_resume(struct sys_device *dev)
{
	return intc_suspend(dev, PMSG_ON);
}

M
Magnus Damm 已提交
955 956 957
static struct sysdev_class intc_sysdev_class = {
	.name = "intc",
	.suspend = intc_suspend,
958
	.resume = intc_resume,
M
Magnus Damm 已提交
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985
};

/* 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 已提交
986 987 988 989

/*
 * Dynamic IRQ allocation and deallocation
 */
990
unsigned int create_irq_nr(unsigned int irq_want, int node)
P
Paul Mundt 已提交
991 992 993 994 995 996 997 998
{
	unsigned int irq = 0, new;
	unsigned long flags;
	struct irq_desc *desc;

	spin_lock_irqsave(&vector_lock, flags);

	/*
999
	 * First try the wanted IRQ
P
Paul Mundt 已提交
1000
	 */
1001 1002 1003 1004
	if (test_and_set_bit(irq_want, intc_irq_map) == 0) {
		new = irq_want;
	} else {
		/* .. then fall back to scanning. */
P
Paul Mundt 已提交
1005 1006 1007 1008 1009 1010 1011
		new = find_first_zero_bit(intc_irq_map, nr_irqs);
		if (unlikely(new == nr_irqs))
			goto out_unlock;

		__set_bit(new, intc_irq_map);
	}

1012 1013 1014 1015 1016 1017 1018 1019 1020
	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);
	irq = new;

P
Paul Mundt 已提交
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
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;

1035
	irq = create_irq_nr(NR_IRQS_LEGACY, nid);
P
Paul Mundt 已提交
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
	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);
}
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076

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);
}