mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
sparc32: Use PROM infrastructure for probing and mapping sun4d timers.
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
69c010b245
commit
f5f1085720
2 changed files with 85 additions and 71 deletions
|
@ -35,19 +35,6 @@ struct sun4c_timer_info {
|
|||
|
||||
#define SUN_TIMER_PHYSADDR 0xf3000000
|
||||
|
||||
#define SUN4D_PRM_CNT_L 0x80000000
|
||||
#define SUN4D_PRM_CNT_LVALUE 0x7FFFFC00
|
||||
|
||||
struct sun4d_timer_regs {
|
||||
volatile unsigned int l10_timer_limit;
|
||||
volatile unsigned int l10_cur_countx;
|
||||
volatile unsigned int l10_limit_noclear;
|
||||
volatile unsigned int ctrl;
|
||||
volatile unsigned int l10_cur_count;
|
||||
};
|
||||
|
||||
extern struct sun4d_timer_regs *sun4d_timers;
|
||||
|
||||
extern __volatile__ unsigned int *master_l10_counter;
|
||||
extern __volatile__ unsigned int *master_l10_limit;
|
||||
|
||||
|
|
|
@ -45,7 +45,16 @@
|
|||
/* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
|
||||
/* #define DISTRIBUTE_IRQS */
|
||||
|
||||
struct sun4d_timer_regs *sun4d_timers;
|
||||
struct sun4d_timer_regs {
|
||||
u32 l10_timer_limit;
|
||||
u32 l10_cur_countx;
|
||||
u32 l10_limit_noclear;
|
||||
u32 ctrl;
|
||||
u32 l10_cur_count;
|
||||
};
|
||||
|
||||
static struct sun4d_timer_regs __iomem *sun4d_timers;
|
||||
|
||||
#define TIMER_IRQ 10
|
||||
|
||||
#define MAX_STATIC_ALLOC 4
|
||||
|
@ -446,8 +455,7 @@ void __init sun4d_distribute_irqs(void)
|
|||
|
||||
static void sun4d_clear_clock_irq(void)
|
||||
{
|
||||
volatile unsigned int clear_intr;
|
||||
clear_intr = sun4d_timers->l10_timer_limit;
|
||||
sbus_readl(&sun4d_timers->l10_timer_limit);
|
||||
}
|
||||
|
||||
static void sun4d_clear_profile_irq(int cpu)
|
||||
|
@ -460,73 +468,92 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit)
|
|||
bw_set_prof_limit(cpu, limit);
|
||||
}
|
||||
|
||||
static void __init sun4d_init_timers(irq_handler_t counter_fn)
|
||||
static void __init sun4d_load_profile_irqs(void)
|
||||
{
|
||||
int irq;
|
||||
int cpu;
|
||||
struct resource r;
|
||||
int mid;
|
||||
int cpu = 0, mid;
|
||||
|
||||
/* Map the User Timer registers. */
|
||||
memset(&r, 0, sizeof(r));
|
||||
#ifdef CONFIG_SMP
|
||||
r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT;
|
||||
#else
|
||||
r.start = CSR_BASE(0)+BW_TIMER_LIMIT;
|
||||
#endif
|
||||
r.flags = 0xf;
|
||||
sun4d_timers = (struct sun4d_timer_regs *) of_ioremap(&r, 0,
|
||||
PAGE_SIZE, "user timer");
|
||||
|
||||
sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
|
||||
master_l10_counter = &sun4d_timers->l10_cur_count;
|
||||
master_l10_limit = &sun4d_timers->l10_timer_limit;
|
||||
|
||||
irq = request_irq(TIMER_IRQ,
|
||||
counter_fn,
|
||||
(IRQF_DISABLED | SA_STATIC_ALLOC),
|
||||
"timer", NULL);
|
||||
if (irq) {
|
||||
prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
/* Enable user timer free run for CPU 0 in BW */
|
||||
/* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
|
||||
|
||||
cpu = 0;
|
||||
while (!cpu_find_by_instance(cpu, NULL, &mid)) {
|
||||
sun4d_load_profile_irq(mid >> 3, 0);
|
||||
cpu++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void __init sun4d_fixup_trap_table(void)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
{
|
||||
unsigned long flags;
|
||||
extern unsigned long lvl14_save[4];
|
||||
struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
|
||||
extern unsigned int real_irq_entry[], smp4d_ticker[];
|
||||
extern unsigned int patchme_maybe_smp_msg[];
|
||||
unsigned long flags;
|
||||
extern unsigned long lvl14_save[4];
|
||||
struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
|
||||
extern unsigned int real_irq_entry[], smp4d_ticker[];
|
||||
extern unsigned int patchme_maybe_smp_msg[];
|
||||
|
||||
/* Adjust so that we jump directly to smp4d_ticker */
|
||||
lvl14_save[2] += smp4d_ticker - real_irq_entry;
|
||||
/* Adjust so that we jump directly to smp4d_ticker */
|
||||
lvl14_save[2] += smp4d_ticker - real_irq_entry;
|
||||
|
||||
/* For SMP we use the level 14 ticker, however the bootup code
|
||||
* has copied the firmware's level 14 vector into the boot cpu's
|
||||
* trap table, we must fix this now or we get squashed.
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
|
||||
trap_table->inst_one = lvl14_save[0];
|
||||
trap_table->inst_two = lvl14_save[1];
|
||||
trap_table->inst_three = lvl14_save[2];
|
||||
trap_table->inst_four = lvl14_save[3];
|
||||
local_flush_cache_all();
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
/* For SMP we use the level 14 ticker, however the bootup code
|
||||
* has copied the firmware's level 14 vector into the boot cpu's
|
||||
* trap table, we must fix this now or we get squashed.
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
|
||||
trap_table->inst_one = lvl14_save[0];
|
||||
trap_table->inst_two = lvl14_save[1];
|
||||
trap_table->inst_three = lvl14_save[2];
|
||||
trap_table->inst_four = lvl14_save[3];
|
||||
local_flush_cache_all();
|
||||
local_irq_restore(flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __init sun4d_init_timers(irq_handler_t counter_fn)
|
||||
{
|
||||
struct device_node *dp;
|
||||
struct resource res;
|
||||
const u32 *reg;
|
||||
int err;
|
||||
|
||||
dp = of_find_node_by_name(NULL, "cpu-unit");
|
||||
if (!dp) {
|
||||
prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
/* Which cpu-unit we use is arbitrary, we can view the bootbus timer
|
||||
* registers via any cpu's mapping. The first 'reg' property is the
|
||||
* bootbus.
|
||||
*/
|
||||
reg = of_get_property(dp, "reg", NULL);
|
||||
if (!reg) {
|
||||
prom_printf("sun4d_init_timers: No reg property\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
res.start = reg[1];
|
||||
res.end = reg[2] - 1;
|
||||
res.flags = reg[0] & 0xff;
|
||||
sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
|
||||
sizeof(struct sun4d_timer_regs), "user timer");
|
||||
if (!sun4d_timers) {
|
||||
prom_printf("sun4d_init_timers: Can't map timer regs\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
|
||||
|
||||
master_l10_counter = &sun4d_timers->l10_cur_count;
|
||||
master_l10_limit = &sun4d_timers->l10_timer_limit;
|
||||
|
||||
err = request_irq(TIMER_IRQ, counter_fn,
|
||||
(IRQF_DISABLED | SA_STATIC_ALLOC),
|
||||
"timer", NULL);
|
||||
if (err) {
|
||||
prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err);
|
||||
prom_halt();
|
||||
}
|
||||
sun4d_load_profile_irqs();
|
||||
sun4d_fixup_trap_table();
|
||||
}
|
||||
|
||||
void __init sun4d_init_sbi_irq(void)
|
||||
{
|
||||
struct device_node *dp;
|
||||
|
|
Loading…
Reference in a new issue