/trunk/kernel/arch/sparc64/src/smp/smp.c |
---|
0,0 → 1,109 |
/* |
* Copyright (C) 2006 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** @file |
*/ |
#include <smp/smp.h> |
#include <genarch/ofw/ofw_tree.h> |
#include <cpu.h> |
#include <arch/cpu.h> |
#include <arch.h> |
#include <config.h> |
#include <macros.h> |
#include <arch/types.h> |
#include <synch/synch.h> |
#include <synch/waitq.h> |
#include <typedefs.h> |
#include <print.h> |
/** |
* This global variable is used to pick-up application processors |
* from their active loop in start.S. When a processor looping in |
* start.S sees that this variable contains its MID, it can |
* proceed with its initialization. |
* |
* This variable is modified only by the bootstrap processor. |
* Other processors access it read-only. |
*/ |
volatile uint64_t waking_up_mid = (uint64_t) -1; |
/** Determine number of processors. */ |
void smp_init(void) |
{ |
ofw_tree_node_t *node; |
count_t cnt = 0; |
node = ofw_tree_find_child_by_device_type(ofw_tree_lookup("/"), "cpu"); |
while (node) { |
cnt++; |
node = ofw_tree_find_peer_by_device_type(node, "cpu"); |
} |
config.cpu_count = max(1, cnt); |
} |
/** Wake application processors up. */ |
void kmp(void *arg) |
{ |
ofw_tree_node_t *node; |
int i; |
node = ofw_tree_find_child_by_device_type(ofw_tree_lookup("/"), "cpu"); |
for (i = 0; node; node = ofw_tree_find_peer_by_device_type(node, "cpu"), i++) { |
uint32_t mid; |
ofw_tree_property_t *prop; |
prop = ofw_tree_getprop(node, "upa-portid"); |
if (!prop || !prop->value) |
continue; |
mid = *((uint32_t *) prop->value); |
if (CPU->arch.mid == mid) { |
/* |
* Skip the current CPU. |
*/ |
continue; |
} |
/* |
* Processor with ID == mid can proceed with its initialization. |
*/ |
waking_up_mid = mid; |
if (waitq_sleep_timeout(&ap_completion_wq, 1000000, SYNCH_FLAGS_NONE) == ESYNCH_TIMEOUT) |
printf("%s: waiting for processor (mid = %d) timed out\n", |
__FUNCTION__, mid); |
} |
} |
/** @} |
*/ |
/trunk/kernel/arch/sparc64/src/smp/ipi.c |
---|
0,0 → 1,43 |
/* |
* Copyright (C) 2006 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** @file |
*/ |
#include <smp/ipi.h> |
void ipi_broadcast_arch(int ipi) |
{ |
/* TODO */ |
} |
/** @} |
*/ |
/trunk/kernel/arch/sparc64/src/sparc64.c |
---|
70,12 → 70,14 |
void arch_pre_mm_init(void) |
{ |
trap_init(); |
if (config.cpu_active == 1) |
trap_init(); |
} |
void arch_post_mm_init(void) |
{ |
standalone_sparc64_console_init(); |
if (config.cpu_active == 1) |
standalone_sparc64_console_init(); |
} |
void arch_post_cpu_init(void) |
90,13 → 92,15 |
{ |
thread_t *t; |
/* |
* Create thread that polls keyboard. |
*/ |
t = thread_create(kkbdpoll, NULL, TASK, 0, "kkbdpoll"); |
if (!t) |
panic("cannot create kkbdpoll\n"); |
thread_ready(t); |
if (config.cpu_active == 1) { |
/* |
* Create thread that polls keyboard. |
*/ |
t = thread_create(kkbdpoll, NULL, TASK, 0, "kkbdpoll"); |
if (!t) |
panic("cannot create kkbdpoll\n"); |
thread_ready(t); |
} |
} |
/** Calibrate delay loop. |
/trunk/kernel/arch/sparc64/src/cpu/cpu.c |
---|
50,6 → 50,8 |
upa_config_t upa_config; |
upa_config.value = upa_config_read(); |
CPU->arch.mid = upa_config.mid; |
node = ofw_tree_find_child_by_device_type(ofw_tree_lookup("/"), "cpu"); |
while (node) { |
ofw_tree_property_t *prop; |
57,7 → 59,7 |
prop = ofw_tree_getprop(node, "upa-portid"); |
if (prop && prop->value) { |
mid = *((uint32_t *) prop->value); |
if (mid == upa_config.mid) { |
if (mid == CPU->arch.mid) { |
prop = ofw_tree_getprop(node, "clock-frequency"); |
if (prop && prop->value) |
clock_frequency = *((uint32_t *) prop->value); |
78,6 → 80,8 |
/** Print version information for a processor. |
* |
* This function is called by the bootstrap processor. |
* |
* @param m Processor structure of the CPU for which version information is to be printed. |
*/ |
void cpu_print_report(cpu_t *m) |
84,50 → 88,50 |
{ |
char *manuf, *impl; |
switch (CPU->arch.ver.manuf) { |
case MANUF_FUJITSU: |
switch (m->arch.ver.manuf) { |
case MANUF_FUJITSU: |
manuf = "Fujitsu"; |
break; |
case MANUF_ULTRASPARC: |
case MANUF_ULTRASPARC: |
manuf = "UltraSPARC"; |
break; |
case MANUF_SUN: |
case MANUF_SUN: |
manuf = "Sun"; |
break; |
default: |
default: |
manuf = "Unknown"; |
break; |
} |
switch (CPU->arch.ver.impl) { |
case IMPL_ULTRASPARCI: |
case IMPL_ULTRASPARCI: |
impl = "UltraSPARC I"; |
break; |
case IMPL_ULTRASPARCII: |
case IMPL_ULTRASPARCII: |
impl = "UltraSPARC II"; |
break; |
case IMPL_ULTRASPARCII_I: |
case IMPL_ULTRASPARCII_I: |
impl = "UltraSPARC IIi"; |
break; |
case IMPL_ULTRASPARCII_E: |
case IMPL_ULTRASPARCII_E: |
impl = "UltraSPARC IIe"; |
break; |
case IMPL_ULTRASPARCIII: |
case IMPL_ULTRASPARCIII: |
impl = "UltraSPARC III"; |
break; |
case IMPL_ULTRASPARCIV_PLUS: |
case IMPL_ULTRASPARCIV_PLUS: |
impl = "UltraSPARC IV+"; |
break; |
case IMPL_SPARC64V: |
case IMPL_SPARC64V: |
impl = "SPARC 64V"; |
break; |
default: |
default: |
impl = "Unknown"; |
break; |
} |
printf("cpu%d: manuf=%s, impl=%s, mask=%d (%dMHz)\n", |
CPU->id, manuf, impl, CPU->arch.ver.mask, CPU->arch.clock_frequency/1000000); |
m->id, manuf, impl, m->arch.ver.mask, m->arch.clock_frequency/1000000); |
} |
/** @} |
/trunk/kernel/arch/sparc64/src/mm/as.c |
---|
37,6 → 37,7 |
#include <genarch/mm/as_ht.h> |
#include <genarch/mm/asid_fifo.h> |
#include <debug.h> |
#include <config.h> |
#ifdef CONFIG_TSB |
#include <arch/mm/tsb.h> |
51,8 → 52,10 |
/** Architecture dependent address space init. */ |
void as_arch_init(void) |
{ |
as_operations = &as_ht_operations; |
asid_fifo_init(); |
if (config.cpu_active == 1) { |
as_operations = &as_ht_operations; |
asid_fifo_init(); |
} |
} |
int as_constructor_arch(as_t *as, int flags) |
/trunk/kernel/arch/sparc64/src/mm/frame.c |
---|
53,21 → 53,23 |
int i; |
pfn_t confdata; |
for (i = 0; i < bootinfo.memmap.count; i++) { |
uintptr_t start = bootinfo.memmap.zones[i].start; |
size_t size = bootinfo.memmap.zones[i].size; |
if (config.cpu_active == 1) { |
for (i = 0; i < bootinfo.memmap.count; i++) { |
uintptr_t start = bootinfo.memmap.zones[i].start; |
size_t size = bootinfo.memmap.zones[i].size; |
/* |
* The memmap is created by HelenOS boot loader. |
* It already contains no holes. |
*/ |
/* |
* The memmap is created by HelenOS boot loader. |
* It already contains no holes. |
*/ |
confdata = ADDR2PFN(start); |
if (confdata == 0) |
confdata = 2; |
zone_create(ADDR2PFN(start), SIZE2FRAMES(ALIGN_DOWN(size, FRAME_SIZE)), confdata, 0); |
confdata = ADDR2PFN(start); |
if (confdata == 0) |
confdata = 2; |
zone_create(ADDR2PFN(start), SIZE2FRAMES(ALIGN_DOWN(size, FRAME_SIZE)), confdata, 0); |
last_frame = max(last_frame, start + ALIGN_UP(size, FRAME_SIZE)); |
last_frame = max(last_frame, start + ALIGN_UP(size, FRAME_SIZE)); |
} |
} |
} |
/trunk/kernel/arch/sparc64/src/mm/page.c |
---|
40,10 → 40,45 |
#include <bitops.h> |
#include <debug.h> |
#include <align.h> |
#include <config.h> |
#ifdef CONFIG_SMP |
/** Entries locked in DTLB of BSP. |
* |
* Application processors need to have the same locked entries |
* in their DTLBs as the bootstrap processor. |
*/ |
static struct { |
uintptr_t virt_page; |
uintptr_t phys_page; |
int pagesize_code; |
} bsp_locked_dtlb_entry[DTLB_ENTRY_COUNT]; |
/** Number of entries in bsp_locked_dtlb_entry array. */ |
static count_t bsp_locked_dtlb_entries = 0; |
#endif /* CONFIG_SMP */ |
/** Perform sparc64 specific initialization of paging. */ |
void page_arch_init(void) |
{ |
page_mapping_operations = &ht_mapping_operations; |
if (config.cpu_active == 1) { |
page_mapping_operations = &ht_mapping_operations; |
} else { |
#ifdef CONFIG_SMP |
int i; |
/* |
* Copy locked DTLB entries from the BSP. |
*/ |
for (i = 0; i < bsp_locked_dtlb_entries; i++) { |
dtlb_insert_mapping(bsp_locked_dtlb_entry[i].virt_page, |
bsp_locked_dtlb_entry[i].phys_page, bsp_locked_dtlb_entry[i].pagesize_code, |
true, false); |
} |
#endif |
} |
} |
/** Map memory-mapped device into virtual memory. |
67,8 → 102,10 |
unsigned int order; |
int i; |
ASSERT(config.cpu_active == 1); |
struct { |
int pagesize; |
int pagesize_code; |
size_t increment; |
count_t count; |
} sizemap[] = { |
101,11 → 138,25 |
uintptr_t virtaddr = ALIGN_UP(last_frame, 1<<(order + FRAME_WIDTH)); |
last_frame = ALIGN_UP(virtaddr + size, 1<<(order + FRAME_WIDTH)); |
for (i = 0; i < sizemap[order].count; i++) |
for (i = 0; i < sizemap[order].count; i++) { |
/* |
* First, insert the mapping into DTLB. |
*/ |
dtlb_insert_mapping(virtaddr + i*sizemap[order].increment, |
physaddr + i*sizemap[order].increment, |
sizemap[order].pagesize, true, false); |
sizemap[order].pagesize_code, true, false); |
#ifdef CONFIG_SMP |
/* |
* Second, save the information about the mapping for APs. |
*/ |
bsp_locked_dtlb_entry[bsp_locked_dtlb_entries].virt_page = virtaddr + i*sizemap[order].increment; |
bsp_locked_dtlb_entry[bsp_locked_dtlb_entries].phys_page = physaddr + i*sizemap[order].increment; |
bsp_locked_dtlb_entry[bsp_locked_dtlb_entries].pagesize_code = sizemap[order].pagesize_code; |
bsp_locked_dtlb_entries++; |
#endif |
} |
return virtaddr; |
} |
/trunk/kernel/arch/sparc64/src/start.S |
---|
26,6 → 26,7 |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
#include <arch/arch.h> |
#include <arch/regdef.h> |
#include <arch/boot/boot.h> |
33,6 → 34,10 |
#include <arch/mm/tlb.h> |
#include <arch/mm/tte.h> |
#ifdef CONFIG_SMP |
#include <arch/context_offset.h> |
#endif |
.register %g2, #scratch |
.register %g3, #scratch |
226,7 → 231,8 |
! set TL back to 0 |
wrpr %g0, 0, %tl |
brz %l7, 2f ! skip if you are not the bootstrap CPU |
brz %l7, 1f ! skip if you are not the bootstrap CPU |
nop |
call arch_pre_main |
nop |
236,6 → 242,48 |
/* Not reached. */ |
0: |
ba 0b |
nop |
/* |
* Read MID from the processor. |
*/ |
1: |
ldxa [%g0] ASI_UPA_CONFIG, %g1 |
srlx %g1, UPA_CONFIG_MID_SHIFT, %g1 |
and %g1, UPA_CONFIG_MID_MASK, %g1 |
/* |
* Active loop for APs until the BSP picks them up. |
* A processor cannot leave the loop until the |
* global variable 'waking_up_mid' equals its |
* MID. |
*/ |
set waking_up_mid, %g2 |
2: |
b 2b |
ldx [%g2], %g3 |
cmp %g3, %g1 |
bne 2b |
nop |
#ifdef CONFIG_SMP |
/* |
* Configure stack for the AP. |
* The AP is expected to use the stack saved |
* in the ctx global variable. |
*/ |
set ctx, %g1 |
add %g1, OFFSET_SP, %g1 |
ldx [%g1], %o6 |
call main_ap |
nop |
#endif |
/* Not reached. */ |
0: |
ba 0b |
nop |