Commit c8f1c8be629ee34991fdba8bfe46a5c455393209
Committed by
Paul Mackerras
1 parent
7f853352e7
Exists in
master
and in
4 other branches
[PATCH] ppc64: Take udbg out of ppc_md
Take udbg out of ppc_md. Allows us to not overwrite early udbg inits when assigning ppc_md. Signed-off-by: Milton Miller <miltonm@bga.com> Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Showing 9 changed files with 51 additions and 58 deletions Inline Diff
arch/ppc64/kernel/pSeries_lpar.c
| 1 | /* | 1 | /* |
| 2 | * pSeries_lpar.c | 2 | * pSeries_lpar.c |
| 3 | * Copyright (C) 2001 Todd Inglett, IBM Corporation | 3 | * Copyright (C) 2001 Todd Inglett, IBM Corporation |
| 4 | * | 4 | * |
| 5 | * pSeries LPAR support. | 5 | * pSeries LPAR support. |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
| 9 | * the Free Software Foundation; either version 2 of the License, or | 9 | * the Free Software Foundation; either version 2 of the License, or |
| 10 | * (at your option) any later version. | 10 | * (at your option) any later version. |
| 11 | * | 11 | * |
| 12 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
| 16 | * | 16 | * |
| 17 | * You should have received a copy of the GNU General Public License | 17 | * You should have received a copy of the GNU General Public License |
| 18 | * along with this program; if not, write to the Free Software | 18 | * along with this program; if not, write to the Free Software |
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #define DEBUG | 22 | #define DEBUG |
| 23 | 23 | ||
| 24 | #include <linux/config.h> | 24 | #include <linux/config.h> |
| 25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
| 26 | #include <linux/dma-mapping.h> | 26 | #include <linux/dma-mapping.h> |
| 27 | #include <asm/processor.h> | 27 | #include <asm/processor.h> |
| 28 | #include <asm/mmu.h> | 28 | #include <asm/mmu.h> |
| 29 | #include <asm/page.h> | 29 | #include <asm/page.h> |
| 30 | #include <asm/pgtable.h> | 30 | #include <asm/pgtable.h> |
| 31 | #include <asm/machdep.h> | 31 | #include <asm/machdep.h> |
| 32 | #include <asm/abs_addr.h> | 32 | #include <asm/abs_addr.h> |
| 33 | #include <asm/mmu_context.h> | 33 | #include <asm/mmu_context.h> |
| 34 | #include <asm/ppcdebug.h> | 34 | #include <asm/ppcdebug.h> |
| 35 | #include <asm/iommu.h> | 35 | #include <asm/iommu.h> |
| 36 | #include <asm/tlbflush.h> | 36 | #include <asm/tlbflush.h> |
| 37 | #include <asm/tlb.h> | 37 | #include <asm/tlb.h> |
| 38 | #include <asm/prom.h> | 38 | #include <asm/prom.h> |
| 39 | #include <asm/abs_addr.h> | 39 | #include <asm/abs_addr.h> |
| 40 | #include <asm/cputable.h> | 40 | #include <asm/cputable.h> |
| 41 | #include <asm/plpar_wrappers.h> | 41 | #include <asm/plpar_wrappers.h> |
| 42 | 42 | ||
| 43 | #ifdef DEBUG | 43 | #ifdef DEBUG |
| 44 | #define DBG(fmt...) udbg_printf(fmt) | 44 | #define DBG(fmt...) udbg_printf(fmt) |
| 45 | #else | 45 | #else |
| 46 | #define DBG(fmt...) | 46 | #define DBG(fmt...) |
| 47 | #endif | 47 | #endif |
| 48 | 48 | ||
| 49 | /* in pSeries_hvCall.S */ | 49 | /* in pSeries_hvCall.S */ |
| 50 | EXPORT_SYMBOL(plpar_hcall); | 50 | EXPORT_SYMBOL(plpar_hcall); |
| 51 | EXPORT_SYMBOL(plpar_hcall_4out); | 51 | EXPORT_SYMBOL(plpar_hcall_4out); |
| 52 | EXPORT_SYMBOL(plpar_hcall_norets); | 52 | EXPORT_SYMBOL(plpar_hcall_norets); |
| 53 | EXPORT_SYMBOL(plpar_hcall_8arg_2ret); | 53 | EXPORT_SYMBOL(plpar_hcall_8arg_2ret); |
| 54 | 54 | ||
| 55 | extern void pSeries_find_serial_port(void); | 55 | extern void pSeries_find_serial_port(void); |
| 56 | 56 | ||
| 57 | 57 | ||
| 58 | int vtermno; /* virtual terminal# for udbg */ | 58 | int vtermno; /* virtual terminal# for udbg */ |
| 59 | 59 | ||
| 60 | #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) | 60 | #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) |
| 61 | static void udbg_hvsi_putc(unsigned char c) | 61 | static void udbg_hvsi_putc(unsigned char c) |
| 62 | { | 62 | { |
| 63 | /* packet's seqno isn't used anyways */ | 63 | /* packet's seqno isn't used anyways */ |
| 64 | uint8_t packet[] __ALIGNED__ = { 0xff, 5, 0, 0, c }; | 64 | uint8_t packet[] __ALIGNED__ = { 0xff, 5, 0, 0, c }; |
| 65 | int rc; | 65 | int rc; |
| 66 | 66 | ||
| 67 | if (c == '\n') | 67 | if (c == '\n') |
| 68 | udbg_hvsi_putc('\r'); | 68 | udbg_hvsi_putc('\r'); |
| 69 | 69 | ||
| 70 | do { | 70 | do { |
| 71 | rc = plpar_put_term_char(vtermno, sizeof(packet), packet); | 71 | rc = plpar_put_term_char(vtermno, sizeof(packet), packet); |
| 72 | } while (rc == H_Busy); | 72 | } while (rc == H_Busy); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | static long hvsi_udbg_buf_len; | 75 | static long hvsi_udbg_buf_len; |
| 76 | static uint8_t hvsi_udbg_buf[256]; | 76 | static uint8_t hvsi_udbg_buf[256]; |
| 77 | 77 | ||
| 78 | static int udbg_hvsi_getc_poll(void) | 78 | static int udbg_hvsi_getc_poll(void) |
| 79 | { | 79 | { |
| 80 | unsigned char ch; | 80 | unsigned char ch; |
| 81 | int rc, i; | 81 | int rc, i; |
| 82 | 82 | ||
| 83 | if (hvsi_udbg_buf_len == 0) { | 83 | if (hvsi_udbg_buf_len == 0) { |
| 84 | rc = plpar_get_term_char(vtermno, &hvsi_udbg_buf_len, hvsi_udbg_buf); | 84 | rc = plpar_get_term_char(vtermno, &hvsi_udbg_buf_len, hvsi_udbg_buf); |
| 85 | if (rc != H_Success || hvsi_udbg_buf[0] != 0xff) { | 85 | if (rc != H_Success || hvsi_udbg_buf[0] != 0xff) { |
| 86 | /* bad read or non-data packet */ | 86 | /* bad read or non-data packet */ |
| 87 | hvsi_udbg_buf_len = 0; | 87 | hvsi_udbg_buf_len = 0; |
| 88 | } else { | 88 | } else { |
| 89 | /* remove the packet header */ | 89 | /* remove the packet header */ |
| 90 | for (i = 4; i < hvsi_udbg_buf_len; i++) | 90 | for (i = 4; i < hvsi_udbg_buf_len; i++) |
| 91 | hvsi_udbg_buf[i-4] = hvsi_udbg_buf[i]; | 91 | hvsi_udbg_buf[i-4] = hvsi_udbg_buf[i]; |
| 92 | hvsi_udbg_buf_len -= 4; | 92 | hvsi_udbg_buf_len -= 4; |
| 93 | } | 93 | } |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | if (hvsi_udbg_buf_len <= 0 || hvsi_udbg_buf_len > 256) { | 96 | if (hvsi_udbg_buf_len <= 0 || hvsi_udbg_buf_len > 256) { |
| 97 | /* no data ready */ | 97 | /* no data ready */ |
| 98 | hvsi_udbg_buf_len = 0; | 98 | hvsi_udbg_buf_len = 0; |
| 99 | return -1; | 99 | return -1; |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | ch = hvsi_udbg_buf[0]; | 102 | ch = hvsi_udbg_buf[0]; |
| 103 | /* shift remaining data down */ | 103 | /* shift remaining data down */ |
| 104 | for (i = 1; i < hvsi_udbg_buf_len; i++) { | 104 | for (i = 1; i < hvsi_udbg_buf_len; i++) { |
| 105 | hvsi_udbg_buf[i-1] = hvsi_udbg_buf[i]; | 105 | hvsi_udbg_buf[i-1] = hvsi_udbg_buf[i]; |
| 106 | } | 106 | } |
| 107 | hvsi_udbg_buf_len--; | 107 | hvsi_udbg_buf_len--; |
| 108 | 108 | ||
| 109 | return ch; | 109 | return ch; |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | static unsigned char udbg_hvsi_getc(void) | 112 | static unsigned char udbg_hvsi_getc(void) |
| 113 | { | 113 | { |
| 114 | int ch; | 114 | int ch; |
| 115 | for (;;) { | 115 | for (;;) { |
| 116 | ch = udbg_hvsi_getc_poll(); | 116 | ch = udbg_hvsi_getc_poll(); |
| 117 | if (ch == -1) { | 117 | if (ch == -1) { |
| 118 | /* This shouldn't be needed...but... */ | 118 | /* This shouldn't be needed...but... */ |
| 119 | volatile unsigned long delay; | 119 | volatile unsigned long delay; |
| 120 | for (delay=0; delay < 2000000; delay++) | 120 | for (delay=0; delay < 2000000; delay++) |
| 121 | ; | 121 | ; |
| 122 | } else { | 122 | } else { |
| 123 | return ch; | 123 | return ch; |
| 124 | } | 124 | } |
| 125 | } | 125 | } |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | static void udbg_putcLP(unsigned char c) | 128 | static void udbg_putcLP(unsigned char c) |
| 129 | { | 129 | { |
| 130 | char buf[16]; | 130 | char buf[16]; |
| 131 | unsigned long rc; | 131 | unsigned long rc; |
| 132 | 132 | ||
| 133 | if (c == '\n') | 133 | if (c == '\n') |
| 134 | udbg_putcLP('\r'); | 134 | udbg_putcLP('\r'); |
| 135 | 135 | ||
| 136 | buf[0] = c; | 136 | buf[0] = c; |
| 137 | do { | 137 | do { |
| 138 | rc = plpar_put_term_char(vtermno, 1, buf); | 138 | rc = plpar_put_term_char(vtermno, 1, buf); |
| 139 | } while(rc == H_Busy); | 139 | } while(rc == H_Busy); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | /* Buffered chars getc */ | 142 | /* Buffered chars getc */ |
| 143 | static long inbuflen; | 143 | static long inbuflen; |
| 144 | static long inbuf[2]; /* must be 2 longs */ | 144 | static long inbuf[2]; /* must be 2 longs */ |
| 145 | 145 | ||
| 146 | static int udbg_getc_pollLP(void) | 146 | static int udbg_getc_pollLP(void) |
| 147 | { | 147 | { |
| 148 | /* The interface is tricky because it may return up to 16 chars. | 148 | /* The interface is tricky because it may return up to 16 chars. |
| 149 | * We save them statically for future calls to udbg_getc(). | 149 | * We save them statically for future calls to udbg_getc(). |
| 150 | */ | 150 | */ |
| 151 | char ch, *buf = (char *)inbuf; | 151 | char ch, *buf = (char *)inbuf; |
| 152 | int i; | 152 | int i; |
| 153 | long rc; | 153 | long rc; |
| 154 | if (inbuflen == 0) { | 154 | if (inbuflen == 0) { |
| 155 | /* get some more chars. */ | 155 | /* get some more chars. */ |
| 156 | inbuflen = 0; | 156 | inbuflen = 0; |
| 157 | rc = plpar_get_term_char(vtermno, &inbuflen, buf); | 157 | rc = plpar_get_term_char(vtermno, &inbuflen, buf); |
| 158 | if (rc != H_Success) | 158 | if (rc != H_Success) |
| 159 | inbuflen = 0; /* otherwise inbuflen is garbage */ | 159 | inbuflen = 0; /* otherwise inbuflen is garbage */ |
| 160 | } | 160 | } |
| 161 | if (inbuflen <= 0 || inbuflen > 16) { | 161 | if (inbuflen <= 0 || inbuflen > 16) { |
| 162 | /* Catch error case as well as other oddities (corruption) */ | 162 | /* Catch error case as well as other oddities (corruption) */ |
| 163 | inbuflen = 0; | 163 | inbuflen = 0; |
| 164 | return -1; | 164 | return -1; |
| 165 | } | 165 | } |
| 166 | ch = buf[0]; | 166 | ch = buf[0]; |
| 167 | for (i = 1; i < inbuflen; i++) /* shuffle them down. */ | 167 | for (i = 1; i < inbuflen; i++) /* shuffle them down. */ |
| 168 | buf[i-1] = buf[i]; | 168 | buf[i-1] = buf[i]; |
| 169 | inbuflen--; | 169 | inbuflen--; |
| 170 | return ch; | 170 | return ch; |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | static unsigned char udbg_getcLP(void) | 173 | static unsigned char udbg_getcLP(void) |
| 174 | { | 174 | { |
| 175 | int ch; | 175 | int ch; |
| 176 | for (;;) { | 176 | for (;;) { |
| 177 | ch = udbg_getc_pollLP(); | 177 | ch = udbg_getc_pollLP(); |
| 178 | if (ch == -1) { | 178 | if (ch == -1) { |
| 179 | /* This shouldn't be needed...but... */ | 179 | /* This shouldn't be needed...but... */ |
| 180 | volatile unsigned long delay; | 180 | volatile unsigned long delay; |
| 181 | for (delay=0; delay < 2000000; delay++) | 181 | for (delay=0; delay < 2000000; delay++) |
| 182 | ; | 182 | ; |
| 183 | } else { | 183 | } else { |
| 184 | return ch; | 184 | return ch; |
| 185 | } | 185 | } |
| 186 | } | 186 | } |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | /* call this from early_init() for a working debug console on | 189 | /* call this from early_init() for a working debug console on |
| 190 | * vterm capable LPAR machines | 190 | * vterm capable LPAR machines |
| 191 | */ | 191 | */ |
| 192 | void udbg_init_debug_lpar(void) | 192 | void udbg_init_debug_lpar(void) |
| 193 | { | 193 | { |
| 194 | vtermno = 0; | 194 | vtermno = 0; |
| 195 | ppc_md.udbg_putc = udbg_putcLP; | 195 | udbg_putc = udbg_putcLP; |
| 196 | ppc_md.udbg_getc = udbg_getcLP; | 196 | udbg_getc = udbg_getcLP; |
| 197 | ppc_md.udbg_getc_poll = udbg_getc_pollLP; | 197 | udbg_getc_poll = udbg_getc_pollLP; |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | /* returns 0 if couldn't find or use /chosen/stdout as console */ | 200 | /* returns 0 if couldn't find or use /chosen/stdout as console */ |
| 201 | int find_udbg_vterm(void) | 201 | int find_udbg_vterm(void) |
| 202 | { | 202 | { |
| 203 | struct device_node *stdout_node; | 203 | struct device_node *stdout_node; |
| 204 | u32 *termno; | 204 | u32 *termno; |
| 205 | char *name; | 205 | char *name; |
| 206 | int found = 0; | 206 | int found = 0; |
| 207 | 207 | ||
| 208 | /* find the boot console from /chosen/stdout */ | 208 | /* find the boot console from /chosen/stdout */ |
| 209 | if (!of_chosen) | 209 | if (!of_chosen) |
| 210 | return 0; | 210 | return 0; |
| 211 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); | 211 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); |
| 212 | if (name == NULL) | 212 | if (name == NULL) |
| 213 | return 0; | 213 | return 0; |
| 214 | stdout_node = of_find_node_by_path(name); | 214 | stdout_node = of_find_node_by_path(name); |
| 215 | if (!stdout_node) | 215 | if (!stdout_node) |
| 216 | return 0; | 216 | return 0; |
| 217 | 217 | ||
| 218 | /* now we have the stdout node; figure out what type of device it is. */ | 218 | /* now we have the stdout node; figure out what type of device it is. */ |
| 219 | name = (char *)get_property(stdout_node, "name", NULL); | 219 | name = (char *)get_property(stdout_node, "name", NULL); |
| 220 | if (!name) { | 220 | if (!name) { |
| 221 | printk(KERN_WARNING "stdout node missing 'name' property!\n"); | 221 | printk(KERN_WARNING "stdout node missing 'name' property!\n"); |
| 222 | goto out; | 222 | goto out; |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | if (strncmp(name, "vty", 3) == 0) { | 225 | if (strncmp(name, "vty", 3) == 0) { |
| 226 | if (device_is_compatible(stdout_node, "hvterm1")) { | 226 | if (device_is_compatible(stdout_node, "hvterm1")) { |
| 227 | termno = (u32 *)get_property(stdout_node, "reg", NULL); | 227 | termno = (u32 *)get_property(stdout_node, "reg", NULL); |
| 228 | if (termno) { | 228 | if (termno) { |
| 229 | vtermno = termno[0]; | 229 | vtermno = termno[0]; |
| 230 | ppc_md.udbg_putc = udbg_putcLP; | 230 | udbg_putc = udbg_putcLP; |
| 231 | ppc_md.udbg_getc = udbg_getcLP; | 231 | udbg_getc = udbg_getcLP; |
| 232 | ppc_md.udbg_getc_poll = udbg_getc_pollLP; | 232 | udbg_getc_poll = udbg_getc_pollLP; |
| 233 | found = 1; | 233 | found = 1; |
| 234 | } | 234 | } |
| 235 | } else if (device_is_compatible(stdout_node, "hvterm-protocol")) { | 235 | } else if (device_is_compatible(stdout_node, "hvterm-protocol")) { |
| 236 | termno = (u32 *)get_property(stdout_node, "reg", NULL); | 236 | termno = (u32 *)get_property(stdout_node, "reg", NULL); |
| 237 | if (termno) { | 237 | if (termno) { |
| 238 | vtermno = termno[0]; | 238 | vtermno = termno[0]; |
| 239 | ppc_md.udbg_putc = udbg_hvsi_putc; | 239 | udbg_putc = udbg_hvsi_putc; |
| 240 | ppc_md.udbg_getc = udbg_hvsi_getc; | 240 | udbg_getc = udbg_hvsi_getc; |
| 241 | ppc_md.udbg_getc_poll = udbg_hvsi_getc_poll; | 241 | udbg_getc_poll = udbg_hvsi_getc_poll; |
| 242 | found = 1; | 242 | found = 1; |
| 243 | } | 243 | } |
| 244 | } | 244 | } |
| 245 | } else if (strncmp(name, "serial", 6)) { | 245 | } else if (strncmp(name, "serial", 6)) { |
| 246 | /* XXX fix ISA serial console */ | 246 | /* XXX fix ISA serial console */ |
| 247 | printk(KERN_WARNING "serial stdout on LPAR ('%s')! " | 247 | printk(KERN_WARNING "serial stdout on LPAR ('%s')! " |
| 248 | "can't print udbg messages\n", | 248 | "can't print udbg messages\n", |
| 249 | stdout_node->full_name); | 249 | stdout_node->full_name); |
| 250 | } else { | 250 | } else { |
| 251 | printk(KERN_WARNING "don't know how to print to stdout '%s'\n", | 251 | printk(KERN_WARNING "don't know how to print to stdout '%s'\n", |
| 252 | stdout_node->full_name); | 252 | stdout_node->full_name); |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | out: | 255 | out: |
| 256 | of_node_put(stdout_node); | 256 | of_node_put(stdout_node); |
| 257 | return found; | 257 | return found; |
| 258 | } | 258 | } |
| 259 | 259 | ||
| 260 | void vpa_init(int cpu) | 260 | void vpa_init(int cpu) |
| 261 | { | 261 | { |
| 262 | int hwcpu = get_hard_smp_processor_id(cpu); | 262 | int hwcpu = get_hard_smp_processor_id(cpu); |
| 263 | unsigned long vpa = (unsigned long)&(paca[cpu].lppaca); | 263 | unsigned long vpa = (unsigned long)&(paca[cpu].lppaca); |
| 264 | long ret; | 264 | long ret; |
| 265 | unsigned long flags; | 265 | unsigned long flags; |
| 266 | 266 | ||
| 267 | /* Register the Virtual Processor Area (VPA) */ | 267 | /* Register the Virtual Processor Area (VPA) */ |
| 268 | flags = 1UL << (63 - 18); | 268 | flags = 1UL << (63 - 18); |
| 269 | 269 | ||
| 270 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) | 270 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) |
| 271 | paca[cpu].lppaca.vmxregs_in_use = 1; | 271 | paca[cpu].lppaca.vmxregs_in_use = 1; |
| 272 | 272 | ||
| 273 | ret = register_vpa(flags, hwcpu, __pa(vpa)); | 273 | ret = register_vpa(flags, hwcpu, __pa(vpa)); |
| 274 | 274 | ||
| 275 | if (ret) | 275 | if (ret) |
| 276 | printk(KERN_ERR "WARNING: vpa_init: VPA registration for " | 276 | printk(KERN_ERR "WARNING: vpa_init: VPA registration for " |
| 277 | "cpu %d (hw %d) of area %lx returns %ld\n", | 277 | "cpu %d (hw %d) of area %lx returns %ld\n", |
| 278 | cpu, hwcpu, __pa(vpa), ret); | 278 | cpu, hwcpu, __pa(vpa), ret); |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | long pSeries_lpar_hpte_insert(unsigned long hpte_group, | 281 | long pSeries_lpar_hpte_insert(unsigned long hpte_group, |
| 282 | unsigned long va, unsigned long prpn, | 282 | unsigned long va, unsigned long prpn, |
| 283 | unsigned long vflags, unsigned long rflags) | 283 | unsigned long vflags, unsigned long rflags) |
| 284 | { | 284 | { |
| 285 | unsigned long lpar_rc; | 285 | unsigned long lpar_rc; |
| 286 | unsigned long flags; | 286 | unsigned long flags; |
| 287 | unsigned long slot; | 287 | unsigned long slot; |
| 288 | unsigned long hpte_v, hpte_r; | 288 | unsigned long hpte_v, hpte_r; |
| 289 | unsigned long dummy0, dummy1; | 289 | unsigned long dummy0, dummy1; |
| 290 | 290 | ||
| 291 | hpte_v = ((va >> 23) << HPTE_V_AVPN_SHIFT) | vflags | HPTE_V_VALID; | 291 | hpte_v = ((va >> 23) << HPTE_V_AVPN_SHIFT) | vflags | HPTE_V_VALID; |
| 292 | if (vflags & HPTE_V_LARGE) | 292 | if (vflags & HPTE_V_LARGE) |
| 293 | hpte_v &= ~(1UL << HPTE_V_AVPN_SHIFT); | 293 | hpte_v &= ~(1UL << HPTE_V_AVPN_SHIFT); |
| 294 | 294 | ||
| 295 | hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags; | 295 | hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags; |
| 296 | 296 | ||
| 297 | /* Now fill in the actual HPTE */ | 297 | /* Now fill in the actual HPTE */ |
| 298 | /* Set CEC cookie to 0 */ | 298 | /* Set CEC cookie to 0 */ |
| 299 | /* Zero page = 0 */ | 299 | /* Zero page = 0 */ |
| 300 | /* I-cache Invalidate = 0 */ | 300 | /* I-cache Invalidate = 0 */ |
| 301 | /* I-cache synchronize = 0 */ | 301 | /* I-cache synchronize = 0 */ |
| 302 | /* Exact = 0 */ | 302 | /* Exact = 0 */ |
| 303 | flags = 0; | 303 | flags = 0; |
| 304 | 304 | ||
| 305 | /* XXX why is this here? - Anton */ | 305 | /* XXX why is this here? - Anton */ |
| 306 | if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) | 306 | if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) |
| 307 | hpte_r &= ~_PAGE_COHERENT; | 307 | hpte_r &= ~_PAGE_COHERENT; |
| 308 | 308 | ||
| 309 | lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, hpte_v, | 309 | lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, hpte_v, |
| 310 | hpte_r, &slot, &dummy0, &dummy1); | 310 | hpte_r, &slot, &dummy0, &dummy1); |
| 311 | 311 | ||
| 312 | if (unlikely(lpar_rc == H_PTEG_Full)) | 312 | if (unlikely(lpar_rc == H_PTEG_Full)) |
| 313 | return -1; | 313 | return -1; |
| 314 | 314 | ||
| 315 | /* | 315 | /* |
| 316 | * Since we try and ioremap PHBs we don't own, the pte insert | 316 | * Since we try and ioremap PHBs we don't own, the pte insert |
| 317 | * will fail. However we must catch the failure in hash_page | 317 | * will fail. However we must catch the failure in hash_page |
| 318 | * or we will loop forever, so return -2 in this case. | 318 | * or we will loop forever, so return -2 in this case. |
| 319 | */ | 319 | */ |
| 320 | if (unlikely(lpar_rc != H_Success)) | 320 | if (unlikely(lpar_rc != H_Success)) |
| 321 | return -2; | 321 | return -2; |
| 322 | 322 | ||
| 323 | /* Because of iSeries, we have to pass down the secondary | 323 | /* Because of iSeries, we have to pass down the secondary |
| 324 | * bucket bit here as well | 324 | * bucket bit here as well |
| 325 | */ | 325 | */ |
| 326 | return (slot & 7) | (!!(vflags & HPTE_V_SECONDARY) << 3); | 326 | return (slot & 7) | (!!(vflags & HPTE_V_SECONDARY) << 3); |
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | static DEFINE_SPINLOCK(pSeries_lpar_tlbie_lock); | 329 | static DEFINE_SPINLOCK(pSeries_lpar_tlbie_lock); |
| 330 | 330 | ||
| 331 | static long pSeries_lpar_hpte_remove(unsigned long hpte_group) | 331 | static long pSeries_lpar_hpte_remove(unsigned long hpte_group) |
| 332 | { | 332 | { |
| 333 | unsigned long slot_offset; | 333 | unsigned long slot_offset; |
| 334 | unsigned long lpar_rc; | 334 | unsigned long lpar_rc; |
| 335 | int i; | 335 | int i; |
| 336 | unsigned long dummy1, dummy2; | 336 | unsigned long dummy1, dummy2; |
| 337 | 337 | ||
| 338 | /* pick a random slot to start at */ | 338 | /* pick a random slot to start at */ |
| 339 | slot_offset = mftb() & 0x7; | 339 | slot_offset = mftb() & 0x7; |
| 340 | 340 | ||
| 341 | for (i = 0; i < HPTES_PER_GROUP; i++) { | 341 | for (i = 0; i < HPTES_PER_GROUP; i++) { |
| 342 | 342 | ||
| 343 | /* don't remove a bolted entry */ | 343 | /* don't remove a bolted entry */ |
| 344 | lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset, | 344 | lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset, |
| 345 | (0x1UL << 4), &dummy1, &dummy2); | 345 | (0x1UL << 4), &dummy1, &dummy2); |
| 346 | 346 | ||
| 347 | if (lpar_rc == H_Success) | 347 | if (lpar_rc == H_Success) |
| 348 | return i; | 348 | return i; |
| 349 | 349 | ||
| 350 | BUG_ON(lpar_rc != H_Not_Found); | 350 | BUG_ON(lpar_rc != H_Not_Found); |
| 351 | 351 | ||
| 352 | slot_offset++; | 352 | slot_offset++; |
| 353 | slot_offset &= 0x7; | 353 | slot_offset &= 0x7; |
| 354 | } | 354 | } |
| 355 | 355 | ||
| 356 | return -1; | 356 | return -1; |
| 357 | } | 357 | } |
| 358 | 358 | ||
| 359 | static void pSeries_lpar_hptab_clear(void) | 359 | static void pSeries_lpar_hptab_clear(void) |
| 360 | { | 360 | { |
| 361 | unsigned long size_bytes = 1UL << ppc64_pft_size; | 361 | unsigned long size_bytes = 1UL << ppc64_pft_size; |
| 362 | unsigned long hpte_count = size_bytes >> 4; | 362 | unsigned long hpte_count = size_bytes >> 4; |
| 363 | unsigned long dummy1, dummy2; | 363 | unsigned long dummy1, dummy2; |
| 364 | int i; | 364 | int i; |
| 365 | 365 | ||
| 366 | /* TODO: Use bulk call */ | 366 | /* TODO: Use bulk call */ |
| 367 | for (i = 0; i < hpte_count; i++) | 367 | for (i = 0; i < hpte_count; i++) |
| 368 | plpar_pte_remove(0, i, 0, &dummy1, &dummy2); | 368 | plpar_pte_remove(0, i, 0, &dummy1, &dummy2); |
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | /* | 371 | /* |
| 372 | * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and | 372 | * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and |
| 373 | * the low 3 bits of flags happen to line up. So no transform is needed. | 373 | * the low 3 bits of flags happen to line up. So no transform is needed. |
| 374 | * We can probably optimize here and assume the high bits of newpp are | 374 | * We can probably optimize here and assume the high bits of newpp are |
| 375 | * already zero. For now I am paranoid. | 375 | * already zero. For now I am paranoid. |
| 376 | */ | 376 | */ |
| 377 | static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, | 377 | static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, |
| 378 | unsigned long va, int large, int local) | 378 | unsigned long va, int large, int local) |
| 379 | { | 379 | { |
| 380 | unsigned long lpar_rc; | 380 | unsigned long lpar_rc; |
| 381 | unsigned long flags = (newpp & 7) | H_AVPN; | 381 | unsigned long flags = (newpp & 7) | H_AVPN; |
| 382 | unsigned long avpn = va >> 23; | 382 | unsigned long avpn = va >> 23; |
| 383 | 383 | ||
| 384 | if (large) | 384 | if (large) |
| 385 | avpn &= ~0x1UL; | 385 | avpn &= ~0x1UL; |
| 386 | 386 | ||
| 387 | lpar_rc = plpar_pte_protect(flags, slot, (avpn << 7)); | 387 | lpar_rc = plpar_pte_protect(flags, slot, (avpn << 7)); |
| 388 | 388 | ||
| 389 | if (lpar_rc == H_Not_Found) | 389 | if (lpar_rc == H_Not_Found) |
| 390 | return -1; | 390 | return -1; |
| 391 | 391 | ||
| 392 | BUG_ON(lpar_rc != H_Success); | 392 | BUG_ON(lpar_rc != H_Success); |
| 393 | 393 | ||
| 394 | return 0; | 394 | return 0; |
| 395 | } | 395 | } |
| 396 | 396 | ||
| 397 | static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot) | 397 | static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot) |
| 398 | { | 398 | { |
| 399 | unsigned long dword0; | 399 | unsigned long dword0; |
| 400 | unsigned long lpar_rc; | 400 | unsigned long lpar_rc; |
| 401 | unsigned long dummy_word1; | 401 | unsigned long dummy_word1; |
| 402 | unsigned long flags; | 402 | unsigned long flags; |
| 403 | 403 | ||
| 404 | /* Read 1 pte at a time */ | 404 | /* Read 1 pte at a time */ |
| 405 | /* Do not need RPN to logical page translation */ | 405 | /* Do not need RPN to logical page translation */ |
| 406 | /* No cross CEC PFT access */ | 406 | /* No cross CEC PFT access */ |
| 407 | flags = 0; | 407 | flags = 0; |
| 408 | 408 | ||
| 409 | lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1); | 409 | lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1); |
| 410 | 410 | ||
| 411 | BUG_ON(lpar_rc != H_Success); | 411 | BUG_ON(lpar_rc != H_Success); |
| 412 | 412 | ||
| 413 | return dword0; | 413 | return dword0; |
| 414 | } | 414 | } |
| 415 | 415 | ||
| 416 | static long pSeries_lpar_hpte_find(unsigned long vpn) | 416 | static long pSeries_lpar_hpte_find(unsigned long vpn) |
| 417 | { | 417 | { |
| 418 | unsigned long hash; | 418 | unsigned long hash; |
| 419 | unsigned long i, j; | 419 | unsigned long i, j; |
| 420 | long slot; | 420 | long slot; |
| 421 | unsigned long hpte_v; | 421 | unsigned long hpte_v; |
| 422 | 422 | ||
| 423 | hash = hpt_hash(vpn, 0); | 423 | hash = hpt_hash(vpn, 0); |
| 424 | 424 | ||
| 425 | for (j = 0; j < 2; j++) { | 425 | for (j = 0; j < 2; j++) { |
| 426 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | 426 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; |
| 427 | for (i = 0; i < HPTES_PER_GROUP; i++) { | 427 | for (i = 0; i < HPTES_PER_GROUP; i++) { |
| 428 | hpte_v = pSeries_lpar_hpte_getword0(slot); | 428 | hpte_v = pSeries_lpar_hpte_getword0(slot); |
| 429 | 429 | ||
| 430 | if ((HPTE_V_AVPN_VAL(hpte_v) == (vpn >> 11)) | 430 | if ((HPTE_V_AVPN_VAL(hpte_v) == (vpn >> 11)) |
| 431 | && (hpte_v & HPTE_V_VALID) | 431 | && (hpte_v & HPTE_V_VALID) |
| 432 | && (!!(hpte_v & HPTE_V_SECONDARY) == j)) { | 432 | && (!!(hpte_v & HPTE_V_SECONDARY) == j)) { |
| 433 | /* HPTE matches */ | 433 | /* HPTE matches */ |
| 434 | if (j) | 434 | if (j) |
| 435 | slot = -slot; | 435 | slot = -slot; |
| 436 | return slot; | 436 | return slot; |
| 437 | } | 437 | } |
| 438 | ++slot; | 438 | ++slot; |
| 439 | } | 439 | } |
| 440 | hash = ~hash; | 440 | hash = ~hash; |
| 441 | } | 441 | } |
| 442 | 442 | ||
| 443 | return -1; | 443 | return -1; |
| 444 | } | 444 | } |
| 445 | 445 | ||
| 446 | static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, | 446 | static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, |
| 447 | unsigned long ea) | 447 | unsigned long ea) |
| 448 | { | 448 | { |
| 449 | unsigned long lpar_rc; | 449 | unsigned long lpar_rc; |
| 450 | unsigned long vsid, va, vpn, flags; | 450 | unsigned long vsid, va, vpn, flags; |
| 451 | long slot; | 451 | long slot; |
| 452 | 452 | ||
| 453 | vsid = get_kernel_vsid(ea); | 453 | vsid = get_kernel_vsid(ea); |
| 454 | va = (vsid << 28) | (ea & 0x0fffffff); | 454 | va = (vsid << 28) | (ea & 0x0fffffff); |
| 455 | vpn = va >> PAGE_SHIFT; | 455 | vpn = va >> PAGE_SHIFT; |
| 456 | 456 | ||
| 457 | slot = pSeries_lpar_hpte_find(vpn); | 457 | slot = pSeries_lpar_hpte_find(vpn); |
| 458 | BUG_ON(slot == -1); | 458 | BUG_ON(slot == -1); |
| 459 | 459 | ||
| 460 | flags = newpp & 7; | 460 | flags = newpp & 7; |
| 461 | lpar_rc = plpar_pte_protect(flags, slot, 0); | 461 | lpar_rc = plpar_pte_protect(flags, slot, 0); |
| 462 | 462 | ||
| 463 | BUG_ON(lpar_rc != H_Success); | 463 | BUG_ON(lpar_rc != H_Success); |
| 464 | } | 464 | } |
| 465 | 465 | ||
| 466 | static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, | 466 | static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, |
| 467 | int large, int local) | 467 | int large, int local) |
| 468 | { | 468 | { |
| 469 | unsigned long avpn = va >> 23; | 469 | unsigned long avpn = va >> 23; |
| 470 | unsigned long lpar_rc; | 470 | unsigned long lpar_rc; |
| 471 | unsigned long dummy1, dummy2; | 471 | unsigned long dummy1, dummy2; |
| 472 | 472 | ||
| 473 | if (large) | 473 | if (large) |
| 474 | avpn &= ~0x1UL; | 474 | avpn &= ~0x1UL; |
| 475 | 475 | ||
| 476 | lpar_rc = plpar_pte_remove(H_AVPN, slot, (avpn << 7), &dummy1, | 476 | lpar_rc = plpar_pte_remove(H_AVPN, slot, (avpn << 7), &dummy1, |
| 477 | &dummy2); | 477 | &dummy2); |
| 478 | 478 | ||
| 479 | if (lpar_rc == H_Not_Found) | 479 | if (lpar_rc == H_Not_Found) |
| 480 | return; | 480 | return; |
| 481 | 481 | ||
| 482 | BUG_ON(lpar_rc != H_Success); | 482 | BUG_ON(lpar_rc != H_Success); |
| 483 | } | 483 | } |
| 484 | 484 | ||
| 485 | /* | 485 | /* |
| 486 | * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie | 486 | * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie |
| 487 | * lock. | 487 | * lock. |
| 488 | */ | 488 | */ |
| 489 | void pSeries_lpar_flush_hash_range(unsigned long context, unsigned long number, | 489 | void pSeries_lpar_flush_hash_range(unsigned long context, unsigned long number, |
| 490 | int local) | 490 | int local) |
| 491 | { | 491 | { |
| 492 | int i; | 492 | int i; |
| 493 | unsigned long flags = 0; | 493 | unsigned long flags = 0; |
| 494 | struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); | 494 | struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); |
| 495 | int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); | 495 | int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); |
| 496 | 496 | ||
| 497 | if (lock_tlbie) | 497 | if (lock_tlbie) |
| 498 | spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); | 498 | spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); |
| 499 | 499 | ||
| 500 | for (i = 0; i < number; i++) | 500 | for (i = 0; i < number; i++) |
| 501 | flush_hash_page(context, batch->addr[i], batch->pte[i], local); | 501 | flush_hash_page(context, batch->addr[i], batch->pte[i], local); |
| 502 | 502 | ||
| 503 | if (lock_tlbie) | 503 | if (lock_tlbie) |
| 504 | spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); | 504 | spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); |
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | void hpte_init_lpar(void) | 507 | void hpte_init_lpar(void) |
| 508 | { | 508 | { |
| 509 | ppc_md.hpte_invalidate = pSeries_lpar_hpte_invalidate; | 509 | ppc_md.hpte_invalidate = pSeries_lpar_hpte_invalidate; |
| 510 | ppc_md.hpte_updatepp = pSeries_lpar_hpte_updatepp; | 510 | ppc_md.hpte_updatepp = pSeries_lpar_hpte_updatepp; |
| 511 | ppc_md.hpte_updateboltedpp = pSeries_lpar_hpte_updateboltedpp; | 511 | ppc_md.hpte_updateboltedpp = pSeries_lpar_hpte_updateboltedpp; |
| 512 | ppc_md.hpte_insert = pSeries_lpar_hpte_insert; | 512 | ppc_md.hpte_insert = pSeries_lpar_hpte_insert; |
| 513 | ppc_md.hpte_remove = pSeries_lpar_hpte_remove; | 513 | ppc_md.hpte_remove = pSeries_lpar_hpte_remove; |
| 514 | ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range; | 514 | ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range; |
| 515 | ppc_md.hpte_clear_all = pSeries_lpar_hptab_clear; | 515 | ppc_md.hpte_clear_all = pSeries_lpar_hptab_clear; |
| 516 | 516 | ||
| 517 | htab_finish_init(); | 517 | htab_finish_init(); |
| 518 | } | 518 | } |
| 519 | 519 |
arch/ppc64/kernel/pmac_setup.c
| 1 | /* | 1 | /* |
| 2 | * arch/ppc/platforms/setup.c | 2 | * arch/ppc/platforms/setup.c |
| 3 | * | 3 | * |
| 4 | * PowerPC version | 4 | * PowerPC version |
| 5 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | 5 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) |
| 6 | * | 6 | * |
| 7 | * Adapted for Power Macintosh by Paul Mackerras | 7 | * Adapted for Power Macintosh by Paul Mackerras |
| 8 | * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) | 8 | * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) |
| 9 | * | 9 | * |
| 10 | * Derived from "arch/alpha/kernel/setup.c" | 10 | * Derived from "arch/alpha/kernel/setup.c" |
| 11 | * Copyright (C) 1995 Linus Torvalds | 11 | * Copyright (C) 1995 Linus Torvalds |
| 12 | * | 12 | * |
| 13 | * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) | 13 | * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) |
| 14 | * | 14 | * |
| 15 | * This program is free software; you can redistribute it and/or | 15 | * This program is free software; you can redistribute it and/or |
| 16 | * modify it under the terms of the GNU General Public License | 16 | * modify it under the terms of the GNU General Public License |
| 17 | * as published by the Free Software Foundation; either version | 17 | * as published by the Free Software Foundation; either version |
| 18 | * 2 of the License, or (at your option) any later version. | 18 | * 2 of the License, or (at your option) any later version. |
| 19 | * | 19 | * |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | /* | 22 | /* |
| 23 | * bootup setup stuff.. | 23 | * bootup setup stuff.. |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #undef DEBUG | 26 | #undef DEBUG |
| 27 | 27 | ||
| 28 | #include <linux/config.h> | 28 | #include <linux/config.h> |
| 29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
| 30 | #include <linux/errno.h> | 30 | #include <linux/errno.h> |
| 31 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
| 32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
| 33 | #include <linux/mm.h> | 33 | #include <linux/mm.h> |
| 34 | #include <linux/stddef.h> | 34 | #include <linux/stddef.h> |
| 35 | #include <linux/unistd.h> | 35 | #include <linux/unistd.h> |
| 36 | #include <linux/ptrace.h> | 36 | #include <linux/ptrace.h> |
| 37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
| 38 | #include <linux/user.h> | 38 | #include <linux/user.h> |
| 39 | #include <linux/a.out.h> | 39 | #include <linux/a.out.h> |
| 40 | #include <linux/tty.h> | 40 | #include <linux/tty.h> |
| 41 | #include <linux/string.h> | 41 | #include <linux/string.h> |
| 42 | #include <linux/delay.h> | 42 | #include <linux/delay.h> |
| 43 | #include <linux/ioport.h> | 43 | #include <linux/ioport.h> |
| 44 | #include <linux/major.h> | 44 | #include <linux/major.h> |
| 45 | #include <linux/initrd.h> | 45 | #include <linux/initrd.h> |
| 46 | #include <linux/vt_kern.h> | 46 | #include <linux/vt_kern.h> |
| 47 | #include <linux/console.h> | 47 | #include <linux/console.h> |
| 48 | #include <linux/ide.h> | 48 | #include <linux/ide.h> |
| 49 | #include <linux/pci.h> | 49 | #include <linux/pci.h> |
| 50 | #include <linux/adb.h> | 50 | #include <linux/adb.h> |
| 51 | #include <linux/cuda.h> | 51 | #include <linux/cuda.h> |
| 52 | #include <linux/pmu.h> | 52 | #include <linux/pmu.h> |
| 53 | #include <linux/irq.h> | 53 | #include <linux/irq.h> |
| 54 | #include <linux/seq_file.h> | 54 | #include <linux/seq_file.h> |
| 55 | #include <linux/root_dev.h> | 55 | #include <linux/root_dev.h> |
| 56 | #include <linux/bitops.h> | 56 | #include <linux/bitops.h> |
| 57 | 57 | ||
| 58 | #include <asm/processor.h> | 58 | #include <asm/processor.h> |
| 59 | #include <asm/sections.h> | 59 | #include <asm/sections.h> |
| 60 | #include <asm/prom.h> | 60 | #include <asm/prom.h> |
| 61 | #include <asm/system.h> | 61 | #include <asm/system.h> |
| 62 | #include <asm/io.h> | 62 | #include <asm/io.h> |
| 63 | #include <asm/pci-bridge.h> | 63 | #include <asm/pci-bridge.h> |
| 64 | #include <asm/iommu.h> | 64 | #include <asm/iommu.h> |
| 65 | #include <asm/machdep.h> | 65 | #include <asm/machdep.h> |
| 66 | #include <asm/dma.h> | 66 | #include <asm/dma.h> |
| 67 | #include <asm/btext.h> | 67 | #include <asm/btext.h> |
| 68 | #include <asm/cputable.h> | 68 | #include <asm/cputable.h> |
| 69 | #include <asm/pmac_feature.h> | 69 | #include <asm/pmac_feature.h> |
| 70 | #include <asm/time.h> | 70 | #include <asm/time.h> |
| 71 | #include <asm/of_device.h> | 71 | #include <asm/of_device.h> |
| 72 | #include <asm/lmb.h> | 72 | #include <asm/lmb.h> |
| 73 | #include <asm/smu.h> | 73 | #include <asm/smu.h> |
| 74 | #include <asm/pmc.h> | 74 | #include <asm/pmc.h> |
| 75 | 75 | ||
| 76 | #include "pmac.h" | 76 | #include "pmac.h" |
| 77 | #include "mpic.h" | 77 | #include "mpic.h" |
| 78 | 78 | ||
| 79 | #ifdef DEBUG | 79 | #ifdef DEBUG |
| 80 | #define DBG(fmt...) udbg_printf(fmt) | 80 | #define DBG(fmt...) udbg_printf(fmt) |
| 81 | #else | 81 | #else |
| 82 | #define DBG(fmt...) | 82 | #define DBG(fmt...) |
| 83 | #endif | 83 | #endif |
| 84 | 84 | ||
| 85 | static int current_root_goodness = -1; | 85 | static int current_root_goodness = -1; |
| 86 | #define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ | 86 | #define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ |
| 87 | 87 | ||
| 88 | extern int powersave_nap; | 88 | extern int powersave_nap; |
| 89 | int sccdbg; | 89 | int sccdbg; |
| 90 | 90 | ||
| 91 | sys_ctrler_t sys_ctrler; | 91 | sys_ctrler_t sys_ctrler; |
| 92 | EXPORT_SYMBOL(sys_ctrler); | 92 | EXPORT_SYMBOL(sys_ctrler); |
| 93 | 93 | ||
| 94 | #ifdef CONFIG_PMAC_SMU | 94 | #ifdef CONFIG_PMAC_SMU |
| 95 | unsigned long smu_cmdbuf_abs; | 95 | unsigned long smu_cmdbuf_abs; |
| 96 | EXPORT_SYMBOL(smu_cmdbuf_abs); | 96 | EXPORT_SYMBOL(smu_cmdbuf_abs); |
| 97 | #endif | 97 | #endif |
| 98 | 98 | ||
| 99 | extern void udbg_init_scc(struct device_node *np); | 99 | extern void udbg_init_scc(struct device_node *np); |
| 100 | 100 | ||
| 101 | static void __pmac pmac_show_cpuinfo(struct seq_file *m) | 101 | static void __pmac pmac_show_cpuinfo(struct seq_file *m) |
| 102 | { | 102 | { |
| 103 | struct device_node *np; | 103 | struct device_node *np; |
| 104 | char *pp; | 104 | char *pp; |
| 105 | int plen; | 105 | int plen; |
| 106 | char* mbname; | 106 | char* mbname; |
| 107 | int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, | 107 | int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, |
| 108 | PMAC_MB_INFO_MODEL, 0); | 108 | PMAC_MB_INFO_MODEL, 0); |
| 109 | unsigned int mbflags = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, | 109 | unsigned int mbflags = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, |
| 110 | PMAC_MB_INFO_FLAGS, 0); | 110 | PMAC_MB_INFO_FLAGS, 0); |
| 111 | 111 | ||
| 112 | if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, | 112 | if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, |
| 113 | (long)&mbname) != 0) | 113 | (long)&mbname) != 0) |
| 114 | mbname = "Unknown"; | 114 | mbname = "Unknown"; |
| 115 | 115 | ||
| 116 | /* find motherboard type */ | 116 | /* find motherboard type */ |
| 117 | seq_printf(m, "machine\t\t: "); | 117 | seq_printf(m, "machine\t\t: "); |
| 118 | np = find_devices("device-tree"); | 118 | np = find_devices("device-tree"); |
| 119 | if (np != NULL) { | 119 | if (np != NULL) { |
| 120 | pp = (char *) get_property(np, "model", NULL); | 120 | pp = (char *) get_property(np, "model", NULL); |
| 121 | if (pp != NULL) | 121 | if (pp != NULL) |
| 122 | seq_printf(m, "%s\n", pp); | 122 | seq_printf(m, "%s\n", pp); |
| 123 | else | 123 | else |
| 124 | seq_printf(m, "PowerMac\n"); | 124 | seq_printf(m, "PowerMac\n"); |
| 125 | pp = (char *) get_property(np, "compatible", &plen); | 125 | pp = (char *) get_property(np, "compatible", &plen); |
| 126 | if (pp != NULL) { | 126 | if (pp != NULL) { |
| 127 | seq_printf(m, "motherboard\t:"); | 127 | seq_printf(m, "motherboard\t:"); |
| 128 | while (plen > 0) { | 128 | while (plen > 0) { |
| 129 | int l = strlen(pp) + 1; | 129 | int l = strlen(pp) + 1; |
| 130 | seq_printf(m, " %s", pp); | 130 | seq_printf(m, " %s", pp); |
| 131 | plen -= l; | 131 | plen -= l; |
| 132 | pp += l; | 132 | pp += l; |
| 133 | } | 133 | } |
| 134 | seq_printf(m, "\n"); | 134 | seq_printf(m, "\n"); |
| 135 | } | 135 | } |
| 136 | } else | 136 | } else |
| 137 | seq_printf(m, "PowerMac\n"); | 137 | seq_printf(m, "PowerMac\n"); |
| 138 | 138 | ||
| 139 | /* print parsed model */ | 139 | /* print parsed model */ |
| 140 | seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname); | 140 | seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname); |
| 141 | seq_printf(m, "pmac flags\t: %08x\n", mbflags); | 141 | seq_printf(m, "pmac flags\t: %08x\n", mbflags); |
| 142 | 142 | ||
| 143 | /* Indicate newworld */ | 143 | /* Indicate newworld */ |
| 144 | seq_printf(m, "pmac-generation\t: NewWorld\n"); | 144 | seq_printf(m, "pmac-generation\t: NewWorld\n"); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | 147 | ||
| 148 | static void __init pmac_setup_arch(void) | 148 | static void __init pmac_setup_arch(void) |
| 149 | { | 149 | { |
| 150 | /* init to some ~sane value until calibrate_delay() runs */ | 150 | /* init to some ~sane value until calibrate_delay() runs */ |
| 151 | loops_per_jiffy = 50000000; | 151 | loops_per_jiffy = 50000000; |
| 152 | 152 | ||
| 153 | /* Probe motherboard chipset */ | 153 | /* Probe motherboard chipset */ |
| 154 | pmac_feature_init(); | 154 | pmac_feature_init(); |
| 155 | #if 0 | 155 | #if 0 |
| 156 | /* Lock-enable the SCC channel used for debug */ | 156 | /* Lock-enable the SCC channel used for debug */ |
| 157 | if (sccdbg) { | 157 | if (sccdbg) { |
| 158 | np = of_find_node_by_name(NULL, "escc"); | 158 | np = of_find_node_by_name(NULL, "escc"); |
| 159 | if (np) | 159 | if (np) |
| 160 | pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, | 160 | pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, |
| 161 | PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); | 161 | PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); |
| 162 | } | 162 | } |
| 163 | #endif | 163 | #endif |
| 164 | /* We can NAP */ | 164 | /* We can NAP */ |
| 165 | powersave_nap = 1; | 165 | powersave_nap = 1; |
| 166 | 166 | ||
| 167 | #ifdef CONFIG_ADB_PMU | 167 | #ifdef CONFIG_ADB_PMU |
| 168 | /* Initialize the PMU if any */ | 168 | /* Initialize the PMU if any */ |
| 169 | find_via_pmu(); | 169 | find_via_pmu(); |
| 170 | #endif | 170 | #endif |
| 171 | #ifdef CONFIG_PMAC_SMU | 171 | #ifdef CONFIG_PMAC_SMU |
| 172 | /* Initialize the SMU if any */ | 172 | /* Initialize the SMU if any */ |
| 173 | smu_init(); | 173 | smu_init(); |
| 174 | #endif | 174 | #endif |
| 175 | 175 | ||
| 176 | /* Init NVRAM access */ | 176 | /* Init NVRAM access */ |
| 177 | pmac_nvram_init(); | 177 | pmac_nvram_init(); |
| 178 | 178 | ||
| 179 | /* Setup SMP callback */ | 179 | /* Setup SMP callback */ |
| 180 | #ifdef CONFIG_SMP | 180 | #ifdef CONFIG_SMP |
| 181 | pmac_setup_smp(); | 181 | pmac_setup_smp(); |
| 182 | #endif | 182 | #endif |
| 183 | 183 | ||
| 184 | /* Lookup PCI hosts */ | 184 | /* Lookup PCI hosts */ |
| 185 | pmac_pci_init(); | 185 | pmac_pci_init(); |
| 186 | 186 | ||
| 187 | #ifdef CONFIG_DUMMY_CONSOLE | 187 | #ifdef CONFIG_DUMMY_CONSOLE |
| 188 | conswitchp = &dummy_con; | 188 | conswitchp = &dummy_con; |
| 189 | #endif | 189 | #endif |
| 190 | 190 | ||
| 191 | printk(KERN_INFO "Using native/NAP idle loop\n"); | 191 | printk(KERN_INFO "Using native/NAP idle loop\n"); |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | #ifdef CONFIG_SCSI | 194 | #ifdef CONFIG_SCSI |
| 195 | void note_scsi_host(struct device_node *node, void *host) | 195 | void note_scsi_host(struct device_node *node, void *host) |
| 196 | { | 196 | { |
| 197 | /* Obsolete */ | 197 | /* Obsolete */ |
| 198 | } | 198 | } |
| 199 | #endif | 199 | #endif |
| 200 | 200 | ||
| 201 | 201 | ||
| 202 | static int initializing = 1; | 202 | static int initializing = 1; |
| 203 | 203 | ||
| 204 | static int pmac_late_init(void) | 204 | static int pmac_late_init(void) |
| 205 | { | 205 | { |
| 206 | initializing = 0; | 206 | initializing = 0; |
| 207 | return 0; | 207 | return 0; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | late_initcall(pmac_late_init); | 210 | late_initcall(pmac_late_init); |
| 211 | 211 | ||
| 212 | /* can't be __init - can be called whenever a disk is first accessed */ | 212 | /* can't be __init - can be called whenever a disk is first accessed */ |
| 213 | void __pmac note_bootable_part(dev_t dev, int part, int goodness) | 213 | void __pmac note_bootable_part(dev_t dev, int part, int goodness) |
| 214 | { | 214 | { |
| 215 | extern dev_t boot_dev; | 215 | extern dev_t boot_dev; |
| 216 | char *p; | 216 | char *p; |
| 217 | 217 | ||
| 218 | if (!initializing) | 218 | if (!initializing) |
| 219 | return; | 219 | return; |
| 220 | if ((goodness <= current_root_goodness) && | 220 | if ((goodness <= current_root_goodness) && |
| 221 | ROOT_DEV != DEFAULT_ROOT_DEVICE) | 221 | ROOT_DEV != DEFAULT_ROOT_DEVICE) |
| 222 | return; | 222 | return; |
| 223 | p = strstr(saved_command_line, "root="); | 223 | p = strstr(saved_command_line, "root="); |
| 224 | if (p != NULL && (p == saved_command_line || p[-1] == ' ')) | 224 | if (p != NULL && (p == saved_command_line || p[-1] == ' ')) |
| 225 | return; | 225 | return; |
| 226 | 226 | ||
| 227 | if (!boot_dev || dev == boot_dev) { | 227 | if (!boot_dev || dev == boot_dev) { |
| 228 | ROOT_DEV = dev + part; | 228 | ROOT_DEV = dev + part; |
| 229 | boot_dev = 0; | 229 | boot_dev = 0; |
| 230 | current_root_goodness = goodness; | 230 | current_root_goodness = goodness; |
| 231 | } | 231 | } |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | static void __pmac pmac_restart(char *cmd) | 234 | static void __pmac pmac_restart(char *cmd) |
| 235 | { | 235 | { |
| 236 | switch(sys_ctrler) { | 236 | switch(sys_ctrler) { |
| 237 | #ifdef CONFIG_ADB_PMU | 237 | #ifdef CONFIG_ADB_PMU |
| 238 | case SYS_CTRLER_PMU: | 238 | case SYS_CTRLER_PMU: |
| 239 | pmu_restart(); | 239 | pmu_restart(); |
| 240 | break; | 240 | break; |
| 241 | #endif | 241 | #endif |
| 242 | 242 | ||
| 243 | #ifdef CONFIG_PMAC_SMU | 243 | #ifdef CONFIG_PMAC_SMU |
| 244 | case SYS_CTRLER_SMU: | 244 | case SYS_CTRLER_SMU: |
| 245 | smu_restart(); | 245 | smu_restart(); |
| 246 | break; | 246 | break; |
| 247 | #endif | 247 | #endif |
| 248 | default: | 248 | default: |
| 249 | ; | 249 | ; |
| 250 | } | 250 | } |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | static void __pmac pmac_power_off(void) | 253 | static void __pmac pmac_power_off(void) |
| 254 | { | 254 | { |
| 255 | switch(sys_ctrler) { | 255 | switch(sys_ctrler) { |
| 256 | #ifdef CONFIG_ADB_PMU | 256 | #ifdef CONFIG_ADB_PMU |
| 257 | case SYS_CTRLER_PMU: | 257 | case SYS_CTRLER_PMU: |
| 258 | pmu_shutdown(); | 258 | pmu_shutdown(); |
| 259 | break; | 259 | break; |
| 260 | #endif | 260 | #endif |
| 261 | #ifdef CONFIG_PMAC_SMU | 261 | #ifdef CONFIG_PMAC_SMU |
| 262 | case SYS_CTRLER_SMU: | 262 | case SYS_CTRLER_SMU: |
| 263 | smu_shutdown(); | 263 | smu_shutdown(); |
| 264 | break; | 264 | break; |
| 265 | #endif | 265 | #endif |
| 266 | default: | 266 | default: |
| 267 | ; | 267 | ; |
| 268 | } | 268 | } |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | static void __pmac pmac_halt(void) | 271 | static void __pmac pmac_halt(void) |
| 272 | { | 272 | { |
| 273 | pmac_power_off(); | 273 | pmac_power_off(); |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | #ifdef CONFIG_BOOTX_TEXT | 276 | #ifdef CONFIG_BOOTX_TEXT |
| 277 | static void btext_putc(unsigned char c) | 277 | static void btext_putc(unsigned char c) |
| 278 | { | 278 | { |
| 279 | btext_drawchar(c); | 279 | btext_drawchar(c); |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | static void __init init_boot_display(void) | 282 | static void __init init_boot_display(void) |
| 283 | { | 283 | { |
| 284 | char *name; | 284 | char *name; |
| 285 | struct device_node *np = NULL; | 285 | struct device_node *np = NULL; |
| 286 | int rc = -ENODEV; | 286 | int rc = -ENODEV; |
| 287 | 287 | ||
| 288 | printk("trying to initialize btext ...\n"); | 288 | printk("trying to initialize btext ...\n"); |
| 289 | 289 | ||
| 290 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); | 290 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); |
| 291 | if (name != NULL) { | 291 | if (name != NULL) { |
| 292 | np = of_find_node_by_path(name); | 292 | np = of_find_node_by_path(name); |
| 293 | if (np != NULL) { | 293 | if (np != NULL) { |
| 294 | if (strcmp(np->type, "display") != 0) { | 294 | if (strcmp(np->type, "display") != 0) { |
| 295 | printk("boot stdout isn't a display !\n"); | 295 | printk("boot stdout isn't a display !\n"); |
| 296 | of_node_put(np); | 296 | of_node_put(np); |
| 297 | np = NULL; | 297 | np = NULL; |
| 298 | } | 298 | } |
| 299 | } | 299 | } |
| 300 | } | 300 | } |
| 301 | if (np) | 301 | if (np) |
| 302 | rc = btext_initialize(np); | 302 | rc = btext_initialize(np); |
| 303 | if (rc == 0) | 303 | if (rc == 0) |
| 304 | return; | 304 | return; |
| 305 | 305 | ||
| 306 | for (np = NULL; (np = of_find_node_by_type(np, "display"));) { | 306 | for (np = NULL; (np = of_find_node_by_type(np, "display"));) { |
| 307 | if (get_property(np, "linux,opened", NULL)) { | 307 | if (get_property(np, "linux,opened", NULL)) { |
| 308 | printk("trying %s ...\n", np->full_name); | 308 | printk("trying %s ...\n", np->full_name); |
| 309 | rc = btext_initialize(np); | 309 | rc = btext_initialize(np); |
| 310 | printk("result: %d\n", rc); | 310 | printk("result: %d\n", rc); |
| 311 | } | 311 | } |
| 312 | if (rc == 0) | 312 | if (rc == 0) |
| 313 | return; | 313 | return; |
| 314 | } | 314 | } |
| 315 | } | 315 | } |
| 316 | #endif /* CONFIG_BOOTX_TEXT */ | 316 | #endif /* CONFIG_BOOTX_TEXT */ |
| 317 | 317 | ||
| 318 | /* | 318 | /* |
| 319 | * Early initialization. | 319 | * Early initialization. |
| 320 | */ | 320 | */ |
| 321 | static void __init pmac_init_early(void) | 321 | static void __init pmac_init_early(void) |
| 322 | { | 322 | { |
| 323 | DBG(" -> pmac_init_early\n"); | 323 | DBG(" -> pmac_init_early\n"); |
| 324 | 324 | ||
| 325 | /* Initialize hash table, from now on, we can take hash faults | 325 | /* Initialize hash table, from now on, we can take hash faults |
| 326 | * and call ioremap | 326 | * and call ioremap |
| 327 | */ | 327 | */ |
| 328 | hpte_init_native(); | 328 | hpte_init_native(); |
| 329 | 329 | ||
| 330 | /* Init SCC */ | 330 | /* Init SCC */ |
| 331 | if (strstr(cmd_line, "sccdbg")) { | 331 | if (strstr(cmd_line, "sccdbg")) { |
| 332 | sccdbg = 1; | 332 | sccdbg = 1; |
| 333 | udbg_init_scc(NULL); | 333 | udbg_init_scc(NULL); |
| 334 | } | 334 | } |
| 335 | |||
| 336 | else { | ||
| 337 | #ifdef CONFIG_BOOTX_TEXT | 335 | #ifdef CONFIG_BOOTX_TEXT |
| 336 | else { | ||
| 338 | init_boot_display(); | 337 | init_boot_display(); |
| 339 | 338 | ||
| 340 | ppc_md.udbg_putc = btext_putc; | 339 | udbg_putc = btext_putc; |
| 341 | ppc_md.udbg_getc = NULL; | ||
| 342 | ppc_md.udbg_getc_poll = NULL; | ||
| 343 | #endif /* CONFIG_BOOTX_TEXT */ | ||
| 344 | } | 340 | } |
| 341 | #endif /* CONFIG_BOOTX_TEXT */ | ||
| 345 | 342 | ||
| 346 | /* Setup interrupt mapping options */ | 343 | /* Setup interrupt mapping options */ |
| 347 | ppc64_interrupt_controller = IC_OPEN_PIC; | 344 | ppc64_interrupt_controller = IC_OPEN_PIC; |
| 348 | 345 | ||
| 349 | iommu_init_early_u3(); | 346 | iommu_init_early_u3(); |
| 350 | 347 | ||
| 351 | DBG(" <- pmac_init_early\n"); | 348 | DBG(" <- pmac_init_early\n"); |
| 352 | } | 349 | } |
| 353 | 350 | ||
| 354 | static int pmac_u3_cascade(struct pt_regs *regs, void *data) | 351 | static int pmac_u3_cascade(struct pt_regs *regs, void *data) |
| 355 | { | 352 | { |
| 356 | return mpic_get_one_irq((struct mpic *)data, regs); | 353 | return mpic_get_one_irq((struct mpic *)data, regs); |
| 357 | } | 354 | } |
| 358 | 355 | ||
| 359 | static __init void pmac_init_IRQ(void) | 356 | static __init void pmac_init_IRQ(void) |
| 360 | { | 357 | { |
| 361 | struct device_node *irqctrler = NULL; | 358 | struct device_node *irqctrler = NULL; |
| 362 | struct device_node *irqctrler2 = NULL; | 359 | struct device_node *irqctrler2 = NULL; |
| 363 | struct device_node *np = NULL; | 360 | struct device_node *np = NULL; |
| 364 | struct mpic *mpic1, *mpic2; | 361 | struct mpic *mpic1, *mpic2; |
| 365 | 362 | ||
| 366 | /* We first try to detect Apple's new Core99 chipset, since mac-io | 363 | /* We first try to detect Apple's new Core99 chipset, since mac-io |
| 367 | * is quite different on those machines and contains an IBM MPIC2. | 364 | * is quite different on those machines and contains an IBM MPIC2. |
| 368 | */ | 365 | */ |
| 369 | while ((np = of_find_node_by_type(np, "open-pic")) != NULL) { | 366 | while ((np = of_find_node_by_type(np, "open-pic")) != NULL) { |
| 370 | struct device_node *parent = of_get_parent(np); | 367 | struct device_node *parent = of_get_parent(np); |
| 371 | if (parent && !strcmp(parent->name, "u3")) | 368 | if (parent && !strcmp(parent->name, "u3")) |
| 372 | irqctrler2 = of_node_get(np); | 369 | irqctrler2 = of_node_get(np); |
| 373 | else | 370 | else |
| 374 | irqctrler = of_node_get(np); | 371 | irqctrler = of_node_get(np); |
| 375 | of_node_put(parent); | 372 | of_node_put(parent); |
| 376 | } | 373 | } |
| 377 | if (irqctrler != NULL && irqctrler->n_addrs > 0) { | 374 | if (irqctrler != NULL && irqctrler->n_addrs > 0) { |
| 378 | unsigned char senses[128]; | 375 | unsigned char senses[128]; |
| 379 | 376 | ||
| 380 | printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", | 377 | printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", |
| 381 | (unsigned int)irqctrler->addrs[0].address); | 378 | (unsigned int)irqctrler->addrs[0].address); |
| 382 | 379 | ||
| 383 | prom_get_irq_senses(senses, 0, 128); | 380 | prom_get_irq_senses(senses, 0, 128); |
| 384 | mpic1 = mpic_alloc(irqctrler->addrs[0].address, | 381 | mpic1 = mpic_alloc(irqctrler->addrs[0].address, |
| 385 | MPIC_PRIMARY | MPIC_WANTS_RESET, | 382 | MPIC_PRIMARY | MPIC_WANTS_RESET, |
| 386 | 0, 0, 128, 256, senses, 128, " K2-MPIC "); | 383 | 0, 0, 128, 256, senses, 128, " K2-MPIC "); |
| 387 | BUG_ON(mpic1 == NULL); | 384 | BUG_ON(mpic1 == NULL); |
| 388 | mpic_init(mpic1); | 385 | mpic_init(mpic1); |
| 389 | 386 | ||
| 390 | if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 && | 387 | if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 && |
| 391 | irqctrler2->n_addrs > 0) { | 388 | irqctrler2->n_addrs > 0) { |
| 392 | printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n", | 389 | printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n", |
| 393 | (u32)irqctrler2->addrs[0].address, | 390 | (u32)irqctrler2->addrs[0].address, |
| 394 | irqctrler2->intrs[0].line); | 391 | irqctrler2->intrs[0].line); |
| 395 | 392 | ||
| 396 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0); | 393 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0); |
| 397 | prom_get_irq_senses(senses, 128, 128 + 128); | 394 | prom_get_irq_senses(senses, 128, 128 + 128); |
| 398 | 395 | ||
| 399 | /* We don't need to set MPIC_BROKEN_U3 here since we don't have | 396 | /* We don't need to set MPIC_BROKEN_U3 here since we don't have |
| 400 | * hypertransport interrupts routed to it | 397 | * hypertransport interrupts routed to it |
| 401 | */ | 398 | */ |
| 402 | mpic2 = mpic_alloc(irqctrler2->addrs[0].address, | 399 | mpic2 = mpic_alloc(irqctrler2->addrs[0].address, |
| 403 | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET, | 400 | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET, |
| 404 | 0, 128, 128, 0, senses, 128, " U3-MPIC "); | 401 | 0, 128, 128, 0, senses, 128, " U3-MPIC "); |
| 405 | BUG_ON(mpic2 == NULL); | 402 | BUG_ON(mpic2 == NULL); |
| 406 | mpic_init(mpic2); | 403 | mpic_init(mpic2); |
| 407 | mpic_setup_cascade(irqctrler2->intrs[0].line, | 404 | mpic_setup_cascade(irqctrler2->intrs[0].line, |
| 408 | pmac_u3_cascade, mpic2); | 405 | pmac_u3_cascade, mpic2); |
| 409 | } | 406 | } |
| 410 | } | 407 | } |
| 411 | of_node_put(irqctrler); | 408 | of_node_put(irqctrler); |
| 412 | of_node_put(irqctrler2); | 409 | of_node_put(irqctrler2); |
| 413 | } | 410 | } |
| 414 | 411 | ||
| 415 | static void __init pmac_progress(char *s, unsigned short hex) | 412 | static void __init pmac_progress(char *s, unsigned short hex) |
| 416 | { | 413 | { |
| 417 | if (sccdbg) { | 414 | if (sccdbg) { |
| 418 | udbg_puts(s); | 415 | udbg_puts(s); |
| 419 | udbg_puts("\n"); | 416 | udbg_puts("\n"); |
| 420 | } | 417 | } |
| 421 | #ifdef CONFIG_BOOTX_TEXT | 418 | #ifdef CONFIG_BOOTX_TEXT |
| 422 | else if (boot_text_mapped) { | 419 | else if (boot_text_mapped) { |
| 423 | btext_drawstring(s); | 420 | btext_drawstring(s); |
| 424 | btext_drawstring("\n"); | 421 | btext_drawstring("\n"); |
| 425 | } | 422 | } |
| 426 | #endif /* CONFIG_BOOTX_TEXT */ | 423 | #endif /* CONFIG_BOOTX_TEXT */ |
| 427 | } | 424 | } |
| 428 | 425 | ||
| 429 | /* | 426 | /* |
| 430 | * pmac has no legacy IO, anything calling this function has to | 427 | * pmac has no legacy IO, anything calling this function has to |
| 431 | * fail or bad things will happen | 428 | * fail or bad things will happen |
| 432 | */ | 429 | */ |
| 433 | static int pmac_check_legacy_ioport(unsigned int baseport) | 430 | static int pmac_check_legacy_ioport(unsigned int baseport) |
| 434 | { | 431 | { |
| 435 | return -ENODEV; | 432 | return -ENODEV; |
| 436 | } | 433 | } |
| 437 | 434 | ||
| 438 | static int __init pmac_declare_of_platform_devices(void) | 435 | static int __init pmac_declare_of_platform_devices(void) |
| 439 | { | 436 | { |
| 440 | struct device_node *np; | 437 | struct device_node *np; |
| 441 | 438 | ||
| 442 | np = find_devices("u3"); | 439 | np = find_devices("u3"); |
| 443 | if (np) { | 440 | if (np) { |
| 444 | for (np = np->child; np != NULL; np = np->sibling) | 441 | for (np = np->child; np != NULL; np = np->sibling) |
| 445 | if (strncmp(np->name, "i2c", 3) == 0) { | 442 | if (strncmp(np->name, "i2c", 3) == 0) { |
| 446 | of_platform_device_create(np, "u3-i2c"); | 443 | of_platform_device_create(np, "u3-i2c"); |
| 447 | break; | 444 | break; |
| 448 | } | 445 | } |
| 449 | } | 446 | } |
| 450 | 447 | ||
| 451 | return 0; | 448 | return 0; |
| 452 | } | 449 | } |
| 453 | 450 | ||
| 454 | device_initcall(pmac_declare_of_platform_devices); | 451 | device_initcall(pmac_declare_of_platform_devices); |
| 455 | 452 | ||
| 456 | /* | 453 | /* |
| 457 | * Called very early, MMU is off, device-tree isn't unflattened | 454 | * Called very early, MMU is off, device-tree isn't unflattened |
| 458 | */ | 455 | */ |
| 459 | static int __init pmac_probe(int platform) | 456 | static int __init pmac_probe(int platform) |
| 460 | { | 457 | { |
| 461 | if (platform != PLATFORM_POWERMAC) | 458 | if (platform != PLATFORM_POWERMAC) |
| 462 | return 0; | 459 | return 0; |
| 463 | /* | 460 | /* |
| 464 | * On U3, the DART (iommu) must be allocated now since it | 461 | * On U3, the DART (iommu) must be allocated now since it |
| 465 | * has an impact on htab_initialize (due to the large page it | 462 | * has an impact on htab_initialize (due to the large page it |
| 466 | * occupies having to be broken up so the DART itself is not | 463 | * occupies having to be broken up so the DART itself is not |
| 467 | * part of the cacheable linar mapping | 464 | * part of the cacheable linar mapping |
| 468 | */ | 465 | */ |
| 469 | alloc_u3_dart_table(); | 466 | alloc_u3_dart_table(); |
| 470 | 467 | ||
| 471 | #ifdef CONFIG_PMAC_SMU | 468 | #ifdef CONFIG_PMAC_SMU |
| 472 | /* | 469 | /* |
| 473 | * SMU based G5s need some memory below 2Gb, at least the current | 470 | * SMU based G5s need some memory below 2Gb, at least the current |
| 474 | * driver needs that. We have to allocate it now. We allocate 4k | 471 | * driver needs that. We have to allocate it now. We allocate 4k |
| 475 | * (1 small page) for now. | 472 | * (1 small page) for now. |
| 476 | */ | 473 | */ |
| 477 | smu_cmdbuf_abs = lmb_alloc_base(4096, 4096, 0x80000000UL); | 474 | smu_cmdbuf_abs = lmb_alloc_base(4096, 4096, 0x80000000UL); |
| 478 | #endif /* CONFIG_PMAC_SMU */ | 475 | #endif /* CONFIG_PMAC_SMU */ |
| 479 | 476 | ||
| 480 | return 1; | 477 | return 1; |
| 481 | } | 478 | } |
| 482 | 479 | ||
| 483 | struct machdep_calls __initdata pmac_md = { | 480 | struct machdep_calls __initdata pmac_md = { |
| 484 | #ifdef CONFIG_HOTPLUG_CPU | 481 | #ifdef CONFIG_HOTPLUG_CPU |
| 485 | .cpu_die = generic_mach_cpu_die, | 482 | .cpu_die = generic_mach_cpu_die, |
| 486 | #endif | 483 | #endif |
| 487 | .probe = pmac_probe, | 484 | .probe = pmac_probe, |
| 488 | .setup_arch = pmac_setup_arch, | 485 | .setup_arch = pmac_setup_arch, |
| 489 | .init_early = pmac_init_early, | 486 | .init_early = pmac_init_early, |
| 490 | .get_cpuinfo = pmac_show_cpuinfo, | 487 | .get_cpuinfo = pmac_show_cpuinfo, |
| 491 | .init_IRQ = pmac_init_IRQ, | 488 | .init_IRQ = pmac_init_IRQ, |
| 492 | .get_irq = mpic_get_irq, | 489 | .get_irq = mpic_get_irq, |
| 493 | .pcibios_fixup = pmac_pcibios_fixup, | 490 | .pcibios_fixup = pmac_pcibios_fixup, |
| 494 | .restart = pmac_restart, | 491 | .restart = pmac_restart, |
| 495 | .power_off = pmac_power_off, | 492 | .power_off = pmac_power_off, |
| 496 | .halt = pmac_halt, | 493 | .halt = pmac_halt, |
| 497 | .get_boot_time = pmac_get_boot_time, | 494 | .get_boot_time = pmac_get_boot_time, |
| 498 | .set_rtc_time = pmac_set_rtc_time, | 495 | .set_rtc_time = pmac_set_rtc_time, |
| 499 | .get_rtc_time = pmac_get_rtc_time, | 496 | .get_rtc_time = pmac_get_rtc_time, |
| 500 | .calibrate_decr = pmac_calibrate_decr, | 497 | .calibrate_decr = pmac_calibrate_decr, |
| 501 | .feature_call = pmac_do_feature_call, | 498 | .feature_call = pmac_do_feature_call, |
| 502 | .progress = pmac_progress, | 499 | .progress = pmac_progress, |
| 503 | .check_legacy_ioport = pmac_check_legacy_ioport, | 500 | .check_legacy_ioport = pmac_check_legacy_ioport, |
| 504 | .idle_loop = native_idle, | 501 | .idle_loop = native_idle, |
| 505 | .enable_pmcs = power4_enable_pmcs, | 502 | .enable_pmcs = power4_enable_pmcs, |
arch/ppc64/kernel/setup.c
| 1 | /* | 1 | /* |
| 2 | * | 2 | * |
| 3 | * Common boot and setup code. | 3 | * Common boot and setup code. |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2001 PPC64 Team, IBM Corp | 5 | * Copyright (C) 2001 PPC64 Team, IBM Corp |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
| 9 | * as published by the Free Software Foundation; either version | 9 | * as published by the Free Software Foundation; either version |
| 10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #undef DEBUG | 13 | #undef DEBUG |
| 14 | 14 | ||
| 15 | #include <linux/config.h> | 15 | #include <linux/config.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/string.h> | 17 | #include <linux/string.h> |
| 18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
| 19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
| 20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| 21 | #include <linux/reboot.h> | 21 | #include <linux/reboot.h> |
| 22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
| 23 | #include <linux/initrd.h> | 23 | #include <linux/initrd.h> |
| 24 | #include <linux/ide.h> | 24 | #include <linux/ide.h> |
| 25 | #include <linux/seq_file.h> | 25 | #include <linux/seq_file.h> |
| 26 | #include <linux/ioport.h> | 26 | #include <linux/ioport.h> |
| 27 | #include <linux/console.h> | 27 | #include <linux/console.h> |
| 28 | #include <linux/version.h> | 28 | #include <linux/version.h> |
| 29 | #include <linux/tty.h> | 29 | #include <linux/tty.h> |
| 30 | #include <linux/root_dev.h> | 30 | #include <linux/root_dev.h> |
| 31 | #include <linux/notifier.h> | 31 | #include <linux/notifier.h> |
| 32 | #include <linux/cpu.h> | 32 | #include <linux/cpu.h> |
| 33 | #include <linux/unistd.h> | 33 | #include <linux/unistd.h> |
| 34 | #include <linux/serial.h> | 34 | #include <linux/serial.h> |
| 35 | #include <linux/serial_8250.h> | 35 | #include <linux/serial_8250.h> |
| 36 | #include <asm/io.h> | 36 | #include <asm/io.h> |
| 37 | #include <asm/prom.h> | 37 | #include <asm/prom.h> |
| 38 | #include <asm/processor.h> | 38 | #include <asm/processor.h> |
| 39 | #include <asm/pgtable.h> | 39 | #include <asm/pgtable.h> |
| 40 | #include <asm/bootinfo.h> | 40 | #include <asm/bootinfo.h> |
| 41 | #include <asm/smp.h> | 41 | #include <asm/smp.h> |
| 42 | #include <asm/elf.h> | 42 | #include <asm/elf.h> |
| 43 | #include <asm/machdep.h> | 43 | #include <asm/machdep.h> |
| 44 | #include <asm/paca.h> | 44 | #include <asm/paca.h> |
| 45 | #include <asm/ppcdebug.h> | 45 | #include <asm/ppcdebug.h> |
| 46 | #include <asm/time.h> | 46 | #include <asm/time.h> |
| 47 | #include <asm/cputable.h> | 47 | #include <asm/cputable.h> |
| 48 | #include <asm/sections.h> | 48 | #include <asm/sections.h> |
| 49 | #include <asm/btext.h> | 49 | #include <asm/btext.h> |
| 50 | #include <asm/nvram.h> | 50 | #include <asm/nvram.h> |
| 51 | #include <asm/setup.h> | 51 | #include <asm/setup.h> |
| 52 | #include <asm/system.h> | 52 | #include <asm/system.h> |
| 53 | #include <asm/rtas.h> | 53 | #include <asm/rtas.h> |
| 54 | #include <asm/iommu.h> | 54 | #include <asm/iommu.h> |
| 55 | #include <asm/serial.h> | 55 | #include <asm/serial.h> |
| 56 | #include <asm/cache.h> | 56 | #include <asm/cache.h> |
| 57 | #include <asm/page.h> | 57 | #include <asm/page.h> |
| 58 | #include <asm/mmu.h> | 58 | #include <asm/mmu.h> |
| 59 | #include <asm/lmb.h> | 59 | #include <asm/lmb.h> |
| 60 | #include <asm/iSeries/ItLpNaca.h> | 60 | #include <asm/iSeries/ItLpNaca.h> |
| 61 | 61 | ||
| 62 | #ifdef DEBUG | 62 | #ifdef DEBUG |
| 63 | #define DBG(fmt...) udbg_printf(fmt) | 63 | #define DBG(fmt...) udbg_printf(fmt) |
| 64 | #else | 64 | #else |
| 65 | #define DBG(fmt...) | 65 | #define DBG(fmt...) |
| 66 | #endif | 66 | #endif |
| 67 | 67 | ||
| 68 | /* | 68 | /* |
| 69 | * Here are some early debugging facilities. You can enable one | 69 | * Here are some early debugging facilities. You can enable one |
| 70 | * but your kernel will not boot on anything else if you do so | 70 | * but your kernel will not boot on anything else if you do so |
| 71 | */ | 71 | */ |
| 72 | 72 | ||
| 73 | /* This one is for use on LPAR machines that support an HVC console | 73 | /* This one is for use on LPAR machines that support an HVC console |
| 74 | * on vterm 0 | 74 | * on vterm 0 |
| 75 | */ | 75 | */ |
| 76 | extern void udbg_init_debug_lpar(void); | 76 | extern void udbg_init_debug_lpar(void); |
| 77 | /* This one is for use on Apple G5 machines | 77 | /* This one is for use on Apple G5 machines |
| 78 | */ | 78 | */ |
| 79 | extern void udbg_init_pmac_realmode(void); | 79 | extern void udbg_init_pmac_realmode(void); |
| 80 | /* That's RTAS panel debug */ | 80 | /* That's RTAS panel debug */ |
| 81 | extern void call_rtas_display_status_delay(unsigned char c); | 81 | extern void call_rtas_display_status_delay(unsigned char c); |
| 82 | /* Here's maple real mode debug */ | 82 | /* Here's maple real mode debug */ |
| 83 | extern void udbg_init_maple_realmode(void); | 83 | extern void udbg_init_maple_realmode(void); |
| 84 | 84 | ||
| 85 | #define EARLY_DEBUG_INIT() do {} while(0) | 85 | #define EARLY_DEBUG_INIT() do {} while(0) |
| 86 | 86 | ||
| 87 | #if 0 | 87 | #if 0 |
| 88 | #define EARLY_DEBUG_INIT() udbg_init_debug_lpar() | 88 | #define EARLY_DEBUG_INIT() udbg_init_debug_lpar() |
| 89 | #define EARLY_DEBUG_INIT() udbg_init_maple_realmode() | 89 | #define EARLY_DEBUG_INIT() udbg_init_maple_realmode() |
| 90 | #define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() | 90 | #define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() |
| 91 | #define EARLY_DEBUG_INIT() \ | 91 | #define EARLY_DEBUG_INIT() \ |
| 92 | do { ppc_md.udbg_putc = call_rtas_display_status_delay; } while(0) | 92 | do { udbg_putc = call_rtas_display_status_delay; } while(0) |
| 93 | #endif | 93 | #endif |
| 94 | 94 | ||
| 95 | /* extern void *stab; */ | 95 | /* extern void *stab; */ |
| 96 | extern unsigned long klimit; | 96 | extern unsigned long klimit; |
| 97 | 97 | ||
| 98 | extern void mm_init_ppc64(void); | 98 | extern void mm_init_ppc64(void); |
| 99 | extern void stab_initialize(unsigned long stab); | 99 | extern void stab_initialize(unsigned long stab); |
| 100 | extern void htab_initialize(void); | 100 | extern void htab_initialize(void); |
| 101 | extern void early_init_devtree(void *flat_dt); | 101 | extern void early_init_devtree(void *flat_dt); |
| 102 | extern void unflatten_device_tree(void); | 102 | extern void unflatten_device_tree(void); |
| 103 | 103 | ||
| 104 | extern void smp_release_cpus(void); | 104 | extern void smp_release_cpus(void); |
| 105 | 105 | ||
| 106 | int have_of = 1; | 106 | int have_of = 1; |
| 107 | int boot_cpuid = 0; | 107 | int boot_cpuid = 0; |
| 108 | int boot_cpuid_phys = 0; | 108 | int boot_cpuid_phys = 0; |
| 109 | dev_t boot_dev; | 109 | dev_t boot_dev; |
| 110 | u64 ppc64_pft_size; | 110 | u64 ppc64_pft_size; |
| 111 | u64 ppc64_debug_switch; | 111 | u64 ppc64_debug_switch; |
| 112 | 112 | ||
| 113 | struct ppc64_caches ppc64_caches; | 113 | struct ppc64_caches ppc64_caches; |
| 114 | EXPORT_SYMBOL_GPL(ppc64_caches); | 114 | EXPORT_SYMBOL_GPL(ppc64_caches); |
| 115 | 115 | ||
| 116 | /* | 116 | /* |
| 117 | * These are used in binfmt_elf.c to put aux entries on the stack | 117 | * These are used in binfmt_elf.c to put aux entries on the stack |
| 118 | * for each elf executable being started. | 118 | * for each elf executable being started. |
| 119 | */ | 119 | */ |
| 120 | int dcache_bsize; | 120 | int dcache_bsize; |
| 121 | int icache_bsize; | 121 | int icache_bsize; |
| 122 | int ucache_bsize; | 122 | int ucache_bsize; |
| 123 | 123 | ||
| 124 | /* The main machine-dep calls structure | 124 | /* The main machine-dep calls structure |
| 125 | */ | 125 | */ |
| 126 | struct machdep_calls ppc_md; | 126 | struct machdep_calls ppc_md; |
| 127 | EXPORT_SYMBOL(ppc_md); | 127 | EXPORT_SYMBOL(ppc_md); |
| 128 | 128 | ||
| 129 | #ifdef CONFIG_MAGIC_SYSRQ | 129 | #ifdef CONFIG_MAGIC_SYSRQ |
| 130 | unsigned long SYSRQ_KEY; | 130 | unsigned long SYSRQ_KEY; |
| 131 | #endif /* CONFIG_MAGIC_SYSRQ */ | 131 | #endif /* CONFIG_MAGIC_SYSRQ */ |
| 132 | 132 | ||
| 133 | 133 | ||
| 134 | static int ppc64_panic_event(struct notifier_block *, unsigned long, void *); | 134 | static int ppc64_panic_event(struct notifier_block *, unsigned long, void *); |
| 135 | static struct notifier_block ppc64_panic_block = { | 135 | static struct notifier_block ppc64_panic_block = { |
| 136 | .notifier_call = ppc64_panic_event, | 136 | .notifier_call = ppc64_panic_event, |
| 137 | .priority = INT_MIN /* may not return; must be done last */ | 137 | .priority = INT_MIN /* may not return; must be done last */ |
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | /* | 140 | /* |
| 141 | * Perhaps we can put the pmac screen_info[] here | 141 | * Perhaps we can put the pmac screen_info[] here |
| 142 | * on pmac as well so we don't need the ifdef's. | 142 | * on pmac as well so we don't need the ifdef's. |
| 143 | * Until we get multiple-console support in here | 143 | * Until we get multiple-console support in here |
| 144 | * that is. -- Cort | 144 | * that is. -- Cort |
| 145 | * Maybe tie it to serial consoles, since this is really what | 145 | * Maybe tie it to serial consoles, since this is really what |
| 146 | * these processors use on existing boards. -- Dan | 146 | * these processors use on existing boards. -- Dan |
| 147 | */ | 147 | */ |
| 148 | struct screen_info screen_info = { | 148 | struct screen_info screen_info = { |
| 149 | .orig_x = 0, | 149 | .orig_x = 0, |
| 150 | .orig_y = 25, | 150 | .orig_y = 25, |
| 151 | .orig_video_cols = 80, | 151 | .orig_video_cols = 80, |
| 152 | .orig_video_lines = 25, | 152 | .orig_video_lines = 25, |
| 153 | .orig_video_isVGA = 1, | 153 | .orig_video_isVGA = 1, |
| 154 | .orig_video_points = 16 | 154 | .orig_video_points = 16 |
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| 157 | /* | 157 | /* |
| 158 | * Initialize the PPCDBG state. Called before relocation has been enabled. | 158 | * Initialize the PPCDBG state. Called before relocation has been enabled. |
| 159 | */ | 159 | */ |
| 160 | void __init ppcdbg_initialize(void) | 160 | void __init ppcdbg_initialize(void) |
| 161 | { | 161 | { |
| 162 | ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */ | 162 | ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */ |
| 163 | /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; | 163 | /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | /* | 166 | /* |
| 167 | * Early boot console based on udbg | 167 | * Early boot console based on udbg |
| 168 | */ | 168 | */ |
| 169 | static struct console udbg_console = { | 169 | static struct console udbg_console = { |
| 170 | .name = "udbg", | 170 | .name = "udbg", |
| 171 | .write = udbg_console_write, | 171 | .write = udbg_console_write, |
| 172 | .flags = CON_PRINTBUFFER, | 172 | .flags = CON_PRINTBUFFER, |
| 173 | .index = -1, | 173 | .index = -1, |
| 174 | }; | 174 | }; |
| 175 | static int early_console_initialized; | 175 | static int early_console_initialized; |
| 176 | 176 | ||
| 177 | void __init disable_early_printk(void) | 177 | void __init disable_early_printk(void) |
| 178 | { | 178 | { |
| 179 | if (!early_console_initialized) | 179 | if (!early_console_initialized) |
| 180 | return; | 180 | return; |
| 181 | unregister_console(&udbg_console); | 181 | unregister_console(&udbg_console); |
| 182 | early_console_initialized = 0; | 182 | early_console_initialized = 0; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | #if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) | 185 | #if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) |
| 186 | 186 | ||
| 187 | static int smt_enabled_cmdline; | 187 | static int smt_enabled_cmdline; |
| 188 | 188 | ||
| 189 | /* Look for ibm,smt-enabled OF option */ | 189 | /* Look for ibm,smt-enabled OF option */ |
| 190 | static void check_smt_enabled(void) | 190 | static void check_smt_enabled(void) |
| 191 | { | 191 | { |
| 192 | struct device_node *dn; | 192 | struct device_node *dn; |
| 193 | char *smt_option; | 193 | char *smt_option; |
| 194 | 194 | ||
| 195 | /* Allow the command line to overrule the OF option */ | 195 | /* Allow the command line to overrule the OF option */ |
| 196 | if (smt_enabled_cmdline) | 196 | if (smt_enabled_cmdline) |
| 197 | return; | 197 | return; |
| 198 | 198 | ||
| 199 | dn = of_find_node_by_path("/options"); | 199 | dn = of_find_node_by_path("/options"); |
| 200 | 200 | ||
| 201 | if (dn) { | 201 | if (dn) { |
| 202 | smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL); | 202 | smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL); |
| 203 | 203 | ||
| 204 | if (smt_option) { | 204 | if (smt_option) { |
| 205 | if (!strcmp(smt_option, "on")) | 205 | if (!strcmp(smt_option, "on")) |
| 206 | smt_enabled_at_boot = 1; | 206 | smt_enabled_at_boot = 1; |
| 207 | else if (!strcmp(smt_option, "off")) | 207 | else if (!strcmp(smt_option, "off")) |
| 208 | smt_enabled_at_boot = 0; | 208 | smt_enabled_at_boot = 0; |
| 209 | } | 209 | } |
| 210 | } | 210 | } |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | /* Look for smt-enabled= cmdline option */ | 213 | /* Look for smt-enabled= cmdline option */ |
| 214 | static int __init early_smt_enabled(char *p) | 214 | static int __init early_smt_enabled(char *p) |
| 215 | { | 215 | { |
| 216 | smt_enabled_cmdline = 1; | 216 | smt_enabled_cmdline = 1; |
| 217 | 217 | ||
| 218 | if (!p) | 218 | if (!p) |
| 219 | return 0; | 219 | return 0; |
| 220 | 220 | ||
| 221 | if (!strcmp(p, "on") || !strcmp(p, "1")) | 221 | if (!strcmp(p, "on") || !strcmp(p, "1")) |
| 222 | smt_enabled_at_boot = 1; | 222 | smt_enabled_at_boot = 1; |
| 223 | else if (!strcmp(p, "off") || !strcmp(p, "0")) | 223 | else if (!strcmp(p, "off") || !strcmp(p, "0")) |
| 224 | smt_enabled_at_boot = 0; | 224 | smt_enabled_at_boot = 0; |
| 225 | 225 | ||
| 226 | return 0; | 226 | return 0; |
| 227 | } | 227 | } |
| 228 | early_param("smt-enabled", early_smt_enabled); | 228 | early_param("smt-enabled", early_smt_enabled); |
| 229 | 229 | ||
| 230 | /** | 230 | /** |
| 231 | * setup_cpu_maps - initialize the following cpu maps: | 231 | * setup_cpu_maps - initialize the following cpu maps: |
| 232 | * cpu_possible_map | 232 | * cpu_possible_map |
| 233 | * cpu_present_map | 233 | * cpu_present_map |
| 234 | * cpu_sibling_map | 234 | * cpu_sibling_map |
| 235 | * | 235 | * |
| 236 | * Having the possible map set up early allows us to restrict allocations | 236 | * Having the possible map set up early allows us to restrict allocations |
| 237 | * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. | 237 | * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. |
| 238 | * | 238 | * |
| 239 | * We do not initialize the online map here; cpus set their own bits in | 239 | * We do not initialize the online map here; cpus set their own bits in |
| 240 | * cpu_online_map as they come up. | 240 | * cpu_online_map as they come up. |
| 241 | * | 241 | * |
| 242 | * This function is valid only for Open Firmware systems. finish_device_tree | 242 | * This function is valid only for Open Firmware systems. finish_device_tree |
| 243 | * must be called before using this. | 243 | * must be called before using this. |
| 244 | * | 244 | * |
| 245 | * While we're here, we may as well set the "physical" cpu ids in the paca. | 245 | * While we're here, we may as well set the "physical" cpu ids in the paca. |
| 246 | */ | 246 | */ |
| 247 | static void __init setup_cpu_maps(void) | 247 | static void __init setup_cpu_maps(void) |
| 248 | { | 248 | { |
| 249 | struct device_node *dn = NULL; | 249 | struct device_node *dn = NULL; |
| 250 | int cpu = 0; | 250 | int cpu = 0; |
| 251 | int swap_cpuid = 0; | 251 | int swap_cpuid = 0; |
| 252 | 252 | ||
| 253 | check_smt_enabled(); | 253 | check_smt_enabled(); |
| 254 | 254 | ||
| 255 | while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { | 255 | while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { |
| 256 | u32 *intserv; | 256 | u32 *intserv; |
| 257 | int j, len = sizeof(u32), nthreads; | 257 | int j, len = sizeof(u32), nthreads; |
| 258 | 258 | ||
| 259 | intserv = (u32 *)get_property(dn, "ibm,ppc-interrupt-server#s", | 259 | intserv = (u32 *)get_property(dn, "ibm,ppc-interrupt-server#s", |
| 260 | &len); | 260 | &len); |
| 261 | if (!intserv) | 261 | if (!intserv) |
| 262 | intserv = (u32 *)get_property(dn, "reg", NULL); | 262 | intserv = (u32 *)get_property(dn, "reg", NULL); |
| 263 | 263 | ||
| 264 | nthreads = len / sizeof(u32); | 264 | nthreads = len / sizeof(u32); |
| 265 | 265 | ||
| 266 | for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { | 266 | for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { |
| 267 | cpu_set(cpu, cpu_present_map); | 267 | cpu_set(cpu, cpu_present_map); |
| 268 | set_hard_smp_processor_id(cpu, intserv[j]); | 268 | set_hard_smp_processor_id(cpu, intserv[j]); |
| 269 | 269 | ||
| 270 | if (intserv[j] == boot_cpuid_phys) | 270 | if (intserv[j] == boot_cpuid_phys) |
| 271 | swap_cpuid = cpu; | 271 | swap_cpuid = cpu; |
| 272 | cpu_set(cpu, cpu_possible_map); | 272 | cpu_set(cpu, cpu_possible_map); |
| 273 | cpu++; | 273 | cpu++; |
| 274 | } | 274 | } |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that | 277 | /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that |
| 278 | * boot cpu is logical 0. | 278 | * boot cpu is logical 0. |
| 279 | */ | 279 | */ |
| 280 | if (boot_cpuid_phys != get_hard_smp_processor_id(0)) { | 280 | if (boot_cpuid_phys != get_hard_smp_processor_id(0)) { |
| 281 | u32 tmp; | 281 | u32 tmp; |
| 282 | tmp = get_hard_smp_processor_id(0); | 282 | tmp = get_hard_smp_processor_id(0); |
| 283 | set_hard_smp_processor_id(0, boot_cpuid_phys); | 283 | set_hard_smp_processor_id(0, boot_cpuid_phys); |
| 284 | set_hard_smp_processor_id(swap_cpuid, tmp); | 284 | set_hard_smp_processor_id(swap_cpuid, tmp); |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | /* | 287 | /* |
| 288 | * On pSeries LPAR, we need to know how many cpus | 288 | * On pSeries LPAR, we need to know how many cpus |
| 289 | * could possibly be added to this partition. | 289 | * could possibly be added to this partition. |
| 290 | */ | 290 | */ |
| 291 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR && | 291 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR && |
| 292 | (dn = of_find_node_by_path("/rtas"))) { | 292 | (dn = of_find_node_by_path("/rtas"))) { |
| 293 | int num_addr_cell, num_size_cell, maxcpus; | 293 | int num_addr_cell, num_size_cell, maxcpus; |
| 294 | unsigned int *ireg; | 294 | unsigned int *ireg; |
| 295 | 295 | ||
| 296 | num_addr_cell = prom_n_addr_cells(dn); | 296 | num_addr_cell = prom_n_addr_cells(dn); |
| 297 | num_size_cell = prom_n_size_cells(dn); | 297 | num_size_cell = prom_n_size_cells(dn); |
| 298 | 298 | ||
| 299 | ireg = (unsigned int *) | 299 | ireg = (unsigned int *) |
| 300 | get_property(dn, "ibm,lrdr-capacity", NULL); | 300 | get_property(dn, "ibm,lrdr-capacity", NULL); |
| 301 | 301 | ||
| 302 | if (!ireg) | 302 | if (!ireg) |
| 303 | goto out; | 303 | goto out; |
| 304 | 304 | ||
| 305 | maxcpus = ireg[num_addr_cell + num_size_cell]; | 305 | maxcpus = ireg[num_addr_cell + num_size_cell]; |
| 306 | 306 | ||
| 307 | /* Double maxcpus for processors which have SMT capability */ | 307 | /* Double maxcpus for processors which have SMT capability */ |
| 308 | if (cpu_has_feature(CPU_FTR_SMT)) | 308 | if (cpu_has_feature(CPU_FTR_SMT)) |
| 309 | maxcpus *= 2; | 309 | maxcpus *= 2; |
| 310 | 310 | ||
| 311 | if (maxcpus > NR_CPUS) { | 311 | if (maxcpus > NR_CPUS) { |
| 312 | printk(KERN_WARNING | 312 | printk(KERN_WARNING |
| 313 | "Partition configured for %d cpus, " | 313 | "Partition configured for %d cpus, " |
| 314 | "operating system maximum is %d.\n", | 314 | "operating system maximum is %d.\n", |
| 315 | maxcpus, NR_CPUS); | 315 | maxcpus, NR_CPUS); |
| 316 | maxcpus = NR_CPUS; | 316 | maxcpus = NR_CPUS; |
| 317 | } else | 317 | } else |
| 318 | printk(KERN_INFO "Partition configured for %d cpus.\n", | 318 | printk(KERN_INFO "Partition configured for %d cpus.\n", |
| 319 | maxcpus); | 319 | maxcpus); |
| 320 | 320 | ||
| 321 | for (cpu = 0; cpu < maxcpus; cpu++) | 321 | for (cpu = 0; cpu < maxcpus; cpu++) |
| 322 | cpu_set(cpu, cpu_possible_map); | 322 | cpu_set(cpu, cpu_possible_map); |
| 323 | out: | 323 | out: |
| 324 | of_node_put(dn); | 324 | of_node_put(dn); |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | /* | 327 | /* |
| 328 | * Do the sibling map; assume only two threads per processor. | 328 | * Do the sibling map; assume only two threads per processor. |
| 329 | */ | 329 | */ |
| 330 | for_each_cpu(cpu) { | 330 | for_each_cpu(cpu) { |
| 331 | cpu_set(cpu, cpu_sibling_map[cpu]); | 331 | cpu_set(cpu, cpu_sibling_map[cpu]); |
| 332 | if (cpu_has_feature(CPU_FTR_SMT)) | 332 | if (cpu_has_feature(CPU_FTR_SMT)) |
| 333 | cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); | 333 | cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | systemcfg->processorCount = num_present_cpus(); | 336 | systemcfg->processorCount = num_present_cpus(); |
| 337 | } | 337 | } |
| 338 | #endif /* defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) */ | 338 | #endif /* defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) */ |
| 339 | 339 | ||
| 340 | 340 | ||
| 341 | #ifdef CONFIG_PPC_MULTIPLATFORM | 341 | #ifdef CONFIG_PPC_MULTIPLATFORM |
| 342 | 342 | ||
| 343 | extern struct machdep_calls pSeries_md; | 343 | extern struct machdep_calls pSeries_md; |
| 344 | extern struct machdep_calls pmac_md; | 344 | extern struct machdep_calls pmac_md; |
| 345 | extern struct machdep_calls maple_md; | 345 | extern struct machdep_calls maple_md; |
| 346 | extern struct machdep_calls bpa_md; | 346 | extern struct machdep_calls bpa_md; |
| 347 | 347 | ||
| 348 | /* Ultimately, stuff them in an elf section like initcalls... */ | 348 | /* Ultimately, stuff them in an elf section like initcalls... */ |
| 349 | static struct machdep_calls __initdata *machines[] = { | 349 | static struct machdep_calls __initdata *machines[] = { |
| 350 | #ifdef CONFIG_PPC_PSERIES | 350 | #ifdef CONFIG_PPC_PSERIES |
| 351 | &pSeries_md, | 351 | &pSeries_md, |
| 352 | #endif /* CONFIG_PPC_PSERIES */ | 352 | #endif /* CONFIG_PPC_PSERIES */ |
| 353 | #ifdef CONFIG_PPC_PMAC | 353 | #ifdef CONFIG_PPC_PMAC |
| 354 | &pmac_md, | 354 | &pmac_md, |
| 355 | #endif /* CONFIG_PPC_PMAC */ | 355 | #endif /* CONFIG_PPC_PMAC */ |
| 356 | #ifdef CONFIG_PPC_MAPLE | 356 | #ifdef CONFIG_PPC_MAPLE |
| 357 | &maple_md, | 357 | &maple_md, |
| 358 | #endif /* CONFIG_PPC_MAPLE */ | 358 | #endif /* CONFIG_PPC_MAPLE */ |
| 359 | #ifdef CONFIG_PPC_BPA | 359 | #ifdef CONFIG_PPC_BPA |
| 360 | &bpa_md, | 360 | &bpa_md, |
| 361 | #endif | 361 | #endif |
| 362 | NULL | 362 | NULL |
| 363 | }; | 363 | }; |
| 364 | 364 | ||
| 365 | /* | 365 | /* |
| 366 | * Early initialization entry point. This is called by head.S | 366 | * Early initialization entry point. This is called by head.S |
| 367 | * with MMU translation disabled. We rely on the "feature" of | 367 | * with MMU translation disabled. We rely on the "feature" of |
| 368 | * the CPU that ignores the top 2 bits of the address in real | 368 | * the CPU that ignores the top 2 bits of the address in real |
| 369 | * mode so we can access kernel globals normally provided we | 369 | * mode so we can access kernel globals normally provided we |
| 370 | * only toy with things in the RMO region. From here, we do | 370 | * only toy with things in the RMO region. From here, we do |
| 371 | * some early parsing of the device-tree to setup out LMB | 371 | * some early parsing of the device-tree to setup out LMB |
| 372 | * data structures, and allocate & initialize the hash table | 372 | * data structures, and allocate & initialize the hash table |
| 373 | * and segment tables so we can start running with translation | 373 | * and segment tables so we can start running with translation |
| 374 | * enabled. | 374 | * enabled. |
| 375 | * | 375 | * |
| 376 | * It is this function which will call the probe() callback of | 376 | * It is this function which will call the probe() callback of |
| 377 | * the various platform types and copy the matching one to the | 377 | * the various platform types and copy the matching one to the |
| 378 | * global ppc_md structure. Your platform can eventually do | 378 | * global ppc_md structure. Your platform can eventually do |
| 379 | * some very early initializations from the probe() routine, but | 379 | * some very early initializations from the probe() routine, but |
| 380 | * this is not recommended, be very careful as, for example, the | 380 | * this is not recommended, be very careful as, for example, the |
| 381 | * device-tree is not accessible via normal means at this point. | 381 | * device-tree is not accessible via normal means at this point. |
| 382 | */ | 382 | */ |
| 383 | 383 | ||
| 384 | void __init early_setup(unsigned long dt_ptr) | 384 | void __init early_setup(unsigned long dt_ptr) |
| 385 | { | 385 | { |
| 386 | struct paca_struct *lpaca = get_paca(); | 386 | struct paca_struct *lpaca = get_paca(); |
| 387 | static struct machdep_calls **mach; | 387 | static struct machdep_calls **mach; |
| 388 | 388 | ||
| 389 | /* | 389 | /* |
| 390 | * Enable early debugging if any specified (see top of | 390 | * Enable early debugging if any specified (see top of |
| 391 | * this file) | 391 | * this file) |
| 392 | */ | 392 | */ |
| 393 | EARLY_DEBUG_INIT(); | 393 | EARLY_DEBUG_INIT(); |
| 394 | 394 | ||
| 395 | DBG(" -> early_setup()\n"); | 395 | DBG(" -> early_setup()\n"); |
| 396 | 396 | ||
| 397 | /* | 397 | /* |
| 398 | * Fill the default DBG level (do we want to keep | 398 | * Fill the default DBG level (do we want to keep |
| 399 | * that old mecanism around forever ?) | 399 | * that old mecanism around forever ?) |
| 400 | */ | 400 | */ |
| 401 | ppcdbg_initialize(); | 401 | ppcdbg_initialize(); |
| 402 | 402 | ||
| 403 | /* | 403 | /* |
| 404 | * Do early initializations using the flattened device | 404 | * Do early initializations using the flattened device |
| 405 | * tree, like retreiving the physical memory map or | 405 | * tree, like retreiving the physical memory map or |
| 406 | * calculating/retreiving the hash table size | 406 | * calculating/retreiving the hash table size |
| 407 | */ | 407 | */ |
| 408 | early_init_devtree(__va(dt_ptr)); | 408 | early_init_devtree(__va(dt_ptr)); |
| 409 | 409 | ||
| 410 | /* | 410 | /* |
| 411 | * Iterate all ppc_md structures until we find the proper | 411 | * Iterate all ppc_md structures until we find the proper |
| 412 | * one for the current machine type | 412 | * one for the current machine type |
| 413 | */ | 413 | */ |
| 414 | DBG("Probing machine type for platform %x...\n", | 414 | DBG("Probing machine type for platform %x...\n", |
| 415 | systemcfg->platform); | 415 | systemcfg->platform); |
| 416 | 416 | ||
| 417 | for (mach = machines; *mach; mach++) { | 417 | for (mach = machines; *mach; mach++) { |
| 418 | if ((*mach)->probe(systemcfg->platform)) | 418 | if ((*mach)->probe(systemcfg->platform)) |
| 419 | break; | 419 | break; |
| 420 | } | 420 | } |
| 421 | /* What can we do if we didn't find ? */ | 421 | /* What can we do if we didn't find ? */ |
| 422 | if (*mach == NULL) { | 422 | if (*mach == NULL) { |
| 423 | DBG("No suitable machine found !\n"); | 423 | DBG("No suitable machine found !\n"); |
| 424 | for (;;); | 424 | for (;;); |
| 425 | } | 425 | } |
| 426 | ppc_md = **mach; | 426 | ppc_md = **mach; |
| 427 | |||
| 428 | /* our udbg callbacks got overriden by the above, let's put them | ||
| 429 | * back in. Ultimately, I want those things to be split from the | ||
| 430 | * main ppc_md | ||
| 431 | */ | ||
| 432 | EARLY_DEBUG_INIT(); | ||
| 433 | 427 | ||
| 434 | DBG("Found, Initializing memory management...\n"); | 428 | DBG("Found, Initializing memory management...\n"); |
| 435 | 429 | ||
| 436 | /* | 430 | /* |
| 437 | * Initialize stab / SLB management | 431 | * Initialize stab / SLB management |
| 438 | */ | 432 | */ |
| 439 | stab_initialize(lpaca->stab_real); | 433 | stab_initialize(lpaca->stab_real); |
| 440 | 434 | ||
| 441 | /* | 435 | /* |
| 442 | * Initialize the MMU Hash table and create the linear mapping | 436 | * Initialize the MMU Hash table and create the linear mapping |
| 443 | * of memory | 437 | * of memory |
| 444 | */ | 438 | */ |
| 445 | htab_initialize(); | 439 | htab_initialize(); |
| 446 | 440 | ||
| 447 | DBG(" <- early_setup()\n"); | 441 | DBG(" <- early_setup()\n"); |
| 448 | } | 442 | } |
| 449 | 443 | ||
| 450 | 444 | ||
| 451 | /* | 445 | /* |
| 452 | * Initialize some remaining members of the ppc64_caches and systemcfg structures | 446 | * Initialize some remaining members of the ppc64_caches and systemcfg structures |
| 453 | * (at least until we get rid of them completely). This is mostly some | 447 | * (at least until we get rid of them completely). This is mostly some |
| 454 | * cache informations about the CPU that will be used by cache flush | 448 | * cache informations about the CPU that will be used by cache flush |
| 455 | * routines and/or provided to userland | 449 | * routines and/or provided to userland |
| 456 | */ | 450 | */ |
| 457 | static void __init initialize_cache_info(void) | 451 | static void __init initialize_cache_info(void) |
| 458 | { | 452 | { |
| 459 | struct device_node *np; | 453 | struct device_node *np; |
| 460 | unsigned long num_cpus = 0; | 454 | unsigned long num_cpus = 0; |
| 461 | 455 | ||
| 462 | DBG(" -> initialize_cache_info()\n"); | 456 | DBG(" -> initialize_cache_info()\n"); |
| 463 | 457 | ||
| 464 | for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { | 458 | for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { |
| 465 | num_cpus += 1; | 459 | num_cpus += 1; |
| 466 | 460 | ||
| 467 | /* We're assuming *all* of the CPUs have the same | 461 | /* We're assuming *all* of the CPUs have the same |
| 468 | * d-cache and i-cache sizes... -Peter | 462 | * d-cache and i-cache sizes... -Peter |
| 469 | */ | 463 | */ |
| 470 | 464 | ||
| 471 | if ( num_cpus == 1 ) { | 465 | if ( num_cpus == 1 ) { |
| 472 | u32 *sizep, *lsizep; | 466 | u32 *sizep, *lsizep; |
| 473 | u32 size, lsize; | 467 | u32 size, lsize; |
| 474 | const char *dc, *ic; | 468 | const char *dc, *ic; |
| 475 | 469 | ||
| 476 | /* Then read cache informations */ | 470 | /* Then read cache informations */ |
| 477 | if (systemcfg->platform == PLATFORM_POWERMAC) { | 471 | if (systemcfg->platform == PLATFORM_POWERMAC) { |
| 478 | dc = "d-cache-block-size"; | 472 | dc = "d-cache-block-size"; |
| 479 | ic = "i-cache-block-size"; | 473 | ic = "i-cache-block-size"; |
| 480 | } else { | 474 | } else { |
| 481 | dc = "d-cache-line-size"; | 475 | dc = "d-cache-line-size"; |
| 482 | ic = "i-cache-line-size"; | 476 | ic = "i-cache-line-size"; |
| 483 | } | 477 | } |
| 484 | 478 | ||
| 485 | size = 0; | 479 | size = 0; |
| 486 | lsize = cur_cpu_spec->dcache_bsize; | 480 | lsize = cur_cpu_spec->dcache_bsize; |
| 487 | sizep = (u32 *)get_property(np, "d-cache-size", NULL); | 481 | sizep = (u32 *)get_property(np, "d-cache-size", NULL); |
| 488 | if (sizep != NULL) | 482 | if (sizep != NULL) |
| 489 | size = *sizep; | 483 | size = *sizep; |
| 490 | lsizep = (u32 *) get_property(np, dc, NULL); | 484 | lsizep = (u32 *) get_property(np, dc, NULL); |
| 491 | if (lsizep != NULL) | 485 | if (lsizep != NULL) |
| 492 | lsize = *lsizep; | 486 | lsize = *lsizep; |
| 493 | if (sizep == 0 || lsizep == 0) | 487 | if (sizep == 0 || lsizep == 0) |
| 494 | DBG("Argh, can't find dcache properties ! " | 488 | DBG("Argh, can't find dcache properties ! " |
| 495 | "sizep: %p, lsizep: %p\n", sizep, lsizep); | 489 | "sizep: %p, lsizep: %p\n", sizep, lsizep); |
| 496 | 490 | ||
| 497 | systemcfg->dcache_size = ppc64_caches.dsize = size; | 491 | systemcfg->dcache_size = ppc64_caches.dsize = size; |
| 498 | systemcfg->dcache_line_size = | 492 | systemcfg->dcache_line_size = |
| 499 | ppc64_caches.dline_size = lsize; | 493 | ppc64_caches.dline_size = lsize; |
| 500 | ppc64_caches.log_dline_size = __ilog2(lsize); | 494 | ppc64_caches.log_dline_size = __ilog2(lsize); |
| 501 | ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; | 495 | ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; |
| 502 | 496 | ||
| 503 | size = 0; | 497 | size = 0; |
| 504 | lsize = cur_cpu_spec->icache_bsize; | 498 | lsize = cur_cpu_spec->icache_bsize; |
| 505 | sizep = (u32 *)get_property(np, "i-cache-size", NULL); | 499 | sizep = (u32 *)get_property(np, "i-cache-size", NULL); |
| 506 | if (sizep != NULL) | 500 | if (sizep != NULL) |
| 507 | size = *sizep; | 501 | size = *sizep; |
| 508 | lsizep = (u32 *)get_property(np, ic, NULL); | 502 | lsizep = (u32 *)get_property(np, ic, NULL); |
| 509 | if (lsizep != NULL) | 503 | if (lsizep != NULL) |
| 510 | lsize = *lsizep; | 504 | lsize = *lsizep; |
| 511 | if (sizep == 0 || lsizep == 0) | 505 | if (sizep == 0 || lsizep == 0) |
| 512 | DBG("Argh, can't find icache properties ! " | 506 | DBG("Argh, can't find icache properties ! " |
| 513 | "sizep: %p, lsizep: %p\n", sizep, lsizep); | 507 | "sizep: %p, lsizep: %p\n", sizep, lsizep); |
| 514 | 508 | ||
| 515 | systemcfg->icache_size = ppc64_caches.isize = size; | 509 | systemcfg->icache_size = ppc64_caches.isize = size; |
| 516 | systemcfg->icache_line_size = | 510 | systemcfg->icache_line_size = |
| 517 | ppc64_caches.iline_size = lsize; | 511 | ppc64_caches.iline_size = lsize; |
| 518 | ppc64_caches.log_iline_size = __ilog2(lsize); | 512 | ppc64_caches.log_iline_size = __ilog2(lsize); |
| 519 | ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; | 513 | ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; |
| 520 | } | 514 | } |
| 521 | } | 515 | } |
| 522 | 516 | ||
| 523 | /* Add an eye catcher and the systemcfg layout version number */ | 517 | /* Add an eye catcher and the systemcfg layout version number */ |
| 524 | strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); | 518 | strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); |
| 525 | systemcfg->version.major = SYSTEMCFG_MAJOR; | 519 | systemcfg->version.major = SYSTEMCFG_MAJOR; |
| 526 | systemcfg->version.minor = SYSTEMCFG_MINOR; | 520 | systemcfg->version.minor = SYSTEMCFG_MINOR; |
| 527 | systemcfg->processor = mfspr(SPRN_PVR); | 521 | systemcfg->processor = mfspr(SPRN_PVR); |
| 528 | 522 | ||
| 529 | DBG(" <- initialize_cache_info()\n"); | 523 | DBG(" <- initialize_cache_info()\n"); |
| 530 | } | 524 | } |
| 531 | 525 | ||
| 532 | static void __init check_for_initrd(void) | 526 | static void __init check_for_initrd(void) |
| 533 | { | 527 | { |
| 534 | #ifdef CONFIG_BLK_DEV_INITRD | 528 | #ifdef CONFIG_BLK_DEV_INITRD |
| 535 | u64 *prop; | 529 | u64 *prop; |
| 536 | 530 | ||
| 537 | DBG(" -> check_for_initrd()\n"); | 531 | DBG(" -> check_for_initrd()\n"); |
| 538 | 532 | ||
| 539 | if (of_chosen) { | 533 | if (of_chosen) { |
| 540 | prop = (u64 *)get_property(of_chosen, | 534 | prop = (u64 *)get_property(of_chosen, |
| 541 | "linux,initrd-start", NULL); | 535 | "linux,initrd-start", NULL); |
| 542 | if (prop != NULL) { | 536 | if (prop != NULL) { |
| 543 | initrd_start = (unsigned long)__va(*prop); | 537 | initrd_start = (unsigned long)__va(*prop); |
| 544 | prop = (u64 *)get_property(of_chosen, | 538 | prop = (u64 *)get_property(of_chosen, |
| 545 | "linux,initrd-end", NULL); | 539 | "linux,initrd-end", NULL); |
| 546 | if (prop != NULL) { | 540 | if (prop != NULL) { |
| 547 | initrd_end = (unsigned long)__va(*prop); | 541 | initrd_end = (unsigned long)__va(*prop); |
| 548 | initrd_below_start_ok = 1; | 542 | initrd_below_start_ok = 1; |
| 549 | } else | 543 | } else |
| 550 | initrd_start = 0; | 544 | initrd_start = 0; |
| 551 | } | 545 | } |
| 552 | } | 546 | } |
| 553 | 547 | ||
| 554 | /* If we were passed an initrd, set the ROOT_DEV properly if the values | 548 | /* If we were passed an initrd, set the ROOT_DEV properly if the values |
| 555 | * look sensible. If not, clear initrd reference. | 549 | * look sensible. If not, clear initrd reference. |
| 556 | */ | 550 | */ |
| 557 | if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && | 551 | if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && |
| 558 | initrd_end > initrd_start) | 552 | initrd_end > initrd_start) |
| 559 | ROOT_DEV = Root_RAM0; | 553 | ROOT_DEV = Root_RAM0; |
| 560 | else | 554 | else |
| 561 | initrd_start = initrd_end = 0; | 555 | initrd_start = initrd_end = 0; |
| 562 | 556 | ||
| 563 | if (initrd_start) | 557 | if (initrd_start) |
| 564 | printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); | 558 | printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); |
| 565 | 559 | ||
| 566 | DBG(" <- check_for_initrd()\n"); | 560 | DBG(" <- check_for_initrd()\n"); |
| 567 | #endif /* CONFIG_BLK_DEV_INITRD */ | 561 | #endif /* CONFIG_BLK_DEV_INITRD */ |
| 568 | } | 562 | } |
| 569 | 563 | ||
| 570 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 564 | #endif /* CONFIG_PPC_MULTIPLATFORM */ |
| 571 | 565 | ||
| 572 | /* | 566 | /* |
| 573 | * Do some initial setup of the system. The parameters are those which | 567 | * Do some initial setup of the system. The parameters are those which |
| 574 | * were passed in from the bootloader. | 568 | * were passed in from the bootloader. |
| 575 | */ | 569 | */ |
| 576 | void __init setup_system(void) | 570 | void __init setup_system(void) |
| 577 | { | 571 | { |
| 578 | DBG(" -> setup_system()\n"); | 572 | DBG(" -> setup_system()\n"); |
| 579 | 573 | ||
| 580 | #ifdef CONFIG_PPC_ISERIES | 574 | #ifdef CONFIG_PPC_ISERIES |
| 581 | /* pSeries systems are identified in prom.c via OF. */ | 575 | /* pSeries systems are identified in prom.c via OF. */ |
| 582 | if (itLpNaca.xLparInstalled == 1) | 576 | if (itLpNaca.xLparInstalled == 1) |
| 583 | systemcfg->platform = PLATFORM_ISERIES_LPAR; | 577 | systemcfg->platform = PLATFORM_ISERIES_LPAR; |
| 584 | 578 | ||
| 585 | ppc_md.init_early(); | 579 | ppc_md.init_early(); |
| 586 | #else /* CONFIG_PPC_ISERIES */ | 580 | #else /* CONFIG_PPC_ISERIES */ |
| 587 | 581 | ||
| 588 | /* | 582 | /* |
| 589 | * Unflatten the device-tree passed by prom_init or kexec | 583 | * Unflatten the device-tree passed by prom_init or kexec |
| 590 | */ | 584 | */ |
| 591 | unflatten_device_tree(); | 585 | unflatten_device_tree(); |
| 592 | 586 | ||
| 593 | /* | 587 | /* |
| 594 | * Fill the ppc64_caches & systemcfg structures with informations | 588 | * Fill the ppc64_caches & systemcfg structures with informations |
| 595 | * retreived from the device-tree. Need to be called before | 589 | * retreived from the device-tree. Need to be called before |
| 596 | * finish_device_tree() since the later requires some of the | 590 | * finish_device_tree() since the later requires some of the |
| 597 | * informations filled up here to properly parse the interrupt | 591 | * informations filled up here to properly parse the interrupt |
| 598 | * tree. | 592 | * tree. |
| 599 | * It also sets up the cache line sizes which allows to call | 593 | * It also sets up the cache line sizes which allows to call |
| 600 | * routines like flush_icache_range (used by the hash init | 594 | * routines like flush_icache_range (used by the hash init |
| 601 | * later on). | 595 | * later on). |
| 602 | */ | 596 | */ |
| 603 | initialize_cache_info(); | 597 | initialize_cache_info(); |
| 604 | 598 | ||
| 605 | #ifdef CONFIG_PPC_RTAS | 599 | #ifdef CONFIG_PPC_RTAS |
| 606 | /* | 600 | /* |
| 607 | * Initialize RTAS if available | 601 | * Initialize RTAS if available |
| 608 | */ | 602 | */ |
| 609 | rtas_initialize(); | 603 | rtas_initialize(); |
| 610 | #endif /* CONFIG_PPC_RTAS */ | 604 | #endif /* CONFIG_PPC_RTAS */ |
| 611 | 605 | ||
| 612 | /* | 606 | /* |
| 613 | * Check if we have an initrd provided via the device-tree | 607 | * Check if we have an initrd provided via the device-tree |
| 614 | */ | 608 | */ |
| 615 | check_for_initrd(); | 609 | check_for_initrd(); |
| 616 | 610 | ||
| 617 | /* | 611 | /* |
| 618 | * Do some platform specific early initializations, that includes | 612 | * Do some platform specific early initializations, that includes |
| 619 | * setting up the hash table pointers. It also sets up some interrupt-mapping | 613 | * setting up the hash table pointers. It also sets up some interrupt-mapping |
| 620 | * related options that will be used by finish_device_tree() | 614 | * related options that will be used by finish_device_tree() |
| 621 | */ | 615 | */ |
| 622 | ppc_md.init_early(); | 616 | ppc_md.init_early(); |
| 623 | 617 | ||
| 624 | /* | 618 | /* |
| 625 | * "Finish" the device-tree, that is do the actual parsing of | 619 | * "Finish" the device-tree, that is do the actual parsing of |
| 626 | * some of the properties like the interrupt map | 620 | * some of the properties like the interrupt map |
| 627 | */ | 621 | */ |
| 628 | finish_device_tree(); | 622 | finish_device_tree(); |
| 629 | 623 | ||
| 630 | /* | 624 | /* |
| 631 | * Initialize xmon | 625 | * Initialize xmon |
| 632 | */ | 626 | */ |
| 633 | #ifdef CONFIG_XMON_DEFAULT | 627 | #ifdef CONFIG_XMON_DEFAULT |
| 634 | xmon_init(1); | 628 | xmon_init(1); |
| 635 | #endif | 629 | #endif |
| 636 | /* | 630 | /* |
| 637 | * Register early console | 631 | * Register early console |
| 638 | */ | 632 | */ |
| 639 | early_console_initialized = 1; | 633 | early_console_initialized = 1; |
| 640 | register_console(&udbg_console); | 634 | register_console(&udbg_console); |
| 641 | 635 | ||
| 642 | /* Save unparsed command line copy for /proc/cmdline */ | 636 | /* Save unparsed command line copy for /proc/cmdline */ |
| 643 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); | 637 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); |
| 644 | 638 | ||
| 645 | parse_early_param(); | 639 | parse_early_param(); |
| 646 | #endif /* !CONFIG_PPC_ISERIES */ | 640 | #endif /* !CONFIG_PPC_ISERIES */ |
| 647 | 641 | ||
| 648 | #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) | 642 | #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) |
| 649 | /* | 643 | /* |
| 650 | * iSeries has already initialized the cpu maps at this point. | 644 | * iSeries has already initialized the cpu maps at this point. |
| 651 | */ | 645 | */ |
| 652 | setup_cpu_maps(); | 646 | setup_cpu_maps(); |
| 653 | 647 | ||
| 654 | /* Release secondary cpus out of their spinloops at 0x60 now that | 648 | /* Release secondary cpus out of their spinloops at 0x60 now that |
| 655 | * we can map physical -> logical CPU ids | 649 | * we can map physical -> logical CPU ids |
| 656 | */ | 650 | */ |
| 657 | smp_release_cpus(); | 651 | smp_release_cpus(); |
| 658 | #endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */ | 652 | #endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */ |
| 659 | 653 | ||
| 660 | printk("Starting Linux PPC64 %s\n", UTS_RELEASE); | 654 | printk("Starting Linux PPC64 %s\n", UTS_RELEASE); |
| 661 | 655 | ||
| 662 | printk("-----------------------------------------------------\n"); | 656 | printk("-----------------------------------------------------\n"); |
| 663 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); | 657 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); |
| 664 | printk("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch); | 658 | printk("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch); |
| 665 | printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); | 659 | printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); |
| 666 | printk("systemcfg = 0x%p\n", systemcfg); | 660 | printk("systemcfg = 0x%p\n", systemcfg); |
| 667 | printk("systemcfg->platform = 0x%x\n", systemcfg->platform); | 661 | printk("systemcfg->platform = 0x%x\n", systemcfg->platform); |
| 668 | printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); | 662 | printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); |
| 669 | printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); | 663 | printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); |
| 670 | printk("ppc64_caches.dcache_line_size = 0x%x\n", | 664 | printk("ppc64_caches.dcache_line_size = 0x%x\n", |
| 671 | ppc64_caches.dline_size); | 665 | ppc64_caches.dline_size); |
| 672 | printk("ppc64_caches.icache_line_size = 0x%x\n", | 666 | printk("ppc64_caches.icache_line_size = 0x%x\n", |
| 673 | ppc64_caches.iline_size); | 667 | ppc64_caches.iline_size); |
| 674 | printk("htab_address = 0x%p\n", htab_address); | 668 | printk("htab_address = 0x%p\n", htab_address); |
| 675 | printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); | 669 | printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); |
| 676 | printk("-----------------------------------------------------\n"); | 670 | printk("-----------------------------------------------------\n"); |
| 677 | 671 | ||
| 678 | mm_init_ppc64(); | 672 | mm_init_ppc64(); |
| 679 | 673 | ||
| 680 | DBG(" <- setup_system()\n"); | 674 | DBG(" <- setup_system()\n"); |
| 681 | } | 675 | } |
| 682 | 676 | ||
| 683 | /* also used by kexec */ | 677 | /* also used by kexec */ |
| 684 | void machine_shutdown(void) | 678 | void machine_shutdown(void) |
| 685 | { | 679 | { |
| 686 | if (ppc_md.nvram_sync) | 680 | if (ppc_md.nvram_sync) |
| 687 | ppc_md.nvram_sync(); | 681 | ppc_md.nvram_sync(); |
| 688 | } | 682 | } |
| 689 | 683 | ||
| 690 | void machine_restart(char *cmd) | 684 | void machine_restart(char *cmd) |
| 691 | { | 685 | { |
| 692 | machine_shutdown(); | 686 | machine_shutdown(); |
| 693 | ppc_md.restart(cmd); | 687 | ppc_md.restart(cmd); |
| 694 | #ifdef CONFIG_SMP | 688 | #ifdef CONFIG_SMP |
| 695 | smp_send_stop(); | 689 | smp_send_stop(); |
| 696 | #endif | 690 | #endif |
| 697 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | 691 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); |
| 698 | local_irq_disable(); | 692 | local_irq_disable(); |
| 699 | while (1) ; | 693 | while (1) ; |
| 700 | } | 694 | } |
| 701 | 695 | ||
| 702 | void machine_power_off(void) | 696 | void machine_power_off(void) |
| 703 | { | 697 | { |
| 704 | machine_shutdown(); | 698 | machine_shutdown(); |
| 705 | ppc_md.power_off(); | 699 | ppc_md.power_off(); |
| 706 | #ifdef CONFIG_SMP | 700 | #ifdef CONFIG_SMP |
| 707 | smp_send_stop(); | 701 | smp_send_stop(); |
| 708 | #endif | 702 | #endif |
| 709 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | 703 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); |
| 710 | local_irq_disable(); | 704 | local_irq_disable(); |
| 711 | while (1) ; | 705 | while (1) ; |
| 712 | } | 706 | } |
| 713 | /* Used by the G5 thermal driver */ | 707 | /* Used by the G5 thermal driver */ |
| 714 | EXPORT_SYMBOL_GPL(machine_power_off); | 708 | EXPORT_SYMBOL_GPL(machine_power_off); |
| 715 | 709 | ||
| 716 | void machine_halt(void) | 710 | void machine_halt(void) |
| 717 | { | 711 | { |
| 718 | machine_shutdown(); | 712 | machine_shutdown(); |
| 719 | ppc_md.halt(); | 713 | ppc_md.halt(); |
| 720 | #ifdef CONFIG_SMP | 714 | #ifdef CONFIG_SMP |
| 721 | smp_send_stop(); | 715 | smp_send_stop(); |
| 722 | #endif | 716 | #endif |
| 723 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | 717 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); |
| 724 | local_irq_disable(); | 718 | local_irq_disable(); |
| 725 | while (1) ; | 719 | while (1) ; |
| 726 | } | 720 | } |
| 727 | 721 | ||
| 728 | static int ppc64_panic_event(struct notifier_block *this, | 722 | static int ppc64_panic_event(struct notifier_block *this, |
| 729 | unsigned long event, void *ptr) | 723 | unsigned long event, void *ptr) |
| 730 | { | 724 | { |
| 731 | ppc_md.panic((char *)ptr); /* May not return */ | 725 | ppc_md.panic((char *)ptr); /* May not return */ |
| 732 | return NOTIFY_DONE; | 726 | return NOTIFY_DONE; |
| 733 | } | 727 | } |
| 734 | 728 | ||
| 735 | 729 | ||
| 736 | #ifdef CONFIG_SMP | 730 | #ifdef CONFIG_SMP |
| 737 | DEFINE_PER_CPU(unsigned int, pvr); | 731 | DEFINE_PER_CPU(unsigned int, pvr); |
| 738 | #endif | 732 | #endif |
| 739 | 733 | ||
| 740 | static int show_cpuinfo(struct seq_file *m, void *v) | 734 | static int show_cpuinfo(struct seq_file *m, void *v) |
| 741 | { | 735 | { |
| 742 | unsigned long cpu_id = (unsigned long)v - 1; | 736 | unsigned long cpu_id = (unsigned long)v - 1; |
| 743 | unsigned int pvr; | 737 | unsigned int pvr; |
| 744 | unsigned short maj; | 738 | unsigned short maj; |
| 745 | unsigned short min; | 739 | unsigned short min; |
| 746 | 740 | ||
| 747 | if (cpu_id == NR_CPUS) { | 741 | if (cpu_id == NR_CPUS) { |
| 748 | seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); | 742 | seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); |
| 749 | 743 | ||
| 750 | if (ppc_md.get_cpuinfo != NULL) | 744 | if (ppc_md.get_cpuinfo != NULL) |
| 751 | ppc_md.get_cpuinfo(m); | 745 | ppc_md.get_cpuinfo(m); |
| 752 | 746 | ||
| 753 | return 0; | 747 | return 0; |
| 754 | } | 748 | } |
| 755 | 749 | ||
| 756 | /* We only show online cpus: disable preempt (overzealous, I | 750 | /* We only show online cpus: disable preempt (overzealous, I |
| 757 | * knew) to prevent cpu going down. */ | 751 | * knew) to prevent cpu going down. */ |
| 758 | preempt_disable(); | 752 | preempt_disable(); |
| 759 | if (!cpu_online(cpu_id)) { | 753 | if (!cpu_online(cpu_id)) { |
| 760 | preempt_enable(); | 754 | preempt_enable(); |
| 761 | return 0; | 755 | return 0; |
| 762 | } | 756 | } |
| 763 | 757 | ||
| 764 | #ifdef CONFIG_SMP | 758 | #ifdef CONFIG_SMP |
| 765 | pvr = per_cpu(pvr, cpu_id); | 759 | pvr = per_cpu(pvr, cpu_id); |
| 766 | #else | 760 | #else |
| 767 | pvr = mfspr(SPRN_PVR); | 761 | pvr = mfspr(SPRN_PVR); |
| 768 | #endif | 762 | #endif |
| 769 | maj = (pvr >> 8) & 0xFF; | 763 | maj = (pvr >> 8) & 0xFF; |
| 770 | min = pvr & 0xFF; | 764 | min = pvr & 0xFF; |
| 771 | 765 | ||
| 772 | seq_printf(m, "processor\t: %lu\n", cpu_id); | 766 | seq_printf(m, "processor\t: %lu\n", cpu_id); |
| 773 | seq_printf(m, "cpu\t\t: "); | 767 | seq_printf(m, "cpu\t\t: "); |
| 774 | 768 | ||
| 775 | if (cur_cpu_spec->pvr_mask) | 769 | if (cur_cpu_spec->pvr_mask) |
| 776 | seq_printf(m, "%s", cur_cpu_spec->cpu_name); | 770 | seq_printf(m, "%s", cur_cpu_spec->cpu_name); |
| 777 | else | 771 | else |
| 778 | seq_printf(m, "unknown (%08x)", pvr); | 772 | seq_printf(m, "unknown (%08x)", pvr); |
| 779 | 773 | ||
| 780 | #ifdef CONFIG_ALTIVEC | 774 | #ifdef CONFIG_ALTIVEC |
| 781 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) | 775 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) |
| 782 | seq_printf(m, ", altivec supported"); | 776 | seq_printf(m, ", altivec supported"); |
| 783 | #endif /* CONFIG_ALTIVEC */ | 777 | #endif /* CONFIG_ALTIVEC */ |
| 784 | 778 | ||
| 785 | seq_printf(m, "\n"); | 779 | seq_printf(m, "\n"); |
| 786 | 780 | ||
| 787 | /* | 781 | /* |
| 788 | * Assume here that all clock rates are the same in a | 782 | * Assume here that all clock rates are the same in a |
| 789 | * smp system. -- Cort | 783 | * smp system. -- Cort |
| 790 | */ | 784 | */ |
| 791 | seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000, | 785 | seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000, |
| 792 | ppc_proc_freq % 1000000); | 786 | ppc_proc_freq % 1000000); |
| 793 | 787 | ||
| 794 | seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min); | 788 | seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min); |
| 795 | 789 | ||
| 796 | preempt_enable(); | 790 | preempt_enable(); |
| 797 | return 0; | 791 | return 0; |
| 798 | } | 792 | } |
| 799 | 793 | ||
| 800 | static void *c_start(struct seq_file *m, loff_t *pos) | 794 | static void *c_start(struct seq_file *m, loff_t *pos) |
| 801 | { | 795 | { |
| 802 | return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL; | 796 | return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL; |
| 803 | } | 797 | } |
| 804 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | 798 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) |
| 805 | { | 799 | { |
| 806 | ++*pos; | 800 | ++*pos; |
| 807 | return c_start(m, pos); | 801 | return c_start(m, pos); |
| 808 | } | 802 | } |
| 809 | static void c_stop(struct seq_file *m, void *v) | 803 | static void c_stop(struct seq_file *m, void *v) |
| 810 | { | 804 | { |
| 811 | } | 805 | } |
| 812 | struct seq_operations cpuinfo_op = { | 806 | struct seq_operations cpuinfo_op = { |
| 813 | .start =c_start, | 807 | .start =c_start, |
| 814 | .next = c_next, | 808 | .next = c_next, |
| 815 | .stop = c_stop, | 809 | .stop = c_stop, |
| 816 | .show = show_cpuinfo, | 810 | .show = show_cpuinfo, |
| 817 | }; | 811 | }; |
| 818 | 812 | ||
| 819 | /* | 813 | /* |
| 820 | * These three variables are used to save values passed to us by prom_init() | 814 | * These three variables are used to save values passed to us by prom_init() |
| 821 | * via the device tree. The TCE variables are needed because with a memory_limit | 815 | * via the device tree. The TCE variables are needed because with a memory_limit |
| 822 | * in force we may need to explicitly map the TCE are at the top of RAM. | 816 | * in force we may need to explicitly map the TCE are at the top of RAM. |
| 823 | */ | 817 | */ |
| 824 | unsigned long memory_limit; | 818 | unsigned long memory_limit; |
| 825 | unsigned long tce_alloc_start; | 819 | unsigned long tce_alloc_start; |
| 826 | unsigned long tce_alloc_end; | 820 | unsigned long tce_alloc_end; |
| 827 | 821 | ||
| 828 | #ifdef CONFIG_PPC_ISERIES | 822 | #ifdef CONFIG_PPC_ISERIES |
| 829 | /* | 823 | /* |
| 830 | * On iSeries we just parse the mem=X option from the command line. | 824 | * On iSeries we just parse the mem=X option from the command line. |
| 831 | * On pSeries it's a bit more complicated, see prom_init_mem() | 825 | * On pSeries it's a bit more complicated, see prom_init_mem() |
| 832 | */ | 826 | */ |
| 833 | static int __init early_parsemem(char *p) | 827 | static int __init early_parsemem(char *p) |
| 834 | { | 828 | { |
| 835 | if (!p) | 829 | if (!p) |
| 836 | return 0; | 830 | return 0; |
| 837 | 831 | ||
| 838 | memory_limit = ALIGN(memparse(p, &p), PAGE_SIZE); | 832 | memory_limit = ALIGN(memparse(p, &p), PAGE_SIZE); |
| 839 | 833 | ||
| 840 | return 0; | 834 | return 0; |
| 841 | } | 835 | } |
| 842 | early_param("mem", early_parsemem); | 836 | early_param("mem", early_parsemem); |
| 843 | #endif /* CONFIG_PPC_ISERIES */ | 837 | #endif /* CONFIG_PPC_ISERIES */ |
| 844 | 838 | ||
| 845 | #ifdef CONFIG_PPC_MULTIPLATFORM | 839 | #ifdef CONFIG_PPC_MULTIPLATFORM |
| 846 | static int __init set_preferred_console(void) | 840 | static int __init set_preferred_console(void) |
| 847 | { | 841 | { |
| 848 | struct device_node *prom_stdout = NULL; | 842 | struct device_node *prom_stdout = NULL; |
| 849 | char *name; | 843 | char *name; |
| 850 | u32 *spd; | 844 | u32 *spd; |
| 851 | int offset = 0; | 845 | int offset = 0; |
| 852 | 846 | ||
| 853 | DBG(" -> set_preferred_console()\n"); | 847 | DBG(" -> set_preferred_console()\n"); |
| 854 | 848 | ||
| 855 | /* The user has requested a console so this is already set up. */ | 849 | /* The user has requested a console so this is already set up. */ |
| 856 | if (strstr(saved_command_line, "console=")) { | 850 | if (strstr(saved_command_line, "console=")) { |
| 857 | DBG(" console was specified !\n"); | 851 | DBG(" console was specified !\n"); |
| 858 | return -EBUSY; | 852 | return -EBUSY; |
| 859 | } | 853 | } |
| 860 | 854 | ||
| 861 | if (!of_chosen) { | 855 | if (!of_chosen) { |
| 862 | DBG(" of_chosen is NULL !\n"); | 856 | DBG(" of_chosen is NULL !\n"); |
| 863 | return -ENODEV; | 857 | return -ENODEV; |
| 864 | } | 858 | } |
| 865 | /* We are getting a weird phandle from OF ... */ | 859 | /* We are getting a weird phandle from OF ... */ |
| 866 | /* ... So use the full path instead */ | 860 | /* ... So use the full path instead */ |
| 867 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); | 861 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); |
| 868 | if (name == NULL) { | 862 | if (name == NULL) { |
| 869 | DBG(" no linux,stdout-path !\n"); | 863 | DBG(" no linux,stdout-path !\n"); |
| 870 | return -ENODEV; | 864 | return -ENODEV; |
| 871 | } | 865 | } |
| 872 | prom_stdout = of_find_node_by_path(name); | 866 | prom_stdout = of_find_node_by_path(name); |
| 873 | if (!prom_stdout) { | 867 | if (!prom_stdout) { |
| 874 | DBG(" can't find stdout package %s !\n", name); | 868 | DBG(" can't find stdout package %s !\n", name); |
| 875 | return -ENODEV; | 869 | return -ENODEV; |
| 876 | } | 870 | } |
| 877 | DBG("stdout is %s\n", prom_stdout->full_name); | 871 | DBG("stdout is %s\n", prom_stdout->full_name); |
| 878 | 872 | ||
| 879 | name = (char *)get_property(prom_stdout, "name", NULL); | 873 | name = (char *)get_property(prom_stdout, "name", NULL); |
| 880 | if (!name) { | 874 | if (!name) { |
| 881 | DBG(" stdout package has no name !\n"); | 875 | DBG(" stdout package has no name !\n"); |
| 882 | goto not_found; | 876 | goto not_found; |
| 883 | } | 877 | } |
| 884 | spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); | 878 | spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); |
| 885 | 879 | ||
| 886 | if (0) | 880 | if (0) |
| 887 | ; | 881 | ; |
| 888 | #ifdef CONFIG_SERIAL_8250_CONSOLE | 882 | #ifdef CONFIG_SERIAL_8250_CONSOLE |
| 889 | else if (strcmp(name, "serial") == 0) { | 883 | else if (strcmp(name, "serial") == 0) { |
| 890 | int i; | 884 | int i; |
| 891 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); | 885 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); |
| 892 | if (i > 8) { | 886 | if (i > 8) { |
| 893 | switch (reg[1]) { | 887 | switch (reg[1]) { |
| 894 | case 0x3f8: | 888 | case 0x3f8: |
| 895 | offset = 0; | 889 | offset = 0; |
| 896 | break; | 890 | break; |
| 897 | case 0x2f8: | 891 | case 0x2f8: |
| 898 | offset = 1; | 892 | offset = 1; |
| 899 | break; | 893 | break; |
| 900 | case 0x898: | 894 | case 0x898: |
| 901 | offset = 2; | 895 | offset = 2; |
| 902 | break; | 896 | break; |
| 903 | case 0x890: | 897 | case 0x890: |
| 904 | offset = 3; | 898 | offset = 3; |
| 905 | break; | 899 | break; |
| 906 | default: | 900 | default: |
| 907 | /* We dont recognise the serial port */ | 901 | /* We dont recognise the serial port */ |
| 908 | goto not_found; | 902 | goto not_found; |
| 909 | } | 903 | } |
| 910 | } | 904 | } |
| 911 | } | 905 | } |
| 912 | #endif /* CONFIG_SERIAL_8250_CONSOLE */ | 906 | #endif /* CONFIG_SERIAL_8250_CONSOLE */ |
| 913 | #ifdef CONFIG_PPC_PSERIES | 907 | #ifdef CONFIG_PPC_PSERIES |
| 914 | else if (strcmp(name, "vty") == 0) { | 908 | else if (strcmp(name, "vty") == 0) { |
| 915 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); | 909 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); |
| 916 | char *compat = (char *)get_property(prom_stdout, "compatible", NULL); | 910 | char *compat = (char *)get_property(prom_stdout, "compatible", NULL); |
| 917 | 911 | ||
| 918 | if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { | 912 | if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { |
| 919 | /* Host Virtual Serial Interface */ | 913 | /* Host Virtual Serial Interface */ |
| 920 | int offset; | 914 | int offset; |
| 921 | switch (reg[0]) { | 915 | switch (reg[0]) { |
| 922 | case 0x30000000: | 916 | case 0x30000000: |
| 923 | offset = 0; | 917 | offset = 0; |
| 924 | break; | 918 | break; |
| 925 | case 0x30000001: | 919 | case 0x30000001: |
| 926 | offset = 1; | 920 | offset = 1; |
| 927 | break; | 921 | break; |
| 928 | default: | 922 | default: |
| 929 | goto not_found; | 923 | goto not_found; |
| 930 | } | 924 | } |
| 931 | of_node_put(prom_stdout); | 925 | of_node_put(prom_stdout); |
| 932 | DBG("Found hvsi console at offset %d\n", offset); | 926 | DBG("Found hvsi console at offset %d\n", offset); |
| 933 | return add_preferred_console("hvsi", offset, NULL); | 927 | return add_preferred_console("hvsi", offset, NULL); |
| 934 | } else { | 928 | } else { |
| 935 | /* pSeries LPAR virtual console */ | 929 | /* pSeries LPAR virtual console */ |
| 936 | of_node_put(prom_stdout); | 930 | of_node_put(prom_stdout); |
| 937 | DBG("Found hvc console\n"); | 931 | DBG("Found hvc console\n"); |
| 938 | return add_preferred_console("hvc", 0, NULL); | 932 | return add_preferred_console("hvc", 0, NULL); |
| 939 | } | 933 | } |
| 940 | } | 934 | } |
| 941 | #endif /* CONFIG_PPC_PSERIES */ | 935 | #endif /* CONFIG_PPC_PSERIES */ |
| 942 | #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE | 936 | #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE |
| 943 | else if (strcmp(name, "ch-a") == 0) | 937 | else if (strcmp(name, "ch-a") == 0) |
| 944 | offset = 0; | 938 | offset = 0; |
| 945 | else if (strcmp(name, "ch-b") == 0) | 939 | else if (strcmp(name, "ch-b") == 0) |
| 946 | offset = 1; | 940 | offset = 1; |
| 947 | #endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ | 941 | #endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ |
| 948 | else | 942 | else |
| 949 | goto not_found; | 943 | goto not_found; |
| 950 | of_node_put(prom_stdout); | 944 | of_node_put(prom_stdout); |
| 951 | 945 | ||
| 952 | DBG("Found serial console at ttyS%d\n", offset); | 946 | DBG("Found serial console at ttyS%d\n", offset); |
| 953 | 947 | ||
| 954 | if (spd) { | 948 | if (spd) { |
| 955 | static char __initdata opt[16]; | 949 | static char __initdata opt[16]; |
| 956 | sprintf(opt, "%d", *spd); | 950 | sprintf(opt, "%d", *spd); |
| 957 | return add_preferred_console("ttyS", offset, opt); | 951 | return add_preferred_console("ttyS", offset, opt); |
| 958 | } else | 952 | } else |
| 959 | return add_preferred_console("ttyS", offset, NULL); | 953 | return add_preferred_console("ttyS", offset, NULL); |
| 960 | 954 | ||
| 961 | not_found: | 955 | not_found: |
| 962 | DBG("No preferred console found !\n"); | 956 | DBG("No preferred console found !\n"); |
| 963 | of_node_put(prom_stdout); | 957 | of_node_put(prom_stdout); |
| 964 | return -ENODEV; | 958 | return -ENODEV; |
| 965 | } | 959 | } |
| 966 | console_initcall(set_preferred_console); | 960 | console_initcall(set_preferred_console); |
| 967 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 961 | #endif /* CONFIG_PPC_MULTIPLATFORM */ |
| 968 | 962 | ||
| 969 | #ifdef CONFIG_IRQSTACKS | 963 | #ifdef CONFIG_IRQSTACKS |
| 970 | static void __init irqstack_early_init(void) | 964 | static void __init irqstack_early_init(void) |
| 971 | { | 965 | { |
| 972 | unsigned int i; | 966 | unsigned int i; |
| 973 | 967 | ||
| 974 | /* | 968 | /* |
| 975 | * interrupt stacks must be under 256MB, we cannot afford to take | 969 | * interrupt stacks must be under 256MB, we cannot afford to take |
| 976 | * SLB misses on them. | 970 | * SLB misses on them. |
| 977 | */ | 971 | */ |
| 978 | for_each_cpu(i) { | 972 | for_each_cpu(i) { |
| 979 | softirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, | 973 | softirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, |
| 980 | THREAD_SIZE, 0x10000000)); | 974 | THREAD_SIZE, 0x10000000)); |
| 981 | hardirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, | 975 | hardirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, |
| 982 | THREAD_SIZE, 0x10000000)); | 976 | THREAD_SIZE, 0x10000000)); |
| 983 | } | 977 | } |
| 984 | } | 978 | } |
| 985 | #else | 979 | #else |
| 986 | #define irqstack_early_init() | 980 | #define irqstack_early_init() |
| 987 | #endif | 981 | #endif |
| 988 | 982 | ||
| 989 | /* | 983 | /* |
| 990 | * Stack space used when we detect a bad kernel stack pointer, and | 984 | * Stack space used when we detect a bad kernel stack pointer, and |
| 991 | * early in SMP boots before relocation is enabled. | 985 | * early in SMP boots before relocation is enabled. |
| 992 | */ | 986 | */ |
| 993 | static void __init emergency_stack_init(void) | 987 | static void __init emergency_stack_init(void) |
| 994 | { | 988 | { |
| 995 | unsigned long limit; | 989 | unsigned long limit; |
| 996 | unsigned int i; | 990 | unsigned int i; |
| 997 | 991 | ||
| 998 | /* | 992 | /* |
| 999 | * Emergency stacks must be under 256MB, we cannot afford to take | 993 | * Emergency stacks must be under 256MB, we cannot afford to take |
| 1000 | * SLB misses on them. The ABI also requires them to be 128-byte | 994 | * SLB misses on them. The ABI also requires them to be 128-byte |
| 1001 | * aligned. | 995 | * aligned. |
| 1002 | * | 996 | * |
| 1003 | * Since we use these as temporary stacks during secondary CPU | 997 | * Since we use these as temporary stacks during secondary CPU |
| 1004 | * bringup, we need to get at them in real mode. This means they | 998 | * bringup, we need to get at them in real mode. This means they |
| 1005 | * must also be within the RMO region. | 999 | * must also be within the RMO region. |
| 1006 | */ | 1000 | */ |
| 1007 | limit = min(0x10000000UL, lmb.rmo_size); | 1001 | limit = min(0x10000000UL, lmb.rmo_size); |
| 1008 | 1002 | ||
| 1009 | for_each_cpu(i) | 1003 | for_each_cpu(i) |
| 1010 | paca[i].emergency_sp = __va(lmb_alloc_base(PAGE_SIZE, 128, | 1004 | paca[i].emergency_sp = __va(lmb_alloc_base(PAGE_SIZE, 128, |
| 1011 | limit)) + PAGE_SIZE; | 1005 | limit)) + PAGE_SIZE; |
| 1012 | } | 1006 | } |
| 1013 | 1007 | ||
| 1014 | /* | 1008 | /* |
| 1015 | * Called from setup_arch to initialize the bitmap of available | 1009 | * Called from setup_arch to initialize the bitmap of available |
| 1016 | * syscalls in the systemcfg page | 1010 | * syscalls in the systemcfg page |
| 1017 | */ | 1011 | */ |
| 1018 | void __init setup_syscall_map(void) | 1012 | void __init setup_syscall_map(void) |
| 1019 | { | 1013 | { |
| 1020 | unsigned int i, count64 = 0, count32 = 0; | 1014 | unsigned int i, count64 = 0, count32 = 0; |
| 1021 | extern unsigned long *sys_call_table; | 1015 | extern unsigned long *sys_call_table; |
| 1022 | extern unsigned long *sys_call_table32; | 1016 | extern unsigned long *sys_call_table32; |
| 1023 | extern unsigned long sys_ni_syscall; | 1017 | extern unsigned long sys_ni_syscall; |
| 1024 | 1018 | ||
| 1025 | 1019 | ||
| 1026 | for (i = 0; i < __NR_syscalls; i++) { | 1020 | for (i = 0; i < __NR_syscalls; i++) { |
| 1027 | if (sys_call_table[i] == sys_ni_syscall) | 1021 | if (sys_call_table[i] == sys_ni_syscall) |
| 1028 | continue; | 1022 | continue; |
| 1029 | count64++; | 1023 | count64++; |
| 1030 | systemcfg->syscall_map_64[i >> 5] |= 0x80000000UL >> (i & 0x1f); | 1024 | systemcfg->syscall_map_64[i >> 5] |= 0x80000000UL >> (i & 0x1f); |
| 1031 | } | 1025 | } |
| 1032 | for (i = 0; i < __NR_syscalls; i++) { | 1026 | for (i = 0; i < __NR_syscalls; i++) { |
| 1033 | if (sys_call_table32[i] == sys_ni_syscall) | 1027 | if (sys_call_table32[i] == sys_ni_syscall) |
| 1034 | continue; | 1028 | continue; |
| 1035 | count32++; | 1029 | count32++; |
| 1036 | systemcfg->syscall_map_32[i >> 5] |= 0x80000000UL >> (i & 0x1f); | 1030 | systemcfg->syscall_map_32[i >> 5] |= 0x80000000UL >> (i & 0x1f); |
| 1037 | } | 1031 | } |
| 1038 | printk(KERN_INFO "Syscall map setup, %d 32 bits and %d 64 bits syscalls\n", | 1032 | printk(KERN_INFO "Syscall map setup, %d 32 bits and %d 64 bits syscalls\n", |
| 1039 | count32, count64); | 1033 | count32, count64); |
| 1040 | } | 1034 | } |
| 1041 | 1035 | ||
| 1042 | /* | 1036 | /* |
| 1043 | * Called into from start_kernel, after lock_kernel has been called. | 1037 | * Called into from start_kernel, after lock_kernel has been called. |
| 1044 | * Initializes bootmem, which is unsed to manage page allocation until | 1038 | * Initializes bootmem, which is unsed to manage page allocation until |
| 1045 | * mem_init is called. | 1039 | * mem_init is called. |
| 1046 | */ | 1040 | */ |
| 1047 | void __init setup_arch(char **cmdline_p) | 1041 | void __init setup_arch(char **cmdline_p) |
| 1048 | { | 1042 | { |
| 1049 | extern void do_init_bootmem(void); | 1043 | extern void do_init_bootmem(void); |
| 1050 | 1044 | ||
| 1051 | ppc64_boot_msg(0x12, "Setup Arch"); | 1045 | ppc64_boot_msg(0x12, "Setup Arch"); |
| 1052 | 1046 | ||
| 1053 | *cmdline_p = cmd_line; | 1047 | *cmdline_p = cmd_line; |
| 1054 | 1048 | ||
| 1055 | /* | 1049 | /* |
| 1056 | * Set cache line size based on type of cpu as a default. | 1050 | * Set cache line size based on type of cpu as a default. |
| 1057 | * Systems with OF can look in the properties on the cpu node(s) | 1051 | * Systems with OF can look in the properties on the cpu node(s) |
| 1058 | * for a possibly more accurate value. | 1052 | * for a possibly more accurate value. |
| 1059 | */ | 1053 | */ |
| 1060 | dcache_bsize = ppc64_caches.dline_size; | 1054 | dcache_bsize = ppc64_caches.dline_size; |
| 1061 | icache_bsize = ppc64_caches.iline_size; | 1055 | icache_bsize = ppc64_caches.iline_size; |
| 1062 | 1056 | ||
| 1063 | /* reboot on panic */ | 1057 | /* reboot on panic */ |
| 1064 | panic_timeout = 180; | 1058 | panic_timeout = 180; |
| 1065 | 1059 | ||
| 1066 | if (ppc_md.panic) | 1060 | if (ppc_md.panic) |
| 1067 | notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); | 1061 | notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); |
| 1068 | 1062 | ||
| 1069 | init_mm.start_code = PAGE_OFFSET; | 1063 | init_mm.start_code = PAGE_OFFSET; |
| 1070 | init_mm.end_code = (unsigned long) _etext; | 1064 | init_mm.end_code = (unsigned long) _etext; |
| 1071 | init_mm.end_data = (unsigned long) _edata; | 1065 | init_mm.end_data = (unsigned long) _edata; |
| 1072 | init_mm.brk = klimit; | 1066 | init_mm.brk = klimit; |
| 1073 | 1067 | ||
| 1074 | irqstack_early_init(); | 1068 | irqstack_early_init(); |
| 1075 | emergency_stack_init(); | 1069 | emergency_stack_init(); |
| 1076 | 1070 | ||
| 1077 | stabs_alloc(); | 1071 | stabs_alloc(); |
| 1078 | 1072 | ||
| 1079 | /* set up the bootmem stuff with available memory */ | 1073 | /* set up the bootmem stuff with available memory */ |
| 1080 | do_init_bootmem(); | 1074 | do_init_bootmem(); |
| 1081 | sparse_init(); | 1075 | sparse_init(); |
| 1082 | 1076 | ||
| 1083 | /* initialize the syscall map in systemcfg */ | 1077 | /* initialize the syscall map in systemcfg */ |
| 1084 | setup_syscall_map(); | 1078 | setup_syscall_map(); |
| 1085 | 1079 | ||
| 1086 | ppc_md.setup_arch(); | 1080 | ppc_md.setup_arch(); |
| 1087 | 1081 | ||
| 1088 | /* Use the default idle loop if the platform hasn't provided one. */ | 1082 | /* Use the default idle loop if the platform hasn't provided one. */ |
| 1089 | if (NULL == ppc_md.idle_loop) { | 1083 | if (NULL == ppc_md.idle_loop) { |
| 1090 | ppc_md.idle_loop = default_idle; | 1084 | ppc_md.idle_loop = default_idle; |
| 1091 | printk(KERN_INFO "Using default idle loop\n"); | 1085 | printk(KERN_INFO "Using default idle loop\n"); |
| 1092 | } | 1086 | } |
| 1093 | 1087 | ||
| 1094 | paging_init(); | 1088 | paging_init(); |
| 1095 | ppc64_boot_msg(0x15, "Setup Done"); | 1089 | ppc64_boot_msg(0x15, "Setup Done"); |
| 1096 | } | 1090 | } |
| 1097 | 1091 | ||
| 1098 | 1092 | ||
| 1099 | /* ToDo: do something useful if ppc_md is not yet setup. */ | 1093 | /* ToDo: do something useful if ppc_md is not yet setup. */ |
| 1100 | #define PPC64_LINUX_FUNCTION 0x0f000000 | 1094 | #define PPC64_LINUX_FUNCTION 0x0f000000 |
| 1101 | #define PPC64_IPL_MESSAGE 0xc0000000 | 1095 | #define PPC64_IPL_MESSAGE 0xc0000000 |
| 1102 | #define PPC64_TERM_MESSAGE 0xb0000000 | 1096 | #define PPC64_TERM_MESSAGE 0xb0000000 |
| 1103 | #define PPC64_ATTN_MESSAGE 0xa0000000 | 1097 | #define PPC64_ATTN_MESSAGE 0xa0000000 |
| 1104 | #define PPC64_DUMP_MESSAGE 0xd0000000 | 1098 | #define PPC64_DUMP_MESSAGE 0xd0000000 |
| 1105 | 1099 | ||
| 1106 | static void ppc64_do_msg(unsigned int src, const char *msg) | 1100 | static void ppc64_do_msg(unsigned int src, const char *msg) |
| 1107 | { | 1101 | { |
| 1108 | if (ppc_md.progress) { | 1102 | if (ppc_md.progress) { |
| 1109 | char buf[128]; | 1103 | char buf[128]; |
| 1110 | 1104 | ||
| 1111 | sprintf(buf, "%08X\n", src); | 1105 | sprintf(buf, "%08X\n", src); |
| 1112 | ppc_md.progress(buf, 0); | 1106 | ppc_md.progress(buf, 0); |
| 1113 | snprintf(buf, 128, "%s", msg); | 1107 | snprintf(buf, 128, "%s", msg); |
| 1114 | ppc_md.progress(buf, 0); | 1108 | ppc_md.progress(buf, 0); |
| 1115 | } | 1109 | } |
| 1116 | } | 1110 | } |
| 1117 | 1111 | ||
| 1118 | /* Print a boot progress message. */ | 1112 | /* Print a boot progress message. */ |
| 1119 | void ppc64_boot_msg(unsigned int src, const char *msg) | 1113 | void ppc64_boot_msg(unsigned int src, const char *msg) |
| 1120 | { | 1114 | { |
| 1121 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg); | 1115 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg); |
| 1122 | printk("[boot]%04x %s\n", src, msg); | 1116 | printk("[boot]%04x %s\n", src, msg); |
| 1123 | } | 1117 | } |
| 1124 | 1118 | ||
| 1125 | /* Print a termination message (print only -- does not stop the kernel) */ | 1119 | /* Print a termination message (print only -- does not stop the kernel) */ |
| 1126 | void ppc64_terminate_msg(unsigned int src, const char *msg) | 1120 | void ppc64_terminate_msg(unsigned int src, const char *msg) |
| 1127 | { | 1121 | { |
| 1128 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg); | 1122 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg); |
| 1129 | printk("[terminate]%04x %s\n", src, msg); | 1123 | printk("[terminate]%04x %s\n", src, msg); |
| 1130 | } | 1124 | } |
| 1131 | 1125 | ||
| 1132 | /* Print something that needs attention (device error, etc) */ | 1126 | /* Print something that needs attention (device error, etc) */ |
| 1133 | void ppc64_attention_msg(unsigned int src, const char *msg) | 1127 | void ppc64_attention_msg(unsigned int src, const char *msg) |
| 1134 | { | 1128 | { |
| 1135 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg); | 1129 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg); |
| 1136 | printk("[attention]%04x %s\n", src, msg); | 1130 | printk("[attention]%04x %s\n", src, msg); |
| 1137 | } | 1131 | } |
| 1138 | 1132 | ||
| 1139 | /* Print a dump progress message. */ | 1133 | /* Print a dump progress message. */ |
| 1140 | void ppc64_dump_msg(unsigned int src, const char *msg) | 1134 | void ppc64_dump_msg(unsigned int src, const char *msg) |
| 1141 | { | 1135 | { |
| 1142 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg); | 1136 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg); |
| 1143 | printk("[dump]%04x %s\n", src, msg); | 1137 | printk("[dump]%04x %s\n", src, msg); |
| 1144 | } | 1138 | } |
| 1145 | 1139 | ||
| 1146 | /* This should only be called on processor 0 during calibrate decr */ | 1140 | /* This should only be called on processor 0 during calibrate decr */ |
| 1147 | void __init setup_default_decr(void) | 1141 | void __init setup_default_decr(void) |
| 1148 | { | 1142 | { |
| 1149 | struct paca_struct *lpaca = get_paca(); | 1143 | struct paca_struct *lpaca = get_paca(); |
| 1150 | 1144 | ||
| 1151 | lpaca->default_decr = tb_ticks_per_jiffy; | 1145 | lpaca->default_decr = tb_ticks_per_jiffy; |
| 1152 | lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy; | 1146 | lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy; |
| 1153 | } | 1147 | } |
| 1154 | 1148 | ||
| 1155 | #ifndef CONFIG_PPC_ISERIES | 1149 | #ifndef CONFIG_PPC_ISERIES |
| 1156 | /* | 1150 | /* |
| 1157 | * This function can be used by platforms to "find" legacy serial ports. | 1151 | * This function can be used by platforms to "find" legacy serial ports. |
| 1158 | * It works for "serial" nodes under an "isa" node, and will try to | 1152 | * It works for "serial" nodes under an "isa" node, and will try to |
| 1159 | * respect the "ibm,aix-loc" property if any. It works with up to 8 | 1153 | * respect the "ibm,aix-loc" property if any. It works with up to 8 |
| 1160 | * ports. | 1154 | * ports. |
| 1161 | */ | 1155 | */ |
| 1162 | 1156 | ||
| 1163 | #define MAX_LEGACY_SERIAL_PORTS 8 | 1157 | #define MAX_LEGACY_SERIAL_PORTS 8 |
| 1164 | static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; | 1158 | static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; |
| 1165 | static unsigned int old_serial_count; | 1159 | static unsigned int old_serial_count; |
| 1166 | 1160 | ||
| 1167 | void __init generic_find_legacy_serial_ports(u64 *physport, | 1161 | void __init generic_find_legacy_serial_ports(u64 *physport, |
| 1168 | unsigned int *default_speed) | 1162 | unsigned int *default_speed) |
| 1169 | { | 1163 | { |
| 1170 | struct device_node *np; | 1164 | struct device_node *np; |
| 1171 | u32 *sizeprop; | 1165 | u32 *sizeprop; |
| 1172 | 1166 | ||
| 1173 | struct isa_reg_property { | 1167 | struct isa_reg_property { |
| 1174 | u32 space; | 1168 | u32 space; |
| 1175 | u32 address; | 1169 | u32 address; |
| 1176 | u32 size; | 1170 | u32 size; |
| 1177 | }; | 1171 | }; |
| 1178 | struct pci_reg_property { | 1172 | struct pci_reg_property { |
| 1179 | struct pci_address addr; | 1173 | struct pci_address addr; |
| 1180 | u32 size_hi; | 1174 | u32 size_hi; |
| 1181 | u32 size_lo; | 1175 | u32 size_lo; |
| 1182 | }; | 1176 | }; |
| 1183 | 1177 | ||
| 1184 | DBG(" -> generic_find_legacy_serial_port()\n"); | 1178 | DBG(" -> generic_find_legacy_serial_port()\n"); |
| 1185 | 1179 | ||
| 1186 | *physport = 0; | 1180 | *physport = 0; |
| 1187 | if (default_speed) | 1181 | if (default_speed) |
| 1188 | *default_speed = 0; | 1182 | *default_speed = 0; |
| 1189 | 1183 | ||
| 1190 | np = of_find_node_by_path("/"); | 1184 | np = of_find_node_by_path("/"); |
| 1191 | if (!np) | 1185 | if (!np) |
| 1192 | return; | 1186 | return; |
| 1193 | 1187 | ||
| 1194 | /* First fill our array */ | 1188 | /* First fill our array */ |
| 1195 | for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { | 1189 | for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { |
| 1196 | struct device_node *isa, *pci; | 1190 | struct device_node *isa, *pci; |
| 1197 | struct isa_reg_property *reg; | 1191 | struct isa_reg_property *reg; |
| 1198 | unsigned long phys_size, addr_size, io_base; | 1192 | unsigned long phys_size, addr_size, io_base; |
| 1199 | u32 *rangesp; | 1193 | u32 *rangesp; |
| 1200 | u32 *interrupts, *clk, *spd; | 1194 | u32 *interrupts, *clk, *spd; |
| 1201 | char *typep; | 1195 | char *typep; |
| 1202 | int index, rlen, rentsize; | 1196 | int index, rlen, rentsize; |
| 1203 | 1197 | ||
| 1204 | /* Ok, first check if it's under an "isa" parent */ | 1198 | /* Ok, first check if it's under an "isa" parent */ |
| 1205 | isa = of_get_parent(np); | 1199 | isa = of_get_parent(np); |
| 1206 | if (!isa || strcmp(isa->name, "isa")) { | 1200 | if (!isa || strcmp(isa->name, "isa")) { |
| 1207 | DBG("%s: no isa parent found\n", np->full_name); | 1201 | DBG("%s: no isa parent found\n", np->full_name); |
| 1208 | continue; | 1202 | continue; |
| 1209 | } | 1203 | } |
| 1210 | 1204 | ||
| 1211 | /* Now look for an "ibm,aix-loc" property that gives us ordering | 1205 | /* Now look for an "ibm,aix-loc" property that gives us ordering |
| 1212 | * if any... | 1206 | * if any... |
| 1213 | */ | 1207 | */ |
| 1214 | typep = (char *)get_property(np, "ibm,aix-loc", NULL); | 1208 | typep = (char *)get_property(np, "ibm,aix-loc", NULL); |
| 1215 | 1209 | ||
| 1216 | /* Get the ISA port number */ | 1210 | /* Get the ISA port number */ |
| 1217 | reg = (struct isa_reg_property *)get_property(np, "reg", NULL); | 1211 | reg = (struct isa_reg_property *)get_property(np, "reg", NULL); |
| 1218 | if (reg == NULL) | 1212 | if (reg == NULL) |
| 1219 | goto next_port; | 1213 | goto next_port; |
| 1220 | /* We assume the interrupt number isn't translated ... */ | 1214 | /* We assume the interrupt number isn't translated ... */ |
| 1221 | interrupts = (u32 *)get_property(np, "interrupts", NULL); | 1215 | interrupts = (u32 *)get_property(np, "interrupts", NULL); |
| 1222 | /* get clock freq. if present */ | 1216 | /* get clock freq. if present */ |
| 1223 | clk = (u32 *)get_property(np, "clock-frequency", NULL); | 1217 | clk = (u32 *)get_property(np, "clock-frequency", NULL); |
| 1224 | /* get default speed if present */ | 1218 | /* get default speed if present */ |
| 1225 | spd = (u32 *)get_property(np, "current-speed", NULL); | 1219 | spd = (u32 *)get_property(np, "current-speed", NULL); |
| 1226 | /* Default to locate at end of array */ | 1220 | /* Default to locate at end of array */ |
| 1227 | index = old_serial_count; /* end of the array by default */ | 1221 | index = old_serial_count; /* end of the array by default */ |
| 1228 | 1222 | ||
| 1229 | /* If we have a location index, then use it */ | 1223 | /* If we have a location index, then use it */ |
| 1230 | if (typep && *typep == 'S') { | 1224 | if (typep && *typep == 'S') { |
| 1231 | index = simple_strtol(typep+1, NULL, 0) - 1; | 1225 | index = simple_strtol(typep+1, NULL, 0) - 1; |
| 1232 | /* if index is out of range, use end of array instead */ | 1226 | /* if index is out of range, use end of array instead */ |
| 1233 | if (index >= MAX_LEGACY_SERIAL_PORTS) | 1227 | if (index >= MAX_LEGACY_SERIAL_PORTS) |
| 1234 | index = old_serial_count; | 1228 | index = old_serial_count; |
| 1235 | /* if our index is still out of range, that mean that | 1229 | /* if our index is still out of range, that mean that |
| 1236 | * array is full, we could scan for a free slot but that | 1230 | * array is full, we could scan for a free slot but that |
| 1237 | * make little sense to bother, just skip the port | 1231 | * make little sense to bother, just skip the port |
| 1238 | */ | 1232 | */ |
| 1239 | if (index >= MAX_LEGACY_SERIAL_PORTS) | 1233 | if (index >= MAX_LEGACY_SERIAL_PORTS) |
| 1240 | goto next_port; | 1234 | goto next_port; |
| 1241 | if (index >= old_serial_count) | 1235 | if (index >= old_serial_count) |
| 1242 | old_serial_count = index + 1; | 1236 | old_serial_count = index + 1; |
| 1243 | /* Check if there is a port who already claimed our slot */ | 1237 | /* Check if there is a port who already claimed our slot */ |
| 1244 | if (serial_ports[index].iobase != 0) { | 1238 | if (serial_ports[index].iobase != 0) { |
| 1245 | /* if we still have some room, move it, else override */ | 1239 | /* if we still have some room, move it, else override */ |
| 1246 | if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { | 1240 | if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { |
| 1247 | DBG("Moved legacy port %d -> %d\n", index, | 1241 | DBG("Moved legacy port %d -> %d\n", index, |
| 1248 | old_serial_count); | 1242 | old_serial_count); |
| 1249 | serial_ports[old_serial_count++] = | 1243 | serial_ports[old_serial_count++] = |
| 1250 | serial_ports[index]; | 1244 | serial_ports[index]; |
| 1251 | } else { | 1245 | } else { |
| 1252 | DBG("Replacing legacy port %d\n", index); | 1246 | DBG("Replacing legacy port %d\n", index); |
| 1253 | } | 1247 | } |
| 1254 | } | 1248 | } |
| 1255 | } | 1249 | } |
| 1256 | if (index >= MAX_LEGACY_SERIAL_PORTS) | 1250 | if (index >= MAX_LEGACY_SERIAL_PORTS) |
| 1257 | goto next_port; | 1251 | goto next_port; |
| 1258 | if (index >= old_serial_count) | 1252 | if (index >= old_serial_count) |
| 1259 | old_serial_count = index + 1; | 1253 | old_serial_count = index + 1; |
| 1260 | 1254 | ||
| 1261 | /* Now fill the entry */ | 1255 | /* Now fill the entry */ |
| 1262 | memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); | 1256 | memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); |
| 1263 | serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; | 1257 | serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; |
| 1264 | serial_ports[index].iobase = reg->address; | 1258 | serial_ports[index].iobase = reg->address; |
| 1265 | serial_ports[index].irq = interrupts ? interrupts[0] : 0; | 1259 | serial_ports[index].irq = interrupts ? interrupts[0] : 0; |
| 1266 | serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; | 1260 | serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; |
| 1267 | 1261 | ||
| 1268 | DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", | 1262 | DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", |
| 1269 | index, | 1263 | index, |
| 1270 | serial_ports[index].iobase, | 1264 | serial_ports[index].iobase, |
| 1271 | serial_ports[index].irq, | 1265 | serial_ports[index].irq, |
| 1272 | serial_ports[index].uartclk); | 1266 | serial_ports[index].uartclk); |
| 1273 | 1267 | ||
| 1274 | /* Get phys address of IO reg for port 1 */ | 1268 | /* Get phys address of IO reg for port 1 */ |
| 1275 | if (index != 0) | 1269 | if (index != 0) |
| 1276 | goto next_port; | 1270 | goto next_port; |
| 1277 | 1271 | ||
| 1278 | pci = of_get_parent(isa); | 1272 | pci = of_get_parent(isa); |
| 1279 | if (!pci) { | 1273 | if (!pci) { |
| 1280 | DBG("%s: no pci parent found\n", np->full_name); | 1274 | DBG("%s: no pci parent found\n", np->full_name); |
| 1281 | goto next_port; | 1275 | goto next_port; |
| 1282 | } | 1276 | } |
| 1283 | 1277 | ||
| 1284 | rangesp = (u32 *)get_property(pci, "ranges", &rlen); | 1278 | rangesp = (u32 *)get_property(pci, "ranges", &rlen); |
| 1285 | if (rangesp == NULL) { | 1279 | if (rangesp == NULL) { |
| 1286 | of_node_put(pci); | 1280 | of_node_put(pci); |
| 1287 | goto next_port; | 1281 | goto next_port; |
| 1288 | } | 1282 | } |
| 1289 | rlen /= 4; | 1283 | rlen /= 4; |
| 1290 | 1284 | ||
| 1291 | /* we need the #size-cells of the PCI bridge node itself */ | 1285 | /* we need the #size-cells of the PCI bridge node itself */ |
| 1292 | phys_size = 1; | 1286 | phys_size = 1; |
| 1293 | sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); | 1287 | sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); |
| 1294 | if (sizeprop != NULL) | 1288 | if (sizeprop != NULL) |
| 1295 | phys_size = *sizeprop; | 1289 | phys_size = *sizeprop; |
| 1296 | /* we need the parent #addr-cells */ | 1290 | /* we need the parent #addr-cells */ |
| 1297 | addr_size = prom_n_addr_cells(pci); | 1291 | addr_size = prom_n_addr_cells(pci); |
| 1298 | rentsize = 3 + addr_size + phys_size; | 1292 | rentsize = 3 + addr_size + phys_size; |
| 1299 | io_base = 0; | 1293 | io_base = 0; |
| 1300 | for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { | 1294 | for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { |
| 1301 | if (((rangesp[0] >> 24) & 0x3) != 1) | 1295 | if (((rangesp[0] >> 24) & 0x3) != 1) |
| 1302 | continue; /* not IO space */ | 1296 | continue; /* not IO space */ |
| 1303 | io_base = rangesp[3]; | 1297 | io_base = rangesp[3]; |
| 1304 | if (addr_size == 2) | 1298 | if (addr_size == 2) |
| 1305 | io_base = (io_base << 32) | rangesp[4]; | 1299 | io_base = (io_base << 32) | rangesp[4]; |
| 1306 | } | 1300 | } |
| 1307 | if (io_base != 0) { | 1301 | if (io_base != 0) { |
| 1308 | *physport = io_base + reg->address; | 1302 | *physport = io_base + reg->address; |
| 1309 | if (default_speed && spd) | 1303 | if (default_speed && spd) |
| 1310 | *default_speed = *spd; | 1304 | *default_speed = *spd; |
| 1311 | } | 1305 | } |
| 1312 | of_node_put(pci); | 1306 | of_node_put(pci); |
| 1313 | next_port: | 1307 | next_port: |
| 1314 | of_node_put(isa); | 1308 | of_node_put(isa); |
| 1315 | } | 1309 | } |
| 1316 | 1310 | ||
| 1317 | DBG(" <- generic_find_legacy_serial_port()\n"); | 1311 | DBG(" <- generic_find_legacy_serial_port()\n"); |
| 1318 | } | 1312 | } |
| 1319 | 1313 | ||
| 1320 | static struct platform_device serial_device = { | 1314 | static struct platform_device serial_device = { |
| 1321 | .name = "serial8250", | 1315 | .name = "serial8250", |
| 1322 | .id = 0, | 1316 | .id = 0, |
| 1323 | .dev = { | 1317 | .dev = { |
| 1324 | .platform_data = serial_ports, | 1318 | .platform_data = serial_ports, |
| 1325 | }, | 1319 | }, |
| 1326 | }; | 1320 | }; |
| 1327 | 1321 | ||
| 1328 | static int __init serial_dev_init(void) | 1322 | static int __init serial_dev_init(void) |
| 1329 | { | 1323 | { |
| 1330 | return platform_device_register(&serial_device); | 1324 | return platform_device_register(&serial_device); |
| 1331 | } | 1325 | } |
| 1332 | arch_initcall(serial_dev_init); | 1326 | arch_initcall(serial_dev_init); |
| 1333 | 1327 | ||
| 1334 | #endif /* CONFIG_PPC_ISERIES */ | 1328 | #endif /* CONFIG_PPC_ISERIES */ |
| 1335 | 1329 | ||
| 1336 | int check_legacy_ioport(unsigned long base_port) | 1330 | int check_legacy_ioport(unsigned long base_port) |
| 1337 | { | 1331 | { |
| 1338 | if (ppc_md.check_legacy_ioport == NULL) | 1332 | if (ppc_md.check_legacy_ioport == NULL) |
| 1339 | return 0; | 1333 | return 0; |
| 1340 | return ppc_md.check_legacy_ioport(base_port); | 1334 | return ppc_md.check_legacy_ioport(base_port); |
| 1341 | } | 1335 | } |
| 1342 | EXPORT_SYMBOL(check_legacy_ioport); | 1336 | EXPORT_SYMBOL(check_legacy_ioport); |
| 1343 | 1337 | ||
| 1344 | #ifdef CONFIG_XMON | 1338 | #ifdef CONFIG_XMON |
| 1345 | static int __init early_xmon(char *p) | 1339 | static int __init early_xmon(char *p) |
| 1346 | { | 1340 | { |
| 1347 | /* ensure xmon is enabled */ | 1341 | /* ensure xmon is enabled */ |
| 1348 | if (p) { | 1342 | if (p) { |
| 1349 | if (strncmp(p, "on", 2) == 0) | 1343 | if (strncmp(p, "on", 2) == 0) |
| 1350 | xmon_init(1); | 1344 | xmon_init(1); |
| 1351 | if (strncmp(p, "off", 3) == 0) | 1345 | if (strncmp(p, "off", 3) == 0) |
| 1352 | xmon_init(0); | 1346 | xmon_init(0); |
| 1353 | if (strncmp(p, "early", 5) != 0) | 1347 | if (strncmp(p, "early", 5) != 0) |
| 1354 | return 0; | 1348 | return 0; |
| 1355 | } | 1349 | } |
| 1356 | xmon_init(1); | 1350 | xmon_init(1); |
| 1357 | debugger(NULL); | 1351 | debugger(NULL); |
| 1358 | 1352 | ||
| 1359 | return 0; | 1353 | return 0; |
| 1360 | } | 1354 | } |
| 1361 | early_param("xmon", early_xmon); | 1355 | early_param("xmon", early_xmon); |
| 1362 | #endif | 1356 | #endif |
| 1363 | 1357 | ||
| 1364 | void cpu_die(void) | 1358 | void cpu_die(void) |
| 1365 | { | 1359 | { |
| 1366 | if (ppc_md.cpu_die) | 1360 | if (ppc_md.cpu_die) |
| 1367 | ppc_md.cpu_die(); | 1361 | ppc_md.cpu_die(); |
| 1368 | } | 1362 | } |
| 1369 | 1363 |
arch/ppc64/kernel/udbg.c
| 1 | /* | 1 | /* |
| 2 | * polling mode stateless debugging stuff, originally for NS16550 Serial Ports | 2 | * polling mode stateless debugging stuff, originally for NS16550 Serial Ports |
| 3 | * | 3 | * |
| 4 | * c 2001 PPC 64 Team, IBM Corp | 4 | * c 2001 PPC 64 Team, IBM Corp |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
| 8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
| 9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <stdarg.h> | 12 | #include <stdarg.h> |
| 13 | #define WANT_PPCDBG_TAB /* Only defined here */ | 13 | #define WANT_PPCDBG_TAB /* Only defined here */ |
| 14 | #include <linux/config.h> | 14 | #include <linux/config.h> |
| 15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
| 16 | #include <asm/ppcdebug.h> | 16 | #include <asm/ppcdebug.h> |
| 17 | #include <asm/processor.h> | 17 | #include <asm/processor.h> |
| 18 | #include <asm/uaccess.h> | 18 | #include <asm/uaccess.h> |
| 19 | #include <asm/machdep.h> | 19 | #include <asm/machdep.h> |
| 20 | #include <asm/io.h> | 20 | #include <asm/io.h> |
| 21 | #include <asm/prom.h> | 21 | #include <asm/prom.h> |
| 22 | 22 | ||
| 23 | void (*udbg_putc)(unsigned char c); | ||
| 24 | unsigned char (*udbg_getc)(void); | ||
| 25 | int (*udbg_getc_poll)(void); | ||
| 26 | |||
| 23 | void udbg_puts(const char *s) | 27 | void udbg_puts(const char *s) |
| 24 | { | 28 | { |
| 25 | if (ppc_md.udbg_putc) { | 29 | if (udbg_putc) { |
| 26 | char c; | 30 | char c; |
| 27 | 31 | ||
| 28 | if (s && *s != '\0') { | 32 | if (s && *s != '\0') { |
| 29 | while ((c = *s++) != '\0') | 33 | while ((c = *s++) != '\0') |
| 30 | ppc_md.udbg_putc(c); | 34 | udbg_putc(c); |
| 31 | } | 35 | } |
| 32 | } | 36 | } |
| 33 | #if 0 | 37 | #if 0 |
| 34 | else { | 38 | else { |
| 35 | printk("%s", s); | 39 | printk("%s", s); |
| 36 | } | 40 | } |
| 37 | #endif | 41 | #endif |
| 38 | } | 42 | } |
| 39 | 43 | ||
| 40 | int udbg_write(const char *s, int n) | 44 | int udbg_write(const char *s, int n) |
| 41 | { | 45 | { |
| 42 | int remain = n; | 46 | int remain = n; |
| 43 | char c; | 47 | char c; |
| 44 | 48 | ||
| 45 | if (!ppc_md.udbg_putc) | 49 | if (!udbg_putc) |
| 46 | return 0; | 50 | return 0; |
| 47 | 51 | ||
| 48 | if (s && *s != '\0') { | 52 | if (s && *s != '\0') { |
| 49 | while (((c = *s++) != '\0') && (remain-- > 0)) { | 53 | while (((c = *s++) != '\0') && (remain-- > 0)) { |
| 50 | ppc_md.udbg_putc(c); | 54 | udbg_putc(c); |
| 51 | } | 55 | } |
| 52 | } | 56 | } |
| 53 | 57 | ||
| 54 | return n - remain; | 58 | return n - remain; |
| 55 | } | 59 | } |
| 56 | 60 | ||
| 57 | int udbg_read(char *buf, int buflen) | 61 | int udbg_read(char *buf, int buflen) |
| 58 | { | 62 | { |
| 59 | char c, *p = buf; | 63 | char c, *p = buf; |
| 60 | int i; | 64 | int i; |
| 61 | 65 | ||
| 62 | if (!ppc_md.udbg_getc) | 66 | if (!udbg_getc) |
| 63 | return 0; | 67 | return 0; |
| 64 | 68 | ||
| 65 | for (i = 0; i < buflen; ++i) { | 69 | for (i = 0; i < buflen; ++i) { |
| 66 | do { | 70 | do { |
| 67 | c = ppc_md.udbg_getc(); | 71 | c = udbg_getc(); |
| 68 | } while (c == 0x11 || c == 0x13); | 72 | } while (c == 0x11 || c == 0x13); |
| 69 | if (c == 0) | 73 | if (c == 0) |
| 70 | break; | 74 | break; |
| 71 | *p++ = c; | 75 | *p++ = c; |
| 72 | } | 76 | } |
| 73 | 77 | ||
| 74 | return i; | 78 | return i; |
| 75 | } | 79 | } |
| 76 | 80 | ||
| 77 | void udbg_console_write(struct console *con, const char *s, unsigned int n) | 81 | void udbg_console_write(struct console *con, const char *s, unsigned int n) |
| 78 | { | 82 | { |
| 79 | udbg_write(s, n); | 83 | udbg_write(s, n); |
| 80 | } | 84 | } |
| 81 | 85 | ||
| 82 | #define UDBG_BUFSIZE 256 | 86 | #define UDBG_BUFSIZE 256 |
| 83 | void udbg_printf(const char *fmt, ...) | 87 | void udbg_printf(const char *fmt, ...) |
| 84 | { | 88 | { |
| 85 | unsigned char buf[UDBG_BUFSIZE]; | 89 | unsigned char buf[UDBG_BUFSIZE]; |
| 86 | va_list args; | 90 | va_list args; |
| 87 | 91 | ||
| 88 | va_start(args, fmt); | 92 | va_start(args, fmt); |
| 89 | vsnprintf(buf, UDBG_BUFSIZE, fmt, args); | 93 | vsnprintf(buf, UDBG_BUFSIZE, fmt, args); |
| 90 | udbg_puts(buf); | 94 | udbg_puts(buf); |
| 91 | va_end(args); | 95 | va_end(args); |
| 92 | } | 96 | } |
| 93 | 97 | ||
| 94 | /* Special print used by PPCDBG() macro */ | 98 | /* Special print used by PPCDBG() macro */ |
| 95 | void udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...) | 99 | void udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...) |
| 96 | { | 100 | { |
| 97 | unsigned long active_debugs = debug_flags & ppc64_debug_switch; | 101 | unsigned long active_debugs = debug_flags & ppc64_debug_switch; |
| 98 | 102 | ||
| 99 | if (active_debugs) { | 103 | if (active_debugs) { |
| 100 | va_list ap; | 104 | va_list ap; |
| 101 | unsigned char buf[UDBG_BUFSIZE]; | 105 | unsigned char buf[UDBG_BUFSIZE]; |
| 102 | unsigned long i, len = 0; | 106 | unsigned long i, len = 0; |
| 103 | 107 | ||
| 104 | for (i=0; i < PPCDBG_NUM_FLAGS; i++) { | 108 | for (i=0; i < PPCDBG_NUM_FLAGS; i++) { |
| 105 | if (((1U << i) & active_debugs) && | 109 | if (((1U << i) & active_debugs) && |
| 106 | trace_names[i]) { | 110 | trace_names[i]) { |
| 107 | len += strlen(trace_names[i]); | 111 | len += strlen(trace_names[i]); |
| 108 | udbg_puts(trace_names[i]); | 112 | udbg_puts(trace_names[i]); |
| 109 | break; | 113 | break; |
| 110 | } | 114 | } |
| 111 | } | 115 | } |
| 112 | 116 | ||
| 113 | snprintf(buf, UDBG_BUFSIZE, " [%s]: ", current->comm); | 117 | snprintf(buf, UDBG_BUFSIZE, " [%s]: ", current->comm); |
| 114 | len += strlen(buf); | 118 | len += strlen(buf); |
| 115 | udbg_puts(buf); | 119 | udbg_puts(buf); |
| 116 | 120 | ||
| 117 | while (len < 18) { | 121 | while (len < 18) { |
| 118 | udbg_puts(" "); | 122 | udbg_puts(" "); |
| 119 | len++; | 123 | len++; |
| 120 | } | 124 | } |
| 121 | 125 | ||
| 122 | va_start(ap, fmt); | 126 | va_start(ap, fmt); |
| 123 | vsnprintf(buf, UDBG_BUFSIZE, fmt, ap); | 127 | vsnprintf(buf, UDBG_BUFSIZE, fmt, ap); |
| 124 | udbg_puts(buf); | 128 | udbg_puts(buf); |
| 125 | va_end(ap); | 129 | va_end(ap); |
| 126 | } | 130 | } |
| 127 | } | 131 | } |
| 128 | 132 | ||
| 129 | unsigned long udbg_ifdebug(unsigned long flags) | 133 | unsigned long udbg_ifdebug(unsigned long flags) |
| 130 | { | 134 | { |
| 131 | return (flags & ppc64_debug_switch); | 135 | return (flags & ppc64_debug_switch); |
| 132 | } | 136 | } |
| 133 | 137 |
arch/ppc64/kernel/udbg_16550.c
| 1 | /* | 1 | /* |
| 2 | * udbg for for NS16550 compatable serial ports | 2 | * udbg for for NS16550 compatable serial ports |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp | 4 | * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
| 8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
| 9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | #include <linux/config.h> | 11 | #include <linux/config.h> |
| 12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
| 13 | #include <asm/ppcdebug.h> | 13 | #include <asm/ppcdebug.h> |
| 14 | #include <asm/processor.h> | 14 | #include <asm/processor.h> |
| 15 | #include <asm/naca.h> | 15 | #include <asm/naca.h> |
| 16 | #include <asm/uaccess.h> | 16 | #include <asm/uaccess.h> |
| 17 | #include <asm/machdep.h> | 17 | #include <asm/machdep.h> |
| 18 | #include <asm/io.h> | 18 | #include <asm/io.h> |
| 19 | #include <asm/prom.h> | 19 | #include <asm/prom.h> |
| 20 | 20 | ||
| 21 | extern u8 real_readb(volatile u8 __iomem *addr); | 21 | extern u8 real_readb(volatile u8 __iomem *addr); |
| 22 | extern void real_writeb(u8 data, volatile u8 __iomem *addr); | 22 | extern void real_writeb(u8 data, volatile u8 __iomem *addr); |
| 23 | 23 | ||
| 24 | struct NS16550 { | 24 | struct NS16550 { |
| 25 | /* this struct must be packed */ | 25 | /* this struct must be packed */ |
| 26 | unsigned char rbr; /* 0 */ | 26 | unsigned char rbr; /* 0 */ |
| 27 | unsigned char ier; /* 1 */ | 27 | unsigned char ier; /* 1 */ |
| 28 | unsigned char fcr; /* 2 */ | 28 | unsigned char fcr; /* 2 */ |
| 29 | unsigned char lcr; /* 3 */ | 29 | unsigned char lcr; /* 3 */ |
| 30 | unsigned char mcr; /* 4 */ | 30 | unsigned char mcr; /* 4 */ |
| 31 | unsigned char lsr; /* 5 */ | 31 | unsigned char lsr; /* 5 */ |
| 32 | unsigned char msr; /* 6 */ | 32 | unsigned char msr; /* 6 */ |
| 33 | unsigned char scr; /* 7 */ | 33 | unsigned char scr; /* 7 */ |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | #define thr rbr | 36 | #define thr rbr |
| 37 | #define iir fcr | 37 | #define iir fcr |
| 38 | #define dll rbr | 38 | #define dll rbr |
| 39 | #define dlm ier | 39 | #define dlm ier |
| 40 | #define dlab lcr | 40 | #define dlab lcr |
| 41 | 41 | ||
| 42 | #define LSR_DR 0x01 /* Data ready */ | 42 | #define LSR_DR 0x01 /* Data ready */ |
| 43 | #define LSR_OE 0x02 /* Overrun */ | 43 | #define LSR_OE 0x02 /* Overrun */ |
| 44 | #define LSR_PE 0x04 /* Parity error */ | 44 | #define LSR_PE 0x04 /* Parity error */ |
| 45 | #define LSR_FE 0x08 /* Framing error */ | 45 | #define LSR_FE 0x08 /* Framing error */ |
| 46 | #define LSR_BI 0x10 /* Break */ | 46 | #define LSR_BI 0x10 /* Break */ |
| 47 | #define LSR_THRE 0x20 /* Xmit holding register empty */ | 47 | #define LSR_THRE 0x20 /* Xmit holding register empty */ |
| 48 | #define LSR_TEMT 0x40 /* Xmitter empty */ | 48 | #define LSR_TEMT 0x40 /* Xmitter empty */ |
| 49 | #define LSR_ERR 0x80 /* Error */ | 49 | #define LSR_ERR 0x80 /* Error */ |
| 50 | 50 | ||
| 51 | static volatile struct NS16550 __iomem *udbg_comport; | 51 | static volatile struct NS16550 __iomem *udbg_comport; |
| 52 | 52 | ||
| 53 | static void udbg_550_putc(unsigned char c) | 53 | static void udbg_550_putc(unsigned char c) |
| 54 | { | 54 | { |
| 55 | if (udbg_comport) { | 55 | if (udbg_comport) { |
| 56 | while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) | 56 | while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) |
| 57 | /* wait for idle */; | 57 | /* wait for idle */; |
| 58 | out_8(&udbg_comport->thr, c); | 58 | out_8(&udbg_comport->thr, c); |
| 59 | if (c == '\n') | 59 | if (c == '\n') |
| 60 | udbg_550_putc('\r'); | 60 | udbg_550_putc('\r'); |
| 61 | } | 61 | } |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static int udbg_550_getc_poll(void) | 64 | static int udbg_550_getc_poll(void) |
| 65 | { | 65 | { |
| 66 | if (udbg_comport) { | 66 | if (udbg_comport) { |
| 67 | if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0) | 67 | if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0) |
| 68 | return in_8(&udbg_comport->rbr); | 68 | return in_8(&udbg_comport->rbr); |
| 69 | else | 69 | else |
| 70 | return -1; | 70 | return -1; |
| 71 | } | 71 | } |
| 72 | return -1; | 72 | return -1; |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | static unsigned char udbg_550_getc(void) | 75 | static unsigned char udbg_550_getc(void) |
| 76 | { | 76 | { |
| 77 | if (udbg_comport) { | 77 | if (udbg_comport) { |
| 78 | while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0) | 78 | while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0) |
| 79 | /* wait for char */; | 79 | /* wait for char */; |
| 80 | return in_8(&udbg_comport->rbr); | 80 | return in_8(&udbg_comport->rbr); |
| 81 | } | 81 | } |
| 82 | return 0; | 82 | return 0; |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | void udbg_init_uart(void __iomem *comport, unsigned int speed) | 85 | void udbg_init_uart(void __iomem *comport, unsigned int speed) |
| 86 | { | 86 | { |
| 87 | u16 dll = speed ? (115200 / speed) : 12; | 87 | u16 dll = speed ? (115200 / speed) : 12; |
| 88 | 88 | ||
| 89 | if (comport) { | 89 | if (comport) { |
| 90 | udbg_comport = (struct NS16550 __iomem *)comport; | 90 | udbg_comport = (struct NS16550 __iomem *)comport; |
| 91 | out_8(&udbg_comport->lcr, 0x00); | 91 | out_8(&udbg_comport->lcr, 0x00); |
| 92 | out_8(&udbg_comport->ier, 0xff); | 92 | out_8(&udbg_comport->ier, 0xff); |
| 93 | out_8(&udbg_comport->ier, 0x00); | 93 | out_8(&udbg_comport->ier, 0x00); |
| 94 | out_8(&udbg_comport->lcr, 0x80); /* Access baud rate */ | 94 | out_8(&udbg_comport->lcr, 0x80); /* Access baud rate */ |
| 95 | out_8(&udbg_comport->dll, dll & 0xff); /* 1 = 115200, 2 = 57600, | 95 | out_8(&udbg_comport->dll, dll & 0xff); /* 1 = 115200, 2 = 57600, |
| 96 | 3 = 38400, 12 = 9600 baud */ | 96 | 3 = 38400, 12 = 9600 baud */ |
| 97 | out_8(&udbg_comport->dlm, dll >> 8); /* dll >> 8 which should be zero | 97 | out_8(&udbg_comport->dlm, dll >> 8); /* dll >> 8 which should be zero |
| 98 | for fast rates; */ | 98 | for fast rates; */ |
| 99 | out_8(&udbg_comport->lcr, 0x03); /* 8 data, 1 stop, no parity */ | 99 | out_8(&udbg_comport->lcr, 0x03); /* 8 data, 1 stop, no parity */ |
| 100 | out_8(&udbg_comport->mcr, 0x03); /* RTS/DTR */ | 100 | out_8(&udbg_comport->mcr, 0x03); /* RTS/DTR */ |
| 101 | out_8(&udbg_comport->fcr ,0x07); /* Clear & enable FIFOs */ | 101 | out_8(&udbg_comport->fcr ,0x07); /* Clear & enable FIFOs */ |
| 102 | ppc_md.udbg_putc = udbg_550_putc; | 102 | udbg_putc = udbg_550_putc; |
| 103 | ppc_md.udbg_getc = udbg_550_getc; | 103 | udbg_getc = udbg_550_getc; |
| 104 | ppc_md.udbg_getc_poll = udbg_550_getc_poll; | 104 | udbg_getc_poll = udbg_550_getc_poll; |
| 105 | } | 105 | } |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | #ifdef CONFIG_PPC_MAPLE | 108 | #ifdef CONFIG_PPC_MAPLE |
| 109 | void udbg_maple_real_putc(unsigned char c) | 109 | void udbg_maple_real_putc(unsigned char c) |
| 110 | { | 110 | { |
| 111 | if (udbg_comport) { | 111 | if (udbg_comport) { |
| 112 | while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) | 112 | while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) |
| 113 | /* wait for idle */; | 113 | /* wait for idle */; |
| 114 | real_writeb(c, &udbg_comport->thr); eieio(); | 114 | real_writeb(c, &udbg_comport->thr); eieio(); |
| 115 | if (c == '\n') | 115 | if (c == '\n') |
| 116 | udbg_maple_real_putc('\r'); | 116 | udbg_maple_real_putc('\r'); |
| 117 | } | 117 | } |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | void udbg_init_maple_realmode(void) | 120 | void udbg_init_maple_realmode(void) |
| 121 | { | 121 | { |
| 122 | udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8; | 122 | udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8; |
| 123 | 123 | ||
| 124 | ppc_md.udbg_putc = udbg_maple_real_putc; | 124 | udbg_putc = udbg_maple_real_putc; |
| 125 | ppc_md.udbg_getc = NULL; | 125 | udbg_getc = NULL; |
| 126 | ppc_md.udbg_getc_poll = NULL; | 126 | udbg_getc_poll = NULL; |
| 127 | } | 127 | } |
| 128 | #endif /* CONFIG_PPC_MAPLE */ | 128 | #endif /* CONFIG_PPC_MAPLE */ |
| 129 | 129 |
arch/ppc64/kernel/udbg_scc.c
| 1 | /* | 1 | /* |
| 2 | * udbg for for zilog scc ports as found on Apple PowerMacs | 2 | * udbg for for zilog scc ports as found on Apple PowerMacs |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp | 4 | * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
| 8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
| 9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | #include <linux/config.h> | 11 | #include <linux/config.h> |
| 12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
| 13 | #include <asm/ppcdebug.h> | 13 | #include <asm/ppcdebug.h> |
| 14 | #include <asm/processor.h> | 14 | #include <asm/processor.h> |
| 15 | #include <asm/naca.h> | 15 | #include <asm/naca.h> |
| 16 | #include <asm/uaccess.h> | 16 | #include <asm/uaccess.h> |
| 17 | #include <asm/machdep.h> | 17 | #include <asm/machdep.h> |
| 18 | #include <asm/io.h> | 18 | #include <asm/io.h> |
| 19 | #include <asm/prom.h> | 19 | #include <asm/prom.h> |
| 20 | #include <asm/pmac_feature.h> | 20 | #include <asm/pmac_feature.h> |
| 21 | 21 | ||
| 22 | extern u8 real_readb(volatile u8 __iomem *addr); | 22 | extern u8 real_readb(volatile u8 __iomem *addr); |
| 23 | extern void real_writeb(u8 data, volatile u8 __iomem *addr); | 23 | extern void real_writeb(u8 data, volatile u8 __iomem *addr); |
| 24 | 24 | ||
| 25 | #define SCC_TXRDY 4 | 25 | #define SCC_TXRDY 4 |
| 26 | #define SCC_RXRDY 1 | 26 | #define SCC_RXRDY 1 |
| 27 | 27 | ||
| 28 | static volatile u8 __iomem *sccc; | 28 | static volatile u8 __iomem *sccc; |
| 29 | static volatile u8 __iomem *sccd; | 29 | static volatile u8 __iomem *sccd; |
| 30 | 30 | ||
| 31 | static void udbg_scc_putc(unsigned char c) | 31 | static void udbg_scc_putc(unsigned char c) |
| 32 | { | 32 | { |
| 33 | if (sccc) { | 33 | if (sccc) { |
| 34 | while ((in_8(sccc) & SCC_TXRDY) == 0) | 34 | while ((in_8(sccc) & SCC_TXRDY) == 0) |
| 35 | ; | 35 | ; |
| 36 | out_8(sccd, c); | 36 | out_8(sccd, c); |
| 37 | if (c == '\n') | 37 | if (c == '\n') |
| 38 | udbg_scc_putc('\r'); | 38 | udbg_scc_putc('\r'); |
| 39 | } | 39 | } |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | static int udbg_scc_getc_poll(void) | 42 | static int udbg_scc_getc_poll(void) |
| 43 | { | 43 | { |
| 44 | if (sccc) { | 44 | if (sccc) { |
| 45 | if ((in_8(sccc) & SCC_RXRDY) != 0) | 45 | if ((in_8(sccc) & SCC_RXRDY) != 0) |
| 46 | return in_8(sccd); | 46 | return in_8(sccd); |
| 47 | else | 47 | else |
| 48 | return -1; | 48 | return -1; |
| 49 | } | 49 | } |
| 50 | return -1; | 50 | return -1; |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | static unsigned char udbg_scc_getc(void) | 53 | static unsigned char udbg_scc_getc(void) |
| 54 | { | 54 | { |
| 55 | if (sccc) { | 55 | if (sccc) { |
| 56 | while ((in_8(sccc) & SCC_RXRDY) == 0) | 56 | while ((in_8(sccc) & SCC_RXRDY) == 0) |
| 57 | ; | 57 | ; |
| 58 | return in_8(sccd); | 58 | return in_8(sccd); |
| 59 | } | 59 | } |
| 60 | return 0; | 60 | return 0; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static unsigned char scc_inittab[] = { | 63 | static unsigned char scc_inittab[] = { |
| 64 | 13, 0, /* set baud rate divisor */ | 64 | 13, 0, /* set baud rate divisor */ |
| 65 | 12, 0, | 65 | 12, 0, |
| 66 | 14, 1, /* baud rate gen enable, src=rtxc */ | 66 | 14, 1, /* baud rate gen enable, src=rtxc */ |
| 67 | 11, 0x50, /* clocks = br gen */ | 67 | 11, 0x50, /* clocks = br gen */ |
| 68 | 5, 0xea, /* tx 8 bits, assert DTR & RTS */ | 68 | 5, 0xea, /* tx 8 bits, assert DTR & RTS */ |
| 69 | 4, 0x46, /* x16 clock, 1 stop */ | 69 | 4, 0x46, /* x16 clock, 1 stop */ |
| 70 | 3, 0xc1, /* rx enable, 8 bits */ | 70 | 3, 0xc1, /* rx enable, 8 bits */ |
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | void udbg_init_scc(struct device_node *np) | 73 | void udbg_init_scc(struct device_node *np) |
| 74 | { | 74 | { |
| 75 | u32 *reg; | 75 | u32 *reg; |
| 76 | unsigned long addr; | 76 | unsigned long addr; |
| 77 | int i, x; | 77 | int i, x; |
| 78 | 78 | ||
| 79 | if (np == NULL) | 79 | if (np == NULL) |
| 80 | np = of_find_node_by_name(NULL, "escc"); | 80 | np = of_find_node_by_name(NULL, "escc"); |
| 81 | if (np == NULL || np->parent == NULL) | 81 | if (np == NULL || np->parent == NULL) |
| 82 | return; | 82 | return; |
| 83 | 83 | ||
| 84 | udbg_printf("found SCC...\n"); | 84 | udbg_printf("found SCC...\n"); |
| 85 | /* Get address within mac-io ASIC */ | 85 | /* Get address within mac-io ASIC */ |
| 86 | reg = (u32 *)get_property(np, "reg", NULL); | 86 | reg = (u32 *)get_property(np, "reg", NULL); |
| 87 | if (reg == NULL) | 87 | if (reg == NULL) |
| 88 | return; | 88 | return; |
| 89 | addr = reg[0]; | 89 | addr = reg[0]; |
| 90 | udbg_printf("local addr: %lx\n", addr); | 90 | udbg_printf("local addr: %lx\n", addr); |
| 91 | /* Get address of mac-io PCI itself */ | 91 | /* Get address of mac-io PCI itself */ |
| 92 | reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL); | 92 | reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL); |
| 93 | if (reg == NULL) | 93 | if (reg == NULL) |
| 94 | return; | 94 | return; |
| 95 | addr += reg[2]; | 95 | addr += reg[2]; |
| 96 | udbg_printf("final addr: %lx\n", addr); | 96 | udbg_printf("final addr: %lx\n", addr); |
| 97 | 97 | ||
| 98 | /* Setup for 57600 8N1 */ | 98 | /* Setup for 57600 8N1 */ |
| 99 | addr += 0x20; | 99 | addr += 0x20; |
| 100 | sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; | 100 | sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; |
| 101 | sccc += addr & ~PAGE_MASK; | 101 | sccc += addr & ~PAGE_MASK; |
| 102 | sccd = sccc + 0x10; | 102 | sccd = sccc + 0x10; |
| 103 | 103 | ||
| 104 | udbg_printf("ioremap result sccc: %p\n", sccc); | 104 | udbg_printf("ioremap result sccc: %p\n", sccc); |
| 105 | mb(); | 105 | mb(); |
| 106 | 106 | ||
| 107 | for (i = 20000; i != 0; --i) | 107 | for (i = 20000; i != 0; --i) |
| 108 | x = in_8(sccc); | 108 | x = in_8(sccc); |
| 109 | out_8(sccc, 0x09); /* reset A or B side */ | 109 | out_8(sccc, 0x09); /* reset A or B side */ |
| 110 | out_8(sccc, 0xc0); | 110 | out_8(sccc, 0xc0); |
| 111 | for (i = 0; i < sizeof(scc_inittab); ++i) | 111 | for (i = 0; i < sizeof(scc_inittab); ++i) |
| 112 | out_8(sccc, scc_inittab[i]); | 112 | out_8(sccc, scc_inittab[i]); |
| 113 | 113 | ||
| 114 | ppc_md.udbg_putc = udbg_scc_putc; | 114 | udbg_putc = udbg_scc_putc; |
| 115 | ppc_md.udbg_getc = udbg_scc_getc; | 115 | udbg_getc = udbg_scc_getc; |
| 116 | ppc_md.udbg_getc_poll = udbg_scc_getc_poll; | 116 | udbg_getc_poll = udbg_scc_getc_poll; |
| 117 | 117 | ||
| 118 | udbg_puts("Hello World !\n"); | 118 | udbg_puts("Hello World !\n"); |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | static void udbg_real_scc_putc(unsigned char c) | 121 | static void udbg_real_scc_putc(unsigned char c) |
| 122 | { | 122 | { |
| 123 | while ((real_readb(sccc) & SCC_TXRDY) == 0) | 123 | while ((real_readb(sccc) & SCC_TXRDY) == 0) |
| 124 | ; | 124 | ; |
| 125 | real_writeb(c, sccd); | 125 | real_writeb(c, sccd); |
| 126 | if (c == '\n') | 126 | if (c == '\n') |
| 127 | udbg_real_scc_putc('\r'); | 127 | udbg_real_scc_putc('\r'); |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | void udbg_init_pmac_realmode(void) | 130 | void udbg_init_pmac_realmode(void) |
| 131 | { | 131 | { |
| 132 | sccc = (volatile u8 __iomem *)0x80013020ul; | 132 | sccc = (volatile u8 __iomem *)0x80013020ul; |
| 133 | sccd = (volatile u8 __iomem *)0x80013030ul; | 133 | sccd = (volatile u8 __iomem *)0x80013030ul; |
| 134 | 134 | ||
| 135 | ppc_md.udbg_putc = udbg_real_scc_putc; | 135 | udbg_putc = udbg_real_scc_putc; |
| 136 | ppc_md.udbg_getc = NULL; | 136 | udbg_getc = NULL; |
| 137 | ppc_md.udbg_getc_poll = NULL; | 137 | udbg_getc_poll = NULL; |
| 138 | } | 138 | } |
| 139 | 139 |
arch/ppc64/xmon/start.c
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 1996 Paul Mackerras. | 2 | * Copyright (C) 1996 Paul Mackerras. |
| 3 | * | 3 | * |
| 4 | * This program is free software; you can redistribute it and/or | 4 | * This program is free software; you can redistribute it and/or |
| 5 | * modify it under the terms of the GNU General Public License | 5 | * modify it under the terms of the GNU General Public License |
| 6 | * as published by the Free Software Foundation; either version | 6 | * as published by the Free Software Foundation; either version |
| 7 | * 2 of the License, or (at your option) any later version. | 7 | * 2 of the License, or (at your option) any later version. |
| 8 | */ | 8 | */ |
| 9 | #include <linux/config.h> | 9 | #include <linux/config.h> |
| 10 | #include <linux/string.h> | 10 | #include <linux/string.h> |
| 11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
| 12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
| 13 | #include <linux/sysrq.h> | 13 | #include <linux/sysrq.h> |
| 14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 15 | #include <asm/machdep.h> | 15 | #include <asm/machdep.h> |
| 16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
| 17 | #include <asm/page.h> | 17 | #include <asm/page.h> |
| 18 | #include <asm/prom.h> | 18 | #include <asm/prom.h> |
| 19 | #include <asm/processor.h> | 19 | #include <asm/processor.h> |
| 20 | #include <asm/udbg.h> | 20 | #include <asm/udbg.h> |
| 21 | #include <asm/system.h> | 21 | #include <asm/system.h> |
| 22 | #include "nonstdio.h" | 22 | #include "nonstdio.h" |
| 23 | 23 | ||
| 24 | #ifdef CONFIG_MAGIC_SYSRQ | 24 | #ifdef CONFIG_MAGIC_SYSRQ |
| 25 | 25 | ||
| 26 | static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, | 26 | static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, |
| 27 | struct tty_struct *tty) | 27 | struct tty_struct *tty) |
| 28 | { | 28 | { |
| 29 | /* ensure xmon is enabled */ | 29 | /* ensure xmon is enabled */ |
| 30 | xmon_init(1); | 30 | xmon_init(1); |
| 31 | debugger(pt_regs); | 31 | debugger(pt_regs); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | static struct sysrq_key_op sysrq_xmon_op = | 34 | static struct sysrq_key_op sysrq_xmon_op = |
| 35 | { | 35 | { |
| 36 | .handler = sysrq_handle_xmon, | 36 | .handler = sysrq_handle_xmon, |
| 37 | .help_msg = "Xmon", | 37 | .help_msg = "Xmon", |
| 38 | .action_msg = "Entering xmon", | 38 | .action_msg = "Entering xmon", |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | static int __init setup_xmon_sysrq(void) | 41 | static int __init setup_xmon_sysrq(void) |
| 42 | { | 42 | { |
| 43 | register_sysrq_key('x', &sysrq_xmon_op); | 43 | register_sysrq_key('x', &sysrq_xmon_op); |
| 44 | return 0; | 44 | return 0; |
| 45 | } | 45 | } |
| 46 | __initcall(setup_xmon_sysrq); | 46 | __initcall(setup_xmon_sysrq); |
| 47 | #endif /* CONFIG_MAGIC_SYSRQ */ | 47 | #endif /* CONFIG_MAGIC_SYSRQ */ |
| 48 | 48 | ||
| 49 | int | 49 | int |
| 50 | xmon_write(void *handle, void *ptr, int nb) | 50 | xmon_write(void *handle, void *ptr, int nb) |
| 51 | { | 51 | { |
| 52 | return udbg_write(ptr, nb); | 52 | return udbg_write(ptr, nb); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | int | 55 | int |
| 56 | xmon_read(void *handle, void *ptr, int nb) | 56 | xmon_read(void *handle, void *ptr, int nb) |
| 57 | { | 57 | { |
| 58 | return udbg_read(ptr, nb); | 58 | return udbg_read(ptr, nb); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | int | 61 | int |
| 62 | xmon_read_poll(void) | 62 | xmon_read_poll(void) |
| 63 | { | 63 | { |
| 64 | if (ppc_md.udbg_getc_poll) | 64 | if (udbg_getc_poll) |
| 65 | return ppc_md.udbg_getc_poll(); | 65 | return udbg_getc_poll(); |
| 66 | return -1; | 66 | return -1; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | FILE *xmon_stdin; | 69 | FILE *xmon_stdin; |
| 70 | FILE *xmon_stdout; | 70 | FILE *xmon_stdout; |
| 71 | 71 | ||
| 72 | int | 72 | int |
| 73 | xmon_putc(int c, void *f) | 73 | xmon_putc(int c, void *f) |
| 74 | { | 74 | { |
| 75 | char ch = c; | 75 | char ch = c; |
| 76 | 76 | ||
| 77 | if (c == '\n') | 77 | if (c == '\n') |
| 78 | xmon_putc('\r', f); | 78 | xmon_putc('\r', f); |
| 79 | return xmon_write(f, &ch, 1) == 1? c: -1; | 79 | return xmon_write(f, &ch, 1) == 1? c: -1; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | int | 82 | int |
| 83 | xmon_putchar(int c) | 83 | xmon_putchar(int c) |
| 84 | { | 84 | { |
| 85 | return xmon_putc(c, xmon_stdout); | 85 | return xmon_putc(c, xmon_stdout); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | int | 88 | int |
| 89 | xmon_fputs(char *str, void *f) | 89 | xmon_fputs(char *str, void *f) |
| 90 | { | 90 | { |
| 91 | int n = strlen(str); | 91 | int n = strlen(str); |
| 92 | 92 | ||
| 93 | return xmon_write(f, str, n) == n? 0: -1; | 93 | return xmon_write(f, str, n) == n? 0: -1; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | int | 96 | int |
| 97 | xmon_readchar(void) | 97 | xmon_readchar(void) |
| 98 | { | 98 | { |
| 99 | char ch; | 99 | char ch; |
| 100 | 100 | ||
| 101 | for (;;) { | 101 | for (;;) { |
| 102 | switch (xmon_read(xmon_stdin, &ch, 1)) { | 102 | switch (xmon_read(xmon_stdin, &ch, 1)) { |
| 103 | case 1: | 103 | case 1: |
| 104 | return ch; | 104 | return ch; |
| 105 | case -1: | 105 | case -1: |
| 106 | xmon_printf("read(stdin) returned -1\r\n", 0, 0); | 106 | xmon_printf("read(stdin) returned -1\r\n", 0, 0); |
| 107 | return -1; | 107 | return -1; |
| 108 | } | 108 | } |
| 109 | } | 109 | } |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | static char line[256]; | 112 | static char line[256]; |
| 113 | static char *lineptr; | 113 | static char *lineptr; |
| 114 | static int lineleft; | 114 | static int lineleft; |
| 115 | 115 | ||
| 116 | int | 116 | int |
| 117 | xmon_getchar(void) | 117 | xmon_getchar(void) |
| 118 | { | 118 | { |
| 119 | int c; | 119 | int c; |
| 120 | 120 | ||
| 121 | if (lineleft == 0) { | 121 | if (lineleft == 0) { |
| 122 | lineptr = line; | 122 | lineptr = line; |
| 123 | for (;;) { | 123 | for (;;) { |
| 124 | c = xmon_readchar(); | 124 | c = xmon_readchar(); |
| 125 | if (c == -1 || c == 4) | 125 | if (c == -1 || c == 4) |
| 126 | break; | 126 | break; |
| 127 | if (c == '\r' || c == '\n') { | 127 | if (c == '\r' || c == '\n') { |
| 128 | *lineptr++ = '\n'; | 128 | *lineptr++ = '\n'; |
| 129 | xmon_putchar('\n'); | 129 | xmon_putchar('\n'); |
| 130 | break; | 130 | break; |
| 131 | } | 131 | } |
| 132 | switch (c) { | 132 | switch (c) { |
| 133 | case 0177: | 133 | case 0177: |
| 134 | case '\b': | 134 | case '\b': |
| 135 | if (lineptr > line) { | 135 | if (lineptr > line) { |
| 136 | xmon_putchar('\b'); | 136 | xmon_putchar('\b'); |
| 137 | xmon_putchar(' '); | 137 | xmon_putchar(' '); |
| 138 | xmon_putchar('\b'); | 138 | xmon_putchar('\b'); |
| 139 | --lineptr; | 139 | --lineptr; |
| 140 | } | 140 | } |
| 141 | break; | 141 | break; |
| 142 | case 'U' & 0x1F: | 142 | case 'U' & 0x1F: |
| 143 | while (lineptr > line) { | 143 | while (lineptr > line) { |
| 144 | xmon_putchar('\b'); | 144 | xmon_putchar('\b'); |
| 145 | xmon_putchar(' '); | 145 | xmon_putchar(' '); |
| 146 | xmon_putchar('\b'); | 146 | xmon_putchar('\b'); |
| 147 | --lineptr; | 147 | --lineptr; |
| 148 | } | 148 | } |
| 149 | break; | 149 | break; |
| 150 | default: | 150 | default: |
| 151 | if (lineptr >= &line[sizeof(line) - 1]) | 151 | if (lineptr >= &line[sizeof(line) - 1]) |
| 152 | xmon_putchar('\a'); | 152 | xmon_putchar('\a'); |
| 153 | else { | 153 | else { |
| 154 | xmon_putchar(c); | 154 | xmon_putchar(c); |
| 155 | *lineptr++ = c; | 155 | *lineptr++ = c; |
| 156 | } | 156 | } |
| 157 | } | 157 | } |
| 158 | } | 158 | } |
| 159 | lineleft = lineptr - line; | 159 | lineleft = lineptr - line; |
| 160 | lineptr = line; | 160 | lineptr = line; |
| 161 | } | 161 | } |
| 162 | if (lineleft == 0) | 162 | if (lineleft == 0) |
| 163 | return -1; | 163 | return -1; |
| 164 | --lineleft; | 164 | --lineleft; |
| 165 | return *lineptr++; | 165 | return *lineptr++; |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | char * | 168 | char * |
| 169 | xmon_fgets(char *str, int nb, void *f) | 169 | xmon_fgets(char *str, int nb, void *f) |
| 170 | { | 170 | { |
| 171 | char *p; | 171 | char *p; |
| 172 | int c; | 172 | int c; |
| 173 | 173 | ||
| 174 | for (p = str; p < str + nb - 1; ) { | 174 | for (p = str; p < str + nb - 1; ) { |
| 175 | c = xmon_getchar(); | 175 | c = xmon_getchar(); |
| 176 | if (c == -1) { | 176 | if (c == -1) { |
| 177 | if (p == str) | 177 | if (p == str) |
| 178 | return NULL; | 178 | return NULL; |
| 179 | break; | 179 | break; |
| 180 | } | 180 | } |
| 181 | *p++ = c; | 181 | *p++ = c; |
| 182 | if (c == '\n') | 182 | if (c == '\n') |
| 183 | break; | 183 | break; |
| 184 | } | 184 | } |
| 185 | *p = 0; | 185 | *p = 0; |
| 186 | return str; | 186 | return str; |
| 187 | } | 187 | } |
| 188 | 188 |
include/asm-ppc64/machdep.h
| 1 | #ifdef __KERNEL__ | 1 | #ifdef __KERNEL__ |
| 2 | #ifndef _PPC64_MACHDEP_H | 2 | #ifndef _PPC64_MACHDEP_H |
| 3 | #define _PPC64_MACHDEP_H | 3 | #define _PPC64_MACHDEP_H |
| 4 | 4 | ||
| 5 | /* | 5 | /* |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
| 8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
| 9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/config.h> | 12 | #include <linux/config.h> |
| 13 | #include <linux/seq_file.h> | 13 | #include <linux/seq_file.h> |
| 14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 15 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
| 16 | 16 | ||
| 17 | #include <asm/setup.h> | 17 | #include <asm/setup.h> |
| 18 | 18 | ||
| 19 | struct pt_regs; | 19 | struct pt_regs; |
| 20 | struct pci_bus; | 20 | struct pci_bus; |
| 21 | struct device_node; | 21 | struct device_node; |
| 22 | struct iommu_table; | 22 | struct iommu_table; |
| 23 | struct rtc_time; | 23 | struct rtc_time; |
| 24 | struct file; | 24 | struct file; |
| 25 | 25 | ||
| 26 | #ifdef CONFIG_SMP | 26 | #ifdef CONFIG_SMP |
| 27 | struct smp_ops_t { | 27 | struct smp_ops_t { |
| 28 | void (*message_pass)(int target, int msg); | 28 | void (*message_pass)(int target, int msg); |
| 29 | int (*probe)(void); | 29 | int (*probe)(void); |
| 30 | void (*kick_cpu)(int nr); | 30 | void (*kick_cpu)(int nr); |
| 31 | void (*setup_cpu)(int nr); | 31 | void (*setup_cpu)(int nr); |
| 32 | void (*take_timebase)(void); | 32 | void (*take_timebase)(void); |
| 33 | void (*give_timebase)(void); | 33 | void (*give_timebase)(void); |
| 34 | int (*cpu_enable)(unsigned int nr); | 34 | int (*cpu_enable)(unsigned int nr); |
| 35 | int (*cpu_disable)(void); | 35 | int (*cpu_disable)(void); |
| 36 | void (*cpu_die)(unsigned int nr); | 36 | void (*cpu_die)(unsigned int nr); |
| 37 | int (*cpu_bootable)(unsigned int nr); | 37 | int (*cpu_bootable)(unsigned int nr); |
| 38 | }; | 38 | }; |
| 39 | #endif | 39 | #endif |
| 40 | 40 | ||
| 41 | struct machdep_calls { | 41 | struct machdep_calls { |
| 42 | void (*hpte_invalidate)(unsigned long slot, | 42 | void (*hpte_invalidate)(unsigned long slot, |
| 43 | unsigned long va, | 43 | unsigned long va, |
| 44 | int large, | 44 | int large, |
| 45 | int local); | 45 | int local); |
| 46 | long (*hpte_updatepp)(unsigned long slot, | 46 | long (*hpte_updatepp)(unsigned long slot, |
| 47 | unsigned long newpp, | 47 | unsigned long newpp, |
| 48 | unsigned long va, | 48 | unsigned long va, |
| 49 | int large, | 49 | int large, |
| 50 | int local); | 50 | int local); |
| 51 | void (*hpte_updateboltedpp)(unsigned long newpp, | 51 | void (*hpte_updateboltedpp)(unsigned long newpp, |
| 52 | unsigned long ea); | 52 | unsigned long ea); |
| 53 | long (*hpte_insert)(unsigned long hpte_group, | 53 | long (*hpte_insert)(unsigned long hpte_group, |
| 54 | unsigned long va, | 54 | unsigned long va, |
| 55 | unsigned long prpn, | 55 | unsigned long prpn, |
| 56 | unsigned long vflags, | 56 | unsigned long vflags, |
| 57 | unsigned long rflags); | 57 | unsigned long rflags); |
| 58 | long (*hpte_remove)(unsigned long hpte_group); | 58 | long (*hpte_remove)(unsigned long hpte_group); |
| 59 | void (*flush_hash_range)(unsigned long context, | 59 | void (*flush_hash_range)(unsigned long context, |
| 60 | unsigned long number, | 60 | unsigned long number, |
| 61 | int local); | 61 | int local); |
| 62 | /* special for kexec, to be called in real mode, linar mapping is | 62 | /* special for kexec, to be called in real mode, linar mapping is |
| 63 | * destroyed as well */ | 63 | * destroyed as well */ |
| 64 | void (*hpte_clear_all)(void); | 64 | void (*hpte_clear_all)(void); |
| 65 | 65 | ||
| 66 | void (*tce_build)(struct iommu_table * tbl, | 66 | void (*tce_build)(struct iommu_table * tbl, |
| 67 | long index, | 67 | long index, |
| 68 | long npages, | 68 | long npages, |
| 69 | unsigned long uaddr, | 69 | unsigned long uaddr, |
| 70 | enum dma_data_direction direction); | 70 | enum dma_data_direction direction); |
| 71 | void (*tce_free)(struct iommu_table *tbl, | 71 | void (*tce_free)(struct iommu_table *tbl, |
| 72 | long index, | 72 | long index, |
| 73 | long npages); | 73 | long npages); |
| 74 | void (*tce_flush)(struct iommu_table *tbl); | 74 | void (*tce_flush)(struct iommu_table *tbl); |
| 75 | void (*iommu_dev_setup)(struct pci_dev *dev); | 75 | void (*iommu_dev_setup)(struct pci_dev *dev); |
| 76 | void (*iommu_bus_setup)(struct pci_bus *bus); | 76 | void (*iommu_bus_setup)(struct pci_bus *bus); |
| 77 | void (*irq_bus_setup)(struct pci_bus *bus); | 77 | void (*irq_bus_setup)(struct pci_bus *bus); |
| 78 | 78 | ||
| 79 | int (*probe)(int platform); | 79 | int (*probe)(int platform); |
| 80 | void (*setup_arch)(void); | 80 | void (*setup_arch)(void); |
| 81 | void (*init_early)(void); | 81 | void (*init_early)(void); |
| 82 | /* Optional, may be NULL. */ | 82 | /* Optional, may be NULL. */ |
| 83 | void (*get_cpuinfo)(struct seq_file *m); | 83 | void (*get_cpuinfo)(struct seq_file *m); |
| 84 | 84 | ||
| 85 | void (*init_IRQ)(void); | 85 | void (*init_IRQ)(void); |
| 86 | int (*get_irq)(struct pt_regs *); | 86 | int (*get_irq)(struct pt_regs *); |
| 87 | void (*cpu_irq_down)(int secondary); | 87 | void (*cpu_irq_down)(int secondary); |
| 88 | 88 | ||
| 89 | /* PCI stuff */ | 89 | /* PCI stuff */ |
| 90 | void (*pcibios_fixup)(void); | 90 | void (*pcibios_fixup)(void); |
| 91 | 91 | ||
| 92 | void (*restart)(char *cmd); | 92 | void (*restart)(char *cmd); |
| 93 | void (*power_off)(void); | 93 | void (*power_off)(void); |
| 94 | void (*halt)(void); | 94 | void (*halt)(void); |
| 95 | void (*panic)(char *str); | 95 | void (*panic)(char *str); |
| 96 | void (*cpu_die)(void); | 96 | void (*cpu_die)(void); |
| 97 | 97 | ||
| 98 | int (*set_rtc_time)(struct rtc_time *); | 98 | int (*set_rtc_time)(struct rtc_time *); |
| 99 | void (*get_rtc_time)(struct rtc_time *); | 99 | void (*get_rtc_time)(struct rtc_time *); |
| 100 | void (*get_boot_time)(struct rtc_time *); | 100 | void (*get_boot_time)(struct rtc_time *); |
| 101 | 101 | ||
| 102 | void (*calibrate_decr)(void); | 102 | void (*calibrate_decr)(void); |
| 103 | 103 | ||
| 104 | void (*progress)(char *, unsigned short); | 104 | void (*progress)(char *, unsigned short); |
| 105 | 105 | ||
| 106 | /* Debug interface. Low level I/O to some terminal device */ | ||
| 107 | void (*udbg_putc)(unsigned char c); | ||
| 108 | unsigned char (*udbg_getc)(void); | ||
| 109 | int (*udbg_getc_poll)(void); | ||
| 110 | |||
| 111 | /* Interface for platform error logging */ | 106 | /* Interface for platform error logging */ |
| 112 | void (*log_error)(char *buf, unsigned int err_type, int fatal); | 107 | void (*log_error)(char *buf, unsigned int err_type, int fatal); |
| 113 | 108 | ||
| 114 | ssize_t (*nvram_write)(char *buf, size_t count, loff_t *index); | 109 | ssize_t (*nvram_write)(char *buf, size_t count, loff_t *index); |
| 115 | ssize_t (*nvram_read)(char *buf, size_t count, loff_t *index); | 110 | ssize_t (*nvram_read)(char *buf, size_t count, loff_t *index); |
| 116 | ssize_t (*nvram_size)(void); | 111 | ssize_t (*nvram_size)(void); |
| 117 | int (*nvram_sync)(void); | 112 | int (*nvram_sync)(void); |
| 118 | 113 | ||
| 119 | /* Exception handlers */ | 114 | /* Exception handlers */ |
| 120 | void (*system_reset_exception)(struct pt_regs *regs); | 115 | void (*system_reset_exception)(struct pt_regs *regs); |
| 121 | int (*machine_check_exception)(struct pt_regs *regs); | 116 | int (*machine_check_exception)(struct pt_regs *regs); |
| 122 | 117 | ||
| 123 | /* Motherboard/chipset features. This is a kind of general purpose | 118 | /* Motherboard/chipset features. This is a kind of general purpose |
| 124 | * hook used to control some machine specific features (like reset | 119 | * hook used to control some machine specific features (like reset |
| 125 | * lines, chip power control, etc...). | 120 | * lines, chip power control, etc...). |
| 126 | */ | 121 | */ |
| 127 | long (*feature_call)(unsigned int feature, ...); | 122 | long (*feature_call)(unsigned int feature, ...); |
| 128 | 123 | ||
| 129 | /* Check availability of legacy devices like i8042 */ | 124 | /* Check availability of legacy devices like i8042 */ |
| 130 | int (*check_legacy_ioport)(unsigned int baseport); | 125 | int (*check_legacy_ioport)(unsigned int baseport); |
| 131 | 126 | ||
| 132 | /* Get legacy PCI/IDE interrupt mapping */ | 127 | /* Get legacy PCI/IDE interrupt mapping */ |
| 133 | int (*pci_get_legacy_ide_irq)(struct pci_dev *dev, int channel); | 128 | int (*pci_get_legacy_ide_irq)(struct pci_dev *dev, int channel); |
| 134 | 129 | ||
| 135 | /* Get access protection for /dev/mem */ | 130 | /* Get access protection for /dev/mem */ |
| 136 | pgprot_t (*phys_mem_access_prot)(struct file *file, | 131 | pgprot_t (*phys_mem_access_prot)(struct file *file, |
| 137 | unsigned long offset, | 132 | unsigned long offset, |
| 138 | unsigned long size, | 133 | unsigned long size, |
| 139 | pgprot_t vma_prot); | 134 | pgprot_t vma_prot); |
| 140 | 135 | ||
| 141 | /* Idle loop for this platform, leave empty for default idle loop */ | 136 | /* Idle loop for this platform, leave empty for default idle loop */ |
| 142 | int (*idle_loop)(void); | 137 | int (*idle_loop)(void); |
| 143 | 138 | ||
| 144 | /* Function to enable pmcs for this platform, called once per cpu. */ | 139 | /* Function to enable pmcs for this platform, called once per cpu. */ |
| 145 | void (*enable_pmcs)(void); | 140 | void (*enable_pmcs)(void); |
| 146 | }; | 141 | }; |
| 147 | 142 | ||
| 148 | extern int default_idle(void); | 143 | extern int default_idle(void); |
| 149 | extern int native_idle(void); | 144 | extern int native_idle(void); |
| 150 | 145 | ||
| 151 | extern struct machdep_calls ppc_md; | 146 | extern struct machdep_calls ppc_md; |
| 152 | extern char cmd_line[COMMAND_LINE_SIZE]; | 147 | extern char cmd_line[COMMAND_LINE_SIZE]; |
| 153 | 148 | ||
| 154 | #ifdef CONFIG_PPC_PMAC | 149 | #ifdef CONFIG_PPC_PMAC |
| 155 | /* | 150 | /* |
| 156 | * Power macintoshes have either a CUDA, PMU or SMU controlling | 151 | * Power macintoshes have either a CUDA, PMU or SMU controlling |
| 157 | * system reset, power, NVRAM, RTC. | 152 | * system reset, power, NVRAM, RTC. |
| 158 | */ | 153 | */ |
| 159 | typedef enum sys_ctrler_kind { | 154 | typedef enum sys_ctrler_kind { |
| 160 | SYS_CTRLER_UNKNOWN = 0, | 155 | SYS_CTRLER_UNKNOWN = 0, |
| 161 | SYS_CTRLER_CUDA = 1, | 156 | SYS_CTRLER_CUDA = 1, |
| 162 | SYS_CTRLER_PMU = 2, | 157 | SYS_CTRLER_PMU = 2, |
| 163 | SYS_CTRLER_SMU = 3, | 158 | SYS_CTRLER_SMU = 3, |
| 164 | } sys_ctrler_t; | 159 | } sys_ctrler_t; |
| 165 | extern sys_ctrler_t sys_ctrler; | 160 | extern sys_ctrler_t sys_ctrler; |
| 166 | 161 | ||
| 167 | #endif /* CONFIG_PPC_PMAC */ | 162 | #endif /* CONFIG_PPC_PMAC */ |
| 168 | 163 | ||
| 169 | 164 | ||
| 170 | 165 | ||
| 171 | /* Functions to produce codes on the leds. | 166 | /* Functions to produce codes on the leds. |
| 172 | * The SRC code should be unique for the message category and should | 167 | * The SRC code should be unique for the message category and should |
| 173 | * be limited to the lower 24 bits (the upper 8 are set by these funcs), | 168 | * be limited to the lower 24 bits (the upper 8 are set by these funcs), |
| 174 | * and (for boot & dump) should be sorted numerically in the order | 169 | * and (for boot & dump) should be sorted numerically in the order |
| 175 | * the events occur. | 170 | * the events occur. |
| 176 | */ | 171 | */ |
| 177 | /* Print a boot progress message. */ | 172 | /* Print a boot progress message. */ |
| 178 | void ppc64_boot_msg(unsigned int src, const char *msg); | 173 | void ppc64_boot_msg(unsigned int src, const char *msg); |
| 179 | /* Print a termination message (print only -- does not stop the kernel) */ | 174 | /* Print a termination message (print only -- does not stop the kernel) */ |
| 180 | void ppc64_terminate_msg(unsigned int src, const char *msg); | 175 | void ppc64_terminate_msg(unsigned int src, const char *msg); |
| 181 | /* Print something that needs attention (device error, etc) */ | 176 | /* Print something that needs attention (device error, etc) */ |
| 182 | void ppc64_attention_msg(unsigned int src, const char *msg); | 177 | void ppc64_attention_msg(unsigned int src, const char *msg); |
| 183 | /* Print a dump progress message. */ | 178 | /* Print a dump progress message. */ |
| 184 | void ppc64_dump_msg(unsigned int src, const char *msg); | 179 | void ppc64_dump_msg(unsigned int src, const char *msg); |
| 185 | 180 | ||
| 186 | static inline void log_error(char *buf, unsigned int err_type, int fatal) | 181 | static inline void log_error(char *buf, unsigned int err_type, int fatal) |
| 187 | { | 182 | { |
| 188 | if (ppc_md.log_error) | 183 | if (ppc_md.log_error) |
| 189 | ppc_md.log_error(buf, err_type, fatal); | 184 | ppc_md.log_error(buf, err_type, fatal); |
| 190 | } | 185 | } |
| 191 | 186 | ||
| 192 | #endif /* _PPC64_MACHDEP_H */ | 187 | #endif /* _PPC64_MACHDEP_H */ |
| 193 | #endif /* __KERNEL__ */ | 188 | #endif /* __KERNEL__ */ |
| 194 | 189 |
include/asm-ppc64/udbg.h
| 1 | #ifndef __UDBG_HDR | 1 | #ifndef __UDBG_HDR |
| 2 | #define __UDBG_HDR | 2 | #define __UDBG_HDR |
| 3 | 3 | ||
| 4 | #include <linux/compiler.h> | 4 | #include <linux/compiler.h> |
| 5 | 5 | ||
| 6 | /* | 6 | /* |
| 7 | * c 2001 PPC 64 Team, IBM Corp | 7 | * c 2001 PPC 64 Team, IBM Corp |
| 8 | * | 8 | * |
| 9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
| 10 | * modify it under the terms of the GNU General Public License | 10 | * modify it under the terms of the GNU General Public License |
| 11 | * as published by the Free Software Foundation; either version | 11 | * as published by the Free Software Foundation; either version |
| 12 | * 2 of the License, or (at your option) any later version. | 12 | * 2 of the License, or (at your option) any later version. |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | void udbg_init_uart(void __iomem *comport, unsigned int speed); | 15 | extern void (*udbg_putc)(unsigned char c); |
| 16 | void udbg_putc(unsigned char c); | 16 | extern unsigned char (*udbg_getc)(void); |
| 17 | unsigned char udbg_getc(void); | 17 | extern int (*udbg_getc_poll)(void); |
| 18 | int udbg_getc_poll(void); | 18 | |
| 19 | void udbg_puts(const char *s); | 19 | extern void udbg_puts(const char *s); |
| 20 | int udbg_write(const char *s, int n); | 20 | extern int udbg_write(const char *s, int n); |
| 21 | int udbg_read(char *buf, int buflen); | 21 | extern int udbg_read(char *buf, int buflen); |
| 22 | |||
| 22 | struct console; | 23 | struct console; |
| 23 | void udbg_console_write(struct console *con, const char *s, unsigned int n); | 24 | extern void udbg_console_write(struct console *con, const char *s, unsigned int n); |
| 24 | void udbg_printf(const char *fmt, ...); | 25 | extern void udbg_printf(const char *fmt, ...); |
| 25 | void udbg_ppcdbg(unsigned long flags, const char *fmt, ...); | 26 | extern void udbg_ppcdbg(unsigned long flags, const char *fmt, ...); |
| 26 | unsigned long udbg_ifdebug(unsigned long flags); | 27 | extern unsigned long udbg_ifdebug(unsigned long flags); |
| 27 | 28 | ||
| 29 | |||
| 30 | extern void udbg_init_uart(void __iomem *comport, unsigned int speed); | ||
| 28 | #endif | 31 | #endif |
| 29 | 32 |