xref: /illumos-gate/usr/src/uts/intel/io/intel_nb5000/nb5000_init.c (revision f6f4cb8ada400367a1921f6b93fb9e02f53ac5e6)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/cmn_err.h>
29 #include <sys/errno.h>
30 #include <sys/log.h>
31 #include <sys/systm.h>
32 #include <sys/modctl.h>
33 #include <sys/errorq.h>
34 #include <sys/controlregs.h>
35 #include <sys/fm/util.h>
36 #include <sys/fm/protocol.h>
37 #include <sys/sysevent.h>
38 #include <sys/pghw.h>
39 #include <sys/cyclic.h>
40 #include <sys/pci_cfgspace.h>
41 #include <sys/mc_intel.h>
42 #include <sys/smbios.h>
43 #include <sys/pci.h>
44 #include <sys/pcie.h>
45 #include "nb5000.h"
46 #include "nb_log.h"
47 #include "dimm_phys.h"
48 #include "rank.h"
49 
50 int nb_hw_memory_scrub_enable = 1;
51 static int nb_sw_scrub_disabled = 0;
52 
53 int nb_5000_memory_controller = 0;
54 int nb_number_memory_controllers = NB_5000_MAX_MEM_CONTROLLERS;
55 int nb_dimms_per_channel = 0;
56 static int ndimms = 0;
57 
58 nb_dimm_t **nb_dimms;
59 int nb_ndimm;
60 uint32_t nb_chipset;
61 enum nb_memory_mode nb_mode;
62 bank_select_t nb_banks[NB_MAX_MEM_BRANCH_SELECT];
63 rank_select_t nb_ranks[NB_5000_MAX_MEM_CONTROLLERS][NB_MAX_MEM_RANK_SELECT];
64 uint32_t top_of_low_memory;
65 uint8_t spare_rank[NB_5000_MAX_MEM_CONTROLLERS];
66 
67 errorq_t *nb_queue;
68 kmutex_t nb_mutex;
69 
70 static uint8_t nb_err0_int;
71 static uint8_t nb_err1_int;
72 static uint8_t nb_err2_int;
73 static uint8_t nb_mcerr_int;
74 static uint32_t nb_emask_int;
75 
76 static uint32_t nb_err0_fbd;
77 static uint32_t nb_err1_fbd;
78 static uint32_t nb_err2_fbd;
79 static uint32_t nb_mcerr_fbd;
80 static uint32_t nb_emask_fbd;
81 
82 static uint16_t nb_err0_fsb;
83 static uint16_t nb_err1_fsb;
84 static uint16_t nb_err2_fsb;
85 static uint16_t nb_mcerr_fsb;
86 static uint16_t nb_emask_fsb;
87 
88 static uint16_t nb_err0_thr;
89 static uint16_t nb_err1_thr;
90 static uint16_t nb_err2_thr;
91 static uint16_t nb_mcerr_thr;
92 static uint16_t nb_emask_thr;
93 
94 static uint32_t	emask_uncor_pex[NB_PCI_DEV];
95 static uint32_t emask_cor_pex[NB_PCI_DEV];
96 static uint32_t emask_rp_pex[NB_PCI_DEV];
97 static uint32_t docmd_pex[NB_PCI_DEV];
98 static uint32_t uncerrsev[NB_PCI_DEV];
99 
100 static uint8_t l_mcerr_int;
101 static uint32_t l_mcerr_fbd;
102 static uint16_t l_mcerr_fsb;
103 static uint16_t l_mcerr_thr;
104 
105 uint_t nb5000_emask_fbd = EMASK_5000_FBD_RES;
106 uint_t nb5400_emask_fbd = 0;
107 int nb5000_reset_emask_fbd = 1;
108 uint_t nb5000_mask_poll_fbd = EMASK_FBD_NF;
109 uint_t nb5000_mask_bios_fbd = EMASK_FBD_FATAL;
110 uint_t nb5400_mask_poll_fbd = EMASK_5400_FBD_NF;
111 uint_t nb5400_mask_bios_fbd = EMASK_5400_FBD_FATAL;
112 
113 uint_t nb5000_emask_fsb = 0;
114 int nb5000_reset_emask_fsb = 1;
115 uint_t nb5000_mask_poll_fsb = EMASK_FSB_NF;
116 uint_t nb5000_mask_bios_fsb = EMASK_FSB_FATAL;
117 
118 uint_t nb5400_emask_int = 0;
119 
120 uint_t nb7300_emask_int = EMASK_INT_7300;
121 uint_t nb7300_emask_int_step0 = EMASK_INT_7300_STEP_0;
122 uint_t nb5000_emask_int = EMASK_INT_5000;
123 int nb5000_reset_emask_int = 1;
124 uint_t nb5000_mask_poll_int = EMASK_INT_NF;
125 uint_t nb5000_mask_bios_int = EMASK_INT_FATAL;
126 
127 uint_t nb_mask_poll_thr = EMASK_THR_NF;
128 uint_t nb_mask_bios_thr = EMASK_THR_FATAL;
129 
130 int nb5000_reset_uncor_pex = 0;
131 uint_t nb5000_mask_uncor_pex = 0;
132 int nb5000_reset_cor_pex = 0;
133 uint_t nb5000_mask_cor_pex = 0xffffffff;
134 int nb_set_docmd = 1;
135 uint32_t nb5000_rp_pex = 0x1;
136 uint32_t nb5000_docmd_pex_mask = DOCMD_PEX_MASK;
137 uint32_t nb5400_docmd_pex_mask = DOCMD_5400_PEX_MASK;
138 uint32_t nb5000_docmd_pex = DOCMD_PEX;
139 uint32_t nb5400_docmd_pex = DOCMD_5400_PEX;
140 
141 int nb_mask_mc_set;
142 
143 typedef struct find_dimm_label {
144 	void (*label_function)(int, char *, int);
145 } find_dimm_label_t;
146 
147 static void x8450_dimm_label(int, char *, int);
148 
149 static struct platform_label {
150 	const char *sys_vendor;		/* SMB_TYPE_SYSTEM vendor prefix */
151 	const char *sys_product;	/* SMB_TYPE_SYSTEM product prefix */
152 	find_dimm_label_t dimm_label;
153 	int dimms_per_channel;
154 } platform_label[] = {
155 	{ "SUN MICROSYSTEMS", "SUN BLADE X8450 SERVER MODULE",
156 	    x8450_dimm_label, 8 },
157 	{ NULL, NULL, NULL, 0 }
158 };
159 
160 static unsigned short
161 read_spd(int bus)
162 {
163 	unsigned short rt = 0;
164 	int branch = bus >> 1;
165 	int channel = bus & 1;
166 
167 	rt = SPD_RD(branch, channel);
168 
169 	return (rt);
170 }
171 
172 static void
173 write_spdcmd(int bus, uint32_t val)
174 {
175 	int branch = bus >> 1;
176 	int channel = bus & 1;
177 	SPDCMD_WR(branch, channel, val);
178 }
179 
180 static int
181 read_spd_eeprom(int bus, int slave, int addr)
182 {
183 	int retry = 4;
184 	int wait;
185 	int spd;
186 	uint32_t cmd;
187 
188 	for (;;) {
189 		wait = 1000;
190 		for (;;) {
191 			spd = read_spd(bus);
192 			if ((spd & SPD_BUSY) == 0)
193 				break;
194 			if (--wait == 0)
195 				return (-1);
196 			drv_usecwait(10);
197 		}
198 		cmd = SPD_EEPROM_WRITE | SPD_ADDR(slave, addr);
199 		write_spdcmd(bus, cmd);
200 		wait = 1000;
201 		for (;;) {
202 			spd = read_spd(bus);
203 			if ((spd & SPD_BUSY) == 0)
204 				break;
205 			if (--wait == 0) {
206 				spd = SPD_BUS_ERROR;
207 				break;
208 			}
209 			drv_usecwait(10);
210 		}
211 		while ((spd & SPD_BUS_ERROR) == 0 &&
212 		    (spd & (SPD_READ_DATA_VALID|SPD_BUSY)) !=
213 		    SPD_READ_DATA_VALID) {
214 			spd = read_spd(bus);
215 			if (--wait == 0)
216 				return (-1);
217 		}
218 		if ((spd & SPD_BUS_ERROR) == 0)
219 			break;
220 		if (--retry == 0)
221 			return (-1);
222 	}
223 	return (spd & 0xff);
224 }
225 
226 static void
227 nb_fini()
228 {
229 	int i, j;
230 	int nchannels = nb_number_memory_controllers * 2;
231 	nb_dimm_t **dimmpp;
232 	nb_dimm_t *dimmp;
233 
234 	dimmpp = nb_dimms;
235 	for (i = 0; i < nchannels; i++) {
236 		for (j = 0; j < nb_dimms_per_channel; j++) {
237 			dimmp = *dimmpp;
238 			if (dimmp) {
239 				kmem_free(dimmp, sizeof (nb_dimm_t));
240 				*dimmpp = NULL;
241 			}
242 			dimmp++;
243 		}
244 	}
245 	kmem_free(nb_dimms, sizeof (nb_dimm_t *) *
246 	    nb_number_memory_controllers * 2 * nb_dimms_per_channel);
247 	nb_dimms = NULL;
248 	dimm_fini();
249 }
250 
251 void
252 nb_scrubber_enable()
253 {
254 	uint32_t mc;
255 
256 	if (!nb_hw_memory_scrub_enable)
257 		return;
258 
259 	mc = MC_RD();
260 	if ((mc & MC_MIRROR) != 0) /* mirror mode */
261 		mc |= MC_PATROL_SCRUB;
262 	else
263 		mc |= MC_PATROL_SCRUB|MC_DEMAND_SCRUB;
264 	MC_WR(mc);
265 
266 	if (nb_sw_scrub_disabled++)
267 		cmi_mc_sw_memscrub_disable();
268 }
269 
270 static nb_dimm_t *
271 nb_dimm_init(int channel, int dimm, uint16_t mtr)
272 {
273 	nb_dimm_t *dp;
274 	int i, t;
275 	int spd_sz;
276 
277 	if (MTR_PRESENT(mtr) == 0)
278 		return (NULL);
279 	t = read_spd_eeprom(channel, dimm, 2) & 0xf;
280 
281 	if (t != 9)
282 		return (NULL);
283 
284 	dp = kmem_zalloc(sizeof (nb_dimm_t), KM_SLEEP);
285 
286 	t = read_spd_eeprom(channel, dimm, 0) & 0xf;
287 	if (t == 1)
288 		spd_sz = 128;
289 	else if (t == 2)
290 		spd_sz = 176;
291 	else
292 		spd_sz = 256;
293 	dp->manufacture_id = read_spd_eeprom(channel, dimm, 117) |
294 	    (read_spd_eeprom(channel, dimm, 118) << 8);
295 	dp->manufacture_location = read_spd_eeprom(channel, dimm, 119);
296 	dp->serial_number =
297 	    (read_spd_eeprom(channel, dimm, 122) << 24) |
298 	    (read_spd_eeprom(channel, dimm, 123) << 16) |
299 	    (read_spd_eeprom(channel, dimm, 124) << 8) |
300 	    read_spd_eeprom(channel, dimm, 125);
301 	t = read_spd_eeprom(channel, dimm, 121);
302 	dp->manufacture_week = (t >> 4) * 10 + (t & 0xf);
303 	dp->manufacture_year = read_spd_eeprom(channel, dimm, 120);
304 	if (spd_sz > 128) {
305 		for (i = 0; i < sizeof (dp->part_number); i++) {
306 			dp->part_number[i] =
307 			    read_spd_eeprom(channel, dimm, 128 + i);
308 		}
309 		for (i = 0; i < sizeof (dp->revision); i++) {
310 			dp->revision[i] =
311 			    read_spd_eeprom(channel, dimm, 146 + i);
312 		}
313 	}
314 	dp->mtr_present = MTR_PRESENT(mtr);
315 	dp->nranks = MTR_NUMRANK(mtr);
316 	dp->nbanks = MTR_NUMBANK(mtr);
317 	dp->ncolumn = MTR_NUMCOL(mtr);
318 	dp->nrow = MTR_NUMROW(mtr);
319 	dp->width = MTR_WIDTH(mtr);
320 	dp->dimm_size = MTR_DIMMSIZE(mtr);
321 
322 	return (dp);
323 }
324 
325 static uint64_t
326 mc_range(int controller, uint64_t base)
327 {
328 	int i;
329 	uint64_t limit = 0;
330 
331 	for (i = 0; i < NB_MEM_BRANCH_SELECT; i++) {
332 		if (nb_banks[i].way[controller] && base >= nb_banks[i].base &&
333 		    base < nb_banks[i].limit) {
334 			limit = nb_banks[i].limit;
335 			if (base <= top_of_low_memory &&
336 			    limit > top_of_low_memory) {
337 				limit -= TLOW_MAX - top_of_low_memory;
338 			}
339 			if (nb_banks[i].way[0] && nb_banks[i].way[1] &&
340 			    nb_mode != NB_MEMORY_MIRROR) {
341 				limit = limit / 2;
342 			}
343 		}
344 	}
345 	return (limit);
346 }
347 
348 void
349 nb_mc_init()
350 {
351 	uint16_t tolm;
352 	uint16_t mir;
353 	uint32_t hole_base;
354 	uint32_t hole_size;
355 	uint32_t dmir;
356 	uint64_t base;
357 	uint64_t limit;
358 	uint8_t way0, way1, rank0, rank1, rank2, rank3, branch_interleave;
359 	int i, j, k;
360 	uint8_t interleave;
361 
362 	base = 0;
363 	tolm = TOLM_RD();
364 	top_of_low_memory = ((uint32_t)(tolm >> 12) & 0xf) << 28;
365 	for (i = 0; i < NB_MEM_BRANCH_SELECT; i++) {
366 		mir = MIR_RD(i);
367 		limit = (uint64_t)(mir >> 4) << 28;
368 		way0 = mir & 1;
369 		way1 = (mir >> 1) & 1;
370 		if (way0 == 0 && way1 == 0) {
371 			way0 = 1;
372 			way1 = 1;
373 		}
374 		if (limit > top_of_low_memory)
375 			limit += TLOW_MAX - top_of_low_memory;
376 		nb_banks[i].base = base;
377 		nb_banks[i].limit = limit;
378 		nb_banks[i].way[0] = way0;
379 		nb_banks[i].way[1] = way1;
380 		base = limit;
381 	}
382 	for (i = 0; i < nb_number_memory_controllers; i++) {
383 		base = 0;
384 
385 		for (j = 0; j < NB_MEM_RANK_SELECT; j++) {
386 			dmir = DMIR_RD(i, j);
387 			limit = ((uint64_t)(dmir >> 16) & 0xff) << 28;
388 			if (limit == 0) {
389 				limit = mc_range(i, base);
390 			}
391 			branch_interleave = 0;
392 			hole_base = 0;
393 			hole_size = 0;
394 			DMIR_RANKS(dmir, rank0, rank1, rank2, rank3);
395 			if (rank0 == rank1)
396 				interleave = 1;
397 			else if (rank0 == rank2)
398 				interleave = 2;
399 			else
400 				interleave = 4;
401 			if (nb_mode != NB_MEMORY_MIRROR &&
402 			    nb_mode != NB_MEMORY_SINGLE_CHANNEL) {
403 				for (k = 0; k < NB_MEM_BRANCH_SELECT; k++) {
404 					if (base >= nb_banks[k].base &&
405 					    base < nb_banks[k].limit) {
406 						if (nb_banks[i].way[0] &&
407 						    nb_banks[i].way[1]) {
408 							interleave *= 2;
409 							limit *= 2;
410 							branch_interleave = 1;
411 						}
412 						break;
413 					}
414 				}
415 			}
416 			if (base < top_of_low_memory &&
417 			    limit > top_of_low_memory) {
418 				hole_base = top_of_low_memory;
419 				hole_size = TLOW_MAX - top_of_low_memory;
420 				limit += hole_size;
421 			} else if (base > top_of_low_memory) {
422 				limit += TLOW_MAX - top_of_low_memory;
423 			}
424 			nb_ranks[i][j].base = base;
425 			nb_ranks[i][j].limit = limit;
426 			nb_ranks[i][j].rank[0] = rank0;
427 			nb_ranks[i][j].rank[1] = rank1;
428 			nb_ranks[i][j].rank[2] = rank2;
429 			nb_ranks[i][j].rank[3] = rank3;
430 			nb_ranks[i][j].interleave = interleave;
431 			nb_ranks[i][j].branch_interleave = branch_interleave;
432 			nb_ranks[i][j].hole_base = hole_base;
433 			nb_ranks[i][j].hole_size = hole_size;
434 			if (limit > base) {
435 				dimm_add_rank(i, rank0, branch_interleave, 0,
436 				    base, hole_base, hole_size, interleave,
437 				    limit);
438 				if (rank0 != rank1) {
439 					dimm_add_rank(i, rank1,
440 					    branch_interleave, 1, base,
441 					    hole_base, hole_size, interleave,
442 					    limit);
443 					if (rank0 != rank2) {
444 						dimm_add_rank(i, rank2,
445 						    branch_interleave, 2, base,
446 						    hole_base, hole_size,
447 						    interleave, limit);
448 						dimm_add_rank(i, rank3,
449 						    branch_interleave, 3, base,
450 						    hole_base, hole_size,
451 						    interleave, limit);
452 					}
453 				}
454 			}
455 			base = limit;
456 		}
457 	}
458 }
459 
460 void
461 nb_used_spare_rank(int branch, int bad_rank)
462 {
463 	int i;
464 	int j;
465 
466 	for (i = 0; i < NB_MEM_RANK_SELECT; i++) {
467 		for (j = 0; j < NB_RANKS_IN_SELECT; j++) {
468 			if (nb_ranks[branch][i].rank[j] == bad_rank) {
469 				nb_ranks[branch][i].rank[j] =
470 				    spare_rank[branch];
471 				i = NB_MEM_RANK_SELECT;
472 				break;
473 			}
474 		}
475 	}
476 }
477 
478 /*ARGSUSED*/
479 static int
480 memoryarray(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
481 {
482 	smbios_memarray_t ma;
483 
484 	if (sp->smbstr_type == SMB_TYPE_MEMARRAY &&
485 	    smbios_info_memarray(shp, sp->smbstr_id, &ma) == 0) {
486 		ndimms += ma.smbma_ndevs;
487 	}
488 	return (0);
489 }
490 
491 find_dimm_label_t *
492 find_dimms_per_channel()
493 {
494 	struct platform_label *pl;
495 	smbios_info_t si;
496 	smbios_system_t sy;
497 	id_t id;
498 	int read_memarray = 1;
499 	find_dimm_label_t *rt = NULL;
500 
501 	if (ksmbios != NULL) {
502 		if ((id = smbios_info_system(ksmbios, &sy)) != SMB_ERR &&
503 		    smbios_info_common(ksmbios, id, &si) != SMB_ERR) {
504 			for (pl = platform_label; pl->sys_vendor; pl++) {
505 				if (strncmp(pl->sys_vendor,
506 				    si.smbi_manufacturer,
507 				    strlen(pl->sys_vendor)) == 0 &&
508 				    strncmp(pl->sys_product, si.smbi_product,
509 				    strlen(pl->sys_product)) == 0) {
510 					nb_dimms_per_channel =
511 					    pl->dimms_per_channel;
512 					read_memarray = 0;
513 					rt = &pl->dimm_label;
514 					break;
515 				}
516 			}
517 		}
518 		if (read_memarray)
519 			(void) smbios_iter(ksmbios, memoryarray, 0);
520 	}
521 	if (nb_dimms_per_channel == 0) {
522 		if (ndimms) {
523 			nb_dimms_per_channel = ndimms /
524 			    (nb_number_memory_controllers * 2);
525 		} else {
526 			nb_dimms_per_channel = NB_MAX_DIMMS_PER_CHANNEL;
527 		}
528 	}
529 	return (rt);
530 }
531 
532 static int
533 dimm_label(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
534 {
535 	nb_dimm_t ***dimmpp = arg;
536 	nb_dimm_t *dimmp;
537 	smbios_memdevice_t md;
538 
539 	if (sp->smbstr_type == SMB_TYPE_MEMDEVICE) {
540 		dimmp = **dimmpp;
541 		if (dimmp && smbios_info_memdevice(shp, sp->smbstr_id,
542 		    &md) == 0 && md.smbmd_dloc != NULL) {
543 			(void) snprintf(dimmp->label,
544 			    sizeof (dimmp->label), "%s", md.smbmd_dloc);
545 		}
546 		(*dimmpp)++;
547 	}
548 	return (0);
549 }
550 
551 void
552 nb_smbios()
553 {
554 	nb_dimm_t **dimmpp;
555 
556 	if (ksmbios != NULL) {
557 		dimmpp = nb_dimms;
558 		(void) smbios_iter(ksmbios, dimm_label, &dimmpp);
559 	}
560 }
561 
562 static void
563 x8450_dimm_label(int dimm, char *label, int label_sz)
564 {
565 	int channel = dimm >> 3;
566 
567 	dimm = dimm & 0x7;
568 	(void) snprintf(label, label_sz, "D%d", (dimm * 4) + channel);
569 }
570 
571 static void
572 nb_dimms_init(find_dimm_label_t *label_function)
573 {
574 	int i, j, k, l;
575 	uint16_t mtr;
576 	uint32_t mc, mca;
577 	uint32_t spcpc;
578 	uint8_t spcps;
579 	nb_dimm_t **dimmpp;
580 
581 	mca = MCA_RD();
582 	mc = MC_RD();
583 	if (mca & MCA_SCHDIMM)  /* single-channel mode */
584 		nb_mode = NB_MEMORY_SINGLE_CHANNEL;
585 	else if ((mc & MC_MIRROR) != 0) /* mirror mode */
586 		nb_mode = NB_MEMORY_MIRROR;
587 	else
588 		nb_mode = NB_MEMORY_NORMAL;
589 	nb_dimms = (nb_dimm_t **)kmem_zalloc(sizeof (nb_dimm_t *) *
590 	    nb_number_memory_controllers * 2 * nb_dimms_per_channel, KM_SLEEP);
591 	dimmpp = nb_dimms;
592 	for (i = 0; i < nb_number_memory_controllers; i++) {
593 		if (nb_mode == NB_MEMORY_NORMAL) {
594 			spcpc = SPCPC_RD(i);
595 			spcps = SPCPS_RD(i);
596 			if ((spcpc & SPCPC_SPARE_ENABLE) != 0 &&
597 			    (spcps & SPCPS_SPARE_DEPLOYED) != 0)
598 				nb_mode = NB_MEMORY_SPARE_RANK;
599 			spare_rank[i] = SPCPC_SPRANK(spcpc);
600 		}
601 		for (j = 0; j < nb_dimms_per_channel; j++) {
602 			mtr = MTR_RD(i, j);
603 			k = i * 2;
604 			dimmpp[j] = nb_dimm_init(k, j, mtr);
605 			if (dimmpp[j]) {
606 				nb_ndimm ++;
607 				dimm_add_geometry(i, j, dimmpp[j]->nbanks,
608 				    dimmpp[j]->width, dimmpp[j]->ncolumn,
609 				    dimmpp[j]->nrow);
610 				if (label_function) {
611 					label_function->label_function(
612 					    (k * nb_dimms_per_channel) + j,
613 					    dimmpp[j]->label,
614 					    sizeof (dimmpp[j]->label));
615 				}
616 			}
617 			dimmpp[j + nb_dimms_per_channel] =
618 			    nb_dimm_init(k + 1, j, mtr);
619 			l = j + nb_dimms_per_channel;
620 			if (dimmpp[l]) {
621 				if (label_function) {
622 					label_function->label_function(
623 					    (k * nb_dimms_per_channel) + l,
624 					    dimmpp[l]->label,
625 					    sizeof (dimmpp[l]->label));
626 				}
627 				nb_ndimm ++;
628 			}
629 		}
630 		dimmpp += nb_dimms_per_channel * 2;
631 	}
632 	if (label_function == NULL)
633 		nb_smbios();
634 }
635 
636 static void
637 nb_pex_init()
638 {
639 	int i;
640 	uint32_t mask;
641 
642 	for (i = 0; i < NB_PCI_DEV; i++) {
643 		switch (nb_chipset) {
644 		case INTEL_NB_5000P:
645 		case INTEL_NB_5000X:
646 			if (i == 1 || i > 8)
647 				continue;
648 			break;
649 		case INTEL_NB_5000V:
650 			if (i == 1 || i > 3)
651 				continue;
652 			break;
653 		case INTEL_NB_5000Z:
654 			if (i == 1 || i > 5)
655 				continue;
656 			break;
657 		case INTEL_NB_5400:
658 			break;
659 		case INTEL_NB_7300:
660 			if (i > 8)
661 				continue;
662 			break;
663 		}
664 		emask_uncor_pex[i] = EMASK_UNCOR_PEX_RD(i);
665 		emask_cor_pex[i] = EMASK_COR_PEX_RD(i);
666 		emask_rp_pex[i] = EMASK_RP_PEX_RD(i);
667 		docmd_pex[i] = PEX_ERR_DOCMD_RD(i);
668 		uncerrsev[i] = UNCERRSEV_RD(i);
669 
670 		if (nb5000_reset_uncor_pex)
671 			EMASK_UNCOR_PEX_WR(i, nb5000_mask_uncor_pex);
672 		if (nb5000_reset_cor_pex)
673 			EMASK_COR_PEX_WR(i, nb5000_mask_cor_pex);
674 		if (nb_set_docmd) {
675 			if (nb_chipset == INTEL_NB_5400) {
676 				/* disable masking of ERR pins used by DOCMD */
677 				PEX_ERR_PIN_MASK_WR(i, 0x10);
678 
679 				mask = (docmd_pex[i] & nb5400_docmd_pex_mask) |
680 				    (nb5400_docmd_pex & ~nb5400_docmd_pex_mask);
681 			} else {
682 				mask = (docmd_pex[i] & nb5000_docmd_pex_mask) |
683 				    (nb5000_docmd_pex & ~nb5000_docmd_pex_mask);
684 			}
685 			PEX_ERR_DOCMD_WR(i, mask);
686 		}
687 
688 		/* RP error message (CE/NFE/FE) detect mask */
689 		EMASK_RP_PEX_WR(i, nb5000_rp_pex);
690 
691 		/* Setup ESI port registers to enable SERR for southbridge */
692 		if (i == 0) {
693 			uint16_t regw;
694 
695 			/* Command Register - Enable SERR */
696 			regw = nb_pci_getw(0, i, 0, PCI_CONF_COMM, 0);
697 			nb_pci_putw(0, i, 0, PCI_CONF_COMM,
698 			    regw | PCI_COMM_SERR_ENABLE);
699 
700 			/* Root Control Register - SERR on NFE/FE */
701 			PEXROOTCTL_WR(i, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
702 			    PCIE_ROOTCTL_SYS_ERR_ON_FE_EN);
703 
704 			/* AER UE Mask - Mask UR */
705 			UNCERRMSK_WR(i, PCIE_AER_UCE_UR);
706 		}
707 	}
708 }
709 
710 static void
711 nb_pex_fini()
712 {
713 	int i;
714 
715 	for (i = 0; i < NB_PCI_DEV; i++) {
716 		switch (nb_chipset) {
717 		case INTEL_NB_5000P:
718 		case INTEL_NB_5000X:
719 			if (i == 1 && i > 8)
720 				continue;
721 			break;
722 		case INTEL_NB_5000V:
723 			if (i == 1 || i > 3)
724 				continue;
725 			break;
726 		case INTEL_NB_5000Z:
727 			if (i == 1 || i > 5)
728 				continue;
729 			break;
730 		case INTEL_NB_5400:
731 			break;
732 		case INTEL_NB_7300:
733 			if (i > 8)
734 				continue;
735 			break;
736 		}
737 		EMASK_UNCOR_PEX_WR(i, emask_uncor_pex[i]);
738 		EMASK_COR_PEX_WR(i, emask_cor_pex[i]);
739 		EMASK_RP_PEX_WR(i, emask_rp_pex[i]);
740 		PEX_ERR_DOCMD_WR(i, docmd_pex[i]);
741 
742 		if (nb5000_reset_uncor_pex)
743 			EMASK_UNCOR_PEX_WR(i, nb5000_mask_uncor_pex);
744 		if (nb5000_reset_cor_pex)
745 			EMASK_COR_PEX_WR(i, nb5000_mask_cor_pex);
746 	}
747 }
748 
749 void
750 nb_int_init()
751 {
752 	uint8_t err0_int;
753 	uint8_t err1_int;
754 	uint8_t err2_int;
755 	uint8_t mcerr_int;
756 	uint32_t emask_int;
757 	uint16_t stepping;
758 
759 	err0_int = ERR0_INT_RD();
760 	err1_int = ERR1_INT_RD();
761 	err2_int = ERR2_INT_RD();
762 	mcerr_int = MCERR_INT_RD();
763 	emask_int = EMASK_INT_RD();
764 
765 	nb_err0_int = err0_int;
766 	nb_err1_int = err1_int;
767 	nb_err2_int = err2_int;
768 	nb_mcerr_int = mcerr_int;
769 	nb_emask_int = emask_int;
770 
771 	ERR0_INT_WR(0xff);
772 	ERR1_INT_WR(0xff);
773 	ERR2_INT_WR(0xff);
774 	MCERR_INT_WR(0xff);
775 	EMASK_INT_WR(0xff);
776 
777 	mcerr_int &= ~nb5000_mask_bios_int;
778 	mcerr_int |= nb5000_mask_bios_int & (~err0_int | ~err1_int | ~err2_int);
779 	mcerr_int |= nb5000_mask_poll_int;
780 	err0_int |= nb5000_mask_poll_int;
781 	err1_int |= nb5000_mask_poll_int;
782 	err2_int |= nb5000_mask_poll_int;
783 
784 	l_mcerr_int = mcerr_int;
785 	ERR0_INT_WR(err0_int);
786 	ERR1_INT_WR(err1_int);
787 	ERR2_INT_WR(err2_int);
788 	MCERR_INT_WR(mcerr_int);
789 	if (nb5000_reset_emask_int) {
790 		if (nb_chipset == INTEL_NB_7300) {
791 			stepping = NB5000_STEPPING();
792 			if (stepping == 0)
793 				EMASK_5000_INT_WR(nb7300_emask_int_step0);
794 			else
795 				EMASK_5000_INT_WR(nb7300_emask_int);
796 		} else if (nb_chipset == INTEL_NB_5400) {
797 			EMASK_5400_INT_WR(nb5400_emask_int |
798 			    (emask_int & EMASK_INT_RES));
799 		} else {
800 			EMASK_5000_INT_WR(nb5000_emask_int);
801 		}
802 	} else {
803 		EMASK_INT_WR(nb_emask_int);
804 	}
805 }
806 
807 void
808 nb_int_fini()
809 {
810 	ERR0_INT_WR(0xff);
811 	ERR1_INT_WR(0xff);
812 	ERR2_INT_WR(0xff);
813 	MCERR_INT_WR(0xff);
814 	EMASK_INT_WR(0xff);
815 
816 	ERR0_INT_WR(nb_err0_int);
817 	ERR1_INT_WR(nb_err1_int);
818 	ERR2_INT_WR(nb_err2_int);
819 	MCERR_INT_WR(nb_mcerr_int);
820 	EMASK_INT_WR(nb_emask_int);
821 }
822 
823 void
824 nb_int_mask_mc(uint32_t mc_mask_int)
825 {
826 	uint32_t emask_int;
827 
828 	emask_int = MCERR_INT_RD();
829 	if ((emask_int & mc_mask_int) != mc_mask_int) {
830 		MCERR_INT_WR(emask_int|mc_mask_int);
831 		nb_mask_mc_set = 1;
832 	}
833 }
834 
835 void
836 nb_fbd_init()
837 {
838 	uint32_t err0_fbd;
839 	uint32_t err1_fbd;
840 	uint32_t err2_fbd;
841 	uint32_t mcerr_fbd;
842 	uint32_t emask_fbd;
843 	uint32_t emask_bios_fbd;
844 	uint32_t emask_poll_fbd;
845 
846 	err0_fbd = ERR0_FBD_RD();
847 	err1_fbd = ERR1_FBD_RD();
848 	err2_fbd = ERR2_FBD_RD();
849 	mcerr_fbd = MCERR_FBD_RD();
850 	emask_fbd = EMASK_FBD_RD();
851 
852 	nb_err0_fbd = err0_fbd;
853 	nb_err1_fbd = err1_fbd;
854 	nb_err2_fbd = err2_fbd;
855 	nb_mcerr_fbd = mcerr_fbd;
856 	nb_emask_fbd = emask_fbd;
857 
858 	ERR0_FBD_WR(0xffffffff);
859 	ERR1_FBD_WR(0xffffffff);
860 	ERR2_FBD_WR(0xffffffff);
861 	MCERR_FBD_WR(0xffffffff);
862 	EMASK_FBD_WR(0xffffffff);
863 
864 	if (nb_chipset == INTEL_NB_7300 && nb_mode == NB_MEMORY_MIRROR) {
865 		/* MCH 7300 errata 34 */
866 		emask_bios_fbd = nb5000_mask_bios_fbd & ~EMASK_FBD_M23;
867 		emask_poll_fbd = nb5000_mask_poll_fbd;
868 		mcerr_fbd |= EMASK_FBD_M23;
869 	} else if (nb_chipset == INTEL_NB_5400) {
870 		emask_bios_fbd = nb5400_mask_bios_fbd;
871 		emask_poll_fbd = nb5400_mask_poll_fbd;
872 	} else {
873 		emask_bios_fbd = nb5000_mask_bios_fbd;
874 		emask_poll_fbd = nb5000_mask_poll_fbd;
875 	}
876 	mcerr_fbd &= ~emask_bios_fbd;
877 	mcerr_fbd |= emask_bios_fbd & (~err0_fbd | ~err1_fbd | ~err2_fbd);
878 	mcerr_fbd |= emask_poll_fbd;
879 	err0_fbd |= emask_poll_fbd;
880 	err1_fbd |= emask_poll_fbd;
881 	err2_fbd |= emask_poll_fbd;
882 
883 	l_mcerr_fbd = mcerr_fbd;
884 	ERR0_FBD_WR(err0_fbd);
885 	ERR1_FBD_WR(err1_fbd);
886 	ERR2_FBD_WR(err2_fbd);
887 	MCERR_FBD_WR(mcerr_fbd);
888 	if (nb5000_reset_emask_fbd) {
889 		if (nb_chipset == INTEL_NB_5400)
890 			EMASK_FBD_WR(nb5400_emask_fbd);
891 		else
892 			EMASK_FBD_WR(nb5000_emask_fbd);
893 	} else {
894 		EMASK_FBD_WR(nb_emask_fbd);
895 	}
896 }
897 
898 void
899 nb_fbd_mask_mc(uint32_t mc_mask_fbd)
900 {
901 	uint32_t emask_fbd;
902 
903 	emask_fbd = MCERR_FBD_RD();
904 	if ((emask_fbd & mc_mask_fbd) != mc_mask_fbd) {
905 		MCERR_FBD_WR(emask_fbd|mc_mask_fbd);
906 		nb_mask_mc_set = 1;
907 	}
908 }
909 
910 void
911 nb_fbd_fini()
912 {
913 	ERR0_FBD_WR(0xffffffff);
914 	ERR1_FBD_WR(0xffffffff);
915 	ERR2_FBD_WR(0xffffffff);
916 	MCERR_FBD_WR(0xffffffff);
917 	EMASK_FBD_WR(0xffffffff);
918 
919 	ERR0_FBD_WR(nb_err0_fbd);
920 	ERR1_FBD_WR(nb_err1_fbd);
921 	ERR2_FBD_WR(nb_err2_fbd);
922 	MCERR_FBD_WR(nb_mcerr_fbd);
923 	EMASK_FBD_WR(nb_emask_fbd);
924 }
925 
926 static void
927 nb_fsb_init()
928 {
929 	uint16_t err0_fsb;
930 	uint16_t err1_fsb;
931 	uint16_t err2_fsb;
932 	uint16_t mcerr_fsb;
933 	uint16_t emask_fsb;
934 
935 	err0_fsb = ERR0_FSB_RD(0);
936 	err1_fsb = ERR1_FSB_RD(0);
937 	err2_fsb = ERR2_FSB_RD(0);
938 	mcerr_fsb = MCERR_FSB_RD(0);
939 	emask_fsb = EMASK_FSB_RD(0);
940 
941 	ERR0_FSB_WR(0, 0xffff);
942 	ERR1_FSB_WR(0, 0xffff);
943 	ERR2_FSB_WR(0, 0xffff);
944 	MCERR_FSB_WR(0, 0xffff);
945 	EMASK_FSB_WR(0, 0xffff);
946 
947 	ERR0_FSB_WR(1, 0xffff);
948 	ERR1_FSB_WR(1, 0xffff);
949 	ERR2_FSB_WR(1, 0xffff);
950 	MCERR_FSB_WR(1, 0xffff);
951 	EMASK_FSB_WR(1, 0xffff);
952 
953 	nb_err0_fsb = err0_fsb;
954 	nb_err1_fsb = err1_fsb;
955 	nb_err2_fsb = err2_fsb;
956 	nb_mcerr_fsb = mcerr_fsb;
957 	nb_emask_fsb = emask_fsb;
958 
959 	mcerr_fsb &= ~nb5000_mask_bios_fsb;
960 	mcerr_fsb |= nb5000_mask_bios_fsb & (~err2_fsb | ~err1_fsb | ~err0_fsb);
961 	mcerr_fsb |= nb5000_mask_poll_fsb;
962 	err0_fsb |= nb5000_mask_poll_fsb;
963 	err1_fsb |= nb5000_mask_poll_fsb;
964 	err2_fsb |= nb5000_mask_poll_fsb;
965 
966 	l_mcerr_fsb = mcerr_fsb;
967 	ERR0_FSB_WR(0, err0_fsb);
968 	ERR1_FSB_WR(0, err1_fsb);
969 	ERR2_FSB_WR(0, err2_fsb);
970 	MCERR_FSB_WR(0, mcerr_fsb);
971 	if (nb5000_reset_emask_fsb) {
972 		EMASK_FSB_WR(0, nb5000_emask_fsb);
973 	} else {
974 		EMASK_FSB_WR(0, nb_emask_fsb);
975 	}
976 
977 	ERR0_FSB_WR(1, err0_fsb);
978 	ERR1_FSB_WR(1, err1_fsb);
979 	ERR2_FSB_WR(1, err2_fsb);
980 	MCERR_FSB_WR(1, mcerr_fsb);
981 	if (nb5000_reset_emask_fsb) {
982 		EMASK_FSB_WR(1, nb5000_emask_fsb);
983 	} else {
984 		EMASK_FSB_WR(1, nb_emask_fsb);
985 	}
986 
987 	if (nb_chipset == INTEL_NB_7300) {
988 		ERR0_FSB_WR(2, 0xffff);
989 		ERR1_FSB_WR(2, 0xffff);
990 		ERR2_FSB_WR(2, 0xffff);
991 		MCERR_FSB_WR(2, 0xffff);
992 		EMASK_FSB_WR(2, 0xffff);
993 
994 		ERR0_FSB_WR(3, 0xffff);
995 		ERR1_FSB_WR(3, 0xffff);
996 		ERR2_FSB_WR(3, 0xffff);
997 		MCERR_FSB_WR(3, 0xffff);
998 		EMASK_FSB_WR(3, 0xffff);
999 
1000 		ERR0_FSB_WR(2, err0_fsb);
1001 		ERR1_FSB_WR(2, err1_fsb);
1002 		ERR2_FSB_WR(2, err2_fsb);
1003 		MCERR_FSB_WR(2, mcerr_fsb);
1004 		if (nb5000_reset_emask_fsb) {
1005 			EMASK_FSB_WR(2, nb5000_emask_fsb);
1006 		} else {
1007 			EMASK_FSB_WR(2, nb_emask_fsb);
1008 		}
1009 
1010 		ERR0_FSB_WR(3, err0_fsb);
1011 		ERR1_FSB_WR(3, err1_fsb);
1012 		ERR2_FSB_WR(3, err2_fsb);
1013 		MCERR_FSB_WR(3, mcerr_fsb);
1014 		if (nb5000_reset_emask_fsb) {
1015 			EMASK_FSB_WR(3, nb5000_emask_fsb);
1016 		} else {
1017 			EMASK_FSB_WR(3, nb_emask_fsb);
1018 		}
1019 	}
1020 }
1021 
1022 static void
1023 nb_fsb_fini() {
1024 	ERR0_FSB_WR(0, 0xffff);
1025 	ERR1_FSB_WR(0, 0xffff);
1026 	ERR2_FSB_WR(0, 0xffff);
1027 	MCERR_FSB_WR(0, 0xffff);
1028 	EMASK_FSB_WR(0, 0xffff);
1029 
1030 	ERR0_FSB_WR(0, nb_err0_fsb);
1031 	ERR1_FSB_WR(0, nb_err1_fsb);
1032 	ERR2_FSB_WR(0, nb_err2_fsb);
1033 	MCERR_FSB_WR(0, nb_mcerr_fsb);
1034 	EMASK_FSB_WR(0, nb_emask_fsb);
1035 
1036 	ERR0_FSB_WR(1, 0xffff);
1037 	ERR1_FSB_WR(1, 0xffff);
1038 	ERR2_FSB_WR(1, 0xffff);
1039 	MCERR_FSB_WR(1, 0xffff);
1040 	EMASK_FSB_WR(1, 0xffff);
1041 
1042 	ERR0_FSB_WR(1, nb_err0_fsb);
1043 	ERR1_FSB_WR(1, nb_err1_fsb);
1044 	ERR2_FSB_WR(1, nb_err2_fsb);
1045 	MCERR_FSB_WR(1, nb_mcerr_fsb);
1046 	EMASK_FSB_WR(1, nb_emask_fsb);
1047 
1048 	if (nb_chipset == INTEL_NB_7300) {
1049 		ERR0_FSB_WR(2, 0xffff);
1050 		ERR1_FSB_WR(2, 0xffff);
1051 		ERR2_FSB_WR(2, 0xffff);
1052 		MCERR_FSB_WR(2, 0xffff);
1053 		EMASK_FSB_WR(2, 0xffff);
1054 
1055 		ERR0_FSB_WR(2, nb_err0_fsb);
1056 		ERR1_FSB_WR(2, nb_err1_fsb);
1057 		ERR2_FSB_WR(2, nb_err2_fsb);
1058 		MCERR_FSB_WR(2, nb_mcerr_fsb);
1059 		EMASK_FSB_WR(2, nb_emask_fsb);
1060 
1061 		ERR0_FSB_WR(3, 0xffff);
1062 		ERR1_FSB_WR(3, 0xffff);
1063 		ERR2_FSB_WR(3, 0xffff);
1064 		MCERR_FSB_WR(3, 0xffff);
1065 		EMASK_FSB_WR(3, 0xffff);
1066 
1067 		ERR0_FSB_WR(3, nb_err0_fsb);
1068 		ERR1_FSB_WR(3, nb_err1_fsb);
1069 		ERR2_FSB_WR(3, nb_err2_fsb);
1070 		MCERR_FSB_WR(3, nb_mcerr_fsb);
1071 		EMASK_FSB_WR(3, nb_emask_fsb);
1072 	}
1073 }
1074 
1075 void
1076 nb_fsb_mask_mc(int fsb, uint16_t mc_mask_fsb)
1077 {
1078 	uint16_t emask_fsb;
1079 
1080 	emask_fsb = MCERR_FSB_RD(fsb);
1081 	if ((emask_fsb & mc_mask_fsb) != mc_mask_fsb) {
1082 		MCERR_FSB_WR(fsb, emask_fsb|mc_mask_fsb|EMASK_FBD_RES);
1083 		nb_mask_mc_set = 1;
1084 	}
1085 }
1086 
1087 static void
1088 nb_thr_init()
1089 {
1090 	uint16_t err0_thr;
1091 	uint16_t err1_thr;
1092 	uint16_t err2_thr;
1093 	uint16_t mcerr_thr;
1094 	uint16_t emask_thr;
1095 
1096 	if (nb_chipset == INTEL_NB_5400) {
1097 		err0_thr = ERR0_THR_RD(0);
1098 		err1_thr = ERR1_THR_RD(0);
1099 		err2_thr = ERR2_THR_RD(0);
1100 		mcerr_thr = MCERR_THR_RD(0);
1101 		emask_thr = EMASK_THR_RD(0);
1102 
1103 		ERR0_THR_WR(0xffff);
1104 		ERR1_THR_WR(0xffff);
1105 		ERR2_THR_WR(0xffff);
1106 		MCERR_THR_WR(0xffff);
1107 		EMASK_THR_WR(0xffff);
1108 
1109 		nb_err0_thr = err0_thr;
1110 		nb_err1_thr = err1_thr;
1111 		nb_err2_thr = err2_thr;
1112 		nb_mcerr_thr = mcerr_thr;
1113 		nb_emask_thr = emask_thr;
1114 
1115 		mcerr_thr &= ~nb_mask_bios_thr;
1116 		mcerr_thr |= nb_mask_bios_thr &
1117 		    (~err2_thr | ~err1_thr | ~err0_thr);
1118 		mcerr_thr |= nb_mask_poll_thr;
1119 		err0_thr |= nb_mask_poll_thr;
1120 		err1_thr |= nb_mask_poll_thr;
1121 		err2_thr |= nb_mask_poll_thr;
1122 
1123 		l_mcerr_thr = mcerr_thr;
1124 		ERR0_THR_WR(err0_thr);
1125 		ERR1_THR_WR(err1_thr);
1126 		ERR2_THR_WR(err2_thr);
1127 		MCERR_THR_WR(mcerr_thr);
1128 		EMASK_THR_WR(nb_emask_thr);
1129 	}
1130 }
1131 
1132 static void
1133 nb_thr_fini()
1134 {
1135 	if (nb_chipset == INTEL_NB_5400) {
1136 		ERR0_THR_WR(0xffff);
1137 		ERR1_THR_WR(0xffff);
1138 		ERR2_THR_WR(0xffff);
1139 		MCERR_THR_WR(0xffff);
1140 		EMASK_THR_WR(0xffff);
1141 
1142 		ERR0_THR_WR(nb_err0_thr);
1143 		ERR1_THR_WR(nb_err1_thr);
1144 		ERR2_THR_WR(nb_err2_thr);
1145 		MCERR_THR_WR(nb_mcerr_thr);
1146 		EMASK_THR_WR(nb_emask_thr);
1147 	}
1148 }
1149 
1150 void
1151 nb_thr_mask_mc(uint16_t mc_mask_thr)
1152 {
1153 	uint16_t emask_thr;
1154 
1155 	emask_thr = MCERR_THR_RD(0);
1156 	if ((emask_thr & mc_mask_thr) != mc_mask_thr) {
1157 		MCERR_THR_WR(emask_thr|mc_mask_thr);
1158 		nb_mask_mc_set = 1;
1159 	}
1160 }
1161 
1162 void
1163 nb_mask_mc_reset()
1164 {
1165 	MCERR_FBD_WR(l_mcerr_fbd);
1166 	MCERR_INT_WR(l_mcerr_int);
1167 	MCERR_FSB_WR(0, l_mcerr_fsb);
1168 	MCERR_FSB_WR(1, l_mcerr_fsb);
1169 	if (nb_chipset == INTEL_NB_7300) {
1170 		MCERR_FSB_WR(2, l_mcerr_fsb);
1171 		MCERR_FSB_WR(3, l_mcerr_fsb);
1172 	}
1173 	if (nb_chipset == INTEL_NB_5400) {
1174 		MCERR_THR_WR(l_mcerr_thr);
1175 	}
1176 }
1177 
1178 int
1179 nb_dev_init()
1180 {
1181 	find_dimm_label_t *label_function_p;
1182 
1183 	label_function_p = find_dimms_per_channel();
1184 	mutex_init(&nb_mutex, NULL, MUTEX_DRIVER, NULL);
1185 	nb_queue = errorq_create("nb_queue", nb_drain, NULL, NB_MAX_ERRORS,
1186 	    sizeof (nb_logout_t), 1, ERRORQ_VITAL);
1187 	if (nb_queue == NULL) {
1188 		mutex_destroy(&nb_mutex);
1189 		return (EAGAIN);
1190 	}
1191 	nb_int_init();
1192 	nb_thr_init();
1193 	dimm_init();
1194 	nb_dimms_init(label_function_p);
1195 	nb_mc_init();
1196 	nb_pex_init();
1197 	nb_fbd_init();
1198 	nb_fsb_init();
1199 	nb_scrubber_enable();
1200 	return (0);
1201 }
1202 
1203 int
1204 nb_init()
1205 {
1206 	/* return ENOTSUP if there is no PCI config space support. */
1207 	if (pci_getl_func == NULL)
1208 		return (ENOTSUP);
1209 
1210 	/* get vendor and device */
1211 	nb_chipset = (*pci_getl_func)(0, 0, 0, PCI_CONF_VENID);
1212 	switch (nb_chipset) {
1213 	default:
1214 		if (nb_5000_memory_controller == 0)
1215 			return (ENOTSUP);
1216 		break;
1217 	case INTEL_NB_7300:
1218 	case INTEL_NB_5000P:
1219 	case INTEL_NB_5000X:
1220 		break;
1221 	case INTEL_NB_5000V:
1222 	case INTEL_NB_5000Z:
1223 		nb_number_memory_controllers = 1;
1224 		break;
1225 	case INTEL_NB_5400:
1226 	case INTEL_NB_5400A:
1227 	case INTEL_NB_5400B:
1228 		nb_chipset = INTEL_NB_5400;
1229 		break;
1230 	}
1231 	return (0);
1232 }
1233 
1234 void
1235 nb_dev_reinit()
1236 {
1237 	int i, j;
1238 	int nchannels = nb_number_memory_controllers * 2;
1239 	nb_dimm_t **dimmpp;
1240 	nb_dimm_t *dimmp;
1241 	nb_dimm_t **old_nb_dimms;
1242 	int old_nb_dimms_per_channel;
1243 	find_dimm_label_t *label_function_p;
1244 
1245 	old_nb_dimms = nb_dimms;
1246 	old_nb_dimms_per_channel = nb_dimms_per_channel;
1247 
1248 	dimm_fini();
1249 	label_function_p = find_dimms_per_channel();
1250 	dimm_init();
1251 	nb_dimms_init(label_function_p);
1252 	nb_mc_init();
1253 	nb_pex_init();
1254 	nb_int_init();
1255 	nb_thr_init();
1256 	nb_fbd_init();
1257 	nb_fsb_init();
1258 	nb_scrubber_enable();
1259 
1260 	dimmpp = old_nb_dimms;
1261 	for (i = 0; i < nchannels; i++) {
1262 		for (j = 0; j < old_nb_dimms_per_channel; j++) {
1263 			dimmp = *dimmpp;
1264 			if (dimmp) {
1265 				kmem_free(dimmp, sizeof (nb_dimm_t));
1266 				*dimmpp = NULL;
1267 			}
1268 			dimmp++;
1269 		}
1270 	}
1271 	kmem_free(old_nb_dimms, sizeof (nb_dimm_t *) *
1272 	    nb_number_memory_controllers * 2 * old_nb_dimms_per_channel);
1273 }
1274 
1275 void
1276 nb_dev_unload()
1277 {
1278 	errorq_destroy(nb_queue);
1279 	nb_queue = NULL;
1280 	mutex_destroy(&nb_mutex);
1281 	nb_int_fini();
1282 	nb_thr_fini();
1283 	nb_fbd_fini();
1284 	nb_fsb_fini();
1285 	nb_pex_fini();
1286 	nb_fini();
1287 }
1288 
1289 void
1290 nb_unload()
1291 {
1292 }
1293