o) Add SMP support for Octeon using U-Boot to launch all the processors at the

same time.
o) Remove some unused trivial uart functions from octeon_machdep now that the
   uart part is fully working and they are unused.
o) Use __func__ instead of __FUNCTION__.
o) Use intr_*() instead of other routines that do the same thing.
o) Remove some duplicate printfs from the Octeon port, as well as duplicate
   setting of Maxmem.
o) Use the right frequency divider on Octeon.
o) Use PCPU_GET(cpuid) consistently to get the cpuid of the running core.
o) Remove some unused macros in the Octeon port.
o) Use mips_sync() around use of the global dpcpu, whose value may not be
   visible to APs at first.
o) When loading the first thread's stack, use macros to make the code correct
   for n64 as well.
o) Remove stub, do-nothing FAU init/enable/disable functions from the RGMX
   driver.
This commit is contained in:
Juli Mallett 2010-04-17 03:08:13 +00:00
parent a97a1ee3d9
commit b6777295a6
11 changed files with 210 additions and 513 deletions

View File

@ -1,182 +1,66 @@
/***********************license start***************
* Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
* reserved.
/*-
* Copyright (c) 2004-2010 Juli Mallett <jmallett@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
*
* * 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.
*
* * Neither the name of Cavium Networks nor the names of
* its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
* AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
* OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
* RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
* REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
* DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
* OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
* PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
* POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT
* OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
*
*
* For any questions regarding licensing please contact marketing@caviumnetworks.com
*
***********************license end**************************************/
/* $FreeBSD$ */
* $FreeBSD$
*/
#include <machine/asm.h>
#include <machine/cache_r4k.h>
#include <machine/cpuregs.h>
#include <machine/param.h>
#include <machine/pte.h>
#include "assym.s"
.set noreorder
#define CPU_DISABLE_INTERRUPTS(reg, reg2, reg3) \
mfc0 reg, MIPS_COP_0_STATUS; \
nop; \
move reg3, reg; \
li reg2, ~MIPS_SR_INT_IE; \
and reg, reg2, reg; \
mtc0 reg, MIPS_COP_0_STATUS; \
COP0_SYNC
#define CPU_ENABLE_INTERRUPTS(reg, reg3) \
mfc0 reg, MIPS_COP_0_STATUS; \
nop; \
or reg, reg, reg3; \
mtc0 reg, MIPS_COP_0_STATUS; \
COP0_SYNC
#define PUSHR(reg) \
addiu sp,sp,-16 ; \
sd reg, 8(sp) ; \
nop ;
#define POPR(reg) \
ld reg, 8(sp) ; \
addiu sp,sp,16 ; \
nop ;
#ifdef SMP
/*
* octeon_ciu_get_interrupt_reg_addr
*
* Given Int-X, En-X combination, return the CIU Interrupt Enable Register addr
* a0 = ciu Int-X: 0/1
* a1 = ciu EN-0: 0/1
* This function must be implemented in assembly because it is called early
* in AP boot without a valid stack.
*/
LEAF(octeon_ciu_get_interrupt_reg_addr)
.set noreorder
.set mips3
LEAF(platform_processor_id)
.set push
.set mips32r2
jr ra
rdhwr v0, $0
.set pop
END(platform_processor_id)
beqz a0, ciu_get_interrupt_reg_addr_Int_0
nop
ciu_get_interrupt_reg_addr_Int_1:
beqz a1, ciu_get_interrupt_reg_addr_Int_1_En_0
nop
ciu_get_interrupt_reg_addr_Int_1_En1:
li a0, OCTEON_CIU_ADDR_HI
dsll32 a0, a0, 0
nop
ori a0, OCTEON_CIU_EN1_INT1_LO
j ciu_get_interrupt_reg_addr_ret
nop
ciu_get_interrupt_reg_addr_Int_1_En_0:
li a0, OCTEON_CIU_ADDR_HI
dsll32 a0, a0, 0
nop
ori a0, OCTEON_CIU_EN0_INT1_LO
j ciu_get_interrupt_reg_addr_ret
nop
ciu_get_interrupt_reg_addr_Int_0:
beqz a1, ciu_get_interrupt_reg_addr_Int_0_En_0
nop
ciu_get_interrupt_reg_addr_Int_0_En_1:
li a0, OCTEON_CIU_ADDR_HI
dsll32 a0, a0, 0
nop
ori a0, OCTEON_CIU_EN1_INT0_LO
j ciu_get_interrupt_reg_addr_ret
nop
ciu_get_interrupt_reg_addr_Int_0_En_0:
li a0, OCTEON_CIU_ADDR_HI
dsll32 a0, a0, 0
nop
ori a0, OCTEON_CIU_EN0_INT0_LO
ciu_get_interrupt_reg_addr_ret:
j ra
nop
.set mips0
.set reorder
END(octeon_ciu_get_interrupt_reg_addr)
/*
* octeon_ciu_mask_all_interrupts
*
* a0 = ciu Interrupt-X: 0/1
* a1 = ciu Enable-X: 0/1
* Called on APs to wait until they are told to launch.
*/
LEAF(octeon_ciu_mask_all_interrupts)
.set noreorder
.set mips3
LEAF(octeon_ap_wait)
jal platform_processor_id
nop
PUSHR(ra)
PUSHR(s0)
move t0, a0
move t1, a1
li a0, MIPS_SR_INT_IE
CPU_DISABLE_INTERRUPTS(a2, a1, s0)
move a0, t0
move t1, a1
jal octeon_ciu_get_interrupt_reg_addr
nop
ld a2, 0(a0) # Dummy read
nop
move a2, zero # Clear all
sd a2, 0(a0) # Write new Enable bits
nop
CPU_ENABLE_INTERRUPTS(a2, s0)
1: ll t0, octeon_ap_boot
bne v0, t0, 1b
nop
POPR(s0)
POPR(ra)
j ra # Return
nop # (bd slot)
move t0, zero
sc t0, octeon_ap_boot
.set mips0
.set reorder
END(octeon_ciu_mask_all_interrupts)
beqz t0, 1b
nop
j mpentry
nop
END(octeon_ap_wait)
#endif

View File

@ -1,83 +0,0 @@
/***********************license start***************
* Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). 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.
*
* * Neither the name of Cavium Networks nor the names of
* its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
* AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
* OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
* RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
* REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
* DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
* OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
* PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
* POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT
* OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
*
*
* For any questions regarding licensing please contact marketing@caviumnetworks.com
*
***********************license end**************************************/
/*------------------------------------------------------------------
* octeon_fau.c Fetch & Add Block
*
*------------------------------------------------------------------
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <mips/cavium/octeon_pcmap_regs.h>
#include "octeon_fau.h"
/*
* oct_fau_init
*
* How do we initialize FAU unit. I don't even think we can reset it.
*/
void octeon_fau_init (void)
{
}
/*
* oct_fau_enable
*
* Let the Fetch/Add unit roll
*/
void octeon_fau_enable (void)
{
}
/*
* oct_fau_disable
*
* disable fau
*
* Don't know if we can even do that.
*/
void octeon_fau_disable (void)
{
}

View File

@ -217,9 +217,4 @@ static inline void octeon_fau_atomic_add64 (octeon_fau_reg_64_t reg, int64_t val
}
extern void octeon_fau_init(void);
extern void octeon_fau_enable(void);
extern void octeon_fau_disable(void);
#endif /* ___OCTEON_FAU__H___ */

View File

@ -1481,7 +1481,7 @@ static void octeon_config_hw_units_post_ports (void)
oct_write64(OCTEON_POW_WORKQUEUE_INT_THRESHOLD(OCTEON_POW_RX_GROUP_NUM), thr.word64);
#endif
ciu_enable_interrupts(OCTEON_CORE_ID, OCTEON_RGMX_CIU_INTX, OCTEON_RGMX_CIU_ENX,
ciu_enable_interrupts(PCPU_GET(cpuid), OCTEON_RGMX_CIU_INTX, OCTEON_RGMX_CIU_ENX,
(OCTEON_POW_RX_GROUP_MASK |
CIU_GENTIMER_BITS_ENABLE(CIU_GENTIMER_NUM_1)), CIU_MIPS_IP2);

View File

@ -1,8 +1,7 @@
# $FreeBSD$
# Octeon Support Files
#
mips/mips/mp_machdep.c optional smp
mips/cavium/dev/rgmii/octeon_fau.c optional rgmii
mips/cavium/asm_octeon.S optional smp
mips/cavium/dev/rgmii/octeon_fpa.c optional rgmii
mips/cavium/dev/rgmii/octeon_ipd.c optional rgmii
mips/cavium/dev/rgmii/octeon_pko.c optional rgmii
@ -10,6 +9,7 @@ mips/cavium/dev/rgmii/octeon_rgmx.c optional rgmii
mips/cavium/obio.c optional uart
mips/cavium/octeon_ebt3000_cf.c optional cf
mips/cavium/octeon_machdep.c standard
mips/cavium/octeon_mp.c optional smp
mips/cavium/uart_bus_octeonusart.c optional uart
mips/cavium/uart_cpu_octeonusart.c optional uart
mips/cavium/uart_dev_oct16550.c optional uart

View File

@ -111,25 +111,6 @@ platform_reset(void)
oct_write64(OCTEON_CIU_SOFT_RST, 1);
}
static inline uint32_t
octeon_disable_interrupts(void)
{
uint32_t status_bits;
status_bits = mips_rd_status();
mips_wr_status(status_bits & ~MIPS_SR_INT_IE);
return (status_bits);
}
static inline void
octeon_set_interrupts(uint32_t status_bits)
{
mips_wr_status(status_bits);
}
void
octeon_led_write_char(int char_position, char val)
{
@ -203,82 +184,6 @@ octeon_led_run_wheel(int *prog_count, int led_position)
*prog_count &= 0x7;
}
#define LSR_DATAREADY 0x01 /* Data ready */
#define LSR_THRE 0x20 /* Transmit holding register empty */
#define LSR_TEMT 0x40 /* Transmitter Empty. THR, TSR & FIFO */
#define USR_TXFIFO_NOTFULL 0x02 /* Uart TX FIFO Not full */
/*
* octeon_uart_write_byte
*
* Put out a single byte off of uart port.
*/
void
octeon_uart_write_byte(int uart_index, uint8_t ch)
{
uint64_t val, val2;
if (uart_index < 0 || uart_index > 1)
return;
while (1) {
val = oct_read64(OCTEON_MIO_UART0_LSR + (uart_index * 0x400));
val2 = oct_read64(OCTEON_MIO_UART0_USR + (uart_index * 0x400));
if ((((uint8_t) val) & LSR_THRE) ||
(((uint8_t) val2) & USR_TXFIFO_NOTFULL)) {
break;
}
}
/* Write the byte */
oct_write8(OCTEON_MIO_UART0_THR + (uart_index * 0x400), (uint64_t) ch);
/* Force Flush the IOBus */
oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
}
void
octeon_uart_write_byte0(uint8_t ch)
{
uint64_t val, val2;
while (1) {
val = oct_read64(OCTEON_MIO_UART0_LSR);
val2 = oct_read64(OCTEON_MIO_UART0_USR);
if ((((uint8_t) val) & LSR_THRE) ||
(((uint8_t) val2) & USR_TXFIFO_NOTFULL)) {
break;
}
}
/* Write the byte */
oct_write8(OCTEON_MIO_UART0_THR, (uint64_t) ch);
/* Force Flush the IOBus */
oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
}
/*
* octeon_uart_write_string
*
*/
void
octeon_uart_write_string(int uart_index, const char *str)
{
/* Just loop writing one byte at a time */
while (*str) {
octeon_uart_write_byte(uart_index, *str);
if (*str == '\n') {
octeon_uart_write_byte(uart_index, '\r');
}
str++;
}
}
static char wstr[30];
void
octeon_led_write_hex(uint32_t wl)
{
@ -289,44 +194,6 @@ octeon_led_write_hex(uint32_t wl)
}
void octeon_uart_write_hex2(uint32_t wl, uint32_t wh)
{
sprintf(wstr, "0x%X-0x%X ", wh, wl);
octeon_uart_write_string(0, wstr);
}
void
octeon_uart_write_hex(uint32_t wl)
{
sprintf(wstr, " 0x%X ", wl);
octeon_uart_write_string(0, wstr);
}
/*
* octeon_wait_uart_flush
*/
void
octeon_wait_uart_flush(int uart_index, uint8_t ch)
{
uint64_t val;
int64_t val3;
uint32_t cpu_status_bits;
if (uart_index < 0 || uart_index > 1)
return;
cpu_status_bits = octeon_disable_interrupts();
/* Force Flush the IOBus */
oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
for (val3 = 0xfffffffff; val3 > 0; val3--) {
val = oct_read64(OCTEON_MIO_UART0_LSR + (uart_index * 0x400));
if (((uint8_t) val) & LSR_TEMT)
break;
}
octeon_set_interrupts(cpu_status_bits);
}
/*
* octeon_debug_symbol
*
@ -450,17 +317,17 @@ ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip)
/* XXX kasserts? */
if (enx < CIU_EN_0 || enx > CIU_EN_1) {
printf("%s: invalid enx value %d, should be %d or %d\n",
__FUNCTION__, enx, CIU_EN_0, CIU_EN_1);
__func__, enx, CIU_EN_0, CIU_EN_1);
return 0;
}
if (intx < CIU_INT_0 || intx > CIU_INT_1) {
printf("%s: invalid intx value %d, should be %d or %d\n",
__FUNCTION__, enx, CIU_INT_0, CIU_INT_1);
__func__, enx, CIU_INT_0, CIU_INT_1);
return 0;
}
if (ciu_ip < CIU_MIPS_IP2 || ciu_ip > CIU_MIPS_IP3) {
printf("%s: invalid ciu_ip value %d, should be %d or %d\n",
__FUNCTION__, ciu_ip, CIU_MIPS_IP2, CIU_MIPS_IP3);
__func__, ciu_ip, CIU_MIPS_IP2, CIU_MIPS_IP3);
return 0;
}
@ -517,7 +384,7 @@ ciu_clear_int_summary(int core_num, int intx, int enx, uint64_t write_bits)
core_num, intx, enx, write_bits);
#endif
cpu_status_bits = octeon_disable_interrupts();
cpu_status_bits = intr_disable();
ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx);
@ -535,7 +402,7 @@ ciu_clear_int_summary(int core_num, int intx, int enx, uint64_t write_bits)
printf(" Readback: 0x%llX\n\n ", (uint64_t) oct_read64(ciu_intr_sum_reg_addr));
#endif
octeon_set_interrupts(cpu_status_bits);
intr_restore(cpu_status_bits);
}
/*
@ -550,7 +417,7 @@ ciu_disable_intr(int core_num, int intx, int enx)
if (core_num == CIU_THIS_CORE)
core_num = octeon_get_core_num();
cpu_status_bits = octeon_disable_interrupts();
cpu_status_bits = intr_disable();
ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
@ -559,7 +426,7 @@ ciu_disable_intr(int core_num, int intx, int enx)
oct_write64(ciu_intr_reg_addr, 0LL);
oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */
octeon_set_interrupts(cpu_status_bits);
intr_restore(cpu_status_bits);
}
void
@ -580,7 +447,7 @@ ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip)
#endif
if (!ciu_intr_reg_addr) {
printf("Bad call to %s\n", __FUNCTION__);
printf("Bad call to %s\n", __func__);
while(1);
return;
}
@ -612,7 +479,7 @@ void ciu_enable_interrupts(int core_num, int intx, int enx,
core_num, intx, enx, ciu_ip, set_these_interrupt_bits);
#endif
cpu_status_bits = octeon_disable_interrupts();
cpu_status_bits = intr_disable();
#ifndef OCTEON_SMP_1
ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
@ -621,7 +488,7 @@ void ciu_enable_interrupts(int core_num, int intx, int enx,
#endif
if (!ciu_intr_reg_addr) {
printf("Bad call to %s\n", __FUNCTION__);
printf("Bad call to %s\n", __func__);
while(1);
return; /* XXX */
}
@ -634,7 +501,7 @@ void ciu_enable_interrupts(int core_num, int intx, int enx,
#endif
ciu_intr_bits |= set_these_interrupt_bits;
oct_write64(ciu_intr_reg_addr, ciu_intr_bits);
#ifdef OCTEON_SMP
#ifdef SMP
mips_wbflush();
#endif
oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */
@ -644,7 +511,7 @@ void ciu_enable_interrupts(int core_num, int intx, int enx,
(uint64_t)oct_read64(ciu_intr_reg_addr));
#endif
octeon_set_interrupts(cpu_status_bits);
intr_restore(cpu_status_bits);
}
unsigned long
@ -659,12 +526,8 @@ octeon_memory_init(void)
uint32_t realmem_bytes;
if (octeon_board_real()) {
printf("octeon_dram == %jx\n", (intmax_t)octeon_dram);
printf("reduced to ram: %u MB", (uint32_t)octeon_dram >> 20);
realmem_bytes = (octeon_dram - PAGE_SIZE);
realmem_bytes &= ~(PAGE_SIZE - 1);
printf("Real memory bytes is %x\n", realmem_bytes);
} else {
/* Simulator we limit to 96 meg */
realmem_bytes = (96 << 20);
@ -678,8 +541,6 @@ octeon_memory_init(void)
phys_avail[1] = realmem_bytes;
realmem_bytes -= OCTEON_DRAM_FIRST_256_END;
realmem_bytes &= ~(PAGE_SIZE - 1);
printf("phys_avail[0] = %#lx phys_avail[1] = %#lx\n",
(long)phys_avail[0], (long)phys_avail[1]);
} else {
/* Simulator gets 96Meg period. */
phys_avail[1] = (96 << 20);
@ -705,23 +566,14 @@ octeon_memory_init(void)
realmem_bytes &= ~(PAGE_SIZE - 1);
/* Now map the rest of the memory */
phys_avail[2] = 0x20000000;
printf("realmem_bytes is now at %x\n", realmem_bytes);
phys_avail[3] = ((uint32_t) 0x20000000 + realmem_bytes);
printf("Next block of memory goes from %#lx to %#lx\n",
(long)phys_avail[2], (long)phys_avail[3]);
physmem += btoc(phys_avail[3] - phys_avail[2]);
} else {
printf("realmem_bytes is %d\n", realmem_bytes);
}
realmem = physmem;
printf("Total DRAM Size %#X\n", (uint32_t) octeon_dram);
printf("Bank 0 = %#08lX -> %#08lX\n", (long)phys_avail[0], (long)phys_avail[1]);
printf("Bank 1 = %#08lX -> %#08lX\n", (long)phys_avail[2], (long)phys_avail[3]);
printf("physmem: %#lx\n", physmem);
Maxmem = physmem;
}
void
@ -760,7 +612,15 @@ platform_start(__register_t a0, __register_t a1, __register_t a2 __unused,
kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
#endif
platform_counter_freq = octeon_get_clock_rate();
mips_timer_init_params(platform_counter_freq, 1);
mips_timer_init_params(platform_counter_freq, 0);
#ifdef SMP
/*
* Clear any pending IPIs and enable the IPI interrupt.
*/
oct_write64(OCTEON_CIU_MBOX_CLRX(0), 0xffffffff);
ciu_enable_interrupts(0, CIU_INT_1, CIU_EN_0, OCTEON_CIU_ENABLE_MBOX_INTR, CIU_MIPS_IP3);
#endif
}
/* impSTART: This stuff should move back into the Cavium SDK */
@ -982,7 +842,7 @@ octeon_boot_params_init(register_t ptr)
printf("Boot Descriptor Ver: %u -> %u/%u",
octeon_bd_ver, octeon_cvmx_bd_ver/100, octeon_cvmx_bd_ver%100);
printf(" CPU clock: %uMHz\n", octeon_cpu_clock/1000000);
printf(" CPU clock: %uMHz Core Mask: %#x\n", octeon_cpu_clock/1000000, octeon_core_mask);
printf(" Dram: %u MB", (uint32_t)(octeon_dram >> 20));
printf(" Board Type: %u Revision: %u/%u\n",
octeon_board_type, octeon_board_rev_major, octeon_board_rev_minor);

102
sys/mips/cavium/octeon_mp.c Normal file
View File

@ -0,0 +1,102 @@
/*-
* Copyright (c) 2004-2010 Juli Mallett <jmallett@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
*
* $FreeBSD$
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <machine/hwfunc.h>
#include <machine/smp.h>
#include <mips/cavium/octeon_pcmap_regs.h>
unsigned octeon_ap_boot = ~0;
void
platform_ipi_send(int cpuid)
{
oct_write64(OCTEON_CIU_MBOX_SETX(cpuid), 1);
mips_wbflush();
}
void
platform_ipi_clear(void)
{
uint64_t action;
action = oct_read64(OCTEON_CIU_MBOX_CLRX(PCPU_GET(cpuid)));
KASSERT(action == 1, ("unexpected IPIs: %#jx", (uintmax_t)action));
oct_write64(OCTEON_CIU_MBOX_CLRX(PCPU_GET(cpuid)), action);
}
int
platform_ipi_intrnum(void)
{
return (1);
}
void
platform_init_ap(int cpuid)
{
/*
* Set the exception base.
*/
mips_wr_prid1(0x80000000 | cpuid);
/*
* Set up interrupts, clear IPIs and unmask the IPI interrupt.
*/
octeon_ciu_reset();
oct_write64(OCTEON_CIU_MBOX_CLRX(cpuid), 0xffffffff);
ciu_enable_interrupts(cpuid, CIU_INT_1, CIU_EN_0, OCTEON_CIU_ENABLE_MBOX_INTR, CIU_MIPS_IP3);
mips_wbflush();
}
int
platform_num_processors(void)
{
return (fls(octeon_core_mask));
}
int
platform_start_ap(int cpuid)
{
if (atomic_cmpset_32(&octeon_ap_boot, ~0, cpuid) == 0)
return (-1);
for (;;) {
DELAY(1000);
if (atomic_cmpset_32(&octeon_ap_boot, 0, ~0) != 0)
return (0);
printf("Waiting for cpu%d to start\n", cpuid);
}
}

View File

@ -54,14 +54,6 @@
#ifndef LOCORE
/* XXXimp: From Cavium's include/pcpu.h, need to port that over */
#ifndef OCTEON_SMP
#define OCTEON_CORE_ID 0
#else
extern struct pcpu *cpuid_to_pcpu[];
#define OCTEON_CORE_ID (mips_rd_coreid())
#endif
/*
* Utility inlines & macros
*/
@ -324,62 +316,6 @@ static inline void oct_write32 (uint64_t csr_addr, uint32_t val32)
#define OCTEON_SCRATCH_2 32
static inline uint64_t oct_mf_chord (void)
{
uint64_t dest;
__asm __volatile ( ".set push\n"
".set noreorder\n"
".set noat\n"
".set mips64\n"
"dmfc2 $1, 0x400\n"
"move %0, $1\n"
".set pop\n"
: "=r" (dest) : : "$1");
return dest;
}
#define MIPS64_DMFCz(cop,regnum,cp0reg,select) \
.word (0x40200000 | (cop << 25) | (regnum << 16) | (cp0reg << 11) | select)
#define mips64_getcpz_xstr(s) mips64_getcpz_str(s)
#define mips64_getcpz_str(s) #s
#define mips64_dgetcpz(cop,cpzreg,sel,val_ptr) \
({ __asm __volatile( \
".set push\n" \
".set mips3\n" \
".set noreorder\n" \
".set noat\n" \
mips64_getcpz_xstr(MIPS64_DMFCz(cop,1,cpzreg,sel)) "\n" \
"nop\n" \
"nop\n" \
"nop\n" \
"nop\n" \
"sd $1,0(%0)\n" \
".set pop" \
: /* no outputs */ : "r" (val_ptr) : "$1"); \
})
#define mips64_dgetcp2(cp2reg,sel,retval_ptr) \
mips64_dgetcpz(2,cp2reg,sel,retval_ptr)
#define OCTEON_MF_CHORD(dest) mips64_dgetcp2(0x400, 0, &dest)
#define OCTEON_RDHWR(result, regstr) \
__asm __volatile ( \
".set mips3\n" \
"rdhwr %0,$" OCTEON_TMP_STR(regstr) "\n" \
".set mips\n" \
: "=d" (result));
#define CVMX_MF_CHORD(dest) OCTEON_RDHWR(dest, 30)
#define OCTEON_CHORD_HEX(dest_ptr) \
({ __asm __volatile( \
@ -397,15 +333,6 @@ static inline uint64_t oct_mf_chord (void)
: /* no outputs */ : "r" (dest_ptr) : "$2"); \
})
#define OCTEON_MF_CHORD_BAD(dest) \
__asm __volatile ( \
".set mips3\n" \
"dmfc2 %0, 0x400\n" \
".set mips0\n" \
: "=&r" (dest) : )
static inline uint64_t oct_scratch_read64 (uint64_t address)
{
return(*((volatile uint64_t *)(OCTEON_SCRATCH_BASE + address)));
@ -417,17 +344,6 @@ static inline void oct_scratch_write64 (uint64_t address, uint64_t value)
}
#define OCTEON_READ_CSR32(addr, val) \
addr_ptr = addr; \
oct_read_32_ptr(&addr_ptr, &val);
#define OCTEON_WRITE_CSR32(addr, val, val_dummy) \
addr_ptr = addr; \
oct_write_32_ptr(&addr_ptr, &val); \
oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
/*
* Octeon Address Space Definitions
*/
@ -791,12 +707,6 @@ extern void octeon_led_write_hexchar(int char_position, char hexval);
extern void octeon_led_write_hex(uint32_t wl);
extern void octeon_led_write_string(const char *str);
extern void octeon_reset(void);
extern void octeon_uart_write_byte(int uart_index, uint8_t ch);
extern void octeon_uart_write_string(int uart_index, const char *str);
extern void octeon_uart_write_hex(uint32_t wl);
extern void octeon_uart_write_hex2(uint32_t wl, uint32_t wh);
extern void octeon_wait_uart_flush(int uart_index, uint8_t ch);
extern void octeon_uart_write_byte0(uint8_t ch);
extern void octeon_led_write_char0(char val);
extern void octeon_led_run_wheel(int *pos, int led_position);
extern void octeon_debug_symbol(void);

View File

@ -162,6 +162,18 @@ VECTOR(_locore, unknown)
sw a2, _C_LABEL(fenvp)
#endif
#if defined(TARGET_OCTEON) && defined(SMP)
.set push
.set mips32r2
rdhwr t2, $0
beqz t2, 1f
nop
j octeon_ap_wait
nop
.set pop
1:
#endif
/*
* Initialize stack and call machine startup.
*/
@ -178,10 +190,10 @@ VECTOR(_locore, unknown)
nop
PTR_LA sp, _C_LABEL(thread0)
lw a0, TD_PCB(sp)
li t0, ~7
PTR_L a0, TD_PCB(sp)
REG_LI t0, ~7
and a0, a0, t0
subu sp, a0, CALLFRAME_SIZ
PTR_SUBU sp, a0, CALLFRAME_SIZ
jal _C_LABEL(mi_startup) # mi_startup(frame)
sw zero, CALLFRAME_SIZ - 8(sp) # Zero out old fp for debugger

View File

@ -157,6 +157,8 @@ start_ap(int cpuid)
cpus = mp_naps;
dpcpu = (void *)kmem_alloc(kernel_map, DPCPU_SIZE);
mips_sync();
if (platform_start_ap(cpuid) != 0)
return (-1); /* could not start AP */
@ -246,6 +248,8 @@ smp_init_secondary(u_int32_t cpuid)
mips_dcache_wbinv_all();
mips_icache_sync_all();
mips_sync();
MachSetPID(0);
pcpu_init(PCPU_ADDR(cpuid), cpuid, sizeof(struct pcpu));

View File

@ -36,8 +36,21 @@
.set noat
.set noreorder
#ifdef TARGET_OCTEON
#define CLEAR_STATUS \
mfc0 a0, COP_0_STATUS_REG ;\
li a2, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) ; \
or a0, a0, a2 ; \
li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER | MIPS_SR_BEV) ; \
and a0, a0, a2 ; \
mtc0 a0, COP_0_STATUS_REG
#else
#define CLEAR_STATUS \
mtc0 zero, COP_0_STATUS_REG
#endif
GLOBAL(mpentry)
mtc0 zero, COP_0_STATUS_REG /* disable interrupts */
CLEAR_STATUS /* disable interrupts */
mtc0 zero, COP_0_CAUSE_REG /* clear soft interrupts */