Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.6 526 lines 13 kB view raw
1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 7 * Copyright (C) 2008 Nicolas Schichan <nschichan@freebox.fr> 8 */ 9 10#include <linux/kernel.h> 11#include <linux/init.h> 12#include <linux/interrupt.h> 13#include <linux/module.h> 14#include <linux/irq.h> 15#include <asm/irq_cpu.h> 16#include <asm/mipsregs.h> 17#include <bcm63xx_cpu.h> 18#include <bcm63xx_regs.h> 19#include <bcm63xx_io.h> 20#include <bcm63xx_irq.h> 21 22static void __dispatch_internal(void) __maybe_unused; 23static void __dispatch_internal_64(void) __maybe_unused; 24static void __internal_irq_mask_32(unsigned int irq) __maybe_unused; 25static void __internal_irq_mask_64(unsigned int irq) __maybe_unused; 26static void __internal_irq_unmask_32(unsigned int irq) __maybe_unused; 27static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; 28 29#ifndef BCMCPU_RUNTIME_DETECT 30#ifdef CONFIG_BCM63XX_CPU_6328 31#define irq_stat_reg PERF_IRQSTAT_6328_REG 32#define irq_mask_reg PERF_IRQMASK_6328_REG 33#define irq_bits 64 34#define is_ext_irq_cascaded 1 35#define ext_irq_start (BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE) 36#define ext_irq_end (BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE) 37#define ext_irq_count 4 38#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6328 39#define ext_irq_cfg_reg2 0 40#endif 41#ifdef CONFIG_BCM63XX_CPU_6338 42#define irq_stat_reg PERF_IRQSTAT_6338_REG 43#define irq_mask_reg PERF_IRQMASK_6338_REG 44#define irq_bits 32 45#define is_ext_irq_cascaded 0 46#define ext_irq_start 0 47#define ext_irq_end 0 48#define ext_irq_count 4 49#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6338 50#define ext_irq_cfg_reg2 0 51#endif 52#ifdef CONFIG_BCM63XX_CPU_6345 53#define irq_stat_reg PERF_IRQSTAT_6345_REG 54#define irq_mask_reg PERF_IRQMASK_6345_REG 55#define irq_bits 32 56#define is_ext_irq_cascaded 0 57#define ext_irq_start 0 58#define ext_irq_end 0 59#define ext_irq_count 0 60#define ext_irq_cfg_reg1 0 61#define ext_irq_cfg_reg2 0 62#endif 63#ifdef CONFIG_BCM63XX_CPU_6348 64#define irq_stat_reg PERF_IRQSTAT_6348_REG 65#define irq_mask_reg PERF_IRQMASK_6348_REG 66#define irq_bits 32 67#define is_ext_irq_cascaded 0 68#define ext_irq_start 0 69#define ext_irq_end 0 70#define ext_irq_count 4 71#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6348 72#define ext_irq_cfg_reg2 0 73#endif 74#ifdef CONFIG_BCM63XX_CPU_6358 75#define irq_stat_reg PERF_IRQSTAT_6358_REG 76#define irq_mask_reg PERF_IRQMASK_6358_REG 77#define irq_bits 32 78#define is_ext_irq_cascaded 1 79#define ext_irq_start (BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE) 80#define ext_irq_end (BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE) 81#define ext_irq_count 4 82#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6358 83#define ext_irq_cfg_reg2 0 84#endif 85#ifdef CONFIG_BCM63XX_CPU_6368 86#define irq_stat_reg PERF_IRQSTAT_6368_REG 87#define irq_mask_reg PERF_IRQMASK_6368_REG 88#define irq_bits 64 89#define is_ext_irq_cascaded 1 90#define ext_irq_start (BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE) 91#define ext_irq_end (BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE) 92#define ext_irq_count 6 93#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6368 94#define ext_irq_cfg_reg2 PERF_EXTIRQ_CFG_REG2_6368 95#endif 96 97#if irq_bits == 32 98#define dispatch_internal __dispatch_internal 99#define internal_irq_mask __internal_irq_mask_32 100#define internal_irq_unmask __internal_irq_unmask_32 101#else 102#define dispatch_internal __dispatch_internal_64 103#define internal_irq_mask __internal_irq_mask_64 104#define internal_irq_unmask __internal_irq_unmask_64 105#endif 106 107#define irq_stat_addr (bcm63xx_regset_address(RSET_PERF) + irq_stat_reg) 108#define irq_mask_addr (bcm63xx_regset_address(RSET_PERF) + irq_mask_reg) 109 110static inline void bcm63xx_init_irq(void) 111{ 112} 113#else /* ! BCMCPU_RUNTIME_DETECT */ 114 115static u32 irq_stat_addr, irq_mask_addr; 116static void (*dispatch_internal)(void); 117static int is_ext_irq_cascaded; 118static unsigned int ext_irq_count; 119static unsigned int ext_irq_start, ext_irq_end; 120static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2; 121static void (*internal_irq_mask)(unsigned int irq); 122static void (*internal_irq_unmask)(unsigned int irq); 123 124static void bcm63xx_init_irq(void) 125{ 126 int irq_bits; 127 128 irq_stat_addr = bcm63xx_regset_address(RSET_PERF); 129 irq_mask_addr = bcm63xx_regset_address(RSET_PERF); 130 131 switch (bcm63xx_get_cpu_id()) { 132 case BCM6328_CPU_ID: 133 irq_stat_addr += PERF_IRQSTAT_6328_REG; 134 irq_mask_addr += PERF_IRQMASK_6328_REG; 135 irq_bits = 64; 136 ext_irq_count = 4; 137 is_ext_irq_cascaded = 1; 138 ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE; 139 ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE; 140 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328; 141 break; 142 case BCM6338_CPU_ID: 143 irq_stat_addr += PERF_IRQSTAT_6338_REG; 144 irq_mask_addr += PERF_IRQMASK_6338_REG; 145 irq_bits = 32; 146 break; 147 case BCM6345_CPU_ID: 148 irq_stat_addr += PERF_IRQSTAT_6345_REG; 149 irq_mask_addr += PERF_IRQMASK_6345_REG; 150 irq_bits = 32; 151 break; 152 case BCM6348_CPU_ID: 153 irq_stat_addr += PERF_IRQSTAT_6348_REG; 154 irq_mask_addr += PERF_IRQMASK_6348_REG; 155 irq_bits = 32; 156 ext_irq_count = 4; 157 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348; 158 break; 159 case BCM6358_CPU_ID: 160 irq_stat_addr += PERF_IRQSTAT_6358_REG; 161 irq_mask_addr += PERF_IRQMASK_6358_REG; 162 irq_bits = 32; 163 ext_irq_count = 4; 164 is_ext_irq_cascaded = 1; 165 ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE; 166 ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE; 167 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358; 168 break; 169 case BCM6368_CPU_ID: 170 irq_stat_addr += PERF_IRQSTAT_6368_REG; 171 irq_mask_addr += PERF_IRQMASK_6368_REG; 172 irq_bits = 64; 173 ext_irq_count = 6; 174 is_ext_irq_cascaded = 1; 175 ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE; 176 ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE; 177 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368; 178 ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368; 179 break; 180 default: 181 BUG(); 182 } 183 184 if (irq_bits == 32) { 185 dispatch_internal = __dispatch_internal; 186 internal_irq_mask = __internal_irq_mask_32; 187 internal_irq_unmask = __internal_irq_unmask_32; 188 } else { 189 dispatch_internal = __dispatch_internal_64; 190 internal_irq_mask = __internal_irq_mask_64; 191 internal_irq_unmask = __internal_irq_unmask_64; 192 } 193} 194#endif /* ! BCMCPU_RUNTIME_DETECT */ 195 196static inline u32 get_ext_irq_perf_reg(int irq) 197{ 198 if (irq < 4) 199 return ext_irq_cfg_reg1; 200 return ext_irq_cfg_reg2; 201} 202 203static inline void handle_internal(int intbit) 204{ 205 if (is_ext_irq_cascaded && 206 intbit >= ext_irq_start && intbit <= ext_irq_end) 207 do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE); 208 else 209 do_IRQ(intbit + IRQ_INTERNAL_BASE); 210} 211 212/* 213 * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not 214 * prioritize any interrupt relatively to another. the static counter 215 * will resume the loop where it ended the last time we left this 216 * function. 217 */ 218static void __dispatch_internal(void) 219{ 220 u32 pending; 221 static int i; 222 223 pending = bcm_readl(irq_stat_addr) & bcm_readl(irq_mask_addr); 224 225 if (!pending) 226 return ; 227 228 while (1) { 229 int to_call = i; 230 231 i = (i + 1) & 0x1f; 232 if (pending & (1 << to_call)) { 233 handle_internal(to_call); 234 break; 235 } 236 } 237} 238 239static void __dispatch_internal_64(void) 240{ 241 u64 pending; 242 static int i; 243 244 pending = bcm_readq(irq_stat_addr) & bcm_readq(irq_mask_addr); 245 246 if (!pending) 247 return ; 248 249 while (1) { 250 int to_call = i; 251 252 i = (i + 1) & 0x3f; 253 if (pending & (1ull << to_call)) { 254 handle_internal(to_call); 255 break; 256 } 257 } 258} 259 260asmlinkage void plat_irq_dispatch(void) 261{ 262 u32 cause; 263 264 do { 265 cause = read_c0_cause() & read_c0_status() & ST0_IM; 266 267 if (!cause) 268 break; 269 270 if (cause & CAUSEF_IP7) 271 do_IRQ(7); 272 if (cause & CAUSEF_IP2) 273 dispatch_internal(); 274 if (!is_ext_irq_cascaded) { 275 if (cause & CAUSEF_IP3) 276 do_IRQ(IRQ_EXT_0); 277 if (cause & CAUSEF_IP4) 278 do_IRQ(IRQ_EXT_1); 279 if (cause & CAUSEF_IP5) 280 do_IRQ(IRQ_EXT_2); 281 if (cause & CAUSEF_IP6) 282 do_IRQ(IRQ_EXT_3); 283 } 284 } while (1); 285} 286 287/* 288 * internal IRQs operations: only mask/unmask on PERF irq mask 289 * register. 290 */ 291static void __internal_irq_mask_32(unsigned int irq) 292{ 293 u32 mask; 294 295 mask = bcm_readl(irq_mask_addr); 296 mask &= ~(1 << irq); 297 bcm_writel(mask, irq_mask_addr); 298} 299 300static void __internal_irq_mask_64(unsigned int irq) 301{ 302 u64 mask; 303 304 mask = bcm_readq(irq_mask_addr); 305 mask &= ~(1ull << irq); 306 bcm_writeq(mask, irq_mask_addr); 307} 308 309static void __internal_irq_unmask_32(unsigned int irq) 310{ 311 u32 mask; 312 313 mask = bcm_readl(irq_mask_addr); 314 mask |= (1 << irq); 315 bcm_writel(mask, irq_mask_addr); 316} 317 318static void __internal_irq_unmask_64(unsigned int irq) 319{ 320 u64 mask; 321 322 mask = bcm_readq(irq_mask_addr); 323 mask |= (1ull << irq); 324 bcm_writeq(mask, irq_mask_addr); 325} 326 327static void bcm63xx_internal_irq_mask(struct irq_data *d) 328{ 329 internal_irq_mask(d->irq - IRQ_INTERNAL_BASE); 330} 331 332static void bcm63xx_internal_irq_unmask(struct irq_data *d) 333{ 334 internal_irq_unmask(d->irq - IRQ_INTERNAL_BASE); 335} 336 337/* 338 * external IRQs operations: mask/unmask and clear on PERF external 339 * irq control register. 340 */ 341static void bcm63xx_external_irq_mask(struct irq_data *d) 342{ 343 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 344 u32 reg, regaddr; 345 346 regaddr = get_ext_irq_perf_reg(irq); 347 reg = bcm_perf_readl(regaddr); 348 349 if (BCMCPU_IS_6348()) 350 reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4); 351 else 352 reg &= ~EXTIRQ_CFG_MASK(irq % 4); 353 354 bcm_perf_writel(reg, regaddr); 355 if (is_ext_irq_cascaded) 356 internal_irq_mask(irq + ext_irq_start); 357} 358 359static void bcm63xx_external_irq_unmask(struct irq_data *d) 360{ 361 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 362 u32 reg, regaddr; 363 364 regaddr = get_ext_irq_perf_reg(irq); 365 reg = bcm_perf_readl(regaddr); 366 367 if (BCMCPU_IS_6348()) 368 reg |= EXTIRQ_CFG_MASK_6348(irq % 4); 369 else 370 reg |= EXTIRQ_CFG_MASK(irq % 4); 371 372 bcm_perf_writel(reg, regaddr); 373 374 if (is_ext_irq_cascaded) 375 internal_irq_unmask(irq + ext_irq_start); 376} 377 378static void bcm63xx_external_irq_clear(struct irq_data *d) 379{ 380 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 381 u32 reg, regaddr; 382 383 regaddr = get_ext_irq_perf_reg(irq); 384 reg = bcm_perf_readl(regaddr); 385 386 if (BCMCPU_IS_6348()) 387 reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4); 388 else 389 reg |= EXTIRQ_CFG_CLEAR(irq % 4); 390 391 bcm_perf_writel(reg, regaddr); 392} 393 394static int bcm63xx_external_irq_set_type(struct irq_data *d, 395 unsigned int flow_type) 396{ 397 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 398 u32 reg, regaddr; 399 int levelsense, sense, bothedge; 400 401 flow_type &= IRQ_TYPE_SENSE_MASK; 402 403 if (flow_type == IRQ_TYPE_NONE) 404 flow_type = IRQ_TYPE_LEVEL_LOW; 405 406 levelsense = sense = bothedge = 0; 407 switch (flow_type) { 408 case IRQ_TYPE_EDGE_BOTH: 409 bothedge = 1; 410 break; 411 412 case IRQ_TYPE_EDGE_RISING: 413 sense = 1; 414 break; 415 416 case IRQ_TYPE_EDGE_FALLING: 417 break; 418 419 case IRQ_TYPE_LEVEL_HIGH: 420 levelsense = 1; 421 sense = 1; 422 break; 423 424 case IRQ_TYPE_LEVEL_LOW: 425 levelsense = 1; 426 break; 427 428 default: 429 printk(KERN_ERR "bogus flow type combination given !\n"); 430 return -EINVAL; 431 } 432 433 regaddr = get_ext_irq_perf_reg(irq); 434 reg = bcm_perf_readl(regaddr); 435 irq %= 4; 436 437 if (BCMCPU_IS_6348()) { 438 if (levelsense) 439 reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq); 440 else 441 reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq); 442 if (sense) 443 reg |= EXTIRQ_CFG_SENSE_6348(irq); 444 else 445 reg &= ~EXTIRQ_CFG_SENSE_6348(irq); 446 if (bothedge) 447 reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq); 448 else 449 reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq); 450 } 451 452 if (BCMCPU_IS_6338() || BCMCPU_IS_6358() || BCMCPU_IS_6368()) { 453 if (levelsense) 454 reg |= EXTIRQ_CFG_LEVELSENSE(irq); 455 else 456 reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); 457 if (sense) 458 reg |= EXTIRQ_CFG_SENSE(irq); 459 else 460 reg &= ~EXTIRQ_CFG_SENSE(irq); 461 if (bothedge) 462 reg |= EXTIRQ_CFG_BOTHEDGE(irq); 463 else 464 reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); 465 } 466 467 bcm_perf_writel(reg, regaddr); 468 469 irqd_set_trigger_type(d, flow_type); 470 if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) 471 __irq_set_handler_locked(d->irq, handle_level_irq); 472 else 473 __irq_set_handler_locked(d->irq, handle_edge_irq); 474 475 return IRQ_SET_MASK_OK_NOCOPY; 476} 477 478static struct irq_chip bcm63xx_internal_irq_chip = { 479 .name = "bcm63xx_ipic", 480 .irq_mask = bcm63xx_internal_irq_mask, 481 .irq_unmask = bcm63xx_internal_irq_unmask, 482}; 483 484static struct irq_chip bcm63xx_external_irq_chip = { 485 .name = "bcm63xx_epic", 486 .irq_ack = bcm63xx_external_irq_clear, 487 488 .irq_mask = bcm63xx_external_irq_mask, 489 .irq_unmask = bcm63xx_external_irq_unmask, 490 491 .irq_set_type = bcm63xx_external_irq_set_type, 492}; 493 494static struct irqaction cpu_ip2_cascade_action = { 495 .handler = no_action, 496 .name = "cascade_ip2", 497 .flags = IRQF_NO_THREAD, 498}; 499 500static struct irqaction cpu_ext_cascade_action = { 501 .handler = no_action, 502 .name = "cascade_extirq", 503 .flags = IRQF_NO_THREAD, 504}; 505 506void __init arch_init_irq(void) 507{ 508 int i; 509 510 bcm63xx_init_irq(); 511 mips_cpu_irq_init(); 512 for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i) 513 irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip, 514 handle_level_irq); 515 516 for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i) 517 irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip, 518 handle_edge_irq); 519 520 if (!is_ext_irq_cascaded) { 521 for (i = 3; i < 3 + ext_irq_count; ++i) 522 setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action); 523 } 524 525 setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action); 526}