svn commit: r203985 - in head/sys/mips: mips sibyte

Neel Natu neel at FreeBSD.org
Wed Feb 17 06:43:38 UTC 2010


Author: neel
Date: Wed Feb 17 06:43:37 2010
New Revision: 203985
URL: http://svn.freebsd.org/changeset/base/203985

Log:
  Various fixes to get the SWARM config working on a big-endian Sibyte CPU.
  
  Getting the little-endian PCI bus working on the big-endian CPU proved to be
  quite challenging. We let the PCI devices be mapped in the "match byte lanes"
  address window. This is where they are mapped by the CFE and DMA transfers
  generated to or from addresses within this window are not subject to automatic
  byte-swapping.
  
  However any access by the driver to memory-mapped pci space is redirected
  via the "match bit lanes" address window. We get the benefit of automatic
  byte swapping through this address window and drivers don't need to change
  to deal with CPU big-endianness.

Added:
  head/sys/mips/sibyte/sb_bus_space.h   (contents, props changed)
Modified:
  head/sys/mips/mips/bus_space_generic.c
  head/sys/mips/sibyte/sb_asm.S
  head/sys/mips/sibyte/sb_zbpci.c

Modified: head/sys/mips/mips/bus_space_generic.c
==============================================================================
--- head/sys/mips/mips/bus_space_generic.c	Wed Feb 17 06:11:05 2010	(r203984)
+++ head/sys/mips/mips/bus_space_generic.c	Wed Feb 17 06:43:37 2010	(r203985)
@@ -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)

Modified: head/sys/mips/sibyte/sb_asm.S
==============================================================================
--- head/sys/mips/sibyte/sb_asm.S	Wed Feb 17 06:11:05 2010	(r203984)
+++ head/sys/mips/sibyte/sb_asm.S	Wed Feb 17 06:43:37 2010	(r203985)
@@ -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

Added: head/sys/mips/sibyte/sb_bus_space.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/sibyte/sb_bus_space.h	Wed Feb 17 06:43:37 2010	(r203985)
@@ -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

Modified: head/sys/mips/sibyte/sb_zbpci.c
==============================================================================
--- head/sys/mips/sibyte/sb_zbpci.c	Wed Feb 17 06:11:05 2010	(r203984)
+++ head/sys/mips/sibyte/sb_zbpci.c	Wed Feb 17 06:43:37 2010	(r203985)
@@ -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 =
 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,
 		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, zbpc
 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 */


More information about the svn-src-head mailing list