From 52c72abcb3c99eb241e6b9fe541cc3242d1f69f3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 18 Aug 2003 23:00:15 -0700 Subject: [SPARC64]: Kill prom_cpu_nodes, unused. --- include/asm-sparc64/smp.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h index faf98d375f2a..96c409a7cc5f 100644 --- a/include/asm-sparc64/smp.h +++ b/include/asm-sparc64/smp.h @@ -28,7 +28,6 @@ struct prom_cpuinfo { extern int linux_num_cpus; /* number of CPUs probed */ extern struct prom_cpuinfo linux_cpus[NR_CPUS]; -extern unsigned int prom_cpu_nodes[NR_CPUS]; #endif /* !(__ASSEMBLY__) */ -- cgit v1.2.3 From 3881024fd1f05a92ea59cad0354b3f5dced2bf21 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 19 Aug 2003 02:01:19 -0700 Subject: [SPARC64]: Kill linux_cpus[]/linux_num_cpus, replace with cpu probe helpers. --- arch/sparc64/kernel/devices.c | 144 ++++++++++++++++++++++++++-------------- arch/sparc64/kernel/pci_sabre.c | 4 +- arch/sparc64/kernel/setup.c | 2 +- arch/sparc64/kernel/smp.c | 44 ++++++------ arch/sparc64/kernel/time.c | 2 +- arch/sparc64/kernel/traps.c | 31 +++++---- include/asm-sparc64/oplib.h | 4 ++ include/asm-sparc64/smp.h | 12 ---- 8 files changed, 142 insertions(+), 101 deletions(-) (limited to 'include') diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 4d10c04c935f..3678721d9275 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -24,68 +25,113 @@ */ spinlock_t ns87303_lock = SPIN_LOCK_UNLOCKED; -struct prom_cpuinfo linux_cpus[NR_CPUS] __initdata = { { 0 } }; -int linux_num_cpus = 0; - extern void cpu_probe(void); extern void central_probe(void); -void __init device_scan(void) +static char *cpu_mid_prop(void) +{ + if (tlb_type == spitfire) + return "upa-portid"; + return "portid"; +} + +static int check_cpu_node(int nd, int *cur_inst, + int (*compare)(int, int, void *), void *compare_arg, + int *prom_node, int *mid) { char node_str[128]; - int nd, prom_node_cpu, thismid; - int cpu_nds[64]; /* One node for each cpu */ - int cpu_ctr = 0; + prom_getstring(nd, "device_type", node_str, sizeof(node_str)); + if (strcmp(node_str, "cpu")) + return -ENODEV; + + if (!compare(nd, *cur_inst, compare_arg)) { + if (prom_node) + *prom_node = nd; + if (mid) + *mid = prom_getintdefault(nd, cpu_mid_prop(), 0); + return 0; + } + + (*cur_inst)++; + + return -ENODEV; +} + +static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg, + int *prom_node, int *mid) +{ + int nd, cur_inst, err; + + nd = prom_root_node; + cur_inst = 0; + + err = check_cpu_node(nd, &cur_inst, + compare, compare_arg, + prom_node, mid); + if (err == 0) + return 0; + + nd = prom_getchild(nd); + while ((nd = prom_getsibling(nd)) != 0) { + err = check_cpu_node(nd, &cur_inst, + compare, compare_arg, + prom_node, mid); + if (err == 0) + return 0; + } + + return -ENODEV; +} + +static int cpu_instance_compare(int nd, int instance, void *_arg) +{ + int desired_instance = (int) (long) _arg; + + if (instance == desired_instance) + return 0; + return -ENODEV; +} + +int cpu_find_by_instance(int instance, int *prom_node, int *mid) +{ + return __cpu_find_by(cpu_instance_compare, (void *)(long)instance, + prom_node, mid); +} + +static int cpu_mid_compare(int nd, int instance, void *_arg) +{ + int desired_mid = (int) (long) _arg; + int this_mid; + + this_mid = prom_getintdefault(nd, cpu_mid_prop(), 0); + if (this_mid == desired_mid) + return 0; + return -ENODEV; +} + +int cpu_find_by_mid(int mid, int *prom_node) +{ + return __cpu_find_by(cpu_mid_compare, (void *)(long)mid, + prom_node, NULL); +} + +void __init device_scan(void) +{ /* FIX ME FAST... -DaveM */ ioport_resource.end = 0xffffffffffffffffUL; - prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str)); - prom_printf("Booting Linux...\n"); - if(strcmp(node_str, "cpu") == 0) { - cpu_nds[0] = prom_root_node; - linux_cpus[0].prom_node = prom_root_node; - linux_cpus[0].mid = 0; - cpu_ctr++; - } else { - int scan; - scan = prom_getchild(prom_root_node); - /* prom_printf("root child is %08x\n", (unsigned) scan); */ - nd = 0; - while((scan = prom_getsibling(scan)) != 0) { - prom_getstring(scan, "device_type", node_str, sizeof(node_str)); - if(strcmp(node_str, "cpu") == 0) { - cpu_nds[cpu_ctr] = scan; - linux_cpus[cpu_ctr].prom_node = scan; - thismid = 0; - if (tlb_type == spitfire) { - prom_getproperty(scan, "upa-portid", - (char *) &thismid, sizeof(thismid)); - } else if (tlb_type == cheetah || - tlb_type == cheetah_plus) { - prom_getproperty(scan, "portid", - (char *) &thismid, sizeof(thismid)); - } - linux_cpus[cpu_ctr].mid = thismid; - printk("Found CPU %d (node=%08x,mid=%d)\n", - cpu_ctr, (unsigned) scan, thismid); - cpu_ctr++; - } - }; - if(cpu_ctr == 0) { - prom_printf("No CPU nodes found, cannot continue.\n"); - prom_halt(); - } - printk("Found %d CPU prom device tree node(s).\n", cpu_ctr); - } - prom_node_cpu = cpu_nds[0]; - linux_num_cpus = cpu_ctr; - #ifndef CONFIG_SMP { - up_clock_tick = prom_getintdefault(prom_node_cpu, + int err, cpu_node; + err = cpu_find_by_instance(0, &cpu_node, NULL); + if (err) { + prom_printf("No cpu nodes, cannot continue\n"); + prom_halt(); + } + up_clock_tick = prom_getintdefault(cpu_node, "clock-frequency", 0); } diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 07e79c66163f..54979a96493c 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "pci_impl.h" #include "iommu_common.h" @@ -1518,11 +1519,12 @@ void __init sabre_init(int pnode, char *model_name) !strcmp(compat, "pci108e,a001")) { hummingbird_p = 1; } else { - int cpu_node = linux_cpus[0].prom_node; + int cpu_node; /* Of course, Sun has to encode things a thousand * different ways, inconsistently. */ + cpu_find_by_instance(0, &cpu_node, NULL); if (prom_getproperty(cpu_node, "name", compat, sizeof(compat)) > 0 && !strcmp(compat, "SUNW,UltraSPARC-IIe")) diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 113be02dfd2c..67791a6a58bd 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -618,7 +618,7 @@ static int show_cpuinfo(struct seq_file *m, void *__unused) prom_prev >> 16, (prom_prev >> 8) & 0xff, prom_prev & 0xff, - (long)linux_num_cpus, + (long)num_possible_cpus(), (long)num_online_cpus() #ifndef CONFIG_SMP , loops_per_jiffy/(500000/HZ), diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 4bae4f2cb19f..dfb200bb2269 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -80,17 +80,14 @@ void smp_bogo(struct seq_file *m) void __init smp_store_cpu_info(int id) { - int i, no; + int i, cpu_node; /* multiplier and counter set by smp_setup_percpu_timer() */ cpu_data[id].udelay_val = loops_per_jiffy; - for (no = 0; no < linux_num_cpus; no++) - if (linux_cpus[no].mid == id) - break; - - cpu_data[id].clock_tick = prom_getintdefault(linux_cpus[no].prom_node, + cpu_find_by_mid(id, &cpu_node); + cpu_data[id].clock_tick = prom_getintdefault(cpu_node, "clock-frequency", 0); cpu_data[id].pgcache_size = 0; @@ -297,8 +294,6 @@ static void smp_synchronize_one_tick(int cpu) spin_unlock_irqrestore(&itc_sync_lock, flags); } -extern struct prom_cpuinfo linux_cpus[NR_CPUS]; - extern unsigned long sparc64_cpu_startup; /* The OBP cpu startup callback truncates the 3rd arg cookie to @@ -314,7 +309,7 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu) unsigned long cookie = (unsigned long)(&cpu_new_thread); struct task_struct *p; - int timeout, no, ret; + int timeout, ret, cpu_node; kernel_thread(NULL, NULL, CLONE_IDLETASK); @@ -325,12 +320,12 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu) unhash_process(p); callin_flag = 0; - for (no = 0; no < linux_num_cpus; no++) - if (linux_cpus[no].mid == cpu) - break; cpu_new_thread = p->thread_info; cpu_set(cpu, cpu_callout_map); - prom_startcpu(linux_cpus[no].prom_node, entry, cookie); + + cpu_find_by_mid(cpu, &cpu_node); + prom_startcpu(cpu_node, entry, cookie); + for (timeout = 0; timeout < 5000000; timeout++) { if (callin_flag) break; @@ -1150,6 +1145,7 @@ static void __init smp_tune_scheduling(void) unsigned long orig_flush_base, flush_base, flags, *p; unsigned int ecache_size, order; cycles_t tick1, tick2, raw; + int cpu_node; /* Approximate heuristic for SMP scheduling. It is an * estimation of the time it takes to flush the L2 cache @@ -1167,7 +1163,8 @@ static void __init smp_tune_scheduling(void) goto report; } - ecache_size = prom_getintdefault(linux_cpus[0].prom_node, + cpu_find_by_instance(0, &cpu_node, NULL); + ecache_size = prom_getintdefault(cpu_node, "ecache-size", (512 * 1024)); if (ecache_size > (4 * 1024 * 1024)) ecache_size = (4 * 1024 * 1024); @@ -1249,22 +1246,27 @@ int setup_profiling_timer(unsigned int multiplier) void __init smp_prepare_cpus(unsigned int max_cpus) { - int i; + int instance, mid; - for (i = 0; i < linux_num_cpus; i++) { - if (linux_cpus[i].mid < max_cpus) { - cpu_set(linux_cpus[i].mid, phys_cpu_present_map); + instance = 0; + while (!cpu_find_by_instance(instance, NULL, &mid)) { + if (mid < max_cpus) { + cpu_set(mid, phys_cpu_present_map); atomic_inc(&sparc64_num_cpus_possible); } + instance++; } + if (atomic_read(&sparc64_num_cpus_possible) > max_cpus) { - for (i = linux_num_cpus - 1; i >= 0; i--) { - if (linux_cpus[i].mid != boot_cpu_id) { - cpu_clear(linux_cpus[i].mid, phys_cpu_present_map); + instance = 0; + while (!cpu_find_by_instance(instance, NULL, &mid)) { + if (mid != boot_cpu_id) { + cpu_clear(mid, phys_cpu_present_map); atomic_dec(&sparc64_num_cpus_possible); if (atomic_read(&sparc64_num_cpus_possible) <= max_cpus) break; } + instance++; } } diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 141574731613..65e0298cddd5 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -956,7 +956,7 @@ static unsigned long sparc64_init_timers(irqreturn_t (*cfunc)(int, void *, struc clock = prom_getint(node, "stick-frequency"); } else { tick_ops = &tick_operations; - node = linux_cpus[0].prom_node; + cpu_find_by_instance(0, &node, NULL); clock = prom_getint(node, "clock-frequency"); } } else { diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index b0e0c7ccffea..44057dd8ddd4 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -613,8 +613,7 @@ extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector void __init cheetah_ecache_flush_init(void) { unsigned long largest_size, smallest_linesize, order, ver; - char type[16]; - int node, i; + int node, i, instance; /* Scan all cpu device tree nodes, note two values: * 1) largest E-cache size @@ -622,21 +621,21 @@ void __init cheetah_ecache_flush_init(void) */ largest_size = 0UL; smallest_linesize = ~0UL; - node = prom_getchild(prom_root_node); - while ((node = prom_getsibling(node)) != 0) { - prom_getstring(node, "device_type", type, sizeof(type)); - if (!strcmp(type, "cpu")) { - unsigned long val; - - val = prom_getintdefault(node, "ecache-size", - (2 * 1024 * 1024)); - if (val > largest_size) - largest_size = val; - val = prom_getintdefault(node, "ecache-line-size", 64); - if (val < smallest_linesize) - smallest_linesize = val; - } + + instance = 0; + while (!cpu_find_by_instance(instance, &node, NULL)) { + unsigned long val; + + val = prom_getintdefault(node, "ecache-size", + (2 * 1024 * 1024)); + if (val > largest_size) + largest_size = val; + val = prom_getintdefault(node, "ecache-line-size", 64); + if (val < smallest_linesize) + smallest_linesize = val; + instance++; } + if (largest_size == 0UL || smallest_linesize == ~0UL) { prom_printf("cheetah_ecache_flush_init: Cannot probe cpu E-cache " "parameters.\n"); diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h index c2cb33f588f6..a432d9e7daaa 100644 --- a/include/asm-sparc64/oplib.h +++ b/include/asm-sparc64/oplib.h @@ -327,6 +327,10 @@ extern int prom_setprop(int node, char *prop_name, char *prop_value, extern int prom_pathtoinode(char *path); extern int prom_inst2pkg(int); +/* CPU probing helpers. */ +int cpu_find_by_instance(int instance, int *prom_node, int *mid); +int cpu_find_by_mid(int mid, int *prom_node); + /* Client interface level routines. */ extern void prom_set_trap_table(unsigned long tba); diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h index 96c409a7cc5f..b4b4e9675d9f 100644 --- a/include/asm-sparc64/smp.h +++ b/include/asm-sparc64/smp.h @@ -17,18 +17,6 @@ #include #include -/* PROM provided per-processor information we need - * to start them all up. - */ - -struct prom_cpuinfo { - int prom_node; - int mid; -}; - -extern int linux_num_cpus; /* number of CPUs probed */ -extern struct prom_cpuinfo linux_cpus[NR_CPUS]; - #endif /* !(__ASSEMBLY__) */ #ifdef CONFIG_SMP -- cgit v1.2.3 From ab6ae966c67d14a853e6570cd95a6ee42d0389e6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 19 Aug 2003 05:00:50 -0700 Subject: [SPARC64]: Turn cpu_data into per-cpu data. --- arch/sparc64/kernel/ebus.c | 1 + arch/sparc64/kernel/head.S | 66 ++++++------------------------------- arch/sparc64/kernel/irq.c | 42 +++++++++++++++++------ arch/sparc64/kernel/process.c | 5 +-- arch/sparc64/kernel/smp.c | 60 ++++++++++++++++++++++----------- arch/sparc64/kernel/sparc64_ksyms.c | 4 ++- arch/sparc64/kernel/time.c | 11 ++++--- arch/sparc64/kernel/trampoline.S | 16 +++------ drivers/serial/sunsab.c | 1 + include/asm-sparc64/cpudata.h | 30 +++++++++++++++++ include/asm-sparc64/delay.h | 3 +- include/asm-sparc64/pgalloc.h | 3 +- include/asm-sparc64/processor.h | 1 - include/asm-sparc64/smp.h | 46 -------------------------- 14 files changed, 135 insertions(+), 154 deletions(-) create mode 100644 include/asm-sparc64/cpudata.h (limited to 'include') diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 25ee033134f0..dbe2d7a30d23 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index dfc500908ef9..27ba29c7f59b 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -628,70 +628,21 @@ spitfire_vpte_base: #undef KERN_HIGHBITS #undef KERN_LOWBITS - /* Setup Interrupt globals */ - wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate -#ifndef CONFIG_SMP - sethi %hi(__up_workvec), %g5 - or %g5, %lo(__up_workvec), %g6 -#else - /* By definition of where we are, this is boot_cpu. */ - brz,pt %i0, not_starfire - sethi %hi(0x1fff4000), %g1 - or %g1, %lo(0x1fff4000), %g1 - sllx %g1, 12, %g1 - or %g1, 0xd0, %g1 - lduwa [%g1] ASI_PHYS_BYPASS_EC_E, %g1 - b,pt %xcc, set_worklist - nop - -not_starfire: - BRANCH_IF_JALAPENO(g1,g5,is_jalapeno) - BRANCH_IF_ANY_CHEETAH(g1,g5,is_cheetah) - - ba,pt %xcc, not_cheetah - nop - -is_jalapeno: - ldxa [%g0] ASI_JBUS_CONFIG, %g1 - srlx %g1, 17, %g1 - ba,pt %xcc, set_worklist - and %g1, 0x1f, %g1 ! 5bit JBUS ID - -is_cheetah: - ldxa [%g0] ASI_SAFARI_CONFIG, %g1 - srlx %g1, 17, %g1 - ba,pt %xcc, set_worklist - and %g1, 0x3ff, %g1 ! 10bit Safari Agent ID - -not_cheetah: - ldxa [%g0] ASI_UPA_CONFIG, %g1 - srlx %g1, 17, %g1 - and %g1, 0x1f, %g1 - - /* In theory this is: &(cpu_data[boot_cpu_id].irq_worklists[0]) */ -set_worklist: - sethi %hi(cpu_data), %g5 - or %g5, %lo(cpu_data), %g5 - sllx %g1, 7, %g1 - add %g5, %g1, %g5 - add %g5, 64, %g6 -#endif - /* Kill PROM timer */ - sethi %hi(0x80000000), %g1 - sllx %g1, 32, %g1 - wr %g1, 0, %tick_cmpr + sethi %hi(0x80000000), %o2 + sllx %o2, 32, %o2 + wr %o2, 0, %tick_cmpr - BRANCH_IF_ANY_CHEETAH(g1,g5,1f) + BRANCH_IF_ANY_CHEETAH(o2,o3,1f) ba,pt %xcc, 2f nop /* Disable STICK_INT interrupts. */ 1: - sethi %hi(0x80000000), %g1 - sllx %g1, 32, %g1 - wr %g1, %asr25 + sethi %hi(0x80000000), %o2 + sllx %o2, 32, %o2 + wr %o2, %asr25 /* Ok, we're done setting up all the state our trap mechanims needs, * now get back into normal globals and let the PROM know what is up. @@ -700,6 +651,9 @@ set_worklist: wrpr %g0, %g0, %wstate wrpr %o1, PSTATE_IE, %pstate + call init_irqwork_curcpu + nop + sethi %hi(sparc64_ttable_tl0), %g5 call prom_set_trap_table mov %g5, %o0 diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index f9d9c5364f21..c9ea7b107011 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef CONFIG_SMP static void distribute_irqs(void); @@ -56,12 +57,18 @@ static void distribute_irqs(void); struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES))); -#ifndef CONFIG_SMP -unsigned int __up_workvec[16] __attribute__ ((aligned (SMP_CACHE_BYTES))); -#define irq_work(__cpu, __pil) &(__up_workvec[(void)(__cpu), (__pil)]) -#else -#define irq_work(__cpu, __pil) &(cpu_data[(__cpu)].irq_worklists[(__pil)]) -#endif +/* This has to be in the main kernel image, it cannot be + * turned into per-cpu data. The reason is that the main + * kernel image is locked into the TLB and this structure + * is accessed from the vectored interrupt trap handler. If + * access to this structure takes a TLB miss it could cause + * the 5-level sparc v9 trap stack to overflow. + */ +struct irq_work_struct { + unsigned int irq_worklists[16]; +}; +struct irq_work_struct __irq_work[NR_CPUS]; +#define irq_work(__cpu, __pil) &(__irq_work[(__cpu)].irq_worklists[(__pil)]) #ifdef CONFIG_PCI /* This is a table of physical addresses used to deal with IBF_DMA_SYNC. @@ -706,7 +713,7 @@ static inline void redirect_intr(int cpu, struct ino_bucket *bp) goto out; /* Voo-doo programming. */ - if (cpu_data[buddy].idle_volume < FORWARD_VOLUME) + if (cpu_data(buddy).idle_volume < FORWARD_VOLUME) goto out; /* This just so happens to be correct on Cheetah @@ -1083,15 +1090,30 @@ void enable_prom_timer(void) prom_timers->count0 = 0; } +void init_irqwork_curcpu(void) +{ + register struct irq_work_struct *workp asm("o2"); + unsigned long tmp; + + memset(__irq_work + smp_processor_id(), 0, sizeof(*workp)); + + /* Set interrupt globals. */ + workp = &__irq_work[smp_processor_id()]; + __asm__ __volatile__( + "rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate\n\t" + "mov %2, %%g6\n\t" + "wrpr %0, 0x0, %%pstate\n\t" + : "=&r" (tmp) + : "i" (PSTATE_IG | PSTATE_IE), "r" (workp)); +} + /* Only invoked on boot processor. */ void __init init_IRQ(void) { map_prom_timers(); kill_prom_timer(); memset(&ivector_table[0], 0, sizeof(ivector_table)); -#ifndef CONFIG_SMP - memset(&__up_workvec[0], 0, sizeof(__up_workvec)); -#endif /* We need to clear any IRQ's pending in the soft interrupt * registers, a spurious one could be left around from the diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 812d2b3cd193..84ae8431c653 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -41,6 +41,7 @@ #include #include #include +#include /* #define VERBOSE_SHOWREGS */ @@ -84,8 +85,8 @@ int cpu_idle(void) /* * the idle loop on a UltraMultiPenguin... */ -#define idle_me_harder() (cpu_data[smp_processor_id()].idle_volume += 1) -#define unidle_me() (cpu_data[smp_processor_id()].idle_volume = 0) +#define idle_me_harder() (cpu_data(smp_processor_id()).idle_volume += 1) +#define unidle_me() (cpu_data(smp_processor_id()).idle_volume = 0) int cpu_idle(void) { set_thread_flag(TIF_POLLING_NRFLAG); diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index dfb200bb2269..d19f7d00ce8f 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,7 @@ extern int linux_num_cpus; extern void calibrate_delay(void); -cpuinfo_sparc cpu_data[NR_CPUS]; +DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 }; /* Please don't make this stuff initdata!!! --DaveM */ static unsigned char boot_cpu_id; @@ -73,32 +74,29 @@ void smp_bogo(struct seq_file *m) seq_printf(m, "Cpu%dBogo\t: %lu.%02lu\n" "Cpu%dClkTck\t: %016lx\n", - i, cpu_data[i].udelay_val / (500000/HZ), - (cpu_data[i].udelay_val / (5000/HZ)) % 100, - i, cpu_data[i].clock_tick); + i, cpu_data(i).udelay_val / (500000/HZ), + (cpu_data(i).udelay_val / (5000/HZ)) % 100, + i, cpu_data(i).clock_tick); } void __init smp_store_cpu_info(int id) { - int i, cpu_node; + int cpu_node; /* multiplier and counter set by smp_setup_percpu_timer() */ - cpu_data[id].udelay_val = loops_per_jiffy; + cpu_data(id).udelay_val = loops_per_jiffy; cpu_find_by_mid(id, &cpu_node); - cpu_data[id].clock_tick = prom_getintdefault(cpu_node, + cpu_data(id).clock_tick = prom_getintdefault(cpu_node, "clock-frequency", 0); - cpu_data[id].pgcache_size = 0; - cpu_data[id].pte_cache[0] = NULL; - cpu_data[id].pte_cache[1] = NULL; - cpu_data[id].pgdcache_size = 0; - cpu_data[id].pgd_cache = NULL; - cpu_data[id].idle_volume = 1; - - for (i = 0; i < 16; i++) - cpu_data[id].irq_worklists[i] = 0; + cpu_data(id).pgcache_size = 0; + cpu_data(id).pte_cache[0] = NULL; + cpu_data(id).pte_cache[1] = NULL; + cpu_data(id).pgdcache_size = 0; + cpu_data(id).pgd_cache = NULL; + cpu_data(id).idle_volume = 1; } static void smp_setup_percpu_timer(void); @@ -1039,8 +1037,8 @@ void smp_promstop_others(void) extern void sparc64_do_profile(struct pt_regs *regs); -#define prof_multiplier(__cpu) cpu_data[(__cpu)].multiplier -#define prof_counter(__cpu) cpu_data[(__cpu)].counter +#define prof_multiplier(__cpu) cpu_data(__cpu).multiplier +#define prof_counter(__cpu) cpu_data(__cpu).counter void smp_percpu_timer_interrupt(struct pt_regs *regs) { @@ -1303,7 +1301,7 @@ void __init smp_cpus_done(unsigned int max_cpus) for (i = 0; i < NR_CPUS; i++) { if (cpu_online(i)) - bogosum += cpu_data[i].udelay_val; + bogosum += cpu_data(i).udelay_val; } printk("Total of %ld processors activated " "(%lu.%02lu BogoMIPS).\n", @@ -1316,3 +1314,27 @@ void __init smp_cpus_done(unsigned int max_cpus) */ smp_tune_scheduling(); } + +/* This needn't do anything as we do not sleep the cpu + * inside of the idler task, so an interrupt is not needed + * to get a clean fast response. + * + * XXX Reverify this assumption... -DaveM + * + * Addendum: We do want it to do something for the signal + * delivery case, we detect that by just seeing + * if we are trying to send this to an idler or not. + */ +void smp_send_reschedule(int cpu) +{ + if (cpu_data(cpu).idle_volume == 0) + smp_receive_signal(cpu); +} + +/* This is a nop because we capture all other cpus + * anyways when making the PROM active. + */ +void smp_send_stop(void) +{ +} + diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index e1f66dfd3ae7..a1f0795974ec 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,7 @@ #include #include #include +#include struct poll { int fd; @@ -143,7 +145,7 @@ EXPORT_SYMBOL_NOVERS(mcount); #endif /* Per-CPU information table */ -EXPORT_SYMBOL(cpu_data); +EXPORT_PER_CPU_SYMBOL(__cpu_data); /* CPU online map and active count. */ EXPORT_SYMBOL(cpu_online_map); diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 65e0298cddd5..782509012e3b 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -42,6 +42,7 @@ #include #include #include +#include spinlock_t mostek_lock = SPIN_LOCK_UNLOCKED; spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; @@ -1013,7 +1014,7 @@ unsigned long sparc64_get_clock_tick(unsigned int cpu) if (ft->clock_tick_ref) return ft->clock_tick_ref; #ifdef CONFIG_SMP - return cpu_data[cpu].clock_tick; + return cpu_data(cpu).clock_tick; #else return up_clock_tick; #endif @@ -1031,16 +1032,16 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val #ifdef CONFIG_SMP if (!ft->ref_freq) { ft->ref_freq = freq->old; - ft->udelay_val_ref = cpu_data[cpu].udelay_val; - ft->clock_tick_ref = cpu_data[cpu].clock_tick; + ft->udelay_val_ref = cpu_data(cpu).udelay_val; + ft->clock_tick_ref = cpu_data(cpu).clock_tick; } if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { - cpu_data[cpu].udelay_val = + cpu_data(cpu).udelay_val = cpufreq_scale(ft->udelay_val_ref, ft->ref_freq, freq->new); - cpu_data[cpu].clock_tick = + cpu_data(cpu).clock_tick = cpufreq_scale(ft->clock_tick_ref, ft->ref_freq, freq->new); diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S index 8b4cbd401be3..28fe12b23e30 100644 --- a/arch/sparc64/kernel/trampoline.S +++ b/arch/sparc64/kernel/trampoline.S @@ -246,20 +246,12 @@ startup_continue: wrpr %o1, 0x0, %pstate ldx [%g6 + TI_TASK], %g4 - /* Setup interrupt globals, we are always SMP. */ - wrpr %o1, PSTATE_IG, %pstate - - /* Get our UPA MID. */ - ldub [%o2 + TI_CPU], %g1 - sethi %hi(cpu_data), %g5 - or %g5, %lo(cpu_data), %g5 + wrpr %g0, 0, %wstate - /* In theory this is: &(cpu_data[this_upamid].irq_worklists[0]) */ - sllx %g1, 7, %g1 - add %g5, %g1, %g1 - add %g1, 64, %g6 + call init_irqwork_curcpu + nop - wrpr %g0, 0, %wstate + rdpr %pstate, %o1 or %o1, PSTATE_IE, %o1 wrpr %o1, 0, %pstate diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 5ddd135d99bb..afb27a2b50f3 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h new file mode 100644 index 000000000000..d7625ffc0b85 --- /dev/null +++ b/include/asm-sparc64/cpudata.h @@ -0,0 +1,30 @@ +/* cpudata.h: Per-cpu parameters. + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + */ + +#ifndef _SPARC64_CPUDATA_H +#define _SPARC64_CPUDATA_H + +#include + +typedef struct { + /* Dcache line 1 */ + unsigned int __pad0; /* bh_count moved to irq_stat for consistency. KAO */ + unsigned int multiplier; + unsigned int counter; + unsigned int idle_volume; + unsigned long clock_tick; /* %tick's per second */ + unsigned long udelay_val; + + /* Dcache line 2 */ + unsigned int pgcache_size; + unsigned int pgdcache_size; + unsigned long *pte_cache[2]; + unsigned long *pgd_cache; +} cpuinfo_sparc; + +DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); +#define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu)) + +#endif /* _SPARC64_CPUDATA_H */ diff --git a/include/asm-sparc64/delay.h b/include/asm-sparc64/delay.h index 4157717dd736..0c3be9aec361 100644 --- a/include/asm-sparc64/delay.h +++ b/include/asm-sparc64/delay.h @@ -9,6 +9,7 @@ #include #include +#include #ifndef __ASSEMBLY__ @@ -59,7 +60,7 @@ extern __inline__ void __ndelay(unsigned long usecs, unsigned long lps) } #ifdef CONFIG_SMP -#define __udelay_val cpu_data[smp_processor_id()].udelay_val +#define __udelay_val cpu_data(smp_processor_id()).udelay_val #else #define __udelay_val loops_per_jiffy #endif diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h index 41673d9f1d5c..8f2ff1dc299d 100644 --- a/include/asm-sparc64/pgalloc.h +++ b/include/asm-sparc64/pgalloc.h @@ -10,11 +10,12 @@ #include #include #include +#include /* Page table allocation/freeing. */ #ifdef CONFIG_SMP /* Sliiiicck */ -#define pgt_quicklists cpu_data[smp_processor_id()] +#define pgt_quicklists cpu_data(smp_processor_id()) #else extern struct pgtable_cache_struct { unsigned long *pgd_cache; diff --git a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h index a1eb3d00ef43..bec2ef59d771 100644 --- a/include/asm-sparc64/processor.h +++ b/include/asm-sparc64/processor.h @@ -20,7 +20,6 @@ #include #include #include -#include /* Bus types */ #define EISA_bus 0 diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h index b4b4e9675d9f..c7fbd6613a31 100644 --- a/include/asm-sparc64/smp.h +++ b/include/asm-sparc64/smp.h @@ -23,30 +23,6 @@ #ifndef __ASSEMBLY__ -/* Per processor Sparc parameters we need. */ - -/* Keep this a multiple of 64-bytes for cache reasons. */ -typedef struct { - /* Dcache line 1 */ - unsigned int __pad0; /* bh_count moved to irq_stat for consistency. KAO */ - unsigned int multiplier; - unsigned int counter; - unsigned int idle_volume; - unsigned long clock_tick; /* %tick's per second */ - unsigned long udelay_val; - - /* Dcache line 2 */ - unsigned int pgcache_size; - unsigned int pgdcache_size; - unsigned long *pte_cache[2]; - unsigned long *pgd_cache; - - /* Dcache lines 3 and 4 */ - unsigned int irq_worklists[16]; -} ____cacheline_aligned cpuinfo_sparc; - -extern cpuinfo_sparc cpu_data[NR_CPUS]; - /* * Private routines/data */ @@ -97,28 +73,6 @@ static __inline__ int hard_smp_processor_id(void) #define smp_processor_id() (current_thread_info()->cpu) -/* This needn't do anything as we do not sleep the cpu - * inside of the idler task, so an interrupt is not needed - * to get a clean fast response. - * - * XXX Reverify this assumption... -DaveM - * - * Addendum: We do want it to do something for the signal - * delivery case, we detect that by just seeing - * if we are trying to send this to an idler or not. - */ -static __inline__ void smp_send_reschedule(int cpu) -{ - extern void smp_receive_signal(int); - if (cpu_data[cpu].idle_volume == 0) - smp_receive_signal(cpu); -} - -/* This is a nop as well because we capture all other cpus - * anyways when making the PROM active. - */ -static __inline__ void smp_send_stop(void) { } - #endif /* !(__ASSEMBLY__) */ #endif /* !(CONFIG_SMP) */ -- cgit v1.2.3 From e66332eac3736374626e1e753dc717c2f5140b18 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 19 Aug 2003 05:05:19 -0700 Subject: [SPARC64]: Remove unused crap from asm/irq.h --- include/asm-sparc64/irq.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'include') diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index aa3de3bc9d22..e3ba6bc2cc3e 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h @@ -121,13 +121,6 @@ extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap); extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); -extern unsigned int psycho_build_irq(void *psycho, int imap_off, int ino, int need_dma_sync); - -#ifdef CONFIG_SMP -extern void set_cpu_int(int, int); -extern void clear_cpu_int(int, int); -extern void set_irq_udt(int); -#endif extern int request_fast_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), -- cgit v1.2.3 From 0dfed24c083c619981b59729fad328c6b81ddb28 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 19 Aug 2003 05:24:20 -0700 Subject: [SPARC64]: Kill up_clock_tick, use cpu_data(). --- arch/sparc64/kernel/devices.c | 6 +++--- arch/sparc64/kernel/setup.c | 6 +----- arch/sparc64/kernel/time.c | 17 ----------------- include/asm-sparc64/timer.h | 4 ---- 4 files changed, 4 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 3678721d9275..09a6f374c608 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -131,9 +131,9 @@ void __init device_scan(void) prom_printf("No cpu nodes, cannot continue\n"); prom_halt(); } - up_clock_tick = prom_getintdefault(cpu_node, - "clock-frequency", - 0); + cpu_data(0).clock_tick = prom_getintdefault(cpu_node, + "clock-frequency", + 0); } #endif diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 67791a6a58bd..174919cb2c5e 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -593,10 +593,6 @@ extern void smp_info(struct seq_file *); extern void smp_bogo(struct seq_file *); extern void mmu_info(struct seq_file *); -#ifndef CONFIG_SMP -unsigned long up_clock_tick; -#endif - static int show_cpuinfo(struct seq_file *m, void *__unused) { seq_printf(m, @@ -623,7 +619,7 @@ static int show_cpuinfo(struct seq_file *m, void *__unused) #ifndef CONFIG_SMP , loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ)) % 100, - up_clock_tick + cpu_data(0).clock_tick #endif ); #ifdef CONFIG_SMP diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 782509012e3b..2572fdcd9908 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1013,11 +1013,7 @@ unsigned long sparc64_get_clock_tick(unsigned int cpu) if (ft->clock_tick_ref) return ft->clock_tick_ref; -#ifdef CONFIG_SMP return cpu_data(cpu).clock_tick; -#else - return up_clock_tick; -#endif } #ifdef CONFIG_CPU_FREQ @@ -1029,7 +1025,6 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val unsigned int cpu = freq->cpu; struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu); -#ifdef CONFIG_SMP if (!ft->ref_freq) { ft->ref_freq = freq->old; ft->udelay_val_ref = cpu_data(cpu).udelay_val; @@ -1046,18 +1041,6 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val ft->ref_freq, freq->new); } -#else - /* In the non-SMP case, kernel/cpufreq.c takes care of adjusting - * loops_per_jiffy. - */ - if (!ft->ref_freq) { - ft->ref_freq = freq->old; - ft->clock_tick_ref = up_clock_tick; - } - if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || - (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) - up_clock_tick = cpufreq_scale(ft->clock_tick_ref, ft->ref_freq, freq->new); -#endif return 0; } diff --git a/include/asm-sparc64/timer.h b/include/asm-sparc64/timer.h index 0910e9deea0d..ba33a2b6b7bd 100644 --- a/include/asm-sparc64/timer.h +++ b/include/asm-sparc64/timer.h @@ -69,10 +69,6 @@ struct pt_regs; extern void timer_tick_interrupt(struct pt_regs *); #endif -#ifndef CONFIG_SMP -extern unsigned long up_clock_tick; -#endif - extern unsigned long sparc64_get_clock_tick(unsigned int cpu); #endif /* _SPARC64_TIMER_H */ -- cgit v1.2.3 From 13d5cf603752077d27e92a450895c95d83cf3d17 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 19 Aug 2003 05:28:41 -0700 Subject: [SPARC64]: Always use cpu_data().udelay_val. --- arch/sparc64/kernel/setup.c | 4 ++-- arch/sparc64/mm/init.c | 4 ++++ include/asm-sparc64/delay.h | 4 ---- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 174919cb2c5e..c875fbf09eac 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -617,8 +617,8 @@ static int show_cpuinfo(struct seq_file *m, void *__unused) (long)num_possible_cpus(), (long)num_online_cpus() #ifndef CONFIG_SMP - , loops_per_jiffy/(500000/HZ), - (loops_per_jiffy/(5000/HZ)) % 100, + , cpu_data(0).udelay_val/(500000/HZ), + (cpu_data(0).udelay_val/(5000/HZ)) % 100, cpu_data(0).clock_tick #endif ); diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 6127d73d1e8e..bb3fd74b0a2b 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1706,6 +1706,10 @@ void __init mem_init(void) unsigned long addr, last; int i; +#ifndef CONFIG_SMP + cpu_data(0).udelay_val = loops_per_jiffy; +#endif + i = last_valid_pfn >> ((22 - PAGE_SHIFT) + 6); i += 1; sparc64_valid_addr_bitmap = (unsigned long *) diff --git a/include/asm-sparc64/delay.h b/include/asm-sparc64/delay.h index 0c3be9aec361..e6fced5dce1c 100644 --- a/include/asm-sparc64/delay.h +++ b/include/asm-sparc64/delay.h @@ -59,11 +59,7 @@ extern __inline__ void __ndelay(unsigned long usecs, unsigned long lps) __delay(usecs * HZ); } -#ifdef CONFIG_SMP #define __udelay_val cpu_data(smp_processor_id()).udelay_val -#else -#define __udelay_val loops_per_jiffy -#endif #define udelay(usecs) __udelay((usecs),__udelay_val) #define ndelay(usecs) __ndelay((usecs),__udelay_val) -- cgit v1.2.3 From 6532914aea749d060dbd745bdb859eb03c3b1a26 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 19 Aug 2003 07:30:03 -0700 Subject: [CPUMASK]: Prevent unused variable warnings on uniprocessor. --- include/asm-generic/cpumask_up.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/asm-generic/cpumask_up.h b/include/asm-generic/cpumask_up.h index 13ef0d83816d..51e3f3d419f2 100644 --- a/include/asm-generic/cpumask_up.h +++ b/include/asm-generic/cpumask_up.h @@ -3,10 +3,10 @@ #define cpus_coerce(map) (map) -#define cpu_set(cpu, map) do { cpus_coerce(map) = 1UL; } while (0) -#define cpu_clear(cpu, map) do { cpus_coerce(map) = 0UL; } while (0) -#define cpu_isset(cpu, map) (cpus_coerce(map) != 0UL) -#define cpu_test_and_set(cpu, map) test_and_set_bit(0, (map).mask) +#define cpu_set(cpu, map) do { (void)(cpu); cpus_coerce(map) = 1UL; } while (0) +#define cpu_clear(cpu, map) do { (void)(cpu); cpus_coerce(map) = 0UL; } while (0) +#define cpu_isset(cpu, map) ((void)(cpu), cpus_coerce(map) != 0UL) +#define cpu_test_and_set(cpu, map) ((void)(cpu), test_and_set_bit(0, (map).mask)) #define cpus_and(dst, src1, src2) \ do { \ @@ -46,7 +46,7 @@ cpus_coerce(__tmp__) = map; \ __tmp__; \ }) -#define cpumask_of_cpu(cpu) cpus_promote(1) +#define cpumask_of_cpu(cpu) ((void)(cpu), cpus_promote(1)) #define any_online_cpu(map) (cpus_coerce(map) ? 0 : 1) /* -- cgit v1.2.3 From 0c58869245c6e43bd982f56a19c9394e6ba9e5d4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 19 Aug 2003 07:30:44 -0700 Subject: [SPARC64]: Fix uniprocessor build. --- arch/sparc64/kernel/devices.c | 1 + include/asm-sparc64/smp.h | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'include') diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 09a6f374c608..559b6d753881 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -19,6 +19,7 @@ #include #include #include +#include /* Used to synchronize acceses to NatSemi SUPER I/O chip configure * operations in asm/ns87303.h diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h index c7fbd6613a31..7d8378846e55 100644 --- a/include/asm-sparc64/smp.h +++ b/include/asm-sparc64/smp.h @@ -75,6 +75,10 @@ static __inline__ int hard_smp_processor_id(void) #endif /* !(__ASSEMBLY__) */ +#else + +#define num_possible_cpus() (1) + #endif /* !(CONFIG_SMP) */ #define NO_PROC_ID 0xFF -- cgit v1.2.3