···302 bool303 default y304305-config MSCHUNKS306- bool307- depends on PPC_ISERIES308- default y309-310-311config PPC_RTAS312 bool313 depends on PPC_PSERIES || PPC_BPA···344345 If unsure, say Y. Only embedded should say N here.346000000000000000000000000000000000347endmenu348349config ISA_DMA_API350 bool351 default y352353-menu "General setup"354355config ISA356 bool···416 bool417 default PCI418419-source "fs/Kconfig.binfmt"420-421source "drivers/pci/Kconfig"422-423-config HOTPLUG_CPU424- bool "Support for hot-pluggable CPUs"425- depends on SMP && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)426- select HOTPLUG427- ---help---428- Say Y here to be able to turn CPUs off and on.429-430- Say N if you are unsure.431432source "drivers/pcmcia/Kconfig"433434source "drivers/pci/hotplug/Kconfig"435-436-config PROC_DEVICETREE437- bool "Support for Open Firmware device tree in /proc"438- depends on !PPC_ISERIES439- help440- This option adds a device-tree directory under /proc which contains441- an image of the device tree that the kernel copies from Open442- Firmware. If unsure, say Y here.443-444-config CMDLINE_BOOL445- bool "Default bootloader kernel arguments"446- depends on !PPC_ISERIES447-448-config CMDLINE449- string "Initial kernel command string"450- depends on CMDLINE_BOOL451- default "console=ttyS0,9600 console=tty0 root=/dev/sda2"452- help453- On some platforms, there is currently no way for the boot loader to454- pass arguments to the kernel. For these platforms, you can supply455- some command-line options at build time by entering them here. In456- most cases you will need to specify the root device here.457458endmenu459
···302 bool303 default y304000000305config PPC_RTAS306 bool307 depends on PPC_PSERIES || PPC_BPA···350351 If unsure, say Y. Only embedded should say N here.352353+source "fs/Kconfig.binfmt"354+355+config HOTPLUG_CPU356+ bool "Support for hot-pluggable CPUs"357+ depends on SMP && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)358+ select HOTPLUG359+ ---help---360+ Say Y here to be able to turn CPUs off and on.361+362+ Say N if you are unsure.363+364+config PROC_DEVICETREE365+ bool "Support for Open Firmware device tree in /proc"366+ depends on !PPC_ISERIES367+ help368+ This option adds a device-tree directory under /proc which contains369+ an image of the device tree that the kernel copies from Open370+ Firmware. If unsure, say Y here.371+372+config CMDLINE_BOOL373+ bool "Default bootloader kernel arguments"374+ depends on !PPC_ISERIES375+376+config CMDLINE377+ string "Initial kernel command string"378+ depends on CMDLINE_BOOL379+ default "console=ttyS0,9600 console=tty0 root=/dev/sda2"380+ help381+ On some platforms, there is currently no way for the boot loader to382+ pass arguments to the kernel. For these platforms, you can supply383+ some command-line options at build time by entering them here. In384+ most cases you will need to specify the root device here.385+386endmenu387388config ISA_DMA_API389 bool390 default y391392+menu "Bus Options"393394config ISA395 bool···389 bool390 default PCI39100392source "drivers/pci/Kconfig"000000000393394source "drivers/pcmcia/Kconfig"395396source "drivers/pci/hotplug/Kconfig"0000000000000000000000397398endmenu399
···9 * NOTE: this code runs in 32 bit mode and is packaged as ELF32.10 */1112-#include <asm/ppc_asm.h>1314 .text15 .globl _start
···9 * NOTE: this code runs in 32 bit mode and is packaged as ELF32.10 */1112+#include "ppc_asm.h"1314 .text15 .globl _start
+1-1
arch/ppc64/boot/div64.S
···13 * as published by the Free Software Foundation; either version14 * 2 of the License, or (at your option) any later version.15 */16-#include <asm/ppc_asm.h>1718 .globl __div64_3219__div64_32:
···13 * as published by the Free Software Foundation; either version14 * 2 of the License, or (at your option) any later version.15 */16+#include "ppc_asm.h"1718 .globl __div64_3219__div64_32:
···1+#ifndef _PPC_BOOT_ELF_H_2+#define _PPC_BOOT_ELF_H_3+4+/* 32-bit ELF base types. */5+typedef unsigned int Elf32_Addr;6+typedef unsigned short Elf32_Half;7+typedef unsigned int Elf32_Off;8+typedef signed int Elf32_Sword;9+typedef unsigned int Elf32_Word;10+11+/* 64-bit ELF base types. */12+typedef unsigned long long Elf64_Addr;13+typedef unsigned short Elf64_Half;14+typedef signed short Elf64_SHalf;15+typedef unsigned long long Elf64_Off;16+typedef signed int Elf64_Sword;17+typedef unsigned int Elf64_Word;18+typedef unsigned long long Elf64_Xword;19+typedef signed long long Elf64_Sxword;20+21+/* These constants are for the segment types stored in the image headers */22+#define PT_NULL 023+#define PT_LOAD 124+#define PT_DYNAMIC 225+#define PT_INTERP 326+#define PT_NOTE 427+#define PT_SHLIB 528+#define PT_PHDR 629+#define PT_TLS 7 /* Thread local storage segment */30+#define PT_LOOS 0x60000000 /* OS-specific */31+#define PT_HIOS 0x6fffffff /* OS-specific */32+#define PT_LOPROC 0x7000000033+#define PT_HIPROC 0x7fffffff34+#define PT_GNU_EH_FRAME 0x6474e55035+36+#define PT_GNU_STACK (PT_LOOS + 0x474e551)37+38+/* These constants define the different elf file types */39+#define ET_NONE 040+#define ET_REL 141+#define ET_EXEC 242+#define ET_DYN 343+#define ET_CORE 444+#define ET_LOPROC 0xff0045+#define ET_HIPROC 0xffff46+47+/* These constants define the various ELF target machines */48+#define EM_NONE 049+#define EM_PPC 20 /* PowerPC */50+#define EM_PPC64 21 /* PowerPC64 */51+52+#define EI_NIDENT 1653+54+typedef struct elf32_hdr {55+ unsigned char e_ident[EI_NIDENT];56+ Elf32_Half e_type;57+ Elf32_Half e_machine;58+ Elf32_Word e_version;59+ Elf32_Addr e_entry; /* Entry point */60+ Elf32_Off e_phoff;61+ Elf32_Off e_shoff;62+ Elf32_Word e_flags;63+ Elf32_Half e_ehsize;64+ Elf32_Half e_phentsize;65+ Elf32_Half e_phnum;66+ Elf32_Half e_shentsize;67+ Elf32_Half e_shnum;68+ Elf32_Half e_shstrndx;69+} Elf32_Ehdr;70+71+typedef struct elf64_hdr {72+ unsigned char e_ident[16]; /* ELF "magic number" */73+ Elf64_Half e_type;74+ Elf64_Half e_machine;75+ Elf64_Word e_version;76+ Elf64_Addr e_entry; /* Entry point virtual address */77+ Elf64_Off e_phoff; /* Program header table file offset */78+ Elf64_Off e_shoff; /* Section header table file offset */79+ Elf64_Word e_flags;80+ Elf64_Half e_ehsize;81+ Elf64_Half e_phentsize;82+ Elf64_Half e_phnum;83+ Elf64_Half e_shentsize;84+ Elf64_Half e_shnum;85+ Elf64_Half e_shstrndx;86+} Elf64_Ehdr;87+88+/* These constants define the permissions on sections in the program89+ header, p_flags. */90+#define PF_R 0x491+#define PF_W 0x292+#define PF_X 0x193+94+typedef struct elf32_phdr {95+ Elf32_Word p_type;96+ Elf32_Off p_offset;97+ Elf32_Addr p_vaddr;98+ Elf32_Addr p_paddr;99+ Elf32_Word p_filesz;100+ Elf32_Word p_memsz;101+ Elf32_Word p_flags;102+ Elf32_Word p_align;103+} Elf32_Phdr;104+105+typedef struct elf64_phdr {106+ Elf64_Word p_type;107+ Elf64_Word p_flags;108+ Elf64_Off p_offset; /* Segment file offset */109+ Elf64_Addr p_vaddr; /* Segment virtual address */110+ Elf64_Addr p_paddr; /* Segment physical address */111+ Elf64_Xword p_filesz; /* Segment size in file */112+ Elf64_Xword p_memsz; /* Segment size in memory */113+ Elf64_Xword p_align; /* Segment alignment, file & memory */114+} Elf64_Phdr;115+116+#define EI_MAG0 0 /* e_ident[] indexes */117+#define EI_MAG1 1118+#define EI_MAG2 2119+#define EI_MAG3 3120+#define EI_CLASS 4121+#define EI_DATA 5122+#define EI_VERSION 6123+#define EI_OSABI 7124+#define EI_PAD 8125+126+#define ELFMAG0 0x7f /* EI_MAG */127+#define ELFMAG1 'E'128+#define ELFMAG2 'L'129+#define ELFMAG3 'F'130+#define ELFMAG "\177ELF"131+#define SELFMAG 4132+133+#define ELFCLASSNONE 0 /* EI_CLASS */134+#define ELFCLASS32 1135+#define ELFCLASS64 2136+#define ELFCLASSNUM 3137+138+#define ELFDATANONE 0 /* e_ident[EI_DATA] */139+#define ELFDATA2LSB 1140+#define ELFDATA2MSB 2141+142+#define EV_NONE 0 /* e_version, EI_VERSION */143+#define EV_CURRENT 1144+#define EV_NUM 2145+146+#define ELFOSABI_NONE 0147+#define ELFOSABI_LINUX 3148+149+#endif /* _PPC_BOOT_ELF_H_ */
+18-33
arch/ppc64/boot/main.c
···8 * as published by the Free Software Foundation; either version9 * 2 of the License, or (at your option) any later version.10 */11-#include "ppc32-types.h"00000012#include "zlib.h"13-#include <linux/elf.h>14-#include <linux/string.h>15-#include <asm/processor.h>16-#include <asm/page.h>1718-extern void *finddevice(const char *);19-extern int getprop(void *, const char *, void *, int);20-extern void printf(const char *fmt, ...);21-extern int sprintf(char *buf, const char *fmt, ...);22-void gunzip(void *, int, unsigned char *, int *);23-void *claim(unsigned int, unsigned int, unsigned int);24-void flush_cache(void *, unsigned long);25-void pause(void);26-extern void exit(void);2728-unsigned long strlen(const char *s);29-void *memmove(void *dest, const void *src, unsigned long n);30-void *memcpy(void *dest, const void *src, unsigned long n);3132/* Value picked to match that used by yaboot */33#define PROG_START 0x0140000034#define RAM_END (256<<20) // Fixme: use OF */3536-char *avail_ram;37-char *begin_avail, *end_avail;38-char *avail_high;39-unsigned int heap_use;40-unsigned int heap_max;4142extern char _start[];43extern char _vmlinux_start[];···44 unsigned long size;45 unsigned long memsize;46};47-struct addr_range vmlinux = {0, 0, 0};48-struct addr_range vmlinuz = {0, 0, 0};49-struct addr_range initrd = {0, 0, 0};5051static char scratch[128<<10]; /* 128kB of scratch space for gunzip */52···55 void *,56 void *);5758-59-int (*prom)(void *);60-61-void *chosen_handle;62-void *stdin;63-void *stdout;64-void *stderr;6566#undef DEBUG67···262263#define DEFLATED 8264265-void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)266{267 z_stream s;268 int r, i, flags;
···8 * as published by the Free Software Foundation; either version9 * 2 of the License, or (at your option) any later version.10 */11+#include <stdarg.h>12+#include <stddef.h>13+#include "elf.h"14+#include "page.h"15+#include "string.h"16+#include "stdio.h"17+#include "prom.h"18#include "zlib.h"00001920+static void gunzip(void *, int, unsigned char *, int *);21+extern void flush_cache(void *, unsigned long);0000000220002324/* Value picked to match that used by yaboot */25#define PROG_START 0x0140000026#define RAM_END (256<<20) // Fixme: use OF */2728+static char *avail_ram;29+static char *begin_avail, *end_avail;30+static char *avail_high;31+static unsigned int heap_use;32+static unsigned int heap_max;3334extern char _start[];35extern char _vmlinux_start[];···52 unsigned long size;53 unsigned long memsize;54};55+static struct addr_range vmlinux = {0, 0, 0};56+static struct addr_range vmlinuz = {0, 0, 0};57+static struct addr_range initrd = {0, 0, 0};5859static char scratch[128<<10]; /* 128kB of scratch space for gunzip */60···63 void *,64 void *);6500000006667#undef DEBUG68···277278#define DEFLATED 8279280+static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)281{282 z_stream s;283 int r, i, flags;
+34
arch/ppc64/boot/page.h
···0000000000000000000000000000000000
···1+#ifndef _PPC_BOOT_PAGE_H2+#define _PPC_BOOT_PAGE_H3+/*4+ * Copyright (C) 2001 PPC64 Team, IBM Corp5+ *6+ * This program is free software; you can redistribute it and/or7+ * modify it under the terms of the GNU General Public License8+ * as published by the Free Software Foundation; either version9+ * 2 of the License, or (at your option) any later version.10+ */11+12+#ifdef __ASSEMBLY__13+#define ASM_CONST(x) x14+#else15+#define __ASM_CONST(x) x##UL16+#define ASM_CONST(x) __ASM_CONST(x)17+#endif18+19+/* PAGE_SHIFT determines the page size */20+#define PAGE_SHIFT 1221+#define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT)22+#define PAGE_MASK (~(PAGE_SIZE-1))23+24+/* align addr on a size boundary - adjust address up/down if needed */25+#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1)))26+#define _ALIGN_DOWN(addr,size) ((addr)&(~((size)-1)))27+28+/* align addr on a size boundary - adjust address up if needed */29+#define _ALIGN(addr,size) _ALIGN_UP(addr,size)30+31+/* to align the pointer to the (next) page boundary */32+#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)33+34+#endif /* _PPC_BOOT_PAGE_H */
-36
arch/ppc64/boot/ppc32-types.h
···1-#ifndef _PPC64_TYPES_H2-#define _PPC64_TYPES_H3-4-typedef __signed__ char __s8;5-typedef unsigned char __u8;6-7-typedef __signed__ short __s16;8-typedef unsigned short __u16;9-10-typedef __signed__ int __s32;11-typedef unsigned int __u32;12-13-typedef __signed__ long long __s64;14-typedef unsigned long long __u64;15-16-typedef signed char s8;17-typedef unsigned char u8;18-19-typedef signed short s16;20-typedef unsigned short u16;21-22-typedef signed int s32;23-typedef unsigned int u32;24-25-typedef signed long long s64;26-typedef unsigned long long u64;27-28-typedef struct {29- __u32 u[4];30-} __attribute((aligned(16))) __vector128;31-32-#define BITS_PER_LONG 3233-34-typedef __vector128 vector128;35-36-#endif /* _PPC64_TYPES_H */
···1+#ifndef _PPC64_PPC_ASM_H2+#define _PPC64_PPC_ASM_H3+/*4+ *5+ * Definitions used by various bits of low-level assembly code on PowerPC.6+ *7+ * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan.8+ *9+ * This program is free software; you can redistribute it and/or10+ * modify it under the terms of the GNU General Public License11+ * as published by the Free Software Foundation; either version12+ * 2 of the License, or (at your option) any later version.13+ */14+15+/* Condition Register Bit Fields */16+17+#define cr0 018+#define cr1 119+#define cr2 220+#define cr3 321+#define cr4 422+#define cr5 523+#define cr6 624+#define cr7 725+26+27+/* General Purpose Registers (GPRs) */28+29+#define r0 030+#define r1 131+#define r2 232+#define r3 333+#define r4 434+#define r5 535+#define r6 636+#define r7 737+#define r8 838+#define r9 939+#define r10 1040+#define r11 1141+#define r12 1242+#define r13 1343+#define r14 1444+#define r15 1545+#define r16 1646+#define r17 1747+#define r18 1848+#define r19 1949+#define r20 2050+#define r21 2151+#define r22 2252+#define r23 2353+#define r24 2454+#define r25 2555+#define r26 2656+#define r27 2757+#define r28 2858+#define r29 2959+#define r30 3060+#define r31 3161+62+#endif /* _PPC64_PPC_ASM_H */
+27-169
arch/ppc64/boot/prom.c
···7 * 2 of the License, or (at your option) any later version.8 */9#include <stdarg.h>10-#include <linux/types.h>11-#include <linux/string.h>12-#include <linux/ctype.h>13-14-extern __u32 __div64_32(unsigned long long *dividend, __u32 divisor);15-16-/* The unnecessary pointer compare is there17- * to check for type safety (n must be 64bit)18- */19-# define do_div(n,base) ({ \20- __u32 __base = (base); \21- __u32 __rem; \22- (void)(((typeof((n)) *)0) == ((unsigned long long *)0)); \23- if (((n) >> 32) == 0) { \24- __rem = (__u32)(n) % __base; \25- (n) = (__u32)(n) / __base; \26- } else \27- __rem = __div64_32(&(n), __base); \28- __rem; \29- })3031int (*prom)(void *);3233void *chosen_handle;034void *stdin;35void *stdout;36void *stderr;3738-void exit(void);39-void *finddevice(const char *name);40-int getprop(void *phandle, const char *name, void *buf, int buflen);41-void chrpboot(int a1, int a2, void *prom); /* in main.c */42-43-int printf(char *fmt, ...);44-45-/* there is no convenient header to get this from... -- paulus */46-extern unsigned long strlen(const char *);4748int49write(void *handle, void *ptr, int nb)···186 return write(f, str, n) == n? 0: -1;187}188189-int190-readchar(void)191-{192- char ch;193-194- for (;;) {195- switch (read(stdin, &ch, 1)) {196- case 1:197- return ch;198- case -1:199- printf("read(stdin) returned -1\r\n");200- return -1;201- }202- }203-}204-205-static char line[256];206-static char *lineptr;207-static int lineleft;208-209-int210-getchar(void)211-{212- int c;213-214- if (lineleft == 0) {215- lineptr = line;216- for (;;) {217- c = readchar();218- if (c == -1 || c == 4)219- break;220- if (c == '\r' || c == '\n') {221- *lineptr++ = '\n';222- putchar('\n');223- break;224- }225- switch (c) {226- case 0177:227- case '\b':228- if (lineptr > line) {229- putchar('\b');230- putchar(' ');231- putchar('\b');232- --lineptr;233- }234- break;235- case 'U' & 0x1F:236- while (lineptr > line) {237- putchar('\b');238- putchar(' ');239- putchar('\b');240- --lineptr;241- }242- break;243- default:244- if (lineptr >= &line[sizeof(line) - 1])245- putchar('\a');246- else {247- putchar(c);248- *lineptr++ = c;249- }250- }251- }252- lineleft = lineptr - line;253- lineptr = line;254- }255- if (lineleft == 0)256- return -1;257- --lineleft;258- return *lineptr++;259-}260-261-262-263-/* String functions lifted from lib/vsprintf.c and lib/ctype.c */264-unsigned char _ctype[] = {265-_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */266-_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */267-_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */268-_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */269-_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */270-_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */271-_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */272-_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */273-_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */274-_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */275-_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */276-_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */277-_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */278-_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */279-_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */280-_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */281-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */282-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */283-_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */284-_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */285-_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */286-_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */287-_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */288-_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */289-290size_t strnlen(const char * s, size_t count)291{292 const char *sc;···195 return sc - s;196}197198-unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)199-{200- unsigned long result = 0,value;201202- if (!base) {203- base = 10;204- if (*cp == '0') {205- base = 8;206- cp++;207- if ((*cp == 'x') && isxdigit(cp[1])) {208- cp++;209- base = 16;210- }211- }212- }213- while (isxdigit(*cp) &&214- (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {215- result = result*base + value;216- cp++;217- }218- if (endp)219- *endp = (char *)cp;220- return result;221-}222-223-long simple_strtol(const char *cp,char **endp,unsigned int base)224-{225- if(*cp=='-')226- return -simple_strtoul(cp+1,endp,base);227- return simple_strtoul(cp,endp,base);228-}229230static int skip_atoi(const char **s)231{232- int i=0;233234- while (isdigit(**s))235- i = i*10 + *((*s)++) - '0';236 return i;237}238···297 return str;298}299300-/* Forward decl. needed for IP address printing stuff... */301-int sprintf(char * buf, const char *fmt, ...);302-303int vsprintf(char *buf, const char *fmt, va_list args)304{305 int len;···335336 /* get field width */337 field_width = -1;338- if (isdigit(*fmt))339 field_width = skip_atoi(&fmt);340 else if (*fmt == '*') {341 ++fmt;···351 precision = -1;352 if (*fmt == '.') {353 ++fmt; 354- if (isdigit(*fmt))355 precision = skip_atoi(&fmt);356 else if (*fmt == '*') {357 ++fmt;···486static char sprint_buf[1024];487488int489-printf(char *fmt, ...)490{491 va_list args;492 int n;
···7 * 2 of the License, or (at your option) any later version.8 */9#include <stdarg.h>10+#include <stddef.h>11+#include "string.h"12+#include "stdio.h"13+#include "prom.h"00000000000000001415int (*prom)(void *);1617void *chosen_handle;18+19void *stdin;20void *stdout;21void *stderr;220000000002324int25write(void *handle, void *ptr, int nb)···210 return write(f, str, n) == n? 0: -1;211}21200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000213size_t strnlen(const char * s, size_t count)214{215 const char *sc;···320 return sc - s;321}322323+extern unsigned int __div64_32(unsigned long long *dividend,324+ unsigned int divisor);0325326+/* The unnecessary pointer compare is there327+ * to check for type safety (n must be 64bit)328+ */329+# define do_div(n,base) ({ \330+ unsigned int __base = (base); \331+ unsigned int __rem; \332+ (void)(((typeof((n)) *)0) == ((unsigned long long *)0)); \333+ if (((n) >> 32) == 0) { \334+ __rem = (unsigned int)(n) % __base; \335+ (n) = (unsigned int)(n) / __base; \336+ } else \337+ __rem = __div64_32(&(n), __base); \338+ __rem; \339+ })0000000000000340341static int skip_atoi(const char **s)342{343+ int i, c;344345+ for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)346+ i = i*10 + c - '0';347 return i;348}349···436 return str;437}438000439int vsprintf(char *buf, const char *fmt, va_list args)440{441 int len;···477478 /* get field width */479 field_width = -1;480+ if ('0' <= *fmt && *fmt <= '9')481 field_width = skip_atoi(&fmt);482 else if (*fmt == '*') {483 ++fmt;···493 precision = -1;494 if (*fmt == '.') {495 ++fmt; 496+ if ('0' <= *fmt && *fmt <= '9')497 precision = skip_atoi(&fmt);498 else if (*fmt == '*') {499 ++fmt;···628static char sprint_buf[1024];629630int631+printf(const char *fmt, ...)632{633 va_list args;634 int n;
+18
arch/ppc64/boot/prom.h
···000000000000000000
···1+#ifndef _PPC_BOOT_PROM_H_2+#define _PPC_BOOT_PROM_H_3+4+extern int (*prom) (void *);5+extern void *chosen_handle;6+7+extern void *stdin;8+extern void *stdout;9+extern void *stderr;10+11+extern int write(void *handle, void *ptr, int nb);12+extern int read(void *handle, void *ptr, int nb);13+extern void exit(void);14+extern void pause(void);15+extern void *finddevice(const char *);16+extern void *claim(unsigned long virt, unsigned long size, unsigned long align);17+extern int getprop(void *phandle, const char *name, void *buf, int buflen);18+#endif /* _PPC_BOOT_PROM_H_ */
+16
arch/ppc64/boot/stdio.h
···0000000000000000
···1+#ifndef _PPC_BOOT_STDIO_H_2+#define _PPC_BOOT_STDIO_H_3+4+extern int printf(const char *fmt, ...);5+6+extern int sprintf(char *buf, const char *fmt, ...);7+8+extern int vsprintf(char *buf, const char *fmt, va_list args);9+10+extern int putc(int c, void *f);11+extern int putchar(int c);12+extern int getchar(void);13+14+extern int fputs(char *str, void *f);15+16+#endif /* _PPC_BOOT_STDIO_H_ */
+1-1
arch/ppc64/boot/string.S
···9 * NOTE: this code runs in 32 bit mode and is packaged as ELF32.10 */1112-#include <asm/ppc_asm.h>1314 .text15 .globl strcpy
···9 * NOTE: this code runs in 32 bit mode and is packaged as ELF32.10 */1112+#include "ppc_asm.h"1314 .text15 .globl strcpy
···99# CONFIG_HZ_1000 is not set100CONFIG_HZ=100101CONFIG_GENERIC_HARDIRQS=y102-CONFIG_MSCHUNKS=y103CONFIG_LPARCFG=y104CONFIG_SECCOMP=y105CONFIG_ISA_DMA_API=y
···99# CONFIG_HZ_1000 is not set100CONFIG_HZ=100101CONFIG_GENERIC_HARDIRQS=y0102CONFIG_LPARCFG=y103CONFIG_SECCOMP=y104CONFIG_ISA_DMA_API=y
+11-26
arch/ppc64/kernel/LparData.c
···51 0xf4, 0x4b, 0xf6, 0xf4 },52};530000000000054extern void system_reset_iSeries(void);55extern void machine_check_iSeries(void);56extern void data_access_iSeries(void);···225 0,0226 }227};228-229-struct msChunks msChunks;230-EXPORT_SYMBOL(msChunks);231-232-/* Depending on whether this is called from iSeries or pSeries setup233- * code, the location of the msChunks struct may or may not have234- * to be reloc'd, so we force the caller to do that for us by passing235- * in a pointer to the structure.236- */237-unsigned long238-msChunks_alloc(unsigned long mem, unsigned long num_chunks, unsigned long chunk_size)239-{240- unsigned long offset = reloc_offset();241- struct msChunks *_msChunks = PTRRELOC(&msChunks);242-243- _msChunks->num_chunks = num_chunks;244- _msChunks->chunk_size = chunk_size;245- _msChunks->chunk_shift = __ilog2(chunk_size);246- _msChunks->chunk_mask = (1UL<<_msChunks->chunk_shift)-1;247-248- mem = _ALIGN(mem, sizeof(msChunks_entry));249- _msChunks->abs = (msChunks_entry *)(mem + offset);250- mem += num_chunks * sizeof(msChunks_entry);251-252- return mem;253-}
···51 0xf4, 0x4b, 0xf6, 0xf4 },52};5354+/*55+ * The NACA. The first dword of the naca is required by the iSeries56+ * hypervisor to point to itVpdAreas. The hypervisor finds the NACA57+ * through the pointer in hvReleaseData.58+ */59+struct naca_struct naca = {60+ .xItVpdAreas = &itVpdAreas,61+ .xRamDisk = 0,62+ .xRamDiskSize = 0,63+};64+65extern void system_reset_iSeries(void);66extern void machine_check_iSeries(void);67extern void data_access_iSeries(void);···214 0,0215 }216};00000000000000000000000000
···1+/*2+ * arch/ppc64/kernel/firmware.c3+ *4+ * Extracted from cputable.c5+ *6+ * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)7+ *8+ * Modifications for ppc64:9+ * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>10+ * Copyright (C) 2005 Stephen Rothwell, IBM Corporation11+ *12+ * This program is free software; you can redistribute it and/or13+ * modify it under the terms of the GNU General Public License14+ * as published by the Free Software Foundation; either version15+ * 2 of the License, or (at your option) any later version.16+ */17+18+#include <linux/config.h>19+20+#include <asm/firmware.h>21+22+unsigned long ppc64_firmware_features;23+24+#ifdef CONFIG_PPC_PSERIES25+firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = {26+ {FW_FEATURE_PFT, "hcall-pft"},27+ {FW_FEATURE_TCE, "hcall-tce"},28+ {FW_FEATURE_SPRG0, "hcall-sprg0"},29+ {FW_FEATURE_DABR, "hcall-dabr"},30+ {FW_FEATURE_COPY, "hcall-copy"},31+ {FW_FEATURE_ASR, "hcall-asr"},32+ {FW_FEATURE_DEBUG, "hcall-debug"},33+ {FW_FEATURE_PERF, "hcall-perf"},34+ {FW_FEATURE_DUMP, "hcall-dump"},35+ {FW_FEATURE_INTERRUPT, "hcall-interrupt"},36+ {FW_FEATURE_MIGRATE, "hcall-migrate"},37+ {FW_FEATURE_PERFMON, "hcall-perfmon"},38+ {FW_FEATURE_CRQ, "hcall-crq"},39+ {FW_FEATURE_VIO, "hcall-vio"},40+ {FW_FEATURE_RDMA, "hcall-rdma"},41+ {FW_FEATURE_LLAN, "hcall-lLAN"},42+ {FW_FEATURE_BULK, "hcall-bulk"},43+ {FW_FEATURE_XDABR, "hcall-xdabr"},44+ {FW_FEATURE_MULTITCE, "hcall-multi-tce"},45+ {FW_FEATURE_SPLPAR, "hcall-splpar"},46+};47+#endif
+194-319
arch/ppc64/kernel/head.S
···23 * 2 of the License, or (at your option) any later version.24 */2526-#define SECONDARY_PROCESSORS27-28#include <linux/config.h>29#include <linux/threads.h>30#include <asm/processor.h>31#include <asm/page.h>32#include <asm/mmu.h>33-#include <asm/naca.h>34#include <asm/systemcfg.h>35#include <asm/ppc_asm.h>36#include <asm/offsets.h>···42#endif4344/*45- * hcall interface to pSeries LPAR46- */47-#define H_SET_ASR 0x3048-49-/*50 * We layout physical memory as follows:51 * 0x0000 - 0x00ff : Secondary processor spin code52 * 0x0100 - 0x2fff : pSeries Interrupt prologs53- * 0x3000 - 0x3fff : Interrupt support54- * 0x4000 - 0x4fff : NACA55- * 0x6000 : iSeries and common interrupt prologs56- * 0x9000 - 0x9fff : Initial segment table57 */5859/*···8687 /* Catch branch to 0 in real mode */88 trap089#ifdef CONFIG_PPC_ISERIES90 /*91 * At offset 0x20, there is a pointer to iSeries LPAR data.···96 .llong hvReleaseData-KERNELBASE9798 /*99- * At offset 0x28 and 0x30 are offsets to the msChunks100 * array (used by the iSeries LPAR debugger to do translation101 * between physical addresses and absolute addresses) and102 * to the pidhash table (also used by the debugger)103 */104- .llong msChunks-KERNELBASE105 .llong 0 /* pidhash-KERNELBASE SFRXXX */106107 /* Offset 0x38 - Pointer to start of embedded System.map */···113embedded_sysmap_end:114 .llong 0115116-#else /* CONFIG_PPC_ISERIES */117118 /* Secondary processors spin on this value until it goes to 1. */119 .globl __secondary_hold_spinloop···148 std r24,__secondary_hold_acknowledge@l(0)149 sync150151- /* All secondary cpu's wait here until told to start. */152100: ld r4,__secondary_hold_spinloop@l(0)153 cmpdi 0,r4,1154 bne 100b···161 b .pSeries_secondary_smp_init162#else163 BUG_OPCODE164-#endif165#endif166#endif167···494 STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint)495 STD_EXCEPTION_PSERIES(0x1700, altivec_assist)496497- /* moved from 0xf00 */498- STD_EXCEPTION_PSERIES(0x3000, performance_monitor)499500- . = 0x310000000501_GLOBAL(do_stab_bolted_pSeries)502 mtcrf 0x80,r12503 mfspr r12,SPRG2504 EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted)505506-507- /* Space for the naca. Architected to be located at real address508- * NACA_PHYS_ADDR. Various tools rely on this location being fixed.509- * The first dword of the naca is required by iSeries LPAR to510- * point to itVpdAreas. On pSeries native, this value is not used.511- */512- . = NACA_PHYS_ADDR513- .globl __end_interrupts514-__end_interrupts:00000000515#ifdef CONFIG_PPC_ISERIES516- .globl naca517-naca:518- .llong itVpdAreas519- .llong 0 /* xRamDisk */520- .llong 0 /* xRamDiskSize */521-522- . = 0x6100523-524/*** ISeries-LPAR interrupt handlers ***/525526 STD_EXCEPTION_ISERIES(0x200, machine_check, PACA_EXMC)···622623 cmpwi 0,r23,0624 beq iSeries_secondary_smp_loop /* Loop until told to go */625-#ifdef SECONDARY_PROCESSORS626 bne .__secondary_start /* Loop until told to go */627-#endif628iSeries_secondary_smp_loop:629 /* Let the Hypervisor know we are alive */630 /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */···665 ld r13,PACA_EXGEN+EX_R13(r13)666 rfid667 b . /* prevent speculative execution */668-#endif669-670-/*671- * Data area reserved for FWNMI option.672- */673- .= 0x7000674- .globl fwnmi_data_area675-fwnmi_data_area:676-677-#ifdef CONFIG_PPC_ISERIES678- . = LPARMAP_PHYS679-#include "lparmap.s"680#endif /* CONFIG_PPC_ISERIES */681-682-/*683- * Vectors for the FWNMI option. Share common code.684- */685- . = 0x8000686- .globl system_reset_fwnmi687-system_reset_fwnmi:688- HMT_MEDIUM689- mtspr SPRG1,r13 /* save r13 */690- RUNLATCH_ON(r13)691- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)692- .globl machine_check_fwnmi693-machine_check_fwnmi:694- HMT_MEDIUM695- mtspr SPRG1,r13 /* save r13 */696- RUNLATCH_ON(r13)697- EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)698-699- /*700- * Space for the initial segment table701- * For LPAR, the hypervisor must fill in at least one entry702- * before we get control (with relocate on)703- */704- . = STAB0_PHYS_ADDR705- .globl __start_stab706-__start_stab:707-708- . = (STAB0_PHYS_ADDR + PAGE_SIZE)709- .globl __end_stab710-__end_stab:711-712713/*** Common interrupt handlers ***/714···703 * R9 contains the saved CR, r13 points to the paca,704 * r10 contains the (bad) kernel stack pointer,705 * r11 and r12 contain the saved SRR0 and SRR1.706- * We switch to using the paca guard page as an emergency stack,707- * save the registers there, and call kernel_bad_stack(), which panics.708 */709bad_stack:710 ld r1,PACAEMERGSP(r13)···857 bl .kernel_fp_unavailable_exception858 BUG_OPCODE85900000000000000000000000000000000000000000000000000000000860 .align 7861 .globl altivec_unavailable_common862altivec_unavailable_common:···927 ENABLE_INTS928 bl .altivec_unavailable_exception929 b .ret_from_except00000000000000000000000000000000000000000000000000000000000000000000000000930931/*932 * Hash table stuff···1248 bl .unrecoverable_exception1249 b 1b1250000000000000000000000012511252/*1253 * On pSeries, secondary processors spin in the following code.···1303 b .kexec_wait /* next kernel might do better */130413052: mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */1306- /* From now on, r24 is expected to be logica cpuid */1307 mr r24,r513083: HMT_LOW1309 lbz r23,PACAPROCSTART(r13) /* Test if this processor should */···13161317 cmpwi 0,r23,01318#ifdef CONFIG_SMP1319-#ifdef SECONDARY_PROCESSORS1320 bne .__secondary_start1321-#endif1322#endif1323 b 3b /* Loop until told to go */1324···15301531.align 81532copy_to_here:1533-1534-/*1535- * load_up_fpu(unused, unused, tsk)1536- * Disable FP for the task which had the FPU previously,1537- * and save its floating-point registers in its thread_struct.1538- * Enables the FPU for use in the kernel on return.1539- * On SMP we know the fpu is free, since we give it up every1540- * switch (ie, no lazy save of the FP registers).1541- * On entry: r13 == 'current' && last_task_used_math != 'current'1542- */1543-_STATIC(load_up_fpu)1544- mfmsr r5 /* grab the current MSR */1545- ori r5,r5,MSR_FP1546- mtmsrd r5 /* enable use of fpu now */1547- isync1548-/*1549- * For SMP, we don't do lazy FPU switching because it just gets too1550- * horrendously complex, especially when a task switches from one CPU1551- * to another. Instead we call giveup_fpu in switch_to.1552- *1553- */1554-#ifndef CONFIG_SMP1555- ld r3,last_task_used_math@got(r2)1556- ld r4,0(r3)1557- cmpdi 0,r4,01558- beq 1f1559- /* Save FP state to last_task_used_math's THREAD struct */1560- addi r4,r4,THREAD1561- SAVE_32FPRS(0, r4)1562- mffs fr01563- stfd fr0,THREAD_FPSCR(r4)1564- /* Disable FP for last_task_used_math */1565- ld r5,PT_REGS(r4)1566- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)1567- li r6,MSR_FP|MSR_FE0|MSR_FE11568- andc r4,r4,r61569- std r4,_MSR-STACK_FRAME_OVERHEAD(r5)1570-1:1571-#endif /* CONFIG_SMP */1572- /* enable use of FP after return */1573- ld r4,PACACURRENT(r13)1574- addi r5,r4,THREAD /* Get THREAD */1575- ld r4,THREAD_FPEXC_MODE(r5)1576- ori r12,r12,MSR_FP1577- or r12,r12,r41578- std r12,_MSR(r1)1579- lfd fr0,THREAD_FPSCR(r5)1580- mtfsf 0xff,fr01581- REST_32FPRS(0, r5)1582-#ifndef CONFIG_SMP1583- /* Update last_task_used_math to 'current' */1584- subi r4,r5,THREAD /* Back to 'current' */1585- std r4,0(r3)1586-#endif /* CONFIG_SMP */1587- /* restore registers and return */1588- b fast_exception_return1589-1590-/*1591- * disable_kernel_fp()1592- * Disable the FPU.1593- */1594-_GLOBAL(disable_kernel_fp)1595- mfmsr r31596- rldicl r0,r3,(63-MSR_FP_LG),11597- rldicl r3,r0,(MSR_FP_LG+1),01598- mtmsrd r3 /* disable use of fpu now */1599- isync1600- blr1601-1602-/*1603- * giveup_fpu(tsk)1604- * Disable FP for the task given as the argument,1605- * and save the floating-point registers in its thread_struct.1606- * Enables the FPU for use in the kernel on return.1607- */1608-_GLOBAL(giveup_fpu)1609- mfmsr r51610- ori r5,r5,MSR_FP1611- mtmsrd r5 /* enable use of fpu now */1612- isync1613- cmpdi 0,r3,01614- beqlr- /* if no previous owner, done */1615- addi r3,r3,THREAD /* want THREAD of task */1616- ld r5,PT_REGS(r3)1617- cmpdi 0,r5,01618- SAVE_32FPRS(0, r3)1619- mffs fr01620- stfd fr0,THREAD_FPSCR(r3)1621- beq 1f1622- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)1623- li r3,MSR_FP|MSR_FE0|MSR_FE11624- andc r4,r4,r3 /* disable FP for previous task */1625- std r4,_MSR-STACK_FRAME_OVERHEAD(r5)1626-1:1627-#ifndef CONFIG_SMP1628- li r5,01629- ld r4,last_task_used_math@got(r2)1630- std r5,0(r4)1631-#endif /* CONFIG_SMP */1632- blr1633-1634-1635-#ifdef CONFIG_ALTIVEC1636-1637-/*1638- * load_up_altivec(unused, unused, tsk)1639- * Disable VMX for the task which had it previously,1640- * and save its vector registers in its thread_struct.1641- * Enables the VMX for use in the kernel on return.1642- * On SMP we know the VMX is free, since we give it up every1643- * switch (ie, no lazy save of the vector registers).1644- * On entry: r13 == 'current' && last_task_used_altivec != 'current'1645- */1646-_STATIC(load_up_altivec)1647- mfmsr r5 /* grab the current MSR */1648- oris r5,r5,MSR_VEC@h1649- mtmsrd r5 /* enable use of VMX now */1650- isync1651-1652-/*1653- * For SMP, we don't do lazy VMX switching because it just gets too1654- * horrendously complex, especially when a task switches from one CPU1655- * to another. Instead we call giveup_altvec in switch_to.1656- * VRSAVE isn't dealt with here, that is done in the normal context1657- * switch code. Note that we could rely on vrsave value to eventually1658- * avoid saving all of the VREGs here...1659- */1660-#ifndef CONFIG_SMP1661- ld r3,last_task_used_altivec@got(r2)1662- ld r4,0(r3)1663- cmpdi 0,r4,01664- beq 1f1665- /* Save VMX state to last_task_used_altivec's THREAD struct */1666- addi r4,r4,THREAD1667- SAVE_32VRS(0,r5,r4)1668- mfvscr vr01669- li r10,THREAD_VSCR1670- stvx vr0,r10,r41671- /* Disable VMX for last_task_used_altivec */1672- ld r5,PT_REGS(r4)1673- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)1674- lis r6,MSR_VEC@h1675- andc r4,r4,r61676- std r4,_MSR-STACK_FRAME_OVERHEAD(r5)1677-1:1678-#endif /* CONFIG_SMP */1679- /* Hack: if we get an altivec unavailable trap with VRSAVE1680- * set to all zeros, we assume this is a broken application1681- * that fails to set it properly, and thus we switch it to1682- * all 1's1683- */1684- mfspr r4,SPRN_VRSAVE1685- cmpdi 0,r4,01686- bne+ 1f1687- li r4,-11688- mtspr SPRN_VRSAVE,r41689-1:1690- /* enable use of VMX after return */1691- ld r4,PACACURRENT(r13)1692- addi r5,r4,THREAD /* Get THREAD */1693- oris r12,r12,MSR_VEC@h1694- std r12,_MSR(r1)1695- li r4,11696- li r10,THREAD_VSCR1697- stw r4,THREAD_USED_VR(r5)1698- lvx vr0,r10,r51699- mtvscr vr01700- REST_32VRS(0,r4,r5)1701-#ifndef CONFIG_SMP1702- /* Update last_task_used_math to 'current' */1703- subi r4,r5,THREAD /* Back to 'current' */1704- std r4,0(r3)1705-#endif /* CONFIG_SMP */1706- /* restore registers and return */1707- b fast_exception_return1708-1709-/*1710- * disable_kernel_altivec()1711- * Disable the VMX.1712- */1713-_GLOBAL(disable_kernel_altivec)1714- mfmsr r31715- rldicl r0,r3,(63-MSR_VEC_LG),11716- rldicl r3,r0,(MSR_VEC_LG+1),01717- mtmsrd r3 /* disable use of VMX now */1718- isync1719- blr1720-1721-/*1722- * giveup_altivec(tsk)1723- * Disable VMX for the task given as the argument,1724- * and save the vector registers in its thread_struct.1725- * Enables the VMX for use in the kernel on return.1726- */1727-_GLOBAL(giveup_altivec)1728- mfmsr r51729- oris r5,r5,MSR_VEC@h1730- mtmsrd r5 /* enable use of VMX now */1731- isync1732- cmpdi 0,r3,01733- beqlr- /* if no previous owner, done */1734- addi r3,r3,THREAD /* want THREAD of task */1735- ld r5,PT_REGS(r3)1736- cmpdi 0,r5,01737- SAVE_32VRS(0,r4,r3)1738- mfvscr vr01739- li r4,THREAD_VSCR1740- stvx vr0,r4,r31741- beq 1f1742- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)1743- lis r3,MSR_VEC@h1744- andc r4,r4,r3 /* disable FP for previous task */1745- std r4,_MSR-STACK_FRAME_OVERHEAD(r5)1746-1:1747-#ifndef CONFIG_SMP1748- li r5,01749- ld r4,last_task_used_altivec@got(r2)1750- std r5,0(r4)1751-#endif /* CONFIG_SMP */1752- blr1753-1754-#endif /* CONFIG_ALTIVEC */17551756#ifdef CONFIG_SMP1757#ifdef CONFIG_PPC_PMAC···18811882 bl .start_kernel18831884-_GLOBAL(__setup_cpu_power3)1885- blr1886-1887_GLOBAL(hmt_init)1888#ifdef CONFIG_HMT1889 LOADADDR(r5, hmt_thread_data)···19711972/*1973 * We put a few things here that have to be page-aligned.1974- * This stuff goes at the beginning of the data segment,1975- * which is page-aligned.1976 */1977- .data01978 .align 121979- .globl sdata1980-sdata:1981 .globl empty_zero_page1982empty_zero_page:1983- .space 409619841985 .globl swapper_pg_dir1986swapper_pg_dir:1987- .space 409619881989/*1990 * This space gets a copy of optional info passed to us by the bootstrap
···23 * 2 of the License, or (at your option) any later version.24 */250026#include <linux/config.h>27#include <linux/threads.h>28#include <asm/processor.h>29#include <asm/page.h>30#include <asm/mmu.h>031#include <asm/systemcfg.h>32#include <asm/ppc_asm.h>33#include <asm/offsets.h>···45#endif4647/*0000048 * We layout physical memory as follows:49 * 0x0000 - 0x00ff : Secondary processor spin code50 * 0x0100 - 0x2fff : pSeries Interrupt prologs51+ * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs52+ * 0x6000 - 0x6fff : Initial (CPU0) segment table53+ * 0x7000 - 0x7fff : FWNMI data area54+ * 0x8000 - : Early init and support code55 */5657/*···9495 /* Catch branch to 0 in real mode */96 trap97+98#ifdef CONFIG_PPC_ISERIES99 /*100 * At offset 0x20, there is a pointer to iSeries LPAR data.···103 .llong hvReleaseData-KERNELBASE104105 /*106+ * At offset 0x28 and 0x30 are offsets to the mschunks_map107 * array (used by the iSeries LPAR debugger to do translation108 * between physical addresses and absolute addresses) and109 * to the pidhash table (also used by the debugger)110 */111+ .llong mschunks_map-KERNELBASE112 .llong 0 /* pidhash-KERNELBASE SFRXXX */113114 /* Offset 0x38 - Pointer to start of embedded System.map */···120embedded_sysmap_end:121 .llong 0122123+#endif /* CONFIG_PPC_ISERIES */124125 /* Secondary processors spin on this value until it goes to 1. */126 .globl __secondary_hold_spinloop···155 std r24,__secondary_hold_acknowledge@l(0)156 sync157158+ /* All secondary cpus wait here until told to start. */159100: ld r4,__secondary_hold_spinloop@l(0)160 cmpdi 0,r4,1161 bne 100b···168 b .pSeries_secondary_smp_init169#else170 BUG_OPCODE0171#endif172#endif173···502 STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint)503 STD_EXCEPTION_PSERIES(0x1700, altivec_assist)504505+ . = 0x30000506507+/*** pSeries interrupt support ***/508+509+ /* moved from 0xf00 */510+ STD_EXCEPTION_PSERIES(., performance_monitor)511+512+ .align 7513_GLOBAL(do_stab_bolted_pSeries)514 mtcrf 0x80,r12515 mfspr r12,SPRG2516 EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted)517518+/*519+ * Vectors for the FWNMI option. Share common code.520+ */521+ .globl system_reset_fwnmi522+system_reset_fwnmi:523+ HMT_MEDIUM524+ mtspr SPRG1,r13 /* save r13 */525+ RUNLATCH_ON(r13)526+ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)527+528+ .globl machine_check_fwnmi529+machine_check_fwnmi:530+ HMT_MEDIUM531+ mtspr SPRG1,r13 /* save r13 */532+ RUNLATCH_ON(r13)533+ EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)534+535#ifdef CONFIG_PPC_ISERIES00000000536/*** ISeries-LPAR interrupt handlers ***/537538 STD_EXCEPTION_ISERIES(0x200, machine_check, PACA_EXMC)···626627 cmpwi 0,r23,0628 beq iSeries_secondary_smp_loop /* Loop until told to go */0629 bne .__secondary_start /* Loop until told to go */0630iSeries_secondary_smp_loop:631 /* Let the Hypervisor know we are alive */632 /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */···671 ld r13,PACA_EXGEN+EX_R13(r13)672 rfid673 b . /* prevent speculative execution */000000000000674#endif /* CONFIG_PPC_ISERIES */0000000000000000000000000000000675676/*** Common interrupt handlers ***/677···752 * R9 contains the saved CR, r13 points to the paca,753 * r10 contains the (bad) kernel stack pointer,754 * r11 and r12 contain the saved SRR0 and SRR1.755+ * We switch to using an emergency stack, save the registers there,756+ * and call kernel_bad_stack(), which panics.757 */758bad_stack:759 ld r1,PACAEMERGSP(r13)···906 bl .kernel_fp_unavailable_exception907 BUG_OPCODE908909+/*910+ * load_up_fpu(unused, unused, tsk)911+ * Disable FP for the task which had the FPU previously,912+ * and save its floating-point registers in its thread_struct.913+ * Enables the FPU for use in the kernel on return.914+ * On SMP we know the fpu is free, since we give it up every915+ * switch (ie, no lazy save of the FP registers).916+ * On entry: r13 == 'current' && last_task_used_math != 'current'917+ */918+_STATIC(load_up_fpu)919+ mfmsr r5 /* grab the current MSR */920+ ori r5,r5,MSR_FP921+ mtmsrd r5 /* enable use of fpu now */922+ isync923+/*924+ * For SMP, we don't do lazy FPU switching because it just gets too925+ * horrendously complex, especially when a task switches from one CPU926+ * to another. Instead we call giveup_fpu in switch_to.927+ *928+ */929+#ifndef CONFIG_SMP930+ ld r3,last_task_used_math@got(r2)931+ ld r4,0(r3)932+ cmpdi 0,r4,0933+ beq 1f934+ /* Save FP state to last_task_used_math's THREAD struct */935+ addi r4,r4,THREAD936+ SAVE_32FPRS(0, r4)937+ mffs fr0938+ stfd fr0,THREAD_FPSCR(r4)939+ /* Disable FP for last_task_used_math */940+ ld r5,PT_REGS(r4)941+ ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)942+ li r6,MSR_FP|MSR_FE0|MSR_FE1943+ andc r4,r4,r6944+ std r4,_MSR-STACK_FRAME_OVERHEAD(r5)945+1:946+#endif /* CONFIG_SMP */947+ /* enable use of FP after return */948+ ld r4,PACACURRENT(r13)949+ addi r5,r4,THREAD /* Get THREAD */950+ ld r4,THREAD_FPEXC_MODE(r5)951+ ori r12,r12,MSR_FP952+ or r12,r12,r4953+ std r12,_MSR(r1)954+ lfd fr0,THREAD_FPSCR(r5)955+ mtfsf 0xff,fr0956+ REST_32FPRS(0, r5)957+#ifndef CONFIG_SMP958+ /* Update last_task_used_math to 'current' */959+ subi r4,r5,THREAD /* Back to 'current' */960+ std r4,0(r3)961+#endif /* CONFIG_SMP */962+ /* restore registers and return */963+ b fast_exception_return964+965 .align 7966 .globl altivec_unavailable_common967altivec_unavailable_common:···920 ENABLE_INTS921 bl .altivec_unavailable_exception922 b .ret_from_except923+924+#ifdef CONFIG_ALTIVEC925+/*926+ * load_up_altivec(unused, unused, tsk)927+ * Disable VMX for the task which had it previously,928+ * and save its vector registers in its thread_struct.929+ * Enables the VMX for use in the kernel on return.930+ * On SMP we know the VMX is free, since we give it up every931+ * switch (ie, no lazy save of the vector registers).932+ * On entry: r13 == 'current' && last_task_used_altivec != 'current'933+ */934+_STATIC(load_up_altivec)935+ mfmsr r5 /* grab the current MSR */936+ oris r5,r5,MSR_VEC@h937+ mtmsrd r5 /* enable use of VMX now */938+ isync939+940+/*941+ * For SMP, we don't do lazy VMX switching because it just gets too942+ * horrendously complex, especially when a task switches from one CPU943+ * to another. Instead we call giveup_altvec in switch_to.944+ * VRSAVE isn't dealt with here, that is done in the normal context945+ * switch code. Note that we could rely on vrsave value to eventually946+ * avoid saving all of the VREGs here...947+ */948+#ifndef CONFIG_SMP949+ ld r3,last_task_used_altivec@got(r2)950+ ld r4,0(r3)951+ cmpdi 0,r4,0952+ beq 1f953+ /* Save VMX state to last_task_used_altivec's THREAD struct */954+ addi r4,r4,THREAD955+ SAVE_32VRS(0,r5,r4)956+ mfvscr vr0957+ li r10,THREAD_VSCR958+ stvx vr0,r10,r4959+ /* Disable VMX for last_task_used_altivec */960+ ld r5,PT_REGS(r4)961+ ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)962+ lis r6,MSR_VEC@h963+ andc r4,r4,r6964+ std r4,_MSR-STACK_FRAME_OVERHEAD(r5)965+1:966+#endif /* CONFIG_SMP */967+ /* Hack: if we get an altivec unavailable trap with VRSAVE968+ * set to all zeros, we assume this is a broken application969+ * that fails to set it properly, and thus we switch it to970+ * all 1's971+ */972+ mfspr r4,SPRN_VRSAVE973+ cmpdi 0,r4,0974+ bne+ 1f975+ li r4,-1976+ mtspr SPRN_VRSAVE,r4977+1:978+ /* enable use of VMX after return */979+ ld r4,PACACURRENT(r13)980+ addi r5,r4,THREAD /* Get THREAD */981+ oris r12,r12,MSR_VEC@h982+ std r12,_MSR(r1)983+ li r4,1984+ li r10,THREAD_VSCR985+ stw r4,THREAD_USED_VR(r5)986+ lvx vr0,r10,r5987+ mtvscr vr0988+ REST_32VRS(0,r4,r5)989+#ifndef CONFIG_SMP990+ /* Update last_task_used_math to 'current' */991+ subi r4,r5,THREAD /* Back to 'current' */992+ std r4,0(r3)993+#endif /* CONFIG_SMP */994+ /* restore registers and return */995+ b fast_exception_return996+#endif /* CONFIG_ALTIVEC */997998/*999 * Hash table stuff···1167 bl .unrecoverable_exception1168 b 1b11691170+/*1171+ * Space for CPU0's segment table.1172+ *1173+ * On iSeries, the hypervisor must fill in at least one entry before1174+ * we get control (with relocate on). The address is give to the hv1175+ * as a page number (see xLparMap in LparData.c), so this must be at a1176+ * fixed address (the linker can't compute (u64)&initial_stab >>1177+ * PAGE_SHIFT).1178+ */1179+ . = STAB0_PHYS_ADDR /* 0x6000 */1180+ .globl initial_stab1181+initial_stab:1182+ .space 40961183+1184+/*1185+ * Data area reserved for FWNMI option.1186+ * This address (0x7000) is fixed by the RPA.1187+ */1188+ .= 0x70001189+ .globl fwnmi_data_area1190+fwnmi_data_area:1191+ .space PAGE_SIZE11921193/*1194 * On pSeries, secondary processors spin in the following code.···1200 b .kexec_wait /* next kernel might do better */120112022: mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */1203+ /* From now on, r24 is expected to be logical cpuid */1204 mr r24,r512053: HMT_LOW1206 lbz r23,PACAPROCSTART(r13) /* Test if this processor should */···12131214 cmpwi 0,r23,01215#ifdef CONFIG_SMP01216 bne .__secondary_start01217#endif1218 b 3b /* Loop until told to go */1219···14291430.align 81431copy_to_here:00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014321433#ifdef CONFIG_SMP1434#ifdef CONFIG_PPC_PMAC···20022003 bl .start_kernel20040002005_GLOBAL(hmt_init)2006#ifdef CONFIG_HMT2007 LOADADDR(r5, hmt_thread_data)···20952096/*2097 * We put a few things here that have to be page-aligned.2098+ * This stuff goes at the beginning of the bss, which is page-aligned.02099 */2100+ .section ".bss"2101+2102 .align 122103+02104 .globl empty_zero_page2105empty_zero_page:2106+ .space PAGE_SIZE21072108 .globl swapper_pg_dir2109swapper_pg_dir:2110+ .space PAGE_SIZE21112112/*2113 * This space gets a copy of optional info passed to us by the bootstrap
+4-1
arch/ppc64/kernel/iSeries_htab.c
···41 unsigned long prpn, unsigned long vflags,42 unsigned long rflags)43{044 long slot;45 hpte_t lhpte;46 int secondary = 0;···71 slot &= 0x7fffffffffffffff;72 }730074 lhpte.v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID;75- lhpte.r = (physRpn_to_absRpn(prpn) << HPTE_R_RPN_SHIFT) | rflags;7677 /* Now fill in the actual HPTE */78 HvCallHpt_addValidate(slot, secondary, &lhpte);
···41 unsigned long prpn, unsigned long vflags,42 unsigned long rflags)43{44+ unsigned long arpn;45 long slot;46 hpte_t lhpte;47 int secondary = 0;···70 slot &= 0x7fffffffffffffff;71 }7273+ arpn = phys_to_abs(prpn << PAGE_SHIFT) >> PAGE_SHIFT;74+75 lhpte.v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID;76+ lhpte.r = (arpn << HPTE_R_RPN_SHIFT) | rflags;7778 /* Now fill in the actual HPTE */79 HvCallHpt_addValidate(slot, secondary, &lhpte);
+26-4
arch/ppc64/kernel/iSeries_setup.c
···39#include <asm/cputable.h>40#include <asm/sections.h>41#include <asm/iommu.h>04243#include <asm/time.h>44#include "iSeries_setup.h"···315316 DBG(" -> iSeries_init_early()\n");31700318 ppcdbg_initialize();319320#if defined(CONFIG_BLK_DEV_INITRD)···415 DBG(" <- iSeries_init_early()\n");416}4170000000000000000418/*419 * The iSeries may have very large memories ( > 128 GB ) and a partition420 * may get memory in "chunks" that may be anywhere in the 2**52 real···468469 /* Chunk size on iSeries is 256K bytes */470 totalChunks = (u32)HvLpConfig_getMsChunks();471- klimit = msChunks_alloc(klimit, totalChunks, 1UL << 18);472473 /*474 * Get absolute address of our load area···505 printk("Load area size %dK\n", loadAreaSize * 256);506507 for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk)508- msChunks.abs[nextPhysChunk] =509 loadAreaFirstChunk + nextPhysChunk;510511 /*···514 */515 hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress());516 hptSizePages = (u32)HvCallHpt_getHptPages();517- hptSizeChunks = hptSizePages >> (msChunks.chunk_shift - PAGE_SHIFT);518 hptLastChunk = hptFirstChunk + hptSizeChunks - 1;519520 printk("HPT absolute addr = %016lx, size = %dK\n",···571 (absChunk > hptLastChunk)) &&572 ((absChunk < loadAreaFirstChunk) ||573 (absChunk > loadAreaLastChunk))) {574- msChunks.abs[nextPhysChunk] = absChunk;0575 ++nextPhysChunk;576 }577 }···963 ppc_md.get_rtc_time = iSeries_get_rtc_time;964 ppc_md.calibrate_decr = iSeries_calibrate_decr;965 ppc_md.progress = iSeries_progress;00966967 if (get_paca()->lppaca.shared_proc) {968 ppc_md.idle_loop = iseries_shared_idle;
···39#include <asm/cputable.h>40#include <asm/sections.h>41#include <asm/iommu.h>42+#include <asm/firmware.h>4344#include <asm/time.h>45#include "iSeries_setup.h"···314315 DBG(" -> iSeries_init_early()\n");316317+ ppc64_firmware_features = FW_FEATURE_ISERIES;318+319 ppcdbg_initialize();320321#if defined(CONFIG_BLK_DEV_INITRD)···412 DBG(" <- iSeries_init_early()\n");413}414415+struct mschunks_map mschunks_map = {416+ /* XXX We don't use these, but Piranha might need them. */417+ .chunk_size = MSCHUNKS_CHUNK_SIZE,418+ .chunk_shift = MSCHUNKS_CHUNK_SHIFT,419+ .chunk_mask = MSCHUNKS_OFFSET_MASK,420+};421+EXPORT_SYMBOL(mschunks_map);422+423+void mschunks_alloc(unsigned long num_chunks)424+{425+ klimit = _ALIGN(klimit, sizeof(u32));426+ mschunks_map.mapping = (u32 *)klimit;427+ klimit += num_chunks * sizeof(u32);428+ mschunks_map.num_chunks = num_chunks;429+}430+431/*432 * The iSeries may have very large memories ( > 128 GB ) and a partition433 * may get memory in "chunks" that may be anywhere in the 2**52 real···449450 /* Chunk size on iSeries is 256K bytes */451 totalChunks = (u32)HvLpConfig_getMsChunks();452+ mschunks_alloc(totalChunks);453454 /*455 * Get absolute address of our load area···486 printk("Load area size %dK\n", loadAreaSize * 256);487488 for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk)489+ mschunks_map.mapping[nextPhysChunk] =490 loadAreaFirstChunk + nextPhysChunk;491492 /*···495 */496 hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress());497 hptSizePages = (u32)HvCallHpt_getHptPages();498+ hptSizeChunks = hptSizePages >> (MSCHUNKS_CHUNK_SHIFT - PAGE_SHIFT);499 hptLastChunk = hptFirstChunk + hptSizeChunks - 1;500501 printk("HPT absolute addr = %016lx, size = %dK\n",···552 (absChunk > hptLastChunk)) &&553 ((absChunk < loadAreaFirstChunk) ||554 (absChunk > loadAreaLastChunk))) {555+ mschunks_map.mapping[nextPhysChunk] =556+ absChunk;557 ++nextPhysChunk;558 }559 }···943 ppc_md.get_rtc_time = iSeries_get_rtc_time;944 ppc_md.calibrate_decr = iSeries_calibrate_decr;945 ppc_md.progress = iSeries_progress;946+947+ /* XXX Implement enable_pmcs for iSeries */948949 if (get_paca()->lppaca.shared_proc) {950 ppc_md.idle_loop = iseries_shared_idle;
···1+/*2+ * IBM PowerPC iSeries Virtual I/O Infrastructure Support.3+ *4+ * Copyright (c) 2005 Stephen Rothwell, IBM Corp.5+ *6+ * This program is free software; you can redistribute it and/or7+ * modify it under the terms of the GNU General Public License8+ * as published by the Free Software Foundation; either version9+ * 2 of the License, or (at your option) any later version.10+ */11+#include <linux/types.h>12+#include <linux/device.h>13+#include <linux/init.h>14+15+#include <asm/vio.h>16+#include <asm/iommu.h>17+#include <asm/abs_addr.h>18+#include <asm/page.h>19+#include <asm/iSeries/vio.h>20+#include <asm/iSeries/HvTypes.h>21+#include <asm/iSeries/HvLpConfig.h>22+#include <asm/iSeries/HvCallXm.h>23+24+struct device *iSeries_vio_dev = &vio_bus_device.dev;25+EXPORT_SYMBOL(iSeries_vio_dev);26+27+static struct iommu_table veth_iommu_table;28+static struct iommu_table vio_iommu_table;29+30+static void __init iommu_vio_init(void)31+{32+ struct iommu_table *t;33+ struct iommu_table_cb cb;34+ unsigned long cbp;35+ unsigned long itc_entries;36+37+ cb.itc_busno = 255; /* Bus 255 is the virtual bus */38+ cb.itc_virtbus = 0xff; /* Ask for virtual bus */39+40+ cbp = virt_to_abs(&cb);41+ HvCallXm_getTceTableParms(cbp);42+43+ itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry);44+ veth_iommu_table.it_size = itc_entries / 2;45+ veth_iommu_table.it_busno = cb.itc_busno;46+ veth_iommu_table.it_offset = cb.itc_offset;47+ veth_iommu_table.it_index = cb.itc_index;48+ veth_iommu_table.it_type = TCE_VB;49+ veth_iommu_table.it_blocksize = 1;50+51+ t = iommu_init_table(&veth_iommu_table);52+53+ if (!t)54+ printk("Virtual Bus VETH TCE table failed.\n");55+56+ vio_iommu_table.it_size = itc_entries - veth_iommu_table.it_size;57+ vio_iommu_table.it_busno = cb.itc_busno;58+ vio_iommu_table.it_offset = cb.itc_offset +59+ veth_iommu_table.it_size;60+ vio_iommu_table.it_index = cb.itc_index;61+ vio_iommu_table.it_type = TCE_VB;62+ vio_iommu_table.it_blocksize = 1;63+64+ t = iommu_init_table(&vio_iommu_table);65+66+ if (!t)67+ printk("Virtual Bus VIO TCE table failed.\n");68+}69+70+/**71+ * vio_register_device: - Register a new vio device.72+ * @voidev: The device to register.73+ */74+static struct vio_dev *__init vio_register_device_iseries(char *type,75+ uint32_t unit_num)76+{77+ struct vio_dev *viodev;78+79+ /* allocate a vio_dev for this node */80+ viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);81+ if (!viodev)82+ return NULL;83+ memset(viodev, 0, sizeof(struct vio_dev));84+85+ snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num);86+87+ return vio_register_device_common(viodev, viodev->dev.bus_id, type,88+ unit_num, &vio_iommu_table);89+}90+91+void __init probe_bus_iseries(void)92+{93+ HvLpIndexMap vlan_map;94+ struct vio_dev *viodev;95+ int i;96+97+ /* there is only one of each of these */98+ vio_register_device_iseries("viocons", 0);99+ vio_register_device_iseries("vscsi", 0);100+101+ vlan_map = HvLpConfig_getVirtualLanIndexMap();102+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {103+ if ((vlan_map & (0x8000 >> i)) == 0)104+ continue;105+ viodev = vio_register_device_iseries("vlan", i);106+ /* veth is special and has it own iommu_table */107+ viodev->iommu_table = &veth_iommu_table;108+ }109+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)110+ vio_register_device_iseries("viodasd", i);111+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)112+ vio_register_device_iseries("viocd", i);113+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)114+ vio_register_device_iseries("viotape", i);115+}116+117+/**118+ * vio_match_device_iseries: - Tell if a iSeries VIO device matches a119+ * vio_device_id120+ */121+static int vio_match_device_iseries(const struct vio_device_id *id,122+ const struct vio_dev *dev)123+{124+ return strncmp(dev->type, id->type, strlen(id->type)) == 0;125+}126+127+/**128+ * vio_bus_init_iseries: - Initialize the iSeries virtual IO bus129+ */130+static int __init vio_bus_init_iseries(void)131+{132+ int err;133+134+ err = vio_bus_init(vio_match_device_iseries, NULL, NULL);135+ if (err == 0) {136+ iommu_vio_init();137+ vio_bus_device.iommu_table = &vio_iommu_table;138+ iSeries_vio_dev = &vio_bus_device.dev;139+ probe_bus_iseries();140+ }141+ return err;142+}143+144+__initcall(vio_bus_init_iseries);
+38-111
arch/ppc64/kernel/lmb.c
···28{29#ifdef DEBUG30 unsigned long i;31- struct lmb *_lmb = &lmb;3233 udbg_printf("lmb_dump_all:\n");34 udbg_printf(" memory.cnt = 0x%lx\n",35- _lmb->memory.cnt);36 udbg_printf(" memory.size = 0x%lx\n",37- _lmb->memory.size);38- for (i=0; i < _lmb->memory.cnt ;i++) {39 udbg_printf(" memory.region[0x%x].base = 0x%lx\n",40- i, _lmb->memory.region[i].base);41- udbg_printf(" .physbase = 0x%lx\n",42- _lmb->memory.region[i].physbase);43 udbg_printf(" .size = 0x%lx\n",44- _lmb->memory.region[i].size);45 }4647 udbg_printf("\n reserved.cnt = 0x%lx\n",48- _lmb->reserved.cnt);49 udbg_printf(" reserved.size = 0x%lx\n",50- _lmb->reserved.size);51- for (i=0; i < _lmb->reserved.cnt ;i++) {52 udbg_printf(" reserved.region[0x%x].base = 0x%lx\n",53- i, _lmb->reserved.region[i].base);54- udbg_printf(" .physbase = 0x%lx\n",55- _lmb->reserved.region[i].physbase);56 udbg_printf(" .size = 0x%lx\n",57- _lmb->reserved.region[i].size);58 }59#endif /* DEBUG */60}···93 rgn->region[r1].size += rgn->region[r2].size;94 for (i=r2; i < rgn->cnt-1; i++) {95 rgn->region[i].base = rgn->region[i+1].base;96- rgn->region[i].physbase = rgn->region[i+1].physbase;97 rgn->region[i].size = rgn->region[i+1].size;98 }99 rgn->cnt--;···102void __init103lmb_init(void)104{105- struct lmb *_lmb = &lmb;106-107 /* Create a dummy zero size LMB which will get coalesced away later.108 * This simplifies the lmb_add() code below...109 */110- _lmb->memory.region[0].base = 0;111- _lmb->memory.region[0].size = 0;112- _lmb->memory.cnt = 1;113114 /* Ditto. */115- _lmb->reserved.region[0].base = 0;116- _lmb->reserved.region[0].size = 0;117- _lmb->reserved.cnt = 1;118}119120/* This routine called with relocation disabled. */121void __init122lmb_analyze(void)123{124- unsigned long i;125- unsigned long mem_size = 0;126- unsigned long size_mask = 0;127- struct lmb *_lmb = &lmb;128-#ifdef CONFIG_MSCHUNKS129- unsigned long physbase = 0;130-#endif131132- for (i=0; i < _lmb->memory.cnt; i++) {133- unsigned long lmb_size;134135- lmb_size = _lmb->memory.region[i].size;136-137-#ifdef CONFIG_MSCHUNKS138- _lmb->memory.region[i].physbase = physbase;139- physbase += lmb_size;140-#else141- _lmb->memory.region[i].physbase = _lmb->memory.region[i].base;142-#endif143- mem_size += lmb_size;144- size_mask |= lmb_size;145- }146-147- _lmb->memory.size = mem_size;148}149150/* This routine called with relocation disabled. */···142 adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize);143 if ( adjacent > 0 ) {144 rgn->region[i].base -= size;145- rgn->region[i].physbase -= size;146 rgn->region[i].size += size;147 coalesced++;148 break;···168 for (i=rgn->cnt-1; i >= 0; i--) {169 if (base < rgn->region[i].base) {170 rgn->region[i+1].base = rgn->region[i].base;171- rgn->region[i+1].physbase = rgn->region[i].physbase;172 rgn->region[i+1].size = rgn->region[i].size;173 } else {174 rgn->region[i+1].base = base;175- rgn->region[i+1].physbase = lmb_abs_to_phys(base);176 rgn->region[i+1].size = size;177 break;178 }···184long __init185lmb_add(unsigned long base, unsigned long size)186{187- struct lmb *_lmb = &lmb;188- struct lmb_region *_rgn = &(_lmb->memory);189190 /* On pSeries LPAR systems, the first LMB is our RMO region. */191 if ( base == 0 )192- _lmb->rmo_size = size;193194 return lmb_add_region(_rgn, base, size);195···197long __init198lmb_reserve(unsigned long base, unsigned long size)199{200- struct lmb *_lmb = &lmb;201- struct lmb_region *_rgn = &(_lmb->reserved);202203 return lmb_add_region(_rgn, base, size);204}···229{230 long i, j;231 unsigned long base = 0;232- struct lmb *_lmb = &lmb;233- struct lmb_region *_mem = &(_lmb->memory);234- struct lmb_region *_rsv = &(_lmb->reserved);235236- for (i=_mem->cnt-1; i >= 0; i--) {237- unsigned long lmbbase = _mem->region[i].base;238- unsigned long lmbsize = _mem->region[i].size;239240 if ( max_addr == LMB_ALLOC_ANYWHERE )241 base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);···242 continue;243244 while ( (lmbbase <= base) &&245- ((j = lmb_overlaps_region(_rsv,base,size)) >= 0) ) {246- base = _ALIGN_DOWN(_rsv->region[j].base-size, align);247 }248249 if ( (base != 0) && (lmbbase <= base) )···253 if ( i < 0 )254 return 0;255256- lmb_add_region(_rsv, base, size);257258 return base;259}2600261unsigned long __init262lmb_phys_mem_size(void)263{264- struct lmb *_lmb = &lmb;265-#ifdef CONFIG_MSCHUNKS266- return _lmb->memory.size;267-#else268- struct lmb_region *_mem = &(_lmb->memory);269- unsigned long total = 0;270- int i;271-272- /* add all physical memory to the bootmem map */273- for (i=0; i < _mem->cnt; i++)274- total += _mem->region[i].size;275- return total;276-#endif /* CONFIG_MSCHUNKS */277}278279unsigned long __init280lmb_end_of_DRAM(void)281{282- struct lmb *_lmb = &lmb;283- struct lmb_region *_mem = &(_lmb->memory);284- int idx = _mem->cnt - 1;285286-#ifdef CONFIG_MSCHUNKS287- return (_mem->region[idx].physbase + _mem->region[idx].size);288-#else289- return (_mem->region[idx].base + _mem->region[idx].size);290-#endif /* CONFIG_MSCHUNKS */291-292- return 0;293-}294-295-unsigned long __init296-lmb_abs_to_phys(unsigned long aa)297-{298- unsigned long i, pa = aa;299- struct lmb *_lmb = &lmb;300- struct lmb_region *_mem = &(_lmb->memory);301-302- for (i=0; i < _mem->cnt; i++) {303- unsigned long lmbbase = _mem->region[i].base;304- unsigned long lmbsize = _mem->region[i].size;305- if ( lmb_addrs_overlap(aa,1,lmbbase,lmbsize) ) {306- pa = _mem->region[i].physbase + (aa - lmbbase);307- break;308- }309- }310-311- return pa;312}313314/*···281{282 extern unsigned long memory_limit;283 unsigned long i, limit;284- struct lmb_region *mem = &(lmb.memory);285286 if (! memory_limit)287 return;288289 limit = memory_limit;290- for (i = 0; i < mem->cnt; i++) {291- if (limit > mem->region[i].size) {292- limit -= mem->region[i].size;293 continue;294 }295296- mem->region[i].size = limit;297- mem->cnt = i + 1;298 break;299 }300}
···28{29#ifdef DEBUG30 unsigned long i;03132 udbg_printf("lmb_dump_all:\n");33 udbg_printf(" memory.cnt = 0x%lx\n",34+ lmb.memory.cnt);35 udbg_printf(" memory.size = 0x%lx\n",36+ lmb.memory.size);37+ for (i=0; i < lmb.memory.cnt ;i++) {38 udbg_printf(" memory.region[0x%x].base = 0x%lx\n",39+ i, lmb.memory.region[i].base);0040 udbg_printf(" .size = 0x%lx\n",41+ lmb.memory.region[i].size);42 }4344 udbg_printf("\n reserved.cnt = 0x%lx\n",45+ lmb.reserved.cnt);46 udbg_printf(" reserved.size = 0x%lx\n",47+ lmb.reserved.size);48+ for (i=0; i < lmb.reserved.cnt ;i++) {49 udbg_printf(" reserved.region[0x%x].base = 0x%lx\n",50+ i, lmb.reserved.region[i].base);0051 udbg_printf(" .size = 0x%lx\n",52+ lmb.reserved.region[i].size);53 }54#endif /* DEBUG */55}···98 rgn->region[r1].size += rgn->region[r2].size;99 for (i=r2; i < rgn->cnt-1; i++) {100 rgn->region[i].base = rgn->region[i+1].base;0101 rgn->region[i].size = rgn->region[i+1].size;102 }103 rgn->cnt--;···108void __init109lmb_init(void)110{00111 /* Create a dummy zero size LMB which will get coalesced away later.112 * This simplifies the lmb_add() code below...113 */114+ lmb.memory.region[0].base = 0;115+ lmb.memory.region[0].size = 0;116+ lmb.memory.cnt = 1;117118 /* Ditto. */119+ lmb.reserved.region[0].base = 0;120+ lmb.reserved.region[0].size = 0;121+ lmb.reserved.cnt = 1;122}123124/* This routine called with relocation disabled. */125void __init126lmb_analyze(void)127{128+ int i;000000129130+ lmb.memory.size = 0;0131132+ for (i = 0; i < lmb.memory.cnt; i++)133+ lmb.memory.size += lmb.memory.region[i].size;00000000000134}135136/* This routine called with relocation disabled. */···168 adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize);169 if ( adjacent > 0 ) {170 rgn->region[i].base -= size;0171 rgn->region[i].size += size;172 coalesced++;173 break;···195 for (i=rgn->cnt-1; i >= 0; i--) {196 if (base < rgn->region[i].base) {197 rgn->region[i+1].base = rgn->region[i].base;0198 rgn->region[i+1].size = rgn->region[i].size;199 } else {200 rgn->region[i+1].base = base;0201 rgn->region[i+1].size = size;202 break;203 }···213long __init214lmb_add(unsigned long base, unsigned long size)215{216+ struct lmb_region *_rgn = &(lmb.memory);0217218 /* On pSeries LPAR systems, the first LMB is our RMO region. */219 if ( base == 0 )220+ lmb.rmo_size = size;221222 return lmb_add_region(_rgn, base, size);223···227long __init228lmb_reserve(unsigned long base, unsigned long size)229{230+ struct lmb_region *_rgn = &(lmb.reserved);0231232 return lmb_add_region(_rgn, base, size);233}···260{261 long i, j;262 unsigned long base = 0;000263264+ for (i=lmb.memory.cnt-1; i >= 0; i--) {265+ unsigned long lmbbase = lmb.memory.region[i].base;266+ unsigned long lmbsize = lmb.memory.region[i].size;267268 if ( max_addr == LMB_ALLOC_ANYWHERE )269 base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);···276 continue;277278 while ( (lmbbase <= base) &&279+ ((j = lmb_overlaps_region(&lmb.reserved,base,size)) >= 0) ) {280+ base = _ALIGN_DOWN(lmb.reserved.region[j].base-size, align);281 }282283 if ( (base != 0) && (lmbbase <= base) )···287 if ( i < 0 )288 return 0;289290+ lmb_add_region(&lmb.reserved, base, size);291292 return base;293}294295+/* You must call lmb_analyze() before this. */296unsigned long __init297lmb_phys_mem_size(void)298{299+ return lmb.memory.size;000000000000300}301302unsigned long __init303lmb_end_of_DRAM(void)304{305+ int idx = lmb.memory.cnt - 1;00306307+ return (lmb.memory.region[idx].base + lmb.memory.region[idx].size);0000000000000000000000000308}309310/*···353{354 extern unsigned long memory_limit;355 unsigned long i, limit;0356357 if (! memory_limit)358 return;359360 limit = memory_limit;361+ for (i = 0; i < lmb.memory.cnt; i++) {362+ if (limit > lmb.memory.region[i].size) {363+ limit -= lmb.memory.region[i].size;364 continue;365 }366367+ lmb.memory.region[i].size = limit;368+ lmb.memory.cnt = i + 1;369 break;370 }371}
+3-3
arch/ppc64/kernel/lparcfg.c
···29#include <asm/iSeries/HvLpConfig.h>30#include <asm/lppaca.h>31#include <asm/hvcall.h>32-#include <asm/cputable.h>33#include <asm/rtas.h>34#include <asm/system.h>35#include <asm/time.h>···377378 partition_active_processors = lparcfg_count_active_processors();379380- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {381 unsigned long h_entitled, h_unallocated;382 unsigned long h_aggregation, h_resource;383 unsigned long pool_idle_time, pool_procs;···571 mode_t mode = S_IRUSR;572573 /* Allow writing if we have FW_FEATURE_SPLPAR */574- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {575 lparcfg_fops.write = lparcfg_write;576 mode |= S_IWUSR;577 }
···29#include <asm/iSeries/HvLpConfig.h>30#include <asm/lppaca.h>31#include <asm/hvcall.h>32+#include <asm/firmware.h>33#include <asm/rtas.h>34#include <asm/system.h>35#include <asm/time.h>···377378 partition_active_processors = lparcfg_count_active_processors();379380+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {381 unsigned long h_entitled, h_unallocated;382 unsigned long h_aggregation, h_resource;383 unsigned long pool_idle_time, pool_procs;···571 mode_t mode = S_IRUSR;572573 /* Allow writing if we have FW_FEATURE_SPLPAR */574+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {575 lparcfg_fops.write = lparcfg_write;576 mode |= S_IWUSR;577 }
+98
arch/ppc64/kernel/misc.S
···680 ld r30,-16(r1)681 blr68200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000683/* kexec_wait(phys_cpu)684 *685 * wait for the flag to change, indicating this kernel is going away but
···680 ld r30,-16(r1)681 blr682683+/*684+ * disable_kernel_fp()685+ * Disable the FPU.686+ */687+_GLOBAL(disable_kernel_fp)688+ mfmsr r3689+ rldicl r0,r3,(63-MSR_FP_LG),1690+ rldicl r3,r0,(MSR_FP_LG+1),0691+ mtmsrd r3 /* disable use of fpu now */692+ isync693+ blr694+695+/*696+ * giveup_fpu(tsk)697+ * Disable FP for the task given as the argument,698+ * and save the floating-point registers in its thread_struct.699+ * Enables the FPU for use in the kernel on return.700+ */701+_GLOBAL(giveup_fpu)702+ mfmsr r5703+ ori r5,r5,MSR_FP704+ mtmsrd r5 /* enable use of fpu now */705+ isync706+ cmpdi 0,r3,0707+ beqlr- /* if no previous owner, done */708+ addi r3,r3,THREAD /* want THREAD of task */709+ ld r5,PT_REGS(r3)710+ cmpdi 0,r5,0711+ SAVE_32FPRS(0, r3)712+ mffs fr0713+ stfd fr0,THREAD_FPSCR(r3)714+ beq 1f715+ ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)716+ li r3,MSR_FP|MSR_FE0|MSR_FE1717+ andc r4,r4,r3 /* disable FP for previous task */718+ std r4,_MSR-STACK_FRAME_OVERHEAD(r5)719+1:720+#ifndef CONFIG_SMP721+ li r5,0722+ ld r4,last_task_used_math@got(r2)723+ std r5,0(r4)724+#endif /* CONFIG_SMP */725+ blr726+727+#ifdef CONFIG_ALTIVEC728+729+#if 0 /* this has no callers for now */730+/*731+ * disable_kernel_altivec()732+ * Disable the VMX.733+ */734+_GLOBAL(disable_kernel_altivec)735+ mfmsr r3736+ rldicl r0,r3,(63-MSR_VEC_LG),1737+ rldicl r3,r0,(MSR_VEC_LG+1),0738+ mtmsrd r3 /* disable use of VMX now */739+ isync740+ blr741+#endif /* 0 */742+743+/*744+ * giveup_altivec(tsk)745+ * Disable VMX for the task given as the argument,746+ * and save the vector registers in its thread_struct.747+ * Enables the VMX for use in the kernel on return.748+ */749+_GLOBAL(giveup_altivec)750+ mfmsr r5751+ oris r5,r5,MSR_VEC@h752+ mtmsrd r5 /* enable use of VMX now */753+ isync754+ cmpdi 0,r3,0755+ beqlr- /* if no previous owner, done */756+ addi r3,r3,THREAD /* want THREAD of task */757+ ld r5,PT_REGS(r3)758+ cmpdi 0,r5,0759+ SAVE_32VRS(0,r4,r3)760+ mfvscr vr0761+ li r4,THREAD_VSCR762+ stvx vr0,r4,r3763+ beq 1f764+ ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)765+ lis r3,MSR_VEC@h766+ andc r4,r4,r3 /* disable FP for previous task */767+ std r4,_MSR-STACK_FRAME_OVERHEAD(r5)768+1:769+#ifndef CONFIG_SMP770+ li r5,0771+ ld r4,last_task_used_altivec@got(r2)772+ std r5,0(r4)773+#endif /* CONFIG_SMP */774+ blr775+776+#endif /* CONFIG_ALTIVEC */777+778+_GLOBAL(__setup_cpu_power3)779+ blr780+781/* kexec_wait(phys_cpu)782 *783 * wait for the flag to change, indicating this kernel is going away but
···52EXPORT_SYMBOL(plpar_hcall_norets);53EXPORT_SYMBOL(plpar_hcall_8arg_2ret);5455-extern void fw_feature_init(void);56extern void pSeries_find_serial_port(void);5758···278 unsigned long va, unsigned long prpn,279 unsigned long vflags, unsigned long rflags)280{281- unsigned long arpn = physRpn_to_absRpn(prpn);282 unsigned long lpar_rc;283 unsigned long flags;284 unsigned long slot;···288 if (vflags & HPTE_V_LARGE)289 hpte_v &= ~(1UL << HPTE_V_AVPN_SHIFT);290291- hpte_r = (arpn << HPTE_R_RPN_SHIFT) | rflags;292293 /* Now fill in the actual HPTE */294 /* Set CEC cookie to 0 */
···52EXPORT_SYMBOL(plpar_hcall_norets);53EXPORT_SYMBOL(plpar_hcall_8arg_2ret);54055extern void pSeries_find_serial_port(void);5657···279 unsigned long va, unsigned long prpn,280 unsigned long vflags, unsigned long rflags)281{0282 unsigned long lpar_rc;283 unsigned long flags;284 unsigned long slot;···290 if (vflags & HPTE_V_LARGE)291 hpte_v &= ~(1UL << HPTE_V_AVPN_SHIFT);292293+ hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags;294295 /* Now fill in the actual HPTE */296 /* Set CEC cookie to 0 */
+29-10
arch/ppc64/kernel/pSeries_setup.c
···60#include <asm/nvram.h>61#include <asm/plpar_wrappers.h>62#include <asm/xics.h>63-#include <asm/cputable.h>06465#include "i8259.h"66#include "mpic.h"···188 " MPIC ");189}190000000000000000191static void __init pSeries_setup_arch(void)192{193 /* Fixup ppc_md depending on the type of interrupt controller */···247248 pSeries_nvram_init();249250- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)251- vpa_init(boot_cpuid);252-253 /* Choose an idle loop */254- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {0255 if (get_paca()->lppaca.shared_proc) {256 printk(KERN_INFO "Using shared processor idle loop\n");257 ppc_md.idle_loop = pseries_shared_idle;···261 printk(KERN_INFO "Using default idle loop\n");262 ppc_md.idle_loop = default_idle;263 }00000264}265266static int __init pSeries_init_panel(void)···279arch_initcall(pSeries_init_panel);280281282-/* Build up the firmware_features bitmask field283 * using contents of device-tree/ibm,hypertas-functions.284 * Ultimately this functionality may be moved into prom.c prom_init().285 */286-void __init fw_feature_init(void)287{288 struct device_node * dn;289 char * hypertas;···291292 DBG(" -> fw_feature_init()\n");293294- cur_cpu_spec->firmware_features = 0;295 dn = of_find_node_by_path("/rtas");296 if (dn == NULL) {297 printk(KERN_ERR "WARNING ! Cannot find RTAS in device-tree !\n");···307 if ((firmware_features_table[i].name) &&308 (strcmp(firmware_features_table[i].name,hypertas))==0) {309 /* we have a match */310- cur_cpu_spec->firmware_features |= 311 (firmware_features_table[i].val);312 break;313 } ···321 of_node_put(dn);322 no_rtas:323 printk(KERN_INFO "firmware_features = 0x%lx\n", 324- cur_cpu_spec->firmware_features);325326 DBG(" <- fw_feature_init()\n");327}
···60#include <asm/nvram.h>61#include <asm/plpar_wrappers.h>62#include <asm/xics.h>63+#include <asm/firmware.h>64+#include <asm/pmc.h>6566#include "i8259.h"67#include "mpic.h"···187 " MPIC ");188}189190+static void pseries_lpar_enable_pmcs(void)191+{192+ unsigned long set, reset;193+194+ power4_enable_pmcs();195+196+ set = 1UL << 63;197+ reset = 0;198+ plpar_hcall_norets(H_PERFMON, set, reset);199+200+ /* instruct hypervisor to maintain PMCs */201+ if (firmware_has_feature(FW_FEATURE_SPLPAR))202+ get_paca()->lppaca.pmcregs_in_use = 1;203+}204+205static void __init pSeries_setup_arch(void)206{207 /* Fixup ppc_md depending on the type of interrupt controller */···231232 pSeries_nvram_init();233000234 /* Choose an idle loop */235+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {236+ vpa_init(boot_cpuid);237 if (get_paca()->lppaca.shared_proc) {238 printk(KERN_INFO "Using shared processor idle loop\n");239 ppc_md.idle_loop = pseries_shared_idle;···247 printk(KERN_INFO "Using default idle loop\n");248 ppc_md.idle_loop = default_idle;249 }250+251+ if (systemcfg->platform & PLATFORM_LPAR)252+ ppc_md.enable_pmcs = pseries_lpar_enable_pmcs;253+ else254+ ppc_md.enable_pmcs = power4_enable_pmcs;255}256257static int __init pSeries_init_panel(void)···260arch_initcall(pSeries_init_panel);261262263+/* Build up the ppc64_firmware_features bitmask field264 * using contents of device-tree/ibm,hypertas-functions.265 * Ultimately this functionality may be moved into prom.c prom_init().266 */267+static void __init fw_feature_init(void)268{269 struct device_node * dn;270 char * hypertas;···272273 DBG(" -> fw_feature_init()\n");274275+ ppc64_firmware_features = 0;276 dn = of_find_node_by_path("/rtas");277 if (dn == NULL) {278 printk(KERN_ERR "WARNING ! Cannot find RTAS in device-tree !\n");···288 if ((firmware_features_table[i].name) &&289 (strcmp(firmware_features_table[i].name,hypertas))==0) {290 /* we have a match */291+ ppc64_firmware_features |= 292 (firmware_features_table[i].val);293 break;294 } ···302 of_node_put(dn);303 no_rtas:304 printk(KERN_INFO "firmware_features = 0x%lx\n", 305+ ppc64_firmware_features);306307 DBG(" <- fw_feature_init()\n");308}
+2-1
arch/ppc64/kernel/pSeries_smp.c
···41#include <asm/machdep.h>42#include <asm/xics.h>43#include <asm/cputable.h>044#include <asm/system.h>45#include <asm/rtas.h>46#include <asm/plpar_wrappers.h>···327 if (cpu != boot_cpuid)328 xics_setup_cpu();329330- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)331 vpa_init(cpu);332333 cpu_clear(cpu, of_spin_map);
···41#include <asm/machdep.h>42#include <asm/xics.h>43#include <asm/cputable.h>44+#include <asm/firmware.h>45#include <asm/system.h>46#include <asm/rtas.h>47#include <asm/plpar_wrappers.h>···326 if (cpu != boot_cpuid)327 xics_setup_cpu();328329+ if (firmware_has_feature(FW_FEATURE_SPLPAR))330 vpa_init(cpu);331332 cpu_clear(cpu, of_spin_map);
···1+/*2+ * IBM PowerPC pSeries Virtual I/O Infrastructure Support.3+ *4+ * Copyright (c) 2003-2005 IBM Corp.5+ * Dave Engebretsen engebret@us.ibm.com6+ * Santiago Leon santil@us.ibm.com7+ * Hollis Blanchard <hollisb@us.ibm.com>8+ * Stephen Rothwell9+ *10+ * This program is free software; you can redistribute it and/or11+ * modify it under the terms of the GNU General Public License12+ * as published by the Free Software Foundation; either version13+ * 2 of the License, or (at your option) any later version.14+ */15+16+#include <linux/init.h>17+#include <linux/module.h>18+#include <linux/mm.h>19+#include <linux/kobject.h>20+#include <asm/iommu.h>21+#include <asm/dma.h>22+#include <asm/vio.h>23+#include <asm/hvcall.h>24+25+extern struct subsystem devices_subsys; /* needed for vio_find_name() */26+27+static void probe_bus_pseries(void)28+{29+ struct device_node *node_vroot, *of_node;30+31+ node_vroot = find_devices("vdevice");32+ if ((node_vroot == NULL) || (node_vroot->child == NULL))33+ /* this machine doesn't do virtual IO, and that's ok */34+ return;35+36+ /*37+ * Create struct vio_devices for each virtual device in the device tree.38+ * Drivers will associate with them later.39+ */40+ for (of_node = node_vroot->child; of_node != NULL;41+ of_node = of_node->sibling) {42+ printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node);43+ vio_register_device_node(of_node);44+ }45+}46+47+/**48+ * vio_match_device_pseries: - Tell if a pSeries VIO device matches a49+ * vio_device_id50+ */51+static int vio_match_device_pseries(const struct vio_device_id *id,52+ const struct vio_dev *dev)53+{54+ return (strncmp(dev->type, id->type, strlen(id->type)) == 0) &&55+ device_is_compatible(dev->dev.platform_data, id->compat);56+}57+58+static void vio_release_device_pseries(struct device *dev)59+{60+ /* XXX free TCE table */61+ of_node_put(dev->platform_data);62+}63+64+static ssize_t viodev_show_devspec(struct device *dev,65+ struct device_attribute *attr, char *buf)66+{67+ struct device_node *of_node = dev->platform_data;68+69+ return sprintf(buf, "%s\n", of_node->full_name);70+}71+DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL);72+73+static void vio_unregister_device_pseries(struct vio_dev *viodev)74+{75+ device_remove_file(&viodev->dev, &dev_attr_devspec);76+}77+78+/**79+ * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus80+ */81+static int __init vio_bus_init_pseries(void)82+{83+ int err;84+85+ err = vio_bus_init(vio_match_device_pseries,86+ vio_unregister_device_pseries,87+ vio_release_device_pseries);88+ if (err == 0)89+ probe_bus_pseries();90+ return err;91+}92+93+__initcall(vio_bus_init_pseries);94+95+/**96+ * vio_build_iommu_table: - gets the dma information from OF and97+ * builds the TCE tree.98+ * @dev: the virtual device.99+ *100+ * Returns a pointer to the built tce tree, or NULL if it can't101+ * find property.102+*/103+static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)104+{105+ unsigned int *dma_window;106+ struct iommu_table *newTceTable;107+ unsigned long offset;108+ int dma_window_property_size;109+110+ dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size);111+ if(!dma_window) {112+ return NULL;113+ }114+115+ newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL);116+117+ /* There should be some code to extract the phys-encoded offset118+ using prom_n_addr_cells(). However, according to a comment119+ on earlier versions, it's always zero, so we don't bother */120+ offset = dma_window[1] >> PAGE_SHIFT;121+122+ /* TCE table size - measured in tce entries */123+ newTceTable->it_size = dma_window[4] >> PAGE_SHIFT;124+ /* offset for VIO should always be 0 */125+ newTceTable->it_offset = offset;126+ newTceTable->it_busno = 0;127+ newTceTable->it_index = (unsigned long)dma_window[0];128+ newTceTable->it_type = TCE_VB;129+130+ return iommu_init_table(newTceTable);131+}132+133+/**134+ * vio_register_device_node: - Register a new vio device.135+ * @of_node: The OF node for this device.136+ *137+ * Creates and initializes a vio_dev structure from the data in138+ * of_node (dev.platform_data) and adds it to the list of virtual devices.139+ * Returns a pointer to the created vio_dev or NULL if node has140+ * NULL device_type or compatible fields.141+ */142+struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)143+{144+ struct vio_dev *viodev;145+ unsigned int *unit_address;146+ unsigned int *irq_p;147+148+ /* we need the 'device_type' property, in order to match with drivers */149+ if ((NULL == of_node->type)) {150+ printk(KERN_WARNING151+ "%s: node %s missing 'device_type'\n", __FUNCTION__,152+ of_node->name ? of_node->name : "<unknown>");153+ return NULL;154+ }155+156+ unit_address = (unsigned int *)get_property(of_node, "reg", NULL);157+ if (!unit_address) {158+ printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__,159+ of_node->name ? of_node->name : "<unknown>");160+ return NULL;161+ }162+163+ /* allocate a vio_dev for this node */164+ viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);165+ if (!viodev) {166+ return NULL;167+ }168+ memset(viodev, 0, sizeof(struct vio_dev));169+170+ viodev->dev.platform_data = of_node_get(of_node);171+172+ viodev->irq = NO_IRQ;173+ irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);174+ if (irq_p) {175+ int virq = virt_irq_create_mapping(*irq_p);176+ if (virq == NO_IRQ) {177+ printk(KERN_ERR "Unable to allocate interrupt "178+ "number for %s\n", of_node->full_name);179+ } else180+ viodev->irq = irq_offset_up(virq);181+ }182+183+ snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);184+185+ /* register with generic device framework */186+ if (vio_register_device_common(viodev, of_node->name, of_node->type,187+ *unit_address, vio_build_iommu_table(viodev))188+ == NULL) {189+ /* XXX free TCE table */190+ kfree(viodev);191+ return NULL;192+ }193+ device_create_file(&viodev->dev, &dev_attr_devspec);194+195+ return viodev;196+}197+EXPORT_SYMBOL(vio_register_device_node);198+199+/**200+ * vio_get_attribute: - get attribute for virtual device201+ * @vdev: The vio device to get property.202+ * @which: The property/attribute to be extracted.203+ * @length: Pointer to length of returned data size (unused if NULL).204+ *205+ * Calls prom.c's get_property() to return the value of the206+ * attribute specified by the preprocessor constant @which207+*/208+const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length)209+{210+ return get_property(vdev->dev.platform_data, (char*)which, length);211+}212+EXPORT_SYMBOL(vio_get_attribute);213+214+/* vio_find_name() - internal because only vio.c knows how we formatted the215+ * kobject name216+ * XXX once vio_bus_type.devices is actually used as a kset in217+ * drivers/base/bus.c, this function should be removed in favor of218+ * "device_find(kobj_name, &vio_bus_type)"219+ */220+static struct vio_dev *vio_find_name(const char *kobj_name)221+{222+ struct kobject *found;223+224+ found = kset_find_obj(&devices_subsys.kset, kobj_name);225+ if (!found)226+ return NULL;227+228+ return to_vio_dev(container_of(found, struct device, kobj));229+}230+231+/**232+ * vio_find_node - find an already-registered vio_dev233+ * @vnode: device_node of the virtual device we're looking for234+ */235+struct vio_dev *vio_find_node(struct device_node *vnode)236+{237+ uint32_t *unit_address;238+ char kobj_name[BUS_ID_SIZE];239+240+ /* construct the kobject name from the device node */241+ unit_address = (uint32_t *)get_property(vnode, "reg", NULL);242+ if (!unit_address)243+ return NULL;244+ snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);245+246+ return vio_find_name(kobj_name);247+}248+EXPORT_SYMBOL(vio_find_node);249+250+int vio_enable_interrupts(struct vio_dev *dev)251+{252+ int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);253+ if (rc != H_Success)254+ printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);255+ return rc;256+}257+EXPORT_SYMBOL(vio_enable_interrupts);258+259+int vio_disable_interrupts(struct vio_dev *dev)260+{261+ int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);262+ if (rc != H_Success)263+ printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);264+ return rc;265+}266+EXPORT_SYMBOL(vio_disable_interrupts);
···50#include <asm/machdep.h>51#include <asm/iSeries/HvCallHpt.h>52#include <asm/cputable.h>053#include <asm/sections.h>54#include <asm/tlbflush.h>55#include <asm/time.h>···203 new_thread = &new->thread;204 old_thread = ¤t->thread;205206-/* Collect purr utilization data per process and per processor wise */207-/* purr is nothing but processor time base */208-209-#if defined(CONFIG_PPC_PSERIES)210- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {211 struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);212 long unsigned start_tb, current_tb;213 start_tb = old_thread->start_tb;···214 old_thread->accum_tb += (current_tb - start_tb);215 new_thread->start_tb = current_tb;216 }217-#endif218-219220 local_irq_save(flags);221 last = _switch(old_thread, new_thread);
···50#include <asm/machdep.h>51#include <asm/iSeries/HvCallHpt.h>52#include <asm/cputable.h>53+#include <asm/firmware.h>54#include <asm/sections.h>55#include <asm/tlbflush.h>56#include <asm/time.h>···202 new_thread = &new->thread;203 old_thread = ¤t->thread;204205+ /* Collect purr utilization data per process and per processor206+ * wise purr is nothing but processor time base207+ */208+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {0209 struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);210 long unsigned start_tb, current_tb;211 start_tb = old_thread->start_tb;···214 old_thread->accum_tb += (current_tb - start_tb);215 new_thread->start_tb = current_tb;216 }00217218 local_irq_save(flags);219 last = _switch(old_thread, new_thread);
+152-32
arch/ppc64/kernel/prom.c
···625626static inline char *find_flat_dt_string(u32 offset)627{628- return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings629- + offset;630}631632/**···635 * unflatten the tree636 */637static int __init scan_flat_dt(int (*it)(unsigned long node,638- const char *full_path, void *data),0639 void *data)640{641 unsigned long p = ((unsigned long)initial_boot_params) +642 initial_boot_params->off_dt_struct;643 int rc = 0;0644645 do {646 u32 tag = *((u32 *)p);647 char *pathp;648649 p += 4;650- if (tag == OF_DT_END_NODE)0000651 continue;652 if (tag == OF_DT_END)653 break;654 if (tag == OF_DT_PROP) {655 u32 sz = *((u32 *)p);656 p += 8;657- p = _ALIGN(p, sz >= 8 ? 8 : 4);0658 p += sz;659 p = _ALIGN(p, 4);660 continue;···671 " device tree !\n", tag);672 return -EINVAL;673 }0674 pathp = (char *)p;675 p = _ALIGN(p + strlen(pathp) + 1, 4);676- rc = it(p, pathp, data);00000000677 if (rc != 0)678 break; 679 } while(1);···705 const char *nstr;706707 p += 4;00708 if (tag != OF_DT_PROP)709 return NULL;710711 sz = *((u32 *)p);712 noff = *((u32 *)(p + 4));713 p += 8;714- p = _ALIGN(p, sz >= 8 ? 8 : 4);0715716 nstr = find_flat_dt_string(noff);717 if (nstr == NULL) {718- printk(KERN_WARNING "Can't find property index name !\n");0719 return NULL;720 }721 if (strcmp(name, nstr) == 0) {···733}734735static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,736- unsigned long align)737{738 void *res;739···747static unsigned long __init unflatten_dt_node(unsigned long mem,748 unsigned long *p,749 struct device_node *dad,750- struct device_node ***allnextpp)0751{752 struct device_node *np;753 struct property *pp, **prev_pp = NULL;754 char *pathp;755 u32 tag;756- unsigned int l;00757758 tag = *((u32 *)(*p));759 if (tag != OF_DT_BEGIN_NODE) {···765 }766 *p += 4;767 pathp = (char *)*p;768- l = strlen(pathp) + 1;769 *p = _ALIGN(*p + l, 4);770771- np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l,0000000000000000000000000772 __alignof__(struct device_node));773 if (allnextpp) {774 memset(np, 0, sizeof(*np));775 np->full_name = ((char*)np) + sizeof(struct device_node);776- memcpy(np->full_name, pathp, l);0000000000000000777 prev_pp = &np->properties;778 **allnextpp = np;779 *allnextpp = &np->allnext;780 if (dad != NULL) {781 np->parent = dad;782- /* we temporarily use the `next' field as `last_child'. */783 if (dad->next == 0)784 dad->child = np;785 else···834 char *pname;835836 tag = *((u32 *)(*p));0000837 if (tag != OF_DT_PROP)838 break;839 *p += 4;840 sz = *((u32 *)(*p));841 noff = *((u32 *)((*p) + 4));842- *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4);00843844 pname = find_flat_dt_string(noff);845 if (pname == NULL) {846 printk("Can't find property name in list !\n");847 break;848 }00849 l = strlen(pname) + 1;850 pp = unflatten_dt_alloc(&mem, sizeof(struct property),851 __alignof__(struct property));···873 }874 *p = _ALIGN((*p) + sz, 4);875 }000000000000000000000000000000876 if (allnextpp) {877 *prev_pp = NULL;878 np->name = get_property(np, "name", NULL);···914 np->type = "<NULL>";915 }916 while (tag == OF_DT_BEGIN_NODE) {917- mem = unflatten_dt_node(mem, p, np, allnextpp);918 tag = *((u32 *)(*p));919 }920 if (tag != OF_DT_END_NODE) {921- printk("Weird tag at start of node: %x\n", tag);922 return mem;923 }924 *p += 4;···944 /* First pass, scan for size */945 start = ((unsigned long)initial_boot_params) +946 initial_boot_params->off_dt_struct;947- size = unflatten_dt_node(0, &start, NULL, NULL);0948949 DBG(" size is %lx, allocating...\n", size);950951 /* Allocate memory for the expanded device tree */952- mem = (unsigned long)abs_to_virt(lmb_alloc(size,953- __alignof__(struct device_node)));0000000954 DBG(" unflattening...\n", mem);955956 /* Second pass, do actual unflattening */957 start = ((unsigned long)initial_boot_params) +958 initial_boot_params->off_dt_struct;959- unflatten_dt_node(mem, &start, NULL, &allnextp);960 if (*((u32 *)start) != OF_DT_END)961- printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start));000962 *allnextp = NULL;963964 /* Get pointer to OF "/chosen" node for use everywhere */···993994995static int __init early_init_dt_scan_cpus(unsigned long node,996- const char *full_path, void *data)997{998 char *type = get_flat_dt_prop(node, "device_type", NULL);999 u32 *prop;···1060}10611062static int __init early_init_dt_scan_chosen(unsigned long node,1063- const char *full_path, void *data)1064{1065 u32 *prop;1066 u64 *prop64;1067 extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end;10681069- if (strcmp(full_path, "/chosen") != 0)001070 return 0;10711072 /* get platform type */···1118}11191120static int __init early_init_dt_scan_root(unsigned long node,1121- const char *full_path, void *data)1122{1123 u32 *prop;11241125- if (strcmp(full_path, "/") != 0)1126 return 0;11271128 prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL);1129 dt_root_size_cells = (prop == NULL) ? 1 : *prop;1130-01131 prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL);1132 dt_root_addr_cells = (prop == NULL) ? 2 : *prop;011331134 /* break now */1135 return 1;···115911601161static int __init early_init_dt_scan_memory(unsigned long node,1162- const char *full_path, void *data)1163{1164 char *type = get_flat_dt_prop(node, "device_type", NULL);1165 cell_t *reg, *endp;···11751176 endp = reg + (l / sizeof(cell_t));11771178- DBG("memory scan node %s ...\n", full_path);001179 while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {1180 unsigned long base, size;1181···1588 struct device_node *np = allnodes;15891590 read_lock(&devtree_lock);1591- for (; np != 0; np = np->allnext)1592 if (np->full_name != 0 && strcasecmp(np->full_name, path) == 01593 && of_node_get(np))1594 break;01595 read_unlock(&devtree_lock);1596 return np;1597}
···625626static inline char *find_flat_dt_string(u32 offset)627{628+ return ((char *)initial_boot_params) +629+ initial_boot_params->off_dt_strings + offset;630}631632/**···635 * unflatten the tree636 */637static int __init scan_flat_dt(int (*it)(unsigned long node,638+ const char *uname, int depth,639+ void *data),640 void *data)641{642 unsigned long p = ((unsigned long)initial_boot_params) +643 initial_boot_params->off_dt_struct;644 int rc = 0;645+ int depth = -1;646647 do {648 u32 tag = *((u32 *)p);649 char *pathp;650651 p += 4;652+ if (tag == OF_DT_END_NODE) {653+ depth --;654+ continue;655+ }656+ if (tag == OF_DT_NOP)657 continue;658 if (tag == OF_DT_END)659 break;660 if (tag == OF_DT_PROP) {661 u32 sz = *((u32 *)p);662 p += 8;663+ if (initial_boot_params->version < 0x10)664+ p = _ALIGN(p, sz >= 8 ? 8 : 4);665 p += sz;666 p = _ALIGN(p, 4);667 continue;···664 " device tree !\n", tag);665 return -EINVAL;666 }667+ depth++;668 pathp = (char *)p;669 p = _ALIGN(p + strlen(pathp) + 1, 4);670+ if ((*pathp) == '/') {671+ char *lp, *np;672+ for (lp = NULL, np = pathp; *np; np++)673+ if ((*np) == '/')674+ lp = np+1;675+ if (lp != NULL)676+ pathp = lp;677+ }678+ rc = it(p, pathp, depth, data);679 if (rc != 0)680 break; 681 } while(1);···689 const char *nstr;690691 p += 4;692+ if (tag == OF_DT_NOP)693+ continue;694 if (tag != OF_DT_PROP)695 return NULL;696697 sz = *((u32 *)p);698 noff = *((u32 *)(p + 4));699 p += 8;700+ if (initial_boot_params->version < 0x10)701+ p = _ALIGN(p, sz >= 8 ? 8 : 4);702703 nstr = find_flat_dt_string(noff);704 if (nstr == NULL) {705+ printk(KERN_WARNING "Can't find property index"706+ " name !\n");707 return NULL;708 }709 if (strcmp(name, nstr) == 0) {···713}714715static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,716+ unsigned long align)717{718 void *res;719···727static unsigned long __init unflatten_dt_node(unsigned long mem,728 unsigned long *p,729 struct device_node *dad,730+ struct device_node ***allnextpp,731+ unsigned long fpsize)732{733 struct device_node *np;734 struct property *pp, **prev_pp = NULL;735 char *pathp;736 u32 tag;737+ unsigned int l, allocl;738+ int has_name = 0;739+ int new_format = 0;740741 tag = *((u32 *)(*p));742 if (tag != OF_DT_BEGIN_NODE) {···742 }743 *p += 4;744 pathp = (char *)*p;745+ l = allocl = strlen(pathp) + 1;746 *p = _ALIGN(*p + l, 4);747748+ /* version 0x10 has a more compact unit name here instead of the full749+ * path. we accumulate the full path size using "fpsize", we'll rebuild750+ * it later. We detect this because the first character of the name is751+ * not '/'.752+ */753+ if ((*pathp) != '/') {754+ new_format = 1;755+ if (fpsize == 0) {756+ /* root node: special case. fpsize accounts for path757+ * plus terminating zero. root node only has '/', so758+ * fpsize should be 2, but we want to avoid the first759+ * level nodes to have two '/' so we use fpsize 1 here760+ */761+ fpsize = 1;762+ allocl = 2;763+ } else {764+ /* account for '/' and path size minus terminal 0765+ * already in 'l'766+ */767+ fpsize += l;768+ allocl = fpsize;769+ }770+ }771+772+773+ np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,774 __alignof__(struct device_node));775 if (allnextpp) {776 memset(np, 0, sizeof(*np));777 np->full_name = ((char*)np) + sizeof(struct device_node);778+ if (new_format) {779+ char *p = np->full_name;780+ /* rebuild full path for new format */781+ if (dad && dad->parent) {782+ strcpy(p, dad->full_name);783+#ifdef DEBUG784+ if ((strlen(p) + l + 1) != allocl) {785+ DBG("%s: p: %d, l: %d, a: %d\n",786+ pathp, strlen(p), l, allocl);787+ }788+#endif789+ p += strlen(p);790+ }791+ *(p++) = '/';792+ memcpy(p, pathp, l);793+ } else794+ memcpy(np->full_name, pathp, l);795 prev_pp = &np->properties;796 **allnextpp = np;797 *allnextpp = &np->allnext;798 if (dad != NULL) {799 np->parent = dad;800+ /* we temporarily use the next field as `last_child'*/801 if (dad->next == 0)802 dad->child = np;803 else···770 char *pname;771772 tag = *((u32 *)(*p));773+ if (tag == OF_DT_NOP) {774+ *p += 4;775+ continue;776+ }777 if (tag != OF_DT_PROP)778 break;779 *p += 4;780 sz = *((u32 *)(*p));781 noff = *((u32 *)((*p) + 4));782+ *p += 8;783+ if (initial_boot_params->version < 0x10)784+ *p = _ALIGN(*p, sz >= 8 ? 8 : 4);785786 pname = find_flat_dt_string(noff);787 if (pname == NULL) {788 printk("Can't find property name in list !\n");789 break;790 }791+ if (strcmp(pname, "name") == 0)792+ has_name = 1;793 l = strlen(pname) + 1;794 pp = unflatten_dt_alloc(&mem, sizeof(struct property),795 __alignof__(struct property));···801 }802 *p = _ALIGN((*p) + sz, 4);803 }804+ /* with version 0x10 we may not have the name property, recreate805+ * it here from the unit name if absent806+ */807+ if (!has_name) {808+ char *p = pathp, *ps = pathp, *pa = NULL;809+ int sz;810+811+ while (*p) {812+ if ((*p) == '@')813+ pa = p;814+ if ((*p) == '/')815+ ps = p + 1;816+ p++;817+ }818+ if (pa < ps)819+ pa = p;820+ sz = (pa - ps) + 1;821+ pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,822+ __alignof__(struct property));823+ if (allnextpp) {824+ pp->name = "name";825+ pp->length = sz;826+ pp->value = (unsigned char *)(pp + 1);827+ *prev_pp = pp;828+ prev_pp = &pp->next;829+ memcpy(pp->value, ps, sz - 1);830+ ((char *)pp->value)[sz - 1] = 0;831+ DBG("fixed up name for %s -> %s\n", pathp, pp->value);832+ }833+ }834 if (allnextpp) {835 *prev_pp = NULL;836 np->name = get_property(np, "name", NULL);···812 np->type = "<NULL>";813 }814 while (tag == OF_DT_BEGIN_NODE) {815+ mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);816 tag = *((u32 *)(*p));817 }818 if (tag != OF_DT_END_NODE) {819+ printk("Weird tag at end of node: %x\n", tag);820 return mem;821 }822 *p += 4;···842 /* First pass, scan for size */843 start = ((unsigned long)initial_boot_params) +844 initial_boot_params->off_dt_struct;845+ size = unflatten_dt_node(0, &start, NULL, NULL, 0);846+ size = (size | 3) + 1;847848 DBG(" size is %lx, allocating...\n", size);849850 /* Allocate memory for the expanded device tree */851+ mem = lmb_alloc(size + 4, __alignof__(struct device_node));852+ if (!mem) {853+ DBG("Couldn't allocate memory with lmb_alloc()!\n");854+ panic("Couldn't allocate memory with lmb_alloc()!\n");855+ }856+ mem = (unsigned long)abs_to_virt(mem);857+858+ ((u32 *)mem)[size / 4] = 0xdeadbeef;859+860 DBG(" unflattening...\n", mem);861862 /* Second pass, do actual unflattening */863 start = ((unsigned long)initial_boot_params) +864 initial_boot_params->off_dt_struct;865+ unflatten_dt_node(mem, &start, NULL, &allnextp, 0);866 if (*((u32 *)start) != OF_DT_END)867+ printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start));868+ if (((u32 *)mem)[size / 4] != 0xdeadbeef)869+ printk(KERN_WARNING "End of tree marker overwritten: %08x\n",870+ ((u32 *)mem)[size / 4] );871 *allnextp = NULL;872873 /* Get pointer to OF "/chosen" node for use everywhere */···880881882static int __init early_init_dt_scan_cpus(unsigned long node,883+ const char *uname, int depth, void *data)884{885 char *type = get_flat_dt_prop(node, "device_type", NULL);886 u32 *prop;···947}948949static int __init early_init_dt_scan_chosen(unsigned long node,950+ const char *uname, int depth, void *data)951{952 u32 *prop;953 u64 *prop64;954 extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end;955956+ DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);957+958+ if (depth != 1 || strcmp(uname, "chosen") != 0)959 return 0;960961 /* get platform type */···1003}10041005static int __init early_init_dt_scan_root(unsigned long node,1006+ const char *uname, int depth, void *data)1007{1008 u32 *prop;10091010+ if (depth != 0)1011 return 0;10121013 prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL);1014 dt_root_size_cells = (prop == NULL) ? 1 : *prop;1015+ DBG("dt_root_size_cells = %x\n", dt_root_size_cells);1016+1017 prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL);1018 dt_root_addr_cells = (prop == NULL) ? 2 : *prop;1019+ DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);10201021 /* break now */1022 return 1;···104210431044static int __init early_init_dt_scan_memory(unsigned long node,1045+ const char *uname, int depth, void *data)1046{1047 char *type = get_flat_dt_prop(node, "device_type", NULL);1048 cell_t *reg, *endp;···10581059 endp = reg + (l / sizeof(cell_t));10601061+ DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n",1062+ uname, l, reg[0], reg[1], reg[2], reg[3]);1063+1064 while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {1065 unsigned long base, size;1066···1469 struct device_node *np = allnodes;14701471 read_lock(&devtree_lock);1472+ for (; np != 0; np = np->allnext) {1473 if (np->full_name != 0 && strcasecmp(np->full_name, path) == 01474 && of_node_get(np))1475 break;1476+ }1477 read_unlock(&devtree_lock);1478 return np;1479}
+55-33
arch/ppc64/kernel/prom_init.c
···1534 */1535#define MAX_PROPERTY_NAME 6415361537-static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,01538 unsigned long *mem_end)1539{1540 unsigned long offset = reloc_offset();···1548 /* get and store all property names */1549 prev_name = RELOC("");1550 for (;;) {1551- int rc;1552-1553 /* 64 is max len of name including nul. */1554 namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);1555- rc = call_prom("nextprop", 3, 1, node, prev_name, namep);1556- if (rc != 1) {1557 /* No more nodes: unwind alloc */1558 *mem_start = (unsigned long)namep;1559 break;1560 }000000001561 soff = dt_find_string(namep);1562 if (soff != 0) {1563 *mem_start = (unsigned long)namep;···15771578 /* do all our children */1579 child = call_prom("child", 1, 1, node);1580- while (child != (phandle)0) {1581 scan_dt_build_strings(child, mem_start, mem_end);1582 child = call_prom("peer", 1, 1, child);1583 }···1586static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,1587 unsigned long *mem_end)1588{1589- int l, align;1590 phandle child;1591- char *namep, *prev_name, *sstart, *p, *ep;1592 unsigned long soff;1593 unsigned char *valp;1594 unsigned long offset = reloc_offset();1595- char pname[MAX_PROPERTY_NAME];1596- char *path;1597-1598- path = RELOC(prom_scratch);15991600 dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);1601···1602 namep, *mem_end - *mem_start);1603 if (l >= 0) {1604 /* Didn't fit? Get more room. */1605- if (l+1 > *mem_end - *mem_start) {1606 namep = make_room(mem_start, mem_end, l+1, 1);1607 call_prom("package-to-path", 3, 1, node, namep, l);1608 }1609 namep[l] = '\0';01610 /* Fixup an Apple bug where they have bogus \0 chars in the1611 * middle of the path in some properties1612 */1613 for (p = namep, ep = namep + l; p < ep; p++)1614 if (*p == '\0') {1615 memmove(p, p+1, ep - p);1616- ep--; l--;1617 }1618- *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4);000000001619 }16201621 /* get it again for debugging */01622 memset(path, 0, PROM_SCRATCH_SIZE);1623 call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);1624···1636 prev_name = RELOC("");1637 sstart = (char *)RELOC(dt_string_start);1638 for (;;) {1639- int rc;1640-1641- rc = call_prom("nextprop", 3, 1, node, prev_name, pname);1642- if (rc != 1)1643 break;16440000001645 /* find string offset */1646- soff = dt_find_string(pname);1647 if (soff == 0) {1648- prom_printf("WARNING: Can't find string index for <%s>, node %s\n",1649- pname, path);1650 break;1651 }1652 prev_name = sstart + soff;16531654 /* get length */1655- l = call_prom("getproplen", 2, 1, node, pname);16561657 /* sanity checks */1658 if (l == PROM_ERROR)···1665 prom_printf("WARNING: ignoring large property ");1666 /* It seems OF doesn't null-terminate the path :-( */1667 prom_printf("[%s] ", path);1668- prom_printf("%s length 0x%x\n", pname, l);1669 continue;1670 }1671···1675 dt_push_token(soff, mem_start, mem_end);16761677 /* push property content */1678- align = (l >= 8) ? 8 : 4;1679- valp = make_room(mem_start, mem_end, l, align);1680- call_prom("getprop", 4, 1, node, pname, valp, l);1681 *mem_start = _ALIGN(*mem_start, 4);1682 }16831684 /* Add a "linux,phandle" property. */1685 soff = dt_find_string(RELOC("linux,phandle"));1686 if (soff == 0)1687- prom_printf("WARNING: Can't find string index for <linux-phandle>"1688- " node %s\n", path);1689 else {1690 dt_push_token(OF_DT_PROP, mem_start, mem_end);1691 dt_push_token(4, mem_start, mem_end);···16951696 /* do all our children */1697 child = call_prom("child", 1, 1, node);1698- while (child != (phandle)0) {1699 scan_dt_build_struct(child, mem_start, mem_end);1700 child = call_prom("peer", 1, 1, child);1701 }···17341735 /* Build header and make room for mem rsv map */ 1736 mem_start = _ALIGN(mem_start, 4);1737- hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4);01738 RELOC(dt_header_start) = (unsigned long)hdr;1739 rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);1740···1748 namep = make_room(&mem_start, &mem_end, 16, 1);1749 strcpy(namep, RELOC("linux,phandle"));1750 mem_start = (unsigned long)namep + strlen(namep) + 1;1751- RELOC(dt_string_end) = mem_start;17521753 /* Build string array */1754 prom_printf("Building dt strings...\n"); 1755 scan_dt_build_strings(root, &mem_start, &mem_end);017561757 /* Build structure */1758 mem_start = PAGE_ALIGN(mem_start);···1767 hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start);1768 hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start);1769 hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start);01770 hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start);1771 hdr->version = OF_DT_VERSION;1772- hdr->last_comp_version = 1;017731774 /* Reserve the whole thing and copy the reserve map in, we1775 * also bump mem_reserve_cnt to cause further reservations to···1827 /* does it need fixup ? */1828 if (prom_getproplen(i2c, "interrupts") > 0)1829 return;0001830 /* interrupt on this revision of u3 is number 0 and level */1831 interrupts[0] = 0;1832 interrupts[1] = 1;
···1534 */1535#define MAX_PROPERTY_NAME 6415361537+static void __init scan_dt_build_strings(phandle node,1538+ unsigned long *mem_start,1539 unsigned long *mem_end)1540{1541 unsigned long offset = reloc_offset();···1547 /* get and store all property names */1548 prev_name = RELOC("");1549 for (;;) {001550 /* 64 is max len of name including nul. */1551 namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);1552+ if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) {01553 /* No more nodes: unwind alloc */1554 *mem_start = (unsigned long)namep;1555 break;1556 }1557+1558+ /* skip "name" */1559+ if (strcmp(namep, RELOC("name")) == 0) {1560+ *mem_start = (unsigned long)namep;1561+ prev_name = RELOC("name");1562+ continue;1563+ }1564+ /* get/create string entry */1565 soff = dt_find_string(namep);1566 if (soff != 0) {1567 *mem_start = (unsigned long)namep;···15711572 /* do all our children */1573 child = call_prom("child", 1, 1, node);1574+ while (child != 0) {1575 scan_dt_build_strings(child, mem_start, mem_end);1576 child = call_prom("peer", 1, 1, child);1577 }···1580static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,1581 unsigned long *mem_end)1582{01583 phandle child;1584+ char *namep, *prev_name, *sstart, *p, *ep, *lp, *path;1585 unsigned long soff;1586 unsigned char *valp;1587 unsigned long offset = reloc_offset();1588+ static char pname[MAX_PROPERTY_NAME];1589+ int l;0015901591 dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);1592···1599 namep, *mem_end - *mem_start);1600 if (l >= 0) {1601 /* Didn't fit? Get more room. */1602+ if ((l+1) > (*mem_end - *mem_start)) {1603 namep = make_room(mem_start, mem_end, l+1, 1);1604 call_prom("package-to-path", 3, 1, node, namep, l);1605 }1606 namep[l] = '\0';1607+1608 /* Fixup an Apple bug where they have bogus \0 chars in the1609 * middle of the path in some properties1610 */1611 for (p = namep, ep = namep + l; p < ep; p++)1612 if (*p == '\0') {1613 memmove(p, p+1, ep - p);1614+ ep--; l--; p--;1615 }1616+1617+ /* now try to extract the unit name in that mess */1618+ for (p = namep, lp = NULL; *p; p++)1619+ if (*p == '/')1620+ lp = p + 1;1621+ if (lp != NULL)1622+ memmove(namep, lp, strlen(lp) + 1);1623+ *mem_start = _ALIGN(((unsigned long) namep) +1624+ strlen(namep) + 1, 4);1625 }16261627 /* get it again for debugging */1628+ path = RELOC(prom_scratch);1629 memset(path, 0, PROM_SCRATCH_SIZE);1630 call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);1631···1623 prev_name = RELOC("");1624 sstart = (char *)RELOC(dt_string_start);1625 for (;;) {1626+ if (call_prom("nextprop", 3, 1, node, prev_name,1627+ RELOC(pname)) != 1)001628 break;16291630+ /* skip "name" */1631+ if (strcmp(RELOC(pname), RELOC("name")) == 0) {1632+ prev_name = RELOC("name");1633+ continue;1634+ }1635+1636 /* find string offset */1637+ soff = dt_find_string(RELOC(pname));1638 if (soff == 0) {1639+ prom_printf("WARNING: Can't find string index for"1640+ " <%s>, node %s\n", RELOC(pname), path);1641 break;1642 }1643 prev_name = sstart + soff;16441645 /* get length */1646+ l = call_prom("getproplen", 2, 1, node, RELOC(pname));16471648 /* sanity checks */1649 if (l == PROM_ERROR)···1648 prom_printf("WARNING: ignoring large property ");1649 /* It seems OF doesn't null-terminate the path :-( */1650 prom_printf("[%s] ", path);1651+ prom_printf("%s length 0x%x\n", RELOC(pname), l);1652 continue;1653 }1654···1658 dt_push_token(soff, mem_start, mem_end);16591660 /* push property content */1661+ valp = make_room(mem_start, mem_end, l, 4);1662+ call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);01663 *mem_start = _ALIGN(*mem_start, 4);1664 }16651666 /* Add a "linux,phandle" property. */1667 soff = dt_find_string(RELOC("linux,phandle"));1668 if (soff == 0)1669+ prom_printf("WARNING: Can't find string index for"1670+ " <linux-phandle> node %s\n", path);1671 else {1672 dt_push_token(OF_DT_PROP, mem_start, mem_end);1673 dt_push_token(4, mem_start, mem_end);···16791680 /* do all our children */1681 child = call_prom("child", 1, 1, node);1682+ while (child != 0) {1683 scan_dt_build_struct(child, mem_start, mem_end);1684 child = call_prom("peer", 1, 1, child);1685 }···17181719 /* Build header and make room for mem rsv map */ 1720 mem_start = _ALIGN(mem_start, 4);1721+ hdr = make_room(&mem_start, &mem_end,1722+ sizeof(struct boot_param_header), 4);1723 RELOC(dt_header_start) = (unsigned long)hdr;1724 rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);1725···1731 namep = make_room(&mem_start, &mem_end, 16, 1);1732 strcpy(namep, RELOC("linux,phandle"));1733 mem_start = (unsigned long)namep + strlen(namep) + 1;017341735 /* Build string array */1736 prom_printf("Building dt strings...\n"); 1737 scan_dt_build_strings(root, &mem_start, &mem_end);1738+ RELOC(dt_string_end) = mem_start;17391740 /* Build structure */1741 mem_start = PAGE_ALIGN(mem_start);···1750 hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start);1751 hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start);1752 hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start);1753+ hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start);1754 hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start);1755 hdr->version = OF_DT_VERSION;1756+ /* Version 16 is not backward compatible */1757+ hdr->last_comp_version = 0x10;17581759 /* Reserve the whole thing and copy the reserve map in, we1760 * also bump mem_reserve_cnt to cause further reservations to···1808 /* does it need fixup ? */1809 if (prom_getproplen(i2c, "interrupts") > 0)1810 return;1811+1812+ prom_printf("fixing up bogus interrupts for u3 i2c...\n");1813+1814 /* interrupt on this revision of u3 is number 0 and level */1815 interrupts[0] = 0;1816 interrupts[1] = 1;
+17-2
arch/ppc64/kernel/rtas_pci.c
···58 return 0;59}6000000000000000061static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)62{63 int returnval = -1;···118119 /* Search only direct children of the bus */120 for (dn = busdn->child; dn; dn = dn->sibling)121- if (dn->devfn == devfn)122 return rtas_read_config(dn, where, size, val);123 return PCIBIOS_DEVICE_NOT_FOUND;124}···161162 /* Search only direct children of the bus */163 for (dn = busdn->child; dn; dn = dn->sibling)164- if (dn->devfn == devfn)165 return rtas_write_config(dn, where, size, val);166 return PCIBIOS_DEVICE_NOT_FOUND;167}
···58 return 0;59}6061+static int of_device_available(struct device_node * dn)62+{63+ char * status;64+65+ status = get_property(dn, "status", NULL);66+67+ if (!status)68+ return 1;69+70+ if (!strcmp(status, "okay"))71+ return 1;72+73+ return 0;74+}75+76static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)77{78 int returnval = -1;···103104 /* Search only direct children of the bus */105 for (dn = busdn->child; dn; dn = dn->sibling)106+ if (dn->devfn == devfn && of_device_available(dn))107 return rtas_read_config(dn, where, size, val);108 return PCIBIOS_DEVICE_NOT_FOUND;109}···146147 /* Search only direct children of the bus */148 for (dn = busdn->child; dn; dn = dn->sibling)149+ if (dn->devfn == devfn && of_device_available(dn))150 return rtas_write_config(dn, where, size, val);151 return PCIBIOS_DEVICE_NOT_FOUND;152}
+17-11
arch/ppc64/kernel/setup.c
···536537 DBG(" -> check_for_initrd()\n");538539- prop = (u64 *)get_property(of_chosen, "linux,initrd-start", NULL);540- if (prop != NULL) {541- initrd_start = (unsigned long)__va(*prop);542- prop = (u64 *)get_property(of_chosen, "linux,initrd-end", NULL);543 if (prop != NULL) {544- initrd_end = (unsigned long)__va(*prop);545- initrd_below_start_ok = 1;546- } else547- initrd_start = 0;00000548 }549550 /* If we were passed an initrd, set the ROOT_DEV properly if the values···631 * Initialize xmon632 */633#ifdef CONFIG_XMON_DEFAULT634- xmon_init();635#endif636 /*637 * Register early console···1347 /* ensure xmon is enabled */1348 if (p) {1349 if (strncmp(p, "on", 2) == 0)1350- xmon_init();001351 if (strncmp(p, "early", 5) != 0)1352 return 0;1353 }1354- xmon_init();1355 debugger(NULL);13561357 return 0;
···536537 DBG(" -> check_for_initrd()\n");538539+ if (of_chosen) {540+ prop = (u64 *)get_property(of_chosen,541+ "linux,initrd-start", NULL);0542 if (prop != NULL) {543+ initrd_start = (unsigned long)__va(*prop);544+ prop = (u64 *)get_property(of_chosen,545+ "linux,initrd-end", NULL);546+ if (prop != NULL) {547+ initrd_end = (unsigned long)__va(*prop);548+ initrd_below_start_ok = 1;549+ } else550+ initrd_start = 0;551+ }552 }553554 /* If we were passed an initrd, set the ROOT_DEV properly if the values···627 * Initialize xmon628 */629#ifdef CONFIG_XMON_DEFAULT630+ xmon_init(1);631#endif632 /*633 * Register early console···1343 /* ensure xmon is enabled */1344 if (p) {1345 if (strncmp(p, "on", 2) == 0)1346+ xmon_init(1);1347+ if (strncmp(p, "off", 3) == 0)1348+ xmon_init(0);1349 if (strncmp(p, "early", 5) != 0)1350 return 0;1351 }1352+ xmon_init(1);1353 debugger(NULL);13541355 return 0;
+5-52
arch/ppc64/kernel/sysfs.c
···13#include <asm/current.h>14#include <asm/processor.h>15#include <asm/cputable.h>016#include <asm/hvcall.h>17#include <asm/prom.h>18#include <asm/systemcfg.h>···101}102__setup("smt-snooze-delay=", setup_smt_snooze_delay);10300104/*105 * Enabling PMCs will slow partition context switch times so we only do106 * it the first time we write to the PMCs.···112113void ppc64_enable_pmcs(void)114{115- unsigned long hid0;116-#ifdef CONFIG_PPC_PSERIES117- unsigned long set, reset;118-#endif /* CONFIG_PPC_PSERIES */119-120 /* Only need to enable them once */121 if (__get_cpu_var(pmcs_enabled))122 return;123124 __get_cpu_var(pmcs_enabled) = 1;125126- switch (systemcfg->platform) {127- case PLATFORM_PSERIES:128- case PLATFORM_POWERMAC:129- hid0 = mfspr(HID0);130- hid0 |= 1UL << (63 - 20);131-132- /* POWER4 requires the following sequence */133- asm volatile(134- "sync\n"135- "mtspr %1, %0\n"136- "mfspr %0, %1\n"137- "mfspr %0, %1\n"138- "mfspr %0, %1\n"139- "mfspr %0, %1\n"140- "mfspr %0, %1\n"141- "mfspr %0, %1\n"142- "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0):143- "memory");144- break;145-146-#ifdef CONFIG_PPC_PSERIES147- case PLATFORM_PSERIES_LPAR:148- set = 1UL << 63;149- reset = 0;150- plpar_hcall_norets(H_PERFMON, set, reset);151- break;152-#endif /* CONFIG_PPC_PSERIES */153-154- default:155- break;156- }157-158-#ifdef CONFIG_PPC_PSERIES159- /* instruct hypervisor to maintain PMCs */160- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)161- get_paca()->lppaca.pmcregs_in_use = 1;162-#endif /* CONFIG_PPC_PSERIES */163}164-165-#else166-167-/* PMC stuff */168-void ppc64_enable_pmcs(void)169-{170- /* XXX Implement for iseries */171-}172-#endif /* CONFIG_PPC_MULTIPLATFORM */173-174EXPORT_SYMBOL(ppc64_enable_pmcs);175176/* XXX convert to rusty's on_one_cpu */
···13#include <asm/current.h>14#include <asm/processor.h>15#include <asm/cputable.h>16+#include <asm/firmware.h>17#include <asm/hvcall.h>18#include <asm/prom.h>19#include <asm/systemcfg.h>···100}101__setup("smt-snooze-delay=", setup_smt_snooze_delay);102103+#endif /* CONFIG_PPC_MULTIPLATFORM */104+105/*106 * Enabling PMCs will slow partition context switch times so we only do107 * it the first time we write to the PMCs.···109110void ppc64_enable_pmcs(void)111{00000112 /* Only need to enable them once */113 if (__get_cpu_var(pmcs_enabled))114 return;115116 __get_cpu_var(pmcs_enabled) = 1;117118+ if (ppc_md.enable_pmcs)119+ ppc_md.enable_pmcs();00000000000000000000000000000000000120}0000000000121EXPORT_SYMBOL(ppc64_enable_pmcs);122123/* XXX convert to rusty's on_one_cpu */
···1/*2 * IBM PowerPC Virtual I/O Infrastructure Support.3 *4- * Copyright (c) 2003 IBM Corp.5 * Dave Engebretsen engebret@us.ibm.com6 * Santiago Leon santil@us.ibm.com7 * Hollis Blanchard <hollisb@us.ibm.com>08 *9 * This program is free software; you can redistribute it and/or10 * modify it under the terms of the GNU General Public License···1516#include <linux/init.h>17#include <linux/console.h>18-#include <linux/version.h>19#include <linux/module.h>20-#include <linux/kobject.h>21#include <linux/mm.h>22#include <linux/dma-mapping.h>23-#include <asm/rtas.h>24#include <asm/iommu.h>25#include <asm/dma.h>26-#include <asm/ppcdebug.h>27#include <asm/vio.h>28-#include <asm/hvcall.h>29-#include <asm/iSeries/vio.h>30-#include <asm/iSeries/HvTypes.h>31-#include <asm/iSeries/HvCallXm.h>32-#include <asm/iSeries/HvLpConfig.h>33-34-#define DBGENTER() pr_debug("%s entered\n", __FUNCTION__)35-36-extern struct subsystem devices_subsys; /* needed for vio_find_name() */3738static const struct vio_device_id *vio_match_device(39 const struct vio_device_id *, const struct vio_dev *);4041-#ifdef CONFIG_PPC_PSERIES42-static struct iommu_table *vio_build_iommu_table(struct vio_dev *);43-static int vio_num_address_cells;44-#endif45-#ifdef CONFIG_PPC_ISERIES46-static struct iommu_table veth_iommu_table;47-static struct iommu_table vio_iommu_table;48-#endif49-static struct vio_dev vio_bus_device = { /* fake "parent" device */50 .name = vio_bus_device.dev.bus_id,51 .type = "",52-#ifdef CONFIG_PPC_ISERIES53- .iommu_table = &vio_iommu_table,54-#endif55 .dev.bus_id = "vio",56 .dev.bus = &vio_bus_type,57};5859-#ifdef CONFIG_PPC_ISERIES60-static struct vio_dev *__init vio_register_device_iseries(char *type,61- uint32_t unit_num);62-63-struct device *iSeries_vio_dev = &vio_bus_device.dev;64-EXPORT_SYMBOL(iSeries_vio_dev);65-66-#define device_is_compatible(a, b) 167-68-#endif6970/* convert from struct device to struct vio_dev and pass to driver.71 * dev->driver has already been set by generic code because vio_bus_match···46 struct vio_driver *viodrv = to_vio_driver(dev->driver);47 const struct vio_device_id *id;48 int error = -ENODEV;49-50- DBGENTER();5152 if (!viodrv->probe)53 return error;···63{64 struct vio_dev *viodev = to_vio_dev(dev);65 struct vio_driver *viodrv = to_vio_driver(dev->driver);66-67- DBGENTER();6869 if (viodrv->remove) {70 return viodrv->remove(viodev);···113static const struct vio_device_id * vio_match_device(const struct vio_device_id *ids,114 const struct vio_dev *dev)115{116- DBGENTER();117-118 while (ids->type) {119- if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) &&120- device_is_compatible(dev->dev.platform_data, ids->compat))121 return ids;122 ids++;123 }124 return NULL;125}126127-#ifdef CONFIG_PPC_ISERIES128-void __init iommu_vio_init(void)129-{130- struct iommu_table *t;131- struct iommu_table_cb cb;132- unsigned long cbp;133- unsigned long itc_entries;134-135- cb.itc_busno = 255; /* Bus 255 is the virtual bus */136- cb.itc_virtbus = 0xff; /* Ask for virtual bus */137-138- cbp = virt_to_abs(&cb);139- HvCallXm_getTceTableParms(cbp);140-141- itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry);142- veth_iommu_table.it_size = itc_entries / 2;143- veth_iommu_table.it_busno = cb.itc_busno;144- veth_iommu_table.it_offset = cb.itc_offset;145- veth_iommu_table.it_index = cb.itc_index;146- veth_iommu_table.it_type = TCE_VB;147- veth_iommu_table.it_blocksize = 1;148-149- t = iommu_init_table(&veth_iommu_table);150-151- if (!t)152- printk("Virtual Bus VETH TCE table failed.\n");153-154- vio_iommu_table.it_size = itc_entries - veth_iommu_table.it_size;155- vio_iommu_table.it_busno = cb.itc_busno;156- vio_iommu_table.it_offset = cb.itc_offset +157- veth_iommu_table.it_size;158- vio_iommu_table.it_index = cb.itc_index;159- vio_iommu_table.it_type = TCE_VB;160- vio_iommu_table.it_blocksize = 1;161-162- t = iommu_init_table(&vio_iommu_table);163-164- if (!t)165- printk("Virtual Bus VIO TCE table failed.\n");166-}167-#endif168-169-#ifdef CONFIG_PPC_PSERIES170-static void probe_bus_pseries(void)171-{172- struct device_node *node_vroot, *of_node;173-174- node_vroot = find_devices("vdevice");175- if ((node_vroot == NULL) || (node_vroot->child == NULL))176- /* this machine doesn't do virtual IO, and that's ok */177- return;178-179- vio_num_address_cells = prom_n_addr_cells(node_vroot->child);180-181- /*182- * Create struct vio_devices for each virtual device in the device tree.183- * Drivers will associate with them later.184- */185- for (of_node = node_vroot->child; of_node != NULL;186- of_node = of_node->sibling) {187- printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node);188- vio_register_device_node(of_node);189- }190-}191-#endif192-193-#ifdef CONFIG_PPC_ISERIES194-static void probe_bus_iseries(void)195-{196- HvLpIndexMap vlan_map = HvLpConfig_getVirtualLanIndexMap();197- struct vio_dev *viodev;198- int i;199-200- /* there is only one of each of these */201- vio_register_device_iseries("viocons", 0);202- vio_register_device_iseries("vscsi", 0);203-204- vlan_map = HvLpConfig_getVirtualLanIndexMap();205- for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {206- if ((vlan_map & (0x8000 >> i)) == 0)207- continue;208- viodev = vio_register_device_iseries("vlan", i);209- /* veth is special and has it own iommu_table */210- viodev->iommu_table = &veth_iommu_table;211- }212- for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)213- vio_register_device_iseries("viodasd", i);214- for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)215- vio_register_device_iseries("viocd", i);216- for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)217- vio_register_device_iseries("viotape", i);218-}219-#endif220-221/**222 * vio_bus_init: - Initialize the virtual IO bus223 */224-static int __init vio_bus_init(void)000225{226 int err;0000227228 err = bus_register(&vio_bus_type);229 if (err) {···141 return err;142 }143144- /* the fake parent of all vio devices, just to give us a nice directory */00145 err = device_register(&vio_bus_device.dev);146 if (err) {147- printk(KERN_WARNING "%s: device_register returned %i\n", __FUNCTION__,148- err);149 return err;150 }151-152-#ifdef CONFIG_PPC_PSERIES153- probe_bus_pseries();154-#endif155-#ifdef CONFIG_PPC_ISERIES156- probe_bus_iseries();157-#endif158159 return 0;160}161162-__initcall(vio_bus_init);163-164/* vio_dev refcount hit 0 */165static void __devinit vio_dev_release(struct device *dev)166{167- DBGENTER();168-169-#ifdef CONFIG_PPC_PSERIES170- /* XXX free TCE table */171- of_node_put(dev->platform_data);172-#endif173 kfree(to_vio_dev(dev));174}175-176-#ifdef CONFIG_PPC_PSERIES177-static ssize_t viodev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)178-{179- struct device_node *of_node = dev->platform_data;180-181- return sprintf(buf, "%s\n", of_node->full_name);182-}183-DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL);184-#endif185186static ssize_t viodev_show_name(struct device *dev, struct device_attribute *attr, char *buf)187{···168}169DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL);170171-static struct vio_dev * __devinit vio_register_device_common(172 struct vio_dev *viodev, char *name, char *type,173 uint32_t unit_address, struct iommu_table *iommu_table)174{175- DBGENTER();176-177 viodev->name = name;178 viodev->type = type;179 viodev->unit_address = unit_address;···192 return viodev;193}194195-#ifdef CONFIG_PPC_PSERIES196-/**197- * vio_register_device_node: - Register a new vio device.198- * @of_node: The OF node for this device.199- *200- * Creates and initializes a vio_dev structure from the data in201- * of_node (dev.platform_data) and adds it to the list of virtual devices.202- * Returns a pointer to the created vio_dev or NULL if node has203- * NULL device_type or compatible fields.204- */205-struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)206-{207- struct vio_dev *viodev;208- unsigned int *unit_address;209- unsigned int *irq_p;210-211- DBGENTER();212-213- /* we need the 'device_type' property, in order to match with drivers */214- if ((NULL == of_node->type)) {215- printk(KERN_WARNING216- "%s: node %s missing 'device_type'\n", __FUNCTION__,217- of_node->name ? of_node->name : "<unknown>");218- return NULL;219- }220-221- unit_address = (unsigned int *)get_property(of_node, "reg", NULL);222- if (!unit_address) {223- printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__,224- of_node->name ? of_node->name : "<unknown>");225- return NULL;226- }227-228- /* allocate a vio_dev for this node */229- viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);230- if (!viodev) {231- return NULL;232- }233- memset(viodev, 0, sizeof(struct vio_dev));234-235- viodev->dev.platform_data = of_node_get(of_node);236-237- viodev->irq = NO_IRQ;238- irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);239- if (irq_p) {240- int virq = virt_irq_create_mapping(*irq_p);241- if (virq == NO_IRQ) {242- printk(KERN_ERR "Unable to allocate interrupt "243- "number for %s\n", of_node->full_name);244- } else245- viodev->irq = irq_offset_up(virq);246- }247-248- snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);249-250- /* register with generic device framework */251- if (vio_register_device_common(viodev, of_node->name, of_node->type,252- *unit_address, vio_build_iommu_table(viodev))253- == NULL) {254- /* XXX free TCE table */255- kfree(viodev);256- return NULL;257- }258- device_create_file(&viodev->dev, &dev_attr_devspec);259-260- return viodev;261-}262-EXPORT_SYMBOL(vio_register_device_node);263-#endif264-265-#ifdef CONFIG_PPC_ISERIES266-/**267- * vio_register_device: - Register a new vio device.268- * @voidev: The device to register.269- */270-static struct vio_dev *__init vio_register_device_iseries(char *type,271- uint32_t unit_num)272-{273- struct vio_dev *viodev;274-275- DBGENTER();276-277- /* allocate a vio_dev for this node */278- viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);279- if (!viodev)280- return NULL;281- memset(viodev, 0, sizeof(struct vio_dev));282-283- snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num);284-285- return vio_register_device_common(viodev, viodev->dev.bus_id, type,286- unit_num, &vio_iommu_table);287-}288-#endif289-290void __devinit vio_unregister_device(struct vio_dev *viodev)291{292- DBGENTER();293-#ifdef CONFIG_PPC_PSERIES294- device_remove_file(&viodev->dev, &dev_attr_devspec);295-#endif296 device_remove_file(&viodev->dev, &dev_attr_name);297 device_unregister(&viodev->dev);298}299EXPORT_SYMBOL(vio_unregister_device);300-301-#ifdef CONFIG_PPC_PSERIES302-/**303- * vio_get_attribute: - get attribute for virtual device304- * @vdev: The vio device to get property.305- * @which: The property/attribute to be extracted.306- * @length: Pointer to length of returned data size (unused if NULL).307- *308- * Calls prom.c's get_property() to return the value of the309- * attribute specified by the preprocessor constant @which310-*/311-const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length)312-{313- return get_property(vdev->dev.platform_data, (char*)which, length);314-}315-EXPORT_SYMBOL(vio_get_attribute);316-317-/* vio_find_name() - internal because only vio.c knows how we formatted the318- * kobject name319- * XXX once vio_bus_type.devices is actually used as a kset in320- * drivers/base/bus.c, this function should be removed in favor of321- * "device_find(kobj_name, &vio_bus_type)"322- */323-static struct vio_dev *vio_find_name(const char *kobj_name)324-{325- struct kobject *found;326-327- found = kset_find_obj(&devices_subsys.kset, kobj_name);328- if (!found)329- return NULL;330-331- return to_vio_dev(container_of(found, struct device, kobj));332-}333-334-/**335- * vio_find_node - find an already-registered vio_dev336- * @vnode: device_node of the virtual device we're looking for337- */338-struct vio_dev *vio_find_node(struct device_node *vnode)339-{340- uint32_t *unit_address;341- char kobj_name[BUS_ID_SIZE];342-343- /* construct the kobject name from the device node */344- unit_address = (uint32_t *)get_property(vnode, "reg", NULL);345- if (!unit_address)346- return NULL;347- snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);348-349- return vio_find_name(kobj_name);350-}351-EXPORT_SYMBOL(vio_find_node);352-353-/**354- * vio_build_iommu_table: - gets the dma information from OF and builds the TCE tree.355- * @dev: the virtual device.356- *357- * Returns a pointer to the built tce tree, or NULL if it can't358- * find property.359-*/360-static struct iommu_table * vio_build_iommu_table(struct vio_dev *dev)361-{362- unsigned int *dma_window;363- struct iommu_table *newTceTable;364- unsigned long offset;365- int dma_window_property_size;366-367- dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size);368- if(!dma_window) {369- return NULL;370- }371-372- newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL);373-374- /* There should be some code to extract the phys-encoded offset375- using prom_n_addr_cells(). However, according to a comment376- on earlier versions, it's always zero, so we don't bother */377- offset = dma_window[1] >> PAGE_SHIFT;378-379- /* TCE table size - measured in tce entries */380- newTceTable->it_size = dma_window[4] >> PAGE_SHIFT;381- /* offset for VIO should always be 0 */382- newTceTable->it_offset = offset;383- newTceTable->it_busno = 0;384- newTceTable->it_index = (unsigned long)dma_window[0];385- newTceTable->it_type = TCE_VB;386-387- return iommu_init_table(newTceTable);388-}389-390-int vio_enable_interrupts(struct vio_dev *dev)391-{392- int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);393- if (rc != H_Success) {394- printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);395- }396- return rc;397-}398-EXPORT_SYMBOL(vio_enable_interrupts);399-400-int vio_disable_interrupts(struct vio_dev *dev)401-{402- int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);403- if (rc != H_Success) {404- printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);405- }406- return rc;407-}408-EXPORT_SYMBOL(vio_disable_interrupts);409-#endif410411static dma_addr_t vio_map_single(struct device *dev, void *vaddr,412 size_t size, enum dma_data_direction direction)···263 struct vio_driver *vio_drv = to_vio_driver(drv);264 const struct vio_device_id *ids = vio_drv->id_table;265 const struct vio_device_id *found_id;266-267- DBGENTER();268269 if (!ids)270 return 0;
···1/*2 * IBM PowerPC Virtual I/O Infrastructure Support.3 *4+ * Copyright (c) 2003-2005 IBM Corp.5 * Dave Engebretsen engebret@us.ibm.com6 * Santiago Leon santil@us.ibm.com7 * Hollis Blanchard <hollisb@us.ibm.com>8+ * Stephen Rothwell9 *10 * This program is free software; you can redistribute it and/or11 * modify it under the terms of the GNU General Public License···1415#include <linux/init.h>16#include <linux/console.h>017#include <linux/module.h>018#include <linux/mm.h>19#include <linux/dma-mapping.h>020#include <asm/iommu.h>21#include <asm/dma.h>022#include <asm/vio.h>0000000002324static const struct vio_device_id *vio_match_device(25 const struct vio_device_id *, const struct vio_dev *);2627+struct vio_dev vio_bus_device = { /* fake "parent" device */0000000028 .name = vio_bus_device.dev.bus_id,29 .type = "",00030 .dev.bus_id = "vio",31 .dev.bus = &vio_bus_type,32};3334+static int (*is_match)(const struct vio_device_id *id,35+ const struct vio_dev *dev);36+static void (*unregister_device_callback)(struct vio_dev *dev);37+static void (*release_device_callback)(struct device *dev);0000003839/* convert from struct device to struct vio_dev and pass to driver.40 * dev->driver has already been set by generic code because vio_bus_match···75 struct vio_driver *viodrv = to_vio_driver(dev->driver);76 const struct vio_device_id *id;77 int error = -ENODEV;007879 if (!viodrv->probe)80 return error;···94{95 struct vio_dev *viodev = to_vio_dev(dev);96 struct vio_driver *viodrv = to_vio_driver(dev->driver);009798 if (viodrv->remove) {99 return viodrv->remove(viodev);···146static const struct vio_device_id * vio_match_device(const struct vio_device_id *ids,147 const struct vio_dev *dev)148{00149 while (ids->type) {150+ if (is_match(ids, dev))0151 return ids;152 ids++;153 }154 return NULL;155}1560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000157/**158 * vio_bus_init: - Initialize the virtual IO bus159 */160+int __init vio_bus_init(int (*match_func)(const struct vio_device_id *id,161+ const struct vio_dev *dev),162+ void (*unregister_dev)(struct vio_dev *),163+ void (*release_dev)(struct device *))164{165 int err;166+167+ is_match = match_func;168+ unregister_device_callback = unregister_dev;169+ release_device_callback = release_dev;170171 err = bus_register(&vio_bus_type);172 if (err) {···264 return err;265 }266267+ /* the fake parent of all vio devices, just to give us268+ * a nice directory269+ */270 err = device_register(&vio_bus_device.dev);271 if (err) {272+ printk(KERN_WARNING "%s: device_register returned %i\n",273+ __FUNCTION__, err);274 return err;275 }0000000276277 return 0;278}27900280/* vio_dev refcount hit 0 */281static void __devinit vio_dev_release(struct device *dev)282{283+ if (release_device_callback)284+ release_device_callback(dev);0000285 kfree(to_vio_dev(dev));286}0000000000287288static ssize_t viodev_show_name(struct device *dev, struct device_attribute *attr, char *buf)289{···312}313DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL);314315+struct vio_dev * __devinit vio_register_device_common(316 struct vio_dev *viodev, char *name, char *type,317 uint32_t unit_address, struct iommu_table *iommu_table)318{00319 viodev->name = name;320 viodev->type = type;321 viodev->unit_address = unit_address;···338 return viodev;339}34000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000341void __devinit vio_unregister_device(struct vio_dev *viodev)342{343+ if (unregister_device_callback)344+ unregister_device_callback(viodev);00345 device_remove_file(&viodev->dev, &dev_attr_name);346 device_unregister(&viodev->dev);347}348EXPORT_SYMBOL(vio_unregister_device);00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000349350static dma_addr_t vio_map_single(struct device *dev, void *vaddr,351 size_t size, enum dma_data_direction direction)···616 struct vio_driver *vio_drv = to_vio_driver(drv);617 const struct vio_device_id *ids = vio_drv->id_table;618 const struct vio_device_id *found_id;00619620 if (!ids)621 return 0;
+1-2
arch/ppc64/mm/hash_native.c
···51 unsigned long prpn, unsigned long vflags,52 unsigned long rflags)53{54- unsigned long arpn = physRpn_to_absRpn(prpn);55 hpte_t *hptep = htab_address + hpte_group;56 unsigned long hpte_v, hpte_r;57 int i;···73 hpte_v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID;74 if (vflags & HPTE_V_LARGE)75 va &= ~(1UL << HPTE_V_AVPN_SHIFT);76- hpte_r = (arpn << HPTE_R_RPN_SHIFT) | rflags;7778 hptep->r = hpte_r;79 /* Guarantee the second dword is visible before the valid bit */
···51 unsigned long prpn, unsigned long vflags,52 unsigned long rflags)53{054 hpte_t *hptep = htab_address + hpte_group;55 unsigned long hpte_v, hpte_r;56 int i;···74 hpte_v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID;75 if (vflags & HPTE_V_LARGE)76 va &= ~(1UL << HPTE_V_AVPN_SHIFT);77+ hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags;7879 hptep->r = hpte_r;80 /* Guarantee the second dword is visible before the valid bit */
+2-2
arch/ppc64/mm/hash_utils.c
···210211 /* create bolted the linear mapping in the hash table */212 for (i=0; i < lmb.memory.cnt; i++) {213- base = lmb.memory.region[i].physbase + KERNELBASE;214 size = lmb.memory.region[i].size;215216 DBG("creating mapping for region: %lx : %lx\n", base, size);···302 int local = 0;303 cpumask_t tmp;304305- if ((ea & ~REGION_MASK) > EADDR_MASK)306 return 1;307308 switch (REGION_ID(ea)) {
···210211 /* create bolted the linear mapping in the hash table */212 for (i=0; i < lmb.memory.cnt; i++) {213+ base = lmb.memory.region[i].base + KERNELBASE;214 size = lmb.memory.region[i].size;215216 DBG("creating mapping for region: %lx : %lx\n", base, size);···302 int local = 0;303 cpumask_t tmp;304305+ if ((ea & ~REGION_MASK) >= PGTABLE_RANGE)306 return 1;307308 switch (REGION_ID(ea)) {
+222-186
arch/ppc64/mm/hugetlbpage.c
···2728#include <linux/sysctl.h>2930-#define HUGEPGDIR_SHIFT (HPAGE_SHIFT + PAGE_SHIFT - 3)31-#define HUGEPGDIR_SIZE (1UL << HUGEPGDIR_SHIFT)32-#define HUGEPGDIR_MASK (~(HUGEPGDIR_SIZE-1))3334-#define HUGEPTE_INDEX_SIZE 935-#define HUGEPGD_INDEX_SIZE 1036-37-#define PTRS_PER_HUGEPTE (1 << HUGEPTE_INDEX_SIZE)38-#define PTRS_PER_HUGEPGD (1 << HUGEPGD_INDEX_SIZE)39-40-static inline int hugepgd_index(unsigned long addr)41{42- return (addr & ~REGION_MASK) >> HUGEPGDIR_SHIFT;43-}004445-static pud_t *hugepgd_offset(struct mm_struct *mm, unsigned long addr)46-{47- int index;48-49- if (! mm->context.huge_pgdir)50- return NULL;51-52-53- index = hugepgd_index(addr);54- BUG_ON(index >= PTRS_PER_HUGEPGD);55- return (pud_t *)(mm->context.huge_pgdir + index);56-}57-58-static inline pte_t *hugepte_offset(pud_t *dir, unsigned long addr)59-{60- int index;61-62- if (pud_none(*dir))63- return NULL;64-65- index = (addr >> HPAGE_SHIFT) % PTRS_PER_HUGEPTE;66- return (pte_t *)pud_page(*dir) + index;67-}68-69-static pud_t *hugepgd_alloc(struct mm_struct *mm, unsigned long addr)70-{71 BUG_ON(! in_hugepage_area(mm->context, addr));7273- if (! mm->context.huge_pgdir) {74- pgd_t *new;75- spin_unlock(&mm->page_table_lock);76- /* Don't use pgd_alloc(), because we want __GFP_REPEAT */77- new = kmem_cache_alloc(zero_cache, GFP_KERNEL | __GFP_REPEAT);78- BUG_ON(memcmp(new, empty_zero_page, PAGE_SIZE));79- spin_lock(&mm->page_table_lock);8081- /*82- * Because we dropped the lock, we should re-check the83- * entry, as somebody else could have populated it..84- */85- if (mm->context.huge_pgdir)86- pgd_free(new);87- else88- mm->context.huge_pgdir = new;89- }90- return hugepgd_offset(mm, addr);91-}92-93-static pte_t *hugepte_alloc(struct mm_struct *mm, pud_t *dir, unsigned long addr)94-{95- if (! pud_present(*dir)) {96- pte_t *new;97-98- spin_unlock(&mm->page_table_lock);99- new = kmem_cache_alloc(zero_cache, GFP_KERNEL | __GFP_REPEAT);100- BUG_ON(memcmp(new, empty_zero_page, PAGE_SIZE));101- spin_lock(&mm->page_table_lock);102- /*103- * Because we dropped the lock, we should re-check the104- * entry, as somebody else could have populated it..105- */106- if (pud_present(*dir)) {107- if (new)108- kmem_cache_free(zero_cache, new);109- } else {110- struct page *ptepage;111-112- if (! new)113- return NULL;114- ptepage = virt_to_page(new);115- ptepage->mapping = (void *) mm;116- ptepage->index = addr & HUGEPGDIR_MASK;117- pud_populate(mm, dir, new);118 }119 }120121- return hugepte_offset(dir, addr);122-}123-124-pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)125-{126- pud_t *pud;127-128- BUG_ON(! in_hugepage_area(mm->context, addr));129-130- pud = hugepgd_offset(mm, addr);131- if (! pud)132- return NULL;133-134- return hugepte_offset(pud, addr);135}136137pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)138{139- pud_t *pud;000140141 BUG_ON(! in_hugepage_area(mm->context, addr));142143- pud = hugepgd_alloc(mm, addr);144- if (! pud)145- return NULL;146147- return hugepte_alloc(mm, pud, addr);0000000000000000000000000000000000000000000000148}149150/*···132 return 0;133}134135-static void flush_segments(void *parm)136{137- u16 segs = (unsigned long) parm;138 unsigned long i;139140 asm volatile("isync" : : : "memory");141142- for (i = 0; i < 16; i++) {143- if (! (segs & (1U << i)))00144 continue;145 asm volatile("slbie %0" : : "r" (i << SID_SHIFT));146 }···150 asm volatile("isync" : : : "memory");151}152153-static int prepare_low_seg_for_htlb(struct mm_struct *mm, unsigned long seg)154{155- unsigned long start = seg << SID_SHIFT;156- unsigned long end = (seg+1) << SID_SHIFT;00000000000000000000157 struct vm_area_struct *vma;158159- BUG_ON(seg >= 16);160161 /* Check no VMAs are in the region */162 vma = find_vma(mm, start);···186 return 0;187}188189-static int open_low_hpage_segs(struct mm_struct *mm, u16 newsegs)0000000000000000190{191 unsigned long i;192193- newsegs &= ~(mm->context.htlb_segs);194- if (! newsegs)000195 return 0; /* The segments we want are already open */196197- for (i = 0; i < 16; i++)198- if ((1 << i) & newsegs)199- if (prepare_low_seg_for_htlb(mm, i) != 0)200 return -EBUSY;201202- mm->context.htlb_segs |= newsegs;203204 /* update the paca copy of the context struct */205 get_paca()->context = mm->context;···226 /* the context change must make it to memory before the flush,227 * so that further SLB misses do the right thing. */228 mb();229- on_each_cpu(flush_segments, (void *)(unsigned long)newsegs, 0, 1);000000000000000000000000000000230231 return 0;232}233234int prepare_hugepage_range(unsigned long addr, unsigned long len)235{236- if (within_hugepage_high_range(addr, len))237- return 0;238- else if ((addr < 0x100000000UL) && ((addr+len) < 0x100000000UL)) {239- int err;240- /* Yes, we need both tests, in case addr+len overflows241- * 64-bit arithmetic */242- err = open_low_hpage_segs(current->mm,243 LOW_ESID_MASK(addr, len));244- if (err)245- printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)"246- " failed (segs: 0x%04hx)\n", addr, len,247- LOW_ESID_MASK(addr, len));0000248 return err;249 }250251- return -EINVAL;252}253254struct page *···354 vma = find_vma(mm, addr);355 continue;356 }357- if (touches_hugepage_high_range(addr, len)) {358- addr = TASK_HPAGE_END;359 vma = find_vma(mm, addr);360 continue;361 }···434 if (touches_hugepage_low_range(mm, addr, len)) {435 addr = (addr & ((~0) << SID_SHIFT)) - len;436 goto hugepage_recheck;437- } else if (touches_hugepage_high_range(addr, len)) {438- addr = TASK_HPAGE_BASE - len;0439 }440441 /*···527 return -ENOMEM;528}529530-static unsigned long htlb_get_high_area(unsigned long len)531{532- unsigned long addr = TASK_HPAGE_BASE;533 struct vm_area_struct *vma;534535 vma = find_vma(current->mm, addr);536- for (vma = find_vma(current->mm, addr);537- addr + len <= TASK_HPAGE_END;538- vma = vma->vm_next) {539 BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */540- BUG_ON(! within_hugepage_high_range(addr, len));00000541542 if (!vma || (addr + len) <= vma->vm_start)543 return addr;544 addr = ALIGN(vma->vm_end, HPAGE_SIZE);545- /* Because we're in a hugepage region, this alignment546- * should not skip us over any VMAs */00547 }548549 return -ENOMEM;···558 unsigned long len, unsigned long pgoff,559 unsigned long flags)560{000561 if (len & ~HPAGE_MASK)562 return -EINVAL;563···568 return -EINVAL;569570 if (test_thread_flag(TIF_32BIT)) {571- int lastshift = 0;572- u16 segmask, cursegs = current->mm->context.htlb_segs;573574 /* First see if we can do the mapping in the existing575- * low hpage segments */576- addr = htlb_get_low_area(len, cursegs);577 if (addr != -ENOMEM)578 return addr;579580- for (segmask = LOW_ESID_MASK(0x100000000UL-len, len);581- ! lastshift; segmask >>=1) {582- if (segmask & 1)0583 lastshift = 1;584585- addr = htlb_get_low_area(len, cursegs | segmask);586 if ((addr != -ENOMEM)587- && open_low_hpage_segs(current->mm, segmask) == 0)588 return addr;589 }590- printk(KERN_DEBUG "hugetlb_get_unmapped_area() unable to open"591- " enough segments\n");592- return -ENOMEM;593 } else {594- return htlb_get_high_area(len);595- }596-}597598-void hugetlb_mm_free_pgd(struct mm_struct *mm)599-{600- int i;601- pgd_t *pgdir;0602603- spin_lock(&mm->page_table_lock);0000604605- pgdir = mm->context.huge_pgdir;606- if (! pgdir)607- goto out;608-609- mm->context.huge_pgdir = NULL;610-611- /* cleanup any hugepte pages leftover */612- for (i = 0; i < PTRS_PER_HUGEPGD; i++) {613- pud_t *pud = (pud_t *)(pgdir + i);614-615- if (! pud_none(*pud)) {616- pte_t *pte = (pte_t *)pud_page(*pud);617- struct page *ptepage = virt_to_page(pte);618-619- ptepage->mapping = NULL;620-621- BUG_ON(memcmp(pte, empty_zero_page, PAGE_SIZE));622- kmem_cache_free(zero_cache, pte);623 }624- pud_clear(pud);625 }626-627- BUG_ON(memcmp(pgdir, empty_zero_page, PAGE_SIZE));628- kmem_cache_free(zero_cache, pgdir);629-630- out:631- spin_unlock(&mm->page_table_lock);632}633634int hash_huge_page(struct mm_struct *mm, unsigned long access,
···2728#include <linux/sysctl.h>2930+#define NUM_LOW_AREAS (0x100000000UL >> SID_SHIFT)31+#define NUM_HIGH_AREAS (PGTABLE_RANGE >> HTLB_AREA_SHIFT)03233+/* Modelled after find_linux_pte() */34+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)0000035{36+ pgd_t *pg;37+ pud_t *pu;38+ pmd_t *pm;39+ pte_t *pt;400000000000000000000000000041 BUG_ON(! in_hugepage_area(mm->context, addr));4243+ addr &= HPAGE_MASK;0000004445+ pg = pgd_offset(mm, addr);46+ if (!pgd_none(*pg)) {47+ pu = pud_offset(pg, addr);48+ if (!pud_none(*pu)) {49+ pm = pmd_offset(pu, addr);50+ pt = (pte_t *)pm;51+ BUG_ON(!pmd_none(*pm)52+ && !(pte_present(*pt) && pte_huge(*pt)));53+ return pt;000000000000000000000000000054 }55 }5657+ return NULL;000000000000058}5960pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)61{62+ pgd_t *pg;63+ pud_t *pu;64+ pmd_t *pm;65+ pte_t *pt;6667 BUG_ON(! in_hugepage_area(mm->context, addr));6869+ addr &= HPAGE_MASK;007071+ pg = pgd_offset(mm, addr);72+ pu = pud_alloc(mm, pg, addr);73+74+ if (pu) {75+ pm = pmd_alloc(mm, pu, addr);76+ if (pm) {77+ pt = (pte_t *)pm;78+ BUG_ON(!pmd_none(*pm)79+ && !(pte_present(*pt) && pte_huge(*pt)));80+ return pt;81+ }82+ }83+84+ return NULL;85+}86+87+#define HUGEPTE_BATCH_SIZE (HPAGE_SIZE / PMD_SIZE)88+89+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,90+ pte_t *ptep, pte_t pte)91+{92+ int i;93+94+ if (pte_present(*ptep)) {95+ pte_clear(mm, addr, ptep);96+ flush_tlb_pending();97+ }98+99+ for (i = 0; i < HUGEPTE_BATCH_SIZE; i++) {100+ *ptep = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);101+ ptep++;102+ }103+}104+105+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,106+ pte_t *ptep)107+{108+ unsigned long old = pte_update(ptep, ~0UL);109+ int i;110+111+ if (old & _PAGE_HASHPTE)112+ hpte_update(mm, addr, old, 0);113+114+ for (i = 1; i < HUGEPTE_BATCH_SIZE; i++)115+ ptep[i] = __pte(0);116+117+ return __pte(old);118}119120/*···162 return 0;163}164165+static void flush_low_segments(void *parm)166{167+ u16 areas = (unsigned long) parm;168 unsigned long i;169170 asm volatile("isync" : : : "memory");171172+ BUILD_BUG_ON((sizeof(areas)*8) != NUM_LOW_AREAS);173+174+ for (i = 0; i < NUM_LOW_AREAS; i++) {175+ if (! (areas & (1U << i)))176 continue;177 asm volatile("slbie %0" : : "r" (i << SID_SHIFT));178 }···178 asm volatile("isync" : : : "memory");179}180181+static void flush_high_segments(void *parm)182{183+ u16 areas = (unsigned long) parm;184+ unsigned long i, j;185+186+ asm volatile("isync" : : : "memory");187+188+ BUILD_BUG_ON((sizeof(areas)*8) != NUM_HIGH_AREAS);189+190+ for (i = 0; i < NUM_HIGH_AREAS; i++) {191+ if (! (areas & (1U << i)))192+ continue;193+ for (j = 0; j < (1UL << (HTLB_AREA_SHIFT-SID_SHIFT)); j++)194+ asm volatile("slbie %0"195+ :: "r" ((i << HTLB_AREA_SHIFT) + (j << SID_SHIFT)));196+ }197+198+ asm volatile("isync" : : : "memory");199+}200+201+static int prepare_low_area_for_htlb(struct mm_struct *mm, unsigned long area)202+{203+ unsigned long start = area << SID_SHIFT;204+ unsigned long end = (area+1) << SID_SHIFT;205 struct vm_area_struct *vma;206207+ BUG_ON(area >= NUM_LOW_AREAS);208209 /* Check no VMAs are in the region */210 vma = find_vma(mm, start);···194 return 0;195}196197+static int prepare_high_area_for_htlb(struct mm_struct *mm, unsigned long area)198+{199+ unsigned long start = area << HTLB_AREA_SHIFT;200+ unsigned long end = (area+1) << HTLB_AREA_SHIFT;201+ struct vm_area_struct *vma;202+203+ BUG_ON(area >= NUM_HIGH_AREAS);204+205+ /* Check no VMAs are in the region */206+ vma = find_vma(mm, start);207+ if (vma && (vma->vm_start < end))208+ return -EBUSY;209+210+ return 0;211+}212+213+static int open_low_hpage_areas(struct mm_struct *mm, u16 newareas)214{215 unsigned long i;216217+ BUILD_BUG_ON((sizeof(newareas)*8) != NUM_LOW_AREAS);218+ BUILD_BUG_ON((sizeof(mm->context.low_htlb_areas)*8) != NUM_LOW_AREAS);219+220+ newareas &= ~(mm->context.low_htlb_areas);221+ if (! newareas)222 return 0; /* The segments we want are already open */223224+ for (i = 0; i < NUM_LOW_AREAS; i++)225+ if ((1 << i) & newareas)226+ if (prepare_low_area_for_htlb(mm, i) != 0)227 return -EBUSY;228229+ mm->context.low_htlb_areas |= newareas;230231 /* update the paca copy of the context struct */232 get_paca()->context = mm->context;···215 /* the context change must make it to memory before the flush,216 * so that further SLB misses do the right thing. */217 mb();218+ on_each_cpu(flush_low_segments, (void *)(unsigned long)newareas, 0, 1);219+220+ return 0;221+}222+223+static int open_high_hpage_areas(struct mm_struct *mm, u16 newareas)224+{225+ unsigned long i;226+227+ BUILD_BUG_ON((sizeof(newareas)*8) != NUM_HIGH_AREAS);228+ BUILD_BUG_ON((sizeof(mm->context.high_htlb_areas)*8)229+ != NUM_HIGH_AREAS);230+231+ newareas &= ~(mm->context.high_htlb_areas);232+ if (! newareas)233+ return 0; /* The areas we want are already open */234+235+ for (i = 0; i < NUM_HIGH_AREAS; i++)236+ if ((1 << i) & newareas)237+ if (prepare_high_area_for_htlb(mm, i) != 0)238+ return -EBUSY;239+240+ mm->context.high_htlb_areas |= newareas;241+242+ /* update the paca copy of the context struct */243+ get_paca()->context = mm->context;244+245+ /* the context change must make it to memory before the flush,246+ * so that further SLB misses do the right thing. */247+ mb();248+ on_each_cpu(flush_high_segments, (void *)(unsigned long)newareas, 0, 1);249250 return 0;251}252253int prepare_hugepage_range(unsigned long addr, unsigned long len)254{255+ int err;256+257+ if ( (addr+len) < addr )258+ return -EINVAL;259+260+ if ((addr + len) < 0x100000000UL)261+ err = open_low_hpage_areas(current->mm,262 LOW_ESID_MASK(addr, len));263+ else264+ err = open_high_hpage_areas(current->mm,265+ HTLB_AREA_MASK(addr, len));266+ if (err) {267+ printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)"268+ " failed (lowmask: 0x%04hx, highmask: 0x%04hx)\n",269+ addr, len,270+ LOW_ESID_MASK(addr, len), HTLB_AREA_MASK(addr, len));271 return err;272 }273274+ return 0;275}276277struct page *···309 vma = find_vma(mm, addr);310 continue;311 }312+ if (touches_hugepage_high_range(mm, addr, len)) {313+ addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);314 vma = find_vma(mm, addr);315 continue;316 }···389 if (touches_hugepage_low_range(mm, addr, len)) {390 addr = (addr & ((~0) << SID_SHIFT)) - len;391 goto hugepage_recheck;392+ } else if (touches_hugepage_high_range(mm, addr, len)) {393+ addr = (addr & ((~0UL) << HTLB_AREA_SHIFT)) - len;394+ goto hugepage_recheck;395 }396397 /*···481 return -ENOMEM;482}483484+static unsigned long htlb_get_high_area(unsigned long len, u16 areamask)485{486+ unsigned long addr = 0x100000000UL;487 struct vm_area_struct *vma;488489 vma = find_vma(current->mm, addr);490+ while (addr + len <= TASK_SIZE_USER64) {00491 BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */492+493+ if (! __within_hugepage_high_range(addr, len, areamask)) {494+ addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);495+ vma = find_vma(current->mm, addr);496+ continue;497+ }498499 if (!vma || (addr + len) <= vma->vm_start)500 return addr;501 addr = ALIGN(vma->vm_end, HPAGE_SIZE);502+ /* Depending on segmask this might not be a confirmed503+ * hugepage region, so the ALIGN could have skipped504+ * some VMAs */505+ vma = find_vma(current->mm, addr);506 }507508 return -ENOMEM;···507 unsigned long len, unsigned long pgoff,508 unsigned long flags)509{510+ int lastshift;511+ u16 areamask, curareas;512+513 if (len & ~HPAGE_MASK)514 return -EINVAL;515···514 return -EINVAL;515516 if (test_thread_flag(TIF_32BIT)) {517+ curareas = current->mm->context.low_htlb_areas;0518519 /* First see if we can do the mapping in the existing520+ * low areas */521+ addr = htlb_get_low_area(len, curareas);522 if (addr != -ENOMEM)523 return addr;524525+ lastshift = 0;526+ for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);527+ ! lastshift; areamask >>=1) {528+ if (areamask & 1)529 lastshift = 1;530531+ addr = htlb_get_low_area(len, curareas | areamask);532 if ((addr != -ENOMEM)533+ && open_low_hpage_areas(current->mm, areamask) == 0)534 return addr;535 }000536 } else {537+ curareas = current->mm->context.high_htlb_areas;00538539+ /* First see if we can do the mapping in the existing540+ * high areas */541+ addr = htlb_get_high_area(len, curareas);542+ if (addr != -ENOMEM)543+ return addr;544545+ lastshift = 0;546+ for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);547+ ! lastshift; areamask >>=1) {548+ if (areamask & 1)549+ lastshift = 1;550551+ addr = htlb_get_high_area(len, curareas | areamask);552+ if ((addr != -ENOMEM)553+ && open_high_hpage_areas(current->mm, areamask) == 0)554+ return addr;00000000000000555 }0556 }557+ printk(KERN_DEBUG "hugetlb_get_unmapped_area() unable to open"558+ " enough areas\n");559+ return -ENOMEM;000560}561562int hash_huge_page(struct mm_struct *mm, unsigned long access,
···4243#include <asm/pgalloc.h>44#include <asm/page.h>45-#include <asm/abs_addr.h>46#include <asm/prom.h>47#include <asm/lmb.h>48#include <asm/rtas.h>···64#include <asm/abs_addr.h>65#include <asm/vdso.h>66#include <asm/imalloc.h>000000006768int mem_init_done;69unsigned long ioremap_bot = IMALLOC_BASE;···166 ptep = pte_alloc_kernel(&init_mm, pmdp, ea);167 if (!ptep)168 return -ENOMEM;169- pa = abs_to_phys(pa);170 set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,171 __pgprot(flags)));172 spin_unlock(&init_mm.page_table_lock);···232 * Before that, we map using addresses going233 * up from ioremap_bot. imalloc will use234 * the addresses from ioremap_bot through235- * IMALLOC_END (0xE000001fffffffff)236 * 237 */238 pa = addr & PAGE_MASK;···423 int index;424 int err;425426-#ifdef CONFIG_HUGETLB_PAGE427- /* We leave htlb_segs as it was, but for a fork, we need to428- * clear the huge_pgdir. */429- mm->context.huge_pgdir = NULL;430-#endif431-432again:433 if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL))434 return -ENOMEM;···453 spin_unlock(&mmu_context_lock);454455 mm->context.id = NO_CONTEXT;456-457- hugetlb_mm_free_pgd(mm);458}459460/*···482 for (i = 1; i < lmb.memory.cnt; i++) {483 unsigned long base, prevbase, prevsize;484485- prevbase = lmb.memory.region[i-1].physbase;486 prevsize = lmb.memory.region[i-1].size;487- base = lmb.memory.region[i].physbase;488 if (base > (prevbase + prevsize)) {489 io_hole_start = prevbase + prevsize;490 io_hole_size = base - (prevbase + prevsize);···511 for (i=0; i < lmb.memory.cnt; i++) {512 unsigned long base;513514-#ifdef CONFIG_MSCHUNKS515- base = lmb.memory.region[i].physbase;516-#else517 base = lmb.memory.region[i].base;518-#endif519 if ((paddr >= base) &&520 (paddr < (base + lmb.memory.region[i].size))) {521 return 1;···542 */543 bootmap_pages = bootmem_bootmap_pages(total_pages);544545- start = abs_to_phys(lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE));546 BUG_ON(!start);547548 boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);···553 * present.554 */555 for (i=0; i < lmb.memory.cnt; i++) {556- unsigned long physbase, size;557 unsigned long start_pfn, end_pfn;558559- physbase = lmb.memory.region[i].physbase;560 size = lmb.memory.region[i].size;561562- start_pfn = physbase >> PAGE_SHIFT;563 end_pfn = start_pfn + (size >> PAGE_SHIFT);564 memory_present(0, start_pfn, end_pfn);565566- free_bootmem(physbase, size);567 }568569 /* reserve the sections we're already using */570 for (i=0; i < lmb.reserved.cnt; i++) {571- unsigned long physbase = lmb.reserved.region[i].physbase;572 unsigned long size = lmb.reserved.region[i].size;573574- reserve_bootmem(physbase, size);575 }576}577···610 int i;611612 for (i=0; i < lmb.memory.cnt; i++) {613- unsigned long physbase, size;614 struct kcore_list *kcore_mem;615616- physbase = lmb.memory.region[i].physbase;617 size = lmb.memory.region[i].size;618619 /* GFP_ATOMIC to avoid might_sleep warnings during boot */···621 if (!kcore_mem)622 panic("mem_init: kmalloc failed\n");623624- kclist_add(kcore_mem, __va(physbase), size);625 }626627 kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START);···681682 mem_init_done = 1;683684-#ifdef CONFIG_PPC_ISERIES685- iommu_vio_init();686-#endif687 /* Initialize the vDSO */688 vdso_init();689}···825 return virt_addr;826}827828-kmem_cache_t *zero_cache;829-830-static void zero_ctor(void *pte, kmem_cache_t *cache, unsigned long flags)831{832- memset(pte, 0, PAGE_SIZE);833}000000000834835void pgtable_cache_init(void)836{837- zero_cache = kmem_cache_create("zero",838- PAGE_SIZE,839- 0,840- SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,841- zero_ctor,842- NULL);843- if (!zero_cache)844- panic("pgtable_cache_init(): could not create zero_cache!\n");0000000000000845}846847pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
···4243#include <asm/pgalloc.h>44#include <asm/page.h>045#include <asm/prom.h>46#include <asm/lmb.h>47#include <asm/rtas.h>···65#include <asm/abs_addr.h>66#include <asm/vdso.h>67#include <asm/imalloc.h>68+69+#if PGTABLE_RANGE > USER_VSID_RANGE70+#warning Limited user VSID range means pagetable space is wasted71+#endif72+73+#if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE)74+#warning TASK_SIZE is smaller than it needs to be.75+#endif7677int mem_init_done;78unsigned long ioremap_bot = IMALLOC_BASE;···159 ptep = pte_alloc_kernel(&init_mm, pmdp, ea);160 if (!ptep)161 return -ENOMEM;0162 set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,163 __pgprot(flags)));164 spin_unlock(&init_mm.page_table_lock);···226 * Before that, we map using addresses going227 * up from ioremap_bot. imalloc will use228 * the addresses from ioremap_bot through229+ * IMALLOC_END230 * 231 */232 pa = addr & PAGE_MASK;···417 int index;418 int err;419000000420again:421 if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL))422 return -ENOMEM;···453 spin_unlock(&mmu_context_lock);454455 mm->context.id = NO_CONTEXT;00456}457458/*···484 for (i = 1; i < lmb.memory.cnt; i++) {485 unsigned long base, prevbase, prevsize;486487+ prevbase = lmb.memory.region[i-1].base;488 prevsize = lmb.memory.region[i-1].size;489+ base = lmb.memory.region[i].base;490 if (base > (prevbase + prevsize)) {491 io_hole_start = prevbase + prevsize;492 io_hole_size = base - (prevbase + prevsize);···513 for (i=0; i < lmb.memory.cnt; i++) {514 unsigned long base;515000516 base = lmb.memory.region[i].base;517+518 if ((paddr >= base) &&519 (paddr < (base + lmb.memory.region[i].size))) {520 return 1;···547 */548 bootmap_pages = bootmem_bootmap_pages(total_pages);549550+ start = lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE);551 BUG_ON(!start);552553 boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);···558 * present.559 */560 for (i=0; i < lmb.memory.cnt; i++) {561+ unsigned long base, size;562 unsigned long start_pfn, end_pfn;563564+ base = lmb.memory.region[i].base;565 size = lmb.memory.region[i].size;566567+ start_pfn = base >> PAGE_SHIFT;568 end_pfn = start_pfn + (size >> PAGE_SHIFT);569 memory_present(0, start_pfn, end_pfn);570571+ free_bootmem(base, size);572 }573574 /* reserve the sections we're already using */575 for (i=0; i < lmb.reserved.cnt; i++) {576+ unsigned long base = lmb.reserved.region[i].base;577 unsigned long size = lmb.reserved.region[i].size;578579+ reserve_bootmem(base, size);580 }581}582···615 int i;616617 for (i=0; i < lmb.memory.cnt; i++) {618+ unsigned long base, size;619 struct kcore_list *kcore_mem;620621+ base = lmb.memory.region[i].base;622 size = lmb.memory.region[i].size;623624 /* GFP_ATOMIC to avoid might_sleep warnings during boot */···626 if (!kcore_mem)627 panic("mem_init: kmalloc failed\n");628629+ kclist_add(kcore_mem, __va(base), size);630 }631632 kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START);···686687 mem_init_done = 1;688000689 /* Initialize the vDSO */690 vdso_init();691}···833 return virt_addr;834}835836+static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags)00837{838+ memset(addr, 0, kmem_cache_size(cache));839}840+841+static const int pgtable_cache_size[2] = {842+ PTE_TABLE_SIZE, PMD_TABLE_SIZE843+};844+static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {845+ "pgd_pte_cache", "pud_pmd_cache",846+};847+848+kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)];849850void pgtable_cache_init(void)851{852+ int i;853+854+ BUILD_BUG_ON(PTE_TABLE_SIZE != pgtable_cache_size[PTE_CACHE_NUM]);855+ BUILD_BUG_ON(PMD_TABLE_SIZE != pgtable_cache_size[PMD_CACHE_NUM]);856+ BUILD_BUG_ON(PUD_TABLE_SIZE != pgtable_cache_size[PUD_CACHE_NUM]);857+ BUILD_BUG_ON(PGD_TABLE_SIZE != pgtable_cache_size[PGD_CACHE_NUM]);858+859+ for (i = 0; i < ARRAY_SIZE(pgtable_cache_size); i++) {860+ int size = pgtable_cache_size[i];861+ const char *name = pgtable_cache_name[i];862+863+ pgtable_cache[i] = kmem_cache_create(name,864+ size, size,865+ SLAB_HWCACHE_ALIGN866+ | SLAB_MUST_HWCACHE_ALIGN,867+ zero_ctor,868+ NULL);869+ if (! pgtable_cache[i])870+ panic("pgtable_cache_init(): could not create %s!\n",871+ name);872+ }873}874875pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
+1-1
arch/ppc64/mm/numa.c
···671 * Mark reserved regions on this node672 */673 for (i = 0; i < lmb.reserved.cnt; i++) {674- unsigned long physbase = lmb.reserved.region[i].physbase;675 unsigned long size = lmb.reserved.region[i].size;676677 if (pa_to_nid(physbase) != nid &&
···671 * Mark reserved regions on this node672 */673 for (i = 0; i < lmb.reserved.cnt; i++) {674+ unsigned long physbase = lmb.reserved.region[i].base;675 unsigned long size = lmb.reserved.region[i].size;676677 if (pa_to_nid(physbase) != nid &&
+14-13
arch/ppc64/mm/slb_low.S
···89 b 9f90910: /* user address: proto-VSID = context<<15 | ESID */92- li r11,SLB_VSID_USER93-94- srdi. r9,r3,1395 bne- 8f /* invalid ea bits set */9697#ifdef CONFIG_HUGETLB_PAGE98BEGIN_FTR_SECTION99- /* check against the hugepage ranges */100- cmpldi r3,(TASK_HPAGE_END>>SID_SHIFT)101- bge 6f /* >= TASK_HPAGE_END */102- cmpldi r3,(TASK_HPAGE_BASE>>SID_SHIFT)103- bge 5f /* TASK_HPAGE_BASE..TASK_HPAGE_END */104- cmpldi r3,16105- bge 6f /* 4GB..TASK_HPAGE_BASE */106107- lhz r9,PACAHTLBSEGS(r13)00000108 srd r9,r9,r3109 andi. r9,r9,10110 beq 6f111112-5: /* this is a hugepage user address */113- li r11,(SLB_VSID_USER|SLB_VSID_L)114END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE)115#endif /* CONFIG_HUGETLB_PAGE */116
···89 b 9f90910: /* user address: proto-VSID = context<<15 | ESID */92+ srdi. r9,r3,USER_ESID_BITS0093 bne- 8f /* invalid ea bits set */9495#ifdef CONFIG_HUGETLB_PAGE96BEGIN_FTR_SECTION97+ lhz r9,PACAHIGHHTLBAREAS(r13)98+ srdi r11,r3,(HTLB_AREA_SHIFT-SID_SHIFT)99+ srd r9,r9,r11100+ andi. r9,r9,1101+ bne 5f00102103+ li r11,SLB_VSID_USER104+105+ cmpldi r3,16106+ bge 6f107+108+ lhz r9,PACALOWHTLBAREAS(r13)109 srd r9,r9,r3110 andi. r9,r9,1111+112 beq 6f113114+5: li r11,SLB_VSID_USER|SLB_VSID_L0115END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE)116#endif /* CONFIG_HUGETLB_PAGE */117
+55-40
arch/ppc64/mm/tlb.c
···41DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);42unsigned long pte_freelist_forced_free;4344-void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage)00000000000000000000000000000000000000000000000000045{46 /* This is safe as we are holding page_table_lock */47 cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id());···100101 if (atomic_read(&tlb->mm->mm_users) < 2 ||102 cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) {103- pte_free(ptepage);104 return;105 }106107 if (*batchp == NULL) {108 *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);109 if (*batchp == NULL) {110- pte_free_now(ptepage);111 return;112 }113 (*batchp)->index = 0;114 }115- (*batchp)->pages[(*batchp)->index++] = ptepage;116 if ((*batchp)->index == PTE_FREELIST_SIZE) {117 pte_free_submit(*batchp);118 *batchp = NULL;···181 flush_hash_range(batch->context, i, local);182 batch->index = 0;183 put_cpu();184-}185-186-#ifdef CONFIG_SMP187-static void pte_free_smp_sync(void *arg)188-{189- /* Do nothing, just ensure we sync with all CPUs */190-}191-#endif192-193-/* This is only called when we are critically out of memory194- * (and fail to get a page in pte_free_tlb).195- */196-void pte_free_now(struct page *ptepage)197-{198- pte_freelist_forced_free++;199-200- smp_call_function(pte_free_smp_sync, NULL, 0, 1);201-202- pte_free(ptepage);203-}204-205-static void pte_free_rcu_callback(struct rcu_head *head)206-{207- struct pte_freelist_batch *batch =208- container_of(head, struct pte_freelist_batch, rcu);209- unsigned int i;210-211- for (i = 0; i < batch->index; i++)212- pte_free(batch->pages[i]);213- free_page((unsigned long)batch);214-}215-216-void pte_free_submit(struct pte_freelist_batch *batch)217-{218- INIT_RCU_HEAD(&batch->rcu);219- call_rcu(&batch->rcu, pte_free_rcu_callback);220}221222void pte_free_finish(void)
···41DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);42unsigned long pte_freelist_forced_free;4344+struct pte_freelist_batch45+{46+ struct rcu_head rcu;47+ unsigned int index;48+ pgtable_free_t tables[0];49+};50+51+DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);52+unsigned long pte_freelist_forced_free;53+54+#define PTE_FREELIST_SIZE \55+ ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \56+ / sizeof(pgtable_free_t))57+58+#ifdef CONFIG_SMP59+static void pte_free_smp_sync(void *arg)60+{61+ /* Do nothing, just ensure we sync with all CPUs */62+}63+#endif64+65+/* This is only called when we are critically out of memory66+ * (and fail to get a page in pte_free_tlb).67+ */68+static void pgtable_free_now(pgtable_free_t pgf)69+{70+ pte_freelist_forced_free++;71+72+ smp_call_function(pte_free_smp_sync, NULL, 0, 1);73+74+ pgtable_free(pgf);75+}76+77+static void pte_free_rcu_callback(struct rcu_head *head)78+{79+ struct pte_freelist_batch *batch =80+ container_of(head, struct pte_freelist_batch, rcu);81+ unsigned int i;82+83+ for (i = 0; i < batch->index; i++)84+ pgtable_free(batch->tables[i]);85+86+ free_page((unsigned long)batch);87+}88+89+static void pte_free_submit(struct pte_freelist_batch *batch)90+{91+ INIT_RCU_HEAD(&batch->rcu);92+ call_rcu(&batch->rcu, pte_free_rcu_callback);93+}94+95+void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf)96{97 /* This is safe as we are holding page_table_lock */98 cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id());···4950 if (atomic_read(&tlb->mm->mm_users) < 2 ||51 cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) {52+ pgtable_free(pgf);53 return;54 }5556 if (*batchp == NULL) {57 *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);58 if (*batchp == NULL) {59+ pgtable_free_now(pgf);60 return;61 }62 (*batchp)->index = 0;63 }64+ (*batchp)->tables[(*batchp)->index++] = pgf;65 if ((*batchp)->index == PTE_FREELIST_SIZE) {66 pte_free_submit(*batchp);67 *batchp = NULL;···130 flush_hash_range(batch->context, i, local);131 batch->index = 0;132 put_cpu();000000000000000000000000000000000000133}134135void pte_free_finish(void)
···104105#ifdef CONFIG_PPC_ISERIES106107-/* Initializes tables for bio buses */108-extern void __init iommu_vio_init(void);109-110struct iSeries_Device_Node;111/* Creates table for an individual device node */112extern void iommu_devnode_init_iSeries(struct iSeries_Device_Node *dn);
···104105#ifdef CONFIG_PPC_ISERIES106000107struct iSeries_Device_Node;108/* Creates table for an individual device node */109extern void iommu_devnode_init_iSeries(struct iSeries_Device_Node *dn);
-1
include/asm-ppc64/lmb.h
···2223struct lmb_property {24 unsigned long base;25- unsigned long physbase;26 unsigned long size;27};28
···2223struct lmb_property {24 unsigned long base;025 unsigned long size;26};27
+3
include/asm-ppc64/machdep.h
···140141 /* Idle loop for this platform, leave empty for default idle loop */142 int (*idle_loop)(void);000143};144145extern int default_idle(void);
···140141 /* Idle loop for this platform, leave empty for default idle loop */142 int (*idle_loop)(void);143+144+ /* Function to enable pmcs for this platform, called once per cpu. */145+ void (*enable_pmcs)(void);146};147148extern int default_idle(void);
···1213#include <asm/types.h>1415-#ifndef __ASSEMBLY__16-17struct naca_struct {18 /* Kernel only data - undefined for user space */19 void *xItVpdAreas; /* VPD Data 0x00 */···20};2122extern struct naca_struct naca;23-24-#endif /* __ASSEMBLY__ */25-26-#define NACA_PAGE 0x427-#define NACA_PHYS_ADDR (NACA_PAGE<<PAGE_SHIFT)2829#endif /* _NACA_H */
···1213#include <asm/types.h>140015struct naca_struct {16 /* Kernel only data - undefined for user space */17 void *xItVpdAreas; /* VPD Data 0x00 */···22};2324extern struct naca_struct naca;000002526#endif /* _NACA_H */
···6#include <linux/cpumask.h>7#include <linux/percpu.h>89-extern kmem_cache_t *zero_cache;000001011/*12 * This program is free software; you can redistribute it and/or···20 * 2 of the License, or (at your option) any later version.21 */2223-static inline pgd_t *24-pgd_alloc(struct mm_struct *mm)25{26- return kmem_cache_alloc(zero_cache, GFP_KERNEL);27}2829-static inline void30-pgd_free(pgd_t *pgd)31{32- kmem_cache_free(zero_cache, pgd);000000000000033}3435#define pud_populate(MM, PUD, PMD) pud_set(PUD, PMD)3637-static inline pmd_t *38-pmd_alloc_one(struct mm_struct *mm, unsigned long addr)39{40- return kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT);041}4243-static inline void44-pmd_free(pmd_t *pmd)45{46- kmem_cache_free(zero_cache, pmd);47}4849#define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, pte)···6263static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)64{65- return kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT);066}6768static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)69{70- pte_t *pte = kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT);71- if (pte)72- return virt_to_page(pte);73- return NULL;74}7576static inline void pte_free_kernel(pte_t *pte)77{78- kmem_cache_free(zero_cache, pte);79}8081static inline void pte_free(struct page *ptepage)82{83- kmem_cache_free(zero_cache, page_address(ptepage));84}8586-struct pte_freelist_batch000000087{88- struct rcu_head rcu;89- unsigned int index;90- struct page * pages[0];91-};9293-#define PTE_FREELIST_SIZE ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) / \94- sizeof(struct page *))9596-extern void pte_free_now(struct page *ptepage);97-extern void pte_free_submit(struct pte_freelist_batch *batch);009899-DECLARE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);0100101-void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage);102-#define __pmd_free_tlb(tlb, pmd) __pte_free_tlb(tlb, virt_to_page(pmd))000000000103104#define check_pgt_cache() do { } while (0)105
···6#include <linux/cpumask.h>7#include <linux/percpu.h>89+extern kmem_cache_t *pgtable_cache[];10+11+#define PTE_CACHE_NUM 012+#define PMD_CACHE_NUM 113+#define PUD_CACHE_NUM 114+#define PGD_CACHE_NUM 01516/*17 * This program is free software; you can redistribute it and/or···15 * 2 of the License, or (at your option) any later version.16 */1718+static inline pgd_t *pgd_alloc(struct mm_struct *mm)019{20+ return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL);21}2223+static inline void pgd_free(pgd_t *pgd)024{25+ kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd);26+}27+28+#define pgd_populate(MM, PGD, PUD) pgd_set(PGD, PUD)29+30+static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)31+{32+ return kmem_cache_alloc(pgtable_cache[PUD_CACHE_NUM],33+ GFP_KERNEL|__GFP_REPEAT);34+}35+36+static inline void pud_free(pud_t *pud)37+{38+ kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud);39}4041#define pud_populate(MM, PUD, PMD) pud_set(PUD, PMD)4243+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)044{45+ return kmem_cache_alloc(pgtable_cache[PMD_CACHE_NUM],46+ GFP_KERNEL|__GFP_REPEAT);47}4849+static inline void pmd_free(pmd_t *pmd)050{51+ kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd);52}5354#define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, pte)···4748static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)49{50+ return kmem_cache_alloc(pgtable_cache[PTE_CACHE_NUM],51+ GFP_KERNEL|__GFP_REPEAT);52}5354static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)55{56+ return virt_to_page(pte_alloc_one_kernel(mm, address));00057}5859static inline void pte_free_kernel(pte_t *pte)60{61+ kmem_cache_free(pgtable_cache[PTE_CACHE_NUM], pte);62}6364static inline void pte_free(struct page *ptepage)65{66+ pte_free_kernel(page_address(ptepage));67}6869+#define PGF_CACHENUM_MASK 0xf70+71+typedef struct pgtable_free {72+ unsigned long val;73+} pgtable_free_t;74+75+static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,76+ unsigned long mask)77{78+ BUG_ON(cachenum > PGF_CACHENUM_MASK);0007980+ return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum};81+}8283+static inline void pgtable_free(pgtable_free_t pgf)84+{85+ void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);86+ int cachenum = pgf.val & PGF_CACHENUM_MASK;8788+ kmem_cache_free(pgtable_cache[cachenum], p);89+}9091+void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);92+93+#define __pte_free_tlb(tlb, ptepage) \94+ pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \95+ PTE_CACHE_NUM, PTE_TABLE_SIZE-1))96+#define __pmd_free_tlb(tlb, pmd) \97+ pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \98+ PMD_CACHE_NUM, PMD_TABLE_SIZE-1))99+#define __pud_free_tlb(tlb, pmd) \100+ pgtable_free_tlb(tlb, pgtable_free_cache(pud, \101+ PUD_CACHE_NUM, PUD_TABLE_SIZE-1))102103#define check_pgt_cache() do { } while (0)104
+54-38
include/asm-ppc64/pgtable.h
···15#include <asm/tlbflush.h>16#endif /* __ASSEMBLY__ */1718-#include <asm-generic/pgtable-nopud.h>19-20/*21 * Entries per page directory level. The PTE level must use a 64b record22 * for each page table entry. The PMD and PGD level use a 32b record for 23 * each entry by assuming that each entry is page aligned.24 */25#define PTE_INDEX_SIZE 926-#define PMD_INDEX_SIZE 1027-#define PGD_INDEX_SIZE 100000002829#define PTRS_PER_PTE (1 << PTE_INDEX_SIZE)30#define PTRS_PER_PMD (1 << PMD_INDEX_SIZE)031#define PTRS_PER_PGD (1 << PGD_INDEX_SIZE)3233/* PMD_SHIFT determines what a second-level page table entry can map */···40#define PMD_SIZE (1UL << PMD_SHIFT)41#define PMD_MASK (~(PMD_SIZE-1))4243-/* PGDIR_SHIFT determines what a third-level page table entry can map */44-#define PGDIR_SHIFT (PMD_SHIFT + PMD_INDEX_SIZE)0000045#define PGDIR_SIZE (1UL << PGDIR_SHIFT)46#define PGDIR_MASK (~(PGDIR_SIZE-1))47···55/*56 * Size of EA range mapped by our pagetables.57 */58-#define EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \59- PGD_INDEX_SIZE + PAGE_SHIFT)60-#define EADDR_MASK ((1UL << EADDR_SIZE) - 1)000000006162/*63 * Define the address range of the vmalloc VM area.64 */65#define VMALLOC_START (0xD000000000000000ul)66-#define VMALLOC_SIZE (0x10000000000UL)67#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)6869/*···172#ifndef __ASSEMBLY__173int hash_huge_page(struct mm_struct *mm, unsigned long access,174 unsigned long ea, unsigned long vsid, int local);175-176-void hugetlb_mm_free_pgd(struct mm_struct *mm);177#endif /* __ASSEMBLY__ */178179#define HAVE_ARCH_UNMAPPED_AREA···179#else180181#define hash_huge_page(mm,a,ea,vsid,local) -1182-#define hugetlb_mm_free_pgd(mm) do {} while (0)183184#endif185···212#define pte_pfn(x) ((unsigned long)((pte_val(x) >> PTE_SHIFT)))213#define pte_page(x) pfn_to_page(pte_pfn(x))214215-#define pmd_set(pmdp, ptep) \216- (pmd_val(*(pmdp)) = __ba_to_bpn(ptep))217#define pmd_none(pmd) (!pmd_val(pmd))218#define pmd_bad(pmd) (pmd_val(pmd) == 0)219#define pmd_present(pmd) (pmd_val(pmd) != 0)220#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0)221-#define pmd_page_kernel(pmd) (__bpn_to_ba(pmd_val(pmd)))222#define pmd_page(pmd) virt_to_page(pmd_page_kernel(pmd))223224-#define pud_set(pudp, pmdp) (pud_val(*(pudp)) = (__ba_to_bpn(pmdp)))225#define pud_none(pud) (!pud_val(pud))226-#define pud_bad(pud) ((pud_val(pud)) == 0UL)227-#define pud_present(pud) (pud_val(pud) != 0UL)228-#define pud_clear(pudp) (pud_val(*(pudp)) = 0UL)229-#define pud_page(pud) (__bpn_to_ba(pud_val(pud)))0000000230231/* 232 * Find an entry in a page-table-directory. We combine the address region 233 * (the high order N bits) and the pgd portion of the address.234 */235/* to avoid overflow in free_pgtables we don't use PTRS_PER_PGD here */236-#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & 0x7ff)237238#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))239240-/* Find an entry in the second-level page table.. */241-#define pmd_offset(pudp,addr) \242- ((pmd_t *) pud_page(*(pudp)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))243244-/* Find an entry in the third-level page table.. */00245#define pte_offset_kernel(dir,addr) \246- ((pte_t *) pmd_page_kernel(*(dir)) \247- + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))248249#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))250#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr))···479#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)480481#define pmd_ERROR(e) \482- printk("%s:%d: bad pmd %08x.\n", __FILE__, __LINE__, pmd_val(e))00483#define pgd_ERROR(e) \484- printk("%s:%d: bad pgd %08x.\n", __FILE__, __LINE__, pgd_val(e))485486extern pgd_t swapper_pg_dir[];487488extern void paging_init(void);489490-/*491- * Because the huge pgtables are only 2 level, they can take492- * at most around 4M, much less than one hugepage which the493- * process is presumably entitled to use. So we don't bother494- * freeing up the pagetables on unmap, and wait until495- * destroy_context() to clean up the lot.496- */497#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) \498- do { } while (0)499500/*501 * This gets called at the end of handling a page fault, when
···15#include <asm/tlbflush.h>16#endif /* __ASSEMBLY__ */170018/*19 * Entries per page directory level. The PTE level must use a 64b record20 * for each page table entry. The PMD and PGD level use a 32b record for 21 * each entry by assuming that each entry is page aligned.22 */23#define PTE_INDEX_SIZE 924+#define PMD_INDEX_SIZE 725+#define PUD_INDEX_SIZE 726+#define PGD_INDEX_SIZE 927+28+#define PTE_TABLE_SIZE (sizeof(pte_t) << PTE_INDEX_SIZE)29+#define PMD_TABLE_SIZE (sizeof(pmd_t) << PMD_INDEX_SIZE)30+#define PUD_TABLE_SIZE (sizeof(pud_t) << PUD_INDEX_SIZE)31+#define PGD_TABLE_SIZE (sizeof(pgd_t) << PGD_INDEX_SIZE)3233#define PTRS_PER_PTE (1 << PTE_INDEX_SIZE)34#define PTRS_PER_PMD (1 << PMD_INDEX_SIZE)35+#define PTRS_PER_PUD (1 << PMD_INDEX_SIZE)36#define PTRS_PER_PGD (1 << PGD_INDEX_SIZE)3738/* PMD_SHIFT determines what a second-level page table entry can map */···35#define PMD_SIZE (1UL << PMD_SHIFT)36#define PMD_MASK (~(PMD_SIZE-1))3738+/* PUD_SHIFT determines what a third-level page table entry can map */39+#define PUD_SHIFT (PMD_SHIFT + PMD_INDEX_SIZE)40+#define PUD_SIZE (1UL << PUD_SHIFT)41+#define PUD_MASK (~(PUD_SIZE-1))42+43+/* PGDIR_SHIFT determines what a fourth-level page table entry can map */44+#define PGDIR_SHIFT (PUD_SHIFT + PUD_INDEX_SIZE)45#define PGDIR_SIZE (1UL << PGDIR_SHIFT)46#define PGDIR_MASK (~(PGDIR_SIZE-1))47···45/*46 * Size of EA range mapped by our pagetables.47 */48+#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \49+ PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)50+#define PGTABLE_RANGE (1UL << PGTABLE_EADDR_SIZE)51+52+#if TASK_SIZE_USER64 > PGTABLE_RANGE53+#error TASK_SIZE_USER64 exceeds pagetable range54+#endif55+56+#if TASK_SIZE_USER64 > (1UL << (USER_ESID_BITS + SID_SHIFT))57+#error TASK_SIZE_USER64 exceeds user VSID range58+#endif5960/*61 * Define the address range of the vmalloc VM area.62 */63#define VMALLOC_START (0xD000000000000000ul)64+#define VMALLOC_SIZE (0x80000000000UL)65#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)6667/*···154#ifndef __ASSEMBLY__155int hash_huge_page(struct mm_struct *mm, unsigned long access,156 unsigned long ea, unsigned long vsid, int local);00157#endif /* __ASSEMBLY__ */158159#define HAVE_ARCH_UNMAPPED_AREA···163#else164165#define hash_huge_page(mm,a,ea,vsid,local) -10166167#endif168···197#define pte_pfn(x) ((unsigned long)((pte_val(x) >> PTE_SHIFT)))198#define pte_page(x) pfn_to_page(pte_pfn(x))199200+#define pmd_set(pmdp, ptep) ({BUG_ON((u64)ptep < KERNELBASE); pmd_val(*(pmdp)) = (unsigned long)(ptep);})0201#define pmd_none(pmd) (!pmd_val(pmd))202#define pmd_bad(pmd) (pmd_val(pmd) == 0)203#define pmd_present(pmd) (pmd_val(pmd) != 0)204#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0)205+#define pmd_page_kernel(pmd) (pmd_val(pmd))206#define pmd_page(pmd) virt_to_page(pmd_page_kernel(pmd))207208+#define pud_set(pudp, pmdp) (pud_val(*(pudp)) = (unsigned long)(pmdp))209#define pud_none(pud) (!pud_val(pud))210+#define pud_bad(pud) ((pud_val(pud)) == 0)211+#define pud_present(pud) (pud_val(pud) != 0)212+#define pud_clear(pudp) (pud_val(*(pudp)) = 0)213+#define pud_page(pud) (pud_val(pud))214+215+#define pgd_set(pgdp, pudp) ({pgd_val(*(pgdp)) = (unsigned long)(pudp);})216+#define pgd_none(pgd) (!pgd_val(pgd))217+#define pgd_bad(pgd) (pgd_val(pgd) == 0)218+#define pgd_present(pgd) (pgd_val(pgd) != 0)219+#define pgd_clear(pgdp) (pgd_val(*(pgdp)) = 0)220+#define pgd_page(pgd) (pgd_val(pgd))221222/* 223 * Find an entry in a page-table-directory. We combine the address region 224 * (the high order N bits) and the pgd portion of the address.225 */226/* to avoid overflow in free_pgtables we don't use PTRS_PER_PGD here */227+#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & 0x1ff)228229#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))230231+#define pud_offset(pgdp, addr) \232+ (((pud_t *) pgd_page(*(pgdp))) + (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)))0233234+#define pmd_offset(pudp,addr) \235+ (((pmd_t *) pud_page(*(pudp))) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))236+237#define pte_offset_kernel(dir,addr) \238+ (((pte_t *) pmd_page_kernel(*(dir))) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))0239240#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))241#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr))···458#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)459460#define pmd_ERROR(e) \461+ printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))462+#define pud_ERROR(e) \463+ printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pud_val(e))464#define pgd_ERROR(e) \465+ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))466467extern pgd_t swapper_pg_dir[];468469extern void paging_init(void);4700000000471#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) \472+ free_pgd_range(tlb, addr, end, floor, ceiling)473474/*475 * This gets called at the end of handling a page fault, when
···382extern struct task_struct *last_task_used_math;383extern struct task_struct *last_task_used_altivec;384385-/* 64-bit user address space is 41-bits (2TBs user VM) */386-#define TASK_SIZE_USER64 (0x0000020000000000UL)387388/* 389 * 32-bit user address space is 4GB - 1 page
···382extern struct task_struct *last_task_used_math;383extern struct task_struct *last_task_used_altivec;384385+/* 64-bit user address space is 44-bits (16TB user VM) */386+#define TASK_SIZE_USER64 (0x0000100000000000UL)387388/* 389 * 32-bit user address space is 4GB - 1 page
+9-5
include/asm-ppc64/prom.h
···22#define RELOC(x) (*PTRRELOC(&(x)))2324/* Definitions used by the flattened device tree */25-#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */26-#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */27#define OF_DT_END_NODE 0x2 /* End node */28-#define OF_DT_PROP 0x3 /* Property: name off, size, content */0029#define OF_DT_END 0x93031-#define OF_DT_VERSION 13233/*34 * This is what gets passed to the kernel by prom_init or kexec···56 u32 version; /* format version */57 u32 last_comp_version; /* last compatible version */58 /* version 2 fields below */59- u32 boot_cpuid_phys; /* Which physical CPU id we're booting on */0060};6162
···22#define RELOC(x) (*PTRRELOC(&(x)))2324/* Definitions used by the flattened device tree */25+#define OF_DT_HEADER 0xd00dfeed /* marker */26+#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */27#define OF_DT_END_NODE 0x2 /* End node */28+#define OF_DT_PROP 0x3 /* Property: name off, size,29+ * content */30+#define OF_DT_NOP 0x4 /* nop */31#define OF_DT_END 0x93233+#define OF_DT_VERSION 0x103435/*36 * This is what gets passed to the kernel by prom_init or kexec···54 u32 version; /* format version */55 u32 last_comp_version; /* last compatible version */56 /* version 2 fields below */57+ u32 boot_cpuid_phys; /* Physical CPU id we're booting on */58+ /* version 3 fields below */59+ u32 dt_strings_size; /* size of the DT strings block */60};6162