| @@ -1,1270 +1,1269 @@ | | | @@ -1,1270 +1,1269 @@ |
1 | /* $NetBSD: cpu_subr.c,v 1.48 2008/09/23 13:58:59 macallan Exp $ */ | | 1 | /* $NetBSD: cpu_subr.c,v 1.49 2008/10/04 17:20:06 chs Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2001 Matt Thomas. | | 4 | * Copyright (c) 2001 Matt Thomas. |
5 | * Copyright (c) 2001 Tsubai Masanari. | | 5 | * Copyright (c) 2001 Tsubai Masanari. |
6 | * Copyright (c) 1998, 1999, 2001 Internet Research Institute, Inc. | | 6 | * Copyright (c) 1998, 1999, 2001 Internet Research Institute, Inc. |
7 | * All rights reserved. | | 7 | * All rights reserved. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. All advertising materials mentioning features or use of this software | | 17 | * 3. All advertising materials mentioning features or use of this software |
18 | * must display the following acknowledgement: | | 18 | * must display the following acknowledgement: |
19 | * This product includes software developed by | | 19 | * This product includes software developed by |
20 | * Internet Research Institute, Inc. | | 20 | * Internet Research Institute, Inc. |
21 | * 4. The name of the author may not be used to endorse or promote products | | 21 | * 4. The name of the author may not be used to endorse or promote products |
22 | * derived from this software without specific prior written permission. | | 22 | * derived from this software without specific prior written permission. |
23 | * | | 23 | * |
24 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 24 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
25 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 25 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
26 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 26 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
27 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 27 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
28 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 28 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
29 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 29 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
30 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 30 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
31 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 31 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
32 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | | 32 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
34 | */ | | 34 | */ |
35 | | | 35 | |
36 | #include <sys/cdefs.h> | | 36 | #include <sys/cdefs.h> |
37 | __KERNEL_RCSID(0, "$NetBSD: cpu_subr.c,v 1.48 2008/09/23 13:58:59 macallan Exp $"); | | 37 | __KERNEL_RCSID(0, "$NetBSD: cpu_subr.c,v 1.49 2008/10/04 17:20:06 chs Exp $"); |
38 | | | 38 | |
39 | #include "opt_ppcparam.h" | | 39 | #include "opt_ppcparam.h" |
40 | #include "opt_multiprocessor.h" | | 40 | #include "opt_multiprocessor.h" |
41 | #include "opt_altivec.h" | | 41 | #include "opt_altivec.h" |
42 | #include "sysmon_envsys.h" | | 42 | #include "sysmon_envsys.h" |
43 | | | 43 | |
44 | #include <sys/param.h> | | 44 | #include <sys/param.h> |
45 | #include <sys/systm.h> | | 45 | #include <sys/systm.h> |
46 | #include <sys/device.h> | | 46 | #include <sys/device.h> |
47 | #include <sys/types.h> | | 47 | #include <sys/types.h> |
48 | #include <sys/lwp.h> | | 48 | #include <sys/lwp.h> |
49 | #include <sys/user.h> | | 49 | #include <sys/user.h> |
50 | #include <sys/malloc.h> | | 50 | #include <sys/malloc.h> |
51 | | | 51 | |
52 | #include <uvm/uvm_extern.h> | | 52 | #include <uvm/uvm_extern.h> |
53 | | | 53 | |
54 | #include <powerpc/oea/hid.h> | | 54 | #include <powerpc/oea/hid.h> |
55 | #include <powerpc/oea/hid_601.h> | | 55 | #include <powerpc/oea/hid_601.h> |
56 | #include <powerpc/spr.h> | | 56 | #include <powerpc/spr.h> |
57 | #include <powerpc/oea/cpufeat.h> | | 57 | #include <powerpc/oea/cpufeat.h> |
58 | | | 58 | |
59 | #include <dev/sysmon/sysmonvar.h> | | 59 | #include <dev/sysmon/sysmonvar.h> |
60 | | | 60 | |
61 | static void cpu_enable_l2cr(register_t); | | 61 | static void cpu_enable_l2cr(register_t); |
62 | static void cpu_enable_l3cr(register_t); | | 62 | static void cpu_enable_l3cr(register_t); |
63 | static void cpu_config_l2cr(int); | | 63 | static void cpu_config_l2cr(int); |
64 | static void cpu_config_l3cr(int); | | 64 | static void cpu_config_l3cr(int); |
65 | static void cpu_probe_speed(struct cpu_info *); | | 65 | static void cpu_probe_speed(struct cpu_info *); |
66 | static void cpu_idlespin(void); | | 66 | static void cpu_idlespin(void); |
67 | #if NSYSMON_ENVSYS > 0 | | 67 | #if NSYSMON_ENVSYS > 0 |
68 | static void cpu_tau_setup(struct cpu_info *); | | 68 | static void cpu_tau_setup(struct cpu_info *); |
69 | static void cpu_tau_refresh(struct sysmon_envsys *, envsys_data_t *); | | 69 | static void cpu_tau_refresh(struct sysmon_envsys *, envsys_data_t *); |
70 | #endif | | 70 | #endif |
71 | | | 71 | |
72 | int cpu; | | 72 | int cpu; |
73 | int ncpus; | | 73 | int ncpus; |
74 | | | 74 | |
75 | struct fmttab { | | 75 | struct fmttab { |
76 | register_t fmt_mask; | | 76 | register_t fmt_mask; |
77 | register_t fmt_value; | | 77 | register_t fmt_value; |
78 | const char *fmt_string; | | 78 | const char *fmt_string; |
79 | }; | | 79 | }; |
80 | | | 80 | |
81 | static const struct fmttab cpu_7450_l2cr_formats[] = { | | 81 | static const struct fmttab cpu_7450_l2cr_formats[] = { |
82 | { L2CR_L2E, 0, " disabled" }, | | 82 | { L2CR_L2E, 0, " disabled" }, |
83 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, | | 83 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, |
84 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, | | 84 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, |
85 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, | | 85 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, |
86 | { L2CR_L2E, ~0, " 256KB L2 cache" }, | | 86 | { L2CR_L2E, ~0, " 256KB L2 cache" }, |
87 | { L2CR_L2PE, 0, " no parity" }, | | 87 | { L2CR_L2PE, 0, " no parity" }, |
88 | { L2CR_L2PE, ~0, " parity enabled" }, | | 88 | { L2CR_L2PE, ~0, " parity enabled" }, |
89 | { 0, 0, NULL } | | 89 | { 0, 0, NULL } |
90 | }; | | 90 | }; |
91 | | | 91 | |
92 | static const struct fmttab cpu_7448_l2cr_formats[] = { | | 92 | static const struct fmttab cpu_7448_l2cr_formats[] = { |
93 | { L2CR_L2E, 0, " disabled" }, | | 93 | { L2CR_L2E, 0, " disabled" }, |
94 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, | | 94 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, |
95 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, | | 95 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, |
96 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, | | 96 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, |
97 | { L2CR_L2E, ~0, " 1MB L2 cache" }, | | 97 | { L2CR_L2E, ~0, " 1MB L2 cache" }, |
98 | { L2CR_L2PE, 0, " no parity" }, | | 98 | { L2CR_L2PE, 0, " no parity" }, |
99 | { L2CR_L2PE, ~0, " parity enabled" }, | | 99 | { L2CR_L2PE, ~0, " parity enabled" }, |
100 | { 0, 0, NULL } | | 100 | { 0, 0, NULL } |
101 | }; | | 101 | }; |
102 | | | 102 | |
103 | static const struct fmttab cpu_7457_l2cr_formats[] = { | | 103 | static const struct fmttab cpu_7457_l2cr_formats[] = { |
104 | { L2CR_L2E, 0, " disabled" }, | | 104 | { L2CR_L2E, 0, " disabled" }, |
105 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, | | 105 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, |
106 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, | | 106 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, |
107 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, | | 107 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, |
108 | { L2CR_L2E, ~0, " 512KB L2 cache" }, | | 108 | { L2CR_L2E, ~0, " 512KB L2 cache" }, |
109 | { L2CR_L2PE, 0, " no parity" }, | | 109 | { L2CR_L2PE, 0, " no parity" }, |
110 | { L2CR_L2PE, ~0, " parity enabled" }, | | 110 | { L2CR_L2PE, ~0, " parity enabled" }, |
111 | { 0, 0, NULL } | | 111 | { 0, 0, NULL } |
112 | }; | | 112 | }; |
113 | | | 113 | |
114 | static const struct fmttab cpu_7450_l3cr_formats[] = { | | 114 | static const struct fmttab cpu_7450_l3cr_formats[] = { |
115 | { L3CR_L3DO|L3CR_L3IO, L3CR_L3DO, " data-only" }, | | 115 | { L3CR_L3DO|L3CR_L3IO, L3CR_L3DO, " data-only" }, |
116 | { L3CR_L3DO|L3CR_L3IO, L3CR_L3IO, " instruction-only" }, | | 116 | { L3CR_L3DO|L3CR_L3IO, L3CR_L3IO, " instruction-only" }, |
117 | { L3CR_L3DO|L3CR_L3IO, L3CR_L3DO|L3CR_L3IO, " locked" }, | | 117 | { L3CR_L3DO|L3CR_L3IO, L3CR_L3DO|L3CR_L3IO, " locked" }, |
118 | { L3CR_L3SIZ, L3SIZ_2M, " 2MB" }, | | 118 | { L3CR_L3SIZ, L3SIZ_2M, " 2MB" }, |
119 | { L3CR_L3SIZ, L3SIZ_1M, " 1MB" }, | | 119 | { L3CR_L3SIZ, L3SIZ_1M, " 1MB" }, |
120 | { L3CR_L3PE|L3CR_L3APE, L3CR_L3PE|L3CR_L3APE, " parity" }, | | 120 | { L3CR_L3PE|L3CR_L3APE, L3CR_L3PE|L3CR_L3APE, " parity" }, |
121 | { L3CR_L3PE|L3CR_L3APE, L3CR_L3PE, " data-parity" }, | | 121 | { L3CR_L3PE|L3CR_L3APE, L3CR_L3PE, " data-parity" }, |
122 | { L3CR_L3PE|L3CR_L3APE, L3CR_L3APE, " address-parity" }, | | 122 | { L3CR_L3PE|L3CR_L3APE, L3CR_L3APE, " address-parity" }, |
123 | { L3CR_L3PE|L3CR_L3APE, 0, " no-parity" }, | | 123 | { L3CR_L3PE|L3CR_L3APE, 0, " no-parity" }, |
124 | { L3CR_L3SIZ, ~0, " L3 cache" }, | | 124 | { L3CR_L3SIZ, ~0, " L3 cache" }, |
125 | { L3CR_L3RT, L3RT_MSUG2_DDR, " (DDR SRAM)" }, | | 125 | { L3CR_L3RT, L3RT_MSUG2_DDR, " (DDR SRAM)" }, |
126 | { L3CR_L3RT, L3RT_PIPELINE_LATE, " (LW SRAM)" }, | | 126 | { L3CR_L3RT, L3RT_PIPELINE_LATE, " (LW SRAM)" }, |
127 | { L3CR_L3RT, L3RT_PB2_SRAM, " (PB2 SRAM)" }, | | 127 | { L3CR_L3RT, L3RT_PB2_SRAM, " (PB2 SRAM)" }, |
128 | { L3CR_L3CLK, ~0, " at" }, | | 128 | { L3CR_L3CLK, ~0, " at" }, |
129 | { L3CR_L3CLK, L3CLK_20, " 2:1" }, | | 129 | { L3CR_L3CLK, L3CLK_20, " 2:1" }, |
130 | { L3CR_L3CLK, L3CLK_25, " 2.5:1" }, | | 130 | { L3CR_L3CLK, L3CLK_25, " 2.5:1" }, |
131 | { L3CR_L3CLK, L3CLK_30, " 3:1" }, | | 131 | { L3CR_L3CLK, L3CLK_30, " 3:1" }, |
132 | { L3CR_L3CLK, L3CLK_35, " 3.5:1" }, | | 132 | { L3CR_L3CLK, L3CLK_35, " 3.5:1" }, |
133 | { L3CR_L3CLK, L3CLK_40, " 4:1" }, | | 133 | { L3CR_L3CLK, L3CLK_40, " 4:1" }, |
134 | { L3CR_L3CLK, L3CLK_50, " 5:1" }, | | 134 | { L3CR_L3CLK, L3CLK_50, " 5:1" }, |
135 | { L3CR_L3CLK, L3CLK_60, " 6:1" }, | | 135 | { L3CR_L3CLK, L3CLK_60, " 6:1" }, |
136 | { L3CR_L3CLK, ~0, " ratio" }, | | 136 | { L3CR_L3CLK, ~0, " ratio" }, |
137 | { 0, 0, NULL }, | | 137 | { 0, 0, NULL }, |
138 | }; | | 138 | }; |
139 | | | 139 | |
140 | static const struct fmttab cpu_ibm750_l2cr_formats[] = { | | 140 | static const struct fmttab cpu_ibm750_l2cr_formats[] = { |
141 | { L2CR_L2E, 0, " disabled" }, | | 141 | { L2CR_L2E, 0, " disabled" }, |
142 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, | | 142 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, |
143 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, | | 143 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, |
144 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, | | 144 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, |
145 | { 0, ~0, " 512KB" }, | | 145 | { 0, ~0, " 512KB" }, |
146 | { L2CR_L2WT, L2CR_L2WT, " WT" }, | | 146 | { L2CR_L2WT, L2CR_L2WT, " WT" }, |
147 | { L2CR_L2WT, 0, " WB" }, | | 147 | { L2CR_L2WT, 0, " WB" }, |
148 | { L2CR_L2PE, L2CR_L2PE, " with ECC" }, | | 148 | { L2CR_L2PE, L2CR_L2PE, " with ECC" }, |
149 | { 0, ~0, " L2 cache" }, | | 149 | { 0, ~0, " L2 cache" }, |
150 | { 0, 0, NULL } | | 150 | { 0, 0, NULL } |
151 | }; | | 151 | }; |
152 | | | 152 | |
153 | static const struct fmttab cpu_l2cr_formats[] = { | | 153 | static const struct fmttab cpu_l2cr_formats[] = { |
154 | { L2CR_L2E, 0, " disabled" }, | | 154 | { L2CR_L2E, 0, " disabled" }, |
155 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, | | 155 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO, " data-only" }, |
156 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, | | 156 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2IO, " instruction-only" }, |
157 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, | | 157 | { L2CR_L2DO|L2CR_L2IO, L2CR_L2DO|L2CR_L2IO, " locked" }, |
158 | { L2CR_L2PE, L2CR_L2PE, " parity" }, | | 158 | { L2CR_L2PE, L2CR_L2PE, " parity" }, |
159 | { L2CR_L2PE, 0, " no-parity" }, | | 159 | { L2CR_L2PE, 0, " no-parity" }, |
160 | { L2CR_L2SIZ, L2SIZ_2M, " 2MB" }, | | 160 | { L2CR_L2SIZ, L2SIZ_2M, " 2MB" }, |
161 | { L2CR_L2SIZ, L2SIZ_1M, " 1MB" }, | | 161 | { L2CR_L2SIZ, L2SIZ_1M, " 1MB" }, |
162 | { L2CR_L2SIZ, L2SIZ_512K, " 512KB" }, | | 162 | { L2CR_L2SIZ, L2SIZ_512K, " 512KB" }, |
163 | { L2CR_L2SIZ, L2SIZ_256K, " 256KB" }, | | 163 | { L2CR_L2SIZ, L2SIZ_256K, " 256KB" }, |
164 | { L2CR_L2WT, L2CR_L2WT, " WT" }, | | 164 | { L2CR_L2WT, L2CR_L2WT, " WT" }, |
165 | { L2CR_L2WT, 0, " WB" }, | | 165 | { L2CR_L2WT, 0, " WB" }, |
166 | { L2CR_L2E, ~0, " L2 cache" }, | | 166 | { L2CR_L2E, ~0, " L2 cache" }, |
167 | { L2CR_L2RAM, L2RAM_FLOWTHRU_BURST, " (FB SRAM)" }, | | 167 | { L2CR_L2RAM, L2RAM_FLOWTHRU_BURST, " (FB SRAM)" }, |
168 | { L2CR_L2RAM, L2RAM_PIPELINE_LATE, " (LW SRAM)" }, | | 168 | { L2CR_L2RAM, L2RAM_PIPELINE_LATE, " (LW SRAM)" }, |
169 | { L2CR_L2RAM, L2RAM_PIPELINE_BURST, " (PB SRAM)" }, | | 169 | { L2CR_L2RAM, L2RAM_PIPELINE_BURST, " (PB SRAM)" }, |
170 | { L2CR_L2CLK, ~0, " at" }, | | 170 | { L2CR_L2CLK, ~0, " at" }, |
171 | { L2CR_L2CLK, L2CLK_10, " 1:1" }, | | 171 | { L2CR_L2CLK, L2CLK_10, " 1:1" }, |
172 | { L2CR_L2CLK, L2CLK_15, " 1.5:1" }, | | 172 | { L2CR_L2CLK, L2CLK_15, " 1.5:1" }, |
173 | { L2CR_L2CLK, L2CLK_20, " 2:1" }, | | 173 | { L2CR_L2CLK, L2CLK_20, " 2:1" }, |
174 | { L2CR_L2CLK, L2CLK_25, " 2.5:1" }, | | 174 | { L2CR_L2CLK, L2CLK_25, " 2.5:1" }, |
175 | { L2CR_L2CLK, L2CLK_30, " 3:1" }, | | 175 | { L2CR_L2CLK, L2CLK_30, " 3:1" }, |
176 | { L2CR_L2CLK, L2CLK_35, " 3.5:1" }, | | 176 | { L2CR_L2CLK, L2CLK_35, " 3.5:1" }, |
177 | { L2CR_L2CLK, L2CLK_40, " 4:1" }, | | 177 | { L2CR_L2CLK, L2CLK_40, " 4:1" }, |
178 | { L2CR_L2CLK, ~0, " ratio" }, | | 178 | { L2CR_L2CLK, ~0, " ratio" }, |
179 | { 0, 0, NULL } | | 179 | { 0, 0, NULL } |
180 | }; | | 180 | }; |
181 | | | 181 | |
182 | static void cpu_fmttab_print(const struct fmttab *, register_t); | | 182 | static void cpu_fmttab_print(const struct fmttab *, register_t); |
183 | | | 183 | |
184 | struct cputab { | | 184 | struct cputab { |
185 | const char name[8]; | | 185 | const char name[8]; |
186 | uint16_t version; | | 186 | uint16_t version; |
187 | uint16_t revfmt; | | 187 | uint16_t revfmt; |
188 | }; | | 188 | }; |
189 | #define REVFMT_MAJMIN 1 /* %u.%u */ | | 189 | #define REVFMT_MAJMIN 1 /* %u.%u */ |
190 | #define REVFMT_HEX 2 /* 0x%04x */ | | 190 | #define REVFMT_HEX 2 /* 0x%04x */ |
191 | #define REVFMT_DEC 3 /* %u */ | | 191 | #define REVFMT_DEC 3 /* %u */ |
192 | static const struct cputab models[] = { | | 192 | static const struct cputab models[] = { |
193 | { "601", MPC601, REVFMT_DEC }, | | 193 | { "601", MPC601, REVFMT_DEC }, |
194 | { "602", MPC602, REVFMT_DEC }, | | 194 | { "602", MPC602, REVFMT_DEC }, |
195 | { "603", MPC603, REVFMT_MAJMIN }, | | 195 | { "603", MPC603, REVFMT_MAJMIN }, |
196 | { "603e", MPC603e, REVFMT_MAJMIN }, | | 196 | { "603e", MPC603e, REVFMT_MAJMIN }, |
197 | { "603ev", MPC603ev, REVFMT_MAJMIN }, | | 197 | { "603ev", MPC603ev, REVFMT_MAJMIN }, |
198 | { "G2", MPCG2, REVFMT_MAJMIN }, | | 198 | { "G2", MPCG2, REVFMT_MAJMIN }, |
199 | { "604", MPC604, REVFMT_MAJMIN }, | | 199 | { "604", MPC604, REVFMT_MAJMIN }, |
200 | { "604e", MPC604e, REVFMT_MAJMIN }, | | 200 | { "604e", MPC604e, REVFMT_MAJMIN }, |
201 | { "604ev", MPC604ev, REVFMT_MAJMIN }, | | 201 | { "604ev", MPC604ev, REVFMT_MAJMIN }, |
202 | { "620", MPC620, REVFMT_HEX }, | | 202 | { "620", MPC620, REVFMT_HEX }, |
203 | { "750", MPC750, REVFMT_MAJMIN }, | | 203 | { "750", MPC750, REVFMT_MAJMIN }, |
204 | { "750FX", IBM750FX, REVFMT_MAJMIN }, | | 204 | { "750FX", IBM750FX, REVFMT_MAJMIN }, |
205 | { "7400", MPC7400, REVFMT_MAJMIN }, | | 205 | { "7400", MPC7400, REVFMT_MAJMIN }, |
206 | { "7410", MPC7410, REVFMT_MAJMIN }, | | 206 | { "7410", MPC7410, REVFMT_MAJMIN }, |
207 | { "7450", MPC7450, REVFMT_MAJMIN }, | | 207 | { "7450", MPC7450, REVFMT_MAJMIN }, |
208 | { "7455", MPC7455, REVFMT_MAJMIN }, | | 208 | { "7455", MPC7455, REVFMT_MAJMIN }, |
209 | { "7457", MPC7457, REVFMT_MAJMIN }, | | 209 | { "7457", MPC7457, REVFMT_MAJMIN }, |
210 | { "7447A", MPC7447A, REVFMT_MAJMIN }, | | 210 | { "7447A", MPC7447A, REVFMT_MAJMIN }, |
211 | { "7448", MPC7448, REVFMT_MAJMIN }, | | 211 | { "7448", MPC7448, REVFMT_MAJMIN }, |
212 | { "8240", MPC8240, REVFMT_MAJMIN }, | | 212 | { "8240", MPC8240, REVFMT_MAJMIN }, |
213 | { "8245", MPC8245, REVFMT_MAJMIN }, | | 213 | { "8245", MPC8245, REVFMT_MAJMIN }, |
214 | { "970", IBM970, REVFMT_MAJMIN }, | | 214 | { "970", IBM970, REVFMT_MAJMIN }, |
215 | { "970FX", IBM970FX, REVFMT_MAJMIN }, | | 215 | { "970FX", IBM970FX, REVFMT_MAJMIN }, |
216 | { "970MP", IBM970MP, REVFMT_MAJMIN }, | | 216 | { "970MP", IBM970MP, REVFMT_MAJMIN }, |
217 | { "POWER3II", IBMPOWER3II, REVFMT_MAJMIN }, | | 217 | { "POWER3II", IBMPOWER3II, REVFMT_MAJMIN }, |
218 | { "", 0, REVFMT_HEX } | | 218 | { "", 0, REVFMT_HEX } |
219 | }; | | 219 | }; |
220 | | | 220 | |
221 | #ifdef MULTIPROCESSOR | | 221 | #ifdef MULTIPROCESSOR |
222 | struct cpu_info cpu_info[CPU_MAXNUM] = { { .ci_curlwp = &lwp0, }, }; | | 222 | struct cpu_info cpu_info[CPU_MAXNUM] = { { .ci_curlwp = &lwp0, }, }; |
223 | volatile struct cpu_hatch_data *cpu_hatch_data; | | 223 | volatile struct cpu_hatch_data *cpu_hatch_data; |
224 | volatile int cpu_hatch_stack; | | 224 | volatile int cpu_hatch_stack; |
225 | extern int ticks_per_intr; | | 225 | extern int ticks_per_intr; |
226 | #include <powerpc/oea/bat.h> | | 226 | #include <powerpc/oea/bat.h> |
227 | #include <arch/powerpc/pic/picvar.h> | | 227 | #include <arch/powerpc/pic/picvar.h> |
228 | #include <arch/powerpc/pic/ipivar.h> | | 228 | #include <arch/powerpc/pic/ipivar.h> |
229 | extern struct bat battable[]; | | 229 | extern struct bat battable[]; |
230 | #else | | 230 | #else |
231 | struct cpu_info cpu_info[1] = { { .ci_curlwp = &lwp0, }, }; | | 231 | struct cpu_info cpu_info[1] = { { .ci_curlwp = &lwp0, }, }; |
232 | #endif /*MULTIPROCESSOR*/ | | 232 | #endif /*MULTIPROCESSOR*/ |
233 | | | 233 | |
234 | int cpu_altivec; | | 234 | int cpu_altivec; |
235 | int cpu_psluserset, cpu_pslusermod; | | 235 | int cpu_psluserset, cpu_pslusermod; |
236 | char cpu_model[80]; | | 236 | char cpu_model[80]; |
237 | | | 237 | |
238 | /* This is to be called from locore.S, and nowhere else. */ | | 238 | /* This is to be called from locore.S, and nowhere else. */ |
239 | | | 239 | |
240 | void | | 240 | void |
241 | cpu_model_init(void) | | 241 | cpu_model_init(void) |
242 | { | | 242 | { |
243 | u_int pvr, vers; | | 243 | u_int pvr, vers; |
244 | | | 244 | |
245 | pvr = mfpvr(); | | 245 | pvr = mfpvr(); |
246 | vers = pvr >> 16; | | 246 | vers = pvr >> 16; |
247 | | | 247 | |
248 | oeacpufeat = 0; | | 248 | oeacpufeat = 0; |
249 | | | 249 | |
250 | if ((vers >= IBMRS64II && vers <= IBM970GX) || vers == MPC620 || | | 250 | if ((vers >= IBMRS64II && vers <= IBM970GX) || vers == MPC620 || |
251 | vers == IBMCELL || vers == IBMPOWER6P5) | | 251 | vers == IBMCELL || vers == IBMPOWER6P5) |
252 | oeacpufeat |= OEACPU_64 | OEACPU_64_BRIDGE | OEACPU_NOBAT; | | 252 | oeacpufeat |= OEACPU_64 | OEACPU_64_BRIDGE | OEACPU_NOBAT; |
253 | | | 253 | |
254 | else if (vers == MPC601) | | 254 | else if (vers == MPC601) |
255 | oeacpufeat |= OEACPU_601; | | 255 | oeacpufeat |= OEACPU_601; |
256 | | | 256 | |
257 | else if (MPC745X_P(vers) && vers != MPC7450) | | 257 | else if (MPC745X_P(vers) && vers != MPC7450) |
258 | oeacpufeat |= OEACPU_XBSEN | OEACPU_HIGHBAT | OEACPU_HIGHSPRG; | | 258 | oeacpufeat |= OEACPU_XBSEN | OEACPU_HIGHBAT | OEACPU_HIGHSPRG; |
259 | } | | 259 | } |
260 | | | 260 | |
261 | void | | 261 | void |
262 | cpu_fmttab_print(const struct fmttab *fmt, register_t data) | | 262 | cpu_fmttab_print(const struct fmttab *fmt, register_t data) |
263 | { | | 263 | { |
264 | for (; fmt->fmt_mask != 0 || fmt->fmt_value != 0; fmt++) { | | 264 | for (; fmt->fmt_mask != 0 || fmt->fmt_value != 0; fmt++) { |
265 | if ((~fmt->fmt_mask & fmt->fmt_value) != 0 || | | 265 | if ((~fmt->fmt_mask & fmt->fmt_value) != 0 || |
266 | (data & fmt->fmt_mask) == fmt->fmt_value) | | 266 | (data & fmt->fmt_mask) == fmt->fmt_value) |
267 | aprint_normal("%s", fmt->fmt_string); | | 267 | aprint_normal("%s", fmt->fmt_string); |
268 | } | | 268 | } |
269 | } | | 269 | } |
270 | | | 270 | |
271 | void | | 271 | void |
272 | cpu_idlespin(void) | | 272 | cpu_idlespin(void) |
273 | { | | 273 | { |
274 | register_t msr; | | 274 | register_t msr; |
275 | | | 275 | |
276 | if (powersave <= 0) | | 276 | if (powersave <= 0) |
277 | return; | | 277 | return; |
278 | | | 278 | |
279 | __asm volatile( | | 279 | __asm volatile( |
280 | "sync;" | | 280 | "sync;" |
281 | "mfmsr %0;" | | 281 | "mfmsr %0;" |
282 | "oris %0,%0,%1@h;" /* enter power saving mode */ | | 282 | "oris %0,%0,%1@h;" /* enter power saving mode */ |
283 | "mtmsr %0;" | | 283 | "mtmsr %0;" |
284 | "isync;" | | 284 | "isync;" |
285 | : "=r"(msr) | | 285 | : "=r"(msr) |
286 | : "J"(PSL_POW)); | | 286 | : "J"(PSL_POW)); |
287 | } | | 287 | } |
288 | | | 288 | |
289 | void | | 289 | void |
290 | cpu_probe_cache(void) | | 290 | cpu_probe_cache(void) |
291 | { | | 291 | { |
292 | u_int assoc, pvr, vers; | | 292 | u_int assoc, pvr, vers; |
293 | | | 293 | |
294 | pvr = mfpvr(); | | 294 | pvr = mfpvr(); |
295 | vers = pvr >> 16; | | 295 | vers = pvr >> 16; |
296 | | | 296 | |
297 | | | 297 | |
298 | /* Presently common across almost all implementations. */ | | 298 | /* Presently common across almost all implementations. */ |
299 | curcpu()->ci_ci.dcache_line_size = 32; | | 299 | curcpu()->ci_ci.dcache_line_size = 32; |
300 | curcpu()->ci_ci.icache_line_size = 32; | | 300 | curcpu()->ci_ci.icache_line_size = 32; |
301 | | | 301 | |
302 | | | 302 | |
303 | switch (vers) { | | 303 | switch (vers) { |
304 | #define K *1024 | | 304 | #define K *1024 |
305 | case IBM750FX: | | 305 | case IBM750FX: |
306 | case MPC601: | | 306 | case MPC601: |
307 | case MPC750: | | 307 | case MPC750: |
308 | case MPC7400: | | 308 | case MPC7400: |
309 | case MPC7447A: | | 309 | case MPC7447A: |
310 | case MPC7448: | | 310 | case MPC7448: |
311 | case MPC7450: | | 311 | case MPC7450: |
312 | case MPC7455: | | 312 | case MPC7455: |
313 | case MPC7457: | | 313 | case MPC7457: |
314 | curcpu()->ci_ci.dcache_size = 32 K; | | 314 | curcpu()->ci_ci.dcache_size = 32 K; |
315 | curcpu()->ci_ci.icache_size = 32 K; | | 315 | curcpu()->ci_ci.icache_size = 32 K; |
316 | assoc = 8; | | 316 | assoc = 8; |
317 | break; | | 317 | break; |
318 | case MPC603: | | 318 | case MPC603: |
319 | curcpu()->ci_ci.dcache_size = 8 K; | | 319 | curcpu()->ci_ci.dcache_size = 8 K; |
320 | curcpu()->ci_ci.icache_size = 8 K; | | 320 | curcpu()->ci_ci.icache_size = 8 K; |
321 | assoc = 2; | | 321 | assoc = 2; |
322 | break; | | 322 | break; |
323 | case MPC603e: | | 323 | case MPC603e: |
324 | case MPC603ev: | | 324 | case MPC603ev: |
325 | case MPC604: | | 325 | case MPC604: |
326 | case MPC8240: | | 326 | case MPC8240: |
327 | case MPC8245: | | 327 | case MPC8245: |
328 | case MPCG2: | | 328 | case MPCG2: |
329 | curcpu()->ci_ci.dcache_size = 16 K; | | 329 | curcpu()->ci_ci.dcache_size = 16 K; |
330 | curcpu()->ci_ci.icache_size = 16 K; | | 330 | curcpu()->ci_ci.icache_size = 16 K; |
331 | assoc = 4; | | 331 | assoc = 4; |
332 | break; | | 332 | break; |
333 | case MPC604e: | | 333 | case MPC604e: |
334 | case MPC604ev: | | 334 | case MPC604ev: |
335 | curcpu()->ci_ci.dcache_size = 32 K; | | 335 | curcpu()->ci_ci.dcache_size = 32 K; |
336 | curcpu()->ci_ci.icache_size = 32 K; | | 336 | curcpu()->ci_ci.icache_size = 32 K; |
337 | assoc = 4; | | 337 | assoc = 4; |
338 | break; | | 338 | break; |
339 | case IBMPOWER3II: | | 339 | case IBMPOWER3II: |
340 | curcpu()->ci_ci.dcache_size = 64 K; | | 340 | curcpu()->ci_ci.dcache_size = 64 K; |
341 | curcpu()->ci_ci.icache_size = 32 K; | | 341 | curcpu()->ci_ci.icache_size = 32 K; |
342 | curcpu()->ci_ci.dcache_line_size = 128; | | 342 | curcpu()->ci_ci.dcache_line_size = 128; |
343 | curcpu()->ci_ci.icache_line_size = 128; | | 343 | curcpu()->ci_ci.icache_line_size = 128; |
344 | assoc = 128; /* not a typo */ | | 344 | assoc = 128; /* not a typo */ |
345 | break; | | 345 | break; |
346 | case IBM970: | | 346 | case IBM970: |
347 | case IBM970FX: | | 347 | case IBM970FX: |
348 | case IBM970MP: | | 348 | case IBM970MP: |
349 | curcpu()->ci_ci.dcache_size = 32 K; | | 349 | curcpu()->ci_ci.dcache_size = 32 K; |
350 | curcpu()->ci_ci.icache_size = 64 K; | | 350 | curcpu()->ci_ci.icache_size = 64 K; |
351 | curcpu()->ci_ci.dcache_line_size = 128; | | 351 | curcpu()->ci_ci.dcache_line_size = 128; |
352 | curcpu()->ci_ci.icache_line_size = 128; | | 352 | curcpu()->ci_ci.icache_line_size = 128; |
353 | assoc = 2; | | 353 | assoc = 2; |
354 | break; | | 354 | break; |
355 | | | 355 | |
356 | default: | | 356 | default: |
357 | curcpu()->ci_ci.dcache_size = PAGE_SIZE; | | 357 | curcpu()->ci_ci.dcache_size = PAGE_SIZE; |
358 | curcpu()->ci_ci.icache_size = PAGE_SIZE; | | 358 | curcpu()->ci_ci.icache_size = PAGE_SIZE; |
359 | assoc = 1; | | 359 | assoc = 1; |
360 | #undef K | | 360 | #undef K |
361 | } | | 361 | } |
362 | | | 362 | |
363 | /* | | 363 | /* |
364 | * Possibly recolor. | | 364 | * Possibly recolor. |
365 | */ | | 365 | */ |
366 | uvm_page_recolor(atop(curcpu()->ci_ci.dcache_size / assoc)); | | 366 | uvm_page_recolor(atop(curcpu()->ci_ci.dcache_size / assoc)); |
367 | } | | 367 | } |
368 | | | 368 | |
369 | struct cpu_info * | | 369 | struct cpu_info * |
370 | cpu_attach_common(struct device *self, int id) | | 370 | cpu_attach_common(struct device *self, int id) |
371 | { | | 371 | { |
372 | struct cpu_info *ci; | | 372 | struct cpu_info *ci; |
373 | u_int pvr, vers; | | 373 | u_int pvr, vers; |
374 | | | 374 | |
375 | ci = &cpu_info[id]; | | 375 | ci = &cpu_info[id]; |
376 | #ifndef MULTIPROCESSOR | | 376 | #ifndef MULTIPROCESSOR |
377 | /* | | 377 | /* |
378 | * If this isn't the primary CPU, print an error message | | 378 | * If this isn't the primary CPU, print an error message |
379 | * and just bail out. | | 379 | * and just bail out. |
380 | */ | | 380 | */ |
381 | if (id != 0) { | | 381 | if (id != 0) { |
382 | aprint_normal(": ID %d\n", id); | | 382 | aprint_normal(": ID %d\n", id); |
383 | aprint_normal("%s: processor off-line; multiprocessor support " | | 383 | aprint_normal("%s: processor off-line; multiprocessor support " |
384 | "not present in kernel\n", self->dv_xname); | | 384 | "not present in kernel\n", self->dv_xname); |
385 | return (NULL); | | 385 | return (NULL); |
386 | } | | 386 | } |
387 | #endif | | 387 | #endif |
388 | | | 388 | |
389 | ci->ci_cpuid = id; | | 389 | ci->ci_cpuid = id; |
390 | ci->ci_intrdepth = -1; | | 390 | ci->ci_intrdepth = -1; |
391 | ci->ci_dev = self; | | 391 | ci->ci_dev = self; |
392 | ci->ci_idlespin = cpu_idlespin; | | 392 | ci->ci_idlespin = cpu_idlespin; |
393 | | | 393 | |
394 | pvr = mfpvr(); | | 394 | pvr = mfpvr(); |
395 | vers = (pvr >> 16) & 0xffff; | | 395 | vers = (pvr >> 16) & 0xffff; |
396 | | | 396 | |
397 | switch (id) { | | 397 | switch (id) { |
398 | case 0: | | 398 | case 0: |
399 | /* load my cpu_number to PIR */ | | 399 | /* load my cpu_number to PIR */ |
400 | switch (vers) { | | 400 | switch (vers) { |
401 | case MPC601: | | 401 | case MPC601: |
402 | case MPC604: | | 402 | case MPC604: |
403 | case MPC604e: | | 403 | case MPC604e: |
404 | case MPC604ev: | | 404 | case MPC604ev: |
405 | case MPC7400: | | 405 | case MPC7400: |
406 | case MPC7410: | | 406 | case MPC7410: |
407 | case MPC7447A: | | 407 | case MPC7447A: |
408 | case MPC7448: | | 408 | case MPC7448: |
409 | case MPC7450: | | 409 | case MPC7450: |
410 | case MPC7455: | | 410 | case MPC7455: |
411 | case MPC7457: | | 411 | case MPC7457: |
412 | mtspr(SPR_PIR, id); | | 412 | mtspr(SPR_PIR, id); |
413 | } | | 413 | } |
414 | cpu_setup(self, ci); | | 414 | cpu_setup(self, ci); |
415 | break; | | 415 | break; |
416 | default: | | 416 | default: |
417 | if (id >= CPU_MAXNUM) { | | 417 | if (id >= CPU_MAXNUM) { |
418 | aprint_normal(": more than %d cpus?\n", CPU_MAXNUM); | | 418 | aprint_normal(": more than %d cpus?\n", CPU_MAXNUM); |
419 | panic("cpuattach"); | | 419 | panic("cpuattach"); |
420 | } | | 420 | } |
421 | #ifndef MULTIPROCESSOR | | 421 | #ifndef MULTIPROCESSOR |
422 | aprint_normal(" not configured\n"); | | 422 | aprint_normal(" not configured\n"); |
423 | return NULL; | | 423 | return NULL; |
424 | #else | | 424 | #else |
425 | mi_cpu_attach(ci); | | 425 | mi_cpu_attach(ci); |
426 | break; | | 426 | break; |
427 | #endif | | 427 | #endif |
428 | } | | 428 | } |
429 | return (ci); | | 429 | return (ci); |
430 | } | | 430 | } |
431 | | | 431 | |
432 | void | | 432 | void |
433 | cpu_setup(self, ci) | | 433 | cpu_setup(self, ci) |
434 | struct device *self; | | 434 | struct device *self; |
435 | struct cpu_info *ci; | | 435 | struct cpu_info *ci; |
436 | { | | 436 | { |
437 | u_int hid0, hid0_save, pvr, vers; | | 437 | u_int hid0, hid0_save, pvr, vers; |
438 | const char *bitmask; | | 438 | const char *bitmask; |
439 | char hidbuf[128]; | | 439 | char hidbuf[128]; |
440 | char model[80]; | | 440 | char model[80]; |
441 | | | 441 | |
442 | pvr = mfpvr(); | | 442 | pvr = mfpvr(); |
443 | vers = (pvr >> 16) & 0xffff; | | 443 | vers = (pvr >> 16) & 0xffff; |
444 | | | 444 | |
445 | cpu_identify(model, sizeof(model)); | | 445 | cpu_identify(model, sizeof(model)); |
446 | aprint_normal(": %s, ID %d%s\n", model, cpu_number(), | | 446 | aprint_normal(": %s, ID %d%s\n", model, cpu_number(), |
447 | cpu_number() == 0 ? " (primary)" : ""); | | 447 | cpu_number() == 0 ? " (primary)" : ""); |
448 | | | 448 | |
449 | /* set the cpu number */ | | 449 | /* set the cpu number */ |
450 | ci->ci_cpuid = cpu_number(); | | 450 | ci->ci_cpuid = cpu_number(); |
451 | hid0_save = hid0 = mfspr(SPR_HID0); | | 451 | hid0_save = hid0 = mfspr(SPR_HID0); |
452 | | | 452 | |
453 | cpu_probe_cache(); | | 453 | cpu_probe_cache(); |
454 | | | 454 | |
455 | /* | | 455 | /* |
456 | * Configure power-saving mode. | | 456 | * Configure power-saving mode. |
457 | */ | | 457 | */ |
458 | switch (vers) { | | 458 | switch (vers) { |
459 | case MPC604: | | 459 | case MPC604: |
460 | case MPC604e: | | 460 | case MPC604e: |
461 | case MPC604ev: | | 461 | case MPC604ev: |
462 | /* | | 462 | /* |
463 | * Do not have HID0 support settings, but can support | | 463 | * Do not have HID0 support settings, but can support |
464 | * MSR[POW] off | | 464 | * MSR[POW] off |
465 | */ | | 465 | */ |
466 | powersave = 1; | | 466 | powersave = 1; |
467 | break; | | 467 | break; |
468 | | | 468 | |
469 | case MPC603: | | 469 | case MPC603: |
470 | case MPC603e: | | 470 | case MPC603e: |
471 | case MPC603ev: | | 471 | case MPC603ev: |
472 | case MPC750: | | 472 | case MPC750: |
473 | case IBM750FX: | | 473 | case IBM750FX: |
474 | case MPC7400: | | 474 | case MPC7400: |
475 | case MPC7410: | | 475 | case MPC7410: |
476 | case MPC8240: | | 476 | case MPC8240: |
477 | case MPC8245: | | 477 | case MPC8245: |
478 | case MPCG2: | | 478 | case MPCG2: |
479 | /* Select DOZE mode. */ | | 479 | /* Select DOZE mode. */ |
480 | hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); | | 480 | hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); |
481 | hid0 |= HID0_DOZE | HID0_DPM; | | 481 | hid0 |= HID0_DOZE | HID0_DPM; |
482 | powersave = 1; | | 482 | powersave = 1; |
483 | break; | | 483 | break; |
484 | | | 484 | |
485 | case MPC7447A: | | 485 | case MPC7447A: |
486 | case MPC7448: | | 486 | case MPC7448: |
487 | case MPC7457: | | 487 | case MPC7457: |
488 | case MPC7455: | | 488 | case MPC7455: |
489 | case MPC7450: | | 489 | case MPC7450: |
490 | /* Enable the 7450 branch caches */ | | 490 | /* Enable the 7450 branch caches */ |
491 | hid0 |= HID0_SGE | HID0_BTIC; | | 491 | hid0 |= HID0_SGE | HID0_BTIC; |
492 | hid0 |= HID0_LRSTK | HID0_FOLD | HID0_BHT; | | 492 | hid0 |= HID0_LRSTK | HID0_FOLD | HID0_BHT; |
493 | /* Enable more and larger BAT registers */ | | 493 | /* Enable more and larger BAT registers */ |
494 | if (oeacpufeat & OEACPU_XBSEN) | | 494 | if (oeacpufeat & OEACPU_XBSEN) |
495 | hid0 |= HID0_XBSEN; | | 495 | hid0 |= HID0_XBSEN; |
496 | if (oeacpufeat & OEACPU_HIGHBAT) | | 496 | if (oeacpufeat & OEACPU_HIGHBAT) |
497 | hid0 |= HID0_HIGH_BAT_EN; | | 497 | hid0 |= HID0_HIGH_BAT_EN; |
498 | /* Disable BTIC on 7450 Rev 2.0 or earlier */ | | 498 | /* Disable BTIC on 7450 Rev 2.0 or earlier */ |
499 | if (vers == MPC7450 && (pvr & 0xFFFF) <= 0x0200) | | 499 | if (vers == MPC7450 && (pvr & 0xFFFF) <= 0x0200) |
500 | hid0 &= ~HID0_BTIC; | | 500 | hid0 &= ~HID0_BTIC; |
501 | /* Select NAP mode. */ | | 501 | /* Select NAP mode. */ |
502 | hid0 &= ~HID0_SLEEP; | | 502 | hid0 &= ~HID0_SLEEP; |
503 | hid0 |= HID0_NAP | HID0_DPM; | | 503 | hid0 |= HID0_NAP | HID0_DPM; |
504 | powersave = 1; | | 504 | powersave = 1; |
505 | break; | | 505 | break; |
506 | | | 506 | |
507 | case IBM970: | | 507 | case IBM970: |
508 | case IBM970FX: | | 508 | case IBM970FX: |
509 | case IBM970MP: | | 509 | case IBM970MP: |
510 | case IBMPOWER3II: | | 510 | case IBMPOWER3II: |
511 | default: | | 511 | default: |
512 | /* No power-saving mode is available. */ ; | | 512 | /* No power-saving mode is available. */ ; |
513 | } | | 513 | } |
514 | | | 514 | |
515 | #ifdef NAPMODE | | 515 | #ifdef NAPMODE |
516 | switch (vers) { | | 516 | switch (vers) { |
517 | case IBM750FX: | | 517 | case IBM750FX: |
518 | case MPC750: | | 518 | case MPC750: |
519 | case MPC7400: | | 519 | case MPC7400: |
520 | /* Select NAP mode. */ | | 520 | /* Select NAP mode. */ |
521 | hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); | | 521 | hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); |
522 | hid0 |= HID0_NAP; | | 522 | hid0 |= HID0_NAP; |
523 | break; | | 523 | break; |
524 | } | | 524 | } |
525 | #endif | | 525 | #endif |
526 | | | 526 | |
527 | switch (vers) { | | 527 | switch (vers) { |
528 | case IBM750FX: | | 528 | case IBM750FX: |
529 | case MPC750: | | 529 | case MPC750: |
530 | hid0 &= ~HID0_DBP; /* XXX correct? */ | | 530 | hid0 &= ~HID0_DBP; /* XXX correct? */ |
531 | hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; | | 531 | hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; |
532 | break; | | 532 | break; |
533 | | | 533 | |
534 | case MPC7400: | | 534 | case MPC7400: |
535 | case MPC7410: | | 535 | case MPC7410: |
536 | hid0 &= ~HID0_SPD; | | 536 | hid0 &= ~HID0_SPD; |
537 | hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; | | 537 | hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; |
538 | hid0 |= HID0_EIEC; | | 538 | hid0 |= HID0_EIEC; |
539 | break; | | 539 | break; |
540 | } | | 540 | } |
541 | | | 541 | |
542 | if (hid0 != hid0_save) { | | 542 | if (hid0 != hid0_save) { |
543 | mtspr(SPR_HID0, hid0); | | 543 | mtspr(SPR_HID0, hid0); |
544 | __asm volatile("sync;isync"); | | 544 | __asm volatile("sync;isync"); |
545 | } | | 545 | } |
546 | | | 546 | |
547 | | | 547 | |
548 | switch (vers) { | | 548 | switch (vers) { |
549 | case MPC601: | | 549 | case MPC601: |
550 | bitmask = HID0_601_BITMASK; | | 550 | bitmask = HID0_601_BITMASK; |
551 | break; | | 551 | break; |
552 | case MPC7450: | | 552 | case MPC7450: |
553 | case MPC7455: | | 553 | case MPC7455: |
554 | case MPC7457: | | 554 | case MPC7457: |
555 | bitmask = HID0_7450_BITMASK; | | 555 | bitmask = HID0_7450_BITMASK; |
556 | break; | | 556 | break; |
557 | case IBM970: | | 557 | case IBM970: |
558 | case IBM970FX: | | 558 | case IBM970FX: |
559 | case IBM970MP: | | 559 | case IBM970MP: |
560 | bitmask = 0; | | 560 | bitmask = 0; |
561 | break; | | 561 | break; |
562 | default: | | 562 | default: |
563 | bitmask = HID0_BITMASK; | | 563 | bitmask = HID0_BITMASK; |
564 | break; | | 564 | break; |
565 | } | | 565 | } |
566 | bitmask_snprintf(hid0, bitmask, hidbuf, sizeof hidbuf); | | 566 | bitmask_snprintf(hid0, bitmask, hidbuf, sizeof hidbuf); |
567 | aprint_normal("%s: HID0 %s, powersave: %d\n", self->dv_xname, hidbuf, | | 567 | aprint_normal("%s: HID0 %s, powersave: %d\n", self->dv_xname, hidbuf, |
568 | powersave); | | 568 | powersave); |
569 | | | 569 | |
570 | ci->ci_khz = 0; | | 570 | ci->ci_khz = 0; |
571 | | | 571 | |
572 | /* | | 572 | /* |
573 | * Display speed and cache configuration. | | 573 | * Display speed and cache configuration. |
574 | */ | | 574 | */ |
575 | switch (vers) { | | 575 | switch (vers) { |
576 | case MPC604: | | 576 | case MPC604: |
577 | case MPC604e: | | 577 | case MPC604e: |
578 | case MPC604ev: | | 578 | case MPC604ev: |
579 | case MPC750: | | 579 | case MPC750: |
580 | case IBM750FX: | | 580 | case IBM750FX: |
581 | case MPC7400: | | 581 | case MPC7400: |
582 | case MPC7410: | | 582 | case MPC7410: |
583 | case MPC7447A: | | 583 | case MPC7447A: |
584 | case MPC7448: | | 584 | case MPC7448: |
585 | case MPC7450: | | 585 | case MPC7450: |
586 | case MPC7455: | | 586 | case MPC7455: |
587 | case MPC7457: | | 587 | case MPC7457: |
588 | aprint_normal("%s: ", self->dv_xname); | | 588 | aprint_normal("%s: ", self->dv_xname); |
589 | cpu_probe_speed(ci); | | 589 | cpu_probe_speed(ci); |
590 | aprint_normal("%u.%02u MHz", | | 590 | aprint_normal("%u.%02u MHz", |
591 | ci->ci_khz / 1000, (ci->ci_khz / 10) % 100); | | 591 | ci->ci_khz / 1000, (ci->ci_khz / 10) % 100); |
592 | switch (vers) { | | 592 | switch (vers) { |
593 | case MPC7450: /* 7441 does not have L3! */ | | 593 | case MPC7450: /* 7441 does not have L3! */ |
594 | case MPC7455: /* 7445 does not have L3! */ | | 594 | case MPC7455: /* 7445 does not have L3! */ |
595 | case MPC7457: /* 7447 does not have L3! */ | | 595 | case MPC7457: /* 7447 does not have L3! */ |
596 | cpu_config_l3cr(vers); | | 596 | cpu_config_l3cr(vers); |
597 | break; | | 597 | break; |
598 | case IBM750FX: | | 598 | case IBM750FX: |
599 | case MPC750: | | 599 | case MPC750: |
600 | case MPC7400: | | 600 | case MPC7400: |
601 | case MPC7410: | | 601 | case MPC7410: |
602 | case MPC7447A: | | 602 | case MPC7447A: |
603 | case MPC7448: | | 603 | case MPC7448: |
604 | cpu_config_l2cr(pvr); | | 604 | cpu_config_l2cr(pvr); |
605 | break; | | 605 | break; |
606 | default: | | 606 | default: |
607 | break; | | 607 | break; |
608 | } | | 608 | } |
609 | aprint_normal("\n"); | | 609 | aprint_normal("\n"); |
610 | break; | | 610 | break; |
611 | } | | 611 | } |
612 | | | 612 | |
613 | #if NSYSMON_ENVSYS > 0 | | 613 | #if NSYSMON_ENVSYS > 0 |
614 | /* | | 614 | /* |
615 | * Attach MPC750 temperature sensor to the envsys subsystem. | | 615 | * Attach MPC750 temperature sensor to the envsys subsystem. |
616 | * XXX the 74xx series also has this sensor, but it is not | | 616 | * XXX the 74xx series also has this sensor, but it is not |
617 | * XXX supported by Motorola and may return values that are off by | | 617 | * XXX supported by Motorola and may return values that are off by |
618 | * XXX 35-55 degrees C. | | 618 | * XXX 35-55 degrees C. |
619 | */ | | 619 | */ |
620 | if (vers == MPC750 || vers == IBM750FX) | | 620 | if (vers == MPC750 || vers == IBM750FX) |
621 | cpu_tau_setup(ci); | | 621 | cpu_tau_setup(ci); |
622 | #endif | | 622 | #endif |
623 | | | 623 | |
624 | evcnt_attach_dynamic(&ci->ci_ev_clock, EVCNT_TYPE_INTR, | | 624 | evcnt_attach_dynamic(&ci->ci_ev_clock, EVCNT_TYPE_INTR, |
625 | NULL, self->dv_xname, "clock"); | | 625 | NULL, self->dv_xname, "clock"); |
626 | evcnt_attach_dynamic(&ci->ci_ev_softclock, EVCNT_TYPE_INTR, | | 626 | evcnt_attach_dynamic(&ci->ci_ev_softclock, EVCNT_TYPE_INTR, |
627 | NULL, self->dv_xname, "soft clock"); | | 627 | NULL, self->dv_xname, "soft clock"); |
628 | evcnt_attach_dynamic(&ci->ci_ev_softnet, EVCNT_TYPE_INTR, | | 628 | evcnt_attach_dynamic(&ci->ci_ev_softnet, EVCNT_TYPE_INTR, |
629 | NULL, self->dv_xname, "soft net"); | | 629 | NULL, self->dv_xname, "soft net"); |
630 | evcnt_attach_dynamic(&ci->ci_ev_softserial, EVCNT_TYPE_INTR, | | 630 | evcnt_attach_dynamic(&ci->ci_ev_softserial, EVCNT_TYPE_INTR, |
631 | NULL, self->dv_xname, "soft serial"); | | 631 | NULL, self->dv_xname, "soft serial"); |
632 | evcnt_attach_dynamic(&ci->ci_ev_traps, EVCNT_TYPE_TRAP, | | 632 | evcnt_attach_dynamic(&ci->ci_ev_traps, EVCNT_TYPE_TRAP, |
633 | NULL, self->dv_xname, "traps"); | | 633 | NULL, self->dv_xname, "traps"); |
634 | evcnt_attach_dynamic(&ci->ci_ev_kdsi, EVCNT_TYPE_TRAP, | | 634 | evcnt_attach_dynamic(&ci->ci_ev_kdsi, EVCNT_TYPE_TRAP, |
635 | &ci->ci_ev_traps, self->dv_xname, "kernel DSI traps"); | | 635 | &ci->ci_ev_traps, self->dv_xname, "kernel DSI traps"); |
636 | evcnt_attach_dynamic(&ci->ci_ev_udsi, EVCNT_TYPE_TRAP, | | 636 | evcnt_attach_dynamic(&ci->ci_ev_udsi, EVCNT_TYPE_TRAP, |
637 | &ci->ci_ev_traps, self->dv_xname, "user DSI traps"); | | 637 | &ci->ci_ev_traps, self->dv_xname, "user DSI traps"); |
638 | evcnt_attach_dynamic(&ci->ci_ev_udsi_fatal, EVCNT_TYPE_TRAP, | | 638 | evcnt_attach_dynamic(&ci->ci_ev_udsi_fatal, EVCNT_TYPE_TRAP, |
639 | &ci->ci_ev_udsi, self->dv_xname, "user DSI failures"); | | 639 | &ci->ci_ev_udsi, self->dv_xname, "user DSI failures"); |
640 | evcnt_attach_dynamic(&ci->ci_ev_kisi, EVCNT_TYPE_TRAP, | | 640 | evcnt_attach_dynamic(&ci->ci_ev_kisi, EVCNT_TYPE_TRAP, |
641 | &ci->ci_ev_traps, self->dv_xname, "kernel ISI traps"); | | 641 | &ci->ci_ev_traps, self->dv_xname, "kernel ISI traps"); |
642 | evcnt_attach_dynamic(&ci->ci_ev_isi, EVCNT_TYPE_TRAP, | | 642 | evcnt_attach_dynamic(&ci->ci_ev_isi, EVCNT_TYPE_TRAP, |
643 | &ci->ci_ev_traps, self->dv_xname, "user ISI traps"); | | 643 | &ci->ci_ev_traps, self->dv_xname, "user ISI traps"); |
644 | evcnt_attach_dynamic(&ci->ci_ev_isi_fatal, EVCNT_TYPE_TRAP, | | 644 | evcnt_attach_dynamic(&ci->ci_ev_isi_fatal, EVCNT_TYPE_TRAP, |
645 | &ci->ci_ev_isi, self->dv_xname, "user ISI failures"); | | 645 | &ci->ci_ev_isi, self->dv_xname, "user ISI failures"); |
646 | evcnt_attach_dynamic(&ci->ci_ev_scalls, EVCNT_TYPE_TRAP, | | 646 | evcnt_attach_dynamic(&ci->ci_ev_scalls, EVCNT_TYPE_TRAP, |
647 | &ci->ci_ev_traps, self->dv_xname, "system call traps"); | | 647 | &ci->ci_ev_traps, self->dv_xname, "system call traps"); |
648 | evcnt_attach_dynamic(&ci->ci_ev_pgm, EVCNT_TYPE_TRAP, | | 648 | evcnt_attach_dynamic(&ci->ci_ev_pgm, EVCNT_TYPE_TRAP, |
649 | &ci->ci_ev_traps, self->dv_xname, "PGM traps"); | | 649 | &ci->ci_ev_traps, self->dv_xname, "PGM traps"); |
650 | evcnt_attach_dynamic(&ci->ci_ev_fpu, EVCNT_TYPE_TRAP, | | 650 | evcnt_attach_dynamic(&ci->ci_ev_fpu, EVCNT_TYPE_TRAP, |
651 | &ci->ci_ev_traps, self->dv_xname, "FPU unavailable traps"); | | 651 | &ci->ci_ev_traps, self->dv_xname, "FPU unavailable traps"); |
652 | evcnt_attach_dynamic(&ci->ci_ev_fpusw, EVCNT_TYPE_TRAP, | | 652 | evcnt_attach_dynamic(&ci->ci_ev_fpusw, EVCNT_TYPE_TRAP, |
653 | &ci->ci_ev_fpu, self->dv_xname, "FPU context switches"); | | 653 | &ci->ci_ev_fpu, self->dv_xname, "FPU context switches"); |
654 | evcnt_attach_dynamic(&ci->ci_ev_ali, EVCNT_TYPE_TRAP, | | 654 | evcnt_attach_dynamic(&ci->ci_ev_ali, EVCNT_TYPE_TRAP, |
655 | &ci->ci_ev_traps, self->dv_xname, "user alignment traps"); | | 655 | &ci->ci_ev_traps, self->dv_xname, "user alignment traps"); |
656 | evcnt_attach_dynamic(&ci->ci_ev_ali_fatal, EVCNT_TYPE_TRAP, | | 656 | evcnt_attach_dynamic(&ci->ci_ev_ali_fatal, EVCNT_TYPE_TRAP, |
657 | &ci->ci_ev_ali, self->dv_xname, "user alignment traps"); | | 657 | &ci->ci_ev_ali, self->dv_xname, "user alignment traps"); |
658 | evcnt_attach_dynamic(&ci->ci_ev_umchk, EVCNT_TYPE_TRAP, | | 658 | evcnt_attach_dynamic(&ci->ci_ev_umchk, EVCNT_TYPE_TRAP, |
659 | &ci->ci_ev_umchk, self->dv_xname, "user MCHK failures"); | | 659 | &ci->ci_ev_umchk, self->dv_xname, "user MCHK failures"); |
660 | evcnt_attach_dynamic(&ci->ci_ev_vec, EVCNT_TYPE_TRAP, | | 660 | evcnt_attach_dynamic(&ci->ci_ev_vec, EVCNT_TYPE_TRAP, |
661 | &ci->ci_ev_traps, self->dv_xname, "AltiVec unavailable"); | | 661 | &ci->ci_ev_traps, self->dv_xname, "AltiVec unavailable"); |
662 | #ifdef ALTIVEC | | 662 | #ifdef ALTIVEC |
663 | if (cpu_altivec) { | | 663 | if (cpu_altivec) { |
664 | evcnt_attach_dynamic(&ci->ci_ev_vecsw, EVCNT_TYPE_TRAP, | | 664 | evcnt_attach_dynamic(&ci->ci_ev_vecsw, EVCNT_TYPE_TRAP, |
665 | &ci->ci_ev_vec, self->dv_xname, "AltiVec context switches"); | | 665 | &ci->ci_ev_vec, self->dv_xname, "AltiVec context switches"); |
666 | } | | 666 | } |
667 | #endif | | 667 | #endif |
668 | evcnt_attach_dynamic(&ci->ci_ev_ipi, EVCNT_TYPE_INTR, | | 668 | evcnt_attach_dynamic(&ci->ci_ev_ipi, EVCNT_TYPE_INTR, |
669 | NULL, self->dv_xname, "IPIs"); | | 669 | NULL, self->dv_xname, "IPIs"); |
670 | } | | 670 | } |
671 | | | 671 | |
672 | /* | | 672 | /* |
673 | * According to a document labeled "PVR Register Settings": | | 673 | * According to a document labeled "PVR Register Settings": |
674 | ** For integrated microprocessors the PVR register inside the device | | 674 | ** For integrated microprocessors the PVR register inside the device |
675 | ** will identify the version of the microprocessor core. You must also | | 675 | ** will identify the version of the microprocessor core. You must also |
676 | ** read the Device ID, PCI register 02, to identify the part and the | | 676 | ** read the Device ID, PCI register 02, to identify the part and the |
677 | ** Revision ID, PCI register 08, to identify the revision of the | | 677 | ** Revision ID, PCI register 08, to identify the revision of the |
678 | ** integrated microprocessor. | | 678 | ** integrated microprocessor. |
679 | * This apparently applies to 8240/8245/8241, PVR 00810101 and 80811014 | | 679 | * This apparently applies to 8240/8245/8241, PVR 00810101 and 80811014 |
680 | */ | | 680 | */ |
681 | | | 681 | |
682 | void | | 682 | void |
683 | cpu_identify(char *str, size_t len) | | 683 | cpu_identify(char *str, size_t len) |
684 | { | | 684 | { |
685 | u_int pvr, major, minor; | | 685 | u_int pvr, major, minor; |
686 | uint16_t vers, rev, revfmt; | | 686 | uint16_t vers, rev, revfmt; |
687 | const struct cputab *cp; | | 687 | const struct cputab *cp; |
688 | const char *name; | | 688 | const char *name; |
689 | size_t n; | | 689 | size_t n; |
690 | | | 690 | |
691 | pvr = mfpvr(); | | 691 | pvr = mfpvr(); |
692 | vers = pvr >> 16; | | 692 | vers = pvr >> 16; |
693 | rev = pvr; | | 693 | rev = pvr; |
694 | | | 694 | |
695 | switch (vers) { | | 695 | switch (vers) { |
696 | case MPC7410: | | 696 | case MPC7410: |
697 | minor = (pvr >> 0) & 0xff; | | 697 | minor = (pvr >> 0) & 0xff; |
698 | major = minor <= 4 ? 1 : 2; | | 698 | major = minor <= 4 ? 1 : 2; |
699 | break; | | 699 | break; |
700 | case MPCG2: /*XXX see note above */ | | 700 | case MPCG2: /*XXX see note above */ |
701 | major = (pvr >> 4) & 0xf; | | 701 | major = (pvr >> 4) & 0xf; |
702 | minor = (pvr >> 0) & 0xf; | | 702 | minor = (pvr >> 0) & 0xf; |
703 | break; | | 703 | break; |
704 | default: | | 704 | default: |
705 | major = (pvr >> 8) & 0xf; | | 705 | major = (pvr >> 8) & 0xf; |
706 | minor = (pvr >> 0) & 0xf; | | 706 | minor = (pvr >> 0) & 0xf; |
707 | } | | 707 | } |
708 | | | 708 | |
709 | for (cp = models; cp->name[0] != '\0'; cp++) { | | 709 | for (cp = models; cp->name[0] != '\0'; cp++) { |
710 | if (cp->version == vers) | | 710 | if (cp->version == vers) |
711 | break; | | 711 | break; |
712 | } | | 712 | } |
713 | | | 713 | |
714 | if (str == NULL) { | | 714 | if (str == NULL) { |
715 | str = cpu_model; | | 715 | str = cpu_model; |
716 | len = sizeof(cpu_model); | | 716 | len = sizeof(cpu_model); |
717 | cpu = vers; | | 717 | cpu = vers; |
718 | } | | 718 | } |
719 | | | 719 | |
720 | revfmt = cp->revfmt; | | 720 | revfmt = cp->revfmt; |
721 | name = cp->name; | | 721 | name = cp->name; |
722 | if (rev == MPC750 && pvr == 15) { | | 722 | if (rev == MPC750 && pvr == 15) { |
723 | name = "755"; | | 723 | name = "755"; |
724 | revfmt = REVFMT_HEX; | | 724 | revfmt = REVFMT_HEX; |
725 | } | | 725 | } |
726 | | | 726 | |
727 | if (cp->name[0] != '\0') { | | 727 | if (cp->name[0] != '\0') { |
728 | n = snprintf(str, len, "%s (Revision ", cp->name); | | 728 | n = snprintf(str, len, "%s (Revision ", cp->name); |
729 | } else { | | 729 | } else { |
730 | n = snprintf(str, len, "Version %#x (Revision ", vers); | | 730 | n = snprintf(str, len, "Version %#x (Revision ", vers); |
731 | } | | 731 | } |
732 | if (len > n) { | | 732 | if (len > n) { |
733 | switch (revfmt) { | | 733 | switch (revfmt) { |
734 | case REVFMT_MAJMIN: | | 734 | case REVFMT_MAJMIN: |
735 | snprintf(str + n, len - n, "%u.%u)", major, minor); | | 735 | snprintf(str + n, len - n, "%u.%u)", major, minor); |
736 | break; | | 736 | break; |
737 | case REVFMT_HEX: | | 737 | case REVFMT_HEX: |
738 | snprintf(str + n, len - n, "0x%04x)", rev); | | 738 | snprintf(str + n, len - n, "0x%04x)", rev); |
739 | break; | | 739 | break; |
740 | case REVFMT_DEC: | | 740 | case REVFMT_DEC: |
741 | snprintf(str + n, len - n, "%u)", rev); | | 741 | snprintf(str + n, len - n, "%u)", rev); |
742 | break; | | 742 | break; |
743 | } | | 743 | } |
744 | } | | 744 | } |
745 | } | | 745 | } |
746 | | | 746 | |
747 | #ifdef L2CR_CONFIG | | 747 | #ifdef L2CR_CONFIG |
748 | u_int l2cr_config = L2CR_CONFIG; | | 748 | u_int l2cr_config = L2CR_CONFIG; |
749 | #else | | 749 | #else |
750 | u_int l2cr_config = 0; | | 750 | u_int l2cr_config = 0; |
751 | #endif | | 751 | #endif |
752 | | | 752 | |
753 | #ifdef L3CR_CONFIG | | 753 | #ifdef L3CR_CONFIG |
754 | u_int l3cr_config = L3CR_CONFIG; | | 754 | u_int l3cr_config = L3CR_CONFIG; |
755 | #else | | 755 | #else |
756 | u_int l3cr_config = 0; | | 756 | u_int l3cr_config = 0; |
757 | #endif | | 757 | #endif |
758 | | | 758 | |
759 | void | | 759 | void |
760 | cpu_enable_l2cr(register_t l2cr) | | 760 | cpu_enable_l2cr(register_t l2cr) |
761 | { | | 761 | { |
762 | register_t msr, x; | | 762 | register_t msr, x; |
763 | uint16_t vers; | | 763 | uint16_t vers; |
764 | | | 764 | |
765 | vers = mfpvr() >> 16; | | 765 | vers = mfpvr() >> 16; |
766 | | | 766 | |
767 | /* Disable interrupts and set the cache config bits. */ | | 767 | /* Disable interrupts and set the cache config bits. */ |
768 | msr = mfmsr(); | | 768 | msr = mfmsr(); |
769 | mtmsr(msr & ~PSL_EE); | | 769 | mtmsr(msr & ~PSL_EE); |
770 | #ifdef ALTIVEC | | 770 | #ifdef ALTIVEC |
771 | if (cpu_altivec) | | 771 | if (cpu_altivec) |
772 | __asm volatile("dssall"); | | 772 | __asm volatile("dssall"); |
773 | #endif | | 773 | #endif |
774 | __asm volatile("sync"); | | 774 | __asm volatile("sync"); |
775 | mtspr(SPR_L2CR, l2cr & ~L2CR_L2E); | | 775 | mtspr(SPR_L2CR, l2cr & ~L2CR_L2E); |
776 | __asm volatile("sync"); | | 776 | __asm volatile("sync"); |
777 | | | 777 | |
778 | /* Wait for L2 clock to be stable (640 L2 clocks). */ | | 778 | /* Wait for L2 clock to be stable (640 L2 clocks). */ |
779 | delay(100); | | 779 | delay(100); |
780 | | | 780 | |
781 | /* Invalidate all L2 contents. */ | | 781 | /* Invalidate all L2 contents. */ |
782 | if (MPC745X_P(vers)) { | | 782 | if (MPC745X_P(vers)) { |
783 | mtspr(SPR_L2CR, l2cr | L2CR_L2I); | | 783 | mtspr(SPR_L2CR, l2cr | L2CR_L2I); |
784 | do { | | 784 | do { |
785 | x = mfspr(SPR_L2CR); | | 785 | x = mfspr(SPR_L2CR); |
786 | } while (x & L2CR_L2I); | | 786 | } while (x & L2CR_L2I); |
787 | } else { | | 787 | } else { |
788 | mtspr(SPR_L2CR, l2cr | L2CR_L2I); | | 788 | mtspr(SPR_L2CR, l2cr | L2CR_L2I); |
789 | do { | | 789 | do { |
790 | x = mfspr(SPR_L2CR); | | 790 | x = mfspr(SPR_L2CR); |
791 | } while (x & L2CR_L2IP); | | 791 | } while (x & L2CR_L2IP); |
792 | } | | 792 | } |
793 | /* Enable L2 cache. */ | | 793 | /* Enable L2 cache. */ |
794 | l2cr |= L2CR_L2E; | | 794 | l2cr |= L2CR_L2E; |
795 | mtspr(SPR_L2CR, l2cr); | | 795 | mtspr(SPR_L2CR, l2cr); |
796 | mtmsr(msr); | | 796 | mtmsr(msr); |
797 | } | | 797 | } |
798 | | | 798 | |
799 | void | | 799 | void |
800 | cpu_enable_l3cr(register_t l3cr) | | 800 | cpu_enable_l3cr(register_t l3cr) |
801 | { | | 801 | { |
802 | register_t x; | | 802 | register_t x; |
803 | | | 803 | |
804 | /* By The Book (numbered steps from section 3.7.1.3 of MPC7450UM) */ | | 804 | /* By The Book (numbered steps from section 3.7.1.3 of MPC7450UM) */ |
805 | | | 805 | |
806 | /* | | 806 | /* |
807 | * 1: Set all L3CR bits for final config except L3E, L3I, L3PE, and | | 807 | * 1: Set all L3CR bits for final config except L3E, L3I, L3PE, and |
808 | * L3CLKEN. (also mask off reserved bits in case they were included | | 808 | * L3CLKEN. (also mask off reserved bits in case they were included |
809 | * in L3CR_CONFIG) | | 809 | * in L3CR_CONFIG) |
810 | */ | | 810 | */ |
811 | l3cr &= ~(L3CR_L3E|L3CR_L3I|L3CR_L3PE|L3CR_L3CLKEN|L3CR_RESERVED); | | 811 | l3cr &= ~(L3CR_L3E|L3CR_L3I|L3CR_L3PE|L3CR_L3CLKEN|L3CR_RESERVED); |
812 | mtspr(SPR_L3CR, l3cr); | | 812 | mtspr(SPR_L3CR, l3cr); |
813 | | | 813 | |
814 | /* 2: Set L3CR[5] (otherwise reserved bit) to 1 */ | | 814 | /* 2: Set L3CR[5] (otherwise reserved bit) to 1 */ |
815 | l3cr |= 0x04000000; | | 815 | l3cr |= 0x04000000; |
816 | mtspr(SPR_L3CR, l3cr); | | 816 | mtspr(SPR_L3CR, l3cr); |
817 | | | 817 | |
818 | /* 3: Set L3CLKEN to 1*/ | | 818 | /* 3: Set L3CLKEN to 1*/ |
819 | l3cr |= L3CR_L3CLKEN; | | 819 | l3cr |= L3CR_L3CLKEN; |
820 | mtspr(SPR_L3CR, l3cr); | | 820 | mtspr(SPR_L3CR, l3cr); |
821 | | | 821 | |
822 | /* 4/5: Perform a global cache invalidate (ref section 3.7.3.6) */ | | 822 | /* 4/5: Perform a global cache invalidate (ref section 3.7.3.6) */ |
823 | __asm volatile("dssall;sync"); | | 823 | __asm volatile("dssall;sync"); |
824 | /* L3 cache is already disabled, no need to clear L3E */ | | 824 | /* L3 cache is already disabled, no need to clear L3E */ |
825 | mtspr(SPR_L3CR, l3cr|L3CR_L3I); | | 825 | mtspr(SPR_L3CR, l3cr|L3CR_L3I); |
826 | do { | | 826 | do { |
827 | x = mfspr(SPR_L3CR); | | 827 | x = mfspr(SPR_L3CR); |
828 | } while (x & L3CR_L3I); | | 828 | } while (x & L3CR_L3I); |
829 | | | 829 | |
830 | /* 6: Clear L3CLKEN to 0 */ | | 830 | /* 6: Clear L3CLKEN to 0 */ |
831 | l3cr &= ~L3CR_L3CLKEN; | | 831 | l3cr &= ~L3CR_L3CLKEN; |
832 | mtspr(SPR_L3CR, l3cr); | | 832 | mtspr(SPR_L3CR, l3cr); |
833 | | | 833 | |
834 | /* 7: Perform a 'sync' and wait at least 100 CPU cycles */ | | 834 | /* 7: Perform a 'sync' and wait at least 100 CPU cycles */ |
835 | __asm volatile("sync"); | | 835 | __asm volatile("sync"); |
836 | delay(100); | | 836 | delay(100); |
837 | | | 837 | |
838 | /* 8: Set L3E and L3CLKEN */ | | 838 | /* 8: Set L3E and L3CLKEN */ |
839 | l3cr |= (L3CR_L3E|L3CR_L3CLKEN); | | 839 | l3cr |= (L3CR_L3E|L3CR_L3CLKEN); |
840 | mtspr(SPR_L3CR, l3cr); | | 840 | mtspr(SPR_L3CR, l3cr); |
841 | | | 841 | |
842 | /* 9: Perform a 'sync' and wait at least 100 CPU cycles */ | | 842 | /* 9: Perform a 'sync' and wait at least 100 CPU cycles */ |
843 | __asm volatile("sync"); | | 843 | __asm volatile("sync"); |
844 | delay(100); | | 844 | delay(100); |
845 | } | | 845 | } |
846 | | | 846 | |
847 | void | | 847 | void |
848 | cpu_config_l2cr(int pvr) | | 848 | cpu_config_l2cr(int pvr) |
849 | { | | 849 | { |
850 | register_t l2cr; | | 850 | register_t l2cr; |
851 | u_int vers = (pvr >> 16) & 0xffff; | | 851 | u_int vers = (pvr >> 16) & 0xffff; |
852 | | | 852 | |
853 | l2cr = mfspr(SPR_L2CR); | | 853 | l2cr = mfspr(SPR_L2CR); |
854 | | | 854 | |
855 | /* | | 855 | /* |
856 | * For MP systems, the firmware may only configure the L2 cache | | 856 | * For MP systems, the firmware may only configure the L2 cache |
857 | * on the first CPU. In this case, assume that the other CPUs | | 857 | * on the first CPU. In this case, assume that the other CPUs |
858 | * should use the same value for L2CR. | | 858 | * should use the same value for L2CR. |
859 | */ | | 859 | */ |
860 | if ((l2cr & L2CR_L2E) != 0 && l2cr_config == 0) { | | 860 | if ((l2cr & L2CR_L2E) != 0 && l2cr_config == 0) { |
861 | l2cr_config = l2cr; | | 861 | l2cr_config = l2cr; |
862 | } | | 862 | } |
863 | | | 863 | |
864 | /* | | 864 | /* |
865 | * Configure L2 cache if not enabled. | | 865 | * Configure L2 cache if not enabled. |
866 | */ | | 866 | */ |
867 | if ((l2cr & L2CR_L2E) == 0 && l2cr_config != 0) { | | 867 | if ((l2cr & L2CR_L2E) == 0 && l2cr_config != 0) { |
868 | cpu_enable_l2cr(l2cr_config); | | 868 | cpu_enable_l2cr(l2cr_config); |
869 | l2cr = mfspr(SPR_L2CR); | | 869 | l2cr = mfspr(SPR_L2CR); |
870 | } | | 870 | } |
871 | | | 871 | |
872 | if ((l2cr & L2CR_L2E) == 0) { | | 872 | if ((l2cr & L2CR_L2E) == 0) { |
873 | aprint_normal(" L2 cache present but not enabled "); | | 873 | aprint_normal(" L2 cache present but not enabled "); |
874 | return; | | 874 | return; |
875 | } | | 875 | } |
876 | aprint_normal(","); | | 876 | aprint_normal(","); |
877 | | | 877 | |
878 | switch (vers) { | | 878 | switch (vers) { |
879 | case IBM750FX: | | 879 | case IBM750FX: |
880 | cpu_fmttab_print(cpu_ibm750_l2cr_formats, l2cr); | | 880 | cpu_fmttab_print(cpu_ibm750_l2cr_formats, l2cr); |
881 | break; | | 881 | break; |
882 | case MPC750: | | 882 | case MPC750: |
883 | if ((pvr & 0xffffff00) == 0x00082200 /* IBM750CX */ || | | 883 | if ((pvr & 0xffffff00) == 0x00082200 /* IBM750CX */ || |
884 | (pvr & 0xffffef00) == 0x00082300 /* IBM750CXe */) | | 884 | (pvr & 0xffffef00) == 0x00082300 /* IBM750CXe */) |
885 | cpu_fmttab_print(cpu_ibm750_l2cr_formats, l2cr); | | 885 | cpu_fmttab_print(cpu_ibm750_l2cr_formats, l2cr); |
886 | else | | 886 | else |
887 | cpu_fmttab_print(cpu_l2cr_formats, l2cr); | | 887 | cpu_fmttab_print(cpu_l2cr_formats, l2cr); |
888 | break; | | 888 | break; |
889 | case MPC7447A: | | 889 | case MPC7447A: |
890 | case MPC7457: | | 890 | case MPC7457: |
891 | cpu_fmttab_print(cpu_7457_l2cr_formats, l2cr); | | 891 | cpu_fmttab_print(cpu_7457_l2cr_formats, l2cr); |
892 | return; | | 892 | return; |
893 | case MPC7448: | | 893 | case MPC7448: |
894 | cpu_fmttab_print(cpu_7448_l2cr_formats, l2cr); | | 894 | cpu_fmttab_print(cpu_7448_l2cr_formats, l2cr); |
895 | return; | | 895 | return; |
896 | case MPC7450: | | 896 | case MPC7450: |
897 | case MPC7455: | | 897 | case MPC7455: |
898 | cpu_fmttab_print(cpu_7450_l2cr_formats, l2cr); | | 898 | cpu_fmttab_print(cpu_7450_l2cr_formats, l2cr); |
899 | break; | | 899 | break; |
900 | default: | | 900 | default: |
901 | cpu_fmttab_print(cpu_l2cr_formats, l2cr); | | 901 | cpu_fmttab_print(cpu_l2cr_formats, l2cr); |
902 | break; | | 902 | break; |
903 | } | | 903 | } |
904 | } | | 904 | } |
905 | | | 905 | |
906 | void | | 906 | void |
907 | cpu_config_l3cr(int vers) | | 907 | cpu_config_l3cr(int vers) |
908 | { | | 908 | { |
909 | register_t l2cr; | | 909 | register_t l2cr; |
910 | register_t l3cr; | | 910 | register_t l3cr; |
911 | | | 911 | |
912 | l2cr = mfspr(SPR_L2CR); | | 912 | l2cr = mfspr(SPR_L2CR); |
913 | | | 913 | |
914 | /* | | 914 | /* |
915 | * For MP systems, the firmware may only configure the L2 cache | | 915 | * For MP systems, the firmware may only configure the L2 cache |
916 | * on the first CPU. In this case, assume that the other CPUs | | 916 | * on the first CPU. In this case, assume that the other CPUs |
917 | * should use the same value for L2CR. | | 917 | * should use the same value for L2CR. |
918 | */ | | 918 | */ |
919 | if ((l2cr & L2CR_L2E) != 0 && l2cr_config == 0) { | | 919 | if ((l2cr & L2CR_L2E) != 0 && l2cr_config == 0) { |
920 | l2cr_config = l2cr; | | 920 | l2cr_config = l2cr; |
921 | } | | 921 | } |
922 | | | 922 | |
923 | /* | | 923 | /* |
924 | * Configure L2 cache if not enabled. | | 924 | * Configure L2 cache if not enabled. |
925 | */ | | 925 | */ |
926 | if ((l2cr & L2CR_L2E) == 0 && l2cr_config != 0) { | | 926 | if ((l2cr & L2CR_L2E) == 0 && l2cr_config != 0) { |
927 | cpu_enable_l2cr(l2cr_config); | | 927 | cpu_enable_l2cr(l2cr_config); |
928 | l2cr = mfspr(SPR_L2CR); | | 928 | l2cr = mfspr(SPR_L2CR); |
929 | } | | 929 | } |
930 | | | 930 | |
931 | aprint_normal(","); | | 931 | aprint_normal(","); |
932 | switch (vers) { | | 932 | switch (vers) { |
933 | case MPC7447A: | | 933 | case MPC7447A: |
934 | case MPC7457: | | 934 | case MPC7457: |
935 | cpu_fmttab_print(cpu_7457_l2cr_formats, l2cr); | | 935 | cpu_fmttab_print(cpu_7457_l2cr_formats, l2cr); |
936 | return; | | 936 | return; |
937 | case MPC7448: | | 937 | case MPC7448: |
938 | cpu_fmttab_print(cpu_7448_l2cr_formats, l2cr); | | 938 | cpu_fmttab_print(cpu_7448_l2cr_formats, l2cr); |
939 | return; | | 939 | return; |
940 | default: | | 940 | default: |
941 | cpu_fmttab_print(cpu_7450_l2cr_formats, l2cr); | | 941 | cpu_fmttab_print(cpu_7450_l2cr_formats, l2cr); |
942 | break; | | 942 | break; |
943 | } | | 943 | } |
944 | | | 944 | |
945 | l3cr = mfspr(SPR_L3CR); | | 945 | l3cr = mfspr(SPR_L3CR); |
946 | | | 946 | |
947 | /* | | 947 | /* |
948 | * For MP systems, the firmware may only configure the L3 cache | | 948 | * For MP systems, the firmware may only configure the L3 cache |
949 | * on the first CPU. In this case, assume that the other CPUs | | 949 | * on the first CPU. In this case, assume that the other CPUs |
950 | * should use the same value for L3CR. | | 950 | * should use the same value for L3CR. |
951 | */ | | 951 | */ |
952 | if ((l3cr & L3CR_L3E) != 0 && l3cr_config == 0) { | | 952 | if ((l3cr & L3CR_L3E) != 0 && l3cr_config == 0) { |
953 | l3cr_config = l3cr; | | 953 | l3cr_config = l3cr; |
954 | } | | 954 | } |
955 | | | 955 | |
956 | /* | | 956 | /* |
957 | * Configure L3 cache if not enabled. | | 957 | * Configure L3 cache if not enabled. |
958 | */ | | 958 | */ |
959 | if ((l3cr & L3CR_L3E) == 0 && l3cr_config != 0) { | | 959 | if ((l3cr & L3CR_L3E) == 0 && l3cr_config != 0) { |
960 | cpu_enable_l3cr(l3cr_config); | | 960 | cpu_enable_l3cr(l3cr_config); |
961 | l3cr = mfspr(SPR_L3CR); | | 961 | l3cr = mfspr(SPR_L3CR); |
962 | } | | 962 | } |
963 | | | 963 | |
964 | if (l3cr & L3CR_L3E) { | | 964 | if (l3cr & L3CR_L3E) { |
965 | aprint_normal(","); | | 965 | aprint_normal(","); |
966 | cpu_fmttab_print(cpu_7450_l3cr_formats, l3cr); | | 966 | cpu_fmttab_print(cpu_7450_l3cr_formats, l3cr); |
967 | } | | 967 | } |
968 | } | | 968 | } |
969 | | | 969 | |
970 | void | | 970 | void |
971 | cpu_probe_speed(struct cpu_info *ci) | | 971 | cpu_probe_speed(struct cpu_info *ci) |
972 | { | | 972 | { |
973 | uint64_t cps; | | 973 | uint64_t cps; |
974 | | | 974 | |
975 | mtspr(SPR_MMCR0, MMCR0_FC); | | 975 | mtspr(SPR_MMCR0, MMCR0_FC); |
976 | mtspr(SPR_PMC1, 0); | | 976 | mtspr(SPR_PMC1, 0); |
977 | mtspr(SPR_MMCR0, MMCR0_PMC1SEL(PMCN_CYCLES)); | | 977 | mtspr(SPR_MMCR0, MMCR0_PMC1SEL(PMCN_CYCLES)); |
978 | delay(100000); | | 978 | delay(100000); |
979 | cps = (mfspr(SPR_PMC1) * 10) + 4999; | | 979 | cps = (mfspr(SPR_PMC1) * 10) + 4999; |
980 | | | 980 | |
981 | mtspr(SPR_MMCR0, MMCR0_FC); | | 981 | mtspr(SPR_MMCR0, MMCR0_FC); |
982 | | | 982 | |
983 | ci->ci_khz = cps / 1000; | | 983 | ci->ci_khz = cps / 1000; |
984 | } | | 984 | } |
985 | | | 985 | |
986 | #if NSYSMON_ENVSYS > 0 | | 986 | #if NSYSMON_ENVSYS > 0 |
987 | void | | 987 | void |
988 | cpu_tau_setup(struct cpu_info *ci) | | 988 | cpu_tau_setup(struct cpu_info *ci) |
989 | { | | 989 | { |
990 | struct sysmon_envsys *sme; | | 990 | struct sysmon_envsys *sme; |
991 | envsys_data_t sensor; | | 991 | envsys_data_t sensor; |
992 | int error; | | 992 | int error; |
993 | | | 993 | |
994 | sme = sysmon_envsys_create(); | | 994 | sme = sysmon_envsys_create(); |
995 | | | 995 | |
996 | sensor.state = ENVSYS_SVALID; | | 996 | sensor.state = ENVSYS_SVALID; |
997 | sensor.units = ENVSYS_STEMP; | | 997 | sensor.units = ENVSYS_STEMP; |
998 | (void)strlcpy(sensor.desc, "CPU Temp", sizeof(sensor.desc)); | | 998 | (void)strlcpy(sensor.desc, "CPU Temp", sizeof(sensor.desc)); |
999 | if (sysmon_envsys_sensor_attach(sme, &sensor)) { | | 999 | if (sysmon_envsys_sensor_attach(sme, &sensor)) { |
1000 | sysmon_envsys_destroy(sme); | | 1000 | sysmon_envsys_destroy(sme); |
1001 | return; | | 1001 | return; |
1002 | } | | 1002 | } |
1003 | | | 1003 | |
1004 | sme->sme_name = ci->ci_dev->dv_xname; | | 1004 | sme->sme_name = ci->ci_dev->dv_xname; |
1005 | sme->sme_cookie = ci; | | 1005 | sme->sme_cookie = ci; |
1006 | sme->sme_refresh = cpu_tau_refresh; | | 1006 | sme->sme_refresh = cpu_tau_refresh; |
1007 | | | 1007 | |
1008 | if ((error = sysmon_envsys_register(sme)) != 0) { | | 1008 | if ((error = sysmon_envsys_register(sme)) != 0) { |
1009 | aprint_error("%s: unable to register with sysmon (%d)\n", | | 1009 | aprint_error("%s: unable to register with sysmon (%d)\n", |
1010 | ci->ci_dev->dv_xname, error); | | 1010 | ci->ci_dev->dv_xname, error); |
1011 | sysmon_envsys_destroy(sme); | | 1011 | sysmon_envsys_destroy(sme); |
1012 | } | | 1012 | } |
1013 | } | | 1013 | } |
1014 | | | 1014 | |
1015 | | | 1015 | |
1016 | /* Find the temperature of the CPU. */ | | 1016 | /* Find the temperature of the CPU. */ |
1017 | void | | 1017 | void |
1018 | cpu_tau_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) | | 1018 | cpu_tau_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) |
1019 | { | | 1019 | { |
1020 | int i, threshold, count; | | 1020 | int i, threshold, count; |
1021 | | | 1021 | |
1022 | threshold = 64; /* Half of the 7-bit sensor range */ | | 1022 | threshold = 64; /* Half of the 7-bit sensor range */ |
1023 | mtspr(SPR_THRM1, 0); | | 1023 | mtspr(SPR_THRM1, 0); |
1024 | mtspr(SPR_THRM2, 0); | | 1024 | mtspr(SPR_THRM2, 0); |
1025 | /* XXX This counter is supposed to be "at least 20 microseonds, in | | 1025 | /* XXX This counter is supposed to be "at least 20 microseonds, in |
1026 | * XXX units of clock cycles". Since we don't have convenient | | 1026 | * XXX units of clock cycles". Since we don't have convenient |
1027 | * XXX access to the CPU speed, set it to a conservative value, | | 1027 | * XXX access to the CPU speed, set it to a conservative value, |
1028 | * XXX that is, assuming a fast (1GHz) G3 CPU (As of February 2002, | | 1028 | * XXX that is, assuming a fast (1GHz) G3 CPU (As of February 2002, |
1029 | * XXX the fastest G3 processor is 700MHz) . The cost is that | | 1029 | * XXX the fastest G3 processor is 700MHz) . The cost is that |
1030 | * XXX measuring the temperature takes a bit longer. | | 1030 | * XXX measuring the temperature takes a bit longer. |
1031 | */ | | 1031 | */ |
1032 | mtspr(SPR_THRM3, SPR_THRM_TIMER(20000) | SPR_THRM_ENABLE); | | 1032 | mtspr(SPR_THRM3, SPR_THRM_TIMER(20000) | SPR_THRM_ENABLE); |
1033 | | | 1033 | |
1034 | /* Successive-approximation code adapted from Motorola | | 1034 | /* Successive-approximation code adapted from Motorola |
1035 | * application note AN1800/D, "Programming the Thermal Assist | | 1035 | * application note AN1800/D, "Programming the Thermal Assist |
1036 | * Unit in the MPC750 Microprocessor". | | 1036 | * Unit in the MPC750 Microprocessor". |
1037 | */ | | 1037 | */ |
1038 | for (i = 4; i >= 0 ; i--) { | | 1038 | for (i = 4; i >= 0 ; i--) { |
1039 | mtspr(SPR_THRM1, | | 1039 | mtspr(SPR_THRM1, |
1040 | SPR_THRM_THRESHOLD(threshold) | SPR_THRM_VALID); | | 1040 | SPR_THRM_THRESHOLD(threshold) | SPR_THRM_VALID); |
1041 | count = 0; | | 1041 | count = 0; |
1042 | while ((count < 100) && | | 1042 | while ((count < 100) && |
1043 | ((mfspr(SPR_THRM1) & SPR_THRM_TIV) == 0)) { | | 1043 | ((mfspr(SPR_THRM1) & SPR_THRM_TIV) == 0)) { |
1044 | count++; | | 1044 | count++; |
1045 | delay(1); | | 1045 | delay(1); |
1046 | } | | 1046 | } |
1047 | if (mfspr(SPR_THRM1) & SPR_THRM_TIN) { | | 1047 | if (mfspr(SPR_THRM1) & SPR_THRM_TIN) { |
1048 | /* The interrupt bit was set, meaning the | | 1048 | /* The interrupt bit was set, meaning the |
1049 | * temperature was above the threshold | | 1049 | * temperature was above the threshold |
1050 | */ | | 1050 | */ |
1051 | threshold += 2 << i; | | 1051 | threshold += 2 << i; |
1052 | } else { | | 1052 | } else { |
1053 | /* Temperature was below the threshold */ | | 1053 | /* Temperature was below the threshold */ |
1054 | threshold -= 2 << i; | | 1054 | threshold -= 2 << i; |
1055 | } | | 1055 | } |
1056 | } | | 1056 | } |
1057 | threshold += 2; | | 1057 | threshold += 2; |
1058 | | | 1058 | |
1059 | /* Convert the temperature in degrees C to microkelvin */ | | 1059 | /* Convert the temperature in degrees C to microkelvin */ |
1060 | edata->value_cur = (threshold * 1000000) + 273150000; | | 1060 | edata->value_cur = (threshold * 1000000) + 273150000; |
1061 | } | | 1061 | } |
1062 | #endif /* NSYSMON_ENVSYS > 0 */ | | 1062 | #endif /* NSYSMON_ENVSYS > 0 */ |
1063 | | | 1063 | |
1064 | #ifdef MULTIPROCESSOR | | 1064 | #ifdef MULTIPROCESSOR |
1065 | extern volatile u_int cpu_spinstart_ack; | | 1065 | extern volatile u_int cpu_spinstart_ack; |
1066 | | | 1066 | |
1067 | int | | 1067 | int |
1068 | cpu_spinup(struct device *self, struct cpu_info *ci) | | 1068 | cpu_spinup(struct device *self, struct cpu_info *ci) |
1069 | { | | 1069 | { |
1070 | volatile struct cpu_hatch_data hatch_data, *h = &hatch_data; | | 1070 | volatile struct cpu_hatch_data hatch_data, *h = &hatch_data; |
1071 | struct pglist mlist; | | 1071 | struct pglist mlist; |
1072 | int i, error, pvr, vers; | | 1072 | int i, error, pvr, vers; |
1073 | char *cp, *hp; | | 1073 | char *cp, *hp; |
1074 | | | 1074 | |
1075 | pvr = mfpvr(); | | 1075 | pvr = mfpvr(); |
1076 | vers = pvr >> 16; | | 1076 | vers = pvr >> 16; |
1077 | KASSERT(ci != curcpu()); | | 1077 | KASSERT(ci != curcpu()); |
1078 | | | 1078 | |
1079 | /* | | 1079 | /* |
1080 | * Allocate some contiguous pages for the intteup PCB and stack | | 1080 | * Allocate some contiguous pages for the intteup PCB and stack |
1081 | * from the lowest 256MB (because bat0 always maps it va == pa). | | 1081 | * from the lowest 256MB (because bat0 always maps it va == pa). |
1082 | * Must be 16 byte aligned. | | 1082 | * Must be 16 byte aligned. |
1083 | */ | | 1083 | */ |
1084 | error = uvm_pglistalloc(INTSTK, 0x10000, 0x10000000, 16, 0, | | 1084 | error = uvm_pglistalloc(INTSTK, 0x10000, 0x10000000, 16, 0, |
1085 | &mlist, 1, 1); | | 1085 | &mlist, 1, 1); |
1086 | if (error) { | | 1086 | if (error) { |
1087 | aprint_error(": unable to allocate idle stack\n"); | | 1087 | aprint_error(": unable to allocate idle stack\n"); |
1088 | return -1; | | 1088 | return -1; |
1089 | } | | 1089 | } |
1090 | | | 1090 | |
1091 | KASSERT(ci != &cpu_info[0]); | | 1091 | KASSERT(ci != &cpu_info[0]); |
1092 | | | 1092 | |
1093 | cp = (void *)VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist)); | | 1093 | cp = (void *)VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist)); |
1094 | memset(cp, 0, INTSTK); | | 1094 | memset(cp, 0, INTSTK); |
1095 | | | 1095 | |
1096 | ci->ci_intstk = cp; | | 1096 | ci->ci_intstk = cp; |
1097 | | | 1097 | |
1098 | /* Now allocate a hatch stack */ | | 1098 | /* Now allocate a hatch stack */ |
1099 | error = uvm_pglistalloc(0x1000, 0x10000, 0x10000000, 16, 0, | | 1099 | error = uvm_pglistalloc(0x1000, 0x10000, 0x10000000, 16, 0, |
1100 | &mlist, 1, 1); | | 1100 | &mlist, 1, 1); |
1101 | if (error) { | | 1101 | if (error) { |
1102 | aprint_error(": unable to allocate hatch stack\n"); | | 1102 | aprint_error(": unable to allocate hatch stack\n"); |
1103 | return -1; | | 1103 | return -1; |
1104 | } | | 1104 | } |
1105 | | | 1105 | |
1106 | hp = (void *)VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist)); | | 1106 | hp = (void *)VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist)); |
1107 | memset(hp, 0, 0x1000); | | 1107 | memset(hp, 0, 0x1000); |
1108 | | | 1108 | |
1109 | /* Initialize secondary cpu's initial lwp to its idlelwp. */ | | 1109 | /* Initialize secondary cpu's initial lwp to its idlelwp. */ |
1110 | ci->ci_curlwp = ci->ci_data.cpu_idlelwp; | | 1110 | ci->ci_curlwp = ci->ci_data.cpu_idlelwp; |
1111 | ci->ci_curpcb = &ci->ci_curlwp->l_addr->u_pcb; | | 1111 | ci->ci_curpcb = &ci->ci_curlwp->l_addr->u_pcb; |
1112 | ci->ci_curpm = ci->ci_curpcb->pcb_pm; | | 1112 | ci->ci_curpm = ci->ci_curpcb->pcb_pm; |
1113 | | | 1113 | |
1114 | cpu_hatch_data = h; | | 1114 | cpu_hatch_data = h; |
1115 | h->running = 0; | | 1115 | h->running = 0; |
1116 | h->self = self; | | 1116 | h->self = self; |
1117 | h->ci = ci; | | 1117 | h->ci = ci; |
1118 | h->pir = ci->ci_cpuid; | | 1118 | h->pir = ci->ci_cpuid; |
1119 | | | 1119 | |
1120 | cpu_hatch_stack = (uint32_t)hp; | | 1120 | cpu_hatch_stack = (uint32_t)hp; |
1121 | ci->ci_lasttb = cpu_info[0].ci_lasttb; | | 1121 | ci->ci_lasttb = cpu_info[0].ci_lasttb; |
1122 | | | 1122 | |
1123 | /* copy special registers */ | | 1123 | /* copy special registers */ |
1124 | | | 1124 | |
1125 | h->hid0 = mfspr(SPR_HID0); | | 1125 | h->hid0 = mfspr(SPR_HID0); |
1126 | | | 1126 | |
1127 | __asm volatile ("mfsdr1 %0" : "=r"(h->sdr1)); | | 1127 | __asm volatile ("mfsdr1 %0" : "=r"(h->sdr1)); |
1128 | for (i = 0; i < 16; i++) { | | 1128 | for (i = 0; i < 16; i++) { |
1129 | __asm ("mfsrin %0,%1" : "=r"(h->sr[i]) : | | 1129 | __asm ("mfsrin %0,%1" : "=r"(h->sr[i]) : |
1130 | "r"(i << ADDR_SR_SHFT)); | | 1130 | "r"(i << ADDR_SR_SHFT)); |
1131 | } | | 1131 | } |
1132 | if (oeacpufeat & OEACPU_64) | | 1132 | if (oeacpufeat & OEACPU_64) |
1133 | h->asr = mfspr(SPR_ASR); | | 1133 | h->asr = mfspr(SPR_ASR); |
1134 | else | | 1134 | else |
1135 | h->asr = 0; | | 1135 | h->asr = 0; |
1136 | | | 1136 | |
1137 | /* copy the bat regs */ | | 1137 | /* copy the bat regs */ |
1138 | __asm volatile ("mfibatu %0,0" : "=r"(h->batu[0])); | | 1138 | __asm volatile ("mfibatu %0,0" : "=r"(h->batu[0])); |
1139 | __asm volatile ("mfibatl %0,0" : "=r"(h->batl[0])); | | 1139 | __asm volatile ("mfibatl %0,0" : "=r"(h->batl[0])); |
1140 | __asm volatile ("mfibatu %0,1" : "=r"(h->batu[1])); | | 1140 | __asm volatile ("mfibatu %0,1" : "=r"(h->batu[1])); |
1141 | __asm volatile ("mfibatl %0,1" : "=r"(h->batl[1])); | | 1141 | __asm volatile ("mfibatl %0,1" : "=r"(h->batl[1])); |
1142 | __asm volatile ("mfibatu %0,2" : "=r"(h->batu[2])); | | 1142 | __asm volatile ("mfibatu %0,2" : "=r"(h->batu[2])); |
1143 | __asm volatile ("mfibatl %0,2" : "=r"(h->batl[2])); | | 1143 | __asm volatile ("mfibatl %0,2" : "=r"(h->batl[2])); |
1144 | __asm volatile ("mfibatu %0,3" : "=r"(h->batu[3])); | | 1144 | __asm volatile ("mfibatu %0,3" : "=r"(h->batu[3])); |
1145 | __asm volatile ("mfibatl %0,3" : "=r"(h->batl[3])); | | 1145 | __asm volatile ("mfibatl %0,3" : "=r"(h->batl[3])); |
1146 | __asm volatile ("sync; isync"); | | 1146 | __asm volatile ("sync; isync"); |
1147 | | | 1147 | |
1148 | if (md_setup_trampoline(h, ci) == -1) | | 1148 | if (md_setup_trampoline(h, ci) == -1) |
1149 | return -1; | | 1149 | return -1; |
1150 | md_presync_timebase(h); | | 1150 | md_presync_timebase(h); |
1151 | md_start_timebase(h); | | 1151 | md_start_timebase(h); |
1152 | | | 1152 | |
1153 | /* wait for secondary printf */ | | 1153 | /* wait for secondary printf */ |
1154 | | | 1154 | |
1155 | delay(200000); | | 1155 | delay(200000); |
1156 | | | 1156 | |
1157 | if (h->running < 1) { | | 1157 | if (h->running < 1) { |
1158 | aprint_error("%d:CPU %d didn't start %d\n", cpu_spinstart_ack, | | 1158 | aprint_error("%d:CPU %d didn't start %d\n", cpu_spinstart_ack, |
1159 | ci->ci_cpuid, cpu_spinstart_ack); | | 1159 | ci->ci_cpuid, cpu_spinstart_ack); |
1160 | Debugger(); | | 1160 | Debugger(); |
1161 | return -1; | | 1161 | return -1; |
1162 | } | | 1162 | } |
1163 | | | 1163 | |
1164 | /* Register IPI Interrupt */ | | 1164 | /* Register IPI Interrupt */ |
1165 | if (ipiops.ppc_establish_ipi) | | 1165 | if (ipiops.ppc_establish_ipi) |
1166 | ipiops.ppc_establish_ipi(IST_LEVEL, IPL_HIGH, NULL); | | 1166 | ipiops.ppc_establish_ipi(IST_LEVEL, IPL_HIGH, NULL); |
1167 | | | 1167 | |
1168 | return 0; | | 1168 | return 0; |
1169 | } | | 1169 | } |
1170 | | | 1170 | |
1171 | static volatile int start_secondary_cpu; | | 1171 | static volatile int start_secondary_cpu; |
1172 | extern void tlbia(void); | | 1172 | extern void tlbia(void); |
1173 | | | 1173 | |
1174 | register_t | | 1174 | register_t |
1175 | cpu_hatch(void) | | 1175 | cpu_hatch(void) |
1176 | { | | 1176 | { |
1177 | volatile struct cpu_hatch_data *h = cpu_hatch_data; | | 1177 | volatile struct cpu_hatch_data *h = cpu_hatch_data; |
1178 | struct cpu_info * const ci = h->ci; | | 1178 | struct cpu_info * const ci = h->ci; |
1179 | u_int msr; | | 1179 | u_int msr; |
1180 | int i; | | 1180 | int i; |
1181 | | | 1181 | |
1182 | /* Initialize timebase. */ | | 1182 | /* Initialize timebase. */ |
1183 | __asm ("mttbl %0; mttbu %0; mttbl %0" :: "r"(0)); | | 1183 | __asm ("mttbl %0; mttbu %0; mttbl %0" :: "r"(0)); |
1184 | | | 1184 | |
1185 | /* | | 1185 | /* |
1186 | * Set PIR (Processor Identification Register). i.e. whoami | | 1186 | * Set PIR (Processor Identification Register). i.e. whoami |
1187 | * Note that PIR is read-only on some CPU's. Try to work around | | 1187 | * Note that PIR is read-only on some CPU versions, so we write to it |
1188 | * that as best as possible. Assume that if it is 0, it is meant | | 1188 | * only if it has a different value than we need. |
1189 | * to be setup by us. | | | |
1190 | */ | | 1189 | */ |
1191 | | | 1190 | |
1192 | msr = mfspr(SPR_PIR); | | 1191 | msr = mfspr(SPR_PIR); |
1193 | if (msr == 0) | | 1192 | if (msr != h->pir) |
1194 | mtspr(SPR_PIR, h->pir); | | 1193 | mtspr(SPR_PIR, h->pir); |
1195 | | | 1194 | |
1196 | __asm volatile ("mtsprg 0,%0" :: "r"(ci)); | | 1195 | __asm volatile ("mtsprg 0,%0" :: "r"(ci)); |
1197 | cpu_spinstart_ack = 0; | | 1196 | cpu_spinstart_ack = 0; |
1198 | | | 1197 | |
1199 | /* Initialize MMU. */ | | 1198 | /* Initialize MMU. */ |
1200 | __asm ("mtibatu 0,%0" :: "r"(h->batu[0])); | | 1199 | __asm ("mtibatu 0,%0" :: "r"(h->batu[0])); |
1201 | __asm ("mtibatl 0,%0" :: "r"(h->batl[0])); | | 1200 | __asm ("mtibatl 0,%0" :: "r"(h->batl[0])); |
1202 | __asm ("mtibatu 1,%0" :: "r"(h->batu[1])); | | 1201 | __asm ("mtibatu 1,%0" :: "r"(h->batu[1])); |
1203 | __asm ("mtibatl 1,%0" :: "r"(h->batl[1])); | | 1202 | __asm ("mtibatl 1,%0" :: "r"(h->batl[1])); |
1204 | __asm ("mtibatu 2,%0" :: "r"(h->batu[2])); | | 1203 | __asm ("mtibatu 2,%0" :: "r"(h->batu[2])); |
1205 | __asm ("mtibatl 2,%0" :: "r"(h->batl[2])); | | 1204 | __asm ("mtibatl 2,%0" :: "r"(h->batl[2])); |
1206 | __asm ("mtibatu 3,%0" :: "r"(h->batu[3])); | | 1205 | __asm ("mtibatu 3,%0" :: "r"(h->batu[3])); |
1207 | __asm ("mtibatl 3,%0" :: "r"(h->batl[3])); | | 1206 | __asm ("mtibatl 3,%0" :: "r"(h->batl[3])); |
1208 | | | 1207 | |
1209 | mtspr(SPR_HID0, h->hid0); | | 1208 | mtspr(SPR_HID0, h->hid0); |
1210 | | | 1209 | |
1211 | __asm ("mtibatl 0,%0; mtibatu 0,%1; mtdbatl 0,%0; mtdbatu 0,%1;" | | 1210 | __asm ("mtibatl 0,%0; mtibatu 0,%1; mtdbatl 0,%0; mtdbatu 0,%1;" |
1212 | :: "r"(battable[0].batl), "r"(battable[0].batu)); | | 1211 | :: "r"(battable[0].batl), "r"(battable[0].batu)); |
1213 | | | 1212 | |
1214 | __asm volatile ("sync"); | | 1213 | __asm volatile ("sync"); |
1215 | for (i = 0; i < 16; i++) | | 1214 | for (i = 0; i < 16; i++) |
1216 | __asm ("mtsrin %0,%1" :: "r"(h->sr[i]), "r"(i << ADDR_SR_SHFT)); | | 1215 | __asm ("mtsrin %0,%1" :: "r"(h->sr[i]), "r"(i << ADDR_SR_SHFT)); |
1217 | __asm volatile ("sync; isync"); | | 1216 | __asm volatile ("sync; isync"); |
1218 | | | 1217 | |
1219 | if (oeacpufeat & OEACPU_64) | | 1218 | if (oeacpufeat & OEACPU_64) |
1220 | mtspr(SPR_ASR, h->asr); | | 1219 | mtspr(SPR_ASR, h->asr); |
1221 | | | 1220 | |
1222 | cpu_spinstart_ack = 1; | | 1221 | cpu_spinstart_ack = 1; |
1223 | __asm ("ptesync"); | | 1222 | __asm ("ptesync"); |
1224 | __asm ("mtsdr1 %0" :: "r"(h->sdr1)); | | 1223 | __asm ("mtsdr1 %0" :: "r"(h->sdr1)); |
1225 | __asm volatile ("sync; isync"); | | 1224 | __asm volatile ("sync; isync"); |
1226 | | | 1225 | |
1227 | cpu_spinstart_ack = 5; | | 1226 | cpu_spinstart_ack = 5; |
1228 | for (i = 0; i < 16; i++) | | 1227 | for (i = 0; i < 16; i++) |
1229 | __asm ("mfsrin %0,%1" : "=r"(h->sr[i]) : | | 1228 | __asm ("mfsrin %0,%1" : "=r"(h->sr[i]) : |
1230 | "r"(i << ADDR_SR_SHFT)); | | 1229 | "r"(i << ADDR_SR_SHFT)); |
1231 | | | 1230 | |
1232 | /* Enable I/D address translations. */ | | 1231 | /* Enable I/D address translations. */ |
1233 | msr = mfmsr(); | | 1232 | msr = mfmsr(); |
1234 | msr |= PSL_IR|PSL_DR|PSL_ME|PSL_RI; | | 1233 | msr |= PSL_IR|PSL_DR|PSL_ME|PSL_RI; |
1235 | mtmsr(msr); | | 1234 | mtmsr(msr); |
1236 | __asm volatile ("sync; isync"); | | 1235 | __asm volatile ("sync; isync"); |
1237 | cpu_spinstart_ack = 2; | | 1236 | cpu_spinstart_ack = 2; |
1238 | | | 1237 | |
1239 | md_sync_timebase(h); | | 1238 | md_sync_timebase(h); |
1240 | | | 1239 | |
1241 | cpu_setup(h->self, ci); | | 1240 | cpu_setup(h->self, ci); |
1242 | | | 1241 | |
1243 | h->running = 1; | | 1242 | h->running = 1; |
1244 | __asm volatile ("sync; isync"); | | 1243 | __asm volatile ("sync; isync"); |
1245 | | | 1244 | |
1246 | while (start_secondary_cpu == 0) | | 1245 | while (start_secondary_cpu == 0) |
1247 | ; | | 1246 | ; |
1248 | | | 1247 | |
1249 | __asm volatile ("sync; isync"); | | 1248 | __asm volatile ("sync; isync"); |
1250 | | | 1249 | |
1251 | aprint_normal("cpu%d started\n", curcpu()->ci_index); | | 1250 | aprint_normal("cpu%d started\n", curcpu()->ci_index); |
1252 | __asm volatile ("mtdec %0" :: "r"(ticks_per_intr)); | | 1251 | __asm volatile ("mtdec %0" :: "r"(ticks_per_intr)); |
1253 | | | 1252 | |
1254 | md_setup_interrupts(); | | 1253 | md_setup_interrupts(); |
1255 | | | 1254 | |
1256 | ci->ci_ipending = 0; | | 1255 | ci->ci_ipending = 0; |
1257 | ci->ci_cpl = 0; | | 1256 | ci->ci_cpl = 0; |
1258 | | | 1257 | |
1259 | mtmsr(mfmsr() | PSL_EE); | | 1258 | mtmsr(mfmsr() | PSL_EE); |
1260 | return ci->ci_data.cpu_idlelwp->l_addr->u_pcb.pcb_sp; | | 1259 | return ci->ci_data.cpu_idlelwp->l_addr->u_pcb.pcb_sp; |
1261 | } | | 1260 | } |
1262 | | | 1261 | |
1263 | void | | 1262 | void |
1264 | cpu_boot_secondary_processors() | | 1263 | cpu_boot_secondary_processors() |
1265 | { | | 1264 | { |
1266 | start_secondary_cpu = 1; | | 1265 | start_secondary_cpu = 1; |
1267 | __asm volatile ("sync"); | | 1266 | __asm volatile ("sync"); |
1268 | } | | 1267 | } |
1269 | | | 1268 | |
1270 | #endif /*MULTIPROCESSOR*/ | | 1269 | #endif /*MULTIPROCESSOR*/ |