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.8 538 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 4 60#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6345 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 ext_irq_count = 4; 147 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338; 148 break; 149 case BCM6345_CPU_ID: 150 irq_stat_addr += PERF_IRQSTAT_6345_REG; 151 irq_mask_addr += PERF_IRQMASK_6345_REG; 152 irq_bits = 32; 153 ext_irq_count = 4; 154 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345; 155 break; 156 case BCM6348_CPU_ID: 157 irq_stat_addr += PERF_IRQSTAT_6348_REG; 158 irq_mask_addr += PERF_IRQMASK_6348_REG; 159 irq_bits = 32; 160 ext_irq_count = 4; 161 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348; 162 break; 163 case BCM6358_CPU_ID: 164 irq_stat_addr += PERF_IRQSTAT_6358_REG; 165 irq_mask_addr += PERF_IRQMASK_6358_REG; 166 irq_bits = 32; 167 ext_irq_count = 4; 168 is_ext_irq_cascaded = 1; 169 ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE; 170 ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE; 171 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358; 172 break; 173 case BCM6368_CPU_ID: 174 irq_stat_addr += PERF_IRQSTAT_6368_REG; 175 irq_mask_addr += PERF_IRQMASK_6368_REG; 176 irq_bits = 64; 177 ext_irq_count = 6; 178 is_ext_irq_cascaded = 1; 179 ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE; 180 ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE; 181 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368; 182 ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368; 183 break; 184 default: 185 BUG(); 186 } 187 188 if (irq_bits == 32) { 189 dispatch_internal = __dispatch_internal; 190 internal_irq_mask = __internal_irq_mask_32; 191 internal_irq_unmask = __internal_irq_unmask_32; 192 } else { 193 dispatch_internal = __dispatch_internal_64; 194 internal_irq_mask = __internal_irq_mask_64; 195 internal_irq_unmask = __internal_irq_unmask_64; 196 } 197} 198#endif /* ! BCMCPU_RUNTIME_DETECT */ 199 200static inline u32 get_ext_irq_perf_reg(int irq) 201{ 202 if (irq < 4) 203 return ext_irq_cfg_reg1; 204 return ext_irq_cfg_reg2; 205} 206 207static inline void handle_internal(int intbit) 208{ 209 if (is_ext_irq_cascaded && 210 intbit >= ext_irq_start && intbit <= ext_irq_end) 211 do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE); 212 else 213 do_IRQ(intbit + IRQ_INTERNAL_BASE); 214} 215 216/* 217 * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not 218 * prioritize any interrupt relatively to another. the static counter 219 * will resume the loop where it ended the last time we left this 220 * function. 221 */ 222static void __dispatch_internal(void) 223{ 224 u32 pending; 225 static int i; 226 227 pending = bcm_readl(irq_stat_addr) & bcm_readl(irq_mask_addr); 228 229 if (!pending) 230 return ; 231 232 while (1) { 233 int to_call = i; 234 235 i = (i + 1) & 0x1f; 236 if (pending & (1 << to_call)) { 237 handle_internal(to_call); 238 break; 239 } 240 } 241} 242 243static void __dispatch_internal_64(void) 244{ 245 u64 pending; 246 static int i; 247 248 pending = bcm_readq(irq_stat_addr) & bcm_readq(irq_mask_addr); 249 250 if (!pending) 251 return ; 252 253 while (1) { 254 int to_call = i; 255 256 i = (i + 1) & 0x3f; 257 if (pending & (1ull << to_call)) { 258 handle_internal(to_call); 259 break; 260 } 261 } 262} 263 264asmlinkage void plat_irq_dispatch(void) 265{ 266 u32 cause; 267 268 do { 269 cause = read_c0_cause() & read_c0_status() & ST0_IM; 270 271 if (!cause) 272 break; 273 274 if (cause & CAUSEF_IP7) 275 do_IRQ(7); 276 if (cause & CAUSEF_IP2) 277 dispatch_internal(); 278 if (!is_ext_irq_cascaded) { 279 if (cause & CAUSEF_IP3) 280 do_IRQ(IRQ_EXT_0); 281 if (cause & CAUSEF_IP4) 282 do_IRQ(IRQ_EXT_1); 283 if (cause & CAUSEF_IP5) 284 do_IRQ(IRQ_EXT_2); 285 if (cause & CAUSEF_IP6) 286 do_IRQ(IRQ_EXT_3); 287 } 288 } while (1); 289} 290 291/* 292 * internal IRQs operations: only mask/unmask on PERF irq mask 293 * register. 294 */ 295static void __internal_irq_mask_32(unsigned int irq) 296{ 297 u32 mask; 298 299 mask = bcm_readl(irq_mask_addr); 300 mask &= ~(1 << irq); 301 bcm_writel(mask, irq_mask_addr); 302} 303 304static void __internal_irq_mask_64(unsigned int irq) 305{ 306 u64 mask; 307 308 mask = bcm_readq(irq_mask_addr); 309 mask &= ~(1ull << irq); 310 bcm_writeq(mask, irq_mask_addr); 311} 312 313static void __internal_irq_unmask_32(unsigned int irq) 314{ 315 u32 mask; 316 317 mask = bcm_readl(irq_mask_addr); 318 mask |= (1 << irq); 319 bcm_writel(mask, irq_mask_addr); 320} 321 322static void __internal_irq_unmask_64(unsigned int irq) 323{ 324 u64 mask; 325 326 mask = bcm_readq(irq_mask_addr); 327 mask |= (1ull << irq); 328 bcm_writeq(mask, irq_mask_addr); 329} 330 331static void bcm63xx_internal_irq_mask(struct irq_data *d) 332{ 333 internal_irq_mask(d->irq - IRQ_INTERNAL_BASE); 334} 335 336static void bcm63xx_internal_irq_unmask(struct irq_data *d) 337{ 338 internal_irq_unmask(d->irq - IRQ_INTERNAL_BASE); 339} 340 341/* 342 * external IRQs operations: mask/unmask and clear on PERF external 343 * irq control register. 344 */ 345static void bcm63xx_external_irq_mask(struct irq_data *d) 346{ 347 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 348 u32 reg, regaddr; 349 350 regaddr = get_ext_irq_perf_reg(irq); 351 reg = bcm_perf_readl(regaddr); 352 353 if (BCMCPU_IS_6348()) 354 reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4); 355 else 356 reg &= ~EXTIRQ_CFG_MASK(irq % 4); 357 358 bcm_perf_writel(reg, regaddr); 359 if (is_ext_irq_cascaded) 360 internal_irq_mask(irq + ext_irq_start); 361} 362 363static void bcm63xx_external_irq_unmask(struct irq_data *d) 364{ 365 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 366 u32 reg, regaddr; 367 368 regaddr = get_ext_irq_perf_reg(irq); 369 reg = bcm_perf_readl(regaddr); 370 371 if (BCMCPU_IS_6348()) 372 reg |= EXTIRQ_CFG_MASK_6348(irq % 4); 373 else 374 reg |= EXTIRQ_CFG_MASK(irq % 4); 375 376 bcm_perf_writel(reg, regaddr); 377 378 if (is_ext_irq_cascaded) 379 internal_irq_unmask(irq + ext_irq_start); 380} 381 382static void bcm63xx_external_irq_clear(struct irq_data *d) 383{ 384 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 385 u32 reg, regaddr; 386 387 regaddr = get_ext_irq_perf_reg(irq); 388 reg = bcm_perf_readl(regaddr); 389 390 if (BCMCPU_IS_6348()) 391 reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4); 392 else 393 reg |= EXTIRQ_CFG_CLEAR(irq % 4); 394 395 bcm_perf_writel(reg, regaddr); 396} 397 398static int bcm63xx_external_irq_set_type(struct irq_data *d, 399 unsigned int flow_type) 400{ 401 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 402 u32 reg, regaddr; 403 int levelsense, sense, bothedge; 404 405 flow_type &= IRQ_TYPE_SENSE_MASK; 406 407 if (flow_type == IRQ_TYPE_NONE) 408 flow_type = IRQ_TYPE_LEVEL_LOW; 409 410 levelsense = sense = bothedge = 0; 411 switch (flow_type) { 412 case IRQ_TYPE_EDGE_BOTH: 413 bothedge = 1; 414 break; 415 416 case IRQ_TYPE_EDGE_RISING: 417 sense = 1; 418 break; 419 420 case IRQ_TYPE_EDGE_FALLING: 421 break; 422 423 case IRQ_TYPE_LEVEL_HIGH: 424 levelsense = 1; 425 sense = 1; 426 break; 427 428 case IRQ_TYPE_LEVEL_LOW: 429 levelsense = 1; 430 break; 431 432 default: 433 printk(KERN_ERR "bogus flow type combination given !\n"); 434 return -EINVAL; 435 } 436 437 regaddr = get_ext_irq_perf_reg(irq); 438 reg = bcm_perf_readl(regaddr); 439 irq %= 4; 440 441 switch (bcm63xx_get_cpu_id()) { 442 case BCM6348_CPU_ID: 443 if (levelsense) 444 reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq); 445 else 446 reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq); 447 if (sense) 448 reg |= EXTIRQ_CFG_SENSE_6348(irq); 449 else 450 reg &= ~EXTIRQ_CFG_SENSE_6348(irq); 451 if (bothedge) 452 reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq); 453 else 454 reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq); 455 break; 456 457 case BCM6328_CPU_ID: 458 case BCM6338_CPU_ID: 459 case BCM6345_CPU_ID: 460 case BCM6358_CPU_ID: 461 case BCM6368_CPU_ID: 462 if (levelsense) 463 reg |= EXTIRQ_CFG_LEVELSENSE(irq); 464 else 465 reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); 466 if (sense) 467 reg |= EXTIRQ_CFG_SENSE(irq); 468 else 469 reg &= ~EXTIRQ_CFG_SENSE(irq); 470 if (bothedge) 471 reg |= EXTIRQ_CFG_BOTHEDGE(irq); 472 else 473 reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); 474 break; 475 default: 476 BUG(); 477 } 478 479 bcm_perf_writel(reg, regaddr); 480 481 irqd_set_trigger_type(d, flow_type); 482 if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) 483 __irq_set_handler_locked(d->irq, handle_level_irq); 484 else 485 __irq_set_handler_locked(d->irq, handle_edge_irq); 486 487 return IRQ_SET_MASK_OK_NOCOPY; 488} 489 490static struct irq_chip bcm63xx_internal_irq_chip = { 491 .name = "bcm63xx_ipic", 492 .irq_mask = bcm63xx_internal_irq_mask, 493 .irq_unmask = bcm63xx_internal_irq_unmask, 494}; 495 496static struct irq_chip bcm63xx_external_irq_chip = { 497 .name = "bcm63xx_epic", 498 .irq_ack = bcm63xx_external_irq_clear, 499 500 .irq_mask = bcm63xx_external_irq_mask, 501 .irq_unmask = bcm63xx_external_irq_unmask, 502 503 .irq_set_type = bcm63xx_external_irq_set_type, 504}; 505 506static struct irqaction cpu_ip2_cascade_action = { 507 .handler = no_action, 508 .name = "cascade_ip2", 509 .flags = IRQF_NO_THREAD, 510}; 511 512static struct irqaction cpu_ext_cascade_action = { 513 .handler = no_action, 514 .name = "cascade_extirq", 515 .flags = IRQF_NO_THREAD, 516}; 517 518void __init arch_init_irq(void) 519{ 520 int i; 521 522 bcm63xx_init_irq(); 523 mips_cpu_irq_init(); 524 for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i) 525 irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip, 526 handle_level_irq); 527 528 for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i) 529 irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip, 530 handle_edge_irq); 531 532 if (!is_ext_irq_cascaded) { 533 for (i = 3; i < 3 + ext_irq_count; ++i) 534 setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action); 535 } 536 537 setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action); 538}