120c794b3Sgavinm /*
220c794b3Sgavinm  * CDDL HEADER START
320c794b3Sgavinm  *
420c794b3Sgavinm  * The contents of this file are subject to the terms of the
520c794b3Sgavinm  * Common Development and Distribution License (the "License").
620c794b3Sgavinm  * You may not use this file except in compliance with the License.
720c794b3Sgavinm  *
820c794b3Sgavinm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
920c794b3Sgavinm  * or http://www.opensolaris.org/os/licensing.
1020c794b3Sgavinm  * See the License for the specific language governing permissions
1120c794b3Sgavinm  * and limitations under the License.
1220c794b3Sgavinm  *
1320c794b3Sgavinm  * When distributing Covered Code, include this CDDL HEADER in each
1420c794b3Sgavinm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1520c794b3Sgavinm  * If applicable, add the following below this CDDL HEADER, with the
1620c794b3Sgavinm  * fields enclosed by brackets "[]" replaced with your own identifying
1720c794b3Sgavinm  * information: Portions Copyright [yyyy] [name of copyright owner]
1820c794b3Sgavinm  *
1920c794b3Sgavinm  * CDDL HEADER END
2020c794b3Sgavinm  */
2120c794b3Sgavinm 
2220c794b3Sgavinm /*
235de8e333Saf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2420c794b3Sgavinm  * Use is subject to license terms.
2520c794b3Sgavinm  */
2620c794b3Sgavinm 
2720c794b3Sgavinm #include <sys/types.h>
2820c794b3Sgavinm #include <sys/cmn_err.h>
2920c794b3Sgavinm #include <sys/errno.h>
3020c794b3Sgavinm #include <sys/log.h>
3120c794b3Sgavinm #include <sys/systm.h>
3220c794b3Sgavinm #include <sys/modctl.h>
3320c794b3Sgavinm #include <sys/errorq.h>
3420c794b3Sgavinm #include <sys/controlregs.h>
3520c794b3Sgavinm #include <sys/fm/util.h>
3620c794b3Sgavinm #include <sys/fm/protocol.h>
3720c794b3Sgavinm #include <sys/sysevent.h>
3820c794b3Sgavinm #include <sys/pghw.h>
3920c794b3Sgavinm #include <sys/cyclic.h>
4020c794b3Sgavinm #include <sys/pci_cfgspace.h>
4120c794b3Sgavinm #include <sys/mc_intel.h>
4220c794b3Sgavinm #include <sys/smbios.h>
4320c794b3Sgavinm #include <sys/pci.h>
449a12e1bdSjveta #include <sys/pcie.h>
4520c794b3Sgavinm #include "nb5000.h"
4620c794b3Sgavinm #include "nb_log.h"
4720c794b3Sgavinm #include "dimm_phys.h"
4820c794b3Sgavinm #include "rank.h"
4920c794b3Sgavinm 
5020c794b3Sgavinm int nb_hw_memory_scrub_enable = 1;
5120c794b3Sgavinm static int nb_sw_scrub_disabled = 0;
5220c794b3Sgavinm 
5320c794b3Sgavinm int nb_5000_memory_controller = 0;
5420c794b3Sgavinm int nb_number_memory_controllers = NB_5000_MAX_MEM_CONTROLLERS;
5520c794b3Sgavinm int nb_dimms_per_channel = 0;
5620c794b3Sgavinm static int ndimms = 0;
5720c794b3Sgavinm 
5820c794b3Sgavinm nb_dimm_t **nb_dimms;
5920c794b3Sgavinm int nb_ndimm;
6020c794b3Sgavinm uint32_t nb_chipset;
6120c794b3Sgavinm enum nb_memory_mode nb_mode;
625de8e333Saf bank_select_t nb_banks[NB_MAX_MEM_BRANCH_SELECT];
635de8e333Saf rank_select_t nb_ranks[NB_5000_MAX_MEM_CONTROLLERS][NB_MAX_MEM_RANK_SELECT];
6420c794b3Sgavinm uint32_t top_of_low_memory;
6520c794b3Sgavinm uint8_t spare_rank[NB_5000_MAX_MEM_CONTROLLERS];
6620c794b3Sgavinm 
6720c794b3Sgavinm errorq_t *nb_queue;
6820c794b3Sgavinm kmutex_t nb_mutex;
6920c794b3Sgavinm 
7020c794b3Sgavinm static uint8_t nb_err0_int;
7120c794b3Sgavinm static uint8_t nb_err1_int;
7220c794b3Sgavinm static uint8_t nb_err2_int;
7320c794b3Sgavinm static uint8_t nb_mcerr_int;
745f28a827Saf static uint32_t nb_emask_int;
7520c794b3Sgavinm 
7620c794b3Sgavinm static uint32_t nb_err0_fbd;
7720c794b3Sgavinm static uint32_t nb_err1_fbd;
7820c794b3Sgavinm static uint32_t nb_err2_fbd;
7920c794b3Sgavinm static uint32_t nb_mcerr_fbd;
8020c794b3Sgavinm static uint32_t nb_emask_fbd;
8120c794b3Sgavinm 
8220c794b3Sgavinm static uint16_t nb_err0_fsb;
8320c794b3Sgavinm static uint16_t nb_err1_fsb;
8420c794b3Sgavinm static uint16_t nb_err2_fsb;
8520c794b3Sgavinm static uint16_t nb_mcerr_fsb;
8620c794b3Sgavinm static uint16_t nb_emask_fsb;
8720c794b3Sgavinm 
885f28a827Saf static uint16_t nb_err0_thr;
895f28a827Saf static uint16_t nb_err1_thr;
905f28a827Saf static uint16_t nb_err2_thr;
915f28a827Saf static uint16_t nb_mcerr_thr;
925f28a827Saf static uint16_t nb_emask_thr;
935f28a827Saf 
9420c794b3Sgavinm static uint32_t	emask_uncor_pex[NB_PCI_DEV];
9520c794b3Sgavinm static uint32_t emask_cor_pex[NB_PCI_DEV];
9620c794b3Sgavinm static uint32_t emask_rp_pex[NB_PCI_DEV];
9720c794b3Sgavinm static uint32_t docmd_pex[NB_PCI_DEV];
9820c794b3Sgavinm static uint32_t uncerrsev[NB_PCI_DEV];
9920c794b3Sgavinm 
10020c794b3Sgavinm static uint8_t l_mcerr_int;
10120c794b3Sgavinm static uint32_t l_mcerr_fbd;
10220c794b3Sgavinm static uint16_t l_mcerr_fsb;
1035f28a827Saf static uint16_t l_mcerr_thr;
10420c794b3Sgavinm 
1055f28a827Saf uint_t nb5000_emask_fbd = EMASK_5000_FBD_RES;
1065f28a827Saf uint_t nb5400_emask_fbd = 0;
10720c794b3Sgavinm int nb5000_reset_emask_fbd = 1;
10820c794b3Sgavinm uint_t nb5000_mask_poll_fbd = EMASK_FBD_NF;
10920c794b3Sgavinm uint_t nb5000_mask_bios_fbd = EMASK_FBD_FATAL;
1105f28a827Saf uint_t nb5400_mask_poll_fbd = EMASK_5400_FBD_NF;
1115f28a827Saf uint_t nb5400_mask_bios_fbd = EMASK_5400_FBD_FATAL;
11220c794b3Sgavinm 
11320c794b3Sgavinm uint_t nb5000_emask_fsb = 0;
11420c794b3Sgavinm int nb5000_reset_emask_fsb = 1;
11520c794b3Sgavinm uint_t nb5000_mask_poll_fsb = EMASK_FSB_NF;
11620c794b3Sgavinm uint_t nb5000_mask_bios_fsb = EMASK_FSB_FATAL;
11720c794b3Sgavinm 
1185f28a827Saf uint_t nb5400_emask_int = 0;
1195f28a827Saf 
12020c794b3Sgavinm uint_t nb7300_emask_int = EMASK_INT_7300;
12120c794b3Sgavinm uint_t nb7300_emask_int_step0 = EMASK_INT_7300_STEP_0;
12220c794b3Sgavinm uint_t nb5000_emask_int = EMASK_INT_5000;
12320c794b3Sgavinm int nb5000_reset_emask_int = 1;
12420c794b3Sgavinm uint_t nb5000_mask_poll_int = EMASK_INT_NF;
12520c794b3Sgavinm uint_t nb5000_mask_bios_int = EMASK_INT_FATAL;
12620c794b3Sgavinm 
1275f28a827Saf uint_t nb_mask_poll_thr = EMASK_THR_NF;
1285f28a827Saf uint_t nb_mask_bios_thr = EMASK_THR_FATAL;
1295f28a827Saf 
13020c794b3Sgavinm int nb5000_reset_uncor_pex = 0;
13120c794b3Sgavinm uint_t nb5000_mask_uncor_pex = 0;
1325f28a827Saf int nb5000_reset_cor_pex = 0;
13320c794b3Sgavinm uint_t nb5000_mask_cor_pex = 0xffffffff;
1345f28a827Saf int nb_set_docmd = 1;
1359a12e1bdSjveta uint32_t nb5000_rp_pex = 0x1;
13620c794b3Sgavinm uint32_t nb5000_docmd_pex_mask = DOCMD_PEX_MASK;
1375f28a827Saf uint32_t nb5400_docmd_pex_mask = DOCMD_5400_PEX_MASK;
13820c794b3Sgavinm uint32_t nb5000_docmd_pex = DOCMD_PEX;
1395f28a827Saf uint32_t nb5400_docmd_pex = DOCMD_5400_PEX;
14020c794b3Sgavinm 
14120c794b3Sgavinm int nb_mask_mc_set;
14220c794b3Sgavinm 
1439d6aa643Saf typedef struct find_dimm_label {
1449d6aa643Saf 	void (*label_function)(int, char *, int);
1459d6aa643Saf } find_dimm_label_t;
1469d6aa643Saf 
1479d6aa643Saf static void x8450_dimm_label(int, char *, int);
1489d6aa643Saf 
1499d6aa643Saf static struct platform_label {
1509d6aa643Saf 	const char *sys_vendor;		/* SMB_TYPE_SYSTEM vendor prefix */
1519d6aa643Saf 	const char *sys_product;	/* SMB_TYPE_SYSTEM product prefix */
1529d6aa643Saf 	find_dimm_label_t dimm_label;
1539d6aa643Saf 	int dimms_per_channel;
1549d6aa643Saf } platform_label[] = {
1559d6aa643Saf 	{ "SUN MICROSYSTEMS", "SUN BLADE X8450 SERVER MODULE",
1569d6aa643Saf 	    x8450_dimm_label, 8 },
1579d6aa643Saf 	{ NULL, NULL, NULL, 0 }
1589d6aa643Saf };
1599d6aa643Saf 
16020c794b3Sgavinm static unsigned short
16120c794b3Sgavinm read_spd(int bus)
16220c794b3Sgavinm {
16320c794b3Sgavinm 	unsigned short rt = 0;
16420c794b3Sgavinm 	int branch = bus >> 1;
16520c794b3Sgavinm 	int channel = bus & 1;
16620c794b3Sgavinm 
16720c794b3Sgavinm 	rt = SPD_RD(branch, channel);
16820c794b3Sgavinm 
16920c794b3Sgavinm 	return (rt);
17020c794b3Sgavinm }
17120c794b3Sgavinm 
17220c794b3Sgavinm static void
17320c794b3Sgavinm write_spdcmd(int bus, uint32_t val)
17420c794b3Sgavinm {
17520c794b3Sgavinm 	int branch = bus >> 1;
17620c794b3Sgavinm 	int channel = bus & 1;
17720c794b3Sgavinm 	SPDCMD_WR(branch, channel, val);
17820c794b3Sgavinm }
17920c794b3Sgavinm 
18020c794b3Sgavinm static int
18120c794b3Sgavinm read_spd_eeprom(int bus, int slave, int addr)
18220c794b3Sgavinm {
18320c794b3Sgavinm 	int retry = 4;
18420c794b3Sgavinm 	int wait;
18520c794b3Sgavinm 	int spd;
18620c794b3Sgavinm 	uint32_t cmd;
18720c794b3Sgavinm 
18820c794b3Sgavinm 	for (;;) {
18920c794b3Sgavinm 		wait = 1000;
19020c794b3Sgavinm 		for (;;) {
19120c794b3Sgavinm 			spd = read_spd(bus);
19220c794b3Sgavinm 			if ((spd & SPD_BUSY) == 0)
19320c794b3Sgavinm 				break;
19420c794b3Sgavinm 			if (--wait == 0)
19520c794b3Sgavinm 				return (-1);
19620c794b3Sgavinm 			drv_usecwait(10);
19720c794b3Sgavinm 		}
19820c794b3Sgavinm 		cmd = SPD_EEPROM_WRITE | SPD_ADDR(slave, addr);
19920c794b3Sgavinm 		write_spdcmd(bus, cmd);
20020c794b3Sgavinm 		wait = 1000;
20120c794b3Sgavinm 		for (;;) {
20220c794b3Sgavinm 			spd = read_spd(bus);
20320c794b3Sgavinm 			if ((spd & SPD_BUSY) == 0)
20420c794b3Sgavinm 				break;
20520c794b3Sgavinm 			if (--wait == 0) {
20620c794b3Sgavinm 				spd = SPD_BUS_ERROR;
20720c794b3Sgavinm 				break;
20820c794b3Sgavinm 			}
20920c794b3Sgavinm 			drv_usecwait(10);
21020c794b3Sgavinm 		}
21120c794b3Sgavinm 		while ((spd & SPD_BUS_ERROR) == 0 &&
21220c794b3Sgavinm 		    (spd & (SPD_READ_DATA_VALID|SPD_BUSY)) !=
21320c794b3Sgavinm 		    SPD_READ_DATA_VALID) {
21420c794b3Sgavinm 			spd = read_spd(bus);
21520c794b3Sgavinm 			if (--wait == 0)
21620c794b3Sgavinm 				return (-1);
21720c794b3Sgavinm 		}
21820c794b3Sgavinm 		if ((spd & SPD_BUS_ERROR) == 0)
21920c794b3Sgavinm 			break;
22020c794b3Sgavinm 		if (--retry == 0)
22120c794b3Sgavinm 			return (-1);
22220c794b3Sgavinm 	}
22320c794b3Sgavinm 	return (spd & 0xff);
22420c794b3Sgavinm }
22520c794b3Sgavinm 
22620c794b3Sgavinm static void
22720c794b3Sgavinm nb_fini()
22820c794b3Sgavinm {
22920c794b3Sgavinm 	int i, j;
23020c794b3Sgavinm 	int nchannels = nb_number_memory_controllers * 2;
23120c794b3Sgavinm 	nb_dimm_t **dimmpp;
23220c794b3Sgavinm 	nb_dimm_t *dimmp;
23320c794b3Sgavinm 
23420c794b3Sgavinm 	dimmpp = nb_dimms;
23520c794b3Sgavinm 	for (i = 0; i < nchannels; i++) {
23620c794b3Sgavinm 		for (j = 0; j < nb_dimms_per_channel; j++) {
23720c794b3Sgavinm 			dimmp = *dimmpp;
23820c794b3Sgavinm 			if (dimmp) {
23920c794b3Sgavinm 				kmem_free(dimmp, sizeof (nb_dimm_t));
24020c794b3Sgavinm 				*dimmpp = NULL;
24120c794b3Sgavinm 			}
24220c794b3Sgavinm 			dimmp++;
24320c794b3Sgavinm 		}
24420c794b3Sgavinm 	}
24520c794b3Sgavinm 	kmem_free(nb_dimms, sizeof (nb_dimm_t *) *
24620c794b3Sgavinm 	    nb_number_memory_controllers * 2 * nb_dimms_per_channel);
24720c794b3Sgavinm 	nb_dimms = NULL;
24820c794b3Sgavinm 	dimm_fini();
24920c794b3Sgavinm }
25020c794b3Sgavinm 
25120c794b3Sgavinm void
25220c794b3Sgavinm nb_scrubber_enable()
25320c794b3Sgavinm {
25420c794b3Sgavinm 	uint32_t mc;
25520c794b3Sgavinm 
25620c794b3Sgavinm 	if (!nb_hw_memory_scrub_enable)
25720c794b3Sgavinm 		return;
25820c794b3Sgavinm 
25920c794b3Sgavinm 	mc = MC_RD();
26020c794b3Sgavinm 	if ((mc & MC_MIRROR) != 0) /* mirror mode */
26120c794b3Sgavinm 		mc |= MC_PATROL_SCRUB;
26220c794b3Sgavinm 	else
26320c794b3Sgavinm 		mc |= MC_PATROL_SCRUB|MC_DEMAND_SCRUB;
26420c794b3Sgavinm 	MC_WR(mc);
26520c794b3Sgavinm 
26620c794b3Sgavinm 	if (nb_sw_scrub_disabled++)
267*e4b86885SCheng Sean Ye 		cmi_mc_sw_memscrub_disable();
26820c794b3Sgavinm }
26920c794b3Sgavinm 
27020c794b3Sgavinm static nb_dimm_t *
27120c794b3Sgavinm nb_dimm_init(int channel, int dimm, uint16_t mtr)
27220c794b3Sgavinm {
27320c794b3Sgavinm 	nb_dimm_t *dp;
27420c794b3Sgavinm 	int i, t;
27520c794b3Sgavinm 	int spd_sz;
27620c794b3Sgavinm 
2779d6aa643Saf 	if (MTR_PRESENT(mtr) == 0)
2789d6aa643Saf 		return (NULL);
27920c794b3Sgavinm 	t = read_spd_eeprom(channel, dimm, 2) & 0xf;
28020c794b3Sgavinm 
28120c794b3Sgavinm 	if (t != 9)
28220c794b3Sgavinm 		return (NULL);
28320c794b3Sgavinm 
28420c794b3Sgavinm 	dp = kmem_zalloc(sizeof (nb_dimm_t), KM_SLEEP);
2859d6aa643Saf 
28620c794b3Sgavinm 	t = read_spd_eeprom(channel, dimm, 0) & 0xf;
28720c794b3Sgavinm 	if (t == 1)
28820c794b3Sgavinm 		spd_sz = 128;
28920c794b3Sgavinm 	else if (t == 2)
29020c794b3Sgavinm 		spd_sz = 176;
29120c794b3Sgavinm 	else
29220c794b3Sgavinm 		spd_sz = 256;
29320c794b3Sgavinm 	dp->manufacture_id = read_spd_eeprom(channel, dimm, 117) |
29420c794b3Sgavinm 	    (read_spd_eeprom(channel, dimm, 118) << 8);
29520c794b3Sgavinm 	dp->manufacture_location = read_spd_eeprom(channel, dimm, 119);
29620c794b3Sgavinm 	dp->serial_number =
29720c794b3Sgavinm 	    (read_spd_eeprom(channel, dimm, 122) << 24) |
29820c794b3Sgavinm 	    (read_spd_eeprom(channel, dimm, 123) << 16) |
29920c794b3Sgavinm 	    (read_spd_eeprom(channel, dimm, 124) << 8) |
30020c794b3Sgavinm 	    read_spd_eeprom(channel, dimm, 125);
30120c794b3Sgavinm 	t = read_spd_eeprom(channel, dimm, 121);
30220c794b3Sgavinm 	dp->manufacture_week = (t >> 4) * 10 + (t & 0xf);
30320c794b3Sgavinm 	dp->manufacture_year = read_spd_eeprom(channel, dimm, 120);
30420c794b3Sgavinm 	if (spd_sz > 128) {
30520c794b3Sgavinm 		for (i = 0; i < sizeof (dp->part_number); i++) {
30620c794b3Sgavinm 			dp->part_number[i] =
30720c794b3Sgavinm 			    read_spd_eeprom(channel, dimm, 128 + i);
30820c794b3Sgavinm 		}
30920c794b3Sgavinm 		for (i = 0; i < sizeof (dp->revision); i++) {
31020c794b3Sgavinm 			dp->revision[i] =
31120c794b3Sgavinm 			    read_spd_eeprom(channel, dimm, 146 + i);
31220c794b3Sgavinm 		}
31320c794b3Sgavinm 	}
3145de8e333Saf 	dp->mtr_present = MTR_PRESENT(mtr);
31520c794b3Sgavinm 	dp->nranks = MTR_NUMRANK(mtr);
31620c794b3Sgavinm 	dp->nbanks = MTR_NUMBANK(mtr);
31720c794b3Sgavinm 	dp->ncolumn = MTR_NUMCOL(mtr);
31820c794b3Sgavinm 	dp->nrow = MTR_NUMROW(mtr);
31920c794b3Sgavinm 	dp->width = MTR_WIDTH(mtr);
32020c794b3Sgavinm 	dp->dimm_size = MTR_DIMMSIZE(mtr);
32120c794b3Sgavinm 
32220c794b3Sgavinm 	return (dp);
32320c794b3Sgavinm }
32420c794b3Sgavinm 
32520c794b3Sgavinm static uint64_t
32620c794b3Sgavinm mc_range(int controller, uint64_t base)
32720c794b3Sgavinm {
32820c794b3Sgavinm 	int i;
32920c794b3Sgavinm 	uint64_t limit = 0;
33020c794b3Sgavinm 
33120c794b3Sgavinm 	for (i = 0; i < NB_MEM_BRANCH_SELECT; i++) {
33220c794b3Sgavinm 		if (nb_banks[i].way[controller] && base >= nb_banks[i].base &&
33320c794b3Sgavinm 		    base < nb_banks[i].limit) {
33420c794b3Sgavinm 			limit = nb_banks[i].limit;
33520c794b3Sgavinm 			if (base <= top_of_low_memory &&
33620c794b3Sgavinm 			    limit > top_of_low_memory) {
33720c794b3Sgavinm 				limit -= TLOW_MAX - top_of_low_memory;
33820c794b3Sgavinm 			}
33920c794b3Sgavinm 			if (nb_banks[i].way[0] && nb_banks[i].way[1] &&
34020c794b3Sgavinm 			    nb_mode != NB_MEMORY_MIRROR) {
34120c794b3Sgavinm 				limit = limit / 2;
34220c794b3Sgavinm 			}
34320c794b3Sgavinm 		}
34420c794b3Sgavinm 	}
34520c794b3Sgavinm 	return (limit);
34620c794b3Sgavinm }
34720c794b3Sgavinm 
34820c794b3Sgavinm void
34920c794b3Sgavinm nb_mc_init()
35020c794b3Sgavinm {
35120c794b3Sgavinm 	uint16_t tolm;
35220c794b3Sgavinm 	uint16_t mir;
35320c794b3Sgavinm 	uint32_t hole_base;
35420c794b3Sgavinm 	uint32_t hole_size;
35520c794b3Sgavinm 	uint32_t dmir;
35620c794b3Sgavinm 	uint64_t base;
35720c794b3Sgavinm 	uint64_t limit;
35820c794b3Sgavinm 	uint8_t way0, way1, rank0, rank1, rank2, rank3, branch_interleave;
35920c794b3Sgavinm 	int i, j, k;
36020c794b3Sgavinm 	uint8_t interleave;
36120c794b3Sgavinm 
36220c794b3Sgavinm 	base = 0;
36320c794b3Sgavinm 	tolm = TOLM_RD();
36420c794b3Sgavinm 	top_of_low_memory = ((uint32_t)(tolm >> 12) & 0xf) << 28;
36520c794b3Sgavinm 	for (i = 0; i < NB_MEM_BRANCH_SELECT; i++) {
36620c794b3Sgavinm 		mir = MIR_RD(i);
36720c794b3Sgavinm 		limit = (uint64_t)(mir >> 4) << 28;
36820c794b3Sgavinm 		way0 = mir & 1;
36920c794b3Sgavinm 		way1 = (mir >> 1) & 1;
37020c794b3Sgavinm 		if (way0 == 0 && way1 == 0) {
37120c794b3Sgavinm 			way0 = 1;
37220c794b3Sgavinm 			way1 = 1;
37320c794b3Sgavinm 		}
37420c794b3Sgavinm 		if (limit > top_of_low_memory)
37520c794b3Sgavinm 			limit += TLOW_MAX - top_of_low_memory;
37620c794b3Sgavinm 		nb_banks[i].base = base;
37720c794b3Sgavinm 		nb_banks[i].limit = limit;
37820c794b3Sgavinm 		nb_banks[i].way[0] = way0;
37920c794b3Sgavinm 		nb_banks[i].way[1] = way1;
38020c794b3Sgavinm 		base = limit;
38120c794b3Sgavinm 	}
38220c794b3Sgavinm 	for (i = 0; i < nb_number_memory_controllers; i++) {
38320c794b3Sgavinm 		base = 0;
38420c794b3Sgavinm 
38520c794b3Sgavinm 		for (j = 0; j < NB_MEM_RANK_SELECT; j++) {
38620c794b3Sgavinm 			dmir = DMIR_RD(i, j);
38720c794b3Sgavinm 			limit = ((uint64_t)(dmir >> 16) & 0xff) << 28;
38820c794b3Sgavinm 			if (limit == 0) {
38920c794b3Sgavinm 				limit = mc_range(i, base);
39020c794b3Sgavinm 			}
39120c794b3Sgavinm 			branch_interleave = 0;
39220c794b3Sgavinm 			hole_base = 0;
39320c794b3Sgavinm 			hole_size = 0;
3949d6aa643Saf 			DMIR_RANKS(dmir, rank0, rank1, rank2, rank3);
39520c794b3Sgavinm 			if (rank0 == rank1)
39620c794b3Sgavinm 				interleave = 1;
39720c794b3Sgavinm 			else if (rank0 == rank2)
39820c794b3Sgavinm 				interleave = 2;
39920c794b3Sgavinm 			else
40020c794b3Sgavinm 				interleave = 4;
40120c794b3Sgavinm 			if (nb_mode != NB_MEMORY_MIRROR &&
40220c794b3Sgavinm 			    nb_mode != NB_MEMORY_SINGLE_CHANNEL) {
40320c794b3Sgavinm 				for (k = 0; k < NB_MEM_BRANCH_SELECT; k++) {
40420c794b3Sgavinm 					if (base >= nb_banks[k].base &&
40520c794b3Sgavinm 					    base < nb_banks[k].limit) {
40620c794b3Sgavinm 						if (nb_banks[i].way[0] &&
40720c794b3Sgavinm 						    nb_banks[i].way[1]) {
40820c794b3Sgavinm 							interleave *= 2;
40920c794b3Sgavinm 							limit *= 2;
41020c794b3Sgavinm 							branch_interleave = 1;
41120c794b3Sgavinm 						}
41220c794b3Sgavinm 						break;
41320c794b3Sgavinm 					}
41420c794b3Sgavinm 				}
41520c794b3Sgavinm 			}
41620c794b3Sgavinm 			if (base < top_of_low_memory &&
41720c794b3Sgavinm 			    limit > top_of_low_memory) {
41820c794b3Sgavinm 				hole_base = top_of_low_memory;
41920c794b3Sgavinm 				hole_size = TLOW_MAX - top_of_low_memory;
42020c794b3Sgavinm 				limit += hole_size;
42120c794b3Sgavinm 			} else if (base > top_of_low_memory) {
42220c794b3Sgavinm 				limit += TLOW_MAX - top_of_low_memory;
42320c794b3Sgavinm 			}
42420c794b3Sgavinm 			nb_ranks[i][j].base = base;
42520c794b3Sgavinm 			nb_ranks[i][j].limit = limit;
42620c794b3Sgavinm 			nb_ranks[i][j].rank[0] = rank0;
42720c794b3Sgavinm 			nb_ranks[i][j].rank[1] = rank1;
42820c794b3Sgavinm 			nb_ranks[i][j].rank[2] = rank2;
42920c794b3Sgavinm 			nb_ranks[i][j].rank[3] = rank3;
43020c794b3Sgavinm 			nb_ranks[i][j].interleave = interleave;
43120c794b3Sgavinm 			nb_ranks[i][j].branch_interleave = branch_interleave;
43220c794b3Sgavinm 			nb_ranks[i][j].hole_base = hole_base;
43320c794b3Sgavinm 			nb_ranks[i][j].hole_size = hole_size;
43420c794b3Sgavinm 			if (limit > base) {
43520c794b3Sgavinm 				dimm_add_rank(i, rank0, branch_interleave, 0,
43620c794b3Sgavinm 				    base, hole_base, hole_size, interleave,
43720c794b3Sgavinm 				    limit);
43820c794b3Sgavinm 				if (rank0 != rank1) {
43920c794b3Sgavinm 					dimm_add_rank(i, rank1,
44020c794b3Sgavinm 					    branch_interleave, 1, base,
44120c794b3Sgavinm 					    hole_base, hole_size, interleave,
44220c794b3Sgavinm 					    limit);
44320c794b3Sgavinm 					if (rank0 != rank2) {
44420c794b3Sgavinm 						dimm_add_rank(i, rank2,
44520c794b3Sgavinm 						    branch_interleave, 2, base,
44620c794b3Sgavinm 						    hole_base, hole_size,
44720c794b3Sgavinm 						    interleave, limit);
44820c794b3Sgavinm 						dimm_add_rank(i, rank3,
44920c794b3Sgavinm 						    branch_interleave, 3, base,
45020c794b3Sgavinm 						    hole_base, hole_size,
45120c794b3Sgavinm 						    interleave, limit);
45220c794b3Sgavinm 					}
45320c794b3Sgavinm 				}
45420c794b3Sgavinm 			}
45520c794b3Sgavinm 			base = limit;
45620c794b3Sgavinm 		}
45720c794b3Sgavinm 	}
45820c794b3Sgavinm }
45920c794b3Sgavinm 
46020c794b3Sgavinm void
46120c794b3Sgavinm nb_used_spare_rank(int branch, int bad_rank)
46220c794b3Sgavinm {
46320c794b3Sgavinm 	int i;
46420c794b3Sgavinm 	int j;
46520c794b3Sgavinm 
46620c794b3Sgavinm 	for (i = 0; i < NB_MEM_RANK_SELECT; i++) {
46720c794b3Sgavinm 		for (j = 0; j < NB_RANKS_IN_SELECT; j++) {
46820c794b3Sgavinm 			if (nb_ranks[branch][i].rank[j] == bad_rank) {
46920c794b3Sgavinm 				nb_ranks[branch][i].rank[j] =
47020c794b3Sgavinm 				    spare_rank[branch];
47120c794b3Sgavinm 				i = NB_MEM_RANK_SELECT;
47220c794b3Sgavinm 				break;
47320c794b3Sgavinm 			}
47420c794b3Sgavinm 		}
47520c794b3Sgavinm 	}
47620c794b3Sgavinm }
47720c794b3Sgavinm 
47820c794b3Sgavinm /*ARGSUSED*/
47920c794b3Sgavinm static int
48020c794b3Sgavinm memoryarray(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
48120c794b3Sgavinm {
48220c794b3Sgavinm 	smbios_memarray_t ma;
48320c794b3Sgavinm 
48420c794b3Sgavinm 	if (sp->smbstr_type == SMB_TYPE_MEMARRAY &&
48520c794b3Sgavinm 	    smbios_info_memarray(shp, sp->smbstr_id, &ma) == 0) {
48620c794b3Sgavinm 		ndimms += ma.smbma_ndevs;
48720c794b3Sgavinm 	}
48820c794b3Sgavinm 	return (0);
48920c794b3Sgavinm }
49020c794b3Sgavinm 
4919d6aa643Saf find_dimm_label_t *
49220c794b3Sgavinm find_dimms_per_channel()
49320c794b3Sgavinm {
4949d6aa643Saf 	struct platform_label *pl;
4959d6aa643Saf 	smbios_info_t si;
4969d6aa643Saf 	smbios_system_t sy;
4979d6aa643Saf 	id_t id;
4989d6aa643Saf 	int read_memarray = 1;
4999d6aa643Saf 	find_dimm_label_t *rt = NULL;
5009d6aa643Saf 
5019d6aa643Saf 	if (ksmbios != NULL) {
5029d6aa643Saf 		if ((id = smbios_info_system(ksmbios, &sy)) != SMB_ERR &&
5039d6aa643Saf 		    smbios_info_common(ksmbios, id, &si) != SMB_ERR) {
5049d6aa643Saf 			for (pl = platform_label; pl->sys_vendor; pl++) {
5059d6aa643Saf 				if (strncmp(pl->sys_vendor,
5069d6aa643Saf 				    si.smbi_manufacturer,
5079d6aa643Saf 				    strlen(pl->sys_vendor)) == 0 &&
5089d6aa643Saf 				    strncmp(pl->sys_product, si.smbi_product,
5099d6aa643Saf 				    strlen(pl->sys_product)) == 0) {
5109d6aa643Saf 					nb_dimms_per_channel =
5119d6aa643Saf 					    pl->dimms_per_channel;
5129d6aa643Saf 					read_memarray = 0;
5139d6aa643Saf 					rt = &pl->dimm_label;
5149d6aa643Saf 					break;
5159d6aa643Saf 				}
5169d6aa643Saf 			}
5179d6aa643Saf 		}
5189d6aa643Saf 		if (read_memarray)
51920c794b3Sgavinm 			(void) smbios_iter(ksmbios, memoryarray, 0);
5209d6aa643Saf 	}
5219d6aa643Saf 	if (nb_dimms_per_channel == 0) {
5229d6aa643Saf 		if (ndimms) {
52320c794b3Sgavinm 			nb_dimms_per_channel = ndimms /
52420c794b3Sgavinm 			    (nb_number_memory_controllers * 2);
5259d6aa643Saf 		} else {
5269d6aa643Saf 			nb_dimms_per_channel = NB_MAX_DIMMS_PER_CHANNEL;
52720c794b3Sgavinm 		}
52820c794b3Sgavinm 	}
5299d6aa643Saf 	return (rt);
53020c794b3Sgavinm }
53120c794b3Sgavinm 
53220c794b3Sgavinm static int
53320c794b3Sgavinm dimm_label(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
53420c794b3Sgavinm {
53520c794b3Sgavinm 	nb_dimm_t ***dimmpp = arg;
53620c794b3Sgavinm 	nb_dimm_t *dimmp;
53720c794b3Sgavinm 	smbios_memdevice_t md;
53820c794b3Sgavinm 
53920c794b3Sgavinm 	if (sp->smbstr_type == SMB_TYPE_MEMDEVICE) {
54020c794b3Sgavinm 		dimmp = **dimmpp;
54120c794b3Sgavinm 		if (dimmp && smbios_info_memdevice(shp, sp->smbstr_id,
54220c794b3Sgavinm 		    &md) == 0 && md.smbmd_dloc != NULL) {
54320c794b3Sgavinm 			(void) snprintf(dimmp->label,
54420c794b3Sgavinm 			    sizeof (dimmp->label), "%s", md.smbmd_dloc);
54520c794b3Sgavinm 		}
54620c794b3Sgavinm 		(*dimmpp)++;
54720c794b3Sgavinm 	}
54820c794b3Sgavinm 	return (0);
54920c794b3Sgavinm }
55020c794b3Sgavinm 
55120c794b3Sgavinm void
55220c794b3Sgavinm nb_smbios()
55320c794b3Sgavinm {
55420c794b3Sgavinm 	nb_dimm_t **dimmpp;
55520c794b3Sgavinm 
55620c794b3Sgavinm 	if (ksmbios != NULL) {
55720c794b3Sgavinm 		dimmpp = nb_dimms;
55820c794b3Sgavinm 		(void) smbios_iter(ksmbios, dimm_label, &dimmpp);
55920c794b3Sgavinm 	}
56020c794b3Sgavinm }
56120c794b3Sgavinm 
56220c794b3Sgavinm static void
5639d6aa643Saf x8450_dimm_label(int dimm, char *label, int label_sz)
56420c794b3Sgavinm {
5659d6aa643Saf 	int channel = dimm >> 3;
5669d6aa643Saf 
5679d6aa643Saf 	dimm = dimm & 0x7;
5689d6aa643Saf 	(void) snprintf(label, label_sz, "D%d", (dimm * 4) + channel);
5699d6aa643Saf }
5709d6aa643Saf 
5719d6aa643Saf static void
5729d6aa643Saf nb_dimms_init(find_dimm_label_t *label_function)
5739d6aa643Saf {
5749d6aa643Saf 	int i, j, k, l;
57520c794b3Sgavinm 	uint16_t mtr;
57620c794b3Sgavinm 	uint32_t mc, mca;
57720c794b3Sgavinm 	uint32_t spcpc;
57820c794b3Sgavinm 	uint8_t spcps;
57920c794b3Sgavinm 	nb_dimm_t **dimmpp;
58020c794b3Sgavinm 
58120c794b3Sgavinm 	mca = MCA_RD();
58220c794b3Sgavinm 	mc = MC_RD();
58320c794b3Sgavinm 	if (mca & MCA_SCHDIMM)  /* single-channel mode */
58420c794b3Sgavinm 		nb_mode = NB_MEMORY_SINGLE_CHANNEL;
58520c794b3Sgavinm 	else if ((mc & MC_MIRROR) != 0) /* mirror mode */
58620c794b3Sgavinm 		nb_mode = NB_MEMORY_MIRROR;
58720c794b3Sgavinm 	else
58820c794b3Sgavinm 		nb_mode = NB_MEMORY_NORMAL;
58920c794b3Sgavinm 	nb_dimms = (nb_dimm_t **)kmem_zalloc(sizeof (nb_dimm_t *) *
59020c794b3Sgavinm 	    nb_number_memory_controllers * 2 * nb_dimms_per_channel, KM_SLEEP);
59120c794b3Sgavinm 	dimmpp = nb_dimms;
59220c794b3Sgavinm 	for (i = 0; i < nb_number_memory_controllers; i++) {
59320c794b3Sgavinm 		if (nb_mode == NB_MEMORY_NORMAL) {
59420c794b3Sgavinm 			spcpc = SPCPC_RD(i);
59520c794b3Sgavinm 			spcps = SPCPS_RD(i);
59620c794b3Sgavinm 			if ((spcpc & SPCPC_SPARE_ENABLE) != 0 &&
59720c794b3Sgavinm 			    (spcps & SPCPS_SPARE_DEPLOYED) != 0)
59820c794b3Sgavinm 				nb_mode = NB_MEMORY_SPARE_RANK;
59920c794b3Sgavinm 			spare_rank[i] = SPCPC_SPRANK(spcpc);
60020c794b3Sgavinm 		}
60120c794b3Sgavinm 		for (j = 0; j < nb_dimms_per_channel; j++) {
60220c794b3Sgavinm 			mtr = MTR_RD(i, j);
60320c794b3Sgavinm 			k = i * 2;
60420c794b3Sgavinm 			dimmpp[j] = nb_dimm_init(k, j, mtr);
60520c794b3Sgavinm 			if (dimmpp[j]) {
60620c794b3Sgavinm 				nb_ndimm ++;
60720c794b3Sgavinm 				dimm_add_geometry(i, j, dimmpp[j]->nbanks,
60820c794b3Sgavinm 				    dimmpp[j]->width, dimmpp[j]->ncolumn,
60920c794b3Sgavinm 				    dimmpp[j]->nrow);
6109d6aa643Saf 				if (label_function) {
6119d6aa643Saf 					label_function->label_function(
6129d6aa643Saf 					    (k * nb_dimms_per_channel) + j,
6139d6aa643Saf 					    dimmpp[j]->label,
6149d6aa643Saf 					    sizeof (dimmpp[j]->label));
6159d6aa643Saf 				}
61620c794b3Sgavinm 			}
61720c794b3Sgavinm 			dimmpp[j + nb_dimms_per_channel] =
61820c794b3Sgavinm 			    nb_dimm_init(k + 1, j, mtr);
6199d6aa643Saf 			l = j + nb_dimms_per_channel;
6209d6aa643Saf 			if (dimmpp[l]) {
6219d6aa643Saf 				if (label_function) {
6229d6aa643Saf 					label_function->label_function(
6239d6aa643Saf 					    (k * nb_dimms_per_channel) + l,
6249d6aa643Saf 					    dimmpp[l]->label,
6259d6aa643Saf 					    sizeof (dimmpp[l]->label));
6269d6aa643Saf 				}
62720c794b3Sgavinm 				nb_ndimm ++;
6289d6aa643Saf 			}
62920c794b3Sgavinm 		}
63020c794b3Sgavinm 		dimmpp += nb_dimms_per_channel * 2;
63120c794b3Sgavinm 	}
6329d6aa643Saf 	if (label_function == NULL)
6339d6aa643Saf 		nb_smbios();
63420c794b3Sgavinm }
63520c794b3Sgavinm 
63620c794b3Sgavinm static void
63720c794b3Sgavinm nb_pex_init()
63820c794b3Sgavinm {
63920c794b3Sgavinm 	int i;
6405f28a827Saf 	uint32_t mask;
64120c794b3Sgavinm 
64220c794b3Sgavinm 	for (i = 0; i < NB_PCI_DEV; i++) {
64320c794b3Sgavinm 		switch (nb_chipset) {
64420c794b3Sgavinm 		case INTEL_NB_5000P:
64520c794b3Sgavinm 		case INTEL_NB_5000X:
6465f28a827Saf 			if (i == 1 || i > 8)
64720c794b3Sgavinm 				continue;
64820c794b3Sgavinm 			break;
64920c794b3Sgavinm 		case INTEL_NB_5000V:
65020c794b3Sgavinm 			if (i == 1 || i > 3)
65120c794b3Sgavinm 				continue;
65220c794b3Sgavinm 			break;
65320c794b3Sgavinm 		case INTEL_NB_5000Z:
65420c794b3Sgavinm 			if (i == 1 || i > 5)
65520c794b3Sgavinm 				continue;
65620c794b3Sgavinm 			break;
6575f28a827Saf 		case INTEL_NB_5400:
6585f28a827Saf 			break;
65920c794b3Sgavinm 		case INTEL_NB_7300:
6605f28a827Saf 			if (i > 8)
6615f28a827Saf 				continue;
66220c794b3Sgavinm 			break;
66320c794b3Sgavinm 		}
66420c794b3Sgavinm 		emask_uncor_pex[i] = EMASK_UNCOR_PEX_RD(i);
66520c794b3Sgavinm 		emask_cor_pex[i] = EMASK_COR_PEX_RD(i);
66620c794b3Sgavinm 		emask_rp_pex[i] = EMASK_RP_PEX_RD(i);
66720c794b3Sgavinm 		docmd_pex[i] = PEX_ERR_DOCMD_RD(i);
66820c794b3Sgavinm 		uncerrsev[i] = UNCERRSEV_RD(i);
66920c794b3Sgavinm 
67020c794b3Sgavinm 		if (nb5000_reset_uncor_pex)
67120c794b3Sgavinm 			EMASK_UNCOR_PEX_WR(i, nb5000_mask_uncor_pex);
67220c794b3Sgavinm 		if (nb5000_reset_cor_pex)
67320c794b3Sgavinm 			EMASK_COR_PEX_WR(i, nb5000_mask_cor_pex);
6745f28a827Saf 		if (nb_set_docmd) {
6755f28a827Saf 			if (nb_chipset == INTEL_NB_5400) {
6769a12e1bdSjveta 				/* disable masking of ERR pins used by DOCMD */
6779a12e1bdSjveta 				PEX_ERR_PIN_MASK_WR(i, 0x10);
6789a12e1bdSjveta 
6795f28a827Saf 				mask = (docmd_pex[i] & nb5400_docmd_pex_mask) |
6805f28a827Saf 				    (nb5400_docmd_pex & ~nb5400_docmd_pex_mask);
6815f28a827Saf 			} else {
6825f28a827Saf 				mask = (docmd_pex[i] & nb5000_docmd_pex_mask) |
6835f28a827Saf 				    (nb5000_docmd_pex & ~nb5000_docmd_pex_mask);
6845f28a827Saf 			}
6855f28a827Saf 			PEX_ERR_DOCMD_WR(i, mask);
6865f28a827Saf 		}
6879a12e1bdSjveta 
6889a12e1bdSjveta 		/* RP error message (CE/NFE/FE) detect mask */
6899a12e1bdSjveta 		EMASK_RP_PEX_WR(i, nb5000_rp_pex);
6909a12e1bdSjveta 
6919a12e1bdSjveta 		/* Setup ESI port registers to enable SERR for southbridge */
6929a12e1bdSjveta 		if (i == 0) {
6939a12e1bdSjveta 			uint16_t regw;
6949a12e1bdSjveta 
6959a12e1bdSjveta 			/* Command Register - Enable SERR */
6969a12e1bdSjveta 			regw = nb_pci_getw(0, i, 0, PCI_CONF_COMM, 0);
6979a12e1bdSjveta 			nb_pci_putw(0, i, 0, PCI_CONF_COMM,
6989a12e1bdSjveta 			    regw | PCI_COMM_SERR_ENABLE);
6999a12e1bdSjveta 
7009a12e1bdSjveta 			/* Root Control Register - SERR on NFE/FE */
7019a12e1bdSjveta 			PEXROOTCTL_WR(i, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
7029a12e1bdSjveta 			    PCIE_ROOTCTL_SYS_ERR_ON_FE_EN);
7039a12e1bdSjveta 
7049a12e1bdSjveta 			/* AER UE Mask - Mask UR */
7059a12e1bdSjveta 			UNCERRMSK_WR(i, PCIE_AER_UCE_UR);
7069a12e1bdSjveta 		}
70720c794b3Sgavinm 	}
70820c794b3Sgavinm }
70920c794b3Sgavinm 
71020c794b3Sgavinm static void
71120c794b3Sgavinm nb_pex_fini()
71220c794b3Sgavinm {
71320c794b3Sgavinm 	int i;
71420c794b3Sgavinm 
71520c794b3Sgavinm 	for (i = 0; i < NB_PCI_DEV; i++) {
71620c794b3Sgavinm 		switch (nb_chipset) {
71720c794b3Sgavinm 		case INTEL_NB_5000P:
71820c794b3Sgavinm 		case INTEL_NB_5000X:
7195f28a827Saf 			if (i == 1 && i > 8)
72020c794b3Sgavinm 				continue;
72120c794b3Sgavinm 			break;
72220c794b3Sgavinm 		case INTEL_NB_5000V:
72320c794b3Sgavinm 			if (i == 1 || i > 3)
72420c794b3Sgavinm 				continue;
72520c794b3Sgavinm 			break;
72620c794b3Sgavinm 		case INTEL_NB_5000Z:
72720c794b3Sgavinm 			if (i == 1 || i > 5)
72820c794b3Sgavinm 				continue;
72920c794b3Sgavinm 			break;
7305f28a827Saf 		case INTEL_NB_5400:
7315f28a827Saf 			break;
73220c794b3Sgavinm 		case INTEL_NB_7300:
7335f28a827Saf 			if (i > 8)
7345f28a827Saf 				continue;
73520c794b3Sgavinm 			break;
73620c794b3Sgavinm 		}
73720c794b3Sgavinm 		EMASK_UNCOR_PEX_WR(i, emask_uncor_pex[i]);
73820c794b3Sgavinm 		EMASK_COR_PEX_WR(i, emask_cor_pex[i]);
73920c794b3Sgavinm 		EMASK_RP_PEX_WR(i, emask_rp_pex[i]);
74020c794b3Sgavinm 		PEX_ERR_DOCMD_WR(i, docmd_pex[i]);
74120c794b3Sgavinm 
74220c794b3Sgavinm 		if (nb5000_reset_uncor_pex)
74320c794b3Sgavinm 			EMASK_UNCOR_PEX_WR(i, nb5000_mask_uncor_pex);
74420c794b3Sgavinm 		if (nb5000_reset_cor_pex)
74520c794b3Sgavinm 			EMASK_COR_PEX_WR(i, nb5000_mask_cor_pex);
74620c794b3Sgavinm 	}
74720c794b3Sgavinm }
74820c794b3Sgavinm 
74920c794b3Sgavinm void
75020c794b3Sgavinm nb_int_init()
75120c794b3Sgavinm {
75220c794b3Sgavinm 	uint8_t err0_int;
75320c794b3Sgavinm 	uint8_t err1_int;
75420c794b3Sgavinm 	uint8_t err2_int;
75520c794b3Sgavinm 	uint8_t mcerr_int;
7565f28a827Saf 	uint32_t emask_int;
75720c794b3Sgavinm 	uint16_t stepping;
75820c794b3Sgavinm 
75920c794b3Sgavinm 	err0_int = ERR0_INT_RD();
76020c794b3Sgavinm 	err1_int = ERR1_INT_RD();
76120c794b3Sgavinm 	err2_int = ERR2_INT_RD();
76220c794b3Sgavinm 	mcerr_int = MCERR_INT_RD();
76320c794b3Sgavinm 	emask_int = EMASK_INT_RD();
76420c794b3Sgavinm 
76520c794b3Sgavinm 	nb_err0_int = err0_int;
76620c794b3Sgavinm 	nb_err1_int = err1_int;
76720c794b3Sgavinm 	nb_err2_int = err2_int;
76820c794b3Sgavinm 	nb_mcerr_int = mcerr_int;
76920c794b3Sgavinm 	nb_emask_int = emask_int;
77020c794b3Sgavinm 
77120c794b3Sgavinm 	ERR0_INT_WR(0xff);
77220c794b3Sgavinm 	ERR1_INT_WR(0xff);
77320c794b3Sgavinm 	ERR2_INT_WR(0xff);
77420c794b3Sgavinm 	MCERR_INT_WR(0xff);
77520c794b3Sgavinm 	EMASK_INT_WR(0xff);
77620c794b3Sgavinm 
77720c794b3Sgavinm 	mcerr_int &= ~nb5000_mask_bios_int;
77820c794b3Sgavinm 	mcerr_int |= nb5000_mask_bios_int & (~err0_int | ~err1_int | ~err2_int);
77920c794b3Sgavinm 	mcerr_int |= nb5000_mask_poll_int;
78020c794b3Sgavinm 	err0_int |= nb5000_mask_poll_int;
78120c794b3Sgavinm 	err1_int |= nb5000_mask_poll_int;
78220c794b3Sgavinm 	err2_int |= nb5000_mask_poll_int;
78320c794b3Sgavinm 
78420c794b3Sgavinm 	l_mcerr_int = mcerr_int;
78520c794b3Sgavinm 	ERR0_INT_WR(err0_int);
78620c794b3Sgavinm 	ERR1_INT_WR(err1_int);
78720c794b3Sgavinm 	ERR2_INT_WR(err2_int);
78820c794b3Sgavinm 	MCERR_INT_WR(mcerr_int);
78920c794b3Sgavinm 	if (nb5000_reset_emask_int) {
79020c794b3Sgavinm 		if (nb_chipset == INTEL_NB_7300) {
79120c794b3Sgavinm 			stepping = NB5000_STEPPING();
79220c794b3Sgavinm 			if (stepping == 0)
7935f28a827Saf 				EMASK_5000_INT_WR(nb7300_emask_int_step0);
79420c794b3Sgavinm 			else
7955f28a827Saf 				EMASK_5000_INT_WR(nb7300_emask_int);
7965f28a827Saf 		} else if (nb_chipset == INTEL_NB_5400) {
7975f28a827Saf 			EMASK_5400_INT_WR(nb5400_emask_int |
7985f28a827Saf 			    (emask_int & EMASK_INT_RES));
79920c794b3Sgavinm 		} else {
8005f28a827Saf 			EMASK_5000_INT_WR(nb5000_emask_int);
80120c794b3Sgavinm 		}
80220c794b3Sgavinm 	} else {
80320c794b3Sgavinm 		EMASK_INT_WR(nb_emask_int);
80420c794b3Sgavinm 	}
80520c794b3Sgavinm }
80620c794b3Sgavinm 
80720c794b3Sgavinm void
80820c794b3Sgavinm nb_int_fini()
80920c794b3Sgavinm {
81020c794b3Sgavinm 	ERR0_INT_WR(0xff);
81120c794b3Sgavinm 	ERR1_INT_WR(0xff);
81220c794b3Sgavinm 	ERR2_INT_WR(0xff);
81320c794b3Sgavinm 	MCERR_INT_WR(0xff);
81420c794b3Sgavinm 	EMASK_INT_WR(0xff);
81520c794b3Sgavinm 
81620c794b3Sgavinm 	ERR0_INT_WR(nb_err0_int);
81720c794b3Sgavinm 	ERR1_INT_WR(nb_err1_int);
81820c794b3Sgavinm 	ERR2_INT_WR(nb_err2_int);
81920c794b3Sgavinm 	MCERR_INT_WR(nb_mcerr_int);
82020c794b3Sgavinm 	EMASK_INT_WR(nb_emask_int);
82120c794b3Sgavinm }
82220c794b3Sgavinm 
82320c794b3Sgavinm void
8245f28a827Saf nb_int_mask_mc(uint32_t mc_mask_int)
82520c794b3Sgavinm {
8265f28a827Saf 	uint32_t emask_int;
82720c794b3Sgavinm 
82820c794b3Sgavinm 	emask_int = MCERR_INT_RD();
82920c794b3Sgavinm 	if ((emask_int & mc_mask_int) != mc_mask_int) {
83020c794b3Sgavinm 		MCERR_INT_WR(emask_int|mc_mask_int);
83120c794b3Sgavinm 		nb_mask_mc_set = 1;
83220c794b3Sgavinm 	}
83320c794b3Sgavinm }
83420c794b3Sgavinm 
83520c794b3Sgavinm void
83620c794b3Sgavinm nb_fbd_init()
83720c794b3Sgavinm {
83820c794b3Sgavinm 	uint32_t err0_fbd;
83920c794b3Sgavinm 	uint32_t err1_fbd;
84020c794b3Sgavinm 	uint32_t err2_fbd;
84120c794b3Sgavinm 	uint32_t mcerr_fbd;
84220c794b3Sgavinm 	uint32_t emask_fbd;
8435f28a827Saf 	uint32_t emask_bios_fbd;
8445f28a827Saf 	uint32_t emask_poll_fbd;
84520c794b3Sgavinm 
84620c794b3Sgavinm 	err0_fbd = ERR0_FBD_RD();
84720c794b3Sgavinm 	err1_fbd = ERR1_FBD_RD();
84820c794b3Sgavinm 	err2_fbd = ERR2_FBD_RD();
84920c794b3Sgavinm 	mcerr_fbd = MCERR_FBD_RD();
85020c794b3Sgavinm 	emask_fbd = EMASK_FBD_RD();
85120c794b3Sgavinm 
85220c794b3Sgavinm 	nb_err0_fbd = err0_fbd;
85320c794b3Sgavinm 	nb_err1_fbd = err1_fbd;
85420c794b3Sgavinm 	nb_err2_fbd = err2_fbd;
85520c794b3Sgavinm 	nb_mcerr_fbd = mcerr_fbd;
85620c794b3Sgavinm 	nb_emask_fbd = emask_fbd;
85720c794b3Sgavinm 
85820c794b3Sgavinm 	ERR0_FBD_WR(0xffffffff);
85920c794b3Sgavinm 	ERR1_FBD_WR(0xffffffff);
86020c794b3Sgavinm 	ERR2_FBD_WR(0xffffffff);
86120c794b3Sgavinm 	MCERR_FBD_WR(0xffffffff);
86220c794b3Sgavinm 	EMASK_FBD_WR(0xffffffff);
86320c794b3Sgavinm 
86420c794b3Sgavinm 	if (nb_chipset == INTEL_NB_7300 && nb_mode == NB_MEMORY_MIRROR) {
86520c794b3Sgavinm 		/* MCH 7300 errata 34 */
8665f28a827Saf 		emask_bios_fbd = nb5000_mask_bios_fbd & ~EMASK_FBD_M23;
8675f28a827Saf 		emask_poll_fbd = nb5000_mask_poll_fbd;
86820c794b3Sgavinm 		mcerr_fbd |= EMASK_FBD_M23;
8695f28a827Saf 	} else if (nb_chipset == INTEL_NB_5400) {
8705f28a827Saf 		emask_bios_fbd = nb5400_mask_bios_fbd;
8715f28a827Saf 		emask_poll_fbd = nb5400_mask_poll_fbd;
8725f28a827Saf 	} else {
8735f28a827Saf 		emask_bios_fbd = nb5000_mask_bios_fbd;
8745f28a827Saf 		emask_poll_fbd = nb5000_mask_poll_fbd;
87520c794b3Sgavinm 	}
8765f28a827Saf 	mcerr_fbd &= ~emask_bios_fbd;
8775f28a827Saf 	mcerr_fbd |= emask_bios_fbd & (~err0_fbd | ~err1_fbd | ~err2_fbd);
8785f28a827Saf 	mcerr_fbd |= emask_poll_fbd;
8795f28a827Saf 	err0_fbd |= emask_poll_fbd;
8805f28a827Saf 	err1_fbd |= emask_poll_fbd;
8815f28a827Saf 	err2_fbd |= emask_poll_fbd;
88220c794b3Sgavinm 
88320c794b3Sgavinm 	l_mcerr_fbd = mcerr_fbd;
88420c794b3Sgavinm 	ERR0_FBD_WR(err0_fbd);
88520c794b3Sgavinm 	ERR1_FBD_WR(err1_fbd);
88620c794b3Sgavinm 	ERR2_FBD_WR(err2_fbd);
88720c794b3Sgavinm 	MCERR_FBD_WR(mcerr_fbd);
8885f28a827Saf 	if (nb5000_reset_emask_fbd) {
8895f28a827Saf 		if (nb_chipset == INTEL_NB_5400)
8905f28a827Saf 			EMASK_FBD_WR(nb5400_emask_fbd);
8915f28a827Saf 		else
8925f28a827Saf 			EMASK_FBD_WR(nb5000_emask_fbd);
8935f28a827Saf 	} else {
89420c794b3Sgavinm 		EMASK_FBD_WR(nb_emask_fbd);
8955f28a827Saf 	}
89620c794b3Sgavinm }
89720c794b3Sgavinm 
89820c794b3Sgavinm void
89920c794b3Sgavinm nb_fbd_mask_mc(uint32_t mc_mask_fbd)
90020c794b3Sgavinm {
90120c794b3Sgavinm 	uint32_t emask_fbd;
90220c794b3Sgavinm 
90320c794b3Sgavinm 	emask_fbd = MCERR_FBD_RD();
90420c794b3Sgavinm 	if ((emask_fbd & mc_mask_fbd) != mc_mask_fbd) {
90520c794b3Sgavinm 		MCERR_FBD_WR(emask_fbd|mc_mask_fbd);
90620c794b3Sgavinm 		nb_mask_mc_set = 1;
90720c794b3Sgavinm 	}
90820c794b3Sgavinm }
90920c794b3Sgavinm 
91020c794b3Sgavinm void
91120c794b3Sgavinm nb_fbd_fini()
91220c794b3Sgavinm {
91320c794b3Sgavinm 	ERR0_FBD_WR(0xffffffff);
91420c794b3Sgavinm 	ERR1_FBD_WR(0xffffffff);
91520c794b3Sgavinm 	ERR2_FBD_WR(0xffffffff);
91620c794b3Sgavinm 	MCERR_FBD_WR(0xffffffff);
91720c794b3Sgavinm 	EMASK_FBD_WR(0xffffffff);
91820c794b3Sgavinm 
91920c794b3Sgavinm 	ERR0_FBD_WR(nb_err0_fbd);
92020c794b3Sgavinm 	ERR1_FBD_WR(nb_err1_fbd);
92120c794b3Sgavinm 	ERR2_FBD_WR(nb_err2_fbd);
92220c794b3Sgavinm 	MCERR_FBD_WR(nb_mcerr_fbd);
92320c794b3Sgavinm 	EMASK_FBD_WR(nb_emask_fbd);
92420c794b3Sgavinm }
92520c794b3Sgavinm 
92620c794b3Sgavinm static void
92720c794b3Sgavinm nb_fsb_init()
92820c794b3Sgavinm {
92920c794b3Sgavinm 	uint16_t err0_fsb;
93020c794b3Sgavinm 	uint16_t err1_fsb;
93120c794b3Sgavinm 	uint16_t err2_fsb;
93220c794b3Sgavinm 	uint16_t mcerr_fsb;
93320c794b3Sgavinm 	uint16_t emask_fsb;
93420c794b3Sgavinm 
93520c794b3Sgavinm 	err0_fsb = ERR0_FSB_RD(0);
93620c794b3Sgavinm 	err1_fsb = ERR1_FSB_RD(0);
93720c794b3Sgavinm 	err2_fsb = ERR2_FSB_RD(0);
93820c794b3Sgavinm 	mcerr_fsb = MCERR_FSB_RD(0);
93920c794b3Sgavinm 	emask_fsb = EMASK_FSB_RD(0);
94020c794b3Sgavinm 
94120c794b3Sgavinm 	ERR0_FSB_WR(0, 0xffff);
94220c794b3Sgavinm 	ERR1_FSB_WR(0, 0xffff);
94320c794b3Sgavinm 	ERR2_FSB_WR(0, 0xffff);
94420c794b3Sgavinm 	MCERR_FSB_WR(0, 0xffff);
94520c794b3Sgavinm 	EMASK_FSB_WR(0, 0xffff);
94620c794b3Sgavinm 
94720c794b3Sgavinm 	ERR0_FSB_WR(1, 0xffff);
94820c794b3Sgavinm 	ERR1_FSB_WR(1, 0xffff);
94920c794b3Sgavinm 	ERR2_FSB_WR(1, 0xffff);
95020c794b3Sgavinm 	MCERR_FSB_WR(1, 0xffff);
95120c794b3Sgavinm 	EMASK_FSB_WR(1, 0xffff);
95220c794b3Sgavinm 
95320c794b3Sgavinm 	nb_err0_fsb = err0_fsb;
95420c794b3Sgavinm 	nb_err1_fsb = err1_fsb;
95520c794b3Sgavinm 	nb_err2_fsb = err2_fsb;
95620c794b3Sgavinm 	nb_mcerr_fsb = mcerr_fsb;
95720c794b3Sgavinm 	nb_emask_fsb = emask_fsb;
95820c794b3Sgavinm 
95920c794b3Sgavinm 	mcerr_fsb &= ~nb5000_mask_bios_fsb;
96020c794b3Sgavinm 	mcerr_fsb |= nb5000_mask_bios_fsb & (~err2_fsb | ~err1_fsb | ~err0_fsb);
96120c794b3Sgavinm 	mcerr_fsb |= nb5000_mask_poll_fsb;
96220c794b3Sgavinm 	err0_fsb |= nb5000_mask_poll_fsb;
96320c794b3Sgavinm 	err1_fsb |= nb5000_mask_poll_fsb;
96420c794b3Sgavinm 	err2_fsb |= nb5000_mask_poll_fsb;
96520c794b3Sgavinm 
96620c794b3Sgavinm 	l_mcerr_fsb = mcerr_fsb;
96720c794b3Sgavinm 	ERR0_FSB_WR(0, err0_fsb);
96820c794b3Sgavinm 	ERR1_FSB_WR(0, err1_fsb);
96920c794b3Sgavinm 	ERR2_FSB_WR(0, err2_fsb);
97020c794b3Sgavinm 	MCERR_FSB_WR(0, mcerr_fsb);
9715f28a827Saf 	if (nb5000_reset_emask_fsb) {
97220c794b3Sgavinm 		EMASK_FSB_WR(0, nb5000_emask_fsb);
9735f28a827Saf 	} else {
97420c794b3Sgavinm 		EMASK_FSB_WR(0, nb_emask_fsb);
9755f28a827Saf 	}
97620c794b3Sgavinm 
97720c794b3Sgavinm 	ERR0_FSB_WR(1, err0_fsb);
97820c794b3Sgavinm 	ERR1_FSB_WR(1, err1_fsb);
97920c794b3Sgavinm 	ERR2_FSB_WR(1, err2_fsb);
98020c794b3Sgavinm 	MCERR_FSB_WR(1, mcerr_fsb);
9815f28a827Saf 	if (nb5000_reset_emask_fsb) {
98220c794b3Sgavinm 		EMASK_FSB_WR(1, nb5000_emask_fsb);
9835f28a827Saf 	} else {
98420c794b3Sgavinm 		EMASK_FSB_WR(1, nb_emask_fsb);
9855f28a827Saf 	}
98620c794b3Sgavinm 
98720c794b3Sgavinm 	if (nb_chipset == INTEL_NB_7300) {
98820c794b3Sgavinm 		ERR0_FSB_WR(2, 0xffff);
98920c794b3Sgavinm 		ERR1_FSB_WR(2, 0xffff);
99020c794b3Sgavinm 		ERR2_FSB_WR(2, 0xffff);
99120c794b3Sgavinm 		MCERR_FSB_WR(2, 0xffff);
99220c794b3Sgavinm 		EMASK_FSB_WR(2, 0xffff);
99320c794b3Sgavinm 
99420c794b3Sgavinm 		ERR0_FSB_WR(3, 0xffff);
99520c794b3Sgavinm 		ERR1_FSB_WR(3, 0xffff);
99620c794b3Sgavinm 		ERR2_FSB_WR(3, 0xffff);
99720c794b3Sgavinm 		MCERR_FSB_WR(3, 0xffff);
99820c794b3Sgavinm 		EMASK_FSB_WR(3, 0xffff);
99920c794b3Sgavinm 
100020c794b3Sgavinm 		ERR0_FSB_WR(2, err0_fsb);
100120c794b3Sgavinm 		ERR1_FSB_WR(2, err1_fsb);
100220c794b3Sgavinm 		ERR2_FSB_WR(2, err2_fsb);
100320c794b3Sgavinm 		MCERR_FSB_WR(2, mcerr_fsb);
10045f28a827Saf 		if (nb5000_reset_emask_fsb) {
100520c794b3Sgavinm 			EMASK_FSB_WR(2, nb5000_emask_fsb);
10065f28a827Saf 		} else {
100720c794b3Sgavinm 			EMASK_FSB_WR(2, nb_emask_fsb);
10085f28a827Saf 		}
100920c794b3Sgavinm 
101020c794b3Sgavinm 		ERR0_FSB_WR(3, err0_fsb);
101120c794b3Sgavinm 		ERR1_FSB_WR(3, err1_fsb);
101220c794b3Sgavinm 		ERR2_FSB_WR(3, err2_fsb);
101320c794b3Sgavinm 		MCERR_FSB_WR(3, mcerr_fsb);
10145f28a827Saf 		if (nb5000_reset_emask_fsb) {
101520c794b3Sgavinm 			EMASK_FSB_WR(3, nb5000_emask_fsb);
10165f28a827Saf 		} else {
101720c794b3Sgavinm 			EMASK_FSB_WR(3, nb_emask_fsb);
10185f28a827Saf 		}
101920c794b3Sgavinm 	}
102020c794b3Sgavinm }
102120c794b3Sgavinm 
102220c794b3Sgavinm static void
102320c794b3Sgavinm nb_fsb_fini() {
102420c794b3Sgavinm 	ERR0_FSB_WR(0, 0xffff);
102520c794b3Sgavinm 	ERR1_FSB_WR(0, 0xffff);
102620c794b3Sgavinm 	ERR2_FSB_WR(0, 0xffff);
102720c794b3Sgavinm 	MCERR_FSB_WR(0, 0xffff);
102820c794b3Sgavinm 	EMASK_FSB_WR(0, 0xffff);
102920c794b3Sgavinm 
103020c794b3Sgavinm 	ERR0_FSB_WR(0, nb_err0_fsb);
103120c794b3Sgavinm 	ERR1_FSB_WR(0, nb_err1_fsb);
103220c794b3Sgavinm 	ERR2_FSB_WR(0, nb_err2_fsb);
103320c794b3Sgavinm 	MCERR_FSB_WR(0, nb_mcerr_fsb);
103420c794b3Sgavinm 	EMASK_FSB_WR(0, nb_emask_fsb);
103520c794b3Sgavinm 
103620c794b3Sgavinm 	ERR0_FSB_WR(1, 0xffff);
103720c794b3Sgavinm 	ERR1_FSB_WR(1, 0xffff);
103820c794b3Sgavinm 	ERR2_FSB_WR(1, 0xffff);
103920c794b3Sgavinm 	MCERR_FSB_WR(1, 0xffff);
104020c794b3Sgavinm 	EMASK_FSB_WR(1, 0xffff);
104120c794b3Sgavinm 
104220c794b3Sgavinm 	ERR0_FSB_WR(1, nb_err0_fsb);
104320c794b3Sgavinm 	ERR1_FSB_WR(1, nb_err1_fsb);
104420c794b3Sgavinm 	ERR2_FSB_WR(1, nb_err2_fsb);
104520c794b3Sgavinm 	MCERR_FSB_WR(1, nb_mcerr_fsb);
104620c794b3Sgavinm 	EMASK_FSB_WR(1, nb_emask_fsb);
104720c794b3Sgavinm 
104820c794b3Sgavinm 	if (nb_chipset == INTEL_NB_7300) {
104920c794b3Sgavinm 		ERR0_FSB_WR(2, 0xffff);
105020c794b3Sgavinm 		ERR1_FSB_WR(2, 0xffff);
105120c794b3Sgavinm 		ERR2_FSB_WR(2, 0xffff);
105220c794b3Sgavinm 		MCERR_FSB_WR(2, 0xffff);
105320c794b3Sgavinm 		EMASK_FSB_WR(2, 0xffff);
105420c794b3Sgavinm 
105520c794b3Sgavinm 		ERR0_FSB_WR(2, nb_err0_fsb);
105620c794b3Sgavinm 		ERR1_FSB_WR(2, nb_err1_fsb);
105720c794b3Sgavinm 		ERR2_FSB_WR(2, nb_err2_fsb);
105820c794b3Sgavinm 		MCERR_FSB_WR(2, nb_mcerr_fsb);
105920c794b3Sgavinm 		EMASK_FSB_WR(2, nb_emask_fsb);
106020c794b3Sgavinm 
106120c794b3Sgavinm 		ERR0_FSB_WR(3, 0xffff);
106220c794b3Sgavinm 		ERR1_FSB_WR(3, 0xffff);
106320c794b3Sgavinm 		ERR2_FSB_WR(3, 0xffff);
106420c794b3Sgavinm 		MCERR_FSB_WR(3, 0xffff);
106520c794b3Sgavinm 		EMASK_FSB_WR(3, 0xffff);
106620c794b3Sgavinm 
106720c794b3Sgavinm 		ERR0_FSB_WR(3, nb_err0_fsb);
106820c794b3Sgavinm 		ERR1_FSB_WR(3, nb_err1_fsb);
106920c794b3Sgavinm 		ERR2_FSB_WR(3, nb_err2_fsb);
107020c794b3Sgavinm 		MCERR_FSB_WR(3, nb_mcerr_fsb);
107120c794b3Sgavinm 		EMASK_FSB_WR(3, nb_emask_fsb);
107220c794b3Sgavinm 	}
107320c794b3Sgavinm }
107420c794b3Sgavinm 
107520c794b3Sgavinm void
107620c794b3Sgavinm nb_fsb_mask_mc(int fsb, uint16_t mc_mask_fsb)
107720c794b3Sgavinm {
107820c794b3Sgavinm 	uint16_t emask_fsb;
107920c794b3Sgavinm 
108020c794b3Sgavinm 	emask_fsb = MCERR_FSB_RD(fsb);
108120c794b3Sgavinm 	if ((emask_fsb & mc_mask_fsb) != mc_mask_fsb) {
108220c794b3Sgavinm 		MCERR_FSB_WR(fsb, emask_fsb|mc_mask_fsb|EMASK_FBD_RES);
108320c794b3Sgavinm 		nb_mask_mc_set = 1;
108420c794b3Sgavinm 	}
108520c794b3Sgavinm }
108620c794b3Sgavinm 
10875f28a827Saf static void
10885f28a827Saf nb_thr_init()
10895f28a827Saf {
10905f28a827Saf 	uint16_t err0_thr;
10915f28a827Saf 	uint16_t err1_thr;
10925f28a827Saf 	uint16_t err2_thr;
10935f28a827Saf 	uint16_t mcerr_thr;
10945f28a827Saf 	uint16_t emask_thr;
10955f28a827Saf 
10965f28a827Saf 	if (nb_chipset == INTEL_NB_5400) {
10975f28a827Saf 		err0_thr = ERR0_THR_RD(0);
10985f28a827Saf 		err1_thr = ERR1_THR_RD(0);
10995f28a827Saf 		err2_thr = ERR2_THR_RD(0);
11005f28a827Saf 		mcerr_thr = MCERR_THR_RD(0);
11015f28a827Saf 		emask_thr = EMASK_THR_RD(0);
11025f28a827Saf 
11035f28a827Saf 		ERR0_THR_WR(0xffff);
11045f28a827Saf 		ERR1_THR_WR(0xffff);
11055f28a827Saf 		ERR2_THR_WR(0xffff);
11065f28a827Saf 		MCERR_THR_WR(0xffff);
11075f28a827Saf 		EMASK_THR_WR(0xffff);
11085f28a827Saf 
11095f28a827Saf 		nb_err0_thr = err0_thr;
11105f28a827Saf 		nb_err1_thr = err1_thr;
11115f28a827Saf 		nb_err2_thr = err2_thr;
11125f28a827Saf 		nb_mcerr_thr = mcerr_thr;
11135f28a827Saf 		nb_emask_thr = emask_thr;
11145f28a827Saf 
11155f28a827Saf 		mcerr_thr &= ~nb_mask_bios_thr;
11165f28a827Saf 		mcerr_thr |= nb_mask_bios_thr &
11175f28a827Saf 		    (~err2_thr | ~err1_thr | ~err0_thr);
11185f28a827Saf 		mcerr_thr |= nb_mask_poll_thr;
11195f28a827Saf 		err0_thr |= nb_mask_poll_thr;
11205f28a827Saf 		err1_thr |= nb_mask_poll_thr;
11215f28a827Saf 		err2_thr |= nb_mask_poll_thr;
11225f28a827Saf 
11235f28a827Saf 		l_mcerr_thr = mcerr_thr;
11245f28a827Saf 		ERR0_THR_WR(err0_thr);
11255f28a827Saf 		ERR1_THR_WR(err1_thr);
11265f28a827Saf 		ERR2_THR_WR(err2_thr);
11275f28a827Saf 		MCERR_THR_WR(mcerr_thr);
11285f28a827Saf 		EMASK_THR_WR(nb_emask_thr);
11295f28a827Saf 	}
11305f28a827Saf }
11315f28a827Saf 
11325f28a827Saf static void
11335f28a827Saf nb_thr_fini()
11345f28a827Saf {
11355f28a827Saf 	if (nb_chipset == INTEL_NB_5400) {
11365f28a827Saf 		ERR0_THR_WR(0xffff);
11375f28a827Saf 		ERR1_THR_WR(0xffff);
11385f28a827Saf 		ERR2_THR_WR(0xffff);
11395f28a827Saf 		MCERR_THR_WR(0xffff);
11405f28a827Saf 		EMASK_THR_WR(0xffff);
11415f28a827Saf 
11425f28a827Saf 		ERR0_THR_WR(nb_err0_thr);
11435f28a827Saf 		ERR1_THR_WR(nb_err1_thr);
11445f28a827Saf 		ERR2_THR_WR(nb_err2_thr);
11455f28a827Saf 		MCERR_THR_WR(nb_mcerr_thr);
11465f28a827Saf 		EMASK_THR_WR(nb_emask_thr);
11475f28a827Saf 	}
11485f28a827Saf }
11495f28a827Saf 
11505f28a827Saf void
11515f28a827Saf nb_thr_mask_mc(uint16_t mc_mask_thr)
11525f28a827Saf {
11535f28a827Saf 	uint16_t emask_thr;
11545f28a827Saf 
11555f28a827Saf 	emask_thr = MCERR_THR_RD(0);
11565f28a827Saf 	if ((emask_thr & mc_mask_thr) != mc_mask_thr) {
11575f28a827Saf 		MCERR_THR_WR(emask_thr|mc_mask_thr);
11585f28a827Saf 		nb_mask_mc_set = 1;
11595f28a827Saf 	}
11605f28a827Saf }
11615f28a827Saf 
116220c794b3Sgavinm void
116320c794b3Sgavinm nb_mask_mc_reset()
116420c794b3Sgavinm {
116520c794b3Sgavinm 	MCERR_FBD_WR(l_mcerr_fbd);
116620c794b3Sgavinm 	MCERR_INT_WR(l_mcerr_int);
116720c794b3Sgavinm 	MCERR_FSB_WR(0, l_mcerr_fsb);
116820c794b3Sgavinm 	MCERR_FSB_WR(1, l_mcerr_fsb);
116920c794b3Sgavinm 	if (nb_chipset == INTEL_NB_7300) {
117020c794b3Sgavinm 		MCERR_FSB_WR(2, l_mcerr_fsb);
117120c794b3Sgavinm 		MCERR_FSB_WR(3, l_mcerr_fsb);
117220c794b3Sgavinm 	}
11735f28a827Saf 	if (nb_chipset == INTEL_NB_5400) {
11745f28a827Saf 		MCERR_THR_WR(l_mcerr_thr);
11755f28a827Saf 	}
117620c794b3Sgavinm }
117720c794b3Sgavinm 
117820c794b3Sgavinm int
117920c794b3Sgavinm nb_dev_init()
118020c794b3Sgavinm {
11819d6aa643Saf 	find_dimm_label_t *label_function_p;
11829d6aa643Saf 
11839d6aa643Saf 	label_function_p = find_dimms_per_channel();
118420c794b3Sgavinm 	mutex_init(&nb_mutex, NULL, MUTEX_DRIVER, NULL);
118520c794b3Sgavinm 	nb_queue = errorq_create("nb_queue", nb_drain, NULL, NB_MAX_ERRORS,
118620c794b3Sgavinm 	    sizeof (nb_logout_t), 1, ERRORQ_VITAL);
118720c794b3Sgavinm 	if (nb_queue == NULL) {
118820c794b3Sgavinm 		mutex_destroy(&nb_mutex);
118920c794b3Sgavinm 		return (EAGAIN);
119020c794b3Sgavinm 	}
11919d6aa643Saf 	nb_int_init();
11925f28a827Saf 	nb_thr_init();
119320c794b3Sgavinm 	dimm_init();
11949d6aa643Saf 	nb_dimms_init(label_function_p);
119520c794b3Sgavinm 	nb_mc_init();
119620c794b3Sgavinm 	nb_pex_init();
119720c794b3Sgavinm 	nb_fbd_init();
119820c794b3Sgavinm 	nb_fsb_init();
119920c794b3Sgavinm 	nb_scrubber_enable();
120020c794b3Sgavinm 	return (0);
120120c794b3Sgavinm }
120220c794b3Sgavinm 
120320c794b3Sgavinm int
120420c794b3Sgavinm nb_init()
120520c794b3Sgavinm {
1206*e4b86885SCheng Sean Ye 	/* return ENOTSUP if there is no PCI config space support. */
1207*e4b86885SCheng Sean Ye 	if (pci_getl_func == NULL)
1208*e4b86885SCheng Sean Ye 		return (ENOTSUP);
1209*e4b86885SCheng Sean Ye 
121020c794b3Sgavinm 	/* get vendor and device */
121120c794b3Sgavinm 	nb_chipset = (*pci_getl_func)(0, 0, 0, PCI_CONF_VENID);
121220c794b3Sgavinm 	switch (nb_chipset) {
121320c794b3Sgavinm 	default:
121420c794b3Sgavinm 		if (nb_5000_memory_controller == 0)
121520c794b3Sgavinm 			return (ENOTSUP);
121620c794b3Sgavinm 		break;
121720c794b3Sgavinm 	case INTEL_NB_7300:
121820c794b3Sgavinm 	case INTEL_NB_5000P:
121920c794b3Sgavinm 	case INTEL_NB_5000X:
122020c794b3Sgavinm 		break;
122120c794b3Sgavinm 	case INTEL_NB_5000V:
122220c794b3Sgavinm 	case INTEL_NB_5000Z:
122320c794b3Sgavinm 		nb_number_memory_controllers = 1;
122420c794b3Sgavinm 		break;
12255f28a827Saf 	case INTEL_NB_5400:
12265f28a827Saf 	case INTEL_NB_5400A:
12275f28a827Saf 	case INTEL_NB_5400B:
12285f28a827Saf 		nb_chipset = INTEL_NB_5400;
12295f28a827Saf 		break;
123020c794b3Sgavinm 	}
123120c794b3Sgavinm 	return (0);
123220c794b3Sgavinm }
123320c794b3Sgavinm 
123420c794b3Sgavinm void
123520c794b3Sgavinm nb_dev_reinit()
123620c794b3Sgavinm {
123720c794b3Sgavinm 	int i, j;
123820c794b3Sgavinm 	int nchannels = nb_number_memory_controllers * 2;
123920c794b3Sgavinm 	nb_dimm_t **dimmpp;
124020c794b3Sgavinm 	nb_dimm_t *dimmp;
124120c794b3Sgavinm 	nb_dimm_t **old_nb_dimms;
124220c794b3Sgavinm 	int old_nb_dimms_per_channel;
12439d6aa643Saf 	find_dimm_label_t *label_function_p;
124420c794b3Sgavinm 
124520c794b3Sgavinm 	old_nb_dimms = nb_dimms;
124620c794b3Sgavinm 	old_nb_dimms_per_channel = nb_dimms_per_channel;
124720c794b3Sgavinm 
124820c794b3Sgavinm 	dimm_fini();
12499d6aa643Saf 	label_function_p = find_dimms_per_channel();
125020c794b3Sgavinm 	dimm_init();
12519d6aa643Saf 	nb_dimms_init(label_function_p);
125220c794b3Sgavinm 	nb_mc_init();
125320c794b3Sgavinm 	nb_pex_init();
125420c794b3Sgavinm 	nb_int_init();
12555f28a827Saf 	nb_thr_init();
125620c794b3Sgavinm 	nb_fbd_init();
125720c794b3Sgavinm 	nb_fsb_init();
125820c794b3Sgavinm 	nb_scrubber_enable();
125920c794b3Sgavinm 
126020c794b3Sgavinm 	dimmpp = old_nb_dimms;
126120c794b3Sgavinm 	for (i = 0; i < nchannels; i++) {
126220c794b3Sgavinm 		for (j = 0; j < old_nb_dimms_per_channel; j++) {
126320c794b3Sgavinm 			dimmp = *dimmpp;
126420c794b3Sgavinm 			if (dimmp) {
126520c794b3Sgavinm 				kmem_free(dimmp, sizeof (nb_dimm_t));
126620c794b3Sgavinm 				*dimmpp = NULL;
126720c794b3Sgavinm 			}
126820c794b3Sgavinm 			dimmp++;
126920c794b3Sgavinm 		}
127020c794b3Sgavinm 	}
127120c794b3Sgavinm 	kmem_free(old_nb_dimms, sizeof (nb_dimm_t *) *
127220c794b3Sgavinm 	    nb_number_memory_controllers * 2 * old_nb_dimms_per_channel);
127320c794b3Sgavinm }
127420c794b3Sgavinm 
127520c794b3Sgavinm void
127620c794b3Sgavinm nb_dev_unload()
127720c794b3Sgavinm {
127820c794b3Sgavinm 	errorq_destroy(nb_queue);
127920c794b3Sgavinm 	nb_queue = NULL;
128020c794b3Sgavinm 	mutex_destroy(&nb_mutex);
128120c794b3Sgavinm 	nb_int_fini();
12825f28a827Saf 	nb_thr_fini();
128320c794b3Sgavinm 	nb_fbd_fini();
128420c794b3Sgavinm 	nb_fsb_fini();
128520c794b3Sgavinm 	nb_pex_fini();
128620c794b3Sgavinm 	nb_fini();
128720c794b3Sgavinm }
128820c794b3Sgavinm 
128920c794b3Sgavinm void
129020c794b3Sgavinm nb_unload()
129120c794b3Sgavinm {
129220c794b3Sgavinm }
1293