^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Procedures for interfacing to Open Firmware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Paul Mackerras August 1996.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 1996-2005 Paul Mackerras.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * {engebret|bergner}@us.ibm.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #undef DEBUG_PROM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) /* we cannot use FORTIFY as it brings in new symbols */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define __NO_FORTIFY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <stdarg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/threads.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/proc_fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/initrd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/pgtable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <asm/prom.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <asm/rtas.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <asm/page.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <asm/processor.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <asm/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <asm/mmu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <asm/iommu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <asm/btext.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <asm/sections.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <asm/machdep.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <asm/asm-prototypes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <asm/ultravisor-api.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <linux/linux_logo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* All of prom_init bss lives here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define __prombss __section(".bss.prominit")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * Eventually bump that one up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define DEVTREE_CHUNK_SIZE 0x100000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * This is the size of the local memory reserve map that gets copied
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * into the boot params passed to the kernel. That size is totally
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * flexible as the kernel just reads the list until it encounters an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * entry with size 0, so it can be changed without breaking binary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * compatibility
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define MEM_RESERVE_MAP_SIZE 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * prom_init() is called very early on, before the kernel text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * and data have been mapped to KERNELBASE. At this point the code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * is running at whatever address it has been loaded at.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * On ppc32 we compile with -mrelocatable, which means that references
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * to extern and static variables get relocated automatically.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * ppc64 objects are always relocatable, we just need to relocate the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * TOC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * Because OF may have mapped I/O devices into the area starting at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * KERNELBASE, particularly on CHRP machines, we can't safely call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * OF once the kernel has been mapped to KERNELBASE. Therefore all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * OF calls must be done within prom_init().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * ADDR is used in calls to call_prom. The 4th and following
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * arguments to call_prom should be 32-bit values.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * On ppc64, 64 bit values are truncated to 32 bits (and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * fortunately don't get interpreted as two arguments).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define ADDR(x) (u32)(unsigned long)(x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define OF_WORKAROUNDS 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define OF_WORKAROUNDS of_workarounds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static int of_workarounds __prombss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) #define OF_WA_CLAIM 1 /* do phys/virt claim separately, then map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define OF_WA_LONGTRAIL 2 /* work around longtrail bugs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define PROM_BUG() do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) prom_printf("kernel BUG at %s line 0x%x!\n", \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) __FILE__, __LINE__); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) __builtin_trap(); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #ifdef DEBUG_PROM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define prom_debug(x...) prom_printf(x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define prom_debug(x...) do { } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) typedef u32 prom_arg_t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct prom_args {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) __be32 service;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) __be32 nargs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) __be32 nret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) __be32 args[10];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct prom_t {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) ihandle root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) phandle chosen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) ihandle stdout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) ihandle mmumap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) ihandle memory;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct mem_map_entry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) __be64 base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) __be64 size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) typedef __be32 cell_t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) extern void __start(unsigned long r3, unsigned long r4, unsigned long r5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) unsigned long r6, unsigned long r7, unsigned long r8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) unsigned long r9);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) extern int enter_prom(struct prom_args *args, unsigned long entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static inline int enter_prom(struct prom_args *args, unsigned long entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return ((int (*)(struct prom_args *))entry)(args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) extern void copy_and_flush(unsigned long dest, unsigned long src,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) unsigned long size, unsigned long offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /* prom structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static struct prom_t __prombss prom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static unsigned long __prombss prom_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static char __prombss of_stdout_device[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) static char __prombss prom_scratch[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static unsigned long __prombss dt_header_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static unsigned long __prombss dt_struct_start, dt_struct_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static unsigned long __prombss dt_string_start, dt_string_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static unsigned long __prombss prom_initrd_start, prom_initrd_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static int __prombss prom_iommu_force_on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static int __prombss prom_iommu_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static unsigned long __prombss prom_tce_alloc_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static unsigned long __prombss prom_tce_alloc_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) #ifdef CONFIG_PPC_PSERIES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static bool __prombss prom_radix_disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static bool __prombss prom_radix_gtse_disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static bool __prombss prom_xive_disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) #ifdef CONFIG_PPC_SVM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static bool __prombss prom_svm_enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct platform_support {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) bool hash_mmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) bool radix_mmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) bool radix_gtse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) bool xive;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /* Platforms codes are now obsolete in the kernel. Now only used within this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * file and ultimately gone too. Feel free to change them if you need, they
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * are not shared with anything outside of this file anymore
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) #define PLATFORM_PSERIES 0x0100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) #define PLATFORM_PSERIES_LPAR 0x0101
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) #define PLATFORM_LPAR 0x0001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) #define PLATFORM_POWERMAC 0x0400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) #define PLATFORM_GENERIC 0x0500
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static int __prombss of_platform;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static char __prombss prom_cmd_line[COMMAND_LINE_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static unsigned long __prombss prom_memory_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) static unsigned long __prombss alloc_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) static unsigned long __prombss alloc_top_high;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static unsigned long __prombss alloc_bottom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) static unsigned long __prombss rmo_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) static unsigned long __prombss ram_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static struct mem_map_entry __prombss mem_reserve_map[MEM_RESERVE_MAP_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) static int __prombss mem_reserve_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) static cell_t __prombss regbuf[1024];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) static bool __prombss rtas_has_query_cpu_stopped;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * Error results ... some OF calls will return "-1" on error, some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * will return 0, some will return either. To simplify, here are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) * macros to use with any ihandle or phandle return value to check if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * it is valid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) #define PROM_ERROR (-1u)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) #define PHANDLE_VALID(p) ((p) != 0 && (p) != PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) #define IHANDLE_VALID(i) ((i) != 0 && (i) != PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) /* Copied from lib/string.c and lib/kstrtox.c */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) static int __init prom_strcmp(const char *cs, const char *ct)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) unsigned char c1, c2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) c1 = *cs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) c2 = *ct++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (c1 != c2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return c1 < c2 ? -1 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (!c1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static char __init *prom_strcpy(char *dest, const char *src)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) char *tmp = dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) while ((*dest++ = *src++) != '\0')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) /* nothing */;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static int __init prom_strncmp(const char *cs, const char *ct, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) unsigned char c1, c2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) while (count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) c1 = *cs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) c2 = *ct++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (c1 != c2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return c1 < c2 ? -1 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (!c1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static size_t __init prom_strlen(const char *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) const char *sc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) for (sc = s; *sc != '\0'; ++sc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) /* nothing */;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return sc - s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) static int __init prom_memcmp(const void *cs, const void *ct, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) const unsigned char *su1, *su2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) int res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if ((res = *su1 - *su2) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) static char __init *prom_strstr(const char *s1, const char *s2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) size_t l1, l2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) l2 = prom_strlen(s2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (!l2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) return (char *)s1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) l1 = prom_strlen(s1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) while (l1 >= l2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) l1--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (!prom_memcmp(s1, s2, l2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return (char *)s1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) s1++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) static size_t __init prom_strlcat(char *dest, const char *src, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) size_t dsize = prom_strlen(dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) size_t len = prom_strlen(src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) size_t res = dsize + len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) /* This would be a bug */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (dsize >= count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) dest += dsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) count -= dsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (len >= count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) len = count-1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) memcpy(dest, src, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) dest[len] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) #ifdef CONFIG_PPC_PSERIES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) static int __init prom_strtobool(const char *s, bool *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (!s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) switch (s[0]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) case 'y':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) case 'Y':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) case '1':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) *res = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) case 'n':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) case 'N':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) case '0':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) *res = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) case 'o':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) case 'O':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) switch (s[1]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) case 'n':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) case 'N':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) *res = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) case 'f':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) case 'F':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) *res = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) /* This is the one and *ONLY* place where we actually call open
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * firmware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) static int __init call_prom(const char *service, int nargs, int nret, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) struct prom_args args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) va_list list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) args.service = cpu_to_be32(ADDR(service));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) args.nargs = cpu_to_be32(nargs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) args.nret = cpu_to_be32(nret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) va_start(list, nret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) for (i = 0; i < nargs; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) args.args[i] = cpu_to_be32(va_arg(list, prom_arg_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) va_end(list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) for (i = 0; i < nret; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) args.args[nargs+i] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) if (enter_prom(&args, prom_entry) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) return PROM_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return (nret > 0) ? be32_to_cpu(args.args[nargs]) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) static int __init call_prom_ret(const char *service, int nargs, int nret,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) prom_arg_t *rets, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) struct prom_args args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) va_list list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) args.service = cpu_to_be32(ADDR(service));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) args.nargs = cpu_to_be32(nargs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) args.nret = cpu_to_be32(nret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) va_start(list, rets);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) for (i = 0; i < nargs; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) args.args[i] = cpu_to_be32(va_arg(list, prom_arg_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) va_end(list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) for (i = 0; i < nret; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) args.args[nargs+i] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (enter_prom(&args, prom_entry) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) return PROM_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (rets != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) for (i = 1; i < nret; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) rets[i-1] = be32_to_cpu(args.args[nargs+i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) return (nret > 0) ? be32_to_cpu(args.args[nargs]) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) static void __init prom_print(const char *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) const char *p, *q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (prom.stdout == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) for (p = msg; *p != 0; p = q) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) for (q = p; *q != 0 && *q != '\n'; ++q)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) if (q > p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) call_prom("write", 3, 1, prom.stdout, p, q - p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (*q == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) ++q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) call_prom("write", 3, 1, prom.stdout, ADDR("\r\n"), 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) * Both prom_print_hex & prom_print_dec takes an unsigned long as input so that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) * we do not need __udivdi3 or __umoddi3 on 32bits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) static void __init prom_print_hex(unsigned long val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) int i, nibbles = sizeof(val)*2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) char buf[sizeof(val)*2+1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) for (i = nibbles-1; i >= 0; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) buf[i] = (val & 0xf) + '0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (buf[i] > '9')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) buf[i] += ('a'-'0'-10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) val >>= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) buf[nibbles] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) call_prom("write", 3, 1, prom.stdout, buf, nibbles);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) /* max number of decimal digits in an unsigned long */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) #define UL_DIGITS 21
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) static void __init prom_print_dec(unsigned long val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) int i, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) char buf[UL_DIGITS+1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) for (i = UL_DIGITS-1; i >= 0; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) buf[i] = (val % 10) + '0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) val = val/10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) if (val == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) /* shift stuff down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) size = UL_DIGITS - i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) call_prom("write", 3, 1, prom.stdout, buf+i, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) __printf(1, 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) static void __init prom_printf(const char *format, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) const char *p, *q, *s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) va_list args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) unsigned long v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) long vs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) int n = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) va_start(args, format);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) for (p = format; *p != 0; p = q) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (q > p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) call_prom("write", 3, 1, prom.stdout, p, q - p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) if (*q == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) if (*q == '\n') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) ++q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) call_prom("write", 3, 1, prom.stdout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) ADDR("\r\n"), 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) ++q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (*q == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) while (*q == 'l') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) ++q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) ++n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) switch (*q) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) case 's':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) ++q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) s = va_arg(args, const char *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) prom_print(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) case 'x':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) ++q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) switch (n) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) v = va_arg(args, unsigned int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) v = va_arg(args, unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) v = va_arg(args, unsigned long long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) prom_print_hex(v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) case 'u':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) ++q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) switch (n) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) v = va_arg(args, unsigned int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) v = va_arg(args, unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) v = va_arg(args, unsigned long long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) prom_print_dec(v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) case 'd':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) ++q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) switch (n) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) vs = va_arg(args, int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) vs = va_arg(args, long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) vs = va_arg(args, long long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) if (vs < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) prom_print("-");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) vs = -vs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) prom_print_dec(vs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) va_end(args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) unsigned long align)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) if (align == 0 && (OF_WORKAROUNDS & OF_WA_CLAIM)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) * Old OF requires we claim physical and virtual separately
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) * and then map explicitly (assuming virtual mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) prom_arg_t result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) ret = call_prom_ret("call-method", 5, 2, &result,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) ADDR("claim"), prom.memory,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) align, size, virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (ret != 0 || result == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) ret = call_prom_ret("call-method", 5, 2, &result,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) ADDR("claim"), prom.mmumap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) align, size, virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (ret != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) call_prom("call-method", 4, 1, ADDR("release"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) prom.memory, size, virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) /* the 0x12 is M (coherence) + PP == read/write */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) call_prom("call-method", 6, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) ADDR("map"), prom.mmumap, 0x12, size, virt, virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) return virt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) return call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) (prom_arg_t)align);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) static void __init __attribute__((noreturn)) prom_panic(const char *reason)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) prom_print(reason);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) /* Do not call exit because it clears the screen on pmac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) * it also causes some sort of double-fault on early pmacs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) if (of_platform == PLATFORM_POWERMAC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) asm("trap\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) /* ToDo: should put up an SRC here on pSeries */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) call_prom("exit", 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) for (;;) /* should never get here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) static int __init prom_next_node(phandle *nodep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) phandle node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if ((node = *nodep) != 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) && (*nodep = call_prom("child", 1, 1, node)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) if ((node = call_prom("parent", 1, 1, node)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) static inline int __init prom_getprop(phandle node, const char *pname,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) void *value, size_t valuelen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) return call_prom("getprop", 4, 1, node, ADDR(pname),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) (u32)(unsigned long) value, (u32) valuelen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) static inline int __init prom_getproplen(phandle node, const char *pname)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) return call_prom("getproplen", 2, 1, node, ADDR(pname));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) static void add_string(char **str, const char *q)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) char *p = *str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) while (*q)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) *p++ = *q++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) *p++ = ' ';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) *str = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) static char *tohex(unsigned int x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) static const char digits[] __initconst = "0123456789abcdef";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) static char result[9] __prombss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) result[8] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) i = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) --i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) result[i] = digits[x & 0xf];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) x >>= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) } while (x != 0 && i > 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) return &result[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) static int __init prom_setprop(phandle node, const char *nodename,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) const char *pname, void *value, size_t valuelen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) char cmd[256], *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) if (!(OF_WORKAROUNDS & OF_WA_LONGTRAIL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) return call_prom("setprop", 4, 1, node, ADDR(pname),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) (u32)(unsigned long) value, (u32) valuelen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) /* gah... setprop doesn't work on longtrail, have to use interpret */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) p = cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) add_string(&p, "dev");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) add_string(&p, nodename);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) add_string(&p, tohex((u32)(unsigned long) value));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) add_string(&p, tohex(valuelen));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) add_string(&p, tohex(ADDR(pname)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) add_string(&p, tohex(prom_strlen(pname)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) add_string(&p, "property");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) *p = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) /* We can't use the standard versions because of relocation headaches. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) #define isxdigit(c) (('0' <= (c) && (c) <= '9') \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) || ('a' <= (c) && (c) <= 'f') \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) || ('A' <= (c) && (c) <= 'F'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) #define isdigit(c) ('0' <= (c) && (c) <= '9')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) #define islower(c) ('a' <= (c) && (c) <= 'z')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) #define toupper(c) (islower(c) ? ((c) - 'a' + 'A') : (c))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) static unsigned long prom_strtoul(const char *cp, const char **endp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) unsigned long result = 0, base = 10, value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) if (*cp == '0') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) base = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) cp++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) if (toupper(*cp) == 'X') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) cp++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) base = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) while (isxdigit(*cp) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) (value = isdigit(*cp) ? *cp - '0' : toupper(*cp) - 'A' + 10) < base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) result = result * base + value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) cp++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) if (endp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) *endp = cp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) static unsigned long prom_memparse(const char *ptr, const char **retptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) unsigned long ret = prom_strtoul(ptr, retptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) int shift = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) * We can't use a switch here because GCC *may* generate a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) * jump table which won't work, because we're not running at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) * the address we're linked at.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) if ('G' == **retptr || 'g' == **retptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) shift = 30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) if ('M' == **retptr || 'm' == **retptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) shift = 20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) if ('K' == **retptr || 'k' == **retptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) shift = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) if (shift) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) ret <<= shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) (*retptr)++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) * Early parsing of the command line passed to the kernel, used for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) * "mem=x" and the options that affect the iommu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) static void __init early_cmdline_parse(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) const char *opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) char *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) int l = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) prom_cmd_line[0] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) p = prom_cmd_line;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && (long)prom.chosen > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) l = prom_getprop(prom.chosen, "bootargs", p, COMMAND_LINE_SIZE-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || l <= 0 || p[0] == '\0')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) prom_strlcat(prom_cmd_line, " " CONFIG_CMDLINE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) sizeof(prom_cmd_line));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) prom_printf("command line: %s\n", prom_cmd_line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) opt = prom_strstr(prom_cmd_line, "iommu=");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) if (opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) prom_printf("iommu opt is: %s\n", opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) opt += 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) while (*opt && *opt == ' ')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) opt++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) if (!prom_strncmp(opt, "off", 3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) prom_iommu_off = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) else if (!prom_strncmp(opt, "force", 5))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) prom_iommu_force_on = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) opt = prom_strstr(prom_cmd_line, "mem=");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) if (opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) opt += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) prom_memory_limit = prom_memparse(opt, (const char **)&opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) /* Align to 16 MB == size of ppc64 large page */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) prom_memory_limit = ALIGN(prom_memory_limit, 0x1000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) #ifdef CONFIG_PPC_PSERIES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) prom_radix_disable = !IS_ENABLED(CONFIG_PPC_RADIX_MMU_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) opt = prom_strstr(prom_cmd_line, "disable_radix");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) if (opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) opt += 13;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) if (*opt && *opt == '=') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) bool val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) if (prom_strtobool(++opt, &val))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) prom_radix_disable = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) prom_radix_disable = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) prom_radix_disable = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) if (prom_radix_disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) prom_debug("Radix disabled from cmdline\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) opt = prom_strstr(prom_cmd_line, "radix_hcall_invalidate=on");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) if (opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) prom_radix_gtse_disable = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) prom_debug("Radix GTSE disabled from cmdline\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) opt = prom_strstr(prom_cmd_line, "xive=off");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) if (opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) prom_xive_disable = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) prom_debug("XIVE disabled from cmdline\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) #endif /* CONFIG_PPC_PSERIES */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) #ifdef CONFIG_PPC_SVM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) opt = prom_strstr(prom_cmd_line, "svm=");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) bool val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) opt += sizeof("svm=") - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) if (!prom_strtobool(opt, &val))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) prom_svm_enable = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) #endif /* CONFIG_PPC_SVM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) #ifdef CONFIG_PPC_PSERIES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) * The architecture vector has an array of PVR mask/value pairs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) * followed by # option vectors - 1, followed by the option vectors.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) * See prom.h for the definition of the bits specified in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) * architecture vector.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) /* Firmware expects the value to be n - 1, where n is the # of vectors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) #define NUM_VECTORS(n) ((n) - 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) * Firmware expects 1 + n - 2, where n is the length of the option vector in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) * bytes. The 1 accounts for the length byte itself, the - 2 .. ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) #define VECTOR_LENGTH(n) (1 + (n) - 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) struct option_vector1 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) u8 byte1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) u8 arch_versions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) u8 arch_versions3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) struct option_vector2 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) u8 byte1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) __be16 reserved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) __be32 real_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) __be32 real_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) __be32 virt_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) __be32 virt_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) __be32 load_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) __be32 min_rma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) __be32 min_load;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) u8 min_rma_percent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) u8 max_pft_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) struct option_vector3 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) u8 byte1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) u8 byte2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) struct option_vector4 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) u8 byte1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) u8 min_vp_cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) struct option_vector5 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) u8 byte1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) u8 byte2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) u8 byte3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) u8 cmo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) u8 associativity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) u8 bin_opts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) u8 micro_checkpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) u8 reserved0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) __be32 max_cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) __be16 papr_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) __be16 reserved1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) u8 platform_facilities;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) u8 reserved2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) __be16 reserved3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) u8 subprocessors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) u8 byte22;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) u8 intarch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) u8 mmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) u8 hash_ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) u8 radix_ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) struct option_vector6 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) u8 reserved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) u8 secondary_pteg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) u8 os_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) struct ibm_arch_vec {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) struct { u32 mask, val; } pvrs[14];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) u8 num_vectors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) u8 vec1_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) struct option_vector1 vec1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) u8 vec2_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) struct option_vector2 vec2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) u8 vec3_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) struct option_vector3 vec3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) u8 vec4_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) struct option_vector4 vec4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) u8 vec5_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) struct option_vector5 vec5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) u8 vec6_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) struct option_vector6 vec6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) static const struct ibm_arch_vec ibm_architecture_vec_template __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) .pvrs = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) .mask = cpu_to_be32(0xfffe0000), /* POWER5/POWER5+ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) .val = cpu_to_be32(0x003a0000),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) .mask = cpu_to_be32(0xffff0000), /* POWER6 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) .val = cpu_to_be32(0x003e0000),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) .mask = cpu_to_be32(0xffff0000), /* POWER7 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) .val = cpu_to_be32(0x003f0000),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) .mask = cpu_to_be32(0xffff0000), /* POWER8E */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) .val = cpu_to_be32(0x004b0000),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) .mask = cpu_to_be32(0xffff0000), /* POWER8NVL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) .val = cpu_to_be32(0x004c0000),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) .mask = cpu_to_be32(0xffff0000), /* POWER8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) .val = cpu_to_be32(0x004d0000),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) .mask = cpu_to_be32(0xffff0000), /* POWER9 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) .val = cpu_to_be32(0x004e0000),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) .mask = cpu_to_be32(0xffff0000), /* POWER10 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) .val = cpu_to_be32(0x00800000),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) .mask = cpu_to_be32(0xffffffff), /* all 3.1-compliant */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) .val = cpu_to_be32(0x0f000006),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) .mask = cpu_to_be32(0xffffffff), /* all 3.00-compliant */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) .val = cpu_to_be32(0x0f000005),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) .mask = cpu_to_be32(0xffffffff), /* all 2.07-compliant */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) .val = cpu_to_be32(0x0f000004),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) .mask = cpu_to_be32(0xffffffff), /* all 2.06-compliant */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) .val = cpu_to_be32(0x0f000003),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) .mask = cpu_to_be32(0xffffffff), /* all 2.05-compliant */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) .val = cpu_to_be32(0x0f000002),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) .mask = cpu_to_be32(0xfffffffe), /* all 2.04-compliant and earlier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) .val = cpu_to_be32(0x0f000001),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) .num_vectors = NUM_VECTORS(6),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) .vec1_len = VECTOR_LENGTH(sizeof(struct option_vector1)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) .vec1 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) .byte1 = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) .arch_versions = OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06 | OV1_PPC_2_07,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) .arch_versions3 = OV1_PPC_3_00 | OV1_PPC_3_1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) .vec2_len = VECTOR_LENGTH(sizeof(struct option_vector2)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) /* option vector 2: Open Firmware options supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) .vec2 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) .byte1 = OV2_REAL_MODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) .reserved = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) .real_base = cpu_to_be32(0xffffffff),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) .real_size = cpu_to_be32(0xffffffff),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) .virt_base = cpu_to_be32(0xffffffff),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) .virt_size = cpu_to_be32(0xffffffff),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) .load_base = cpu_to_be32(0xffffffff),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) .min_rma = cpu_to_be32(512), /* 512MB min RMA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) .min_load = cpu_to_be32(0xffffffff), /* full client load */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) .min_rma_percent = 0, /* min RMA percentage of total RAM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) .max_pft_size = 48, /* max log_2(hash table size) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) .vec3_len = VECTOR_LENGTH(sizeof(struct option_vector3)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) /* option vector 3: processor options supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) .vec3 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) .byte1 = 0, /* don't ignore, don't halt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) .byte2 = OV3_FP | OV3_VMX | OV3_DFP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) .vec4_len = VECTOR_LENGTH(sizeof(struct option_vector4)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) /* option vector 4: IBM PAPR implementation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) .vec4 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) .byte1 = 0, /* don't halt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) .min_vp_cap = OV4_MIN_ENT_CAP, /* minimum VP entitled capacity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) .vec5_len = VECTOR_LENGTH(sizeof(struct option_vector5)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) /* option vector 5: PAPR/OF options */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) .vec5 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) .byte1 = 0, /* don't ignore, don't halt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) .byte2 = OV5_FEAT(OV5_LPAR) | OV5_FEAT(OV5_SPLPAR) | OV5_FEAT(OV5_LARGE_PAGES) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) OV5_FEAT(OV5_DRCONF_MEMORY) | OV5_FEAT(OV5_DONATE_DEDICATE_CPU) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) #ifdef CONFIG_PCI_MSI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) /* PCIe/MSI support. Without MSI full PCIe is not supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) OV5_FEAT(OV5_MSI),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) .byte3 = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) .cmo =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) #ifdef CONFIG_PPC_SMLPAR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) OV5_FEAT(OV5_CMO) | OV5_FEAT(OV5_XCMO),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) .associativity = OV5_FEAT(OV5_TYPE1_AFFINITY) | OV5_FEAT(OV5_PRRN),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) .bin_opts = OV5_FEAT(OV5_RESIZE_HPT) | OV5_FEAT(OV5_HP_EVT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) .micro_checkpoint = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) .reserved0 = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) .max_cpus = cpu_to_be32(NR_CPUS), /* number of cores supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) .papr_level = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) .reserved1 = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) .platform_facilities = OV5_FEAT(OV5_PFO_HW_RNG) | OV5_FEAT(OV5_PFO_HW_ENCR) | OV5_FEAT(OV5_PFO_HW_842),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) .reserved2 = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) .reserved3 = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) .subprocessors = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) .byte22 = OV5_FEAT(OV5_DRMEM_V2) | OV5_FEAT(OV5_DRC_INFO),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) .intarch = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) .mmu = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) .hash_ext = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) .radix_ext = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) /* option vector 6: IBM PAPR hints */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) .vec6_len = VECTOR_LENGTH(sizeof(struct option_vector6)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) .vec6 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) .reserved = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) .secondary_pteg = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) .os_name = OV6_LINUX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) static struct ibm_arch_vec __prombss ibm_architecture_vec ____cacheline_aligned;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) /* Old method - ELF header with PT_NOTE sections only works on BE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) #ifdef __BIG_ENDIAN__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) static const struct fake_elf {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) Elf32_Ehdr elfhdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) Elf32_Phdr phdr[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) struct chrpnote {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) u32 namesz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) u32 descsz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) u32 type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) char name[8]; /* "PowerPC" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) struct chrpdesc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) u32 real_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) u32 real_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) u32 real_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) u32 virt_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) u32 virt_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) u32 load_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) } chrpdesc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) } chrpnote;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) struct rpanote {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) u32 namesz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) u32 descsz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) u32 type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) char name[24]; /* "IBM,RPA-Client-Config" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) struct rpadesc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) u32 lpar_affinity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) u32 min_rmo_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) u32 min_rmo_percent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) u32 max_pft_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) u32 splpar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) u32 min_load;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) u32 new_mem_def;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) u32 ignore_me;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) } rpadesc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) } rpanote;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) } fake_elf __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) .elfhdr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) .e_ident = { 0x7f, 'E', 'L', 'F',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) ELFCLASS32, ELFDATA2MSB, EV_CURRENT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) .e_type = ET_EXEC, /* yeah right */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) .e_machine = EM_PPC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) .e_version = EV_CURRENT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) .e_phoff = offsetof(struct fake_elf, phdr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) .e_phentsize = sizeof(Elf32_Phdr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) .e_phnum = 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) .phdr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) [0] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) .p_type = PT_NOTE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) .p_offset = offsetof(struct fake_elf, chrpnote),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) .p_filesz = sizeof(struct chrpnote)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) }, [1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) .p_type = PT_NOTE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) .p_offset = offsetof(struct fake_elf, rpanote),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) .p_filesz = sizeof(struct rpanote)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) .chrpnote = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) .namesz = sizeof("PowerPC"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) .descsz = sizeof(struct chrpdesc),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) .type = 0x1275,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) .name = "PowerPC",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) .chrpdesc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) .real_mode = ~0U, /* ~0 means "don't care" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) .real_base = ~0U,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) .real_size = ~0U,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) .virt_base = ~0U,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) .virt_size = ~0U,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) .load_base = ~0U
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) .rpanote = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) .namesz = sizeof("IBM,RPA-Client-Config"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) .descsz = sizeof(struct rpadesc),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) .type = 0x12759999,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) .name = "IBM,RPA-Client-Config",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) .rpadesc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) .lpar_affinity = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) .min_rmo_size = 64, /* in megabytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) .min_rmo_percent = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) .max_pft_size = 48, /* 2^48 bytes max PFT size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) .splpar = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) .min_load = ~0U,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) .new_mem_def = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) #endif /* __BIG_ENDIAN__ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) static int __init prom_count_smt_threads(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) phandle node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) char type[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) unsigned int plen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) /* Pick up th first CPU node we can find */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) for (node = 0; prom_next_node(&node); ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) type[0] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) prom_getprop(node, "device_type", type, sizeof(type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) if (prom_strcmp(type, "cpu"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) * There is an entry for each smt thread, each entry being
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) * 4 bytes long. All cpus should have the same number of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) * smt threads, so return after finding the first.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) plen = prom_getproplen(node, "ibm,ppc-interrupt-server#s");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) if (plen == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) plen >>= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) prom_debug("Found %lu smt threads per core\n", (unsigned long)plen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) /* Sanity check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) if (plen < 1 || plen > 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) prom_printf("Threads per core %lu out of bounds, assuming 1\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) (unsigned long)plen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) return plen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) prom_debug("No threads found, assuming 1 per core\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) static void __init prom_parse_mmu_model(u8 val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) struct platform_support *support)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) switch (val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) case OV5_FEAT(OV5_MMU_DYNAMIC):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) case OV5_FEAT(OV5_MMU_EITHER): /* Either Available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) prom_debug("MMU - either supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) support->radix_mmu = !prom_radix_disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) support->hash_mmu = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) case OV5_FEAT(OV5_MMU_RADIX): /* Only Radix */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) prom_debug("MMU - radix only\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) if (prom_radix_disable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) * If we __have__ to do radix, we're better off ignoring
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) * the command line rather than not booting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) prom_printf("WARNING: Ignoring cmdline option disable_radix\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) support->radix_mmu = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) case OV5_FEAT(OV5_MMU_HASH):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) prom_debug("MMU - hash only\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) support->hash_mmu = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) prom_debug("Unknown mmu support option: 0x%x\n", val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) static void __init prom_parse_xive_model(u8 val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) struct platform_support *support)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) switch (val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) case OV5_FEAT(OV5_XIVE_EITHER): /* Either Available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) prom_debug("XIVE - either mode supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) support->xive = !prom_xive_disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) case OV5_FEAT(OV5_XIVE_EXPLOIT): /* Only Exploitation mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) prom_debug("XIVE - exploitation mode supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) if (prom_xive_disable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) * If we __have__ to do XIVE, we're better off ignoring
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) * the command line rather than not booting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) prom_printf("WARNING: Ignoring cmdline option xive=off\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) support->xive = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) case OV5_FEAT(OV5_XIVE_LEGACY): /* Only Legacy mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) prom_debug("XIVE - legacy mode supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) prom_debug("Unknown xive support option: 0x%x\n", val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) static void __init prom_parse_platform_support(u8 index, u8 val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) struct platform_support *support)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) switch (index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) case OV5_INDX(OV5_MMU_SUPPORT): /* MMU Model */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) prom_parse_mmu_model(val & OV5_FEAT(OV5_MMU_SUPPORT), support);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) case OV5_INDX(OV5_RADIX_GTSE): /* Radix Extensions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) if (val & OV5_FEAT(OV5_RADIX_GTSE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) support->radix_gtse = !prom_radix_gtse_disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) case OV5_INDX(OV5_XIVE_SUPPORT): /* Interrupt mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) prom_parse_xive_model(val & OV5_FEAT(OV5_XIVE_SUPPORT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) support);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) static void __init prom_check_platform_support(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) struct platform_support supported = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) .hash_mmu = false,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) .radix_mmu = false,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) .radix_gtse = false,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) .xive = false
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) int prop_len = prom_getproplen(prom.chosen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) "ibm,arch-vec-5-platform-support");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) * First copy the architecture vec template
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) * use memcpy() instead of *vec = *vec_template so that GCC replaces it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) * by __memcpy() when KASAN is active
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) memcpy(&ibm_architecture_vec, &ibm_architecture_vec_template,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) sizeof(ibm_architecture_vec));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) if (prop_len > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) u8 vec[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) prom_debug("Found ibm,arch-vec-5-platform-support, len: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) prop_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) if (prop_len > sizeof(vec))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) prom_printf("WARNING: ibm,arch-vec-5-platform-support longer than expected (len: %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) prop_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) prom_getprop(prom.chosen, "ibm,arch-vec-5-platform-support", &vec, sizeof(vec));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) for (i = 0; i < prop_len; i += 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) prom_debug("%d: index = 0x%x val = 0x%x\n", i / 2, vec[i], vec[i + 1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) prom_parse_platform_support(vec[i], vec[i + 1], &supported);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) if (supported.radix_mmu && IS_ENABLED(CONFIG_PPC_RADIX_MMU)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) /* Radix preferred - Check if GTSE is also supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) prom_debug("Asking for radix\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) ibm_architecture_vec.vec5.mmu = OV5_FEAT(OV5_MMU_RADIX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) if (supported.radix_gtse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) ibm_architecture_vec.vec5.radix_ext =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) OV5_FEAT(OV5_RADIX_GTSE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) prom_debug("Radix GTSE isn't supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) } else if (supported.hash_mmu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) /* Default to hash mmu (if we can) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) prom_debug("Asking for hash\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) ibm_architecture_vec.vec5.mmu = OV5_FEAT(OV5_MMU_HASH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) /* We're probably on a legacy hypervisor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) prom_debug("Assuming legacy hash support\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) if (supported.xive) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) prom_debug("Asking for XIVE\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) ibm_architecture_vec.vec5.intarch = OV5_FEAT(OV5_XIVE_EXPLOIT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) static void __init prom_send_capabilities(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) ihandle root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) prom_arg_t ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) u32 cores;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) /* Check ibm,arch-vec-5-platform-support and fixup vec5 if required */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) prom_check_platform_support();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) root = call_prom("open", 1, 1, ADDR("/"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) if (root != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) /* We need to tell the FW about the number of cores we support.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) * To do that, we count the number of threads on the first core
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) * (we assume this is the same for all cores) and use it to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) * divide NR_CPUS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) cores = DIV_ROUND_UP(NR_CPUS, prom_count_smt_threads());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) prom_printf("Max number of cores passed to firmware: %u (NR_CPUS = %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) cores, NR_CPUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) ibm_architecture_vec.vec5.max_cpus = cpu_to_be32(cores);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) /* try calling the ibm,client-architecture-support method */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) prom_printf("Calling ibm,client-architecture-support...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) if (call_prom_ret("call-method", 3, 2, &ret,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) ADDR("ibm,client-architecture-support"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) root,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) ADDR(&ibm_architecture_vec)) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) /* the call exists... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) prom_printf("\nWARNING: ibm,client-architecture"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) "-support call FAILED!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) call_prom("close", 1, 0, root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) prom_printf(" done\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) call_prom("close", 1, 0, root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) prom_printf(" not implemented\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) #ifdef __BIG_ENDIAN__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) ihandle elfloader;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) /* no ibm,client-architecture-support call, try the old way */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) elfloader = call_prom("open", 1, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) ADDR("/packages/elf-loader"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) if (elfloader == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) prom_printf("couldn't open /packages/elf-loader\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) call_prom("call-method", 3, 1, ADDR("process-elf-header"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) elfloader, ADDR(&fake_elf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) call_prom("close", 1, 0, elfloader);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) #endif /* __BIG_ENDIAN__ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) #endif /* CONFIG_PPC_PSERIES */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) * Memory allocation strategy... our layout is normally:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) * at 14Mb or more we have vmlinux, then a gap and initrd. In some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) * rare cases, initrd might end up being before the kernel though.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) * We assume this won't override the final kernel at 0, we have no
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) * provision to handle that in this version, but it should hopefully
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) * never happen.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) * alloc_top is set to the top of RMO, eventually shrink down if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) * TCEs overlap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) * alloc_bottom is set to the top of kernel/initrd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) * from there, allocations are done this way : rtas is allocated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) * topmost, and the device-tree is allocated from the bottom. We try
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) * to grow the device-tree allocation as we progress. If we can't,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) * then we fail, we don't currently have a facility to restart
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) * elsewhere, but that shouldn't be necessary.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) * Note that calls to reserve_mem have to be done explicitly, memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) * allocated with either alloc_up or alloc_down isn't automatically
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) * reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) * Allocates memory in the RMO upward from the kernel/initrd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) * When align is 0, this is a special case, it means to allocate in place
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) * at the current location of alloc_bottom or fail (that is basically
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) * extending the previous allocation). Used for the device-tree flattening
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) static unsigned long __init alloc_up(unsigned long size, unsigned long align)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) unsigned long base = alloc_bottom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) unsigned long addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) if (align)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) base = ALIGN(base, align);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) prom_debug("%s(%lx, %lx)\n", __func__, size, align);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) if (ram_top == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) prom_panic("alloc_up() called with mem not initialized\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) if (align)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) base = ALIGN(alloc_bottom, align);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) base = alloc_bottom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) for(; (base + size) <= alloc_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) base = ALIGN(base + 0x100000, align)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) prom_debug(" trying: 0x%lx\n\r", base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) addr = (unsigned long)prom_claim(base, size, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) if (addr != PROM_ERROR && addr != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) if (align == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) if (addr == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) alloc_bottom = addr + size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) prom_debug(" -> %lx\n", addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) prom_debug(" alloc_bottom : %lx\n", alloc_bottom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) prom_debug(" alloc_top : %lx\n", alloc_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) prom_debug(" alloc_top_hi : %lx\n", alloc_top_high);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) prom_debug(" rmo_top : %lx\n", rmo_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) prom_debug(" ram_top : %lx\n", ram_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) return addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) * Allocates memory downward, either from top of RMO, or if highmem
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) * is set, from the top of RAM. Note that this one doesn't handle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) * failures. It does claim memory if highmem is not set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) static unsigned long __init alloc_down(unsigned long size, unsigned long align,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) int highmem)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) unsigned long base, addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) prom_debug("%s(%lx, %lx, %s)\n", __func__, size, align,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) highmem ? "(high)" : "(low)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) if (ram_top == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) prom_panic("alloc_down() called with mem not initialized\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) if (highmem) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) /* Carve out storage for the TCE table. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) addr = ALIGN_DOWN(alloc_top_high - size, align);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) if (addr <= alloc_bottom)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) /* Will we bump into the RMO ? If yes, check out that we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) * didn't overlap existing allocations there, if we did,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) * we are dead, we must be the first in town !
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) if (addr < rmo_top) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) /* Good, we are first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) if (alloc_top == rmo_top)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) alloc_top = rmo_top = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) alloc_top_high = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) goto bail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) base = ALIGN_DOWN(alloc_top - size, align);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) for (; base > alloc_bottom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) base = ALIGN_DOWN(base - 0x100000, align)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) prom_debug(" trying: 0x%lx\n\r", base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) addr = (unsigned long)prom_claim(base, size, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) if (addr != PROM_ERROR && addr != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) if (addr == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) alloc_top = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) bail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) prom_debug(" -> %lx\n", addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) prom_debug(" alloc_bottom : %lx\n", alloc_bottom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) prom_debug(" alloc_top : %lx\n", alloc_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) prom_debug(" alloc_top_hi : %lx\n", alloc_top_high);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) prom_debug(" rmo_top : %lx\n", rmo_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) prom_debug(" ram_top : %lx\n", ram_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) return addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) * Parse a "reg" cell
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) static unsigned long __init prom_next_cell(int s, cell_t **cellp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) cell_t *p = *cellp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) unsigned long r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) /* Ignore more than 2 cells */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) while (s > sizeof(unsigned long) / 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) p++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) s--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) r = be32_to_cpu(*p++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) if (s > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) r <<= 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) r |= be32_to_cpu(*(p++));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) *cellp = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) * Very dumb function for adding to the memory reserve list, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) * we don't need anything smarter at this point
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) * XXX Eventually check for collisions. They should NEVER happen.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) * If problems seem to show up, it would be a good start to track
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) * them down.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) static void __init reserve_mem(u64 base, u64 size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) u64 top = base + size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) unsigned long cnt = mem_reserve_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) if (size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) /* We need to always keep one empty entry so that we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) * have our terminator with "size" set to 0 since we are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) * dumb and just copy this entire array to the boot params
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) base = ALIGN_DOWN(base, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) top = ALIGN(top, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) size = top - base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) if (cnt >= (MEM_RESERVE_MAP_SIZE - 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) prom_panic("Memory reserve map exhausted !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) mem_reserve_map[cnt].base = cpu_to_be64(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) mem_reserve_map[cnt].size = cpu_to_be64(size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) mem_reserve_cnt = cnt + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) * Initialize memory allocation mechanism, parse "memory" nodes and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) * obtain that way the top of memory and RMO to setup out local allocator
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) static void __init prom_init_mem(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) phandle node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) char type[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) unsigned int plen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) cell_t *p, *endp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) __be32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) u32 rac, rsc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) * We iterate the memory nodes to find
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) * 1) top of RMO (first node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) * 2) top of memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) val = cpu_to_be32(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) prom_getprop(prom.root, "#address-cells", &val, sizeof(val));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) rac = be32_to_cpu(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) val = cpu_to_be32(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) prom_getprop(prom.root, "#size-cells", &val, sizeof(rsc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) rsc = be32_to_cpu(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) prom_debug("root_addr_cells: %x\n", rac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) prom_debug("root_size_cells: %x\n", rsc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) prom_debug("scanning memory:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) for (node = 0; prom_next_node(&node); ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) type[0] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) prom_getprop(node, "device_type", type, sizeof(type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) if (type[0] == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) * CHRP Longtrail machines have no device_type
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) * on the memory node, so check the name instead...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) prom_getprop(node, "name", type, sizeof(type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) if (prom_strcmp(type, "memory"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) plen = prom_getprop(node, "reg", regbuf, sizeof(regbuf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) if (plen > sizeof(regbuf)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) prom_printf("memory node too large for buffer !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) plen = sizeof(regbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) p = regbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) endp = p + (plen / sizeof(cell_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) #ifdef DEBUG_PROM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) memset(prom_scratch, 0, sizeof(prom_scratch));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) call_prom("package-to-path", 3, 1, node, prom_scratch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) sizeof(prom_scratch) - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) prom_debug(" node %s :\n", prom_scratch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) #endif /* DEBUG_PROM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) while ((endp - p) >= (rac + rsc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) unsigned long base, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) base = prom_next_cell(rac, &p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) size = prom_next_cell(rsc, &p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) if (size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) prom_debug(" %lx %lx\n", base, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) if (base == 0 && (of_platform & PLATFORM_LPAR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) rmo_top = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) if ((base + size) > ram_top)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) ram_top = base + size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) alloc_bottom = PAGE_ALIGN((unsigned long)&_end + 0x4000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) * If prom_memory_limit is set we reduce the upper limits *except* for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) * alloc_top_high. This must be the real top of RAM so we can put
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) * TCE's up there.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) alloc_top_high = ram_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) if (prom_memory_limit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) if (prom_memory_limit <= alloc_bottom) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) prom_printf("Ignoring mem=%lx <= alloc_bottom.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) prom_memory_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) prom_memory_limit = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) } else if (prom_memory_limit >= ram_top) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) prom_printf("Ignoring mem=%lx >= ram_top.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) prom_memory_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) prom_memory_limit = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) ram_top = prom_memory_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) rmo_top = min(rmo_top, prom_memory_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) * Setup our top alloc point, that is top of RMO or top of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) * segment 0 when running non-LPAR.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) * Some RS64 machines have buggy firmware where claims up at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) * 1GB fail. Cap at 768MB as a workaround.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) * Since 768MB is plenty of room, and we need to cap to something
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) * reasonable on 32-bit, cap at 768MB on all machines.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) if (!rmo_top)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) rmo_top = ram_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) rmo_top = min(0x30000000ul, rmo_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) alloc_top = rmo_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) alloc_top_high = ram_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) * Check if we have an initrd after the kernel but still inside
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) * the RMO. If we do move our bottom point to after it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) if (prom_initrd_start &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) prom_initrd_start < rmo_top &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) prom_initrd_end > alloc_bottom)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) alloc_bottom = PAGE_ALIGN(prom_initrd_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) prom_printf("memory layout at init:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735) prom_printf(" memory_limit : %lx (16 MB aligned)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) prom_memory_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) prom_printf(" alloc_bottom : %lx\n", alloc_bottom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) prom_printf(" alloc_top : %lx\n", alloc_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) prom_printf(" alloc_top_hi : %lx\n", alloc_top_high);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) prom_printf(" rmo_top : %lx\n", rmo_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) prom_printf(" ram_top : %lx\n", ram_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) static void __init prom_close_stdin(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) __be32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) ihandle stdin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) if (prom_getprop(prom.chosen, "stdin", &val, sizeof(val)) > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) stdin = be32_to_cpu(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) call_prom("close", 1, 0, stdin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) #ifdef CONFIG_PPC_SVM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) static int prom_rtas_hcall(uint64_t args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) register uint64_t arg1 asm("r3") = H_RTAS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) register uint64_t arg2 asm("r4") = args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) asm volatile("sc 1\n" : "=r" (arg1) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) "r" (arg1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) "r" (arg2) :);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) return arg1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) static struct rtas_args __prombss os_term_args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) static void __init prom_rtas_os_term(char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) phandle rtas_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) __be32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) u32 token;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) prom_debug("%s: start...\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) prom_debug("rtas_node: %x\n", rtas_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) if (!PHANDLE_VALID(rtas_node))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) prom_getprop(rtas_node, "ibm,os-term", &val, sizeof(val));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) token = be32_to_cpu(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) prom_debug("ibm,os-term: %x\n", token);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) if (token == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) prom_panic("Could not get token for ibm,os-term\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) os_term_args.token = cpu_to_be32(token);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) os_term_args.nargs = cpu_to_be32(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) os_term_args.nret = cpu_to_be32(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) os_term_args.args[0] = cpu_to_be32(__pa(str));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) prom_rtas_hcall((uint64_t)&os_term_args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) #endif /* CONFIG_PPC_SVM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) * Allocate room for and instantiate RTAS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) static void __init prom_instantiate_rtas(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800) phandle rtas_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) ihandle rtas_inst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) u32 base, entry = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) __be32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) u32 size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) prom_debug("prom_instantiate_rtas: start...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) prom_debug("rtas_node: %x\n", rtas_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) if (!PHANDLE_VALID(rtas_node))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) prom_getprop(rtas_node, "rtas-size", &val, sizeof(size));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) size = be32_to_cpu(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) if (size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) base = alloc_down(size, PAGE_SIZE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) if (base == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) prom_panic("Could not allocate memory for RTAS\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) rtas_inst = call_prom("open", 1, 1, ADDR("/rtas"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) if (!IHANDLE_VALID(rtas_inst)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) prom_printf("opening rtas package failed (%x)\n", rtas_inst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) prom_printf("instantiating rtas at 0x%x...", base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) if (call_prom_ret("call-method", 3, 2, &entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832) ADDR("instantiate-rtas"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) rtas_inst, base) != 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) || entry == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) prom_printf(" failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) prom_printf(" done\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840) reserve_mem(base, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) val = cpu_to_be32(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) prom_setprop(rtas_node, "/rtas", "linux,rtas-base",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) &val, sizeof(val));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) val = cpu_to_be32(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846) prom_setprop(rtas_node, "/rtas", "linux,rtas-entry",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) &val, sizeof(val));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) /* Check if it supports "query-cpu-stopped-state" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) if (prom_getprop(rtas_node, "query-cpu-stopped-state",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) &val, sizeof(val)) != PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) rtas_has_query_cpu_stopped = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) prom_debug("rtas base = 0x%x\n", base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) prom_debug("rtas entry = 0x%x\n", entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) prom_debug("rtas size = 0x%x\n", size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) prom_debug("prom_instantiate_rtas: end...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) * Allocate room for and instantiate Stored Measurement Log (SML)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) static void __init prom_instantiate_sml(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) phandle ibmvtpm_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) ihandle ibmvtpm_inst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) u32 entry = 0, size = 0, succ = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870) u64 base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871) __be32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) prom_debug("prom_instantiate_sml: start...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) ibmvtpm_node = call_prom("finddevice", 1, 1, ADDR("/vdevice/vtpm"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) prom_debug("ibmvtpm_node: %x\n", ibmvtpm_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) if (!PHANDLE_VALID(ibmvtpm_node))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) ibmvtpm_inst = call_prom("open", 1, 1, ADDR("/vdevice/vtpm"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) if (!IHANDLE_VALID(ibmvtpm_inst)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) prom_printf("opening vtpm package failed (%x)\n", ibmvtpm_inst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) if (prom_getprop(ibmvtpm_node, "ibm,sml-efi-reformat-supported",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887) &val, sizeof(val)) != PROM_ERROR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) if (call_prom_ret("call-method", 2, 2, &succ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889) ADDR("reformat-sml-to-efi-alignment"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) ibmvtpm_inst) != 0 || succ == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) prom_printf("Reformat SML to EFI alignment failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) if (call_prom_ret("call-method", 2, 2, &size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) ADDR("sml-get-allocated-size"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897) ibmvtpm_inst) != 0 || size == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898) prom_printf("SML get allocated size failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) if (call_prom_ret("call-method", 2, 2, &size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) ADDR("sml-get-handover-size"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904) ibmvtpm_inst) != 0 || size == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) prom_printf("SML get handover size failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910) base = alloc_down(size, PAGE_SIZE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911) if (base == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) prom_panic("Could not allocate memory for sml\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914) prom_printf("instantiating sml at 0x%llx...", base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916) memset((void *)base, 0, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918) if (call_prom_ret("call-method", 4, 2, &entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919) ADDR("sml-handover"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920) ibmvtpm_inst, size, base) != 0 || entry == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) prom_printf("SML handover failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924) prom_printf(" done\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926) reserve_mem(base, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) prom_setprop(ibmvtpm_node, "/vdevice/vtpm", "linux,sml-base",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929) &base, sizeof(base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930) prom_setprop(ibmvtpm_node, "/vdevice/vtpm", "linux,sml-size",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931) &size, sizeof(size));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) prom_debug("sml base = 0x%llx\n", base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934) prom_debug("sml size = 0x%x\n", size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936) prom_debug("prom_instantiate_sml: end...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) * Allocate room for and initialize TCE tables
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942) #ifdef __BIG_ENDIAN__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943) static void __init prom_initialize_tce_table(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) phandle node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946) ihandle phb_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947) char compatible[64], type[64], model[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948) char *path = prom_scratch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949) u64 base, align;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950) u32 minalign, minsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951) u64 tce_entry, *tce_entryp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) u64 local_alloc_top, local_alloc_bottom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953) u64 i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955) if (prom_iommu_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) prom_debug("starting prom_initialize_tce_table\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) /* Cache current top of allocs so we reserve a single block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961) local_alloc_top = alloc_top_high;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962) local_alloc_bottom = local_alloc_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) /* Search all nodes looking for PHBs. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965) for (node = 0; prom_next_node(&node); ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) compatible[0] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) type[0] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968) model[0] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969) prom_getprop(node, "compatible",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970) compatible, sizeof(compatible));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971) prom_getprop(node, "device_type", type, sizeof(type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972) prom_getprop(node, "model", model, sizeof(model));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974) if ((type[0] == 0) || (prom_strstr(type, "pci") == NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977) /* Keep the old logic intact to avoid regression. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978) if (compatible[0] != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979) if ((prom_strstr(compatible, "python") == NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980) (prom_strstr(compatible, "Speedwagon") == NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981) (prom_strstr(compatible, "Winnipeg") == NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983) } else if (model[0] != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) if ((prom_strstr(model, "ython") == NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985) (prom_strstr(model, "peedwagon") == NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986) (prom_strstr(model, "innipeg") == NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990) if (prom_getprop(node, "tce-table-minalign", &minalign,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991) sizeof(minalign)) == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992) minalign = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) if (prom_getprop(node, "tce-table-minsize", &minsize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994) sizeof(minsize)) == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995) minsize = 4UL << 20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1997) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1998) * Even though we read what OF wants, we just set the table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1999) * size to 4 MB. This is enough to map 2GB of PCI DMA space.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2000) * By doing this, we avoid the pitfalls of trying to DMA to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2001) * MMIO space and the DMA alias hole.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2002) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2003) minsize = 4UL << 20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2004)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2005) /* Align to the greater of the align or size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2006) align = max(minalign, minsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2007) base = alloc_down(minsize, align, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2008) if (base == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2009) prom_panic("ERROR, cannot find space for TCE table.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2010) if (base < local_alloc_bottom)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2011) local_alloc_bottom = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2013) /* It seems OF doesn't null-terminate the path :-( */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2014) memset(path, 0, sizeof(prom_scratch));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2015) /* Call OF to setup the TCE hardware */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2016) if (call_prom("package-to-path", 3, 1, node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2017) path, sizeof(prom_scratch) - 1) == PROM_ERROR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2018) prom_printf("package-to-path failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2019) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2020)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2021) /* Save away the TCE table attributes for later use. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2022) prom_setprop(node, path, "linux,tce-base", &base, sizeof(base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2023) prom_setprop(node, path, "linux,tce-size", &minsize, sizeof(minsize));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2025) prom_debug("TCE table: %s\n", path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2026) prom_debug("\tnode = 0x%x\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2027) prom_debug("\tbase = 0x%llx\n", base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2028) prom_debug("\tsize = 0x%x\n", minsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2030) /* Initialize the table to have a one-to-one mapping
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2031) * over the allocated size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2032) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2033) tce_entryp = (u64 *)base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2034) for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2035) tce_entry = (i << PAGE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2036) tce_entry |= 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2037) *tce_entryp = tce_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2038) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2040) prom_printf("opening PHB %s", path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2041) phb_node = call_prom("open", 1, 1, path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2042) if (phb_node == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2043) prom_printf("... failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2044) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2045) prom_printf("... done\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2047) call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2048) phb_node, -1, minsize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2049) (u32) base, (u32) (base >> 32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2050) call_prom("close", 1, 0, phb_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2051) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2053) reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2054)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2055) /* These are only really needed if there is a memory limit in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2056) * effect, but we don't know so export them always. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2057) prom_tce_alloc_start = local_alloc_bottom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2058) prom_tce_alloc_end = local_alloc_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2059)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2060) /* Flag the first invalid entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2061) prom_debug("ending prom_initialize_tce_table\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2062) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2063) #endif /* __BIG_ENDIAN__ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2064) #endif /* CONFIG_PPC64 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2065)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2066) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2067) * With CHRP SMP we need to use the OF to start the other processors.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2068) * We can't wait until smp_boot_cpus (the OF is trashed by then)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2069) * so we have to put the processors into a holding pattern controlled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2070) * by the kernel (not OF) before we destroy the OF.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2071) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2072) * This uses a chunk of low memory, puts some holding pattern
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2073) * code there and sends the other processors off to there until
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2074) * smp_boot_cpus tells them to do something. The holding pattern
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2075) * checks that address until its cpu # is there, when it is that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2076) * cpu jumps to __secondary_start(). smp_boot_cpus() takes care
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2077) * of setting those values.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2078) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2079) * We also use physical address 0x4 here to tell when a cpu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2080) * is in its holding pattern code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2081) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2082) * -- Cort
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2083) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2084) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2085) * We want to reference the copy of __secondary_hold_* in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2086) * 0 - 0x100 address range
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2087) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2088) #define LOW_ADDR(x) (((unsigned long) &(x)) & 0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2089)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2090) static void __init prom_hold_cpus(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2091) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2092) unsigned long i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2093) phandle node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2094) char type[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2095) unsigned long *spinloop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2096) = (void *) LOW_ADDR(__secondary_hold_spinloop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2097) unsigned long *acknowledge
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2098) = (void *) LOW_ADDR(__secondary_hold_acknowledge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2099) unsigned long secondary_hold = LOW_ADDR(__secondary_hold);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2101) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2102) * On pseries, if RTAS supports "query-cpu-stopped-state",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2103) * we skip this stage, the CPUs will be started by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2104) * kernel using RTAS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2105) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2106) if ((of_platform == PLATFORM_PSERIES ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2107) of_platform == PLATFORM_PSERIES_LPAR) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2108) rtas_has_query_cpu_stopped) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2109) prom_printf("prom_hold_cpus: skipped\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2110) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2113) prom_debug("prom_hold_cpus: start...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2114) prom_debug(" 1) spinloop = 0x%lx\n", (unsigned long)spinloop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2115) prom_debug(" 1) *spinloop = 0x%lx\n", *spinloop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2116) prom_debug(" 1) acknowledge = 0x%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2117) (unsigned long)acknowledge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2118) prom_debug(" 1) *acknowledge = 0x%lx\n", *acknowledge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2119) prom_debug(" 1) secondary_hold = 0x%lx\n", secondary_hold);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2121) /* Set the common spinloop variable, so all of the secondary cpus
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2122) * will block when they are awakened from their OF spinloop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2123) * This must occur for both SMP and non SMP kernels, since OF will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2124) * be trashed when we move the kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2125) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2126) *spinloop = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2128) /* look for cpus */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2129) for (node = 0; prom_next_node(&node); ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2130) unsigned int cpu_no;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2131) __be32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2133) type[0] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2134) prom_getprop(node, "device_type", type, sizeof(type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2135) if (prom_strcmp(type, "cpu") != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2136) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2138) /* Skip non-configured cpus. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2139) if (prom_getprop(node, "status", type, sizeof(type)) > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2140) if (prom_strcmp(type, "okay") != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2141) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2143) reg = cpu_to_be32(-1); /* make sparse happy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2144) prom_getprop(node, "reg", ®, sizeof(reg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2145) cpu_no = be32_to_cpu(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2147) prom_debug("cpu hw idx = %u\n", cpu_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2149) /* Init the acknowledge var which will be reset by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2150) * the secondary cpu when it awakens from its OF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2151) * spinloop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2152) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2153) *acknowledge = (unsigned long)-1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2155) if (cpu_no != prom.cpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2156) /* Primary Thread of non-boot cpu or any thread */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2157) prom_printf("starting cpu hw idx %u... ", cpu_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2158) call_prom("start-cpu", 3, 0, node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2159) secondary_hold, cpu_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2161) for (i = 0; (i < 100000000) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2162) (*acknowledge == ((unsigned long)-1)); i++ )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2163) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2165) if (*acknowledge == cpu_no)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2166) prom_printf("done\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2167) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2168) prom_printf("failed: %lx\n", *acknowledge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2170) #ifdef CONFIG_SMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2171) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2172) prom_printf("boot cpu hw idx %u\n", cpu_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2173) #endif /* CONFIG_SMP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2176) prom_debug("prom_hold_cpus: end...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2180) static void __init prom_init_client_services(unsigned long pp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2182) /* Get a handle to the prom entry point before anything else */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2183) prom_entry = pp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2185) /* get a handle for the stdout device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2186) prom.chosen = call_prom("finddevice", 1, 1, ADDR("/chosen"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2187) if (!PHANDLE_VALID(prom.chosen))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2188) prom_panic("cannot find chosen"); /* msg won't be printed :( */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2190) /* get device tree root */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2191) prom.root = call_prom("finddevice", 1, 1, ADDR("/"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2192) if (!PHANDLE_VALID(prom.root))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2193) prom_panic("cannot find device tree root"); /* msg won't be printed :( */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2195) prom.mmumap = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2198) #ifdef CONFIG_PPC32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2199) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2200) * For really old powermacs, we need to map things we claim.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2201) * For that, we need the ihandle of the mmu.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2202) * Also, on the longtrail, we need to work around other bugs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2203) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2204) static void __init prom_find_mmu(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2206) phandle oprom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2207) char version[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2209) oprom = call_prom("finddevice", 1, 1, ADDR("/openprom"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2210) if (!PHANDLE_VALID(oprom))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2211) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2212) if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2213) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2214) version[sizeof(version) - 1] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2215) /* XXX might need to add other versions here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2216) if (prom_strcmp(version, "Open Firmware, 1.0.5") == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2217) of_workarounds = OF_WA_CLAIM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2218) else if (prom_strncmp(version, "FirmWorks,3.", 12) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2219) of_workarounds = OF_WA_CLAIM | OF_WA_LONGTRAIL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2220) call_prom("interpret", 1, 1, "dev /memory 0 to allow-reclaim");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2221) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2222) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2223) prom.memory = call_prom("open", 1, 1, ADDR("/memory"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2224) prom_getprop(prom.chosen, "mmu", &prom.mmumap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2225) sizeof(prom.mmumap));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2226) prom.mmumap = be32_to_cpu(prom.mmumap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2227) if (!IHANDLE_VALID(prom.memory) || !IHANDLE_VALID(prom.mmumap))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2228) of_workarounds &= ~OF_WA_CLAIM; /* hmmm */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2230) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2231) #define prom_find_mmu()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2232) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2234) static void __init prom_init_stdout(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2236) char *path = of_stdout_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2237) char type[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2238) phandle stdout_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2239) __be32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2241) if (prom_getprop(prom.chosen, "stdout", &val, sizeof(val)) <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2242) prom_panic("cannot find stdout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2244) prom.stdout = be32_to_cpu(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2246) /* Get the full OF pathname of the stdout device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2247) memset(path, 0, 256);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2248) call_prom("instance-to-path", 3, 1, prom.stdout, path, 255);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2249) prom_printf("OF stdout device is: %s\n", of_stdout_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2250) prom_setprop(prom.chosen, "/chosen", "linux,stdout-path",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2251) path, prom_strlen(path) + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2253) /* instance-to-package fails on PA-Semi */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2254) stdout_node = call_prom("instance-to-package", 1, 1, prom.stdout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2255) if (stdout_node != PROM_ERROR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2256) val = cpu_to_be32(stdout_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2258) /* If it's a display, note it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2259) memset(type, 0, sizeof(type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2260) prom_getprop(stdout_node, "device_type", type, sizeof(type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2261) if (prom_strcmp(type, "display") == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2262) prom_setprop(stdout_node, path, "linux,boot-display", NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2266) static int __init prom_find_machine_type(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2267) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2268) char compat[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2269) int len, i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2270) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2271) phandle rtas;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2272) int x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2273) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2275) /* Look for a PowerMac or a Cell */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2276) len = prom_getprop(prom.root, "compatible",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2277) compat, sizeof(compat)-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2278) if (len > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2279) compat[len] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2280) while (i < len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2281) char *p = &compat[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2282) int sl = prom_strlen(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2283) if (sl == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2284) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2285) if (prom_strstr(p, "Power Macintosh") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2286) prom_strstr(p, "MacRISC"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2287) return PLATFORM_POWERMAC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2288) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2289) /* We must make sure we don't detect the IBM Cell
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2290) * blades as pSeries due to some firmware issues,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2291) * so we do it here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2292) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2293) if (prom_strstr(p, "IBM,CBEA") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2294) prom_strstr(p, "IBM,CPBW-1.0"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2295) return PLATFORM_GENERIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2296) #endif /* CONFIG_PPC64 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2297) i += sl + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2300) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2301) /* Try to figure out if it's an IBM pSeries or any other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2302) * PAPR compliant platform. We assume it is if :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2303) * - /device_type is "chrp" (please, do NOT use that for future
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2304) * non-IBM designs !
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2305) * - it has /rtas
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2306) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2307) len = prom_getprop(prom.root, "device_type",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2308) compat, sizeof(compat)-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2309) if (len <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2310) return PLATFORM_GENERIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2311) if (prom_strcmp(compat, "chrp"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2312) return PLATFORM_GENERIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2314) /* Default to pSeries. We need to know if we are running LPAR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2315) rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2316) if (!PHANDLE_VALID(rtas))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2317) return PLATFORM_GENERIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2318) x = prom_getproplen(rtas, "ibm,hypertas-functions");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2319) if (x != PROM_ERROR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2320) prom_debug("Hypertas detected, assuming LPAR !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2321) return PLATFORM_PSERIES_LPAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2323) return PLATFORM_PSERIES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2324) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2325) return PLATFORM_GENERIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2326) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2329) static int __init prom_set_color(ihandle ih, int i, int r, int g, int b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2330) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2331) return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2334) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2335) * If we have a display that we don't know how to drive,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2336) * we will want to try to execute OF's open method for it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2337) * later. However, OF will probably fall over if we do that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2338) * we've taken over the MMU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2339) * So we check whether we will need to open the display,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2340) * and if so, open it now.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2341) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2342) static void __init prom_check_displays(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2343) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2344) char type[16], *path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2345) phandle node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2346) ihandle ih;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2347) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2349) static const unsigned char default_colors[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2350) 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2351) 0x00, 0x00, 0xaa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2352) 0x00, 0xaa, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2353) 0x00, 0xaa, 0xaa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2354) 0xaa, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2355) 0xaa, 0x00, 0xaa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2356) 0xaa, 0xaa, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2357) 0xaa, 0xaa, 0xaa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2358) 0x55, 0x55, 0x55,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2359) 0x55, 0x55, 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2360) 0x55, 0xff, 0x55,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2361) 0x55, 0xff, 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2362) 0xff, 0x55, 0x55,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2363) 0xff, 0x55, 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2364) 0xff, 0xff, 0x55,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2365) 0xff, 0xff, 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2366) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2367) const unsigned char *clut;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2369) prom_debug("Looking for displays\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2370) for (node = 0; prom_next_node(&node); ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2371) memset(type, 0, sizeof(type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2372) prom_getprop(node, "device_type", type, sizeof(type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2373) if (prom_strcmp(type, "display") != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2374) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2376) /* It seems OF doesn't null-terminate the path :-( */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2377) path = prom_scratch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2378) memset(path, 0, sizeof(prom_scratch));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2380) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2381) * leave some room at the end of the path for appending extra
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2382) * arguments
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2383) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2384) if (call_prom("package-to-path", 3, 1, node, path,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2385) sizeof(prom_scratch) - 10) == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2386) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2387) prom_printf("found display : %s, opening... ", path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2389) ih = call_prom("open", 1, 1, path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2390) if (ih == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2391) prom_printf("failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2392) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2395) /* Success */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2396) prom_printf("done\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2397) prom_setprop(node, path, "linux,opened", NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2399) /* Setup a usable color table when the appropriate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2400) * method is available. Should update this to set-colors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2401) clut = default_colors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2402) for (i = 0; i < 16; i++, clut += 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2403) if (prom_set_color(ih, i, clut[0], clut[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2404) clut[2]) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2405) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2407) #ifdef CONFIG_LOGO_LINUX_CLUT224
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2408) clut = PTRRELOC(logo_linux_clut224.clut);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2409) for (i = 0; i < logo_linux_clut224.clutsize; i++, clut += 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2410) if (prom_set_color(ih, i + 32, clut[0], clut[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2411) clut[2]) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2412) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2413) #endif /* CONFIG_LOGO_LINUX_CLUT224 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2415) #ifdef CONFIG_PPC_EARLY_DEBUG_BOOTX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2416) if (prom_getprop(node, "linux,boot-display", NULL, 0) !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2417) PROM_ERROR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2418) u32 width, height, pitch, addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2420) prom_printf("Setting btext !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2422) if (prom_getprop(node, "width", &width, 4) == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2423) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2425) if (prom_getprop(node, "height", &height, 4) == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2426) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2428) if (prom_getprop(node, "linebytes", &pitch, 4) == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2429) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2431) if (prom_getprop(node, "address", &addr, 4) == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2432) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2434) prom_printf("W=%d H=%d LB=%d addr=0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2435) width, height, pitch, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2436) btext_setup_display(width, height, 8, pitch, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2437) btext_prepare_BAT();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2438) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2439) #endif /* CONFIG_PPC_EARLY_DEBUG_BOOTX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2444) /* Return (relocated) pointer to this much memory: moves initrd if reqd. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2445) static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2446) unsigned long needed, unsigned long align)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2447) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2448) void *ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2450) *mem_start = ALIGN(*mem_start, align);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2451) while ((*mem_start + needed) > *mem_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2452) unsigned long room, chunk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2454) prom_debug("Chunk exhausted, claiming more at %lx...\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2455) alloc_bottom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2456) room = alloc_top - alloc_bottom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2457) if (room > DEVTREE_CHUNK_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2458) room = DEVTREE_CHUNK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2459) if (room < PAGE_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2460) prom_panic("No memory for flatten_device_tree "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2461) "(no room)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2462) chunk = alloc_up(room, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2463) if (chunk == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2464) prom_panic("No memory for flatten_device_tree "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2465) "(claim failed)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2466) *mem_end = chunk + room;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2469) ret = (void *)*mem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2470) *mem_start += needed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2472) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2475) #define dt_push_token(token, mem_start, mem_end) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2476) void *room = make_room(mem_start, mem_end, 4, 4); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2477) *(__be32 *)room = cpu_to_be32(token); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2478) } while(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2480) static unsigned long __init dt_find_string(char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2481) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2482) char *s, *os;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2484) s = os = (char *)dt_string_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2485) s += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2486) while (s < (char *)dt_string_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2487) if (prom_strcmp(s, str) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2488) return s - os;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2489) s += prom_strlen(s) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2491) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2494) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2495) * The Open Firmware 1275 specification states properties must be 31 bytes or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2496) * less, however not all firmwares obey this. Make it 64 bytes to be safe.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2497) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2498) #define MAX_PROPERTY_NAME 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2500) static void __init scan_dt_build_strings(phandle node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2501) unsigned long *mem_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2502) unsigned long *mem_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2503) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2504) char *prev_name, *namep, *sstart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2505) unsigned long soff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2506) phandle child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2508) sstart = (char *)dt_string_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2510) /* get and store all property names */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2511) prev_name = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2512) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2513) /* 64 is max len of name including nul. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2514) namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2515) if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2516) /* No more nodes: unwind alloc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2517) *mem_start = (unsigned long)namep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2518) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2521) /* skip "name" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2522) if (prom_strcmp(namep, "name") == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2523) *mem_start = (unsigned long)namep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2524) prev_name = "name";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2525) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2526) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2527) /* get/create string entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2528) soff = dt_find_string(namep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2529) if (soff != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2530) *mem_start = (unsigned long)namep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2531) namep = sstart + soff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2532) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2533) /* Trim off some if we can */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2534) *mem_start = (unsigned long)namep + prom_strlen(namep) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2535) dt_string_end = *mem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2536) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2537) prev_name = namep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2538) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2540) /* do all our children */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2541) child = call_prom("child", 1, 1, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2542) while (child != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2543) scan_dt_build_strings(child, mem_start, mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2544) child = call_prom("peer", 1, 1, child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2545) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2548) static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2549) unsigned long *mem_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2550) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2551) phandle child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2552) char *namep, *prev_name, *sstart, *p, *ep, *lp, *path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2553) unsigned long soff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2554) unsigned char *valp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2555) static char pname[MAX_PROPERTY_NAME] __prombss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2556) int l, room, has_phandle = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2558) dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2560) /* get the node's full name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2561) namep = (char *)*mem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2562) room = *mem_end - *mem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2563) if (room > 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2564) room = 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2565) l = call_prom("package-to-path", 3, 1, node, namep, room);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2566) if (l >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2567) /* Didn't fit? Get more room. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2568) if (l >= room) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2569) if (l >= *mem_end - *mem_start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2570) namep = make_room(mem_start, mem_end, l+1, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2571) call_prom("package-to-path", 3, 1, node, namep, l);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2573) namep[l] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2575) /* Fixup an Apple bug where they have bogus \0 chars in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2576) * middle of the path in some properties, and extract
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2577) * the unit name (everything after the last '/').
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2578) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2579) for (lp = p = namep, ep = namep + l; p < ep; p++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2580) if (*p == '/')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2581) lp = namep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2582) else if (*p != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2583) *lp++ = *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2585) *lp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2586) *mem_start = ALIGN((unsigned long)lp + 1, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2587) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2589) /* get it again for debugging */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2590) path = prom_scratch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2591) memset(path, 0, sizeof(prom_scratch));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2592) call_prom("package-to-path", 3, 1, node, path, sizeof(prom_scratch) - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2594) /* get and store all properties */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2595) prev_name = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2596) sstart = (char *)dt_string_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2597) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2598) if (call_prom("nextprop", 3, 1, node, prev_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2599) pname) != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2600) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2602) /* skip "name" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2603) if (prom_strcmp(pname, "name") == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2604) prev_name = "name";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2605) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2608) /* find string offset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2609) soff = dt_find_string(pname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2610) if (soff == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2611) prom_printf("WARNING: Can't find string index for"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2612) " <%s>, node %s\n", pname, path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2613) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2614) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2615) prev_name = sstart + soff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2617) /* get length */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2618) l = call_prom("getproplen", 2, 1, node, pname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2620) /* sanity checks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2621) if (l == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2622) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2624) /* push property head */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2625) dt_push_token(OF_DT_PROP, mem_start, mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2626) dt_push_token(l, mem_start, mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2627) dt_push_token(soff, mem_start, mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2629) /* push property content */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2630) valp = make_room(mem_start, mem_end, l, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2631) call_prom("getprop", 4, 1, node, pname, valp, l);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2632) *mem_start = ALIGN(*mem_start, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2634) if (!prom_strcmp(pname, "phandle"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2635) has_phandle = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2638) /* Add a "phandle" property if none already exist */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2639) if (!has_phandle) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2640) soff = dt_find_string("phandle");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2641) if (soff == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2642) prom_printf("WARNING: Can't find string index for <phandle> node %s\n", path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2643) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2644) dt_push_token(OF_DT_PROP, mem_start, mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2645) dt_push_token(4, mem_start, mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2646) dt_push_token(soff, mem_start, mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2647) valp = make_room(mem_start, mem_end, 4, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2648) *(__be32 *)valp = cpu_to_be32(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2649) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2650) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2652) /* do all our children */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2653) child = call_prom("child", 1, 1, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2654) while (child != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2655) scan_dt_build_struct(child, mem_start, mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2656) child = call_prom("peer", 1, 1, child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2659) dt_push_token(OF_DT_END_NODE, mem_start, mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2660) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2662) static void __init flatten_device_tree(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2663) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2664) phandle root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2665) unsigned long mem_start, mem_end, room;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2666) struct boot_param_header *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2667) char *namep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2668) u64 *rsvmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2670) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2671) * Check how much room we have between alloc top & bottom (+/- a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2672) * few pages), crop to 1MB, as this is our "chunk" size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2673) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2674) room = alloc_top - alloc_bottom - 0x4000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2675) if (room > DEVTREE_CHUNK_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2676) room = DEVTREE_CHUNK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2677) prom_debug("starting device tree allocs at %lx\n", alloc_bottom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2679) /* Now try to claim that */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2680) mem_start = (unsigned long)alloc_up(room, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2681) if (mem_start == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2682) prom_panic("Can't allocate initial device-tree chunk\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2683) mem_end = mem_start + room;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2685) /* Get root of tree */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2686) root = call_prom("peer", 1, 1, (phandle)0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2687) if (root == (phandle)0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2688) prom_panic ("couldn't get device tree root\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2690) /* Build header and make room for mem rsv map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2691) mem_start = ALIGN(mem_start, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2692) hdr = make_room(&mem_start, &mem_end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2693) sizeof(struct boot_param_header), 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2694) dt_header_start = (unsigned long)hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2695) rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2697) /* Start of strings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2698) mem_start = PAGE_ALIGN(mem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2699) dt_string_start = mem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2700) mem_start += 4; /* hole */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2702) /* Add "phandle" in there, we'll need it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2703) namep = make_room(&mem_start, &mem_end, 16, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2704) prom_strcpy(namep, "phandle");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2705) mem_start = (unsigned long)namep + prom_strlen(namep) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2707) /* Build string array */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2708) prom_printf("Building dt strings...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2709) scan_dt_build_strings(root, &mem_start, &mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2710) dt_string_end = mem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2712) /* Build structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2713) mem_start = PAGE_ALIGN(mem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2714) dt_struct_start = mem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2715) prom_printf("Building dt structure...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2716) scan_dt_build_struct(root, &mem_start, &mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2717) dt_push_token(OF_DT_END, &mem_start, &mem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2718) dt_struct_end = PAGE_ALIGN(mem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2720) /* Finish header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2721) hdr->boot_cpuid_phys = cpu_to_be32(prom.cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2722) hdr->magic = cpu_to_be32(OF_DT_HEADER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2723) hdr->totalsize = cpu_to_be32(dt_struct_end - dt_header_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2724) hdr->off_dt_struct = cpu_to_be32(dt_struct_start - dt_header_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2725) hdr->off_dt_strings = cpu_to_be32(dt_string_start - dt_header_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2726) hdr->dt_strings_size = cpu_to_be32(dt_string_end - dt_string_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2727) hdr->off_mem_rsvmap = cpu_to_be32(((unsigned long)rsvmap) - dt_header_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2728) hdr->version = cpu_to_be32(OF_DT_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2729) /* Version 16 is not backward compatible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2730) hdr->last_comp_version = cpu_to_be32(0x10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2732) /* Copy the reserve map in */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2733) memcpy(rsvmap, mem_reserve_map, sizeof(mem_reserve_map));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2735) #ifdef DEBUG_PROM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2736) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2737) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2738) prom_printf("reserved memory map:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2739) for (i = 0; i < mem_reserve_cnt; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2740) prom_printf(" %llx - %llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2741) be64_to_cpu(mem_reserve_map[i].base),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2742) be64_to_cpu(mem_reserve_map[i].size));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2743) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2744) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2745) /* Bump mem_reserve_cnt to cause further reservations to fail
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2746) * since it's too late.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2747) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2748) mem_reserve_cnt = MEM_RESERVE_MAP_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2750) prom_printf("Device tree strings 0x%lx -> 0x%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2751) dt_string_start, dt_string_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2752) prom_printf("Device tree struct 0x%lx -> 0x%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2753) dt_struct_start, dt_struct_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2754) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2756) #ifdef CONFIG_PPC_MAPLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2757) /* PIBS Version 1.05.0000 04/26/2005 has an incorrect /ht/isa/ranges property.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2758) * The values are bad, and it doesn't even have the right number of cells. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2759) static void __init fixup_device_tree_maple(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2760) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2761) phandle isa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2762) u32 rloc = 0x01002000; /* IO space; PCI device = 4 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2763) u32 isa_ranges[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2764) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2766) name = "/ht@0/isa@4";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2767) isa = call_prom("finddevice", 1, 1, ADDR(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2768) if (!PHANDLE_VALID(isa)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2769) name = "/ht@0/isa@6";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2770) isa = call_prom("finddevice", 1, 1, ADDR(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2771) rloc = 0x01003000; /* IO space; PCI device = 6 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2772) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2773) if (!PHANDLE_VALID(isa))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2774) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2776) if (prom_getproplen(isa, "ranges") != 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2777) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2778) if (prom_getprop(isa, "ranges", isa_ranges, sizeof(isa_ranges))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2779) == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2780) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2782) if (isa_ranges[0] != 0x1 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2783) isa_ranges[1] != 0xf4000000 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2784) isa_ranges[2] != 0x00010000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2785) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2787) prom_printf("Fixing up bogus ISA range on Maple/Apache...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2789) isa_ranges[0] = 0x1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2790) isa_ranges[1] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2791) isa_ranges[2] = rloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2792) isa_ranges[3] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2793) isa_ranges[4] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2794) isa_ranges[5] = 0x00010000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2795) prom_setprop(isa, name, "ranges",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2796) isa_ranges, sizeof(isa_ranges));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2799) #define CPC925_MC_START 0xf8000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2800) #define CPC925_MC_LENGTH 0x1000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2801) /* The values for memory-controller don't have right number of cells */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2802) static void __init fixup_device_tree_maple_memory_controller(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2803) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2804) phandle mc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2805) u32 mc_reg[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2806) char *name = "/hostbridge@f8000000";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2807) u32 ac, sc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2809) mc = call_prom("finddevice", 1, 1, ADDR(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2810) if (!PHANDLE_VALID(mc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2811) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2813) if (prom_getproplen(mc, "reg") != 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2814) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2816) prom_getprop(prom.root, "#address-cells", &ac, sizeof(ac));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2817) prom_getprop(prom.root, "#size-cells", &sc, sizeof(sc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2818) if ((ac != 2) || (sc != 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2819) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2821) if (prom_getprop(mc, "reg", mc_reg, sizeof(mc_reg)) == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2822) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2823)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2824) if (mc_reg[0] != CPC925_MC_START || mc_reg[1] != CPC925_MC_LENGTH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2825) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2826)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2827) prom_printf("Fixing up bogus hostbridge on Maple...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2829) mc_reg[0] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2830) mc_reg[1] = CPC925_MC_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2831) mc_reg[2] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2832) mc_reg[3] = CPC925_MC_LENGTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2833) prom_setprop(mc, name, "reg", mc_reg, sizeof(mc_reg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2835) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2836) #define fixup_device_tree_maple()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2837) #define fixup_device_tree_maple_memory_controller()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2838) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2840) #ifdef CONFIG_PPC_CHRP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2841) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2842) * Pegasos and BriQ lacks the "ranges" property in the isa node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2843) * Pegasos needs decimal IRQ 14/15, not hexadecimal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2844) * Pegasos has the IDE configured in legacy mode, but advertised as native
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2845) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2846) static void __init fixup_device_tree_chrp(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2847) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2848) phandle ph;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2849) u32 prop[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2850) u32 rloc = 0x01006000; /* IO space; PCI device = 12 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2851) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2852) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2854) name = "/pci@80000000/isa@c";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2855) ph = call_prom("finddevice", 1, 1, ADDR(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2856) if (!PHANDLE_VALID(ph)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2857) name = "/pci@ff500000/isa@6";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2858) ph = call_prom("finddevice", 1, 1, ADDR(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2859) rloc = 0x01003000; /* IO space; PCI device = 6 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2860) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2861) if (PHANDLE_VALID(ph)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2862) rc = prom_getproplen(ph, "ranges");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2863) if (rc == 0 || rc == PROM_ERROR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2864) prom_printf("Fixing up missing ISA range on Pegasos...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2866) prop[0] = 0x1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2867) prop[1] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2868) prop[2] = rloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2869) prop[3] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2870) prop[4] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2871) prop[5] = 0x00010000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2872) prom_setprop(ph, name, "ranges", prop, sizeof(prop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2873) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2874) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2876) name = "/pci@80000000/ide@C,1";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2877) ph = call_prom("finddevice", 1, 1, ADDR(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2878) if (PHANDLE_VALID(ph)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2879) prom_printf("Fixing up IDE interrupt on Pegasos...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2880) prop[0] = 14;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2881) prop[1] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2882) prom_setprop(ph, name, "interrupts", prop, 2*sizeof(u32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2883) prom_printf("Fixing up IDE class-code on Pegasos...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2884) rc = prom_getprop(ph, "class-code", prop, sizeof(u32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2885) if (rc == sizeof(u32)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2886) prop[0] &= ~0x5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2887) prom_setprop(ph, name, "class-code", prop, sizeof(u32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2888) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2889) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2890) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2891) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2892) #define fixup_device_tree_chrp()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2893) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2895) #if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2896) static void __init fixup_device_tree_pmac(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2897) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2898) phandle u3, i2c, mpic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2899) u32 u3_rev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2900) u32 interrupts[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2901) u32 parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2902)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2903) /* Some G5s have a missing interrupt definition, fix it up here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2904) u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2905) if (!PHANDLE_VALID(u3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2906) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2907) i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2908) if (!PHANDLE_VALID(i2c))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2909) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2910) mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2911) if (!PHANDLE_VALID(mpic))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2912) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2914) /* check if proper rev of u3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2915) if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2916) == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2917) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2918) if (u3_rev < 0x35 || u3_rev > 0x39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2919) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2920) /* does it need fixup ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2921) if (prom_getproplen(i2c, "interrupts") > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2922) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2924) prom_printf("fixing up bogus interrupts for u3 i2c...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2926) /* interrupt on this revision of u3 is number 0 and level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2927) interrupts[0] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2928) interrupts[1] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2929) prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupts",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2930) &interrupts, sizeof(interrupts));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2931) parent = (u32)mpic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2932) prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupt-parent",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2933) &parent, sizeof(parent));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2934) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2935) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2936) #define fixup_device_tree_pmac()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2937) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2939) #ifdef CONFIG_PPC_EFIKA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2940) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2941) * The MPC5200 FEC driver requires an phy-handle property to tell it how
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2942) * to talk to the phy. If the phy-handle property is missing, then this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2943) * function is called to add the appropriate nodes and link it to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2944) * ethernet node.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2945) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2946) static void __init fixup_device_tree_efika_add_phy(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2947) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2948) u32 node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2949) char prop[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2950) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2952) /* Check if /builtin/ethernet exists - bail if it doesn't */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2953) node = call_prom("finddevice", 1, 1, ADDR("/builtin/ethernet"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2954) if (!PHANDLE_VALID(node))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2955) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2957) /* Check if the phy-handle property exists - bail if it does */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2958) rv = prom_getprop(node, "phy-handle", prop, sizeof(prop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2959) if (rv <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2960) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2961)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2962) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2963) * At this point the ethernet device doesn't have a phy described.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2964) * Now we need to add the missing phy node and linkage
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2965) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2967) /* Check for an MDIO bus node - if missing then create one */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2968) node = call_prom("finddevice", 1, 1, ADDR("/builtin/mdio"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2969) if (!PHANDLE_VALID(node)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2970) prom_printf("Adding Ethernet MDIO node\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2971) call_prom("interpret", 1, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2972) " s\" /builtin\" find-device"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2973) " new-device"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2974) " 1 encode-int s\" #address-cells\" property"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2975) " 0 encode-int s\" #size-cells\" property"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2976) " s\" mdio\" device-name"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2977) " s\" fsl,mpc5200b-mdio\" encode-string"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2978) " s\" compatible\" property"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2979) " 0xf0003000 0x400 reg"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2980) " 0x2 encode-int"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2981) " 0x5 encode-int encode+"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2982) " 0x3 encode-int encode+"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2983) " s\" interrupts\" property"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2984) " finish-device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2985) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2987) /* Check for a PHY device node - if missing then create one and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2988) * give it's phandle to the ethernet node */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2989) node = call_prom("finddevice", 1, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2990) ADDR("/builtin/mdio/ethernet-phy"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2991) if (!PHANDLE_VALID(node)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2992) prom_printf("Adding Ethernet PHY node\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2993) call_prom("interpret", 1, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2994) " s\" /builtin/mdio\" find-device"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2995) " new-device"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2996) " s\" ethernet-phy\" device-name"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2997) " 0x10 encode-int s\" reg\" property"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2998) " my-self"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2999) " ihandle>phandle"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3000) " finish-device"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3001) " s\" /builtin/ethernet\" find-device"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3002) " encode-int"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3003) " s\" phy-handle\" property"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3004) " device-end");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3005) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3006) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3007)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3008) static void __init fixup_device_tree_efika(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3009) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3010) int sound_irq[3] = { 2, 2, 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3011) int bcomm_irq[3*16] = { 3,0,0, 3,1,0, 3,2,0, 3,3,0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3012) 3,4,0, 3,5,0, 3,6,0, 3,7,0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3013) 3,8,0, 3,9,0, 3,10,0, 3,11,0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3014) 3,12,0, 3,13,0, 3,14,0, 3,15,0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3015) u32 node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3016) char prop[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3017) int rv, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3019) /* Check if we're really running on a EFIKA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3020) node = call_prom("finddevice", 1, 1, ADDR("/"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3021) if (!PHANDLE_VALID(node))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3022) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3024) rv = prom_getprop(node, "model", prop, sizeof(prop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3025) if (rv == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3026) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3027) if (prom_strcmp(prop, "EFIKA5K2"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3028) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3030) prom_printf("Applying EFIKA device tree fixups\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3032) /* Claiming to be 'chrp' is death */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3033) node = call_prom("finddevice", 1, 1, ADDR("/"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3034) rv = prom_getprop(node, "device_type", prop, sizeof(prop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3035) if (rv != PROM_ERROR && (prom_strcmp(prop, "chrp") == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3036) prom_setprop(node, "/", "device_type", "efika", sizeof("efika"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3038) /* CODEGEN,description is exposed in /proc/cpuinfo so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3039) fix that too */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3040) rv = prom_getprop(node, "CODEGEN,description", prop, sizeof(prop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3041) if (rv != PROM_ERROR && (prom_strstr(prop, "CHRP")))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3042) prom_setprop(node, "/", "CODEGEN,description",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3043) "Efika 5200B PowerPC System",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3044) sizeof("Efika 5200B PowerPC System"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3045)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3046) /* Fixup bestcomm interrupts property */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3047) node = call_prom("finddevice", 1, 1, ADDR("/builtin/bestcomm"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3048) if (PHANDLE_VALID(node)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3049) len = prom_getproplen(node, "interrupts");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3050) if (len == 12) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3051) prom_printf("Fixing bestcomm interrupts property\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3052) prom_setprop(node, "/builtin/bestcom", "interrupts",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3053) bcomm_irq, sizeof(bcomm_irq));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3054) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3055) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3056)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3057) /* Fixup sound interrupts property */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3058) node = call_prom("finddevice", 1, 1, ADDR("/builtin/sound"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3059) if (PHANDLE_VALID(node)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3060) rv = prom_getprop(node, "interrupts", prop, sizeof(prop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3061) if (rv == PROM_ERROR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3062) prom_printf("Adding sound interrupts property\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3063) prom_setprop(node, "/builtin/sound", "interrupts",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3064) sound_irq, sizeof(sound_irq));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3065) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3066) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3068) /* Make sure ethernet phy-handle property exists */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3069) fixup_device_tree_efika_add_phy();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3070) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3071) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3072) #define fixup_device_tree_efika()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3073) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3075) #ifdef CONFIG_PPC_PASEMI_NEMO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3076) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3077) * CFE supplied on Nemo is broken in several ways, biggest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3078) * problem is that it reassigns ISA interrupts to unused mpic ints.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3079) * Add an interrupt-controller property for the io-bridge to use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3080) * and correct the ints so we can attach them to an irq_domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3081) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3082) static void __init fixup_device_tree_pasemi(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3083) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3084) u32 interrupts[2], parent, rval, val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3085) char *name, *pci_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3086) phandle iob, node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3088) /* Find the root pci node */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3089) name = "/pxp@0,e0000000";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3090) iob = call_prom("finddevice", 1, 1, ADDR(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3091) if (!PHANDLE_VALID(iob))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3092) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3093)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3094) /* check if interrupt-controller node set yet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3095) if (prom_getproplen(iob, "interrupt-controller") !=PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3096) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3097)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3098) prom_printf("adding interrupt-controller property for SB600...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3099)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3100) prom_setprop(iob, name, "interrupt-controller", &val, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3102) pci_name = "/pxp@0,e0000000/pci@11";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3103) node = call_prom("finddevice", 1, 1, ADDR(pci_name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3104) parent = ADDR(iob);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3106) for( ; prom_next_node(&node); ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3107) /* scan each node for one with an interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3108) if (!PHANDLE_VALID(node))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3109) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3111) rval = prom_getproplen(node, "interrupts");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3112) if (rval == 0 || rval == PROM_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3113) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3115) prom_getprop(node, "interrupts", &interrupts, sizeof(interrupts));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3116) if ((interrupts[0] < 212) || (interrupts[0] > 222))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3117) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3119) /* found a node, update both interrupts and interrupt-parent */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3120) if ((interrupts[0] >= 212) && (interrupts[0] <= 215))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3121) interrupts[0] -= 203;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3122) if ((interrupts[0] >= 216) && (interrupts[0] <= 220))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3123) interrupts[0] -= 213;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3124) if (interrupts[0] == 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3125) interrupts[0] = 14;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3126) if (interrupts[0] == 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3127) interrupts[0] = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3129) prom_setprop(node, pci_name, "interrupts", interrupts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3130) sizeof(interrupts));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3131) prom_setprop(node, pci_name, "interrupt-parent", &parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3132) sizeof(parent));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3135) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3136) * The io-bridge has device_type set to 'io-bridge' change it to 'isa'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3137) * so that generic isa-bridge code can add the SB600 and its on-board
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3138) * peripherals.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3139) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3140) name = "/pxp@0,e0000000/io-bridge@0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3141) iob = call_prom("finddevice", 1, 1, ADDR(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3142) if (!PHANDLE_VALID(iob))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3143) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3145) /* device_type is already set, just change it. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3147) prom_printf("Changing device_type of SB600 node...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3149) prom_setprop(iob, name, "device_type", "isa", sizeof("isa"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3151) #else /* !CONFIG_PPC_PASEMI_NEMO */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3152) static inline void fixup_device_tree_pasemi(void) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3153) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3155) static void __init fixup_device_tree(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3157) fixup_device_tree_maple();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3158) fixup_device_tree_maple_memory_controller();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3159) fixup_device_tree_chrp();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3160) fixup_device_tree_pmac();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3161) fixup_device_tree_efika();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3162) fixup_device_tree_pasemi();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3165) static void __init prom_find_boot_cpu(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3167) __be32 rval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3168) ihandle prom_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3169) phandle cpu_pkg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3171) rval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3172) if (prom_getprop(prom.chosen, "cpu", &rval, sizeof(rval)) <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3173) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3174) prom_cpu = be32_to_cpu(rval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3176) cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3178) if (!PHANDLE_VALID(cpu_pkg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3179) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3181) prom_getprop(cpu_pkg, "reg", &rval, sizeof(rval));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3182) prom.cpu = be32_to_cpu(rval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3184) prom_debug("Booting CPU hw index = %d\n", prom.cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3187) static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3189) #ifdef CONFIG_BLK_DEV_INITRD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3190) if (r3 && r4 && r4 != 0xdeadbeef) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3191) __be64 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3193) prom_initrd_start = is_kernel_addr(r3) ? __pa(r3) : r3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3194) prom_initrd_end = prom_initrd_start + r4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3196) val = cpu_to_be64(prom_initrd_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3197) prom_setprop(prom.chosen, "/chosen", "linux,initrd-start",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3198) &val, sizeof(val));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3199) val = cpu_to_be64(prom_initrd_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3200) prom_setprop(prom.chosen, "/chosen", "linux,initrd-end",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3201) &val, sizeof(val));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3203) reserve_mem(prom_initrd_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3204) prom_initrd_end - prom_initrd_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3206) prom_debug("initrd_start=0x%lx\n", prom_initrd_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3207) prom_debug("initrd_end=0x%lx\n", prom_initrd_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3209) #endif /* CONFIG_BLK_DEV_INITRD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3212) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3213) #ifdef CONFIG_RELOCATABLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3214) static void reloc_toc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3215) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3218) static void unreloc_toc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3221) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3222) static void __reloc_toc(unsigned long offset, unsigned long nr_entries)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3224) unsigned long i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3225) unsigned long *toc_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3227) /* Get the start of the TOC by using r2 directly. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3228) asm volatile("addi %0,2,-0x8000" : "=b" (toc_entry));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3230) for (i = 0; i < nr_entries; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3231) *toc_entry = *toc_entry + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3232) toc_entry++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3236) static void reloc_toc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3237) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3238) unsigned long offset = reloc_offset();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3239) unsigned long nr_entries =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3240) (__prom_init_toc_end - __prom_init_toc_start) / sizeof(long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3242) __reloc_toc(offset, nr_entries);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3244) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3247) static void unreloc_toc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3248) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3249) unsigned long offset = reloc_offset();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3250) unsigned long nr_entries =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3251) (__prom_init_toc_end - __prom_init_toc_start) / sizeof(long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3253) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3255) __reloc_toc(-offset, nr_entries);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3257) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3258) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3260) #ifdef CONFIG_PPC_SVM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3261) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3262) * Perform the Enter Secure Mode ultracall.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3263) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3264) static int enter_secure_mode(unsigned long kbase, unsigned long fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3265) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3266) register unsigned long r3 asm("r3") = UV_ESM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3267) register unsigned long r4 asm("r4") = kbase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3268) register unsigned long r5 asm("r5") = fdt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3270) asm volatile("sc 2" : "+r"(r3) : "r"(r4), "r"(r5));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3272) return r3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3275) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3276) * Call the Ultravisor to transfer us to secure memory if we have an ESM blob.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3277) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3278) static void __init setup_secure_guest(unsigned long kbase, unsigned long fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3279) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3280) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3282) if (!prom_svm_enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3283) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3285) /* Switch to secure mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3286) prom_printf("Switching to secure mode.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3288) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3289) * The ultravisor will do an integrity check of the kernel image but we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3290) * relocated it so the check will fail. Restore the original image by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3291) * relocating it back to the kernel virtual base address.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3292) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3293) if (IS_ENABLED(CONFIG_RELOCATABLE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3294) relocate(KERNELBASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3296) ret = enter_secure_mode(kbase, fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3298) /* Relocate the kernel again. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3299) if (IS_ENABLED(CONFIG_RELOCATABLE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3300) relocate(kbase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3302) if (ret != U_SUCCESS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3303) prom_printf("Returned %d from switching to secure mode.\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3304) prom_rtas_os_term("Switch to secure mode failed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3307) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3308) static void __init setup_secure_guest(unsigned long kbase, unsigned long fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3309) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3311) #endif /* CONFIG_PPC_SVM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3313) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3314) * We enter here early on, when the Open Firmware prom is still
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3315) * handling exceptions and the MMU hash table for us.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3316) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3318) unsigned long __init prom_init(unsigned long r3, unsigned long r4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3319) unsigned long pp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3320) unsigned long r6, unsigned long r7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3321) unsigned long kbase)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3322) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3323) unsigned long hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3325) #ifdef CONFIG_PPC32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3326) unsigned long offset = reloc_offset();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3327) reloc_got2(offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3328) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3329) reloc_toc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3330) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3332) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3333) * First zero the BSS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3334) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3335) memset(&__bss_start, 0, __bss_stop - __bss_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3337) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3338) * Init interface to Open Firmware, get some node references,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3339) * like /chosen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3340) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3341) prom_init_client_services(pp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3343) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3344) * See if this OF is old enough that we need to do explicit maps
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3345) * and other workarounds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3346) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3347) prom_find_mmu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3349) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3350) * Init prom stdout device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3351) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3352) prom_init_stdout();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3354) prom_printf("Preparing to boot %s", linux_banner);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3356) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3357) * Get default machine type. At this point, we do not differentiate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3358) * between pSeries SMP and pSeries LPAR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3359) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3360) of_platform = prom_find_machine_type();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3361) prom_printf("Detected machine type: %x\n", of_platform);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3363) #ifndef CONFIG_NONSTATIC_KERNEL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3364) /* Bail if this is a kdump kernel. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3365) if (PHYSICAL_START > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3366) prom_panic("Error: You can't boot a kdump kernel from OF!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3367) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3369) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3370) * Check for an initrd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3371) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3372) prom_check_initrd(r3, r4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3374) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3375) * Do early parsing of command line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3376) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3377) early_cmdline_parse();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3379) #ifdef CONFIG_PPC_PSERIES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3380) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3381) * On pSeries, inform the firmware about our capabilities
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3382) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3383) if (of_platform == PLATFORM_PSERIES ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3384) of_platform == PLATFORM_PSERIES_LPAR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3385) prom_send_capabilities();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3386) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3388) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3389) * Copy the CPU hold code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3390) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3391) if (of_platform != PLATFORM_POWERMAC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3392) copy_and_flush(0, kbase, 0x100, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3394) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3395) * Initialize memory management within prom_init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3396) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3397) prom_init_mem();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3399) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3400) * Determine which cpu is actually running right _now_
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3401) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3402) prom_find_boot_cpu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3404) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3405) * Initialize display devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3406) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3407) prom_check_displays();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3409) #if defined(CONFIG_PPC64) && defined(__BIG_ENDIAN__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3410) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3411) * Initialize IOMMU (TCE tables) on pSeries. Do that before anything else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3412) * that uses the allocator, we need to make sure we get the top of memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3413) * available for us here...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3414) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3415) if (of_platform == PLATFORM_PSERIES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3416) prom_initialize_tce_table();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3417) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3419) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3420) * On non-powermacs, try to instantiate RTAS. PowerMacs don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3421) * have a usable RTAS implementation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3422) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3423) if (of_platform != PLATFORM_POWERMAC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3424) prom_instantiate_rtas();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3426) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3427) /* instantiate sml */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3428) prom_instantiate_sml();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3429) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3431) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3432) * On non-powermacs, put all CPUs in spin-loops.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3433) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3434) * PowerMacs use a different mechanism to spin CPUs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3435) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3436) * (This must be done after instanciating RTAS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3437) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3438) if (of_platform != PLATFORM_POWERMAC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3439) prom_hold_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3441) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3442) * Fill in some infos for use by the kernel later on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3443) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3444) if (prom_memory_limit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3445) __be64 val = cpu_to_be64(prom_memory_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3446) prom_setprop(prom.chosen, "/chosen", "linux,memory-limit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3447) &val, sizeof(val));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3449) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3450) if (prom_iommu_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3451) prom_setprop(prom.chosen, "/chosen", "linux,iommu-off",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3452) NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3454) if (prom_iommu_force_on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3455) prom_setprop(prom.chosen, "/chosen", "linux,iommu-force-on",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3456) NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3458) if (prom_tce_alloc_start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3459) prom_setprop(prom.chosen, "/chosen", "linux,tce-alloc-start",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3460) &prom_tce_alloc_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3461) sizeof(prom_tce_alloc_start));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3462) prom_setprop(prom.chosen, "/chosen", "linux,tce-alloc-end",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3463) &prom_tce_alloc_end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3464) sizeof(prom_tce_alloc_end));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3466) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3468) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3469) * Fixup any known bugs in the device-tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3470) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3471) fixup_device_tree();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3473) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3474) * Now finally create the flattened device-tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3475) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3476) prom_printf("copying OF device tree...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3477) flatten_device_tree();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3479) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3480) * in case stdin is USB and still active on IBM machines...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3481) * Unfortunately quiesce crashes on some powermacs if we have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3482) * closed stdin already (in particular the powerbook 101).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3483) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3484) if (of_platform != PLATFORM_POWERMAC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3485) prom_close_stdin();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3487) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3488) * Call OF "quiesce" method to shut down pending DMA's from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3489) * devices etc...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3490) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3491) prom_printf("Quiescing Open Firmware ...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3492) call_prom("quiesce", 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3494) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3495) * And finally, call the kernel passing it the flattened device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3496) * tree and NULL as r5, thus triggering the new entry point which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3497) * is common to us and kexec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3498) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3499) hdr = dt_header_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3501) prom_printf("Booting Linux via __start() @ 0x%lx ...\n", kbase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3502) prom_debug("->dt_header_start=0x%lx\n", hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3504) #ifdef CONFIG_PPC32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3505) reloc_got2(-offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3506) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3507) unreloc_toc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3508) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3510) /* Move to secure memory if we're supposed to be secure guests. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3511) setup_secure_guest(kbase, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3513) __start(hdr, kbase, 0, 0, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3515) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3516) }