summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2010-01-09 18:59:03 +0000
committerimp <imp@FreeBSD.org>2010-01-09 18:59:03 +0000
commite50f5ca653b02dbbd242aa85e2c021d2fca6fe6a (patch)
treecbc238f7e17a4917c1e7c3b93aa3a528dfc4bf6d
parent163965d76ff445ba40ea87abfbdaff6b84dab74d (diff)
parent75f6d17b0e6c09d65b88078c4f9eb12e4e637651 (diff)
downloadFreeBSD-src-e50f5ca653b02dbbd242aa85e2c021d2fca6fe6a.zip
FreeBSD-src-e50f5ca653b02dbbd242aa85e2c021d2fca6fe6a.tar.gz
Merge from projects/mips to head by hand:
Copy the support files for the Octeon 1 CPU from sys/mips/octeon1 on the projects/mips side to sys/mips/cavium on the head side to conform to the other vendor code. This code was contributed by Cavium to the project and forward ported by Warner Losh, with some additional code from Randal Stewart. # I'll fix the building problems the move creates in a future commit.
-rw-r--r--sys/mips/cavium/asm_octeon.S143
-rw-r--r--sys/mips/cavium/dev/rgmii/octeon_fau.c42
-rw-r--r--sys/mips/cavium/dev/rgmii/octeon_fau.h185
-rw-r--r--sys/mips/cavium/dev/rgmii/octeon_fpa.c187
-rw-r--r--sys/mips/cavium/dev/rgmii/octeon_fpa.h219
-rw-r--r--sys/mips/cavium/dev/rgmii/octeon_ipd.c107
-rw-r--r--sys/mips/cavium/dev/rgmii/octeon_ipd.h164
-rw-r--r--sys/mips/cavium/dev/rgmii/octeon_pip.h179
-rw-r--r--sys/mips/cavium/dev/rgmii/octeon_pko.c337
-rw-r--r--sys/mips/cavium/dev/rgmii/octeon_pko.h292
-rw-r--r--sys/mips/cavium/dev/rgmii/octeon_rgmx.c2222
-rw-r--r--sys/mips/cavium/dev/rgmii/octeon_rgmx.h590
-rw-r--r--sys/mips/cavium/driveid.h259
-rw-r--r--sys/mips/cavium/files.octeon117
-rw-r--r--sys/mips/cavium/obio.c182
-rw-r--r--sys/mips/cavium/obiovar.h58
-rw-r--r--sys/mips/cavium/octeon_ebt3000_cf.c621
-rw-r--r--sys/mips/cavium/octeon_ebt3000_cf.h35
-rw-r--r--sys/mips/cavium/octeon_machdep.c965
-rw-r--r--sys/mips/cavium/octeon_pcmap_regs.h1080
-rw-r--r--sys/mips/cavium/octeonreg.h247
-rw-r--r--sys/mips/cavium/std.octeon122
-rw-r--r--sys/mips/cavium/uart_bus_octeonusart.c121
-rw-r--r--sys/mips/cavium/uart_cpu_octeonusart.c191
-rw-r--r--sys/mips/cavium/uart_dev_oct16550.c827
25 files changed, 9292 insertions, 0 deletions
diff --git a/sys/mips/cavium/asm_octeon.S b/sys/mips/cavium/asm_octeon.S
new file mode 100644
index 0000000..e4df30e
--- /dev/null
+++ b/sys/mips/cavium/asm_octeon.S
@@ -0,0 +1,143 @@
+
+#include <machine/asm.h>
+#include <machine/cache_r4k.h>
+#include <machine/cpuregs.h>
+#include <machine/param.h>
+#include <machine/pte.h>
+
+#include "assym.s"
+
+
+
+#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 ;
+
+
+
+
+/*
+ * 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
+ */
+LEAF(octeon_ciu_get_interrupt_reg_addr)
+ .set noreorder
+ .set mips3
+
+ 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
+ */
+LEAF(octeon_ciu_mask_all_interrupts)
+ .set noreorder
+ .set mips3
+
+ 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)
+
+ POPR(s0)
+ POPR(ra)
+ j ra # Return
+ nop # (bd slot)
+
+ .set mips0
+ .set reorder
+END(octeon_ciu_mask_all_interrupts)
+
diff --git a/sys/mips/cavium/dev/rgmii/octeon_fau.c b/sys/mips/cavium/dev/rgmii/octeon_fau.c
new file mode 100644
index 0000000..849ffd4
--- /dev/null
+++ b/sys/mips/cavium/dev/rgmii/octeon_fau.c
@@ -0,0 +1,42 @@
+/*------------------------------------------------------------------
+ * octeon_fau.c Fetch & Add Block
+ *
+ *------------------------------------------------------------------
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <mips/octeon1/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)
+{
+}
diff --git a/sys/mips/cavium/dev/rgmii/octeon_fau.h b/sys/mips/cavium/dev/rgmii/octeon_fau.h
new file mode 100644
index 0000000..fc87395
--- /dev/null
+++ b/sys/mips/cavium/dev/rgmii/octeon_fau.h
@@ -0,0 +1,185 @@
+/*------------------------------------------------------------------
+ * octeon_fau.h Fetch & Add Unit
+ *
+ *------------------------------------------------------------------
+ */
+
+
+#ifndef ___OCTEON_FAU__H___
+#define ___OCTEON_FAU__H___
+
+
+
+
+typedef enum {
+ OCTEON_FAU_OP_SIZE_8 = 0,
+ OCTEON_FAU_OP_SIZE_16 = 1,
+ OCTEON_FAU_OP_SIZE_32 = 2,
+ OCTEON_FAU_OP_SIZE_64 = 3
+} octeon_fau_op_size_t;
+
+
+
+#define OCTEON_FAU_LOAD_IO_ADDRESS octeon_build_io_address(0x1e, 0)
+#define OCTEON_FAU_BITS_SCRADDR 63,56
+#define OCTEON_FAU_BITS_LEN 55,48
+#define OCTEON_FAU_BITS_INEVAL 35,14
+#define OCTEON_FAU_BITS_TAGWAIT 13,13
+#define OCTEON_FAU_BITS_NOADD 13,13
+#define OCTEON_FAU_BITS_SIZE 12,11
+#define OCTEON_FAU_BITS_REGISTER 10,0
+
+#define OCTEON_FAU_REG_64_ADDR(x) ((x <<3) + OCTEON_FAU_REG_64_START)
+typedef enum
+{
+ OCTEON_FAU_REG_64_START = 0,
+ OCTEON_FAU_REG_OQ_ADDR_INDEX = OCTEON_FAU_REG_64_ADDR(0),
+ OCTEON_FAU_REG_OQ_ADDR_END = OCTEON_FAU_REG_64_ADDR(31),
+ OCTEON_FAU_REG_64_END = OCTEON_FAU_REG_64_ADDR(39),
+} octeon_fau_reg_64_t;
+
+#define OCTEON_FAU_REG_32_ADDR(x) ((x <<2) + OCTEON_FAU_REG_32_START)
+typedef enum
+{
+ OCTEON_FAU_REG_32_START = OCTEON_FAU_REG_64_END,
+ OCTEON_FAU_REG_32_END = OCTEON_FAU_REG_32_ADDR(0),
+} octeon_fau_reg_32_t;
+
+
+
+/*
+ * octeon_fau_atomic_address
+ *
+ * Builds a I/O address for accessing the FAU
+ *
+ * @param tagwait Should the atomic add wait for the current tag switch
+ * operation to complete.
+ * - 0 = Don't wait
+ * - 1 = Wait for tag switch to complete
+ * @param reg FAU atomic register to access. 0 <= reg < 4096.
+ * - Step by 2 for 16 bit access.
+ * - Step by 4 for 32 bit access.
+ * - Step by 8 for 64 bit access.
+ * @param value Signed value to add.
+ * Note: When performing 32 and 64 bit access, only the low
+ * 22 bits are available.
+ * @return Address to read from for atomic update
+ */
+static inline uint64_t octeon_fau_atomic_address (uint64_t tagwait, uint64_t reg,
+ int64_t value)
+{
+ return (OCTEON_ADD_IO_SEG(OCTEON_FAU_LOAD_IO_ADDRESS) |
+ octeon_build_bits(OCTEON_FAU_BITS_INEVAL, value) |
+ octeon_build_bits(OCTEON_FAU_BITS_TAGWAIT, tagwait) |
+ octeon_build_bits(OCTEON_FAU_BITS_REGISTER, reg));
+}
+
+
+/*
+ * octeon_fau_store_address
+ *
+ * Builds a store I/O address for writing to the FAU
+ *
+ * noadd 0 = Store value is atomically added to the current value
+ * 1 = Store value is atomically written over the current value
+ * reg FAU atomic register to access. 0 <= reg < 4096.
+ * - Step by 2 for 16 bit access.
+ * - Step by 4 for 32 bit access.
+ * - Step by 8 for 64 bit access.
+ * Returns Address to store for atomic update
+ */
+static inline uint64_t octeon_fau_store_address (uint64_t noadd, uint64_t reg)
+{
+ return (OCTEON_ADD_IO_SEG(OCTEON_FAU_LOAD_IO_ADDRESS) |
+ octeon_build_bits(OCTEON_FAU_BITS_NOADD, noadd) |
+ octeon_build_bits(OCTEON_FAU_BITS_REGISTER, reg));
+}
+
+
+/*
+ * octeon_fau_atomic_add32
+ *
+ * Perform an atomic 32 bit add
+ *
+ * @param reg FAU atomic register to access. 0 <= reg < 4096.
+ * - Step by 4 for 32 bit access.
+ * @param value Signed value to add.
+ */
+static inline void octeon_fau_atomic_add32 (octeon_fau_reg_32_t reg, int32_t value)
+{
+ oct_write32(octeon_fau_store_address(0, reg), value);
+}
+
+/*
+ * octeon_fau_fetch_and_add
+ *
+ * reg FAU atomic register to access. 0 <= reg < 4096.
+ * - Step by 8 for 64 bit access.
+ * value Signed value to add.
+ * Note: Only the low 22 bits are available.
+ * returns Value of the register before the update
+ */
+static inline int64_t octeon_fau_fetch_and_add64 (octeon_fau_reg_64_t reg,
+ int64_t val64)
+{
+
+ return (oct_read64(octeon_fau_atomic_address(0, reg, val64)));
+}
+
+/*
+ * octeon_fau_fetch_and_add32
+ *
+ * reg FAU atomic register to access. 0 <= reg < 4096.
+ * - Step by 8 for 64 bit access.
+ * value Signed value to add.
+ * Note: Only the low 22 bits are available.
+ * returns Value of the register before the update
+ */
+static inline int32_t octeon_fau_fetch_and_add32 (octeon_fau_reg_64_t reg,
+ int32_t val32)
+{
+ return (oct_read32(octeon_fau_atomic_address(0, reg, val32)));
+}
+
+/*
+ * octeon_fau_atomic_write32
+ *
+ * Perform an atomic 32 bit write
+ *
+ * @param reg FAU atomic register to access. 0 <= reg < 4096.
+ * - Step by 4 for 32 bit access.
+ * @param value Signed value to write.
+ */
+static inline void octeon_fau_atomic_write32(octeon_fau_reg_32_t reg, int32_t value)
+{
+ oct_write32(octeon_fau_store_address(1, reg), value);
+}
+
+
+/*
+ * octeon_fau_atomic_write64
+ *
+ * Perform an atomic 32 bit write
+ *
+ * reg FAU atomic register to access. 0 <= reg < 4096.
+ * - Step by 8 for 64 bit access.
+ * value Signed value to write.
+ */
+static inline void octeon_fau_atomic_write64 (octeon_fau_reg_64_t reg, int64_t value)
+{
+ oct_write64(octeon_fau_store_address(1, reg), value);
+}
+
+
+static inline void octeon_fau_atomic_add64 (octeon_fau_reg_64_t reg, int64_t value)
+{
+ oct_write64_int64(octeon_fau_store_address(0, reg), value);
+}
+
+
+extern void octeon_fau_init(void);
+extern void octeon_fau_enable(void);
+extern void octeon_fau_disable(void);
+
+
+#endif /* ___OCTEON_FAU__H___ */
diff --git a/sys/mips/cavium/dev/rgmii/octeon_fpa.c b/sys/mips/cavium/dev/rgmii/octeon_fpa.c
new file mode 100644
index 0000000..b5d8f7c
--- /dev/null
+++ b/sys/mips/cavium/dev/rgmii/octeon_fpa.c
@@ -0,0 +1,187 @@
+/*------------------------------------------------------------------
+ * octeon_fpa.c Free Pool Allocator
+ *
+ *------------------------------------------------------------------
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+
+#include <mips/octeon1/octeon_pcmap_regs.h>
+#include "octeon_fpa.h"
+
+
+//#define FPA_DEBUG 1
+
+/*
+ * octeon_dump_fpa
+ *
+ */
+void octeon_dump_fpa (void)
+{
+ int i;
+ octeon_fpa_ctl_status_t status;
+ octeon_fpa_queue_available_t q_avail;
+
+ status.word64 = oct_read64(OCTEON_FPA_CTL_STATUS);
+ if (!status.bits.enb) {
+ printf("\n FPA Disabled");
+ /*
+ * No dumping if disabled
+ */
+ return;
+ }
+ printf(" FPA Ctrl-Status-reg 0x%llX := 0x%llX EN %X M1_E %X M0_E %X\n",
+ OCTEON_FPA_CTL_STATUS, (unsigned long long)status.word64,
+ status.bits.enb, status.bits.mem1_err, status.bits.mem0_err);
+ for (i = 0; i < OCTEON_FPA_QUEUES; i++) {
+ printf(" Pool: %d\n", i);
+
+ q_avail.word64 = oct_read64((OCTEON_FPA_QUEUE_AVAILABLE + (i)*8ull));
+ printf(" Avail-reg 0x%llX := Size: 0x%X\n",
+ (OCTEON_FPA_QUEUE_AVAILABLE + (i)*8ull), q_avail.bits.queue_size);
+ }
+}
+
+void octeon_dump_fpa_pool (u_int pool)
+{
+ octeon_fpa_ctl_status_t status;
+ octeon_fpa_queue_available_t q_avail;
+
+ status.word64 = oct_read64(OCTEON_FPA_CTL_STATUS);
+ if (!status.bits.enb) {
+ printf("\n FPA Disabled");
+ /*
+ * No dumping if disabled
+ */
+ return;
+ }
+ printf(" FPA Ctrl-Status-reg 0x%llX := 0x%llX EN %X M1_E %X M0_E %X\n",
+ OCTEON_FPA_CTL_STATUS, (unsigned long long)status.word64,
+ status.bits.enb, status.bits.mem1_err, status.bits.mem0_err);
+ q_avail.word64 = oct_read64((OCTEON_FPA_QUEUE_AVAILABLE + (pool)*8ull));
+ printf(" FPA Pool: %u Avail-reg 0x%llX := Size: 0x%X\n", pool,
+ (OCTEON_FPA_QUEUE_AVAILABLE + (pool)*8ull), q_avail.bits.queue_size);
+}
+
+
+u_int octeon_fpa_pool_size (u_int pool)
+{
+ octeon_fpa_queue_available_t q_avail;
+ u_int size = 0;
+
+ if (pool < 7) {
+ q_avail.word64 = oct_read64((OCTEON_FPA_QUEUE_AVAILABLE + (pool)*8ull));
+ size = q_avail.bits.queue_size;
+ }
+ return (size);
+}
+
+
+/*
+ * octeon_enable_fpa
+ *
+ * configure fpa with defaults and then mark it enabled.
+ */
+void octeon_enable_fpa (void)
+{
+ int i;
+ octeon_fpa_ctl_status_t status;
+ octeon_fpa_fpf_marks_t marks;
+
+ for (i = 0; i < OCTEON_FPA_QUEUES; i++) {
+ marks.word64 = oct_read64((OCTEON_FPA_FPF_MARKS + (i)*8ull));
+
+ marks.bits.fpf_wr = 0xe0;
+ oct_write64((OCTEON_FPA_FPF_MARKS + (i)*8ull), marks.word64);
+ }
+
+ /* Enforce a 10 cycle delay between config and enable */
+ octeon_wait(10);
+
+ status.word64 = 0;
+ status.bits.enb = 1;
+ oct_write64(OCTEON_FPA_CTL_STATUS, status.word64);
+}
+
+
+//#define FPA_DEBUG_TERSE 1
+
+/*
+ * octeon_fpa_fill_pool_mem
+ *
+ * Fill the specified FPA pool with elem_num number of
+ * elements of size elem_size_words * 8
+ */
+void octeon_fpa_fill_pool_mem (u_int pool, u_int elem_size_words, u_int elem_num)
+{
+ void *memory;
+ u_int bytes, elem_size_bytes;
+ u_int block_size;
+
+#ifdef FPA_DEBUG
+ u_int elems = elem_num;
+ printf(" FPA fill: Pool %u elem_size_words %u Num: %u\n", pool, elem_size_words, elem_num);
+#endif
+ elem_size_bytes = elem_size_words * sizeof(uint64_t);
+ block_size = OCTEON_ALIGN(elem_size_bytes);
+
+// block_size = ((elem_size_bytes / OCTEON_FPA_POOL_ALIGNMENT) + 1) * OCTEON_FPA_POOL_ALIGNMENT;
+
+ bytes = (elem_num * block_size);
+
+#ifdef FPA_DEBUG
+ printf(" elem_size_bytes = words * 8 = %u; block_size %u\n", elem_size_bytes, block_size);
+#endif
+
+
+#ifdef FPA_DEBUG
+ int block = 0;
+
+ printf(" %% Filling Pool %u with %u blocks of %u bytes %u words\n",
+ pool, elem_num, elem_size_bytes, elem_size_words);
+#endif
+
+// memory = malloc(bytes, M_DEVBUF, M_NOWAIT | M_ZERO);
+ memory = contigmalloc(bytes, M_DEVBUF, M_NOWAIT | M_ZERO,
+ 0, 0x20000000,
+ OCTEON_FPA_POOL_ALIGNMENT, 0);
+
+ if (memory == NULL) {
+ printf(" %% FPA pool %u could not be filled with %u bytes\n",
+ pool, bytes);
+ return;
+ }
+
+ /*
+ * Forward Align allocated mem to needed alignment. Don't worry about growth, we
+ * already preallocated extra
+ */
+#ifdef FPA_DEBUG
+ printf(" %% Huge MemBlock 0x%X Bytes %u\n", memory, bytes);
+#endif
+
+ memory = (void *) OCTEON_ALIGN(memory);
+
+#ifdef FPA_DEBUG_TERSE
+ printf("FPA fill: %u Count: %u SizeBytes: %u SizeBytesAligned: %u 1st: 0x%X = %p\n",
+ pool, elem_num, elem_size_bytes, block_size, memory, (void *)OCTEON_PTR2PHYS(memory));
+#endif
+
+// memory = (void *) ((((u_int) memory / OCTEON_FPA_POOL_ALIGNMENT) + 1) * OCTEON_FPA_POOL_ALIGNMENT);
+
+ while (elem_num--) {
+#ifdef FPA_DEBUG
+ if (((elems - elem_num) < 4) || (elem_num < 4))
+ printf(" %% Block %d: 0x%X Phys 0x%X Bytes %u\n", block, memory, OCTEON_PTR2PHYS(memory), elem_size_bytes);
+ block++;
+#endif
+ octeon_fpa_free(memory, pool, 0);
+ memory = (void *) (((u_long) memory) + block_size);
+ }
+}
+
diff --git a/sys/mips/cavium/dev/rgmii/octeon_fpa.h b/sys/mips/cavium/dev/rgmii/octeon_fpa.h
new file mode 100644
index 0000000..174ff73
--- /dev/null
+++ b/sys/mips/cavium/dev/rgmii/octeon_fpa.h
@@ -0,0 +1,219 @@
+/*------------------------------------------------------------------
+ * octeon_fpa.h Free Pool Allocator
+ *
+ *------------------------------------------------------------------
+ */
+
+
+#ifndef ___OCTEON_FPA__H___
+#define ___OCTEON_FPA__H___
+
+
+#define OCTEON_FPA_FPA_OUTPUT_BUFFER_POOL 2 /* Same in octeon_rgmx.h */
+
+
+/*
+ * OCTEON_FPA_FPF_MARKS = FPA's Queue Free Page FIFO Read Write Marks
+ *
+ * The high and low watermark register that determines when we write and
+ * read free pages from L2C for Queue.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 42; /* Must be zero */
+ uint64_t fpf_wr : 11; /* Write Hi Water mark */
+ uint64_t fpf_rd : 11; /* Read Lo Water mark */
+ } bits;
+} octeon_fpa_fpf_marks_t;
+
+
+/*
+ * OCTEON_FPA_CTL_STATUS = FPA's Control/Status Register
+ *
+ * The FPA's interrupt enable register.
+ * - Use with the CVMX_FPA_CTL_STATUS CSR.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 49; /* Must be zero */
+ uint64_t enb : 1; /* Enable */
+ uint64_t mem1_err : 7; /* ECC flip 1 */
+ uint64_t mem0_err : 7; /* ECC flip 0 */
+ } bits;
+} octeon_fpa_ctl_status_t;
+
+
+/*
+ * OCTEON_FPA_FPF_SIZE = FPA's Queue N Free Page FIFO Size
+ *
+ * The number of page pointers that will be kept local to the FPA for
+ * this Queue. FPA Queues are assigned in order from Queue 0 to
+ * Queue 7, though only Queue 0 through Queue x can be used.
+ * The sum of the 8 (0-7)OCTEON_FPA_FPF#_SIZE registers must be limited to 2048.
+ * - Use with the CVMX_FPA_FPF0_SIZE CSR.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 52; /* Must be zero */
+ /*
+ * The number of entries assigned in the FPA FIFO (used to hold
+ * page-pointers) for this Queue.
+ * The value of this register must divisable by 2, and the FPA will
+ * ignore bit [0] of this register.
+ * The total of the FPF_SIZ field of the 8 (0-7)OCTEON_FPA_FPF#_MARKS
+ * registers must not exceed 2048.
+ * After writing this field the FPA will need 10 core clock cycles
+ * to be ready for operation. The assignment of location in
+ * the FPA FIFO must start with Queue 0, then 1, 2, etc.
+ * The number of useable entries will be FPF_SIZ-2.
+ */
+ uint64_t fpf_siz : 12;
+ } bits;
+} octeon_fpa_fpf_size_t;
+
+/*
+ *OCTEON_FPA_INT_ENB = FPA's Interrupt Enable
+ *
+ * The FPA's interrupt enable register.
+ * - Use with the CVMX_FPA_INT_ENB CSR.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 60; /* Must be zero */
+ uint64_t fed1_dbe : 1; /* Int iff bit3 Int-Sum set */
+ uint64_t fed1_sbe : 1; /* Int iff bit2 Int-Sum set */
+ uint64_t fed0_dbe : 1; /* Int iff bit1 Int-Sum set */
+ uint64_t fed0_sbe : 1; /* Int iff bit0 Int-Sum set */
+ } bits;
+} octeon_fpa_int_enb_t;
+
+/**
+ *OCTEON_FPA_INT_SUM = FPA's Interrupt Summary Register
+ *
+ * Contains the diffrent interrupt summary bits of the FPA.
+ * - Use with the CVMX_FPA_INT_SUM CSR.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 60; /**< Must be zero */
+ uint64_t fed1_dbe : 1;
+ uint64_t fed1_sbe : 1;
+ uint64_t fed0_dbe : 1;
+ uint64_t fed0_sbe : 1;
+ } bits;
+} octeon_fpa_int_sum_t;
+
+
+/*
+ *OCTEON_FPA_QUEUE_PAGES_AVAILABLE = FPA's Queue 0-7 Free Page Available Register
+ *
+ * The number of page pointers that are available in the FPA and local DRAM.
+ * - Use with the CVMX_FPA_QUEX_AVAILABLE(0..7) CSR.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 38; /* Must be zero */
+ uint64_t queue_size : 26; /* free pages available */
+ } bits;
+} octeon_fpa_queue_available_t;
+
+
+/*
+ *OCTEON_FPA_QUEUE_PAGE_INDEX
+ *
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 39; /* Must be zero */
+ uint64_t page_index : 25; /* page_index */
+ } bits;
+} octeon_fpa_queue_page_index_t;
+
+
+#define OCTEON_DID_FPA 5ULL
+
+#define OCTEON_FPA_POOL_ALIGNMENT (OCTEON_CACHE_LINE_SIZE)
+
+
+/*
+ * Externs
+ */
+extern void octeon_dump_fpa(void);
+extern void octeon_dump_fpa_pool(u_int pool);
+extern u_int octeon_fpa_pool_size(u_int pool);
+extern void octeon_enable_fpa(void);
+extern void octeon_fpa_fill_pool_mem(u_int pool,
+ u_int block_size_words,
+ u_int block_num);
+
+/*
+ * octeon_fpa_free
+ *
+ * Free a mem-block to FPA pool.
+ *
+ * Takes away this 'buffer' from SW and passes it to FPA for management.
+ *
+ * pool is FPA pool num, ptr is block ptr, num_cache_lines is number of
+ * cache lines to invalidate (not written back).
+ */
+static inline void octeon_fpa_free (void *ptr, u_int pool,
+ u_int num_cache_lines)
+{
+ octeon_addr_t free_ptr;
+
+ free_ptr.word64 = (uint64_t)OCTEON_PTR2PHYS(ptr);
+
+ free_ptr.sfilldidspace.didspace = OCTEON_ADDR_DIDSPACE(
+ OCTEON_ADDR_FULL_DID(OCTEON_DID_FPA, pool));
+
+ /*
+ * Do not 'sync'
+ * asm volatile ("sync\n");
+ */
+ oct_write64(free_ptr.word64, num_cache_lines);
+}
+
+
+
+/*
+ * octeon_fpa_alloc
+ *
+ * Allocate a new block from the FPA
+ *
+ * Buffer passes away from FPA management to SW control
+ */
+static inline void *octeon_fpa_alloc (u_int pool)
+{
+ uint64_t address;
+
+ address = oct_read64(OCTEON_ADDR_DID(OCTEON_ADDR_FULL_DID(OCTEON_DID_FPA,
+ pool)));
+ if (address) {
+
+/*
+ * 32 bit FPA pointers only
+ */
+ /*
+ * We only use 32 bit pointers at this time
+ */
+/*XXX mips64 issue */
+ return ((void *) MIPS_PHYS_TO_KSEG0(address & 0xffffffff));
+ }
+ return (NULL);
+}
+
+static inline uint64_t octeon_fpa_alloc_phys (u_int pool)
+{
+
+ return (oct_read64(OCTEON_ADDR_DID(OCTEON_ADDR_FULL_DID(OCTEON_DID_FPA,
+ pool))));
+}
+
+#endif /* ___OCTEON_FPA__H___ */
diff --git a/sys/mips/cavium/dev/rgmii/octeon_ipd.c b/sys/mips/cavium/dev/rgmii/octeon_ipd.c
new file mode 100644
index 0000000..069b537
--- /dev/null
+++ b/sys/mips/cavium/dev/rgmii/octeon_ipd.c
@@ -0,0 +1,107 @@
+/*------------------------------------------------------------------
+ * octeon_ipd.c Input Packet Unit
+ *
+ *------------------------------------------------------------------
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <mips/octeon1/octeon_pcmap_regs.h>
+#include "octeon_ipd.h"
+
+/*
+ * octeon_ipd_enable
+ *
+ * enable ipd
+ */
+void octeon_ipd_enable (void)
+{
+ octeon_ipd_ctl_status_t octeon_ipd_reg;
+
+ octeon_ipd_reg.word64 = oct_read64(OCTEON_IPD_CTL_STATUS);
+ octeon_ipd_reg.bits.ipd_en = 1;
+ oct_write64(OCTEON_IPD_CTL_STATUS, octeon_ipd_reg.word64);
+}
+
+
+/*
+ * octeon_ipd_disable
+ *
+ * disable ipd
+ */
+void octeon_ipd_disable (void)
+{
+ octeon_ipd_ctl_status_t octeon_ipd_reg;
+
+ octeon_ipd_reg.word64 = oct_read64(OCTEON_IPD_CTL_STATUS);
+ octeon_ipd_reg.bits.ipd_en = 0;
+ oct_write64(OCTEON_IPD_CTL_STATUS, octeon_ipd_reg.word64);
+}
+
+
+/*
+ * octeon_ipd_config
+ *
+ * Configure IPD
+ *
+ * mbuff_size Packets buffer size in 8 byte words
+ * first_mbuff_skip
+ * Number of 8 byte words to skip in the first buffer
+ * not_first_mbuff_skip
+ * Number of 8 byte words to skip in each following buffer
+ * first_back Must be same as first_mbuff_skip / Cache_Line_size
+ * second_back
+ * Must be same as not_first_mbuff_skip / Cache_Line_Size
+ * wqe_fpa_pool
+ * FPA pool to get work entries from
+ * cache_mode
+ * back_pres_enable_flag
+ * Enable or disable port back pressure
+ */
+void octeon_ipd_config (u_int mbuff_size,
+ u_int first_mbuff_skip,
+ u_int not_first_mbuff_skip,
+ u_int first_back,
+ u_int second_back,
+ u_int wqe_fpa_pool,
+ octeon_ipd_mode_t cache_mode,
+ u_int back_pres_enable_flag)
+{
+ octeon_ipd_mbuff_first_skip_t first_skip;
+ octeon_ipd_mbuff_not_first_skip_t not_first_skip;
+ octeon_ipd_mbuff_size_t size;
+ octeon_ipd_first_next_ptr_back_t first_back_struct;
+ octeon_ipd_second_next_ptr_back_t second_back_struct;
+ octeon_ipd_wqe_fpa_pool_t wqe_pool;
+ octeon_ipd_ctl_status_t octeon_ipd_ctl_reg;
+
+ first_skip.word64 = 0;
+ first_skip.bits.skip_sz = first_mbuff_skip;
+ oct_write64(OCTEON_IPD_1ST_MBUFF_SKIP, first_skip.word64);
+
+ not_first_skip.word64 = 0;
+ not_first_skip.bits.skip_sz = not_first_mbuff_skip;
+ oct_write64(OCTEON_IPD_NOT_1ST_MBUFF_SKIP, not_first_skip.word64);
+
+ size.word64 = 0;
+ size.bits.mb_size = mbuff_size;
+ oct_write64(OCTEON_IPD_PACKET_MBUFF_SIZE, size.word64);
+
+ first_back_struct.word64 = 0;
+ first_back_struct.bits.back = first_back;
+ oct_write64(OCTEON_IPD_1ST_NEXT_PTR_BACK, first_back_struct.word64);
+
+ second_back_struct.word64 = 0;
+ second_back_struct.bits.back = second_back;
+ oct_write64(OCTEON_IPD_2ND_NEXT_PTR_BACK, second_back_struct.word64);
+
+ wqe_pool.word64 = 0;
+ wqe_pool.bits.wqe_pool = wqe_fpa_pool;
+ oct_write64(OCTEON_IPD_WQE_FPA_QUEUE, wqe_pool.word64);
+
+ octeon_ipd_ctl_reg.word64 = 0;
+ octeon_ipd_ctl_reg.bits.opc_mode = cache_mode;
+ octeon_ipd_ctl_reg.bits.pbp_en = back_pres_enable_flag;
+ oct_write64(OCTEON_IPD_CTL_STATUS, octeon_ipd_ctl_reg.word64);
+}
diff --git a/sys/mips/cavium/dev/rgmii/octeon_ipd.h b/sys/mips/cavium/dev/rgmii/octeon_ipd.h
new file mode 100644
index 0000000..21e26c8
--- /dev/null
+++ b/sys/mips/cavium/dev/rgmii/octeon_ipd.h
@@ -0,0 +1,164 @@
+/*------------------------------------------------------------------
+ * octeon_ipd.h Input Packet Unit
+ *
+ *------------------------------------------------------------------
+ */
+
+
+#ifndef ___OCTEON_IPD__H___
+#define ___OCTEON_IPD__H___
+
+
+
+typedef enum {
+ OCTEON_IPD_OPC_MODE_STT = 0LL, /* All blocks DRAM, not cached in L2 */
+ OCTEON_IPD_OPC_MODE_STF = 1LL, /* All blocks into L2 */
+ OCTEON_IPD_OPC_MODE_STF1_STT = 2LL, /* 1st block L2, rest DRAM */
+ OCTEON_IPD_OPC_MODE_STF2_STT = 3LL /* 1st, 2nd blocks L2, rest DRAM */
+} octeon_ipd_mode_t;
+
+
+
+
+/*
+ * IPD_CTL_STATUS = IPS'd Control Status Register
+ * The number of words in a MBUFF used for packet data store.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 58; /* Reserved */
+ uint64_t pkt_lend : 1; /* Pkt Lil-Endian Writes to L2C */
+ uint64_t wqe_lend : 1; /* WQE Lik-Endian Writes to L2C */
+ uint64_t pbp_en : 1; /* Enable Back-Pressure */
+ octeon_ipd_mode_t opc_mode : 2; /* Pkt data in Mem/L2-cache ? */
+ uint64_t ipd_en : 1; /* Enable IPD */
+ } bits;
+} octeon_ipd_ctl_status_t;
+
+
+/*
+ * IPD_1ST_NEXT_PTR_BACK = IPD First Next Pointer Back Values
+ *
+ * Contains the Back Field for use in creating the Next Pointer Header
+ * for the First MBUF
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 60; /* Must be zero */
+ uint64_t back : 4; /* Used to find head of buffer from the nxt-hdr-ptr. */
+ } bits;
+} octeon_ipd_first_next_ptr_back_t;
+
+
+/*
+ * IPD_INTERRUPT_ENB = IPD Interrupt Enable Register
+ *
+ * Used to enable the various interrupting conditions of IPD
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 59; /* Must be zero */
+ uint64_t bp_sub : 1; /* BP subtract is illegal val */
+ uint64_t prc_par3 : 1; /* PBM Bits [127:96] Parity Err */
+ uint64_t prc_par2 : 1; /* PBM Bits [ 95:64] Parity Err */
+ uint64_t prc_par1 : 1; /* PBM Bits [ 63:32] Parity Err */
+ uint64_t prc_par0 : 1; /* PBM Bits [ 31:0 ] Parity Err */
+ } bits;
+} octeon_ipd_int_enb_t;
+
+
+/*
+ * IPD_INTERRUPT_SUM = IPD Interrupt Summary Register
+ *
+ * Set when an interrupt condition occurs, write '1' to clear.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 59; /* Must be zero */
+ uint64_t bp_sub : 1; /* BP subtract is illegal val */
+ uint64_t prc_par3 : 1; /* PBM Bits [127:96] Parity Err */
+ uint64_t prc_par2 : 1; /* PBM Bits [ 95:64] Parity Err */
+ uint64_t prc_par1 : 1; /* PBM Bits [ 63:32] Parity Err */
+ uint64_t prc_par0 : 1; /* PBM Bits [ 31:0 ] Parity Err */
+ } bits;
+} octeon_ipd_int_sum_t;
+
+
+/**
+ * IPD_1ST_MBUFF_SKIP = IPD First MBUFF Word Skip Size
+ *
+ * The number of words that the IPD will skip when writing the first MBUFF.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 58; /* Must be zero */
+ uint64_t skip_sz : 6; /* 64bit words from the top of */
+ /* 1st MBUFF that the IPD will */
+ /* store the next-pointer. */
+ /* [0..32] && */
+ /* (skip_sz + 16) <= IPD_PACKET_MBUFF_SIZE[MB_SIZE]. */
+ } bits;
+} octeon_ipd_mbuff_first_skip_t;
+
+
+/*
+ * IPD_PACKET_MBUFF_SIZE = IPD's PACKET MUBUF Size In Words
+ *
+ * The number of words in a MBUFF used for packet data store.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 52; /* Must be zero */
+ uint64_t mb_size : 12; /* 64bit words in a MBUF. */
+ /* Must be [32..2048] */
+ /* Is also the size of the FPA's */
+ /* Queue-0 Free-Page */
+ } bits;
+} octeon_ipd_mbuff_size_t;
+
+
+/*
+ * IPD_WQE_FPA_QUEUE = IPD Work-Queue-Entry FPA Page Size
+ *
+ * Which FPA Queue (0-7) to fetch page-pointers from for WQE's
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 61; /* Must be zero */
+ uint64_t wqe_pool : 3; /* FPA Pool to fetch WQE Page-ptrs */
+ } bits;
+} octeon_ipd_wqe_fpa_pool_t;
+
+
+
+
+/* End of Control and Status Register (CSR) definitions */
+
+typedef octeon_ipd_mbuff_first_skip_t octeon_ipd_mbuff_not_first_skip_t;
+typedef octeon_ipd_first_next_ptr_back_t octeon_ipd_second_next_ptr_back_t;
+
+
+/*
+ * Externs
+ */
+extern void octeon_ipd_enable(void);
+extern void octeon_ipd_disable(void);
+extern void octeon_ipd_config(u_int mbuff_size,
+ u_int first_mbuff_skip,
+ u_int not_first_mbuff_skip,
+ u_int first_back,
+ u_int second_back,
+ u_int wqe_fpa_pool,
+ octeon_ipd_mode_t cache_mode,
+ u_int back_pres_enable_flag);
+
+
+
+#endif /* ___OCTEON_IPD__H___ */
diff --git a/sys/mips/cavium/dev/rgmii/octeon_pip.h b/sys/mips/cavium/dev/rgmii/octeon_pip.h
new file mode 100644
index 0000000..f474e5e
--- /dev/null
+++ b/sys/mips/cavium/dev/rgmii/octeon_pip.h
@@ -0,0 +1,179 @@
+/*
+ * octeon_pip.h Packet Input Processing Block
+ *
+ */
+
+
+
+#ifndef __OCTEON_PIP_H__
+#define __OCTEON_PIP_H__
+
+/**
+ * Enumeration representing the amount of packet processing
+ * and validation performed by the input hardware.
+ */
+typedef enum
+{
+ OCTEON_PIP_PORT_CFG_MODE_NONE = 0ull, /**< Packet input doesn't perform any
+ processing of the input packet. */
+ OCTEON_PIP_PORT_CFG_MODE_SKIPL2 = 1ull,/**< Full packet processing is performed
+ with pointer starting at the L2
+ (ethernet MAC) header. */
+ OCTEON_PIP_PORT_CFG_MODE_SKIPIP = 2ull /**< Input packets are assumed to be IP.
+ Results from non IP packets is
+ undefined. Pointers reference the
+ beginning of the IP header. */
+} octeon_pip_port_parse_mode_t;
+
+
+
+#define OCTEON_PIP_PRT_CFGX(offset) (0x80011800A0000200ull+((offset)*8))
+#define OCTEON_PIP_PRT_TAGX(offset) (0x80011800A0000400ull+((offset)*8))
+#define OCTEON_PIP_STAT_INB_PKTS(port) (0x80011800A0001A00ull+((port) * 32))
+#define OCTEON_PIP_STAT_INB_ERRS(port) (0x80011800A0001A10ull+((port) * 32))
+
+/*
+ * PIP Global Config
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved2 : 45; /* Must be zero */
+ uint64_t tag_syn : 1; /* Not Include src_crc in TCP..*/
+ uint64_t ip6_udp : 1; /* IPv6/UDP checksum is mandatory */
+ uint64_t max_l2 : 1; /* Largest L2 frame. 0/1 : 1500/1535 */
+ uint64_t reserved1 : 5; /* Must be zero */
+ uint64_t raw_shf : 3; /* PCI RAW Packet shift/pad amount */
+ uint64_t reserved0 : 5; /* Must be zero */
+ uint64_t nip_shf : 3; /* Non-IP shift/pad amount */
+ } bits;
+} octeon_pip_gbl_cfg_t;
+
+
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved4 : 37; /* Must be zero */
+ uint64_t qos : 3; /* Default POW QoS queue */
+ uint64_t qos_wat : 4; /* Bitfield to enable QoS watcher */
+ /* look up tables. 4 per port. */
+ uint64_t reserved3 : 1; /* Must be zero */
+ uint64_t spare : 1; /* Must be zero */
+ uint64_t qos_diff : 1; /* Use IP diffserv to determine */
+ /* the queue in the POW */
+ uint64_t qos_vlan : 1; /* Use the VLAN tag to determine */
+ /* the queue in the POW */
+ uint64_t reserved2 : 3; /* Must be zero */
+ uint64_t crc_en : 1; /* Enable HW checksum */
+ uint64_t reserved1 : 2; /* Must be zero */
+ octeon_pip_port_parse_mode_t mode : 2; /* Raw/Parsed/IP/etc */
+ uint64_t reserved0 : 1; /* Must be zero */
+ uint64_t skip : 7; /* 8 byte words to skip in the */
+ /* beginning of a packet buffer */
+ } bits;
+} octeon_pip_port_cfg_t;
+
+
+
+/*
+ * Packet input to POW interface. How input packets are tagged for
+ * the POW is controlled here.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 24; /**< Reserved */
+ uint64_t grptagbase : 4; /**< Offset to use when computing group from tag bits
+ when GRPTAG is set. Only applies to IP packets.
+ (PASS2 only) */
+ uint64_t grptagmask : 4; /**< Which bits of the tag to exclude when computing
+ group when GRPTAG is set. Only applies to IP packets.
+ (PASS2 only) */
+ uint64_t grptag : 1; /**< When set, use the lower bit of the tag to compute
+ the group in the work queue entry
+ GRP = WQE[TAG[3:0]] & ~GRPTAGMASK + GRPTAGBASE.
+ Only applies to IP packets. (PASS2 only) */
+ uint64_t spare : 1; /**< Spare bit
+ (PASS2 only) */
+ uint64_t tag_mode : 2; /**< Which tag algorithm to use
+ 0 = always use tuple tag algorithm
+ 1 = always use mask tag algorithm
+ 2 = if packet is IP, use tuple else use mask
+ 3 = tuple XOR mask
+ (PASS2 only) */
+ uint64_t inc_vs : 2; /**< determines the VLAN ID (VID) to be included in
+ tuple tag when VLAN stacking is detected
+ 0 = do not include VID in tuple tag generation
+ 1 = include VID (VLAN0) in hash
+ 2 = include VID (VLAN1) in hash
+ 3 = include VID ([VLAN0,VLAN1]) in hash
+ (PASS2 only) */
+ uint64_t inc_vlan : 1; /**< when set, the VLAN ID is included in tuple tag
+ when VLAN stacking is not detected
+ 0 = do not include VID in tuple tag generation
+ 1 = include VID in hash
+ (PASS2 only) */
+ uint64_t inc_prt_flag : 1; /**< sets whether the port is included in tuple tag */
+ uint64_t ip6_dprt_flag : 1; /**< sets whether the TCP/UDP dst port is
+ included in tuple tag for IPv6 packets */
+ uint64_t ip4_dprt_flag : 1; /**< sets whether the TCP/UDP dst port is
+ included in tuple tag for IPv4 */
+ uint64_t ip6_sprt_flag : 1; /**< sets whether the TCP/UDP src port is
+ included in tuple tag for IPv6 packets */
+ uint64_t ip4_sprt_flag : 1; /**< sets whether the TCP/UDP src port is
+ included in tuple tag for IPv4 */
+ uint64_t ip6_nxth_flag : 1; /**< sets whether ipv6 includes next header in tuple
+ tag hash */
+ uint64_t ip4_pctl_flag : 1; /**< sets whether ipv4 includes protocol in tuple
+ tag hash */
+ uint64_t ip6_dst_flag : 1; /**< sets whether ipv6 includes dst address in tuple
+ tag hash */
+ uint64_t ip4_dst_flag : 1; /**< sets whether ipv4 includes dst address in tuple
+ tag hash */
+ uint64_t ip6_src_flag : 1; /**< sets whether ipv6 includes src address in tuple
+ tag hash */
+ uint64_t ip4_src_flag : 1; /**< sets whether ipv4 includes src address in tuple
+ tag hash */
+ uint64_t tcp6_tag_type : 2; /**< sets the tag_type of a TCP packet (IPv6)
+ 0 = ordered tags
+ 1 = atomic tags
+ 2 = Null tags */
+ uint64_t tcp4_tag_type : 2; /**< sets the tag_type of a TCP packet (IPv4)
+ 0 = ordered tags
+ 1 = atomic tags
+ 2 = Null tags */
+ uint64_t ip6_tag_type : 2; /**< sets whether IPv6 packet tag type
+ 0 = ordered tags
+ 1 = atomic tags
+ 2 = Null tags */
+ uint64_t ip4_tag_type : 2; /**< sets whether IPv4 packet tag type
+ 0 = ordered tags
+ 1 = atomic tags
+ 2 = Null tags */
+ uint64_t non_tag_type : 2; /**< sets whether non-IP packet tag type
+ 0 = ordered tags
+ 1 = atomic tags
+ 2 = Null tags */
+ uint64_t grp : 4; /* POW group for input pkts */
+ } bits;
+} octeon_pip_port_tag_cfg_t;
+
+
+/**
+ * Configure an ethernet input port
+ *
+ * @param port_num Port number to configure
+ * @param port_cfg Port hardware configuration
+ * @param port_tag_cfg
+ * Port POW tagging configuration
+ */
+static inline void octeon_pip_config_port(u_int port_num,
+ octeon_pip_port_cfg_t port_cfg,
+ octeon_pip_port_tag_cfg_t port_tag_cfg)
+{
+ oct_write64(OCTEON_PIP_PRT_CFGX(port_num), port_cfg.word64);
+ oct_write64(OCTEON_PIP_PRT_TAGX(port_num), port_tag_cfg.word64);
+}
+
+
+#endif /* __OCTEON_PIP_H__ */
diff --git a/sys/mips/cavium/dev/rgmii/octeon_pko.c b/sys/mips/cavium/dev/rgmii/octeon_pko.c
new file mode 100644
index 0000000..cfd8cd4
--- /dev/null
+++ b/sys/mips/cavium/dev/rgmii/octeon_pko.c
@@ -0,0 +1,337 @@
+/*------------------------------------------------------------------
+ * octeon_pko.c Packet Output Unit
+ *
+ *------------------------------------------------------------------
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <mips/octeon1/octeon_pcmap_regs.h>
+#include "octeon_fau.h"
+#include "octeon_fpa.h"
+#include "octeon_pko.h"
+
+
+/*
+ *
+ */
+static void octeon_pko_clear_port_counts (u_int port)
+{
+ u_int port_num;
+ octeon_pko_read_idx_t octeon_pko_idx;
+
+ octeon_pko_idx.word64 = 0;
+ octeon_pko_idx.bits.idx = port;
+ octeon_pko_idx.bits.inc = 0;
+ oct_write64(OCTEON_PKO_REG_READ_IDX, octeon_pko_idx.word64);
+
+ port_num = port;
+ oct_write64(OCTEON_PKO_MEM_COUNT0, port_num);
+ port_num = port;
+ oct_write64(OCTEON_PKO_MEM_COUNT1, port_num);
+}
+
+/*
+ * octeon_pko_init
+ *
+ */
+void octeon_pko_init (void)
+{
+ u_int queue, port;
+ octeon_pko_read_idx_t octeon_pko_idx;
+ octeon_pko_queue_cfg_t octeon_pko_queue_cfg;
+
+ for (port = 0; port < OCTEON_PKO_PORTS_MAX; port++) {
+ octeon_pko_clear_port_counts(port);
+ }
+
+ octeon_pko_idx.word64 = 0;
+ octeon_pko_idx.bits.idx = 0;
+ octeon_pko_idx.bits.inc = 1;
+ oct_write64(OCTEON_PKO_REG_READ_IDX, octeon_pko_idx.word64);
+ for (queue = 0; queue < OCTEON_PKO_QUEUES_MAX; queue++) {
+
+ octeon_pko_queue_cfg.word64 = 0;
+ octeon_pko_queue_cfg.bits.queue = queue;
+ octeon_pko_queue_cfg.bits.port = OCTEON_PKO_PORT_ILLEGAL;
+ octeon_pko_queue_cfg.bits.buf_ptr = 0;
+ oct_write64(OCTEON_PKO_MEM_QUEUE_PTRS, octeon_pko_queue_cfg.word64);
+ }
+}
+
+
+/*
+ * octeon_pko_enable
+ *
+ * enable pko
+ */
+void octeon_pko_enable (void)
+{
+
+ /*
+ * PKO enable
+ */
+ oct_write64(OCTEON_PKO_REG_FLAGS, 3); /* octeon_pko_enable() */
+}
+
+
+/*
+ * octeon_pko_disable
+ *
+ * disable pko
+ */
+void octeon_pko_disable (void)
+{
+
+ /*
+ * PKO disable
+ */
+ oct_write64(OCTEON_PKO_REG_FLAGS, 0); /* pko_disable() */
+}
+
+/*
+ * octeon_pko_config_cmdbuf_global_defaults
+ *
+ */
+void octeon_pko_config_cmdbuf_global_defaults (u_int cmdbuf_pool,
+ u_int cmdbuf_pool_elem_size )
+{
+ octeon_pko_pool_cfg_t octeon_pko_pool_config;
+
+ octeon_pko_pool_config.word64 = 0;
+ octeon_pko_pool_config.bits.pool = cmdbuf_pool;
+ octeon_pko_pool_config.bits.size = cmdbuf_pool_elem_size;
+ oct_write64(OCTEON_PKO_CMD_BUF, octeon_pko_pool_config.word64);
+}
+
+/*
+ * octeon_pko_config_rgmx_ports
+ *
+ * Configure rgmx pko. Always enables 4 + 4 ports
+ */
+void octeon_pko_config_rgmx_ports (void)
+{
+ octeon_pko_reg_gmx_port_mode_t octeon_pko_gmx_mode;
+
+ octeon_pko_gmx_mode.word64 = 0;
+ octeon_pko_gmx_mode.bits.mode0 = 2; /* 16 >> 2 == 4 ports */
+ octeon_pko_gmx_mode.bits.mode1 = 2; /* 16 >> 2 == 4 ports */
+ oct_write64(OCTEON_PKO_GMX_PORT_MODE, octeon_pko_gmx_mode.word64);
+}
+
+
+/*
+ * octeon_pko_config
+ *
+ * Configure PKO
+ *
+ */
+void octeon_pko_config (void)
+{
+}
+
+/*
+ * octeon_pko_get_port_status
+ *
+ * Get the status counters for a PKO port.
+ *
+ * port_num Port number to get statistics for.
+ * clear Set to 1 to clear the counters after they are read
+ * status Where to put the results.
+ */
+void octeon_pko_get_port_status (u_int port, u_int clear,
+ octeon_pko_port_status_t *status)
+{
+ octeon_word_t packet_num;
+ octeon_pko_read_idx_t octeon_pko_idx;
+
+ packet_num.word64 = 0;
+
+ octeon_pko_idx.word64 = 0;
+ octeon_pko_idx.bits.idx = port;
+ octeon_pko_idx.bits.inc = 0;
+ oct_write64(OCTEON_PKO_REG_READ_IDX, octeon_pko_idx.word64);
+
+ packet_num.word64 = oct_read64(OCTEON_PKO_MEM_COUNT0);
+ status->packets = packet_num.bits.word32lo;
+
+ status->octets = oct_read64(OCTEON_PKO_MEM_COUNT1);
+ status->doorbell = oct_read64(OCTEON_PKO_MEM_DEBUG9);
+ status->doorbell = (status->doorbell >> 8) & 0xfffff;
+ if (clear) {
+ octeon_pko_clear_port_counts(port);
+ }
+}
+
+static void octeon_pko_doorbell_data_dump(uint64_t port);
+
+static void octeon_pko_doorbell_data_dump (uint64_t port)
+{
+ octeon_pko_port_status_t status;
+
+ octeon_pko_get_port_status(port, 0, &status);
+ printf("\n Port #%lld Pkts %ld Bytes %lld DoorBell %lld",
+ (unsigned long long)port, status.packets,
+ (unsigned long long)status.octets,
+ (unsigned long long)status.doorbell);
+}
+
+/*
+ * octeon_pko_show
+ *
+ * Show the OCTEON_PKO status & configs
+ */
+void octeon_pko_show (u_int start_port, u_int end_port)
+{
+ u_int queue, queue_max, gmx_int0_ports, gmx_int1_ports;
+ u_int port;
+ uint64_t val64;
+ octeon_pko_port_status_t status;
+ octeon_pko_pool_cfg_t octeon_pko_pool_config;
+ octeon_pko_read_idx_t octeon_pko_idx;
+ octeon_pko_queue_mode_t octeon_pko_queue_mode;
+ octeon_pko_reg_gmx_port_mode_t octeon_pko_gmx_mode;
+ octeon_pko_crc_ports_enable_t octeon_pko_crc_ports;
+ octeon_pko_queue_cfg_t octeon_pko_queue_cfg;
+
+ printf("\n\nPKO Status:");
+ val64 = oct_read64(OCTEON_PKO_REG_FLAGS);
+ if ((val64 & 0x3) != 0x3) {
+ printf(" Disabled");
+ return;
+ } else {
+ printf(" Enabled");
+ }
+ octeon_pko_queue_mode.word64 = oct_read64(OCTEON_PKO_QUEUE_MODE);
+ queue_max = (128 >> octeon_pko_queue_mode.bits.mode);
+ octeon_pko_gmx_mode.word64 = oct_read64(OCTEON_PKO_GMX_PORT_MODE);
+ gmx_int0_ports = (16 >> octeon_pko_gmx_mode.bits.mode0);
+ gmx_int1_ports = (16 >> octeon_pko_gmx_mode.bits.mode1);
+ octeon_pko_crc_ports.word64 = oct_read64(OCTEON_PKO_REG_CRC_ENABLE);
+ printf("\n Total Queues: 0..%d Ports GMX0 %d GMX1 %d CRC 0x%X",
+ queue_max - 1, gmx_int0_ports, gmx_int1_ports,
+ octeon_pko_crc_ports.bits.crc_ports_mask);
+
+ octeon_pko_pool_config.word64 = oct_read64(OCTEON_PKO_CMD_BUF);
+ printf("\n CmdBuf Pool: %d CmdBuf Size in Words: %d Bytes: %d",
+ octeon_pko_pool_config.bits.pool, octeon_pko_pool_config.bits.size,
+ octeon_pko_pool_config.bits.size * 8);
+
+ octeon_pko_idx.word64 = 0;
+ octeon_pko_idx.bits.idx = 0;
+ octeon_pko_idx.bits.inc = 1;
+ oct_write64(OCTEON_PKO_REG_READ_IDX, octeon_pko_idx.word64);
+ for (queue = 0; queue < queue_max; queue++) {
+
+ octeon_pko_queue_cfg.word64 = oct_read64(OCTEON_PKO_MEM_QUEUE_PTRS);
+ if (!octeon_pko_queue_cfg.bits.buf_ptr) continue;
+ printf("\n Port # %d Queue %3d [%d] BufPtr: 0x%llX Mask: %X%s",
+ octeon_pko_queue_cfg.bits.port, octeon_pko_queue_cfg.bits.queue,
+ octeon_pko_queue_cfg.bits.index,
+ (unsigned long long)octeon_pko_queue_cfg.bits.buf_ptr,
+ octeon_pko_queue_cfg.bits.qos_mask,
+ (octeon_pko_queue_cfg.bits.tail)? " Last":"");
+ }
+ printf("\n");
+
+ for (port = start_port; port < (end_port + 1); port++) {
+
+ octeon_pko_get_port_status(port, 0, &status);
+ octeon_pko_doorbell_data_dump(port);
+
+ }
+}
+
+
+
+
+/*
+ * octeon_pko_config_port
+ *
+ * Configure a output port and the associated queues for use.
+ *
+ */
+octeon_pko_status_t octeon_pko_config_port (u_int port,
+ u_int base_queue,
+ u_int num_queues,
+ const u_int priority[],
+ u_int pko_output_cmdbuf_fpa_pool,
+ octeon_pko_sw_queue_info_t sw_queues[])
+{
+ octeon_pko_status_t result_code;
+ u_int queue;
+ octeon_pko_queue_cfg_t qconfig;
+
+ if ((port >= OCTEON_PKO_PORTS_MAX) && (port != OCTEON_PKO_PORT_ILLEGAL)) {
+ printf("\n%% Error: octeon_pko_config_port: Invalid port %u", port);
+ return (OCTEON_PKO_INVALID_PORT);
+ }
+
+ if ((base_queue + num_queues) > OCTEON_PKO_QUEUES_MAX) {
+ printf("\n%% Error: octeon_pko_config_port: Invalid queue range");
+ return (OCTEON_PKO_INVALID_QUEUE);
+ }
+
+ result_code = OCTEON_PKO_SUCCESS;
+
+ for (queue = 0; queue < num_queues; queue++) {
+ uint64_t buf_ptr = 0;
+
+ qconfig.word64 = 0;
+ qconfig.bits.tail = (queue == (num_queues - 1)) ? 1 : 0;
+ qconfig.bits.index = queue;
+ qconfig.bits.port = port;
+ qconfig.bits.queue = base_queue + queue;
+
+ /* Convert the priority into an enable bit field. */
+ /* Try to space the bits out evenly so the pkts don't get grouped up */
+ switch ((int)priority[queue]) {
+ case 0: qconfig.bits.qos_mask = 0x00; break;
+ case 1: qconfig.bits.qos_mask = 0x01; break;
+ case 2: qconfig.bits.qos_mask = 0x11; break;
+ case 3: qconfig.bits.qos_mask = 0x49; break;
+ case 4: qconfig.bits.qos_mask = 0x55; break;
+ case 5: qconfig.bits.qos_mask = 0x57; break;
+ case 6: qconfig.bits.qos_mask = 0x77; break;
+ case 7: qconfig.bits.qos_mask = 0x7f; break;
+ case 8: qconfig.bits.qos_mask = 0xff; break;
+ default:
+ printf("\n%% Error: octeon_pko_config_port Invalid priority %llu",
+ (unsigned long long)priority[queue]);
+ qconfig.bits.qos_mask = 0xff;
+ result_code = OCTEON_PKO_INVALID_PRIORITY;
+ break;
+ }
+ if (port != OCTEON_PKO_PORT_ILLEGAL) {
+
+ buf_ptr = octeon_fpa_alloc_phys(pko_output_cmdbuf_fpa_pool);
+ if (!buf_ptr) {
+ printf("\n%% Error: octeon_pko_config_port: Unable to allocate");
+ return (OCTEON_PKO_NO_MEMORY);
+ }
+
+ sw_queues[queue].xmit_command_state = (buf_ptr << OCTEON_PKO_INDEX_BITS);
+ octeon_spinlock_init(&(sw_queues[queue].lock));
+
+//#define DEBUG_TX
+
+#ifdef DEBUG_TX
+ printf(" PKO: port %u pool: %u base+queue %u %u %u buf_ptr: 0x%llX\n",
+ port,
+ pko_output_cmdbuf_fpa_pool,
+ base_queue, queue, base_queue+queue,
+ buf_ptr);
+
+#endif
+ qconfig.bits.buf_ptr = buf_ptr;
+ oct_write64(OCTEON_PKO_MEM_QUEUE_PTRS, qconfig.word64);
+
+ }
+ }
+
+ return (result_code);
+}
+
diff --git a/sys/mips/cavium/dev/rgmii/octeon_pko.h b/sys/mips/cavium/dev/rgmii/octeon_pko.h
new file mode 100644
index 0000000..4ecc3b9
--- /dev/null
+++ b/sys/mips/cavium/dev/rgmii/octeon_pko.h
@@ -0,0 +1,292 @@
+/*------------------------------------------------------------------
+ * octeon_pko.h Packet Output Block
+ *
+ *------------------------------------------------------------------
+ */
+
+
+#ifndef ___OCTEON_PKO__H___
+#define ___OCTEON_PKO__H___
+
+
+
+/*
+ * PKO Command Buffer Register.
+ * Specify Pool-# and Size of each entry in Pool. For Output Cmd Buffers.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t unused_mbz : 41; /* Must be zero */
+ uint64_t pool : 3; /* FPA Pool to use */
+ uint64_t unused_mbz2 : 7; /* Must be zero */
+ uint64_t size : 13; /* Size of the pool blocks */
+ } bits;
+} octeon_pko_pool_cfg_t;
+
+
+/*
+ * PKO GMX Mode Register
+ * Specify the # of GMX1 ports and GMX0 ports
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t unused_mbz : 58; /* MBZ */
+ uint64_t mode1 : 3; /* # GMX1 ports; */
+ /* 16 >> MODE1, 0 <= MODE1 <=4 */
+ uint64_t mode0 : 3; /* # GMX0 ports; */
+ /* 16 >> MODE0, 0 <= MODE0 <=4 */
+ } bits;
+} octeon_pko_reg_gmx_port_mode_t;
+
+
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t unused_mbz : 62; /* MBZ */
+ uint64_t mode : 2; /* Queues Mode */
+ } bits;
+} octeon_pko_queue_mode_t;
+
+
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t unused_mbz : 32; /* MBZ */
+ uint64_t crc_ports_mask : 32; /* CRC Ports Enable mask */
+ } bits;
+} octeon_pko_crc_ports_enable_t;
+
+
+
+#define OCTEON_PKO_QUEUES_MAX 128
+#define OCTEON_PKO_PORTS_MAX 36
+#define OCTEON_PKO_PORT_ILLEGAL 63
+
+/* Defines how the PKO command buffer FAU register is used */
+
+#define OCTEON_PKO_INDEX_BITS 12
+#define OCTEON_PKO_INDEX_MASK ((1ull << OCTEON_PKO_INDEX_BITS) - 1)
+
+
+
+typedef enum {
+ OCTEON_PKO_SUCCESS,
+ OCTEON_PKO_INVALID_PORT,
+ OCTEON_PKO_INVALID_QUEUE,
+ OCTEON_PKO_INVALID_PRIORITY,
+ OCTEON_PKO_NO_MEMORY
+} octeon_pko_status_t;
+
+
+typedef struct {
+ long packets;
+ uint64_t octets;
+ uint64_t doorbell;
+} octeon_pko_port_status_t;
+
+
+typedef union {
+ uint64_t word64;
+ struct {
+ octeon_mips_space_t mem_space : 2; /* Octeon IO_SEG */
+ uint64_t unused_mbz :13; /* Must be zero */
+ uint64_t is_io : 1; /* Must be one */
+ uint64_t did : 8; /* device-ID on non-coherent bus*/
+ uint64_t unused_mbz2 : 4; /* Must be zero */
+ uint64_t unused_mbz3 :18; /* Must be zero */
+ uint64_t port : 6; /* output port */
+ uint64_t queue : 9; /* output queue to send */
+ uint64_t unused_mbz4 : 3; /* Must be zero */
+ } bits;
+} octeon_pko_doorbell_address_t;
+
+/*
+ * Structure of the first packet output command word.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ octeon_fau_op_size_t size1 : 2; /* The size of reg1 operation */
+ /* - could be 8, 16, 32, or 64 bits */
+ octeon_fau_op_size_t size0 : 2; /* The size of the reg0 operation */
+ /* - could be 8, 16, 32, or 64 bits */
+ uint64_t subone1 : 1; /* Subtract 1, else sub pkt size */
+ uint64_t reg1 :11; /* The register, subtract will be */
+ /* done if reg1 is non-zero */
+ uint64_t subone0 : 1; /* Subtract 1, else sub pkt size */
+ uint64_t reg0 :11; /* The register, subtract will be */
+ /* done if reg0 is non-zero */
+ uint64_t unused : 2; /* Must be zero */
+ uint64_t wqp : 1; /* If rsp, then word3 contains a */
+ /* ptr to a work queue entry */
+ uint64_t rsp : 1; /* HW will respond when done */
+ uint64_t gather : 1; /* If set, the supplied pkt_ptr is */
+ /* a ptr to a list of pkt_ptr's */
+ uint64_t ipoffp1 : 7; /* Off to IP hdr. For HW checksum */
+ uint64_t ignore_i : 1; /* Ignore I bit in all pointers */
+ uint64_t dontfree : 1; /* Don't free buffs containing pkt */
+ uint64_t segs : 6; /* Number of segs. If gather set, */
+ /* also gather list length */
+ uint64_t total_bytes :16; /* Includes L2, w/o trailing CRC */
+ } bits;
+} octeon_pko_command_word0_t;
+
+
+typedef union {
+ void* ptr;
+ uint64_t word64;
+ struct {
+ uint64_t i : 1; /* Invert the "free" pick of the overall pkt. */
+ /* For inbound pkts, HW always sets this to 0 */
+ uint64_t back : 4; /* Amount to back up to get to buffer start */
+ /* in cache lines. This is mostly less than 1 */
+ /* complete cache line; so the value is zero */
+ uint64_t pool : 3; /* FPA pool that the buffer belongs to */
+ uint64_t size :16; /* segment size (bytes) pointed at by addr */
+ uint64_t addr :40; /* Ptr to 1st data byte. NOT buffer */
+ } bits;
+} octeon_pko_packet_ptr_t;
+
+
+/*
+ * Definition of the hardware structure used to configure an
+ * output queue.
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t unused_mbz : 3; /* Must be zero */
+ uint64_t qos_mask : 8; /* Control Mask priority */
+ /* across 8 QOS levels */
+ uint64_t buf_ptr : 36; /* Command buffer pointer, */
+ /* 8 byte-aligned */
+ uint64_t tail : 1; /* Set if this queue is the tail */
+ /* of the port queue array */
+ uint64_t index : 3; /* Index (distance from head) in */
+ /* the port queue array */
+ uint64_t port : 6; /* Port ID for this queue mapping */
+ uint64_t queue : 7; /* Hardware queue number */
+ } bits;
+} octeon_pko_queue_cfg_t;
+
+
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t unused_mbz : 48;
+ uint64_t inc : 8;
+ uint64_t idx : 8;
+ } bits;
+} octeon_pko_read_idx_t;
+
+
+typedef struct octeon_pko_sw_queue_info_t_
+{
+ uint64_t xmit_command_state;
+ octeon_spinlock_t lock;
+ uint32_t pad[29];
+} octeon_pko_sw_queue_info_t;
+
+
+
+#define OCTEON_DID_PKT 10ULL
+#define OCTEON_DID_PKT_SEND OCTEON_ADDR_FULL_DID(OCTEON_DID_PKT,2ULL)
+
+
+/*
+ * Ring the packet output doorbell. This tells the packet
+ * output hardware that "len" command words have been added
+ * to its pending list. This command includes the required
+ * SYNCW before the doorbell ring.
+ *
+ * @param port Port the packet is for
+ * @param queue Queue the packet is for
+ * @param len Length of the command in 64 bit words
+ */
+extern void octeon_pko_doorbell_data(u_int port);
+
+//#define CORE_0_ONLY 1
+
+static inline void octeon_pko_ring_doorbell (u_int port, u_int queue,
+ u_int len)
+{
+ octeon_pko_doorbell_address_t ptr;
+
+ ptr.word64 = 0;
+ ptr.bits.mem_space = OCTEON_IO_SEG;
+ ptr.bits.did = OCTEON_DID_PKT_SEND;
+ ptr.bits.is_io = 1;
+ ptr.bits.port = port;
+ ptr.bits.queue = queue;
+ OCTEON_SYNCWS;
+ oct_write64(ptr.word64, len);
+}
+
+
+
+#define OCTEON_PKO_QUEUES_PER_PORT_INTERFACE0 1
+#define OCTEON_PKO_QUEUES_PER_PORT_INTERFACE1 1
+#define OCTEON_PKO_QUEUES_PER_PORT_PCI 1
+
+/*
+ * octeon_pko_get_base_queue
+ *
+ * For a given port number, return the base pko output queue
+ * for the port.
+ */
+static inline u_int octeon_pko_get_base_queue (u_int port)
+{
+ if (port < 16) {
+ return (port * OCTEON_PKO_QUEUES_PER_PORT_INTERFACE0);
+ }
+ if (port < 32) {
+ return (16 * OCTEON_PKO_QUEUES_PER_PORT_INTERFACE0 +
+ (port - 16) * OCTEON_PKO_QUEUES_PER_PORT_INTERFACE1);
+ }
+ return (16 * OCTEON_PKO_QUEUES_PER_PORT_INTERFACE0 +
+ 16 * OCTEON_PKO_QUEUES_PER_PORT_INTERFACE1 +
+ (port - 32) * OCTEON_PKO_QUEUES_PER_PORT_PCI);
+}
+
+
+/*
+ * For a given port number, return the number of pko output queues.
+ *
+ * @param port Port number
+ * @return Number of output queues
+ */
+static inline u_int octeon_pko_get_num_queues(u_int port)
+{
+ if (port < 16) {
+ return (OCTEON_PKO_QUEUES_PER_PORT_INTERFACE0);
+ } else if (port<32) {
+ return (OCTEON_PKO_QUEUES_PER_PORT_INTERFACE1);
+ }
+
+ return (OCTEON_PKO_QUEUES_PER_PORT_PCI);
+}
+
+
+
+/*
+ * Externs
+ */
+extern void octeon_pko_init(void);
+extern void octeon_pko_enable(void);
+extern void octeon_pko_disable(void);
+extern void octeon_pko_show(u_int start_port, u_int end_port);
+extern void octeon_pko_config(void);
+extern void octeon_pko_config_cmdbuf_global_defaults(u_int cmdbuf_pool, u_int elem_size);
+extern void octeon_pko_config_rgmx_ports(void);
+extern void octeon_pko_get_port_status(u_int, u_int, octeon_pko_port_status_t *status);
+extern octeon_pko_status_t octeon_pko_config_port(u_int port,
+ u_int base_queue,
+ u_int num_queues,
+ const u_int priority[],
+ u_int pko_output_cmdbuf_fpa_pool,
+ octeon_pko_sw_queue_info_t sw_queues[]);
+
+
+#endif /* ___OCTEON_PKO__H___ */
diff --git a/sys/mips/cavium/dev/rgmii/octeon_rgmx.c b/sys/mips/cavium/dev/rgmii/octeon_rgmx.c
new file mode 100644
index 0000000..af4aba3
--- /dev/null
+++ b/sys/mips/cavium/dev/rgmii/octeon_rgmx.c
@@ -0,0 +1,2222 @@
+/*
+ * octeon_rgmx.c RGMII Ethernet Interfaces on Octeon
+ *
+ */
+
+
+/*
+ * Driver for the Reduced Gigabit Media Independent Interface (RGMII)
+ * present on the Cavium Networks' Octeon chip.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/power.h>
+#include <sys/smp.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/malloc.h>
+#include <sys/kthread.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/taskqueue.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_mib.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <net/bpf.h>
+
+#include <machine/clock.h>
+#include <machine/locore.h>
+#include <machine/md_var.h>
+
+#include <mips/octeon1/octeon_pcmap_regs.h>
+
+#include "octeon_fau.h"
+#include "octeon_fpa.h"
+#include "octeon_ipd.h"
+#include "octeon_pko.h"
+#include "octeon_pip.h"
+#include "octeon_rgmx.h"
+
+
+/* The "battleship" boards have 8 ports */
+#define OCTEON_RGMX_NUM_PORTS_MAX 8
+#define NUM_TX_PACKETS 80
+#define NUM_RX_PACKETS 300
+#define MAX_RX_BUFS (NUM_RX_PACKETS) * (OCTEON_RGMX_NUM_PORTS_MAX)
+#define MAX_TX_BUFS (NUM_TX_PACKETS)
+#define OCTEON_RGMX_DEV_NAME "rgmx"
+#define OCTEON_RGMX_MIN_PORT 0
+#define OCTEON_RGMX_MAX_PORT 19
+#define OCTEON_RGMX_OQUEUE_PER_PORT 8
+
+
+#define OCTEON_RGMX_SCHEDULED_ISRS 1 /* Use Scheduled ISRs from kernel tasks */
+
+
+#ifndef POW_MAX_LOOP
+#define POW_MAX_LOOP 0x800
+#endif
+
+
+/*
+ * CIU related stuff for enabling POW interrupts
+ */
+#define OCTEON_RGMX_CIU_INTX CIU_INT_0
+#define OCTEON_RGMX_CIU_ENX CIU_EN_0
+
+MALLOC_DEFINE(M_RGMII_WQE, "rgmii_wqe", "FPA pool for WQEs");
+
+/* Driver data */
+
+struct rgmx_softc_dev {
+ device_t sc_dev; /* Device ID */
+ uint64_t link_status;
+ struct ifnet *ifp;
+ int sc_unit;
+
+ u_int port;
+ u_int idx;
+ u_char ieee[6];
+
+ char const * typestr; /* printable name of the interface. */
+ u_short txb_size; /* size of TX buffer, in bytes */
+
+ /* Transmission buffer management. */
+ u_short txb_free; /* free bytes in TX buffer */
+ u_char txb_count; /* number of packets in TX buffer */
+ u_char txb_sched; /* number of scheduled packets */
+
+ /* Media information. */
+ struct ifmedia media; /* used by if_media. */
+ u_short mbitmap; /* bitmap for supported media; see bit2media */
+ int defmedia; /* default media */
+ struct ifqueue tx_pending_queue; /* Queue of mbuf given to PKO currently */
+ octeon_pko_sw_queue_info_t *outq_ptr;
+
+ struct mtx mtx;
+};
+
+
+/*
+ * Device methods
+ */
+static int rgmii_probe(device_t);
+static void rgmii_identify(driver_t *, device_t);
+static int rgmii_attach(device_t);
+
+
+
+/*
+ * Octeon specific routines
+ */
+static int octeon_has_4ports(void);
+static void octeon_config_rgmii_port(u_int port);
+static void octeon_rgmx_config_pip(u_int port);
+static void octeon_line_status_loop(void *);
+static void octeon_rx_loop(void *);
+static void octeon_config_hw_units_post_ports(void);
+static void octeon_config_hw_units_pre_ports(void);
+static void octeon_config_hw_units_port(struct rgmx_softc_dev *sc, u_int port);
+static struct rgmx_softc_dev *get_rgmx_softc(u_int port);
+static void octeon_rgmx_start_port(u_int port);
+static u_int octeon_rgmx_stop_port(u_int port);
+static u_int get_rgmx_port_ordinal(u_int port);
+static void octeon_rgmx_set_mac(u_int port);
+static void octeon_rgmx_init_sc(struct rgmx_softc_dev *sc, device_t dev, u_int port, u_int num_devices);
+static int octeon_rgmx_init_ifnet(struct rgmx_softc_dev *sc);
+static void octeon_rgmx_mark_ready(struct rgmx_softc_dev *sc);
+static void octeon_rgmx_stop(struct rgmx_softc_dev *sc);
+static void octeon_rgmx_config_speed(u_int port, u_int);
+#ifdef DEBUG_RGMX_DUMP
+static void octeon_dump_rgmx_stats(u_int port);
+static void octeon_dump_pow_stats(void);
+#endif
+#ifdef __not_used__
+static void rgmx_timer_periodic(void);
+#endif
+static void octeon_rgmx_enable_RED_all(int, int);
+
+#ifdef OCTEON_RGMX_SCHEDULED_ISRS
+static void octeon_rgmx_isr_link(void *context, int pending);
+static void octeon_rgmx_isr_rxtx(void *context, int pending);
+static int octeon_rgmx_intr_fast(void *arg);
+#else
+static int octeon_rgmx_intr(void *arg);
+#endif
+
+
+
+
+
+
+
+/* Standard driver entry points. These can be static. */
+static void octeon_rgmx_init (void *);
+//static driver_intr_t rgmx_intr;
+static int octeon_rgmx_ioctl (struct ifnet *, u_long, caddr_t);
+static void octeon_rgmx_output_start (struct ifnet *);
+static void octeon_rgmx_output_start_locked (struct ifnet *);
+#if 0
+static void octeon_rgmx_watchdog (struct ifnet *);
+#endif
+static int octeon_rgmx_medchange (struct ifnet *);
+static void octeon_rgmx_medstat (struct ifnet *, struct ifmediareq *);
+
+
+/* Mapping between media bitmap (in fe_softc.mbitmap) and ifm_media. */
+static int const bit2media [] = {
+ IFM_ETHER | IFM_AUTO,
+ IFM_ETHER | IFM_MANUAL,
+ IFM_ETHER | IFM_10_T,
+ IFM_ETHER | IFM_10_2,
+ IFM_ETHER | IFM_10_5,
+ IFM_ETHER | IFM_10_FL,
+ IFM_ETHER | IFM_10_T,
+ /* More can be added here... */
+};
+
+/* Mapping between media bitmap (in fe_softc.mbitmap) and ifm_media. */
+#define MB_HA 0x0001
+#define MB_HM 0x0002
+#define MB_HT 0x0004
+#define MB_H2 0x0008
+#define MB_H5 0x0010
+#define MB_HF 0x0020
+#define MB_FT 0x0040
+
+#define LEBLEN (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN)
+
+
+static struct rgmx_softc_dev *rgmx_scdev_array[OCTEON_RGMX_NUM_PORTS_MAX] = {NULL};
+static u_int port_array[OCTEON_RGMX_NUM_PORTS_MAX] = {0};
+static u_int num_devices = 0;
+static octeon_pko_sw_queue_info_t output_queues_array[OCTEON_RGMX_NUM_PORTS_MAX * OCTEON_RGMX_OQUEUE_PER_PORT];
+static struct resource *irq_res; /* Interrupt resource. */
+static void *int_handler_tag;
+
+
+#ifdef OCTEON_RGMX_SCHEDULED_ISRS
+
+struct task link_isr_task;
+struct task rxtx_isr_task;
+struct taskqueue *tq; /* private task queue */
+
+#endif
+
+
+
+static u_int get_rgmx_port_ordinal (u_int port)
+{
+ u_int idx;
+
+ for (idx = 0; idx < OCTEON_RGMX_NUM_PORTS_MAX; idx++) {
+ if (port_array[idx] == port) {
+ return (idx);
+ }
+ }
+ return (-1);
+}
+
+static struct rgmx_softc_dev *get_rgmx_softc (u_int port)
+{
+ u_int idx;
+
+ idx = get_rgmx_port_ordinal(port);
+ if (idx != -1) {
+ return (rgmx_scdev_array[idx]);
+ }
+ return (NULL);
+}
+
+
+
+static void octeon_rgmx_init_sc (struct rgmx_softc_dev *sc, device_t dev, u_int port, u_int num_devices)
+{
+ int ii;
+
+ /* No software-controllable media selection. */
+ sc->mbitmap = MB_HM;
+ sc->defmedia = MB_HM;
+
+ sc->sc_dev = dev;
+ sc->port = port;
+ sc->idx = num_devices;
+ sc->link_status = 0;
+ sc->sc_unit = num_devices;
+ sc->mbitmap = MB_HT;
+ sc->defmedia = MB_HT;
+ sc->tx_pending_queue.ifq_maxlen = NUM_TX_PACKETS;
+ sc->tx_pending_queue.ifq_head = sc->tx_pending_queue.ifq_tail = NULL;
+ sc->tx_pending_queue.ifq_len = sc->tx_pending_queue.ifq_drops = 0;
+ mtx_init(&sc->tx_pending_queue.ifq_mtx, "if->sc->txpq.ifqmtx", NULL, MTX_DEF);
+
+ sc->outq_ptr = &(output_queues_array[num_devices * OCTEON_RGMX_OQUEUE_PER_PORT]);
+
+ for (ii = 0; ii < 6; ii++) {
+ sc->ieee[ii] = octeon_mac_addr[ii];
+ }
+ sc->ieee[5] += get_rgmx_port_ordinal(port);
+
+}
+
+static int octeon_rgmx_init_ifnet (struct rgmx_softc_dev *sc)
+{
+ struct ifnet *ifp;
+
+ ifp = sc->ifp = if_alloc(IFT_ETHER);
+ if (NULL == ifp) {
+ device_printf(sc->sc_dev, "can not ifalloc for rgmx port\n");
+ return (ENOSPC);
+ }
+ /*
+ * Initialize ifnet structure
+ */
+ ifp->if_softc = sc;
+ if_initname(sc->ifp, device_get_name(sc->sc_dev), device_get_unit(sc->sc_dev));
+ ifp->if_start = octeon_rgmx_output_start;
+ ifp->if_ioctl = octeon_rgmx_ioctl;
+ /* Watchdog interface is now deprecated.
+ ifp->if_watchdog = octeon_rgmx_watchdog;
+ */
+ ifp->if_hwassist = CSUM_TCP | CSUM_UDP;
+ ifp->if_capabilities = IFCAP_HWCSUM;
+ ifp->if_capenable = ifp->if_capabilities;
+ ifp->if_init = octeon_rgmx_init;
+ ifp->if_linkmib = NULL; // &sc->mibdata;
+ ifp->if_linkmiblen = 0; // sizeof (sc->mibdata);
+ /*
+ * Set fixed interface flags.
+ */
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+// | IFF_NEEDSGIANT;
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ ifmedia_init(&sc->media, 0, octeon_rgmx_medchange, octeon_rgmx_medstat);
+ ifmedia_add(&sc->media, bit2media[0], 0, NULL);
+ ifmedia_set(&sc->media, bit2media[0]);
+
+ ether_ifattach(sc->ifp, sc->ieee);
+ /* Print additional info when attached. */
+ device_printf(sc->sc_dev, "type %s, full duplex\n", sc->typestr);
+
+ return (0);
+}
+
+
+
+/* Driver methods */
+
+
+/* ------------------------------------------------------------------- *
+ * rgmii_identify() *
+ * ------------------------------------------------------------------- */
+static void rgmii_identify (driver_t *drv, device_t parent)
+{
+ BUS_ADD_CHILD(parent, 0, "rgmii", 0);
+}
+
+
+/* ------------------------------------------------------------------- *
+ * rgmii_probe() *
+ * ------------------------------------------------------------------- */
+static int rgmii_probe (device_t dev)
+{
+ if (device_get_unit(dev) != 0)
+ panic("can't probe/attach more rgmii devices\n");
+
+ device_set_desc(dev, "Octeon RGMII");
+ return (0);
+}
+
+
+
+/* ------------------------------------------------------------------- *
+ * rgmii_attach() *
+ * ------------------------------------------------------------------- */
+static int rgmii_attach (device_t dev)
+{
+ struct rgmx_softc_dev *sc;
+ device_t child;
+ int iface, port, nr_ports, error;
+ void *softc;
+ int irq_rid;
+
+ octeon_config_hw_units_pre_ports();
+
+ /* Count interfaces and ports*/
+ octeon_gmxx_inf_mode_t iface_mode;
+ iface_mode.word64 = 0;
+
+ for (iface = 0; iface < 2; iface++) {
+ iface_mode.word64 = oct_read64(OCTEON_RGMX_INF_MODE(iface));
+
+ /* interface is either disabled or SPI */
+ if (!iface_mode.bits.en)
+ continue;
+ if (octeon_get_chipid() == OCTEON_CN3020_CHIP) {
+ nr_ports = 2;
+ } else {
+ nr_ports = (octeon_has_4ports()) ? 4 : 3;
+ if (iface_mode.bits.type ) {
+ if (octeon_get_chipid() == OCTEON_CN5020_CHIP)
+ nr_ports = 2;
+ else
+ continue;
+ }
+ }
+
+ oct_write64(OCTEON_RGMX_TX_PRTS(iface), nr_ports);
+
+ for (port = iface * 16; port < iface * 16 + nr_ports; port++) {
+
+ child = device_add_child(dev, OCTEON_RGMX_DEV_NAME, num_devices);
+ if (child == NULL)
+ panic("%s: device_add_child() failed\n", __func__);
+
+ softc = malloc(sizeof(struct rgmx_softc_dev), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (!softc) {
+ panic("%s malloc failed for softc\n", __func__);
+ }
+ device_set_softc(child, softc);
+ device_set_desc(child, "Octeon RGMII");
+ sc = device_get_softc(child);
+ if (!sc) {
+ printf(" No sc\n");
+ num_devices++;
+ continue;
+ }
+ port_array[num_devices] = port;
+ rgmx_scdev_array[num_devices] = sc;
+ RGMX_LOCK_INIT(sc, device_get_nameunit(child));
+ octeon_rgmx_init_sc(sc, child, port, num_devices);
+ octeon_config_hw_units_port(sc, port);
+ if (octeon_rgmx_init_ifnet(sc)) {
+ device_printf(dev, " ifinit failed for rgmx port %u\n", port);
+ return (ENOSPC);
+ }
+/*
+ * Don't call octeon_rgmx_mark_ready()
+ * ifnet will call it indirectly via octeon_rgmx_init()
+ *
+ * octeon_rgmx_mark_ready(sc);
+ */
+ num_devices++;
+ }
+ }
+
+ octeon_config_hw_units_post_ports();
+
+ irq_rid = 0;
+ irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &irq_rid, 0, 0, 1, RF_SHAREABLE | RF_ACTIVE);
+ if (irq_res == NULL) {
+ device_printf(dev, "failed to allocate irq\n");
+ return (ENXIO);
+ }
+
+
+#ifdef OCTEON_RGMX_SCHEDULED_ISRS
+ /*
+ * Single task queues for all child devices. Since POW gives us a unified
+ * interrupt based on POW groups, not based on PORTs.
+ */
+ TASK_INIT(&rxtx_isr_task, 0, octeon_rgmx_isr_rxtx, NULL);
+ TASK_INIT(&link_isr_task, 0, octeon_rgmx_isr_link, NULL);
+ tq = taskqueue_create_fast("octeon_rgmx_taskq", M_NOWAIT,
+ taskqueue_thread_enqueue, &tq);
+ taskqueue_start_threads(&tq, 1, PI_NET, "%s taskq", device_get_nameunit(dev));
+
+ error = bus_setup_intr(dev, irq_res, INTR_TYPE_NET, octeon_rgmx_intr_fast, NULL,
+ NULL, &int_handler_tag);
+ if (error != 0) {
+ device_printf(dev, "bus_setup_intr returned %d\n", error);
+ taskqueue_free(tq);
+ tq = NULL;
+ return (error);
+ }
+
+#else /* OCTEON_RGMX_SCHEDULED_ISRS */
+
+ error = bus_setup_intr(dev, irq_res, INTR_TYPE_NET, octeon_rgmx_intr, NULL,
+ NULL, &int_handler_tag);
+
+ if (error != 0) {
+ device_printf(dev, "bus_setup_intr returned %d\n", error);
+ tq = NULL;
+ return (error);
+ }
+
+#endif /* OCTEON_RGMX_SCHEDULED_ISRS */
+
+ return (bus_generic_attach(dev));
+}
+
+
+
+
+#define OCTEON_MAX_RGMX_PORT_NUMS 32
+
+
+
+#define OCTEON_POW_RX_GROUP_NUM 0
+#define OCTEON_POW_TX_GROUP_NUM 1 /* If using TX WQE from PKO */
+
+#define OCTEON_POW_RX_GROUP_MASK (1 << OCTEON_POW_RX_GROUP_NUM)
+#define OCTEON_POW_TX_GROUP_MASK (1 << OCTEON_POW_TX_GROUP_NUM)
+#define OCTEON_POW_ALL_OUR_GROUPS_MASK (OCTEON_POW_RX_GROUP_MASK | OCTEON_POW_RX_GROUP_MASK)
+#define OCTEON_POW_ALL_GROUPS_MASK 0xffff
+#define OCTEON_POW_WORKQUEUE_INT (0x8001670000000200ull)
+#define OCTEON_POW_WORKQUEUE_INT_PC (0x8001670000000208ull)
+#define OCTEON_POW_WORKQUEUE_INT_THRESHOLD(group_num) ((0x8001670000000080ull+((group_num)*0x8)))
+#define OCTEON_RGMX_POW_NOS_CNT (0x8001670000000228ull)
+#define OCTEON_POW_INT_CNTR(core) (0x8001670000000100ull+((core)*0x8))
+#define OCTEON_POW_INPT_Q_ALL_QOS (0x8001670000000388ull)
+#define OCTEON_POW_INPT_QOS_GRP(grp) (0x8001670000000340ull + ((grp) * 0x8))
+
+
+
+
+#define NUM_RX_PACKETS_CTL (MAX_RX_BUFS + 3000)
+#define NUM_TX_PACKETS_CTL 40
+
+#define FPA_NOPOOL 0
+
+#define OCTEON_FPA_RX_PACKET_POOL 0
+#define OCTEON_FPA_RX_PACKET_POOL_WORDS 208 /* 2048 bytes */
+#define OCTEON_FPA_RX_PACKET_POOL_ELEM_SIZE (OCTEON_FPA_RX_PACKET_POOL_WORDS)
+#define OCTEON_FPA_RX_PACKET_POOL_ELEMENTS (MAX_RX_BUFS)
+#define OCTEON_RX_MAX_SIZE (OCTEON_FPA_RX_PACKET_POOL_WORDS * sizeof(uint64_t))
+
+#define OCTEON_FPA_WQE_RX_POOL 1
+#define OCTEON_FPA_WQE_RX_WORDS (OCTEON_CACHE_LINE_SIZE/8)
+#define OCTEON_FPA_WQE_RX_POOL_ELEM_SIZE (OCTEON_FPA_WQE_RX_WORDS)
+#define OCTEON_FPA_WQE_RX_POOL_ELEMENTS (NUM_RX_PACKETS_CTL)
+
+#define OCTEON_FPA_TX_PACKET_POOL 2
+#define OCTEON_FPA_TX_PACKET_POOL_WORDS 208 /* 2048 bytes */
+#define OCTEON_FPA_TX_PACKET_POOL_ELEM_SIZE (OCTEON_FPA_TX_PACKET_POOL_WORDS)
+#define OCTEON_FPA_TX_PACKET_POOL_ELEMENTS (MAX_TX_BUFS)
+#define OCTEON_TX_MAX_SIZE (OCTEON_FPA_TX_PACKET_POOL_WORDS * sizeof(uint64_t))
+
+#define OCTEON_FPA_TX_CMDBUF_POOL 3
+#define OCTEON_FPA_TX_CMD_SIZE 2
+#define OCTEON_FPA_TX_CMD_NUM 300
+#define OCTEON_FPA_TX_CMDBUF_POOL_WORDS (OCTEON_FPA_TX_CMD_SIZE * OCTEON_FPA_TX_CMD_NUM)
+#define OCTEON_FPA_TX_CMDBUF_POOL_ELEM_SIZE (OCTEON_FPA_TX_CMDBUF_POOL_WORDS +1)
+#define OCTEON_FPA_TX_CMDBUF_POOL_ELEMENTS (30 * OCTEON_RGMX_NUM_PORTS_MAX)
+
+#define FIRST_PARTICLE_SKIP 0
+#define NOT_FIRST_PARTICLE_SKIP 0
+
+#define ENABLE_BACK_PRESSURE 0
+#define RGMX_MAX_PAK_RECEIVE 5000000
+
+
+#ifdef OCTEON_RGMX_SCHEDULED_ISRS
+
+
+static void octeon_rgmx_isr_link (void *context, int pending)
+{
+ octeon_line_status_loop(NULL);
+}
+
+
+static void octeon_rgmx_isr_rxtx (void *context, int pending)
+{
+ octeon_rx_loop(NULL);
+}
+
+
+/*********************************************************************
+ *
+ * Fast Interrupt Service routine
+ *
+ *********************************************************************/
+
+//#define OCTEON_RGMX_POW_TIME_THR_INTS 1
+
+
+static int octeon_rgmx_intr_fast(void *arg)
+{
+
+ int handled_flag = 0;
+ uint64_t ciu_summary;
+
+ ciu_summary = ciu_get_int_summary(CIU_THIS_CORE, OCTEON_RGMX_CIU_INTX,
+ OCTEON_RGMX_CIU_ENX);
+
+ if (ciu_summary & CIU_GENTIMER_BITS_ENABLE(CIU_GENTIMER_NUM_1)) {
+
+ /*
+ * Timer Interrupt for link status checks
+ * Acknowledging it will mask it for this cycle.
+ */
+ ciu_clear_int_summary(CIU_THIS_CORE, OCTEON_RGMX_CIU_INTX,
+ OCTEON_RGMX_CIU_ENX,
+ CIU_GENTIMER_BITS_ENABLE(CIU_GENTIMER_NUM_1));
+
+ taskqueue_enqueue(taskqueue_fast, &link_isr_task);
+ handled_flag = 1;
+ }
+
+ if (ciu_summary & OCTEON_POW_ALL_GROUPS_MASK) {
+#ifndef OCTEON_RGMX_POW_TIME_THR_INTS
+ /*
+ * When using POW IQ/DSQ size based interrupts, then
+ * ack the interrupts right away. So they don't interrupt
+ * until the queue size goes to 0 again.
+ */
+ oct_write64(OCTEON_POW_WORKQUEUE_INT,
+ 0x10001 << OCTEON_POW_RX_GROUP_NUM);
+
+#else
+ /*
+ * We use POW thresholds based interrupt signalled on timer
+ * countdown. Acknowledge it now so that it doesn't
+ * interrupt us until next countdown to zero.
+ */
+ oct_write64(OCTEON_POW_WORKQUEUE_INT,
+ 0x1 << OCTEON_POW_RX_GROUP_NUM);
+#endif
+
+ taskqueue_enqueue(tq, &rxtx_isr_task);
+ handled_flag = 1;
+ }
+
+ return ((handled_flag) ? FILTER_HANDLED : FILTER_STRAY);
+}
+
+
+#else /* ! OCTEON_RGMX_SCHEDULED_ISRS */
+
+
+/*
+ * octeon_rgmx_intr
+ *
+ * This is direct inline isr. Will do all its work and heavy-lifting in interrupt context.
+ *
+ * Also note that the RGMX_LOCK/UNLOCK code will have to checked/added, since that is new and
+ * was not supported with this model.
+ */
+static int octeon_rgmx_intr (void *arg)
+{
+ int flag = 0;
+ uint64_t ciu_summary;
+
+ /*
+ * read ciu to see if any bits are pow
+ */
+ while (1) {
+ ciu_summary = ciu_get_int_summary(CIU_THIS_CORE, OCTEON_RGMX_CIU_INTX,
+ OCTEON_RGMX_CIU_ENX);
+
+ if ((ciu_summary & (OCTEON_POW_ALL_GROUPS_MASK | CIU_GENTIMER_BITS_ENABLE(CIU_GENTIMER_NUM_1))) == 0) {
+ break;
+ }
+
+ flag = 1;
+
+ if (ciu_summary & OCTEON_POW_ALL_GROUPS_MASK) {
+ octeon_rx_loop(NULL);
+ /*
+ * Acknowledge the interrupt after processing queues.
+ */
+ oct_write64(OCTEON_POW_WORKQUEUE_INT, OCTEON_POW_RX_GROUP_MASK);
+ }
+ if (ciu_summary & CIU_GENTIMER_BITS_ENABLE(CIU_GENTIMER_NUM_1)) {
+ octeon_line_status_loop(NULL);
+ ciu_clear_int_summary(CIU_THIS_CORE, OCTEON_RGMX_CIU_INTX,
+ OCTEON_RGMX_CIU_ENX,
+ CIU_GENTIMER_BITS_ENABLE(CIU_GENTIMER_NUM_1));
+ }
+ }
+
+ return ((flag) ? FILTER_HANDLED : FILTER_STRAY);
+}
+
+
+#endif /* OCTEON_RGMX_SCHEDULED_ISRS */
+
+
+
+static struct mbuf *octeon_rgmx_build_new_rx_mbuf(struct ifnet *ifp, void *data_start, u_int totlen);
+
+static struct mbuf *octeon_rgmx_build_new_rx_mbuf (struct ifnet *ifp, void *data_start, u_int totlen)
+{
+ struct mbuf *m, *m0, *newm;
+ caddr_t newdata;
+ int len;
+
+ if (totlen <= ETHER_HDR_LEN || totlen > LEBLEN - ETHER_CRC_LEN) {
+#ifdef LEDEBUG
+ if_printf(ifp, "invalid packet size %d; dropping\n", totlen);
+#endif
+ return (NULL);
+ }
+
+ MGETHDR(m0, M_DONTWAIT, MT_DATA);
+ if (m0 == NULL) {
+ return (NULL);
+ }
+
+ /* Initialize packet header info. */
+ m0->m_pkthdr.rcvif = ifp;
+ m0->m_pkthdr.len = totlen;
+ m0->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+ m0->m_pkthdr.csum_data = 0xffff;
+ len = MHLEN;
+ m = m0;
+
+ while (totlen > 0) {
+ if (totlen >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0)
+ goto octeon_rgmx_build_new_rx_mbuf_bad;
+ len = MCLBYTES;
+ }
+
+ if (m == m0) {
+ newdata = (caddr_t)ALIGN(m->m_data + ETHER_HDR_LEN) - ETHER_HDR_LEN;
+ len -= newdata - m->m_data;
+ m->m_data = newdata;
+ }
+
+ /* Set the length of this mbuf. */
+ m->m_len = len = min(totlen, len);
+ bcopy(data_start, mtod(m, caddr_t), len);
+ data_start = (void *) (((u_long) (data_start)) + len);
+
+ totlen -= len;
+ if (totlen > 0) {
+ MGET(newm, M_DONTWAIT, MT_DATA);
+ if (newm == 0)
+ goto octeon_rgmx_build_new_rx_mbuf_bad;
+ len = MLEN;
+ m = m->m_next = newm;
+ }
+ }
+
+ return (m0);
+
+octeon_rgmx_build_new_rx_mbuf_bad:
+
+ m_freem(m0);
+ return (NULL);
+}
+
+
+
+//#define DEBUG_RX 1
+
+static void octeon_rgmx_rx_process_work (octeon_wqe_t *work, u_int port)
+{
+ struct rgmx_softc_dev *sc;
+ struct ifnet *ifp;
+ u_int len;
+ void *data_start, *new_data_start;
+ struct mbuf *mbuf;
+
+//#define DEBUG_RX_PKT_DUMP 1
+#ifdef DEBUG_RX_PKT_DUMP
+ int i; u_char *dc;
+#endif
+
+ data_start = octeon_pow_pktptr_to_kbuffer(work->packet_ptr);
+
+//#define DEBUG_RX2
+#ifdef DEBUG_RX2
+ printf(" WQE 0x%X: port:%u ", work, port);
+ printf(" Grp: %u, %llX Tag: %u %llX type: %u 0x%llx\n",
+ work->grp, work->grp, work->tag, work->tag, work->tag_type, work->tag_type);
+#endif
+
+ if ((port >= OCTEON_RGMX_MIN_PORT) || (port <= OCTEON_RGMX_MAX_PORT)) {
+
+ sc = get_rgmx_softc(port);
+
+ if (!sc || !sc->ifp) {
+
+ printf(" octeon_rgmx_rx_process_work No sc or sc->ifp - port:%u", port);
+ } else {
+
+ ifp = sc->ifp;
+
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+
+ if (!work->word2.bits.rcv_error) {
+
+ len = work->len;
+
+ /*
+ * We cannot pass the same FPA phys-buffer higher up.
+ * User space will not be able to use this phys-buffer.
+ *
+ * Start building a mbuf packet here using data_start & len.
+ */
+
+ new_data_start = data_start;
+ if (!work->word2.bits.not_IP) {
+ new_data_start = (void *) (((unsigned long) (new_data_start)) + 14);
+ /* mark it as checksum checked */
+ } else {
+ new_data_start = (void *) (((unsigned long) (new_data_start)) + 8);
+ }
+
+#ifdef DEBUG_RX_PKT_DUMP
+ dc = new_data_start; printf("In:\n");
+ for (i = 0; i < len; i++) { if (!(i % 16)) printf ("\n"); printf(" %02X", dc[i]); }
+#endif
+
+ mbuf = octeon_rgmx_build_new_rx_mbuf(ifp, new_data_start, len);
+ if (mbuf) {
+// printf(" Passing pkt to ifp: pkt_len: %u len: %u ", mbuf->m_pkthdr.len, mbuf->m_len);
+#ifdef DEBUG_RX_PKT_DUMP
+
+ dc = mtod(mbuf, u_char *); printf("\n"); printf("In: ");
+ for (i = 0; i < mbuf->m_len; i++) { if (!(i % 16)) printf ("\n"); printf(" %02X", dc[i]); }
+
+#endif
+
+ /* Feed the packet to upper layer. */
+ (*ifp->if_input)(ifp, mbuf);
+ ifp->if_ipackets++;
+
+ } else { /* mbuf error */
+ if_printf(ifp, "mbuf rx construct error\n");
+ printf(" mbuf rx construct error\n");
+ ifp->if_ierrors++;
+ } /* mbuf error */
+
+ } else { /* rcv_error */
+ ifp->if_ierrors++;
+ } /* rcv_error */
+
+ } /* IFF_DRV_RUNNING */
+
+ } /* sc && sc->ifp */
+
+ } else { /* port number */
+ printf(" rgmx_rx:%u bad port\n", port);
+ }
+
+ octeon_fpa_free(data_start, OCTEON_FPA_RX_PACKET_POOL, 0);
+ octeon_fpa_free((void *)work, OCTEON_FPA_WQE_RX_POOL, 0);
+}
+
+
+
+
+/* ------------------------------------------------------------------- *
+ * octeon_rx_loop() *
+ * ------------------------------------------------------------------- */
+
+
+//#define OCTEON_VISUAL_RGMX 1
+#ifdef OCTEON_VISUAL_RGMX
+static int where0 = 0;
+static int where1 = 0;
+#endif
+
+static void octeon_rx_loop (void *unused)
+{
+ u_int core_id;
+ uint64_t prev_grp_mask;
+ u_int pak_count;
+ octeon_wqe_t *work;
+
+ core_id = octeon_get_core_num();
+ pak_count = 0;
+
+ /* Only allow work for our group */
+ prev_grp_mask = oct_read64(OCTEON_POW_CORE_GROUP_MASK(core_id));
+ oct_write64(OCTEON_POW_CORE_GROUP_MASK(core_id), OCTEON_POW_ALL_GROUPS_MASK);
+
+
+#ifdef OCTEON_VISUAL_RGMX
+ octeon_led_run_wheel(&where0, 3);
+#endif
+ while(1) {
+
+ if (pak_count++ > RGMX_MAX_PAK_RECEIVE) {
+ break;
+ }
+
+ work = octeon_pow_work_request_sync(OCTEON_POW_WAIT);
+
+ if (work == NULL) {
+ /*
+ * No more incoming packets. We can take a break now.
+ */
+ break;
+ }
+
+#ifdef OCTEON_VISUAL_RGMX
+ octeon_led_run_wheel(&where1, 4);
+#endif
+ octeon_rgmx_rx_process_work(work, work->ipprt);
+
+ }
+
+ oct_write64(OCTEON_POW_CORE_GROUP_MASK(core_id), prev_grp_mask);
+}
+
+
+static void *octeon_rgmx_write_mbufs_to_fpa_buff (struct rgmx_softc_dev *sc, struct mbuf *m, u_int len)
+{
+ struct mbuf *mp;
+ void *data_area;
+ u_char *write_offset;
+
+ /*
+ * FIXME
+ *
+ * Compare len with max FPA-tx-packet size. Or else we will possibly corrupt the next pkt.
+ */
+
+
+ /*
+ * Get an FPA buffer from Xmit-packets FPA pool
+ */
+ data_area = octeon_fpa_alloc(OCTEON_FPA_TX_PACKET_POOL);
+ if (!data_area) {
+ /*
+ * Fail. No room. No resources.
+ */
+ return (NULL);
+ }
+
+ /*
+ * Transfer the data from mbuf chain to the transmission buffer.
+ */
+ write_offset = data_area;
+ for (mp = m; mp != 0; mp = mp->m_next) {
+ if (mp->m_len) {
+ bcopy(mtod(mp, caddr_t), write_offset, mp->m_len);
+ write_offset = (u_char *) (((u_long) write_offset) + mp->m_len);
+ }
+ }
+ return (data_area);
+}
+
+
+static u_int octeon_rgmx_pko_xmit_packet (struct rgmx_softc_dev *sc, void *out_buff, u_int len, u_int checksum)
+{
+ octeon_pko_command_word0_t pko_cmd;
+ octeon_pko_packet_ptr_t pko_pkt_word;
+ u_long temp;
+ u_short xmit_cmd_index;
+ uint64_t *xmit_cmd_ptr;
+ uint64_t xmit_cmd_state;
+ int queue = 0; // we should randomize queue # based on core num. Using same
+ // queue 0 for this port, by all cores on is less efficient.
+
+ /*
+ * Prepare the PKO buffer and command word.
+ * Cmd Buf Word 0
+ * No FAU
+ * Set #-segs and #-bytes
+ */
+ pko_cmd.word64 = 0;
+ pko_cmd.bits.segs = 1;
+ pko_cmd.bits.total_bytes = len;
+ if (checksum) {
+ pko_cmd.bits.ipoffp1 = ETHER_HDR_LEN + 1; /* IPOffP1 is +1 based. 1 means offset 0 */
+ }
+
+ /*
+ * Build the PKO buffer pointer. PKO Cmd Buf Word 1
+ */
+ pko_pkt_word.word64 = 0;
+ pko_pkt_word.bits.addr = OCTEON_PTR2PHYS(out_buff);
+ pko_pkt_word.bits.pool = OCTEON_FPA_TX_PACKET_POOL;
+ pko_pkt_word.bits.size = 2048; // dummy. Actual len is above.
+
+#ifdef DEBUG_TX
+ printf(" PKO: 0x%llX 0x%llX ", pko_cmd.word64, pko_pkt_word.word64);
+#endif
+
+ /*
+ * Get the queue command ptr location from the per port per queue, pko info struct.
+ */
+ octeon_spinlock_lock(&(sc->outq_ptr[queue].lock));
+#ifdef DEBUG_TX
+ printf(" xmit: sc->outq_ptr[queue].xmit_command_state: 0x%llX ", sc->outq_ptr[queue].xmit_command_state);
+#endif
+ xmit_cmd_state = sc->outq_ptr[queue].xmit_command_state;
+ sc->outq_ptr[queue].xmit_command_state = xmit_cmd_state + 2;
+
+ temp = (u_long) (xmit_cmd_state >> OCTEON_PKO_INDEX_BITS);
+#ifdef DEBUG_TX
+ printf(" temp: 0x%X ", temp);
+#endif
+ xmit_cmd_ptr = (uint64_t *) MIPS_PHYS_TO_KSEG0(temp);
+ xmit_cmd_index = xmit_cmd_state & OCTEON_PKO_INDEX_MASK;
+ xmit_cmd_ptr += xmit_cmd_index;
+
+ /*
+ * We end the PKO cmd buffer at odd boundary. Towards the end we will have
+ * 4 or 3 or 2 or 1 or 0 word remaining. Case of 4, 2, or 0 can never happen.
+ * We only care when we have 3 words remaining. In this case we write our 2 words
+ * for PKO command and 3rd word as chain for next PKO cmd buffer.
+ */
+ xmit_cmd_ptr[0] = pko_cmd.word64;
+
+ if (xmit_cmd_index < (OCTEON_FPA_TX_CMDBUF_POOL_WORDS - 2)) {
+ /*
+ * Plenty of space left. Write our 2nd word and worry the next time.
+ */
+ xmit_cmd_ptr[1] = pko_pkt_word.word64;
+
+ } else {
+ /*
+ * 3 words or less are left. We write our 2nd word now and then put in a chain link
+ * to new PKO cmd buf.
+ */
+ void *pko_cmd_buf = octeon_fpa_alloc(OCTEON_FPA_TX_CMDBUF_POOL);
+ uint64_t phys_cmd_buf;
+
+ if (!pko_cmd_buf) {
+ /*
+ * FPA pool for xmit-buffer-commands is empty.
+ */
+ sc->outq_ptr[queue].xmit_command_state -= 2;
+ octeon_spinlock_unlock(&(sc->outq_ptr[queue].lock));
+ return (0);
+ }
+ phys_cmd_buf = OCTEON_PTR2PHYS(pko_cmd_buf);
+
+ xmit_cmd_ptr[1] = pko_pkt_word.word64;
+ xmit_cmd_ptr[2] = phys_cmd_buf;
+
+ sc->outq_ptr[queue].xmit_command_state = (phys_cmd_buf << OCTEON_PKO_INDEX_BITS);
+ }
+ /*
+ * Unlock queue structures.
+ */
+ octeon_spinlock_unlock(&(sc->outq_ptr[queue].lock));
+
+ /*
+ * 2 words incremented in PKO. Ring the doorbell.
+ */
+#ifdef DEBUG_TX
+ printf(" Ringing doorbell: Port %u Queue %u words 2", sc->port, octeon_pko_get_base_queue(sc->port) + queue);
+#endif
+ octeon_pko_ring_doorbell(sc->port, octeon_pko_get_base_queue(sc->port) + queue, 2);
+
+ return (1);
+}
+
+
+static void octeon_rgmx_xmit_mark_buffers_done(struct rgmx_softc_dev *sc, u_int n);
+
+static void octeon_rgmx_xmit_mark_buffers_done (struct rgmx_softc_dev *sc, u_int n)
+{
+ struct mbuf *m;
+ u_int i;
+
+ for (i = 0; i < n; i++) {
+ /*
+ * Remove packets in queue. Leaving a lag of 3, to allow for PKO in-flight xmission
+ */
+ if (_IF_QLEN(&sc->tx_pending_queue) > 4) {
+ IF_DEQUEUE(&sc->tx_pending_queue, m);
+ if (!m) {
+ break; // Queue became empty now. Break out.
+ }
+ /*
+ * Return the mbuf to system.
+ */
+ m_freem(m);
+ }
+ }
+ if (!i) {
+ return; // Nothing removed from queue.
+ }
+
+ /*
+ * The transmitter is no more active.
+ * Reset output active flag and watchdog timer.
+ */
+ sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ sc->ifp->if_timer = 0;
+}
+
+
+#define OCTEON_RGMX_FLUSH_N_XMIT_MBUFS_EACH_LOOP 5
+#define OCTEON_RGMX_FLUSH_PENDING_MBUFS_MAX 1000
+
+#ifdef __not_used__
+/*
+ * octeon_rgmx_output_flush
+ *
+ * Drop all packets queued at ifnet layer.
+ */
+static void octeon_rgmx_output_flush (struct ifnet *ifp)
+{
+ struct mbuf *m;
+ u_int max_flush = OCTEON_RGMX_FLUSH_PENDING_MBUFS_MAX; /* Arbitrarily high number */
+
+ while (max_flush-- && _IF_QLEN(&ifp->if_snd)) {
+ /*
+ * Get the next mbuf Packet chain to flush.
+ */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL) {
+ /* No more packets to flush */
+ break;
+ }
+ _IF_DROP(&ifp->if_snd);
+ m_freem(m);
+ ifp->if_oerrors++;
+ }
+}
+#endif
+
+/*
+ * octeon_rgmx_output_start
+ *
+ * Start output on interface.
+ */
+static void octeon_rgmx_output_start (struct ifnet *ifp)
+{
+ struct rgmx_softc_dev *sc = ifp->if_softc;
+
+ RGMX_LOCK(sc);
+ octeon_rgmx_output_start_locked(ifp);
+ RGMX_UNLOCK(sc);
+}
+
+
+
+/*
+ * octeon_rgmx_output_start_locked
+ *
+ * Start output on interface. Assume Driver locked
+ */
+static void octeon_rgmx_output_start_locked (struct ifnet *ifp)
+{
+ struct rgmx_softc_dev *sc = ifp->if_softc;
+ struct mbuf *m;
+ u_int len, need_l4_checksum;
+ void *out_buff;
+
+ /*
+ * Take out some of the last queued mbuf's from xmit-pending queue
+ */
+ octeon_rgmx_xmit_mark_buffers_done(sc, OCTEON_RGMX_FLUSH_N_XMIT_MBUFS_EACH_LOOP);
+
+ while (1) {
+ /*
+ * See if there is room to put another packet in the buffer.
+ * We *could* do better job by peeking the send queue to
+ * know the length of the next packet. Current version just
+ * tests against the worst case (i.e., longest packet). FIXME.
+ *
+ * When adding the packet-peek feature, don't forget adding a
+ * test on txb_count against QUEUEING_MAX.
+ * There is a little chance the packet count exceeds
+ * the limit. Assume transmission buffer is 8KB (2x8KB
+ * configuration) and an application sends a bunch of small
+ * (i.e., minimum packet sized) packets rapidly. An 8KB
+ * buffer can hold 130 blocks of 62 bytes long...
+ */
+
+ /*
+ * If unable to send more.
+ */
+ if (_IF_QLEN(&sc->tx_pending_queue) >= MAX_TX_BUFS) {
+ printf(" Xmit not possible. NO room %u", _IF_QLEN(&sc->tx_pending_queue));
+ goto indicate_active;
+ }
+
+
+ /*
+ * Get the next mbuf chain for a packet to send.
+ */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL) {
+ /* No more packets to send. */
+ goto indicate_inactive;
+ }
+
+ len = m->m_pkthdr.len;
+ /*
+ * Should never send big packets. If such a packet is passed,
+ * it should be a bug of upper layer. We just ignore it.
+ * ... Partial (too short) packets, neither.
+ */
+ if (len < ETHER_HDR_LEN ||
+ len > ETHER_MAX_LEN - ETHER_CRC_LEN) {
+ /*
+ * Fail. Bad packet size. Return the mbuf to system.
+ */
+ if_printf(ifp,
+ "got an out-of-spec packet (%u bytes) to send\n", len);
+ m_freem(m);
+ goto indicate_active;
+ }
+
+ /*
+ * Copy the mbuf chain into the transmission buffer.
+ * txb_* variables are updated as necessary.
+ */
+ out_buff = octeon_rgmx_write_mbufs_to_fpa_buff(sc, m, len);
+ if (!out_buff) {
+ /*
+ * No FPA physical buf resource.
+ * Let's requeue it back. And slow it down for a while.
+ */
+ IF_PREPEND(&ifp->if_snd, m);
+ goto indicate_active;
+ }
+
+ need_l4_checksum = (m->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) ? 1 : 0;
+
+ /*
+ * put the mbuf onto pending queue
+ */
+//#define DEBUG_TX_PKT_DUMP 1
+#ifdef DEBUG_TX_PKT_DUMP
+ int ii;
+ u_char *dc = out_buff;
+
+ printf("\n"); printf("Out: ");
+ for (ii = 0; ii < len; ii++) printf(" %X", dc[ii]); printf("\n");
+#endif
+
+ IF_ENQUEUE(&sc->tx_pending_queue, m);
+
+ /*
+ * Pass the mbuf data packet to PKO for xmission.
+ */
+ octeon_rgmx_pko_xmit_packet(sc, out_buff, len, need_l4_checksum);
+
+ ifp->if_opackets++;
+ }
+
+indicate_inactive:
+ /*
+ * We are using the !OACTIVE flag to indicate to
+ * the outside world that we can accept an
+ * additional packet rather than that the
+ * transmitter is _actually_ active. Indeed, the
+ * transmitter may be active, but if we haven't
+ * filled all the buffers with data then we still
+ * want to accept more.
+ */
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ return;
+
+
+indicate_active:
+ /*
+ * The transmitter is active, and there are no room for
+ * more outgoing packets in the transmission buffer.
+ */
+ ifp->if_oerrors++;
+// sc->mibdata.dot3StatsInternalMacTransmitErrors++;
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ return;
+}
+
+
+
+
+/* ------------------------------------------------------------------- *
+ * octeon_config_hw_units() *
+ * ------------------------------------------------------------------- *
+ *
+ * Initialize Octeon hardware components. To get the RGMX going.
+ *
+ */
+static void octeon_config_hw_units_pre_ports (void)
+{
+
+ /* Enable FPA */
+ octeon_enable_fpa();
+
+ /* Enable PKO */
+ octeon_pko_enable();
+
+ /* Init PKO */
+ octeon_pko_init();
+
+
+ /* Fill FPA */
+
+ /*
+ * Input Buffers Pool
+ * Pool 0
+ */
+ octeon_fpa_fill_pool_mem(OCTEON_FPA_RX_PACKET_POOL, OCTEON_FPA_RX_PACKET_POOL_ELEM_SIZE,
+ OCTEON_FPA_RX_PACKET_POOL_ELEMENTS);
+
+ /*
+ * WQE Blocks Pool
+ * Pool 1
+ */
+ octeon_fpa_fill_pool_mem(OCTEON_FPA_WQE_RX_POOL, OCTEON_FPA_WQE_RX_POOL_ELEM_SIZE,
+ OCTEON_FPA_WQE_RX_POOL_ELEMENTS);
+
+ /*
+ * PKO Command Pool
+ * Pool 3
+ */
+ octeon_fpa_fill_pool_mem(OCTEON_FPA_TX_CMDBUF_POOL, OCTEON_FPA_TX_CMDBUF_POOL_ELEM_SIZE,
+ OCTEON_FPA_TX_CMDBUF_POOL_ELEMENTS);
+
+ /*
+ * Output Buffers Pool
+ * Pool 2
+ */
+ octeon_fpa_fill_pool_mem(OCTEON_FPA_TX_PACKET_POOL, OCTEON_FPA_TX_PACKET_POOL_ELEM_SIZE,
+ OCTEON_FPA_TX_PACKET_POOL_ELEMENTS);
+
+
+
+ octeon_rgmx_enable_RED_all(OCTEON_FPA_RX_PACKET_POOL_ELEMENTS >> 2, OCTEON_FPA_RX_PACKET_POOL_ELEMENTS >> 3);
+
+ /* Configure IPD */
+ octeon_ipd_config(OCTEON_FPA_RX_PACKET_POOL_WORDS,
+ FIRST_PARTICLE_SKIP / 8,
+ NOT_FIRST_PARTICLE_SKIP / 8,
+ FIRST_PARTICLE_SKIP / 128,
+ NOT_FIRST_PARTICLE_SKIP / 128,
+ OCTEON_FPA_WQE_RX_POOL,
+ OCTEON_IPD_OPC_MODE_STF,
+ ENABLE_BACK_PRESSURE);
+
+ /*
+ * PKO setup Output Command Buffers
+ */
+ octeon_pko_config_cmdbuf_global_defaults(OCTEON_FPA_TX_CMDBUF_POOL,
+ OCTEON_FPA_TX_CMDBUF_POOL_ELEM_SIZE);
+
+}
+
+
+
+static void octeon_config_hw_units_port (struct rgmx_softc_dev *sc, u_int port)
+{
+ const u_int priorities[8] = {8,8,8,8,8,8,8,8};
+ u_int total_queues, base_queue;
+
+ octeon_config_rgmii_port(port);
+
+ total_queues = octeon_pko_get_num_queues(port);
+ base_queue = octeon_pko_get_base_queue(port);
+ /* Packet output configures Queue and Ports */
+ octeon_pko_config_port(port, base_queue,
+ total_queues,
+ priorities,
+ OCTEON_FPA_TX_CMDBUF_POOL,
+ sc->outq_ptr);
+
+ octeon_rgmx_set_mac(port);
+
+ /* Setup Port input tagging */
+ octeon_rgmx_config_pip(port);
+}
+
+
+typedef union
+{
+ uint64_t word64;
+ struct
+ {
+ uint64_t rsvd3 : 35;
+ uint64_t enable : 1;
+ uint64_t time_thr : 4;
+ uint64_t rsvd2 : 1;
+ uint64_t ds_thr : 11;
+ uint64_t rsvd : 1;
+ uint64_t iq_thr : 11;
+ } bits;
+} octeon_rgmx_pow_int_threshold_t;
+
+typedef union
+{
+ uint64_t word64;
+ struct
+ {
+ uint64_t rsvd : 36;
+ uint64_t tc_cnt : 4;
+ uint64_t ds_cnt : 12;
+ uint64_t iq_cnt : 12;
+ } bits;
+} octeon_rgmx_pow_int_cnt_t;
+
+typedef union
+{
+ uint64_t word64;
+ struct
+ {
+ uint64_t rsvd3 : 4;
+ uint64_t thr_freq : 28; // R/O
+ uint64_t rsvd2 : 4;
+ uint64_t thr_period : 20;
+ uint64_t rsvd : 8;
+ } bits;
+} octeon_rgmx_pow_int_pc_t;
+
+
+typedef union
+{
+ uint64_t word64;
+ struct
+ {
+ uint64_t rsvd : 52;
+ uint64_t nos_cnt : 12;
+ } bits;
+} octeon_rgmx_pow_nos_cnt;
+
+
+
+typedef union
+{
+ uint64_t word64;
+ struct
+ {
+ uint64_t rsvd : 32;
+ uint64_t inb_pkts : 32;
+ } bits;
+} octeon_rgmx_pip_inb_pkts;
+
+typedef union
+{
+ uint64_t word64;
+ struct
+ {
+ uint64_t rsvd : 48;
+ uint64_t inb_errs : 16;
+ } bits;
+} octeon_rgmx_pip_inb_errs;
+
+
+
+typedef union
+{
+ uint64_t word64;
+ struct
+ {
+ uint64_t rsvd : 32;
+ uint64_t iq_cnt : 32;
+ } bits;
+} octeon_pow_inpt_q_all_qos;
+
+
+
+typedef union
+{
+ uint64_t word64;
+ struct
+ {
+ uint64_t rsvd : 32;
+ uint64_t iq_cnt : 32;
+ } bits;
+} octeon_pow_inpt_q_grp_qos;
+
+
+static void octeon_config_hw_units_post_ports (void)
+{
+
+ octeon_rgmx_pow_int_threshold_t thr;
+ octeon_rgmx_pow_int_pc_t intpc;
+
+ thr.word64 = 0;
+ intpc.word64 = 0;
+ intpc.bits.thr_freq = (500 * 1000 * 1000) / (1000 * 16 * 256);
+
+#ifdef OCTEON_RGMX_POW_TIME_THR_INTS
+ thr.bits.enable = 1;
+ thr.bits.time_thr = 0xf;
+ oct_write64(OCTEON_POW_WORKQUEUE_INT_THRESHOLD(OCTEON_POW_RX_GROUP_NUM), thr.word64);
+
+ oct_write64(OCTEON_POW_WORKQUEUE_INT_PC, intpc.word64);
+
+#else
+ thr.bits.ds_thr = thr.bits.iq_thr = 1; // Only if doing absolute queue-cnt interrupts.
+ 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,
+ (OCTEON_POW_RX_GROUP_MASK |
+ CIU_GENTIMER_BITS_ENABLE(CIU_GENTIMER_NUM_1)), CIU_MIPS_IP2);
+
+ ciu_clear_int_summary(CIU_THIS_CORE, OCTEON_RGMX_CIU_INTX,
+ OCTEON_RGMX_CIU_ENX, CIU_GENTIMER_BITS_ENABLE(CIU_GENTIMER_NUM_1));
+
+ octeon_ciu_start_gtimer(CIU_GENTIMER_NUM_1, OCTEON_GENTIMER_PERIODIC,
+ OCTEON_GENTIMER_LEN_1SEC);
+ /*
+ * Enable IPD
+ */
+ octeon_ipd_enable();
+}
+
+
+
+
+
+static void octeon_rgmx_config_pip (u_int port)
+{
+ octeon_pip_gbl_cfg_t pip_config;
+ octeon_pip_port_cfg_t pip_port_config;
+ octeon_pip_port_tag_cfg_t pip_tag_config;
+
+ /*
+ * PIP Global config
+ */
+ pip_config.word64 = 0;
+ pip_config.bits.max_l2 = 1;
+ oct_write64(OCTEON_PIP_GBL_CFG, pip_config.word64);
+
+ /*
+ * PIP Port config
+ */
+ pip_port_config.word64 = 0;
+ pip_port_config.bits.mode = OCTEON_PIP_PORT_CFG_MODE_SKIPL2;
+ pip_port_config.bits.qos = port & 0x7;
+ pip_port_config.bits.crc_en = 1;
+
+
+ /*
+ * PIP -> POW tags config
+ *
+ * We don't use any pkt input fields for tag hash, except for Port#
+ */
+ pip_tag_config.word64 = 0;
+
+ pip_tag_config.bits.grptag = 0;
+ pip_tag_config.bits.grptagmask = 0xf;
+ pip_tag_config.bits.grptagbase = 1;
+
+ pip_tag_config.bits.ip6_src_flag = 0;
+ pip_tag_config.bits.ip6_dst_flag = 0;
+ pip_tag_config.bits.ip6_sprt_flag = 0;
+ pip_tag_config.bits.ip6_dprt_flag = 0;
+ pip_tag_config.bits.ip6_nxth_flag = 0;
+
+ pip_tag_config.bits.ip4_src_flag = 1;
+ pip_tag_config.bits.ip4_dst_flag = 1;
+ pip_tag_config.bits.ip4_sprt_flag = 1;
+ pip_tag_config.bits.ip4_dprt_flag = 1;
+ pip_tag_config.bits.ip4_pctl_flag = 1;
+
+ pip_tag_config.bits.tcp6_tag_type = 0;
+ pip_tag_config.bits.tcp4_tag_type = 0;
+ pip_tag_config.bits.ip6_tag_type = 0;
+ pip_tag_config.bits.ip4_tag_type = 0;
+ pip_tag_config.bits.inc_prt_flag = 1;
+ pip_tag_config.bits.non_tag_type = OCTEON_POW_TAG_TYPE_NULL;
+ pip_tag_config.bits.grp = OCTEON_POW_RX_GROUP_NUM;
+
+ octeon_pip_config_port(port, pip_port_config, pip_tag_config);
+
+ oct_write64(OCTEON_POW_CORE_GROUP_MASK(OUR_CORE), OCTEON_POW_ALL_GROUPS_MASK);
+
+}
+
+
+/*
+ * octeon_rgmx_stop_port
+ *
+ */
+static u_int octeon_rgmx_stop_port (u_int port)
+{
+ int interface = INTERFACE(port);
+ int index = INDEX(port);
+ octeon_rgmx_prtx_cfg_t gmx_cfg;
+ u_int last_enabled = 0;
+
+ gmx_cfg.word64 = oct_read64(OCTEON_RGMX_PRTX_CFG(index, interface));
+ last_enabled = (gmx_cfg.bits.en == 1);
+ gmx_cfg.bits.en = 0;
+ oct_write64(OCTEON_RGMX_PRTX_CFG(index, interface), gmx_cfg.word64);
+ return (last_enabled);
+}
+
+static void octeon_rgmx_start_port(u_int port)
+{
+ int interface = INTERFACE(port);
+ int index = INDEX(port);
+ octeon_rgmx_prtx_cfg_t gmx_cfg;
+
+ gmx_cfg.word64 = oct_read64(OCTEON_RGMX_PRTX_CFG(index, interface));
+ gmx_cfg.bits.en = 1;
+ oct_write64(OCTEON_RGMX_PRTX_CFG(index, interface), gmx_cfg.word64);
+}
+
+
+static void octeon_rgmx_stop (struct rgmx_softc_dev *sc)
+{
+ octeon_rgmx_stop_port(sc->port);
+
+ /* Reset transmitter variables and interface flags. */
+ sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING);
+ sc->ifp->if_timer = 0;
+ sc->txb_count = 0;
+ sc->txb_sched = 0;
+}
+
+
+/* Change the media selection. */
+static int octeon_rgmx_medchange (struct ifnet *ifp)
+{
+ struct rgmx_softc_dev *sc = ifp->if_softc;
+
+#ifdef DIAGNOSTIC
+ /* If_media should not pass any request for a media which this
+ interface doesn't support. */
+ int b;
+
+ for (b = 0; bit2media[b] != 0; b++) {
+ if (bit2media[b] == sc->media.ifm_media) break;
+ }
+ if (((1 << b) & sc->mbitmap) == 0) {
+ if_printf(sc->ifp,
+ "got an unsupported media request (0x%x)\n",
+ sc->media.ifm_media);
+ return EINVAL;
+ }
+#endif
+
+ /* We don't actually change media when the interface is down.
+ fe_init() will do the job, instead. Should we also wait
+ until the transmission buffer being empty? Changing the
+ media when we are sending a frame will cause two garbages
+ on wires, one on old media and another on new. FIXME */
+ if (sc->ifp->if_flags & IFF_UP) {
+ printf(" Media change requested while IF is up\n");
+ } else {
+ printf(" Media change requested while IF is Down\n");
+ }
+
+ return 0;
+}
+
+
+static void octeon_rgmx_medstat (struct ifnet *ifp, struct ifmediareq *ifm)
+{
+ /*
+ * No support for Media Status callback
+ */
+}
+
+static int octeon_rgmx_ioctl (struct ifnet * ifp, u_long command, caddr_t data)
+{
+ struct rgmx_softc_dev *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int error = 0;
+
+ if (!sc) {
+ printf(" octeon_rgmx_ioctl. No sc\n");
+ return (0);
+ }
+ switch (command) {
+
+ case SIOCSIFFLAGS:
+ /*
+ * Switch interface state between "running" and
+ * "stopped", reflecting the UP flag.
+ */
+ if (ifp->if_flags & IFF_UP) {
+
+
+ /*
+ * New state is IFF_UP
+ * Restart or Start now, if driver is not running currently.
+ */
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ printf(" SIOCSTIFFLAGS UP/Not-running\n"); break;
+ octeon_rgmx_init(sc);
+ } else {
+ printf(" SIOCSTIFFLAGS UP/Running\n"); break;
+ }
+ } else {
+ /*
+ * New state is IFF_DOWN.
+ * Stop & shut it down now, if driver is running currently.
+ */
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
+ printf(" SIOCSTIFFLAGS Down/Running\n"); break;
+ octeon_rgmx_stop(sc);
+ } else {
+ printf(" SIOCSTIFFLAGS Down/Not-Running\n"); break;
+ }
+ }
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ break;
+
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ /* Let if_media to handle these commands and to call
+ us back. */
+ error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
+ break;
+
+ case SIOCSIFCAP:
+ {
+ int mask;
+
+ ifp->if_hwassist &= ~CSUM_TSO;
+ ifp->if_capenable &= ~IFCAP_VLAN_HWTAGGING;
+ mask = ifr->ifr_reqcap ^ ifp->if_capenable;
+ if (mask & IFCAP_HWCSUM) {
+ ifp->if_capenable ^= IFCAP_HWCSUM;
+ if (ifp->if_capenable & IFCAP_TXCSUM) {
+ ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
+ } else {
+ ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP);
+ }
+ }
+ }
+ break;
+
+ default:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ }
+
+ return (error);
+}
+
+
+
+
+/*
+ * octeon_rgmx_mark_ready
+ *
+ * Initialize the rgmx driver for this instance
+ * Initialize device.
+ */
+static void octeon_rgmx_mark_ready (struct rgmx_softc_dev *sc)
+{
+
+ /* Enable interrupts. */
+ /* For RGMX they are already enabled earlier */
+
+ /* Enable transmitter and receiver. */
+ /* For RGMX they are already enabled earlier */
+
+ /* Flush out all HW receive buffers for this interface. */
+ /* For RGMX, no means to flush an individual port */
+
+ /* Set 'running' flag, because we are now running. */
+ sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
+
+ /* Set the HW Address filter. aka program Mac-addr & Multicast filters */
+ /* For RGMX this was taken care of via set_mac_addr() */
+
+ /* Kick start the output */
+ /* Hopefully PKO is running and will pick up packets via the timer or receive loop */
+}
+
+
+static void octeon_rgmx_init (void *xsc)
+{
+
+ /*
+ * Called mostly from ifnet interface ifp->if_init();
+ * I think we can anchor most of our iniialization here and
+ * not do it in different places from driver_attach().
+ */
+ /*
+ * For now, we only mark the interface ready
+ */
+ octeon_rgmx_mark_ready((struct rgmx_softc_dev *) xsc);
+}
+
+
+
+static void octeon_rgmx_config_speed (u_int port, u_int report_link)
+{
+ int index = INDEX(port);
+ int iface = INTERFACE(port);
+ struct rgmx_softc_dev *sc;
+ octeon_rgmx_rxx_rx_inbnd_t link_status, old_link_status;
+ octeon_rgmx_prtx_cfg_t gmx_cfg;
+ uint64_t val64_tx_clk, val64_tx_slot, val64_tx_burst;
+ u_int last_enabled;
+
+
+ sc = get_rgmx_softc(port);
+ if (!sc) {
+ printf(" config_speed didn't find sc int:%u port:%u", iface, port);
+ return;
+ }
+
+ /*
+ * Look up interface-port speed params
+ */
+ link_status.word64 = oct_read64(OCTEON_RGMX_RXX_RX_INBND(index, iface));
+
+ /*
+ * Compre to prev known state. If same then nothing to do.
+ */
+ if (link_status.word64 == sc->link_status) {
+ return;
+ }
+
+ RGMX_LOCK(sc);
+
+ old_link_status.word64 = sc->link_status;
+
+ sc->link_status = link_status.word64;
+
+ last_enabled = octeon_rgmx_stop_port(port);
+
+ gmx_cfg.word64 = oct_read64(OCTEON_RGMX_PRTX_CFG(index, iface));
+
+ /*
+ * Duplex
+ */
+ gmx_cfg.bits.duplex = 1;
+
+ switch (link_status.bits.speed) {
+ case 0: /* 10Mbps */
+ gmx_cfg.bits.speed = 0;
+ gmx_cfg.bits.slottime = 0;
+ val64_tx_clk = 50; val64_tx_slot = 0x40; val64_tx_burst = 0;
+ break;
+ case 1: /* 100Mbps */
+ gmx_cfg.bits.speed = 0;
+ gmx_cfg.bits.slottime = 0;
+ val64_tx_clk = 5; val64_tx_slot = 0x40; val64_tx_burst = 0;
+ break;
+
+ case 2: /* 1Gbps */
+ gmx_cfg.bits.speed = 1;
+ gmx_cfg.bits.slottime = 1;
+ val64_tx_clk = 1; val64_tx_slot = 0x200; val64_tx_burst = 0x2000;
+ break;
+
+ case 3: /* ?? */
+ default:
+ gmx_cfg.bits.speed = 1;
+ gmx_cfg.bits.slottime = 1;
+ val64_tx_clk = 1; val64_tx_slot = 0x200; val64_tx_burst = 0x2000;
+ break;
+ }
+
+ oct_write64(OCTEON_RGMX_TXX_CLK(index, iface), val64_tx_clk);
+ oct_write64(OCTEON_RGMX_TXX_SLOT(index, iface), val64_tx_slot);
+ oct_write64(OCTEON_RGMX_TXX_BURST(index, iface), val64_tx_burst);
+
+ oct_write64(OCTEON_RGMX_PRTX_CFG(index, iface), gmx_cfg.word64);
+
+ if (last_enabled) octeon_rgmx_start_port(port);
+
+ if (link_status.bits.status != old_link_status.bits.status) {
+
+//#define DEBUG_LINESTATUS
+ if (link_status.bits.status) {
+#ifdef DEBUG_LINESTATUS
+ printf(" %u/%u: Interface is now alive\n", iface, port);
+#endif
+ if (report_link) if_link_state_change(sc->ifp, LINK_STATE_UP);
+ } else {
+#ifdef DEBUG_LINESTATUS
+ printf(" %u/%u: Interface went down\n", iface, port);
+#endif
+ if (report_link) if_link_state_change(sc->ifp, LINK_STATE_DOWN);
+ }
+ }
+ RGMX_UNLOCK(sc);
+
+}
+
+
+
+#ifdef DEBUG_RGMX_DUMP
+static void octeon_dump_rgmx_stats (u_int port)
+{
+
+}
+#endif
+
+#ifdef __not_used__
+static void rgmx_timer_periodic (void)
+{
+ u_int port;
+ int index;
+ struct rgmx_softc_dev *sc;
+ struct ifnet *ifp;
+
+ for (index = 0; index < OCTEON_RGMX_NUM_PORTS_MAX; index ++) {
+
+ port = port_array[index];
+ sc = rgmx_scdev_array[index];
+
+ /*
+ * Skip over ports/slots not in service.
+ */
+ if ((port < OCTEON_RGMX_MIN_PORT) || (port > OCTEON_RGMX_MAX_PORT)) {
+ continue;
+ }
+ if ((NULL == sc) || (((struct rgmx_softc_dev *)-1) == sc)) {
+ continue;
+ }
+
+ /*
+ * Now look for anamolous conditions
+ */
+ if (sc != get_rgmx_softc(port)) {
+ printf(" port %u sc %p not in sync with index: %u\n",
+ port, sc, index);
+ continue;
+ }
+
+ if (sc->port != port) {
+ printf(" port %u sc %p port-> %u not in sync with index: %u\n",
+ port, sc, sc->port, index);
+ continue;
+ }
+
+ ifp = sc->ifp;
+ if (ifp == NULL) {
+ printf(" port %u sc %p . Bad ifp %p\n", port, sc, ifp);
+ continue;
+ }
+
+ /*
+ * Check if packets queued at ifnet layer. Kick start output if we can.
+ */
+ if (sc->ifp->if_flags & IFF_UP) {
+ octeon_rgmx_output_start(ifp);
+ } else {
+ octeon_rgmx_output_flush(ifp);
+ }
+
+ /*
+ * Check if line status changed ? Adjust ourselves.
+ */
+ octeon_rgmx_config_speed(port, 1);
+ }
+}
+#endif
+
+#ifdef DEBUG_RGMX_DUMP
+static void octeon_dump_pow_stats(void)
+{
+ octeon_rgmx_pow_nos_cnt nos_cnt;
+ octeon_rgmx_pow_int_pc_t intpc;
+ octeon_rgmx_pow_int_threshold_t thr;
+ octeon_rgmx_pow_int_cnt_t int_cnt;
+ int core = octeon_get_core_num();
+ octeon_pow_inpt_q_all_qos inpt_q_all;
+ octeon_pow_inpt_q_grp_qos inpt_q_grp;
+ octeon_rgmx_pip_inb_pkts pkts;
+ octeon_rgmx_pip_inb_errs errs;
+ static u_int pkts0 = 0;
+ static u_int pkts1 = 0;
+ static u_int errs0 = 0;
+ static u_int errs1 = 0;
+ int i;
+
+
+ nos_cnt.word64 = oct_read64(OCTEON_RGMX_POW_NOS_CNT);
+ if (nos_cnt.bits.nos_cnt) printf(" *** No sched cnt %u\n", nos_cnt.bits.nos_cnt);
+ printf(" \nGroup mask: 0x%llX WorkQueue Int : 0x%llX\n", oct_read64(OCTEON_POW_CORE_GROUP_MASK(OUR_CORE)), oct_read64(OCTEON_POW_WORKQUEUE_INT));
+ intpc.word64 = oct_read64(OCTEON_POW_WORKQUEUE_INT_PC);
+ printf(" Intr Periodic Cntr: PC %u thr: %u\n", intpc.bits.thr_freq, intpc.bits.thr_period);
+ thr.word64 = oct_read64(OCTEON_POW_WORKQUEUE_INT_THRESHOLD(OCTEON_POW_RX_GROUP_NUM));
+ printf(" Thresholds iq %u ds %u time %u enable %u\n",
+ thr.bits.iq_thr, thr.bits.ds_thr, thr.bits.time_thr, thr.bits.enable);
+ int_cnt.word64 = oct_read64(OCTEON_POW_INT_CNTR(core));
+ printf(" Int_cnt iq_cnt %u ds_cnt %u tc_cnt %u\n",
+ int_cnt.bits.iq_cnt, int_cnt.bits.ds_cnt, int_cnt.bits.tc_cnt);
+ pkts.word64 = oct_read64(OCTEON_PIP_STAT_INB_PKTS(16)); pkts0 += pkts.bits.inb_pkts;
+ errs.word64 = oct_read64(OCTEON_PIP_STAT_INB_ERRS(16)); errs0 += errs.bits.inb_errs;
+ pkts.word64 = oct_read64(OCTEON_PIP_STAT_INB_PKTS(17)); pkts1 += pkts.bits.inb_pkts;
+ errs.word64 = oct_read64(OCTEON_PIP_STAT_INB_ERRS(17)); errs1 += errs.bits.inb_errs;
+ printf(" PIP inbound pkts(16): %u Errors: %u inbound(17): %u Errors: %u\n", pkts0, errs0, pkts1, errs1);
+ inpt_q_all.word64 = oct_read64(OCTEON_POW_INPT_Q_ALL_QOS);
+ printf(" All queued pkt in qos Levels: %u -- ", inpt_q_all.bits.iq_cnt);
+ for (i = 0 ; i < 7; i++) {
+ inpt_q_grp.word64 = oct_read64(OCTEON_POW_INPT_QOS_GRP(i));
+ if (inpt_q_grp.bits.iq_cnt) printf(" Grp-%u: %u ", i, inpt_q_grp.bits.iq_cnt);
+ }
+}
+#endif
+
+/* ------------------------------------------------------------------- *
+ * octeon_line_status_loop() *
+ * ------------------------------------------------------------------- */
+static void octeon_line_status_loop (void *unused)
+{
+ struct rgmx_softc_dev *sc;
+ u_int idx;
+
+ for (idx = 0; idx < num_devices; idx++) {
+ sc = rgmx_scdev_array[idx];
+ if (sc && sc->ifp) {
+ if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+ octeon_rgmx_config_speed(sc->port, 1);
+
+ octeon_rgmx_output_start(sc->ifp);
+ }
+ }
+ }
+
+//#define DEBUG_RGMX_DUMP
+#ifdef DEBUG_RGMX_DUMP
+ static int count = 0;
+
+ if (++count > 5) {
+ count = 0;
+// octeon_dump_fpa_pool(OCTEON_FPA_RX_PACKET_POOL);
+// octeon_dump_fpa_pool(OCTEON_FPA_WQE_RX_POOL);
+// octeon_dump_fpa_pool(OCTEON_FPA_TX_PACKET_POOL);
+ octeon_dump_rgmx_stats(16);
+ octeon_dump_pow_stats();
+ }
+#endif
+}
+
+
+/* ------------------------------------------------------------------- *
+ * octeon_rgmx_set_mac *
+ * ------------------------------------------------------------------- *
+ *
+ * octeon_rgmx_set_mac
+ *
+ * Program the ethernet HW address
+ *
+ */
+static void octeon_rgmx_set_mac (u_int port)
+{
+ struct rgmx_softc_dev *sc;
+ u_int iface = INTERFACE(port);
+ u_int index = INDEX(port);
+ int ii;
+ uint64_t mac = 0;
+ u_int last_enabled;
+
+ sc = get_rgmx_softc(port);
+ if (!sc) {
+ printf(" octeon_rgmx_set_mac Missing sc. port:%u", port);
+ return;
+ }
+
+ for (ii = 0; ii < 6; ii++) {
+ mac = (mac << 8) | (uint64_t)(sc->ieee[ii]);
+ }
+
+ last_enabled = octeon_rgmx_stop_port(port);
+
+ oct_write64(OCTEON_RGMX_SMACX(index, iface), mac);
+ oct_write64(OCTEON_RGMX_RXX_ADR_CAM0(index, iface), sc->ieee[0]);
+ oct_write64(OCTEON_RGMX_RXX_ADR_CAM1(index, iface), sc->ieee[1]);
+ oct_write64(OCTEON_RGMX_RXX_ADR_CAM2(index, iface), sc->ieee[2]);
+ oct_write64(OCTEON_RGMX_RXX_ADR_CAM3(index, iface), sc->ieee[3]);
+ oct_write64(OCTEON_RGMX_RXX_ADR_CAM4(index, iface), sc->ieee[4]);
+ oct_write64(OCTEON_RGMX_RXX_ADR_CAM5(index, iface), sc->ieee[5]);
+ oct_write64(OCTEON_RGMX_RXX_ADR_CTL(index, iface),
+ OCTEON_RGMX_ADRCTL_ACCEPT_BROADCAST |
+ OCTEON_RGMX_ADRCTL_ACCEPT_ALL_MULTICAST |
+ OCTEON_RGMX_ADRCTL_CAM_MODE_ACCEPT_DMAC);
+ oct_write64(OCTEON_RGMX_RXX_ADR_CAM_EN(index, iface), 1);
+ if (last_enabled) octeon_rgmx_start_port(port);
+}
+
+
+/* ------------------------------------------------------------------- *
+ * octeon_config_rgmii_port() *
+ * ------------------------------------------------------------------- */
+static void octeon_config_rgmii_port (u_int port)
+{
+ u_int iface = INTERFACE(port);
+ u_int index = INDEX(port);
+
+ /*
+ * Configure an RGMII port
+ */
+ octeon_rgmx_prtx_cfg_t gmx_cfg;
+
+ /* Enable ASX */
+ oct_write64(OCTEON_ASXX_RX_PRT_EN(iface), oct_read64(OCTEON_ASXX_RX_PRT_EN(iface)) | (1<<index));
+ oct_write64(OCTEON_ASXX_TX_PRT_EN(iface), oct_read64(OCTEON_ASXX_TX_PRT_EN(iface)) | (1<<index));
+
+ /* Enable RGMX */
+ gmx_cfg.word64 = oct_read64(OCTEON_RGMX_PRTX_CFG(index, iface));
+ gmx_cfg.bits.en = 1;
+ oct_write64(OCTEON_RGMX_PRTX_CFG(index, iface), gmx_cfg.word64);
+
+
+ octeon_rgmx_config_speed(port, 0);
+
+ oct_write64(OCTEON_RGMX_TXX_THRESH(index, iface), 32);
+
+ /*
+ * Set hi water mark
+ */
+ oct_write64(OCTEON_ASXX_TX_HI_WATERX(index, iface), 10);
+ if (octeon_get_chipid() == OCTEON_CN5020_CHIP) {
+ oct_write64(OCTEON_ASXX_TX_CLK_SETX(index, iface), 16);
+ oct_write64(OCTEON_ASXX_RX_CLK_SETX(index, iface), 16);
+ } else {
+ oct_write64(OCTEON_ASXX_TX_CLK_SETX(index, iface), 24);
+ oct_write64(OCTEON_ASXX_RX_CLK_SETX(index, iface), 24);
+ }
+}
+
+
+
+static void octeon_rgmx_enable_RED_queue (int queue, int slow_drop, int all_drop)
+{
+ octeon_rgmx_ipd_queue_red_marks_t red_marks;
+ octeon_rgmx_ipd_red_q_param_t red_param;
+
+ if (slow_drop == all_drop) { printf("Bad val in %s", __FUNCTION__); return; }
+ red_marks.word64 = 0;
+ red_marks.bits.all_drop = all_drop;
+ red_marks.bits.slow_drop = slow_drop;
+ oct_write64(OCTEON_IPD_QOSX_RED_MARKS(queue), red_marks.word64);
+
+ /* Use the actual queue 0 counter, not the average */
+ red_param.word64 = 0;
+ red_param.bits.prb_con = (255ul << 24) / (slow_drop - all_drop);
+ red_param.bits.avg_con = 1;
+ red_param.bits.new_con = 255;
+ red_param.bits.use_pagecount = 1;
+ oct_write64(OCTEON_IPD_RED_Q_PARAM(queue), red_param.word64);
+}
+
+
+static void octeon_rgmx_enable_RED_all (int slow_drop, int all_drop)
+{
+
+ int port, queue;
+ octeon_ipd_port_bp_page_count_t ipd_bp_page_count;
+ octeon_ipd_red_port_enable_t red_port_enable;
+
+ /*
+ * First remove BP settings
+ */
+ ipd_bp_page_count.word64 = 0;
+ ipd_bp_page_count.bits.bp_enable = 0;
+ ipd_bp_page_count.bits.page_count = 100;
+
+ for (port = 0; port < OCTEON_RGMX_MAX_PORT; port++) {
+ oct_write64(OCTEON_IPD_PORT_BP_PAGE_COUNT(port), ipd_bp_page_count.word64);
+ }
+
+ /*
+ * Enable RED for each individual queue
+ */
+ for (queue = 0; queue < 8; queue++) {
+ octeon_rgmx_enable_RED_queue(queue, slow_drop, all_drop);
+ }
+
+ oct_write64(OCTEON_IPD_BP_PORT_RED_END, 0);
+
+ red_port_enable.word64 = 0;
+ red_port_enable.bits.port_enable = 0xfffffffffull;
+ red_port_enable.bits.avg_dly = 10000;
+ red_port_enable.bits.prb_dly = 10000;
+ oct_write64(OCTEON_IPD_RED_PORT_ENABLE, red_port_enable.word64);
+}
+
+
+
+/* ------------------------------------------------------------------- *
+ * octeon_has_4ports() *
+ * ------------------------------------------------------------------- */
+static int octeon_has_4ports (void)
+{
+ u_int chipid;
+ int retcode = 1;
+
+ chipid = octeon_get_chipid() & 0xffffff00;
+
+ switch (chipid) {
+ case OCTEON_CN31XX_CHIP:
+ case OCTEON_CN30XX_CHIP:
+ case OCTEON_CN5020_CHIP:
+ retcode = 0;
+ break;
+
+ default:
+ break;
+ }
+ return (retcode);
+}
+
+
+#ifdef __not_used__
+/*
+ * octeon_rgmx_free_intr
+ *
+ * We have 4 child and one parent device.
+ * It's tricky and unexpected that anyone will detach the device that is built'in on
+ * the chip.
+ * We will not support detachment for now. But keep adding good code that will be used
+ * someday.
+ */
+static void octeon_rgmx_free_intr (struct rgmx_softc_dev *sc)
+{
+ device_t dev = sc->sc_dev;
+
+ /*
+ * Make sure that sc/dev are the parent Root structs. Not one
+ * of the rgmxN childs.
+ */
+ if (int_handler_tag != NULL) {
+ bus_teardown_intr(dev, irq_res, int_handler_tag);
+ int_handler_tag = NULL;
+ }
+
+#ifdef OCTEON_RGMX_SCHEDULED_ISRS
+ if (tq != NULL) {
+ taskqueue_drain(tq, &rxtx_isr_task);
+ taskqueue_drain(taskqueue_fast, &link_isr_task);
+ taskqueue_free(tq);
+ tq = NULL;
+ }
+#endif
+
+}
+#endif
+
+static device_method_t rgmii_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, rgmii_probe),
+ DEVMETHOD(device_identify, rgmii_identify),
+ DEVMETHOD(device_attach, rgmii_attach),
+ DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ { 0, 0 }
+};
+
+static driver_t rgmii_driver = {
+ "rgmii", rgmii_methods, sizeof(struct rgmx_softc_dev)
+};
+
+static devclass_t rgmii_devclass;
+
+DRIVER_MODULE(rgmii, nexus, rgmii_driver, rgmii_devclass, 0, 0);
diff --git a/sys/mips/cavium/dev/rgmii/octeon_rgmx.h b/sys/mips/cavium/dev/rgmii/octeon_rgmx.h
new file mode 100644
index 0000000..e6d8e76
--- /dev/null
+++ b/sys/mips/cavium/dev/rgmii/octeon_rgmx.h
@@ -0,0 +1,590 @@
+/*------------------------------------------------------------------
+ * octeon_rgmx.h RGMII Ethernet Interfaces
+ *
+ *------------------------------------------------------------------
+ */
+
+
+#ifndef ___OCTEON_RGMX__H___
+#define ___OCTEON_RGMX__H___
+
+
+
+#define OCTEON_FPA_PACKET_POOL 0
+#define OCTEON_FPA_WQE_RX_POOL 1
+#define OCTEON_FPA_OUTPUT_BUFFER_POOL 2
+#define OCTEON_FPA_WQE_POOL_SIZE (1 * OCTEON_CACHE_LINE_SIZE)
+#define OCTEON_FPA_OUTPUT_BUFFER_POOL_SIZE (8 * OCTEON_CACHE_LINE_SIZE)
+#define OCTEON_FPA_PACKET_POOL_SIZE (16 * OCTEON_CACHE_LINE_SIZE)
+
+#define OCTEON_POW_WORK_REQUEST(wait) (0x8001600000000000ull | (wait<<3))
+
+typedef union
+{
+ void* ptr;
+ uint64_t word64;
+ struct
+ {
+ uint64_t i : 1;
+ uint64_t back : 4;
+ uint64_t pool : 3;
+ uint64_t size :16;
+ uint64_t addr :40;
+ } bits;
+} octeon_buf_ptr_t;
+
+/**
+ * Work queue entry format
+ */
+typedef struct
+{
+ uint16_t hw_chksum;
+ uint8_t unused;
+ uint64_t next_ptr : 40;
+ uint64_t len :16;
+ uint64_t ipprt : 6;
+ uint64_t qos : 3;
+ uint64_t grp : 4;
+ uint64_t tag_type : 3;
+ uint64_t tag :32;
+ union
+ {
+ uint64_t word64;
+ struct
+ {
+ uint64_t bufs : 8;
+ uint64_t ip_offset : 8;
+ uint64_t vlan_valid : 1;
+ uint64_t unassigned : 2;
+ uint64_t vlan_cfi : 1;
+ uint64_t vlan_id :12;
+ uint64_t unassigned2 :12;
+ uint64_t dec_ipcomp : 1;
+ uint64_t tcp_or_udp : 1;
+ uint64_t dec_ipsec : 1;
+ uint64_t is_v6 : 1;
+ uint64_t software : 1;
+ uint64_t L4_error : 1;
+ uint64_t is_frag : 1;
+ uint64_t IP_exc : 1;
+ uint64_t is_bcast : 1;
+ uint64_t is_mcast : 1;
+ uint64_t not_IP : 1;
+ uint64_t rcv_error : 1;
+ uint64_t err_code : 8;
+ } bits;
+ struct
+ {
+ uint64_t bufs : 8;
+ uint64_t unused : 8;
+ uint64_t vlan_valid : 1;
+ uint64_t unassigned : 2;
+ uint64_t vlan_cfi : 1;
+ uint64_t vlan_id :12;
+ uint64_t unassigned2 :16;
+ uint64_t software : 1;
+ uint64_t unassigned3 : 1;
+ uint64_t is_rarp : 1;
+ uint64_t is_arp : 1;
+ uint64_t is_bcast : 1;
+ uint64_t is_mcast : 1;
+ uint64_t not_IP : 1;
+ uint64_t rcv_error : 1;
+ uint64_t err_code : 8;
+ } snoip;
+ } word2;
+ octeon_buf_ptr_t packet_ptr;
+ uint8_t packet_data[96];
+} octeon_wqe_t;
+
+typedef union {
+ uint64_t word64;
+
+ struct {
+ uint64_t scraddr : 8; /**< the (64-bit word) location in scratchpad to write to (if len != 0) */
+ uint64_t len : 8; /**< the number of words in the response (0 => no response) */
+ uint64_t did : 8; /**< the ID of the device on the non-coherent bus */
+ uint64_t unused :36;
+ uint64_t wait : 1; /**< if set, don't return load response until work is available */
+ uint64_t unused2 : 3;
+ } bits;
+
+} octeon_pow_iobdma_store_t;
+
+
+/**
+ * Wait flag values for pow functions.
+ */
+typedef enum
+{
+ OCTEON_POW_WAIT = 1,
+ OCTEON_POW_NO_WAIT = 0,
+} octeon_pow_wait_t;
+
+
+
+static inline void * phys_to_virt (unsigned long address)
+{
+ return (void *)(address + 0x80000000UL);
+}
+
+// decode within DMA space
+typedef enum {
+ OCTEON_ADD_WIN_DMA_ADD = 0L, // add store data to the write buffer entry, allocating it if necessary
+ OCTEON_ADD_WIN_DMA_SENDMEM = 1L, // send out the write buffer entry to DRAM
+ // store data must be normal DRAM memory space address in this case
+ OCTEON_ADD_WIN_DMA_SENDDMA = 2L, // send out the write buffer entry as an IOBDMA command
+ // see OCTEON_ADD_WIN_DMA_SEND_DEC for data contents
+ OCTEON_ADD_WIN_DMA_SENDIO = 3L, // send out the write buffer entry as an IO write
+ // store data must be normal IO space address in this case
+ OCTEON_ADD_WIN_DMA_SENDSINGLE = 4L, // send out a single-tick command on the NCB bus
+ // no write buffer data needed/used
+} octeon_add_win_dma_dec_t;
+
+
+#define OCTEON_OCT_DID_FPA 5ULL
+#define OCTEON_OCT_DID_TAG 12ULL
+#define OCTEON_OCT_DID_TAG_SWTAG OCTEON_ADDR_FULL_DID(OCTEON_OCT_DID_TAG, 0ULL)
+
+
+#define OCTEON_IOBDMA_OFFSET (-3*1024ll)
+#define OCTEON_IOBDMA_SEP 16
+#define OCTEON_IOBDMA_SENDSINGLE (OCTEON_IOBDMA_OFFSET + \
+ (OCTEON_ADD_WIN_DMA_SENDSINGLE *\
+ OCTEON_IOBDMA_SEP))
+
+static inline void octeon_send_single (uint64_t data)
+{
+ oct_write64((uint64_t)(OCTEON_IOBDMA_SENDSINGLE * (long long)8), data);
+}
+
+
+static inline void octeon_pow_work_request_async_nocheck (int scratch_addr,
+ octeon_pow_wait_t wait)
+{
+ octeon_pow_iobdma_store_t data;
+
+ /* scratch_addr must be 8 byte aligned */
+ data.bits.scraddr = scratch_addr >> 3;
+ data.bits.len = 1;
+ data.bits.did = OCTEON_OCT_DID_TAG_SWTAG;
+ data.bits.wait = wait;
+ octeon_send_single(data.word64);
+}
+
+
+
+/**
+ * octeon_gmx_inf_mode
+ *
+ * GMX_INF_MODE = Interface Mode
+ *
+ */
+typedef union
+{
+ uint64_t word64;
+ struct gmxx_inf_mode_s
+ {
+ uint64_t reserved_3_63 : 61;
+ uint64_t p0mii : 1; /**< Port 0 Interface Mode
+ 0: Port 0 is RGMII
+ 1: Port 0 is MII */
+ uint64_t en : 1; /**< Interface Enable */
+ uint64_t type : 1; /**< Interface Mode
+ 0: RGMII Mode
+ 1: Spi4 Mode */
+ } bits;
+ struct gmxx_inf_mode_cn3020
+ {
+ uint64_t reserved_2_63 : 62;
+ uint64_t en : 1; /**< Interface Enable */
+ uint64_t type : 1; /**< Interface Mode
+ 0: All three ports are RGMII ports
+ 1: prt0 is RGMII, prt1 is GMII, and prt2 is unused */
+ } cn3020;
+ struct gmxx_inf_mode_s cn30xx;
+ struct gmxx_inf_mode_cn3020 cn31xx;
+ struct gmxx_inf_mode_cn3020 cn36xx;
+ struct gmxx_inf_mode_cn3020 cn38xx;
+ struct gmxx_inf_mode_cn3020 cn38xxp2;
+ struct gmxx_inf_mode_cn3020 cn56xx;
+ struct gmxx_inf_mode_cn3020 cn58xx;
+} octeon_gmxx_inf_mode_t;
+
+
+
+
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 60; /* Reserved */
+ uint64_t slottime : 1; /* Slot Time for Half-Duplex */
+ /* operation - 0 = 512 bitimes (10/100Mbs operation) */
+ /* - 1 = 4096 bitimes (1000Mbs operation) */
+ uint64_t duplex : 1; /* Duplex - 0 = Half Duplex */
+ /* (collisions/extentions/bursts) - 1 = Full Duplex */
+ uint64_t speed : 1; /* Link Speed - 0 = 10/100Mbs */
+ /* operation - 1 = 1000Mbs operation */
+ uint64_t en : 1; /* Link Enable */
+ } bits;
+} octeon_rgmx_prtx_cfg_t;
+
+
+/*
+ * GMX_RX_INBND = RGMX InBand Link Status
+ *
+ */
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 60; /* Reserved */
+ uint64_t duplex : 1; /* 0 = Half, 1 = Full */
+ uint64_t speed : 2; /* Inbound Link Speed */
+ /* 00 = 2.5Mhz, 01 = 25Mhz */
+ /* 10 = 125MHz, 11 = Reserved */
+ uint64_t status : 1; /* Inbound Status Up/Down */
+ } bits;
+} octeon_rgmx_rxx_rx_inbnd_t;
+
+
+
+typedef union
+{
+ uint64_t word64;
+ struct {
+ uint64_t all_drop : 32;
+ uint64_t slow_drop : 32;
+ } bits;
+} octeon_rgmx_ipd_queue_red_marks_t;
+
+
+typedef union
+{
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 15;
+ uint64_t use_pagecount : 1;
+ uint64_t new_con : 8;
+ uint64_t avg_con : 8;
+ uint64_t prb_con : 32;
+ } bits;
+} octeon_rgmx_ipd_red_q_param_t;
+
+
+
+typedef union
+{
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 46;
+ uint64_t bp_enable : 1;
+ uint64_t page_count : 17;
+ } bits;
+} octeon_ipd_port_bp_page_count_t;
+
+
+typedef union
+{
+ uint64_t word64;
+ struct {
+ uint64_t prb_dly : 14;
+ uint64_t avg_dly : 14;
+ uint64_t port_enable : 36;
+ } bits;
+} octeon_ipd_red_port_enable_t;
+
+
+/**
+ * Tag type definitions
+ */
+typedef enum
+{
+ OCTEON_POW_TAG_TYPE_ORDERED = 0L, /**< Tag ordering is maintained */
+ OCTEON_POW_TAG_TYPE_ATOMIC = 1L, /**< Tag ordering is maintained, and at most one PP has the tag */
+ OCTEON_POW_TAG_TYPE_NULL = 2L, /**< The work queue entry from the order
+ - NEVER tag switch from NULL to NULL */
+ OCTEON_POW_TAG_TYPE_NULL_NULL = 3L /**< A tag switch to NULL, and there is no space reserved in POW
+ - NEVER tag switch to NULL_NULL
+ - NEVER tag switch from NULL_NULL
+ - NULL_NULL is entered at the beginning of time and on a deschedule.
+ - NULL_NULL can be exited by a new work request. A NULL_SWITCH load can also switch the state to NULL */
+} octeon_pow_tag_type_t ;
+
+/**
+ * This structure defines the response to a load/SENDSINGLE to POW (except CSR reads)
+ */
+typedef union {
+ uint64_t word64;
+
+ octeon_wqe_t *wqp;
+
+ // response to new work request loads
+ struct {
+ uint64_t no_work : 1; // set when no new work queue entry was returned
+ // If there was de-scheduled work, the HW will definitely
+ // return it. When this bit is set, it could mean
+ // either mean:
+ // - There was no work, or
+ // - There was no work that the HW could find. This
+ // case can happen, regardless of the wait bit value
+ // in the original request, when there is work
+ // in the IQ's that is too deep down the list.
+ uint64_t unused : 23;
+ uint64_t addr : 40; // 36 in O1 -- the work queue pointer
+ } s_work;
+
+ // response to NULL_RD request loads
+ struct {
+ uint64_t unused : 62;
+ uint64_t state : 2; // of type octeon_pow_tag_type_t
+ // state is one of the following:
+ // OCTEON_POW_TAG_TYPE_ORDERED
+ // OCTEON_POW_TAG_TYPE_ATOMIC
+ // OCTEON_POW_TAG_TYPE_NULL
+ // OCTEON_POW_TAG_TYPE_NULL_NULL
+ } s_null_rd;
+
+} octeon_pow_tag_load_resp_t;
+
+
+/*
+ * This structure describes the address to load stuff from POW
+ */
+typedef union {
+ uint64_t word64;
+
+ // address for new work request loads (did<2:0> == 0)
+ struct {
+ uint64_t mem_region :2;
+ uint64_t mbz :13;
+ uint64_t is_io : 1; // must be one
+ uint64_t did : 8; // the ID of POW -- did<2:0> == 0 in this case
+ uint64_t unaddr : 4;
+ uint64_t unused :32;
+ uint64_t wait : 1; // if set, don't return load response until work is available
+ uint64_t mbzl : 3; // must be zero
+ } swork; // physical address
+
+
+ // address for NULL_RD request (did<2:0> == 4)
+ // when this is read, HW attempts to change the state to NULL if it is NULL_NULL
+ // (the hardware cannot switch from NULL_NULL to NULL if a POW entry is not available -
+ // software may need to recover by finishing another piece of work before a POW
+ // entry can ever become available.)
+ struct {
+ uint64_t mem_region :2;
+ uint64_t mbz :13;
+ uint64_t is_io : 1; // must be one
+ uint64_t did : 8; // the ID of POW -- did<2:0> == 4 in this case
+ uint64_t unaddr : 4;
+ uint64_t unused :33;
+ uint64_t mbzl : 3; // must be zero
+ } snull_rd; // physical address
+
+ // address for CSR accesses
+ struct {
+ uint64_t mem_region :2;
+ uint64_t mbz :13;
+ uint64_t is_io : 1; // must be one
+ uint64_t did : 8; // the ID of POW -- did<2:0> == 7 in this case
+ uint64_t unaddr : 4;
+ uint64_t csraddr:36; // only 36 bits in O1, addr<2:0> must be zero
+ } stagcsr; // physical address
+
+} octeon_pow_load_addr_t;
+
+
+static inline void octeon_pow_tag_switch_wait (void)
+{
+ uint64_t switch_complete;
+
+ do
+ {
+ OCTEON_CHORD_HEX(&switch_complete);
+ } while (!switch_complete);
+
+ return;
+}
+
+
+static inline octeon_wqe_t *octeon_pow_work_request_sync_nocheck (octeon_pow_wait_t wait)
+{
+ octeon_pow_load_addr_t ptr;
+ octeon_pow_tag_load_resp_t result;
+
+ ptr.word64 = 0;
+ ptr.swork.mem_region = OCTEON_IO_SEG;
+ ptr.swork.is_io = 1;
+ ptr.swork.did = OCTEON_OCT_DID_TAG_SWTAG;
+ ptr.swork.wait = wait;
+
+ result.word64 = oct_read64(ptr.word64);
+
+ if (result.s_work.no_work || !result.s_work.addr) {
+ return NULL;
+ }
+ return (octeon_wqe_t *) MIPS_PHYS_TO_KSEG0(result.s_work.addr);
+}
+
+static inline octeon_wqe_t *octeon_pow_work_request_sync_nocheck_debug (octeon_pow_wait_t wait)
+{
+ octeon_pow_load_addr_t ptr;
+ octeon_pow_tag_load_resp_t result;
+
+ ptr.word64 = 0;
+ ptr.swork.mem_region = OCTEON_IO_SEG;
+ ptr.swork.is_io = 1;
+ ptr.swork.did = OCTEON_OCT_DID_TAG_SWTAG;
+ ptr.swork.wait = wait;
+
+ result.word64 = oct_read64(ptr.word64);
+
+ printf("WQE Result: 0x%llX No-work %X Addr %llX Ptr: %p\n",
+ (unsigned long long)result.word64, result.s_work.no_work,
+ (unsigned long long)result.s_work.addr,
+ (void *)MIPS_PHYS_TO_KSEG0(result.s_work.addr));
+
+ if (result.s_work.no_work || !result.s_work.addr) {
+ return NULL;
+ }
+ return (octeon_wqe_t *) MIPS_PHYS_TO_KSEG0(result.s_work.addr);
+}
+
+static inline octeon_wqe_t *octeon_pow_work_request_sync (octeon_pow_wait_t wait)
+{
+ octeon_pow_tag_switch_wait();
+ return (octeon_pow_work_request_sync_nocheck(wait));
+}
+
+
+static inline octeon_wqe_t *octeon_pow_work_request_sync_debug (octeon_pow_wait_t wait)
+{
+ octeon_pow_tag_switch_wait();
+ return (octeon_pow_work_request_sync_nocheck_debug(wait));
+}
+
+
+
+/**
+ * Gets result of asynchronous work request. Performs a IOBDMA sync
+ * to wait for the response.
+ *
+ * @param scratch_addr Scratch memory address to get result from
+ * Byte address, must be 8 byte aligned.
+ * @return Returns the WQE from the scratch register, or NULL if no work was available.
+ */
+static inline octeon_wqe_t *octeon_pow_work_response_async(int scratch_addr)
+{
+ octeon_pow_tag_load_resp_t result;
+
+ OCTEON_SYNCIOBDMA;
+ result.word64 = oct_scratch_read64(scratch_addr);
+
+ if (result.s_work.no_work) {
+ return NULL;
+ }
+ return (octeon_wqe_t*) MIPS_PHYS_TO_KSEG0(result.s_work.addr);
+}
+
+
+
+/*
+ * The address from POW is a physical address. Adjust for back ptr, as well as
+ * make it accessible using KSEG0.
+ */
+static inline void *octeon_pow_pktptr_to_kbuffer (octeon_buf_ptr_t pkt_ptr)
+{
+ return ((void *)MIPS_PHYS_TO_KSEG0(
+ ((pkt_ptr.bits.addr >> 7) - pkt_ptr.bits.back) << 7));
+}
+
+#define INTERFACE(port) (port >> 4) /* Ports 0-15 are interface 0, 16-31 are interface 1 */
+#define INDEX(port) (port & 0xf)
+
+
+#define OCTEON_RGMX_PRTX_CFG(index,interface) (0x8001180008000010ull+((index)*2048)+((interface)*0x8000000ull))
+#define OCTEON_RGMX_SMACX(offset,block_id) (0x8001180008000230ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_RXX_ADR_CAM0(offset,block_id) (0x8001180008000180ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_RXX_ADR_CAM1(offset,block_id) (0x8001180008000188ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_RXX_ADR_CAM2(offset,block_id) (0x8001180008000190ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_RXX_ADR_CAM3(offset,block_id) (0x8001180008000198ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_RXX_ADR_CAM4(offset,block_id) (0x80011800080001A0ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_RXX_ADR_CAM5(offset,block_id) (0x80011800080001A8ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_RXX_ADR_CTL(offset,block_id) (0x8001180008000100ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_RXX_ADR_CAM_EN(offset,block_id) (0x8001180008000108ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_INF_MODE(block_id) (0x80011800080007F8ull+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_TX_PRTS(block_id) (0x8001180008000480ull+((block_id)*0x8000000ull))
+#define OCTEON_ASXX_RX_PRT_EN(block_id) (0x80011800B0000000ull+((block_id)*0x8000000ull))
+#define OCTEON_ASXX_TX_PRT_EN(block_id) (0x80011800B0000008ull+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_TXX_THRESH(offset,block_id) (0x8001180008000210ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_ASXX_TX_HI_WATERX(offset,block_id) (0x80011800B0000080ull+((offset)*8)+((block_id)*0x8000000ull))
+#define OCTEON_ASXX_RX_CLK_SETX(offset,block_id) (0x80011800B0000020ull+((offset)*8)+((block_id)*0x8000000ull))
+#define OCTEON_ASXX_TX_CLK_SETX(offset,block_id) (0x80011800B0000048ull+((offset)*8)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_RXX_RX_INBND(offset,block_id) (0x8001180008000060ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_TXX_CLK(offset,block_id) (0x8001180008000208ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_TXX_SLOT(offset,block_id) (0x8001180008000220ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_RGMX_TXX_BURST(offset,block_id) (0x8001180008000228ull+((offset)*2048)+((block_id)*0x8000000ull))
+#define OCTEON_PIP_GBL_CTL (0x80011800A0000020ull)
+#define OCTEON_PIP_GBL_CFG (0x80011800A0000028ull)
+#define OCTEON_PIP_PRT_CFGX(offset) (0x80011800A0000200ull+((offset)*8))
+#define OCTEON_PIP_PRT_TAGX(offset) (0x80011800A0000400ull+((offset)*8))
+
+
+
+#define OUR_CORE 0
+#define IP2 0
+#define IP3 1
+#define CIU_TIMERS 4
+#define OCTEON_POW_CORE_GROUP_MASK(core) (0x8001670000000000ull + (8 * core))
+
+#define OCTEON_CIU_INT_EN0(CORE,IP) (0x8001070000000200ull + (IP * 16) + \
+ ((CORE) * 32))
+#define OCTEON_CIU_INT_SUM0(CORE,IP) (0x8001070000000000ull + (IP * 8) + \
+ ((CORE) * 32))
+#define OCTEON_CIU_TIMX(offset) (0x8001070000000480ull+((offset)*8))
+
+#define OCTEON_POW_WQ_INT_THRX(offset) ((0x8001670000000080ull+((offset)*8)))
+#define OCTEON_POW_WQ_INT_CNTX(offset) ((0x8001670000000100ull+((offset)*8)))
+#define OCTEON_POW_QOS_THRX(offset) ((0x8001670000000180ull+((offset)*8)))
+#define OCTEON_POW_QOS_RNDX(offset) ((0x80016700000001C0ull+((offset)*8)))
+#define OCTEON_POW_WQ_INT_PC (0x8001670000000208ull)
+#define OCTEON_POW_NW_TIM (0x8001670000000210ull)
+#define OCTEON_POW_ECC_ERR (0x8001670000000218ull)
+#define OCTEON_POW_INT_CTL (0x8001670000000220ull)
+#define OCTEON_POW_NOS_CNT (0x8001670000000228ull)
+#define OCTEON_POW_WS_PCX(offset) ((0x8001670000000280ull+((offset)*8)))
+#define OCTEON_POW_WA_PCX(offset) ((0x8001670000000300ull+((offset)*8)))
+#define OCTEON_POW_IQ_CNTX(offset) ((0x8001670000000340ull+((offset)*8)))
+#define OCTEON_POW_WA_COM_PC (0x8001670000000380ull)
+#define OCTEON_POW_IQ_COM_CNT (0x8001670000000388ull)
+#define OCTEON_POW_TS_PC (0x8001670000000390ull)
+#define OCTEON_POW_DS_PC (0x8001670000000398ull)
+#define OCTEON_POW_BIST_STAT (0x80016700000003F8ull)
+
+
+#define OCTEON_POW_WQ_INT (0x8001670000000200ull)
+
+#define OCTEON_IPD_PORT_BP_COUNTERS_PAIRX(offset) (0x80014F00000001B8ull+((offset)*8))
+
+/*
+ * Current Counts that triggered interrupt
+ */
+#define OCTEON_POW_WQ_INT_CNTX(offset) ((0x8001670000000100ull+((offset)*8)))
+
+
+
+#define OCTEON_RGMX_ADRCTL_CAM_MODE_REJECT_DMAC 0
+#define OCTEON_RGMX_ADRCTL_ACCEPT_BROADCAST 1
+#define OCTEON_RGMX_ADRCTL_REJECT_ALL_MULTICAST 2
+#define OCTEON_RGMX_ADRCTL_ACCEPT_ALL_MULTICAST 4
+#define OCTEON_RGMX_ADRCTL_CAM_MODE_ACCEPT_DMAC 8
+
+
+#define RGMX_LOCK_INIT(_sc, _name) \
+ mtx_init(&(_sc)->mtx, _name, MTX_NETWORK_LOCK, MTX_DEF)
+#define RGMX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx)
+#define RGMX_LOCK(_sc) mtx_lock(&(_sc)->mtx)
+#define RGMX_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
+#define RGMX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED)
+
+#endif /* ___OCTEON_RGMX__H___ */
diff --git a/sys/mips/cavium/driveid.h b/sys/mips/cavium/driveid.h
new file mode 100644
index 0000000..b7befea
--- /dev/null
+++ b/sys/mips/cavium/driveid.h
@@ -0,0 +1,259 @@
+
+/*
+ * driveid.h
+ *
+ */
+
+#ifndef __DRIVEID_H__
+#define __DRIVEID_H__
+
+
+struct hd_driveid {
+ unsigned short config; /* lots of obsolete bit flags */
+ unsigned short cyls; /* Obsolete, "physical" cyls */
+ unsigned short reserved2; /* reserved (word 2) */
+ unsigned short heads; /* Obsolete, "physical" heads */
+ unsigned short track_bytes; /* unformatted bytes per track */
+ unsigned short sector_bytes; /* unformatted bytes per sector */
+ unsigned short sectors; /* Obsolete, "physical" sectors per track */
+ unsigned short vendor0; /* vendor unique */
+ unsigned short vendor1; /* vendor unique */
+ unsigned short vendor2; /* Retired vendor unique */
+ unsigned char serial_no[20]; /* 0 = not_specified */
+ unsigned short buf_type; /* Retired */
+ unsigned short buf_size; /* Retired, 512 byte increments
+ * 0 = not_specified
+ */
+ unsigned short ecc_bytes; /* for r/w long cmds; 0 = not_specified */
+ unsigned char fw_rev[8]; /* 0 = not_specified */
+ unsigned char model[40]; /* 0 = not_specified */
+ unsigned char max_multsect; /* 0=not_implemented */
+ unsigned char vendor3; /* vendor unique */
+ unsigned short dword_io; /* 0=not_implemented; 1=implemented */
+ unsigned char vendor4; /* vendor unique */
+ unsigned char capability; /* (upper byte of word 49)
+ * 3: IORDYsup
+ * 2: IORDYsw
+ * 1: LBA
+ * 0: DMA
+ */
+ unsigned short reserved50; /* reserved (word 50) */
+ unsigned char vendor5; /* Obsolete, vendor unique */
+ unsigned char tPIO; /* Obsolete, 0=slow, 1=medium, 2=fast */
+ unsigned char vendor6; /* Obsolete, vendor unique */
+ unsigned char tDMA; /* Obsolete, 0=slow, 1=medium, 2=fast */
+ unsigned short field_valid; /* (word 53)
+ * 2: ultra_ok word 88
+ * 1: eide_ok words 64-70
+ * 0: cur_ok words 54-58
+ */
+ unsigned short cur_cyls; /* Obsolete, logical cylinders */
+ unsigned short cur_heads; /* Obsolete, l heads */
+ unsigned short cur_sectors; /* Obsolete, l sectors per track */
+ unsigned short cur_capacity0; /* Obsolete, l total sectors on drive */
+ unsigned short cur_capacity1; /* Obsolete, (2 words, misaligned int) */
+ unsigned char multsect; /* current multiple sector count */
+ unsigned char multsect_valid; /* when (bit0==1) multsect is ok */
+ unsigned int lba_capacity; /* Obsolete, total number of sectors */
+ unsigned short dma_1word; /* Obsolete, single-word dma info */
+ unsigned short dma_mword; /* multiple-word dma info */
+ unsigned short eide_pio_modes; /* bits 0:mode3 1:mode4 */
+ unsigned short eide_dma_min; /* min mword dma cycle time (ns) */
+ unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */
+ unsigned short eide_pio; /* min cycle time (ns), no IORDY */
+ unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */
+ unsigned short words69_70[2]; /* reserved words 69-70
+ * future command overlap and queuing
+ */
+ /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
+ unsigned short words71_74[4]; /* reserved words 71-74
+ * for IDENTIFY PACKET DEVICE command
+ */
+ unsigned short queue_depth; /* (word 75)
+ * 15:5 reserved
+ * 4:0 Maximum queue depth -1
+ */
+ unsigned short words76_79[4]; /* reserved words 76-79 */
+ unsigned short major_rev_num; /* (word 80) */
+ unsigned short minor_rev_num; /* (word 81) */
+ unsigned short command_set_1; /* (word 82) supported
+ * 15: Obsolete
+ * 14: NOP command
+ * 13: READ_BUFFER
+ * 12: WRITE_BUFFER
+ * 11: Obsolete
+ * 10: Host Protected Area
+ * 9: DEVICE Reset
+ * 8: SERVICE Interrupt
+ * 7: Release Interrupt
+ * 6: look-ahead
+ * 5: write cache
+ * 4: PACKET Command
+ * 3: Power Management Feature Set
+ * 2: Removable Feature Set
+ * 1: Security Feature Set
+ * 0: SMART Feature Set
+ */
+ unsigned short command_set_2; /* (word 83)
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13: FLUSH CACHE EXT
+ * 12: FLUSH CACHE
+ * 11: Device Configuration Overlay
+ * 10: 48-bit Address Feature Set
+ * 9: Automatic Acoustic Management
+ * 8: SET MAX security
+ * 7: reserved 1407DT PARTIES
+ * 6: SetF sub-command Power-Up
+ * 5: Power-Up in Standby Feature Set
+ * 4: Removable Media Notification
+ * 3: APM Feature Set
+ * 2: CFA Feature Set
+ * 1: READ/WRITE DMA QUEUED
+ * 0: Download MicroCode
+ */
+ unsigned short cfsse; /* (word 84)
+ * cmd set-feature supported extensions
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13:6 reserved
+ * 5: General Purpose Logging
+ * 4: Streaming Feature Set
+ * 3: Media Card Pass Through
+ * 2: Media Serial Number Valid
+ * 1: SMART selt-test supported
+ * 0: SMART error logging
+ */
+ unsigned short cfs_enable_1; /* (word 85)
+ * command set-feature enabled
+ * 15: Obsolete
+ * 14: NOP command
+ * 13: READ_BUFFER
+ * 12: WRITE_BUFFER
+ * 11: Obsolete
+ * 10: Host Protected Area
+ * 9: DEVICE Reset
+ * 8: SERVICE Interrupt
+ * 7: Release Interrupt
+ * 6: look-ahead
+ * 5: write cache
+ * 4: PACKET Command
+ * 3: Power Management Feature Set
+ * 2: Removable Feature Set
+ * 1: Security Feature Set
+ * 0: SMART Feature Set
+ */
+ unsigned short cfs_enable_2; /* (word 86)
+ * command set-feature enabled
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13: FLUSH CACHE EXT
+ * 12: FLUSH CACHE
+ * 11: Device Configuration Overlay
+ * 10: 48-bit Address Feature Set
+ * 9: Automatic Acoustic Management
+ * 8: SET MAX security
+ * 7: reserved 1407DT PARTIES
+ * 6: SetF sub-command Power-Up
+ * 5: Power-Up in Standby Feature Set
+ * 4: Removable Media Notification
+ * 3: APM Feature Set
+ * 2: CFA Feature Set
+ * 1: READ/WRITE DMA QUEUED
+ * 0: Download MicroCode
+ */
+ unsigned short csf_default; /* (word 87)
+ * command set-feature default
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13:6 reserved
+ * 5: General Purpose Logging enabled
+ * 4: Valid CONFIGURE STREAM executed
+ * 3: Media Card Pass Through enabled
+ * 2: Media Serial Number Valid
+ * 1: SMART selt-test supported
+ * 0: SMART error logging
+ */
+ unsigned short dma_ultra; /* (word 88) */
+ unsigned short trseuc; /* time required for security erase */
+ unsigned short trsEuc; /* time required for enhanced erase */
+ unsigned short CurAPMvalues; /* current APM values */
+ unsigned short mprc; /* master password revision code */
+ unsigned short hw_config; /* hardware config (word 93)
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13:
+ * 12:
+ * 11:
+ * 10:
+ * 9:
+ * 8:
+ * 7:
+ * 6:
+ * 5:
+ * 4:
+ * 3:
+ * 2:
+ * 1:
+ * 0: Shall be ONE
+ */
+ unsigned short acoustic; /* (word 94)
+ * 15:8 Vendor's recommended value
+ * 7:0 current value
+ */
+ unsigned short msrqs; /* min stream request size */
+ unsigned short sxfert; /* stream transfer time */
+ unsigned short sal; /* stream access latency */
+ unsigned int spg; /* stream performance granularity */
+ unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
+ unsigned short words104_125[22];/* reserved words 104-125 */
+ unsigned short last_lun; /* (word 126) */
+ unsigned short word127; /* (word 127) Feature Set
+ * Removable Media Notification
+ * 15:2 reserved
+ * 1:0 00 = not supported
+ * 01 = supported
+ * 10 = reserved
+ * 11 = reserved
+ */
+ unsigned short dlf; /* (word 128)
+ * device lock function
+ * 15:9 reserved
+ * 8 security level 1:max 0:high
+ * 7:6 reserved
+ * 5 enhanced erase
+ * 4 expire
+ * 3 frozen
+ * 2 locked
+ * 1 en/disabled
+ * 0 capability
+ */
+ unsigned short csfo; /* (word 129)
+ * current set features options
+ * 15:4 reserved
+ * 3: auto reassign
+ * 2: reverting
+ * 1: read-look-ahead
+ * 0: write cache
+ */
+ unsigned short words130_155[26];/* reserved vendor words 130-155 */
+ unsigned short word156; /* reserved vendor word 156 */
+ unsigned short words157_159[3];/* reserved vendor words 157-159 */
+ unsigned short cfa_power; /* (word 160) CFA Power Mode
+ * 15 word 160 supported
+ * 14 reserved
+ * 13
+ * 12
+ * 11:0
+ */
+ unsigned short words161_175[15];/* Reserved for CFA */
+ unsigned short words176_205[30];/* Current Media Serial Number */
+ unsigned short words206_254[49];/* reserved words 206-254 */
+ unsigned short integrity_word; /* (word 255)
+ * 15:8 Checksum
+ * 7:0 Signature
+ */
+};
+
+#endif /* __DRIVEID_H__ */
+
diff --git a/sys/mips/cavium/files.octeon1 b/sys/mips/cavium/files.octeon1
new file mode 100644
index 0000000..190d3b8
--- /dev/null
+++ b/sys/mips/cavium/files.octeon1
@@ -0,0 +1,17 @@
+# $FreeBSD$
+# Octeon Support Files
+#
+mips/mips/mp_machdep.c optional smp
+mips/octeon1/dev/rgmii/octeon_fau.c optional rgmii
+mips/octeon1/dev/rgmii/octeon_fpa.c optional rgmii
+mips/octeon1/dev/rgmii/octeon_ipd.c optional rgmii
+mips/octeon1/dev/rgmii/octeon_pko.c optional rgmii
+mips/octeon1/dev/rgmii/octeon_rgmx.c optional rgmii
+mips/octeon1/obio.c optional uart
+mips/octeon1/octeon_ebt3000_cf.c optional cf
+mips/octeon1/octeon_machdep.c standard
+mips/octeon1/uart_bus_octeonusart.c optional uart
+mips/octeon1/uart_cpu_octeonusart.c optional uart
+mips/octeon1/uart_dev_oct16550.c optional uart
+mips/mips/intr_machdep.c standard
+mips/mips/tick.c standard
diff --git a/sys/mips/cavium/obio.c b/sys/mips/cavium/obio.c
new file mode 100644
index 0000000..de3910b
--- /dev/null
+++ b/sys/mips/cavium/obio.c
@@ -0,0 +1,182 @@
+/* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */
+
+/*-
+ * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ */
+
+/*
+ * On-board device autoconfiguration support for Intel IQ80321
+ * evaluation boards.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <mips/octeon1/octeonreg.h>
+#include <mips/octeon1/obiovar.h>
+
+int obio_probe(device_t);
+int obio_attach(device_t);
+
+/*
+ * We need only one obio. Any other device hanging off of it,
+ * shouldn't cause multiple of these to be found.
+ */
+static int have_one = 0;
+
+int
+obio_probe(device_t dev)
+{
+ if (!have_one) {
+ have_one = 1;
+ return 0;
+ }
+ return (ENXIO);
+}
+
+int
+obio_attach(device_t dev)
+{
+ struct obio_softc *sc = device_get_softc(dev);
+
+ sc->oba_st = mips_bus_space_generic;
+ sc->oba_addr = OCTEON_UART0ADR;
+ sc->oba_size = 0x10000;
+ sc->oba_rman.rm_type = RMAN_ARRAY;
+ sc->oba_rman.rm_descr = "OBIO I/O";
+ if (rman_init(&sc->oba_rman) != 0 ||
+ rman_manage_region(&sc->oba_rman,
+ sc->oba_addr, sc->oba_addr + sc->oba_size) != 0)
+ panic("obio_attach: failed to set up I/O rman");
+ sc->oba_irq_rman.rm_type = RMAN_ARRAY;
+ sc->oba_irq_rman.rm_descr = "OBIO IRQ";
+
+ /*
+ * This module is intended for UART purposes only and
+ * it's IRQ is 0 corresponding to IP2.
+ */
+ if (rman_init(&sc->oba_irq_rman) != 0 ||
+ rman_manage_region(&sc->oba_irq_rman, 0, 0) != 0)
+ panic("obio_attach: failed to set up IRQ rman");
+
+ device_add_child(dev, "uart", 1); /* Setup Uart-1 first. */
+ device_add_child(dev, "uart", 0); /* Uart-0 next. So it is first in console list */
+ bus_generic_probe(dev);
+ bus_generic_attach(dev);
+ return (0);
+}
+
+static struct resource *
+obio_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct resource *rv;
+ struct rman *rm;
+ bus_space_tag_t bt = 0;
+ bus_space_handle_t bh = 0;
+ struct obio_softc *sc = device_get_softc(bus);
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &sc->oba_irq_rman;
+ break;
+ case SYS_RES_MEMORY:
+ return (NULL);
+ case SYS_RES_IOPORT:
+ rm = &sc->oba_rman;
+ bt = sc->oba_st;
+ bh = device_get_unit(child) ? OCTEON_UART1ADR : OCTEON_UART0ADR;
+ start = bh;
+ break;
+ default:
+ return (NULL);
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == NULL) {
+ return (NULL);
+ }
+ if (type == SYS_RES_IRQ) {
+ return (rv);
+ }
+ rman_set_rid(rv, *rid);
+ rman_set_bustag(rv, bt);
+ rman_set_bushandle(rv, bh);
+
+ if (0) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ }
+ return (rv);
+
+}
+
+static int
+obio_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+ return (0);
+}
+static device_method_t obio_methods[] = {
+ DEVMETHOD(device_probe, obio_probe),
+ DEVMETHOD(device_attach, obio_attach),
+
+ DEVMETHOD(bus_alloc_resource, obio_alloc_resource),
+ DEVMETHOD(bus_activate_resource, obio_activate_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+
+ {0, 0},
+};
+
+static driver_t obio_driver = {
+ "obio",
+ obio_methods,
+ sizeof(struct obio_softc),
+};
+static devclass_t obio_devclass;
+
+DRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0);
diff --git a/sys/mips/cavium/obiovar.h b/sys/mips/cavium/obiovar.h
new file mode 100644
index 0000000..ab8b6b2
--- /dev/null
+++ b/sys/mips/cavium/obiovar.h
@@ -0,0 +1,58 @@
+/* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 2002, 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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$
+ *
+ */
+
+#ifndef _OCTEON_OBIOVAR_H_
+#define _OCTEON_OBIOVAR_H_
+
+#include <sys/rman.h>
+
+struct obio_softc {
+ bus_space_tag_t oba_st; /* bus space tag */
+ bus_addr_t oba_addr; /* address of device */
+ bus_size_t oba_size; /* size of device */
+ int oba_width; /* bus width */
+ int oba_irq; /* XINT interrupt bit # */
+ struct rman oba_rman;
+ struct rman oba_irq_rman;
+
+};
+extern struct bus_space obio_bs_tag;
+
+#endif /* _OCTEON_OBIOVAR_H_ */
diff --git a/sys/mips/cavium/octeon_ebt3000_cf.c b/sys/mips/cavium/octeon_ebt3000_cf.c
new file mode 100644
index 0000000..babeece
--- /dev/null
+++ b/sys/mips/cavium/octeon_ebt3000_cf.c
@@ -0,0 +1,621 @@
+/*
+ * octeon_ebt3000_cf.c
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bio.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/power.h>
+#include <sys/smp.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/malloc.h>
+
+#include <geom/geom.h>
+
+#include <machine/clock.h>
+#include <machine/locore.h>
+#include <machine/md_var.h>
+#include <machine/cpuregs.h>
+
+#include "octeon_ebt3000_cf.h"
+#include "driveid.h"
+#include <mips/octeon1/octeon_pcmap_regs.h>
+
+/* ATA Commands */
+#define CMD_READ_SECTOR 0x20
+#define CMD_WRITE_SECTOR 0x30
+#define CMD_IDENTIFY 0xEC
+
+/* The ATA Task File */
+#define TF_DATA 0x00
+#define TF_ERROR 0x01
+#define TF_PRECOMP 0x01
+#define TF_SECTOR_COUNT 0x02
+#define TF_SECTOR_NUMBER 0x03
+#define TF_CYL_LSB 0x04
+#define TF_CYL_MSB 0x05
+#define TF_DRV_HEAD 0x06
+#define TF_STATUS 0x07
+#define TF_COMMAND 0x07
+
+/* Status Register */
+#define STATUS_BSY 0x80 /* Drive is busy */
+#define STATUS_RDY 0x40 /* Drive is ready */
+#define STATUS_DRQ 0x08 /* Data can be transferred */
+
+/* Miscelaneous */
+#define SECTOR_SIZE 512
+#define WAIT_DELAY 1000
+#define NR_TRIES 1000
+#define SWAP_SHORT(x) ((x << 8) | (x >> 8))
+#define SWAP_LONG(x) (((x << 24) & 0xFF000000) | ((x << 8) & 0x00FF0000) | \
+ ((x >> 8) & 0x0000FF00) | ((x << 24) & 0x000000FF) )
+#define MODEL_STR_SIZE 40
+
+
+/* Globals */
+int bus_width;
+void *base_addr;
+
+/* Device softc */
+struct cf_priv {
+
+ device_t dev;
+ struct drive_param *drive_param;
+
+ struct bio_queue_head cf_bq;
+ struct g_geom *cf_geom;
+ struct g_provider *cf_provider;
+
+};
+
+/* Device parameters */
+struct drive_param{
+ union {
+ char buf[SECTOR_SIZE];
+ struct hd_driveid driveid;
+ } u;
+
+ char model[MODEL_STR_SIZE];
+ uint32_t nr_sectors;
+ uint16_t sector_size;
+ uint16_t heads;
+ uint16_t tracks;
+ uint16_t sec_track;
+
+} drive_param;
+
+/* GEOM class implementation */
+static g_access_t cf_access;
+static g_start_t cf_start;
+static g_ioctl_t cf_ioctl;
+
+struct g_class g_cf_class = {
+ .name = "CF",
+ .version = G_VERSION,
+ .start = cf_start,
+ .access = cf_access,
+ .ioctl = cf_ioctl,
+};
+
+/* Device methods */
+static int cf_probe(device_t);
+static void cf_identify(driver_t *, device_t);
+static int cf_attach(device_t);
+static int cf_attach_geom(void *, int);
+
+/* ATA methods */
+static void cf_cmd_identify(void);
+static void cf_cmd_write(uint32_t, uint32_t, void *);
+static void cf_cmd_read(uint32_t, uint32_t, void *);
+static void cf_wait_busy(void);
+static void cf_send_cmd(uint32_t, uint8_t);
+static void cf_attach_geom_proxy(void *arg, int flag);
+
+/* Miscelenous */
+static void cf_swap_ascii(unsigned char[], char[]);
+
+
+/* ------------------------------------------------------------------- *
+ * cf_access() *
+ * ------------------------------------------------------------------- */
+static int cf_access (struct g_provider *pp, int r, int w, int e)
+{
+
+ pp->sectorsize = drive_param.sector_size;
+ pp->stripesize = drive_param.heads * drive_param.sec_track * drive_param.sector_size;
+ pp->mediasize = pp->stripesize * drive_param.tracks;
+
+ return (0);
+}
+
+
+/* ------------------------------------------------------------------- *
+ * cf_start() *
+ * ------------------------------------------------------------------- */
+static void cf_start (struct bio *bp)
+{
+ /*
+ * Handle actual I/O requests. The request is passed down through
+ * the bio struct.
+ */
+
+ if(bp->bio_cmd & BIO_GETATTR) {
+ if (g_handleattr_int(bp, "GEOM::fwsectors", drive_param.sec_track))
+ return;
+ if (g_handleattr_int(bp, "GEOM::fwheads", drive_param.heads))
+ return;
+ g_io_deliver(bp, ENOIOCTL);
+ return;
+ }
+
+ if ((bp->bio_cmd & (BIO_READ | BIO_WRITE))) {
+
+ if (bp->bio_cmd & BIO_READ) {
+ cf_cmd_read(bp->bio_length / drive_param.sector_size,
+ bp->bio_offset / drive_param.sector_size, bp->bio_data);
+
+ } else if (bp->bio_cmd & BIO_WRITE) {
+ cf_cmd_write(bp->bio_length / drive_param.sector_size,
+ bp->bio_offset/drive_param.sector_size, bp->bio_data);
+ }
+
+ bp->bio_resid = 0;
+ bp->bio_completed = bp->bio_length;
+ g_io_deliver(bp, 0);
+ }
+}
+
+
+static int cf_ioctl (struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td)
+{
+ return (0);
+}
+
+
+/* ------------------------------------------------------------------- *
+ * cf_cmd_read() *
+ * ------------------------------------------------------------------- *
+ *
+ * Read nr_sectors from the device starting from start_sector.
+ */
+static void cf_cmd_read (uint32_t nr_sectors, uint32_t start_sector, void *buf)
+{
+ unsigned long lba;
+ uint32_t count;
+ uint16_t *ptr_16;
+ uint8_t *ptr_8;
+
+//#define OCTEON_VISUAL_CF_0 1
+#ifdef OCTEON_VISUAL_CF_0
+ octeon_led_write_char(0, 'R');
+#endif
+ ptr_8 = (uint8_t*)buf;
+ ptr_16 = (uint16_t*)buf;
+ lba = start_sector;
+
+
+ while (nr_sectors--) {
+
+ cf_send_cmd(lba, CMD_READ_SECTOR);
+
+ if (bus_width == 8) {
+ volatile uint8_t *task_file = (volatile uint8_t*)base_addr;
+ volatile uint8_t dummy;
+ for (count = 0; count < SECTOR_SIZE; count++) {
+ *ptr_8++ = task_file[TF_DATA];
+ if ((count & 0xf) == 0) dummy = task_file[TF_STATUS];
+ }
+ } else {
+ volatile uint16_t *task_file = (volatile uint16_t*)base_addr;
+ volatile uint16_t dummy;
+ for (count = 0; count < SECTOR_SIZE; count+=2) {
+ uint16_t temp;
+ temp = task_file[TF_DATA];
+ *ptr_16++ = SWAP_SHORT(temp);
+ if ((count & 0xf) == 0) dummy = task_file[TF_STATUS/2];
+ }
+ }
+
+ lba ++;
+ }
+#ifdef OCTEON_VISUAL_CF_0
+ octeon_led_write_char(0, ' ');
+#endif
+}
+
+
+/* ------------------------------------------------------------------- *
+ * cf_cmd_write() *
+ * ------------------------------------------------------------------- *
+ *
+ * Write nr_sectors to the device starting from start_sector.
+ */
+static void cf_cmd_write (uint32_t nr_sectors, uint32_t start_sector, void *buf)
+{
+ uint32_t lba;
+ uint32_t count;
+ uint16_t *ptr_16;
+ uint8_t *ptr_8;
+
+//#define OCTEON_VISUAL_CF_1 1
+#ifdef OCTEON_VISUAL_CF_1
+ octeon_led_write_char(1, 'W');
+#endif
+ lba = start_sector;
+ ptr_8 = (uint8_t*)buf;
+ ptr_16 = (uint16_t*)buf;
+
+ while (nr_sectors--) {
+
+ cf_send_cmd(lba, CMD_WRITE_SECTOR);
+
+ if (bus_width == 8) {
+ volatile uint8_t *task_file;
+ volatile uint8_t dummy;
+
+ task_file = (volatile uint8_t *) base_addr;
+ for (count = 0; count < SECTOR_SIZE; count++) {
+ task_file[TF_DATA] = *ptr_8++;
+ if ((count & 0xf) == 0) dummy = task_file[TF_STATUS];
+ }
+ } else {
+ volatile uint16_t *task_file;
+ volatile uint16_t dummy;
+
+ task_file = (volatile uint16_t *) base_addr;
+ for (count = 0; count < SECTOR_SIZE; count+=2) {
+ uint16_t temp = *ptr_16++;
+ task_file[TF_DATA] = SWAP_SHORT(temp);
+ if ((count & 0xf) == 0) dummy = task_file[TF_STATUS/2];
+ }
+ }
+
+ lba ++;
+ }
+#ifdef OCTEON_VISUAL_CF_1
+ octeon_led_write_char(1, ' ');
+#endif
+}
+
+
+/* ------------------------------------------------------------------- *
+ * cf_cmd_identify() *
+ * ------------------------------------------------------------------- *
+ *
+ * Read parameters and other information from the drive and store
+ * it in the drive_param structure
+ *
+ */
+static void cf_cmd_identify (void)
+{
+ int count;
+ uint8_t status;
+
+ if (bus_width == 8) {
+ volatile uint8_t *task_file;
+
+ task_file = (volatile uint8_t *) base_addr;
+
+ while ((status = task_file[TF_STATUS]) & STATUS_BSY) {
+ DELAY(WAIT_DELAY);
+ }
+
+ task_file[TF_SECTOR_COUNT] = 0;
+ task_file[TF_SECTOR_NUMBER] = 0;
+ task_file[TF_CYL_LSB] = 0;
+ task_file[TF_CYL_MSB] = 0;
+ task_file[TF_DRV_HEAD] = 0;
+ task_file[TF_COMMAND] = CMD_IDENTIFY;
+
+ cf_wait_busy();
+
+ for (count = 0; count < SECTOR_SIZE; count++)
+ drive_param.u.buf[count] = task_file[TF_DATA];
+
+ } else {
+ volatile uint16_t *task_file;
+
+ task_file = (volatile uint16_t *) base_addr;
+
+ while ((status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY) {
+ DELAY(WAIT_DELAY);
+ }
+
+ task_file[TF_SECTOR_COUNT/2] = 0; /* this includes TF_SECTOR_NUMBER */
+ task_file[TF_CYL_LSB/2] = 0; /* this includes TF_CYL_MSB */
+ task_file[TF_DRV_HEAD/2] = 0 | (CMD_IDENTIFY<<8); /* this includes TF_COMMAND */
+
+ cf_wait_busy();
+
+ for (count = 0; count < SECTOR_SIZE; count+=2) {
+ uint16_t temp;
+ temp = task_file[TF_DATA];
+
+ /* endianess will be swapped below */
+ drive_param.u.buf[count] = (temp & 0xff);
+ drive_param.u.buf[count+1] = (temp & 0xff00)>>8;
+ }
+ }
+
+ cf_swap_ascii(drive_param.u.driveid.model, drive_param.model);
+
+ drive_param.sector_size = 512; //= SWAP_SHORT (drive_param.u.driveid.sector_bytes);
+ drive_param.heads = SWAP_SHORT (drive_param.u.driveid.cur_heads);
+ drive_param.tracks = SWAP_SHORT (drive_param.u.driveid.cur_cyls);
+ drive_param.sec_track = SWAP_SHORT (drive_param.u.driveid.cur_sectors);
+ drive_param.nr_sectors = SWAP_LONG (drive_param.u.driveid.lba_capacity);
+
+}
+
+
+/* ------------------------------------------------------------------- *
+ * cf_send_cmd() *
+ * ------------------------------------------------------------------- *
+ *
+ * Send command to read/write one sector specified by lba.
+ *
+ */
+static void cf_send_cmd (uint32_t lba, uint8_t cmd)
+{
+ uint8_t status;
+
+ if (bus_width == 8) {
+ volatile uint8_t *task_file;
+
+ task_file = (volatile uint8_t *) base_addr;
+
+ while ( (status = task_file[TF_STATUS]) & STATUS_BSY) {
+ DELAY(WAIT_DELAY);
+ }
+
+ task_file[TF_SECTOR_COUNT] = 1;
+ task_file[TF_SECTOR_NUMBER] = (lba & 0xff);
+ task_file[TF_CYL_LSB] = ((lba >> 8) & 0xff);
+ task_file[TF_CYL_MSB] = ((lba >> 16) & 0xff);
+ task_file[TF_DRV_HEAD] = ((lba >> 24) & 0xff) | 0xe0;
+ task_file[TF_COMMAND] = cmd;
+
+ } else {
+ volatile uint16_t *task_file;
+
+ task_file = (volatile uint16_t *) base_addr;
+
+ while ( (status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY) {
+ DELAY(WAIT_DELAY);
+ }
+
+ task_file[TF_SECTOR_COUNT/2] = 1 | ((lba & 0xff) << 8);
+ task_file[TF_CYL_LSB/2] = ((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8);
+ task_file[TF_DRV_HEAD/2] = (((lba >> 24) & 0xff) | 0xe0) | (cmd << 8);
+
+ }
+
+ cf_wait_busy();
+}
+
+/* ------------------------------------------------------------------- *
+ * cf_wait_busy() *
+ * ------------------------------------------------------------------- *
+ *
+ * Wait until the drive finishes a given command and data is
+ * ready to be transferred. This is done by repeatedly checking
+ * the BSY and DRQ bits of the status register. When the controller
+ * is ready for data transfer, it clears the BSY bit and sets the
+ * DRQ bit.
+ *
+ */
+static void cf_wait_busy (void)
+{
+ uint8_t status;
+
+//#define OCTEON_VISUAL_CF_2 1
+#ifdef OCTEON_VISUAL_CF_2
+ static int where0 = 0;
+
+ octeon_led_run_wheel(&where0, 2);
+#endif
+
+ if (bus_width == 8) {
+ volatile uint8_t *task_file;
+ task_file = (volatile uint8_t *)base_addr;
+
+ status = task_file[TF_STATUS];
+ while ((status & STATUS_BSY) == STATUS_BSY || (status & STATUS_DRQ) != STATUS_DRQ ) {
+ DELAY(WAIT_DELAY);
+ status = task_file[TF_STATUS];
+ }
+ } else {
+ volatile uint16_t *task_file;
+ task_file = (volatile uint16_t *)base_addr;
+
+ status = task_file[TF_STATUS/2]>>8;
+ while ((status & STATUS_BSY) == STATUS_BSY || (status & STATUS_DRQ) != STATUS_DRQ ) {
+ DELAY(WAIT_DELAY);
+ status = (uint8_t)(task_file[TF_STATUS/2]>>8);
+ }
+ }
+
+#ifdef OCTEON_VISUAL_CF_2
+ octeon_led_write_char(2, ' ');
+#endif
+}
+
+/* ------------------------------------------------------------------- *
+ * cf_swap_ascii() *
+ * ------------------------------------------------------------------- *
+ *
+ * The ascii string returned by the controller specifying
+ * the model of the drive is byte-swaped. This routine
+ * corrects the byte ordering.
+ *
+ */
+static void cf_swap_ascii (unsigned char str1[], char str2[])
+{
+ int i;
+
+ for(i = 0; i < MODEL_STR_SIZE; i++) {
+ str2[i] = str1[i^1];
+ }
+}
+
+
+/* ------------------------------------------------------------------- *
+ * cf_probe() *
+ * ------------------------------------------------------------------- */
+
+static int cf_probe (device_t dev)
+{
+ if (!octeon_board_real()) return 1;
+
+ if (device_get_unit(dev) != 0) {
+ panic("can't attach more devices\n");
+ }
+
+ device_set_desc(dev, "Octeon Compact Flash Driver");
+
+ cf_cmd_identify();
+
+ return (0);
+}
+
+/* ------------------------------------------------------------------- *
+ * cf_identify() *
+ * ------------------------------------------------------------------- *
+ *
+ * Find the bootbus region for the CF to determine
+ * 16 or 8 bit and check to see if device is
+ * inserted.
+ *
+ */
+static void cf_identify (driver_t *drv, device_t parent)
+{
+ uint8_t status;
+ int bus_region;
+ int count = 0;
+ octeon_mio_boot_reg_cfgx_t cfg;
+
+
+ if (!octeon_board_real())
+ return;
+
+ base_addr = (void *) MIPS_PHYS_TO_KSEG0(OCTEON_CF_COMMON_BASE_ADDR);
+
+ for (bus_region = 0; bus_region < 8; bus_region++)
+ {
+ cfg.word64 = oct_read64(OCTEON_MIO_BOOT_REG_CFGX(bus_region));
+ if (cfg.bits.base == OCTEON_CF_COMMON_BASE_ADDR >> 16)
+ {
+ bus_width = (cfg.bits.width) ? 16: 8;
+ printf("Compact flash found in bootbus region %d (%d bit).\n", bus_region, bus_width);
+ break;
+ }
+ }
+
+ if (bus_width == 8) {
+ volatile uint8_t *task_file;
+ task_file = (volatile uint8_t *) base_addr;
+ /* Check if CF is inserted */
+ while ( (status = task_file[TF_STATUS]) & STATUS_BSY){
+ if ((count++) == NR_TRIES ) {
+ printf("Compact Flash not present\n");
+ return;
+ }
+ DELAY(WAIT_DELAY);
+ }
+ } else {
+ volatile uint16_t *task_file;
+ task_file = (volatile uint16_t *) base_addr;
+ /* Check if CF is inserted */
+ while ( (status = (task_file[TF_STATUS/2]>>8)) & STATUS_BSY){
+ if ((count++) == NR_TRIES ) {
+ printf("Compact Flash not present\n");
+ return;
+ }
+ DELAY(WAIT_DELAY);
+ }
+ }
+
+ BUS_ADD_CHILD(parent, 0, "cf", 0);
+}
+
+
+/* ------------------------------------------------------------------- *
+ * cf_attach_geom() *
+ * ------------------------------------------------------------------- */
+
+static int cf_attach_geom (void *arg, int flag)
+{
+ struct cf_priv *cf_priv;
+
+ cf_priv = (struct cf_priv *) arg;
+ cf_priv->cf_geom = g_new_geomf(&g_cf_class, "cf%d", device_get_unit(cf_priv->dev));
+ cf_priv->cf_provider = g_new_providerf(cf_priv->cf_geom, cf_priv->cf_geom->name);
+ cf_priv->cf_geom->softc = cf_priv;
+ g_error_provider(cf_priv->cf_provider, 0);
+
+ return (0);
+}
+
+/* ------------------------------------------------------------------- *
+ * cf_attach_geom() *
+ * ------------------------------------------------------------------- */
+static void cf_attach_geom_proxy (void *arg, int flag)
+{
+ cf_attach_geom(arg, flag);
+}
+
+
+
+/* ------------------------------------------------------------------- *
+ * cf_attach() *
+ * ------------------------------------------------------------------- */
+
+static int cf_attach (device_t dev)
+{
+ struct cf_priv *cf_priv;
+
+ if (!octeon_board_real()) return 1;
+
+ cf_priv = device_get_softc(dev);
+ cf_priv->dev = dev;
+ cf_priv->drive_param = &drive_param;
+
+ g_post_event(cf_attach_geom_proxy, cf_priv, M_WAITOK, NULL);
+ bioq_init(&cf_priv->cf_bq);
+
+ return 0;
+}
+
+
+static device_method_t cf_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, cf_probe),
+ DEVMETHOD(device_identify, cf_identify),
+ DEVMETHOD(device_attach, cf_attach),
+ DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ { 0, 0 }
+};
+
+static driver_t cf_driver = {
+ "cf",
+ cf_methods,
+ sizeof(struct cf_priv)
+};
+
+static devclass_t cf_devclass;
+
+DRIVER_MODULE(cf, nexus, cf_driver, cf_devclass, 0, 0);
+
diff --git a/sys/mips/cavium/octeon_ebt3000_cf.h b/sys/mips/cavium/octeon_ebt3000_cf.h
new file mode 100644
index 0000000..1e99512
--- /dev/null
+++ b/sys/mips/cavium/octeon_ebt3000_cf.h
@@ -0,0 +1,35 @@
+/*
+ * octeon_ebt3000_cf.h
+ *
+ */
+
+
+#ifndef __OCTEON_EBT3000_H__
+#define __OCTEON_EBT3000_H__
+
+
+
+#define OCTEON_CF_COMMON_BASE_ADDR (0x1d000000 | (1 << 11))
+#define OCTEON_MIO_BOOT_REG_CFGX(offset) (0x8001180000000000ull + ((offset) * 8))
+
+
+typedef union
+{
+ uint64_t word64;
+ struct
+ {
+ uint64_t reserved : 27; /**< Reserved */
+ uint64_t sam : 1; /**< Region 0 SAM */
+ uint64_t we_ext : 2; /**< Region 0 write enable count extension */
+ uint64_t oe_ext : 2; /**< Region 0 output enable count extension */
+ uint64_t en : 1; /**< Region 0 enable */
+ uint64_t orbit : 1; /**< No function for region 0 */
+ uint64_t ale : 1; /**< Region 0 ALE mode */
+ uint64_t width : 1; /**< Region 0 bus width */
+ uint64_t size : 12; /**< Region 0 size */
+ uint64_t base : 16; /**< Region 0 base address */
+ } bits;
+} octeon_mio_boot_reg_cfgx_t;
+
+
+#endif /* __OCTEON_EBT3000_H__ */
diff --git a/sys/mips/cavium/octeon_machdep.c b/sys/mips/cavium/octeon_machdep.c
new file mode 100644
index 0000000..adec47b
--- /dev/null
+++ b/sys/mips/cavium/octeon_machdep.c
@@ -0,0 +1,965 @@
+/*-
+ * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@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 <sys/imgact.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/cons.h>
+#include <sys/exec.h>
+#include <sys/ucontext.h>
+#include <sys/proc.h>
+#include <sys/kdb.h>
+#include <sys/ptrace.h>
+#include <sys/reboot.h>
+#include <sys/signalvar.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/user.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <machine/atomic.h>
+#include <machine/cache.h>
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cpuregs.h>
+#include <machine/cpufunc.h>
+#include <mips/octeon1/octeon_pcmap_regs.h>
+#include <mips/octeon1/octeonreg.h>
+#include <machine/hwfunc.h>
+#include <machine/intr_machdep.h>
+#include <machine/locore.h>
+#include <machine/md_var.h>
+#include <machine/pcpu.h>
+#include <machine/pte.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+#if defined(__mips_n64)
+#define MAX_APP_DESC_ADDR 0xffffffffafffffff
+#else
+#define MAX_APP_DESC_ADDR 0xafffffff
+#endif
+
+extern int *edata;
+extern int *end;
+
+uint64_t ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip);
+void ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip);
+
+static void octeon_boot_params_init(register_t ptr);
+static uint64_t ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx);
+static uint64_t ciu_get_intr_en_reg_addr(int core_num, int intx, int enx);
+
+void
+platform_cpu_init()
+{
+ /* Nothing special yet */
+}
+
+/*
+ * Perform a board-level soft-reset.
+ */
+void
+platform_reset(void)
+{
+ ((void(*)(void))0x1fc00000)(); /* Jump to this hex address */
+}
+
+
+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)
+{
+ uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
+
+ if (!octeon_board_real())
+ return;
+
+ char_position &= 0x7; /* only 8 chars */
+ ptr += char_position;
+ oct_write8_x8(ptr, val);
+}
+
+void
+octeon_led_write_char0(char val)
+{
+ uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
+
+ if (!octeon_board_real())
+ return;
+ oct_write8_x8(ptr, val);
+}
+
+void
+octeon_led_write_hexchar(int char_position, char hexval)
+{
+ uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
+ char char1, char2;
+
+ if (!octeon_board_real())
+ return;
+
+ char1 = (hexval >> 4) & 0x0f; char1 = (char1 < 10)?char1+'0':char1+'7';
+ char2 = (hexval & 0x0f); char2 = (char2 < 10)?char2+'0':char2+'7';
+ char_position &= 0x7; /* only 8 chars */
+ if (char_position > 6)
+ char_position = 6;
+ ptr += char_position;
+ oct_write8_x8(ptr, char1);
+ ptr++;
+ oct_write8_x8(ptr, char2);
+}
+
+void
+octeon_led_write_string(const char *str)
+{
+ uint64_t ptr = (OCTEON_CHAR_LED_BASE_ADDR | 0xf8);
+ int i;
+
+ if (!octeon_board_real())
+ return;
+
+ for (i=0; i<8; i++, ptr++) {
+ if (str && *str)
+ oct_write8_x8(ptr, *str++);
+ else
+ oct_write8_x8(ptr, ' ');
+ oct_read64(OCTEON_MIO_BOOT_BIST_STAT);
+ }
+}
+
+static char progress[8] = { '-', '/', '|', '\\', '-', '/', '|', '\\'};
+
+void
+octeon_led_run_wheel(int *prog_count, int led_position)
+{
+ if (!octeon_board_real())
+ return;
+ octeon_led_write_char(led_position, progress[*prog_count]);
+ *prog_count += 1;
+ *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)
+{
+ char nbuf[80];
+
+ sprintf(nbuf, "%X", wl);
+ octeon_led_write_string(nbuf);
+}
+
+
+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
+ *
+ * Does nothing.
+ * Used to mark the point for simulator to begin tracing
+ */
+void
+octeon_debug_symbol(void)
+{
+}
+
+void
+octeon_ciu_stop_gtimer(int timer)
+{
+ oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), 0ll);
+}
+
+void
+octeon_ciu_start_gtimer(int timer, u_int one_shot, uint64_t time_cycles)
+{
+ octeon_ciu_gentimer gentimer;
+
+ gentimer.word64 = 0;
+ gentimer.bits.one_shot = one_shot;
+ gentimer.bits.len = time_cycles - 1;
+ oct_write64(OCTEON_CIU_GENTIMER_ADDR(timer), gentimer.word64);
+}
+
+/*
+ * octeon_ciu_reset
+ *
+ * Shutdown all CIU to IP2, IP3 mappings
+ */
+void
+octeon_ciu_reset(void)
+{
+
+ octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_0);
+ octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_1);
+ octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_2);
+ octeon_ciu_stop_gtimer(CIU_GENTIMER_NUM_3);
+
+ ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0);
+ ciu_disable_intr(CIU_THIS_CORE, CIU_INT_0, CIU_EN_1);
+ ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0);
+ ciu_disable_intr(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1);
+
+ ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_0, CIU_EN_0, 0ll);
+ ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_0, 0ll);
+ ciu_clear_int_summary(CIU_THIS_CORE, CIU_INT_1, CIU_EN_1, 0ll);
+}
+
+/*
+ * mips_disable_interrupt_controllers
+ *
+ * Disable interrupts in the CPU controller
+ */
+void
+mips_disable_interrupt_controls(void)
+{
+ /*
+ * Disable interrupts in CIU.
+ */
+ octeon_ciu_reset();
+}
+
+/*
+ * ciu_get_intr_sum_reg_addr
+ */
+static uint64_t
+ciu_get_intr_sum_reg_addr(int core_num, int intx, int enx)
+{
+ uint64_t ciu_intr_sum_reg_addr;
+
+ if (enx == CIU_EN_0)
+ ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_BASE_ADDR +
+ (core_num * 0x10) + (intx * 0x8);
+ else
+ ciu_intr_sum_reg_addr = OCTEON_CIU_SUMMARY_INT1_ADDR;
+
+ return (ciu_intr_sum_reg_addr);
+}
+
+
+/*
+ * ciu_get_intr_en_reg_addr
+ */
+static uint64_t
+ciu_get_intr_en_reg_addr(int core_num, int intx, int enx)
+{
+ uint64_t ciu_intr_reg_addr;
+
+ ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR +
+ ((enx == 0) ? 0x0 : 0x8) + (intx * 0x10) + (core_num * 0x20);
+ return (ciu_intr_reg_addr);
+}
+
+
+
+
+/*
+ * ciu_get_intr_reg_addr
+ *
+ * 200 ---int0,en0 ip2
+ * 208 ---int0,en1 ip2 ----> this is wrong... this is watchdog
+ *
+ * 210 ---int0,en0 ip3 --
+ * 218 ---int0,en1 ip3 ----> same here.. .this is watchdog... right?
+ *
+ * 220 ---int1,en0 ip2
+ * 228 ---int1,en1 ip2
+ * 230 ---int1,en0 ip3 --
+ * 238 ---int1,en1 ip3
+ *
+ */
+uint64_t
+ciu_get_en_reg_addr_new(int corenum, int intx, int enx, int ciu_ip)
+{
+ uint64_t ciu_intr_reg_addr = OCTEON_CIU_ENABLE_BASE_ADDR;
+
+ /* 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);
+ 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);
+ 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);
+ return 0;
+ }
+
+ ciu_intr_reg_addr += (enx * 0x8);
+ ciu_intr_reg_addr += (ciu_ip * 0x10);
+ ciu_intr_reg_addr += (intx * 0x20);
+ return (ciu_intr_reg_addr);
+}
+
+/*
+ * ciu_get_int_summary
+ */
+uint64_t
+ciu_get_int_summary(int core_num, int intx, int enx)
+{
+ uint64_t ciu_intr_sum_reg_addr;
+
+ if (core_num == CIU_THIS_CORE)
+ core_num = octeon_get_core_num();
+ ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx);
+ return (oct_read64(ciu_intr_sum_reg_addr));
+}
+
+//#define DEBUG_CIU 1
+
+#ifdef DEBUG_CIU
+#define DEBUG_CIU_SUM 1
+#define DEBUG_CIU_EN 1
+#endif
+
+
+/*
+ * ciu_clear_int_summary
+ */
+void
+ciu_clear_int_summary(int core_num, int intx, int enx, uint64_t write_bits)
+{
+ uint32_t cpu_status_bits;
+ uint64_t ciu_intr_sum_reg_addr;
+
+//#define DEBUG_CIU_SUM 1
+
+#ifdef DEBUG_CIU_SUM
+ uint64_t ciu_intr_sum_bits;
+#endif
+
+
+ if (core_num == CIU_THIS_CORE) {
+ core_num = octeon_get_core_num();
+ }
+
+#ifdef DEBUG_CIU_SUM
+ printf(" CIU: core %u clear sum IntX %u Enx %u Bits: 0x%llX\n",
+ core_num, intx, enx, write_bits);
+#endif
+
+ cpu_status_bits = octeon_disable_interrupts();
+
+ ciu_intr_sum_reg_addr = ciu_get_intr_sum_reg_addr(core_num, intx, enx);
+
+#ifdef DEBUG_CIU_SUM
+ ciu_intr_sum_bits = oct_read64(ciu_intr_sum_reg_addr); /* unneeded dummy read */
+ printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX",
+ cpu_status_bits, ciu_intr_sum_reg_addr, ciu_intr_sum_bits,
+ ciu_intr_sum_bits | write_bits);
+#endif
+
+ oct_write64(ciu_intr_sum_reg_addr, write_bits);
+ oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */
+
+#ifdef DEBUG_CIU_SUM
+ printf(" Readback: 0x%llX\n\n ", (uint64_t) oct_read64(ciu_intr_sum_reg_addr));
+#endif
+
+ octeon_set_interrupts(cpu_status_bits);
+}
+
+/*
+ * ciu_disable_intr
+ */
+void
+ciu_disable_intr(int core_num, int intx, int enx)
+{
+ uint32_t cpu_status_bits;
+ uint64_t ciu_intr_reg_addr;
+
+ if (core_num == CIU_THIS_CORE)
+ core_num = octeon_get_core_num();
+
+ cpu_status_bits = octeon_disable_interrupts();
+
+ ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
+
+ oct_read64(ciu_intr_reg_addr); /* Dummy read */
+
+ oct_write64(ciu_intr_reg_addr, 0LL);
+ oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */
+
+ octeon_set_interrupts(cpu_status_bits);
+}
+
+void
+ciu_dump_interrutps_enabled(int core_num, int intx, int enx, int ciu_ip)
+{
+
+ uint64_t ciu_intr_reg_addr;
+ uint64_t ciu_intr_bits;
+
+ if (core_num == CIU_THIS_CORE) {
+ core_num = octeon_get_core_num();
+ }
+
+#ifndef OCTEON_SMP_1
+ ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
+#else
+ ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip);
+#endif
+
+ if (!ciu_intr_reg_addr) {
+ printf("Bad call to %s\n", __FUNCTION__);
+ while(1);
+ return;
+ }
+
+ ciu_intr_bits = oct_read64(ciu_intr_reg_addr);
+ printf(" CIU core %d int: %d en: %d ip: %d Add: %#llx enabled: %#llx SR: %x\n",
+ core_num, intx, enx, ciu_ip, (unsigned long long)ciu_intr_reg_addr,
+ (unsigned long long)ciu_intr_bits, mips_rd_status());
+}
+
+
+/*
+ * ciu_enable_interrupts
+ */
+void ciu_enable_interrupts(int core_num, int intx, int enx,
+ uint64_t set_these_interrupt_bits, int ciu_ip)
+{
+ uint32_t cpu_status_bits;
+ uint64_t ciu_intr_reg_addr;
+ uint64_t ciu_intr_bits;
+
+ if (core_num == CIU_THIS_CORE)
+ core_num = octeon_get_core_num();
+
+//#define DEBUG_CIU_EN 1
+
+#ifdef DEBUG_CIU_EN
+ printf(" CIU: core %u enabling Intx %u Enx %u IP %d Bits: 0x%llX\n",
+ core_num, intx, enx, ciu_ip, set_these_interrupt_bits);
+#endif
+
+ cpu_status_bits = octeon_disable_interrupts();
+
+#ifndef OCTEON_SMP_1
+ ciu_intr_reg_addr = ciu_get_intr_en_reg_addr(core_num, intx, enx);
+#else
+ ciu_intr_reg_addr = ciu_get_en_reg_addr_new(core_num, intx, enx, ciu_ip);
+#endif
+
+ if (!ciu_intr_reg_addr) {
+ printf("Bad call to %s\n", __FUNCTION__);
+ while(1);
+ return; /* XXX */
+ }
+
+ ciu_intr_bits = oct_read64(ciu_intr_reg_addr);
+
+#ifdef DEBUG_CIU_EN
+ printf(" CIU: status: 0x%X reg_addr: 0x%llX Val: 0x%llX -> 0x%llX",
+ cpu_status_bits, ciu_intr_reg_addr, ciu_intr_bits, ciu_intr_bits | set_these_interrupt_bits);
+#endif
+ ciu_intr_bits |= set_these_interrupt_bits;
+ oct_write64(ciu_intr_reg_addr, ciu_intr_bits);
+#ifdef OCTEON_SMP
+ mips_wbflush();
+#endif
+ oct_read64(OCTEON_MIO_BOOT_BIST_STAT); /* Bus Barrier */
+
+#ifdef DEBUG_CIU_EN
+ printf(" Readback: 0x%llX\n\n ",
+ (uint64_t)oct_read64(ciu_intr_reg_addr));
+#endif
+
+ octeon_set_interrupts(cpu_status_bits);
+}
+
+void
+platform_start(__register_t a0, __register_t a1, __register_t a2 __unused,
+ __register_t a3)
+{
+ uint64_t platform_counter_freq;
+ vm_offset_t kernend;
+ int argc = a0;
+ char **argv = (char **)a1;
+ int i, mem;
+
+ /* clear the BSS and SBSS segments */
+ kernend = round_page((vm_offset_t)&end);
+ memset(&edata, 0, kernend - (vm_offset_t)(&edata));
+
+ /* Initialize pcpu stuff */
+ mips_pcpu0_init();
+
+ octeon_boot_params_init(a3);
+ /* XXX octeon boot decriptor has args in it... */
+ octeon_ciu_reset();
+ octeon_uart_write_string(0, "Platform Starting\n");
+
+ /*
+ * Looking for mem=XXM argument
+ */
+ mem = 0; /* Just something to start with */
+ for (i=0; i < argc; i++) {
+ if (strncmp(argv[i], "mem=", 4) == 0) {
+ mem = strtol(argv[i] + 4, NULL, 0);
+ break;
+ }
+ }
+
+ bootverbose = 1;
+ if (mem > 0)
+ realmem = btoc(mem << 20);
+ else
+ realmem = btoc(32 << 20);
+
+ for (i = 0; i < 10; i++)
+ phys_avail[i] = 0;
+
+ /* phys_avail regions are in bytes */
+ phys_avail[0] = MIPS_KSEG0_TO_PHYS((vm_offset_t)&end);
+ phys_avail[1] = ctob(realmem);
+
+ physmem = realmem;
+
+ pmap_bootstrap();
+ mips_proc0_init();
+
+ init_param1();
+ /* TODO: parse argc,argv */
+ platform_counter_freq = 330000000UL; /* XXX: from idt */
+ mips_timer_init_params(platform_counter_freq, 1);
+ cninit();
+ printf("cmd line: ");
+ for (i=0; i < argc; i++)
+ printf("%s ", argv[i]);
+ printf("\n");
+ init_param2(physmem);
+ mips_cpu_init();
+ mutex_init();
+#ifdef DDB
+ kdb_init();
+#endif
+}
+
+/*
+ ****************************************************************************************
+ *
+ * APP/BOOT DESCRIPTOR STUFF
+ *
+ ****************************************************************************************
+ */
+
+/* Define the struct that is initialized by the bootloader used by the
+ * startup code.
+ *
+ * Copyright (c) 2004, 2005, 2006 Cavium Networks.
+ *
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply.
+ */
+
+#define OCTEON_CURRENT_DESC_VERSION 6
+#define OCTEON_ARGV_MAX_ARGS (64)
+#define OCTOEN_SERIAL_LEN 20
+
+
+typedef struct {
+ /* Start of block referenced by assembly code - do not change! */
+ uint32_t desc_version;
+ uint32_t desc_size;
+
+ uint64_t stack_top;
+ uint64_t heap_base;
+ uint64_t heap_end;
+ uint64_t entry_point; /* Only used by bootloader */
+ uint64_t desc_vaddr;
+ /* End of This block referenced by assembly code - do not change! */
+
+ uint32_t exception_base_addr;
+ uint32_t stack_size;
+ uint32_t heap_size;
+ uint32_t argc; /* Argc count for application */
+ uint32_t argv[OCTEON_ARGV_MAX_ARGS];
+ uint32_t flags;
+ uint32_t core_mask;
+ uint32_t dram_size; /**< DRAM size in megabyes */
+ uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/
+ uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */
+ uint32_t eclock_hz; /**< CPU clock speed, in hz */
+ uint32_t dclock_hz; /**< DRAM clock speed, in hz */
+ uint32_t spi_clock_hz; /**< SPI4 clock in hz */
+ uint16_t board_type;
+ uint8_t board_rev_major;
+ uint8_t board_rev_minor;
+ uint16_t chip_type;
+ uint8_t chip_rev_major;
+ uint8_t chip_rev_minor;
+ char board_serial_number[OCTOEN_SERIAL_LEN];
+ uint8_t mac_addr_base[6];
+ uint8_t mac_addr_count;
+ uint64_t cvmx_desc_vaddr;
+} octeon_boot_descriptor_t;
+
+
+typedef struct {
+ uint32_t major_version;
+ uint32_t minor_version;
+
+ uint64_t stack_top;
+ uint64_t heap_base;
+ uint64_t heap_end;
+ uint64_t desc_vaddr;
+
+ uint32_t exception_base_addr;
+ uint32_t stack_size;
+ uint32_t flags;
+ uint32_t core_mask;
+ uint32_t dram_size; /**< DRAM size in megabyes */
+ uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/
+ uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */
+ uint32_t eclock_hz; /**< CPU clock speed, in hz */
+ uint32_t dclock_hz; /**< DRAM clock speed, in hz */
+ uint32_t spi_clock_hz; /**< SPI4 clock in hz */
+ uint16_t board_type;
+ uint8_t board_rev_major;
+ uint8_t board_rev_minor;
+ uint16_t chip_type;
+ uint8_t chip_rev_major;
+ uint8_t chip_rev_minor;
+ char board_serial_number[OCTOEN_SERIAL_LEN];
+ uint8_t mac_addr_base[6];
+ uint8_t mac_addr_count;
+} cvmx_bootinfo_t;
+
+uint32_t octeon_cpu_clock;
+uint64_t octeon_dram;
+uint32_t octeon_bd_ver = 0, octeon_cvmx_bd_ver = 0, octeon_board_rev_major, octeon_board_rev_minor, octeon_board_type;
+uint8_t octeon_mac_addr[6] = { 0 };
+int octeon_core_mask, octeon_mac_addr_count;
+int octeon_chip_rev_major = 0, octeon_chip_rev_minor = 0, octeon_chip_type = 0;
+
+extern int32_t app_descriptor_addr;
+static octeon_boot_descriptor_t *app_desc_ptr;
+static cvmx_bootinfo_t *cvmx_desc_ptr;
+
+#define OCTEON_BOARD_TYPE_NONE 0
+#define OCTEON_BOARD_TYPE_SIM 1
+
+#define OCTEON_CLOCK_MIN (100 * 1000 * 1000)
+#define OCTEON_CLOCK_MAX (800 * 1000 * 1000)
+#define OCTEON_DRAM_DEFAULT (256 * 1024 * 1024)
+#define OCTEON_DRAM_MIN 30
+#define OCTEON_DRAM_MAX 3000
+
+
+int
+octeon_board_real(void)
+{
+ if ((octeon_board_type == OCTEON_BOARD_TYPE_NONE) ||
+ (octeon_board_type == OCTEON_BOARD_TYPE_SIM) ||
+ !octeon_board_rev_major)
+ return 0;
+ return 1;
+}
+
+static void
+octeon_process_app_desc_ver_unknown(void)
+{
+ printf(" Unknown Boot-Descriptor: Using Defaults\n");
+
+ octeon_cpu_clock = OCTEON_CLOCK_DEFAULT;
+ octeon_dram = OCTEON_DRAM_DEFAULT;
+ octeon_board_rev_major = octeon_board_rev_minor = octeon_board_type = 0;
+ octeon_core_mask = 1;
+ octeon_cpu_clock = OCTEON_CLOCK_DEFAULT;
+ octeon_chip_type = octeon_chip_rev_major = octeon_chip_rev_minor = 0;
+ octeon_mac_addr[0] = 0x00; octeon_mac_addr[1] = 0x0f;
+ octeon_mac_addr[2] = 0xb7; octeon_mac_addr[3] = 0x10;
+ octeon_mac_addr[4] = 0x09; octeon_mac_addr[5] = 0x06;
+ octeon_mac_addr_count = 1;
+}
+
+static int
+octeon_process_app_desc_ver_6(void)
+{
+ /* XXX Why is 0x00000000ffffffffULL a bad value? */
+ if (app_desc_ptr->cvmx_desc_vaddr == 0 ||
+ app_desc_ptr->cvmx_desc_vaddr == 0xfffffffful) {
+ printf ("Bad cvmx_desc_ptr %p\n", cvmx_desc_ptr);
+ return 1;
+ }
+ cvmx_desc_ptr =
+ (cvmx_bootinfo_t *)(intptr_t)app_desc_ptr->cvmx_desc_vaddr;
+ cvmx_desc_ptr =
+ (cvmx_bootinfo_t *) ((intptr_t)cvmx_desc_ptr | MIPS_KSEG0_START);
+ octeon_cvmx_bd_ver = (cvmx_desc_ptr->major_version * 100) +
+ cvmx_desc_ptr->minor_version;
+ /* Too early for panic? */
+ if (cvmx_desc_ptr->major_version != 1) {
+ printf("Incompatible CVMX descriptor from bootloader: %d.%d %p\n",
+ (int) cvmx_desc_ptr->major_version,
+ (int) cvmx_desc_ptr->minor_version, cvmx_desc_ptr);
+ while (1); /* Never return */
+ return 1; /* Satisfy the compiler */
+ }
+
+ octeon_core_mask = cvmx_desc_ptr->core_mask;
+ octeon_cpu_clock = cvmx_desc_ptr->eclock_hz;
+ octeon_board_type = cvmx_desc_ptr->board_type;
+ octeon_board_rev_major = cvmx_desc_ptr->board_rev_major;
+ octeon_board_rev_minor = cvmx_desc_ptr->board_rev_minor;
+ octeon_chip_type = cvmx_desc_ptr->chip_type;
+ octeon_chip_rev_major = cvmx_desc_ptr->chip_rev_major;
+ octeon_chip_rev_minor = cvmx_desc_ptr->chip_rev_minor;
+ octeon_mac_addr[0] = cvmx_desc_ptr->mac_addr_base[0];
+ octeon_mac_addr[1] = cvmx_desc_ptr->mac_addr_base[1];
+ octeon_mac_addr[2] = cvmx_desc_ptr->mac_addr_base[2];
+ octeon_mac_addr[3] = cvmx_desc_ptr->mac_addr_base[3];
+ octeon_mac_addr[4] = cvmx_desc_ptr->mac_addr_base[4];
+ octeon_mac_addr[5] = cvmx_desc_ptr->mac_addr_base[5];
+ octeon_mac_addr_count = cvmx_desc_ptr->mac_addr_count;
+
+ if (app_desc_ptr->dram_size > 16*1024*1024)
+ octeon_dram = (uint64_t)app_desc_ptr->dram_size;
+ else
+ octeon_dram = (uint64_t)app_desc_ptr->dram_size << 20;
+ return 0;
+}
+
+static int
+octeon_process_app_desc_ver_3_4_5(void)
+{
+
+ octeon_cvmx_bd_ver = octeon_bd_ver;
+ octeon_core_mask = app_desc_ptr->core_mask;
+
+ if (app_desc_ptr->desc_version > 3)
+ octeon_cpu_clock = app_desc_ptr->eclock_hz;
+ else
+ octeon_cpu_clock = OCTEON_CLOCK_DEFAULT;
+ if (app_desc_ptr->dram_size > 16*1024*1024)
+ octeon_dram = (uint64_t)app_desc_ptr->dram_size;
+ else
+ octeon_dram = (uint64_t)app_desc_ptr->dram_size << 20;
+
+ if (app_desc_ptr->desc_version > 4) {
+ octeon_board_type = app_desc_ptr->board_type;
+ octeon_board_rev_major = app_desc_ptr->board_rev_major;
+ octeon_board_rev_minor = app_desc_ptr->board_rev_minor;
+ octeon_chip_type = app_desc_ptr->chip_type;
+ octeon_chip_rev_major = app_desc_ptr->chip_rev_major;
+ octeon_chip_rev_minor = app_desc_ptr->chip_rev_minor;
+
+ octeon_mac_addr[0] = app_desc_ptr->mac_addr_base[0];
+ octeon_mac_addr[1] = app_desc_ptr->mac_addr_base[1];
+ octeon_mac_addr[2] = app_desc_ptr->mac_addr_base[2];
+ octeon_mac_addr[3] = app_desc_ptr->mac_addr_base[3];
+ octeon_mac_addr[4] = app_desc_ptr->mac_addr_base[4];
+ octeon_mac_addr[5] = app_desc_ptr->mac_addr_base[5];
+ octeon_mac_addr_count = app_desc_ptr->mac_addr_count;
+ }
+ return 0;
+}
+
+
+static void
+octeon_boot_params_init(register_t ptr)
+{
+ int bad_desc = 1;
+
+ if (ptr != 0 && ptr < MAX_APP_DESC_ADDR) {
+ app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr;
+ octeon_bd_ver = app_desc_ptr->desc_version;
+ if ((octeon_bd_ver >= 3) && (octeon_bd_ver <= 5))
+ bad_desc = octeon_process_app_desc_ver_3_4_5();
+ else if (app_desc_ptr->desc_version == 6)
+ bad_desc = octeon_process_app_desc_ver_6();
+ }
+ if (bad_desc)
+ octeon_process_app_desc_ver_unknown();
+
+ 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(" 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);
+ printf(" Octeon Chip: %u Rev %u/%u",
+ octeon_chip_type, octeon_chip_rev_major, octeon_chip_rev_minor);
+
+ printf(" Mac Address %02X.%02X.%02X.%02X.%02X.%02X\n",
+ octeon_mac_addr[0], octeon_mac_addr[1], octeon_mac_addr[2],
+ octeon_mac_addr[3], octeon_mac_addr[4], octeon_mac_addr[5]);
+}
diff --git a/sys/mips/cavium/octeon_pcmap_regs.h b/sys/mips/cavium/octeon_pcmap_regs.h
new file mode 100644
index 0000000..1655566
--- /dev/null
+++ b/sys/mips/cavium/octeon_pcmap_regs.h
@@ -0,0 +1,1080 @@
+/*
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors."
+*/
+
+#ifndef __OCTEON_PCMAP_REGS_H__
+#define __OCTEON_PCMAP_REGS_H__
+
+#include "opt_cputype.h"
+
+#define OCTEON_CACHE_LINE_SIZE 0x80 /* 128 bytes cache line size */
+#define IS_OCTEON_ALIGNED(p) (!((u_long)(p) & 0x7f))
+#define OCTEON_ALIGN(p) (((u_long)(p) + ((OCTEON_CACHE_LINE_SIZE) - 1)) & ~((OCTEON_CACHE_LINE_SIZE) - 1))
+
+#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
+ */
+
+/* turn the variable name into a string */
+#define OCTEON_TMP_STR(x) OCTEON_TMP_STR2(x)
+#define OCTEON_TMP_STR2(x) #x
+
+#define OCTEON_PREFETCH_PREF0(address, offset) \
+ __asm __volatile ( ".set mips64\n" \
+ ".set noreorder\n" \
+ "pref 0, " OCTEON_TMP_STR(offset) "(%0)\n" \
+ ".set reorder\n" \
+ ".set mips0\n" \
+ : \
+ : "r" (address) );
+
+#define OCTEON_PREFETCH(address, offset) OCTEON_PREFETCH_PREF0(address,offset)
+
+#define OCTEON_PREFETCH0(address) OCTEON_PREFETCH(address, 0)
+#define OCTEON_PREFETCH128(address) OCTEON_PREFETCH(address, 128)
+
+#define OCTEON_SYNCIOBDMA __asm __volatile (".word 0x8f" : : :"memory")
+
+#define OCTEON_SYNCW __asm __volatile (".word 0x10f" : : )
+#define OCTEON_SYNCW __asm __volatile (".word 0x10f" : : )
+#define OCTEON_SYNCWS __asm __volatile (".word 0x14f" : : )
+
+//#if defined(__mips_n32) || defined(__mips_n64)
+#if defined(__not_used)
+
+static inline void oct_write64 (uint64_t csr_addr, uint64_t val64)
+{
+ uint64_t *ptr = (uint64_t *) csr_addr;
+ *ptr = val64;
+}
+
+static inline void oct_write64_int64 (uint64_t csr_addr, int64_t val64i)
+{
+ int64_t *ptr = (int64_t *) csr_addr;
+ *ptr = val64i;
+}
+
+static inline void oct_write8_x8 (uint64_t csr_addr, uint8_t val8)
+{
+ uint64_t *ptr = (uint64_t *) csr_addr;
+ *ptr = (uint64_t) val8;
+}
+
+static inline void oct_write8 (uint64_t csr_addr, uint8_t val8)
+{
+ oct_write64(csr_addr, (uint64_t) val8);
+}
+
+static inline void oct_write16 (uint64_t csr_addr, uint16_t val16)
+{
+ oct_write64(csr_addr, (uint64_t) val16);
+}
+
+static inline void oct_write32 (uint64_t csr_addr, uint32_t val32)
+{
+ oct_write64(csr_addr, (uint64_t) val32);
+}
+
+static inline uint8_t oct_read8 (uint64_t csr_addr)
+{
+ uint8_t *ptr = (uint8_t *) csr_addr;
+ return (*ptr);
+}
+
+static inline uint8_t oct_read16 (uint64_t csr_addr)
+{
+ uint16_t *ptr = (uint16_t *) csr_addr;
+ return (*ptr);
+}
+
+
+static inline uint32_t oct_read32 (uint64_t csr_addr)
+{
+ uint32_t *ptr = (uint32_t *) csr_addr;
+ return (*ptr);
+}
+
+static inline uint64_t oct_read64 (uint64_t csr_addr)
+{
+ uint64_t *ptr = (uint64_t *) csr_addr;
+ return (*ptr);
+}
+
+static inline int32_t oct_readint32 (uint64_t csr_addr)
+{
+ int32_t *ptr = (int32_t *) csr_addr;
+ return (*ptr);
+}
+
+
+
+#else
+
+
+/* ABI o32 */
+
+
+/*
+ * Read/write functions
+ */
+static inline void oct_write64 (uint64_t csr_addr, uint64_t val64)
+{
+ uint32_t csr_addrh = csr_addr >> 32;
+ uint32_t csr_addrl = csr_addr;
+ uint32_t valh = (uint64_t)val64 >> 32;
+ uint32_t vall = val64;
+ uint32_t tmp1;
+ uint32_t tmp2;
+ uint32_t tmp3;
+
+ __asm __volatile (
+ ".set mips64\n"
+ "dsll %0, %3, 32\n"
+ "dsll %1, %5, 32\n"
+ "dsll %2, %4, 32\n"
+ "dsrl %2, %2, 32\n"
+ "or %0, %0, %2\n"
+ "dsll %2, %6, 32\n"
+ "dsrl %2, %2, 32\n"
+ "or %1, %1, %2\n"
+ "sd %0, 0(%1)\n"
+ ".set mips0\n"
+ : "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3)
+ : "r" (valh), "r" (vall),
+ "r" (csr_addrh), "r" (csr_addrl)
+ );
+}
+
+static inline void oct_write64_int64 (uint64_t csr_addr, int64_t val64i)
+{
+ uint32_t csr_addrh = csr_addr >> 32;
+ uint32_t csr_addrl = csr_addr;
+ int32_t valh = (uint64_t)val64i >> 32;
+ int32_t vall = val64i;
+ uint32_t tmp1;
+ uint32_t tmp2;
+ uint32_t tmp3;
+
+ __asm __volatile (
+ ".set mips64\n"
+ "dsll %0, %3, 32\n"
+ "dsll %1, %5, 32\n"
+ "dsll %2, %4, 32\n"
+ "dsrl %2, %2, 32\n"
+ "or %0, %0, %2\n"
+ "dsll %2, %6, 32\n"
+ "dsrl %2, %2, 32\n"
+ "or %1, %1, %2\n"
+ "sd %0, 0(%1)\n"
+ ".set mips0\n"
+ : "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3)
+ : "r" (valh), "r" (vall),
+ "r" (csr_addrh), "r" (csr_addrl)
+ );
+}
+
+
+/*
+ * oct_write8_x8
+ *
+ * 8 bit data write into IO Space. Written using an 8 bit bus io transaction
+ */
+static inline void oct_write8_x8 (uint64_t csr_addr, uint8_t val8)
+{
+ uint32_t csr_addrh = csr_addr>>32;
+ uint32_t csr_addrl = csr_addr;
+ uint32_t tmp1;
+ uint32_t tmp2;
+
+ __asm __volatile (
+ ".set mips64\n"
+ "dsll %0, %3, 32\n"
+ "dsll %1, %4, 32\n"
+ "dsrl %1, %1, 32\n"
+ "or %0, %0, %1\n"
+ "sb %2, 0(%0)\n"
+ ".set mips0\n"
+ : "=&r" (tmp1), "=&r" (tmp2)
+ : "r" (val8), "r" (csr_addrh), "r" (csr_addrl) );
+}
+
+/*
+ * oct_write8
+ *
+ * 8 bit data write into IO Space. Written using a 64 bit bus io transaction
+ */
+static inline void oct_write8 (uint64_t csr_addr, uint8_t val8)
+{
+#if 1
+ oct_write64(csr_addr, (uint64_t) val8);
+#else
+
+ uint32_t csr_addrh = csr_addr>>32;
+ uint32_t csr_addrl = csr_addr;
+ uint32_t tmp1;
+ uint32_t tmp2;
+
+ __asm __volatile (
+ ".set mips64\n"
+ "dsll %0, %3, 32\n"
+ "dsll %1, %4, 32\n"
+ "dsrl %1, %1, 32\n"
+ "or %0, %0, %1\n"
+ "sb %2, 0(%0)\n"
+ ".set mips0\n"
+ : "=&r" (tmp1), "=&r" (tmp2)
+ : "r" (val8), "r" (csr_addrh), "r" (csr_addrl) );
+#endif
+}
+
+static inline void oct_write16 (uint64_t csr_addr, uint16_t val16)
+{
+#if 1
+ oct_write64(csr_addr, (uint64_t) val16);
+
+#else
+ uint32_t csr_addrh = csr_addr>>32;
+ uint32_t csr_addrl = csr_addr;
+ uint32_t tmp1;
+ uint32_t tmp2;
+
+ __asm __volatile (
+ ".set mips64\n"
+ "dsll %0, %3, 32\n"
+ "dsll %1, %4, 32\n"
+ "dsrl %1, %1, 32\n"
+ "or %0, %0, %1\n"
+ "sh %2, 0(%0)\n"
+ ".set mips0\n"
+ : "=&r" (tmp1), "=&r" (tmp2)
+ : "r" (val16), "r" (csr_addrh), "r" (csr_addrl) );
+#endif
+}
+
+static inline void oct_write32 (uint64_t csr_addr, uint32_t val32)
+{
+#if 1
+ oct_write64(csr_addr, (uint64_t) val32);
+#else
+
+ uint32_t csr_addrh = csr_addr>>32;
+ uint32_t csr_addrl = csr_addr;
+ uint32_t tmp1;
+ uint32_t tmp2;
+
+ __asm __volatile (
+ ".set mips64\n"
+ "dsll %0, %3, 32\n"
+ "dsll %1, %4, 32\n"
+ "dsrl %1, %1, 32\n"
+ "or %0, %0, %1\n"
+ "sw %2, 0(%0)\n"
+ ".set mips0\n"
+ : "=&r" (tmp1), "=&r" (tmp2)
+ : "r" (val32), "r" (csr_addrh), "r" (csr_addrl) );
+#endif
+}
+
+
+
+static inline uint8_t oct_read8 (uint64_t csr_addr)
+{
+ uint32_t csr_addrh = csr_addr>>32;
+ uint32_t csr_addrl = csr_addr;
+ uint32_t tmp1, tmp2;
+
+ __asm __volatile (
+ ".set mips64\n"
+ "dsll %1, %2, 32\n"
+ "dsll %0, %3, 32\n"
+ "dsrl %0, %0, 32\n"
+ "or %1, %1, %0\n"
+ "lb %1, 0(%1)\n"
+ ".set mips0\n"
+ : "=&r" (tmp1), "=&r" (tmp2)
+ : "r" (csr_addrh), "r" (csr_addrl) );
+ return ((uint8_t) tmp2);
+}
+
+static inline uint8_t oct_read16 (uint64_t csr_addr)
+{
+ uint32_t csr_addrh = csr_addr>>32;
+ uint32_t csr_addrl = csr_addr;
+ uint32_t tmp1, tmp2;
+
+ __asm __volatile (
+ ".set mips64\n"
+ "dsll %1, %2, 32\n"
+ "dsll %0, %3, 32\n"
+ "dsrl %0, %0, 32\n"
+ "or %1, %1, %0\n"
+ "lh %1, 0(%1)\n"
+ ".set mips0\n"
+ : "=&r" (tmp1), "=&r" (tmp2)
+ : "r" (csr_addrh), "r" (csr_addrl) );
+ return ((uint16_t) tmp2);
+}
+
+
+static inline uint32_t oct_read32 (uint64_t csr_addr)
+{
+ uint32_t csr_addrh = csr_addr>>32;
+ uint32_t csr_addrl = csr_addr;
+ uint32_t val32;
+ uint32_t tmp;
+
+ __asm __volatile (
+ ".set mips64\n"
+ "dsll %0, %2, 32\n"
+ "dsll %1, %3, 32\n"
+ "dsrl %1, %1, 32\n"
+ "or %0, %0, %1\n"
+ "lw %0, 0(%0)\n"
+ ".set mips0\n"
+ : "=&r" (val32), "=&r" (tmp)
+ : "r" (csr_addrh), "r" (csr_addrl) );
+ return (val32);
+}
+
+
+static inline uint64_t oct_read64 (uint64_t csr_addr)
+{
+ uint32_t csr_addrh = csr_addr >> 32;
+ uint32_t csr_addrl = csr_addr;
+ uint32_t valh;
+ uint32_t vall;
+
+ __asm __volatile (
+ ".set mips64\n"
+ "dsll %0, %2, 32\n"
+ "dsll %1, %3, 32\n"
+ "dsrl %1, %1, 32\n"
+ "or %0, %0, %1\n"
+ "ld %1, 0(%0)\n"
+ "dsrl %0, %1, 32\n"
+ "dsll %1, %1, 32\n"
+ "dsrl %1, %1, 32\n"
+ ".set mips0\n"
+ : "=&r" (valh), "=&r" (vall)
+ : "r" (csr_addrh), "r" (csr_addrl)
+ );
+ return ((uint64_t)valh << 32) | vall;
+}
+
+
+static inline int32_t oct_readint32 (uint64_t csr_addr)
+{
+ uint32_t csr_addrh = csr_addr>>32;
+ uint32_t csr_addrl = csr_addr;
+ int32_t val32;
+ uint32_t tmp;
+
+ __asm __volatile (
+ ".set mips64\n"
+ "dsll %0, %2, 32\n"
+ "dsll %1, %3, 32\n"
+ "dsrl %1, %1, 32\n"
+ "or %0, %0, %1\n"
+ "lw %0, 0(%0)\n"
+ : "=&r" (val32), "=&r" (tmp)
+ : "r" (csr_addrh), "r" (csr_addrl) );
+ return (val32);
+}
+
+
+#endif
+
+
+#define OCTEON_HW_BASE ((volatile uint64_t *) 0L)
+#define OCTEON_REG_OFFSET (-4 * 1024ll) /* local scratchpad reg base */
+#define OCTEON_SCRATCH_BASE ((volatile uint8_t *)(OCTEON_HW_BASE + \
+ OCTEON_REG_OFFSET))
+
+#define OCTEON_SCR_SCRATCH 8
+#define OCTEON_SCRATCH_0 16
+#define OCTEON_SCRATCH_1 24
+#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( \
+ ".set push\n" \
+ ".set mips3\n" \
+ ".set noreorder\n" \
+ ".set noat\n" \
+ ".word 0x7c02f03b \n"\
+ "nop\n" \
+ "nop\n" \
+ "nop\n" \
+ "nop\n" \
+ "sd $2,0(%0)\n" \
+ ".set pop" \
+ : /* 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)));
+}
+
+static inline void oct_scratch_write64 (uint64_t address, uint64_t value)
+{
+ *((volatile uint64_t *)(OCTEON_SCRATCH_BASE + address)) = 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
+ */
+typedef enum {
+ OCTEON_MIPS_SPACE_XKSEG = 3LL,
+ OCTEON_MIPS_SPACE_XKPHYS = 2LL,
+ OCTEON_MIPS_SPACE_XSSEG = 1LL,
+ OCTEON_MIPS_SPACE_XUSEG = 0LL
+} octeon_mips_space_t;
+
+typedef enum {
+ OCTEON_MIPS_XKSEG_SPACE_KSEG0 = 0LL,
+ OCTEON_MIPS_XKSEG_SPACE_KSEG1 = 1LL,
+ OCTEON_MIPS_XKSEG_SPACE_SSEG = 2LL,
+ OCTEON_MIPS_XKSEG_SPACE_KSEG3 = 3LL
+} octeon_mips_xkseg_space_t;
+
+
+/*
+***********************************************************************
+ * 32 bit mode alert
+ * The kseg0 calc below might fail in xkphys.
+ */
+
+/*
+ * We limit the allocated device physical blocks to low mem. So use Kseg0
+ */
+
+/*
+ * Need to go back to kernel to find v->p mappings & vice-versa
+ * We are getting non 1-1 mappings.
+ * #define OCTEON_PTR2PHYS(addr) ((unsigned long) addr & 0x7fffffff)
+ */
+#define OCTEON_PTR2PHYS(addr) octeon_ptr_to_phys(addr)
+
+
+
+/* PTR_SIZE == sizeof(uint32_t) */
+
+#ifdef ISA_MIPS32
+#define mipsx_addr_size uint32_t // u_int64
+#define MIPSX_ADDR_SIZE_KSEGX_BIT_SHIFT 30 // 62
+#define MIPSX_ADDR_SIZE_KSEGX_MASK_REMOVED 0x1fffffff // 0x1fffffff
+#else
+#define mipsx_addr_size uint64_t
+#define MIPSX_ADDR_SIZE_KSEGX_BIT_SHIFT 62
+#define MIPSX_ADDR_SIZE_KSEGX_MASK_REMOVED 0x1fffffffffffffff
+#endif
+
+
+#define octeon_ptr_to_phys(ptr) \
+ ((((mipsx_addr_size) ptr) >> MIPSX_ADDR_SIZE_KSEGX_BIT_SHIFT) == 2) ? \
+ ((mipsx_addr_size) ptr & MIPSX_ADDR_SIZE_KSEGX_MASK_REMOVED) : \
+ (vtophys(ptr))
+
+
+#ifdef CODE_FOR_64_BIT_NEEDED
+static inline mipsx_addr_size octeon_ptr_to_phys (void *ptr)
+{
+ if ((((mipsx_addr_size) ptr) >> MIPSX_ADDR_SIZE_KSEGX_BIT_SHIFT) == 2) {
+ /*
+ * KSEG0 based address ?
+ */
+ return ((mipsx_addr_size) ptr & MIPSX_ADDR_SIZE_KSEGX_MASK_REMOVED);
+ } else {
+ /*
+ * Ask kernel/vm to give us the phys translation.
+ */
+ return (vtophys(ptr));
+ }
+}
+#endif
+
+#define OCTEON_IO_SEG OCTEON_MIPS_SPACE_XKPHYS
+
+
+#define OCTEON_ADD_SEG(segment, add) ((((uint64_t)segment) << 62) | (add))
+
+#define OCTEON_ADD_IO_SEG(add) OCTEON_ADD_SEG(OCTEON_IO_SEG, (add))
+#define OCTEON_ADDR_DID(did) (OCTEON_ADDR_DIDSPACE(did) << 40)
+#define OCTEON_ADDR_DIDSPACE(did) (((OCTEON_IO_SEG) << 22) | ((1ULL) << 8) | (did))
+#define OCTEON_ADDR_FULL_DID(did,subdid) (((did) << 3) | (subdid))
+
+
+#define OCTEON_CIU_PP_RST OCTEON_ADD_IO_SEG(0x0001070000000700ull)
+#define OCTEON_OCTEON_DID_TAG 12ULL
+
+
+
+
+/*
+ * octeon_addr_t
+ */
+typedef union {
+ uint64_t word64;
+
+ struct {
+ octeon_mips_space_t R : 2;
+ uint64_t offset :62;
+ } sva; // mapped or unmapped virtual address
+
+ struct {
+ uint64_t zeroes :33;
+ uint64_t offset :31;
+ } suseg; // mapped USEG virtual addresses (typically)
+
+ struct {
+ uint64_t ones :33;
+ octeon_mips_xkseg_space_t sp : 2;
+ uint64_t offset :29;
+ } sxkseg; // mapped or unmapped virtual address
+
+ struct {
+ octeon_mips_space_t R :2; // CVMX_MIPS_SPACE_XKPHYS in this case
+ uint64_t cca : 3; // ignored by octeon
+ uint64_t mbz :10;
+ uint64_t pa :49; // physical address
+ } sxkphys; // physical address accessed through xkphys unmapped virtual address
+
+ struct {
+ uint64_t mbz :15;
+ uint64_t is_io : 1; // if set, the address is uncached and resides on MCB bus
+ uint64_t did : 8; // the hardware ignores this field when is_io==0, else device ID
+ uint64_t unaddr: 4; // the hardware ignores <39:36> in Octeon I
+ uint64_t offset :36;
+ } sphys; // physical address
+
+ struct {
+ uint64_t zeroes :24; // techically, <47:40> are dont-cares
+ uint64_t unaddr: 4; // the hardware ignores <39:36> in Octeon I
+ uint64_t offset :36;
+ } smem; // physical mem address
+
+ struct {
+ uint64_t mem_region :2;
+ uint64_t mbz :13;
+ uint64_t is_io : 1; // 1 in this case
+ uint64_t did : 8; // the hardware ignores this field when is_io==0, else device ID
+ uint64_t unaddr: 4; // the hardware ignores <39:36> in Octeon I
+ uint64_t offset :36;
+ } sio; // physical IO address
+
+ struct {
+ uint64_t didspace : 24;
+ uint64_t unused : 40;
+ } sfilldidspace;
+
+} octeon_addr_t;
+
+
+typedef union {
+ uint64_t word64;
+ struct {
+ uint32_t word32hi;
+ uint32_t word32lo;
+ } bits;
+} octeon_word_t;
+
+
+
+
+/*
+ * octeon_build_io_address
+ *
+ * Builds a memory address for I/O based on the Major 5bits and Sub DID 3bits
+ */
+static inline uint64_t octeon_build_io_address (uint64_t major_did,
+ uint64_t sub_did)
+{
+ return ((0x1ull << 48) | (major_did << 43) | (sub_did << 40));
+}
+
+/*
+ * octeon_build_mask
+ *
+ * Builds a bit mask given the required size in bits.
+ *
+ * @param bits Number of bits in the mask
+ * @return The mask
+ */
+static inline uint64_t octeon_build_mask (uint64_t bits)
+{
+ return ~((~0x0ull) << bits);
+}
+
+/*
+ * octeon_build_bits
+ *
+ * Perform mask and shift to place the supplied value into
+ * the supplied bit rage.
+ *
+ * Example: octeon_build_bits(39,24,value)
+ * <pre>
+ * 6 5 4 3 3 2 1
+ * 3 5 7 9 1 3 5 7 0
+ * +-------+-------+-------+-------+-------+-------+-------+------+
+ * 000000000000000000000000___________value000000000000000000000000
+ * </pre>
+ *
+ * @param high_bit Highest bit value can occupy (inclusive) 0-63
+ * @param low_bit Lowest bit value can occupy inclusive 0-high_bit
+ * @param value Value to use
+ * @return Value masked and shifted
+ */
+static inline uint64_t octeon_build_bits (uint64_t high_bit, uint64_t low_bit,
+ uint64_t value)
+{
+ return ((value & octeon_build_mask(high_bit - low_bit + 1)) << low_bit);
+}
+
+
+/********************** simple spinlocks ***************/
+typedef struct {
+ volatile uint32_t value;
+} octeon_spinlock_t;
+
+// note - macros not expanded in inline ASM, so values hardcoded
+#define OCTEON_SPINLOCK_UNLOCKED_VAL 0
+#define OCTEON_SPINLOCK_LOCKED_VAL 1
+
+/**
+ * Initialize a spinlock
+ *
+ * @param lock Lock to initialize
+ */
+static inline void octeon_spinlock_init(octeon_spinlock_t *lock)
+{
+ lock->value = OCTEON_SPINLOCK_UNLOCKED_VAL;
+}
+/**
+ * Releases lock
+ *
+ * @param lock pointer to lock structure
+ */
+static inline void octeon_spinlock_unlock(octeon_spinlock_t *lock)
+{
+ OCTEON_SYNCWS;
+
+ lock->value = 0;
+ OCTEON_SYNCWS;
+}
+
+/**
+ * Gets lock, spins until lock is taken
+ *
+ * @param lock pointer to lock structure
+ */
+static inline void octeon_spinlock_lock(octeon_spinlock_t *lock)
+{
+ unsigned int tmp;
+ __asm __volatile(
+ ".set noreorder \n"
+ "1: ll %1, %0 \n"
+ " bnez %1, 1b \n"
+ " li %1, 1 \n"
+ " sc %1, %0 \n"
+ " beqz %1, 1b \n"
+ " nop \n"
+ ".set reorder \n"
+ : "+m" (lock->value), "=&r" (tmp )
+ :
+ : "memory");
+}
+
+/********************** end simple spinlocks ***************/
+
+
+
+/* ------------------------------------------------------------------- *
+ * octeon_get_chipid() *
+ * ------------------------------------------------------------------- */
+#define OCTEON_CN31XX_CHIP 0x000d0100
+#define OCTEON_CN30XX_CHIP 0x000d0200
+#define OCTEON_CN3020_CHIP 0x000d0112
+#define OCTEON_CN5020_CHIP 0x000d0601
+
+static inline uint32_t octeon_get_chipid(void)
+{
+ uint32_t id;
+
+ __asm __volatile ("mfc0 %0, $15,0" : "=r" (id));
+
+ return (id);
+}
+
+
+static inline uint32_t octeon_get_except_base_reg (void)
+{
+ uint32_t tmp;
+
+ __asm volatile (
+ " .set mips64r2 \n"
+ " .set noreorder \n"
+ " mfc0 %0, $15, 1 \n"
+ " .set reorder \n"
+ : "=&r" (tmp) : );
+
+ return(tmp);
+}
+
+
+
+
+static inline unsigned int get_coremask (void)
+{
+ return(~(oct_read64(OCTEON_CIU_PP_RST)) & 0xffff);
+}
+
+
+static inline uint32_t octeon_get_core_num (void)
+{
+
+ return (0x3FF & octeon_get_except_base_reg());
+}
+
+
+static inline uint64_t octeon_get_cycle(void)
+{
+
+/* ABI == 32 */
+
+ uint32_t tmp_low, tmp_hi;
+
+ __asm __volatile (
+ " .set push \n"
+ " .set mips64r2 \n"
+ " .set noreorder \n"
+ " rdhwr %[tmpl], $31 \n"
+ " dadd %[tmph], %[tmpl], $0 \n"
+ " dsrl %[tmph], 32 \n"
+ " dsll %[tmpl], 32 \n"
+ " dsrl %[tmpl], 32 \n"
+ " .set pop \n"
+ : [tmpl] "=&r" (tmp_low), [tmph] "=&r" (tmp_hi) : );
+
+ return(((uint64_t)tmp_hi << 32) + tmp_low);
+}
+
+
+/**
+ * Wait for the specified number of cycle
+ *
+ * @param cycles
+ */
+static inline void octeon_wait (uint64_t cycles)
+{
+ uint64_t done = octeon_get_cycle() + cycles;
+
+ while (octeon_get_cycle() < done)
+ {
+ /* Spin */
+ }
+}
+
+
+
+/*
+ * octeon_machdep.c
+ *
+ * Direct to Board Support level.
+ */
+extern void octeon_led_write_char(int char_position, char val);
+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);
+extern void mips_disable_interrupt_controls(void);
+extern uint32_t octeon_cpu_clock;
+extern uint64_t octeon_dram;
+extern uint32_t octeon_bd_ver, octeon_board_rev_major, octeon_board_rev_minor, octeon_board_type;
+extern uint8_t octeon_mac_addr[6];
+extern int octeon_core_mask, octeon_mac_addr_count, octeon_chip_rev_major, octeon_chip_rev_minor, octeon_chip_type;
+extern void bzero_64(void *str, size_t len);
+extern void bzero_32(void *str, size_t len);
+extern void bzero_16(void *str, size_t len);
+extern void bzero_old(void *str, size_t len);
+extern void octeon_ciu_reset(void);
+extern void ciu_disable_intr(int core_num, int intx, int enx);
+extern void ciu_enable_interrupts (int core_num, int intx, int enx, uint64_t set_these_interrupt_bits, int ciu_ip);
+extern void ciu_clear_int_summary(int core_num, int intx, int enx, uint64_t write_bits);
+extern uint64_t ciu_get_int_summary(int core_num, int intx, int enx);
+extern void octeon_ciu_start_gtimer(int timer, u_int one_shot, uint64_t time_cycles);
+extern void octeon_ciu_stop_gtimer(int timer);
+extern int octeon_board_real(void);
+
+
+
+typedef union {
+ uint64_t word64;
+ struct {
+ uint64_t reserved : 27; /* Not used */
+ uint64_t one_shot : 1; /* Oneshot ? */
+ uint64_t len : 36; /* len of timer in clock cycles - 1 */
+ } bits;
+} octeon_ciu_gentimer;
+
+
+
+#endif /* LOCORE */
+
+
+/*
+ * R4K Address space definitions
+ */
+#define ADRSPC_K0BASE (0x80000000)
+#define ADRSPC_K0SIZE (0x20000000)
+#define ADRSPC_K1BASE (0xA0000000)
+#define ADRSPC_K1SIZE (0x20000000)
+#define ADRSPC_KSBASE (0xC0000000)
+#define ADRSPC_KSSIZE (0x20000000)
+#define ADRSPC_K3BASE (0xE0000000)
+#define ADRSPC_K3SIZE (0x20000000)
+#define ADRSPC_KUBASE (0x00000000)
+#define ADRSPC_KUSIZE (0x80000000)
+#define KSEG_MSB_ADDR 0xFFFFFFFF
+
+
+
+#define OCTEON_CLOCK_DEFAULT (500 * 1000 * 1000)
+
+
+/*
+ * Octeon Boot Bus BIST Status
+ * Mostly used for dummy read to ensure all prev I/Os are write-complete.
+ */
+#define OCTEON_MIO_BOOT_BIST_STAT 0x80011800000000F8ull
+
+/*
+ * Octeon UART unit
+ */
+#define OCTEON_MIO_UART0_THR 0x8001180000000840ull
+#define OCTEON_MIO_UART1_THR 0x8001180000000C40ull
+#define OCTEON_MIO_UART0_LSR 0x8001180000000828ull
+#define OCTEON_MIO_UART1_LSR 0x8001180000000C28ull
+#define OCTEON_MIO_UART0_RBR 0x8001180000000800ull
+#define OCTEON_MIO_UART1_RBR 0x8001180000000C00ull
+#define OCTEON_MIO_UART0_USR 0x8001180000000938ull
+#define OCTEON_MIO_UART1_USR 0x8001180000000D38ull
+#define OCTEON_MIO_ADDR_HI24 0x800118
+
+
+/*
+ * EBT3000 LED Unit
+ */
+#define OCTEON_CHAR_LED_BASE_ADDR (0x1d020000 | (0x1ffffffffull << 31))
+
+#define OCTEON_FPA_QUEUES 8
+
+/*
+ * Octeon FPA I/O Registers
+ */
+#define OCTEON_FPA_CTL_STATUS 0x8001180028000050ull
+#define OCTEON_FPA_FPF_SIZE 0x8001180028000058ull
+#define OCTEON_FPA_FPF_MARKS 0x8001180028000000ull
+#define OCTEON_FPA_INT_SUMMARY 0x8001180028000040ull
+#define OCTEON_FPA_INT_ENABLE 0x8001180028000048ull
+#define OCTEON_FPA_QUEUE_AVAILABLE 0x8001180028000098ull
+#define OCTEON_FPA_PAGE_INDEX 0x80011800280000f0ull
+
+/*
+ * Octeon PKO Unit
+ */
+#define OCTEON_PKO_REG_FLAGS 0x8001180050000000ull
+#define OCTEON_PKO_REG_READ_IDX 0x8001180050000008ull
+#define OCTEON_PKO_CMD_BUF 0x8001180050000010ull
+#define OCTEON_PKO_GMX_PORT_MODE 0x8001180050000018ull
+#define OCTEON_PKO_REG_CRC_ENABLE 0x8001180050000020ull
+#define OCTEON_PKO_QUEUE_MODE 0x8001180050000048ull
+#define OCTEON_PKO_MEM_QUEUE_PTRS 0x8001180050001000ull
+#define OCTEON_PKO_MEM_COUNT0 0x8001180050001080ull
+#define OCTEON_PKO_MEM_COUNT1 0x8001180050001088ull
+#define OCTEON_PKO_MEM_DEBUG0 0x8001180050001100ull
+#define OCTEON_PKO_MEM_DEBUG1 0x8001180050001108ull
+#define OCTEON_PKO_MEM_DEBUG2 0x8001180050001110ull
+#define OCTEON_PKO_MEM_DEBUG3 0x8001180050001118ull
+#define OCTEON_PKO_MEM_DEBUG4 0x8001180050001120ull
+#define OCTEON_PKO_MEM_DEBUG5 0x8001180050001128ull
+#define OCTEON_PKO_MEM_DEBUG6 0x8001180050001130ull
+#define OCTEON_PKO_MEM_DEBUG7 0x8001180050001138ull
+#define OCTEON_PKO_MEM_DEBUG8 0x8001180050001140ull
+#define OCTEON_PKO_MEM_DEBUG9 0x8001180050001148ull
+
+
+/*
+ * Octeon IPD Unit
+ */
+#define OCTEON_IPD_1ST_MBUFF_SKIP 0x80014F0000000000ull
+#define OCTEON_IPD_NOT_1ST_MBUFF_SKIP 0x80014F0000000008ull
+#define OCTEON_IPD_PACKET_MBUFF_SIZE 0x80014F0000000010ull
+#define OCTEON_IPD_1ST_NEXT_PTR_BACK 0x80014F0000000150ull
+#define OCTEON_IPD_2ND_NEXT_PTR_BACK 0x80014F0000000158ull
+#define OCTEON_IPD_WQE_FPA_QUEUE 0x80014F0000000020ull
+#define OCTEON_IPD_CTL_STATUS 0x80014F0000000018ull
+#define OCTEON_IPD_QOSX_RED_MARKS(queue) (0x80014F0000000178ull + ((queue) * 8))
+#define OCTEON_IPD_RED_Q_PARAM(queue) (0x80014F00000002E0ull + ((queue) * 8))
+#define OCTEON_IPD_PORT_BP_PAGE_COUNT(port) (0x80014F0000000028ull + ((port) * 8))
+#define OCTEON_IPD_BP_PORT_RED_END 0x80014F0000000328ull
+#define OCTEON_IPD_RED_PORT_ENABLE 0x80014F00000002D8ull
+
+/*
+ * Octeon CIU Unit
+ */
+#define OCTEON_CIU_ENABLE_BASE_ADDR 0x8001070000000200ull
+#define OCTEON_CIU_SUMMARY_BASE_ADDR 0x8001070000000000ull
+#define OCTEON_CIU_SUMMARY_INT1_ADDR 0x8001070000000108ull
+
+#define OCTEON_CIU_MBOX_SETX(offset) (0x8001070000000600ull+((offset)*8))
+#define OCTEON_CIU_MBOX_CLRX(offset) (0x8001070000000680ull+((offset)*8))
+#define OCTEON_CIU_ENABLE_MBOX_INTR 0x0000000300000000ull /* bits 32, 33 */
+
+#define CIU_MIPS_IP2 0
+#define CIU_MIPS_IP3 1
+
+#define CIU_INT_0 CIU_MIPS_IP2
+#define CIU_INT_1 CIU_MIPS_IP3
+
+#define CIU_EN_0 0
+#define CIU_EN_1 1
+
+#define CIU_THIS_CORE -1
+
+#define CIU_UART_BITS_UART0 (0x1ull << 34) // Bit 34
+#define CIU_UART_BITS_UART1 (0x1ull << 35) // Bit 35
+#define CIU_GENTIMER_BITS_ENABLE(timer) (0x1ull << (52 + (timer))) // Bit 52..55
+
+#define CIU_GENTIMER_NUM_0 0
+#define CIU_GENTIMER_NUM_1 1
+#define CIU_GENTIMER_NUM_2 2
+#define CIU_GENTIMER_NUM_3 3
+#define OCTEON_GENTIMER_ONESHOT 1
+#define OCTEON_GENTIMER_PERIODIC 0
+
+#define OCTEON_CIU_GENTIMER_ADDR(timer) (0x8001070000000480ull + ((timer) * 0x8))
+
+
+#define OCTEON_GENTIMER_LEN_1MS (0x7a120ull) /* Back of envelope. 500Mhz Octeon */ // FIXME IF WRONG
+#define OCTEON_GENTIMER_LEN_1SEC ((OCTEON_GENTIMER_LEN_1MS) * 1000)
+
+/*
+ * Physical Memory Banks
+ */
+/* 1st BANK */
+#define OCTEON_DRAM_FIRST_256_START 0x00000000ull
+#define OCTEON_DRAM_FIRST_256_END (0x10000000ull - 1ull)
+#define OCTEON_DRAM_RESERVED_END 0X1FFF000ULL /* 32 Meg Reserved for Mips Kernel MD Ops */
+#define OCTEON_DRAM_FIRST_BANK_SIZE (OCTEON_DRAM_FIRST_256_END - OCTEON_DRAM_FIRST_256_START + 1)
+
+/* 2nd BANK */
+#define OCTEON_DRAM_SECOND_256_START (0x0000000410000000ull)
+#define OCTEON_DRAM_SECOND_256_END (0x0000000420000000ull - 1ull) /* Requires 64 bit paddr */
+#define OCTEON_DRAM_SECOND_BANK_SIZE (OCTEON_DRAM_SECOND_256_END - OCTEON_DRAM_SECOND_256_START + 1ull)
+
+/* 3rd BANK */
+#define OCTEON_DRAM_ABOVE_512_START 0x20000000ull
+#define OCTEON_DRAM_ABOVE_512_END (0x0000000300000000ull - 1ull) /* To be calculated as remaining */
+#define OCTEON_DRAM_THIRD_BANK_SIZE (OCTEON_DRAM_ABOVE_512_END - OCTEON_DRAM_ABOVE_512_START + 1ull)
+
+#endif /* !OCTEON_PCMAP_REGS_H__ */
diff --git a/sys/mips/cavium/octeonreg.h b/sys/mips/cavium/octeonreg.h
new file mode 100644
index 0000000..44e927d
--- /dev/null
+++ b/sys/mips/cavium/octeonreg.h
@@ -0,0 +1,247 @@
+/* $NetBSD: octeonreg.h,v 1.1 2002/03/07 14:44:04 simonb Exp $ */
+
+/*
+ * Copyright 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Simon Burge for Wasabi Systems, Inc.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ */
+
+/*
+ Memory Map
+
+ 0000.0000 * 128MB Typically SDRAM (on Core Board)
+ 0800.0000 * 256MB Typically PCI
+ 1800.0000 * 62MB Typically PCI
+ 1be0.0000 * 2MB Typically System controller's internal registers
+ 1c00.0000 * 32MB Typically not used
+ 1e00.0000 4MB Monitor Flash
+ 1e40.0000 12MB reserved
+ 1f00.0000 12MB Switches
+ LEDs
+ ASCII display
+ Soft reset
+ FPGA revision number
+ CBUS UART (tty2)
+ General Purpose I/O
+ I2C controller
+ 1f10.0000 * 11MB Typically System Controller specific
+ 1fc0.0000 4MB Maps to Monitor Flash
+ 1fd0.0000 * 3MB Typically System Controller specific
+
+ * depends on implementation of the Core Board and of software
+ */
+
+/*
+ CPU interrupts
+
+ NMI South Bridge or NMI button
+ 0 South Bridge INTR
+ 1 South Bridge SMI
+ 2 CBUS UART (tty2)
+ 3 COREHI (Core Card)
+ 4 CORELO (Core Card)
+ 5 Not used, driven inactive (typically CPU internal timer interrupt
+
+ IRQ mapping (as used by YAMON)
+
+ 0 Timer South Bridge
+ 1 Keyboard SuperIO
+ 2 Reserved by South Bridge (for cascading)
+ 3 UART (tty1) SuperIO
+ 4 UART (tty0) SuperIO
+ 5 Not used
+ 6 Floppy Disk SuperIO
+ 7 Parallel Port SuperIO
+ 8 Real Time Clock South Bridge
+ 9 I2C bus South Bridge
+ 10 PCI A,B,eth PCI slot 1..4, Ethernet
+ 11 PCI C,audio PCI slot 1..4, Audio, USB (South Bridge)
+ PCI D,USB
+ 12 Mouse SuperIO
+ 13 Reserved by South Bridge
+ 14 Primary IDE Primary IDE slot
+ 15 Secondary IDE Secondary IDE slot/Compact flash connector
+ */
+
+#define OCTEON_SYSTEMRAM_BASE 0x00000000 /* System RAM: */
+#define OCTEON_SYSTEMRAM_SIZE 0x08000000 /* 128 MByte */
+
+#define OCTEON_PCIMEM1_BASE 0x08000000 /* PCI 1 memory: */
+#define OCTEON_PCIMEM1_SIZE 0x08000000 /* 128 MByte */
+
+#define OCTEON_PCIMEM2_BASE 0x10000000 /* PCI 2 memory: */
+#define OCTEON_PCIMEM2_SIZE 0x08000000 /* 128 MByte */
+
+#define OCTEON_PCIMEM3_BASE 0x18000000 /* PCI 3 memory */
+#define OCTEON_PCIMEM3_SIZE 0x03e00000 /* 62 MByte */
+
+#define OCTEON_CORECTRL_BASE 0x1be00000 /* Core control: */
+#define OCTEON_CORECTRL_SIZE 0x00200000 /* 2 MByte */
+
+#define OCTEON_RESERVED_BASE1 0x1c000000 /* Reserved: */
+#define OCTEON_RESERVED_SIZE1 0x02000000 /* 32 MByte */
+
+#define OCTEON_MONITORFLASH_BASE 0x1e000000 /* Monitor Flash: */
+#define OCTEON_MONITORFLASH_SIZE 0x003e0000 /* 4 MByte */
+#define OCTEON_MONITORFLASH_SECTORSIZE 0x00010000 /* Sect. = 64 KB */
+
+#define OCTEON_FILEFLASH_BASE 0x1e3e0000 /* File Flash (for monitor): */
+#define OCTEON_FILEFLASH_SIZE 0x00020000 /* 128 KByte */
+
+#define OCTEON_FILEFLASH_SECTORSIZE 0x00010000 /* Sect. = 64 KB */
+
+#define OCTEON_RESERVED_BASE2 0x1e400000 /* Reserved: */
+#define OCTEON_RESERVED_SIZE2 0x00c00000 /* 12 MByte */
+
+#define OCTEON_FPGA_BASE 0x1f000000 /* FPGA: */
+#define OCTEON_FPGA_SIZE 0x00c00000 /* 12 MByte */
+
+#define OCTEON_NMISTATUS (OCTEON_FPGA_BASE + 0x24)
+#define OCTEON_NMI_SB 0x2 /* Pending NMI from the South Bridge */
+#define OCTEON_NMI_ONNMI 0x1 /* Pending NMI from the ON/NMI push button */
+
+#define OCTEON_NMIACK (OCTEON_FPGA_BASE + 0x104)
+#define OCTEON_NMIACK_ONNMI 0x1 /* Write 1 to acknowledge ON/NMI */
+
+#define OCTEON_SWITCH (OCTEON_FPGA_BASE + 0x200)
+#define OCTEON_SWITCH_MASK 0xff /* settings of DIP switch S2 */
+
+#define OCTEON_STATUS (OCTEON_FPGA_BASE + 0x208)
+#define OCTEON_ST_MFWR 0x10 /* Monitor Flash is write protected (JP1) */
+#define OCTEON_S54 0x08 /* switch S5-4 - set YAMON factory default mode */
+#define OCTEON_S53 0x04 /* switch S5-3 */
+#define OCTEON_BIGEND 0x02 /* switch S5-2 - big endian mode */
+
+#define OCTEON_JMPRS (OCTEON_FPGA_BASE + 0x210)
+#define OCTEON_JMPRS_PCICLK 0x1c /* PCI clock frequency */
+#define OCTEON_JMPRS_EELOCK 0x02 /* I2C EEPROM is write protected */
+
+#define OCTEON_LEDBAR (OCTEON_FPGA_BASE + 0x408)
+#define OCTEON_ASCIIWORD (OCTEON_FPGA_BASE + 0x410)
+#define OCTEON_ASCII_BASE (OCTEON_FPGA_BASE + 0x418)
+#define OCTEON_ASCIIPOS0 0x00
+#define OCTEON_ASCIIPOS1 0x08
+#define OCTEON_ASCIIPOS2 0x10
+#define OCTEON_ASCIIPOS3 0x18
+#define OCTEON_ASCIIPOS4 0x20
+#define OCTEON_ASCIIPOS5 0x28
+#define OCTEON_ASCIIPOS6 0x30
+#define OCTEON_ASCIIPOS7 0x38
+
+#define OCTEON_SOFTRES (OCTEON_FPGA_BASE + 0x500)
+#define OCTEON_GORESET 0x42 /* write this to OCTEON_SOFTRES for board reset */
+
+/*
+ * BRKRES is the number of milliseconds before a "break" on tty will
+ * trigger a reset. A value of 0 will disable the reset.
+ */
+#define OCTEON_BRKRES (OCTEON_FPGA_BASE + 0x508)
+#define OCTEON_BRKRES_MASK 0xff
+
+#define OCTEON_CBUSUART 0x8001180000000800ull
+/* 16C550C UART, 8 bit registers on 8 byte boundaries */
+/* RXTX 0x00 */
+/* INTEN 0x08 */
+/* IIFIFO 0x10 */
+/* LCTRL 0x18 */
+/* MCTRL 0x20 */
+/* LSTAT 0x28 */
+/* MSTAT 0x30 */
+/* SCRATCH 0x38 */
+#define OCTEON_CBUSUART_INTR 2
+
+#define OCTEON_GPIO_BASE (OCTEON_FPGA_BASE + 0xa00)
+#define OCTEON_GPOUT 0x0
+#define OCTEON_GPINP 0x8
+
+#define OCTEON_BOOTROM_BASE 0x1fc00000 /* Boot ROM: */
+#define OCTEON_BOOTROM_SIZE 0x00400000 /* 4 MByte */
+
+#define OCTEON_REVISION 0x1fc00010
+#define OCTEON_REV_FPGRV 0xff0000 /* CBUS FPGA revision */
+#define OCTEON_REV_CORID 0x00fc00 /* Core Board ID */
+#define OCTEON_REV_CORRV 0x000300 /* Core Board Revision */
+#define OCTEON_REV_PROID 0x0000f0 /* Product ID */
+#define OCTEON_REV_PRORV 0x00000f /* Product Revision */
+
+/* PCI definitions */
+
+#define OCTEON_UART0ADR 0x8001180000000800ull
+#define OCTEON_UART1ADR 0x8001180000000C00ull
+#define OCTEON_UART_SIZE 0x400
+
+#define OCTEON_MIO_BOOT_BIST_STAT 0x80011800000000F8ull
+
+
+
+/**************************
+ * To Delete
+ */
+#define OCTEON_SOUTHBRIDGE_INTR 0
+
+#define OCTEON_PCI0_IO_BASE OCTEON_PCIMEM3_BASE
+#define OCTEON_PCI0_ADDR( addr ) (OCTEON_PCI0_IO_BASE + (addr))
+
+#define OCTEON_RTCADR 0x70 // OCTEON_PCI_IO_ADDR8(0x70)
+#define OCTEON_RTCDAT 0x71 // OCTEON_PCI_IO_ADDR8(0x71)
+
+#define OCTEON_SMSC_COM1_ADR 0x3f8
+#define OCTEON_SMSC_COM2_ADR 0x2f8
+#define OCTEON_UARTT0ADR OCTEON_PCI0_ADDR(OCTEON_SMSC_COM1_ADR)
+#define OCTEON_UARTT1ADR OCTEON_SMSC_COM2_ADR // OCTEON_PCI0_ADDR(OCTEON_SMSC_COM2_ADR)
+
+#define OCTEON_SMSC_1284_ADR 0x378
+#define OCTEON_1284ADR OCTEON_SMSC_1284_ADR // OCTEON_PCI0_ADDR(OCTEON_SMSC_1284_ADR)
+
+#define OCTEON_SMSC_FDD_ADR 0x3f0
+#define OCTEON_FDDADR OCTEON_SMSC_FDD_ADR // OCTEON_PCI0_ADDR(OCTEON_SMSC_FDD_ADR)
+
+#define OCTEON_SMSC_KYBD_ADR 0x60 /* Fixed 0x60, 0x64 */
+#define OCTEON_KYBDADR OCTEON_SMSC_KYBD_ADR // OCTEON_PCI0_ADDR(OCTEON_SMSC_KYBD_ADR)
+#define OCTEON_SMSC_MOUSE_ADR OCTEON_SMSC_KYBD_ADR
+#define OCTEON_MOUSEADR OCTEON_KYBDADR
+
+
+#define OCTEON_DMA_PCI_PCIBASE 0x00000000UL
+#define OCTEON_DMA_PCI_PHYSBASE 0x00000000UL
+#define OCTEON_DMA_PCI_SIZE (256 * 1024 * 1024)
+
+#define OCTEON_DMA_ISA_PCIBASE 0x00800000UL
+#define OCTEON_DMA_ISA_PHYSBASE 0x00000000UL
+#define OCTEON_DMA_ISA_SIZE (8 * 1024 * 1024)
+
+#ifndef _LOCORE
+void led_bar(uint8_t);
+void led_display_word(uint32_t);
+void led_display_str(const char *);
+void led_display_char(int, uint8_t);
+#endif
diff --git a/sys/mips/cavium/std.octeon1 b/sys/mips/cavium/std.octeon1
new file mode 100644
index 0000000..c46d0c7
--- /dev/null
+++ b/sys/mips/cavium/std.octeon1
@@ -0,0 +1,22 @@
+# /*
+# * This product includes software developed by the University of
+# * California, Berkeley and its contributors."
+# */
+# $FreeBSD$
+#
+files "../octeon1/files.octeon1"
+
+#
+#
+#
+cpu CPU_MIPS4KC
+#device pci
+#device ata
+#device atadisk
+
+#device clock
+#device obio
+#device uart
+
+# Kludge
+options TARGET_OCTEON
diff --git a/sys/mips/cavium/uart_bus_octeonusart.c b/sys/mips/cavium/uart_bus_octeonusart.c
new file mode 100644
index 0000000..2f43c77
--- /dev/null
+++ b/sys/mips/cavium/uart_bus_octeonusart.c
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@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
+ * $Id$
+ */
+/*
+ * Skeleton of this file was based on respective code for ARM
+ * code written by Olivier Houchard.
+ */
+
+/*
+ * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is
+ * experimental and was written for MIPS32 port.
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+/*
+ * XXXMIPS:
+ */
+#include <mips/octeon1/octeonreg.h>
+
+#include "uart_if.h"
+
+extern struct uart_class uart_oct16550_class;
+
+
+static int uart_octeon_probe(device_t dev);
+static void octeon_uart_identify(driver_t * drv, device_t parent);
+
+extern struct uart_class octeon_uart_class;
+
+static device_method_t uart_octeon_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_octeon_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ DEVMETHOD(device_identify, octeon_uart_identify),
+ {0, 0}
+};
+
+static driver_t uart_octeon_driver = {
+ uart_driver_name,
+ uart_octeon_methods,
+ sizeof(struct uart_softc),
+};
+
+extern
+SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+
+static int
+uart_octeon_probe(device_t dev)
+{
+ struct uart_softc *sc;
+ int unit;
+
+ unit = device_get_unit(dev);
+ sc = device_get_softc(dev);
+ sc->sc_class = &uart_oct16550_class;
+
+#if 1
+ /*
+ * We inherit the settings from the systme console. Note, the bst
+ * bad bus_space_map are bogus here, but obio doesn't yet support
+ * them, it seems.
+ */
+ sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs);
+ bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
+ sc->sc_bas.bst = uart_bus_space_mem;
+ if (bus_space_map(sc->sc_bas.bst, OCTEON_UART0ADR, OCTEON_UART_SIZE,
+ 0, &sc->sc_bas.bsh) != 0)
+ return (ENXIO);
+#endif
+ return (uart_bus_probe(dev, sc->sc_bas.regshft, 0, 0, unit));
+}
+
+static void
+octeon_uart_identify(driver_t * drv, device_t parent)
+{
+ BUS_ADD_CHILD(parent, 0, "uart", 0);
+}
+
+DRIVER_MODULE(uart, obio, uart_octeon_driver, uart_devclass, 0, 0);
diff --git a/sys/mips/cavium/uart_cpu_octeonusart.c b/sys/mips/cavium/uart_cpu_octeonusart.c
new file mode 100644
index 0000000..7b0cdbf
--- /dev/null
+++ b/sys/mips/cavium/uart_cpu_octeonusart.c
@@ -0,0 +1,191 @@
+/*-
+ * Copyright (c) 2009 M. Warner Losh <imp@FreeBSD.org>
+ * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@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.
+ *
+ * $Id$
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <mips/octeon1/octeonreg.h>
+#include <mips/octeon1/octeon_pcmap_regs.h>
+
+bus_space_tag_t uart_bus_space_io;
+bus_space_tag_t uart_bus_space_mem;
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/ktr.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_extern.h>
+
+#include <machine/bus.h>
+#include <machine/cache.h>
+
+/*
+ * Specailized uart bus space. We present a 1 apart byte oriented
+ * bus to the outside world, but internally translate to/from the 8-apart
+ * 64-bit word bus that's on the octeon. We only support simple read/write
+ * in this space. Everything else is undefined.
+ */
+
+static uint8_t
+ou_bs_r_1(void *t, bus_space_handle_t handle, bus_size_t offset)
+{
+
+ return (oct_read64(handle + (offset << 3)));
+}
+
+static uint16_t
+ou_bs_r_2(void *t, bus_space_handle_t handle, bus_size_t offset)
+{
+
+ return (oct_read64(handle + (offset << 3)));
+}
+
+static uint32_t
+ou_bs_r_4(void *t, bus_space_handle_t handle, bus_size_t offset)
+{
+
+ return (oct_read64(handle + (offset << 3)));
+}
+
+static uint64_t
+ou_bs_r_8(void *t, bus_space_handle_t handle, bus_size_t offset)
+{
+
+ return (oct_read64(handle + (offset << 3)));
+}
+
+static void
+ou_bs_w_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t value)
+{
+
+ oct_write64(bsh + (offset << 3), value);
+}
+
+static void
+ou_bs_w_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value)
+{
+
+ oct_write64(bsh + (offset << 3), value);
+}
+
+static void
+ou_bs_w_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value)
+{
+
+ oct_write64(bsh + (offset << 3), value);
+}
+
+static void
+ou_bs_w_8(void *t, bus_space_handle_t bsh, bus_size_t offset, uint64_t value)
+{
+
+ oct_write64(bsh + (offset << 3), value);
+}
+
+static struct bus_space octeon_uart_tag = {
+ .bs_map = generic_bs_map,
+ .bs_unmap = generic_bs_unmap,
+ .bs_subregion = generic_bs_subregion,
+ .bs_barrier = generic_bs_barrier,
+ .bs_r_1 = ou_bs_r_1,
+ .bs_r_2 = ou_bs_r_2,
+ .bs_r_4 = ou_bs_r_4,
+ .bs_r_8 = ou_bs_r_8,
+ .bs_w_1 = ou_bs_w_1,
+ .bs_w_2 = ou_bs_w_2,
+ .bs_w_4 = ou_bs_w_4,
+ .bs_w_8 = ou_bs_w_8,
+};
+
+extern struct uart_class uart_oct16550_class;
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+
+ return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+ struct uart_class *class = &uart_oct16550_class;
+
+ /*
+ * These fields need to be setup corretly for uart_getenv to
+ * work in all cases.
+ */
+ uart_bus_space_io = NULL; /* No io map for this device */
+ uart_bus_space_mem = &octeon_uart_tag;
+ di->bas.bst = uart_bus_space_mem;
+
+ /*
+ * If env specification for UART exists it takes precedence:
+ * hw.uart.console="mm:0xf1012000" or similar
+ */
+ if (uart_getenv(devtype, di, class) == 0)
+ return (0);
+
+ /*
+ * Fallback to UART0 for console.
+ */
+ di->ops = uart_getops(class);
+ di->bas.chan = 0;
+ if (bus_space_map(di->bas.bst, OCTEON_UART0ADR, OCTEON_UART_SIZE,
+ 0, &di->bas.bsh) != 0)
+ return (ENXIO);
+ di->bas.regshft = 0;
+ di->bas.rclk = 0;
+ di->baudrate = 115200;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+
+ return (0);
+}
diff --git a/sys/mips/cavium/uart_dev_oct16550.c b/sys/mips/cavium/uart_dev_oct16550.c
new file mode 100644
index 0000000..3b96a68
--- /dev/null
+++ b/sys/mips/cavium/uart_dev_oct16550.c
@@ -0,0 +1,827 @@
+/*-
+ * Copyright (c) 2003 Marcel Moolenaar
+ * 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 ``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.
+ */
+
+/*
+ * uart_dev_oct16550.c
+ *
+ * Derived from uart_dev_ns8250.c
+ *
+ * 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 ``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.
+ *
+ *
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <machine/bus.h>
+#include <machine/pcpu.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+
+#include <dev/ic/ns16550.h>
+
+#include <mips/octeon1/octeon_pcmap_regs.h>
+
+#include "uart_if.h"
+
+/*
+ * Clear pending interrupts. THRE is cleared by reading IIR. Data
+ * that may have been received gets lost here.
+ */
+static void
+oct16550_clrint (struct uart_bas *bas)
+{
+ uint8_t iir;
+
+ iir = uart_getreg(bas, REG_IIR);
+ while ((iir & IIR_NOPEND) == 0) {
+ iir &= IIR_IMASK;
+ if (iir == IIR_RLS)
+ (void)uart_getreg(bas, REG_LSR);
+ else if (iir == IIR_RXRDY || iir == IIR_RXTOUT)
+ (void)uart_getreg(bas, REG_DATA);
+ else if (iir == IIR_MLSC)
+ (void)uart_getreg(bas, REG_MSR);
+ else if (iir == IIR_BUSY)
+ (void) uart_getreg(bas, REG_USR);
+ uart_barrier(bas);
+ iir = uart_getreg(bas, REG_IIR);
+ }
+}
+
+static int delay_changed = 1;
+
+static int
+oct16550_delay (struct uart_bas *bas)
+{
+ int divisor;
+ u_char lcr;
+ static int delay = 0;
+
+ if (!delay_changed) return delay;
+ delay_changed = 0;
+ lcr = uart_getreg(bas, REG_LCR);
+ uart_setreg(bas, REG_LCR, lcr | LCR_DLAB);
+ uart_barrier(bas);
+ divisor = uart_getreg(bas, REG_DLL) | (uart_getreg(bas, REG_DLH) << 8);
+ uart_barrier(bas);
+ uart_setreg(bas, REG_LCR, lcr);
+ uart_barrier(bas);
+
+ if(!bas->rclk)
+ return 10; /* return an approx delay value */
+
+ /* 1/10th the time to transmit 1 character (estimate). */
+ if (divisor <= 134)
+ return (16000000 * divisor / bas->rclk);
+ return (16000 * divisor / (bas->rclk / 1000));
+
+}
+
+static int
+oct16550_divisor (int rclk, int baudrate)
+{
+ int actual_baud, divisor;
+ int error;
+
+ if (baudrate == 0)
+ return (0);
+
+ divisor = (rclk / (baudrate << 3) + 1) >> 1;
+ if (divisor == 0 || divisor >= 65536)
+ return (0);
+ actual_baud = rclk / (divisor << 4);
+
+ /* 10 times error in percent: */
+ error = ((actual_baud - baudrate) * 2000 / baudrate + 1) >> 1;
+
+ /* 3.0% maximum error tolerance: */
+ if (error < -30 || error > 30)
+ return (0);
+
+ return (divisor);
+}
+
+static int
+oct16550_drain (struct uart_bas *bas, int what)
+{
+ int delay, limit;
+
+ delay = oct16550_delay(bas);
+
+ if (what & UART_DRAIN_TRANSMITTER) {
+ /*
+ * Pick an arbitrary high limit to avoid getting stuck in
+ * an infinite loop when the hardware is broken. Make the
+ * limit high enough to handle large FIFOs.
+ */
+ limit = 10*10*10*1024;
+ while ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0 && --limit)
+ DELAY(delay);
+ if (limit == 0) {
+ /* printf("oct16550: transmitter appears stuck... "); */
+ return (0);
+ }
+ }
+
+ if (what & UART_DRAIN_RECEIVER) {
+ /*
+ * Pick an arbitrary high limit to avoid getting stuck in
+ * an infinite loop when the hardware is broken. Make the
+ * limit high enough to handle large FIFOs and integrated
+ * UARTs. The HP rx2600 for example has 3 UARTs on the
+ * management board that tend to get a lot of data send
+ * to it when the UART is first activated.
+ */
+ limit=10*4096;
+ while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) && --limit) {
+ (void)uart_getreg(bas, REG_DATA);
+ uart_barrier(bas);
+ DELAY(delay << 2);
+ }
+ if (limit == 0) {
+ /* printf("oct16550: receiver appears broken... "); */
+ return (EIO);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * We can only flush UARTs with FIFOs. UARTs without FIFOs should be
+ * drained. WARNING: this function clobbers the FIFO setting!
+ */
+static void
+oct16550_flush (struct uart_bas *bas, int what)
+{
+ uint8_t fcr;
+
+ fcr = FCR_ENABLE;
+ if (what & UART_FLUSH_TRANSMITTER)
+ fcr |= FCR_XMT_RST;
+ if (what & UART_FLUSH_RECEIVER)
+ fcr |= FCR_RCV_RST;
+ uart_setreg(bas, REG_FCR, fcr);
+ uart_barrier(bas);
+}
+
+static int
+oct16550_param (struct uart_bas *bas, int baudrate, int databits, int stopbits,
+ int parity)
+{
+ int divisor;
+ uint8_t lcr;
+
+ lcr = 0;
+ if (databits >= 8)
+ lcr |= LCR_8BITS;
+ else if (databits == 7)
+ lcr |= LCR_7BITS;
+ else if (databits == 6)
+ lcr |= LCR_6BITS;
+ else
+ lcr |= LCR_5BITS;
+ if (stopbits > 1)
+ lcr |= LCR_STOPB;
+ lcr |= parity << 3;
+
+ /* Set baudrate. */
+ if (baudrate > 0) {
+ divisor = oct16550_divisor(bas->rclk, baudrate);
+ if (divisor == 0)
+ return (EINVAL);
+ uart_setreg(bas, REG_LCR, lcr | LCR_DLAB);
+ uart_barrier(bas);
+ uart_setreg(bas, REG_DLL, divisor & 0xff);
+ uart_setreg(bas, REG_DLH, (divisor >> 8) & 0xff);
+ uart_barrier(bas);
+ delay_changed = 1;
+ }
+
+ /* Set LCR and clear DLAB. */
+ uart_setreg(bas, REG_LCR, lcr);
+ uart_barrier(bas);
+ return (0);
+}
+
+/*
+ * Low-level UART interface.
+ */
+static int oct16550_probe(struct uart_bas *bas);
+static void oct16550_init(struct uart_bas *bas, int, int, int, int);
+static void oct16550_term(struct uart_bas *bas);
+static void oct16550_putc(struct uart_bas *bas, int);
+static int oct16550_rxready(struct uart_bas *bas);
+static int oct16550_getc(struct uart_bas *bas, struct mtx *);
+
+struct uart_ops uart_oct16550_ops = {
+ .probe = oct16550_probe,
+ .init = oct16550_init,
+ .term = oct16550_term,
+ .putc = oct16550_putc,
+ .rxready = oct16550_rxready,
+ .getc = oct16550_getc,
+};
+
+static int
+oct16550_probe (struct uart_bas *bas)
+{
+ u_char val;
+
+ /* Check known 0 bits that don't depend on DLAB. */
+ val = uart_getreg(bas, REG_IIR);
+ if (val & 0x30)
+ return (ENXIO);
+ val = uart_getreg(bas, REG_MCR);
+ if (val & 0xc0)
+ return (ENXIO);
+ val = uart_getreg(bas, REG_USR);
+ if (val & 0xe0)
+ return (ENXIO);
+ return (0);
+}
+
+static void
+oct16550_init (struct uart_bas *bas, int baudrate, int databits, int stopbits,
+ int parity)
+{
+ u_char ier;
+
+ oct16550_param(bas, baudrate, databits, stopbits, parity);
+
+ /* Disable all interrupt sources. */
+ ier = uart_getreg(bas, REG_IER) & 0x0;
+ uart_setreg(bas, REG_IER, ier);
+ uart_barrier(bas);
+
+ /* Disable the FIFO (if present). */
+// uart_setreg(bas, REG_FCR, 0);
+ uart_barrier(bas);
+
+ /* Set RTS & DTR. */
+ uart_setreg(bas, REG_MCR, MCR_RTS | MCR_DTR);
+ uart_barrier(bas);
+
+ oct16550_clrint(bas);
+}
+
+static void
+oct16550_term (struct uart_bas *bas)
+{
+
+ /* Clear RTS & DTR. */
+ uart_setreg(bas, REG_MCR, 0);
+ uart_barrier(bas);
+}
+
+static inline void oct16550_wait_txhr_empty (struct uart_bas *bas, int limit, int delay)
+{
+ while (((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0) &&
+ ((uart_getreg(bas, REG_USR) & USR_TXFIFO_NOTFULL) == 0))
+ DELAY(delay);
+}
+
+static void
+oct16550_putc (struct uart_bas *bas, int c)
+{
+ int delay;
+
+ /* 1/10th the time to transmit 1 character (estimate). */
+ delay = oct16550_delay(bas);
+ oct16550_wait_txhr_empty(bas, 100, delay);
+ uart_setreg(bas, REG_DATA, c);
+ uart_barrier(bas);
+ oct16550_wait_txhr_empty(bas, 100, delay);
+}
+
+static int
+oct16550_rxready (struct uart_bas *bas)
+{
+
+ return ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) != 0 ? 1 : 0);
+}
+
+static int
+oct16550_getc (struct uart_bas *bas, struct mtx *hwmtx)
+{
+ int c, delay;
+
+ uart_lock(hwmtx);
+
+ /* 1/10th the time to transmit 1 character (estimate). */
+ delay = oct16550_delay(bas);
+
+ while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) == 0) {
+ uart_unlock(hwmtx);
+ DELAY(delay);
+ uart_lock(hwmtx);
+ }
+
+ c = uart_getreg(bas, REG_DATA);
+
+ uart_unlock(hwmtx);
+
+ return (c);
+}
+
+/*
+ * High-level UART interface.
+ */
+struct oct16550_softc {
+ struct uart_softc base;
+ uint8_t fcr;
+ uint8_t ier;
+ uint8_t mcr;
+};
+
+static int oct16550_bus_attach(struct uart_softc *);
+static int oct16550_bus_detach(struct uart_softc *);
+static int oct16550_bus_flush(struct uart_softc *, int);
+static int oct16550_bus_getsig(struct uart_softc *);
+static int oct16550_bus_ioctl(struct uart_softc *, int, intptr_t);
+static int oct16550_bus_ipend(struct uart_softc *);
+static int oct16550_bus_param(struct uart_softc *, int, int, int, int);
+static int oct16550_bus_probe(struct uart_softc *);
+static int oct16550_bus_receive(struct uart_softc *);
+static int oct16550_bus_setsig(struct uart_softc *, int);
+static int oct16550_bus_transmit(struct uart_softc *);
+
+static kobj_method_t oct16550_methods[] = {
+ KOBJMETHOD(uart_attach, oct16550_bus_attach),
+ KOBJMETHOD(uart_detach, oct16550_bus_detach),
+ KOBJMETHOD(uart_flush, oct16550_bus_flush),
+ KOBJMETHOD(uart_getsig, oct16550_bus_getsig),
+ KOBJMETHOD(uart_ioctl, oct16550_bus_ioctl),
+ KOBJMETHOD(uart_ipend, oct16550_bus_ipend),
+ KOBJMETHOD(uart_param, oct16550_bus_param),
+ KOBJMETHOD(uart_probe, oct16550_bus_probe),
+ KOBJMETHOD(uart_receive, oct16550_bus_receive),
+ KOBJMETHOD(uart_setsig, oct16550_bus_setsig),
+ KOBJMETHOD(uart_transmit, oct16550_bus_transmit),
+ { 0, 0 }
+};
+
+struct uart_class uart_oct16550_class = {
+ "oct16550 class",
+ oct16550_methods,
+ sizeof(struct oct16550_softc),
+ .uc_ops = &uart_oct16550_ops,
+ .uc_range = 8,
+ .uc_rclk = 0
+};
+
+#define SIGCHG(c, i, s, d) \
+ if (c) { \
+ i |= (i & s) ? s : s | d; \
+ } else { \
+ i = (i & s) ? (i & ~s) | d : i; \
+ }
+
+static int
+oct16550_bus_attach (struct uart_softc *sc)
+{
+ struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc;
+ struct uart_bas *bas;
+ int unit;
+
+ unit = device_get_unit(sc->sc_dev);
+ bas = &sc->sc_bas;
+
+ oct16550_drain(bas, UART_DRAIN_TRANSMITTER);
+ oct16550->mcr = uart_getreg(bas, REG_MCR);
+ oct16550->fcr = FCR_ENABLE | FCR_RX_HIGH;
+ uart_setreg(bas, REG_FCR, oct16550->fcr);
+ uart_barrier(bas);
+ oct16550_bus_flush(sc, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER);
+
+ if (oct16550->mcr & MCR_DTR)
+ sc->sc_hwsig |= SER_DTR;
+ if (oct16550->mcr & MCR_RTS)
+ sc->sc_hwsig |= SER_RTS;
+ oct16550_bus_getsig(sc);
+
+ oct16550_clrint(bas);
+ oct16550->ier = uart_getreg(bas, REG_IER) & 0xf0;
+ oct16550->ier |= IER_EMSC | IER_ERLS | IER_ERXRDY;
+ uart_setreg(bas, REG_IER, oct16550->ier);
+ uart_barrier(bas);
+
+ uint32_t status_bits = mips_rd_status();
+ mips_wr_status(status_bits & ~MIPS_SR_INT_IE);
+ /*
+ * Enable the interrupt in CIU. // UART-x2 @ IP2
+ */
+ ciu_enable_interrupts(0, CIU_INT_0, CIU_EN_0,
+ (!unit) ? CIU_UART_BITS_UART0 : CIU_UART_BITS_UART1, CIU_MIPS_IP2);
+ return (0);
+}
+
+static int
+oct16550_bus_detach (struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ u_char ier;
+
+ bas = &sc->sc_bas;
+ ier = uart_getreg(bas, REG_IER) & 0xf0;
+ uart_setreg(bas, REG_IER, ier);
+ uart_barrier(bas);
+ oct16550_clrint(bas);
+ return (0);
+}
+
+static int
+oct16550_bus_flush (struct uart_softc *sc, int what)
+{
+ struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc;
+ struct uart_bas *bas;
+ int error;
+
+ bas = &sc->sc_bas;
+ uart_lock(sc->sc_hwmtx);
+ if (sc->sc_rxfifosz > 1) {
+ oct16550_flush(bas, what);
+ uart_setreg(bas, REG_FCR, oct16550->fcr);
+ uart_barrier(bas);
+ error = 0;
+ } else
+ error = oct16550_drain(bas, what);
+ uart_unlock(sc->sc_hwmtx);
+ return (error);
+}
+
+static int
+oct16550_bus_getsig (struct uart_softc *sc)
+{
+ uint32_t new, old, sig;
+ uint8_t msr;
+
+ do {
+ old = sc->sc_hwsig;
+ sig = old;
+ uart_lock(sc->sc_hwmtx);
+ msr = uart_getreg(&sc->sc_bas, REG_MSR);
+ uart_unlock(sc->sc_hwmtx);
+ SIGCHG(msr & MSR_DSR, sig, SER_DSR, SER_DDSR);
+ SIGCHG(msr & MSR_CTS, sig, SER_CTS, SER_DCTS);
+ SIGCHG(msr & MSR_DCD, sig, SER_DCD, SER_DDCD);
+ SIGCHG(msr & MSR_RI, sig, SER_RI, SER_DRI);
+ new = sig & ~SER_MASK_DELTA;
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+ return (sig);
+}
+
+static int
+oct16550_bus_ioctl (struct uart_softc *sc, int request, intptr_t data)
+{
+ struct uart_bas *bas;
+ int baudrate, divisor, error;
+ uint8_t efr, lcr;
+
+ bas = &sc->sc_bas;
+ error = 0;
+ uart_lock(sc->sc_hwmtx);
+ switch (request) {
+ case UART_IOCTL_BREAK:
+ lcr = uart_getreg(bas, REG_LCR);
+ if (data)
+ lcr |= LCR_SBREAK;
+ else
+ lcr &= ~LCR_SBREAK;
+ uart_setreg(bas, REG_LCR, lcr);
+ uart_barrier(bas);
+ break;
+ case UART_IOCTL_IFLOW:
+ lcr = uart_getreg(bas, REG_LCR);
+ uart_barrier(bas);
+ uart_setreg(bas, REG_LCR, 0xbf);
+ uart_barrier(bas);
+ efr = uart_getreg(bas, REG_EFR);
+ if (data)
+ efr |= EFR_RTS;
+ else
+ efr &= ~EFR_RTS;
+ uart_setreg(bas, REG_EFR, efr);
+ uart_barrier(bas);
+ uart_setreg(bas, REG_LCR, lcr);
+ uart_barrier(bas);
+ break;
+ case UART_IOCTL_OFLOW:
+ lcr = uart_getreg(bas, REG_LCR);
+ uart_barrier(bas);
+ uart_setreg(bas, REG_LCR, 0xbf);
+ uart_barrier(bas);
+ efr = uart_getreg(bas, REG_EFR);
+ if (data)
+ efr |= EFR_CTS;
+ else
+ efr &= ~EFR_CTS;
+ uart_setreg(bas, REG_EFR, efr);
+ uart_barrier(bas);
+ uart_setreg(bas, REG_LCR, lcr);
+ uart_barrier(bas);
+ break;
+ case UART_IOCTL_BAUD:
+ lcr = uart_getreg(bas, REG_LCR);
+ uart_setreg(bas, REG_LCR, lcr | LCR_DLAB);
+ uart_barrier(bas);
+ divisor = uart_getreg(bas, REG_DLL) |
+ (uart_getreg(bas, REG_DLH) << 8);
+ uart_barrier(bas);
+ uart_setreg(bas, REG_LCR, lcr);
+ uart_barrier(bas);
+ baudrate = (divisor > 0) ? bas->rclk / divisor / 16 : 0;
+ delay_changed = 1;
+ if (baudrate > 0)
+ *(int*)data = baudrate;
+ else
+ error = ENXIO;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ uart_unlock(sc->sc_hwmtx);
+ return (error);
+}
+
+
+static int
+oct16550_bus_ipend(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int ipend = 0;
+ uint8_t iir, lsr;
+
+ bas = &sc->sc_bas;
+ uart_lock(sc->sc_hwmtx);
+
+ iir = uart_getreg(bas, REG_IIR) & IIR_IMASK;
+ if (iir != IIR_NOPEND) {
+
+ if (iir == IIR_RLS) {
+ lsr = uart_getreg(bas, REG_LSR);
+ if (lsr & LSR_OE)
+ ipend |= SER_INT_OVERRUN;
+ if (lsr & LSR_BI)
+ ipend |= SER_INT_BREAK;
+ if (lsr & LSR_RXRDY)
+ ipend |= SER_INT_RXREADY;
+
+ } else if (iir == IIR_RXRDY) {
+ ipend |= SER_INT_RXREADY;
+
+ } else if (iir == IIR_RXTOUT) {
+ ipend |= SER_INT_RXREADY;
+
+ } else if (iir == IIR_TXRDY) {
+ ipend |= SER_INT_TXIDLE;
+
+ } else if (iir == IIR_MLSC) {
+ ipend |= SER_INT_SIGCHG;
+
+ } else if (iir == IIR_BUSY) {
+ (void) uart_getreg(bas, REG_USR);
+ }
+ }
+ uart_unlock(sc->sc_hwmtx);
+
+//#define OCTEON_VISUAL_UART 1
+#ifdef OCTEON_VISUAL_UART
+ static int where1 = 0;
+
+ if (ipend) octeon_led_run_wheel(&where1, 6 + device_get_unit(sc->sc_dev));
+#endif
+
+ return ((sc->sc_leaving) ? 0 : ipend);
+}
+
+
+
+
+static int
+oct16550_bus_param (struct uart_softc *sc, int baudrate, int databits,
+ int stopbits, int parity)
+{
+ struct uart_bas *bas;
+ int error;
+
+ bas = &sc->sc_bas;
+ uart_lock(sc->sc_hwmtx);
+ error = oct16550_param(bas, baudrate, databits, stopbits, parity);
+ uart_unlock(sc->sc_hwmtx);
+ return (error);
+}
+
+static int
+oct16550_bus_probe (struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int error;
+
+ bas = &sc->sc_bas;
+ bas->rclk = uart_oct16550_class.uc_rclk = octeon_cpu_clock;
+
+ error = oct16550_probe(bas);
+ if (error) {
+ return (error);
+ }
+
+ uart_setreg(bas, REG_MCR, (MCR_DTR | MCR_RTS));
+
+ /*
+ * Enable FIFOs. And check that the UART has them. If not, we're
+ * done. Since this is the first time we enable the FIFOs, we reset
+ * them.
+ */
+ oct16550_drain(bas, UART_DRAIN_TRANSMITTER);
+#define ENABLE_OCTEON_FIFO 1
+#ifdef ENABLE_OCTEON_FIFO
+ uart_setreg(bas, REG_FCR, FCR_ENABLE | FCR_XMT_RST | FCR_RCV_RST);
+#endif
+ uart_barrier(bas);
+
+ oct16550_flush(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER);
+
+ if (device_get_unit(sc->sc_dev)) {
+ device_set_desc(sc->sc_dev, "Octeon-16550 channel 1");
+ } else {
+ device_set_desc(sc->sc_dev, "Octeon-16550 channel 0");
+ }
+#ifdef ENABLE_OCTEON_FIFO
+ sc->sc_rxfifosz = 64;
+ sc->sc_txfifosz = 64;
+#else
+ sc->sc_rxfifosz = 1;
+ sc->sc_txfifosz = 1;
+#endif
+
+
+#if 0
+ /*
+ * XXX there are some issues related to hardware flow control and
+ * it's likely that uart(4) is the cause. This basicly needs more
+ * investigation, but we avoid using for hardware flow control
+ * until then.
+ */
+ /* 16650s or higher have automatic flow control. */
+ if (sc->sc_rxfifosz > 16) {
+ sc->sc_hwiflow = 1;
+ sc->sc_hwoflow = 1;
+ }
+#endif
+
+ return (0);
+}
+
+static int
+oct16550_bus_receive (struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int xc;
+ uint8_t lsr;
+
+ bas = &sc->sc_bas;
+ uart_lock(sc->sc_hwmtx);
+ lsr = uart_getreg(bas, REG_LSR);
+
+ while (lsr & LSR_RXRDY) {
+ if (uart_rx_full(sc)) {
+ sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
+ break;
+ }
+ xc = uart_getreg(bas, REG_DATA);
+ if (lsr & LSR_FE)
+ xc |= UART_STAT_FRAMERR;
+ if (lsr & LSR_PE)
+ xc |= UART_STAT_PARERR;
+ uart_rx_put(sc, xc);
+ lsr = uart_getreg(bas, REG_LSR);
+ }
+ /* Discard everything left in the Rx FIFO. */
+ /*
+ * First do a dummy read/discard anyway, in case the UART was lying to us.
+ * This problem was seen on board, when IIR said RBR, but LSR said no RXRDY
+ * Results in a stuck ipend loop.
+ */
+ (void)uart_getreg(bas, REG_DATA);
+ while (lsr & LSR_RXRDY) {
+ (void)uart_getreg(bas, REG_DATA);
+ uart_barrier(bas);
+ lsr = uart_getreg(bas, REG_LSR);
+ }
+ uart_unlock(sc->sc_hwmtx);
+ return (0);
+}
+
+static int
+oct16550_bus_setsig (struct uart_softc *sc, int sig)
+{
+ struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc;
+ struct uart_bas *bas;
+ uint32_t new, old;
+
+ bas = &sc->sc_bas;
+ do {
+ old = sc->sc_hwsig;
+ new = old;
+ if (sig & SER_DDTR) {
+ SIGCHG(sig & SER_DTR, new, SER_DTR,
+ SER_DDTR);
+ }
+ if (sig & SER_DRTS) {
+ SIGCHG(sig & SER_RTS, new, SER_RTS,
+ SER_DRTS);
+ }
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+ uart_lock(sc->sc_hwmtx);
+ oct16550->mcr &= ~(MCR_DTR|MCR_RTS);
+ if (new & SER_DTR)
+ oct16550->mcr |= MCR_DTR;
+ if (new & SER_RTS)
+ oct16550->mcr |= MCR_RTS;
+ uart_setreg(bas, REG_MCR, oct16550->mcr);
+ uart_barrier(bas);
+ uart_unlock(sc->sc_hwmtx);
+ return (0);
+}
+
+static int
+oct16550_bus_transmit (struct uart_softc *sc)
+{
+ struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc;
+ struct uart_bas *bas;
+ int i;
+
+ bas = &sc->sc_bas;
+ uart_lock(sc->sc_hwmtx);
+#ifdef NO_UART_INTERRUPTS
+ for (i = 0; i < sc->sc_txdatasz; i++) {
+ oct16550_putc(bas, sc->sc_txbuf[i]);
+ }
+#else
+
+ oct16550_wait_txhr_empty(bas, 100, oct16550_delay(bas));
+ uart_setreg(bas, REG_IER, oct16550->ier | IER_ETXRDY);
+ uart_barrier(bas);
+
+ for (i = 0; i < sc->sc_txdatasz; i++) {
+ uart_setreg(bas, REG_DATA, sc->sc_txbuf[i]);
+ uart_barrier(bas);
+ }
+ sc->sc_txbusy = 1;
+#endif
+ uart_unlock(sc->sc_hwmtx);
+ return (0);
+}
OpenPOWER on IntegriCloud