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

[MIPS] time: SMP-proofing of Sibyte clockevent/clocksource code.

The BCM148 has 4 cores but there are also just 4 generic timers available
so use the ZBbus cycle counter instead of it. In addition the ZBbus
counter also offers a much higher resolution and 64-bit counting so I'm
considering a later complete conversion to it once I figure out if all
members of the Sibyte SOC family support it - the docs seem to agree but
the headers files seem to disagree ...

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

+158 -167
+41 -34
arch/mips/sibyte/bcm1480/irq.c
··· 452 452 453 453 extern void bcm1480_mailbox_interrupt(void); 454 454 455 + static inline void dispatch_ip4(void) 456 + { 457 + int cpu = smp_processor_id(); 458 + int irq = K_BCM1480_INT_TIMER_0 + cpu; 459 + 460 + /* Reset the timer */ 461 + __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, 462 + IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); 463 + 464 + do_IRQ(irq); 465 + } 466 + 467 + static inline void dispatch_ip2(void) 468 + { 469 + unsigned long long mask_h, mask_l; 470 + unsigned int cpu = smp_processor_id(); 471 + unsigned long base; 472 + 473 + /* 474 + * Default...we've hit an IP[2] interrupt, which means we've got to 475 + * check the 1480 interrupt registers to figure out what to do. Need 476 + * to detect which CPU we're on, now that smp_affinity is supported. 477 + */ 478 + base = A_BCM1480_IMR_MAPPER(cpu); 479 + mask_h = __raw_readq( 480 + IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H)); 481 + mask_l = __raw_readq( 482 + IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L)); 483 + 484 + if (mask_h) { 485 + if (mask_h ^ 1) 486 + do_IRQ(fls64(mask_h) - 1); 487 + else if (mask_l) 488 + do_IRQ(63 + fls64(mask_l)); 489 + } 490 + } 491 + 455 492 asmlinkage void plat_irq_dispatch(void) 456 493 { 457 494 unsigned int pending; ··· 506 469 else 507 470 #endif 508 471 509 - if (pending & CAUSEF_IP4) { 510 - int cpu = smp_processor_id(); 511 - int irq = K_BCM1480_INT_TIMER_0 + cpu; 512 - 513 - /* Reset the timer */ 514 - __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, 515 - IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); 516 - 517 - do_IRQ(irq); 518 - } 519 - 472 + if (pending & CAUSEF_IP4) 473 + dispatch_ip4(); 520 474 #ifdef CONFIG_SMP 521 475 else if (pending & CAUSEF_IP3) 522 476 bcm1480_mailbox_interrupt(); ··· 518 490 bcm1480_kgdb_interrupt(); /* KGDB (uart 1) */ 519 491 #endif 520 492 521 - else if (pending & CAUSEF_IP2) { 522 - unsigned long long mask_h, mask_l; 523 - unsigned long base; 524 - 525 - /* 526 - * Default...we've hit an IP[2] interrupt, which means we've 527 - * got to check the 1480 interrupt registers to figure out what 528 - * to do. Need to detect which CPU we're on, now that 529 - * smp_affinity is supported. 530 - */ 531 - base = A_BCM1480_IMR_MAPPER(smp_processor_id()); 532 - mask_h = __raw_readq( 533 - IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H)); 534 - mask_l = __raw_readq( 535 - IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L)); 536 - 537 - if (mask_h) { 538 - if (mask_h ^ 1) 539 - do_IRQ(fls64(mask_h) - 1); 540 - else 541 - do_IRQ(63 + fls64(mask_l)); 542 - } 543 - } 493 + else if (pending & CAUSEF_IP2) 494 + dispatch_ip2(); 544 495 }
+2 -2
arch/mips/sibyte/bcm1480/smp.c
··· 58 58 /* 59 59 * SMP init and finish on secondary CPUs 60 60 */ 61 - void bcm1480_smp_init(void) 61 + void __cpuinit bcm1480_smp_init(void) 62 62 { 63 63 unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | 64 64 STATUSF_IP1 | STATUSF_IP0; ··· 67 67 change_c0_status(ST0_IM, imask); 68 68 } 69 69 70 - void bcm1480_smp_finish(void) 70 + void __cpuinit bcm1480_smp_finish(void) 71 71 { 72 72 extern void sb1480_clockevent_init(void); 73 73
+50 -67
arch/mips/sibyte/bcm1480/time.c
··· 15 15 * along with this program; if not, write to the Free Software 16 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 17 */ 18 - 19 - /* 20 - * These are routines to set up and handle interrupts from the 21 - * bcm1480 general purpose timer 0. We're using the timer as a 22 - * system clock, so we set it up to run at 100 Hz. On every 23 - * interrupt, we update our idea of what the time of day is, 24 - * then call do_timer() in the architecture-independent kernel 25 - * code to do general bookkeeping (e.g. update jiffies, run 26 - * bottom halves, etc.) 27 - */ 28 18 #include <linux/clockchips.h> 29 19 #include <linux/interrupt.h> 20 + #include <linux/irq.h> 30 21 #include <linux/percpu.h> 31 22 #include <linux/spinlock.h> 32 23 33 - #include <asm/irq.h> 34 24 #include <asm/addrspace.h> 35 25 #include <asm/time.h> 36 26 #include <asm/io.h> ··· 37 47 #define IMR_IP3_VAL K_BCM1480_INT_MAP_I1 38 48 #define IMR_IP4_VAL K_BCM1480_INT_MAP_I2 39 49 40 - #ifdef CONFIG_SIMULATION 41 - #define BCM1480_HPT_VALUE 50000 42 - #else 43 - #define BCM1480_HPT_VALUE 1000000 44 - #endif 45 - 46 50 extern int bcm1480_steal_irq(int irq); 47 51 48 - void __init plat_time_init(void) 49 - { 50 - unsigned int cpu = smp_processor_id(); 51 - unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu; 52 - 53 - BUG_ON(cpu > 3); /* Only have 4 general purpose timers */ 54 - 55 - bcm1480_mask_irq(cpu, irq); 56 - 57 - /* Map the timer interrupt to ip[4] of this cpu */ 58 - __raw_writeq(IMR_IP4_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) 59 - + (irq<<3))); 60 - 61 - bcm1480_unmask_irq(cpu, irq); 62 - bcm1480_steal_irq(irq); 63 - } 64 - 65 52 /* 66 - * The general purpose timer ticks at 1 Mhz independent if 53 + * The general purpose timer ticks at 1MHz independent if 67 54 * the rest of the system 68 55 */ 69 56 static void sibyte_set_mode(enum clock_event_mode mode, ··· 55 88 switch (mode) { 56 89 case CLOCK_EVT_MODE_PERIODIC: 57 90 __raw_writeq(0, timer_cfg); 58 - __raw_writeq(BCM1480_HPT_VALUE / HZ - 1, timer_init); 91 + __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, timer_init); 59 92 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, 60 93 timer_cfg); 61 94 break; ··· 88 121 return res; 89 122 } 90 123 91 - static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent); 92 - 93 124 static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) 94 125 { 95 126 unsigned int cpu = smp_processor_id(); 96 - struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); 127 + struct clock_event_device *cd = dev_id; 128 + void __iomem *timer_cfg; 129 + 130 + timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); 97 131 98 132 /* Reset the timer */ 99 133 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, 100 - IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); 134 + timer_cfg); 101 135 cd->event_handler(cd); 102 136 103 137 return IRQ_HANDLED; 104 138 } 105 139 106 - static struct irqaction sibyte_counter_irqaction = { 107 - .handler = sibyte_counter_handler, 108 - .flags = IRQF_DISABLED | IRQF_PERCPU, 109 - .name = "timer", 110 - }; 140 + static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent); 141 + static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction); 142 + static DEFINE_PER_CPU(char [18], sibyte_hpt_name); 111 143 112 - /* 113 - * This interrupt is "special" in that it doesn't use the request_irq 114 - * way to hook the irq line. The timer interrupt is initialized early 115 - * enough to make this a major pain, and it's also firing enough to 116 - * warrant a bit of special case code. bcm1480_timer_interrupt is 117 - * called directly from irq_handler.S when IP[4] is set during an 118 - * interrupt 119 - */ 120 144 void __cpuinit sb1480_clockevent_init(void) 121 145 { 122 146 unsigned int cpu = smp_processor_id(); 123 147 unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu; 148 + struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu); 124 149 struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); 150 + unsigned char *name = per_cpu(sibyte_hpt_name, cpu); 125 151 126 - cd->name = "bcm1480-counter"; 152 + BUG_ON(cpu > 3); /* Only have 4 general purpose timers */ 153 + 154 + sprintf(name, "bcm1480-counter %d", cpu); 155 + cd->name = name; 127 156 cd->features = CLOCK_EVT_FEAT_PERIODIC | 128 157 CLOCK_EVT_MODE_ONESHOT; 158 + clockevent_set_clock(cd, V_SCD_TIMER_FREQ); 159 + cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd); 160 + cd->min_delta_ns = clockevent_delta2ns(1, cd); 161 + cd->rating = 200; 162 + cd->irq = irq; 163 + cd->cpumask = cpumask_of_cpu(cpu); 129 164 cd->set_next_event = sibyte_next_event; 130 165 cd->set_mode = sibyte_set_mode; 131 - cd->irq = irq; 132 - clockevent_set_clock(cd, BCM1480_HPT_VALUE); 166 + clockevents_register_device(cd); 133 167 134 - setup_irq(irq, &sibyte_counter_irqaction); 168 + bcm1480_mask_irq(cpu, irq); 169 + 170 + /* 171 + * Map timer interrupt to IP[4] of this cpu 172 + */ 173 + __raw_writeq(IMR_IP4_VAL, 174 + IOADDR(A_BCM1480_IMR_REGISTER(cpu, 175 + R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + (irq << 3))); 176 + 177 + bcm1480_unmask_irq(cpu, irq); 178 + bcm1480_steal_irq(irq); 179 + 180 + action->handler = sibyte_counter_handler; 181 + action->flags = IRQF_DISABLED | IRQF_PERCPU; 182 + action->name = name; 183 + action->dev_id = cd; 184 + setup_irq(irq, action); 135 185 } 136 186 137 187 static cycle_t bcm1480_hpt_read(void) 138 188 { 139 - /* We assume this function is called xtime_lock held. */ 140 - unsigned long count = 141 - __raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT))); 142 - return (jiffies + 1) * (BCM1480_HPT_VALUE / HZ) - count; 189 + return (cycle_t) __raw_readq(IOADDR(A_SCD_ZBBUS_CYCLE_COUNT)); 143 190 } 144 191 145 192 struct clocksource bcm1480_clocksource = { 146 - .name = "MIPS", 193 + .name = "zbbus-cycles", 147 194 .rating = 200, 148 195 .read = bcm1480_hpt_read, 149 - .mask = CLOCKSOURCE_MASK(32), 150 - .shift = 32, 196 + .mask = CLOCKSOURCE_MASK(64), 151 197 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 152 198 }; 153 199 154 200 void __init sb1480_clocksource_init(void) 155 201 { 156 202 struct clocksource *cs = &bcm1480_clocksource; 203 + unsigned int plldiv; 204 + unsigned long zbbus; 157 205 158 - clocksource_set_clock(cs, BCM1480_HPT_VALUE); 206 + plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG))); 207 + zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000); 208 + clocksource_set_clock(cs, zbbus); 159 209 clocksource_register(cs); 160 210 } 161 211 162 - void __init bcm1480_hpt_setup(void) 212 + void __init plat_time_init(void) 163 213 { 164 - mips_hpt_frequency = BCM1480_HPT_VALUE; 165 214 sb1480_clocksource_init(); 166 215 sb1480_clockevent_init(); 167 216 }
+19 -16
arch/mips/sibyte/sb1250/irq.c
··· 402 402 403 403 extern void sb1250_mailbox_interrupt(void); 404 404 405 + static inline void dispatch_ip2(void) 406 + { 407 + unsigned int cpu = smp_processor_id(); 408 + unsigned long long mask; 409 + 410 + /* 411 + * Default...we've hit an IP[2] interrupt, which means we've got to 412 + * check the 1250 interrupt registers to figure out what to do. Need 413 + * to detect which CPU we're on, now that smp_affinity is supported. 414 + */ 415 + mask = __raw_readq(IOADDR(A_IMR_REGISTER(cpu, 416 + R_IMR_INTERRUPT_STATUS_BASE))); 417 + if (mask) 418 + do_IRQ(fls64(mask) - 1); 419 + } 420 + 405 421 asmlinkage void plat_irq_dispatch(void) 406 422 { 407 423 unsigned int cpu = smp_processor_id(); ··· 450 434 sb1250_kgdb_interrupt(); 451 435 #endif 452 436 453 - else if (pending & CAUSEF_IP2) { 454 - unsigned long long mask; 455 - 456 - /* 457 - * Default...we've hit an IP[2] interrupt, which means we've 458 - * got to check the 1250 interrupt registers to figure out what 459 - * to do. Need to detect which CPU we're on, now that 460 - * smp_affinity is supported. 461 - */ 462 - mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(), 463 - R_IMR_INTERRUPT_STATUS_BASE))); 464 - if (mask) 465 - do_IRQ(fls64(mask) - 1); 466 - else 467 - spurious_interrupt(); 468 - } else 437 + else if (pending & CAUSEF_IP2) 438 + dispatch_ip2(); 439 + else 469 440 spurious_interrupt(); 470 441 }
+2 -2
arch/mips/sibyte/sb1250/smp.c
··· 46 46 /* 47 47 * SMP init and finish on secondary CPUs 48 48 */ 49 - void sb1250_smp_init(void) 49 + void __cpuinit sb1250_smp_init(void) 50 50 { 51 51 unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | 52 52 STATUSF_IP1 | STATUSF_IP0; ··· 55 55 change_c0_status(ST0_IM, imask); 56 56 } 57 57 58 - void sb1250_smp_finish(void) 58 + void __cpuinit sb1250_smp_finish(void) 59 59 { 60 60 extern void sb1250_clockevent_init(void); 61 61
+44 -44
arch/mips/sibyte/sb1250/time.c
··· 52 52 53 53 extern int sb1250_steal_irq(int irq); 54 54 55 - static cycle_t sb1250_hpt_read(void); 56 - 57 - void __init sb1250_hpt_setup(void) 58 - { 59 - int cpu = smp_processor_id(); 60 - 61 - if (!cpu) { 62 - /* Setup hpt using timer #3 but do not enable irq for it */ 63 - __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); 64 - __raw_writeq(SB1250_HPT_VALUE, 65 - IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_INIT))); 66 - __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, 67 - IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); 68 - 69 - mips_hpt_frequency = V_SCD_TIMER_FREQ; 70 - clocksource_mips.read = sb1250_hpt_read; 71 - clocksource_mips.mask = M_SCD_TIMER_INIT; 72 - } 73 - } 74 - 75 55 /* 76 56 * The general purpose timer ticks at 1 Mhz independent if 77 57 * the rest of the system ··· 101 121 return 0; 102 122 } 103 123 104 - struct clock_event_device sibyte_hpt_clockevent = { 105 - .name = "sb1250-counter", 106 - .features = CLOCK_EVT_FEAT_PERIODIC, 107 - .set_mode = sibyte_set_mode, 108 - .set_next_event = sibyte_next_event, 109 - .shift = 32, 110 - .irq = 0, 111 - }; 112 - 113 124 static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) 114 125 { 115 - struct clock_event_device *cd = &sibyte_hpt_clockevent; 126 + unsigned int cpu = smp_processor_id(); 127 + struct clock_event_device *cd = dev_id; 128 + 129 + /* ACK interrupt */ 130 + ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, 131 + IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); 116 132 117 133 cd->event_handler(cd); 118 134 ··· 121 145 .name = "timer", 122 146 }; 123 147 148 + static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent); 149 + static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction); 150 + static DEFINE_PER_CPU(char [18], sibyte_hpt_name); 151 + 124 152 void __cpuinit sb1250_clockevent_init(void) 125 153 { 126 - struct clock_event_device *cd = &sibyte_hpt_clockevent; 127 154 unsigned int cpu = smp_processor_id(); 128 - int irq = K_INT_TIMER_0 + cpu; 155 + unsigned int irq = K_INT_TIMER_0 + cpu; 156 + struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu); 157 + struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); 158 + unsigned char *name = per_cpu(sibyte_hpt_name, cpu); 129 159 130 160 /* Only have 4 general purpose timers, and we use last one as hpt */ 131 161 BUG_ON(cpu > 2); 162 + 163 + sprintf(name, "bcm1480-counter %d", cpu); 164 + cd->name = name; 165 + cd->features = CLOCK_EVT_FEAT_PERIODIC | 166 + CLOCK_EVT_MODE_ONESHOT; 167 + clockevent_set_clock(cd, V_SCD_TIMER_FREQ); 168 + cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd); 169 + cd->min_delta_ns = clockevent_delta2ns(1, cd); 170 + cd->rating = 200; 171 + cd->irq = irq; 172 + cd->cpumask = cpumask_of_cpu(cpu); 173 + cd->set_next_event = sibyte_next_event; 174 + cd->set_mode = sibyte_set_mode; 175 + clockevents_register_device(cd); 132 176 133 177 sb1250_mask_irq(cpu, irq); 134 178 ··· 161 165 sb1250_unmask_irq(cpu, irq); 162 166 sb1250_steal_irq(irq); 163 167 164 - /* 165 - * This interrupt is "special" in that it doesn't use the request_irq 166 - * way to hook the irq line. The timer interrupt is initialized early 167 - * enough to make this a major pain, and it's also firing enough to 168 - * warrant a bit of special case code. sb1250_timer_interrupt is 169 - * called directly from irq_handler.S when IP[4] is set during an 170 - * interrupt 171 - */ 168 + action->handler = sibyte_counter_handler; 169 + action->flags = IRQF_DISABLED | IRQF_PERCPU; 170 + action->name = name; 171 + action->dev_id = cd; 172 172 setup_irq(irq, &sibyte_irqaction); 173 - 174 - clockevents_register_device(cd); 175 173 } 176 174 177 175 /* ··· 185 195 .name = "MIPS", 186 196 .rating = 200, 187 197 .read = sb1250_hpt_read, 188 - .mask = CLOCKSOURCE_MASK(32), 189 - .shift = 32, 198 + .mask = CLOCKSOURCE_MASK(23), 190 199 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 191 200 }; 192 201 193 202 void __init sb1250_clocksource_init(void) 194 203 { 195 204 struct clocksource *cs = &bcm1250_clocksource; 205 + 206 + /* Setup hpt using timer #3 but do not enable irq for it */ 207 + __raw_writeq(0, 208 + IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, 209 + R_SCD_TIMER_CFG))); 210 + __raw_writeq(SB1250_HPT_VALUE, 211 + IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, 212 + R_SCD_TIMER_INIT))); 213 + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, 214 + IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, 215 + R_SCD_TIMER_CFG))); 196 216 197 217 clocksource_set_clock(cs, V_SCD_TIMER_FREQ); 198 218 clocksource_register(cs);
-2
include/asm-mips/sibyte/sb1250.h
··· 45 45 extern unsigned int periph_rev; 46 46 extern unsigned int zbbus_mhz; 47 47 48 - extern void sb1250_hpt_setup(void); 49 48 extern void sb1250_time_init(void); 50 49 extern void sb1250_mask_irq(int cpu, int irq); 51 50 extern void sb1250_unmask_irq(int cpu, int irq); 52 51 extern void sb1250_smp_finish(void); 53 52 54 - extern void bcm1480_hpt_setup(void); 55 53 extern void bcm1480_time_init(void); 56 54 extern void bcm1480_mask_irq(int cpu, int irq); 57 55 extern void bcm1480_unmask_irq(int cpu, int irq);