4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
29 #include <sys/nvpair.h>
30 #include <sys/cmn_err.h>
34 #include <sys/sunddi.h>
36 #include <sys/modctl.h>
37 #include <sys/cyclic.h>
38 #include <sys/errorq.h>
40 #include <sys/cpuvar.h>
41 #include <sys/mc_intel.h>
43 #include <sys/fm/protocol.h>
45 #include "intel_nhm.h"
47 extern nvlist_t
*inhm_mc_nvl
[MAX_CPU_NODES
];
48 extern char closed_page
;
49 extern char ecc_enabled
;
50 extern char lockstep
[MAX_CPU_NODES
];
51 extern char mirror_mode
[MAX_CPU_NODES
];
52 extern char spare_channel
[MAX_CPU_NODES
];
55 inhm_vrank(nvlist_t
*vrank
, int num
, uint64_t dimm_base
, uint64_t limit
,
56 uint32_t sinterleave
, uint32_t cinterleave
, uint32_t rinterleave
,
57 uint32_t sway
, uint32_t cway
, uint32_t rway
)
61 (void) snprintf(buf
, sizeof (buf
), "dimm-rank-base-%d", num
);
62 (void) nvlist_add_uint64(vrank
, buf
, dimm_base
);
63 (void) snprintf(buf
, sizeof (buf
), "dimm-rank-limit-%d", num
);
64 (void) nvlist_add_uint64(vrank
, buf
, dimm_base
+ limit
);
65 if (sinterleave
> 1) {
66 (void) snprintf(buf
, sizeof (buf
), "dimm-socket-interleave-%d",
68 (void) nvlist_add_uint32(vrank
, buf
, sinterleave
);
69 (void) snprintf(buf
, sizeof (buf
),
70 "dimm-socket-interleave-way-%d", num
);
71 (void) nvlist_add_uint32(vrank
, buf
, sway
);
73 if (cinterleave
> 1) {
74 (void) snprintf(buf
, sizeof (buf
), "dimm-channel-interleave-%d",
76 (void) nvlist_add_uint32(vrank
, buf
, cinterleave
);
77 (void) snprintf(buf
, sizeof (buf
),
78 "dimm-channel-interleave-way-%d", num
);
79 (void) nvlist_add_uint32(vrank
, buf
, cway
);
81 if (rinterleave
> 1) {
82 (void) snprintf(buf
, sizeof (buf
), "dimm-rank-interleave-%d",
84 (void) nvlist_add_uint32(vrank
, buf
, rinterleave
);
85 (void) snprintf(buf
, sizeof (buf
),
86 "dimm-rank-interleave-way-%d", num
);
87 (void) nvlist_add_uint32(vrank
, buf
, rway
);
92 inhm_rank(nvlist_t
*newdimm
, nhm_dimm_t
*nhm_dimm
, uint32_t node
,
93 uint8_t channel
, uint32_t dimm
, uint64_t rank_size
)
102 uint32_t sinterleave
, cinterleave
, rinterleave
;
103 uint32_t sway
, cway
, rway
;
105 newrank
= kmem_zalloc(sizeof (nvlist_t
*) * nhm_dimm
->nranks
, KM_SLEEP
);
106 for (i
= 0; i
< nhm_dimm
->nranks
; i
++) {
107 (void) nvlist_alloc(&newrank
[i
], NV_UNIQUE_NAME
, KM_SLEEP
);
110 while (rank_addr
< rank_size
) {
111 pa
= dimm_to_addr(node
, channel
, dimm
* 4 + i
,
112 rank_addr
, &dimm_base
, &vrank_sz
, &sinterleave
,
113 &cinterleave
, &rinterleave
, &sway
, &cway
, &rway
);
114 if (pa
== -1 || vrank_sz
== 0)
116 inhm_vrank(newrank
[i
], num
, dimm_base
,
117 vrank_sz
* sinterleave
* cinterleave
* rinterleave
,
118 sinterleave
, cinterleave
, rinterleave
, sway
, cway
,
120 rank_addr
+= vrank_sz
;
125 (void) nvlist_add_nvlist_array(newdimm
, MCINTEL_NVLIST_RANKS
, newrank
,
127 for (i
= 0; i
< nhm_dimm
->nranks
; i
++)
128 nvlist_free(newrank
[i
]);
129 kmem_free(newrank
, sizeof (nvlist_t
*) * nhm_dimm
->nranks
);
133 inhm_dimm(nhm_dimm_t
*nhm_dimm
, uint32_t node
, uint8_t channel
, uint32_t dimm
)
139 (void) nvlist_alloc(&newdimm
, NV_UNIQUE_NAME
, KM_SLEEP
);
140 (void) nvlist_add_uint32(newdimm
, "dimm-number", dimm
);
142 if (nhm_dimm
->dimm_size
>= 1024*1024*1024) {
143 (void) snprintf(sbuf
, sizeof (sbuf
), "%dG",
144 (int)(nhm_dimm
->dimm_size
/ (1024*1024*1024)));
146 (void) snprintf(sbuf
, sizeof (sbuf
), "%dM",
147 (int)(nhm_dimm
->dimm_size
/ (1024*1024)));
149 (void) nvlist_add_string(newdimm
, "dimm-size", sbuf
);
150 (void) nvlist_add_uint64(newdimm
, "size", nhm_dimm
->dimm_size
);
151 (void) nvlist_add_uint32(newdimm
, "nbanks", (uint32_t)nhm_dimm
->nbanks
);
152 (void) nvlist_add_uint32(newdimm
, "ncolumn",
153 (uint32_t)nhm_dimm
->ncolumn
);
154 (void) nvlist_add_uint32(newdimm
, "nrow", (uint32_t)nhm_dimm
->nrow
);
155 (void) nvlist_add_uint32(newdimm
, "width", (uint32_t)nhm_dimm
->width
);
156 (void) nvlist_add_uint32(newdimm
, "ranks", (uint32_t)nhm_dimm
->nranks
);
157 inhm_rank(newdimm
, nhm_dimm
, node
, channel
, dimm
,
158 nhm_dimm
->dimm_size
/ nhm_dimm
->nranks
);
159 if (nhm_dimm
->manufacturer
&& nhm_dimm
->manufacturer
[0]) {
160 t
= sizeof (nhm_dimm
->manufacturer
);
161 (void) strncpy(sbuf
, nhm_dimm
->manufacturer
, t
);
163 (void) nvlist_add_string(newdimm
, "manufacturer", sbuf
);
165 if (nhm_dimm
->serial_number
&& nhm_dimm
->serial_number
[0]) {
166 t
= sizeof (nhm_dimm
->serial_number
);
167 (void) strncpy(sbuf
, nhm_dimm
->serial_number
, t
);
169 (void) nvlist_add_string(newdimm
, FM_FMRI_HC_SERIAL_ID
, sbuf
);
171 if (nhm_dimm
->part_number
&& nhm_dimm
->part_number
[0]) {
172 t
= sizeof (nhm_dimm
->part_number
);
173 (void) strncpy(sbuf
, nhm_dimm
->part_number
, t
);
175 (void) nvlist_add_string(newdimm
, FM_FMRI_HC_PART
, sbuf
);
177 if (nhm_dimm
->revision
&& nhm_dimm
->revision
[0]) {
178 t
= sizeof (nhm_dimm
->revision
);
179 (void) strncpy(sbuf
, nhm_dimm
->revision
, t
);
181 (void) nvlist_add_string(newdimm
, FM_FMRI_HC_REVISION
, sbuf
);
183 t
= sizeof (nhm_dimm
->label
);
184 (void) strncpy(sbuf
, nhm_dimm
->label
, t
);
186 (void) nvlist_add_string(newdimm
, FM_FAULT_FRU_LABEL
, sbuf
);
191 inhm_dimmlist(uint32_t node
, nvlist_t
*nvl
)
194 nvlist_t
**newchannel
;
195 int nchannels
= CHANNELS_PER_MEMORY_CONTROLLER
;
201 dimmlist
= kmem_zalloc(sizeof (nvlist_t
*) * MAX_DIMMS_PER_CHANNEL
,
203 newchannel
= kmem_zalloc(sizeof (nvlist_t
*) * nchannels
, KM_SLEEP
);
204 dimmpp
= &nhm_dimms
[node
* CHANNELS_PER_MEMORY_CONTROLLER
*
205 MAX_DIMMS_PER_CHANNEL
];
206 (void) nvlist_add_string(nvl
, "memory-policy",
207 closed_page
? "closed-page" : "open-page");
208 (void) nvlist_add_string(nvl
, "memory-ecc",
209 ecc_enabled
? lockstep
[node
] ? "x8" : "x4" : "no");
210 for (i
= 0; i
< nchannels
; i
++) {
211 (void) nvlist_alloc(&newchannel
[i
], NV_UNIQUE_NAME
, KM_SLEEP
);
212 (void) nvlist_add_string(newchannel
[i
], "channel-mode",
213 CHANNEL_DISABLED(MC_STATUS_RD(node
), i
) ? "disabled" :
214 i
!= 2 && lockstep
[node
] ? "lockstep" :
215 i
!= 2 && mirror_mode
[node
] ?
216 REDUNDANCY_LOSS(MC_RAS_STATUS_RD(node
)) ?
217 "redundancy-loss" : "mirror" :
218 i
== 2 && spare_channel
[node
] &&
219 !REDUNDANCY_LOSS(MC_RAS_STATUS_RD(node
)) ? "spare" :
222 for (j
= 0; j
< MAX_DIMMS_PER_CHANNEL
; j
++) {
225 dimmlist
[nd
] = inhm_dimm(dimmp
, node
, i
,
232 (void) nvlist_add_nvlist_array(newchannel
[i
],
233 "memory-dimms", dimmlist
, nd
);
234 for (j
= 0; j
< nd
; j
++)
235 nvlist_free(dimmlist
[j
]);
238 (void) nvlist_add_nvlist_array(nvl
, MCINTEL_NVLIST_MC
, newchannel
,
240 for (i
= 0; i
< nchannels
; i
++)
241 nvlist_free(newchannel
[i
]);
242 kmem_free(dimmlist
, sizeof (nvlist_t
*) * MAX_DIMMS_PER_CHANNEL
);
243 kmem_free(newchannel
, sizeof (nvlist_t
*) * nchannels
);
249 return (NHM_INTERCONNECT
);
253 inhm_create_nvl(int chip
)
257 (void) nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
);
258 (void) nvlist_add_uint8(nvl
, MCINTEL_NVLIST_VERSTR
,
259 MCINTEL_NVLIST_VERS
);
260 (void) nvlist_add_string(nvl
, MCINTEL_NVLIST_MEM
, inhm_mc_name());
261 (void) nvlist_add_uint8(nvl
, MCINTEL_NVLIST_NMEM
, 1);
262 (void) nvlist_add_uint8(nvl
, MCINTEL_NVLIST_NRANKS
, 4);
263 inhm_dimmlist(chip
, nvl
);
265 nvlist_free(inhm_mc_nvl
[chip
]);
266 inhm_mc_nvl
[chip
] = nvl
;