summaryrefslogtreecommitdiffstats
path: root/sys/powerpc/ofw
diff options
context:
space:
mode:
authorandreast <andreast@FreeBSD.org>2013-12-11 22:36:20 +0000
committerandreast <andreast@FreeBSD.org>2013-12-11 22:36:20 +0000
commit66bcaa96d680466f9c02406d1c9c6f6fa8147efe (patch)
tree451f1ba31330be9c8b1f330dff4460957da82a74 /sys/powerpc/ofw
parent50221324bd40404e88dea60c7f368087bdd21a77 (diff)
downloadFreeBSD-src-66bcaa96d680466f9c02406d1c9c6f6fa8147efe.zip
FreeBSD-src-66bcaa96d680466f9c02406d1c9c6f6fa8147efe.tar.gz
MFC r257991, r257992, 257993, 258504
r257991: Consolidate Apple firmware hacks and improve them by switching on the presence of mac-io devices in the tree, which uniquely identifies Apple hardware. r257992: Allow OF_decode_addr() to also be able to map resources on big-endian devices. To this end, make PCI device detection rely on the device_type field rather than name, as per the standard. r257993: Make tsec work with the device tree present on the RB800. The previous code assumed that the MDIO bus was a direct child of the Ethernet interface. It may not be and indeed on many device trees is not. While here, add proper locking for MII transactions, which may be on a bus shared by several MACs. r258504: Save and restore the trap vectors when doing OF calls on pSeries machines. It turned out that on pSeries machines the call into OF modified the trap vectors and this made further behaviour unpredictable. With this commit I'm now able to boot multi user on a network booted environment on my IntelliStation 285. This is a POWER5+ machine.
Diffstat (limited to 'sys/powerpc/ofw')
-rw-r--r--sys/powerpc/ofw/ofw_machdep.c77
1 files changed, 63 insertions, 14 deletions
diff --git a/sys/powerpc/ofw/ofw_machdep.c b/sys/powerpc/ofw/ofw_machdep.c
index 8165515..4969ec0 100644
--- a/sys/powerpc/ofw/ofw_machdep.c
+++ b/sys/powerpc/ofw/ofw_machdep.c
@@ -59,18 +59,43 @@ __FBSDID("$FreeBSD$");
#include <machine/md_var.h>
#include <machine/platform.h>
#include <machine/ofw_machdep.h>
+#include <machine/trap.h>
static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ];
static struct mem_region OFfree[PHYS_AVAIL_SZ];
+static int apple_hacks;
+
+#ifdef AIM
extern register_t ofmsr[5];
extern void *openfirmware_entry;
static void *fdt;
int ofw_real_mode;
+extern char save_trap_init[0x2f00]; /* EXC_LAST */
+char save_trap_of[0x2f00]; /* EXC_LAST */
int ofwcall(void *);
static int openfirmware(void *args);
+__inline void
+ofw_save_trap_vec(char *save_trap_vec)
+{
+ if (apple_hacks)
+ return;
+
+ bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST);
+}
+
+static __inline void
+ofw_restore_trap_vec(char *restore_trap_vec)
+{
+ if (apple_hacks)
+ return;
+
+ bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST);
+ __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD);
+}
+
/*
* Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
*/
@@ -79,6 +104,9 @@ register_t ofw_sprg0_save;
static __inline void
ofw_sprg_prepare(void)
{
+ if (!apple_hacks)
+ return;
+
/*
* Assume that interrupt are disabled at this point, or
* SPRG1-3 could be trashed
@@ -98,6 +126,9 @@ ofw_sprg_prepare(void)
static __inline void
ofw_sprg_restore(void)
{
+ if (!apple_hacks)
+ return;
+
/*
* Note that SPRG1-3 contents are irrelevant. They are scratch
* registers used in the early portion of trap handling when
@@ -107,6 +138,7 @@ ofw_sprg_restore(void)
*/
__asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
}
+#endif
/*
* Memory region utilities: determine if two regions overlap,
@@ -178,15 +210,10 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
/*
* On Apple hardware, address_cells is always 1 for "available",
- * even when it is explicitly set to 2. Then all memory above 4 GB
- * should be added by hand to the available list. Detect Apple hardware
- * by seeing if ofw_real_mode is set -- only Apple seems to use
- * virtual-mode OF.
+ * even when it is explicitly set to 2. All memory above 4 GB
+ * also needs to be added by hand to the available list.
*/
- if (strcmp(prop, "available") == 0 && !ofw_real_mode)
- apple_hack_mode = 1;
-
- if (apple_hack_mode)
+ if (strcmp(prop, "available") == 0 && apple_hacks)
address_cells = 1;
/*
@@ -241,7 +268,7 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
sz = j*sizeof(output[0]);
#ifdef __powerpc64__
- if (apple_hack_mode) {
+ if (strcmp(prop, "available") == 0 && apple_hacks) {
/* Add in regions above 4 GB to the available list */
struct mem_region himem[16];
int hisz;
@@ -435,6 +462,7 @@ ofw_mem_regions(struct mem_region **memp, int *memsz,
*availsz = fsz;
}
+#ifdef AIM
void
OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
{
@@ -481,6 +509,9 @@ OF_bootstrap()
OF_init(fdt);
}
+ /* Apple firmware has some bugs. Check for a "mac-io" alias. */
+ apple_hacks = (OF_finddevice("mac-io") != -1) ? 1 : 0;
+
return (status);
}
@@ -516,6 +547,12 @@ openfirmware_core(void *args)
ofw_sprg_prepare();
+ /* Save trap vectors */
+ ofw_save_trap_vec(save_trap_of);
+
+ /* Restore initially saved trap vectors */
+ ofw_restore_trap_vec(save_trap_init);
+
#if defined(AIM) && !defined(__powerpc64__)
/*
* Clear battable[] translations
@@ -527,6 +564,10 @@ openfirmware_core(void *args)
#endif
result = ofwcall(args);
+
+ /* Restore trap vecotrs */
+ ofw_restore_trap_vec(save_trap_of);
+
ofw_sprg_restore();
intr_restore(oldmsr);
@@ -603,6 +644,8 @@ OF_reboot()
for (;;); /* just in case */
}
+#endif /* AIM */
+
void
OF_getetheraddr(device_t dev, u_char *addr)
{
@@ -623,7 +666,7 @@ OF_getetheraddr(device_t dev, u_char *addr)
static void
OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
{
- char name[16];
+ char type[64];
uint32_t addr, size;
int pci, res;
@@ -635,10 +678,10 @@ OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
size = 1;
pci = 0;
if (addr == 3 && size == 2) {
- res = OF_getprop(node, "name", name, sizeof(name));
+ res = OF_getprop(node, "device_type", type, sizeof(type));
if (res != -1) {
- name[sizeof(name) - 1] = '\0';
- pci = (strcmp(name, "pci") == 0) ? 1 : 0;
+ type[sizeof(type) - 1] = '\0';
+ pci = (strcmp(type, "pci") == 0) ? 1 : 0;
}
}
if (addrp != NULL)
@@ -672,8 +715,13 @@ OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
if (tag == NULL || handle == NULL)
return (EINVAL);
+ /* Assume big-endian unless we find a PCI device */
+ *tag = &bs_be_tag;
+
/* Get the requested register. */
OF_get_addr_props(bridge, &naddr, &nsize, &pci);
+ if (pci)
+ *tag = &bs_le_tag;
res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
cell, sizeof(cell));
if (res == -1)
@@ -701,6 +749,8 @@ OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
parent = OF_parent(bridge);
while (parent != 0) {
OF_get_addr_props(parent, &nbridge, NULL, &pcib);
+ if (pcib)
+ *tag = &bs_le_tag;
res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
if (res == -1)
goto next;
@@ -741,7 +791,6 @@ OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
OF_get_addr_props(bridge, &naddr, &nsize, &pci);
}
- *tag = &bs_le_tag;
return (bus_space_map(*tag, addr, size,
prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle));
}
OpenPOWER on IntegriCloud