mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 13:11:40 +00:00
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/voyager-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/jejb/voyager-2.6: [VOYAGER] add smp alternatives [VOYAGER] Use modern techniques to setup and teardown low identiy mappings. [VOYAGER] Convert the monitor thread to use the kthread API [VOYAGER] clockevents driver: bring voyager in to line [VOYAGER] clockevents: correct boot cpu is zero assumption [VOYAGER] add smp_call_function_single
This commit is contained in:
commit
fabb5c4e4a
@ -110,7 +110,7 @@ void __init setup_pit_timer(void)
|
||||
* Start pit with the boot cpu mask and make it global after the
|
||||
* IO_APIC has been initialized.
|
||||
*/
|
||||
pit_clockevent.cpumask = cpumask_of_cpu(0);
|
||||
pit_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
|
||||
pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32);
|
||||
pit_clockevent.max_delta_ns =
|
||||
clockevent_delta2ns(0x7FFF, &pit_clockevent);
|
||||
|
@ -40,10 +40,16 @@ void __init trap_init_hook(void)
|
||||
{
|
||||
}
|
||||
|
||||
static struct irqaction irq0 = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL};
|
||||
static struct irqaction irq0 = {
|
||||
.handler = timer_interrupt,
|
||||
.flags = IRQF_DISABLED | IRQF_NOBALANCING,
|
||||
.mask = CPU_MASK_NONE,
|
||||
.name = "timer"
|
||||
};
|
||||
|
||||
void __init time_init_hook(void)
|
||||
{
|
||||
irq0.mask = cpumask_of_cpu(safe_smp_processor_id());
|
||||
setup_irq(0, &irq0);
|
||||
}
|
||||
|
||||
|
@ -1111,7 +1111,7 @@ voyager_cat_do_common_interrupt(void)
|
||||
printk(KERN_ERR "Voyager front panel switch turned off\n");
|
||||
voyager_status.switch_off = 1;
|
||||
voyager_status.request_from_kernel = 1;
|
||||
up(&kvoyagerd_sem);
|
||||
wake_up_process(voyager_thread);
|
||||
}
|
||||
/* Tell the hardware we're taking care of the
|
||||
* shutdown, otherwise it will power the box off
|
||||
@ -1157,7 +1157,7 @@ voyager_cat_do_common_interrupt(void)
|
||||
outb(VOYAGER_CAT_END, CAT_CMD);
|
||||
voyager_status.power_fail = 1;
|
||||
voyager_status.request_from_kernel = 1;
|
||||
up(&kvoyagerd_sem);
|
||||
wake_up_process(voyager_thread);
|
||||
}
|
||||
|
||||
|
||||
|
@ -536,15 +536,6 @@ do_boot_cpu(__u8 cpu)
|
||||
& ~( voyager_extended_vic_processors
|
||||
& voyager_allowed_boot_processors);
|
||||
|
||||
/* For the 486, we can't use the 4Mb page table trick, so
|
||||
* must map a region of memory */
|
||||
#ifdef CONFIG_M486
|
||||
int i;
|
||||
unsigned long *page_table_copies = (unsigned long *)
|
||||
__get_free_page(GFP_KERNEL);
|
||||
#endif
|
||||
pgd_t orig_swapper_pg_dir0;
|
||||
|
||||
/* This is an area in head.S which was used to set up the
|
||||
* initial kernel stack. We need to alter this to give the
|
||||
* booting CPU a new stack (taken from its idle process) */
|
||||
@ -573,6 +564,8 @@ do_boot_cpu(__u8 cpu)
|
||||
hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF;
|
||||
|
||||
cpucount++;
|
||||
alternatives_smp_switch(1);
|
||||
|
||||
idle = fork_idle(cpu);
|
||||
if(IS_ERR(idle))
|
||||
panic("failed fork for CPU%d", cpu);
|
||||
@ -595,24 +588,11 @@ do_boot_cpu(__u8 cpu)
|
||||
VDEBUG(("VOYAGER SMP: Booting CPU%d at 0x%lx[%x:%x], stack %p\n", cpu,
|
||||
(unsigned long)hijack_source.val, hijack_source.idt.Segment,
|
||||
hijack_source.idt.Offset, stack_start.esp));
|
||||
/* set the original swapper_pg_dir[0] to map 0 to 4Mb transparently
|
||||
* (so that the booting CPU can find start_32 */
|
||||
orig_swapper_pg_dir0 = swapper_pg_dir[0];
|
||||
#ifdef CONFIG_M486
|
||||
if(page_table_copies == NULL)
|
||||
panic("No free memory for 486 page tables\n");
|
||||
for(i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++)
|
||||
page_table_copies[i] = (i * PAGE_SIZE)
|
||||
| _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
|
||||
|
||||
((unsigned long *)swapper_pg_dir)[0] =
|
||||
((virt_to_phys(page_table_copies)) & PAGE_MASK)
|
||||
| _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
|
||||
#else
|
||||
((unsigned long *)swapper_pg_dir)[0] =
|
||||
(virt_to_phys(pg0) & PAGE_MASK)
|
||||
| _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
|
||||
#endif
|
||||
/* init lowmem identity mapping */
|
||||
clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
|
||||
min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
|
||||
flush_tlb_all();
|
||||
|
||||
if(quad_boot) {
|
||||
printk("CPU %d: non extended Quad boot\n", cpu);
|
||||
@ -655,11 +635,7 @@ do_boot_cpu(__u8 cpu)
|
||||
udelay(100);
|
||||
}
|
||||
/* reset the page table */
|
||||
swapper_pg_dir[0] = orig_swapper_pg_dir0;
|
||||
local_flush_tlb();
|
||||
#ifdef CONFIG_M486
|
||||
free_page((unsigned long)page_table_copies);
|
||||
#endif
|
||||
zap_low_mappings();
|
||||
|
||||
if (cpu_booted_map) {
|
||||
VDEBUG(("CPU%d: Booted successfully, back in CPU %d\n",
|
||||
@ -1082,20 +1058,11 @@ smp_call_function_interrupt(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Call this function on all CPUs using the function_interrupt above
|
||||
<func> The function to run. This must be fast and non-blocking.
|
||||
<info> An arbitrary pointer to pass to the function.
|
||||
<retry> If true, keep retrying until ready.
|
||||
<wait> If true, wait until function has completed on other CPUs.
|
||||
[RETURNS] 0 on success, else a negative status code. Does not return until
|
||||
remote CPUs are nearly ready to execute <<func>> or are or have executed.
|
||||
*/
|
||||
int
|
||||
smp_call_function (void (*func) (void *info), void *info, int retry,
|
||||
int wait)
|
||||
static int
|
||||
__smp_call_function_mask (void (*func) (void *info), void *info, int retry,
|
||||
int wait, __u32 mask)
|
||||
{
|
||||
struct call_data_struct data;
|
||||
__u32 mask = cpus_addr(cpu_online_map)[0];
|
||||
|
||||
mask &= ~(1<<smp_processor_id());
|
||||
|
||||
@ -1116,7 +1083,7 @@ smp_call_function (void (*func) (void *info), void *info, int retry,
|
||||
call_data = &data;
|
||||
wmb();
|
||||
/* Send a message to all other CPUs and wait for them to respond */
|
||||
send_CPI_allbutself(VIC_CALL_FUNCTION_CPI);
|
||||
send_CPI(mask, VIC_CALL_FUNCTION_CPI);
|
||||
|
||||
/* Wait for response */
|
||||
while (data.started)
|
||||
@ -1130,8 +1097,48 @@ smp_call_function (void (*func) (void *info), void *info, int retry,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Call this function on all CPUs using the function_interrupt above
|
||||
<func> The function to run. This must be fast and non-blocking.
|
||||
<info> An arbitrary pointer to pass to the function.
|
||||
<retry> If true, keep retrying until ready.
|
||||
<wait> If true, wait until function has completed on other CPUs.
|
||||
[RETURNS] 0 on success, else a negative status code. Does not return until
|
||||
remote CPUs are nearly ready to execute <<func>> or are or have executed.
|
||||
*/
|
||||
int
|
||||
smp_call_function(void (*func) (void *info), void *info, int retry,
|
||||
int wait)
|
||||
{
|
||||
__u32 mask = cpus_addr(cpu_online_map)[0];
|
||||
|
||||
return __smp_call_function_mask(func, info, retry, wait, mask);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_call_function);
|
||||
|
||||
/*
|
||||
* smp_call_function_single - Run a function on another CPU
|
||||
* @func: The function to run. This must be fast and non-blocking.
|
||||
* @info: An arbitrary pointer to pass to the function.
|
||||
* @nonatomic: Currently unused.
|
||||
* @wait: If true, wait until function has completed on other CPUs.
|
||||
*
|
||||
* Retrurns 0 on success, else a negative status code.
|
||||
*
|
||||
* Does not return until the remote CPU is nearly ready to execute <func>
|
||||
* or is or has executed.
|
||||
*/
|
||||
|
||||
int
|
||||
smp_call_function_single(int cpu, void (*func) (void *info), void *info,
|
||||
int nonatomic, int wait)
|
||||
{
|
||||
__u32 mask = 1 << cpu;
|
||||
|
||||
return __smp_call_function_mask(func, info, nonatomic, wait, mask);
|
||||
}
|
||||
EXPORT_SYMBOL(smp_call_function_single);
|
||||
|
||||
/* Sorry about the name. In an APIC based system, the APICs
|
||||
* themselves are programmed to send a timer interrupt. This is used
|
||||
* by linux to reschedule the processor. Voyager doesn't have this,
|
||||
|
@ -24,33 +24,16 @@
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/voyager.h>
|
||||
#include <asm/vic.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/msr.h>
|
||||
|
||||
#define THREAD_NAME "kvoyagerd"
|
||||
|
||||
/* external variables */
|
||||
int kvoyagerd_running = 0;
|
||||
DECLARE_MUTEX_LOCKED(kvoyagerd_sem);
|
||||
|
||||
static int thread(void *);
|
||||
|
||||
static __u8 set_timeout = 0;
|
||||
|
||||
/* Start the machine monitor thread. Return 1 if OK, 0 if fail */
|
||||
static int __init
|
||||
voyager_thread_start(void)
|
||||
{
|
||||
if(kernel_thread(thread, NULL, CLONE_KERNEL) < 0) {
|
||||
/* This is serious, but not fatal */
|
||||
printk(KERN_ERR "Voyager: Failed to create system monitor thread!!!\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
struct task_struct *voyager_thread;
|
||||
static __u8 set_timeout;
|
||||
|
||||
static int
|
||||
execute(const char *string)
|
||||
@ -110,31 +93,15 @@ check_continuing_condition(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wakeup(unsigned long unused)
|
||||
{
|
||||
up(&kvoyagerd_sem);
|
||||
}
|
||||
|
||||
static int
|
||||
thread(void *unused)
|
||||
{
|
||||
struct timer_list wakeup_timer;
|
||||
|
||||
kvoyagerd_running = 1;
|
||||
|
||||
daemonize(THREAD_NAME);
|
||||
|
||||
set_timeout = 0;
|
||||
|
||||
init_timer(&wakeup_timer);
|
||||
|
||||
sigfillset(¤t->blocked);
|
||||
|
||||
printk(KERN_NOTICE "Voyager starting monitor thread\n");
|
||||
|
||||
for(;;) {
|
||||
down_interruptible(&kvoyagerd_sem);
|
||||
for (;;) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(set_timeout ? HZ : MAX_SCHEDULE_TIMEOUT);
|
||||
|
||||
VDEBUG(("Voyager Daemon awoken\n"));
|
||||
if(voyager_status.request_from_kernel == 0) {
|
||||
/* probably awoken from timeout */
|
||||
@ -143,20 +110,26 @@ thread(void *unused)
|
||||
check_from_kernel();
|
||||
voyager_status.request_from_kernel = 0;
|
||||
}
|
||||
if(set_timeout) {
|
||||
del_timer(&wakeup_timer);
|
||||
wakeup_timer.expires = HZ + jiffies;
|
||||
wakeup_timer.function = wakeup;
|
||||
add_timer(&wakeup_timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int __init
|
||||
voyager_thread_start(void)
|
||||
{
|
||||
voyager_thread = kthread_run(thread, NULL, "kvoyagerd");
|
||||
if (IS_ERR(voyager_thread)) {
|
||||
printk(KERN_ERR "Voyager: Failed to create system monitor thread.\n");
|
||||
return PTR_ERR(voyager_thread);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void __exit
|
||||
voyager_thread_stop(void)
|
||||
{
|
||||
/* FIXME: do nothing at the moment */
|
||||
kthread_stop(voyager_thread);
|
||||
}
|
||||
|
||||
module_init(voyager_thread_start);
|
||||
//module_exit(voyager_thread_stop);
|
||||
module_exit(voyager_thread_stop);
|
||||
|
@ -487,15 +487,11 @@ extern struct voyager_qic_cpi *voyager_quad_cpi_addr[NR_CPUS];
|
||||
extern struct voyager_SUS *voyager_SUS;
|
||||
|
||||
/* variables exported always */
|
||||
extern struct task_struct *voyager_thread;
|
||||
extern int voyager_level;
|
||||
extern int kvoyagerd_running;
|
||||
extern struct semaphore kvoyagerd_sem;
|
||||
extern struct voyager_status voyager_status;
|
||||
|
||||
|
||||
|
||||
/* functions exported by the voyager and voyager_smp modules */
|
||||
|
||||
extern int voyager_cat_readb(__u8 module, __u8 asic, int reg);
|
||||
extern void voyager_cat_init(void);
|
||||
extern void voyager_detect(struct voyager_bios_info *);
|
||||
|
Loading…
Reference in New Issue
Block a user