summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/mips/mips/bus_space_generic.c8
-rw-r--r--sys/mips/sibyte/sb_asm.S5
-rw-r--r--sys/mips/sibyte/sb_bus_space.h43
-rw-r--r--sys/mips/sibyte/sb_zbpci.c157
4 files changed, 205 insertions, 8 deletions
diff --git a/sys/mips/mips/bus_space_generic.c b/sys/mips/mips/bus_space_generic.c
index 15780a2..b934ec4 100644
--- a/sys/mips/mips/bus_space_generic.c
+++ b/sys/mips/mips/bus_space_generic.c
@@ -206,6 +206,14 @@ static struct bus_space generic_space = {
#define wr8(a, v) oct_write8(a, v)
#define wr16(a, v) oct_write16(a, v)
#define wr32(a, v) oct_write32(a, v)
+#elif defined(CPU_SB1) && _BYTE_ORDER == _BIG_ENDIAN
+#include <mips/sibyte/sb_bus_space.h>
+#define rd8(a) sb_big_endian_read8(a)
+#define rd16(a) sb_big_endian_read16(a)
+#define rd32(a) sb_big_endian_read32(a)
+#define wr8(a, v) sb_big_endian_write8(a, v)
+#define wr16(a, v) sb_big_endian_write16(a, v)
+#define wr32(a, v) sb_big_endian_write32(a, v)
#else
#define rd8(a) readb(a)
#define rd16(a) readw(a)
diff --git a/sys/mips/sibyte/sb_asm.S b/sys/mips/sibyte/sb_asm.S
index 19d00dd..a822d79 100644
--- a/sys/mips/sibyte/sb_asm.S
+++ b/sys/mips/sibyte/sb_asm.S
@@ -28,6 +28,7 @@
#include <machine/asm.h>
#include <machine/cpuregs.h>
+#include <machine/endian.h>
/*
* We compile a 32-bit kernel to run on the SB-1 processor which is a 64-bit
@@ -50,7 +51,7 @@
LEAF(sb_load64)
ld v1, 0(a0) /* result = *(uint64_t *)ptr */
move v0, v1
-#if defined(TARGET_BIG_ENDIAN)
+#if _BYTE_ORDER == _BIG_ENDIAN
dsll32 v1, v1, 0
dsrl32 v1, v1, 0 /* v1 = lower_uint32(result) */
jr ra
@@ -68,7 +69,7 @@ END(sb_load64)
* Return value: void
*/
LEAF(sb_store64)
-#if defined(TARGET_BIG_ENDIAN)
+#if _BYTE_ORDER == _BIG_ENDIAN
dsll32 a2, a2, 0 /* a2 = upper_uint32(val) */
dsll32 a3, a3, 0 /* a3 = lower_uint32(val) */
dsrl32 a3, a3, 0
diff --git a/sys/mips/sibyte/sb_bus_space.h b/sys/mips/sibyte/sb_bus_space.h
new file mode 100644
index 0000000..f3364f0
--- /dev/null
+++ b/sys/mips/sibyte/sb_bus_space.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2010 Neelkanth Natu
+ * 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$
+ */
+
+#ifndef _SB_BUS_SPACE_H_
+#define _SB_BUS_SPACE_H_
+
+#include <machine/endian.h>
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+uint8_t sb_big_endian_read8(bus_addr_t addr);
+uint16_t sb_big_endian_read16(bus_addr_t addr);
+uint32_t sb_big_endian_read32(bus_addr_t addr);
+void sb_big_endian_write8(bus_addr_t addr, uint8_t val);
+void sb_big_endian_write16(bus_addr_t addr, uint16_t val);
+void sb_big_endian_write32(bus_addr_t addr, uint32_t val);
+#endif
+
+#endif
diff --git a/sys/mips/sibyte/sb_zbpci.c b/sys/mips/sibyte/sb_zbpci.c
index 6107b36..42fed5e 100644
--- a/sys/mips/sibyte/sb_zbpci.c
+++ b/sys/mips/sibyte/sb_zbpci.c
@@ -50,6 +50,7 @@
#include "pcib_if.h"
+#include "sb_bus_space.h"
#include "sb_scd.h"
__FBSDID("$FreeBSD$");
@@ -63,6 +64,15 @@ static const vm_paddr_t CFG_PADDR_BASE = 0xFE000000;
static const u_long PCI_IOSPACE_ADDR = 0xFC000000;
static const u_long PCI_IOSPACE_SIZE = 0x02000000;
+#define PCI_MATCH_BYTE_LANES_START 0x40000000
+#define PCI_MATCH_BYTE_LANES_END 0x5FFFFFFF
+#define PCI_MATCH_BYTE_LANES_SIZE 0x20000000
+
+#define PCI_MATCH_BIT_LANES_MASK (1 << 29)
+#define PCI_MATCH_BIT_LANES_START 0x60000000
+#define PCI_MATCH_BIT_LANES_END 0x7FFFFFFF
+#define PCI_MATCH_BIT_LANES_SIZE 0x20000000
+
static struct rman port_rman;
static int
@@ -112,6 +122,19 @@ zbpci_attach(device_t dev)
panic("Cannot allocate resource for config space accesses.");
/*
+ * Allocate the entire "match bit lanes" address space.
+ */
+#if _BYTE_ORDER == _BIG_ENDIAN
+ rid = 2;
+ res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ PCI_MATCH_BIT_LANES_START,
+ PCI_MATCH_BIT_LANES_END,
+ PCI_MATCH_BIT_LANES_SIZE, 0);
+ if (res == NULL)
+ panic("Cannot allocate resource for pci match bit lanes.");
+#endif /* _BYTE_ORDER ==_BIG_ENDIAN */
+
+ /*
* Allocate KVA for accessing PCI config space.
*/
va = kmem_alloc_nofault(kernel_map, PAGE_SIZE * mp_ncpus);
@@ -177,21 +200,61 @@ static int
zbpci_activate_resource(device_t bus, device_t child, int type, int rid,
struct resource *res)
{
+ int error;
void *vaddr;
- u_long paddr, psize;
+ u_long orig_paddr, paddr, psize;
+
+ paddr = rman_get_start(res);
+ psize = rman_get_size(res);
+ orig_paddr = paddr;
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+ /*
+ * The CFE allocates PCI memory resources that map to the
+ * "match byte lanes" address space. This address space works
+ * best for DMA transfers because it does not do any automatic
+ * byte swaps when data crosses the pci-cpu interface.
+ *
+ * This also makes it sub-optimal for accesses to PCI device
+ * registers because it exposes the little-endian nature of
+ * the PCI bus to the big-endian CPU. The Sibyte has another
+ * address window called the "match bit lanes" window which
+ * automatically swaps bytes when data crosses the pci-cpu
+ * interface.
+ *
+ * We "assume" that any bus_space memory accesses done by the
+ * CPU to a PCI device are register/configuration accesses and
+ * are done through the "match bit lanes" window. Any DMA
+ * transfers will continue to be through the "match byte lanes"
+ * window because the PCI BAR registers will not be changed.
+ */
+ if (type == SYS_RES_MEMORY) {
+ if (paddr >= PCI_MATCH_BYTE_LANES_START &&
+ paddr + psize - 1 <= PCI_MATCH_BYTE_LANES_END) {
+ paddr |= PCI_MATCH_BIT_LANES_MASK;
+ rman_set_start(res, paddr);
+ rman_set_end(res, paddr + psize - 1);
+ }
+ }
+#endif
if (type != SYS_RES_IOPORT) {
- return (bus_generic_activate_resource(bus, child, type,
- rid, res));
+ error = bus_generic_activate_resource(bus, child, type,
+ rid, res);
+#if _BYTE_ORDER == _BIG_ENDIAN
+ if (type == SYS_RES_MEMORY) {
+ rman_set_start(res, orig_paddr);
+ rman_set_end(res, orig_paddr + psize - 1);
+ }
+#endif
+ return (error);
}
/*
* Map the I/O space resource through the memory window starting
* at PCI_IOSPACE_ADDR.
*/
- paddr = rman_get_start(res) + PCI_IOSPACE_ADDR;
- psize = rman_get_size(res);
- vaddr = pmap_mapdev(paddr, psize);
+ vaddr = pmap_mapdev(paddr + PCI_IOSPACE_ADDR, psize);
rman_set_virtual(res, vaddr);
rman_set_bustag(res, mips_bus_space_generic);
@@ -280,6 +343,9 @@ zbpci_config_space_va(int bus, int slot, int func, int reg, int bytes)
va_page = zbpci_config_space[cpu].vaddr;
pa = CFG_PADDR_BASE |
(bus << 16) | (slot << 11) | (func << 8) | reg;
+#if _BYTE_ORDER == _BIG_ENDIAN
+ pa = pa ^ (4 - bytes);
+#endif
pa_page = pa & ~(PAGE_SIZE - 1);
if (zbpci_config_space[cpu].paddr != pa_page) {
pmap_kremove(va_page);
@@ -397,3 +463,82 @@ DEFINE_CLASS_1(zbpci, zbpci_driver, zbpci_methods, 0, pcib_driver);
static devclass_t zbpci_devclass;
DRIVER_MODULE(zbpci, zbbus, zbpci_driver, zbpci_devclass, 0, 0);
+
+/*
+ * Big endian bus space routines
+ */
+#if _BYTE_ORDER == _BIG_ENDIAN
+
+/*
+ * The CPU correctly deals with the big-endian to little-endian swap if
+ * we are accessing 4 bytes at a time. However if we want to read 1 or 2
+ * bytes then we need to fudge the address generated by the CPU such that
+ * it generates the right byte enables on the PCI bus.
+ */
+static bus_addr_t
+sb_match_bit_lane_addr(bus_addr_t addr, int bytes)
+{
+ vm_offset_t pa;
+
+ pa = vtophys(addr);
+
+ if (pa >= PCI_MATCH_BIT_LANES_START && pa <= PCI_MATCH_BIT_LANES_END)
+ return (addr ^ (4 - bytes));
+ else
+ return (addr);
+}
+
+uint8_t
+sb_big_endian_read8(bus_addr_t addr)
+{
+ bus_addr_t addr2;
+
+ addr2 = sb_match_bit_lane_addr(addr, 1);
+ return (readb(addr2));
+}
+
+uint16_t
+sb_big_endian_read16(bus_addr_t addr)
+{
+ bus_addr_t addr2;
+
+ addr2 = sb_match_bit_lane_addr(addr, 2);
+ return (readw(addr2));
+}
+
+uint32_t
+sb_big_endian_read32(bus_addr_t addr)
+{
+ bus_addr_t addr2;
+
+ addr2 = sb_match_bit_lane_addr(addr, 4);
+ return (readl(addr2));
+}
+
+void
+sb_big_endian_write8(bus_addr_t addr, uint8_t val)
+{
+ bus_addr_t addr2;
+
+ addr2 = sb_match_bit_lane_addr(addr, 1);
+ writeb(addr2, val);
+}
+
+void
+sb_big_endian_write16(bus_addr_t addr, uint16_t val)
+{
+ bus_addr_t addr2;
+
+ addr2 = sb_match_bit_lane_addr(addr, 2);
+ writew(addr2, val);
+}
+
+void
+sb_big_endian_write32(bus_addr_t addr, uint32_t val)
+{
+ bus_addr_t addr2;
+
+ addr2 = sb_match_bit_lane_addr(addr, 4);
+ writel(addr2, val);
+}
+#endif /* _BIG_ENDIAN */
OpenPOWER on IntegriCloud